1#![cfg_attr(not(test), no_std)]
2#![feature(c_variadic)]
3#![feature(linkage)]
4#![feature(f128)]
5#![allow(dead_code, non_camel_case_types)]
6
7use core::ffi::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong, c_void, VaList};
8use core::ptr::null_mut;
9use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
10
11include!("encoding_tables.rs");
12include!("math_helpers.rs");
13include!("math_bitmanip.rs");
14include!("math_sqrtfmod.rs");
15include!("math_trig.rs");
16include!("math_exp.rs");
17include!("math_log.rs");
18include!("math_pow.rs");
19include!("math_hypot.rs");
20include!("math_hyperbolic.rs");
21include!("math_invtrig.rs");
22include!("math_lrint.rs");
23
24const EILSEQ: c_int = 84;
29const EINVAL: c_int = 22;
30const EFAULT: c_int = 14;
31const E2BIG: c_int = 7;
32
33const LC_CTYPE: c_int = 0;
34const LC_NUMERIC: c_int = 1;
35const LC_TIME: c_int = 2;
36const LC_COLLATE: c_int = 3;
37const LC_MONETARY: c_int = 4;
38const LC_MESSAGES: c_int = 5;
39const LC_ALL: c_int = 6;
40const ENOMEM: c_int = 12;
41const EINTR: c_int = 4;
42const EPERM: c_int = 1;
43const EAGAIN: c_int = 11;
44const EBUSY: c_int = 16;
45const EDEADLK: c_int = 35;
46const ETIMEDOUT: c_int = 110;
47const ECANCELED: c_int = 125;
48const EOVERFLOW: c_int = 75;
49const EOWNERDEAD: c_int = 130;
50const ENOTRECOVERABLE: c_int = 131;
51
52static mut ERRNO: c_int = 0;
53
54#[no_mangle]
55pub unsafe extern "C" fn __errno_location() -> *mut c_int {
56 core::ptr::addr_of_mut!(ERRNO)
57}
58
59#[cfg(not(test))]
60#[panic_handler]
61fn panic(_: &core::panic::PanicInfo) -> ! {
62 loop {}
63}
64
65#[cfg(not(test))]
67#[no_mangle]
68pub extern "C" fn rust_eh_personality() {}
69
70const PROT_READ: i32 = 1;
75const PROT_WRITE: i32 = 2;
76const MAP_SHARED: i32 = 0x01;
77const MAP_PRIVATE: i32 = 0x02;
78const MAP_ANONYMOUS: i32 = 0x20;
79
80trait Syscalls {
85 unsafe fn syscall0(n: i64) -> i64;
86 unsafe fn syscall1(n: i64, a1: i64) -> i64;
87 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64;
88 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64;
89 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64;
90 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64;
91 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64;
92 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> !;
93}
94
95struct X86_64;
96struct Aarch64;
97
98#[cfg(target_arch = "x86_64")]
99impl Syscalls for X86_64 {
100 #[inline(always)]
101 unsafe fn syscall0(n: i64) -> i64 {
102 let result: i64;
103 core::arch::asm!(
104 "syscall",
105 inlateout("rax") n => result,
106 lateout("rcx") _,
107 lateout("r11") _,
108 );
109 result
110 }
111 #[inline(always)]
112 unsafe fn syscall1(n: i64, a1: i64) -> i64 {
113 let result: i64;
114 core::arch::asm!(
115 "syscall",
116 inlateout("rax") n => result,
117 in("rdi") a1,
118 lateout("rcx") _,
119 lateout("r11") _,
120 );
121 result
122 }
123 #[inline(always)]
124 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
125 let result: i64;
126 core::arch::asm!(
127 "syscall",
128 inlateout("rax") n => result,
129 in("rdi") a1,
130 in("rsi") a2,
131 lateout("rcx") _,
132 lateout("r11") _,
133 );
134 result
135 }
136 #[inline(always)]
137 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
138 let result: i64;
139 core::arch::asm!(
140 "syscall",
141 inlateout("rax") n => result,
142 in("rdi") a1,
143 in("rsi") a2,
144 in("rdx") a3,
145 lateout("rcx") _,
146 lateout("r11") _,
147 );
148 result
149 }
150 #[inline(always)]
151 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
152 let result: i64;
153 core::arch::asm!(
154 "syscall",
155 inlateout("rax") n => result,
156 in("rdi") a1,
157 in("rsi") a2,
158 in("rdx") a3,
159 in("r10") a4,
160 lateout("rcx") _,
161 lateout("r11") _,
162 );
163 result
164 }
165 #[inline(always)]
166 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: 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 in("r8") a5,
176 lateout("rcx") _,
177 lateout("r11") _,
178 );
179 result
180 }
181 #[inline(always)]
182 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
183 let result: i64;
184 core::arch::asm!(
185 "syscall",
186 inlateout("rax") n => result,
187 in("rdi") a1,
188 in("rsi") a2,
189 in("rdx") a3,
190 in("r10") a4,
191 in("r8") a5,
192 in("r9") a6,
193 lateout("rcx") _,
194 lateout("r11") _,
195 );
196 result
197 }
198 #[inline(always)]
199 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
200 core::arch::asm!(
201 "syscall",
202 in("rax") n,
203 in("rdi") a1,
204 options(noreturn)
205 );
206 }
207}
208
209#[cfg(target_arch = "aarch64")]
210impl Syscalls for Aarch64 {
211 #[inline(always)]
212 unsafe fn syscall0(n: i64) -> i64 {
213 let result: i64;
214 core::arch::asm!(
215 "svc #0",
216 inlateout("x8") n => _,
217 lateout("x0") result,
218 options(nostack),
219 );
220 result
221 }
222 #[inline(always)]
223 unsafe fn syscall1(n: i64, a1: i64) -> i64 {
224 let result: i64;
225 core::arch::asm!(
226 "svc #0",
227 inlateout("x8") n => _,
228 inlateout("x0") a1 => result,
229 options(nostack),
230 );
231 result
232 }
233 #[inline(always)]
234 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
235 let result: i64;
236 core::arch::asm!(
237 "svc #0",
238 inlateout("x8") n => _,
239 inlateout("x0") a1 => result,
240 inlateout("x1") a2 => _,
241 options(nostack),
242 );
243 result
244 }
245 #[inline(always)]
246 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
247 let result: i64;
248 core::arch::asm!(
249 "svc #0",
250 inlateout("x8") n => _,
251 inlateout("x0") a1 => result,
252 inlateout("x1") a2 => _,
253 inlateout("x2") a3 => _,
254 options(nostack),
255 );
256 result
257 }
258 #[inline(always)]
259 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
260 let result: i64;
261 core::arch::asm!(
262 "svc #0",
263 inlateout("x8") n => _,
264 inlateout("x0") a1 => result,
265 inlateout("x1") a2 => _,
266 inlateout("x2") a3 => _,
267 inlateout("x3") a4 => _,
268 options(nostack),
269 );
270 result
271 }
272 #[inline(always)]
273 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
274 let result: i64;
275 core::arch::asm!(
276 "svc #0",
277 inlateout("x8") n => _,
278 inlateout("x0") a1 => result,
279 inlateout("x1") a2 => _,
280 inlateout("x2") a3 => _,
281 inlateout("x3") a4 => _,
282 inlateout("x4") a5 => _,
283 options(nostack),
284 );
285 result
286 }
287 #[inline(always)]
288 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: 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 inlateout("x5") a6 => _,
299 options(nostack),
300 );
301 result
302 }
303 #[inline(always)]
304 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
305 core::arch::asm!(
306 "svc #0",
307 in("x8") n,
308 in("x0") a1,
309 options(noreturn, nostack),
310 );
311 }
312}
313
314#[cfg(target_arch = "x86_64")]
315type Arch = X86_64;
316#[cfg(target_arch = "aarch64")]
317type Arch = Aarch64;
318
319
320
321#[cfg(target_arch = "x86_64")]
323mod sysnr {
324 pub const SYS_READ: i64 = 0;
325 pub const SYS_WRITE: i64 = 1;
326 pub const SYS_OPEN: i64 = 2;
327 pub const SYS_CLOSE: i64 = 3;
328 pub const SYS_STAT: i64 = 4;
329 pub const SYS_FSTAT: i64 = 5;
330 pub const SYS_LSEEK: i64 = 8;
331 pub const SYS_MMAP: i64 = 9;
332 pub const SYS_MUNMAP: i64 = 11;
333 pub const SYS_RT_SIGACTION: i64 = 13;
334 pub const SYS_RT_SIGPROCMASK: i64 = 14;
335 pub const SYS_IOCTL: i64 = 16;
336 pub const SYS_ACCESS: i64 = 21;
337 pub const SYS_SHMGET: i64 = 29;
338 pub const SYS_SHMAT: i64 = 30;
339 pub const SYS_SHMCTL: i64 = 31;
340 pub const SYS_DUP: i64 = 32;
341 pub const SYS_NANOSLEEP: i64 = 35;
342 pub const SYS_SETITIMER: i64 = 38;
343 pub const SYS_ALARM: i64 = 37;
344 pub const SYS_SOCKET: i64 = 41;
345 pub const SYS_CONNECT: i64 = 42;
346 pub const SYS_ACCEPT: i64 = 43;
347 pub const SYS_SENDTO: i64 = 44;
348 pub const SYS_RECVFROM: i64 = 45;
349 pub const SYS_SHUTDOWN: i64 = 48;
350 pub const SYS_BIND: i64 = 49;
351 pub const SYS_LISTEN: i64 = 50;
352 pub const SYS_GETSOCKNAME: i64 = 51;
353 pub const SYS_SOCKETPAIR: i64 = 53;
354 pub const SYS_SETSOCKOPT: i64 = 54;
355 pub const SYS_EXECVE: i64 = 59;
356 pub const SYS_WAIT4: i64 = 61;
357 pub const SYS_KILL: i64 = 62;
358 pub const SYS_UNAME: i64 = 63;
359 pub const SYS_SEMGET: i64 = 64;
360 pub const SYS_SEMOP: i64 = 65;
361 pub const SYS_SEMCTL: i64 = 66;
362 pub const SYS_SHMDT: i64 = 67;
363 pub const SYS_MSGGET: i64 = 68;
364 pub const SYS_MSGSND: i64 = 69;
365 pub const SYS_MSGRCV: i64 = 70;
366 pub const SYS_MSGCTL: i64 = 71;
367 pub const SYS_FCNTL: i64 = 72;
368 pub const SYS_FSYNC: i64 = 74;
369 pub const SYS_TRUNCATE: i64 = 76;
370 pub const SYS_FTRUNCATE: i64 = 77;
371 pub const SYS_GETCWD: i64 = 79;
372 pub const SYS_CHDIR: i64 = 80;
373 pub const SYS_SYMLINK: i64 = 88;
374 pub const SYS_FCHMOD: i64 = 91;
375 pub const SYS_UMASK: i64 = 95;
376 pub const SYS_GETRLIMIT: i64 = 97;
377 pub const SYS_SETUID: i64 = 105;
378 pub const SYS_SETGID: i64 = 106;
379 pub const SYS_SETPGID: i64 = 109;
380 pub const SYS_GETGROUPS: i64 = 115;
381 pub const SYS_GETPGID: i64 = 121;
382 pub const SYS_GETSID: i64 = 124;
383 pub const SYS_RT_SIGPENDING: i64 = 127;
384 pub const SYS_RT_SIGTIMEDWAIT: i64 = 128;
385 pub const SYS_RT_SIGSUSPEND: i64 = 130;
386 pub const SYS_SIGALTSTACK: i64 = 131;
387 pub const SYS_SETRLIMIT: i64 = 160;
388 pub const SYS_SETHOSTNAME: i64 = 170;
389 pub const SYS_FUTEX: i64 = 202;
390 pub const SYS_CLOCK_GETTIME: i64 = 228;
391 pub const SYS_CLOCK_GETRES: i64 = 229;
392 pub const SYS_CLOCK_NANOSLEEP: i64 = 230;
393 pub const SYS_EXIT_GROUP: i64 = 231;
394 pub const SYS_TGKILL: i64 = 234;
395 pub const SYS_MKDIRAT: i64 = 258;
396 pub const SYS_NEWFSTATAT: i64 = 262;
397 pub const SYS_UNLINKAT: i64 = 263;
398 pub const SYS_LINKAT: i64 = 265;
399 pub const SYS_SYMLINKAT: i64 = 266;
400 pub const SYS_READLINKAT: i64 = 267;
401 pub const SYS_FCHMODAT: i64 = 268;
402 pub const SYS_SET_ROBUST_LIST: i64 = 273;
403 pub const SYS_UTIMENSAT: i64 = 280;
404 pub const SYS_OPENAT: i64 = 257;
405 pub const SYS_FACCESSAT: i64 = 269;
406 pub const SYS_DUP3: i64 = 292;
407 pub const SYS_PIPE2: i64 = 293;
408 pub const SYS_SYNCFS: i64 = 306;
409 pub const SYS_RENAMEAT2: i64 = 316;
410 pub const SYS_STATFS: i64 = 137;
411 pub const SYS_FSTATFS: i64 = 138;
412 pub const SYS_FDATASYNC: i64 = 75;
413 pub const SYS_PAUSE: i64 = 34;
414 pub const SYS_GETPID: i64 = 39;
415 pub const SYS_FORK: i64 = 57;
416 pub const SYS_EXIT: i64 = 60;
417 pub const SYS_GETPPID: i64 = 110;
418 pub const SYS_SETSID: i64 = 112;
419 pub const SYS_SYNC: i64 = 162;
420 pub const SYS_GETUID: i64 = 102;
421 pub const SYS_GETGID: i64 = 104;
422 pub const SYS_GETEUID: i64 = 107;
423 pub const SYS_GETEGID: i64 = 108;
424 pub const SYS_GETTID: i64 = 186;
425 pub const SYS_CLOCK_SETTIME: i64 = 227;
426 pub const SYS_CLONE: i64 = 56;
427 pub const SYS_PPOLL: i64 = 271;
428 pub const SYS_PREAD64: i64 = 17;
429}
430#[cfg(target_arch = "aarch64")]
431mod sysnr {
432 pub const SYS_READ: i64 = 63;
433 pub const SYS_WRITE: i64 = 64;
434 pub const SYS_CLOSE: i64 = 57;
436 pub const SYS_FSTAT: i64 = 80;
438 pub const SYS_LSEEK: i64 = 62;
439 pub const SYS_MMAP: i64 = 222;
440 pub const SYS_MUNMAP: i64 = 215;
441 pub const SYS_RT_SIGACTION: i64 = 134;
442 pub const SYS_RT_SIGPROCMASK: i64 = 135;
443 pub const SYS_IOCTL: i64 = 29;
444 pub const SYS_SHMGET: i64 = 194;
446 pub const SYS_SHMAT: i64 = 196;
447 pub const SYS_SHMCTL: i64 = 195;
448 pub const SYS_DUP: i64 = 23;
449 pub const SYS_NANOSLEEP: i64 = 101;
450 pub const SYS_SETITIMER: i64 = 103;
451 pub const SYS_SOCKET: i64 = 198;
453 pub const SYS_CONNECT: i64 = 203;
454 pub const SYS_ACCEPT: i64 = 202;
455 pub const SYS_SENDTO: i64 = 206;
456 pub const SYS_RECVFROM: i64 = 207;
457 pub const SYS_SHUTDOWN: i64 = 210;
458 pub const SYS_BIND: i64 = 200;
459 pub const SYS_LISTEN: i64 = 201;
460 pub const SYS_GETSOCKNAME: i64 = 204;
461 pub const SYS_SOCKETPAIR: i64 = 199;
462 pub const SYS_SETSOCKOPT: i64 = 208;
463 pub const SYS_EXECVE: i64 = 221;
464 pub const SYS_WAIT4: i64 = 260;
465 pub const SYS_KILL: i64 = 129;
466 pub const SYS_UNAME: i64 = 160;
467 pub const SYS_SEMGET: i64 = 190;
468 pub const SYS_SEMOP: i64 = 193;
469 pub const SYS_SEMCTL: i64 = 191;
470 pub const SYS_SHMDT: i64 = 197;
471 pub const SYS_MSGGET: i64 = 186;
472 pub const SYS_MSGSND: i64 = 189;
473 pub const SYS_MSGRCV: i64 = 188;
474 pub const SYS_MSGCTL: i64 = 187;
475 pub const SYS_FCNTL: i64 = 25;
476 pub const SYS_FSYNC: i64 = 82;
477 pub const SYS_TRUNCATE: i64 = 45;
478 pub const SYS_FTRUNCATE: i64 = 46;
479 pub const SYS_GETCWD: i64 = 17;
480 pub const SYS_CHDIR: i64 = 49;
481 pub const SYS_FCHMOD: i64 = 52;
483 pub const SYS_UMASK: i64 = 166;
484 pub const SYS_GETRLIMIT: i64 = 163;
485 pub const SYS_SETUID: i64 = 146;
486 pub const SYS_SETGID: i64 = 144;
487 pub const SYS_SETPGID: i64 = 154;
488 pub const SYS_GETGROUPS: i64 = 158;
489 pub const SYS_GETPGID: i64 = 155;
490 pub const SYS_GETSID: i64 = 156;
491 pub const SYS_RT_SIGPENDING: i64 = 136;
492 pub const SYS_RT_SIGTIMEDWAIT: i64 = 137;
493 pub const SYS_RT_SIGSUSPEND: i64 = 133;
494 pub const SYS_SIGALTSTACK: i64 = 132;
495 pub const SYS_SETRLIMIT: i64 = 164;
496 pub const SYS_SETHOSTNAME: i64 = 161;
497 pub const SYS_FUTEX: i64 = 98;
498 pub const SYS_CLOCK_GETTIME: i64 = 113;
499 pub const SYS_CLOCK_GETRES: i64 = 114;
500 pub const SYS_CLOCK_NANOSLEEP: i64 = 115;
501 pub const SYS_EXIT_GROUP: i64 = 94;
502 pub const SYS_TGKILL: i64 = 131;
503 pub const SYS_MKDIRAT: i64 = 34;
504 pub const SYS_NEWFSTATAT: i64 = 79;
505 pub const SYS_UNLINKAT: i64 = 35;
506 pub const SYS_LINKAT: i64 = 37;
507 pub const SYS_SYMLINKAT: i64 = 36;
508 pub const SYS_READLINKAT: i64 = 78;
509 pub const SYS_FCHMODAT: i64 = 53;
510 pub const SYS_SET_ROBUST_LIST: i64 = 99;
511 pub const SYS_UTIMENSAT: i64 = 88;
512 pub const SYS_OPENAT: i64 = 56;
513 pub const SYS_FACCESSAT: i64 = 48;
514 pub const SYS_DUP3: i64 = 24;
515 pub const SYS_PIPE2: i64 = 59;
516 pub const SYS_SYNCFS: i64 = 267;
517 pub const SYS_RENAMEAT2: i64 = 276;
518 pub const SYS_STATFS: i64 = 43;
519 pub const SYS_FSTATFS: i64 = 44;
520 pub const SYS_FDATASYNC: i64 = 83;
521 pub const SYS_GETPID: i64 = 172;
522 pub const SYS_EXIT: i64 = 93;
523 pub const SYS_GETPPID: i64 = 173;
524 pub const SYS_SETSID: i64 = 157;
525 pub const SYS_SYNC: i64 = 81;
526 pub const SYS_GETUID: i64 = 174;
527 pub const SYS_GETGID: i64 = 176;
528 pub const SYS_GETEUID: i64 = 175;
529 pub const SYS_GETEGID: i64 = 177;
530 pub const SYS_GETTID: i64 = 178;
531 pub const SYS_CLOCK_SETTIME: i64 = 112;
532 pub const SYS_CLONE: i64 = 220;
533 pub const SYS_PPOLL: i64 = 73;
534 pub const SYS_PREAD64: i64 = 67;
535}
536pub use sysnr::*;
537
538#[inline]
543unsafe fn sys_write(fd: i64, buf: *const u8, count: usize) -> i64 {
544 <Arch as Syscalls>::syscall3(SYS_WRITE, fd as i64, buf as i64, count as i64)
545}
546
547#[inline]
548unsafe fn sys_read(fd: i64, buf: *mut u8, count: usize) -> i64 {
549 <Arch as Syscalls>::syscall3(SYS_READ, fd as i64, buf as i64, count as i64)
550}
551
552#[inline]
553unsafe fn sys_open(path: *const u8, flags: i64, mode: i64) -> i64 {
554 <Arch as Syscalls>::syscall4(SYS_OPENAT, AT_FDCWD as i64, path as i64, flags as i64, mode as i64)
555}
556
557#[inline]
558unsafe fn sys_close(fd: i64) {
559 let _ = <Arch as Syscalls>::syscall1(SYS_CLOSE, fd as i64);
560}
561
562#[inline]
563unsafe fn sys_lseek(fd: i64, offset: i64, whence: i64) -> i64 {
564 <Arch as Syscalls>::syscall3(SYS_LSEEK, fd as i64, offset as i64, whence as i64)
565}
566
567unsafe fn sys_mmap(
568 addr: *mut u8,
569 length: usize,
570 prot: i32,
571 flags: i32,
572 fd: i32,
573 offset: i64,
574) -> *mut u8 {
575 let result = <Arch as Syscalls>::syscall6(SYS_MMAP, addr as i64, length as i64, prot as i64, flags as i64, fd as i64, offset);
576 if result < 0 && result > -4096 {
577 ERRNO = (-result) as c_int;
578 return MMAP_FAILED;
579 }
580 result as *mut u8
581}
582
583unsafe fn sys_munmap(addr: *mut u8, length: usize) -> i64 {
584 <Arch as Syscalls>::syscall2(SYS_MUNMAP, addr as i64, length as i64)
585}
586
587#[no_mangle]
592pub unsafe extern "C" fn strlen(s: *const c_char) -> usize {
593 let s = s as *const u8;
594 let mut len = 0;
595 while *s.add(len) != 0 {
596 len += 1;
597 }
598 len
599}
600
601#[no_mangle]
602pub unsafe extern "C" fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
603 let dst = dst as *mut u8;
604 let src = src as *const u8;
605 let mut i = 0;
606 while i < n {
607 *dst.add(i) = *src.add(i);
608 i += 1;
609 }
610 dst as *mut c_void
611}
612
613#[no_mangle]
614pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void {
615 let s = s as *mut u8;
616 let mut i = 0;
617 while i < n {
618 *s.add(i) = c as u8;
619 i += 1;
620 }
621 s as *mut c_void
622}
623
624#[no_mangle]
625pub unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
626 let dst = dst as *mut u8;
627 let src = src as *const u8;
628 if (dst as usize) < (src as usize) {
629 let mut i = 0;
630 while i < n {
631 *dst.add(i) = *src.add(i);
632 i += 1;
633 }
634 } else {
635 let mut i = n;
636 while i > 0 {
637 i -= 1;
638 *dst.add(i) = *src.add(i);
639 }
640 }
641 dst as *mut c_void
642}
643
644#[no_mangle]
645pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
646 let s1 = s1 as *const u8;
647 let s2 = s2 as *const u8;
648 let mut i = 0;
649 while i < n {
650 let a = *s1.add(i);
651 let b = *s2.add(i);
652 if a != b {
653 return a as c_int - b as c_int;
654 }
655 i += 1;
656 }
657 0
658}
659
660#[no_mangle]
661pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
662 memcmp(s1, s2, n)
663}
664
665#[no_mangle]
666pub unsafe extern "C" fn strcmp(s1: *const u8, s2: *const u8) -> c_int {
667 let mut i = 0;
668 loop {
669 let a = *s1.add(i);
670 let b = *s2.add(i);
671 if a != b {
672 return a as c_int - b as c_int;
673 }
674 if a == 0 {
675 return 0;
676 }
677 i += 1;
678 }
679}
680
681#[no_mangle]
682pub unsafe extern "C" fn strncmp(s1: *const u8, s2: *const u8, n: usize) -> c_int {
683 let mut i = 0;
684 while i < n {
685 let a = *s1.add(i);
686 let b = *s2.add(i);
687 if a != b {
688 return a as c_int - b as c_int;
689 }
690 if a == 0 {
691 return 0;
692 }
693 i += 1;
694 }
695 0
696}
697
698#[no_mangle]
699pub unsafe extern "C" fn strcpy(dst: *mut u8, src: *const u8) -> *mut u8 {
700 let mut i = 0;
701 loop {
702 let c = *src.add(i);
703 *dst.add(i) = c;
704 if c == 0 {
705 break;
706 }
707 i += 1;
708 }
709 dst
710}
711
712#[no_mangle]
713pub unsafe extern "C" fn strncpy(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
714 let mut i = 0;
715 while i < n && *src.add(i) != 0 {
716 *dst.add(i) = *src.add(i);
717 i += 1;
718 }
719 while i < n {
720 *dst.add(i) = 0;
721 i += 1;
722 }
723 dst
724}
725
726#[no_mangle]
727pub unsafe extern "C" fn strcat(dst: *mut u8, src: *const u8) -> *mut u8 {
728 let mut i = 0;
729 while *dst.add(i) != 0 {
730 i += 1;
731 }
732 let mut j = 0;
733 loop {
734 let c = *src.add(j);
735 *dst.add(i + j) = c;
736 if c == 0 {
737 break;
738 }
739 j += 1;
740 }
741 dst
742}
743
744#[no_mangle]
745pub unsafe extern "C" fn strncat(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
746 let mut i = 0;
747 while *dst.add(i) != 0 {
748 i += 1;
749 }
750 let mut j = 0;
751 while j < n && *src.add(j) != 0 {
752 *dst.add(i + j) = *src.add(j);
753 j += 1;
754 }
755 *dst.add(i + j) = 0;
756 dst
757}
758
759#[no_mangle]
760pub unsafe extern "C" fn strlcpy(dst: *mut u8, src: *const u8, n: usize) -> usize {
761 let l = strlen(src as *const c_char);
762 if n > 0 {
763 let c = if l < n { l } else { n - 1 };
764 core::ptr::copy_nonoverlapping(src, dst, c);
765 *dst.add(c) = 0;
766 }
767 l
768}
769
770#[no_mangle]
771pub unsafe extern "C" fn strlcat(dst: *mut u8, src: *const u8, n: usize) -> usize {
772 let dl = strlen(dst as *const c_char);
773 let sl = strlen(src as *const c_char);
774 if dl >= n { return n + sl; }
775 let c = if sl < n - dl { sl } else { n - dl - 1 };
776 core::ptr::copy_nonoverlapping(src, dst.add(dl), c);
777 *dst.add(dl + c) = 0;
778 dl + sl
779}
780
781#[no_mangle]
782pub unsafe extern "C" fn strchr(s: *const u8, c: c_int) -> *mut u8 {
783 let target = c as u8;
784 let mut i = 0;
785 loop {
786 let ch = *s.add(i);
787 if ch == target {
788 return s.add(i) as *mut u8;
789 }
790 if ch == 0 {
791 return null_mut();
792 }
793 i += 1;
794 }
795}
796
797#[no_mangle]
798pub unsafe extern "C" fn strrchr(s: *const u8, c: c_int) -> *mut u8 {
799 let target = c as u8;
800 let mut i = 0;
801 let mut last: *mut u8 = null_mut();
802 loop {
803 let ch = *s.add(i);
804 if ch == target {
805 last = s.add(i) as *mut u8;
806 }
807 if ch == 0 {
808 return last;
809 }
810 i += 1;
811 }
812}
813
814#[no_mangle]
815pub unsafe extern "C" fn strnlen(s: *const u8, maxlen: usize) -> usize {
816 let mut i = 0;
817 while i < maxlen && *s.add(i) != 0 {
818 i += 1;
819 }
820 i
821}
822
823#[no_mangle]
824pub unsafe extern "C" fn strcspn(s: *const u8, reject: *const u8) -> usize {
825 let mut i = 0;
826 loop {
827 let c = *s.add(i);
828 if c == 0 {
829 return i;
830 }
831 let mut j = 0;
832 loop {
833 let r = *reject.add(j);
834 if r == 0 {
835 break;
836 }
837 if c == r {
838 return i;
839 }
840 j += 1;
841 }
842 i += 1;
843 }
844}
845
846#[no_mangle]
847pub unsafe extern "C" fn strspn(s: *const u8, accept: *const u8) -> usize {
848 let mut i = 0;
849 loop {
850 let c = *s.add(i);
851 if c == 0 {
852 return i;
853 }
854 let mut found = false;
855 let mut j = 0;
856 loop {
857 let a = *accept.add(j);
858 if a == 0 {
859 break;
860 }
861 if c == a {
862 found = true;
863 break;
864 }
865 j += 1;
866 }
867 if !found {
868 return i;
869 }
870 i += 1;
871 }
872}
873
874#[no_mangle]
875pub unsafe extern "C" fn strpbrk(s: *const u8, accept: *const u8) -> *mut u8 {
876 let mut i = 0;
877 loop {
878 let c = *s.add(i);
879 if c == 0 {
880 return null_mut();
881 }
882 let mut j = 0;
883 loop {
884 let a = *accept.add(j);
885 if a == 0 {
886 break;
887 }
888 if c == a {
889 return s.add(i) as *mut u8;
890 }
891 j += 1;
892 }
893 i += 1;
894 }
895}
896
897#[no_mangle]
898pub unsafe extern "C" fn strstr(haystack: *const u8, needle: *const u8) -> *mut u8 {
899 if *needle == 0 {
900 return haystack as *mut u8;
901 }
902 let mut i = 0;
903 loop {
904 let h = *haystack.add(i);
905 if h == 0 {
906 return null_mut();
907 }
908 if h == *needle {
909 let mut j = 0;
910 loop {
911 let n = *needle.add(j);
912 if n == 0 {
913 return haystack.add(i) as *mut u8;
914 }
915 if *haystack.add(i + j) != n {
916 break;
917 }
918 j += 1;
919 }
920 }
921 i += 1;
922 }
923}
924
925#[no_mangle]
926pub unsafe extern "C" fn memchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
927 let target = c as u8;
928 let mut i = 0;
929 while i < n {
930 if *s.add(i) == target {
931 return s.add(i) as *mut u8;
932 }
933 i += 1;
934 }
935 null_mut()
936}
937
938#[no_mangle]
939pub unsafe extern "C" fn memrchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
940 let target = c as u8;
941 let mut i = n;
942 while i > 0 {
943 i -= 1;
944 if *s.add(i) == target {
945 return s.add(i) as *mut u8;
946 }
947 }
948 null_mut()
949}
950
951#[no_mangle]
952pub unsafe extern "C" fn memmem(
953 haystack: *const c_void, haystacklen: usize,
954 needle: *const c_void, needlelen: usize,
955) -> *mut c_void {
956 if needlelen == 0 { return haystack as *mut c_void; }
957 if haystacklen < needlelen { return null_mut(); }
958 let h = haystack as *const u8;
959 let n = needle as *const u8;
960 let last = haystacklen - needlelen;
961 for i in 0..=last {
962 if *h.add(i) == *n && memcmp(h.add(i) as *const c_void, n as *const c_void, needlelen) == 0 {
963 return h.add(i) as *mut c_void;
964 }
965 }
966 null_mut()
967}
968
969#[no_mangle]
970pub unsafe extern "C" fn strtok(s: *mut u8, delim: *const u8) -> *mut u8 {
971 static mut STATE: *mut u8 = core::ptr::null_mut();
972 let mut p = if s.is_null() { STATE } else { s };
973 if p.is_null() {
974 return core::ptr::null_mut();
975 }
976 loop {
977 let c = *p;
978 if c == 0 {
979 STATE = core::ptr::null_mut();
980 return core::ptr::null_mut();
981 }
982 let mut is_delim = false;
983 let mut i = 0;
984 loop {
985 let d = *delim.add(i);
986 if d == 0 {
987 break;
988 }
989 if c == d {
990 is_delim = true;
991 break;
992 }
993 i += 1;
994 }
995 if !is_delim {
996 break;
997 }
998 p = p.add(1);
999 }
1000 let start = p;
1001 loop {
1002 let c = *p;
1003 if c == 0 {
1004 STATE = core::ptr::null_mut();
1005 return start;
1006 }
1007 let mut is_delim = false;
1008 let mut i = 0;
1009 loop {
1010 let d = *delim.add(i);
1011 if d == 0 {
1012 break;
1013 }
1014 if c == d {
1015 is_delim = true;
1016 break;
1017 }
1018 i += 1;
1019 }
1020 if is_delim {
1021 *p = 0;
1022 STATE = p.add(1);
1023 return start;
1024 }
1025 p = p.add(1);
1026 }
1027}
1028
1029type SizeT = usize;
1034type SSizeT = isize;
1035type mode_t = c_uint;
1036type TimeT = c_long;
1037type ClockT = c_long;
1038type wchar_t = c_int;
1039type wint_t = c_uint;
1040type wctype_t = *const c_int;
1041type wctrans_t = *const c_int;
1042
1043const WEOF: wint_t = 0xffffffff;
1044
1045#[repr(C)]
1046pub struct tm {
1047 pub tm_sec: c_int,
1048 pub tm_min: c_int,
1049 pub tm_hour: c_int,
1050 pub tm_mday: c_int,
1051 pub tm_mon: c_int,
1052 pub tm_year: c_int,
1053 pub tm_wday: c_int,
1054 pub tm_yday: c_int,
1055 pub tm_isdst: c_int,
1056 pub tm_gmtoff: c_long,
1057 pub tm_zone: *const c_char,
1058}
1059
1060#[repr(C)]
1061pub struct timeval {
1062 pub tv_sec: TimeT,
1063 pub tv_usec: c_long,
1064}
1065
1066const CT_UPPER: u8 = 1 << 0;
1071const CT_LOWER: u8 = 1 << 1;
1072const CT_DIGIT: u8 = 1 << 2;
1073const CT_SPACE: u8 = 1 << 3;
1074const CT_PUNCT: u8 = 1 << 4;
1075const CT_CNTRL: u8 = 1 << 5;
1076const CT_BLANK: u8 = 1 << 6;
1077const CT_XDIGIT: u8 = 1 << 7;
1078
1079const CT_TABLE: [u8; 128] = {
1080 let mut t = [0u8; 128];
1081 let mut i = 0;
1082 while i < 128 {
1083 let c = i as u8;
1084 let mut flags = 0u8;
1085 if c >= b'A' && c <= b'Z' {
1086 flags |= CT_UPPER;
1087 }
1088 if c >= b'a' && c <= b'z' {
1089 flags |= CT_LOWER;
1090 }
1091 if c >= b'0' && c <= b'9' {
1092 flags |= CT_DIGIT;
1093 }
1094 if c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == b'\x0c' || c == b'\x0b' {
1095 flags |= CT_SPACE;
1096 }
1097 if (c >= b'!' && c <= b'/')
1098 || (c >= b':' && c <= b'@')
1099 || (c >= b'[' && c <= b'`')
1100 || (c >= b'{' && c <= b'~')
1101 {
1102 flags |= CT_PUNCT;
1103 }
1104 if c < 0x20 || c == 0x7f {
1105 flags |= CT_CNTRL;
1106 }
1107 if c == b' ' || c == b'\t' {
1108 flags |= CT_BLANK;
1109 }
1110 if (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'F') || (c >= b'a' && c <= b'f') {
1111 flags |= CT_XDIGIT;
1112 }
1113 t[i] = flags;
1114 i += 1;
1115 }
1116 t
1117};
1118
1119#[inline]
1120fn ct_flags(c: c_int) -> u8 {
1121 if c < 0 || c > 127 {
1122 0
1123 } else {
1124 CT_TABLE[c as usize]
1125 }
1126}
1127
1128#[no_mangle]
1129pub extern "C" fn isalnum(c: c_int) -> c_int {
1130 (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT) != 0) as c_int
1131}
1132
1133#[no_mangle]
1134pub extern "C" fn isalpha(c: c_int) -> c_int {
1135 (ct_flags(c) & (CT_UPPER | CT_LOWER) != 0) as c_int
1136}
1137
1138#[no_mangle]
1139pub extern "C" fn isascii(c: c_int) -> c_int {
1140 ((c as u32) <= 127) as c_int
1141}
1142
1143#[no_mangle]
1144pub extern "C" fn isblank(c: c_int) -> c_int {
1145 (ct_flags(c) & CT_BLANK != 0) as c_int
1146}
1147
1148#[no_mangle]
1149pub extern "C" fn iscntrl(c: c_int) -> c_int {
1150 (ct_flags(c) & CT_CNTRL != 0) as c_int
1151}
1152
1153#[no_mangle]
1154pub extern "C" fn isdigit(c: c_int) -> c_int {
1155 (ct_flags(c) & CT_DIGIT != 0) as c_int
1156}
1157
1158#[no_mangle]
1159pub extern "C" fn isgraph(c: c_int) -> c_int {
1160 (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT) != 0) as c_int
1161}
1162
1163#[no_mangle]
1164pub extern "C" fn islower(c: c_int) -> c_int {
1165 (ct_flags(c) & CT_LOWER != 0) as c_int
1166}
1167
1168#[no_mangle]
1169pub extern "C" fn isprint(c: c_int) -> c_int {
1170 let flags = ct_flags(c);
1171 (flags & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT | CT_BLANK) != 0) as c_int
1172}
1173
1174#[no_mangle]
1175pub extern "C" fn ispunct(c: c_int) -> c_int {
1176 (ct_flags(c) & CT_PUNCT != 0) as c_int
1177}
1178
1179#[no_mangle]
1180pub extern "C" fn isspace(c: c_int) -> c_int {
1181 (ct_flags(c) & CT_SPACE != 0) as c_int
1182}
1183
1184#[no_mangle]
1185pub extern "C" fn isupper(c: c_int) -> c_int {
1186 (ct_flags(c) & CT_UPPER != 0) as c_int
1187}
1188
1189#[no_mangle]
1190pub extern "C" fn isxdigit(c: c_int) -> c_int {
1191 (ct_flags(c) & CT_XDIGIT != 0) as c_int
1192}
1193
1194#[no_mangle]
1195pub extern "C" fn tolower(c: c_int) -> c_int {
1196 if (ct_flags(c) & CT_UPPER) != 0 {
1197 c + (b'a' as c_int - b'A' as c_int)
1198 } else {
1199 c
1200 }
1201}
1202
1203#[no_mangle]
1204pub extern "C" fn toupper(c: c_int) -> c_int {
1205 if (ct_flags(c) & CT_LOWER) != 0 {
1206 c - (b'a' as c_int - b'A' as c_int)
1207 } else {
1208 c
1209 }
1210}
1211
1212unsafe fn parse_digit(c: u8, base: c_int) -> Option<u8> {
1217 if c == 0 { return None; }
1218 let d = if c >= b'0' && c <= b'9' {
1219 c - b'0'
1220 } else if c >= b'a' && c <= b'z' {
1221 c - b'a' + 10
1222 } else if c >= b'A' && c <= b'Z' {
1223 c - b'A' + 10
1224 } else {
1225 return None;
1226 };
1227 if (d as c_int) < base {
1228 Some(d)
1229 } else {
1230 None
1231 }
1232}
1233
1234unsafe fn parse_prefix(s: *const u8, base: *mut c_int) -> *const u8 {
1235 let mut p = s;
1236 if *base == 0 {
1237 if *p == b'0' {
1238 if (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1239 *base = 16;
1240 p = p.add(2);
1241 } else {
1242 *base = 8;
1243 }
1244 } else {
1245 *base = 10;
1246 }
1247 } else if *base == 16 {
1248 if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1249 p = p.add(2);
1250 }
1251 }
1252 p
1253}
1254
1255unsafe fn strtox(
1256 s: *const c_char,
1257 endptr: *mut *mut c_char,
1258 mut base: c_int,
1259 pos_limit: u64,
1260 neg_limit: u64,
1261) -> (u64, bool, bool) {
1262 let s0 = s as *const u8;
1263 let mut p = s0;
1264 while isspace(*p as c_int) != 0 {
1265 p = p.add(1);
1266 }
1267
1268 if base < 0 || base == 1 || base > 36 {
1269 if !endptr.is_null() {
1270 *endptr = s as *mut c_char;
1271 }
1272 ERRNO = EINVAL;
1273 return (0, false, false);
1274 }
1275
1276 let mut neg = false;
1277 match *p {
1278 b'-' => { neg = true; p = p.add(1); }
1279 b'+' => p = p.add(1),
1280 _ => {}
1281 }
1282
1283 p = parse_prefix(p, &mut base);
1284
1285 let limit = if neg { neg_limit } else { pos_limit };
1286 let mut val: u64 = 0;
1287 let mut any = false;
1288 while let Some(d) = parse_digit(*p, base) {
1289 any = true;
1290 if val > (limit - d as u64) / base as u64 {
1291 while parse_digit(*p, base).is_some() { p = p.add(1); }
1292 if !endptr.is_null() { *endptr = p as *mut c_char; }
1293 ERRNO = ERANGE_VAL;
1294 return (limit, true, neg);
1295 }
1296 val = val * base as u64 + d as u64;
1297 p = p.add(1);
1298 }
1299
1300 if !endptr.is_null() {
1301 *endptr = if any { p as *mut c_char } else { s as *mut c_char };
1302 }
1303 (val, false, neg)
1304}
1305
1306#[no_mangle]
1307pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
1308 let pos_limit = c_long::MAX as u64;
1309 let neg_limit = pos_limit.wrapping_add(1);
1310 let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1311 if overflow {
1312 return if neg { c_long::MIN } else { c_long::MAX };
1313 }
1314 if neg { val.wrapping_neg() as c_long } else { val as c_long }
1315}
1316
1317#[no_mangle]
1318pub unsafe extern "C" fn strtoul(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong {
1319 let limit = c_ulong::MAX as u64;
1320 let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1321 if overflow {
1322 return c_ulong::MAX;
1323 }
1324 if neg { val.wrapping_neg() as c_ulong } else { val as c_ulong }
1325}
1326
1327#[no_mangle]
1328pub unsafe extern "C" fn strtoll(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_longlong {
1329 let pos_limit = c_longlong::MAX as u64;
1330 let neg_limit = pos_limit.wrapping_add(1);
1331 let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1332 if overflow {
1333 return if neg { c_longlong::MIN } else { c_longlong::MAX };
1334 }
1335 if neg { val.wrapping_neg() as c_longlong } else { val as c_longlong }
1336}
1337
1338#[no_mangle]
1339pub unsafe extern "C" fn strtoull(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulonglong {
1340 let limit = c_ulonglong::MAX as u64;
1341 let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1342 if overflow {
1343 return c_ulonglong::MAX;
1344 }
1345 if neg { val.wrapping_neg() as c_ulonglong } else { val as c_ulonglong }
1346}
1347
1348#[no_mangle]
1349pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
1350 strtol(s, core::ptr::null_mut(), 10) as c_int
1351}
1352
1353#[no_mangle]
1354pub unsafe extern "C" fn atol(s: *const c_char) -> c_long {
1355 strtol(s, core::ptr::null_mut(), 10)
1356}
1357
1358#[no_mangle]
1359pub unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
1360 strtoll(s, core::ptr::null_mut(), 10)
1361}
1362
1363#[no_mangle]
1364pub extern "C" fn abs(n: c_int) -> c_int {
1365 if n < 0 {
1366 -n
1367 } else {
1368 n
1369 }
1370}
1371
1372#[no_mangle]
1373pub extern "C" fn labs(n: c_long) -> c_long {
1374 if n < 0 {
1375 -n
1376 } else {
1377 n
1378 }
1379}
1380
1381#[no_mangle]
1382pub extern "C" fn llabs(n: c_longlong) -> c_longlong {
1383 if n < 0 {
1384 -n
1385 } else {
1386 n
1387 }
1388}
1389
1390static mut RAND_STATE: c_uint = 1;
1391
1392#[no_mangle]
1393pub extern "C" fn srand(seed: c_uint) {
1394 unsafe {
1395 RAND_STATE = seed;
1396 }
1397}
1398
1399#[no_mangle]
1400pub extern "C" fn rand() -> c_int {
1401 unsafe {
1402 RAND_STATE = RAND_STATE.wrapping_mul(1103515245).wrapping_add(12345);
1403 ((RAND_STATE >> 16) & 0x7fff) as c_int
1404 }
1405}
1406
1407#[repr(C)]
1412pub struct div_t { pub quot: c_int, pub rem: c_int }
1413#[repr(C)]
1414pub struct ldiv_t { pub quot: c_long, pub rem: c_long }
1415#[repr(C)]
1416pub struct lldiv_t { pub quot: c_longlong, pub rem: c_longlong }
1417
1418#[no_mangle]
1419pub extern "C" fn div(num: c_int, den: c_int) -> div_t {
1420 div_t { quot: num / den, rem: num % den }
1421}
1422
1423#[no_mangle]
1424pub extern "C" fn ldiv(num: c_long, den: c_long) -> ldiv_t {
1425 ldiv_t { quot: num / den, rem: num % den }
1426}
1427
1428#[no_mangle]
1429pub extern "C" fn lldiv(num: c_longlong, den: c_longlong) -> lldiv_t {
1430 lldiv_t { quot: num / den, rem: num % den }
1431}
1432
1433type CmpFn = unsafe extern "C" fn(*const c_void, *const c_void) -> c_int;
1438
1439#[no_mangle]
1440pub unsafe extern "C" fn bsearch(
1441 key: *const c_void,
1442 base: *const c_void,
1443 nel: usize,
1444 width: usize,
1445 cmp: CmpFn,
1446) -> *mut c_void {
1447 let mut base = base as *const u8;
1448 let mut nel = nel;
1449 while nel > 0 {
1450 let trial = base.add(width * (nel / 2));
1451 let sign = cmp(key, trial as *const c_void);
1452 if sign < 0 {
1453 nel /= 2;
1454 } else if sign > 0 {
1455 base = trial.add(width);
1456 nel -= nel / 2 + 1;
1457 } else {
1458 return trial as *mut c_void;
1459 }
1460 }
1461 null_mut()
1462}
1463
1464pub const SA_RESTORER: c_ulong = 0x04000000;
1469
1470pub const SIG_DFL: usize = 0;
1471pub const SIG_IGN: usize = 1;
1472pub const SIG_ERR: usize = !0usize;
1473
1474pub const SIGHUP: c_int = 1;
1475pub const SIGINT: c_int = 2;
1476pub const SIGQUIT: c_int = 3;
1477pub const SIGILL: c_int = 4;
1478pub const SIGTRAP: c_int = 5;
1479pub const SIGABRT: c_int = 6;
1480pub const SIGIOT: c_int = 6;
1481pub const SIGBUS: c_int = 7;
1482pub const SIGFPE: c_int = 8;
1483pub const SIGKILL: c_int = 9;
1484pub const SIGUSR1: c_int = 10;
1485pub const SIGSEGV: c_int = 11;
1486pub const SIGUSR2: c_int = 12;
1487pub const SIGPIPE: c_int = 13;
1488pub const SIGALRM: c_int = 14;
1489pub const SIGTERM: c_int = 15;
1490pub const SIGSTKFLT: c_int = 16;
1491pub const SIGCHLD: c_int = 17;
1492pub const SIGCONT: c_int = 18;
1493pub const SIGSTOP: c_int = 19;
1494pub const SIGTSTP: c_int = 20;
1495pub const SIGTTIN: c_int = 21;
1496pub const SIGTTOU: c_int = 22;
1497pub const SIGURG: c_int = 23;
1498pub const SIGXCPU: c_int = 24;
1499pub const SIGXFSZ: c_int = 25;
1500pub const SIGVTALRM: c_int = 26;
1501pub const SIGPROF: c_int = 27;
1502pub const SIGWINCH: c_int = 28;
1503pub const SIGIO: c_int = 29;
1504pub const SIGPOLL: c_int = 29;
1505pub const SIGPWR: c_int = 30;
1506pub const SIGSYS: c_int = 31;
1507pub const SIGUNUSED: c_int = 31;
1508pub const _NSIG: c_int = 65;
1509
1510pub const SIG_BLOCK: c_int = 0;
1511pub const SIG_UNBLOCK: c_int = 1;
1512pub const SIG_SETMASK: c_int = 2;
1513
1514pub const SA_NOCLDSTOP: c_ulong = 1;
1515pub const SA_NOCLDWAIT: c_ulong = 2;
1516pub const SA_SIGINFO: c_ulong = 4;
1517pub const SA_ONSTACK: c_ulong = 0x08000000;
1518pub const SA_RESTART: c_ulong = 0x10000000;
1519pub const SA_NODEFER: c_ulong = 0x40000000;
1520pub const SA_RESETHAND: c_ulong = 0x80000000;
1521
1522pub const SS_ONSTACK: c_int = 1;
1523pub const SS_DISABLE: c_int = 2;
1524pub const MINSIGSTKSZ: usize = 2048;
1525pub const SIGSTKSZ: usize = 8192;
1526
1527pub const SI_USER: c_int = 0;
1528pub const SI_TKILL: c_int = -6;
1529
1530#[repr(C)]
1531pub struct timespec {
1532 pub tv_sec: c_long,
1533 pub tv_nsec: c_long,
1534}
1535
1536#[repr(C)]
1537pub struct siginfo_t {
1538 pub si_signo: c_int,
1539 pub si_errno: c_int,
1540 pub si_code: c_int,
1541 _pad: [u8; 128 - 3 * core::mem::size_of::<c_int>()],
1543}
1544
1545#[repr(C)]
1546pub struct stack_t {
1547 pub ss_sp: *mut c_void,
1548 pub ss_flags: c_int,
1549 pub ss_size: usize,
1550}
1551
1552#[repr(C)]
1553pub struct sigaction {
1554 pub sa_handler: usize,
1555 pub sa_flags: c_ulong,
1556 pub sa_restorer: usize,
1557 pub sa_mask: [c_ulong; 1],
1558}
1559
1560pub type SigSetT = c_ulong;
1561
1562#[cfg(target_arch = "x86_64")]
1563core::arch::global_asm!(
1564 ".global sig_restorer",
1565 ".type sig_restorer, @function",
1566 "sig_restorer:",
1567 "mov eax, 15",
1568 "syscall",
1569);
1570
1571#[cfg(target_arch = "aarch64")]
1572core::arch::global_asm!(
1573 ".global sig_restorer",
1574 ".type sig_restorer, @function",
1575 "sig_restorer:",
1576 "mov x8, #139",
1577 "svc #0",
1578);
1579
1580extern "C" {
1581 fn sig_restorer();
1582}
1583
1584#[inline]
1585unsafe fn sys_rt_sigaction(sig: c_int,
1586 act: *const sigaction,
1587 oldact: *mut sigaction,
1588 sigsetsize: usize,) -> i64 {
1589 <Arch as Syscalls>::syscall4(SYS_RT_SIGACTION, sig as i64, act as i64, oldact as i64, sigsetsize as i64)
1590}
1591
1592#[inline]
1593unsafe fn sys_rt_sigprocmask(how: c_int,
1594 set: *const SigSetT,
1595 oldset: *mut SigSetT,
1596 sigsetsize: usize,) -> i64 {
1597 <Arch as Syscalls>::syscall4(SYS_RT_SIGPROCMASK, how as i64, set as i64, oldset as i64, sigsetsize as i64)
1598}
1599
1600#[inline]
1601unsafe fn sys_rt_sigpending(set: *mut SigSetT, sigsetsize: usize) -> i64 {
1602 <Arch as Syscalls>::syscall2(SYS_RT_SIGPENDING, set as i64, sigsetsize as i64)
1603}
1604
1605#[inline]
1606unsafe fn sys_rt_sigsuspend(mask: *const SigSetT, sigsetsize: usize) -> i64 {
1607 <Arch as Syscalls>::syscall2(SYS_RT_SIGSUSPEND, mask as i64, sigsetsize as i64)
1608}
1609
1610#[inline]
1611unsafe fn sys_rt_sigtimedwait(set: *const SigSetT,
1612 info: *mut siginfo_t,
1613 timeout: *const timespec,
1614 sigsetsize: usize,) -> i64 {
1615 <Arch as Syscalls>::syscall4(SYS_RT_SIGTIMEDWAIT, set as i64, info as i64, timeout as i64, sigsetsize as i64)
1616}
1617
1618#[inline]
1619unsafe fn sys_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> i64 {
1620 <Arch as Syscalls>::syscall2(SYS_SIGALTSTACK, ss as i64, old_ss as i64)
1621}
1622
1623#[inline]
1624unsafe fn sys_tgkill(tgid: c_int, tid: c_int, sig: c_int) -> i64 {
1625 <Arch as Syscalls>::syscall3(SYS_TGKILL, tgid as i64, tid as i64, sig as i64)
1626}
1627
1628const CLOCK_REALTIME: c_int = 0;
1629const CLOCK_MONOTONIC: c_int = 1;
1630
1631#[inline]
1632unsafe fn sys_clock_gettime(clockid: c_int, ts: *mut timespec) -> i64 {
1633 <Arch as Syscalls>::syscall2(SYS_CLOCK_GETTIME, clockid as i64, ts as i64)
1634}
1635
1636#[no_mangle]
1637pub unsafe extern "C" fn clock_gettime(clockid: c_int, ts: *mut timespec) -> c_int {
1638 if sys_clock_gettime(clockid, ts) < 0 { -1 } else { 0 }
1639}
1640
1641#[no_mangle]
1642pub unsafe extern "C" fn sigprocmask(
1643 how: c_int,
1644 set: *const SigSetT,
1645 oldset: *mut SigSetT,
1646) -> c_int {
1647 let internal_mask: SigSetT = (1u64 << 31) | (1u64 << 32);
1649 let filtered: SigSetT;
1650 let set_ptr: *const SigSetT = if set.is_null() {
1651 set
1652 } else {
1653 filtered = *set & !internal_mask;
1654 &filtered
1655 };
1656 let r = sys_rt_sigprocmask(how, set_ptr, oldset, core::mem::size_of::<SigSetT>());
1657 if !oldset.is_null() {
1658 *oldset &= !internal_mask;
1659 }
1660 if r < 0 { -1 } else { 0 }
1661}
1662
1663#[inline]
1664unsafe fn sys_kill(pid: c_int, sig: c_int) -> i64 {
1665 <Arch as Syscalls>::syscall2(SYS_KILL, pid as i64, sig as i64)
1666}
1667
1668#[inline]
1669unsafe fn sys_getpid() -> i64 {
1670 <Arch as Syscalls>::syscall0(SYS_GETPID)
1671}
1672
1673#[no_mangle]
1674pub unsafe extern "C" fn sigaction(
1675 signum: c_int,
1676 act: *const sigaction,
1677 oldact: *mut sigaction,
1678) -> c_int {
1679 let kact: sigaction;
1680 let act_ptr = if act.is_null() {
1681 core::ptr::null()
1682 } else {
1683 kact = sigaction {
1684 sa_handler: (*act).sa_handler,
1685 sa_flags: (*act).sa_flags | SA_RESTORER,
1686 sa_restorer: sig_restorer as *const () as usize,
1687 sa_mask: (*act).sa_mask,
1688 };
1689 &kact as *const sigaction
1690 };
1691 let r = sys_rt_sigaction(signum, act_ptr, oldact, core::mem::size_of::<SigSetT>());
1692 if r < 0 {
1693 ERRNO = (-r) as c_int;
1694 -1
1695 } else {
1696 0
1697 }
1698}
1699
1700#[no_mangle]
1701pub unsafe extern "C" fn signal(signum: c_int, handler: usize) -> usize {
1702 let act = sigaction {
1703 sa_handler: handler,
1704 sa_flags: SA_RESTORER,
1705 sa_restorer: sig_restorer as *const () as usize,
1706 sa_mask: [0],
1707 };
1708 let mut old = sigaction {
1709 sa_handler: 0,
1710 sa_flags: 0,
1711 sa_restorer: 0,
1712 sa_mask: [0],
1713 };
1714 if sigaction(signum, &act, &mut old) == -1 {
1715 SIG_ERR
1716 } else {
1717 old.sa_handler
1718 }
1719}
1720
1721#[no_mangle]
1722pub unsafe extern "C" fn kill(pid: c_int, sig: c_int) -> c_int {
1723 sys_kill(pid, sig) as c_int
1724}
1725
1726#[no_mangle]
1727pub unsafe extern "C" fn tgkill(tgid: c_int, tid: c_int, sig: c_int) -> c_int {
1728 if sys_tgkill(tgid, tid, sig) < 0 { -1 } else { 0 }
1729}
1730
1731#[no_mangle]
1732pub unsafe extern "C" fn getpid() -> c_int {
1733 sys_getpid() as c_int
1734}
1735
1736#[no_mangle]
1737pub unsafe extern "C" fn raise(sig: c_int) -> c_int {
1738 if sys_tgkill(sys_getpid() as c_int, sys_gettid() as c_int, sig) < 0 {
1739 -1
1740 } else {
1741 0
1742 }
1743}
1744
1745#[no_mangle]
1746pub unsafe extern "C" fn sigemptyset(set: *mut SigSetT) -> c_int {
1747 *set = 0;
1748 0
1749}
1750
1751#[no_mangle]
1752pub unsafe extern "C" fn sigfillset(set: *mut SigSetT) -> c_int {
1753 *set = 0xFFFF_FFFC_7FFF_FFFFu64;
1755 0
1756}
1757
1758#[no_mangle]
1759pub unsafe extern "C" fn sigaddset(set: *mut SigSetT, signum: c_int) -> c_int {
1760 let s = (signum as c_uint).wrapping_sub(1);
1761 if s as usize >= 64 {
1762 ERRNO = EINVAL;
1763 return -1;
1764 }
1765 if signum >= 32 && signum < __libc_current_sigrtmin() {
1767 return 0;
1768 }
1769 *set |= 1u64 << s;
1770 0
1771}
1772
1773#[no_mangle]
1774pub unsafe extern "C" fn sigdelset(set: *mut SigSetT, signum: c_int) -> c_int {
1775 let s = (signum as c_uint).wrapping_sub(1);
1776 if s as usize >= 64 {
1777 ERRNO = EINVAL;
1778 return -1;
1779 }
1780 if signum >= 32 && signum < __libc_current_sigrtmin() {
1782 return 0;
1783 }
1784 *set &= !(1u64 << s);
1785 0
1786}
1787
1788#[no_mangle]
1789pub unsafe extern "C" fn sigismember(set: *const SigSetT, signum: c_int) -> c_int {
1790 let s = (signum as c_uint).wrapping_sub(1);
1791 if s as usize >= 64 { return 0; }
1792 if signum >= 32 && signum < __libc_current_sigrtmin() {
1794 return 0;
1795 }
1796 ((*set & (1u64 << s)) != 0) as c_int
1797}
1798
1799#[no_mangle]
1800pub unsafe extern "C" fn sigpending(set: *mut SigSetT) -> c_int {
1801 let r = sys_rt_sigpending(set, core::mem::size_of::<SigSetT>());
1802 if r < 0 {
1803 ERRNO = (-r) as c_int;
1804 return -1;
1805 }
1806 0
1807}
1808
1809#[no_mangle]
1810pub unsafe extern "C" fn sigsuspend(mask: *const SigSetT) -> c_int {
1811 let r = sys_rt_sigsuspend(mask, core::mem::size_of::<SigSetT>());
1812 if r < 0 {
1813 ERRNO = (-r) as c_int;
1814 }
1815 -1
1816}
1817
1818#[no_mangle]
1819pub unsafe extern "C" fn sigtimedwait(
1820 mask: *const SigSetT,
1821 info: *mut siginfo_t,
1822 timeout: *const timespec,
1823) -> c_int {
1824 loop {
1825 let r = sys_rt_sigtimedwait(mask, info, timeout, core::mem::size_of::<SigSetT>());
1826 if r >= 0 {
1827 return r as c_int;
1828 }
1829 let e = (-r) as c_int;
1830 if e != EINTR {
1831 ERRNO = e;
1832 return -1;
1833 }
1834 }
1835}
1836
1837#[no_mangle]
1838pub unsafe extern "C" fn sigwaitinfo(
1839 mask: *const SigSetT,
1840 info: *mut siginfo_t,
1841) -> c_int {
1842 sigtimedwait(mask, info, core::ptr::null())
1843}
1844
1845#[no_mangle]
1846pub unsafe extern "C" fn sigwait(
1847 mask: *const SigSetT,
1848 sig: *mut c_int,
1849) -> c_int {
1850 let mut info: siginfo_t = core::mem::zeroed();
1851 if sigtimedwait(mask, &mut info, core::ptr::null()) < 0 {
1852 return ERRNO;
1853 }
1854 *sig = info.si_signo;
1855 0
1856}
1857
1858#[no_mangle]
1859pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
1860 if !ss.is_null() {
1861 if (*ss).ss_flags & SS_ONSTACK != 0 {
1862 ERRNO = EINVAL;
1863 return -1;
1864 }
1865 if (*ss).ss_flags & SS_DISABLE == 0 && (*ss).ss_size < MINSIGSTKSZ {
1866 ERRNO = ENOMEM;
1867 return -1;
1868 }
1869 }
1870 let r = sys_sigaltstack(ss, old_ss);
1871 if r < 0 {
1872 ERRNO = (-r) as c_int;
1873 return -1;
1874 }
1875 0
1876}
1877
1878#[no_mangle]
1884#[inline(never)]
1885#[cfg(target_arch = "x86_64")]
1886pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
1887 core::arch::asm!(
1888 "mov rax, [rsp]",
1889 "lea rcx, [rsp + 8]",
1890 "mov [r8], rbx",
1891 "mov [r8 + 8], rbp",
1892 "mov [r8 + 16], r12",
1893 "mov [r8 + 24], r13",
1894 "mov [r8 + 32], r14",
1895 "mov [r8 + 40], r15",
1896 "mov [r8 + 48], rcx",
1897 "mov [r8 + 56], rax",
1898 in("r8") env,
1899 lateout("rax") _,
1900 lateout("rcx") _,
1901 options(nostack),
1902 );
1903 0
1904}
1905
1906#[no_mangle]
1907#[inline(never)]
1908#[cfg(target_arch = "x86_64")]
1909pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
1910 let ret = if val == 0 { 1 } else { val } as u32;
1911 core::arch::asm!(
1912 "mov rbx, [r8]",
1913 "mov rbp, [r8 + 8]",
1914 "mov r12, [r8 + 16]",
1915 "mov r13, [r8 + 24]",
1916 "mov r14, [r8 + 32]",
1917 "mov r15, [r8 + 40]",
1918 "mov rsp, [r8 + 48]",
1919 "mov eax, edx",
1920 "jmp [r8 + 56]",
1921 in("r8") env,
1922 in("edx") ret,
1923 options(noreturn),
1924 );
1925}
1926
1927#[no_mangle]
1928#[unsafe(naked)]
1929#[cfg(target_arch = "aarch64")]
1930pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
1931 core::arch::naked_asm!(
1932 "stp x19, x20, [x0, #0]",
1933 "stp x21, x22, [x0, #16]",
1934 "stp x23, x24, [x0, #32]",
1935 "stp x25, x26, [x0, #48]",
1936 "stp x27, x28, [x0, #64]",
1937 "stp x29, x30, [x0, #80]",
1938 "mov x2, sp",
1939 "str x2, [x0, #104]",
1940 "stp d8, d9, [x0, #112]",
1941 "stp d10, d11, [x0, #128]",
1942 "stp d12, d13, [x0, #144]",
1943 "stp d14, d15, [x0, #160]",
1944 "mov x0, #0",
1945 "ret",
1946 );
1947}
1948
1949#[no_mangle]
1950#[inline(never)]
1951#[cfg(target_arch = "aarch64")]
1952pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
1953 let ret = if val == 0 { 1 } else { val } as u64;
1954 core::arch::asm!(
1955 "ldp x19, x20, [x0]",
1956 "ldp x21, x22, [x0, #16]",
1957 "ldp x23, x24, [x0, #32]",
1958 "ldp x25, x26, [x0, #48]",
1959 "ldp x27, x28, [x0, #64]",
1960 "ldp x29, x30, [x0, #80]",
1961 "ldr x2, [x0, #104]",
1962 "mov sp, x2",
1963 "ldp d8, d9, [x0, #112]",
1964 "ldp d10, d11, [x0, #128]",
1965 "ldp d12, d13, [x0, #144]",
1966 "ldp d14, d15, [x0, #160]",
1967 "mov x0, x1",
1968 "br x30",
1969 in("x0") env,
1970 in("x1") ret,
1971 options(noreturn),
1972 );
1973}
1974
1975#[no_mangle]
1983#[unsafe(naked)]
1984#[cfg(target_arch = "x86_64")]
1985pub unsafe extern "C" fn sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
1986 core::arch::naked_asm!("jmp sigsetjmp_real");
1987}
1988
1989#[no_mangle]
1990#[unsafe(naked)]
1991#[cfg(target_arch = "x86_64")]
1992pub unsafe extern "C" fn __sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
1993 core::arch::naked_asm!("jmp sigsetjmp_real");
1994}
1995
1996#[cfg(target_arch = "x86_64")]
1997core::arch::global_asm!(
1998 ".type sigsetjmp_real, @function",
1999 "sigsetjmp_real:",
2000 " test esi, esi",
2001 " jz 1f",
2002 " pop qword ptr [rdi + 64]",
2003 " mov qword ptr [rdi + 80], rbx",
2004 " push rbx",
2005 " mov rbx, rdi",
2006 " call setjmp",
2007 " push qword ptr [rbx + 64]",
2008 " mov rdi, rbx",
2009 " mov esi, eax",
2010 " mov rbx, qword ptr [rbx + 80]",
2011 " lea rdx, [rdi + 72]",
2012 " test esi, esi",
2013 " jz 2f",
2014 " mov rsi, rdx",
2015 " xor rdx, rdx",
2016 " mov edi, 2",
2017 " jmp 3f",
2018 "2:",
2019 " xor rsi, rsi",
2020 " mov edi, 2",
2021 "3:",
2022 " mov eax, 14",
2023 " mov r10d, 8",
2024 " syscall",
2025 " test esi, esi",
2026 " jnz 4f",
2027 " mov rax, 0xfffffffe7fffffff",
2028 " and qword ptr [rdx], rax",
2029 "4:",
2030 " mov eax, esi",
2031 " ret",
2032 "1:",
2033 " jmp setjmp",
2034);
2035
2036#[no_mangle]
2037#[inline(never)]
2038#[cfg(target_arch = "x86_64")]
2039pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2040 longjmp(env, val);
2041}
2042
2043#[no_mangle]
2044#[cfg(target_arch = "aarch64")]
2045pub unsafe extern "C" fn __sigsetjmp_tail(env: *mut c_ulong, ret: c_int) -> c_int {
2046 const SIG_SETMASK: c_int = 2;
2047 let ss = env.add(24) as *mut SigSetT;
2048 let set = if ret != 0 { ss as *const SigSetT } else { core::ptr::null() };
2049 let old = if ret != 0 { core::ptr::null_mut() } else { ss };
2050 let _ = sys_rt_sigprocmask(SIG_SETMASK, set, old, core::mem::size_of::<SigSetT>());
2051 ret
2052}
2053
2054#[no_mangle]
2055#[unsafe(naked)]
2056#[cfg(target_arch = "aarch64")]
2057pub unsafe extern "C" fn sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2058 core::arch::naked_asm!(
2059 "cbz w1, setjmp",
2060 "str x30, [x0, #176]",
2061 "str x19, [x0, #184]",
2062 "mov x19, x0",
2063 "bl setjmp",
2064 "mov w1, w0",
2065 "mov x0, x19",
2066 "ldr x30, [x0, #176]",
2067 "ldr x19, [x0, #184]",
2068 "b __sigsetjmp_tail",
2069 );
2070}
2071
2072#[no_mangle]
2073#[unsafe(naked)]
2074#[cfg(target_arch = "aarch64")]
2075pub unsafe extern "C" fn __sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2076 core::arch::naked_asm!(
2077 "cbz w1, setjmp",
2078 "str x30, [x0, #176]",
2079 "str x19, [x0, #184]",
2080 "mov x19, x0",
2081 "bl setjmp",
2082 "mov w1, w0",
2083 "mov x0, x19",
2084 "ldr x30, [x0, #176]",
2085 "ldr x19, [x0, #184]",
2086 "b __sigsetjmp_tail",
2087 );
2088}
2089
2090#[no_mangle]
2091#[inline(never)]
2092#[cfg(target_arch = "aarch64")]
2093pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2094 longjmp(env, val);
2095}
2096
2097#[inline]
2102unsafe fn sys_newfstatat(dirfd: i32, path: *const c_char, buf: *mut u8, flags: i32) -> i64 {
2103 <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, dirfd as i64, path as i64, buf as i64, flags as i64)
2104}
2105
2106#[inline]
2107unsafe fn sys_fstat(fd: i32, buf: *mut u8) -> i64 {
2108 <Arch as Syscalls>::syscall2(SYS_FSTAT, fd as i64, buf as i64)
2109}
2110
2111#[inline]
2112unsafe fn sys_getrlimit(resource: i32, rlim: *mut u8) -> i64 {
2113 <Arch as Syscalls>::syscall2(SYS_GETRLIMIT, resource as i64, rlim as i64)
2114}
2115
2116#[inline]
2117unsafe fn sys_setrlimit(resource: i32, rlim: *const u8) -> i64 {
2118 <Arch as Syscalls>::syscall2(SYS_SETRLIMIT, resource as i64, rlim as i64)
2119}
2120
2121#[inline]
2122unsafe fn sys_utimensat(dirfd: i32, path: *const c_char, times: *const u8, flags: i32) -> i64 {
2123 <Arch as Syscalls>::syscall4(SYS_UTIMENSAT, dirfd as i64, path as i64, times as i64, flags as i64)
2124}
2125
2126#[inline]
2131unsafe fn sys_fork() -> i64 {
2132 #[cfg(target_arch = "x86_64")]
2133 { <Arch as Syscalls>::syscall0(SYS_FORK) }
2134 #[cfg(target_arch = "aarch64")]
2135 { <Arch as Syscalls>::syscall2(SYS_CLONE, 17, 0) }
2136}
2137
2138#[inline]
2139unsafe fn sys_execve(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> i64 {
2140 <Arch as Syscalls>::syscall3(SYS_EXECVE, path as i64, argv as i64, envp as i64)
2141}
2142
2143#[inline]
2144unsafe fn sys_wait4(pid: c_int, status: *mut c_int, options: c_int, rusage: *mut c_void) -> i64 {
2145 <Arch as Syscalls>::syscall4(SYS_WAIT4, pid as i64, status as i64, options as i64, rusage as i64)
2146}
2147
2148#[inline]
2149unsafe fn sys_getppid() -> i64 {
2150 <Arch as Syscalls>::syscall0(SYS_GETPPID)
2151}
2152
2153#[inline]
2154unsafe fn sys_getuid() -> i64 {
2155 <Arch as Syscalls>::syscall0(SYS_GETUID)
2156}
2157
2158#[inline]
2159unsafe fn sys_getgid() -> i64 {
2160 <Arch as Syscalls>::syscall0(SYS_GETGID)
2161}
2162
2163#[inline]
2164unsafe fn sys_geteuid() -> i64 {
2165 <Arch as Syscalls>::syscall0(SYS_GETEUID)
2166}
2167
2168#[inline]
2169unsafe fn sys_getegid() -> i64 {
2170 <Arch as Syscalls>::syscall0(SYS_GETEGID)
2171}
2172
2173#[no_mangle]
2174pub unsafe extern "C" fn fork() -> c_int {
2175 __fork_handler(-1);
2176 let mut rlim: Rlimit = core::mem::zeroed();
2180 let nproc_limit = sys_getrlimit(RLIMIT_NPROC, &mut rlim as *mut _ as *mut u8);
2181 let nproc_limited = nproc_limit == 0
2182 && rlim.rlim_cur != RLIM_INFINITY
2183 && rlim.rlim_cur == 0;
2184 let ret = if nproc_limited {
2185 -EAGAIN as i64
2186 } else {
2187 sys_fork()
2188 };
2189 let errno_save = if ret < 0 { EAGAIN } else { ERRNO };
2190 if ret == 0 {
2191 __fork_handler(1);
2192 } else {
2193 __fork_handler(0);
2194 }
2195 if ret < 0 {
2196 ERRNO = errno_save;
2197 return -1;
2198 }
2199 ret as c_int
2200}
2201
2202#[no_mangle]
2203pub unsafe extern "C" fn execve(
2204 path: *const c_char,
2205 argv: *const *const c_char,
2206 envp: *const *const c_char,
2207) -> c_int {
2208 sys_execve(path, argv, envp) as c_int
2209}
2210
2211#[no_mangle]
2212pub unsafe extern "C" fn wait(status: *mut c_int) -> c_int {
2213 sys_wait4(-1, status, 0, core::ptr::null_mut()) as c_int
2214}
2215
2216#[no_mangle]
2217pub unsafe extern "C" fn waitpid(pid: c_int, status: *mut c_int, options: c_int) -> c_int {
2218 sys_wait4(pid, status, options, core::ptr::null_mut()) as c_int
2219}
2220
2221#[no_mangle]
2222pub unsafe extern "C" fn getppid() -> c_int {
2223 sys_getppid() as c_int
2224}
2225
2226#[no_mangle]
2227pub unsafe extern "C" fn getuid() -> c_uint {
2228 sys_getuid() as c_uint
2229}
2230
2231#[no_mangle]
2232pub unsafe extern "C" fn getgid() -> c_uint {
2233 sys_getgid() as c_uint
2234}
2235
2236#[no_mangle]
2237pub unsafe extern "C" fn geteuid() -> c_uint {
2238 sys_geteuid() as c_uint
2239}
2240
2241#[no_mangle]
2242pub unsafe extern "C" fn getegid() -> c_uint {
2243 sys_getegid() as c_uint
2244}
2245
2246#[no_mangle]
2248pub unsafe extern "C" fn vfork() -> c_int {
2249 sys_fork() as c_int
2250}
2251
2252#[no_mangle]
2253pub unsafe extern "C" fn execl(path: *const c_char, arg: *const c_char, mut args: ...) -> c_int {
2254 let mut argv: [*const c_char; 256] = [core::ptr::null(); 256];
2255 argv[0] = arg;
2256 let mut n: usize = 1;
2257 loop {
2258 let a: *const c_char = args.next_arg();
2259 if a.is_null() { break; }
2260 if n >= 255 { return -1; }
2261 argv[n] = a;
2262 n += 1;
2263 }
2264 argv[n] = core::ptr::null();
2265 sys_execve(path, argv.as_ptr(), __environ as *const *const c_char) as c_int
2266}
2267
2268const SPAWN_FA_MAX: usize = 5;
2276
2277#[repr(C)]
2278pub struct posix_spawn_file_actions_t {
2279 __pad0: [c_int; 2],
2280 __actions: *mut c_void,
2281 __pad: [c_int; 16],
2282}
2283
2284#[repr(C)]
2285pub struct posix_spawnattr_t {
2286 __flags: c_int,
2287 __pgrp: c_int,
2288 __def: [c_ulong; 16],
2289 __mask: [c_ulong; 16],
2290 __prio: c_int,
2291 __pol: c_int,
2292 __fn: *mut c_void,
2293 __pad: [u8; 64 - core::mem::size_of::<*mut c_void>()],
2294}
2295
2296#[no_mangle]
2297pub unsafe extern "C" fn posix_spawn_file_actions_init(fa: *mut posix_spawn_file_actions_t) -> c_int {
2298 core::ptr::write_bytes(fa, 0, 1);
2299 0
2300}
2301
2302#[no_mangle]
2303pub unsafe extern "C" fn posix_spawn_file_actions_destroy(_fa: *mut posix_spawn_file_actions_t) -> c_int {
2304 0
2305}
2306
2307unsafe fn spawn_fa_add(fa: *mut posix_spawn_file_actions_t, action_type: c_int, fd: c_int, newfd: c_int) -> c_int {
2308 let count = (*fa).__pad0[0] as usize;
2309 if count >= SPAWN_FA_MAX { return ENOMEM; }
2310 let base = count * 3;
2311 (*fa).__pad[base] = action_type;
2312 (*fa).__pad[base + 1] = fd;
2313 (*fa).__pad[base + 2] = newfd;
2314 (*fa).__pad0[0] += 1;
2315 0
2316}
2317
2318#[no_mangle]
2319pub unsafe extern "C" fn posix_spawn_file_actions_addclose(fa: *mut posix_spawn_file_actions_t, fd: c_int) -> c_int {
2320 spawn_fa_add(fa, 0, fd, 0)
2321}
2322
2323#[no_mangle]
2324pub unsafe extern "C" fn posix_spawn_file_actions_adddup2(fa: *mut posix_spawn_file_actions_t, oldfd: c_int, newfd: c_int) -> c_int {
2325 spawn_fa_add(fa, 1, oldfd, newfd)
2326}
2327
2328unsafe fn spawn_apply_actions(fa: *const posix_spawn_file_actions_t) {
2329 if fa.is_null() { return; }
2330 let count = (*fa).__pad0[0] as usize;
2331 for i in 0..count {
2332 let base = i * 3;
2333 match (*fa).__pad[base] {
2334 0 => { sys_close((*fa).__pad[base + 1] as i64); }
2335 1 => { sys_dup2((*fa).__pad[base + 1], (*fa).__pad[base + 2]); }
2336 _ => {}
2337 }
2338 }
2339}
2340
2341unsafe fn spawn_execvp(file: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> ! {
2343 let flen = strlen(file as *const c_char);
2344 let f = file as *const u8;
2345 let mut has_slash = false;
2346 for i in 0..flen {
2347 if *f.add(i) == b'/' { has_slash = true; break; }
2348 }
2349 if has_slash {
2350 sys_execve(file, argv, envp);
2351 _exit(127);
2352 }
2353 let path = getenv(b"PATH\0".as_ptr() as *const c_char);
2354 let default_path = b"/usr/local/bin:/usr/bin:/bin\0";
2355 let p = if path.is_null() { default_path.as_ptr() } else { path as *const u8 };
2356 let plen = strlen(p as *const c_char);
2357 let mut buf: [u8; 4096] = [0; 4096];
2358 let mut i: usize = 0;
2359 while i <= plen {
2360 let start = i;
2361 while i < plen && *p.add(i) != b':' { i += 1; }
2362 let dlen = i - start;
2363 if dlen > 0 && dlen + 1 + flen < 4096 {
2364 core::ptr::copy_nonoverlapping(p.add(start), buf.as_mut_ptr(), dlen);
2365 *buf.as_mut_ptr().add(dlen) = b'/';
2366 core::ptr::copy_nonoverlapping(f, buf.as_mut_ptr().add(dlen + 1), flen + 1);
2367 sys_execve(buf.as_ptr() as *const c_char, argv, envp);
2368 }
2370 i += 1; }
2372 _exit(127);
2373}
2374
2375#[no_mangle]
2376pub unsafe extern "C" fn posix_spawnp(
2377 pid: *mut c_int,
2378 file: *const c_char,
2379 fa: *const posix_spawn_file_actions_t,
2380 _attrp: *const posix_spawnattr_t,
2381 argv: *const *const c_char,
2382 envp: *const *const c_char,
2383) -> c_int {
2384 let child = sys_fork();
2385 if child < 0 {
2386 ERRNO = EAGAIN;
2387 return -1;
2388 }
2389 if child == 0 {
2390 spawn_apply_actions(fa);
2392 let actual_envp = if envp.is_null() { __environ as *const *const c_char } else { envp };
2393 spawn_execvp(file, argv, actual_envp);
2394 }
2396 *pid = child as c_int;
2397 0
2398}
2399
2400#[no_mangle]
2401pub unsafe extern "C" fn posix_spawn(
2402 pid: *mut c_int,
2403 path: *const c_char,
2404 fa: *const posix_spawn_file_actions_t,
2405 attrp: *const posix_spawnattr_t,
2406 argv: *const *const c_char,
2407 envp: *const *const c_char,
2408) -> c_int {
2409 posix_spawnp(pid, path, fa, attrp, argv, envp)
2412}
2413
2414#[no_mangle]
2415pub unsafe extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int {
2416 core::ptr::write_bytes(attr, 0, 1);
2417 0
2418}
2419
2420#[no_mangle]
2421pub unsafe extern "C" fn posix_spawnattr_destroy(_attr: *mut posix_spawnattr_t) -> c_int {
2422 0
2423}
2424
2425#[repr(C)]
2430pub struct Stat {
2431 pub st_dev: u64,
2432 pub st_ino: u64,
2433 pub st_nlink: u64,
2434 pub st_mode: u32,
2435 pub st_uid: u32,
2436 pub st_gid: u32,
2437 _pad0: u32,
2438 pub st_rdev: u64,
2439 pub st_size: i64,
2440 pub st_blksize: i64,
2441 pub st_blocks: i64,
2442 pub st_atim: timespec,
2443 pub st_mtim: timespec,
2444 pub st_ctim: timespec,
2445 _unused: [i64; 3],
2446}
2447
2448pub const S_IFMT: u32 = 0o170000;
2449pub const S_IFDIR: u32 = 0o040000;
2450pub const S_IFCHR: u32 = 0o020000;
2451pub const S_IFBLK: u32 = 0o060000;
2452pub const S_IFREG: u32 = 0o100000;
2453pub const S_IFLNK: u32 = 0o120000;
2454pub const S_IFIFO: u32 = 0o010000;
2455pub const S_IFSOCK: u32 = 0o140000;
2456
2457pub const AT_FDCWD: i32 = -100;
2458
2459#[no_mangle]
2460pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut Stat) -> c_int {
2461 let r = sys_newfstatat(AT_FDCWD, path, buf as *mut u8, 0);
2462 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2463 if *path == b'/' as c_char && strcmp(path as *const u8, b"/dev/null\0".as_ptr()) == 0 {
2464 (*buf).st_mode = ((*buf).st_mode & !0o170000) | 0o020000;
2465 }
2466 0
2467}
2468
2469#[no_mangle]
2470pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut Stat) -> c_int {
2471 let r = sys_fstat(fd, buf as *mut u8);
2472 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2473}
2474
2475#[repr(C)]
2480pub struct Rlimit {
2481 pub rlim_cur: u64,
2482 pub rlim_max: u64,
2483}
2484
2485pub const RLIMIT_NOFILE: c_int = 7;
2486pub const RLIMIT_STACK: c_int = 3;
2487pub const RLIMIT_DATA: c_int = 2;
2488pub const RLIMIT_AS: c_int = 9;
2489pub const RLIMIT_CPU: c_int = 0;
2490pub const RLIMIT_FSIZE: c_int = 1;
2491pub const RLIMIT_CORE: c_int = 4;
2492pub const RLIMIT_RSS: c_int = 5;
2493pub const RLIMIT_NPROC: c_int = 6;
2494pub const RLIMIT_MEMLOCK: c_int = 8;
2495pub const RLIMIT_LOCKS: c_int = 10;
2496pub const RLIMIT_SIGPENDING: c_int = 11;
2497pub const RLIMIT_MSGQUEUE: c_int = 12;
2498pub const RLIMIT_NICE: c_int = 13;
2499pub const RLIMIT_RTPRIO: c_int = 14;
2500pub const RLIMIT_RTTIME: c_int = 15;
2501pub const RLIM_INFINITY: u64 = !0u64;
2502
2503#[no_mangle]
2504pub unsafe extern "C" fn getrlimit(resource: c_int, rlim: *mut Rlimit) -> c_int {
2505 let r = sys_getrlimit(resource, rlim as *mut u8);
2506 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2507}
2508
2509#[no_mangle]
2510pub unsafe extern "C" fn setrlimit(resource: c_int, rlim: *const Rlimit) -> c_int {
2511 let r = sys_setrlimit(resource, rlim as *const u8);
2512 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2513}
2514
2515#[no_mangle]
2520pub unsafe extern "C" fn utimensat(dirfd: c_int, path: *const c_char, times: *const timespec, flags: c_int) -> c_int {
2521 let r = sys_utimensat(dirfd, path, times as *const u8, flags);
2522 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2523}
2524
2525#[no_mangle]
2526pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
2527 let r = sys_utimensat(fd, core::ptr::null(), times as *const u8, 0);
2528 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2529}
2530
2531pub const AF_UNIX: c_int = 1;
2536pub const AF_INET: c_int = 2;
2537pub const AF_INET6: c_int = 10;
2538
2539pub const SOCK_STREAM: c_int = 1;
2540pub const SOCK_DGRAM: c_int = 2;
2541
2542pub const SHUT_RD: c_int = 0;
2543pub const SHUT_WR: c_int = 1;
2544pub const SHUT_RDWR: c_int = 2;
2545
2546pub const SOL_SOCKET: c_int = 1;
2547pub const SO_REUSEADDR: c_int = 2;
2548
2549#[repr(C)]
2550pub struct sockaddr {
2551 pub sa_family: u16,
2552 pub sa_data: [u8; 14],
2553}
2554
2555#[inline]
2556unsafe fn sys_socket(domain: c_int, ty: c_int, protocol: c_int) -> i64 {
2557 <Arch as Syscalls>::syscall3(SYS_SOCKET, domain as i64, ty as i64, protocol as i64)
2558}
2559
2560#[inline]
2561unsafe fn sys_socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> i64 {
2562 <Arch as Syscalls>::syscall4(SYS_SOCKETPAIR, domain as i64, ty as i64, protocol as i64, sv as i64)
2563}
2564
2565#[inline]
2566unsafe fn sys_bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
2567 <Arch as Syscalls>::syscall3(SYS_BIND, fd as i64, addr as i64, len as i64)
2568}
2569
2570#[inline]
2571unsafe fn sys_listen(fd: c_int, backlog: c_int) -> i64 {
2572 <Arch as Syscalls>::syscall2(SYS_LISTEN, fd as i64, backlog as i64)
2573}
2574
2575#[inline]
2576unsafe fn sys_accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
2577 <Arch as Syscalls>::syscall3(SYS_ACCEPT, fd as i64, addr as i64, len as i64)
2578}
2579
2580#[inline]
2581unsafe fn sys_connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
2582 <Arch as Syscalls>::syscall3(SYS_CONNECT, fd as i64, addr as i64, len as i64)
2583}
2584
2585#[inline]
2586unsafe fn sys_sendto(fd: c_int,
2587 buf: *const c_void,
2588 len: usize,
2589 flags: c_int,
2590 addr: *const sockaddr,
2591 addrlen: c_uint,) -> i64 {
2592 <Arch as Syscalls>::syscall6(SYS_SENDTO, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
2593}
2594
2595#[inline]
2596unsafe fn sys_recvfrom(fd: c_int,
2597 buf: *mut c_void,
2598 len: usize,
2599 flags: c_int,
2600 addr: *mut sockaddr,
2601 addrlen: *mut c_uint,) -> i64 {
2602 <Arch as Syscalls>::syscall6(SYS_RECVFROM, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
2603}
2604
2605#[inline]
2606unsafe fn sys_shutdown(fd: c_int, how: c_int) -> i64 {
2607 <Arch as Syscalls>::syscall2(SYS_SHUTDOWN, fd as i64, how as i64)
2608}
2609
2610#[inline]
2611unsafe fn sys_setsockopt(fd: c_int,
2612 level: c_int,
2613 optname: c_int,
2614 optval: *const c_void,
2615 optlen: c_uint,) -> i64 {
2616 <Arch as Syscalls>::syscall5(SYS_SETSOCKOPT, fd as i64, level as i64, optname as i64, optval as i64, optlen as i64)
2617}
2618
2619#[inline]
2620unsafe fn sys_getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
2621 <Arch as Syscalls>::syscall3(SYS_GETSOCKNAME, fd as i64, addr as i64, len as i64)
2622}
2623
2624#[no_mangle]
2625pub unsafe extern "C" fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int {
2626 let r = sys_socket(domain, ty, protocol);
2627 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2628 r as c_int
2629}
2630
2631#[no_mangle]
2632pub unsafe extern "C" fn socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> c_int {
2633 let r = sys_socketpair(domain, ty, protocol, sv);
2634 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2635 0
2636}
2637
2638#[no_mangle]
2639pub unsafe extern "C" fn bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
2640 let r = sys_bind(fd, addr, len);
2641 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2642 0
2643}
2644
2645#[no_mangle]
2646pub unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> c_int {
2647 let r = sys_listen(fd, backlog);
2648 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2649 0
2650}
2651
2652#[no_mangle]
2653pub unsafe extern "C" fn accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
2654 let r = sys_accept(fd, addr, len);
2655 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2656 r as c_int
2657}
2658
2659#[no_mangle]
2660pub unsafe extern "C" fn connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
2661 let r = sys_connect(fd, addr, len);
2662 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2663 0
2664}
2665
2666#[no_mangle]
2667pub unsafe extern "C" fn send(fd: c_int, buf: *const c_void, len: usize, flags: c_int) -> isize {
2668 let r = sys_sendto(fd, buf, len, flags, core::ptr::null(), 0);
2669 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2670 r as isize
2671}
2672
2673#[no_mangle]
2674pub unsafe extern "C" fn recv(fd: c_int, buf: *mut c_void, len: usize, flags: c_int) -> isize {
2675 let r = sys_recvfrom(fd, buf, len, flags, core::ptr::null_mut(), core::ptr::null_mut());
2676 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2677 r as isize
2678}
2679
2680#[no_mangle]
2681pub unsafe extern "C" fn sendto(
2682 fd: c_int,
2683 buf: *const c_void,
2684 len: usize,
2685 flags: c_int,
2686 addr: *const sockaddr,
2687 addrlen: c_uint,
2688) -> isize {
2689 let r = sys_sendto(fd, buf, len, flags, addr, addrlen);
2690 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2691 r as isize
2692}
2693
2694#[no_mangle]
2695pub unsafe extern "C" fn recvfrom(
2696 fd: c_int,
2697 buf: *mut c_void,
2698 len: usize,
2699 flags: c_int,
2700 addr: *mut sockaddr,
2701 addrlen: *mut c_uint,
2702) -> isize {
2703 let r = sys_recvfrom(fd, buf, len, flags, addr, addrlen);
2704 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2705 r as isize
2706}
2707
2708#[no_mangle]
2709pub unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> c_int {
2710 sys_shutdown(fd, how) as c_int
2711}
2712
2713#[no_mangle]
2714pub unsafe extern "C" fn setsockopt(
2715 fd: c_int,
2716 level: c_int,
2717 optname: c_int,
2718 optval: *const c_void,
2719 optlen: c_uint,
2720) -> c_int {
2721 sys_setsockopt(fd, level, optname, optval, optlen) as c_int
2722}
2723
2724#[no_mangle]
2725pub unsafe extern "C" fn getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
2726 sys_getsockname(fd, addr, len) as c_int
2727}
2728
2729#[no_mangle]
2730pub extern "C" fn htonl(hostlong: c_uint) -> c_uint {
2731 hostlong.to_be()
2732}
2733
2734#[no_mangle]
2735pub extern "C" fn ntohl(netlong: c_uint) -> c_uint {
2736 c_uint::from_be(netlong)
2737}
2738
2739#[no_mangle]
2740pub extern "C" fn htons(hostshort: u16) -> u16 {
2741 hostshort.to_be()
2742}
2743
2744#[no_mangle]
2745pub extern "C" fn ntohs(netshort: u16) -> u16 {
2746 u16::from_be(netshort)
2747}
2748
2749pub type PthreadT = c_ulong;
2750
2751#[repr(C)]
2753pub struct pthread_attr_t {
2754 __i: [c_int; 14],
2755}
2756
2757#[repr(C)]
2760pub struct pthread_mutex_t {
2761 __i: [c_int; 10],
2762}
2763
2764#[repr(C)]
2765pub struct pthread_mutexattr_t {
2766 __attr: c_uint,
2767}
2768
2769#[repr(C)]
2772pub struct pthread_cond_t {
2773 __i: [c_int; 12],
2774}
2775
2776#[repr(C)]
2777pub struct pthread_condattr_t {
2778 __attr: c_uint,
2779}
2780
2781#[repr(C)]
2784pub struct pthread_rwlock_t {
2785 __i: [c_int; 14],
2786}
2787
2788#[repr(C)]
2789pub struct pthread_rwlockattr_t {
2790 __attr: [c_uint; 2],
2791}
2792
2793#[repr(C)]
2795pub struct pthread_barrier_t {
2796 __i: [c_int; 8],
2797}
2798
2799#[repr(C)]
2800pub struct pthread_barrierattr_t {
2801 __attr: c_uint,
2802}
2803
2804pub type pthread_spinlock_t = c_int;
2805pub type pthread_once_t = c_int;
2806pub type pthread_key_t = c_uint;
2807
2808#[repr(C)]
2810pub struct sem_t {
2811 __val: [c_int; 8],
2812}
2813
2814#[repr(C)]
2815pub struct sched_param {
2816 pub sched_priority: c_int,
2817}
2818
2819const CLONE_VM: c_ulong = 0x00000100;
2820const CLONE_FS: c_ulong = 0x00000200;
2821const CLONE_FILES: c_ulong = 0x00000400;
2822const CLONE_SIGHAND: c_ulong = 0x00000800;
2823const CLONE_THREAD: c_ulong = 0x00010000;
2824const CLONE_SYSVSEM: c_ulong = 0x00040000;
2825const CLONE_SETTLS: c_ulong = 0x00080000;
2826const CLONE_PARENT_SETTID: c_ulong = 0x00100000;
2827const CLONE_CHILD_CLEARTID: c_ulong = 0x00200000;
2828
2829const FUTEX_WAIT: c_int = 0;
2830const FUTEX_WAKE: c_int = 1;
2831const FUTEX_LOCK_PI: c_int = 6;
2832const FUTEX_UNLOCK_PI: c_int = 7;
2833const FUTEX_TRYLOCK_PI: c_int = 8;
2834
2835const SIGCANCEL: c_int = 32;
2837
2838const PTHREAD_MUTEX_NORMAL: c_int = 0;
2839const PTHREAD_MUTEX_DEFAULT: c_int = 0;
2840const PTHREAD_MUTEX_RECURSIVE: c_int = 1;
2841const PTHREAD_MUTEX_ERRORCHECK: c_int = 2;
2842
2843const PTHREAD_CREATE_JOINABLE: c_int = 0;
2844const PTHREAD_CREATE_DETACHED: c_int = 1;
2845
2846const PTHREAD_CANCEL_ENABLE: c_int = 0;
2847const PTHREAD_CANCEL_DISABLE: c_int = 1;
2848const PTHREAD_CANCEL_DEFERRED: c_int = 0;
2849const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 1;
2850
2851const PTHREAD_SCOPE_SYSTEM: c_int = 0;
2852const PTHREAD_PROCESS_PRIVATE: c_int = 0;
2853const PTHREAD_PROCESS_SHARED: c_int = 1;
2854const PTHREAD_INHERIT_SCHED: c_int = 0;
2855const PTHREAD_EXPLICIT_SCHED: c_int = 1;
2856
2857const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1;
2858
2859const PTHREAD_KEYS_MAX: usize = 128;
2860const PTHREAD_DESTRUCTOR_ITERATIONS: usize = 4;
2861const SEM_VALUE_MAX: c_int = 0x7fffffff;
2862
2863const DT_EXITED: c_int = 0;
2864const DT_EXITING: c_int = 1;
2865const DT_JOINABLE: c_int = 2;
2866const DT_DETACHED: c_int = 3;
2867
2868#[repr(C)]
2870#[derive(Copy, Clone)]
2871pub struct __ptcb {
2872 __f: Option<unsafe extern "C" fn(*mut c_void)>,
2873 __x: *mut c_void,
2874 __next: *mut __ptcb,
2875}
2876
2877#[repr(C)]
2879#[derive(Copy, Clone)]
2880struct robust_list {
2881 next: *mut robust_list,
2882}
2883
2884#[repr(C)]
2885#[derive(Copy, Clone)]
2886struct robust_list_head {
2887 list: robust_list,
2888 futex_offset: c_long,
2889 pending: *mut robust_list,
2890}
2891
2892#[cfg(all(target_arch = "x86_64", not(test)))]
2894core::arch::global_asm!(
2895 ".global __rc_clone",
2896 ".type __rc_clone, @function",
2897 "__rc_clone:",
2898 "mov rax, rdi",
2899 "mov rdi, rdx",
2900 "mov rdx, r8",
2901 "mov r10, [rsp + 8]",
2902 "mov r8, r9",
2903 "mov r9, rax",
2904 "and rsi, -16",
2905 "sub rsi, 8",
2906 "mov [rsi], rcx",
2907 "mov eax, 56",
2908 "syscall",
2909 "test rax, rax",
2910 "jnz 1f",
2911 "pop rdi",
2912 "call r9",
2913 "hlt",
2914 "1:",
2915 "ret",
2916);
2917
2918#[no_mangle]
2920#[unsafe(naked)]
2921#[cfg(target_arch = "aarch64")]
2922pub unsafe extern "C" fn __rc_clone(
2923 fn_: usize,
2924 stack: *mut u8,
2925 flags: c_ulong,
2926 arg: *mut c_void,
2927 ptid: *mut c_int,
2928 tls: c_ulong,
2929 ctid: *mut c_int,
2930) -> i64 {
2931 core::arch::naked_asm!(
2932 "and x1, x1, #-16",
2933 "stp x0, x3, [x1, #-16]!",
2934 "uxtw x0, w2",
2935 "mov x2, x4",
2936 "mov x3, x5",
2937 "mov x4, x6",
2938 "mov x8, #220",
2939 "svc #0",
2940 "cbz x0, 1f",
2941 "ret",
2942 "1:",
2943 "mov x29, #0",
2944 "ldp x1, x0, [sp], #16",
2945 "blr x1",
2946 "mov x8, #93",
2947 "svc #0",
2948 );
2949}
2950
2951#[cfg(all(target_arch = "x86_64", test))]
2952#[inline(never)]
2953unsafe fn __rc_clone(
2954 _fn_: usize,
2955 _stack: *mut u8,
2956 _flags: c_ulong,
2957 _arg: *mut c_void,
2958 _ptid: *mut c_int,
2959 _tls: c_ulong,
2960 _ctid: *mut c_int,
2961) -> i64 {
2962 -1
2963}
2964
2965#[cfg(all(target_arch = "x86_64", not(test)))]
2966extern "C" {
2967 fn __rc_clone(
2968 fn_: usize,
2969 stack: *mut u8,
2970 flags: c_ulong,
2971 arg: *mut c_void,
2972 ptid: *mut c_int,
2973 tls: c_ulong,
2974 ctid: *mut c_int,
2975 ) -> i64;
2976}
2977
2978#[inline(never)]
2979#[linkage = "weak"]
2980#[no_mangle]
2981pub extern "C" fn __rc_create_thread_tls() -> *mut u8 {
2982 core::ptr::null_mut()
2983}
2984
2985#[inline(never)]
2986#[linkage = "weak"]
2987#[no_mangle]
2988pub extern "C" fn __rc_tls_block_size() -> usize {
2989 0
2990}
2991
2992#[inline(never)]
2993#[linkage = "weak"]
2994#[no_mangle]
2995pub extern "C" fn __rc_tls_base_offset() -> usize {
2996 0
2997}
2998
2999#[inline]
3000unsafe fn sys_gettid() -> i64 {
3001 <Arch as Syscalls>::syscall0(SYS_GETTID)
3002}
3003
3004#[inline]
3005unsafe fn sys_futex(uaddr: *mut c_int,
3006 futex_op: c_int,
3007 val: c_int,
3008 timeout: *mut c_void,
3009 uaddr2: *mut c_int,
3010 val3: c_int,) -> i64 {
3011 <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)
3012}
3013
3014const MAX_THREADS: usize = 64;
3015const STACK_SIZE: usize = 1024 * 1024;
3016
3017#[repr(C)]
3018#[derive(Copy, Clone)]
3019struct Thread {
3020 tid: c_int,
3021 detach_state: c_int,
3022 result: *mut c_void,
3023 cancel: c_int,
3024 cancel_state: c_int,
3025 cancel_type: c_int,
3026 user_fn: usize,
3027 user_arg: *mut c_void,
3028 stack: *mut u8,
3029 stack_size: usize,
3030 fs_base: *mut u8,
3031 tsd: [*mut c_void; PTHREAD_KEYS_MAX],
3032 cancelbuf: *mut __ptcb,
3033 robust_list: robust_list_head,
3034}
3035
3036static mut THREADS: [Thread; MAX_THREADS] = [Thread {
3037 tid: -1,
3038 detach_state: DT_JOINABLE,
3039 result: core::ptr::null_mut(),
3040 cancel: 0,
3041 cancel_state: PTHREAD_CANCEL_ENABLE,
3042 cancel_type: PTHREAD_CANCEL_DEFERRED,
3043 user_fn: 0,
3044 user_arg: core::ptr::null_mut(),
3045 stack: core::ptr::null_mut(),
3046 stack_size: 0,
3047 fs_base: core::ptr::null_mut(),
3048 tsd: [core::ptr::null_mut(); PTHREAD_KEYS_MAX],
3049 cancelbuf: core::ptr::null_mut(),
3050 robust_list: robust_list_head {
3051 list: robust_list { next: core::ptr::null_mut() },
3052 futex_offset: 0,
3053 pending: core::ptr::null_mut(),
3054 },
3055}; MAX_THREADS];
3056static NEXT_SLOT: AtomicUsize = AtomicUsize::new(0);
3057static mut KEY_DTORS: [Option<unsafe extern "C" fn(*mut c_void)>; PTHREAD_KEYS_MAX] = [None; PTHREAD_KEYS_MAX];
3058static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
3059
3060unsafe fn futex_wait(addr: *mut c_int, expected: c_int) -> c_int {
3062 let r = sys_futex(addr, FUTEX_WAIT, expected, null_mut(), null_mut(), 0);
3063 if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3064}
3065
3066unsafe fn futex_wake(addr: *mut c_int, count: c_int) {
3067 let c = if count < 0 { c_int::MAX } else { count };
3068 sys_futex(addr, FUTEX_WAKE, c, null_mut(), null_mut(), 0);
3069}
3070
3071unsafe fn futex_lock_pi(addr: *mut c_int, abs_timeout: *const timespec) -> c_int {
3072 let timeout_ptr = if abs_timeout.is_null() { null_mut() } else { abs_timeout as *mut c_void };
3073 let r = sys_futex(addr, FUTEX_LOCK_PI, 0, timeout_ptr, null_mut(), 0);
3074 if r < 0 { (-r) as c_int } else { 0 }
3075}
3076
3077unsafe fn futex_unlock_pi(addr: *mut c_int) -> c_int {
3078 let r = sys_futex(addr, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
3079 if r < 0 { (-r) as c_int } else { 0 }
3080}
3081
3082#[inline]
3083unsafe fn sys_set_robust_list(head: *mut robust_list_head, len: usize) -> i64 {
3084 <Arch as Syscalls>::syscall2(SYS_SET_ROBUST_LIST, head as i64, len as i64)
3085}
3086
3087unsafe fn futex_timedwait(addr: *mut c_int, expected: c_int, abs_timeout: *const timespec) -> c_int {
3088 if abs_timeout.is_null() { return futex_wait(addr, expected); }
3089 let mut now: timespec = core::mem::zeroed();
3090 if sys_clock_gettime(CLOCK_REALTIME, &mut now) < 0 { return EINVAL; }
3091 let mut rel: timespec = core::mem::zeroed();
3092 rel.tv_sec = (*abs_timeout).tv_sec - now.tv_sec;
3093 rel.tv_nsec = (*abs_timeout).tv_nsec - now.tv_nsec;
3094 if rel.tv_nsec < 0 { rel.tv_sec -= 1; rel.tv_nsec += 1_000_000_000; }
3095 if rel.tv_sec < 0 { return ETIMEDOUT; }
3096 let r = sys_futex(addr, FUTEX_WAIT, expected, &mut rel as *mut timespec as *mut c_void, null_mut(), 0);
3097 if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3098}
3099
3100unsafe fn a_cas(addr: *mut c_int, expected: c_int, desired: c_int) -> c_int {
3102 let a = &*(addr as *const AtomicI32);
3103 match a.compare_exchange(expected, desired, Ordering::AcqRel, Ordering::Acquire) {
3104 Ok(v) | Err(v) => v,
3105 }
3106}
3107
3108unsafe fn a_store(addr: *mut c_int, val: c_int) {
3109 (*(addr as *const AtomicI32)).store(val, Ordering::Release);
3110}
3111
3112unsafe fn a_load(addr: *const c_int) -> c_int {
3113 (*(addr as *const AtomicI32)).load(Ordering::Acquire)
3114}
3115
3116unsafe fn a_swap(addr: *mut c_int, val: c_int) -> c_int {
3117 (*(addr as *const AtomicI32)).swap(val, Ordering::AcqRel)
3118}
3119
3120unsafe fn a_fetch_add(addr: *mut c_int, val: c_int) -> c_int {
3121 (*(addr as *const AtomicI32)).fetch_add(val, Ordering::AcqRel)
3122}
3123
3124unsafe fn a_fetch_sub(addr: *mut c_int, val: c_int) -> c_int {
3125 (*(addr as *const AtomicI32)).fetch_sub(val, Ordering::AcqRel)
3126}
3127
3128unsafe fn spinlock_lock(lock: *mut c_int, waiters: *mut c_int) {
3129 while a_swap(lock, 1) != 0 {
3130 let mut spins = 100;
3131 while spins > 0 && a_load(lock) != 0 { core::hint::spin_loop(); spins -= 1; }
3132 if a_load(lock) == 0 { continue; }
3133 a_fetch_add(waiters, 1);
3134 futex_wait(lock, 1);
3135 a_fetch_sub(waiters, 1);
3136 }
3137}
3138
3139unsafe fn spinlock_unlock(lock: *mut c_int, waiters: *mut c_int) {
3140 a_store(lock, 0);
3141 if a_load(waiters) > 0 { futex_wake(lock, 1); }
3142}
3143
3144unsafe fn alloc_thread_slot() -> Option<&'static mut Thread> {
3145 let idx = NEXT_SLOT.fetch_add(1, Ordering::SeqCst);
3146 if idx >= MAX_THREADS { return None; }
3147 Some(&mut THREADS[idx])
3148}
3149
3150unsafe fn run_key_dtors(slot: &mut Thread) {
3151 for _ in 0..PTHREAD_DESTRUCTOR_ITERATIONS {
3152 let mut any = false;
3153 for i in 0..PTHREAD_KEYS_MAX {
3154 let val = slot.tsd[i];
3155 if !val.is_null() {
3156 if let Some(dtor) = KEY_DTORS[i] {
3157 slot.tsd[i] = core::ptr::null_mut();
3158 any = true;
3159 dtor(val);
3160 }
3161 }
3162 }
3163 if !any { break; }
3164 }
3165}
3166
3167unsafe extern "C" fn thread_entry(slot: *mut c_void) -> *mut c_void {
3168 let slot = &mut *(slot as *mut Thread);
3169 let mut set: SigSetT = 0;
3170 sigemptyset(&mut set);
3171 sigaddset(&mut set, SIGCANCEL);
3172 pthread_sigmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
3173 let user_fn: unsafe extern "C" fn(*mut c_void) -> *mut c_void =
3174 core::mem::transmute::<usize, _>(slot.user_fn);
3175 let ret = user_fn(slot.user_arg);
3176 run_key_dtors(slot);
3177 slot.result = ret;
3178 a_store(&raw mut slot.detach_state, DT_EXITED);
3179 futex_wake(&raw mut slot.detach_state, 1);
3180 sys_exit_thread(0)
3181}
3182
3183unsafe fn find_thread() -> Option<&'static mut Thread> {
3184 let me = sys_gettid() as c_int;
3185 let base = core::ptr::addr_of_mut!(THREADS[0]);
3186 for i in 0..MAX_THREADS {
3187 let slot = base.add(i);
3188 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3189 return Some(&mut *slot);
3190 }
3191 }
3192 pthread_self();
3194 for i in 0..MAX_THREADS {
3195 let slot = base.add(i);
3196 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3197 return Some(&mut *slot);
3198 }
3199 }
3200 None
3201}
3202
3203#[no_mangle]
3204pub unsafe extern "C" fn pthread_self() -> PthreadT {
3205 let me = sys_gettid() as c_int;
3206 let base = core::ptr::addr_of_mut!(THREADS[0]);
3207 for i in 0..MAX_THREADS {
3208 let slot = base.add(i);
3209 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3210 return slot as PthreadT;
3211 }
3212 }
3213 let idx = NEXT_SLOT.fetch_add(1, Ordering::SeqCst);
3215 if idx < MAX_THREADS {
3216 let slot = &raw mut THREADS[idx];
3217 (*slot).tid = me;
3218 (*slot).detach_state = DT_JOINABLE;
3219 return slot as PthreadT;
3220 }
3221 0
3222}
3223
3224#[no_mangle]
3225pub unsafe extern "C" fn pthread_equal(t1: PthreadT, t2: PthreadT) -> c_int {
3226 (t1 == t2) as c_int
3227}
3228
3229#[no_mangle]
3230pub unsafe extern "C" fn pthread_create(
3231 thread: *mut PthreadT,
3232 attr: *const pthread_attr_t,
3233 start_routine: usize,
3234 arg: *mut c_void,
3235) -> c_int {
3236 if start_routine == 0 || thread.is_null() { return EINVAL; }
3237 let Some(slot_ref) = alloc_thread_slot() else { return EAGAIN; };
3238 let slot = slot_ref as *mut Thread;
3239 let stack_size = if !attr.is_null() {
3240 let s = *((*attr).__i.as_ptr() as *const usize);
3241 if s > 0 { s } else { STACK_SIZE }
3242 } else { STACK_SIZE };
3243 let stack = sys_mmap(null_mut(), stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
3244 if stack == MMAP_FAILED { return EAGAIN; }
3245 let fs_base = __rc_create_thread_tls();
3246 if fs_base.is_null() { sys_munmap(stack, stack_size); return EAGAIN; }
3247 (*slot).detach_state = DT_JOINABLE;
3248 (*slot).result = core::ptr::null_mut();
3249 (*slot).cancel = 0;
3250 (*slot).cancel_state = PTHREAD_CANCEL_ENABLE;
3251 (*slot).cancel_type = PTHREAD_CANCEL_DEFERRED;
3252 core::ptr::write_bytes((*slot).tsd.as_mut_ptr(), 0, PTHREAD_KEYS_MAX);
3253 (*slot).tid = 1;
3254 (*slot).user_fn = start_routine;
3255 (*slot).user_arg = arg;
3256 (*slot).stack = stack;
3257 (*slot).stack_size = stack_size;
3258 (*slot).fs_base = fs_base;
3259 let stack_top = stack.add(stack_size);
3260 let tid_ptr = &raw mut (*slot).tid;
3261 let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD
3262 | CLONE_SYSVSEM | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS;
3263 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);
3264 if tid < 0 {
3265 (*slot).tid = -1;
3266 sys_munmap(stack, stack_size);
3267 sys_munmap(fs_base.sub(__rc_tls_base_offset()), __rc_tls_block_size());
3268 return EAGAIN;
3269 }
3270 if !attr.is_null() && (*attr).__i[6] == PTHREAD_CREATE_DETACHED {
3271 (*slot).detach_state = DT_DETACHED;
3272 }
3273 *thread = slot as PthreadT;
3274 0
3275}
3276
3277#[no_mangle]
3278pub unsafe extern "C" fn pthread_join(thread: PthreadT, retval: *mut *mut c_void) -> c_int {
3279 let slot = thread as *mut Thread;
3280 if slot.is_null() { return EINVAL; }
3281 if (*slot).detach_state == DT_DETACHED { return EINVAL; }
3282 let tid_ptr = &raw mut (*slot).tid;
3283 loop {
3284 pthread_testcancel();
3285 let tid = core::ptr::read_volatile(tid_ptr);
3286 if tid == 0 { break; }
3287 if tid < 0 { return EINVAL; }
3288 sys_futex(tid_ptr, FUTEX_WAIT, tid, null_mut(), null_mut(), 0);
3289 pthread_testcancel();
3290 }
3291 if !retval.is_null() { *retval = (*slot).result; }
3292 let stack = (*slot).stack;
3293 let stack_size = (*slot).stack_size;
3294 let fs_base = (*slot).fs_base;
3295 (*slot).tid = -1;
3296 (*slot).detach_state = DT_JOINABLE;
3297 (*slot).result = core::ptr::null_mut();
3298 (*slot).stack = core::ptr::null_mut();
3299 (*slot).stack_size = 0;
3300 (*slot).fs_base = core::ptr::null_mut();
3301 if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3302 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); } }
3303 0
3304}
3305
3306#[no_mangle]
3307pub unsafe extern "C" fn pthread_detach(thread: PthreadT) -> c_int {
3308 let slot = thread as *mut Thread;
3309 if slot.is_null() { return EINVAL; }
3310 let old = a_cas(&raw mut (*slot).detach_state, DT_JOINABLE, DT_DETACHED);
3311 if old == DT_EXITED {
3312 let stack = (*slot).stack;
3313 let stack_size = (*slot).stack_size;
3314 let fs_base = (*slot).fs_base;
3315 (*slot).tid = -1;
3316 (*slot).stack = core::ptr::null_mut();
3317 (*slot).stack_size = 0;
3318 (*slot).fs_base = core::ptr::null_mut();
3319 if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3320 if !fs_base.is_null() { let bs = __rc_tls_block_size(); let bo = __rc_tls_base_offset(); sys_munmap(fs_base.sub(bo), bs); }
3321 }
3322 0
3323}
3324
3325#[no_mangle]
3326pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! {
3327 if let Some(slot) = find_thread() {
3328 run_cleanup_handlers(slot);
3329 run_key_dtors(slot);
3330 slot.result = retval;
3331 slot.detach_state = DT_EXITED;
3332 futex_wake(&slot.detach_state as *const c_int as *mut c_int, 1);
3333
3334 let mut active = 0usize;
3336 for i in 0..MAX_THREADS {
3337 if THREADS[i].tid > 0 {
3338 active += 1;
3339 }
3340 }
3341 if active == 1 {
3342 exit(0);
3343 }
3344 }
3345 sys_exit_thread(0);
3346}
3347
3348#[no_mangle]
3350pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int {
3351 core::ptr::write_bytes(attr, 0, 1);
3352 *((*attr).__i.as_mut_ptr() as *mut usize) = STACK_SIZE;
3353 *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = 4096;
3354 (*attr).__i[6] = PTHREAD_CREATE_JOINABLE;
3355 (*attr).__i[7] = PTHREAD_INHERIT_SCHED;
3356 0
3357}
3358#[no_mangle]
3359pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut pthread_attr_t) -> c_int { 0 }
3360#[no_mangle]
3361pub unsafe extern "C" fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, s: c_int) -> c_int {
3362 if s != PTHREAD_CREATE_JOINABLE && s != PTHREAD_CREATE_DETACHED { return EINVAL; }
3363 (*attr).__i[6] = s; 0
3364}
3365#[no_mangle]
3366pub unsafe extern "C" fn pthread_attr_getdetachstate(attr: *const pthread_attr_t, s: *mut c_int) -> c_int {
3367 *s = (*attr).__i[6]; 0
3368}
3369#[no_mangle]
3370pub unsafe extern "C" fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3371 if sz < 16384 { return EINVAL; }
3372 *((*attr).__i.as_mut_ptr() as *mut usize) = sz; 0
3373}
3374#[no_mangle]
3375pub unsafe extern "C" fn pthread_attr_getstacksize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3376 *sz = *((*attr).__i.as_ptr() as *const usize); 0
3377}
3378#[no_mangle]
3379pub unsafe extern "C" fn pthread_attr_setstack(attr: *mut pthread_attr_t, addr: *mut c_void, sz: usize) -> c_int {
3380 if sz < 16384 { return EINVAL; }
3381 *((*attr).__i.as_mut_ptr() as *mut usize) = sz;
3382 *((*attr).__i.as_mut_ptr().add(4) as *mut *mut c_void) = addr; 0
3383}
3384#[no_mangle]
3385pub unsafe extern "C" fn pthread_attr_getstack(attr: *const pthread_attr_t, addr: *mut *mut c_void, sz: *mut usize) -> c_int {
3386 *sz = *((*attr).__i.as_ptr() as *const usize);
3387 *addr = *((*attr).__i.as_ptr().add(4) as *const *mut c_void); 0
3388}
3389#[no_mangle]
3390pub unsafe extern "C" fn pthread_attr_setguardsize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3391 *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = sz; 0
3392}
3393#[no_mangle]
3394pub unsafe extern "C" fn pthread_attr_getguardsize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3395 *sz = *((*attr).__i.as_ptr().add(2) as *const usize); 0
3396}
3397#[no_mangle]
3398pub unsafe extern "C" fn pthread_attr_setscope(_attr: *mut pthread_attr_t, scope: c_int) -> c_int {
3399 if scope != PTHREAD_SCOPE_SYSTEM { return EINVAL; }
3400 0
3401}
3402#[no_mangle]
3403pub unsafe extern "C" fn pthread_attr_getscope(_attr: *const pthread_attr_t, scope: *mut c_int) -> c_int {
3404 *scope = PTHREAD_SCOPE_SYSTEM; 0
3405}
3406#[no_mangle]
3407pub unsafe extern "C" fn pthread_attr_setinheritsched(attr: *mut pthread_attr_t, inh: c_int) -> c_int {
3408 if inh != PTHREAD_INHERIT_SCHED && inh != PTHREAD_EXPLICIT_SCHED { return EINVAL; }
3409 (*attr).__i[7] = inh; 0
3410}
3411#[no_mangle]
3412pub unsafe extern "C" fn pthread_attr_getinheritsched(attr: *const pthread_attr_t, inh: *mut c_int) -> c_int {
3413 *inh = (*attr).__i[7]; 0
3414}
3415#[no_mangle]
3416pub unsafe extern "C" fn pthread_attr_setschedpolicy(attr: *mut pthread_attr_t, p: c_int) -> c_int {
3417 (*attr).__i[8] = p; 0
3418}
3419#[no_mangle]
3420pub unsafe extern "C" fn pthread_attr_getschedpolicy(attr: *const pthread_attr_t, p: *mut c_int) -> c_int {
3421 *p = (*attr).__i[8]; 0
3422}
3423#[no_mangle]
3424pub unsafe extern "C" fn pthread_attr_setschedparam(attr: *mut pthread_attr_t, param: *const sched_param) -> c_int {
3425 (*attr).__i[9] = (*param).sched_priority; 0
3426}
3427#[no_mangle]
3428pub unsafe extern "C" fn pthread_attr_getschedparam(attr: *const pthread_attr_t, param: *mut sched_param) -> c_int {
3429 (*param).sched_priority = (*attr).__i[9]; 0
3430}
3431
3432#[no_mangle]
3434pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
3435 (*attr).__attr = 0; 0
3436}
3437#[no_mangle]
3438pub unsafe extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int { 0 }
3439#[no_mangle]
3440pub unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, t: c_int) -> c_int {
3441 if (t as c_uint) > 2 { return EINVAL; }
3442 (*attr).__attr = ((*attr).__attr & !3) | t as c_uint; 0
3443}
3444#[no_mangle]
3445pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, t: *mut c_int) -> c_int {
3446 *t = ((*attr).__attr & 3) as c_int; 0
3447}
3448#[no_mangle]
3449pub unsafe extern "C" fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, p: c_int) -> c_int {
3450 if (p as c_uint) > 1 { return EINVAL; }
3451 (*attr).__attr = ((*attr).__attr & !128) | ((p as c_uint) << 7); 0
3452}
3453#[no_mangle]
3454pub unsafe extern "C" fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, p: *mut c_int) -> c_int {
3455 *p = (((*attr).__attr >> 7) & 1) as c_int; 0
3456}
3457
3458#[no_mangle]
3459pub unsafe extern "C" fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int {
3460 match protocol {
3461 0 => { (*attr).__attr &= !(MUTEX_PI as c_uint); 0 }
3462 1 => {
3463 let mut lk: c_int = 0;
3464 let r = sys_futex(&raw mut lk, FUTEX_LOCK_PI, 0, null_mut(), null_mut(), 0);
3465 if r < 0 { return (-r) as c_int; }
3466 sys_futex(&raw mut lk, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
3467 (*attr).__attr |= MUTEX_PI as c_uint;
3468 0
3469 }
3470 2 => ENOTSUP,
3471 _ => EINVAL,
3472 }
3473}
3474#[no_mangle]
3475pub unsafe extern "C" fn pthread_mutexattr_getprotocol(attr: *const pthread_mutexattr_t, protocol: *mut c_int) -> c_int {
3476 *protocol = (((*attr).__attr >> 3) & 3) as c_int; 0
3477}
3478
3479const ENOTSUP: c_int = 95;
3480
3481#[no_mangle]
3482pub unsafe extern "C" fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robust: c_int) -> c_int {
3483 if (robust as c_uint) > 1 { return EINVAL; }
3484 if robust != 0 {
3485 (*attr).__attr |= MUTEX_ROBUST as c_uint;
3486 } else {
3487 (*attr).__attr &= !(MUTEX_ROBUST as c_uint);
3488 }
3489 0
3490}
3491#[no_mangle]
3492pub unsafe extern "C" fn pthread_mutexattr_getrobust(attr: *const pthread_mutexattr_t, robust: *mut c_int) -> c_int {
3493 *robust = (((*attr).__attr >> 2) & 1) as c_int; 0
3494}
3495
3496#[no_mangle]
3497pub unsafe extern "C" fn pthread_mutex_consistent(m: *mut pthread_mutex_t) -> c_int {
3498 let old = a_load(&raw const (*m).__i[1]);
3499 let own = old & 0x3fffffff;
3500 if ((*m).__i[0] & MUTEX_ROBUST) == 0 || own == 0 || (old & 0x40000000) == 0 {
3501 return EINVAL;
3502 }
3503 let self_tid = sys_gettid() as c_int;
3504 if own != self_tid { return EPERM; }
3505 a_and(&raw mut (*m).__i[1], !(0x40000000i32));
3506 0
3507}
3508
3509unsafe fn a_and(addr: *mut c_int, val: c_int) {
3510 let a = &*(addr as *const AtomicI32);
3511 a.fetch_and(val, Ordering::AcqRel);
3512}
3513
3514const MUTEX_TYPE_MASK: c_int = 3;
3516const MUTEX_ROBUST: c_int = 4;
3517const MUTEX_PI: c_int = 8;
3518const MUTEX_PSHARED: c_int = 128;
3519
3520unsafe fn ensure_robust_list(slot: &mut Thread) {
3521 if slot.robust_list.futex_offset == 0 {
3522 slot.robust_list.futex_offset = -28;
3523 slot.robust_list.pending = core::ptr::null_mut();
3524 sys_set_robust_list(&mut slot.robust_list, 24);
3525 }
3526}
3527
3528unsafe fn mutex_trylock(m: *mut pthread_mutex_t) -> c_int {
3529 let type_ = (*m).__i[0];
3530 if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL {
3532 return a_cas(&raw mut (*m).__i[1], 0, EBUSY) & EBUSY;
3533 }
3534 let base_type = type_ & MUTEX_TYPE_MASK;
3535 let self_tid = sys_gettid() as c_int;
3536 let old = a_load(&raw const (*m).__i[1]);
3537 let own = old & 0x3fffffff;
3538 if own == self_tid {
3539 if (type_ & MUTEX_PI) != 0 && (*m).__i[5] < 0 {
3540 (*m).__i[5] = 0;
3541 return 0;
3542 }
3543 if base_type == PTHREAD_MUTEX_RECURSIVE {
3544 if (*m).__i[5] >= c_int::MAX { return EAGAIN; }
3545 (*m).__i[5] += 1;
3546 return 0;
3547 }
3548 if base_type == PTHREAD_MUTEX_ERRORCHECK { return EDEADLK; }
3549 return EBUSY;
3550 }
3551 if own == 0x3fffffff { return ENOTRECOVERABLE; }
3552 if own != 0 || (old != 0 && (type_ & MUTEX_ROBUST) == 0) { return EBUSY; }
3553 let mut newtid = self_tid;
3554 if (type_ & MUTEX_ROBUST) != 0 {
3555 if (*m).__i[2] != 0 { newtid |= 1i32 << 31; }
3556 newtid |= old & 0x40000000;
3557 }
3558 if a_cas(&raw mut (*m).__i[1], old, newtid) == old {
3559 (*m).__i[5] = 0;
3560 if (type_ & MUTEX_ROBUST) != 0 {
3561 if let Some(slot) = find_thread() {
3562 ensure_robust_list(slot);
3563 let m_next = &raw mut (*m).__i[8] as *mut robust_list;
3564 let head = &mut slot.robust_list.list;
3565 (*m_next).next = head.next;
3566 head.next = m_next;
3567 }
3568 }
3569 if old != 0 { return EOWNERDEAD; }
3570 0
3571 } else { EBUSY }
3572}
3573
3574unsafe fn mutex_lock_internal(m: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3575 let type_ = (*m).__i[0];
3576 if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL && a_cas(&raw mut (*m).__i[1], 0, EBUSY) == 0 {
3577 return 0;
3578 }
3579 let r = mutex_trylock(m);
3580 if r != EBUSY { return r; }
3581 if (type_ & MUTEX_PI) != 0 {
3582 let timeout_ptr = if abs_timeout.is_null() { core::ptr::null() } else { abs_timeout };
3583 loop {
3584 let e = futex_lock_pi(&raw mut (*m).__i[1], timeout_ptr);
3585 match e {
3586 0 => {
3587 if (type_ & MUTEX_ROBUST) != 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
3588 (*m).__i[5] = -1;
3589 let _ = mutex_trylock(m);
3590 return EOWNERDEAD;
3591 }
3592 if (type_ & MUTEX_ROBUST) == 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
3593 (*m).__i[2] = -1;
3594 futex_unlock_pi(&raw mut (*m).__i[1]);
3595 return EBUSY;
3596 }
3597 (*m).__i[5] = -1;
3598 let r2 = mutex_trylock(m);
3599 if r2 == 0 { return 0; }
3600 return r2;
3601 }
3602 EINTR => continue,
3603 EDEADLK => {
3604 if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK { return e; }
3605 loop { pause(); }
3606 }
3607 EOWNERDEAD => {
3608 (*m).__i[5] = -1;
3609 let _ = mutex_trylock(m);
3610 return EOWNERDEAD;
3611 }
3612 _ => return e,
3613 }
3614 }
3615 }
3616 let mut spins = 100;
3617 while spins > 0 {
3618 let r = mutex_trylock(m);
3619 if r != EBUSY { return r; }
3620 core::hint::spin_loop();
3621 spins -= 1;
3622 }
3623 loop {
3624 let r = mutex_trylock(m);
3625 if r != EBUSY { return r; }
3626 if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK {
3627 let self_tid = sys_gettid() as c_int;
3628 if (a_load(&raw const (*m).__i[1]) & 0x3fffffff) == self_tid { return EDEADLK; }
3629 }
3630 a_fetch_add(&raw mut (*m).__i[2], 1);
3631 let val = a_load(&raw const (*m).__i[1]);
3632 a_cas(&raw mut (*m).__i[1], val, val | (1i32 << 31));
3633 let e = futex_timedwait(&raw mut (*m).__i[1], val | (1i32 << 31), abs_timeout);
3634 a_fetch_sub(&raw mut (*m).__i[2], 1);
3635 if e != 0 && e != EINTR { return e; }
3636 }
3637}
3638
3639#[no_mangle]
3640pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) -> c_int {
3641 core::ptr::write_bytes(mutex, 0, 1);
3642 if !attr.is_null() { (*mutex).__i[0] = (*attr).__attr as c_int; }
3643 0
3644}
3645#[no_mangle]
3646pub unsafe extern "C" fn pthread_mutex_destroy(_mutex: *mut pthread_mutex_t) -> c_int { 0 }
3647#[no_mangle]
3648pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
3649 mutex_lock_internal(mutex, core::ptr::null())
3650}
3651#[no_mangle]
3652pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int {
3653 mutex_trylock(mutex)
3654}
3655#[no_mangle]
3656pub unsafe extern "C" fn pthread_mutex_timedlock(mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3657 mutex_lock_internal(mutex, abs_timeout)
3658}
3659#[no_mangle]
3660pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
3661 let type_ = (*mutex).__i[0];
3662 let base_type = type_ & MUTEX_TYPE_MASK;
3663 let old = a_load(&raw const (*mutex).__i[1]);
3664 if base_type != PTHREAD_MUTEX_NORMAL {
3665 let self_tid = sys_gettid() as c_int;
3666 if (old & 0x3fffffff) != self_tid { return EPERM; }
3667 if base_type == PTHREAD_MUTEX_RECURSIVE && (*mutex).__i[5] > 0 {
3668 (*mutex).__i[5] -= 1;
3669 return 0;
3670 }
3671 }
3672 let mut new = 0;
3673 if (type_ & MUTEX_ROBUST) != 0 && (old & 0x40000000) != 0 {
3674 new = 0x7fffffff;
3675 }
3676 if (type_ & MUTEX_PI) != 0 {
3677 if old < 0 || a_cas(&raw mut (*mutex).__i[1], old, new) != old {
3678 if new != 0 { a_store(&raw mut (*mutex).__i[2], -1); }
3679 return futex_unlock_pi(&raw mut (*mutex).__i[1]);
3680 }
3681 return 0;
3682 }
3683 a_store(&raw mut (*mutex).__i[1], new);
3684 if new == 0 && (a_load(&raw const (*mutex).__i[2]) > 0 || old < 0) {
3685 futex_wake(&raw mut (*mutex).__i[1], 1);
3686 }
3687 0
3688}
3689
3690#[no_mangle]
3692pub unsafe extern "C" fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int {
3693 (*attr).__attr = 0; 0
3694}
3695#[no_mangle]
3696pub unsafe extern "C" fn pthread_condattr_destroy(_attr: *mut pthread_condattr_t) -> c_int { 0 }
3697#[no_mangle]
3698pub unsafe extern "C" fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clk: c_int) -> c_int {
3699 if clk != CLOCK_REALTIME && clk != CLOCK_MONOTONIC { return EINVAL; }
3700 (*attr).__attr = ((*attr).__attr & 0x80000000) | clk as c_uint; 0
3701}
3702#[no_mangle]
3703pub unsafe extern "C" fn pthread_condattr_getclock(attr: *const pthread_condattr_t, clk: *mut c_int) -> c_int {
3704 *clk = ((*attr).__attr & 0x7fffffff) as c_int; 0
3705}
3706#[no_mangle]
3707pub unsafe extern "C" fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, p: c_int) -> c_int {
3708 if (p as c_uint) > 1 { return EINVAL; }
3709 (*attr).__attr = ((*attr).__attr & 0x7fffffff) | ((p as c_uint) << 31); 0
3710}
3711#[no_mangle]
3712pub unsafe extern "C" fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, p: *mut c_int) -> c_int {
3713 *p = ((*attr).__attr >> 31) as c_int; 0
3714}
3715
3716#[no_mangle]
3718pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int {
3719 core::ptr::write_bytes(cond, 0, 1);
3720 if !attr.is_null() {
3721 (*cond).__i[4] = ((*attr).__attr & 0x7fffffff) as c_int;
3722 }
3723 0
3724}
3725#[no_mangle]
3726pub unsafe extern "C" fn pthread_cond_destroy(_cond: *mut pthread_cond_t) -> c_int { 0 }
3727#[no_mangle]
3728pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int {
3729 pthread_cond_timedwait(cond, mutex, core::ptr::null())
3730}
3731#[no_mangle]
3732pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3733 pthread_testcancel();
3734 let seq_ptr = &raw mut (*cond).__i[2];
3735 let waiters_ptr = &raw mut (*cond).__i[3];
3736 let seq = a_load(seq_ptr);
3737 a_fetch_add(waiters_ptr, 1);
3738 pthread_mutex_unlock(mutex);
3739 let e = futex_timedwait(seq_ptr, seq, abs_timeout);
3740 a_fetch_sub(waiters_ptr, 1);
3741 let r = pthread_mutex_lock(mutex);
3742 if r != 0 { return r; }
3743 if e == EINTR {
3744 pthread_testcancel();
3745 }
3746 if e != 0 && e != EINTR { return e; }
3747 0
3748}
3749#[no_mangle]
3750pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int {
3751 if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
3752 a_fetch_add(&raw mut (*cond).__i[2], 1);
3753 futex_wake(&raw mut (*cond).__i[2], 1);
3754 0
3755}
3756#[no_mangle]
3757pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int {
3758 if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
3759 a_fetch_add(&raw mut (*cond).__i[2], 1);
3760 futex_wake(&raw mut (*cond).__i[2], -1);
3761 0
3762}
3763
3764#[no_mangle]
3766pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
3767 (*attr).__attr = [0; 2]; 0
3768}
3769#[no_mangle]
3770pub unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut pthread_rwlockattr_t) -> c_int { 0 }
3771#[no_mangle]
3772pub unsafe extern "C" fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, p: c_int) -> c_int {
3773 if (p as c_uint) > 1 { return EINVAL; }
3774 (*attr).__attr[0] = ((*attr).__attr[0] & !128) | ((p as c_uint) << 7); 0
3775}
3776#[no_mangle]
3777pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, p: *mut c_int) -> c_int {
3778 *p = (((*attr).__attr[0] >> 7) & 1) as c_int; 0
3779}
3780
3781unsafe fn rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int {
3783 loop {
3784 let val = a_load(&raw const (*rw).__i[0]);
3785 let cnt = val & 0x7fffffff;
3786 if cnt == 0x7fffffff { return EBUSY; }
3787 if cnt == 0x7ffffffe { return EAGAIN; }
3788 if a_cas(&raw mut (*rw).__i[0], val, val + 1) == val { return 0; }
3789 }
3790}
3791unsafe fn rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int {
3792 if a_cas(&raw mut (*rw).__i[0], 0, 0x7fffffff) == 0 { 0 } else { EBUSY }
3793}
3794unsafe fn rwlock_timedrdlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
3795 let r = rwlock_tryrdlock(rw);
3796 if r != EBUSY { return r; }
3797 let mut spins = 100;
3798 while spins > 0 { let r = rwlock_tryrdlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
3799 loop {
3800 let r = rwlock_tryrdlock(rw);
3801 if r != EBUSY { return r; }
3802 let val = a_load(&raw const (*rw).__i[0]);
3803 if val & 0x7fffffff != 0x7fffffff { continue; }
3804 a_fetch_add(&raw mut (*rw).__i[1], 1);
3805 a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
3806 let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
3807 a_fetch_sub(&raw mut (*rw).__i[1], 1);
3808 if e != 0 && e != EINTR { return e; }
3809 }
3810}
3811unsafe fn rwlock_timedwrlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
3812 let r = rwlock_trywrlock(rw);
3813 if r != EBUSY { return r; }
3814 let mut spins = 100;
3815 while spins > 0 { let r = rwlock_trywrlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
3816 loop {
3817 let r = rwlock_trywrlock(rw);
3818 if r != EBUSY { return r; }
3819 let val = a_load(&raw const (*rw).__i[0]);
3820 if val == 0 { continue; }
3821 a_fetch_add(&raw mut (*rw).__i[1], 1);
3822 a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
3823 let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
3824 a_fetch_sub(&raw mut (*rw).__i[1], 1);
3825 if e != 0 && e != EINTR { return e; }
3826 }
3827}
3828
3829#[no_mangle]
3830pub unsafe extern "C" fn pthread_rwlock_init(rw: *mut pthread_rwlock_t, attr: *const pthread_rwlockattr_t) -> c_int {
3831 core::ptr::write_bytes(rw, 0, 1);
3832 if !attr.is_null() { (*rw).__i[2] = (*attr).__attr[0] as c_int & 128; }
3833 0
3834}
3835#[no_mangle]
3836pub unsafe extern "C" fn pthread_rwlock_destroy(_rw: *mut pthread_rwlock_t) -> c_int { 0 }
3837#[no_mangle]
3838pub unsafe extern "C" fn pthread_rwlock_rdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedrdlock(rw, core::ptr::null()) }
3839#[no_mangle]
3840pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_tryrdlock(rw) }
3841#[no_mangle]
3842pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedrdlock(rw, t) }
3843#[no_mangle]
3844pub unsafe extern "C" fn pthread_rwlock_wrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedwrlock(rw, core::ptr::null()) }
3845#[no_mangle]
3846pub unsafe extern "C" fn pthread_rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_trywrlock(rw) }
3847#[no_mangle]
3848pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedwrlock(rw, t) }
3849#[no_mangle]
3850pub unsafe extern "C" fn pthread_rwlock_unlock(rw: *mut pthread_rwlock_t) -> c_int {
3851 loop {
3852 let val = a_load(&raw const (*rw).__i[0]);
3853 let cnt = val & 0x7fffffff;
3854 let new_val = if cnt == 0x7fffffff || cnt == 1 { 0 } else { val - 1 };
3855 if a_cas(&raw mut (*rw).__i[0], val, new_val) == val {
3856 if new_val == 0 && (a_load(&raw const (*rw).__i[1]) > 0 || val < 0) {
3857 futex_wake(&raw mut (*rw).__i[0], cnt);
3858 }
3859 return 0;
3860 }
3861 }
3862}
3863
3864#[no_mangle]
3866pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int { (*attr).__attr = 0; 0 }
3867#[no_mangle]
3868pub unsafe extern "C" fn pthread_barrierattr_destroy(_attr: *mut pthread_barrierattr_t) -> c_int { 0 }
3869#[no_mangle]
3870pub unsafe extern "C" fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, p: c_int) -> c_int {
3871 if (p as c_uint) > 1 { return EINVAL; }
3872 (*attr).__attr = p as c_uint; 0
3873}
3874#[no_mangle]
3875pub unsafe extern "C" fn pthread_barrierattr_getpshared(attr: *const pthread_barrierattr_t, p: *mut c_int) -> c_int {
3876 *p = (*attr).__attr as c_int; 0
3877}
3878
3879#[no_mangle]
3881pub unsafe extern "C" fn pthread_barrier_init(b: *mut pthread_barrier_t, _attr: *const pthread_barrierattr_t, count: c_uint) -> c_int {
3882 if count == 0 { return EINVAL; }
3883 core::ptr::write_bytes(b, 0, 1);
3884 (*b).__i[2] = count as c_int - 1;
3885 0
3886}
3887#[no_mangle]
3888pub unsafe extern "C" fn pthread_barrier_destroy(_b: *mut pthread_barrier_t) -> c_int { 0 }
3889#[no_mangle]
3890pub unsafe extern "C" fn pthread_barrier_wait(b: *mut pthread_barrier_t) -> c_int {
3891 let limit = (*b).__i[2];
3892 if limit == 0 { return PTHREAD_BARRIER_SERIAL_THREAD; }
3893 spinlock_lock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3894 let arrived = a_load(&raw const (*b).__i[3]) + 1;
3895 a_store(&raw mut (*b).__i[3], arrived);
3896 if arrived > limit {
3897 a_store(&raw mut (*b).__i[3], 0);
3898 let gen = a_load(&raw const (*b).__i[4]);
3899 a_store(&raw mut (*b).__i[4], gen + 1);
3900 spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3901 futex_wake(&raw mut (*b).__i[4], -1);
3902 return PTHREAD_BARRIER_SERIAL_THREAD;
3903 }
3904 let gen = a_load(&raw const (*b).__i[4]);
3905 spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3906 while a_load(&raw const (*b).__i[4]) == gen {
3907 futex_wait(&raw mut (*b).__i[4], gen);
3908 }
3909 0
3910}
3911
3912#[no_mangle]
3914pub unsafe extern "C" fn pthread_spin_init(s: *mut pthread_spinlock_t, _pshared: c_int) -> c_int { a_store(s, 0); 0 }
3915#[no_mangle]
3916pub unsafe extern "C" fn pthread_spin_destroy(_s: *mut pthread_spinlock_t) -> c_int { 0 }
3917#[no_mangle]
3918pub unsafe extern "C" fn pthread_spin_lock(s: *mut pthread_spinlock_t) -> c_int {
3919 while a_load(s) != 0 || a_cas(s, 0, EBUSY) != 0 { core::hint::spin_loop(); }
3920 0
3921}
3922#[no_mangle]
3923pub unsafe extern "C" fn pthread_spin_trylock(s: *mut pthread_spinlock_t) -> c_int { a_cas(s, 0, EBUSY) }
3924#[no_mangle]
3925pub unsafe extern "C" fn pthread_spin_unlock(s: *mut pthread_spinlock_t) -> c_int { a_store(s, 0); 0 }
3926
3927#[no_mangle]
3929pub unsafe extern "C" fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int {
3930 if value > SEM_VALUE_MAX as c_uint { return EINVAL; }
3931 (*sem).__val[0] = value as c_int;
3932 (*sem).__val[1] = 0;
3933 (*sem).__val[2] = if pshared != 0 { 0 } else { 128 };
3934 0
3935}
3936#[no_mangle]
3937pub unsafe extern "C" fn sem_destroy(_sem: *mut sem_t) -> c_int { 0 }
3938
3939unsafe fn sem_trywait_internal(sem: *mut sem_t) -> c_int {
3940 loop {
3941 let val = a_load(&raw const (*sem).__val[0]);
3942 if val & SEM_VALUE_MAX == 0 { return EAGAIN; }
3943 if a_cas(&raw mut (*sem).__val[0], val, val - 1) == val { return 0; }
3944 }
3945}
3946
3947#[no_mangle]
3948pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
3949 if sem_trywait_internal(sem) == 0 { 0 } else { ERRNO = EAGAIN; -1 }
3950}
3951#[no_mangle]
3952pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int {
3953 pthread_testcancel();
3954 if sem_trywait_internal(sem) == 0 { return 0; }
3955 let mut spins = 100;
3956 while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
3957 loop {
3958 pthread_testcancel();
3959 if sem_trywait_internal(sem) == 0 { return 0; }
3960 let val = a_load(&raw const (*sem).__val[0]);
3961 if val & SEM_VALUE_MAX != 0 { continue; }
3962 a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
3963 a_fetch_add(&raw mut (*sem).__val[1], 1);
3964 futex_wait(&raw mut (*sem).__val[0], 1i32 << 31);
3965 a_fetch_sub(&raw mut (*sem).__val[1], 1);
3966 }
3967}
3968#[no_mangle]
3969pub unsafe extern "C" fn sem_timedwait(sem: *mut sem_t, abs_timeout: *const timespec) -> c_int {
3970 pthread_testcancel();
3971 if sem_trywait_internal(sem) == 0 { return 0; }
3972 let mut spins = 100;
3973 while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
3974 loop {
3975 pthread_testcancel();
3976 if sem_trywait_internal(sem) == 0 { return 0; }
3977 let val = a_load(&raw const (*sem).__val[0]);
3978 if val & SEM_VALUE_MAX != 0 { continue; }
3979 a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
3980 a_fetch_add(&raw mut (*sem).__val[1], 1);
3981 let e = futex_timedwait(&raw mut (*sem).__val[0], 1i32 << 31, abs_timeout);
3982 a_fetch_sub(&raw mut (*sem).__val[1], 1);
3983 if e != 0 && e != EINTR { ERRNO = e; return -1; }
3984 }
3985}
3986#[no_mangle]
3987pub unsafe extern "C" fn sem_post(sem: *mut sem_t) -> c_int {
3988 loop {
3989 let val = a_load(&raw const (*sem).__val[0]);
3990 if (val & SEM_VALUE_MAX) == SEM_VALUE_MAX { ERRNO = EOVERFLOW; return -1; }
3991 let mut new = val + 1;
3992 let waiters = a_load(&raw const (*sem).__val[1]);
3993 if waiters <= 1 { new &= !(1i32 << 31); }
3994 if a_cas(&raw mut (*sem).__val[0], val, new) == val {
3995 if val < 0 || waiters > 0 {
3996 futex_wake(&raw mut (*sem).__val[0], if waiters > 1 { 1 } else { -1 });
3997 }
3998 return 0;
3999 }
4000 }
4001}
4002#[no_mangle]
4003pub unsafe extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int {
4004 *sval = a_load(&raw const (*sem).__val[0]) & SEM_VALUE_MAX;
4005 0
4006}
4007
4008const NAME_MAX: usize = 255;
4013const SEM_NSEMS_MAX: usize = 256;
4014
4015static SEMTAB_LOCK: AtomicI32 = AtomicI32::new(0);
4017
4018struct SemEntry {
4019 ino: u64,
4020 sem: *mut sem_t,
4021 refcnt: u32,
4022}
4023
4024static mut SEMTAB: [SemEntry; SEM_NSEMS_MAX] = {
4026 const ZERO: SemEntry = SemEntry { ino: 0, sem: core::ptr::null_mut(), refcnt: 0 };
4027 [ZERO; SEM_NSEMS_MAX]
4028};
4029
4030unsafe fn semtab_lock() {
4031 while SEMTAB_LOCK.compare_exchange_weak(0, 1, Ordering::Acquire, Ordering::Relaxed).is_err() {
4032 core::hint::spin_loop();
4033 }
4034}
4035
4036unsafe fn semtab_unlock() {
4037 SEMTAB_LOCK.store(0, Ordering::Release);
4038}
4039
4040unsafe fn shm_mapname(name: *const c_char, buf: *mut u8) -> c_int {
4043 let mut p = name;
4044 while *p == b'/' as c_char { p = p.add(1); }
4046 let start = p;
4047 while *p != 0 && *p != b'/' as c_char { p = p.add(1); }
4049 let len = p.offset_from(start) as usize;
4050 if len == 0 || *p != 0 {
4052 ERRNO = EINVAL;
4053 return -1;
4054 }
4055 if len == 1 && *start == b'.' as c_char {
4056 ERRNO = EINVAL;
4057 return -1;
4058 }
4059 if len == 2 && *start == b'.' as c_char && *start.add(1) == b'.' as c_char {
4060 ERRNO = EINVAL;
4061 return -1;
4062 }
4063 if len > NAME_MAX {
4064 ERRNO = ENAMETOOLONG;
4065 return -1;
4066 }
4067 let prefix = b"/dev/shm/\0";
4069 let mut i = 0;
4070 while prefix[i] != 0 {
4071 *buf.add(i) = prefix[i];
4072 i += 1;
4073 }
4074 let mut j = 0;
4075 while j < len {
4076 *buf.add(i + j) = *start.add(j) as u8;
4077 j += 1;
4078 }
4079 *buf.add(i + j) = 0;
4080 (i + j) as c_int
4081}
4082
4083#[no_mangle]
4084pub unsafe extern "C" fn shm_open(name: *const c_char, flags: c_int, mode: mode_t) -> c_int {
4085 let mut buf = [0u8; 16 + NAME_MAX + 1];
4086 if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4087 let fd = sys_open(buf.as_ptr(), (flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4088 if fd < 0 { ERRNO = (-fd) as c_int; return -1; }
4089 fd as c_int
4090}
4091
4092#[no_mangle]
4093pub unsafe extern "C" fn shm_unlink(name: *const c_char) -> c_int {
4094 let mut buf = [0u8; 16 + NAME_MAX + 1];
4095 if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4096 let r = sys_unlink(buf.as_ptr());
4097 if r < 0 { ERRNO = (-r) as c_int; return -1; }
4098 0
4099}
4100
4101#[no_mangle]
4102pub unsafe extern "C" fn sem_open(name: *const c_char, flags: c_int, mut args: ...) -> *mut sem_t {
4103 let mut buf = [0u8; 16 + NAME_MAX + 1];
4104 if shm_mapname(name, buf.as_mut_ptr()).is_negative() {
4105 return core::ptr::null_mut(); }
4107
4108 let oflags = flags & (O_CREAT | O_EXCL);
4109
4110 semtab_lock();
4111
4112 let mut slot: c_int = -1;
4114 for i in 0..SEMTAB_LEN {
4115 if SEMTAB[i].sem.is_null() && slot < 0 { slot = i as c_int; }
4116 }
4117 if slot < 0 {
4118 ERRNO = EMFILE;
4119 semtab_unlock();
4120 return core::ptr::null_mut();
4121 }
4122 SEMTAB[slot as usize].sem = !0usize as *mut sem_t; semtab_unlock();
4125
4126 let mut mode: mode_t = 0;
4128 let mut value: c_uint = 0;
4129 if oflags & O_CREAT != 0 {
4130 mode = args.next_arg::<mode_t>() & 0o666;
4131 value = args.next_arg::<c_uint>();
4132 if value > SEM_VALUE_MAX as c_uint {
4133 ERRNO = EINVAL;
4134 semtab_lock();
4135 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4136 semtab_unlock();
4137 return core::ptr::null_mut();
4138 }
4139 }
4140
4141 if oflags != O_CREAT | O_EXCL {
4143 let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4144 if fd >= 0 {
4145 let map = sys_mmap(
4146 core::ptr::null_mut(),
4147 core::mem::size_of::<sem_t>(),
4148 PROT_READ | PROT_WRITE,
4149 MAP_SHARED,
4150 fd as i32,
4151 0,
4152 );
4153 sys_close(fd);
4154 if map != MMAP_FAILED {
4155 let st_ino = get_ino(fd as c_int, buf.as_ptr());
4156 return sem_register(map as *mut sem_t, st_ino, slot);
4157 }
4158 }
4159 if oflags == 0 {
4160 semtab_lock();
4162 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4163 semtab_unlock();
4164 return core::ptr::null_mut();
4165 }
4166 }
4167
4168 let mut tmp = [0u8; 32];
4170 let tmpname = b"/dev/shm/tmp-XXXXXX\0";
4171 tmp[..tmpname.len()].copy_from_slice(tmpname);
4172 let mut ts: timespec = core::mem::zeroed();
4174 sys_clock_gettime(0, &mut ts);
4175 let mut n = ts.tv_nsec;
4177 let mut pos = tmpname.len() - 1;
4178 tmp[pos] = 0;
4179 pos -= 1;
4180 loop {
4181 tmp[pos] = b'0' + (n % 10) as u8;
4182 n /= 10;
4183 if n == 0 || pos == 0 { break; }
4184 pos -= 1;
4185 }
4186 let tmp_path = tmp.as_ptr();
4188
4189 let mut newsem: sem_t = core::mem::zeroed();
4190 newsem.__val[0] = value as c_int;
4191 newsem.__val[1] = 0;
4192 newsem.__val[2] = 128; loop {
4195 let fd = sys_open(tmp_path as *const u8, (O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4196 if fd < 0 {
4197 if (-fd) as c_int == EEXIST { continue; }
4198 semtab_lock();
4199 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4200 semtab_unlock();
4201 return core::ptr::null_mut();
4202 }
4203 let written = sys_write(fd, &newsem as *const sem_t as *const u8, core::mem::size_of::<sem_t>());
4204 if written != core::mem::size_of::<sem_t>() as i64 {
4205 sys_close(fd);
4206 sys_unlink(tmp_path);
4207 semtab_lock();
4208 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4209 semtab_unlock();
4210 return core::ptr::null_mut();
4211 }
4212 let map = sys_mmap(
4213 core::ptr::null_mut(),
4214 core::mem::size_of::<sem_t>(),
4215 PROT_READ | PROT_WRITE,
4216 MAP_SHARED,
4217 fd as i32,
4218 0,
4219 );
4220 sys_close(fd);
4221 if map == MMAP_FAILED {
4222 sys_unlink(tmp_path);
4223 semtab_lock();
4224 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4225 semtab_unlock();
4226 return core::ptr::null_mut();
4227 }
4228 let r = sys_linkat(AT_FDCWD, tmp_path, AT_FDCWD, buf.as_ptr(), 0);
4230 let e = if r < 0 { (-r) as c_int } else { 0 };
4231 sys_unlink(tmp_path);
4232 if e == 0 {
4233 let st_ino = get_ino(-1, buf.as_ptr());
4234 return sem_register(map as *mut sem_t, st_ino, slot);
4235 }
4236 sys_munmap(map, core::mem::size_of::<sem_t>());
4237 if e != EEXIST || oflags == O_CREAT | O_EXCL {
4238 ERRNO = e;
4239 semtab_lock();
4240 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4241 semtab_unlock();
4242 return core::ptr::null_mut();
4243 }
4244 break;
4246 }
4247
4248 let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4250 if fd < 0 {
4251 semtab_lock();
4252 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4253 semtab_unlock();
4254 return core::ptr::null_mut();
4255 }
4256 let map = sys_mmap(
4257 core::ptr::null_mut(),
4258 core::mem::size_of::<sem_t>(),
4259 PROT_READ | PROT_WRITE,
4260 MAP_SHARED,
4261 fd as i32,
4262 0,
4263 );
4264 sys_close(fd);
4265 if map == MMAP_FAILED {
4266 semtab_lock();
4267 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4268 semtab_unlock();
4269 return core::ptr::null_mut();
4270 }
4271 let st_ino = get_ino(-1, buf.as_ptr());
4272 sem_register(map as *mut sem_t, st_ino, slot)
4273}
4274
4275unsafe fn get_ino(_fd_hint: c_int, path: *const u8) -> u64 {
4276 let mut st: Stat = core::mem::zeroed();
4277 if sys_newfstatat(AT_FDCWD, path as *const c_char, &mut st as *mut Stat as *mut u8, 0) == 0 {
4278 st.st_ino
4279 } else {
4280 0
4281 }
4282}
4283
4284unsafe fn sem_register(map: *mut sem_t, ino: u64, slot_hint: c_int) -> *mut sem_t {
4285 semtab_lock();
4286 for i in 0..SEMTAB_LEN {
4288 if SEMTAB[i].ino == ino && !SEMTAB[i].sem.is_null() && SEMTAB[i].sem != !0usize as *mut sem_t {
4289 sys_munmap(map as *mut u8, core::mem::size_of::<sem_t>());
4291 SEMTAB[slot_hint as usize].sem = core::ptr::null_mut();
4292 SEMTAB[i].refcnt += 1;
4293 let ret = SEMTAB[i].sem;
4294 semtab_unlock();
4295 return ret;
4296 }
4297 }
4298 SEMTAB[slot_hint as usize].sem = map;
4300 SEMTAB[slot_hint as usize].ino = ino;
4301 SEMTAB[slot_hint as usize].refcnt = 1;
4302 semtab_unlock();
4303 map
4304}
4305
4306const SEMTAB_LEN: usize = SEM_NSEMS_MAX;
4307
4308#[no_mangle]
4309pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
4310 semtab_lock();
4311 for i in 0..SEMTAB_LEN {
4312 if SEMTAB[i].sem == sem {
4313 SEMTAB[i].refcnt -= 1;
4314 if SEMTAB[i].refcnt == 0 {
4315 SEMTAB[i].sem = core::ptr::null_mut();
4316 SEMTAB[i].ino = 0;
4317 semtab_unlock();
4318 sys_munmap(sem as *mut u8, core::mem::size_of::<sem_t>());
4319 return 0;
4320 }
4321 semtab_unlock();
4322 return 0;
4323 }
4324 }
4325 semtab_unlock();
4326 0
4327}
4328
4329#[no_mangle]
4330pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
4331 shm_unlink(name)
4332}
4333
4334#[no_mangle]
4336pub unsafe extern "C" fn pthread_once(control: *mut pthread_once_t, init_routine: Option<unsafe extern "C" fn()>) -> c_int {
4337 if a_load(control) == 2 { return 0; }
4338 loop {
4339 match a_cas(control, 0, 1) {
4340 0 => {
4341 if let Some(f) = init_routine { f(); }
4342 if a_swap(control, 2) == 3 { futex_wake(control, -1); }
4343 return 0;
4344 }
4345 1 => { a_cas(control, 1, 3); }
4346 3 => { futex_wait(control, 3); }
4347 _ => { return 0; }
4348 }
4349 }
4350}
4351
4352#[no_mangle]
4354pub unsafe extern "C" fn pthread_key_create(key: *mut pthread_key_t, dtor: Option<unsafe extern "C" fn(*mut c_void)>) -> c_int {
4355 let start = NEXT_KEY.load(Ordering::Relaxed);
4356 let mut j = start;
4357 loop {
4358 if KEY_DTORS[j].is_none() {
4359 KEY_DTORS[j] = dtor;
4360 NEXT_KEY.store((j + 1) % PTHREAD_KEYS_MAX, Ordering::Relaxed);
4361 *key = j as pthread_key_t;
4362 return 0;
4363 }
4364 j = (j + 1) % PTHREAD_KEYS_MAX;
4365 if j == start { return EAGAIN; }
4366 }
4367}
4368#[no_mangle]
4369pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int {
4370 KEY_DTORS[key as usize] = None;
4371 for i in 0..MAX_THREADS {
4372 if THREADS[i].tid > 0 { THREADS[i].tsd[key as usize] = core::ptr::null_mut(); }
4373 }
4374 0
4375}
4376#[no_mangle]
4377pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
4378 if let Some(slot) = find_thread() { slot.tsd[key as usize] } else { core::ptr::null_mut() }
4379}
4380#[no_mangle]
4381pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int {
4382 if let Some(slot) = find_thread() {
4383 slot.tsd[key as usize] = value as *mut c_void;
4384 0
4385 } else { EINVAL }
4386}
4387
4388unsafe fn run_cleanup_handlers(slot: &mut Thread) {
4390 let mut cb = slot.cancelbuf;
4391 while !cb.is_null() {
4392 let cur = &*cb;
4393 let f = cur.__f;
4394 let x = cur.__x;
4395 cb = cur.__next;
4396 if let Some(func) = f {
4397 func(x);
4398 }
4399 }
4400 slot.cancelbuf = core::ptr::null_mut();
4401}
4402
4403unsafe fn do_cancel() -> ! {
4404 if let Some(slot) = find_thread() {
4405 run_cleanup_handlers(slot);
4406 slot.result = !0usize as *mut c_void; slot.detach_state = DT_EXITED;
4408 futex_wake(&raw mut slot.detach_state, 1);
4409 }
4410 sys_exit_thread(0);
4411}
4412
4413extern "C" fn cancel_handler(_sig: c_int) {
4414 unsafe {
4415 if let Some(slot) = find_thread() {
4416 if slot.cancel != 0
4420 && slot.cancel_state == PTHREAD_CANCEL_ENABLE
4421 && slot.cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS
4422 {
4423 do_cancel();
4424 }
4425 }
4426 }
4427}
4428
4429static CANCEL_INIT: AtomicI32 = AtomicI32::new(0);
4430
4431unsafe fn ensure_cancel_handler() {
4432 if CANCEL_INIT.swap(1, Ordering::AcqRel) == 0 {
4433 let act = sigaction {
4434 sa_handler: cancel_handler as *const () as usize,
4435 sa_flags: SA_RESTORER,
4436 sa_restorer: sig_restorer as *const () as usize,
4437 sa_mask: [!0u64],
4438 };
4439 sys_rt_sigaction(SIGCANCEL, &act as *const sigaction, core::ptr::null_mut(), 8);
4440 }
4441}
4442
4443#[no_mangle]
4444pub unsafe extern "C" fn pthread_cancel(thread: PthreadT) -> c_int {
4445 let slot = thread as *mut Thread;
4446 if slot.is_null() { return EINVAL; }
4447 ensure_cancel_handler();
4448 a_store(&raw mut (*slot).cancel, 1);
4449 let tid = (*slot).tid;
4450 if tid > 0 {
4451 sys_tgkill(sys_getpid() as c_int, tid, SIGCANCEL);
4452 }
4453 0
4454}
4455#[no_mangle]
4456pub unsafe extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
4457 if state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE { return EINVAL; }
4458 if let Some(slot) = find_thread() {
4459 if !oldstate.is_null() { *oldstate = slot.cancel_state; }
4460 slot.cancel_state = state;
4461 0
4462 } else { EINVAL }
4463}
4464#[no_mangle]
4465pub unsafe extern "C" fn pthread_setcanceltype(type_: c_int, oldtype: *mut c_int) -> c_int {
4466 if type_ != PTHREAD_CANCEL_DEFERRED && type_ != PTHREAD_CANCEL_ASYNCHRONOUS { return EINVAL; }
4467 if let Some(slot) = find_thread() {
4468 if !oldtype.is_null() { *oldtype = slot.cancel_type; }
4469 slot.cancel_type = type_;
4470 0
4471 } else { EINVAL }
4472}
4473#[no_mangle]
4474pub unsafe extern "C" fn pthread_testcancel() {
4475 if let Some(slot) = find_thread() {
4476 if slot.cancel != 0 && slot.cancel_state == PTHREAD_CANCEL_ENABLE {
4477 do_cancel();
4478 }
4479 }
4480}
4481
4482#[no_mangle]
4483pub unsafe extern "C" fn _pthread_cleanup_push(cb: *mut __ptcb, f: Option<unsafe extern "C" fn(*mut c_void)>, x: *mut c_void) {
4484 (*cb).__f = f;
4485 (*cb).__x = x;
4486 if let Some(slot) = find_thread() {
4487 (*cb).__next = slot.cancelbuf;
4488 slot.cancelbuf = cb;
4489 } else {
4490 (*cb).__next = core::ptr::null_mut();
4491 }
4492}
4493
4494#[no_mangle]
4495pub unsafe extern "C" fn _pthread_cleanup_pop(cb: *mut __ptcb, run: c_int) {
4496 if let Some(slot) = find_thread() {
4497 slot.cancelbuf = (*cb).__next;
4498 }
4499 if run != 0 {
4500 if let Some(f) = (*cb).__f {
4501 f((*cb).__x);
4502 }
4503 }
4504}
4505
4506#[no_mangle]
4507pub unsafe extern "C" fn pthread_kill(thread: PthreadT, sig: c_int) -> c_int {
4508 let slot = thread as *mut Thread;
4509 if slot.is_null() { return EINVAL; }
4510 let tid = (*slot).tid;
4511 if tid <= 0 { return EINVAL; }
4512 if sys_tgkill(sys_getpid() as c_int, tid, sig) < 0 { -1 } else { 0 }
4513}
4514
4515#[no_mangle]
4516pub unsafe extern "C" fn pthread_sigmask(how: c_int, set: *const SigSetT, oldset: *mut SigSetT) -> c_int {
4517 sigprocmask(how, set, oldset)
4518}
4519
4520
4521#[repr(C)]
4522pub struct lconv {
4523 pub decimal_point: *mut c_char,
4524 pub thousands_sep: *mut c_char,
4525 pub grouping: *mut c_char,
4526 pub int_curr_symbol: *mut c_char,
4527 pub currency_symbol: *mut c_char,
4528 pub mon_decimal_point: *mut c_char,
4529 pub mon_thousands_sep: *mut c_char,
4530 pub mon_grouping: *mut c_char,
4531 pub positive_sign: *mut c_char,
4532 pub negative_sign: *mut c_char,
4533 pub int_frac_digits: c_char,
4534 pub frac_digits: c_char,
4535 pub p_cs_precedes: c_char,
4536 pub p_sep_by_space: c_char,
4537 pub n_cs_precedes: c_char,
4538 pub n_sep_by_space: c_char,
4539 pub p_sign_posn: c_char,
4540 pub n_sign_posn: c_char,
4541 pub int_p_cs_precedes: c_char,
4542 pub int_p_sep_by_space: c_char,
4543 pub int_n_cs_precedes: c_char,
4544 pub int_n_sep_by_space: c_char,
4545 pub int_p_sign_posn: c_char,
4546 pub int_n_sign_posn: c_char,
4547}
4548
4549static UTF8_NAME: [u8; 6] = [b'U', b'T', b'F', b'-', b'8', 0];
4550static C_NAME: [u8; 2] = [b'C', 0];
4551static mut LOCALE_NAME: *const c_char = C_NAME.as_ptr() as *const c_char;
4552static mut LOCALE_CTYPE_UTF8: bool = true;
4553static mut EMPTY_STR: [c_char; 1] = [0];
4554static mut DECIMAL_POINT: [c_char; 2] = [b'.' as c_char, 0];
4555static mut LCONV: lconv = lconv {
4556 decimal_point: core::ptr::null_mut(),
4557 thousands_sep: core::ptr::null_mut(),
4558 grouping: core::ptr::null_mut(),
4559 int_curr_symbol: core::ptr::null_mut(),
4560 currency_symbol: core::ptr::null_mut(),
4561 mon_decimal_point: core::ptr::null_mut(),
4562 mon_thousands_sep: core::ptr::null_mut(),
4563 mon_grouping: core::ptr::null_mut(),
4564 positive_sign: core::ptr::null_mut(),
4565 negative_sign: core::ptr::null_mut(),
4566 int_frac_digits: (-1i32) as c_char,
4567 frac_digits: (-1i32) as c_char,
4568 p_cs_precedes: (-1i32) as c_char,
4569 p_sep_by_space: (-1i32) as c_char,
4570 n_cs_precedes: (-1i32) as c_char,
4571 n_sep_by_space: (-1i32) as c_char,
4572 p_sign_posn: (-1i32) as c_char,
4573 n_sign_posn: (-1i32) as c_char,
4574 int_p_cs_precedes: (-1i32) as c_char,
4575 int_p_sep_by_space: (-1i32) as c_char,
4576 int_n_cs_precedes: (-1i32) as c_char,
4577 int_n_sep_by_space: (-1i32) as c_char,
4578 int_p_sign_posn: (-1i32) as c_char,
4579 int_n_sign_posn: (-1i32) as c_char,
4580};
4581
4582unsafe fn cstr_contains_ci(s: *const u8, needle: &[u8]) -> bool {
4583 let len = strlen(s as *const c_char) as usize;
4584 let s_slice = core::slice::from_raw_parts(s, len);
4585 if needle.len() > len { return false; }
4586 for i in 0..=len - needle.len() {
4587 if s_slice[i..i + needle.len()].eq_ignore_ascii_case(needle) {
4588 return true;
4589 }
4590 }
4591 false
4592}
4593
4594#[no_mangle]
4595pub unsafe extern "C" fn setlocale(_category: c_int, locale: *const c_char) -> *mut c_char {
4596 if locale.is_null() || *locale == 0 {
4597 return LOCALE_NAME as *mut c_char;
4598 }
4599 let name = locale as *const u8;
4600 if strcmp(name, b"C\0".as_ptr()) == 0 || strcmp(name, b"POSIX\0".as_ptr()) == 0 {
4601 LOCALE_CTYPE_UTF8 = false;
4602 return LOCALE_NAME as *mut c_char;
4603 }
4604 if cstr_contains_ci(name, b"UTF-8") || cstr_contains_ci(name, b"UTF8") {
4605 LOCALE_CTYPE_UTF8 = true;
4606 return LOCALE_NAME as *mut c_char;
4607 }
4608 core::ptr::null_mut()
4609}
4610
4611#[no_mangle]
4612pub unsafe extern "C" fn localeconv() -> *mut lconv {
4613 let empty = core::ptr::addr_of_mut!(EMPTY_STR) as *mut c_char;
4614 let lconv = core::ptr::addr_of_mut!(LCONV);
4615 (*lconv).decimal_point = core::ptr::addr_of_mut!(DECIMAL_POINT) as *mut c_char;
4616 (*lconv).thousands_sep = empty;
4617 (*lconv).grouping = empty;
4618 (*lconv).int_curr_symbol = empty;
4619 (*lconv).currency_symbol = empty;
4620 (*lconv).mon_decimal_point = empty;
4621 (*lconv).mon_thousands_sep = empty;
4622 (*lconv).mon_grouping = empty;
4623 (*lconv).positive_sign = empty;
4624 (*lconv).negative_sign = empty;
4625 lconv
4626}
4627
4628pub type locale_t = *mut c_void;
4629static mut CURRENT_LOCALE: locale_t = LC_GLOBAL_LOCALE;
4630
4631static mut C_LOCALE_STORAGE: c_int = 0;
4632const C_LOCALE: locale_t = core::ptr::addr_of_mut!(C_LOCALE_STORAGE) as locale_t;
4633const LC_GLOBAL_LOCALE: locale_t = usize::MAX as locale_t;
4634
4635#[no_mangle]
4636pub unsafe extern "C" fn newlocale(_mask: c_int, name: *const c_char, base: locale_t) -> locale_t {
4637 if !name.is_null() && *name != 0 {
4638 let n = name as *const u8;
4639 if strcmp(n, b"C\0".as_ptr()) != 0
4640 && strcmp(n, b"POSIX\0".as_ptr()) != 0
4641 {
4642 return core::ptr::null_mut();
4643 }
4644 }
4645 if base.is_null() || base == C_LOCALE || base == LC_GLOBAL_LOCALE {
4646 C_LOCALE
4647 } else {
4648 core::ptr::null_mut()
4649 }
4650}
4651
4652#[no_mangle]
4653pub unsafe extern "C" fn freelocale(_loc: locale_t) {}
4654
4655#[no_mangle]
4656pub unsafe extern "C" fn uselocale(loc: locale_t) -> locale_t {
4657 let old = CURRENT_LOCALE;
4658 if !loc.is_null() {
4659 CURRENT_LOCALE = loc;
4660 }
4661 old
4662}
4663
4664#[no_mangle]
4665pub unsafe extern "C" fn duplocale(loc: locale_t) -> locale_t {
4666 if loc.is_null() {
4667 return core::ptr::null_mut();
4668 }
4669 C_LOCALE
4670}
4671
4672const NL_ITEM_CODESET: c_int = 14;
4673const NL_ITEM_RADIXCHAR: c_int = 0x10000;
4674const NL_ITEM_THOUSEP: c_int = 0x10001;
4675const NL_ITEM_YESEXPR: c_int = 0x50000;
4676const NL_ITEM_NOEXPR: c_int = 0x50001;
4677
4678const C_TIME_STRINGS: &[u8] = b"Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0\
4679Sunday\0Monday\0Tuesday\0Wednesday\0Thursday\0Friday\0Saturday\0\
4680Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0\
4681January\0February\0March\0April\0May\0June\0July\0August\0\
4682September\0October\0November\0December\0\
4683AM\0PM\0\
4684%a %b %e %T %Y\0%m/%d/%y\0%H:%M:%S\0%I:%M:%S %p\0\
4685\0\0%m/%d/%y\00123456789\0%a %b %e %T %Y\0%H:%M:%S\0";
4686
4687const C_NUMERIC_STRINGS: &[u8] = b".\0\0";
4688const C_MESSAGES_STRINGS: &[u8] = b"^[yY]\0^[nN]\0";
4689
4690unsafe fn langinfo_str(table: *const u8, mut idx: c_int) -> *mut c_char {
4691 let mut p = table;
4692 while idx > 0 {
4693 while *p != 0 { p = p.add(1); }
4694 p = p.add(1);
4695 idx -= 1;
4696 }
4697 p as *mut c_char
4698}
4699
4700#[no_mangle]
4701pub unsafe extern "C" fn nl_langinfo(item: c_int) -> *mut c_char {
4702 if item == NL_ITEM_CODESET {
4703 return if LOCALE_CTYPE_UTF8 {
4704 b"UTF-8\0".as_ptr() as *mut c_char
4705 } else {
4706 b"US-ASCII\0".as_ptr() as *mut c_char
4707 };
4708 }
4709 let cat = item >> 16;
4710 let idx = item & 0xFFFF;
4711 match cat {
4712 1 => {
4713 if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
4714 langinfo_str(C_NUMERIC_STRINGS.as_ptr(), idx)
4715 }
4716 2 => {
4717 if idx > 49 { return b"\0".as_ptr() as *mut c_char; }
4718 langinfo_str(C_TIME_STRINGS.as_ptr(), idx)
4719 }
4720 5 => {
4721 if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
4722 langinfo_str(C_MESSAGES_STRINGS.as_ptr(), idx)
4723 }
4724 _ => b"\0".as_ptr() as *mut c_char,
4725 }
4726}
4727
4728pub type nl_catd = *mut c_void;
4729
4730#[no_mangle]
4731pub unsafe extern "C" fn catopen(_name: *const c_char, _oflag: c_int) -> nl_catd {
4732 !0usize as nl_catd
4733}
4734
4735#[no_mangle]
4736pub unsafe extern "C" fn catclose(_catd: nl_catd) -> c_int { 0 }
4737
4738#[no_mangle]
4739pub unsafe extern "C" fn catgets(catd: nl_catd, _set_id: c_int, _msg_id: c_int, s: *const c_char) -> *mut c_char {
4740 if catd == !0usize as nl_catd { return s as *mut c_char; }
4741 s as *mut c_char
4742}
4743
4744pub type IconvT = *mut c_void;
4745
4746const ENC_UTF8: i32 = 1;
4747const ENC_UTF16LE: i32 = 2;
4748const ENC_UTF16BE: i32 = 3;
4749const ENC_UTF32LE: i32 = 4;
4750const ENC_UTF32BE: i32 = 5;
4751const ENC_WCHAR_T: i32 = 6;
4752const ENC_ASCII: i32 = 7;
4753const ENC_LATIN1: i32 = 8;
4754const ENC_WIN1252: i32 = 9;
4755const ENC_WIN1251: i32 = 10;
4756const ENC_KOI8R: i32 = 11;
4757const ENC_GBK: i32 = 12;
4758const ENC_GB2312: i32 = 13;
4759const ENC_BIG5: i32 = 14;
4760const ENC_EUCJP: i32 = 15;
4761const ENC_SHIFTJIS: i32 = 16;
4762const ENC_ISO8859_2: i32 = 17;
4763const ENC_ISO8859_3: i32 = 18;
4764const ENC_ISO8859_4: i32 = 19;
4765const ENC_ISO8859_5: i32 = 20;
4766const ENC_ISO8859_6: i32 = 21;
4767const ENC_ISO8859_7: i32 = 22;
4768const ENC_ISO8859_8: i32 = 23;
4769const ENC_ISO8859_9: i32 = 24;
4770const ENC_ISO8859_10: i32 = 25;
4771const ENC_ISO8859_11: i32 = 26;
4772const ENC_ISO8859_13: i32 = 27;
4773const ENC_ISO8859_14: i32 = 28;
4774const ENC_ISO8859_15: i32 = 29;
4775const ENC_ISO8859_16: i32 = 30;
4776
4777include!("iconv_iso8859.rs");
4778
4779fn make_cd(from: i32, to: i32) -> IconvT {
4780 ((from as usize) << 16 | (to as usize) << 1 | 1) as IconvT
4781}
4782fn extract_from(cd: IconvT) -> i32 {
4783 ((cd as usize) >> 16) as i32
4784}
4785fn extract_to(cd: IconvT) -> i32 {
4786 (((cd as usize) >> 1) & 0x7fff) as i32
4787}
4788
4789unsafe fn match_name(input: *const u8, target: &[u8]) -> bool {
4790 let mut i = input;
4791 let mut j = 0;
4792 while *i != 0 && j < target.len() {
4793 let mut c = *i;
4794 if !c.is_ascii_alphanumeric() { i = i.add(1); continue; }
4795 c = c.to_ascii_lowercase();
4796 if c != target[j] { return false; }
4797 i = i.add(1);
4798 j += 1;
4799 }
4800 while *i != 0 && !(*i).is_ascii_alphanumeric() { i = i.add(1); }
4801 *i == 0 && j == target.len()
4802}
4803
4804unsafe fn find_encoding(name: *const u8) -> i32 {
4805 if name.is_null() { return -1; }
4806 if match_name(name, b"utf8") || match_name(name, b"utf-8") || match_name(name, b"char") { return ENC_UTF8; }
4807 if match_name(name, b"utf16le") || match_name(name, b"utf-16le") { return ENC_UTF16LE; }
4808 if match_name(name, b"utf16be") || match_name(name, b"utf-16be") { return ENC_UTF16BE; }
4809 if match_name(name, b"utf32le") || match_name(name, b"utf-32le") || match_name(name, b"ucs4le") { return ENC_UTF32LE; }
4810 if match_name(name, b"utf32be") || match_name(name, b"utf-32be") || match_name(name, b"ucs4be") { return ENC_UTF32BE; }
4811 if match_name(name, b"wchart") || match_name(name, b"wchar-t") { return ENC_WCHAR_T; }
4812 if match_name(name, b"ascii") || match_name(name, b"usascii") || match_name(name, b"iso646") { return ENC_ASCII; }
4813 if match_name(name, b"iso88591") || match_name(name, b"iso-8859-1") || match_name(name, b"latin1") { return ENC_LATIN1; }
4814 if match_name(name, b"iso88592") || match_name(name, b"iso-8859-2") { return ENC_ISO8859_2; }
4815 if match_name(name, b"iso88593") || match_name(name, b"iso-8859-3") { return ENC_ISO8859_3; }
4816 if match_name(name, b"iso88594") || match_name(name, b"iso-8859-4") { return ENC_ISO8859_4; }
4817 if match_name(name, b"iso88595") || match_name(name, b"iso-8859-5") { return ENC_ISO8859_5; }
4818 if match_name(name, b"iso88596") || match_name(name, b"iso-8859-6") { return ENC_ISO8859_6; }
4819 if match_name(name, b"iso88597") || match_name(name, b"iso-8859-7") { return ENC_ISO8859_7; }
4820 if match_name(name, b"iso88598") || match_name(name, b"iso-8859-8") { return ENC_ISO8859_8; }
4821 if match_name(name, b"iso88599") || match_name(name, b"iso-8859-9") { return ENC_ISO8859_9; }
4822 if match_name(name, b"iso885910") || match_name(name, b"iso-8859-10") { return ENC_ISO8859_10; }
4823 if match_name(name, b"iso885911") || match_name(name, b"iso-8859-11") || match_name(name, b"tis620") { return ENC_ISO8859_11; }
4824 if match_name(name, b"iso885913") || match_name(name, b"iso-8859-13") { return ENC_ISO8859_13; }
4825 if match_name(name, b"iso885914") || match_name(name, b"iso-8859-14") { return ENC_ISO8859_14; }
4826 if match_name(name, b"iso885915") || match_name(name, b"iso-8859-15") { return ENC_ISO8859_15; }
4827 if match_name(name, b"iso885916") || match_name(name, b"iso-8859-16") { return ENC_ISO8859_16; }
4828 if match_name(name, b"cp1252") || match_name(name, b"windows1252") || match_name(name, b"windows-1252") { return ENC_WIN1252; }
4829 if match_name(name, b"cp1251") || match_name(name, b"windows1251") || match_name(name, b"windows-1251") { return ENC_WIN1251; }
4830 if match_name(name, b"koi8r") || match_name(name, b"koi8-r") { return ENC_KOI8R; }
4831 if match_name(name, b"gbk") || match_name(name, b"cp936") { return ENC_GBK; }
4832 if match_name(name, b"gb2312") { return ENC_GB2312; }
4833 if match_name(name, b"big5") || match_name(name, b"bigfive") || match_name(name, b"cp950") { return ENC_BIG5; }
4834 if match_name(name, b"eucjp") || match_name(name, b"euc-jp") { return ENC_EUCJP; }
4835 if match_name(name, b"shiftjis") || match_name(name, b"sjis") || match_name(name, b"cp932") { return ENC_SHIFTJIS; }
4836 -1
4837}
4838
4839fn uni_to_jis(c: u32) -> u16 {
4840 let mut b = 0usize;
4841 let mut nel = REV_JIS.len();
4842 loop {
4843 let i = nel / 2;
4844 let j = REV_JIS[b + i] as usize;
4845 let row = j / 256;
4846 let col = j % 256;
4847 let d = JIS0208[row * 94 + col] as u32;
4848 if d == c { return (j as u16) + 0x2121; }
4849 if nel == 1 { return 0; }
4850 if c < d { nel /= 2; }
4851 else { b += i; nel -= nel / 2; }
4852 }
4853}
4854
4855unsafe fn iconv_decode(enc: i32, src: *const u8, src_left: usize) -> (u32, usize, c_int) {
4856 if src_left == 0 { return (0, 0, EINVAL); }
4857 match enc {
4858 ENC_UTF8 => {
4859 let c = *src;
4860 if c < 128 { return (c as u32, 1, 0); }
4861 if c < 0xC2 { return (0, 0, EILSEQ); }
4862 if c < 0xE0 {
4863 if src_left < 2 || (*src.add(1) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4864 return (((c as u32 & 0x1F) << 6) | (*src.add(1) as u32 & 0x3F), 2, 0);
4865 }
4866 if c < 0xF0 {
4867 if src_left < 3 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4868 let cp = ((c as u32 & 0x0F) << 12) | ((*src.add(1) as u32 & 0x3F) << 6) | (*src.add(2) as u32 & 0x3F);
4869 if cp < 0x800 { return (0, 0, EILSEQ); }
4870 return (cp, 3, 0);
4871 }
4872 if c < 0xF8 {
4873 if src_left < 4 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 || (*src.add(3) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4874 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);
4875 if cp < 0x10000 || cp >= 0x110000 { return (0, 0, EILSEQ); }
4876 return (cp, 4, 0);
4877 }
4878 (0, 0, EILSEQ)
4879 }
4880 ENC_UTF16LE => {
4881 if src_left < 2 { return (0, 0, EINVAL); }
4882 let c = (*src as u32) | ((*src.add(1) as u32) << 8);
4883 if c >= 0xD800 && c <= 0xDBFF {
4884 if src_left < 4 { return (0, 0, EINVAL); }
4885 let d = (*src.add(2) as u32) | ((*src.add(3) as u32) << 8);
4886 if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
4887 return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
4888 }
4889 if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
4890 (c, 2, 0)
4891 }
4892 ENC_UTF16BE => {
4893 if src_left < 2 { return (0, 0, EINVAL); }
4894 let c = ((*src as u32) << 8) | (*src.add(1) as u32);
4895 if c >= 0xD800 && c <= 0xDBFF {
4896 if src_left < 4 { return (0, 0, EINVAL); }
4897 let d = ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
4898 if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
4899 return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
4900 }
4901 if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
4902 (c, 2, 0)
4903 }
4904 ENC_UTF32LE => {
4905 if src_left < 4 { return (0, 0, EINVAL); }
4906 let c = (*src as u32) | ((*src.add(1) as u32) << 8) | ((*src.add(2) as u32) << 16) | ((*src.add(3) as u32) << 24);
4907 if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
4908 if c >= 0x110000 { return (0, 0, EILSEQ); }
4909 (c, 4, 0)
4910 }
4911 ENC_UTF32BE => {
4912 if src_left < 4 { return (0, 0, EINVAL); }
4913 let c = ((*src as u32) << 24) | ((*src.add(1) as u32) << 16) | ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
4914 if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
4915 if c >= 0x110000 { return (0, 0, EILSEQ); }
4916 (c, 4, 0)
4917 }
4918 ENC_WCHAR_T => {
4919 if src_left < 4 { return (0, 0, EINVAL); }
4920 let c = *(src as *const u32);
4921 if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
4922 if c >= 0x110000 { return (0, 0, EILSEQ); }
4923 (c, 4, 0)
4924 }
4925 ENC_ASCII => {
4926 let c = *src as u32;
4927 if c >= 128 { return (0, 0, EILSEQ); }
4928 (c, 1, 0)
4929 }
4930 ENC_LATIN1 => (*src as u32, 1, 0),
4931 ENC_ISO8859_2 => (iso8859_to_u(&ISO8859_2_TO_U, *src), 1, 0),
4932 ENC_ISO8859_3 => (iso8859_to_u(&ISO8859_3_TO_U, *src), 1, 0),
4933 ENC_ISO8859_4 => (iso8859_to_u(&ISO8859_4_TO_U, *src), 1, 0),
4934 ENC_ISO8859_5 => (iso8859_to_u(&ISO8859_5_TO_U, *src), 1, 0),
4935 ENC_ISO8859_6 => (iso8859_to_u(&ISO8859_6_TO_U, *src), 1, 0),
4936 ENC_ISO8859_7 => (iso8859_to_u(&ISO8859_7_TO_U, *src), 1, 0),
4937 ENC_ISO8859_8 => (iso8859_to_u(&ISO8859_8_TO_U, *src), 1, 0),
4938 ENC_ISO8859_9 => (iso8859_to_u(&ISO8859_9_TO_U, *src), 1, 0),
4939 ENC_ISO8859_10 => (iso8859_to_u(&ISO8859_10_TO_U, *src), 1, 0),
4940 ENC_ISO8859_11 => (iso8859_to_u(&ISO8859_11_TO_U, *src), 1, 0),
4941 ENC_ISO8859_13 => (iso8859_to_u(&ISO8859_13_TO_U, *src), 1, 0),
4942 ENC_ISO8859_14 => (iso8859_to_u(&ISO8859_14_TO_U, *src), 1, 0),
4943 ENC_ISO8859_15 => (iso8859_to_u(&ISO8859_15_TO_U, *src), 1, 0),
4944 ENC_ISO8859_16 => (iso8859_to_u(&ISO8859_16_TO_U, *src), 1, 0),
4945 ENC_WIN1252 => {
4946 let b = *src;
4947 if b < 128 { return (b as u32, 1, 0); }
4948 (WIN1252_TO_U[b as usize - 128], 1, 0)
4949 }
4950 ENC_WIN1251 => {
4951 let b = *src;
4952 if b < 128 { return (b as u32, 1, 0); }
4953 (WIN1251_TO_U[b as usize - 128], 1, 0)
4954 }
4955 ENC_KOI8R => {
4956 let b = *src;
4957 if b < 128 { return (b as u32, 1, 0); }
4958 (KOI8R_TO_U[b as usize - 128], 1, 0)
4959 }
4960 ENC_GBK | ENC_GB2312 => {
4961 let c = *src;
4962 if c < 128 { return (c as u32, 1, 0); }
4963 if c == 128 { return (0x20AC, 1, 0); }
4964 if src_left < 2 { return (0, 0, EINVAL); }
4965 let d = *src.add(1);
4966 if d < 0x40 || d == 0x7F || d > 0xFE { return (0, 0, EILSEQ); }
4967 let row = (c as usize).wrapping_sub(0x81);
4968 if row >= 126 { return (0, 0, EILSEQ); }
4969 let mut col = (d as usize) - 0x40;
4970 if col > 63 { col -= 1; }
4971 let cp = GB18030_TABLE[row * 190 + col] as u32;
4972 if cp == 0 { return (0, 0, EILSEQ); }
4973 (cp, 2, 0)
4974 }
4975 ENC_BIG5 => {
4976 let c = *src;
4977 if c < 128 { return (c as u32, 1, 0); }
4978 if src_left < 2 { return (0, 0, EINVAL); }
4979 let d = *src.add(1);
4980 if d < 0x40 || d == 0x7F || d > 0xFE { return (0, 0, EILSEQ); }
4981 let mut col = (d as usize) - 0x40;
4982 if col > 0x3E { col -= 0x22; }
4983 if c >= 0xA1 && c < 0xFA {
4984 let row = (c as usize) - 0xA1;
4985 if row >= 89 { return (0, 0, EILSEQ); }
4986 let cp = BIG5_TABLE[row * 157 + col] as u32;
4987 if cp == 0 { return (0, 0, EILSEQ); }
4988 return (cp, 2, 0);
4989 }
4990 (0, 0, EILSEQ)
4991 }
4992 ENC_EUCJP => {
4993 let c = *src;
4994 if c < 128 { return (c as u32, 1, 0); }
4995 if c == 0x8E {
4996 if src_left < 2 { return (0, 0, EINVAL); }
4997 let d = *src.add(1);
4998 if d < 0xA1 || d > 0xDF { return (0, 0, EILSEQ); }
4999 return ((d as u32) + 0xFF61 - 0xA1, 2, 0);
5000 }
5001 if c < 0xA1 { return (0, 0, EILSEQ); }
5002 if src_left < 2 { return (0, 0, EINVAL); }
5003 let d = *src.add(1);
5004 if d < 0xA1 || d > 0xFE { return (0, 0, EILSEQ); }
5005 let row = (c as usize) - 0xA1;
5006 let col = (d as usize) - 0xA1;
5007 if row >= 84 || col >= 94 { return (0, 0, EILSEQ); }
5008 let cp = JIS0208[row * 94 + col] as u32;
5009 if cp == 0 { return (0, 0, EILSEQ); }
5010 (cp, 2, 0)
5011 }
5012 ENC_SHIFTJIS => {
5013 let c = *src;
5014 if c < 128 { return (c as u32, 1, 0); }
5015 if c >= 0xA1 && c <= 0xDF { return ((c as u32) + 0xFF61 - 0xA1, 1, 0); }
5016 if src_left < 2 { return (0, 0, EINVAL); }
5017 let d = *src.add(1);
5018 if d < 0x40 || d == 0x7F || d > 0xFC { return (0, 0, EILSEQ); }
5019 let row = if c >= 129 && c <= 159 { (c as usize) - 129 }
5020 else if c >= 224 && c <= 239 { (c as usize) - 193 }
5021 else { return (0, 0, EILSEQ); };
5022 let (col, row_adj) = if d >= 64 && d <= 158 && d != 127 {
5023 let mut dd = d as usize;
5024 if dd > 127 { dd -= 1; }
5025 (dd - 64, row * 2)
5026 } else if d >= 159 && d <= 252 {
5027 ((d as usize) - 159, row * 2 + 1)
5028 } else {
5029 return (0, 0, EILSEQ);
5030 };
5031 if row_adj >= 84 { return (0, 0, EILSEQ); }
5032 let cp = JIS0208[row_adj * 94 + col] as u32;
5033 if cp == 0 { return (0, 0, EILSEQ); }
5034 (cp, 2, 0)
5035 }
5036 _ => (0, 0, EILSEQ),
5037 }
5038}
5039
5040unsafe fn iconv_encode(enc: i32, c: u32, dst: *mut u8, dst_left: usize) -> (usize, c_int) {
5041 match enc {
5042 ENC_UTF8 => {
5043 if c < 0x80 {
5044 if dst_left < 1 { return (0, E2BIG); }
5045 *dst = c as u8; return (1, 0);
5046 }
5047 if c < 0x800 {
5048 if dst_left < 2 { return (0, E2BIG); }
5049 *dst = (0xC0 | (c >> 6)) as u8;
5050 *dst.add(1) = (0x80 | (c & 0x3F)) as u8;
5051 return (2, 0);
5052 }
5053 if c < 0x10000 {
5054 if dst_left < 3 { return (0, E2BIG); }
5055 *dst = (0xE0 | (c >> 12)) as u8;
5056 *dst.add(1) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5057 *dst.add(2) = (0x80 | (c & 0x3F)) as u8;
5058 return (3, 0);
5059 }
5060 if dst_left < 4 { return (0, E2BIG); }
5061 *dst = (0xF0 | (c >> 18)) as u8;
5062 *dst.add(1) = (0x80 | ((c >> 12) & 0x3F)) as u8;
5063 *dst.add(2) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5064 *dst.add(3) = (0x80 | (c & 0x3F)) as u8;
5065 (4, 0)
5066 }
5067 ENC_UTF16LE => {
5068 if c < 0x10000 {
5069 if dst_left < 2 { return (0, E2BIG); }
5070 *dst = (c & 0xFF) as u8;
5071 *dst.add(1) = (c >> 8) as u8;
5072 return (2, 0);
5073 }
5074 if dst_left < 4 { return (0, E2BIG); }
5075 let c = c - 0x10000;
5076 let hi = ((c >> 10) + 0xD800) as u16;
5077 let lo = ((c & 0x3FF) + 0xDC00) as u16;
5078 *dst = (hi & 0xFF) as u8; *dst.add(1) = (hi >> 8) as u8;
5079 *dst.add(2) = (lo & 0xFF) as u8; *dst.add(3) = (lo >> 8) as u8;
5080 (4, 0)
5081 }
5082 ENC_UTF16BE => {
5083 if c < 0x10000 {
5084 if dst_left < 2 { return (0, E2BIG); }
5085 *dst = (c >> 8) as u8;
5086 *dst.add(1) = (c & 0xFF) as u8;
5087 return (2, 0);
5088 }
5089 if dst_left < 4 { return (0, E2BIG); }
5090 let c = c - 0x10000;
5091 let hi = ((c >> 10) + 0xD800) as u16;
5092 let lo = ((c & 0x3FF) + 0xDC00) as u16;
5093 *dst = (hi >> 8) as u8; *dst.add(1) = (hi & 0xFF) as u8;
5094 *dst.add(2) = (lo >> 8) as u8; *dst.add(3) = (lo & 0xFF) as u8;
5095 (4, 0)
5096 }
5097 ENC_UTF32LE => {
5098 if dst_left < 4 { return (0, E2BIG); }
5099 *dst = (c & 0xFF) as u8; *dst.add(1) = ((c >> 8) & 0xFF) as u8;
5100 *dst.add(2) = ((c >> 16) & 0xFF) as u8; *dst.add(3) = (c >> 24) as u8;
5101 (4, 0)
5102 }
5103 ENC_UTF32BE => {
5104 if dst_left < 4 { return (0, E2BIG); }
5105 *dst = (c >> 24) as u8; *dst.add(1) = ((c >> 16) & 0xFF) as u8;
5106 *dst.add(2) = ((c >> 8) & 0xFF) as u8; *dst.add(3) = (c & 0xFF) as u8;
5107 (4, 0)
5108 }
5109 ENC_WCHAR_T => {
5110 if dst_left < 4 { return (0, E2BIG); }
5111 *(dst as *mut u32) = c;
5112 (4, 0)
5113 }
5114 ENC_ASCII => {
5115 if c < 128 {
5116 if dst_left < 1 { return (0, E2BIG); }
5117 *dst = c as u8; return (1, 0);
5118 }
5119 (0, EILSEQ)
5120 }
5121 ENC_LATIN1 => {
5122 if c < 256 {
5123 if dst_left < 1 { return (0, E2BIG); }
5124 *dst = c as u8; return (1, 0);
5125 }
5126 (0, EILSEQ)
5127 }
5128 ENC_ISO8859_2 => {
5129 if let Some(b) = u_to_iso8859(&ISO8859_2_TO_U, c) {
5130 if dst_left < 1 { return (0, E2BIG); }
5131 *dst = b; return (1, 0);
5132 }
5133 (0, EILSEQ)
5134 }
5135 ENC_ISO8859_3 => {
5136 if let Some(b) = u_to_iso8859(&ISO8859_3_TO_U, c) {
5137 if dst_left < 1 { return (0, E2BIG); }
5138 *dst = b; return (1, 0);
5139 }
5140 (0, EILSEQ)
5141 }
5142 ENC_ISO8859_4 => {
5143 if let Some(b) = u_to_iso8859(&ISO8859_4_TO_U, c) {
5144 if dst_left < 1 { return (0, E2BIG); }
5145 *dst = b; return (1, 0);
5146 }
5147 (0, EILSEQ)
5148 }
5149 ENC_ISO8859_5 => {
5150 if let Some(b) = u_to_iso8859(&ISO8859_5_TO_U, c) {
5151 if dst_left < 1 { return (0, E2BIG); }
5152 *dst = b; return (1, 0);
5153 }
5154 (0, EILSEQ)
5155 }
5156 ENC_ISO8859_6 => {
5157 if let Some(b) = u_to_iso8859(&ISO8859_6_TO_U, c) {
5158 if dst_left < 1 { return (0, E2BIG); }
5159 *dst = b; return (1, 0);
5160 }
5161 (0, EILSEQ)
5162 }
5163 ENC_ISO8859_7 => {
5164 if let Some(b) = u_to_iso8859(&ISO8859_7_TO_U, c) {
5165 if dst_left < 1 { return (0, E2BIG); }
5166 *dst = b; return (1, 0);
5167 }
5168 (0, EILSEQ)
5169 }
5170 ENC_ISO8859_8 => {
5171 if let Some(b) = u_to_iso8859(&ISO8859_8_TO_U, c) {
5172 if dst_left < 1 { return (0, E2BIG); }
5173 *dst = b; return (1, 0);
5174 }
5175 (0, EILSEQ)
5176 }
5177 ENC_ISO8859_9 => {
5178 if let Some(b) = u_to_iso8859(&ISO8859_9_TO_U, c) {
5179 if dst_left < 1 { return (0, E2BIG); }
5180 *dst = b; return (1, 0);
5181 }
5182 (0, EILSEQ)
5183 }
5184 ENC_ISO8859_10 => {
5185 if let Some(b) = u_to_iso8859(&ISO8859_10_TO_U, c) {
5186 if dst_left < 1 { return (0, E2BIG); }
5187 *dst = b; return (1, 0);
5188 }
5189 (0, EILSEQ)
5190 }
5191 ENC_ISO8859_11 => {
5192 if let Some(b) = u_to_iso8859(&ISO8859_11_TO_U, c) {
5193 if dst_left < 1 { return (0, E2BIG); }
5194 *dst = b; return (1, 0);
5195 }
5196 (0, EILSEQ)
5197 }
5198 ENC_ISO8859_13 => {
5199 if let Some(b) = u_to_iso8859(&ISO8859_13_TO_U, c) {
5200 if dst_left < 1 { return (0, E2BIG); }
5201 *dst = b; return (1, 0);
5202 }
5203 (0, EILSEQ)
5204 }
5205 ENC_ISO8859_14 => {
5206 if let Some(b) = u_to_iso8859(&ISO8859_14_TO_U, c) {
5207 if dst_left < 1 { return (0, E2BIG); }
5208 *dst = b; return (1, 0);
5209 }
5210 (0, EILSEQ)
5211 }
5212 ENC_ISO8859_15 => {
5213 if let Some(b) = u_to_iso8859(&ISO8859_15_TO_U, c) {
5214 if dst_left < 1 { return (0, E2BIG); }
5215 *dst = b; return (1, 0);
5216 }
5217 (0, EILSEQ)
5218 }
5219 ENC_ISO8859_16 => {
5220 if let Some(b) = u_to_iso8859(&ISO8859_16_TO_U, c) {
5221 if dst_left < 1 { return (0, E2BIG); }
5222 *dst = b; return (1, 0);
5223 }
5224 (0, EILSEQ)
5225 }
5226 ENC_WIN1252 => {
5227 if c < 128 {
5228 if dst_left < 1 { return (0, E2BIG); }
5229 *dst = c as u8; return (1, 0);
5230 }
5231 if c >= 0xA0 && c <= 0xFF && WIN1252_TO_U[c as usize - 128] == c {
5232 if dst_left < 1 { return (0, E2BIG); }
5233 *dst = c as u8; return (1, 0);
5234 }
5235 for i in 0..128usize {
5236 if WIN1252_TO_U[i] == c {
5237 if dst_left < 1 { return (0, E2BIG); }
5238 *dst = (i + 128) as u8; return (1, 0);
5239 }
5240 }
5241 (0, EILSEQ)
5242 }
5243 ENC_WIN1251 => {
5244 if c < 128 {
5245 if dst_left < 1 { return (0, E2BIG); }
5246 *dst = c as u8; return (1, 0);
5247 }
5248 for i in 0..128usize {
5249 if WIN1251_TO_U[i] == c {
5250 if dst_left < 1 { return (0, E2BIG); }
5251 *dst = (i + 128) as u8; return (1, 0);
5252 }
5253 }
5254 (0, EILSEQ)
5255 }
5256 ENC_KOI8R => {
5257 if c < 128 {
5258 if dst_left < 1 { return (0, E2BIG); }
5259 *dst = c as u8; return (1, 0);
5260 }
5261 for i in 0..128usize {
5262 if KOI8R_TO_U[i] == c {
5263 if dst_left < 1 { return (0, E2BIG); }
5264 *dst = (i + 128) as u8; return (1, 0);
5265 }
5266 }
5267 (0, EILSEQ)
5268 }
5269 ENC_GBK | ENC_GB2312 => {
5270 if c < 128 {
5271 if dst_left < 1 { return (0, E2BIG); }
5272 *dst = c as u8; return (1, 0);
5273 }
5274 if c == 0x20AC {
5275 if dst_left < 1 { return (0, E2BIG); }
5276 *dst = 128; return (1, 0);
5277 }
5278 for row in 0..126usize {
5279 for col in 0..190usize {
5280 if GB18030_TABLE[row * 190 + col] as u32 == c {
5281 if dst_left < 2 { return (0, E2BIG); }
5282 *dst = (row + 0x81) as u8;
5283 *dst.add(1) = if col <= 62 { (col + 0x40) as u8 } else { (col + 0x41) as u8 };
5284 return (2, 0);
5285 }
5286 }
5287 }
5288 (0, EILSEQ)
5289 }
5290 ENC_BIG5 => {
5291 if c < 128 {
5292 if dst_left < 1 { return (0, E2BIG); }
5293 *dst = c as u8; return (1, 0);
5294 }
5295 for row in 0..89usize {
5296 for col in 0..157usize {
5297 if BIG5_TABLE[row * 157 + col] as u32 == c {
5298 if dst_left < 2 { return (0, E2BIG); }
5299 *dst = (row + 0xA1) as u8;
5300 *dst.add(1) = if col <= 0x3E { (col + 0x40) as u8 } else { (col + 0x62) as u8 };
5301 return (2, 0);
5302 }
5303 }
5304 }
5305 (0, EILSEQ)
5306 }
5307 ENC_EUCJP => {
5308 if c < 128 {
5309 if dst_left < 1 { return (0, E2BIG); }
5310 *dst = c as u8; return (1, 0);
5311 }
5312 if c >= 0xFF61 && c <= 0xFF9F {
5313 if dst_left < 2 { return (0, E2BIG); }
5314 *dst = 0x8E;
5315 *dst.add(1) = (c - 0xFF61 + 0xA1) as u8;
5316 return (2, 0);
5317 }
5318 let jis = uni_to_jis(c);
5319 if jis == 0 { return (0, EILSEQ); }
5320 if dst_left < 2 { return (0, E2BIG); }
5321 *dst = ((jis >> 8) as u8).wrapping_add(0x80);
5322 *dst.add(1) = ((jis & 0xFF) as u8).wrapping_add(0x80);
5323 (2, 0)
5324 }
5325 ENC_SHIFTJIS => {
5326 if c < 128 {
5327 if dst_left < 1 { return (0, E2BIG); }
5328 *dst = c as u8; return (1, 0);
5329 }
5330 if c >= 0xFF61 && c <= 0xFF9F {
5331 if dst_left < 1 { return (0, E2BIG); }
5332 *dst = (c - 0xFF61 + 0xA1) as u8;
5333 return (1, 0);
5334 }
5335 let jis = uni_to_jis(c);
5336 if jis == 0 { return (0, EILSEQ); }
5337 if dst_left < 2 { return (0, E2BIG); }
5338 let r = (jis >> 8) as usize;
5339 let d = (jis & 0xFF) as usize;
5340 *dst = ((r + 1) / 2 + if r < 95 { 112 } else { 176 }) as u8;
5341 *dst.add(1) = if r % 2 == 1 { (d + 31 + d / 96) as u8 } else { (d + 126) as u8 };
5342 (2, 0)
5343 }
5344 _ => (0, EILSEQ),
5345 }
5346}
5347
5348#[no_mangle]
5349pub unsafe extern "C" fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> IconvT {
5350 let to = find_encoding(tocode as *const u8);
5351 let from = find_encoding(fromcode as *const u8);
5352 if to < 0 || from < 0 {
5353 ERRNO = EINVAL;
5354 return !0usize as IconvT;
5355 }
5356 make_cd(from, to)
5357}
5358
5359#[no_mangle]
5360pub unsafe extern "C" fn iconv(
5361 cd: IconvT,
5362 inbuf: *mut *mut c_char,
5363 inbytesleft: *mut SizeT,
5364 outbuf: *mut *mut c_char,
5365 outbytesleft: *mut SizeT,
5366) -> SizeT {
5367 if cd == !0usize as IconvT {
5368 ERRNO = EINVAL;
5369 return !0usize;
5370 }
5371 if inbuf.is_null() || outbuf.is_null() { return 0; }
5372 let from = extract_from(cd);
5373 let to = extract_to(cd);
5374 let mut src = *inbuf as *const u8;
5375 let mut dst = *outbuf as *mut u8;
5376 let mut src_left = *inbytesleft;
5377 let mut dst_left = *outbytesleft;
5378 let mut subst = 0usize;
5379 while src_left > 0 {
5380 let (cp, consumed, err) = iconv_decode(from, src, src_left);
5381 if err != 0 {
5382 if err == EINVAL { break; }
5383 ERRNO = err;
5384 return !0usize;
5385 }
5386 let (written, err) = iconv_encode(to, cp, dst, dst_left);
5387 if err != 0 {
5388 if err == E2BIG {
5389 ERRNO = E2BIG;
5390 return !0usize;
5391 }
5392 if dst_left < 1 {
5393 ERRNO = E2BIG;
5394 return !0usize;
5395 }
5396 *dst = b'*';
5397 dst = dst.add(1);
5398 dst_left -= 1;
5399 subst += 1;
5400 } else {
5401 dst = dst.add(written);
5402 dst_left -= written;
5403 }
5404 src = src.add(consumed);
5405 src_left -= consumed;
5406 }
5407 *inbuf = src as *mut c_char;
5408 *outbuf = dst as *mut c_char;
5409 *inbytesleft = src_left;
5410 *outbytesleft = dst_left;
5411 subst
5412}
5413
5414#[no_mangle]
5415pub unsafe extern "C" fn iconv_close(_cd: IconvT) -> c_int { 0 }
5416
5417#[no_mangle]
5422pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: SizeT) -> SSizeT {
5423 sys_write(fd as i64, buf as *const u8, count) as SSizeT
5424}
5425
5426#[no_mangle]
5427pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: SizeT) -> SSizeT {
5428 sys_read(fd as i64, buf as *mut u8, count) as SSizeT
5429}
5430
5431#[no_mangle]
5432pub unsafe extern "C" fn open(path: *const c_char, flags: c_int, mode: c_int) -> c_int {
5433 sys_open(path as *const u8, flags as i64, mode as i64) as c_int
5434}
5435
5436#[no_mangle]
5437pub unsafe extern "C" fn close(fd: c_int) -> c_int {
5438 sys_close(fd as i64);
5439 0
5440}
5441
5442#[no_mangle]
5443pub unsafe extern "C" fn lseek(fd: c_int, offset: i64, whence: c_int) -> i64 {
5444 sys_lseek(fd as i64, offset, whence as i64)
5445}
5446
5447const O_RDONLY: i32 = 0;
5452const O_WRONLY: i32 = 1;
5453const O_RDWR: i32 = 2;
5454const O_CREAT: i32 = 64;
5455const O_TRUNC: i32 = 512;
5456const O_APPEND: i32 = 1024;
5457const O_EXCL: i32 = 128;
5458const O_NONBLOCK: i32 = 2048;
5459const O_NOFOLLOW: i32 = 0x40000;
5460const O_CLOEXEC: i32 = 0x80000;
5461
5462const F_GETFD: i32 = 1;
5463const F_SETFD: i32 = 2;
5464const F_GETFL: i32 = 3;
5465const F_SETFL: i32 = 4;
5466const F_GETLK: i32 = 5;
5467const F_SETLK: i32 = 6;
5468const F_SETLKW: i32 = 7;
5469const F_DUPFD: i32 = 0;
5470const F_DUPFD_CLOEXEC: i32 = 1030;
5471const FD_CLOEXEC: i32 = 1;
5472
5473const TIOCGWINSZ: u32 = 0x5413;
5474
5475#[repr(C)]
5476struct winsize {
5477 ws_row: u16,
5478 ws_col: u16,
5479 ws_xpixel: u16,
5480 ws_ypixel: u16,
5481}
5482
5483#[inline]
5484unsafe fn sys_pipe2(fds: *mut c_int, flags: i32) -> i64 {
5485 <Arch as Syscalls>::syscall2(SYS_PIPE2, fds as i64, flags as i64)
5486}
5487
5488#[inline]
5489unsafe fn sys_dup3(oldfd: i32, newfd: i32, flags: i32) -> i64 {
5490 <Arch as Syscalls>::syscall3(SYS_DUP3, oldfd as i64, newfd as i64, flags as i64)
5491}
5492
5493#[inline]
5494unsafe fn sys_fcntl(fd: i32, cmd: i32, arg: i64) -> i64 {
5495 <Arch as Syscalls>::syscall3(SYS_FCNTL, fd as i64, cmd as i64, arg as i64)
5496}
5497
5498#[inline]
5499unsafe fn sys_ioctl(fd: c_int, request: u32, arg: *mut u8) -> i64 {
5500 <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, request as i64, arg as i64)
5501}
5502
5503#[inline]
5504unsafe fn sys_unlinkat(dirfd: i32, path: *const u8, flags: i32) -> i64 {
5505 <Arch as Syscalls>::syscall3(SYS_UNLINKAT, dirfd as i64, path as i64, flags as i64)
5506}
5507
5508#[inline]
5509unsafe fn sys_renameat2(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: u32) -> i64 {
5510 <Arch as Syscalls>::syscall5(SYS_RENAMEAT2, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
5511}
5512
5513const UNGET: usize = 8;
5518const F_PERM: u32 = 1;
5519const F_NORD: u32 = 4;
5520const F_NOWR: u32 = 8;
5521const F_EOF: u32 = 16;
5522const F_ERR: u32 = 32;
5523const F_SVB: u32 = 64;
5524const F_APP: u32 = 128;
5525
5526const BUFSIZ: usize = 1024;
5527
5528const _IOFBF: c_int = 0;
5529const _IOLBF: c_int = 1;
5530const _IONBF: c_int = 2;
5531
5532const SEEK_SET: c_int = 0;
5533const SEEK_CUR: c_int = 1;
5534const SEEK_END: c_int = 2;
5535
5536#[repr(C)]
5538pub struct FILE {
5539 flags: c_uint,
5540 rpos: *mut u8,
5541 rend: *mut u8,
5542 close: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
5543 wend: *mut u8,
5544 wpos: *mut u8,
5545 mustbezero_1: *mut u8,
5546 wbase: *mut u8,
5547 read_fn: Option<unsafe extern "C" fn(*mut FILE, *mut u8, usize) -> usize>,
5548 write_fn: Option<unsafe extern "C" fn(*mut FILE, *const u8, usize) -> usize>,
5549 seek_fn: Option<unsafe extern "C" fn(*mut FILE, i64, c_int) -> i64>,
5550 buf: *mut u8,
5551 buf_size: usize,
5552 prev: *mut FILE,
5553 next: *mut FILE,
5554 fd: c_int,
5555 pipe_pid: c_int,
5556 lockcount: c_long,
5557 mode: c_int,
5558 lock: c_int,
5559 lbf: c_int,
5560 cookie: *mut c_void,
5561 off: i64,
5562 getln_buf: *mut c_char,
5563 mustbezero_2: *mut c_void,
5564 shend: *mut u8,
5565 shlim: i64,
5566 shcnt: i64,
5567 ungotten: [c_int; UNGET],
5568 ungotten_count: c_int,
5569 _eof: c_int,
5570 _err: c_int,
5571}
5572
5573static mut STDIN_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5574static mut STDOUT_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5575static mut STDERR_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5576
5577static mut STDIN_FILE: FILE = FILE {
5578 flags: 0, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5579 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5580 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5581 read_fn: None, write_fn: None, seek_fn: None,
5582 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5583 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5584 fd: 0, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5585 cookie: core::ptr::null_mut(), off: 0,
5586 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5587 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5588 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5589};
5590static mut STDOUT_FILE: FILE = FILE {
5591 flags: F_NOWR as u32 + F_SVB as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5592 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5593 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5594 read_fn: None, write_fn: None, seek_fn: None,
5595 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5596 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5597 fd: 1, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5598 cookie: core::ptr::null_mut(), off: 0,
5599 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5600 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5601 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5602};
5603static mut STDERR_FILE: FILE = FILE {
5604 flags: F_NOWR as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5605 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5606 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5607 read_fn: None, write_fn: None, seek_fn: None,
5608 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5609 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5610 fd: 2, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5611 cookie: core::ptr::null_mut(), off: 0,
5612 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5613 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5614 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5615};
5616
5617#[no_mangle]
5618pub static mut stdin: *mut FILE = &raw mut STDIN_FILE as *mut FILE;
5619#[no_mangle]
5620pub static mut stdout: *mut FILE = &raw mut STDOUT_FILE as *mut FILE;
5621#[no_mangle]
5622pub static mut stderr: *mut FILE = &raw mut STDERR_FILE as *mut FILE;
5623
5624unsafe fn __stdio_init() {
5629 STDIN_FILE.buf = core::ptr::addr_of_mut!(STDIN_BUF) as *mut u8;
5630 STDIN_FILE.buf_size = BUFSIZ;
5631 STDIN_FILE.read_fn = Some(__stdio_read);
5632 STDIN_FILE.write_fn = Some(__stdio_write);
5633 STDIN_FILE.seek_fn = Some(__stdio_seek);
5634 STDOUT_FILE.buf = core::ptr::addr_of_mut!(STDOUT_BUF) as *mut u8;
5635 STDOUT_FILE.buf_size = BUFSIZ;
5636 STDOUT_FILE.lbf = b'\n' as c_int;
5637 STDOUT_FILE.read_fn = Some(__stdio_read);
5638 STDOUT_FILE.write_fn = Some(__stdio_write);
5639 STDOUT_FILE.seek_fn = Some(__stdio_seek);
5640 STDERR_FILE.buf = core::ptr::addr_of_mut!(STDERR_BUF) as *mut u8;
5641 STDERR_FILE.buf_size = BUFSIZ;
5642 STDERR_FILE.read_fn = Some(__stdio_read);
5643 STDERR_FILE.write_fn = Some(__stdio_write);
5644 STDERR_FILE.seek_fn = Some(__stdio_seek);
5645}
5646
5647unsafe fn buf_ptr(f: *mut FILE) -> *mut u8 {
5648 (f as *mut u8).add(core::mem::size_of::<FILE>())
5649}
5650
5651unsafe extern "C" fn __stdio_read(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
5652 let n = sys_read((*f).fd as i64, buf, len);
5653 if n <= 0 {
5654 if n == 0 { (*f).flags |= F_EOF; } else { (*f).flags |= F_ERR; (*f)._err = 1; }
5655 return 0;
5656 }
5657 n as usize
5658}
5659
5660unsafe extern "C" fn __stdio_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
5661 let l = (*f).wpos as usize - (*f).wbase as usize;
5662 let mut iov = [
5663 ((*f).wbase as *const u8, l),
5664 (buf, len),
5665 ];
5666 if iov[0].1 == 0 { iov = [iov[1], (core::ptr::null(), 0)]; }
5667 if (*f).flags & F_APP != 0 {
5668 let _ = sys_lseek((*f).fd as i64, 0, SEEK_END as i64);
5669 }
5670 let mut rem = iov[0].1 + iov[1].1;
5671 let mut idx = 0usize;
5672 while rem > 0 {
5673 let ptr = iov[idx].0;
5674 let cnt = iov[idx].1;
5675 if cnt == 0 { idx += 1; continue; }
5676 let n = sys_write((*f).fd as i64, ptr, cnt);
5677 if n <= 0 {
5678 (*f).wpos = core::ptr::null_mut();
5679 (*f).wbase = core::ptr::null_mut();
5680 (*f).wend = core::ptr::null_mut();
5681 (*f).flags |= F_ERR;
5682 return if iov[idx].0 == buf { 0 } else { len };
5683 }
5684 rem -= n as usize;
5685 iov[idx].0 = iov[idx].0.add(n as usize);
5686 iov[idx].1 -= n as usize;
5687 if iov[idx].1 == 0 { idx += 1; }
5688 }
5689 (*f).wend = (*f).buf.add((*f).buf_size);
5690 (*f).wbase = (*f).buf;
5691 (*f).wpos = (*f).buf;
5692 len
5693}
5694
5695unsafe extern "C" fn __stdio_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
5696 sys_lseek((*f).fd as i64, off, whence as i64)
5697}
5698
5699unsafe fn init_file(
5700 f: *mut FILE,
5701 fd: c_int,
5702 mode: *const c_char,
5703 close_fn: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
5704 buf_area: *mut u8,
5705 buf_sz: usize,
5706) {
5707 core::ptr::write_bytes(f as *mut u8, 0, core::mem::size_of::<FILE>());
5708 (*f).fd = fd;
5709 (*f).close = close_fn;
5710 (*f).lock = -1;
5711 (*f).lbf = -1;
5712 (*f).buf = buf_area;
5713 (*f).buf_size = buf_sz;
5714 (*f).read_fn = Some(__stdio_read);
5715 (*f).write_fn = Some(__stdio_write);
5716 (*f).seek_fn = Some(__stdio_seek);
5717 let m = *mode;
5718 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
5719 if m == b'r' as c_char && !has_plus {
5720 (*f).flags = F_NORD;
5721 } else if !has_plus {
5722 (*f).flags = F_NOWR;
5723 }
5724}
5725
5726unsafe extern "C" fn __stdio_close(f: *mut FILE) -> c_int {
5727 sys_close((*f).fd as i64);
5728 0
5729}
5730
5731unsafe fn fmodeflags(mode: *const c_char) -> c_int {
5732 let mut flags: c_int;
5733 let m = *mode;
5734 if !strchr(mode as *const u8, b'+' as c_int).is_null() {
5735 flags = O_RDWR;
5736 } else if m == b'r' as c_char {
5737 flags = O_RDONLY;
5738 } else {
5739 flags = O_WRONLY;
5740 }
5741 if !strchr(mode as *const u8, b'x' as c_int).is_null() { flags |= O_EXCL; }
5742 if !strchr(mode as *const u8, b'e' as c_int).is_null() { flags |= O_CLOEXEC; }
5743 if m != b'r' as c_char { flags |= O_CREAT; }
5744 if m == b'w' as c_char { flags |= O_TRUNC; }
5745 if m == b'a' as c_char { flags |= O_APPEND; }
5746 flags
5747}
5748
5749const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR;
5750
5751unsafe fn flush_buf(f: *mut FILE) -> c_int {
5752 if (*f).wpos == (*f).wbase {
5753 if !(*f).wpos.is_null() {
5754 (*f).wend = (*f).buf.add((*f).buf_size);
5755 (*f).wpos = (*f).wbase;
5756 }
5757 return 0;
5758 }
5759 if let Some(wfunc) = (*f).write_fn {
5760 let ret = wfunc(f, core::ptr::null(), 0);
5761 if ret == 0 && (*f).wpos.is_null() { return -1; }
5762 return 0;
5763 }
5764 (*f).flags |= F_ERR;
5765 -1
5766}
5767
5768#[no_mangle]
5773pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
5774 if filename.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
5775 let m = *mode;
5776 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
5777 ERRNO = EINVAL; return core::ptr::null_mut();
5778 }
5779 let flags = fmodeflags(mode);
5780 let fd = sys_open(filename as *const u8, flags as i64, 0o666);
5781 if fd < 0 { ERRNO = (-fd) as c_int; return core::ptr::null_mut(); }
5782 fdopen(fd as c_int, mode)
5783}
5784
5785#[no_mangle]
5786pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE {
5787 if fd < 0 || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
5788 let m = *mode;
5789 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
5790 ERRNO = EINVAL; return core::ptr::null_mut();
5791 }
5792 let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
5793 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
5794 let buf = buf_ptr(f);
5795 init_file(f, fd, mode, Some(__stdio_close), buf, BUFSIZ);
5796 if !strchr(mode as *const u8, b'a' as c_int).is_null() { (*f).flags |= F_APP; }
5797 if !strchr(mode as *const u8, b'e' as c_int).is_null() { sys_fcntl(fd, F_SETFD, FD_CLOEXEC as i64); }
5798 if (*f).flags & F_NOWR == 0 {
5799 let mut ws: winsize = core::mem::zeroed();
5800 if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 {
5801 (*f).lbf = b'\n' as c_int;
5802 }
5803 }
5804 f
5805}
5806
5807#[no_mangle]
5808pub unsafe extern "C" fn freopen(
5809 filename: *const c_char, mode: *const c_char, f: *mut FILE,
5810) -> *mut FILE {
5811 fflush(f);
5812 if (*f).pipe_pid > 0 { let _ = __stdio_close(f); }
5813 if filename.is_null() {
5814 let flags = fmodeflags(mode);
5815 if flags == 0 { return core::ptr::null_mut(); }
5816 let mut fl = flags & !(O_CREAT | O_EXCL | O_CLOEXEC);
5817 if (*f).flags & F_APP != 0 { fl = (fl & !O_ACCMODE) | O_WRONLY | O_APPEND; }
5818 if sys_fcntl((*f).fd, F_SETFL, fl as i64) < 0 { return core::ptr::null_mut(); }
5819 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
5820 if has_plus {
5821 (*f).flags &= !(F_NORD | F_NOWR);
5822 } else if *mode == b'r' as c_char {
5823 (*f).flags = ((*f).flags & !F_NOWR) | F_NORD;
5824 } else {
5825 (*f).flags = ((*f).flags & !F_NORD) | F_NOWR;
5826 }
5827 return f;
5828 }
5829 let new_f = fopen(filename, mode);
5830 if new_f.is_null() { let _ = __stdio_close(f); return core::ptr::null_mut(); }
5831 if (*new_f).fd == (*f).fd {
5832 (*new_f).fd = -1;
5833 } else {
5834 sys_dup3((*new_f).fd, (*f).fd, 0);
5835 let _ = __stdio_close(new_f);
5836 }
5837 (*f).flags = (*new_f).flags;
5838 (*f).rpos = core::ptr::null_mut();
5839 (*f).rend = core::ptr::null_mut();
5840 (*f).wpos = core::ptr::null_mut();
5841 (*f).wbase = core::ptr::null_mut();
5842 (*f).wend = core::ptr::null_mut();
5843 (*f).lbf = (*new_f).lbf;
5844 (*f).pipe_pid = 0;
5845 free(new_f as *mut c_void);
5846 f
5847}
5848
5849#[no_mangle]
5850pub unsafe extern "C" fn fclose(f: *mut FILE) -> c_int {
5851 if f.is_null() { return -1; }
5852 let r = fflush(f);
5853 if let Some(close_fn) = (*f).close { let _ = close_fn(f); }
5854 if r != 0 { -1 } else { 0 }
5855}
5856
5857#[no_mangle]
5862pub unsafe extern "C" fn setvbuf(f: *mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int {
5863 if mode != _IOFBF && mode != _IOLBF && mode != _IONBF { return -1; }
5864 fflush(f);
5865 (*f).rpos = core::ptr::null_mut();
5866 (*f).rend = core::ptr::null_mut();
5867 (*f).wpos = core::ptr::null_mut();
5868 (*f).wbase = core::ptr::null_mut();
5869 (*f).wend = core::ptr::null_mut();
5870 if mode == _IONBF {
5871 (*f).buf_size = 0;
5872 } else if !buf.is_null() && size > 0 {
5873 (*f).buf = buf as *mut u8;
5874 (*f).buf_size = size;
5875 }
5876 (*f).lbf = if mode == _IOLBF { b'\n' as c_int } else { -1 };
5877 0
5878}
5879
5880#[no_mangle]
5881pub unsafe extern "C" fn setbuf(f: *mut FILE, buf: *mut c_char) {
5882 if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
5883 else { setvbuf(f, buf, _IOFBF, BUFSIZ); }
5884}
5885
5886#[no_mangle]
5887pub unsafe extern "C" fn setbuffer(f: *mut FILE, buf: *mut c_char, size: usize) {
5888 if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
5889 else { setvbuf(f, buf, _IOFBF, size); }
5890}
5891
5892#[no_mangle]
5893pub unsafe extern "C" fn fflush(f: *mut FILE) -> c_int {
5894 if f.is_null() {
5895 let mut r = 0;
5896 if !stdout.is_null() && !(*stdout).wpos.is_null() && (*stdout).wpos != (*stdout).wbase {
5897 if flush_buf(stdout) != 0 { r = -1; }
5898 }
5899 if !stderr.is_null() && !(*stderr).wpos.is_null() && (*stderr).wpos != (*stderr).wbase {
5900 if flush_buf(stderr) != 0 { r = -1; }
5901 }
5902 return r;
5903 }
5904 if !(*f).wpos.is_null() && (*f).wpos != (*f).wbase {
5905 return flush_buf(f);
5906 }
5907 0
5908}
5909
5910#[no_mangle]
5915pub unsafe extern "C" fn fwide(_f: *mut FILE, mode: c_int) -> c_int { mode }
5916
5917#[no_mangle]
5918pub unsafe extern "C" fn feof(f: *mut FILE) -> c_int { if (*f)._eof != 0 { 1 } else { 0 } }
5919
5920#[no_mangle]
5921pub unsafe extern "C" fn ferror(f: *mut FILE) -> c_int { if (*f)._err != 0 { 1 } else { 0 } }
5922
5923#[no_mangle]
5924pub unsafe extern "C" fn clearerr(f: *mut FILE) { (*f)._eof = 0; (*f)._err = 0; }
5925
5926#[no_mangle]
5927pub unsafe extern "C" fn fileno(f: *mut FILE) -> c_int { (*f).fd }
5928
5929#[no_mangle]
5934pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
5935 fseeko(stream, offset as i64, whence)
5936}
5937
5938#[no_mangle]
5939pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
5940 ftello(stream) as c_long
5941}
5942
5943#[no_mangle]
5944pub unsafe extern "C" fn rewind(stream: *mut FILE) {
5945 fseek(stream, 0, SEEK_SET);
5946 (*stream)._eof = 0;
5947 (*stream)._err = 0;
5948}
5949
5950#[no_mangle]
5951pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: i64, whence: c_int) -> c_int {
5952 if whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END {
5953 ERRNO = EINVAL;
5954 return -1;
5955 }
5956 let f = &mut *stream;
5957 let mut adj_offset = offset;
5958 if whence == SEEK_CUR {
5959 if !f.rpos.is_null() {
5960 adj_offset -= f.rend as i64 - f.rpos as i64;
5961 }
5962 adj_offset -= f.ungotten_count as i64;
5963 }
5964 if !f.wpos.is_null() && f.wpos != f.wbase {
5965 if flush_buf(stream) != 0 { return -1; }
5966 }
5967 f.wpos = core::ptr::null_mut();
5968 f.wbase = core::ptr::null_mut();
5969 f.wend = core::ptr::null_mut();
5970 if let Some(sfunc) = f.seek_fn {
5971 let r = sfunc(stream, adj_offset, whence);
5972 if r < 0 { return -1; }
5973 } else {
5974 ERRNO = EINVAL;
5975 return -1;
5976 }
5977 f.rpos = core::ptr::null_mut();
5978 f.rend = core::ptr::null_mut();
5979 f._eof = 0;
5980 f.ungotten_count = 0;
5981 0
5982}
5983
5984#[no_mangle]
5985pub unsafe extern "C" fn ftello(stream: *mut FILE) -> i64 {
5986 let f = &mut *stream;
5987 if f.flags & F_APP != 0 && !f.wpos.is_null() && f.wpos != f.wbase {
5988 if fflush(stream) != 0 { return -1; }
5989 }
5990 let sfunc = match f.seek_fn { Some(s) => s, None => return -1 };
5991 let pos = sfunc(stream, 0,
5992 if (f.flags & F_APP) != 0 && !f.wpos.is_null() && f.wpos != f.wbase { SEEK_END } else { SEEK_CUR });
5993 if pos < 0 { return -1; }
5994 let mut pos = pos;
5995 if !f.rpos.is_null() {
5996 pos += f.rpos as i64 - f.rend as i64;
5997 } else if !f.wbase.is_null() {
5998 pos += f.wpos as i64 - f.wbase as i64;
5999 }
6000 pos - f.ungotten_count as i64
6001}
6002
6003#[no_mangle]
6004pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut i64) -> c_int {
6005 let off = ftello(stream);
6006 if off < 0 { return -1; }
6007 *pos = off;
6008 0
6009}
6010
6011#[no_mangle]
6012pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const i64) -> c_int {
6013 fseeko(stream, *pos, SEEK_SET)
6014}
6015
6016#[no_mangle]
6021pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
6022 let f = &mut *stream;
6023 if f.ungotten_count > 0 {
6024 f.ungotten_count -= 1;
6025 return f.ungotten[f.ungotten_count as usize];
6026 }
6027 if !f.rpos.is_null() && f.rpos < f.rend {
6028 let c = *f.rpos;
6029 f.rpos = f.rpos.add(1);
6030 return c as c_int;
6031 }
6032 if f._eof != 0 { return -1; }
6033 if let Some(rfunc) = f.read_fn {
6034 let mut buf = [0u8; 1];
6035 let n = rfunc(stream, buf.as_mut_ptr(), 1);
6036 if n == 0 {
6037 if f.flags & F_ERR != 0 { f._err = 1; } else { f._eof = 1; }
6038 return -1;
6039 }
6040 buf[0] as c_int
6041 } else {
6042 f._eof = 1;
6043 -1
6044 }
6045}
6046
6047#[no_mangle]
6048pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { fgetc(stream) }
6049
6050#[no_mangle]
6051pub unsafe extern "C" fn getchar() -> c_int { fgetc(stdin) }
6052
6053#[no_mangle]
6054pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
6055 if c == -1 { return -1; }
6056 let f = &mut *stream;
6057 if f.ungotten_count >= UNGET as c_int { return -1; }
6058 f.ungotten[f.ungotten_count as usize] = c;
6059 f.ungotten_count += 1;
6060 f._eof = 0;
6061 c
6062}
6063
6064#[no_mangle]
6069pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char {
6070 if n <= 0 { return null_mut(); }
6071 let max = (n - 1) as usize;
6072 let mut i = 0usize;
6073 while i < max {
6074 let c = fgetc(stream);
6075 if c == -1 { if i == 0 { return null_mut(); } break; }
6076 *s.add(i) = c as c_char;
6077 i += 1;
6078 if c == b'\n' as c_int { break; }
6079 }
6080 *s.add(i) = 0;
6081 s
6082}
6083
6084#[no_mangle]
6086pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char {
6087 let mut i = 0usize;
6088 loop {
6089 let c = fgetc(stdin);
6090 if c == -1 { if i == 0 { return null_mut(); } break; }
6091 if c == b'\n' as c_int { break; }
6092 *s.add(i) = c as c_char;
6093 i += 1;
6094 }
6095 *s.add(i) = 0;
6096 s
6097}
6098
6099#[no_mangle]
6100pub unsafe extern "C" fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut FILE {
6101 fopen(filename, mode)
6102}
6103
6104const PERROR_BUF_SIZE: usize = 64;
6106static mut PERROR_BUF: [u8; PERROR_BUF_SIZE] = [0; PERROR_BUF_SIZE];
6107
6108#[no_mangle]
6109pub unsafe extern "C" fn perror(msg: *const c_char) {
6110 let fd = (*stderr).fd;
6111 if !msg.is_null() && *msg != 0 {
6112 let len = strlen(msg as *const c_char);
6113 write_str(fd, msg as *const u8, len);
6114 write_str(fd, b": ".as_ptr(), 2);
6115 }
6116 let e = ERRNO;
6117 if e != 0 {
6119 let (buf, len) = format_i64(e as i64);
6120 write_str(fd, buf.as_ptr().add(21 - len), len);
6121 }
6122 write_str(fd, b"\n".as_ptr(), 1);
6123}
6124
6125#[no_mangle]
6126pub unsafe extern "C" fn fread(
6127 ptr: *mut c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6128) -> SizeT {
6129 if size == 0 || nmemb == 0 { return 0; }
6130 let total = size * nmemb;
6131 let mut rd = 0usize;
6132 while rd < total {
6133 let c = fgetc(stream);
6134 if c == -1 { break; }
6135 *(ptr as *mut u8).add(rd) = c as u8;
6136 rd += 1;
6137 }
6138 rd / size
6139}
6140
6141unsafe fn write_str(fd: c_int, s: *const u8, len: usize) {
6146 let mut written = 0usize;
6147 while written < len {
6148 let n = sys_write(fd as i64, s.add(written), len - written);
6149 if n <= 0 { break; }
6150 written += n as usize;
6151 }
6152}
6153
6154unsafe fn __overflow(f: *mut FILE, c: c_int) -> c_int {
6155 if (*f).wpos.is_null() {
6156 (*f).wbase = (*f).buf;
6157 (*f).wpos = (*f).buf;
6158 (*f).wend = (*f).buf.add((*f).buf_size);
6159 }
6160 if flush_buf(f) == -1 { return -1; }
6161 if (*f).wpos >= (*f).wend {
6162 if let Some(wfunc) = (*f).write_fn {
6163 let byte = c as u8;
6164 let ret = wfunc(f, &byte as *const u8, 1);
6165 if ret == 0 { return -1; }
6166 }
6167 return c;
6168 }
6169 *(*f).wpos = c as u8;
6170 (*f).wpos = (*f).wpos.add(1);
6171 if c == (*f).lbf || (*f).wpos >= (*f).wend { let _ = flush_buf(f); }
6172 c
6173}
6174
6175#[no_mangle]
6176pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
6177 let len = strlen(s as *const c_char);
6178 let _ = fwrite(s as *const c_void, 1, len, stdout);
6179 let _ = fwrite(b"\n".as_ptr() as *const c_void, 1, 1, stdout);
6180 let f = &mut *stdout;
6181 if f.lbf >= 0 { let _ = flush_buf(stdout); }
6182 (len + 1) as c_int
6183}
6184
6185#[no_mangle]
6186pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
6187 let len = strlen(s as *const c_char);
6188 fwrite(s as *const c_void, 1, len, stream) as c_int
6189}
6190
6191#[no_mangle]
6192pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
6193 let f = &mut *stream;
6194 if f.wpos.is_null() || f.wpos >= f.wend {
6195 if __overflow(f, c) == -1 { return -1; }
6196 return c;
6197 }
6198 *f.wpos = c as u8;
6199 f.wpos = f.wpos.add(1);
6200 if c == f.lbf || f.wpos >= f.wend { let _ = flush_buf(f); }
6201 c
6202}
6203
6204#[no_mangle]
6205pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { fputc(c, stream) }
6206
6207#[no_mangle]
6208pub unsafe extern "C" fn putchar(c: c_int) -> c_int { fputc(c, stdout) }
6209
6210#[no_mangle]
6211pub unsafe extern "C" fn fwrite(
6212 ptr: *const c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6213) -> SizeT {
6214 if size == 0 || nmemb == 0 { return 0; }
6215 let total = size * nmemb;
6216 let f = &mut *stream;
6217 if f.buf_size == 0 {
6218 if let Some(wfunc) = f.write_fn {
6219 let ret = wfunc(stream, ptr as *const u8, total);
6220 return ret / size;
6221 }
6222 return 0;
6223 }
6224 if f.wpos.is_null() {
6225 f.wbase = f.buf;
6226 f.wpos = f.buf;
6227 f.wend = f.buf.add(f.buf_size);
6228 }
6229 let mut remaining = total;
6230 let mut src = ptr as *const u8;
6231 while remaining > 0 {
6232 let space = f.wend as usize - f.wpos as usize;
6233 if space == 0 {
6234 if flush_buf(f as *mut FILE) == -1 { break; }
6235 continue;
6236 }
6237 let n = if remaining < space { remaining } else { space };
6238 core::ptr::copy_nonoverlapping(src, f.wpos, n);
6239 f.wpos = f.wpos.add(n);
6240 src = src.add(n);
6241 remaining -= n;
6242 if f.wpos >= f.wend { let _ = flush_buf(f as *mut FILE); }
6243 }
6244 if f.lbf >= 0 { let _ = flush_buf(f as *mut FILE); }
6245 (total - remaining) / size
6246}
6247
6248macro_rules! impl_format {
6253 ($fmt:expr, $args:expr, $write_char:expr, $write_str:expr) => {{
6254 let fmt = $fmt;
6255 let args = &mut $args;
6256 let mut count: usize = 0;
6257 let mut i = 0usize;
6258 loop {
6259 let c = *fmt.add(i) as u8;
6260 if c == 0 { break; }
6261 if c != b'%' {
6262 ($write_char)(c);
6263 count += 1; i += 1; continue;
6264 }
6265 i += 1;
6266 let mut flags: u8 = 0;
6268 loop {
6269 let fc = *fmt.add(i) as u8;
6270 match fc {
6271 b'-' => { flags |= FLAG_MINUS; i += 1; }
6272 b'+' => { flags |= FLAG_PLUS; i += 1; }
6273 b' ' => { flags |= FLAG_SPACE; i += 1; }
6274 b'0' => { flags |= FLAG_ZERO; i += 1; }
6275 b'#' => { flags |= FLAG_HASH; i += 1; }
6276 _ => break,
6277 }
6278 }
6279 let mut width: usize = 0;
6281 if *fmt.add(i) as u8 == b'*' {
6282 width = args.next_arg::<c_int>() as usize; i += 1;
6283 } else {
6284 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6285 width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
6286 }
6287 }
6288 let mut precision: i32 = -1;
6290 if *fmt.add(i) as u8 == b'.' {
6291 i += 1;
6292 if *fmt.add(i) as u8 == b'*' {
6293 precision = args.next_arg::<c_int>(); i += 1;
6294 } else {
6295 precision = 0;
6296 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6297 precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
6298 }
6299 }
6300 }
6301 let len_mod = *fmt.add(i) as u8;
6303 let spec: u8;
6304 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' {
6305 i += 1;
6306 let len_mod2 = *fmt.add(i) as u8;
6307 if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
6308 i += 1;
6309 spec = *fmt.add(i) as u8;
6310 match (len_mod, len_mod2, spec) {
6312 (b'h', b'h', b'n') => {
6313 let p = args.next_arg::<*mut c_void>();
6314 if !p.is_null() { *(p as *mut u8) = count as u8; }
6315 }
6316 (b'l', b'l', b'n') => {
6317 let p = args.next_arg::<*mut c_void>();
6318 if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
6319 }
6320 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
6321 let val = args.next_arg::<c_longlong>();
6322 let neg = val < 0;
6323 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6324 let b = format_u64(abs);
6325 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6326 let mut fbuf = [0u8; 32];
6327 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6328 ($write_str)(fbuf.as_ptr(), len); count += len;
6329 }
6330 (b'l', b'l', b'u') => {
6331 let val = args.next_arg::<c_ulonglong>();
6332 let b = format_u64(val as u64);
6333 let mut fbuf = [0u8; 32];
6334 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6335 ($write_str)(fbuf.as_ptr(), len); count += len;
6336 }
6337 (b'l', b'l', b'o') => {
6338 let val = args.next_arg::<c_ulonglong>();
6339 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
6340 let mut fbuf = [0u8; 32];
6341 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6342 ($write_str)(fbuf.as_ptr(), len); count += len;
6343 }
6344 _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(len_mod2); ($write_char)(spec); count += 4; }
6345 }
6346 } else {
6347 spec = len_mod2;
6348 match (len_mod, spec) {
6349 (b'h', b'n') => {
6350 let p = args.next_arg::<*mut c_void>();
6351 if !p.is_null() { *(p as *mut u16) = count as u16; }
6352 }
6353 (b'l', b'n') => {
6354 let p = args.next_arg::<*mut c_void>();
6355 if !p.is_null() { *(p as *mut c_long) = count as c_long; }
6356 }
6357 (b'z', b'n') | (b't', b'n') => {
6358 let p = args.next_arg::<*mut c_void>();
6359 if !p.is_null() { *(p as *mut usize) = count; }
6360 }
6361 (b'j', b'n') => {
6362 let p = args.next_arg::<*mut c_void>();
6363 if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
6364 }
6365 (b'l', b'd') | (b'l', b'i') => {
6366 let val = args.next_arg::<c_long>();
6367 let neg = val < 0;
6368 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6369 let b = format_u64(abs);
6370 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6371 let mut fbuf = [0u8; 32];
6372 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6373 ($write_str)(fbuf.as_ptr(), len); count += len;
6374 }
6375 (b'l', b'u') => {
6376 let val = args.next_arg::<c_ulong>();
6377 let b = format_u64(val as u64);
6378 let mut fbuf = [0u8; 32];
6379 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6380 ($write_str)(fbuf.as_ptr(), len); count += len;
6381 }
6382 (b'l', b'x') => {
6383 let val = args.next_arg::<c_ulong>();
6384 let b = format_hex(val as u64, false);
6385 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
6386 let mut fbuf = [0u8; 32];
6387 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6388 ($write_str)(fbuf.as_ptr(), len); count += len;
6389 }
6390 (b'l', b'X') => {
6391 let val = args.next_arg::<c_ulong>();
6392 let b = format_hex(val as u64, true);
6393 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
6394 let mut fbuf = [0u8; 32];
6395 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6396 ($write_str)(fbuf.as_ptr(), len); count += len;
6397 }
6398 (b'l', b'o') => {
6399 let val = args.next_arg::<c_ulong>();
6400 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
6401 let mut fbuf = [0u8; 32];
6402 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6403 ($write_str)(fbuf.as_ptr(), len); count += len;
6404 }
6405 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
6406 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
6407 let val = args.next_arg::<f64>();
6408 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6409 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6410 let mut fbuf = [0u8; 4224];
6411 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6412 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6413 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6414 ($write_str)(fbuf.as_ptr(), total); count += total;
6415 }
6416 (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
6417 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
6418 #[cfg(target_arch = "aarch64")]
6419 let val = {
6420 let lo: u64 = args.next_arg::<u64>();
6421 let hi: u64 = args.next_arg::<u64>();
6422 let combined: u128 = ((hi as u128) << 64) | (lo as u128);
6423 f128::from_bits(combined) as f64
6424 };
6425 #[cfg(target_arch = "x86_64")]
6426 let val = args.next_arg::<f64>();
6427 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6428 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6429 let mut fbuf = [0u8; 4224];
6430 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6431 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6432 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6433 ($write_str)(fbuf.as_ptr(), total); count += total;
6434 }
6435 _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(spec); count += 3; }
6436 }
6437 }
6438 } else {
6439 spec = *fmt.add(i) as u8;
6440 match spec {
6441 b's' => {
6442 let s = args.next_arg::<*const c_char>();
6443 if s.is_null() {
6444 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
6445 let padded_len = if width > slen { width } else { slen };
6446 let pad = padded_len - slen;
6447 if flags & FLAG_MINUS != 0 {
6448 ($write_str)(b"(null)".as_ptr(), slen);
6449 for _ in 0..pad { ($write_char)(b' '); }
6450 } else {
6451 for _ in 0..pad { ($write_char)(b' '); }
6452 ($write_str)(b"(null)".as_ptr(), slen);
6453 }
6454 count += padded_len;
6455 } else {
6456 let full_len = strlen(s as *const c_char);
6457 let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
6458 let padded_len = if width > slen { width } else { slen };
6459 let pad = padded_len - slen;
6460 if flags & FLAG_MINUS != 0 {
6461 ($write_str)(s as *const u8, slen);
6462 for _ in 0..pad { ($write_char)(b' '); }
6463 } else {
6464 for _ in 0..pad { ($write_char)(b' '); }
6465 ($write_str)(s as *const u8, slen);
6466 }
6467 count += padded_len;
6468 }
6469 }
6470 b'd' | b'i' => {
6471 let d = args.next_arg::<c_int>();
6472 let neg = d < 0;
6473 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
6474 let b = format_u64(abs);
6475 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6476 let mut fbuf = [0u8; 32];
6477 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6478 ($write_str)(fbuf.as_ptr(), len); count += len;
6479 }
6480 b'u' => {
6481 let u = args.next_arg::<c_uint>();
6482 let b = format_u64(u as u64);
6483 let mut fbuf = [0u8; 32];
6484 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6485 ($write_str)(fbuf.as_ptr(), len); count += len;
6486 }
6487 b'x' => {
6488 let x = args.next_arg::<c_uint>();
6489 let b = format_hex(x as u64, false);
6490 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
6491 let mut fbuf = [0u8; 32];
6492 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6493 ($write_str)(fbuf.as_ptr(), len); count += len;
6494 }
6495 b'X' => {
6496 let x = args.next_arg::<c_uint>();
6497 let b = format_hex(x as u64, true);
6498 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
6499 let mut fbuf = [0u8; 32];
6500 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6501 ($write_str)(fbuf.as_ptr(), len); count += len;
6502 }
6503 b'o' => {
6504 let o = args.next_arg::<c_uint>();
6505 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
6506 let mut fbuf = [0u8; 32];
6507 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6508 ($write_str)(fbuf.as_ptr(), len); count += len;
6509 }
6510 b'c' => {
6511 let ch = args.next_arg::<c_int>();
6512 if width > 1 {
6513 let pad = width - 1;
6514 if flags & FLAG_MINUS != 0 {
6515 ($write_char)(ch as u8); count += 1;
6516 for _ in 0..pad { ($write_char)(b' '); count += 1; }
6517 } else {
6518 for _ in 0..pad { ($write_char)(b' '); count += 1; }
6519 ($write_char)(ch as u8); count += 1;
6520 }
6521 } else {
6522 ($write_char)(ch as u8); count += 1;
6523 }
6524 }
6525 b'p' => {
6526 let p = args.next_arg::<*const c_void>();
6527 let mut fbuf = [0u8; 20];
6528 fbuf[0] = b'0'; fbuf[1] = b'x';
6529 let b = format_hex(p as u64, false);
6530 core::ptr::copy_nonoverlapping(b.0.as_ptr(), fbuf.as_mut_ptr().add(2), b.1);
6531 ($write_str)(fbuf.as_ptr(), b.1 + 2); count += b.1 + 2;
6532 }
6533 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
6534 let val = args.next_arg::<f64>();
6535 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6536 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6537 let mut fbuf = [0u8; 4224];
6538 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6539 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6540 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6541 ($write_str)(fbuf.as_ptr(), total); count += total;
6542 }
6543 b'%' => { ($write_char)(b'%'); count += 1; }
6544 b'n' => {
6545 let p = args.next_arg::<*mut c_void>();
6546 if !p.is_null() { *(p as *mut c_int) = count as c_int; }
6547 }
6548 _ => { ($write_char)(b'%'); ($write_char)(spec); count += 2; }
6549 }
6550 }
6551 i += 1;
6552 }
6553 count as c_int
6554 }};
6555}
6556
6557unsafe fn format_u64(mut val: u64) -> ([u8; 20], usize) {
6558 let mut buf = [0u8; 20];
6559 if val == 0 { buf[0] = b'0'; return (buf, 1); }
6560 let mut tmp = [0u8; 20];
6561 let mut pos = 20;
6562 while val > 0 { pos -= 1; tmp[pos] = b'0' + (val % 10) as u8; val /= 10; }
6563 let len = 20 - pos;
6564 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6565 (buf, len)
6566}
6567
6568unsafe fn format_i64(val: i64) -> ([u8; 21], usize) {
6569 let mut buf = [0u8; 21];
6570 if val < 0 {
6571 buf[0] = b'-';
6572 let (inner, len) = format_u64((-(val as i128)) as u64);
6573 core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr().add(1), len);
6574 (buf, len + 1)
6575 } else {
6576 let (inner, len) = format_u64(val as u64);
6577 core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr(), len);
6578 (buf, len)
6579 }
6580}
6581
6582unsafe fn format_hex(mut val: u64, uppercase: bool) -> ([u8; 16], usize) {
6583 let digits = if uppercase { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
6584 let mut buf = [0u8; 16];
6585 if val == 0 { buf[0] = b'0'; return (buf, 1); }
6586 let mut tmp = [0u8; 16];
6587 let mut pos = 16;
6588 while val > 0 { pos -= 1; tmp[pos] = digits[(val & 0xf) as usize]; val >>= 4; }
6589 let len = 16 - pos;
6590 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6591 (buf, len)
6592}
6593
6594unsafe fn format_octal(mut val: u64, alt: bool) -> ([u8; 24], usize) {
6595 let mut buf = [0u8; 24];
6596 if val == 0 {
6597 buf[0] = b'0';
6598 return (buf, 1);
6599 }
6600 let mut tmp = [0u8; 24];
6601 let mut pos = 24;
6602 while val > 0 {
6603 pos -= 1;
6604 tmp[pos] = b'0' + (val & 7) as u8;
6605 val >>= 3;
6606 }
6607 let len = 24 - pos;
6608 if alt {
6609 tmp[pos - 1] = b'0';
6610 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos - 1), buf.as_mut_ptr(), len + 1);
6611 (buf, len + 1)
6612 } else {
6613 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6614 (buf, len)
6615 }
6616}
6617
6618unsafe fn format_int(
6619 dst: *mut u8,
6620 digits: *const u8,
6621 digits_len: usize,
6622 sign: Option<u8>,
6623 prefix: Option<u8>,
6624 precision: i32,
6625 width: usize,
6626 flags: u8,
6627 octal_alt: bool,
6628) -> usize {
6629 let num_digits = if precision == 0 && digits_len == 1 && *digits == b'0' && !octal_alt {
6630 0
6631 } else {
6632 digits_len
6633 };
6634 let prec = precision as usize;
6635 let zero_pad = if precision >= 0 && prec > num_digits { prec - num_digits } else { 0 };
6636
6637 let sign_len = sign.map_or(0, |_| 1);
6638 let prefix_len = prefix.map_or(0, |_| 2);
6639 let content_len = sign_len + prefix_len + zero_pad + num_digits;
6640
6641 let mut buf = [0u8; 32];
6642 let mut pos = 0usize;
6643 if let Some(c) = sign { buf[pos] = c; pos += 1; }
6644 if let Some(c) = prefix { buf[pos] = b'0'; pos += 1; buf[pos] = c; pos += 1; }
6645 for _ in 0..zero_pad { buf[pos] = b'0'; pos += 1; }
6646 if num_digits > 0 {
6647 core::ptr::copy_nonoverlapping(digits, buf.as_mut_ptr().add(pos), num_digits);
6648 }
6649
6650 if content_len >= width {
6651 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
6652 return content_len;
6653 }
6654 let pad = width - content_len;
6655 if flags & FLAG_MINUS != 0 {
6656 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
6657 for i in 0..pad { *dst.add(content_len + i) = b' '; }
6658 } else if flags & FLAG_ZERO != 0 && precision < 0 {
6659 let fixed = sign_len + prefix_len;
6660 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, fixed);
6661 for i in fixed..width - num_digits { *dst.add(i) = b'0'; }
6662 if num_digits > 0 {
6663 core::ptr::copy_nonoverlapping(digits, dst.add(width - num_digits), num_digits);
6664 }
6665 } else {
6666 for i in 0..pad { *dst.add(i) = b' '; }
6667 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst.add(pad), content_len);
6668 }
6669 width
6670}
6671
6672unsafe fn format_f64(val: f64) -> ([u8; 64], usize) {
6673 let mut buf = [0u8; 64];
6674 let mut pos = 0usize;
6675 let mut v = val;
6676 if v.is_nan() {
6677 let nan = b"nan";
6678 core::ptr::copy_nonoverlapping(nan.as_ptr(), buf.as_mut_ptr(), 3);
6679 return (buf, 3);
6680 }
6681 if v < 0.0 { buf[pos] = b'-'; pos += 1; v = -v; }
6682 if v.is_infinite() {
6683 let inf = b"inf";
6684 core::ptr::copy_nonoverlapping(inf.as_ptr(), buf.as_mut_ptr().add(pos), 3);
6685 return (buf, pos + 3);
6686 }
6687 let int_part = v as u64;
6688 let frac = v - int_part as f64;
6689 let (ibuf, ilen) = format_u64(int_part);
6690 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), buf.as_mut_ptr().add(pos), ilen);
6691 pos += ilen;
6692 buf[pos] = b'.';
6693 pos += 1;
6694 let mut f = frac;
6695 for _ in 0..6 { f *= 10.0; let digit = f as u8; buf[pos] = b'0' + digit; pos += 1; f -= digit as f64; }
6696 (buf, pos)
6697}
6698
6699const FMT_F: u8 = 0;
6701const FMT_E: u8 = 1;
6702const FMT_G: u8 = 2;
6703const FMT_A: u8 = 3;
6704
6705const FLAG_HASH: u8 = 1;
6706const FLAG_PLUS: u8 = 2;
6707const FLAG_SPACE: u8 = 4;
6708const FLAG_ZERO: u8 = 8;
6709const FLAG_MINUS: u8 = 16;
6710
6711unsafe fn bigint_to_decimal(buf: *mut u8, mant: u64, shift: u32) -> usize {
6716 let nlimbs = (2 + (shift + 31) / 32) as usize;
6718 let mut limbs = [0u32; 36];
6719 limbs[0] = mant as u32;
6720 limbs[1] = (mant >> 32) as u32;
6721
6722 let ws = (shift / 32) as usize;
6723 let bs = shift % 32;
6724
6725 if ws > 0 {
6727 let mut i = 1usize;
6728 loop {
6729 limbs[i + ws] = limbs[i];
6730 if i == 0 { break; }
6731 i -= 1;
6732 }
6733 for j in 0..ws { limbs[j] = 0; }
6734 }
6735 if bs > 0 {
6737 let mut carry = 0u32;
6738 let end = nlimbs.min(ws + 3);
6739 for i in ws..end {
6740 let new_val = (limbs[i] << bs) | carry;
6741 carry = limbs[i] >> (32 - bs);
6742 limbs[i] = new_val;
6743 }
6744 }
6745
6746 let mut used = nlimbs;
6748 while used > 0 && limbs[used - 1] == 0 { used -= 1; }
6749 if used == 0 { *buf = b'0'; return 1; }
6750
6751 let mut digits = [0u8; 400];
6753 let mut nd = 0usize;
6754 loop {
6755 let mut all_zero = true;
6756 for i in 0..used { if limbs[i] != 0 { all_zero = false; break; } }
6757 if all_zero { break; }
6758 let mut rem = 0u64;
6759 for i in (0..used).rev() {
6760 let val = (rem << 32) | limbs[i] as u64;
6761 limbs[i] = (val / 10) as u32;
6762 rem = val % 10;
6763 }
6764 digits[nd] = rem as u8;
6765 nd += 1;
6766 }
6767 for i in 0..nd { *buf.add(i) = b'0' + digits[nd - 1 - i]; }
6769 nd
6770}
6771
6772unsafe fn frac_digits_u128(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
6775 let mask: u128 = (1u128 << shift) - 1;
6776 let mut rem = frac_bits as u128;
6777 for i in 0..count {
6778 rem *= 10;
6779 let digit = (rem >> shift) as u8;
6780 rem &= mask;
6781 *buf.add(i) = digit;
6782 }
6783 rem != 0
6784}
6785
6786unsafe fn frac_digits_bigint(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
6789 let nlimbs = ((shift + 31) / 32) as usize;
6790 let mut rem = [0u32; 36]; rem[0] = frac_bits as u32;
6792 if nlimbs > 1 { rem[1] = (frac_bits >> 32) as u32; }
6793 let hi_word = (shift / 32) as usize;
6795 let hi_bit = shift % 32;
6796 if hi_bit > 0 && hi_word < nlimbs {
6797 rem[hi_word] &= (1u32 << hi_bit) - 1;
6798 }
6799 let clear_from = if hi_bit > 0 { hi_word + 1 } else { hi_word };
6801 for j in clear_from..nlimbs { rem[j] = 0; }
6802
6803 for i in 0..count {
6804 let mut carry = 0u64;
6806 for j in 0..nlimbs {
6807 let val = rem[j] as u64 * 10 + carry;
6808 rem[j] = val as u32;
6809 carry = val >> 32;
6810 }
6811 let digit: u32;
6813 if hi_bit == 0 {
6814 digit = if hi_word < nlimbs { rem[hi_word] } else { carry as u32 };
6815 } else {
6816 let mut d = if hi_word < nlimbs { rem[hi_word] >> hi_bit } else { 0 };
6817 if hi_word + 1 < nlimbs {
6818 d |= rem[hi_word + 1] << (32 - hi_bit);
6819 } else if carry > 0 {
6820 d |= (carry as u32) << (32 - hi_bit);
6821 }
6822 digit = d;
6823 }
6824 *buf.add(i) = digit.min(9) as u8;
6825 if hi_bit == 0 {
6827 if hi_word < nlimbs { rem[hi_word] = 0; }
6828 } else {
6829 if hi_word < nlimbs {
6830 rem[hi_word] &= (1u32 << hi_bit) - 1;
6831 }
6832 for j in (hi_word + 1)..nlimbs { rem[j] = 0; }
6833 }
6834 }
6835 for i in 0..nlimbs { if rem[i] != 0 { return true; } }
6837 false
6838}
6839
6840unsafe fn increment_decimal(buf: *mut u8, len: &mut usize) {
6842 let mut j = *len;
6843 loop {
6844 if j == 0 {
6845 let l = *len;
6847 for i in (0..l).rev() { *buf.add(i + 1) = *buf.add(i); }
6848 *buf = b'1';
6849 *len = l + 1;
6850 return;
6851 }
6852 j -= 1;
6853 let d = *buf.add(j);
6854 if d < b'9' { *buf.add(j) = d + 1; return; }
6855 *buf.add(j) = b'0';
6856 }
6857}
6858
6859unsafe fn format_f64_full(
6861 dst: *mut u8, val: f64, fmt_type: u8, precision: i32, flags: u8, uppercase: bool,
6862) -> usize {
6863 let mut pos = 0usize;
6864
6865 if val.is_nan() {
6867 let nan_s: &[u8] = if uppercase { b"NAN" } else { b"nan" };
6868 core::ptr::copy_nonoverlapping(nan_s.as_ptr(), dst, 3);
6869 return 3;
6870 }
6871 let neg = val.is_sign_negative();
6872 let v = if neg { -val } else { val };
6873
6874 if v.is_infinite() {
6876 if neg { *dst.add(pos) = b'-'; pos += 1; }
6877 else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
6878 else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
6879 let inf_s: &[u8] = if uppercase { b"INF" } else { b"inf" };
6880 core::ptr::copy_nonoverlapping(inf_s.as_ptr(), dst.add(pos), 3);
6881 return pos + 3;
6882 }
6883
6884 if neg { *dst.add(pos) = b'-'; pos += 1; }
6886 else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
6887 else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
6888
6889 if fmt_type == FMT_A {
6891 return pos + fmt_hex_float(dst.add(pos), val, precision, flags, uppercase);
6892 }
6893
6894 let p: usize;
6896 let mut exp: i32;
6897 let use_f: bool;
6898
6899 match fmt_type {
6900 FMT_G => {
6901 let gp = if precision < 0 { 6usize } else if precision == 0 { 1usize } else { precision as usize };
6902 exp = if v > 0.0 { compute_exp10(v) } else { 0 };
6903 use_f = exp >= -4 && exp < gp as i32;
6904 if use_f {
6905 p = if exp < 0 { gp + ((-exp) as usize - 1) }
6906 else if (exp as usize) < gp { gp - exp as usize - 1 }
6907 else { 0 };
6908 } else {
6909 p = gp - 1;
6910 }
6911 }
6912 FMT_E => {
6913 p = if precision < 0 { 6usize } else { precision as usize };
6914 exp = if v > 0.0 { compute_exp10(v) } else { 0 };
6915 use_f = false;
6916 }
6917 _ => {
6918 p = if precision < 0 { 6usize } else { precision as usize };
6919 exp = 0;
6920 use_f = true;
6921 }
6922 }
6923
6924 if v == 0.0 {
6925 *dst.add(pos) = b'0'; pos += 1;
6926 if !(fmt_type == FMT_G && flags & FLAG_HASH == 0) {
6927 if p > 0 || flags & FLAG_HASH != 0 {
6928 *dst.add(pos) = b'.'; pos += 1;
6929 for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
6930 }
6931 }
6932 if !use_f {
6933 let ec = if uppercase { b'E' } else { b'e' };
6934 *dst.add(pos) = ec; pos += 1;
6935 *dst.add(pos) = b'+'; pos += 1;
6936 *dst.add(pos) = b'0'; pos += 1;
6937 *dst.add(pos) = b'0'; pos += 1;
6938 }
6939 return pos;
6940 }
6941
6942 if use_f {
6944 let bits = v.to_bits();
6945 let raw_mant = bits & 0x000FFFFFFFFFFFFF;
6946 let raw_exp_bits = ((bits >> 52) & 0x7FF) as i32;
6947 let (mant_b, bin_exp) = if raw_exp_bits == 0 {
6948 (raw_mant, -1022i32)
6949 } else {
6950 (raw_mant | (1u64 << 52), raw_exp_bits - 1023)
6951 };
6952
6953 let mut ibuf = [0u8; 400];
6955 let mut ilen: usize;
6956 if bin_exp < 0 {
6957 ibuf[0] = b'0'; ilen = 1;
6958 } else if bin_exp <= 63 {
6959 let int_val = if bin_exp <= 52 { mant_b >> (52 - bin_exp) }
6960 else { mant_b << (bin_exp - 52) };
6961 let (buf2, len2) = format_u64(int_val);
6962 ibuf[..len2].copy_from_slice(&buf2[..len2]);
6963 ilen = len2;
6964 } else {
6965 ilen = bigint_to_decimal(ibuf.as_mut_ptr(), mant_b, (bin_exp - 52) as u32);
6966 }
6967
6968 let mut fbuf = [0u8; 1100];
6970 let mut has_rest = false;
6971 if p > 0 && bin_exp < 52 {
6972 let shift = (52 - bin_exp) as u32;
6973 let frac_bits = if bin_exp >= 0 { mant_b & ((1u64 << shift) - 1) } else { mant_b };
6974 if shift <= 124 {
6975 has_rest = frac_digits_u128(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
6976 } else {
6977 has_rest = frac_digits_bigint(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
6978 }
6979 }
6980
6981 if p > 0 && bin_exp < 52 {
6983 let next_d = fbuf[p];
6984 let last_d = fbuf[p - 1];
6985 if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
6986 let mut carry = true;
6987 for j in (0..p).rev() {
6988 if !carry { break; }
6989 fbuf[j] += 1;
6990 if fbuf[j] < 10 { carry = false; break; }
6991 fbuf[j] = 0;
6992 }
6993 if carry { increment_decimal(ibuf.as_mut_ptr(), &mut ilen); }
6994 }
6995 } else if p == 0 {
6996 if bin_exp >= 0 && bin_exp < 52 {
6998 let shift = (52 - bin_exp) as u32;
6999 let frac_bits = mant_b & ((1u64 << shift) - 1);
7000 let half = 1u64 << (shift - 1);
7001 let last_d = ibuf[ilen - 1] - b'0';
7002 if frac_bits > half || (frac_bits == half && last_d & 1 != 0) {
7003 increment_decimal(ibuf.as_mut_ptr(), &mut ilen);
7004 }
7005 }
7006 }
7007
7008 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
7010 pos += ilen;
7011 if p > 0 || flags & FLAG_HASH != 0 {
7012 *dst.add(pos) = b'.'; pos += 1;
7013 for i in 0..p { *dst.add(pos) = b'0' + fbuf[i]; pos += 1; }
7014 }
7015 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7016 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7017 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7018 }
7019 return pos;
7020 }
7021
7022 let mut fbuf = [0u8; 20];
7025 let mut int_part: u64;
7026 {
7027 let bits_v = v.to_bits();
7028 let raw_mant_v = bits_v & 0x000FFFFFFFFFFFFF;
7029 let raw_exp_v = ((bits_v >> 52) & 0x7FF) as i32;
7030 let (mant_b_v, bin_exp_v) = if raw_exp_v == 0 {
7031 (raw_mant_v, -1022i32)
7032 } else {
7033 (raw_mant_v | (1u64 << 52), raw_exp_v - 1023)
7034 };
7035
7036 let s: i32 = (p as i32) + 1 - exp;
7037 let bs: i32 = bin_exp_v - 52 + s;
7038
7039 let mut limbs = [0u32; 40];
7040 limbs[0] = mant_b_v as u32;
7041 limbs[1] = (mant_b_v >> 32) as u32;
7042 let mut nlimbs: usize = if limbs[1] != 0 { 2 } else { 1 };
7043
7044 if s > 0 {
7045 for _ in 0..(s as usize) {
7046 let mut carry = 0u64;
7047 for j in 0..nlimbs {
7048 let val = limbs[j] as u64 * 5 + carry;
7049 limbs[j] = val as u32;
7050 carry = val >> 32;
7051 }
7052 if carry > 0 { limbs[nlimbs] = carry as u32; nlimbs += 1; }
7053 }
7054 }
7055
7056 if bs > 0 {
7057 let ws = (bs as u32 / 32) as usize;
7058 let bit = bs as u32 % 32;
7059 if ws > 0 {
7060 let mut i = nlimbs;
7061 while i > 0 { i -= 1; if i + ws < 40 { limbs[i + ws] = limbs[i]; } limbs[i] = 0; }
7062 nlimbs += ws;
7063 }
7064 if bit > 0 {
7065 let mut carry = 0u32;
7066 for i in ws..nlimbs {
7067 let new_val = (limbs[i] << bit) | carry;
7068 carry = limbs[i] >> (32 - bit);
7069 limbs[i] = new_val;
7070 }
7071 if carry > 0 && nlimbs < 40 { limbs[nlimbs] = carry; nlimbs += 1; }
7072 }
7073 }
7074
7075 let mut has_rest = false;
7076 if s < 0 {
7077 for _ in 0..(-s as usize) {
7078 let mut rem = 0u64;
7079 for i in (0..nlimbs).rev() {
7080 let val = (rem << 32) | limbs[i] as u64;
7081 limbs[i] = (val / 5) as u32;
7082 rem = val % 5;
7083 }
7084 if rem != 0 { has_rest = true; }
7085 }
7086 }
7087
7088 if bs < 0 {
7089 let rshift = (-bs) as u32;
7090 let ws = (rshift / 32) as usize;
7091 let bit = rshift % 32;
7092 if ws > 0 {
7093 for j in 0..ws.min(nlimbs) { if limbs[j] != 0 { has_rest = true; } }
7094 for i in ws..nlimbs { limbs[i - ws] = limbs[i]; }
7095 nlimbs = nlimbs.saturating_sub(ws);
7096 }
7097 if bit > 0 && nlimbs > 0 {
7098 let mask = (1u32 << bit) - 1;
7099 if limbs[0] & mask != 0 { has_rest = true; }
7100 for i in 0..nlimbs - 1 {
7101 limbs[i] = (limbs[i] >> bit) | (limbs[i + 1] << (32 - bit));
7102 }
7103 limbs[nlimbs - 1] >>= bit;
7104 }
7105 }
7106
7107 while nlimbs > 0 && limbs[nlimbs - 1] == 0 { nlimbs -= 1; }
7108
7109 let ndigits = p + 2;
7110 let mut all_digits = [0u8; 25];
7111 let mut nd = 0usize;
7112 if nlimbs > 0 {
7113 loop {
7114 let mut all_zero = true;
7115 for i in 0..nlimbs { if limbs[i] != 0 { all_zero = false; break; } }
7116 if all_zero { break; }
7117 let mut rem64 = 0u64;
7118 for i in (0..nlimbs).rev() {
7119 let val = (rem64 << 32) | limbs[i] as u64;
7120 limbs[i] = (val / 10) as u32;
7121 rem64 = val % 10;
7122 }
7123 if nd < 25 { all_digits[nd] = rem64 as u8; }
7124 nd += 1;
7125 }
7126 }
7127
7128 if nd >= ndigits {
7129 for i in 0..ndigits { fbuf[ndigits - 1 - i] = all_digits[i]; }
7130 } else {
7131 for i in 0..nd { fbuf[ndigits - 1 - i] = all_digits[i]; }
7132 for i in nd..ndigits { fbuf[ndigits - 1 - i] = 0; }
7133 }
7134
7135 int_part = fbuf[0] as u64;
7136
7137 if p > 0 {
7139 let next_d = fbuf[p + 1];
7140 let last_d = fbuf[p];
7141 if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
7142 let mut carry = true;
7143 for j in (1..=p).rev() {
7144 if !carry { break; }
7145 let d = fbuf[j] + 1;
7146 if d < 10 { fbuf[j] = d; carry = false; break; }
7147 fbuf[j] = 0;
7148 }
7149 if carry { int_part += 1; }
7150 }
7151 } else {
7152 let next_d = fbuf[1];
7153 if next_d > 5 || (next_d == 5 && (has_rest || int_part & 1 != 0)) {
7154 int_part += 1;
7155 }
7156 }
7157
7158 for i in 0..p { fbuf[i] = fbuf[i + 1]; }
7161 }
7162
7163 if !use_f && int_part >= 10 {
7164 exp += 1;
7165 int_part = 1;
7166 }
7167
7168 if use_f {
7170 let (ibuf, ilen) = format_u64(int_part);
7172 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
7173 pos += ilen;
7174 if p > 0 || flags & FLAG_HASH != 0 {
7175 *dst.add(pos) = b'.'; pos += 1;
7176 for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7177 }
7178 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7179 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7180 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7181 }
7182 } else {
7183 *dst.add(pos) = b'0' + int_part as u8; pos += 1;
7185 if p > 0 || flags & FLAG_HASH != 0 {
7186 *dst.add(pos) = b'.'; pos += 1;
7187 for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7188 }
7189 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7190 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7191 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7192 }
7193 let ec = if uppercase { b'E' } else { b'e' };
7194 *dst.add(pos) = ec; pos += 1;
7195 *dst.add(pos) = if exp < 0 { b'-' } else { b'+' }; pos += 1;
7196 let eabs = if exp < 0 { (-exp) as u32 } else { exp as u32 };
7197 if eabs < 10 { *dst.add(pos) = b'0'; pos += 1; }
7198 let (ebuf, elen) = format_u64(eabs as u64);
7199 core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7200 pos += elen;
7201 }
7202
7203 pos
7204}
7205
7206unsafe fn compute_exp10(v: f64) -> i32 {
7208 let e = libm::floor(libm::log10(v)) as i32;
7209 let probe = v / libm::pow(10.0, e as f64);
7210 if probe >= 10.0 { e + 1 }
7211 else if probe < 1.0 { e - 1 }
7212 else { e }
7213}
7214
7215unsafe fn fmt_hex_float(dst: *mut u8, val: f64, precision: i32, _flags: u8, uppercase: bool) -> usize {
7217 if val.to_bits() & 0x7FFFFFFFFFFFFFFF == 0 {
7219 let lc = !uppercase;
7220 let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7221 let p = if precision < 0 { 0usize } else { precision as usize };
7222 let mut pos = 0usize;
7223 core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7224 *dst.add(pos) = b'0'; pos += 1;
7225 if p > 0 {
7226 *dst.add(pos) = b'.'; pos += 1;
7227 for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
7228 }
7229 let pc = if lc { b'p' } else { b'P' };
7230 *dst.add(pos) = pc; pos += 1;
7231 *dst.add(pos) = b'+'; pos += 1;
7232 *dst.add(pos) = b'0'; pos += 1;
7233 return pos;
7234 }
7235 let bits = val.to_bits();
7236 let exp_bits = ((bits >> 52) & 0x7FF) as i32;
7237 let mant_bits = bits & 0x000FFFFFFFFFFFFF;
7238 let (e, m) = if exp_bits == 0 { (1 - 1023, mant_bits) } else { (exp_bits - 1023, mant_bits | (1u64 << 52)) };
7239 let p = if precision < 0 { 13usize } else { precision as usize };
7240 let mut pos = 0usize;
7241 let lc = !uppercase;
7242 let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7243 core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7244
7245 let lead = ((m >> 52) & 0xF) as u8;
7247 *dst.add(pos) = hex_digit_char(lead, lc); pos += 1;
7248 if p > 0 {
7249 *dst.add(pos) = b'.'; pos += 1;
7250 }
7251
7252 let frac_start = pos;
7254 let mut rm = m << 4; for _ in 0..p {
7256 let nib = ((rm >> 48) & 0xF) as u8;
7257 *dst.add(pos) = hex_digit_char(nib, lc); pos += 1;
7258 rm <<= 4;
7259 }
7260
7261 if p > 0 {
7263 let round_nib = ((rm >> 48) & 0xF) as u8;
7264 let rest = rm & 0x0000FFFFFFFFFFFF;
7265 let last_nib = if p > 0 {
7266 let c = *dst.add(pos - 1);
7267 hex_char_val(c)
7268 } else { lead };
7269 let should_round = round_nib > 8 || (round_nib == 8 && (rest != 0 || (last_nib & 1) != 0));
7270 if should_round {
7271 let mut j = pos - 1;
7272 loop {
7273 if j < frac_start { break; }
7274 let v = hex_char_val(*dst.add(j));
7275 if v < 15 {
7276 *dst.add(j) = hex_digit_char(v + 1, lc);
7277 break;
7278 } else {
7279 *dst.add(j) = b'0';
7280 if j == frac_start { break; }
7281 j -= 1;
7282 }
7283 }
7284 }
7285 }
7286
7287 let pc = if lc { b'p' } else { b'P' };
7289 *dst.add(pos) = pc; pos += 1;
7290 *dst.add(pos) = if e < 0 { b'-' } else { b'+' }; pos += 1;
7291 let eabs = if e < 0 { (-e) as u32 } else { e as u32 };
7292 let (ebuf, elen) = format_u64(eabs as u64);
7293 core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7294 pos += elen;
7295 pos
7296}
7297
7298#[inline]
7299fn hex_digit_char(v: u8, lowercase: bool) -> u8 {
7300 if v < 10 { b'0' + v }
7301 else if lowercase { b'a' + v - 10 }
7302 else { b'A' + v - 10 }
7303}
7304
7305#[inline]
7306fn hex_char_val(c: u8) -> u8 {
7307 if c >= b'0' && c <= b'9' { c - b'0' }
7308 else if c >= b'a' && c <= b'f' { c - b'a' + 10 }
7309 else if c >= b'A' && c <= b'F' { c - b'A' + 10 }
7310 else { 0 }
7311}
7312
7313unsafe fn apply_width_flags(
7316 dst: *mut u8, buf: *const u8, len: usize, width: usize, flags: u8,
7317) -> usize {
7318 if len >= width {
7319 core::ptr::copy_nonoverlapping(buf, dst, len);
7320 return len;
7321 }
7322 let pad = width - len;
7323 let pad_char = if flags & FLAG_ZERO != 0 && flags & FLAG_MINUS == 0 { b'0' } else { b' ' };
7324 if flags & FLAG_MINUS != 0 {
7325 core::ptr::copy_nonoverlapping(buf, dst, len);
7327 for i in 0..pad { *dst.add(len + i) = pad_char; }
7328 } else {
7329 if flags & FLAG_ZERO != 0 && len > 0 {
7332 let first = *buf;
7333 if first == b'-' || first == b'+' || first == b' ' {
7334 *dst = first;
7335 for i in 0..pad { *dst.add(1 + i) = pad_char; }
7336 core::ptr::copy_nonoverlapping(buf.add(1), dst.add(1 + pad), len - 1);
7337 return width;
7338 }
7339 }
7340 for i in 0..pad { *dst.add(i) = pad_char; }
7341 core::ptr::copy_nonoverlapping(buf, dst.add(pad), len);
7342 }
7343 width
7344}
7345
7346#[no_mangle]
7347pub unsafe extern "C" fn vprintf(fmt: *const c_char, mut args: VaList) -> c_int {
7348 impl_format!(fmt, args,
7349 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
7350 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
7351 )
7352}
7353
7354#[no_mangle]
7355pub unsafe extern "C" fn vfprintf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
7356 impl_format!(fmt, args,
7357 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
7358 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
7359 )
7360}
7361
7362#[no_mangle]
7363pub unsafe extern "C" fn printf(fmt: *const c_char, mut args: ...) -> c_int {
7364 impl_format!(fmt, args,
7365 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
7366 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
7367 )
7368}
7369
7370#[no_mangle]
7371pub unsafe extern "C" fn fprintf(stream: *mut FILE, fmt: *const c_char, mut args: ...) -> c_int {
7372 impl_format!(fmt, args,
7373 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
7374 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
7375 )
7376}
7377
7378#[no_mangle]
7379pub unsafe extern "C" fn dprintf(fd: c_int, fmt: *const c_char, mut args: ...) -> c_int {
7380 impl_format!(fmt, args,
7381 |c: u8| { write_str(fd, &c as *const u8, 1); },
7382 |s: *const u8, len: usize| { write_str(fd, s, len); }
7383 )
7384}
7385
7386#[no_mangle]
7387pub unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, mut args: VaList) -> c_int {
7388 impl_format!(fmt, args,
7389 |c: u8| { write_str(fd, &c as *const u8, 1); },
7390 |s: *const u8, len: usize| { write_str(fd, s, len); }
7391 )
7392}
7393
7394unsafe fn format_to_buf(buf: *mut u8, cap: usize, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
7399 let mut pos = 0usize;
7400 let mut i = 0usize;
7401 let mut count = 0usize;
7402 macro_rules! wc {
7403 ($c:expr) => { if pos < cap { *buf.add(pos) = $c; } pos += 1; count += 1; }
7404 }
7405 macro_rules! ws {
7406 ($s:expr, $len:expr) => {{
7407 let __len = $len;
7408 for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$s.add(k); } }
7409 pos += __len; count += __len;
7410 }}
7411 }
7412 macro_rules! ws_buf {
7414 ($src:expr, $len:expr) => {{
7415 let __len = $len;
7416 for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$src.add(k); } }
7417 pos += __len; count += __len;
7418 }}
7419 }
7420 loop {
7421 let c = *fmt.add(i) as u8;
7422 if c == 0 { break; }
7423 if c != b'%' { wc!(c); i += 1; continue; }
7424 i += 1;
7425 let mut flags: u8 = 0;
7427 loop {
7428 let fc = *fmt.add(i) as u8;
7429 match fc {
7430 b'-' => { flags |= FLAG_MINUS; i += 1; }
7431 b'+' => { flags |= FLAG_PLUS; i += 1; }
7432 b' ' => { flags |= FLAG_SPACE; i += 1; }
7433 b'0' => { flags |= FLAG_ZERO; i += 1; }
7434 b'#' => { flags |= FLAG_HASH; i += 1; }
7435 _ => break,
7436 }
7437 }
7438 let mut width: usize = 0;
7440 if *fmt.add(i) as u8 == b'*' {
7441 width = args.next_arg::<c_int>() as usize; i += 1;
7442 } else {
7443 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
7444 width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
7445 }
7446 }
7447 let mut precision: i32 = -1;
7449 if *fmt.add(i) as u8 == b'.' {
7450 i += 1;
7451 if *fmt.add(i) as u8 == b'*' {
7452 precision = args.next_arg::<c_int>(); i += 1;
7453 } else {
7454 precision = 0;
7455 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
7456 precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
7457 }
7458 }
7459 }
7460 let len_mod = *fmt.add(i) as u8;
7462 let spec: u8;
7463 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' {
7464 i += 1;
7465 let len_mod2 = *fmt.add(i) as u8;
7466 if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
7467 i += 1;
7468 spec = *fmt.add(i) as u8;
7469 match (len_mod, len_mod2, spec) {
7470 (b'h', b'h', b'n') => {
7471 let p = args.next_arg::<*mut c_void>();
7472 if !p.is_null() { *(p as *mut u8) = count as u8; }
7473 }
7474 (b'l', b'l', b'n') => {
7475 let p = args.next_arg::<*mut c_void>();
7476 if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
7477 }
7478 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
7479 let val = args.next_arg::<c_longlong>();
7480 let neg = val < 0;
7481 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
7482 let b = format_u64(abs);
7483 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7484 let mut fbuf = [0u8; 32];
7485 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7486 ws_buf!(fbuf.as_ptr(), len);
7487 }
7488 (b'l', b'l', b'u') => {
7489 let val = args.next_arg::<c_ulonglong>();
7490 let b = format_u64(val as u64);
7491 let mut fbuf = [0u8; 32];
7492 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7493 ws_buf!(fbuf.as_ptr(), len);
7494 }
7495 (b'l', b'l', b'o') => {
7496 let val = args.next_arg::<c_ulonglong>();
7497 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
7498 let mut fbuf = [0u8; 32];
7499 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7500 ws_buf!(fbuf.as_ptr(), len);
7501 }
7502 _ => { wc!(b'%'); wc!(len_mod); wc!(len_mod2); wc!(spec); }
7503 }
7504 } else {
7505 spec = len_mod2;
7506 match (len_mod, spec) {
7507 (b'h', b'n') => {
7508 let p = args.next_arg::<*mut c_void>();
7509 if !p.is_null() { *(p as *mut u16) = count as u16; }
7510 }
7511 (b'l', b'n') => {
7512 let p = args.next_arg::<*mut c_void>();
7513 if !p.is_null() { *(p as *mut c_long) = count as c_long; }
7514 }
7515 (b'z', b'n') | (b't', b'n') => {
7516 let p = args.next_arg::<*mut c_void>();
7517 if !p.is_null() { *(p as *mut usize) = count; }
7518 }
7519 (b'j', b'n') => {
7520 let p = args.next_arg::<*mut c_void>();
7521 if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
7522 }
7523 (b'l', b'd') | (b'l', b'i') => {
7524 let val = args.next_arg::<c_long>();
7525 let neg = val < 0;
7526 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
7527 let b = format_u64(abs);
7528 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7529 let mut fbuf = [0u8; 32];
7530 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7531 ws_buf!(fbuf.as_ptr(), len);
7532 }
7533 (b'l', b'u') => {
7534 let val = args.next_arg::<c_ulong>();
7535 let b = format_u64(val as u64);
7536 let mut fbuf = [0u8; 32];
7537 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7538 ws_buf!(fbuf.as_ptr(), len);
7539 }
7540 (b'l', b'x') => {
7541 let val = args.next_arg::<c_ulong>();
7542 let b = format_hex(val as u64, false);
7543 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7544 let mut fbuf = [0u8; 32];
7545 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7546 ws_buf!(fbuf.as_ptr(), len);
7547 }
7548 (b'l', b'X') => {
7549 let val = args.next_arg::<c_ulong>();
7550 let b = format_hex(val as u64, true);
7551 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7552 let mut fbuf = [0u8; 32];
7553 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7554 ws_buf!(fbuf.as_ptr(), len);
7555 }
7556 (b'l', b'o') => {
7557 let val = args.next_arg::<c_ulong>();
7558 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
7559 let mut fbuf = [0u8; 32];
7560 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7561 ws_buf!(fbuf.as_ptr(), len);
7562 }
7563 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
7564 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
7565 let val = args.next_arg::<f64>();
7566 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7567 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7568 let mut fbuf = [0u8; 4224];
7569 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7570 let mut wbuf = [0u8; 4224];
7571 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
7572 ws_buf!(wbuf.as_ptr(), wlen);
7573 }
7574 (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
7575 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
7576 #[cfg(target_arch = "aarch64")]
7577 let val = {
7578 let lo: u64 = args.next_arg::<u64>();
7579 let hi: u64 = args.next_arg::<u64>();
7580 let combined: u128 = ((hi as u128) << 64) | (lo as u128);
7581 f128::from_bits(combined) as f64
7582 };
7583 #[cfg(target_arch = "x86_64")]
7584 let val = args.next_arg::<f64>();
7585 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7586 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7587 let mut fbuf = [0u8; 4224];
7588 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7589 let mut wbuf = [0u8; 4224];
7590 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
7591 ws_buf!(wbuf.as_ptr(), wlen);
7592 }
7593 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
7594 }
7595 }
7596 } else {
7597 spec = *fmt.add(i) as u8;
7598 match spec {
7599 b's' => {
7600 let s = args.next_arg::<*const c_char>();
7601 if s.is_null() {
7602 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
7603 let padded_len = if width > slen { width } else { slen };
7604 let pad = padded_len - slen;
7605 if flags & FLAG_MINUS != 0 {
7606 ws!(b"(null)".as_ptr(), slen);
7607 for _ in 0..pad { wc!(b' '); }
7608 } else {
7609 for _ in 0..pad { wc!(b' '); }
7610 ws!(b"(null)".as_ptr(), slen);
7611 }
7612 } else {
7613 let full_len = strlen(s as *const c_char);
7614 let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
7615 let padded_len = if width > slen { width } else { slen };
7616 let pad = padded_len - slen;
7617 if flags & FLAG_MINUS != 0 {
7618 ws!(s as *const u8, slen);
7619 for _ in 0..pad { wc!(b' '); }
7620 } else {
7621 for _ in 0..pad { wc!(b' '); }
7622 ws!(s as *const u8, slen);
7623 }
7624 }
7625 }
7626 b'd' | b'i' => {
7627 let d = args.next_arg::<c_int>();
7628 let neg = d < 0;
7629 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
7630 let b = format_u64(abs);
7631 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7632 let mut fbuf = [0u8; 32];
7633 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7634 ws_buf!(fbuf.as_ptr(), len);
7635 }
7636 b'u' => {
7637 let u = args.next_arg::<c_uint>();
7638 let b = format_u64(u as u64);
7639 let mut fbuf = [0u8; 32];
7640 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7641 ws_buf!(fbuf.as_ptr(), len);
7642 }
7643 b'x' => {
7644 let x = args.next_arg::<c_uint>();
7645 let b = format_hex(x as u64, false);
7646 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7647 let mut fbuf = [0u8; 32];
7648 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7649 ws_buf!(fbuf.as_ptr(), len);
7650 }
7651 b'X' => {
7652 let x = args.next_arg::<c_uint>();
7653 let b = format_hex(x as u64, true);
7654 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7655 let mut fbuf = [0u8; 32];
7656 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7657 ws_buf!(fbuf.as_ptr(), len);
7658 }
7659 b'o' => {
7660 let o = args.next_arg::<c_uint>();
7661 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
7662 let mut fbuf = [0u8; 32];
7663 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7664 ws_buf!(fbuf.as_ptr(), len);
7665 }
7666 b'c' => {
7667 let ch = args.next_arg::<c_int>();
7668 if width > 1 {
7669 let pad = width - 1;
7670 if flags & FLAG_MINUS != 0 {
7671 wc!(ch as u8);
7672 for _ in 0..pad { wc!(b' '); }
7673 } else {
7674 for _ in 0..pad { wc!(b' '); }
7675 wc!(ch as u8);
7676 }
7677 } else {
7678 wc!(ch as u8);
7679 }
7680 }
7681 b'p' => {
7682 wc!(b'0'); wc!(b'x');
7683 let p = args.next_arg::<*const c_void>();
7684 let b = format_hex(p as u64, false);
7685 ws!(b.0.as_ptr(), b.1);
7686 }
7687 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
7688 let val = args.next_arg::<f64>();
7689 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7690 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7691 let mut fbuf = [0u8; 4224];
7692 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7693 let mut wbuf = [0u8; 4224];
7694 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
7695 ws_buf!(wbuf.as_ptr(), wlen);
7696 }
7697 b'%' => { wc!(b'%'); }
7698 b'n' => {
7699 let p = args.next_arg::<*mut c_void>();
7700 if !p.is_null() { *(p as *mut c_int) = count as c_int; }
7701 }
7702 _ => { wc!(b'%'); wc!(spec); }
7703 }
7704 }
7705 i += 1;
7706 }
7707 if cap > 0 { let null_pos = if pos < cap { pos } else { cap - 1 }; *buf.add(null_pos) = 0; }
7708 count as c_int
7709}
7710
7711#[no_mangle]
7712pub unsafe extern "C" fn vsprintf(buf: *mut c_char, fmt: *const c_char, mut args: VaList) -> c_int {
7713 format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
7714}
7715
7716#[no_mangle]
7717pub unsafe extern "C" fn vsnprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: VaList) -> c_int {
7718 format_to_buf(buf as *mut u8, size, fmt, &mut args)
7719}
7720
7721#[no_mangle]
7722pub unsafe extern "C" fn sprintf(buf: *mut c_char, fmt: *const c_char, mut args: ...) -> c_int {
7723 format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
7724}
7725
7726#[no_mangle]
7727pub unsafe extern "C" fn snprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: ...) -> c_int {
7728 format_to_buf(buf as *mut u8, size, fmt, &mut args)
7729}
7730
7731unsafe fn skip_ws(p: *const u8) -> *const u8 {
7736 let mut q = p;
7737 while *q == b' ' || *q == b'\t' || *q == b'\n' || *q == b'\r' { q = q.add(1); }
7738 q
7739}
7740
7741#[inline]
7742fn is_ws_byte(c: u8) -> bool {
7743 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0b || c == 0x0c
7744}
7745
7746unsafe fn scan_int_val(
7749 buf: *const u8, pos: &mut usize, buf_len: usize, base: u32, width: usize,
7750) -> (u64, bool, bool) {
7751 let start = *pos;
7752 let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
7753 let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
7754 else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
7755 else { false };
7756 if *pos >= max { *pos = start; return (0, false, false); }
7757 let mut base = base;
7758 let mut val: u64 = 0;
7759 if (base == 0 || base == 16) && *pos < max && *buf.add(*pos) == b'0' {
7761 *pos += 1;
7762 if *pos < max && (*buf.add(*pos) == b'x' || *buf.add(*pos) == b'X') {
7763 *pos += 1;
7764 if *pos < max {
7765 if let Some(d) = hex_val(*buf.add(*pos)) {
7766 val = d as u64; *pos += 1;
7767 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; } }
7768 return (val, neg, true);
7769 }
7770 }
7771 return (0, neg, false);
7772 } else if base == 0 {
7773 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; } }
7774 return (val, neg, true);
7775 } else {
7776 return (0, neg, true); }
7778 }
7779 if base == 0 { base = 10; }
7780 let mut found = false;
7781 while *pos < max {
7782 let c = *buf.add(*pos);
7783 let d: Option<u64> = match base {
7784 8 => if c >= b'0' && c <= b'7' { Some((c - b'0') as u64) } else { None },
7785 10 => if c >= b'0' && c <= b'9' { Some((c - b'0') as u64) } else { None },
7786 16 => hex_val(c).map(|v| v as u64),
7787 _ => None,
7788 };
7789 match d { Some(digit) => { val = val.wrapping_mul(base as u64).wrapping_add(digit); *pos += 1; found = true; } None => break }
7790 }
7791 if !found { *pos = start; return (0, false, false); }
7792 (val, neg, true)
7793}
7794
7795unsafe fn scan_float_val(
7797 buf: *const u8, pos: &mut usize, buf_len: usize, width: usize,
7798) -> (f64, bool) {
7799 let start = *pos;
7800 let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
7801 let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
7802 else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
7803 else { false };
7804 if *pos + 2 < max {
7806 let (c0,c1,c2) = (*buf.add(*pos), *buf.add(*pos+1), *buf.add(*pos+2));
7807 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); }
7808 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); }
7809 }
7810 if *pos+1 < max && *buf.add(*pos)==b'0' && (*buf.add(*pos+1)==b'x'||*buf.add(*pos+1)==b'X') {
7812 *pos += 2;
7813 let mut val: f64 = 0.0; let mut found = false; let mut frac_scale = 1.0f64; let mut in_frac = false;
7814 while *pos < max {
7815 if let Some(d) = hex_val(*buf.add(*pos)) {
7816 if in_frac { frac_scale /= 16.0; val += d as f64 * frac_scale; } else { val = val * 16.0 + d as f64; }
7817 *pos += 1; found = true;
7818 } else if *buf.add(*pos)==b'.' && !in_frac { in_frac = true; *pos += 1; } else { break; }
7819 }
7820 if !found { *pos = start; return (0.0, false); }
7821 if *pos < max && (*buf.add(*pos)==b'p'||*buf.add(*pos)==b'P') {
7823 *pos += 1;
7824 let mut eneg = false;
7825 if *pos<max && *buf.add(*pos)==b'-' { eneg=true; *pos+=1; }
7826 else if *pos<max && *buf.add(*pos)==b'+' { *pos+=1; }
7827 let mut ev: i32 = 0; let mut ef = false;
7828 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; }
7829 if !ef { return (0.0, false); }
7830 if eneg { ev = -ev; }
7831 val *= libm::pow(2.0, ev as f64);
7832 }
7833 return (if neg{-val}else{val}, true);
7834 }
7835 let token_start = start;
7836 let mut i = start;
7837 let mut saw_digit = false;
7838 let mut saw_dot = false;
7839 let mut saw_exp = false;
7840 let mut first = true;
7841 while i < max {
7842 let c = *buf.add(i);
7843 if (c == b'+' || c == b'-') && first {
7844 i += 1; first = false; continue;
7845 }
7846 if c >= b'0' && c <= b'9' {
7847 saw_digit = true; i += 1; first = false; continue;
7848 }
7849 if c == b'.' && !saw_dot && !saw_exp {
7850 saw_dot = true; i += 1; first = false; continue;
7851 }
7852 if (c == b'e' || c == b'E') && !saw_exp && saw_digit {
7853 saw_exp = true; i += 1; first = true; continue;
7854 }
7855 break;
7856 }
7857 if !saw_digit { return (0.0, false); }
7858 let s = core::str::from_utf8_unchecked(core::slice::from_raw_parts(buf.add(token_start), i - token_start));
7859 match <f64 as core::str::FromStr>::from_str(s) {
7860 Ok(v) => { *pos = i; return (v, true); }
7861 Err(_) => { return (0.0, false); }
7862 }
7863}
7864
7865unsafe fn do_vsscanf(
7868 buf: *const u8, buf_len: usize, fmt: *const c_char, args: &mut VaList<'_>, consumed: *mut usize,
7869) -> c_int {
7870 let mut p = 0usize;
7871 let mut fi = 0usize;
7872 let mut assigned = 0i32;
7873 let mut input_eof = false;
7874 loop {
7875 let fc = *fmt.add(fi) as u8;
7876 if fc == 0 { break; }
7877 if is_ws_byte(fc) {
7878 while is_ws_byte(*fmt.add(fi) as u8) { fi += 1; }
7879 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7880 continue;
7881 }
7882 if fc != b'%' {
7883 if p >= buf_len { input_eof = true; break; }
7884 if *buf.add(p) != fc { break; }
7885 p += 1; fi += 1; continue;
7886 }
7887 fi += 1;
7888 if *fmt.add(fi) as u8 == b'%' {
7890 if p >= buf_len { input_eof = true; break; }
7891 if *buf.add(p) != b'%' { break; }
7892 p += 1; fi += 1; continue;
7893 }
7894 let suppress = if *fmt.add(fi) as u8 == b'*' { fi += 1; true } else { false };
7895 let mut width: usize = 0;
7896 while (*fmt.add(fi) as u8) >= b'0' && (*fmt.add(fi) as u8) <= b'9' {
7897 width = width * 10 + ((*fmt.add(fi) as u8) - b'0') as usize; fi += 1;
7898 }
7899 if *fmt.add(fi) as u8 == b'm' { fi += 1; }
7900 let mut len_mod = 0u8;
7901 match *fmt.add(fi) as u8 {
7902 b'h' => { fi += 1; if *fmt.add(fi) as u8 == b'h' { fi += 1; len_mod = 2; } else { len_mod = 1; } }
7903 b'l' => { fi += 1; if *fmt.add(fi) as u8 == b'l' { fi += 1; len_mod = 4; } else { len_mod = 3; } }
7904 b'j' => { fi += 1; len_mod = 4; }
7905 b'z' | b't' => { fi += 1; len_mod = 3; }
7906 b'L' => { fi += 1; len_mod = 5; }
7907 _ => {}
7908 }
7909 let spec = *fmt.add(fi) as u8;
7910 let (real_spec, _real_len) = if spec==b'C' {(b'c',3u8)} else if spec==b'S' {(b's',3u8)} else {(spec,len_mod)};
7911 match real_spec {
7912 b'n' => {
7913 if !suppress { let out = args.next_arg::<*mut c_int>(); if !out.is_null() { *out = p as c_int; } }
7914 }
7915 b'd' | b'u' => {
7916 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7917 if p >= buf_len { input_eof = true; break; }
7918 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7919 let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 10, width);
7920 if !ok { break; }
7921 if let Some(out) = dest { if !out.is_null() {
7922 *out = if real_spec==b'd' && neg { -(val as i64) as c_int } else { val as c_int };
7923 }}
7924 if !suppress { assigned += 1; }
7925 }
7926 b'i' => {
7927 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7928 if p >= buf_len { input_eof = true; break; }
7929 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7930 let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 0, width);
7931 if !ok { break; }
7932 if let Some(out) = dest { if !out.is_null() { *out = if neg { -(val as i64) as c_int } else { val as c_int }; } }
7933 if !suppress { assigned += 1; }
7934 }
7935 b'o' => {
7936 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7937 if p >= buf_len { input_eof = true; break; }
7938 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7939 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 8, width);
7940 if !ok { break; }
7941 if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
7942 if !suppress { assigned += 1; }
7943 }
7944 b'x' | b'X' => {
7945 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7946 if p >= buf_len { input_eof = true; break; }
7947 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7948 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
7949 if !ok { break; }
7950 if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
7951 if !suppress { assigned += 1; }
7952 }
7953 b'p' => {
7954 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7955 if p >= buf_len { input_eof = true; break; }
7956 let dest = if !suppress { Some(args.next_arg::<*mut *mut c_void>()) } else { None };
7957 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
7958 if !ok { break; }
7959 if let Some(out) = dest { if !out.is_null() { *out = val as usize as *mut c_void; } }
7960 if !suppress { assigned += 1; }
7961 }
7962 b'a' | b'e' | b'f' | b'g' | b'A' | b'E' | b'F' | b'G' => {
7963 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7964 if p >= buf_len { input_eof = true; break; }
7965 let (val, ok) = scan_float_val(buf, &mut p, buf_len, width);
7966 if !ok { break; }
7967 if !suppress {
7968 if _real_len == 3 {
7969 let out = args.next_arg::<*mut f64>(); if !out.is_null() { *out = val; }
7970 } else if _real_len == 5 {
7971 #[cfg(target_arch = "aarch64")]
7972 { let out = args.next_arg::<*mut f128>(); if !out.is_null() { *out = val as f128; } }
7973 #[cfg(target_arch = "x86_64")]
7974 { let out = args.next_arg::<*mut f64>(); if !out.is_null() { *out = val; } }
7975 } else {
7976 let out = args.next_arg::<*mut f32>(); if !out.is_null() { *out = val as f32; }
7977 }
7978 }
7979 if !suppress { assigned += 1; }
7980 }
7981 b'c' => {
7982 let w = if width > 0 { width } else { 1 };
7983 if p >= buf_len { input_eof = true; break; }
7984 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
7985 let start_p = p;
7986 let mut j = 0usize;
7987 while j < w && p < buf_len {
7988 if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
7989 p += 1; j += 1;
7990 }
7991 if j != w { p = start_p; input_eof = true; break; }
7992 if !suppress { assigned += 1; }
7993 }
7994 b's' => {
7995 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7996 if p >= buf_len { input_eof = true; break; }
7997 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
7998 let w = if width > 0 { width } else { usize::MAX };
7999 let mut j = 0usize;
8000 while p < buf_len && *buf.add(p) != 0 && !is_ws_byte(*buf.add(p)) && j < w {
8001 if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
8002 p += 1; j += 1;
8003 }
8004 if j == 0 { break; }
8005 if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
8006 if !suppress { assigned += 1; }
8007 }
8008 b'[' => {
8009 fi += 1;
8010 let negate = if *fmt.add(fi) as u8 == b'^' { fi += 1; true } else { false };
8011 let mut charset = [0u8; 256];
8012 if *fmt.add(fi) as u8 == b']' { charset[b']' as usize] = 1; fi += 1; }
8013 loop { let c = *fmt.add(fi) as u8; if c == b']' || c == 0 { break; } charset[c as usize] = 1; fi += 1; }
8014 if *fmt.add(fi) as u8 == b']' { fi += 1; }
8015 fi -= 1; if p >= buf_len { input_eof = true; break; }
8017 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
8018 let w = if width > 0 { width } else { usize::MAX };
8019 let mut j = 0usize;
8020 while p < buf_len && *buf.add(p) != 0 && j < w {
8021 let c = *buf.add(p);
8022 let in_set = charset[c as usize] != 0;
8023 if negate { if in_set { break; } } else { if !in_set { break; } }
8024 if !dest_ptr.is_null() { *dest_ptr.add(j) = c as c_char; }
8025 p += 1; j += 1;
8026 }
8027 if j == 0 { break; }
8028 if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
8029 if !suppress { assigned += 1; }
8030 }
8031 _ => break,
8032 }
8033 fi += 1;
8034 }
8035 if !consumed.is_null() { *consumed = p; }
8036 if assigned == 0 && input_eof { -1 } else { assigned }
8037}
8038
8039unsafe fn vsscanf_inner(buf: *const u8, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
8040 let len = strlen(buf as *const c_char);
8041 do_vsscanf(buf, len, fmt, args, core::ptr::null_mut())
8042}
8043
8044#[no_mangle]
8045pub unsafe extern "C" fn vsscanf(buf: *const c_char, fmt: *const c_char, mut args: VaList) -> c_int {
8046 vsscanf_inner(buf as *const u8, fmt, &mut args)
8047}
8048
8049#[no_mangle]
8050pub unsafe extern "C" fn vfscanf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
8051 let f = &mut *stream;
8052 let start_ungotten_count = f.ungotten_count as usize;
8053 let sfunc = f.seek_fn;
8054 let start_pos = sfunc.map(|s| s(stream, 0, SEEK_CUR)).unwrap_or(-1);
8055
8056 let mut line = [0u8; 4096];
8057 let mut pos = 0usize;
8058
8059 if start_pos >= 0 {
8060 while pos < line.len() - 1 {
8062 let c = fgetc(stream);
8063 if c == -1 { break; }
8064 line[pos] = c as u8;
8065 pos += 1;
8066 if c == b'\n' as c_int { break; }
8067 }
8068 } else {
8069 while f.ungotten_count > 0 && pos < line.len() - 1 {
8074 f.ungotten_count -= 1;
8075 line[pos] = f.ungotten[f.ungotten_count as usize] as u8;
8076 pos += 1;
8077 }
8078 while !f.rpos.is_null() && f.rpos < f.rend && pos < line.len() - 1 {
8080 line[pos] = *f.rpos;
8081 f.rpos = f.rpos.add(1);
8082 pos += 1;
8083 }
8084 let fd = f.fd;
8086 let old_flags = sys_fcntl(fd, F_GETFL, 0);
8087 if old_flags >= 0 {
8088 let _ = sys_fcntl(fd, F_SETFL, old_flags | O_NONBLOCK as i64);
8089 }
8090 while pos < line.len() - 1 {
8091 let n = sys_read(fd as i64, line.as_mut_ptr().add(pos), line.len() - 1 - pos);
8092 if n <= 0 { break; }
8093 pos += n as usize;
8094 }
8095 if old_flags >= 0 {
8096 let _ = sys_fcntl(fd, F_SETFL, old_flags);
8097 }
8098 f._eof = 0;
8100 f._err = 0;
8101 f.flags &= !(F_EOF | F_ERR);
8102 }
8103
8104 line[pos] = 0;
8105 if pos == 0 { return 0; }
8106
8107 let mut consumed = 0usize;
8108 let assigned = do_vsscanf(line.as_ptr(), pos, fmt, &mut args, &mut consumed);
8109
8110 if start_pos >= 0 {
8111 let file_consumed = consumed.saturating_sub(start_ungotten_count);
8113 let target = start_pos + file_consumed as i64;
8114 if let Some(sfunc) = sfunc {
8115 sfunc(stream, target, SEEK_SET);
8116 }
8117 f.rpos = core::ptr::null_mut();
8118 f.rend = core::ptr::null_mut();
8119 if consumed < pos { f._eof = 0; }
8120 let remaining = start_ungotten_count.saturating_sub(consumed);
8121 f.ungotten_count = remaining as c_int;
8122 } else {
8123 let unconsumed = pos.saturating_sub(consumed);
8125 if unconsumed > 0 && !f.buf.is_null() {
8126 let copy_count = core::cmp::min(unconsumed, f.buf_size);
8127 core::ptr::copy(
8128 line.as_ptr().add(consumed),
8129 f.buf,
8130 copy_count,
8131 );
8132 f.rpos = f.buf;
8133 f.rend = f.buf.add(copy_count);
8134 }
8135 f.ungotten_count = 0;
8136 f._eof = 0;
8137 f.flags &= !F_EOF;
8138 }
8139 assigned
8140}
8141
8142#[no_mangle]
8143pub unsafe extern "C" fn vscanf(fmt: *const c_char, args: VaList) -> c_int {
8144 vfscanf(stdin, fmt, args)
8145}
8146
8147#[no_mangle]
8148pub unsafe extern "C" fn sscanf(buf: *const c_char, fmt: *const c_char, mut args: ...) -> c_int {
8149 vsscanf_inner(buf as *const u8, fmt, &mut args)
8150}
8151
8152#[no_mangle]
8153pub unsafe extern "C" fn fscanf(stream: *mut FILE, fmt: *const c_char, args: ...) -> c_int {
8154 vfscanf(stream, fmt, args)
8155}
8156
8157#[no_mangle]
8158pub unsafe extern "C" fn scanf(fmt: *const c_char, args: ...) -> c_int {
8159 vfscanf(stdin, fmt, args)
8160}
8161
8162#[no_mangle]
8167pub unsafe extern "C" fn getdelim(
8168 lineptr: *mut *mut c_char, n: *mut usize, delim: c_int, stream: *mut FILE,
8169) -> isize {
8170 if lineptr.is_null() || n.is_null() { return -1; }
8171 let mut cap = *n;
8172 let mut buf = *lineptr;
8173 if buf.is_null() || cap == 0 {
8174 cap = 128;
8175 buf = realloc(buf as *mut c_void, cap) as *mut c_char;
8176 if buf.is_null() { return -1; }
8177 *lineptr = buf;
8178 *n = cap;
8179 }
8180 let mut len = 0usize;
8181 loop {
8182 let c = fgetc(stream);
8183 if c == -1 { if len == 0 { return -1; } break; }
8184 if len + 1 >= cap {
8185 let new_cap = cap.wrapping_mul(2);
8186 let new_buf = realloc(buf as *mut c_void, new_cap) as *mut c_char;
8187 if new_buf.is_null() { return -1; }
8188 buf = new_buf; cap = new_cap;
8189 *lineptr = buf; *n = cap;
8190 }
8191 *buf.add(len) = c as c_char;
8192 len += 1;
8193 if c == delim { break; }
8194 }
8195 *buf.add(len) = 0;
8196 len as isize
8197}
8198
8199#[no_mangle]
8200pub unsafe extern "C" fn getline(lineptr: *mut *mut c_char, n: *mut usize, stream: *mut FILE) -> isize {
8201 getdelim(lineptr, n, b'\n' as c_int, stream)
8202}
8203
8204#[no_mangle]
8209pub unsafe extern "C" fn popen(cmd: *const c_char, mode: *const c_char) -> *mut FILE {
8210 if cmd.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
8211 let m = *mode;
8212 if m != b'r' as c_char && m != b'w' as c_char { ERRNO = EINVAL; return core::ptr::null_mut(); }
8213 let mut p: [c_int; 2] = [0; 2];
8214 if sys_pipe2(p.as_mut_ptr(), O_CLOEXEC) < 0 { return core::ptr::null_mut(); }
8215 let op = if m == b'r' as c_char { 0 } else { 1 };
8216 let child_fd = p[1 - op];
8217 let f = fdopen(p[op], mode);
8218 if f.is_null() { sys_close(p[0] as i64); sys_close(p[1] as i64); return core::ptr::null_mut(); }
8219 let pid = sys_fork();
8220 if pid < 0 { fclose(f); sys_close(child_fd as i64); return core::ptr::null_mut(); }
8221 if pid == 0 {
8222 sys_close(p[op] as i64);
8223 if child_fd != (1 - op) as c_int { sys_dup3(child_fd, (1 - op) as c_int, 0); sys_close(child_fd as i64); }
8224 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
8225 let argv = [b"sh\0".as_ptr() as *const c_char, b"-c\0".as_ptr() as *const c_char, cmd, core::ptr::null()];
8226 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
8227 _exit(127);
8228 }
8229 sys_close(child_fd as i64);
8230 (*f).pipe_pid = pid as c_int;
8231 f
8232}
8233
8234#[no_mangle]
8235pub unsafe extern "C" fn pclose(f: *mut FILE) -> c_int {
8236 let pid = (*f).pipe_pid;
8237 let r = fclose(f);
8238 if pid <= 0 { return -1; }
8239 let mut status: c_int = 0;
8240 let mut w: c_int;
8241 loop {
8242 w = waitpid(pid, &mut status, 0);
8243 if w >= 0 || w != -EINTR { break; }
8244 }
8245 if w < 0 || r != 0 { return -1; }
8246 status
8247}
8248
8249const L_TMPNAM: usize = 20;
8254static mut TMPNAM_COUNTER: c_uint = 0;
8255
8256unsafe fn fill_tmpname(out: *mut c_char, seed: c_uint) {
8257 let prefix = b"/tmp/tmp\0";
8258 let mut k = 0;
8259 while k < prefix.len() - 1 { *out.add(k) = prefix[k] as c_char; k += 1; }
8260 let (buf, len) = format_hex(seed as u64, false);
8261 for j in 0..len.min(L_TMPNAM - k - 1) { *out.add(k + j) = buf[j] as c_char; k += 1; }
8262 *out.add(k) = 0;
8263}
8264
8265#[no_mangle]
8266pub unsafe extern "C" fn tmpfile() -> *mut FILE {
8267 let mut name = [0u8; L_TMPNAM];
8268 let mut ctr: c_uint = 0;
8269 loop {
8270 ctr = ctr.wrapping_add(1);
8271 let mut ts: timespec = core::mem::zeroed();
8272 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8273 let seed = (ts.tv_nsec as c_uint).wrapping_add(ctr);
8274 fill_tmpname(name.as_mut_ptr() as *mut c_char, seed);
8275 let fd = sys_open(name.as_ptr(), (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
8276 if fd >= 0 {
8277 sys_unlinkat(AT_FDCWD, name.as_ptr(), 0);
8278 let f = fdopen(fd as c_int, b"w+\0".as_ptr() as *const c_char);
8279 if f.is_null() { sys_close(fd); }
8280 return f;
8281 }
8282 if ctr > 100 { return core::ptr::null_mut(); }
8283 }
8284}
8285
8286#[no_mangle]
8287pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char {
8288 static mut BUF: [c_char; L_TMPNAM] = [0; L_TMPNAM];
8289 let out = if s.is_null() { core::ptr::addr_of_mut!(BUF) as *mut c_char } else { s };
8290 TMPNAM_COUNTER = TMPNAM_COUNTER.wrapping_add(1);
8291 let mut ts: timespec = core::mem::zeroed();
8292 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8293 let seed = (ts.tv_nsec as c_uint).wrapping_add(TMPNAM_COUNTER);
8294 fill_tmpname(out, seed);
8295 out
8296}
8297
8298#[no_mangle]
8299pub unsafe extern "C" fn remove(path: *const c_char) -> c_int {
8300 if path.is_null() { ERRNO = EINVAL; return -1; }
8301 let r = sys_unlinkat(AT_FDCWD, path as *const u8, 0);
8302 if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
8303}
8304
8305#[no_mangle]
8306pub unsafe extern "C" fn rename(old: *const c_char, new_: *const c_char) -> c_int {
8307 if old.is_null() || new_.is_null() { ERRNO = EINVAL; return -1; }
8308 let r = sys_renameat2(AT_FDCWD, old as *const u8, AT_FDCWD, new_ as *const u8, 0);
8309 if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
8310}
8311
8312const MMAP_FAILED: *mut u8 = !0usize as *mut u8;
8318const PAGE: usize = 4096;
8319
8320#[no_mangle]
8321pub unsafe extern "C" fn malloc(size: SizeT) -> *mut c_void {
8322 let alloc_size = if size == 0 { 1 } else { size };
8325 let total = alloc_size + core::mem::size_of::<usize>();
8327 let pages = (total + PAGE - 1) & !(PAGE - 1);
8328 let ptr = sys_mmap(
8329 null_mut(),
8330 pages,
8331 PROT_READ | PROT_WRITE,
8332 MAP_PRIVATE | MAP_ANONYMOUS,
8333 -1,
8334 0,
8335 );
8336 if ptr == MMAP_FAILED {
8337 return null_mut();
8338 }
8339 *(ptr as *mut usize) = pages;
8340 ptr.add(core::mem::size_of::<usize>()) as *mut c_void
8341}
8342
8343#[no_mangle]
8344pub unsafe extern "C" fn free(ptr: *mut c_void) {
8345 if ptr.is_null() {
8346 return;
8347 }
8348 let header = (ptr as *mut u8).sub(core::mem::size_of::<usize>());
8349 let pages = *(header as *const usize);
8350 sys_munmap(header, pages);
8351}
8352
8353#[no_mangle]
8354pub unsafe extern "C" fn calloc(count: SizeT, size: SizeT) -> *mut c_void {
8355 let total = count.saturating_mul(size);
8356 let ptr = malloc(total);
8357 if !ptr.is_null() {
8358 core::ptr::write_bytes(ptr as *mut u8, 0, total);
8359 }
8360 ptr
8361}
8362
8363#[no_mangle]
8364pub unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: SizeT) -> *mut c_void {
8365 if ptr.is_null() {
8366 return malloc(new_size);
8367 }
8368 if new_size == 0 {
8369 free(ptr);
8370 return null_mut();
8371 }
8372 let header = (ptr as *mut u8).sub(core::mem::size_of::<usize>());
8373 let old_pages = *(header as *const usize);
8374 let old_data_size = old_pages - core::mem::size_of::<usize>();
8375 let new_ptr = malloc(new_size);
8376 if new_ptr.is_null() {
8377 return null_mut();
8378 }
8379 let copy_size = if old_data_size < new_size {
8380 old_data_size
8381 } else {
8382 new_size
8383 };
8384 core::ptr::copy_nonoverlapping(ptr as *const u8, new_ptr as *mut u8, copy_size);
8385 free(ptr);
8386 new_ptr
8387}
8388
8389#[no_mangle]
8394pub unsafe extern "C" fn _exit(code: c_int) -> ! {
8395 sys_exit_group(code)
8396}
8397
8398#[inline]
8399unsafe fn sys_exit_group(code: c_int) -> ! {
8400 <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT_GROUP, code as i64)
8401}
8402
8403#[inline]
8404unsafe fn sys_exit_thread(code: c_int) -> ! {
8405 <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT, code as i64)
8406}
8407
8408#[no_mangle]
8409pub unsafe extern "C" fn _Exit(code: c_int) -> ! {
8410 _exit(code);
8411}
8412
8413#[no_mangle]
8414pub unsafe extern "C" fn exit(code: c_int) -> ! {
8415 fflush(core::ptr::null_mut());
8416 __funcs_on_exit();
8417 _exit(code);
8418}
8419
8420#[no_mangle]
8421pub unsafe extern "C" fn abort() -> ! {
8422 raise(6); _exit(128 + 6);
8424}
8425
8426#[no_mangle]
8429pub static mut __stack_chk_guard: usize = 0;
8430
8431#[no_mangle]
8432pub unsafe extern "C" fn __stack_chk_fail() -> ! {
8433 const MSG: &[u8] = b"*** stack smashing detected ***: terminated\n";
8434 let _ = sys_write(2, MSG.as_ptr(), MSG.len());
8435 abort();
8436}
8437
8438type CmpRfn = unsafe extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
8443
8444const AR_LEN: usize = 16 * core::mem::size_of::<usize>();
8445const AR_MASK: usize = AR_LEN - 1;
8446
8447unsafe fn qsort_pntz(p: &[usize; 2]) -> i32 {
8448 if p[0] != 1 {
8449 p[0].wrapping_sub(1).trailing_zeros() as i32
8450 } else if p[1] != 0 {
8451 (8 * core::mem::size_of::<usize>()) as i32 + p[1].trailing_zeros() as i32
8452 } else {
8453 0
8454 }
8455}
8456
8457unsafe fn qsort_cycle(width: usize, ar: &mut [*mut u8; AR_LEN], n: usize) {
8458 if n < 2 { return; }
8459 let mut tmp = [0u8; 256];
8460 ar[n] = tmp.as_mut_ptr();
8461 let mut w = width;
8462 while w > 0 {
8463 let l = if 256 < w { 256 } else { w };
8464 core::ptr::copy_nonoverlapping(ar[0], ar[n], l);
8465 for i in 0..n {
8466 core::ptr::copy_nonoverlapping(ar[i + 1], ar[i], l);
8467 ar[i] = ar[i].add(l);
8468 }
8469 w -= l;
8470 }
8471}
8472
8473unsafe fn qsort_shl(p: &mut [usize; 2], n: i32) {
8474 let bits = (8 * core::mem::size_of::<usize>()) as i32;
8475 if n >= bits {
8476 p[1] = p[0];
8477 p[0] = 0;
8478 let n = n - bits;
8479 if n == 0 { return; }
8480 }
8481 p[1] = (p[1] << n) | (p[0] >> (bits - n));
8482 p[0] <<= n;
8483}
8484
8485unsafe fn qsort_shr(p: &mut [usize; 2], n: i32) {
8486 let bits = (8 * core::mem::size_of::<usize>()) as i32;
8487 if n >= bits {
8488 p[0] = p[1];
8489 p[1] = 0;
8490 let n = n - bits;
8491 if n == 0 { return; }
8492 }
8493 p[0] = (p[0] >> n) | (p[1] << (bits - n));
8494 p[1] >>= n;
8495}
8496
8497unsafe fn qsort_sift(
8498 head: *mut u8, width: usize,
8499 cmp: CmpRfn, arg: *mut c_void,
8500 pshift: i32, lp: &[usize],
8501) {
8502 let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
8503 ar[0] = head;
8504 let mut i = 1usize;
8505 let mut h = head;
8506 let mut ps = pshift;
8507
8508 while ps > 1 {
8509 let rt = h.sub(width);
8510 let lf = h.sub(width + lp[(ps - 2) as usize]);
8511
8512 if cmp(ar[0] as *const c_void, lf as *const c_void, arg) >= 0
8513 && cmp(ar[0] as *const c_void, rt as *const c_void, arg) >= 0
8514 {
8515 break;
8516 }
8517 if cmp(lf as *const c_void, rt as *const c_void, arg) >= 0 {
8518 ar[i & AR_MASK] = lf;
8519 i += 1;
8520 h = lf;
8521 ps -= 1;
8522 } else {
8523 ar[i & AR_MASK] = rt;
8524 i += 1;
8525 h = rt;
8526 ps -= 2;
8527 }
8528 }
8529 qsort_cycle(width, &mut ar, i & AR_MASK);
8530}
8531
8532unsafe fn qsort_trinkle(
8533 head: *mut u8, width: usize,
8534 cmp: CmpRfn, arg: *mut c_void,
8535 pp: &[usize; 2], pshift: i32, trusty: i32,
8536 lp: &[usize],
8537) {
8538 let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
8539 let mut p = *pp;
8540 ar[0] = head;
8541 let mut i = 1usize;
8542 let mut h = head;
8543 let mut ps = pshift;
8544 let mut t = trusty;
8545
8546 while p[0] != 1 || p[1] != 0 {
8547 let stepson = h.sub(lp[ps as usize]);
8548 if cmp(stepson as *const c_void, ar[0] as *const c_void, arg) <= 0 {
8549 break;
8550 }
8551 if t == 0 && ps > 1 {
8552 let rt = h.sub(width);
8553 let lf = h.sub(width + lp[(ps - 2) as usize]);
8554 if cmp(rt as *const c_void, stepson as *const c_void, arg) >= 0
8555 || cmp(lf as *const c_void, stepson as *const c_void, arg) >= 0
8556 {
8557 break;
8558 }
8559 }
8560
8561 ar[i & AR_MASK] = stepson;
8562 i += 1;
8563 h = stepson;
8564 let trail = qsort_pntz(&p);
8565 qsort_shr(&mut p, trail);
8566 ps += trail;
8567 t = 0;
8568 }
8569 if t == 0 {
8570 qsort_cycle(width, &mut ar, i & AR_MASK);
8571 qsort_sift(h, width, cmp, arg, ps, lp);
8572 }
8573}
8574
8575#[no_mangle]
8576pub unsafe extern "C" fn __qsort_r(
8577 base: *mut c_void,
8578 nel: usize,
8579 width: usize,
8580 cmp: CmpRfn,
8581 arg: *mut c_void,
8582) {
8583 let size = width * nel;
8584 if size == 0 { return; }
8585
8586 let mut lp = [0usize; 96];
8587 lp[0] = width;
8588 lp[1] = width;
8589 let mut li = 2;
8590 while {
8591 lp[li] = lp[li - 2] + lp[li - 1] + width;
8592 lp[li] < size
8593 } {
8594 li += 1;
8595 }
8596
8597 let mut head = base as *mut u8;
8598 let high = head.add(size - width);
8599 let mut p: [usize; 2] = [1, 0];
8600 let mut pshift: i32 = 1;
8601
8602 while head < high {
8603 if (p[0] & 3) == 3 {
8604 qsort_sift(head, width, cmp, arg, pshift, &lp);
8605 qsort_shr(&mut p, 2);
8606 pshift += 2;
8607 } else {
8608 if lp[(pshift - 1) as usize] >= (high as usize) - (head as usize) {
8609 qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
8610 } else {
8611 qsort_sift(head, width, cmp, arg, pshift, &lp);
8612 }
8613
8614 if pshift == 1 {
8615 qsort_shl(&mut p, 1);
8616 pshift = 0;
8617 } else {
8618 qsort_shl(&mut p, pshift - 1);
8619 pshift = 1;
8620 }
8621 }
8622
8623 p[0] |= 1;
8624 head = head.add(width);
8625 }
8626
8627 qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
8628
8629 while pshift != 1 || p[0] != 1 || p[1] != 0 {
8630 if pshift <= 1 {
8631 let trail = qsort_pntz(&p);
8632 qsort_shr(&mut p, trail);
8633 pshift += trail;
8634 } else {
8635 qsort_shl(&mut p, 2);
8636 pshift -= 2;
8637 p[0] ^= 7;
8638 qsort_shr(&mut p, 1);
8639 qsort_trinkle(
8640 head.sub(lp[pshift as usize] + width),
8641 width, cmp, arg, &p, pshift + 1, 1, &lp,
8642 );
8643 qsort_shl(&mut p, 1);
8644 p[0] |= 1;
8645 qsort_trinkle(head.sub(width), width, cmp, arg, &p, pshift, 1, &lp);
8646 }
8647 head = head.sub(width);
8648 }
8649}
8650
8651#[no_mangle]
8652pub unsafe extern "C" fn qsort_r(
8653 base: *mut c_void,
8654 nel: usize,
8655 width: usize,
8656 cmp: CmpRfn,
8657 arg: *mut c_void,
8658) {
8659 __qsort_r(base, nel, width, cmp, arg);
8660}
8661
8662unsafe extern "C" fn qsort_wrap_cmp(
8663 a: *const c_void,
8664 b: *const c_void,
8665 cmp_ctx: *mut c_void,
8666) -> c_int {
8667 let cmp: CmpFn = core::mem::transmute(cmp_ctx);
8668 cmp(a, b)
8669}
8670
8671#[no_mangle]
8672pub unsafe extern "C" fn qsort(
8673 base: *mut c_void,
8674 nel: usize,
8675 width: usize,
8676 cmp: CmpFn,
8677) {
8678 __qsort_r(base, nel, width, qsort_wrap_cmp, cmp as *mut c_void);
8679}
8680
8681const ATEXIT_COUNT: usize = 32;
8686
8687#[repr(C)]
8688struct AtExitBlock {
8689 next: *mut AtExitBlock,
8690 f: [Option<unsafe extern "C" fn(*mut c_void)>; ATEXIT_COUNT],
8691 a: [*mut c_void; ATEXIT_COUNT],
8692}
8693
8694static mut ATEXIT_BUILTIN: AtExitBlock = AtExitBlock {
8695 next: core::ptr::null_mut(),
8696 f: [None; ATEXIT_COUNT],
8697 a: [core::ptr::null_mut(); ATEXIT_COUNT],
8698};
8699static mut ATEXIT_HEAD: *mut AtExitBlock = core::ptr::null_mut();
8700static mut ATEXIT_SLOT: usize = 0;
8701static mut ATEXIT_FINISHED: bool = false;
8702
8703#[no_mangle]
8704pub unsafe extern "C" fn __funcs_on_exit() {
8705 while !ATEXIT_HEAD.is_null() {
8706 let head = ATEXIT_HEAD;
8707 while ATEXIT_SLOT > 0 {
8708 ATEXIT_SLOT -= 1;
8709 if let Some(f) = (*head).f[ATEXIT_SLOT] {
8710 let a = (*head).a[ATEXIT_SLOT];
8711 f(a);
8712 }
8713 }
8714 ATEXIT_HEAD = (*head).next;
8715 ATEXIT_SLOT = ATEXIT_COUNT;
8716 }
8717 ATEXIT_FINISHED = true;
8718}
8719
8720#[no_mangle]
8721pub unsafe extern "C" fn __cxa_atexit(
8722 func: unsafe extern "C" fn(*mut c_void),
8723 arg: *mut c_void,
8724 _dso: *mut c_void,
8725) -> c_int {
8726 if ATEXIT_FINISHED {
8727 return -1;
8728 }
8729 if ATEXIT_HEAD.is_null() {
8730 ATEXIT_HEAD = core::ptr::addr_of_mut!(ATEXIT_BUILTIN);
8731 }
8732 if ATEXIT_SLOT == ATEXIT_COUNT {
8733 let new = calloc(1, core::mem::size_of::<AtExitBlock>()) as *mut AtExitBlock;
8734 if new.is_null() {
8735 return -1;
8736 }
8737 (*new).next = ATEXIT_HEAD;
8738 ATEXIT_HEAD = new;
8739 ATEXIT_SLOT = 0;
8740 }
8741 (*ATEXIT_HEAD).f[ATEXIT_SLOT] = Some(func);
8742 (*ATEXIT_HEAD).a[ATEXIT_SLOT] = arg;
8743 ATEXIT_SLOT += 1;
8744 0
8745}
8746
8747unsafe extern "C" fn atexit_caller(arg: *mut c_void) {
8748 let func: unsafe extern "C" fn() = core::mem::transmute(arg);
8749 func();
8750}
8751
8752#[no_mangle]
8753pub unsafe extern "C" fn atexit(func: unsafe extern "C" fn()) -> c_int {
8754 __cxa_atexit(atexit_caller, func as *mut c_void, core::ptr::null_mut())
8755}
8756
8757#[no_mangle]
8758pub unsafe extern "C" fn __cxa_finalize(_dso: *mut c_void) {}
8759
8760#[no_mangle]
8765pub static mut __environ: *mut *mut c_char = core::ptr::null_mut();
8766
8767const ENV_MAX_ALLOCED: usize = 256;
8769static mut ENV_ALLOCED: [*mut c_char; ENV_MAX_ALLOCED] = [core::ptr::null_mut(); ENV_MAX_ALLOCED];
8770static mut ENV_ALLOCED_N: usize = 0;
8771
8772unsafe fn env_rm_add(old: *mut c_char, mut new: *mut c_char) {
8773 for i in 0..ENV_ALLOCED_N {
8774 if ENV_ALLOCED[i] == old {
8775 ENV_ALLOCED[i] = new;
8776 if !old.is_null() {
8777 free(old as *mut c_void);
8778 }
8779 return;
8780 } else if ENV_ALLOCED[i].is_null() && !new.is_null() {
8781 ENV_ALLOCED[i] = new;
8782 new = core::ptr::null_mut();
8783 }
8784 }
8785 if !new.is_null() && ENV_ALLOCED_N < ENV_MAX_ALLOCED {
8786 ENV_ALLOCED[ENV_ALLOCED_N] = new;
8787 ENV_ALLOCED_N += 1;
8788 }
8789}
8790
8791unsafe fn strchrnul(s: *const u8, c: u8) -> *const u8 {
8792 let mut p = s;
8793 while *p != 0 && *p != c {
8794 p = p.add(1);
8795 }
8796 p
8797}
8798
8799#[no_mangle]
8800pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
8801 if __environ.is_null() || name.is_null() {
8802 return core::ptr::null_mut();
8803 }
8804 let name = name as *const u8;
8805 let l = strchrnul(name, b'=') as usize - name as usize;
8806 if l == 0 || *name.add(l) != 0 {
8807 return core::ptr::null_mut();
8808 }
8809 let mut e = __environ;
8810 while !(*e).is_null() {
8811 let entry = *e as *const u8;
8812 if strncmp(entry, name, l) == 0 && *entry.add(l) == b'=' {
8813 return entry.add(l + 1) as *mut c_char;
8814 }
8815 e = e.add(1);
8816 }
8817 core::ptr::null_mut()
8818}
8819
8820#[no_mangle]
8821pub unsafe extern "C" fn setenv(
8822 var: *const c_char,
8823 value: *const c_char,
8824 overwrite: c_int,
8825) -> c_int {
8826 if var.is_null() || value.is_null() {
8827 ERRNO = EINVAL;
8828 return -1;
8829 }
8830 let var = var as *const u8;
8831 let l1 = strchrnul(var, b'=') as usize - var as usize;
8832 if l1 == 0 || *var.add(l1) != 0 {
8833 ERRNO = EINVAL;
8834 return -1;
8835 }
8836 if overwrite == 0 && !getenv(var as *const c_char).is_null() {
8837 return 0;
8838 }
8839 let l2 = strlen(value as *const c_char);
8840 let s = malloc(l1 + l2 + 2) as *mut u8;
8841 if s.is_null() {
8842 return -1;
8843 }
8844 core::ptr::copy_nonoverlapping(var, s, l1);
8845 *s.add(l1) = b'=';
8846 core::ptr::copy_nonoverlapping(value as *const u8, s.add(l1 + 1), l2 + 1);
8847 putenv_internal(s as *mut c_char, l1, s as *mut c_char)
8848}
8849
8850unsafe fn putenv_internal(s: *mut c_char, l: usize, r: *mut c_char) -> c_int {
8851 let mut i = 0;
8852 if !__environ.is_null() {
8853 let mut e = __environ;
8854 while !(*e).is_null() {
8855 if strncmp(s as *const u8, *e as *const u8, l + 1) == 0 {
8856 let tmp = *e;
8857 *e = s;
8858 env_rm_add(tmp, r);
8859 return 0;
8860 }
8861 e = e.add(1);
8862 i += 1;
8863 }
8864 }
8865 let newenv = malloc(core::mem::size_of::<*mut c_char>() * (i + 2)) as *mut *mut c_char;
8866 if newenv.is_null() {
8867 if !r.is_null() { free(r as *mut c_void); }
8868 return -1;
8869 }
8870 if i > 0 && !__environ.is_null() {
8871 core::ptr::copy_nonoverlapping(__environ, newenv, i);
8872 }
8873 *newenv.add(i) = s;
8874 *newenv.add(i + 1) = core::ptr::null_mut();
8875 __environ = newenv;
8877 environ = __environ;
8878 if !r.is_null() {
8879 env_rm_add(core::ptr::null_mut(), r);
8880 }
8881 0
8882}
8883
8884#[no_mangle]
8885pub unsafe extern "C" fn putenv(s: *mut c_char) -> c_int {
8886 if s.is_null() { return -1; }
8887 let l = strchrnul(s as *const u8, b'=') as usize - s as *const u8 as usize;
8888 if l == 0 || *s.add(l) as u8 == 0 {
8889 return unsetenv(s);
8890 }
8891 putenv_internal(s, l, core::ptr::null_mut())
8892}
8893
8894#[no_mangle]
8895pub unsafe extern "C" fn unsetenv(name: *const c_char) -> c_int {
8896 if name.is_null() {
8897 ERRNO = EINVAL;
8898 return -1;
8899 }
8900 let name = name as *const u8;
8901 let l = strchrnul(name, b'=') as usize - name as usize;
8902 if l == 0 || *name.add(l) != 0 {
8903 ERRNO = EINVAL;
8904 return -1;
8905 }
8906 if __environ.is_null() {
8907 return 0;
8908 }
8909 let mut e = __environ;
8910 let mut eo = e;
8911 while !(*e).is_null() {
8912 if strncmp(name, *e as *const u8, l) == 0 && *(*e as *const u8).add(l) == b'=' {
8913 env_rm_add(*e, core::ptr::null_mut());
8914 } else {
8915 if eo != e {
8916 *eo = *e;
8917 }
8918 eo = eo.add(1);
8919 }
8920 e = e.add(1);
8921 }
8922 if eo != e {
8923 *eo = core::ptr::null_mut();
8924 }
8925 environ = __environ;
8926 0
8927}
8928
8929#[no_mangle]
8930pub unsafe extern "C" fn clearenv() -> c_int {
8931 let e = __environ;
8932 __environ = core::ptr::null_mut();
8933 environ = core::ptr::null_mut();
8934 if !e.is_null() {
8935 let mut p = e;
8936 while !(*p).is_null() {
8937 env_rm_add(*p, core::ptr::null_mut());
8938 p = p.add(1);
8939 }
8940 }
8941 0
8942}
8943
8944static mut RANDOM_INIT: [u32; 32] = [
8950 0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646,
8951 0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78,
8952 0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff,
8953 0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc,
8954 0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09,
8955 0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74,
8956 0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115,
8957 0x0cab8628,0xf043bfa4,0x398150e9,0x37521657,
8958];
8959
8960static mut RANDOM_N: i32 = 31;
8961static mut RANDOM_I: i32 = 3;
8962static mut RANDOM_J: i32 = 0;
8963static mut RANDOM_X: *mut u32 = unsafe { core::ptr::addr_of_mut!(RANDOM_INIT).cast::<u32>().add(1) };
8964
8965unsafe fn random_lcg31(x: u32) -> u32 {
8966 (1103515245u32.wrapping_mul(x).wrapping_add(12345)) & 0x7fffffff
8967}
8968
8969unsafe fn random_lcg64(x: u64) -> u64 {
8970 6364136223846793005u64.wrapping_mul(x).wrapping_add(1)
8971}
8972
8973unsafe fn random_savestate() -> *mut u8 {
8974 (*RANDOM_X.offset(-1)) = ((RANDOM_N as u32) << 16) | ((RANDOM_I as u32) << 8) | (RANDOM_J as u32);
8975 RANDOM_X.offset(-1) as *mut u8
8976}
8977
8978unsafe fn random_loadstate(state: *mut u32) {
8979 RANDOM_X = state.add(1);
8980 RANDOM_N = ((*RANDOM_X.offset(-1)) >> 16) as i32;
8981 RANDOM_I = (((*RANDOM_X.offset(-1)) >> 8) & 0xff) as i32;
8982 RANDOM_J = ((*RANDOM_X.offset(-1)) & 0xff) as i32;
8983}
8984
8985unsafe fn random_srandom_inner(seed: u32) {
8986 let mut s = seed as u64;
8987 if RANDOM_N == 0 {
8988 *RANDOM_X = s as u32;
8989 return;
8990 }
8991 RANDOM_I = if RANDOM_N == 31 || RANDOM_N == 7 { 3 } else { 1 };
8992 RANDOM_J = 0;
8993 for k in 0..RANDOM_N as usize {
8994 s = random_lcg64(s);
8995 *RANDOM_X.add(k) = (s >> 32) as u32;
8996 }
8997 *RANDOM_X |= 1;
8998}
8999
9000#[no_mangle]
9001pub unsafe extern "C" fn srandom(seed: c_uint) {
9002 random_srandom_inner(seed);
9003}
9004
9005#[no_mangle]
9006pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: usize) -> *mut c_char {
9007 if size < 8 { return core::ptr::null_mut(); }
9008 let old = random_savestate();
9009 RANDOM_N = if size < 32 { 0 }
9010 else if size < 64 { 7 }
9011 else if size < 128 { 15 }
9012 else if size < 256 { 31 }
9013 else { 63 };
9014 RANDOM_X = (state as *mut u32).add(1);
9015 random_srandom_inner(seed);
9016 random_savestate();
9017 old as *mut c_char
9018}
9019
9020#[no_mangle]
9021pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
9022 let old = random_savestate();
9023 random_loadstate(state as *mut u32);
9024 old as *mut c_char
9025}
9026
9027#[no_mangle]
9028pub unsafe extern "C" fn random() -> c_long {
9029 let k: c_long;
9030 if RANDOM_N == 0 {
9031 *RANDOM_X = random_lcg31(*RANDOM_X);
9032 k = *RANDOM_X as c_long;
9033 } else {
9034 *RANDOM_X.add(RANDOM_I as usize) = (*RANDOM_X.add(RANDOM_I as usize)).wrapping_add(*RANDOM_X.add(RANDOM_J as usize));
9035 k = (*RANDOM_X.add(RANDOM_I as usize) >> 1) as c_long;
9036 RANDOM_I += 1;
9037 if RANDOM_I == RANDOM_N { RANDOM_I = 0; }
9038 RANDOM_J += 1;
9039 if RANDOM_J == RANDOM_N { RANDOM_J = 0; }
9040 }
9041 k
9042}
9043
9044const SA: u8 = 0xC2;
9049const SB: u8 = 0xF4;
9050
9051const BITTAB: [u32; 51] = [
9052 0xC000_0002, 0xC000_0003, 0xC000_0004, 0xC000_0005, 0xC000_0006, 0xC000_0007,
9053 0xC000_0008, 0xC000_0009, 0xC000_000A, 0xC000_000B, 0xC000_000C, 0xC000_000D,
9054 0xC000_000E, 0xC000_000F, 0xC000_0010, 0xC000_0011, 0xC000_0012, 0xC000_0013,
9055 0xC000_0014, 0xC000_0015, 0xC000_0016, 0xC000_0017, 0xC000_0018, 0xC000_0019,
9056 0xC000_001A, 0xC000_001B, 0xC000_001C, 0xC000_001D, 0xC000_001E, 0xC000_001F,
9057 0xB300_0000, 0xC300_0001, 0xC300_0002, 0xC300_0003, 0xC300_0004, 0xC300_0005,
9058 0xC300_0006, 0xC300_0007, 0xC300_0008, 0xC300_0009, 0xC300_000A, 0xC300_000B,
9059 0xC300_000C, 0xD300_000D, 0xC300_000E, 0xC300_000F, 0xBB0C_0000, 0xC30C_0001,
9060 0xC30C_0002, 0xC30C_0003, 0xDB0C_0004,
9061];
9062
9063#[inline]
9064fn mb_oob(c: u32, b: u8) -> u32 {
9065 let b3 = (b >> 3) as u32;
9066 ((b3.wrapping_sub(0x10)) | (b3.wrapping_add((c as i32 >> 26) as u32))) & !7
9067}
9068
9069static mut MB_STATE: c_uint = 0;
9070
9071const MB_CUR_MAX_VAL_UTF8: usize = 4;
9072const MB_CUR_MAX_VAL_C: usize = 1;
9073
9074#[no_mangle]
9075pub extern "C" fn __ctype_get_mb_cur_max() -> usize {
9076 unsafe { if LOCALE_CTYPE_UTF8 { MB_CUR_MAX_VAL_UTF8 } else { MB_CUR_MAX_VAL_C } }
9077}
9078
9079#[no_mangle]
9080pub unsafe extern "C" fn mbrtowc(
9081 wc: *mut c_int,
9082 src: *const c_char,
9083 n: usize,
9084 st: *mut c_uint,
9085) -> usize {
9086 let s = src as *const u8;
9087 let n0 = n;
9088 let mut dummy: c_int = 0;
9089 let wc = if wc.is_null() { &mut dummy } else { &mut *wc };
9090 let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9091
9092 let mut c: u32 = *st;
9093 let mut s = s;
9094 let mut n = n;
9095
9096 if s.is_null() {
9097 if c != 0 { *st = 0; ERRNO = EILSEQ; return !0usize; }
9098 return 0;
9099 }
9100
9101 if n == 0 { return !1usize; }
9102
9103 if unsafe { !LOCALE_CTYPE_UTF8 } {
9104 let b = *s;
9105 *wc = b as c_int;
9106 return if b == 0 { 0 } else { 1 };
9107 }
9108
9109 if c == 0 {
9110 if *s < 0x80 {
9111 let r = if *s == 0 { 0 } else { 1 };
9112 *wc = *s as c_int;
9113 return r;
9114 }
9115 if (*s).wrapping_sub(SA) as u32 > (SB - SA) as u32 {
9116 *st = 0; ERRNO = EILSEQ; return !0usize;
9117 }
9118 c = BITTAB[*s as usize - SA as usize];
9119 s = s.add(1);
9120 n -= 1;
9121 }
9122
9123 if n > 0 {
9124 if mb_oob(c, *s) != 0 {
9125 *st = 0; ERRNO = EILSEQ; return !0usize;
9126 }
9127 loop {
9128 c = (c << 6) | (*s as u32).wrapping_sub(0x80);
9129 s = s.add(1);
9130 n -= 1;
9131 if c & (1u32 << 31) == 0 {
9132 *st = 0;
9133 *wc = c as c_int;
9134 return n0 - n;
9135 }
9136 if n == 0 { break; }
9137 if (*s).wrapping_sub(0x80) >= 0x40 {
9138 *st = 0; ERRNO = EILSEQ; return !0usize;
9139 }
9140 }
9141 }
9142
9143 *st = c;
9144 !1usize
9145}
9146
9147#[no_mangle]
9148pub unsafe extern "C" fn wcrtomb(
9149 s: *mut c_char,
9150 wc: c_int,
9151 _st: *mut c_uint,
9152) -> usize {
9153 if s.is_null() { return 1; }
9154 let wc_u = wc as u32;
9155 if unsafe { !LOCALE_CTYPE_UTF8 } {
9156 if wc_u > 0xFF {
9157 ERRNO = EILSEQ;
9158 return !0usize;
9159 }
9160 *s = wc as c_char;
9161 return 1;
9162 }
9163 if wc_u < 0x80 {
9164 *s = wc as c_char;
9165 return 1;
9166 }
9167 if wc_u < 0x800 {
9168 *s = (0xC0 | (wc_u >> 6)) as c_char;
9169 *s.add(1) = (0x80 | (wc_u & 0x3F)) as c_char;
9170 return 2;
9171 }
9172 if wc_u < 0xD800 || wc_u.wrapping_sub(0xE000) < 0x2000 {
9173 *s = (0xE0 | (wc_u >> 12)) as c_char;
9174 *s.add(1) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9175 *s.add(2) = (0x80 | (wc_u & 0x3F)) as c_char;
9176 return 3;
9177 }
9178 if wc_u.wrapping_sub(0x10000) < 0x100000 {
9179 *s = (0xF0 | (wc_u >> 18)) as c_char;
9180 *s.add(1) = (0x80 | ((wc_u >> 12) & 0x3F)) as c_char;
9181 *s.add(2) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9182 *s.add(3) = (0x80 | (wc_u & 0x3F)) as c_char;
9183 return 4;
9184 }
9185 ERRNO = EILSEQ;
9186 !0usize
9187}
9188
9189#[no_mangle]
9190pub unsafe extern "C" fn mblen(s: *const c_char, n: usize) -> c_int {
9191 if s.is_null() { return 0; }
9192 mbtowc(core::ptr::null_mut(), s, n)
9193}
9194
9195#[no_mangle]
9196pub unsafe extern "C" fn mbtowc(
9197 wc: *mut c_int,
9198 src: *const c_char,
9199 n: usize,
9200) -> c_int {
9201 if src.is_null() { return 0; }
9202 if n == 0 { ERRNO = EILSEQ; return -1; }
9203 let mut state: c_uint = 0;
9204 let mut w: c_int = 0;
9205 let r = mbrtowc(&mut w, src, n, &mut state);
9206 if r == !0usize { return -1; }
9207 if !wc.is_null() { *wc = w; }
9208 r as c_int
9209}
9210
9211#[no_mangle]
9212pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: c_int) -> c_int {
9213 if s.is_null() { return 0; }
9214 wcrtomb(s, wc, core::ptr::null_mut()) as c_int
9215}
9216
9217#[no_mangle]
9218pub unsafe extern "C" fn mbsrtowcs(
9219 ws: *mut c_int,
9220 src: *mut *const c_char,
9221 wn: usize,
9222 st: *mut c_uint,
9223) -> usize {
9224 let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9225 let mut s = *src as *const u8;
9226 let wn0 = wn;
9227 let mut wn = wn;
9228
9229 if ws.is_null() {
9230 while *s != 0 {
9231 if *s < 0x80 {
9232 s = s.add(1);
9233 wn = wn.wrapping_sub(1);
9234 continue;
9235 }
9236 let mut wc: c_int = 0;
9237 let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9238 if r == !0usize { return !0usize; }
9239 if r == !1usize { return wn0 - wn; }
9240 s = s.add(r);
9241 wn = wn.wrapping_sub(1);
9242 }
9243 wn0 - wn
9244 } else {
9245 let mut w = ws;
9246 while wn > 0 {
9247 if *s < 0x80 {
9248 let c = *s as c_int;
9249 *w = c;
9250 if c == 0 {
9251 *src = core::ptr::null();
9252 return wn0 - wn;
9253 }
9254 w = w.add(1);
9255 s = s.add(1);
9256 wn -= 1;
9257 continue;
9258 }
9259 let mut wc: c_int = 0;
9260 let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9261 if r == !0usize {
9262 *src = s as *const c_char;
9263 return !0usize;
9264 }
9265 if r == !1usize {
9266 *src = s as *const c_char;
9267 return wn0 - wn;
9268 }
9269 *w = wc;
9270 w = w.add(1);
9271 s = s.add(r);
9272 wn -= 1;
9273 }
9274 *src = s as *const c_char;
9275 wn0 - wn
9276 }
9277}
9278
9279#[no_mangle]
9280pub unsafe extern "C" fn wcsrtombs(
9281 s: *mut c_char,
9282 ws: *mut *const c_int,
9283 n: usize,
9284 _st: *mut c_uint,
9285) -> usize {
9286 let mut w = *ws;
9287 let n0 = n;
9288 let mut n = n;
9289
9290 if s.is_null() {
9291 let mut count = 0usize;
9292 while *w != 0 {
9293 if (*w as u32) < 0x80 {
9294 count += 1;
9295 } else {
9296 let mut buf = [0u8; 4];
9297 let r = wcrtomb(buf.as_mut_ptr() as *mut c_char, *w, core::ptr::null_mut());
9298 if r == !0usize { return !0usize; }
9299 count += r;
9300 }
9301 w = w.add(1);
9302 }
9303 return count;
9304 }
9305
9306 let mut dst = s;
9307 while n > 0 {
9308 if (*w as u32) < 0x80 {
9309 *dst = *w as c_char;
9310 if *w == 0 {
9311 *ws = core::ptr::null();
9312 return n0 - n;
9313 }
9314 dst = dst.add(1);
9315 n -= 1;
9316 } else {
9317 let r = wcrtomb(dst, *w, core::ptr::null_mut());
9318 if r == !0usize {
9319 *ws = w;
9320 return !0usize;
9321 }
9322 if r > n {
9323 *ws = w;
9324 return n0 - n;
9325 }
9326 dst = dst.add(r);
9327 n -= r;
9328 }
9329 w = w.add(1);
9330 }
9331 *ws = w;
9332 n0
9333}
9334
9335#[no_mangle]
9336pub unsafe extern "C" fn mbstowcs(
9337 ws: *mut c_int,
9338 src: *const c_char,
9339 wn: usize,
9340) -> usize {
9341 let mut src_ptr = src;
9342 mbsrtowcs(ws, &mut src_ptr, wn, core::ptr::null_mut())
9343}
9344
9345#[no_mangle]
9346pub unsafe extern "C" fn wcstombs(
9347 s: *mut c_char,
9348 ws: *const c_int,
9349 n: usize,
9350) -> usize {
9351 let mut ws_ptr = ws;
9352 wcsrtombs(s, &mut ws_ptr, n, core::ptr::null_mut())
9353}
9354
9355#[no_mangle]
9360pub extern "C" fn btowc(c: c_int) -> wint_t {
9361 if c == -1 { return WEOF; }
9362 unsafe {
9363 if LOCALE_CTYPE_UTF8 {
9364 if (c as u32) < 128 { c as wint_t } else { WEOF }
9365 } else {
9366 (c as u8) as wint_t
9367 }
9368 }
9369}
9370
9371#[no_mangle]
9372pub extern "C" fn wctob(c: wint_t) -> c_int {
9373 unsafe {
9374 if LOCALE_CTYPE_UTF8 {
9375 if c < 128 { c as c_int } else { -1 }
9376 } else {
9377 if c <= 0xFF { c as c_int } else { -1 }
9378 }
9379 }
9380}
9381
9382#[no_mangle]
9383pub unsafe extern "C" fn mbsinit(s: *const c_uint) -> c_int {
9384 if s.is_null() || *s == 0 { 1 } else { 0 }
9385}
9386
9387#[no_mangle]
9388pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut c_uint) -> usize {
9389 mbrtowc(core::ptr::null_mut(), s, n, ps)
9390}
9391
9392#[no_mangle]
9397pub unsafe extern "C" fn wcslen(s: *const wchar_t) -> usize {
9398 let mut len = 0;
9399 while *s.add(len) != 0 { len += 1; }
9400 len
9401}
9402
9403#[no_mangle]
9404pub unsafe extern "C" fn wcschr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
9405 let mut i = 0;
9406 loop {
9407 let ch = *s.add(i);
9408 if ch == c { return s.add(i) as *mut wchar_t; }
9409 if ch == 0 { return null_mut(); }
9410 i += 1;
9411 }
9412}
9413
9414#[no_mangle]
9415pub unsafe extern "C" fn wcsrchr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
9416 let mut i = 0;
9417 let mut last: *mut wchar_t = null_mut();
9418 loop {
9419 let ch = *s.add(i);
9420 if ch == c { last = s.add(i) as *mut wchar_t; }
9421 if ch == 0 { return last; }
9422 i += 1;
9423 }
9424}
9425
9426#[no_mangle]
9427pub unsafe extern "C" fn wcsstr(haystack: *const wchar_t, needle: *const wchar_t) -> *mut wchar_t {
9428 if *needle == 0 { return haystack as *mut wchar_t; }
9429 let mut i = 0;
9430 loop {
9431 let h = *haystack.add(i);
9432 if h == 0 { return null_mut(); }
9433 if h == *needle {
9434 let mut j = 0;
9435 loop {
9436 let n = *needle.add(j);
9437 if n == 0 { return haystack.add(i) as *mut wchar_t; }
9438 if *haystack.add(i + j) != n { break; }
9439 j += 1;
9440 }
9441 }
9442 i += 1;
9443 }
9444}
9445
9446#[no_mangle]
9447pub unsafe extern "C" fn wcscmp(s1: *const wchar_t, s2: *const wchar_t) -> c_int {
9448 let mut i = 0;
9449 loop {
9450 let a = *s1.add(i);
9451 let b = *s2.add(i);
9452 if a != b { return a - b; }
9453 if a == 0 { return 0; }
9454 i += 1;
9455 }
9456}
9457
9458#[no_mangle]
9459pub unsafe extern "C" fn wcsncmp(s1: *const wchar_t, s2: *const wchar_t, n: usize) -> c_int {
9460 let mut i = 0;
9461 while i < n {
9462 let a = *s1.add(i);
9463 let b = *s2.add(i);
9464 if a != b { return a - b; }
9465 if a == 0 { return 0; }
9466 i += 1;
9467 }
9468 0
9469}
9470
9471#[no_mangle]
9472pub unsafe extern "C" fn wcscpy(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
9473 let mut i = 0;
9474 loop {
9475 let c = *src.add(i);
9476 *dst.add(i) = c;
9477 if c == 0 { break; }
9478 i += 1;
9479 }
9480 dst
9481}
9482
9483#[no_mangle]
9484pub unsafe extern "C" fn wcsncpy(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
9485 let mut i = 0;
9486 while i < n && *src.add(i) != 0 { *dst.add(i) = *src.add(i); i += 1; }
9487 while i < n { *dst.add(i) = 0; i += 1; }
9488 dst
9489}
9490
9491#[no_mangle]
9492pub unsafe extern "C" fn wcscat(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
9493 let mut i = 0;
9494 while *dst.add(i) != 0 { i += 1; }
9495 let mut j = 0;
9496 loop {
9497 let c = *src.add(j);
9498 *dst.add(i + j) = c;
9499 if c == 0 { break; }
9500 j += 1;
9501 }
9502 dst
9503}
9504
9505#[no_mangle]
9506pub unsafe extern "C" fn wcsncat(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
9507 let mut i = 0;
9508 while *dst.add(i) != 0 { i += 1; }
9509 let mut j = 0;
9510 while j < n && *src.add(j) != 0 { *dst.add(i + j) = *src.add(j); j += 1; }
9511 *dst.add(i + j) = 0;
9512 dst
9513}
9514
9515#[no_mangle]
9516pub unsafe extern "C" fn wcsdup(s: *const wchar_t) -> *mut wchar_t {
9517 let len = wcslen(s);
9518 let p = malloc((len + 1) * core::mem::size_of::<wchar_t>()) as *mut wchar_t;
9519 if p.is_null() { return null_mut(); }
9520 core::ptr::copy_nonoverlapping(s, p, len + 1);
9521 p
9522}
9523
9524#[no_mangle]
9525pub unsafe extern "C" fn wcsnlen(s: *const wchar_t, maxlen: usize) -> usize {
9526 let mut i = 0;
9527 while i < maxlen && *s.add(i) != 0 { i += 1; }
9528 i
9529}
9530
9531#[no_mangle]
9532pub unsafe extern "C" fn wcsspn(s: *const wchar_t, accept: *const wchar_t) -> usize {
9533 let mut i = 0;
9534 loop {
9535 let c = *s.add(i);
9536 if c == 0 { return i; }
9537 let mut found = false;
9538 let mut j = 0;
9539 loop {
9540 let a = *accept.add(j);
9541 if a == 0 { break; }
9542 if c == a { found = true; break; }
9543 j += 1;
9544 }
9545 if !found { return i; }
9546 i += 1;
9547 }
9548}
9549
9550#[no_mangle]
9551pub unsafe extern "C" fn wcscspn(s: *const wchar_t, reject: *const wchar_t) -> usize {
9552 let mut i = 0;
9553 loop {
9554 let c = *s.add(i);
9555 if c == 0 { return i; }
9556 let mut j = 0;
9557 loop {
9558 let r = *reject.add(j);
9559 if r == 0 { break; }
9560 if c == r { return i; }
9561 j += 1;
9562 }
9563 i += 1;
9564 }
9565}
9566
9567#[no_mangle]
9568pub unsafe extern "C" fn wcspbrk(s: *const wchar_t, accept: *const wchar_t) -> *mut wchar_t {
9569 let mut i = 0;
9570 loop {
9571 let c = *s.add(i);
9572 if c == 0 { return null_mut(); }
9573 let mut j = 0;
9574 loop {
9575 let a = *accept.add(j);
9576 if a == 0 { break; }
9577 if c == a { return s.add(i) as *mut wchar_t; }
9578 j += 1;
9579 }
9580 i += 1;
9581 }
9582}
9583
9584#[no_mangle]
9585pub unsafe extern "C" fn wcsxfrm(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> usize {
9586 let len = wcslen(src);
9587 if !dst.is_null() {
9588 let copy = if len < n { len } else { if n > 0 { n - 1 } else { 0 } };
9589 for i in 0..copy { *dst.add(i) = *src.add(i); }
9590 if n > 0 { *dst.add(copy) = 0; }
9591 }
9592 len
9593}
9594
9595unsafe fn wcs_to_bytes(ws: *const wchar_t, buf: *mut u8, bufsz: usize) -> usize {
9600 let mut i = 0;
9601 while i < bufsz - 1 {
9602 let c = *ws.add(i);
9603 if c == 0 { break; }
9604 if (c as u32) > 127 { break; }
9605 *buf.add(i) = c as u8;
9606 i += 1;
9607 }
9608 *buf.add(i) = 0;
9609 i
9610}
9611
9612#[no_mangle]
9613pub unsafe extern "C" fn wcstol(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_long {
9614 let mut buf = [0u8; 256];
9615 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9616 let mut end: *mut c_char = core::ptr::null_mut();
9617 let r = strtol(buf.as_ptr() as *const c_char, &mut end, base);
9618 if !endptr.is_null() {
9619 let offset = end as usize - buf.as_ptr() as usize;
9620 *endptr = s.add(offset) as *mut wchar_t;
9621 }
9622 r
9623}
9624
9625#[no_mangle]
9626pub unsafe extern "C" fn wcstoul(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulong {
9627 let mut buf = [0u8; 256];
9628 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9629 let mut end: *mut c_char = core::ptr::null_mut();
9630 let r = strtoul(buf.as_ptr() as *const c_char, &mut end, base);
9631 if !endptr.is_null() {
9632 let offset = end as usize - buf.as_ptr() as usize;
9633 *endptr = s.add(offset) as *mut wchar_t;
9634 }
9635 r
9636}
9637
9638#[no_mangle]
9639pub unsafe extern "C" fn wcstoll(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong {
9640 let mut buf = [0u8; 256];
9641 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9642 let mut end: *mut c_char = core::ptr::null_mut();
9643 let r = strtoll(buf.as_ptr() as *const c_char, &mut end, base);
9644 if !endptr.is_null() {
9645 let offset = end as usize - buf.as_ptr() as usize;
9646 *endptr = s.add(offset) as *mut wchar_t;
9647 }
9648 r
9649}
9650
9651#[no_mangle]
9652pub unsafe extern "C" fn wcstoull(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong {
9653 let mut buf = [0u8; 256];
9654 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9655 let mut end: *mut c_char = core::ptr::null_mut();
9656 let r = strtoull(buf.as_ptr() as *const c_char, &mut end, base);
9657 if !endptr.is_null() {
9658 let offset = end as usize - buf.as_ptr() as usize;
9659 *endptr = s.add(offset) as *mut wchar_t;
9660 }
9661 r
9662}
9663
9664#[no_mangle]
9665pub unsafe extern "C" fn wcstod(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 {
9666 let mut buf = [0u8; 256];
9667 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9668 let mut end: *mut c_char = core::ptr::null_mut();
9669 let r = strtod(buf.as_ptr() as *const c_char, &mut end);
9670 if !endptr.is_null() {
9671 let offset = end as usize - buf.as_ptr() as usize;
9672 *endptr = s.add(offset) as *mut wchar_t;
9673 }
9674 r
9675}
9676
9677#[no_mangle]
9678pub unsafe extern "C" fn wcstof(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f32 { wcstod(s, endptr) as f32 }
9679
9680#[no_mangle]
9681#[cfg(target_arch = "x86_64")]
9682pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 { wcstod(s, endptr) }
9683
9684#[no_mangle]
9685#[cfg(target_arch = "aarch64")]
9686pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f128 { wcstod(s, endptr) as f128 }
9687
9688#[no_mangle]
9689pub unsafe extern "C" fn wcstoimax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong { wcstoll(s, endptr, base) }
9690
9691#[no_mangle]
9692pub unsafe extern "C" fn wcstoumax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong { wcstoull(s, endptr, base) }
9693
9694const WC_ALPHA: c_int = 1;
9699const WC_DIGIT: c_int = 2;
9700const WC_SPACE: c_int = 4;
9701const WC_UPPER: c_int = 8;
9702const WC_LOWER: c_int = 16;
9703const WC_ALNUM: c_int = WC_ALPHA | WC_DIGIT;
9704const WC_BLANK: c_int = 32;
9705const WC_CNTRL: c_int = 64;
9706const WC_PUNCT: c_int = 128;
9707const WC_GRAPH: c_int = WC_ALNUM | WC_PUNCT;
9708const WC_PRINT: c_int = WC_GRAPH | WC_BLANK;
9709const WC_XDIGIT: c_int = 256;
9710
9711fn wc_flags(c: wint_t) -> c_int {
9712 if c < 128 {
9713 let f = CT_TABLE[c as usize];
9714 let mut r = 0;
9715 if f & (CT_UPPER | CT_LOWER) != 0 { r |= WC_ALPHA; }
9716 if f & CT_DIGIT != 0 { r |= WC_DIGIT; }
9717 if f & CT_SPACE != 0 { r |= WC_SPACE; }
9718 if f & CT_UPPER != 0 { r |= WC_UPPER; }
9719 if f & CT_LOWER != 0 { r |= WC_LOWER; }
9720 if f & CT_BLANK != 0 { r |= WC_BLANK; }
9721 if f & CT_CNTRL != 0 { r |= WC_CNTRL; }
9722 if f & CT_PUNCT != 0 { r |= WC_PUNCT; }
9723 if f & CT_XDIGIT != 0 { r |= WC_XDIGIT; }
9724 r
9725 } else {
9726 if c < 0x100 { 0 }
9727 else { WC_PRINT | WC_ALPHA }
9728 }
9729}
9730
9731#[no_mangle]
9732pub extern "C" fn iswalnum(c: wint_t) -> c_int { (wc_flags(c) & WC_ALNUM != 0) as c_int }
9733#[no_mangle]
9734pub extern "C" fn iswalpha(c: wint_t) -> c_int { (wc_flags(c) & WC_ALPHA != 0) as c_int }
9735#[no_mangle]
9736pub extern "C" fn iswblank(c: wint_t) -> c_int { (wc_flags(c) & WC_BLANK != 0) as c_int }
9737#[no_mangle]
9738pub extern "C" fn iswcntrl(c: wint_t) -> c_int { (wc_flags(c) & WC_CNTRL != 0) as c_int }
9739#[no_mangle]
9740pub extern "C" fn iswdigit(c: wint_t) -> c_int { ((c >= b'0' as wint_t) && (c <= b'9' as wint_t)) as c_int }
9741#[no_mangle]
9742pub extern "C" fn iswgraph(c: wint_t) -> c_int { (wc_flags(c) & WC_GRAPH != 0) as c_int }
9743#[no_mangle]
9744pub extern "C" fn iswlower(c: wint_t) -> c_int { (wc_flags(c) & WC_LOWER != 0) as c_int }
9745#[no_mangle]
9746pub extern "C" fn iswprint(c: wint_t) -> c_int {
9747 if c < 128 { (wc_flags(c) & WC_PRINT != 0) as c_int }
9748 else if c >= 0x100 && c < 0x110000 { 1 }
9749 else { 0 }
9750}
9751#[no_mangle]
9752pub extern "C" fn iswpunct(c: wint_t) -> c_int { (wc_flags(c) & WC_PUNCT != 0) as c_int }
9753#[no_mangle]
9754pub extern "C" fn iswspace(c: wint_t) -> c_int {
9755 if c < 128 { (wc_flags(c) & WC_SPACE != 0) as c_int }
9756 else {
9757 match c {
9758 0x1680 | 0x2000..=0x200A | 0x2028 | 0x2029 | 0x202F | 0x205F | 0x3000 => 1,
9759 _ => 0,
9760 }
9761 }
9762}
9763#[no_mangle]
9764pub extern "C" fn iswupper(c: wint_t) -> c_int { (wc_flags(c) & WC_UPPER != 0) as c_int }
9765#[no_mangle]
9766pub extern "C" fn iswxdigit(c: wint_t) -> c_int { (wc_flags(c) & WC_XDIGIT != 0) as c_int }
9767
9768static WCTYPE_ALNUM: c_int = WC_ALNUM;
9769static WCTYPE_ALPHA: c_int = WC_ALPHA;
9770static WCTYPE_BLANK: c_int = WC_BLANK;
9771static WCTYPE_CNTRL: c_int = WC_CNTRL;
9772static WCTYPE_DIGIT: c_int = WC_DIGIT;
9773static WCTYPE_GRAPH: c_int = WC_GRAPH;
9774static WCTYPE_LOWER: c_int = WC_LOWER;
9775static WCTYPE_PRINT: c_int = WC_PRINT;
9776static WCTYPE_PUNCT: c_int = WC_PUNCT;
9777static WCTYPE_SPACE: c_int = WC_SPACE;
9778static WCTYPE_UPPER: c_int = WC_UPPER;
9779static WCTYPE_XDIGIT: c_int = WC_XDIGIT;
9780
9781#[no_mangle]
9782pub unsafe extern "C" fn wctype(name: *const c_char) -> wctype_t {
9783 if name.is_null() { return core::ptr::null(); }
9784 let n = name as *const u8;
9785 if strcmp(n, b"alnum\0".as_ptr()) == 0 { return &WCTYPE_ALNUM; }
9786 if strcmp(n, b"alpha\0".as_ptr()) == 0 { return &WCTYPE_ALPHA; }
9787 if strcmp(n, b"blank\0".as_ptr()) == 0 { return &WCTYPE_BLANK; }
9788 if strcmp(n, b"cntrl\0".as_ptr()) == 0 { return &WCTYPE_CNTRL; }
9789 if strcmp(n, b"digit\0".as_ptr()) == 0 { return &WCTYPE_DIGIT; }
9790 if strcmp(n, b"graph\0".as_ptr()) == 0 { return &WCTYPE_GRAPH; }
9791 if strcmp(n, b"lower\0".as_ptr()) == 0 { return &WCTYPE_LOWER; }
9792 if strcmp(n, b"print\0".as_ptr()) == 0 { return &WCTYPE_PRINT; }
9793 if strcmp(n, b"punct\0".as_ptr()) == 0 { return &WCTYPE_PUNCT; }
9794 if strcmp(n, b"space\0".as_ptr()) == 0 { return &WCTYPE_SPACE; }
9795 if strcmp(n, b"upper\0".as_ptr()) == 0 { return &WCTYPE_UPPER; }
9796 if strcmp(n, b"xdigit\0".as_ptr()) == 0 { return &WCTYPE_XDIGIT; }
9797 core::ptr::null()
9798}
9799
9800#[no_mangle]
9801pub unsafe extern "C" fn iswctype(c: wint_t, desc: wctype_t) -> c_int {
9802 if desc.is_null() { return 0; }
9803 (wc_flags(c) & *desc != 0) as c_int
9804}
9805
9806static WCTRANS_LOWER: c_int = 1;
9807static WCTRANS_UPPER: c_int = 2;
9808
9809#[no_mangle]
9810pub unsafe extern "C" fn towlower(c: wint_t) -> wint_t {
9811 if c < 128 { tolower(c as c_int) as wint_t } else { c }
9812}
9813
9814#[no_mangle]
9815pub unsafe extern "C" fn towupper(c: wint_t) -> wint_t {
9816 if c < 128 { toupper(c as c_int) as wint_t } else { c }
9817}
9818
9819#[no_mangle]
9820pub unsafe extern "C" fn wctrans(name: *const c_char) -> wctrans_t {
9821 if name.is_null() { return core::ptr::null(); }
9822 let n = name as *const u8;
9823 if strcmp(n, b"tolower\0".as_ptr()) == 0 { return &WCTRANS_LOWER; }
9824 if strcmp(n, b"toupper\0".as_ptr()) == 0 { return &WCTRANS_UPPER; }
9825 core::ptr::null()
9826}
9827
9828#[no_mangle]
9829pub unsafe extern "C" fn towctrans(c: wint_t, desc: wctrans_t) -> wint_t {
9830 if desc.is_null() { return c; }
9831 match *desc {
9832 1 => towlower(c),
9833 2 => towupper(c),
9834 _ => c,
9835 }
9836}
9837
9838#[no_mangle]
9843pub unsafe extern "C" fn fgetwc(f: *mut FILE) -> wint_t {
9844 let mut state: c_uint = 0;
9845 let mut wc: wchar_t = 0;
9846 let mut buf = [0u8; 4];
9847 let c = fgetc(f);
9848 if c == -1 { return WEOF; }
9849 buf[0] = c as u8;
9850 if buf[0] < 0x80 { return buf[0] as wint_t; }
9851 let len = if buf[0] < 0xE0 { 2 } else if buf[0] < 0xF0 { 3 } else { 4 };
9852 let mut n = 1usize;
9853 while n < len {
9854 let c2 = fgetc(f);
9855 if c2 == -1 { return WEOF; }
9856 buf[n] = c2 as u8;
9857 n += 1;
9858 }
9859 let r = mbrtowc(&mut wc, buf.as_ptr() as *const c_char, n, &mut state);
9860 if r == !0usize || r == !1usize { WEOF } else { wc as wint_t }
9861}
9862
9863#[no_mangle]
9864pub unsafe extern "C" fn fputwc(c: wchar_t, f: *mut FILE) -> wint_t {
9865 let mut buf = [0u8; 4];
9866 let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c, core::ptr::null_mut());
9867 if n == !0usize || n == 0 { return WEOF; }
9868 if fwrite(buf.as_ptr() as *const c_void, 1, n, f) != n { return WEOF; }
9869 c as wint_t
9870}
9871
9872#[no_mangle]
9873pub unsafe extern "C" fn fputws(s: *const wchar_t, f: *mut FILE) -> c_int {
9874 let mut i = 0;
9875 while *s.add(i) != 0 {
9876 if fputwc(*s.add(i), f) == WEOF { return -1; }
9877 i += 1;
9878 }
9879 0
9880}
9881
9882#[no_mangle]
9883pub unsafe extern "C" fn ungetwc(c: wint_t, f: *mut FILE) -> wint_t {
9884 if c == WEOF { return WEOF; }
9885 let mut buf = [0u8; 4];
9886 let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c as wchar_t, core::ptr::null_mut());
9887 if n == !0usize || n == 0 { return WEOF; }
9888 let mut i = n;
9889 while i > 0 {
9890 i -= 1;
9891 if ungetc(buf[i] as c_int, f) == -1 { return WEOF; }
9892 }
9893 c
9894}
9895
9896#[no_mangle]
9897pub unsafe extern "C" fn getwchar() -> wint_t { fgetwc(stdin) }
9898
9899#[no_mangle]
9900pub unsafe extern "C" fn putwchar(c: wchar_t) -> wint_t { fputwc(c, stdout) }
9901
9902unsafe fn wfmt_write_str(dst: *mut wchar_t, pos: usize, cap: usize, s: *const u8, len: usize) -> usize {
9907 let mut i = 0;
9908 while i < len {
9909 if pos + i < cap { *dst.add(pos + i) = *s.add(i) as wchar_t; }
9910 i += 1;
9911 }
9912 pos + len
9913}
9914
9915#[no_mangle]
9916pub unsafe extern "C" fn vswprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, mut args: VaList) -> c_int {
9917 if n == 0 { return -1; }
9918 let cap = n - 1;
9919 let mut pos = 0usize;
9920 let mut fmt_narrow = [0u8; 256];
9922 let mut flen = 0usize;
9923 loop {
9924 let ch = *fmt.add(flen) as u32;
9925 if ch == 0 || flen >= 255 { break; }
9926 fmt_narrow[flen] = if ch < 128 { ch as u8 } else { b'?' };
9927 flen += 1;
9928 }
9929 fmt_narrow[flen] = 0;
9930 let mut fi = 0usize;
9931 macro_rules! wc {
9932 ($c:expr) => { if pos < cap { *s.add(pos) = $c as wchar_t; } pos += 1; }
9933 }
9934 loop {
9935 let c = fmt_narrow[fi];
9936 if c == 0 { break; }
9937 if c != b'%' { wc!(c); fi += 1; continue; }
9938 fi += 1;
9939 let mut flags: u8 = 0;
9940 loop {
9941 match fmt_narrow[fi] {
9942 b'-' => { flags |= FLAG_MINUS; fi += 1; }
9943 b'+' => { flags |= FLAG_PLUS; fi += 1; }
9944 b' ' => { flags |= FLAG_SPACE; fi += 1; }
9945 b'0' => { flags |= FLAG_ZERO; fi += 1; }
9946 b'#' => { flags |= FLAG_HASH; fi += 1; }
9947 _ => break,
9948 }
9949 }
9950 let mut width: usize = 0;
9951 if fmt_narrow[fi] == b'*' {
9952 let w = args.next_arg::<c_int>();
9953 if w < 0 { flags |= FLAG_MINUS; width = (-w) as usize; } else { width = w as usize; }
9954 fi += 1;
9955 } else {
9956 while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
9957 width = width * 10 + (fmt_narrow[fi] - b'0') as usize; fi += 1;
9958 }
9959 }
9960 let mut precision: i32 = -1;
9961 if fmt_narrow[fi] == b'.' {
9962 fi += 1;
9963 if fmt_narrow[fi] == b'*' {
9964 let p = args.next_arg::<c_int>();
9965 precision = if p < 0 { -1 } else { p }; fi += 1;
9966 } else {
9967 precision = 0;
9968 while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
9969 precision = precision * 10 + (fmt_narrow[fi] - b'0') as i32; fi += 1;
9970 }
9971 }
9972 }
9973 let len_mod = fmt_narrow[fi];
9974 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' {
9975 fi += 1;
9976 let spec = fmt_narrow[fi];
9977 if (len_mod == b'h' && spec == b'h') || (len_mod == b'l' && spec == b'l') {
9978 fi += 1;
9979 let spec2 = fmt_narrow[fi];
9980 match (len_mod, spec, spec2) {
9981 (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; } }
9982 (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; } }
9983 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
9984 let val = args.next_arg::<c_longlong>();
9985 let neg = val < 0;
9986 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
9987 let b = format_u64(abs);
9988 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
9989 let mut fbuf = [0u8; 32];
9990 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
9991 for k in 0..len { wc!(fbuf[k]); }
9992 }
9993 (b'l', b'l', b'u') => {
9994 let val = args.next_arg::<c_ulonglong>();
9995 let b = format_u64(val as u64);
9996 let mut fbuf = [0u8; 32];
9997 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
9998 for k in 0..len { wc!(fbuf[k]); }
9999 }
10000 (b'l', b'l', b'x') => {
10001 let val = args.next_arg::<c_ulonglong>();
10002 let b = format_hex(val as u64, false);
10003 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10004 let mut fbuf = [0u8; 32];
10005 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10006 for k in 0..len { wc!(fbuf[k]); }
10007 }
10008 (b'l', b'l', b'X') => {
10009 let val = args.next_arg::<c_ulonglong>();
10010 let b = format_hex(val as u64, true);
10011 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10012 let mut fbuf = [0u8; 32];
10013 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10014 for k in 0..len { wc!(fbuf[k]); }
10015 }
10016 (b'l', b'l', b'o') => {
10017 let val = args.next_arg::<c_ulonglong>();
10018 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
10019 let mut fbuf = [0u8; 32];
10020 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10021 for k in 0..len { wc!(fbuf[k]); }
10022 }
10023 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); wc!(spec2); }
10024 }
10025 } else {
10026 match (len_mod, spec) {
10027 (b'h', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut u16) = pos as u16; } }
10028 (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; } }
10029 (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; } }
10030 (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; } }
10031 (b'l', b'd') | (b'l', b'i') => {
10032 let val = args.next_arg::<c_long>();
10033 let neg = val < 0;
10034 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
10035 let b = format_u64(abs);
10036 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10037 let mut fbuf = [0u8; 32];
10038 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10039 for k in 0..len { wc!(fbuf[k]); }
10040 }
10041 (b'l', b'u') => {
10042 let val = args.next_arg::<c_ulong>();
10043 let b = format_u64(val as u64);
10044 let mut fbuf = [0u8; 32];
10045 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10046 for k in 0..len { wc!(fbuf[k]); }
10047 }
10048 (b'l', b'x') => {
10049 let val = args.next_arg::<c_ulong>();
10050 let b = format_hex(val as u64, false);
10051 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10052 let mut fbuf = [0u8; 32];
10053 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10054 for k in 0..len { wc!(fbuf[k]); }
10055 }
10056 (b'l', b'X') => {
10057 let val = args.next_arg::<c_ulong>();
10058 let b = format_hex(val as u64, true);
10059 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10060 let mut fbuf = [0u8; 32];
10061 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10062 for k in 0..len { wc!(fbuf[k]); }
10063 }
10064 (b'l', b'o') => {
10065 let val = args.next_arg::<c_ulong>();
10066 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
10067 let mut fbuf = [0u8; 32];
10068 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10069 for k in 0..len { wc!(fbuf[k]); }
10070 }
10071 (b'l', b'c') => {
10072 let ch = args.next_arg::<wint_t>();
10073 wc!(ch);
10074 }
10075 (b'l', b's') => {
10076 let ws_arg = args.next_arg::<*const wchar_t>();
10077 if ws_arg.is_null() {
10078 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10079 if flags & FLAG_MINUS != 0 {
10080 for k in 0..slen { wc!(b"(null)"[k]); }
10081 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10082 } else {
10083 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10084 for k in 0..slen { wc!(b"(null)"[k]); }
10085 }
10086 } else {
10087 let mut wlen = 0usize;
10088 loop {
10089 let ch = *ws_arg.add(wlen);
10090 if ch == 0 { break; }
10091 if precision >= 0 && wlen >= precision as usize { break; }
10092 wlen += 1;
10093 }
10094 if flags & FLAG_MINUS != 0 {
10095 for k in 0..wlen { wc!(*ws_arg.add(k)); }
10096 for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10097 } else {
10098 for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10099 for k in 0..wlen { wc!(*ws_arg.add(k)); }
10100 }
10101 }
10102 }
10103 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
10104 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
10105 let val = args.next_arg::<f64>();
10106 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10107 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10108 let mut fbuf = [0u8; 4224];
10109 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10110 let mut wbuf = [0u8; 4224];
10111 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10112 for k in 0..wlen { wc!(wbuf[k]); }
10113 }
10114 (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
10115 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
10116 #[cfg(target_arch = "aarch64")]
10117 let val = {
10118 let lo: u64 = args.next_arg::<u64>();
10119 let hi: u64 = args.next_arg::<u64>();
10120 let combined: u128 = ((hi as u128) << 64) | (lo as u128);
10121 f128::from_bits(combined) as f64
10122 };
10123 #[cfg(target_arch = "x86_64")]
10124 let val = args.next_arg::<f64>();
10125 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10126 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10127 let mut fbuf = [0u8; 4224];
10128 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10129 let mut wbuf = [0u8; 4224];
10130 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10131 for k in 0..wlen { wc!(wbuf[k]); }
10132 }
10133 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
10134 }
10135 }
10136 } else {
10137 let spec = fmt_narrow[fi];
10138 match spec {
10139 b'd' | b'i' => {
10140 let d = args.next_arg::<c_int>();
10141 let neg = d < 0;
10142 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
10143 let b = format_u64(abs);
10144 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10145 let mut fbuf = [0u8; 32];
10146 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10147 for k in 0..len { wc!(fbuf[k]); }
10148 }
10149 b'u' => {
10150 let u = args.next_arg::<c_uint>();
10151 let b = format_u64(u as u64);
10152 let mut fbuf = [0u8; 32];
10153 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10154 for k in 0..len { wc!(fbuf[k]); }
10155 }
10156 b'x' => {
10157 let x = args.next_arg::<c_uint>();
10158 let b = format_hex(x as u64, false);
10159 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10160 let mut fbuf = [0u8; 32];
10161 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10162 for k in 0..len { wc!(fbuf[k]); }
10163 }
10164 b'X' => {
10165 let x = args.next_arg::<c_uint>();
10166 let b = format_hex(x as u64, true);
10167 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10168 let mut fbuf = [0u8; 32];
10169 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10170 for k in 0..len { wc!(fbuf[k]); }
10171 }
10172 b'o' => {
10173 let o = args.next_arg::<c_uint>();
10174 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
10175 let mut fbuf = [0u8; 32];
10176 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10177 for k in 0..len { wc!(fbuf[k]); }
10178 }
10179 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
10180 let val = args.next_arg::<f64>();
10181 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10182 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10183 let mut fbuf = [0u8; 4224];
10184 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10185 let mut wbuf = [0u8; 4224];
10186 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10187 for k in 0..wlen { wc!(wbuf[k]); }
10188 }
10189 b'c' => {
10190 let ch = args.next_arg::<c_int>();
10191 wc!(ch as u8);
10192 }
10193 b's' => {
10194 let p = args.next_arg::<*const c_char>();
10195 if p.is_null() {
10196 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10197 if flags & FLAG_MINUS != 0 {
10198 for k in 0..slen { wc!(b"(null)"[k]); }
10199 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10200 } else {
10201 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10202 for k in 0..slen { wc!(b"(null)"[k]); }
10203 }
10204 } else {
10205 let mut wbuf_local = [0i32; 256];
10206 let mut wcount = 0usize;
10207 let mut byte_pos = 0usize;
10208 let pbytes = p as *const u8;
10209 loop {
10210 if precision >= 0 && wcount >= precision as usize { break; }
10211 if wcount >= 256 { break; }
10212 let mut wc_val: c_int = 0;
10213 let consumed = mbrtowc(&mut wc_val as *mut c_int, p.add(byte_pos) as *const c_char, 256, core::ptr::null_mut());
10214 if consumed == !0usize || consumed == !1usize {
10215 wbuf_local[wcount] = *pbytes.add(byte_pos) as c_int;
10216 byte_pos += 1;
10217 wcount += 1;
10218 } else if consumed == 0 {
10219 break;
10220 } else {
10221 wbuf_local[wcount] = wc_val;
10222 byte_pos += consumed;
10223 wcount += 1;
10224 }
10225 }
10226 if flags & FLAG_MINUS != 0 {
10227 for k in 0..wcount { wc!(wbuf_local[k]); }
10228 for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10229 } else {
10230 for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10231 for k in 0..wcount { wc!(wbuf_local[k]); }
10232 }
10233 }
10234 }
10235 b'p' => {
10236 wc!(b'0'); wc!(b'x');
10237 let p = args.next_arg::<*const c_void>();
10238 let b = format_hex(p as u64, false);
10239 for k in 0..b.1 { wc!(b.0[k]); }
10240 }
10241 b'n' => {
10242 let p = args.next_arg::<*mut c_void>();
10243 if !p.is_null() { *(p as *mut c_int) = pos as c_int; }
10244 }
10245 b'%' => { wc!(b'%'); }
10246 _ => { wc!(b'%'); wc!(spec); }
10247 }
10248 }
10249 fi += 1;
10250 }
10251 let null_pos = if pos < cap { pos } else { cap };
10252 *s.add(null_pos) = 0;
10253 if pos > cap { -1 } else { pos as c_int }
10254}
10255
10256#[no_mangle]
10257pub unsafe extern "C" fn swprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, args: ...) -> c_int {
10258 vswprintf(s, n, fmt, args)
10259}
10260
10261#[no_mangle]
10262pub unsafe extern "C" fn vfwprintf(f: *mut FILE, fmt: *const wchar_t, args: VaList) -> c_int {
10263 let mut buf = [0i32; 4096];
10264 let r = vswprintf(buf.as_mut_ptr(), 4096, fmt, args);
10265 if r < 0 { return r; }
10266 let mut i = 0;
10267 while i < r as usize {
10268 let mut mb = [0u8; 4];
10269 let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, buf[i], core::ptr::null_mut());
10270 if n == !0usize { return -1; }
10271 if fwrite(mb.as_ptr() as *const c_void, 1, n, f) != n { return -1; }
10272 i += 1;
10273 }
10274 r
10275}
10276
10277#[no_mangle]
10278pub unsafe extern "C" fn fwprintf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10279 vfwprintf(f, fmt, args)
10280}
10281
10282unsafe fn wcsfmt_to_mbs(dst: *mut u8, dst_len: usize, src: *const wchar_t) {
10288 let mut i = 0usize;
10289 loop {
10290 let ch = *src.add(i) as u32;
10291 if ch == 0 || i >= dst_len - 1 { break; }
10292 *dst.add(i) = if ch < 128 { ch as u8 } else { b'?' };
10293 i += 1;
10294 }
10295 *dst.add(i) = 0;
10296}
10297
10298#[no_mangle]
10299pub unsafe extern "C" fn vswscanf(s: *const wchar_t, fmt: *const wchar_t, mut args: VaList) -> c_int {
10300 let mut mbs_buf = [0u8; 4096];
10301 let mut i = 0usize;
10302 let mut mb_pos = 0usize;
10303 loop {
10304 let wc = *s.add(i) as c_int;
10305 if wc == 0 { break; }
10306 let mut mb = [0u8; 4];
10307 let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, wc, core::ptr::null_mut());
10308 if n == !0usize || n == 0 { break; }
10309 if mb_pos + n >= mbs_buf.len() { break; }
10310 let mut k = 0usize;
10311 while k < n { mbs_buf[mb_pos + k] = mb[k]; k += 1; }
10312 mb_pos += n;
10313 i += 1;
10314 }
10315 mbs_buf[mb_pos] = 0;
10316 let mut mbs_fmt = [0u8; 4096];
10317 wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10318 do_vsscanf(mbs_buf.as_ptr(), mb_pos, mbs_fmt.as_ptr() as *const c_char, &mut args, core::ptr::null_mut())
10319}
10320
10321#[no_mangle]
10322pub unsafe extern "C" fn swscanf(s: *const wchar_t, fmt: *const wchar_t, args: ...) -> c_int {
10323 vswscanf(s, fmt, args)
10324}
10325
10326#[no_mangle]
10327pub unsafe extern "C" fn vfwscanf(f: *mut FILE, fmt: *const wchar_t, mut args: VaList) -> c_int {
10328 let start_pos = ftello(f);
10329 if start_pos < 0 { return -1; }
10330 let mut buf = [0u8; 4096];
10331 let mut n = 0usize;
10332 loop {
10333 if n >= buf.len() - 1 { break; }
10334 let c = fgetc(f);
10335 if c == -1 { break; }
10336 buf[n] = c as u8;
10337 n += 1;
10338 }
10339 buf[n] = 0;
10340 let mut mbs_fmt = [0u8; 4096];
10341 wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10342 let mut consumed = 0usize;
10343 let hit_eof = (*f)._eof != 0;
10344 let result = do_vsscanf(buf.as_ptr(), n, mbs_fmt.as_ptr() as *const c_char, &mut args, &mut consumed);
10345 let _ = fseeko(f, start_pos + consumed as i64, SEEK_SET);
10346 if hit_eof && consumed == n {
10347 (*f)._eof = 1;
10348 }
10349 result
10350}
10351
10352#[no_mangle]
10353pub unsafe extern "C" fn fwscanf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10354 vfwscanf(f, fmt, args)
10355}
10356
10357#[no_mangle]
10358pub unsafe extern "C" fn vwscanf(fmt: *const wchar_t, args: VaList) -> c_int {
10359 vfwscanf(stdin, fmt, args)
10360}
10361
10362#[no_mangle]
10363pub unsafe extern "C" fn wscanf(fmt: *const wchar_t, args: ...) -> c_int {
10364 vfwscanf(stdin, fmt, args)
10365}
10366
10367const LEAPOCH: i64 = 946684800 + 86400 * (31 + 29);
10372const DAYS_PER_400Y: i64 = 365 * 400 + 97;
10373const DAYS_PER_100Y: i64 = 365 * 100 + 24;
10374const DAYS_PER_4Y: i64 = 365 * 4 + 1;
10375
10376const SECS_THROUGH_MONTH: [i32; 12] = [
10377 0, 31*86400, 59*86400, 90*86400, 120*86400, 151*86400,
10378 181*86400, 212*86400, 243*86400, 273*86400, 304*86400, 334*86400,
10379];
10380
10381const DAYS_IN_MONTH: [i32; 12] = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29];
10382
10383unsafe fn year_to_secs(year: i64, is_leap: &mut bool) -> i64 {
10384 if year - 2 <= 136 {
10385 let y = year as i32;
10386 let mut leaps = (y - 68) >> 2;
10387 if (y - 68) & 3 == 0 { leaps -= 1; *is_leap = true; } else { *is_leap = false; }
10388 return 31536000 * (y as i64 - 70) + 86400 * leaps as i64;
10389 }
10390 let mut cycles = ((year - 100) / 400) as i32;
10391 let mut rem = ((year - 100) % 400) as i32;
10392 if rem < 0 { cycles -= 1; rem += 400; }
10393 let (centuries, leaps);
10394 if rem == 0 { *is_leap = true; centuries = 0; leaps = 0; }
10395 else {
10396 let c;
10397 if rem >= 200 { if rem >= 300 { c = 3; rem -= 300; } else { c = 2; rem -= 200; } }
10398 else { if rem >= 100 { c = 1; rem -= 100; } else { c = 0; } }
10399 centuries = c;
10400 if rem == 0 { *is_leap = false; leaps = 0; }
10401 else { leaps = rem / 4; rem %= 4; *is_leap = rem == 0; }
10402 }
10403 let total_leaps = leaps + 97 * cycles + 24 * centuries - (*is_leap as i32);
10404 (year - 100) * 31536000 + total_leaps as i64 * 86400 + 946684800 + 86400
10405}
10406
10407fn month_to_secs(month: i32, is_leap: bool) -> i32 {
10408 let mut t = SECS_THROUGH_MONTH[month as usize];
10409 if is_leap && month >= 2 { t += 86400; }
10410 t
10411}
10412
10413unsafe fn secs_to_tm(t: i64, tm: &mut tm) -> bool {
10414 if t < (i32::MIN as i64) * 31622400 || t > (i32::MAX as i64) * 31622400 { return false; }
10415 let secs = t - LEAPOCH;
10416 let mut days = secs / 86400;
10417 let mut remsecs = (secs % 86400) as i32;
10418 if remsecs < 0 { remsecs += 86400; days -= 1; }
10419 let mut wday = ((3 + days) % 7) as i32;
10420 if wday < 0 { wday += 7; }
10421 let mut qc_cycles = (days / DAYS_PER_400Y) as i32;
10422 let mut remdays = (days % DAYS_PER_400Y) as i32;
10423 if remdays < 0 { remdays += DAYS_PER_400Y as i32; qc_cycles -= 1; }
10424 let mut c_cycles = remdays / DAYS_PER_100Y as i32;
10425 if c_cycles == 4 { c_cycles -= 1; }
10426 remdays -= c_cycles * DAYS_PER_100Y as i32;
10427 let mut q_cycles = remdays / DAYS_PER_4Y as i32;
10428 if q_cycles == 25 { q_cycles -= 1; }
10429 remdays -= q_cycles * DAYS_PER_4Y as i32;
10430 let mut remyears = remdays / 365;
10431 if remyears == 4 { remyears -= 1; }
10432 remdays -= remyears * 365;
10433 let leap = remyears == 0 && (q_cycles != 0 || c_cycles == 0);
10434 let mut yday = remdays + 31 + 28 + leap as i32;
10435 if yday >= 365 + leap as i32 { yday -= 365 + leap as i32; }
10436 let years = remyears as i64 + 4 * q_cycles as i64 + 100 * c_cycles as i64 + 400 * qc_cycles as i64;
10437 let mut months = 0i32;
10438 let mut rd = remdays;
10439 for m in 0..12 {
10440 if DAYS_IN_MONTH[m] <= rd { rd -= DAYS_IN_MONTH[m]; } else { months = m as i32; break; }
10441 }
10442 let mut adj_years = years;
10443 if months >= 10 { months -= 12; adj_years += 1; }
10444 if adj_years + 100 > i32::MAX as i64 || adj_years + 100 < i32::MIN as i64 { return false; }
10445 tm.tm_year = (adj_years + 100) as c_int;
10446 tm.tm_mon = months + 2;
10447 tm.tm_mday = rd + 1;
10448 tm.tm_wday = wday;
10449 tm.tm_yday = yday;
10450 tm.tm_hour = remsecs / 3600;
10451 tm.tm_min = remsecs / 60 % 60;
10452 tm.tm_sec = remsecs % 60;
10453 true
10454}
10455
10456unsafe fn tm_to_secs(tm: *const tm) -> i64 {
10457 let mut year = (*tm).tm_year as i64;
10458 let mut month = (*tm).tm_mon;
10459 if month >= 12 || month < 0 {
10460 let adj = month / 12;
10461 month %= 12;
10462 if month < 0 { month += 12; }
10463 year += adj as i64;
10464 }
10465 let mut is_leap = false;
10466 let mut t = year_to_secs(year, &mut is_leap);
10467 t += month_to_secs(month, is_leap) as i64;
10468 t += 86400 * ((*tm).tm_mday - 1) as i64;
10469 t += 3600 * (*tm).tm_hour as i64;
10470 t += 60 * (*tm).tm_min as i64;
10471 t += (*tm).tm_sec as i64;
10472 t
10473}
10474
10475static mut TM_BUF: tm = tm {
10476 tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0,
10477 tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0,
10478 tm_gmtoff: 0, tm_zone: core::ptr::null(),
10479};
10480
10481static mut UTC_STR: [c_char; 4] = [b'U' as c_char, b'T' as c_char, b'C' as c_char, 0];
10482
10483const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
10484
10485#[no_mangle]
10490pub unsafe extern "C" fn time(t: *mut TimeT) -> TimeT {
10491 let mut ts: timespec = core::mem::zeroed();
10492 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
10493 if !t.is_null() { *t = ts.tv_sec; }
10494 ts.tv_sec
10495}
10496
10497#[no_mangle]
10498pub unsafe extern "C" fn difftime(t1: TimeT, t0: TimeT) -> f64 {
10499 (t1 as i64 - t0 as i64) as f64
10500}
10501
10502#[no_mangle]
10503pub unsafe extern "C" fn clock() -> ClockT {
10504 let mut ts: timespec = core::mem::zeroed();
10505 let _ = sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mut ts);
10506 ts.tv_sec * 1000000 + ts.tv_nsec / 1000
10507}
10508
10509#[no_mangle]
10510pub unsafe extern "C" fn gmtime(t: *const TimeT) -> *mut tm {
10511 gmtime_r(t, &raw mut TM_BUF)
10512}
10513
10514#[no_mangle]
10515pub unsafe extern "C" fn gmtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm {
10516 if !secs_to_tm(*t as i64, &mut *tm) { ERRNO = EOVERFLOW; return core::ptr::null_mut(); }
10517 (*tm).tm_isdst = 0;
10518 (*tm).tm_gmtoff = 0;
10519 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10520 tm
10521}
10522
10523#[no_mangle]
10524pub unsafe extern "C" fn localtime(t: *const TimeT) -> *mut tm { gmtime(t) }
10525
10526#[no_mangle]
10527pub unsafe extern "C" fn localtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm { gmtime_r(t, tm) }
10528
10529#[no_mangle]
10530pub unsafe extern "C" fn mktime(tm: *mut tm) -> TimeT {
10531 let t = tm_to_secs(tm as *const tm);
10532 if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
10533 (*tm).tm_isdst = 0;
10534 (*tm).tm_gmtoff = 0;
10535 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10536 t as TimeT
10537}
10538
10539#[no_mangle]
10540pub unsafe extern "C" fn timegm(tm: *mut tm) -> TimeT {
10541 let t = tm_to_secs(tm as *const tm);
10542 if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
10543 (*tm).tm_isdst = 0;
10544 (*tm).tm_gmtoff = 0;
10545 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10546 t as TimeT
10547}
10548
10549static mut ASCTIME_BUF: [c_char; 26] = [0; 26];
10550
10551const 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"];
10552const 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"];
10553
10554#[no_mangle]
10555pub unsafe extern "C" fn asctime(tm: *const tm) -> *mut c_char {
10556 asctime_r(tm, core::ptr::addr_of_mut!(ASCTIME_BUF).cast::<c_char>())
10557}
10558
10559#[no_mangle]
10560pub unsafe extern "C" fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char {
10561 let wday = if (*tm).tm_wday >= 0 && (*tm).tm_wday < 7 { (*tm).tm_wday as usize } else { 0 };
10562 let mon = if (*tm).tm_mon >= 0 && (*tm).tm_mon < 12 { (*tm).tm_mon as usize } else { 0 };
10563 let dn = DAY_NAMES[wday];
10564 let mn = MON_NAMES[mon];
10565 let mut p = 0;
10566 for k in 0..3 { *buf.add(p) = *dn.as_ptr().add(k) as c_char; p += 1; }
10567 *buf.add(p) = b' ' as c_char; p += 1;
10568 for k in 0..3 { *buf.add(p) = *mn.as_ptr().add(k) as c_char; p += 1; }
10569 *buf.add(p) = b' ' as c_char; p += 1;
10570 let v = (*tm).tm_mday;
10571 *buf.add(p) = (b'0' + (v / 10) as u8) as c_char; p += 1;
10572 *buf.add(p) = (b'0' + (v % 10) as u8) as c_char; p += 1;
10573 *buf.add(p) = b' ' as c_char; p += 1;
10574 let hh = (*tm).tm_hour;
10575 *buf.add(p) = (b'0' + (hh / 10) as u8) as c_char; p += 1;
10576 *buf.add(p) = (b'0' + (hh % 10) as u8) as c_char; p += 1;
10577 *buf.add(p) = b':' as c_char; p += 1;
10578 let mm = (*tm).tm_min;
10579 *buf.add(p) = (b'0' + (mm / 10) as u8) as c_char; p += 1;
10580 *buf.add(p) = (b'0' + (mm % 10) as u8) as c_char; p += 1;
10581 *buf.add(p) = b':' as c_char; p += 1;
10582 let ss = (*tm).tm_sec;
10583 *buf.add(p) = (b'0' + (ss / 10) as u8) as c_char; p += 1;
10584 *buf.add(p) = (b'0' + (ss % 10) as u8) as c_char; p += 1;
10585 *buf.add(p) = b' ' as c_char; p += 1;
10586 let yr = (*tm).tm_year + 1900;
10587 let mut tmp = [0u8; 4];
10588 let mut v2 = yr;
10589 for k in (0..4).rev() { tmp[k] = b'0' + (v2 % 10) as u8; v2 /= 10; }
10590 for k in 0..4 { *buf.add(p) = tmp[k] as c_char; p += 1; }
10591 *buf.add(p) = b'\n' as c_char; p += 1;
10592 *buf.add(p) = 0;
10593 buf
10594}
10595
10596#[no_mangle]
10597pub unsafe extern "C" fn ctime(t: *const TimeT) -> *mut c_char { asctime(gmtime(t)) }
10598
10599#[no_mangle]
10600pub unsafe extern "C" fn ctime_r(t: *const TimeT, buf: *mut c_char) -> *mut c_char {
10601 let mut tmp: tm = core::mem::zeroed();
10602 gmtime_r(t, &mut tmp);
10603 asctime_r(&tmp, buf)
10604}
10605
10606unsafe fn sys_clock_getres(clockid: c_int, ts: *mut timespec) -> i64 {
10611 <Arch as Syscalls>::syscall2(SYS_CLOCK_GETRES, clockid as i64, ts as i64)
10612}
10613
10614unsafe fn sys_clock_settime(clockid: c_int, ts: *const timespec) -> i64 {
10615 <Arch as Syscalls>::syscall2(SYS_CLOCK_SETTIME, clockid as i64, ts as i64)
10616}
10617
10618unsafe fn sys_clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> i64 {
10619 <Arch as Syscalls>::syscall4(SYS_CLOCK_NANOSLEEP, clockid as i64, flags as i64, req as i64, rem as i64)
10620}
10621
10622#[no_mangle]
10623pub unsafe extern "C" fn clock_getres(clockid: c_int, ts: *mut timespec) -> c_int { if sys_clock_getres(clockid, ts) < 0 { -1 } else { 0 } }
10624
10625#[no_mangle]
10626pub unsafe extern "C" fn clock_settime(clockid: c_int, ts: *const timespec) -> c_int { if sys_clock_settime(clockid, ts) < 0 { -1 } else { 0 } }
10627
10628#[no_mangle]
10629pub unsafe extern "C" fn clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> c_int {
10630 let r = sys_clock_nanosleep(clockid, flags, req, rem);
10631 if r < 0 { (-r) as c_int } else { 0 }
10632}
10633
10634#[no_mangle]
10635pub unsafe extern "C" fn gettimeofday(tv: *mut timeval, _tz: *mut c_void) -> c_int {
10636 if tv.is_null() { return 0; }
10637 let mut ts: timespec = core::mem::zeroed();
10638 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
10639 (*tv).tv_sec = ts.tv_sec;
10640 (*tv).tv_usec = ts.tv_nsec / 1000;
10641 0
10642}
10643
10644fn is_leap_year(y: i32) -> bool {
10649 let yr = if y > i32::MAX - 1900 { y - 2000 } else { y + 1900 };
10650 yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0)
10651}
10652
10653fn week_num(tm: &tm) -> i32 {
10654 let mut val = (tm.tm_yday + 7 - ((tm.tm_wday + 6) % 7)) / 7;
10655 if (tm.tm_wday + 371 - tm.tm_yday - 2).rem_euclid(7) <= 2 { val += 1; }
10656 if val == 0 {
10657 val = 52;
10658 let dec31 = (tm.tm_wday + 7 - tm.tm_yday - 1).rem_euclid(7);
10659 if dec31 == 4 || (dec31 == 5 && is_leap_year(tm.tm_year % 400 - 1)) { val += 1; }
10660 } else if val == 53 {
10661 let jan1 = (tm.tm_wday + 371 - tm.tm_yday).rem_euclid(7);
10662 if jan1 != 4 && (jan1 != 3 || !is_leap_year(tm.tm_year)) { val = 1; }
10663 }
10664 val
10665}
10666
10667const ABDAY_1: c_int = 0x20000;
10669const DAY_1: c_int = 0x20007;
10670const ABMON_1: c_int = 0x2000E;
10671const MON_1: c_int = 0x2001A;
10672const AM_STR_LI: c_int = 0x20026;
10673const PM_STR_LI: c_int = 0x20027;
10674const D_T_FMT: c_int = 0x20028;
10675const D_FMT: c_int = 0x20029;
10676const T_FMT: c_int = 0x2002A;
10677const T_FMT_AMPM: c_int = 0x2002B;
10678
10679unsafe fn num_fmt(buf: &mut [u8; 100], val: i64, pad: u8, width: usize) -> (*const u8, usize) {
10682 let negative = val < 0;
10683 let mut v = if negative { -val as u64 } else { val as u64 };
10684 let mut tmp = [0u8; 24];
10685 let mut pos = 24usize;
10686 if v == 0 { pos -= 1; tmp[pos] = b'0'; }
10687 while v > 0 { pos -= 1; tmp[pos] = b'0' + (v % 10) as u8; v /= 10; }
10688 let digits = 24 - pos;
10689 let sign_chars = if negative { 1 } else { 0 };
10690 let needed = sign_chars + digits;
10691 let fill = if width > needed { width - needed } else { 0 };
10692 let total = fill + needed;
10693 let mut p = 0usize;
10694 match pad {
10695 b'-' => { }
10696 b'_' => {
10697 for _ in 0..fill { buf[p] = b' '; p += 1; }
10698 if negative { buf[p] = b'-'; p += 1; }
10699 }
10700 _ => {
10701 if negative { buf[p] = b'-'; p += 1; }
10702 for _ in 0..fill { buf[p] = b'0'; p += 1; }
10703 }
10704 }
10705 for i in 0..digits { buf[p] = tmp[pos + i]; p += 1; }
10706 (buf.as_ptr(), total)
10707}
10708
10709unsafe fn str_to_buf(buf: &mut [u8; 100], s: *const c_char) -> (*const u8, usize) {
10711 let mut k = 0usize;
10712 while *s.add(k) != 0 {
10713 buf[k] = *s.add(k) as u8;
10714 k += 1;
10715 }
10716 (buf.as_ptr(), k)
10717}
10718
10719unsafe fn __strftime_fmt_1(buf: &mut [u8; 100], f: u8, tm: *const tm, pad: u8) -> (*const u8, usize) {
10722 let mut val: i64;
10723 let mut width: usize = 2;
10724 let mut def_pad: u8 = b'0';
10725 let fmt: *const c_char;
10726
10727 match f {
10728 b'a' => {
10729 if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
10730 let p = nl_langinfo(ABDAY_1 + (*tm).tm_wday);
10731 return str_to_buf(buf, p);
10732 }
10733 b'A' => {
10734 if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
10735 let p = nl_langinfo(DAY_1 + (*tm).tm_wday);
10736 return str_to_buf(buf, p);
10737 }
10738 b'h' | b'b' => {
10739 if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
10740 let p = nl_langinfo(ABMON_1 + (*tm).tm_mon);
10741 return str_to_buf(buf, p);
10742 }
10743 b'B' => {
10744 if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
10745 let p = nl_langinfo(MON_1 + (*tm).tm_mon);
10746 return str_to_buf(buf, p);
10747 }
10748 b'c' => {
10749 let p = nl_langinfo(D_T_FMT);
10750 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10751 return (buf.as_ptr(), l);
10752 }
10753 b'C' => {
10754 val = (1900i64 + (*tm).tm_year as i64) / 100;
10755 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10756 }
10757 b'e' => { def_pad = b'_'; }
10758 b'd' => {
10759 val = (*tm).tm_mday as i64;
10760 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10761 }
10762 b'D' => {
10763 fmt = b"%m/%d/%y\0".as_ptr() as *const c_char;
10764 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10765 return (buf.as_ptr(), l);
10766 }
10767 b'F' => {
10768 fmt = b"%Y-%m-%d\0".as_ptr() as *const c_char;
10769 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10770 return (buf.as_ptr(), l);
10771 }
10772 b'g' | b'G' => {
10773 val = (*tm).tm_year as i64 + 1900;
10774 if (*tm).tm_yday < 3 && week_num(&*tm) != 1 { val -= 1; }
10775 else if (*tm).tm_yday > 360 && week_num(&*tm) == 1 { val += 1; }
10776 if f == b'g' { val %= 100; }
10777 else { width = 4; }
10778 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10779 }
10780 b'H' => {
10781 val = (*tm).tm_hour as i64;
10782 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10783 }
10784 b'I' => {
10785 val = (*tm).tm_hour as i64;
10786 if val == 0 { val = 12; }
10787 else if val > 12 { val -= 12; }
10788 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10789 }
10790 b'j' => {
10791 val = (*tm).tm_yday as i64 + 1;
10792 width = 3;
10793 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10794 }
10795 b'm' => {
10796 val = (*tm).tm_mon as i64 + 1;
10797 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10798 }
10799 b'M' => {
10800 val = (*tm).tm_min as i64;
10801 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10802 }
10803 b'n' => { buf[0] = b'\n'; return (buf.as_ptr(), 1); }
10804 b'p' => {
10805 let p = if (*tm).tm_hour >= 12 { nl_langinfo(PM_STR_LI) } else { nl_langinfo(AM_STR_LI) };
10806 return str_to_buf(buf, p);
10807 }
10808 b'r' => {
10809 let p = nl_langinfo(T_FMT_AMPM);
10810 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10811 return (buf.as_ptr(), l);
10812 }
10813 b'R' => {
10814 fmt = b"%H:%M\0".as_ptr() as *const c_char;
10815 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10816 return (buf.as_ptr(), l);
10817 }
10818 b's' => {
10819 val = tm_to_secs(tm) - (*tm).tm_gmtoff as i64;
10820 width = 1;
10821 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10822 }
10823 b'S' => {
10824 val = (*tm).tm_sec as i64;
10825 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10826 }
10827 b't' => { buf[0] = b'\t'; return (buf.as_ptr(), 1); }
10828 b'T' => {
10829 fmt = b"%H:%M:%S\0".as_ptr() as *const c_char;
10830 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10831 return (buf.as_ptr(), l);
10832 }
10833 b'u' => {
10834 val = if (*tm).tm_wday != 0 { (*tm).tm_wday as i64 } else { 7 };
10835 width = 1;
10836 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10837 }
10838 b'U' => {
10839 val = ((*tm).tm_yday as u64 + 7 - (*tm).tm_wday as u64) as i64 / 7;
10840 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10841 }
10842 b'W' => {
10843 val = ((*tm).tm_yday as u64 + 7 - ((*tm).tm_wday as u64 + 6) % 7) as i64 / 7;
10844 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10845 }
10846 b'V' => {
10847 val = week_num(&*tm) as i64;
10848 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10849 }
10850 b'w' => {
10851 val = (*tm).tm_wday as i64;
10852 width = 1;
10853 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10854 }
10855 b'x' => {
10856 let p = nl_langinfo(D_FMT);
10857 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10858 return (buf.as_ptr(), l);
10859 }
10860 b'X' => {
10861 let p = nl_langinfo(T_FMT);
10862 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10863 return (buf.as_ptr(), l);
10864 }
10865 b'y' => {
10866 val = (1900i64 + (*tm).tm_year as i64) % 100;
10867 if val < 0 { val = -val; }
10868 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10869 }
10870 b'Y' => {
10871 val = (*tm).tm_year as i64 + 1900;
10872 if val >= 10000 {
10873 let mut tmp = [0u8; 100];
10874 let (_, k) = num_fmt(&mut tmp, val, b'-', 1);
10875 buf[0] = b'+';
10876 for i in 0..k { buf[1 + i] = tmp[i]; }
10877 return (buf.as_ptr(), 1 + k);
10878 }
10879 width = 4;
10880 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10881 }
10882 b'z' => {
10883 if (*tm).tm_isdst < 0 { return (b"\0".as_ptr(), 0); }
10884 let gmtoff = (*tm).tm_gmtoff as i64;
10885 let sign = if gmtoff >= 0 { b'+' } else { b'-' };
10886 let off = if gmtoff < 0 { -gmtoff } else { gmtoff };
10887 let hh = (off / 3600) as i32;
10888 let mm = ((off % 3600) / 60) as i32;
10889 buf[0] = sign;
10890 buf[1] = b'0' + (hh / 10) as u8;
10891 buf[2] = b'0' + (hh % 10) as u8;
10892 buf[3] = b'0' + (mm / 10) as u8;
10893 buf[4] = b'0' + (mm % 10) as u8;
10894 return (buf.as_ptr(), 5);
10895 }
10896 b'Z' => {
10897 if (*tm).tm_isdst < 0 || (*tm).tm_zone.is_null() { return (b"\0".as_ptr(), 0); }
10898 return str_to_buf(buf, (*tm).tm_zone);
10899 }
10900 b'%' => { buf[0] = b'%'; return (buf.as_ptr(), 1); }
10901 _ => { return (core::ptr::null(), 0); }
10902 }
10903 val = (*tm).tm_mday as i64;
10905 num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width)
10906}
10907
10908unsafe fn __strftime_l(s: *mut c_char, n: usize, f: *const c_char, tm: *const tm) -> usize {
10909 let mut l: usize = 0;
10910 let mut fi: usize = 0;
10911 while l < n {
10912 let ch = *f.add(fi) as u8;
10913 if ch == 0 {
10914 *s.add(l) = 0;
10915 return l;
10916 }
10917 if ch != b'%' {
10918 *s.add(l) = ch as c_char;
10919 l += 1;
10920 fi += 1;
10921 continue;
10922 }
10923 fi += 1;
10924 let mut pad: u8 = 0;
10926 let fc = *f.add(fi) as u8;
10927 if fc == b'-' || fc == b'_' || fc == b'0' { pad = fc; fi += 1; }
10928 let plus = *f.add(fi) as u8 == b'+';
10929 if plus { fi += 1; }
10930 let mut width: usize = 0;
10932 let mut p_idx = fi;
10933 {
10934 let fc2 = *f.add(fi) as u8;
10935 if fc2 >= b'0' && fc2 <= b'9' {
10936 let mut w: usize = 0;
10937 while { let c = *f.add(p_idx) as u8; c >= b'0' && c <= b'9' } {
10938 w = w * 10 + (*f.add(p_idx) as usize - b'0' as usize);
10939 p_idx += 1;
10940 }
10941 width = w;
10942 }
10943 }
10944 let spec_ch = *f.add(p_idx) as u8;
10945 if spec_ch == b'C' || spec_ch == b'F' || spec_ch == b'G' || spec_ch == b'Y' {
10946 if width == 0 && p_idx != fi { width = 1; }
10947 } else {
10948 width = 0;
10949 }
10950 fi = p_idx;
10951 let fc3 = *f.add(fi) as u8;
10953 if fc3 == b'E' || fc3 == b'O' { fi += 1; }
10954 let fch = *f.add(fi) as u8;
10955 let mut buf = [0u8; 100];
10957 let (t, k) = __strftime_fmt_1(&mut buf, fch, tm, pad);
10958 if t.is_null() { break; }
10959 let mut k = k;
10960 let mut t = t;
10961 if width != 0 {
10962 if *t == b'+' || *t == b'-' { t = t.add(1); k -= 1; }
10964 while k > 0 && *t == b'0' && k > 1 && *t.add(1) >= b'0' && *t.add(1) <= b'9' {
10965 t = t.add(1); k -= 1;
10966 }
10967 if width < k { width = k; }
10968 let mut d: usize = 0;
10969 while d < k && *t.add(d) >= b'0' && *t.add(d) <= b'9' { d += 1; }
10970 if (*tm).tm_year < -1900 {
10971 if l < n { *s.add(l) = b'-' as c_char; }
10972 l += 1;
10973 width -= 1;
10974 } else if plus && d + (width - k) >= (if spec_ch == b'C' { 3 } else { 5 }) {
10975 if l < n { *s.add(l) = b'+' as c_char; }
10976 l += 1;
10977 width -= 1;
10978 }
10979 while width > k && l < n {
10980 *s.add(l) = b'0' as c_char;
10981 l += 1;
10982 width -= 1;
10983 }
10984 }
10985 let copy = if k > n - l { n - l } else { k };
10986 core::ptr::copy_nonoverlapping(t, s.add(l) as *mut u8, copy);
10987 l += copy;
10988 fi += 1;
10989 }
10990 if n > 0 {
10991 if l == n { l = n - 1; }
10992 *s.add(l) = 0;
10993 }
10994 0
10995}
10996
10997#[no_mangle]
10998pub unsafe extern "C" fn strftime(s: *mut c_char, maxsize: usize, fmt: *const c_char, tm: *const tm) -> usize {
10999 __strftime_l(s, maxsize, fmt, tm)
11000}
11001
11002unsafe fn match_prefix(s: *const u8, prefix: &[u8]) -> bool {
11007 for i in 0..prefix.len() {
11008 if *s.add(i) == 0 || *s.add(i) != prefix[i] { return false; }
11009 }
11010 true
11011}
11012
11013unsafe fn match_ci_prefix(s: *const u8, prefix: &[u8]) -> bool {
11014 for i in 0..prefix.len() {
11015 let c = *s.add(i);
11016 if c == 0 { return false; }
11017 if c.to_ascii_lowercase() != prefix[i].to_ascii_lowercase() { return false; }
11018 }
11019 true
11020}
11021
11022unsafe fn parse_int(p: *const u8, max_digits: usize) -> (i32, *const u8) {
11023 let mut val = 0i32;
11024 let mut np = p;
11025 let mut count = 0;
11026 while *np >= b'0' && *np <= b'9' && count < max_digits {
11027 val = val * 10 + (*np - b'0') as i32;
11028 np = np.add(1);
11029 count += 1;
11030 }
11031 if count == 0 { (0, p) } else { (val, np) }
11032}
11033
11034unsafe fn parse_range(p: *const u8, min: i32, max: i32) -> (i32, *const u8) {
11035 let (val, np) = parse_int(p, 4);
11036 if np == p || val < min || val > max { (0, p) } else { (val, np) }
11037}
11038
11039fn is_ascii_space(c: u8) -> bool {
11040 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0c || c == 0x0b
11041}
11042
11043#[no_mangle]
11044pub unsafe extern "C" fn strptime(s: *const c_char, fmt: *const c_char, tm: *mut tm) -> *mut c_char {
11045 let mut p = s as *const u8;
11046 let mut f = fmt as *const u8;
11047 let mut want_century = 0i32;
11048 let mut century = 0i32;
11049 let mut relyear = 0i32;
11050 while *f != 0 {
11051 if *f != b'%' {
11052 if is_ascii_space(*f) {
11053 while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
11054 } else {
11055 if *p != *f { return core::ptr::null_mut(); }
11056 p = p.add(1);
11057 }
11058 f = f.add(1);
11059 continue;
11060 }
11061 f = f.add(1);
11062 if *f == b'+' { f = f.add(1); }
11063 while *f >= b'0' && *f <= b'9' { f = f.add(1); }
11064 if *f == b'E' || *f == b'O' { f = f.add(1); }
11065 match *f {
11066 b'a' | b'A' => {
11067 let mut found = false;
11068 for i in 0..7 {
11069 let names: [&[u8]; 7] = [b"Sunday", b"Monday", b"Tuesday", b"Wednesday", b"Thursday", b"Friday", b"Saturday"];
11070 let snames: [&[u8]; 7] = [b"Sun", b"Mon", b"Tue", b"Wed", b"Thu", b"Fri", b"Sat"];
11071 if match_prefix(p, names[i]) { (*tm).tm_wday = i as c_int; p = p.add(names[i].len()); found = true; break; }
11072 if match_prefix(p, snames[i]) { (*tm).tm_wday = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11073 }
11074 if !found { return core::ptr::null_mut(); }
11075 }
11076 b'b' | b'B' | b'h' => {
11077 let mut found = false;
11078 for i in 0..12 {
11079 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"];
11080 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"];
11081 if match_prefix(p, names[i]) { (*tm).tm_mon = i as c_int; p = p.add(names[i].len()); found = true; break; }
11082 if match_prefix(p, snames[i]) { (*tm).tm_mon = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11083 }
11084 if !found { return core::ptr::null_mut(); }
11085 }
11086 b'C' => {
11087 let (v, np) = parse_int(p, 2);
11088 if np == p { return core::ptr::null_mut(); }
11089 century = v;
11090 want_century |= 2;
11091 p = np;
11092 }
11093 b'd' | b'e' => {
11094 let (v, np) = parse_range(p, 1, 31);
11095 if np == p { return core::ptr::null_mut(); }
11096 (*tm).tm_mday = v;
11097 p = np;
11098 }
11099 b'D' => {
11100 let r = strptime(p as *const c_char, b"%m/%d/%y\0".as_ptr() as *const c_char, tm);
11101 if r.is_null() { return core::ptr::null_mut(); }
11102 p = r as *const u8;
11103 }
11104 b'F' => {
11105 let (yv, ynp) = parse_int(p, 4);
11106 if ynp == p { return core::ptr::null_mut(); }
11107 (*tm).tm_year = yv - 1900;
11108 p = ynp;
11109 if *p != b'-' { return core::ptr::null_mut(); }
11110 p = p.add(1);
11111 let (mv, mnp) = parse_range(p, 1, 12);
11112 if mnp == p { return core::ptr::null_mut(); }
11113 (*tm).tm_mon = mv - 1;
11114 p = mnp;
11115 if *p != b'-' { return core::ptr::null_mut(); }
11116 p = p.add(1);
11117 let (dv, dnp) = parse_range(p, 1, 31);
11118 if dnp == p { return core::ptr::null_mut(); }
11119 (*tm).tm_mday = dv;
11120 p = dnp;
11121 }
11122 b'H' | b'I' => {
11123 let (v, np) = parse_range(p, 0, 23);
11124 if np == p { return core::ptr::null_mut(); }
11125 (*tm).tm_hour = v;
11126 p = np;
11127 }
11128 b'j' => {
11129 let (v, np) = parse_range(p, 1, 366);
11130 if np == p { return core::ptr::null_mut(); }
11131 (*tm).tm_yday = v - 1;
11132 p = np;
11133 }
11134 b'm' => {
11135 let (v, np) = parse_range(p, 1, 12);
11136 if np == p { return core::ptr::null_mut(); }
11137 (*tm).tm_mon = v - 1;
11138 p = np;
11139 }
11140 b'M' => {
11141 let (v, np) = parse_range(p, 0, 59);
11142 if np == p { return core::ptr::null_mut(); }
11143 (*tm).tm_min = v;
11144 p = np;
11145 }
11146 b'n' | b't' => {
11147 while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
11148 }
11149 b'p' => {
11150 if match_ci_prefix(p, b"AM") {
11151 if (*tm).tm_hour == 12 { (*tm).tm_hour = 0; }
11152 p = p.add(2);
11153 } else if match_ci_prefix(p, b"PM") {
11154 if (*tm).tm_hour < 12 { (*tm).tm_hour += 12; }
11155 p = p.add(2);
11156 } else { return core::ptr::null_mut(); }
11157 }
11158 b'r' => {
11159 let r = strptime(p as *const c_char, b"%I:%M:%S %p\0".as_ptr() as *const c_char, tm);
11160 if r.is_null() { return core::ptr::null_mut(); }
11161 p = r as *const u8;
11162 }
11163 b'R' => {
11164 let r = strptime(p as *const c_char, b"%H:%M\0".as_ptr() as *const c_char, tm);
11165 if r.is_null() { return core::ptr::null_mut(); }
11166 p = r as *const u8;
11167 }
11168 b's' => {
11169 let neg = if *p == b'-' { p = p.add(1); true } else { false };
11170 if *p < b'0' || *p > b'9' { return core::ptr::null_mut(); }
11171 let mut val = 0i64;
11172 while *p >= b'0' && *p <= b'9' {
11173 val = val * 10 + (*p - b'0') as i64;
11174 p = p.add(1);
11175 }
11176 if neg { val = -val; }
11177 secs_to_tm(val, &mut *tm);
11178 }
11179 b'S' => {
11180 let (v, np) = parse_range(p, 0, 60);
11181 if np == p { return core::ptr::null_mut(); }
11182 (*tm).tm_sec = v;
11183 p = np;
11184 }
11185 b'T' => {
11186 let r = strptime(p as *const c_char, b"%H:%M:%S\0".as_ptr() as *const c_char, tm);
11187 if r.is_null() { return core::ptr::null_mut(); }
11188 p = r as *const u8;
11189 }
11190 b'U' | b'W' => {
11191 let (_, np) = parse_range(p, 0, 53);
11192 if np == p { return core::ptr::null_mut(); }
11193 p = np;
11194 }
11195 b'V' => {
11196 let (_, np) = parse_range(p, 1, 53);
11197 if np == p { return core::ptr::null_mut(); }
11198 p = np;
11199 }
11200 b'w' => {
11201 let (v, np) = parse_range(p, 0, 6);
11202 if np == p { return core::ptr::null_mut(); }
11203 (*tm).tm_wday = v;
11204 p = np;
11205 }
11206 b'y' => {
11207 let (v, np) = parse_int(p, 2);
11208 if np == p { return core::ptr::null_mut(); }
11209 relyear = v;
11210 want_century |= 1;
11211 p = np;
11212 }
11213 b'Y' => {
11214 let neg = if *p == b'-' { p = p.add(1); true } else { false };
11215 let (v, np) = parse_int(p, 4);
11216 if np == p { return core::ptr::null_mut(); }
11217 (*tm).tm_year = if neg { -(v + 1900) } else { v - 1900 };
11218 want_century = 0;
11219 p = np;
11220 }
11221 b'z' => {
11222 if *p != b'+' && *p != b'-' { return core::ptr::null_mut(); }
11223 let neg = *p == b'-';
11224 p = p.add(1);
11225 let mut off = 0i64;
11226 let mut digits = 0;
11227 while digits < 4 && *p >= b'0' && *p <= b'9' {
11228 off = off * 10 + (*p - b'0') as i64;
11229 p = p.add(1);
11230 digits += 1;
11231 }
11232 if digits == 0 { return core::ptr::null_mut(); }
11233 let (hh, mm) = if digits <= 2 { (off, 0i64) } else { (off / 100, off % 100) };
11234 (*tm).tm_gmtoff = (hh * 3600 + mm * 60) * if neg { -1 } else { 1 };
11235 }
11236 b'%' => {
11237 if *p != b'%' { return core::ptr::null_mut(); }
11238 p = p.add(1);
11239 }
11240 _ => { return core::ptr::null_mut(); }
11241 }
11242 f = f.add(1);
11243 }
11244 if want_century != 0 {
11245 (*tm).tm_year = relyear;
11246 if want_century & 2 != 0 { (*tm).tm_year += century * 100 - 1900; }
11247 else if (*tm).tm_year <= 68 { (*tm).tm_year += 100; }
11248 }
11249 p as *mut c_char
11250}
11251
11252#[no_mangle]
11257pub static mut daylight: c_int = 0;
11258#[no_mangle]
11259pub static mut timezone: c_long = 0;
11260#[no_mangle]
11261pub 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];
11262
11263#[no_mangle]
11264pub unsafe extern "C" fn tzset() {
11265 daylight = 0;
11266 timezone = 0;
11267}
11268
11269#[no_mangle]
11274pub unsafe extern "C" fn system(cmd: *const c_char) -> c_int {
11275 if cmd.is_null() {
11276 let pid = sys_fork();
11278 if pid == 0 {
11279 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11280 let dash_c = b"-c\0".as_ptr() as *const c_char;
11281 let exit0 = b"exit 0\0".as_ptr() as *const c_char;
11282 let argv = [b"sh\0".as_ptr() as *const c_char, dash_c, exit0, core::ptr::null()];
11283 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11284 _exit(127);
11285 }
11286 if pid < 0 { return -1; }
11287 let mut status: c_int = 0;
11288 loop {
11289 let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11290 if r >= 0 { return status; }
11291 if r != -4 { return -1; } }
11293 }
11294
11295 let sa_ignore = sigaction {
11296 sa_handler: SIG_IGN,
11297 sa_flags: SA_RESTORER,
11298 sa_restorer: sig_restorer as *const () as usize,
11299 sa_mask: [0],
11300 };
11301 let mut oldint: sigaction = core::mem::zeroed();
11302 let mut oldquit: sigaction = core::mem::zeroed();
11303
11304 sys_rt_sigaction(SIGINT, &sa_ignore, &mut oldint, 8);
11305 sys_rt_sigaction(SIGQUIT, &sa_ignore, &mut oldquit, 8);
11306
11307 let mut block_set: SigSetT = 0;
11308 block_set |= 1u64 << (SIGCHLD - 1);
11309 let mut oldmask: SigSetT = 0;
11310 sys_rt_sigprocmask(SIG_BLOCK, &block_set, &mut oldmask, 8);
11311
11312 let pid = sys_fork();
11313
11314 if pid == 0 {
11315 sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11316 sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11317 sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11318
11319 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11320 let argv = [
11321 b"sh\0".as_ptr() as *const c_char,
11322 b"-c\0".as_ptr() as *const c_char,
11323 cmd,
11324 core::ptr::null(),
11325 ];
11326 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11327 _exit(127);
11328 }
11329
11330 let mut status: c_int = -1;
11331 if pid > 0 {
11332 loop {
11333 let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11334 if r >= 0 { break; }
11335 if r != -4 { break; } }
11337 }
11338
11339 sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11340 sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11341 sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11342
11343 status
11344}
11345
11346const EPERM_VAL: c_int = 1;
11351const ENOENT_VAL: c_int = 2;
11352const ESRCH_VAL: c_int = 3;
11353const EINTR_VAL: c_int = 4;
11354const EIO_VAL: c_int = 5;
11355const ENXIO_VAL: c_int = 6;
11356const E2BIG_VAL: c_int = 7;
11357const ENOEXEC_VAL: c_int = 8;
11358const EBADF_VAL: c_int = 9;
11359const ECHILD_VAL: c_int = 10;
11360const EAGAIN_VAL: c_int = 11;
11361const ENOMEM_VAL: c_int = 12;
11362const EACCES_VAL: c_int = 13;
11363const EFAULT_VAL: c_int = 14;
11364const ENOTBLK_VAL: c_int = 15;
11365const EBUSY_VAL: c_int = 16;
11366const EEXIST_VAL: c_int = 17;
11367const EXDEV_VAL: c_int = 18;
11368const ENODEV_VAL: c_int = 19;
11369const ENOTDIR_VAL: c_int = 20;
11370const EISDIR_VAL: c_int = 21;
11371const EINVAL_VAL: c_int = 22;
11372const ENFILE_VAL: c_int = 23;
11373const EMFILE_VAL: c_int = 24;
11374const ENOTTY_VAL: c_int = 25;
11375const ETXTBSY_VAL: c_int = 26;
11376const EFBIG_VAL: c_int = 27;
11377const ENOSPC_VAL: c_int = 28;
11378const ESPIPE_VAL: c_int = 29;
11379const EROFS_VAL: c_int = 30;
11380const EMLINK_VAL: c_int = 31;
11381const EPIPE_VAL: c_int = 32;
11382const EDOM_VAL: c_int = 33;
11383const ERANGE_VAL: c_int = 34;
11384const EDEADLK_VAL: c_int = 35;
11385const ENAMETOOLONG_VAL: c_int = 36;
11386const ENOLCK_VAL: c_int = 37;
11387const ENOSYS_VAL: c_int = 38;
11388const ENOTEMPTY_VAL: c_int = 39;
11389const ELOOP_VAL: c_int = 40;
11390const EWOULDBLOCK_VAL: c_int = 11;
11391const ENOMSG_VAL: c_int = 42;
11392const EIDRM_VAL: c_int = 43;
11393const ECHRNG_VAL: c_int = 44;
11394const EL2NSYNC_VAL: c_int = 45;
11395const EL3HLT_VAL: c_int = 46;
11396const EL3RST_VAL: c_int = 47;
11397const ELNRNG_VAL: c_int = 48;
11398const EUNATCH_VAL: c_int = 49;
11399const ENOCSI_VAL: c_int = 50;
11400const EL2HLT_VAL: c_int = 51;
11401const EBADE_VAL: c_int = 52;
11402const EBADR_VAL: c_int = 53;
11403const EXFULL_VAL: c_int = 54;
11404const ENOANO_VAL: c_int = 55;
11405const EBADRQC_VAL: c_int = 56;
11406const EBADSLT_VAL: c_int = 57;
11407const EBFONT_VAL: c_int = 59;
11408const ENOSTR_VAL: c_int = 60;
11409const ENODATA_VAL: c_int = 61;
11410const ETIME_VAL: c_int = 62;
11411const ENOSR_VAL: c_int = 63;
11412const ENONET_VAL: c_int = 64;
11413const ENOPKG_VAL: c_int = 65;
11414const EREMOTE_VAL: c_int = 66;
11415const ENOLINK_VAL: c_int = 67;
11416const EADV_VAL: c_int = 68;
11417const ESRMNT_VAL: c_int = 69;
11418const ECOMM_VAL: c_int = 70;
11419const EPROTO_VAL: c_int = 71;
11420const EMULTIHOP_VAL: c_int = 72;
11421const EDOTDOT_VAL: c_int = 73;
11422const EBADMSG_VAL: c_int = 74;
11423const EOVERFLOW_VAL: c_int = 75;
11424const ENOTUNIQ_VAL: c_int = 76;
11425const EBADFD_VAL: c_int = 77;
11426const EREMCHG_VAL: c_int = 78;
11427const ELIBACC_VAL: c_int = 79;
11428const ELIBBAD_VAL: c_int = 80;
11429const ELIBSCN_VAL: c_int = 81;
11430const ELIBMAX_VAL: c_int = 82;
11431const ELIBEXEC_VAL: c_int = 83;
11432const EILSEQ_VAL: c_int = 84;
11433const ERESTART_VAL: c_int = 85;
11434const ESTRPIPE_VAL: c_int = 86;
11435const EUSERS_VAL: c_int = 87;
11436const ENOTSOCK_VAL: c_int = 88;
11437const EDESTADDRREQ_VAL: c_int = 89;
11438const EMSGSIZE_VAL: c_int = 90;
11439const EPROTOTYPE_VAL: c_int = 91;
11440const ENOPROTOOPT_VAL: c_int = 92;
11441const EPROTONOSUPPORT_VAL: c_int = 93;
11442const ESOCKTNOSUPPORT_VAL: c_int = 94;
11443const EOPNOTSUPP_VAL: c_int = 95;
11444const ENOTSUP_VAL: c_int = 95;
11445const EPFNOSUPPORT_VAL: c_int = 96;
11446const EAFNOSUPPORT_VAL: c_int = 97;
11447const EADDRINUSE_VAL: c_int = 98;
11448const EADDRNOTAVAIL_VAL: c_int = 99;
11449const ENETDOWN_VAL: c_int = 100;
11450const ENETUNREACH_VAL: c_int = 101;
11451const ENETRESET_VAL: c_int = 102;
11452const ECONNABORTED_VAL: c_int = 103;
11453const ECONNRESET_VAL: c_int = 104;
11454const ENOBUFS_VAL: c_int = 105;
11455const EISCONN_VAL: c_int = 106;
11456const ENOTCONN_VAL: c_int = 107;
11457const ESHUTDOWN_VAL: c_int = 108;
11458const ETOOMANYREFS_VAL: c_int = 109;
11459const ETIMEDOUT_VAL: c_int = 110;
11460const ECONNREFUSED_VAL: c_int = 111;
11461const EHOSTDOWN_VAL: c_int = 112;
11462const EHOSTUNREACH_VAL: c_int = 113;
11463const EALREADY_VAL: c_int = 114;
11464const EINPROGRESS_VAL: c_int = 115;
11465const ESTALE_VAL: c_int = 116;
11466const EUCLEAN_VAL: c_int = 117;
11467const ENOTNAM_VAL: c_int = 118;
11468const ENAVAIL_VAL: c_int = 119;
11469const EISNAM_VAL: c_int = 120;
11470const EREMOTEIO_VAL: c_int = 121;
11471const EDQUOT_VAL: c_int = 122;
11472const ENOMEDIUM_VAL: c_int = 123;
11473const EMEDIUMTYPE_VAL: c_int = 124;
11474const ECANCELED_VAL: c_int = 125;
11475const ENOKEY_VAL: c_int = 126;
11476const EKEYEXPIRED_VAL: c_int = 127;
11477const EKEYREVOKED_VAL: c_int = 128;
11478const EKEYREJECTED_VAL: c_int = 129;
11479const EOWNERDEAD_VAL: c_int = 130;
11480const ENOTRECOVERABLE_VAL: c_int = 131;
11481const ERFKILL_VAL: c_int = 132;
11482const EHWPOISON_VAL: c_int = 133;
11483
11484static ERR_STRS: [&[u8]; 134] = [
11486 b"Success\0", b"Operation not permitted\0", b"No such file or directory\0", b"No such process\0", b"Interrupted system call\0", b"Input/output error\0", b"No such device or address\0", b"Argument list too long\0", b"Exec format error\0", b"Bad file descriptor\0", b"No child processes\0", b"Resource temporarily unavailable\0", b"Cannot allocate memory\0", b"Permission denied\0", b"Bad address\0", b"Block device required\0", b"Device or resource busy\0", b"File exists\0", b"Invalid cross-device link\0", b"No such device\0", b"Not a directory\0", b"Is a directory\0", b"Invalid argument\0", b"Too many open files in system\0", b"Too many open files\0", b"Inappropriate ioctl for device\0", b"Text file busy\0", b"File too large\0", b"No space left on device\0", b"Illegal seek\0", b"Read-only file system\0", b"Too many links\0", b"Broken pipe\0", b"Numerical argument out of domain\0", b"Numerical result out of range\0", b"Resource deadlock avoided\0", b"File name too long\0", b"No locks available\0", b"Function not implemented\0", b"Directory not empty\0", b"Too many levels of symbolic links\0", b"Unknown error 41\0", b"No message of desired type\0", b"Identifier removed\0", b"Channel number out of range\0", b"Level 2 not synchronized\0", b"Level 3 halted\0", b"Level 3 reset\0", b"Link number out of range\0", b"Protocol driver not attached\0", b"No CSI structure available\0", b"Level 2 halted\0", b"Invalid exchange\0", b"Invalid request descriptor\0", b"Exchange full\0", b"No anode\0", b"Invalid request code\0", b"Invalid slot\0", b"Unknown error 58\0", b"Bad font file format\0", b"Device not a stream\0", b"No data available\0", b"Timer expired\0", b"Out of streams resources\0", b"Machine is not on the network\0", b"Package not installed\0", b"Object is remote\0", b"Link has been severed\0", b"Advertise error\0", b"Srmount error\0", b"Communication error on send\0", b"Protocol error\0", b"Multihop attempted\0", b"RFS specific error\0", b"Bad message\0", b"Value too large for defined data type\0", b"Name not unique on network\0", b"File descriptor in bad state\0", b"Remote address changed\0", b"Can not access a needed shared library\0", b"Accessing a corrupted shared library\0", b".lib section in a.out corrupted\0", b"Attempting to link in too many shared libraries\0", b"Cannot exec a shared library directly\0", b"Invalid or incomplete multibyte or wide character\0", b"Interrupted system call should be restarted\0", b"Streams pipe error\0", b"Too many users\0", b"Socket operation on non-socket\0", b"Destination address required\0", b"Message too long\0", b"Protocol wrong type for socket\0", b"Protocol not available\0", b"Protocol not supported\0", b"Socket type not supported\0", b"Operation not supported\0", b"Protocol family not supported\0", b"Address family not supported by protocol\0", b"Address already in use\0", b"Cannot assign requested address\0", b"Network is down\0", b"Network is unreachable\0", b"Network dropped connection on reset\0", b"Software caused connection abort\0", b"Connection reset by peer\0", b"No buffer space available\0", b"Transport endpoint is already connected\0", b"Transport endpoint is not connected\0", b"Cannot send after transport endpoint shutdown\0", b"Too many references: cannot splice\0", b"Connection timed out\0", b"Connection refused\0", b"Host is down\0", b"No route to host\0", b"Operation already in progress\0", b"Operation now in progress\0", b"Stale file handle\0", b"Structure needs cleaning\0", b"Not a XENIX named type file\0", b"No XENIX semaphores available\0", b"Is a named type file\0", b"Remote I/O error\0", b"Quota exceeded\0", b"No medium found\0", b"Wrong medium type\0", b"Operation canceled\0", b"Required key not available\0", b"Key has expired\0", b"Key has been revoked\0", b"Key was rejected by service\0", b"Owner died\0", b"State not recoverable\0", b"Operation not possible due to RF-kill\0", b"Memory page has hardware error\0", ];
11621
11622#[no_mangle]
11623pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
11624 if errnum < 0 || errnum as usize >= ERR_STRS.len() {
11625 static mut UNKNOWN_BUF: [c_char; 32] = [0; 32];
11627 let prefix = b"Unknown error \0";
11628 let mut i = 0;
11629 while prefix[i] != 0 {
11630 UNKNOWN_BUF[i] = prefix[i] as c_char;
11631 i += 1;
11632 }
11633 let (buf, len) = format_u64(errnum as u64);
11634 for j in 0..len {
11635 UNKNOWN_BUF[i] = buf[20 - len + j] as c_char;
11636 i += 1;
11637 }
11638 UNKNOWN_BUF[i] = 0;
11639 return core::ptr::addr_of_mut!(UNKNOWN_BUF).cast::<c_char>();
11640 }
11641 ERR_STRS[errnum as usize].as_ptr() as *mut c_char
11642}
11643
11644#[no_mangle]
11645pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: usize) -> c_int {
11646 let s = strerror(errnum);
11647 let slen = strlen(s as *const c_char);
11648 if slen >= buflen {
11649 if buflen > 0 {
11650 core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, buflen - 1);
11651 *buf.add(buflen - 1) = 0;
11652 }
11653 return 34; }
11655 core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, slen + 1);
11656 0
11657}
11658
11659#[no_mangle]
11661pub static mut environ: *mut *mut c_char = core::ptr::null_mut();
11662
11663unsafe fn sync_environ() {
11665 environ = __environ;
11666}
11667
11668#[inline]
11673unsafe fn sys_dup(oldfd: i32) -> i64 {
11674 <Arch as Syscalls>::syscall1(SYS_DUP, oldfd as i64)
11675}
11676
11677#[inline]unsafe fn sys_dup2(oldfd: i32, newfd: i32) -> i64 {
11678 sys_dup3(oldfd, newfd, 0)
11680}
11681
11682#[inline]
11683unsafe fn sys_access(path: *const u8, mode: i32) -> i64 {
11684 <Arch as Syscalls>::syscall4(SYS_FACCESSAT, AT_FDCWD as i64, path as i64, mode as i64, 0)
11685}
11686
11687#[inline]unsafe fn sys_unlink(path: *const u8) -> i64 {
11688 sys_unlinkat(AT_FDCWD, path, 0)
11689}
11690
11691#[inline]unsafe fn sys_rmdir(path: *const u8) -> i64 {
11692 sys_unlinkat(AT_FDCWD, path, 512) }
11694
11695#[inline]
11696unsafe fn sys_chdir(path: *const u8) -> i64 {
11697 <Arch as Syscalls>::syscall1(SYS_CHDIR, path as i64)
11698}
11699
11700#[inline]
11701unsafe fn sys_getcwd(buf: *mut u8, size: usize) -> i64 {
11702 <Arch as Syscalls>::syscall2(SYS_GETCWD, buf as i64, size as i64)
11703}
11704
11705#[inline]
11706unsafe fn sys_sethostname(name: *const u8, len: usize) -> i64 {
11707 <Arch as Syscalls>::syscall2(SYS_SETHOSTNAME, name as i64, len as i64)
11708}
11709
11710#[inline]
11711unsafe fn sys_gethostname(buf: *mut u8, len: usize) -> i64 {
11712 #[repr(C)]
11713 struct UtsName {
11714 sysname: [u8; 65],
11715 nodename: [u8; 65],
11716 release: [u8; 65],
11717 version: [u8; 65],
11718 machine: [u8; 65],
11719 domainname: [u8; 65],
11720 }
11721 let mut uts: UtsName = core::mem::zeroed();
11722 let result = <Arch as Syscalls>::syscall1(SYS_UNAME, &mut uts as *mut UtsName as i64);
11723 if result < 0 {
11724 return result;
11725 }
11726 let nlen = strlen(uts.nodename.as_ptr() as *const c_char);
11727 let copylen = if nlen < len { nlen } else { if len > 0 { len - 1 } else { 0 } };
11728 core::ptr::copy_nonoverlapping(uts.nodename.as_ptr(), buf, copylen);
11729 if len > 0 { *buf.add(copylen) = 0; }
11730 0
11731}
11732
11733unsafe fn sys_truncate(path: *const u8, length: i64) -> i64 {
11734 <Arch as Syscalls>::syscall2(SYS_TRUNCATE, path as i64, length as i64)
11735}
11736
11737unsafe fn sys_ftruncate(fd: i32, length: i64) -> i64 {
11738 <Arch as Syscalls>::syscall2(SYS_FTRUNCATE, fd as i64, length as i64)
11739}
11740
11741unsafe fn sys_nanosleep(req: *const timespec, rem: *mut timespec) -> i64 {
11742 <Arch as Syscalls>::syscall2(SYS_NANOSLEEP, req as i64, rem as i64)
11743}
11744
11745const ITIMER_REAL: i32 = 0;
11746
11747#[repr(C)]
11748struct itimerval {
11749 it_interval: timeval,
11750 it_value: timeval,
11751}
11752
11753unsafe fn sys_alarm(seconds: c_uint) -> i64 {
11754 let mut new: itimerval = core::mem::zeroed();
11755 new.it_value.tv_sec = seconds as c_long;
11756 let mut old: itimerval = core::mem::zeroed();
11757 let r = <Arch as Syscalls>::syscall3(
11758 SYS_SETITIMER,
11759 ITIMER_REAL as i64,
11760 &new as *const _ as i64,
11761 &mut old as *mut _ as i64,
11762 );
11763 if r < 0 {
11764 return r;
11765 }
11766 old.it_value.tv_sec as i64
11767}
11768
11769unsafe fn sys_pause() -> i64 {
11770 #[cfg(target_arch = "x86_64")]
11771 { <Arch as Syscalls>::syscall0(SYS_PAUSE) }
11772 #[cfg(target_arch = "aarch64")]
11773 { <Arch as Syscalls>::syscall4(SYS_PPOLL, 0, 0, 0, 0) }
11774}
11775
11776unsafe fn sys_fsync(fd: i32) -> i64 {
11777 <Arch as Syscalls>::syscall1(SYS_FSYNC, fd as i64)
11778}
11779
11780unsafe fn sys_fdatasync(fd: i32) -> i64 {
11781 <Arch as Syscalls>::syscall1(SYS_FDATASYNC, fd as i64)
11782}
11783
11784unsafe fn sys_sync() {
11785 let _ = <Arch as Syscalls>::syscall0(SYS_SYNC);
11786}
11787
11788unsafe fn sys_symlink(target: *const u8, linkpath: *const u8) -> i64 {
11789 <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, AT_FDCWD as i64, linkpath as i64)
11790}
11791
11792unsafe fn sys_symlinkat(target: *const u8, newdirfd: i32, linkpath: *const u8) -> i64 {
11793 <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, newdirfd as i64, linkpath as i64)
11794}
11795
11796unsafe fn sys_readlinkat(dirfd: i32, path: *const u8, buf: *mut u8, bufsiz: usize) -> i64 {
11797 <Arch as Syscalls>::syscall4(SYS_READLINKAT, dirfd as i64, path as i64, buf as i64, bufsiz as i64)
11798}
11799
11800unsafe fn sys_linkat(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: i32) -> i64 {
11801 <Arch as Syscalls>::syscall5(SYS_LINKAT, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
11802}
11803
11804unsafe fn sys_fchmod(fd: i32, mode: u32) -> i64 {
11805 <Arch as Syscalls>::syscall2(SYS_FCHMOD, fd as i64, mode as i64)
11806}
11807
11808unsafe fn sys_fchmodat(dirfd: i32, path: *const u8, mode: u32, flags: i32) -> i64 {
11809 <Arch as Syscalls>::syscall4(SYS_FCHMODAT, dirfd as i64, path as i64, mode as i64, flags as i64)
11810}
11811
11812unsafe fn sys_umask(mask: u32) -> u32 {
11813 <Arch as Syscalls>::syscall1(SYS_UMASK, mask as i64) as u32
11814}
11815
11816unsafe fn sys_getgroups(size: i32, list: *mut c_uint) -> i64 {
11817 <Arch as Syscalls>::syscall2(SYS_GETGROUPS, size as i64, list as i64)
11818}
11819
11820unsafe fn sys_setuid(uid: c_uint) -> i64 {
11821 <Arch as Syscalls>::syscall1(SYS_SETUID, uid as i64)
11822}
11823
11824unsafe fn sys_setgid(gid: c_uint) -> i64 {
11825 <Arch as Syscalls>::syscall1(SYS_SETGID, gid as i64)
11826}
11827
11828unsafe fn sys_setsid() -> i64 {
11829 <Arch as Syscalls>::syscall0(SYS_SETSID)
11830}
11831
11832unsafe fn sys_setpgid(pid: c_int, pgid: c_int) -> i64 {
11833 <Arch as Syscalls>::syscall2(SYS_SETPGID, pid as i64, pgid as i64)
11834}
11835
11836unsafe fn sys_getpgid(pid: c_int) -> i64 {
11837 <Arch as Syscalls>::syscall1(SYS_GETPGID, pid as i64)
11838}
11839
11840unsafe fn sys_getsid(pid: c_int) -> i64 {
11841 <Arch as Syscalls>::syscall1(SYS_GETSID, pid as i64)
11842}
11843
11844unsafe fn sys_mkdirat(dirfd: i32, path: *const u8, mode: u32) -> i64 {
11845 <Arch as Syscalls>::syscall3(SYS_MKDIRAT, dirfd as i64, path as i64, mode as i64)
11846}
11847
11848#[no_mangle]
11851pub unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int {
11852 let r = sys_pipe2(fds, 0);
11853 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11854 0
11855}
11856
11857#[no_mangle]
11858pub unsafe extern "C" fn pipe2(fds: *mut c_int, flags: c_int) -> c_int {
11859 let r = sys_pipe2(fds, flags);
11860 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11861 0
11862}
11863
11864#[no_mangle]
11865pub unsafe extern "C" fn dup(oldfd: c_int) -> c_int {
11866 let r = sys_dup(oldfd);
11867 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11868 r as c_int
11869}
11870
11871#[no_mangle]
11872pub unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> c_int {
11873 let r = sys_dup2(oldfd, newfd);
11874 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11875 r as c_int
11876}
11877
11878#[no_mangle]
11879pub unsafe extern "C" fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int {
11880 let r = sys_dup3(oldfd, newfd, flags);
11881 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11882 r as c_int
11883}
11884
11885#[no_mangle]
11886pub unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, mut args: ...) -> c_int {
11887 let r = match cmd {
11888 F_GETFD | F_GETFL => sys_fcntl(fd, cmd, 0),
11889 F_SETFD | F_SETFL | F_DUPFD | F_DUPFD_CLOEXEC => {
11890 let arg = args.next_arg::<c_int>();
11891 sys_fcntl(fd, cmd, arg as i64)
11892 }
11893 F_GETLK | F_SETLK | F_SETLKW => {
11894 let arg = args.next_arg::<*mut c_void>();
11895 sys_fcntl(fd, cmd, arg as i64)
11896 }
11897 _ => sys_fcntl(fd, cmd, 0),
11898 };
11899 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11900 r as c_int
11901}
11902
11903#[no_mangle]
11904pub unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int {
11905 let r = sys_access(path as *const u8, mode);
11906 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11907 0
11908}
11909
11910#[no_mangle]
11911pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
11912 let r = sys_unlink(path as *const u8);
11913 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11914 0
11915}
11916
11917#[no_mangle]
11918pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int {
11919 let r = sys_rmdir(path as *const u8);
11920 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11921 0
11922}
11923
11924#[no_mangle]
11925pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int {
11926 let r = sys_chdir(path as *const u8);
11927 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11928 0
11929}
11930
11931#[no_mangle]
11932pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
11933 if buf.is_null() {
11934 let alloc_size = if size == 0 { 256 } else { size };
11936 let p = malloc(alloc_size) as *mut c_char;
11937 if p.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
11938 let r = sys_getcwd(p as *mut u8, alloc_size);
11939 if r < 0 { free(p as *mut c_void); ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
11940 return p;
11941 }
11942 if size == 0 { ERRNO = EINVAL; return core::ptr::null_mut(); }
11943 let r = sys_getcwd(buf as *mut u8, size);
11944 if r < 0 { ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
11945 buf
11946}
11947
11948#[no_mangle]
11949pub unsafe extern "C" fn gethostname(name: *mut c_char, len: usize) -> c_int {
11950 let r = sys_gethostname(name as *mut u8, len);
11951 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11952 0
11953}
11954
11955#[no_mangle]
11957pub extern "C" fn getpagesize() -> c_int {
11958 4096
11959}
11960
11961#[no_mangle]
11962pub unsafe extern "C" fn truncate(path: *const c_char, length: i64) -> c_int {
11963 let r = sys_truncate(path as *const u8, length);
11964 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11965 0
11966}
11967
11968#[no_mangle]
11969pub unsafe extern "C" fn ftruncate(fd: c_int, length: i64) -> c_int {
11970 let r = sys_ftruncate(fd, length);
11971 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11972 0
11973}
11974
11975#[no_mangle]
11976pub unsafe extern "C" fn nanosleep(req: *const timespec, rem: *mut timespec) -> c_int {
11977 pthread_testcancel();
11978 let r = sys_nanosleep(req, rem);
11979 pthread_testcancel();
11980 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11981 0
11982}
11983
11984#[no_mangle]
11985pub unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
11986 let req = timespec { tv_sec: seconds as c_long, tv_nsec: 0 };
11987 let mut rem: timespec = core::mem::zeroed();
11988 pthread_testcancel();
11989 let r = sys_nanosleep(&req, &mut rem);
11990 pthread_testcancel();
11991 if r < 0 {
11992 let e = (-r) as c_int;
11993 if e == EINTR { return rem.tv_sec as c_uint; }
11994 }
11995 0
11996}
11997
11998#[no_mangle]
11999pub unsafe extern "C" fn usleep(usec: c_uint) -> c_int {
12000 let req = timespec { tv_sec: (usec / 1000000) as c_long, tv_nsec: ((usec % 1000000) * 1000) as c_long };
12001 pthread_testcancel();
12002 let r = sys_nanosleep(&req, core::ptr::null_mut());
12003 pthread_testcancel();
12004 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12005 0
12006}
12007
12008#[no_mangle]
12009pub unsafe extern "C" fn alarm(seconds: c_uint) -> c_uint {
12010 sys_alarm(seconds) as c_uint
12011}
12012
12013#[no_mangle]
12014pub unsafe extern "C" fn pause() -> c_int {
12015 pthread_testcancel();
12016 sys_pause();
12017 pthread_testcancel();
12018 ERRNO = EINTR;
12019 -1
12020}
12021
12022#[no_mangle]
12023pub unsafe extern "C" fn fsync(fd: c_int) -> c_int {
12024 let r = sys_fsync(fd);
12025 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12026 0
12027}
12028
12029#[no_mangle]
12030pub unsafe extern "C" fn fdatasync(fd: c_int) -> c_int {
12031 let r = sys_fdatasync(fd);
12032 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12033 0
12034}
12035
12036#[no_mangle]
12037pub unsafe extern "C" fn sync() {
12038 sys_sync();
12039}
12040
12041#[no_mangle]
12042pub unsafe extern "C" fn symlink(target: *const c_char, linkpath: *const c_char) -> c_int {
12043 let r = sys_symlinkat(target as *const u8, AT_FDCWD, linkpath as *const u8);
12044 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12045 0
12046}
12047
12048#[no_mangle]
12049pub unsafe extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsiz: usize) -> isize {
12050 let r = sys_readlinkat(AT_FDCWD, path as *const u8, buf as *mut u8, bufsiz);
12051 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12052 r as isize
12053}
12054
12055#[no_mangle]
12056pub unsafe extern "C" fn link(oldpath: *const c_char, newpath: *const c_char) -> c_int {
12057 let r = sys_linkat(AT_FDCWD, oldpath as *const u8, AT_FDCWD, newpath as *const u8, 0);
12058 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12059 0
12060}
12061
12062#[no_mangle]
12063pub unsafe extern "C" fn chmod(path: *const c_char, mode: c_uint) -> c_int {
12064 let r = sys_fchmodat(AT_FDCWD, path as *const u8, mode, 0);
12065 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12066 0
12067}
12068
12069#[no_mangle]
12070pub unsafe extern "C" fn fchmod(fd: c_int, mode: c_uint) -> c_int {
12071 let r = sys_fchmod(fd, mode);
12072 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12073 0
12074}
12075
12076#[no_mangle]
12077pub unsafe extern "C" fn umask(mask: c_uint) -> c_uint {
12078 sys_umask(mask) as c_uint
12079}
12080
12081#[no_mangle]
12082pub unsafe extern "C" fn isatty(fd: c_int) -> c_int {
12083 let mut ws: winsize = core::mem::zeroed();
12084 if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 { 1 } else { 0 }
12085}
12086
12087#[no_mangle]
12089pub unsafe extern "C" fn ttyname(_fd: c_int) -> *mut c_char {
12090 core::ptr::null_mut()
12091}
12092
12093#[no_mangle]
12095pub unsafe extern "C" fn getlogin() -> *mut c_char {
12096 b"root\0".as_ptr() as *mut c_char
12097}
12098
12099#[no_mangle]
12100pub unsafe extern "C" fn getgroups(size: c_int, list: *mut c_uint) -> c_int {
12101 let r = sys_getgroups(size, list);
12102 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12103 r as c_int
12104}
12105
12106#[no_mangle]
12107pub unsafe extern "C" fn setuid(uid: c_uint) -> c_int {
12108 let r = sys_setuid(uid);
12109 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12110 0
12111}
12112
12113#[no_mangle]
12114pub unsafe extern "C" fn setgid(gid: c_uint) -> c_int {
12115 let r = sys_setgid(gid);
12116 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12117 0
12118}
12119
12120#[no_mangle]
12121pub unsafe extern "C" fn seteuid(euid: c_uint) -> c_int {
12122 let r = sys_setuid(euid);
12124 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12125 0
12126}
12127
12128#[no_mangle]
12129pub unsafe extern "C" fn setegid(egid: c_uint) -> c_int {
12130 let r = sys_setgid(egid);
12131 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12132 0
12133}
12134
12135#[no_mangle]
12136pub unsafe extern "C" fn setreuid(_ruid: c_uint, _euid: c_uint) -> c_int {
12137 0
12139}
12140
12141#[no_mangle]
12142pub unsafe extern "C" fn setregid(_rgid: c_uint, _egid: c_uint) -> c_int {
12143 0
12144}
12145
12146#[no_mangle]
12147pub unsafe extern "C" fn setsid() -> c_int {
12148 let r = sys_setsid();
12149 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12150 r as c_int
12151}
12152
12153#[no_mangle]
12154pub unsafe extern "C" fn setpgid(pid: c_int, pgid: c_int) -> c_int {
12155 let r = sys_setpgid(pid, pgid);
12156 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12157 0
12158}
12159
12160#[no_mangle]
12161pub unsafe extern "C" fn getpgid(pid: c_int) -> c_int {
12162 let r = sys_getpgid(pid);
12163 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12164 r as c_int
12165}
12166
12167#[no_mangle]
12168pub unsafe extern "C" fn getsid(pid: c_int) -> c_int {
12169 let r = sys_getsid(pid);
12170 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12171 r as c_int
12172}
12173
12174#[no_mangle]
12175pub unsafe extern "C" fn getpgrp() -> c_int {
12176 sys_getpgid(0) as c_int
12177}
12178
12179#[no_mangle]
12180pub unsafe extern "C" fn setpgrp() -> c_int {
12181 setpgid(0, 0)
12182}
12183
12184#[no_mangle]
12185pub unsafe extern "C" fn mkstemp(template: *mut c_char) -> c_int {
12186 if template.is_null() { ERRNO = EINVAL; return -1; }
12187 let len = strlen(template as *const c_char);
12188 if len < 6 { ERRNO = EINVAL; return -1; }
12189 let x_start = len - 6;
12190 for i in x_start..len {
12192 if *template.add(i) != b'X' as c_char { ERRNO = EINVAL; return -1; }
12193 }
12194 let mut ts: timespec = core::mem::zeroed();
12195 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
12196 let mut ctr: u32 = ts.tv_nsec as u32;
12197 for _ in 0..100 {
12198 ctr = ctr.wrapping_mul(1103515245).wrapping_add(12345);
12199 let seed = ctr;
12200 let hex = b"0123456789abcdef";
12202 let mut s = seed;
12203 for i in x_start..len {
12204 *template.add(i) = hex[(s & 0xf) as usize] as c_char;
12205 s >>= 4;
12206 }
12207 let fd = sys_open(template as *const u8, (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
12208 if fd >= 0 { return fd as c_int; }
12209 let e = (-fd) as c_int;
12210 if e != EEXIST_VAL { ERRNO = e; return -1; }
12211 }
12212 ERRNO = EEXIST_VAL;
12213 -1
12214}
12215
12216#[no_mangle]
12217pub unsafe extern "C" fn mkdir(path: *const c_char, mode: c_uint) -> c_int {
12218 let r = sys_mkdirat(AT_FDCWD, path as *const u8, mode);
12219 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12220 0
12221}
12222
12223#[no_mangle]
12228pub unsafe extern "C" fn dirname(s: *mut c_char) -> *mut c_char {
12229 if s.is_null() || *s == 0 {
12230 return b".\0".as_ptr() as *mut c_char;
12231 }
12232 let mut i = strlen(s as *const c_char);
12233 i = i.wrapping_sub(1);
12234 while i > 0 && *s.add(i) == b'/' as c_char {
12236 i = i.wrapping_sub(1);
12237 }
12238 if i == 0 && *s.add(0) == b'/' as c_char {
12239 return b"/\0".as_ptr() as *mut c_char;
12240 }
12241 while i > 0 && *s.add(i) != b'/' as c_char {
12243 i = i.wrapping_sub(1);
12244 }
12245 if i == 0 {
12246 if *s.add(0) == b'/' as c_char {
12247 return b"/\0".as_ptr() as *mut c_char;
12248 }
12249 return b".\0".as_ptr() as *mut c_char;
12250 }
12251 while i > 0 && *s.add(i - 1) == b'/' as c_char {
12253 i = i.wrapping_sub(1);
12254 }
12255 if i == 0 {
12256 return b"/\0".as_ptr() as *mut c_char;
12257 }
12258 *s.add(i) = 0;
12259 s
12260}
12261
12262#[no_mangle]
12263pub unsafe extern "C" fn basename(s: *mut c_char) -> *mut c_char {
12264 if s.is_null() || *s == 0 {
12265 return b".\0".as_ptr() as *mut c_char;
12266 }
12267 let mut i = strlen(s as *const c_char);
12268 i = i.wrapping_sub(1);
12269 while i > 0 && *s.add(i) == b'/' as c_char {
12271 *s.add(i) = 0;
12272 i = i.wrapping_sub(1);
12273 }
12274 while i > 0 && *s.add(i - 1) != b'/' as c_char {
12276 i = i.wrapping_sub(1);
12277 }
12278 s.add(i)
12279}
12280
12281const AF_INET_VAL: c_int = 2;
12286const AF_INET6_VAL: c_int = 10;
12287const EAFNOSUPPORT: c_int = 97;
12288const ENOSPC_VAL2: c_int = 28;
12289
12290unsafe fn inet_pton_v4(s: *const u8, a: *mut u8) -> c_int {
12291 let mut p = s;
12292 let mut i = 0;
12293 while i < 4 {
12294 let oct_start = p;
12295 let mut v: u32 = 0;
12296 let mut j: u32 = 0;
12297 while j < 3 && *p >= b'0' && *p <= b'9' {
12298 v = v * 10 + (*p - b'0') as u32;
12299 p = p.add(1);
12300 j += 1;
12301 }
12302 if j == 0 || (j > 1 && *oct_start == b'0') || v > 255 { return 0; }
12303 *a.add(i) = v as u8;
12304 if *p == 0 && i == 3 { return 1; }
12305 if *p != b'.' { return 0; }
12306 p = p.add(1);
12307 i += 1;
12308 }
12309 0
12310}
12311
12312unsafe fn inet_pton_v6(s: *const u8, a: *mut u8) -> c_int {
12313 let mut ip = [0u16; 8];
12314 let mut p = s;
12315 let mut i: usize = 0;
12316 let mut brk: isize = -1;
12317 let mut need_v4 = false;
12318 let mut v4_start: *const u8 = core::ptr::null();
12319
12320 if *p == b':' {
12321 p = p.add(1);
12322 if *p != b':' { return 0; }
12323 }
12324
12325 loop {
12326 if *p == b':' && brk < 0 {
12327 brk = i as isize;
12328 ip[i & 7] = 0;
12329 p = p.add(1);
12330 if *p == 0 { break; }
12331 if i == 7 { return 0; }
12332 i += 1;
12333 continue;
12334 }
12335 v4_start = p;
12336 let mut v: u16 = 0;
12337 let mut j = 0;
12338 while j < 4 {
12339 let d = hex_digit(*p);
12340 if d < 0 { break; }
12341 v = v * 16 + d as u16;
12342 p = p.add(1);
12343 j += 1;
12344 }
12345 if j == 0 { return 0; }
12346 ip[i & 7] = v;
12347 if *p == 0 && (brk >= 0 || i == 7) { break; }
12348 if i == 7 { return 0; }
12349 if *p != b':' {
12350 if *p != b'.' || (i < 6 && brk < 0) { return 0; }
12351 need_v4 = true;
12352 i += 1;
12353 ip[i & 7] = 0;
12354 break;
12355 }
12356 p = p.add(1);
12357 i += 1;
12358 }
12359
12360 if brk >= 0 {
12361 let trail_count = i + 1 - brk as usize;
12363 let dest_start = brk as usize + 7 - i;
12364 for j in (0..trail_count).rev() {
12366 ip[dest_start + j] = ip[brk as usize + j];
12367 }
12368 for j in 0..(7 - i) {
12369 ip[brk as usize + j] = 0;
12370 }
12371 }
12372
12373 for k in 0..8 {
12374 *a.add(k * 2) = (ip[k] >> 8) as u8;
12375 *a.add(k * 2 + 1) = (ip[k] & 0xff) as u8;
12376 }
12377
12378 if need_v4 {
12379 if inet_pton_v4(v4_start, a.add(12)) <= 0 { return 0; }
12380 }
12381 1
12382}
12383
12384unsafe fn hex_digit(c: u8) -> i32 {
12385 if c >= b'0' && c <= b'9' { (c - b'0') as i32 }
12386 else if c >= b'a' && c <= b'f' { (c - b'a' + 10) as i32 }
12387 else if c >= b'A' && c <= b'F' { (c - b'A' + 10) as i32 }
12388 else { -1 }
12389}
12390
12391#[no_mangle]
12392pub unsafe extern "C" fn inet_pton(af: c_int, s: *const c_char, a: *mut c_void) -> c_int {
12393 if af == AF_INET_VAL {
12394 inet_pton_v4(s as *const u8, a as *mut u8)
12395 } else if af == AF_INET6_VAL {
12396 inet_pton_v6(s as *const u8, a as *mut u8)
12397 } else {
12398 ERRNO = EAFNOSUPPORT;
12399 -1
12400 }
12401}
12402
12403#[no_mangle]
12404pub unsafe extern "C" fn inet_ntop(af: c_int, a: *const c_void, s: *mut c_char, size: u32) -> *mut c_char {
12405 if af == AF_INET_VAL {
12406 let b = a as *const u8;
12407 let needed = 16; if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
12409 let mut pos = 0;
12410 for i in 0..4 {
12411 if i > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
12412 let (buf, len) = format_u64(*b.add(i) as u64);
12413 for j in 0..len { *s.add(pos) = buf[j] as c_char; pos += 1; }
12414 }
12415 *s.add(pos) = 0;
12416 s
12417 } else if af == AF_INET6_VAL {
12418 let b = a as *const u8;
12419 let needed = 46; if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
12421 let mut words = [0u16; 8];
12422 for i in 0..8 {
12423 words[i] = ((*b.add(i * 2) as u16) << 8) | (*b.add(i * 2 + 1) as u16);
12424 }
12425 let mut pos = 0usize;
12427 if words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0
12428 && words[4] == 0 && words[5] == 0xffff
12429 {
12430 let prefix = b"::ffff:";
12431 for k in 0..prefix.len() { *s.add(pos) = prefix[k] as c_char; pos += 1; }
12432 for idx in 0..4 {
12433 if idx > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
12434 let octet = *b.add(12 + idx);
12435 if octet >= 100 {
12436 *s.add(pos) = (b'0' + octet / 100) as c_char; pos += 1;
12437 *s.add(pos) = (b'0' + (octet / 10) % 10) as c_char; pos += 1;
12438 } else if octet >= 10 {
12439 *s.add(pos) = (b'0' + octet / 10) as c_char; pos += 1;
12440 }
12441 *s.add(pos) = (b'0' + octet % 10) as c_char; pos += 1;
12442 }
12443 *s.add(pos) = 0;
12444 return s;
12445 }
12446 let mut best_start: isize = -1;
12448 let mut best_len: usize = 0;
12449 let mut j: usize = 0;
12450 while j < 8 {
12451 if words[j] == 0 {
12452 let mut k = j;
12453 while k < 8 && words[k] == 0 { k += 1; }
12454 let run = k - j;
12455 if run > best_len { best_start = j as isize; best_len = run; }
12456 j = k;
12457 } else {
12458 j += 1;
12459 }
12460 }
12461 let mut i: usize = 0;
12462 let mut prev_in_run = false;
12463 while i < 8 {
12464 let in_run = best_len >= 2 && i >= best_start as usize && i < best_start as usize + best_len;
12465 if in_run {
12466 if i == best_start as usize {
12467 *s.add(pos) = b':' as c_char; pos += 1;
12468 *s.add(pos) = b':' as c_char; pos += 1;
12469 }
12470 i += 1;
12471 prev_in_run = true;
12472 continue;
12473 }
12474 if i > 0 && !prev_in_run {
12475 *s.add(pos) = b':' as c_char; pos += 1;
12476 }
12477 let (buf, len) = format_hex(words[i] as u64, false);
12478 for k in 0..len { *s.add(pos) = buf[k] as c_char; pos += 1; }
12479 i += 1;
12480 prev_in_run = false;
12481 }
12482 *s.add(pos) = 0;
12483 s
12484 } else {
12485 ERRNO = EAFNOSUPPORT;
12486 core::ptr::null_mut()
12487 }
12488}
12489
12490#[no_mangle]
12491pub unsafe extern "C" fn inet_aton(s: *const c_char, dest: *mut c_void) -> c_int {
12492 let a = dest as *mut u8;
12493 let mut p = s as *const u8;
12494 let mut vals = [0u64; 4];
12495 let mut i = 0usize;
12496 while i < 4 {
12497 if *p < b'0' || *p > b'9' { return 0; }
12498 let mut base = 10u32;
12499 if *p == b'0' {
12500 let c = *p.add(1);
12501 if c == b'x' || c == b'X' {
12502 base = 16;
12503 p = p.add(2);
12504 if !((*p >= b'0' && *p <= b'9')
12505 || (*p >= b'a' && *p <= b'f')
12506 || (*p >= b'A' && *p <= b'F')) {
12507 return 0;
12508 }
12509 } else {
12510 base = 8;
12511 }
12512 }
12513 let mut v: u64 = 0;
12514 let start = p;
12515 loop {
12516 let c = *p;
12517 let d = if c >= b'0' && c <= b'9' {
12518 (c - b'0') as u64
12519 } else if base == 16 && c >= b'a' && c <= b'f' {
12520 (c - b'a' + 10) as u64
12521 } else if base == 16 && c >= b'A' && c <= b'F' {
12522 (c - b'A' + 10) as u64
12523 } else {
12524 break;
12525 };
12526 v = v * (base as u64) + d;
12527 p = p.add(1);
12528 }
12529 if p == start { return 0; }
12530 vals[i] = v;
12531 if *p == 0 {
12532 break;
12533 }
12534 if *p != b'.' || i == 3 { return 0; }
12535 p = p.add(1);
12536 i += 1;
12537 }
12538 if i == 4 { return 0; }
12539 if i < 1 { vals[1] = vals[0] & 0xffffff; vals[0] >>= 24; }
12540 if i < 2 { vals[2] = vals[1] & 0xffff; vals[1] >>= 16; }
12541 if i < 3 { vals[3] = vals[2] & 0xff; vals[2] >>= 8; }
12542 for j in 0..4 {
12543 if vals[j] > 255 { return 0; }
12544 *a.add(j) = vals[j] as u8;
12545 }
12546 1
12547}
12548
12549#[no_mangle]
12550pub unsafe extern "C" fn inet_addr(s: *const c_char) -> u32 {
12551 let mut a = [0u8; 4];
12552 if inet_aton(s, a.as_mut_ptr() as *mut c_void) == 1 {
12553 u32::from_ne_bytes(a)
12554 } else {
12555 !0u32 }
12557}
12558
12559#[no_mangle]
12560pub unsafe extern "C" fn inet_ntoa(addr: u32) -> *mut c_char {
12561 static mut NTOA_BUF: [c_char; 16] = [0; 16];
12562 let b = addr.to_ne_bytes();
12563 let mut pos = 0;
12564 for i in 0..4 {
12565 if i > 0 { NTOA_BUF[pos] = b'.' as c_char; pos += 1; }
12566 let (buf, len) = format_u64(b[i] as u64);
12567 for j in 0..len { NTOA_BUF[pos] = buf[j] as c_char; pos += 1; }
12568 }
12569 NTOA_BUF[pos] = 0;
12570 core::ptr::addr_of_mut!(NTOA_BUF).cast::<c_char>()
12571}
12572
12573#[no_mangle]
12575pub unsafe extern "C" fn inet_network(s: *const c_char) -> u32 {
12576 inet_addr(s).to_be()
12577}
12578
12579#[no_mangle]
12580pub extern "C" fn inet_makeaddr(net: c_int, host: c_int) -> u32 {
12581 let addr: u32;
12582 if (net as u32) < 128 {
12583 addr = (net as u32) << 24;
12584 } else if (net as u32) < 0x10000 {
12585 addr = (net as u32) << 16;
12586 } else if (net as u32) < 0x1000000 {
12587 addr = (net as u32) << 8;
12588 } else {
12589 addr = net as u32;
12590 }
12591 addr | (host as u32 & 0xffffffff)
12592}
12593
12594#[no_mangle]
12595pub extern "C" fn inet_lnaof(addr: u32) -> c_int {
12596 let h = u32::from_be(addr);
12597 if h < 0x80000000 { (h & 0x00ffffff) as c_int }
12598 else if h < 0xc0000000 { (h & 0x0000ffff) as c_int }
12599 else { (h & 0x000000ff) as c_int }
12600}
12601
12602#[no_mangle]
12603pub extern "C" fn inet_netof(addr: u32) -> c_int {
12604 let h = u32::from_be(addr);
12605 if h < 0x80000000 { (h >> 24) as c_int }
12606 else if h < 0xc0000000 { (h >> 16) as c_int }
12607 else { (h >> 8) as c_int }
12608}
12609
12610unsafe fn parse_float(s: *const u8, endptr: *mut *mut u8, is_f32: bool) -> f64 {
12619 let mut p = s;
12620 while *p == b' ' || *p == b'\t' || *p == b'\n' || *p == b'\r' { p = p.add(1); }
12622 let mut neg = false;
12623 if *p == b'-' { neg = true; p = p.add(1); }
12624 else if *p == b'+' { p = p.add(1); }
12625
12626 if (*p | 0x20) == b'i'
12628 && (*p.add(1) | 0x20) == b'n'
12629 && (*p.add(2) | 0x20) == b'f'
12630 {
12631 p = p.add(3);
12632 if (*p | 0x20) == b'i'
12634 && (*p.add(1) | 0x20) == b't'
12635 && (*p.add(2) | 0x20) == b'y'
12636 {
12637 p = p.add(3);
12638 }
12639 if !endptr.is_null() { *endptr = p as *mut u8; }
12640 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12641 }
12642 if (*p | 0x20) == b'n'
12644 && (*p.add(1) | 0x20) == b'a'
12645 && (*p.add(2) | 0x20) == b'n'
12646 {
12647 p = p.add(3);
12648 if *p == b'(' {
12650 p = p.add(1);
12651 while *p != 0 && *p != b')' { p = p.add(1); }
12652 if *p == b')' { p = p.add(1); }
12653 }
12654 if !endptr.is_null() { *endptr = p as *mut u8; }
12655 return if neg { -f64::NAN } else { f64::NAN };
12656 }
12657
12658 if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') {
12660 p = p.add(2);
12661 let mut mant: u128 = 0;
12662 let mut frac_hex: u32 = 0;
12663 let mut found = false;
12664 let mut in_frac = false;
12665
12666 loop {
12667 if let Some(d) = hex_val(*p) {
12668 if mant <= u128::MAX / 16 {
12669 mant = mant * 16 + d as u128;
12670 }
12671 if in_frac { frac_hex += 1; }
12672 p = p.add(1);
12673 found = true;
12674 } else if *p == b'.' && !in_frac {
12675 in_frac = true;
12676 p = p.add(1);
12677 } else {
12678 break;
12679 }
12680 }
12681
12682 if !found {
12683 if !endptr.is_null() { *endptr = s as *mut u8; }
12684 return 0.0;
12685 }
12686
12687 let mut bin_exp: i32 = 0;
12689 if *p == b'p' || *p == b'P' {
12690 p = p.add(1);
12691 let mut exp_neg = false;
12692 if *p == b'-' { exp_neg = true; p = p.add(1); }
12693 else if *p == b'+' { p = p.add(1); }
12694 while *p >= b'0' && *p <= b'9' {
12695 if bin_exp < 100000 {
12696 bin_exp = bin_exp * 10 + (*p - b'0') as i32;
12697 }
12698 p = p.add(1);
12699 }
12700 if exp_neg { bin_exp = -bin_exp; }
12701 }
12702
12703 if !endptr.is_null() { *endptr = p as *mut u8; }
12704 if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
12705
12706 let total_exp = bin_exp as i64 - 4 * frac_hex as i64;
12707 return hex_mant_to_f64(mant, total_exp, neg);
12708 }
12709
12710 let mut buf = [0u8; 65536];
12712 let mut n = 0usize;
12713 let mut found_digit = false;
12714
12715 while *p >= b'0' && *p <= b'9' {
12716 if n < 65535 { buf[n] = *p; n += 1; }
12717 p = p.add(1);
12718 found_digit = true;
12719 }
12720 if *p == b'.' {
12721 if n < 65535 { buf[n] = b'.'; n += 1; }
12722 p = p.add(1);
12723 while *p >= b'0' && *p <= b'9' {
12724 if n < 65535 { buf[n] = *p; n += 1; }
12725 p = p.add(1);
12726 found_digit = true;
12727 }
12728 }
12729 if !found_digit {
12730 if !endptr.is_null() { *endptr = s as *mut u8; }
12731 return 0.0;
12732 }
12733 if *p == b'e' || *p == b'E' {
12734 if n < 65535 { buf[n] = b'e'; n += 1; }
12735 p = p.add(1);
12736 if *p == b'-' || *p == b'+' {
12737 if n < 65535 { buf[n] = *p; n += 1; }
12738 p = p.add(1);
12739 }
12740 while *p >= b'0' && *p <= b'9' {
12741 if n < 65535 { buf[n] = *p; n += 1; }
12742 p = p.add(1);
12743 }
12744 }
12745
12746 if !endptr.is_null() { *endptr = p as *mut u8; }
12747 let s_str = core::str::from_utf8_unchecked(
12748 core::slice::from_raw_parts(buf.as_ptr(), n),
12749 );
12750 if is_f32 {
12751 match <f32 as core::str::FromStr>::from_str(s_str) {
12752 Ok(v) => { let r = v as f64; if neg { -r } else { r } }
12753 Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
12754 }
12755 } else {
12756 match <f64 as core::str::FromStr>::from_str(s_str) {
12757 Ok(v) => if neg { -v } else { v },
12758 Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
12759 }
12760 }
12761}
12762
12763fn hex_mant_to_f64(mant: u128, total_exp: i64, neg: bool) -> f64 {
12767 if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
12768
12769 let msb = (127 - mant.leading_zeros()) as i64;
12770 let unbiased_exp = msb + total_exp;
12771 let biased_exp = unbiased_exp + 1023;
12772
12773 if biased_exp >= 2047 {
12775 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12776 }
12777
12778 if biased_exp <= 0 {
12780 let shift = total_exp + 1074;
12783 if shift < 0 {
12784 return if neg { -0.0 } else { 0.0 };
12785 }
12786 if shift > 128 {
12787 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12788 }
12789 let shifted = mant << (shift as u32);
12790 let mantissa52 = (shifted as u64) & 0x000FFFFFFFFFFFFF;
12791 let guard = ((shifted >> 52) & 1) != 0;
12792 let sticky = (shifted >> 53) != 0;
12793 let mut result = mantissa52;
12794 if guard && (sticky || (result & 1) != 0) {
12795 result += 1;
12796 if result > 0x000FFFFFFFFFFFFF {
12797 return if neg { -f64::from_bits(1u64 << 52) } else { f64::from_bits(1u64 << 52) };
12799 }
12800 }
12801 return if neg { -f64::from_bits(result) } else { f64::from_bits(result) };
12802 }
12803
12804 let shift = msb - 52;
12806
12807 if shift <= 0 {
12808 let mantissa = ((mant as u64) & ((1u64 << msb as u32) - 1)) << ((-shift) as u32);
12810 let bits = ((biased_exp as u64) << 52) | mantissa;
12811 return if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) };
12812 }
12813
12814 let mantissa = ((mant >> shift as u32) as u64) & 0x000FFFFFFFFFFFFF;
12816 let guard = ((mant >> (shift as u32 - 1)) & 1) != 0;
12817 let sticky = if shift > 1 {
12818 (mant & ((1u128 << (shift as u32 - 1)) - 1)) != 0
12819 } else { false };
12820
12821 let mut result_mant = mantissa;
12822 let mut result_exp = biased_exp;
12823 if guard && (sticky || (result_mant & 1) != 0) {
12824 result_mant += 1;
12825 if result_mant > 0x000FFFFFFFFFFFFF {
12826 result_mant = 0;
12827 result_exp += 1;
12828 if result_exp >= 2047 {
12829 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12830 }
12831 }
12832 }
12833
12834 let bits = ((result_exp as u64) << 52) | result_mant;
12835 if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) }
12836}
12837
12838unsafe fn hex_val(c: u8) -> Option<u8> {
12839 if c >= b'0' && c <= b'9' { Some(c - b'0') }
12840 else if c >= b'a' && c <= b'f' { Some(c - b'a' + 10) }
12841 else if c >= b'A' && c <= b'F' { Some(c - b'A' + 10) }
12842 else { None }
12843}
12844
12845#[no_mangle]
12846pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
12847 let mut end: *mut u8 = s as *mut u8;
12848 let r = parse_float(s as *const u8, &mut end, false);
12849 if !endptr.is_null() { *endptr = end as *mut c_char; }
12850 r
12851}
12852
12853#[no_mangle]
12854pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> f32 {
12855 let mut end: *mut u8 = s as *mut u8;
12856 let r = parse_float(s as *const u8, &mut end, true);
12857 if !endptr.is_null() { *endptr = end as *mut c_char; }
12858 r as f32
12859}
12860
12861#[no_mangle]
12862#[cfg(target_arch = "x86_64")]
12863pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
12864 strtod(s, endptr)
12865}
12866
12867#[no_mangle]
12868#[cfg(target_arch = "aarch64")]
12869pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f128 {
12870 strtod(s, endptr) as f128
12871}
12872
12873#[no_mangle]
12874pub unsafe extern "C" fn atof(s: *const c_char) -> f64 {
12875 strtod(s, core::ptr::null_mut())
12876}
12877
12878#[repr(C)]
12883struct MsCookie {
12884 bufp: *mut *mut c_char,
12885 sizep: *mut usize,
12886 pos: usize,
12887 len: usize,
12888 buf: *mut u8,
12889 space: usize,
12890}
12891
12892#[repr(C)]
12893struct MfCookie {
12894 pos: usize,
12895 len: usize,
12896 size: usize,
12897 buf: *mut u8,
12898 mode: c_char,
12899}
12900
12901unsafe extern "C" fn ms_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
12902 let c = (*f).cookie as *mut MsCookie;
12903 if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
12904 let base: i64 = match whence {
12905 0 => 0,
12906 1 => (*c).pos as i64,
12907 2 => (*c).len as i64,
12908 _ => { ERRNO = EINVAL; return -1; }
12909 };
12910 if off < -base || off > isize::MAX as i64 - base { ERRNO = EINVAL; return -1; }
12911 (*c).pos = (base + off) as usize;
12912 (*c).pos as i64
12913}
12914
12915unsafe extern "C" fn ms_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
12916 let c = (*f).cookie as *mut MsCookie;
12917 let buffered = (*f).wpos as usize - (*f).wbase as usize;
12918 if buffered > 0 {
12919 (*f).wpos = (*f).wbase;
12920 if ms_write(f, (*f).wbase, buffered) < buffered { return 0; }
12921 }
12922 if len == 0 { return 0; }
12923 if (*c).pos + len >= (*c).space {
12924 let new_space = 2 * (*c).space + 1 | (*c).pos + len + 1;
12925 let newbuf = realloc((*c).buf as *mut c_void, new_space) as *mut u8;
12926 if newbuf.is_null() { return 0; }
12927 *(*c).bufp = newbuf as *mut c_char;
12928 core::ptr::write_bytes(newbuf.add((*c).space), 0, new_space - (*c).space);
12929 (*c).buf = newbuf;
12930 (*c).space = new_space;
12931 }
12932 core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), len);
12933 (*c).pos += len;
12934 if (*c).pos >= (*c).len { (*c).len = (*c).pos; }
12935 *(*c).sizep = (*c).pos;
12936 len
12937}
12938
12939unsafe extern "C" fn ms_close(_f: *mut FILE) -> c_int {
12940 0
12941}
12942
12943#[no_mangle]
12944pub unsafe extern "C" fn open_memstream(bufp: *mut *mut c_char, sizep: *mut usize) -> *mut FILE {
12945 if bufp.is_null() || sizep.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
12946 let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
12947 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
12948 let buf_area = buf_ptr(f);
12949 init_file(f, -1, b"w\0".as_ptr() as *const c_char, Some(ms_close), buf_area, BUFSIZ);
12950 (*f).flags = F_NORD | F_SVB;
12951 (*f).lbf = -1;
12952 let c = calloc(1, core::mem::size_of::<MsCookie>()) as *mut MsCookie;
12953 if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
12954 (*c).bufp = bufp;
12955 (*c).sizep = sizep;
12956 (*c).pos = 0;
12957 (*c).len = 0;
12958 (*c).buf = core::ptr::null_mut();
12959 (*c).space = 0;
12960 (*f).cookie = c as *mut c_void;
12961 (*f).write_fn = Some(ms_write);
12962 (*f).seek_fn = Some(ms_seek);
12963 *bufp = core::ptr::null_mut();
12964 *sizep = 0;
12965 f
12966}
12967
12968unsafe extern "C" fn mseek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
12969 let c = (*f).cookie as *mut MfCookie;
12970 if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
12971 let base: i64 = match whence {
12972 0 => 0,
12973 1 => (*c).pos as i64,
12974 2 => (*c).len as i64,
12975 _ => { ERRNO = EINVAL; return -1; }
12976 };
12977 if off < -base || off > (*c).size as i64 - base { ERRNO = EINVAL; return -1; }
12978 (*c).pos = (base + off) as usize;
12979 (*c).pos as i64
12980}
12981
12982unsafe extern "C" fn mread(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
12983 let c = (*f).cookie as *mut MfCookie;
12984 let mut rem = if (*c).pos <= (*c).len { (*c).len - (*c).pos } else { 0 };
12985 let mut l = len;
12986 if l > rem {
12987 l = rem;
12988 (*f).flags |= F_EOF;
12989 }
12990 core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), buf, l);
12991 (*c).pos += l;
12992 rem -= l;
12993 if rem > (*f).buf_size { rem = (*f).buf_size; }
12994 (*f).rpos = (*f).buf;
12995 (*f).rend = (*f).buf.add(rem);
12996 core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), (*f).rpos, rem);
12997 (*c).pos += rem;
12998 l
12999}
13000
13001unsafe extern "C" fn mwrite(f: *mut FILE, buf: *const u8, len: usize) -> usize {
13002 let c = (*f).cookie as *mut MfCookie;
13003 let buffered = (*f).wpos as usize - (*f).wbase as usize;
13004 if buffered > 0 {
13005 (*f).wpos = (*f).wbase;
13006 if mwrite(f, (*f).wbase, buffered) < buffered { return 0; }
13007 }
13008 if len == 0 { return 0; }
13009 if (*c).mode == b'a' as c_char { (*c).pos = (*c).len; }
13010 let rem = (*c).size - (*c).pos;
13011 let mut l = len;
13012 if l > rem { l = rem; }
13013 core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), l);
13014 (*c).pos += l;
13015 if (*c).pos > (*c).len {
13016 (*c).len = (*c).pos;
13017 if (*c).len < (*c).size {
13018 *(*c).buf.add((*c).len) = 0;
13019 } else if ((*f).flags & F_NORD) != 0 && (*c).size > 0 {
13020 *(*c).buf.add((*c).size - 1) = 0;
13021 }
13022 }
13023 l
13024}
13025
13026unsafe extern "C" fn mclose(_f: *mut FILE) -> c_int {
13027 0
13028}
13029
13030#[no_mangle]
13031pub unsafe extern "C" fn fmemopen(buf: *mut c_void, size: usize, mode: *const c_char) -> *mut FILE {
13032 if mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
13033 let m = *mode;
13034 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
13035 ERRNO = EINVAL; return core::ptr::null_mut();
13036 }
13037 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
13038 let need_alloc = buf.is_null();
13039 let alloc_size = core::mem::size_of::<FILE>() + UNGET + BUFSIZ + if need_alloc { size } else { 0 };
13040 let f = calloc(1, alloc_size) as *mut FILE;
13041 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
13042 let buf_area = buf_ptr(f);
13043 init_file(f, -1, mode, Some(mclose), buf_area, BUFSIZ);
13044 (*f).flags |= F_SVB;
13045 let actual_buf: *mut u8 = if need_alloc {
13046 (f as *mut u8).add(alloc_size - size)
13047 } else {
13048 buf as *mut u8
13049 };
13050 if need_alloc { core::ptr::write_bytes(actual_buf, 0, size); }
13051 let c = calloc(1, core::mem::size_of::<MfCookie>()) as *mut MfCookie;
13052 if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
13053 (*c).buf = actual_buf;
13054 (*c).size = size;
13055 (*c).mode = m;
13056 (*f).cookie = c as *mut c_void;
13057 (*f).read_fn = Some(mread);
13058 (*f).write_fn = Some(mwrite);
13059 (*f).seek_fn = Some(mseek);
13060 if !has_plus { (*f).flags = if m == b'r' as c_char { F_NOWR } else { F_NORD }; }
13061 if m == b'r' as c_char {
13062 (*c).len = size;
13063 } else if m == b'a' as c_char {
13064 (*c).len = strnlen(actual_buf, size);
13065 (*c).pos = (*c).len;
13066 } else if has_plus {
13067 *actual_buf = 0;
13068 }
13069 f
13070}
13071
13072#[repr(C)]
13077struct kernel_stat64 {
13078 st_dev: u64,
13079 st_ino: u64,
13080 st_nlink: u64,
13081 st_mode: u32,
13082 st_uid: u32,
13083 st_gid: u32,
13084 __pad0: c_int,
13085 st_rdev: u64,
13086 st_size: i64,
13087 st_blksize: i64,
13088 st_blocks: i64,
13089 st_atime: i64,
13090 st_atime_nsec: i64,
13091 st_mtime: i64,
13092 st_mtime_nsec: i64,
13093 st_ctime: i64,
13094 st_ctime_nsec: i64,
13095 __unused: [i64; 3],
13096}
13097
13098#[inline]
13100unsafe fn sys_stat(path: *const u8, statbuf: *mut kernel_stat64) -> i64 {
13101 <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, AT_FDCWD as i64, path as i64, statbuf as i64, 0)
13102}
13103
13104const HSEARCH_MINSIZE: usize = 8;
13109
13110#[repr(C)]
13111#[derive(Copy, Clone)]
13112pub struct HSearchEntry {
13113 key: *mut c_char,
13114 data: *mut c_void,
13115}
13116
13117#[repr(C)]
13118struct HTab {
13119 entries: *mut HSearchEntry,
13120 mask: usize,
13121 used: usize,
13122}
13123
13124#[repr(C)]
13125pub struct HSearchData {
13126 tab: *mut HTab,
13127 __unused1: c_uint,
13128 __unused2: c_uint,
13129}
13130
13131static mut HTAB_DATA: HSearchData = HSearchData {
13133 tab: core::ptr::null_mut(),
13134 __unused1: 0,
13135 __unused2: 0,
13136};
13137
13138unsafe fn keyhash(k: *const c_char) -> usize {
13139 let mut h: usize = 0;
13140 let mut p = k;
13141 while *p != 0 {
13142 h = h.wrapping_mul(31).wrapping_add(*p as usize);
13143 p = p.add(1);
13144 }
13145 h
13146}
13147
13148unsafe fn htab_lookup(key: *const c_char, hash: usize, htab: *mut HSearchData) -> *mut HSearchEntry {
13149 let tab = (*htab).tab;
13150 let mask = (*tab).mask;
13151 let entries = (*tab).entries;
13152 let mut i = hash;
13153 let mut j: usize = 1;
13154 loop {
13155 let e = entries.add(i & mask);
13156 if (*e).key.is_null() || strcmp((*e).key as *const u8, key as *const u8) == 0 {
13157 return e;
13158 }
13159 i = i.wrapping_add(j);
13160 j += 1;
13161 }
13162}
13163
13164unsafe fn htab_resize(nel: usize, htab: *mut HSearchData) -> c_int {
13165 let tab = (*htab).tab;
13166 let old_entries = (*tab).entries;
13167 let old_size = (*tab).mask + 1;
13168
13169 let mut newsize: usize = HSEARCH_MINSIZE;
13170 while newsize < nel {
13171 let Some(next) = newsize.checked_mul(2) else {
13172 ERRNO = ENOMEM;
13173 return 0;
13174 };
13175 newsize = next;
13176 }
13177
13178 let new_entries = calloc(newsize, core::mem::size_of::<HSearchEntry>()) as *mut HSearchEntry;
13179 if new_entries.is_null() {
13180 ERRNO = ENOMEM;
13181 return 0;
13182 }
13183 (*tab).entries = new_entries;
13184 (*tab).mask = newsize - 1;
13185
13186 if !old_entries.is_null() {
13187 for idx in 0..old_size {
13188 let old_e = old_entries.add(idx);
13189 if !(*old_e).key.is_null() {
13190 let h = keyhash((*old_e).key);
13191 let mut i = h;
13192 let mut j: usize = 1;
13193 loop {
13194 let e = new_entries.add(i & (*tab).mask);
13195 if (*e).key.is_null() {
13196 *e = *old_e;
13197 break;
13198 }
13199 i = i.wrapping_add(j);
13200 j += 1;
13201 }
13202 }
13203 }
13204 free(old_entries as *mut c_void);
13205 }
13206 1
13207}
13208
13209unsafe fn hcreate_r_impl(nel: usize, htab: *mut HSearchData) -> c_int {
13210 if nel == 0 || nel > (1usize << 30) {
13211 ERRNO = ENOMEM;
13212 return 0;
13213 }
13214 (*htab).tab = calloc(1, core::mem::size_of::<HTab>()) as *mut HTab;
13215 if (*htab).tab.is_null() {
13216 ERRNO = ENOMEM;
13217 return 0;
13218 }
13219 if htab_resize(nel, htab) == 0 {
13220 free((*htab).tab as *mut c_void);
13221 (*htab).tab = core::ptr::null_mut();
13222 return 0;
13223 }
13224 1
13225}
13226
13227unsafe fn hdestroy_r_impl(htab: *mut HSearchData) {
13228 if !(*htab).tab.is_null() {
13229 if !(*(*htab).tab).entries.is_null() {
13230 free((*(*htab).tab).entries as *mut c_void);
13231 }
13232 free((*htab).tab as *mut c_void);
13233 (*htab).tab = core::ptr::null_mut();
13234 }
13235}
13236
13237unsafe fn hsearch_r_impl(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13238 let hash = keyhash(item.key);
13239 let e = htab_lookup(item.key, hash, htab);
13240
13241 if !(*e).key.is_null() {
13242 *retval = e;
13243 return 1;
13244 }
13245 if action == 0 { *retval = core::ptr::null_mut();
13247 return 0;
13248 }
13249 let item_key = item.key;
13251 *e = item;
13252 (*(*htab).tab).used += 1;
13253 if (*(*htab).tab).used > (*(*htab).tab).mask - (*(*htab).tab).mask / 4 {
13254 if htab_resize(2 * (*(*htab).tab).used, htab) == 0 {
13255 (*(*htab).tab).used -= 1;
13256 (*e).key = core::ptr::null_mut();
13257 *retval = core::ptr::null_mut();
13258 return 0;
13259 }
13260 let e2 = htab_lookup(item_key, hash, htab);
13261 *retval = e2;
13262 return 1;
13263 }
13264 *retval = e;
13265 1
13266}
13267
13268#[no_mangle]
13269pub unsafe extern "C" fn hcreate(nel: usize) -> c_int {
13270 hcreate_r_impl(nel, core::ptr::addr_of_mut!(HTAB_DATA))
13271}
13272
13273#[no_mangle]
13274pub unsafe extern "C" fn hdestroy() {
13275 hdestroy_r_impl(core::ptr::addr_of_mut!(HTAB_DATA));
13276}
13277
13278#[no_mangle]
13279pub unsafe extern "C" fn hsearch(item: HSearchEntry, action: c_int) -> *mut HSearchEntry {
13280 let mut e: *mut HSearchEntry = core::ptr::null_mut();
13281 hsearch_r_impl(item, action, &mut e, core::ptr::addr_of_mut!(HTAB_DATA));
13282 e
13283}
13284
13285#[no_mangle]
13286pub unsafe extern "C" fn hcreate_r(nel: usize, htab: *mut HSearchData) -> c_int {
13287 hcreate_r_impl(nel, htab)
13288}
13289
13290#[no_mangle]
13291pub unsafe extern "C" fn hdestroy_r(htab: *mut HSearchData) {
13292 hdestroy_r_impl(htab);
13293}
13294
13295#[no_mangle]
13296pub unsafe extern "C" fn hsearch_r(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13297 hsearch_r_impl(item, action, retval, htab)
13298}
13299
13300#[repr(C)]
13305struct QueNode {
13306 next: *mut QueNode,
13307 prev: *mut QueNode,
13308}
13309
13310#[no_mangle]
13311pub unsafe extern "C" fn insque(element: *mut c_void, pred: *mut c_void) {
13312 let e = element as *mut QueNode;
13313 let p = pred as *mut QueNode;
13314 if p.is_null() {
13315 (*e).next = core::ptr::null_mut();
13316 (*e).prev = core::ptr::null_mut();
13317 return;
13318 }
13319 (*e).next = (*p).next;
13320 (*e).prev = p;
13321 (*p).next = e;
13322 if !(*e).next.is_null() {
13323 (*(*e).next).prev = e;
13324 }
13325}
13326
13327#[no_mangle]
13328pub unsafe extern "C" fn remque(element: *mut c_void) {
13329 let e = element as *mut QueNode;
13330 if !(*e).next.is_null() {
13331 (*(*e).next).prev = (*e).prev;
13332 }
13333 if !(*e).prev.is_null() {
13334 (*(*e).prev).next = (*e).next;
13335 }
13336}
13337
13338#[no_mangle]
13343pub unsafe extern "C" fn lsearch(
13344 key: *const c_void,
13345 base: *mut c_void,
13346 nelp: *mut usize,
13347 width: usize,
13348 compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
13349) -> *mut c_void {
13350 let n = *nelp;
13351 let p = base as *mut u8;
13352 for i in 0..n {
13353 let elem = p.add(i * width);
13354 if compar.unwrap()(key, elem as *const c_void) == 0 {
13355 return elem as *mut c_void;
13356 }
13357 }
13358 let dest = p.add(n * width);
13359 memcpy(dest as *mut c_void, key as *const c_void, width);
13360 *nelp = n + 1;
13361 dest as *mut c_void
13362}
13363
13364#[no_mangle]
13365pub unsafe extern "C" fn lfind(
13366 key: *const c_void,
13367 base: *const c_void,
13368 nelp: *mut usize,
13369 width: usize,
13370 compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
13371) -> *mut c_void {
13372 let n = *nelp;
13373 let p = base as *const u8;
13374 for i in 0..n {
13375 let elem = p.add(i * width);
13376 if compar.unwrap()(key, elem as *const c_void) == 0 {
13377 return elem as *mut c_void;
13378 }
13379 }
13380 core::ptr::null_mut()
13381}
13382
13383#[repr(C)]
13389pub struct TreeNode {
13390 key: *const c_void,
13391 left: *mut TreeNode,
13392 right: *mut TreeNode,
13393}
13394
13395type ComparFn = Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>;
13396
13397unsafe fn bst_new(key: *const c_void) -> *mut TreeNode {
13398 let n = calloc(1, core::mem::size_of::<TreeNode>()) as *mut TreeNode;
13399 if !n.is_null() {
13400 (*n).key = key;
13401 (*n).left = core::ptr::null_mut();
13402 (*n).right = core::ptr::null_mut();
13403 }
13404 n
13405}
13406
13407#[no_mangle]
13408pub unsafe extern "C" fn tsearch(
13409 key: *const c_void,
13410 rootp: *mut *mut TreeNode,
13411 compar: ComparFn,
13412) -> *mut c_void {
13413 if rootp.is_null() {
13414 return core::ptr::null_mut();
13415 }
13416 let mut pp = rootp;
13417 loop {
13418 let n = *pp;
13419 if n.is_null() {
13420 let r = bst_new(key);
13421 if r.is_null() {
13422 return core::ptr::null_mut();
13423 }
13424 *pp = r;
13425 return r as *mut c_void;
13426 }
13427 let c = compar.unwrap()(key, (*n).key);
13428 if c == 0 {
13429 return n as *mut c_void;
13430 }
13431 if c < 0 {
13432 pp = &mut (*n).left;
13433 } else {
13434 pp = &mut (*n).right;
13435 }
13436 }
13437}
13438
13439#[no_mangle]
13440pub unsafe extern "C" fn tfind(
13441 key: *const c_void,
13442 rootp: *const *mut TreeNode,
13443 compar: ComparFn,
13444) -> *mut c_void {
13445 if rootp.is_null() {
13446 return core::ptr::null_mut();
13447 }
13448 let mut n = *rootp;
13449 loop {
13450 if n.is_null() {
13451 return core::ptr::null_mut();
13452 }
13453 let c = compar.unwrap()(key, (*n).key);
13454 if c == 0 {
13455 return n as *mut c_void;
13456 }
13457 if c < 0 {
13458 n = (*n).left;
13459 } else {
13460 n = (*n).right;
13461 }
13462 }
13463}
13464
13465#[no_mangle]
13466pub unsafe extern "C" fn tdelete(
13467 key: *const c_void,
13468 rootp: *mut *mut TreeNode,
13469 compar: ComparFn,
13470) -> *mut c_void {
13471 if rootp.is_null() {
13472 return core::ptr::null_mut();
13473 }
13474 let mut pp = rootp;
13475 loop {
13476 let n = *pp;
13477 if n.is_null() {
13478 return core::ptr::null_mut();
13479 }
13480 let c = compar.unwrap()(key, (*n).key);
13481 if c == 0 {
13482 break;
13483 }
13484 if c < 0 {
13485 pp = &mut (*n).left;
13486 } else {
13487 pp = &mut (*n).right;
13488 }
13489 }
13490 let n = *pp;
13491 let parent = *rootp;
13493 if !(*n).left.is_null() {
13494 let mut q = &mut (*n).left;
13496 while !(*(*q)).right.is_null() {
13497 q = &mut (*(*q)).right;
13498 }
13499 let pred = *q;
13500 (*n).key = (*pred).key;
13502 *q = (*pred).left;
13504 free(pred as *mut c_void);
13505 } else {
13506 *pp = (*n).right;
13508 free(n as *mut c_void);
13509 }
13510 parent as *mut c_void
13511}
13512
13513#[no_mangle]
13514pub unsafe extern "C" fn twalk(
13515 root: *const TreeNode,
13516 action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
13517) {
13518 unsafe fn walk(
13519 node: *const TreeNode,
13520 action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
13521 depth: c_int,
13522 ) {
13523 if node.is_null() {
13524 return;
13525 }
13526 let is_leaf = (*node).left.is_null() && (*node).right.is_null();
13527 if is_leaf {
13528 action.unwrap()(node as *const c_void, 3, depth); } else {
13530 action.unwrap()(node as *const c_void, 0, depth); walk((*node).left, action, depth + 1);
13532 action.unwrap()(node as *const c_void, 1, depth); walk((*node).right, action, depth + 1);
13534 action.unwrap()(node as *const c_void, 2, depth); }
13536 }
13537 walk(root, action, 0);
13538}
13539
13540#[no_mangle]
13541pub unsafe extern "C" fn tdestroy(root: *mut TreeNode, freekey: Option<unsafe extern "C" fn(*mut c_void)>) {
13542 if root.is_null() {
13543 return;
13544 }
13545 tdestroy((*root).left, freekey);
13546 tdestroy((*root).right, freekey);
13547 if let Some(f) = freekey {
13548 f((*root).key as *mut c_void);
13549 }
13550 free(root as *mut c_void);
13551}
13552
13553const FNM_PATHNAME: c_int = 0x1;
13558const FNM_NOESCAPE: c_int = 0x2;
13559const FNM_PERIOD: c_int = 0x4;
13560const FNM_LEADING_DIR: c_int = 0x8;
13561const FNM_CASEFOLD: c_int = 0x10;
13562const FNM_NOMATCH: c_int = 1;
13563
13564const FNM_END: c_int = 0;
13565const FNM_STAR: c_int = -5;
13566const FNM_QUESTION: c_int = -4;
13567const FNM_BRACKET: c_int = -3;
13568const FNM_UNMATCHABLE: c_int = -2;
13569
13570fn ascii_tolower(c: u8) -> u8 {
13571 if c >= b'A' && c <= b'Z' { c + 32 } else { c }
13572}
13573
13574fn ascii_toupper(c: u8) -> u8 {
13575 if c >= b'a' && c <= b'z' { c - 32 } else { c }
13576}
13577
13578fn ascii_casefold(k: u8) -> u8 {
13579 let upper = ascii_toupper(k);
13580 if upper != k { upper } else { ascii_tolower(k) }
13581}
13582
13583unsafe fn pat_next(pat: *const u8, m: usize, flags: c_int) -> (c_int, usize) {
13586 if m == 0 || *pat == 0 {
13587 return (FNM_END, 0);
13588 }
13589 let mut p = pat;
13590 let mut step = 1usize;
13591 let mut esc = false;
13592 if *p == b'\\' && !(flags & FNM_NOESCAPE != 0) && *p.add(1) != 0 {
13593 p = p.add(1);
13594 step = 2;
13595 esc = true;
13596 }
13597 if *p == b'[' && !esc {
13598 let mut k = 1usize;
13600 if k < m && (*pat.add(k) == b'^' || *pat.add(k) == b'!') { k += 1; }
13601 if k < m && *pat.add(k) == b']' { k += 1; }
13602 while k < m && *pat.add(k) != 0 && *pat.add(k) != b']' {
13603 if k + 1 < m && *pat.add(k) == b'[' &&
13604 (*pat.add(k+1) == b':' || *pat.add(k+1) == b'.' || *pat.add(k+1) == b'=') {
13605 let z = *pat.add(k+1);
13606 k += 2;
13607 if k < m { k += 1; }
13608 while k < m && *pat.add(k) != 0 && (*pat.add(k-1) != z || *pat.add(k) != b']') { k += 1; }
13609 if k == m || *pat.add(k) == 0 { break; }
13610 }
13611 k += 1;
13612 }
13613 if k == m || *pat.add(k) == 0 {
13614 return (b'[' as c_int, 1);
13616 }
13617 return (FNM_BRACKET, k + 1);
13618 }
13619 if *p == b'*' && !esc {
13620 return (FNM_STAR, 1);
13621 }
13622 if *p == b'?' && !esc {
13623 return (FNM_QUESTION, 1);
13624 }
13625 (*p as c_int, step)
13626}
13627
13628unsafe fn match_class(name: &[u8], k: u8, kfold: u8) -> bool {
13629 let eq = |c: u8| k == c || kfold == c;
13630 let in_range = |lo: u8, hi: u8| (k >= lo && k <= hi) || (kfold >= lo && kfold <= hi);
13631 match name {
13632 b"alnum" => in_range(b'0', b'9') || in_range(b'A', b'Z') || in_range(b'a', b'z'),
13633 b"alpha" => in_range(b'A', b'Z') || in_range(b'a', b'z'),
13634 b"blank" => eq(b' ') || eq(b'\t'),
13635 b"cntrl" => k < 0x20 || k == 0x7f,
13636 b"digit" => in_range(b'0', b'9'),
13637 b"graph" => k >= 0x21 && k <= 0x7e,
13638 b"lower" => in_range(b'a', b'z'),
13639 b"print" => k >= 0x20 && k <= 0x7e,
13640 b"punct" =>
13641 (k >= 0x21 && k <= 0x2f) ||
13642 (k >= 0x3a && k <= 0x40) ||
13643 (k >= 0x5b && k <= 0x60) ||
13644 (k >= 0x7b && k <= 0x7e),
13645 b"space" => eq(b' ') || eq(b'\t') || eq(b'\n') || eq(b'\r') || eq(0x0c) || eq(0x0b),
13646 b"upper" => in_range(b'A', b'Z'),
13647 b"xdigit" => in_range(b'0', b'9') || in_range(b'A', b'F') || in_range(b'a', b'f'),
13648 _ => false,
13649 }
13650}
13651
13652unsafe fn match_bracket(mut p: *const u8, k: u8, kfold: u8) -> bool {
13654 let mut inv = false;
13655 p = p.add(1); if *p == b'^' || *p == b'!' {
13657 inv = true;
13658 p = p.add(1);
13659 }
13660 if *p == b']' {
13662 if k == b']' { return !inv; }
13663 p = p.add(1);
13664 } else if *p == b'-' {
13665 if k == b'-' { return !inv; }
13666 p = p.add(1);
13667 }
13668 while *p != b']' && *p != 0 {
13669 if *p == b'-' && *p.add(1) != b']' && *p.add(1) != 0 {
13670 let lo = *p.sub(1);
13672 let hi = *p.add(1);
13673 if lo <= hi && (k >= lo && k <= hi || kfold >= lo && kfold <= hi) {
13674 return !inv;
13675 }
13676 p = p.add(2);
13677 } else if *p == b'[' && (*p.add(1) == b':' || *p.add(1) == b'.' || *p.add(1) == b'=') {
13678 let z = *p.add(1);
13679 let start = p.add(2);
13680 let mut q = start;
13681 while *q != 0 && (*q != z || *q.add(1) != b']') { q = q.add(1); }
13682 if *q != 0 {
13683 let len = (q as usize) - (start as usize);
13684 if len > 0 {
13685 let inner = core::slice::from_raw_parts(start, len);
13686 let matched =
13687 if z == b':' { match_class(inner, k, kfold) }
13688 else { len == 1 && (inner[0] == k || inner[0] == kfold) };
13689 if matched { return !inv; }
13690 }
13691 p = q.add(2);
13692 continue;
13693 }
13694 } else {
13695 if *p == k || *p == kfold {
13696 return !inv;
13697 }
13698 p = p.add(1);
13699 }
13700 }
13701 inv
13702}
13703
13704unsafe fn fnmatch_internal(pat: *const u8, str: *const u8, flags: c_int) -> c_int {
13706 if flags & FNM_PERIOD != 0 && *str == b'.' && *pat != b'.' {
13708 return FNM_NOMATCH;
13709 }
13710
13711 let mut p = pat;
13712 let mut s = str;
13713
13714 loop {
13716 let (tok, step) = pat_next(p, usize::MAX, flags);
13717 match tok {
13718 FNM_END => {
13719 return if *s == 0 { 0 } else { FNM_NOMATCH };
13720 }
13721 FNM_STAR => {
13722 p = p.add(1);
13723 break;
13724 }
13725 FNM_QUESTION => {
13726 if *s == 0 { return FNM_NOMATCH; }
13727 s = s.add(1);
13728 p = p.add(step);
13729 }
13730 FNM_BRACKET => {
13731 if *s == 0 { return FNM_NOMATCH; }
13732 let k = *s;
13733 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13734 if !match_bracket(p, k, kfold) { return FNM_NOMATCH; }
13735 p = p.add(step);
13736 s = s.add(1);
13737 }
13738 c => {
13739 if *s == 0 { return FNM_NOMATCH; }
13740 let k = *s;
13741 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13742 if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
13743 p = p.add(step);
13744 s = s.add(1);
13745 }
13746 }
13747 }
13748
13749 let mut ptail = p;
13752 let mut tailcnt: usize = 0;
13753 let mut pp = p;
13754 loop {
13755 let (tok, step) = pat_next(pp, usize::MAX, flags);
13756 if tok == FNM_END { break; }
13757 if tok == FNM_STAR {
13758 tailcnt = 0;
13759 ptail = pp.add(1);
13760 } else {
13761 tailcnt += 1;
13762 }
13763 pp = pp.add(step);
13764 }
13765
13766 let slen = strlen(s as *const c_char);
13768 if slen < tailcnt { return FNM_NOMATCH; }
13769
13770 let stail = s.add(slen - tailcnt);
13772 let mut tp = ptail;
13773 let mut ts = stail;
13774 loop {
13775 let (tok, step) = pat_next(tp, usize::MAX, flags);
13776 tp = tp.add(step);
13777 if tok == FNM_END {
13778 break;
13779 }
13780 let k = *ts;
13781 if k == 0 { return FNM_NOMATCH; }
13782 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13783 match tok {
13784 FNM_QUESTION => { ts = ts.add(1); }
13785 FNM_BRACKET => {
13786 if !match_bracket(tp.sub(step), k, kfold) { return FNM_NOMATCH; }
13787 ts = ts.add(1);
13788 }
13789 c => {
13790 if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
13791 ts = ts.add(1);
13792 }
13793 }
13794 }
13795
13796 let endstr = stail;
13797 let endpat = ptail;
13798
13799 let mut cp = p;
13800 let mut cs = s;
13801 while cp < endpat {
13802 let (tok, step) = pat_next(cp, usize::MAX, flags);
13803 if tok == FNM_STAR {
13804 cp = cp.add(step);
13805 cs = s;
13806 continue;
13807 }
13808 let comp_start = cp;
13809 let mut ok = false;
13810 let mut try_s = cs;
13811 while try_s < endstr {
13812 let mut tmp_p = comp_start;
13813 let mut tmp_s = try_s;
13814 let mut matched = true;
13815 loop {
13816 let (t, st) = pat_next(tmp_p, usize::MAX, flags);
13817 if t == FNM_STAR || t == FNM_END {
13818 cp = tmp_p;
13819 cs = tmp_s;
13820 ok = true;
13821 break;
13822 }
13823 if *tmp_s == 0 {
13824 matched = false;
13825 break;
13826 }
13827 let k = *tmp_s;
13828 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13829 match t {
13830 FNM_QUESTION => {
13831 tmp_s = tmp_s.add(1);
13832 }
13833 FNM_BRACKET => {
13834 if !match_bracket(tmp_p, k, kfold) {
13835 matched = false;
13836 break;
13837 }
13838 tmp_s = tmp_s.add(1);
13839 }
13840 c => {
13841 if k as c_int != c && kfold as c_int != c {
13842 matched = false;
13843 break;
13844 }
13845 tmp_s = tmp_s.add(1);
13846 }
13847 }
13848 tmp_p = tmp_p.add(st);
13849 }
13850 if ok { break; }
13851 if !matched {
13852 try_s = try_s.add(1);
13853 }
13854 }
13855 if !ok {
13856 return FNM_NOMATCH;
13857 }
13858 }
13859 0
13860}
13861
13862#[no_mangle]
13863pub unsafe extern "C" fn fnmatch(pat: *const c_char, str: *const c_char, flags: c_int) -> c_int {
13864 let pat = pat as *const u8;
13865 let str = str as *const u8;
13866
13867 if flags & FNM_PATHNAME != 0 {
13868 let mut s = str;
13870 let mut p = pat;
13871 loop {
13872 let mut send = s;
13874 while *send != 0 && *send != b'/' { send = send.add(1); }
13875 let mut pend = p;
13877 loop {
13878 let (tok, step) = pat_next(pend, usize::MAX, flags);
13879 if tok == FNM_END || (tok >= 0 && tok as u8 == b'/') {
13880 break;
13881 }
13882 pend = pend.add(step);
13883 }
13884 let (ptok, pstep) = pat_next(pend, usize::MAX, flags);
13885 let pat_is_slash = ptok >= 0 && ptok as u8 == b'/';
13886 let str_is_slash = *send == b'/';
13887 if pat_is_slash != str_is_slash && (*send != 0 || !(flags & FNM_LEADING_DIR != 0)) {
13888 return FNM_NOMATCH;
13889 }
13890 let plen = (pend as usize) - (p as usize);
13893 let slen = (send as usize) - (s as usize);
13894 if plen > 1024 || slen > 1024 { return FNM_NOMATCH; }
13897 let mut pbuf = [0u8; 1025];
13898 let mut sbuf = [0u8; 1025];
13899 core::ptr::copy_nonoverlapping(p, pbuf.as_mut_ptr(), plen);
13900 pbuf[plen] = 0;
13901 core::ptr::copy_nonoverlapping(s, sbuf.as_mut_ptr(), slen);
13902 sbuf[slen] = 0;
13903 if fnmatch_internal(pbuf.as_ptr(), sbuf.as_ptr(), flags & !FNM_LEADING_DIR) != 0 {
13904 return FNM_NOMATCH;
13905 }
13906 if !pat_is_slash {
13907 return 0;
13908 }
13909 s = send.add(1);
13910 p = pend.add(pstep);
13911 }
13912 }
13913
13914 if flags & FNM_LEADING_DIR != 0 {
13915 let mut s = str;
13917 while *s != 0 {
13918 if *s == b'/' {
13919 let len = (s as usize) - (str as usize);
13922 if len < 4096 {
13924 let mut buf = [0u8; 4096];
13925 core::ptr::copy_nonoverlapping(str, buf.as_mut_ptr(), len);
13926 buf[len] = 0;
13927 if fnmatch_internal(pat, buf.as_ptr(), flags) == 0 {
13928 return 0;
13929 }
13930 }
13931 }
13932 s = s.add(1);
13933 }
13934 }
13935
13936 fnmatch_internal(pat, str, flags)
13937}
13938
13939#[no_mangle]
13944pub unsafe extern "C" fn setmntent(name: *const c_char, mode: *const c_char) -> *mut FILE {
13945 fopen(name, mode)
13946}
13947
13948#[no_mangle]
13949pub unsafe extern "C" fn endmntent(f: *mut FILE) -> c_int {
13950 if !f.is_null() {
13951 fclose(f);
13952 }
13953 1
13954}
13955
13956static mut MNTENT_MNT: MntEnt = MntEnt {
13958 mnt_fsname: core::ptr::null_mut(),
13959 mnt_dir: core::ptr::null_mut(),
13960 mnt_type: core::ptr::null_mut(),
13961 mnt_opts: core::ptr::null_mut(),
13962 mnt_freq: 0,
13963 mnt_passno: 0,
13964};
13965
13966#[repr(C)]
13967pub struct MntEnt {
13968 mnt_fsname: *mut c_char,
13969 mnt_dir: *mut c_char,
13970 mnt_type: *mut c_char,
13971 mnt_opts: *mut c_char,
13972 mnt_freq: c_int,
13973 mnt_passno: c_int,
13974}
13975
13976unsafe fn unescape_ent(beg: *mut c_char) -> *mut c_char {
13977 let mut dest = beg;
13978 let mut src = beg;
13979 while *src != 0 {
13980 if *src != b'\\' as c_char {
13981 *dest = *src;
13982 dest = dest.add(1);
13983 src = src.add(1);
13984 continue;
13985 }
13986 if *src.add(1) == b'\\' as c_char {
13988 src = src.add(1);
13989 *dest = *src;
13990 dest = dest.add(1);
13991 src = src.add(1);
13992 continue;
13993 }
13994 let mut val: u8 = 0;
13996 let mut cnt = 0;
13997 let mut sp = src.add(1);
13998 while cnt < 3 && *sp >= b'0' as c_char && *sp <= b'7' as c_char {
13999 val = val * 8 + (*sp as u8 - b'0');
14000 sp = sp.add(1);
14001 cnt += 1;
14002 }
14003 if cnt > 0 {
14004 *dest = val as c_char;
14005 dest = dest.add(1);
14006 src = sp;
14007 } else {
14008 *dest = *src;
14009 dest = dest.add(1);
14010 src = src.add(1);
14011 }
14012 }
14013 *dest = 0;
14014 beg
14015}
14016
14017unsafe fn parse_mntent_line(
14018 linebuf: *mut c_char,
14019 mnt: *mut MntEnt,
14020) -> *mut MntEnt {
14021 let _len = strlen(linebuf as *const c_char);
14022 let mut p = linebuf;
14025 while *p == b' ' as c_char || *p == b'\t' as c_char || *p == b'\n' as c_char || *p == b'\r' as c_char {
14027 p = p.add(1);
14028 }
14029 if *p == 0 || *p == b'#' as c_char {
14030 return core::ptr::null_mut();
14031 }
14032
14033 (*mnt).mnt_fsname = p;
14035 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14036 p = p.add(1);
14037 }
14038 if *p == 0 { return core::ptr::null_mut(); }
14039 *p = 0;
14040 p = p.add(1);
14041 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14042
14043 (*mnt).mnt_dir = p;
14045 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14046 p = p.add(1);
14047 }
14048 if *p == 0 { return core::ptr::null_mut(); }
14049 *p = 0;
14050 p = p.add(1);
14051 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14052
14053 (*mnt).mnt_type = p;
14055 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14056 p = p.add(1);
14057 }
14058 if *p == 0 { return core::ptr::null_mut(); }
14059 *p = 0;
14060 p = p.add(1);
14061 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14062
14063 (*mnt).mnt_opts = p;
14065 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14066 p = p.add(1);
14067 }
14068 if *p != 0 {
14069 *p = 0;
14070 p = p.add(1);
14071 }
14072 if *(*mnt).mnt_opts == 0 {
14073 (*mnt).mnt_opts = b"defaults\0".as_ptr() as *mut c_char;
14074 }
14075
14076 (*mnt).mnt_freq = 0;
14078 (*mnt).mnt_passno = 0;
14079 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14081 if *p >= b'0' as c_char && *p <= b'9' as c_char {
14082 (*mnt).mnt_freq = (*p - b'0' as c_char) as c_int;
14083 p = p.add(1);
14084 while *p >= b'0' as c_char && *p <= b'9' as c_char {
14085 (*mnt).mnt_freq = (*mnt).mnt_freq * 10 + (*p - b'0' as c_char) as c_int;
14086 p = p.add(1);
14087 }
14088 }
14089 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14090 if *p >= b'0' as c_char && *p <= b'9' as c_char {
14091 (*mnt).mnt_passno = (*p - b'0' as c_char) as c_int;
14092 p = p.add(1);
14093 while *p >= b'0' as c_char && *p <= b'9' as c_char {
14094 (*mnt).mnt_passno = (*mnt).mnt_passno * 10 + (*p - b'0' as c_char) as c_int;
14095 p = p.add(1);
14096 }
14097 }
14098
14099 unescape_ent((*mnt).mnt_fsname);
14101 unescape_ent((*mnt).mnt_dir);
14102 unescape_ent((*mnt).mnt_type);
14103 unescape_ent((*mnt).mnt_opts);
14104
14105 mnt
14106}
14107
14108static SENTINEL_PTR: usize = 1;
14111
14112unsafe fn mntent_fgetc(f: *mut FILE) -> c_int {
14114 fgetc(f)
14115}
14116
14117unsafe fn mntent_fgets(buf: *mut c_char, n: usize, f: *mut FILE) -> *mut c_char {
14118 if n == 0 { return core::ptr::null_mut(); }
14119 let max = n - 1;
14120 let mut i = 0usize;
14121 while i < max {
14122 let c = mntent_fgetc(f);
14123 if c == -1 { if i == 0 { return core::ptr::null_mut(); } break; }
14124 *buf.add(i) = c as c_char;
14125 i += 1;
14126 if c == b'\n' as c_int { break; }
14127 }
14128 *buf.add(i) = 0;
14129 buf
14130}
14131
14132#[no_mangle]
14133pub unsafe extern "C" fn getmntent_r(
14134 f: *mut FILE,
14135 mnt: *mut MntEnt,
14136 mut linebuf: *mut c_char,
14137 _buflen: c_int,
14138) -> *mut MntEnt {
14139 let use_internal = linebuf as usize == SENTINEL_PTR;
14140
14141 (*mnt).mnt_freq = 0;
14142 (*mnt).mnt_passno = 0;
14143
14144 static mut INTERNAL_BUF: [c_char; 4096] = [0; 4096];
14146
14147 loop {
14148 if use_internal {
14149 linebuf = core::ptr::addr_of_mut!(INTERNAL_BUF).cast::<c_char>();
14150 }
14151 let res = mntent_fgets(linebuf, 4096, f);
14152 if res.is_null() {
14153 return core::ptr::null_mut();
14154 }
14155 let mut has_newline = false;
14156 let mut p = linebuf;
14157 while *p != 0 { if *p == b'\n' as c_char { has_newline = true; break; } p = p.add(1); }
14158 if !has_newline {
14159 ERRNO = 34;
14160 return core::ptr::null_mut();
14161 }
14162 let result = parse_mntent_line(linebuf, mnt);
14163 if !result.is_null() {
14164 return result;
14165 }
14166 }
14167}
14168
14169#[no_mangle]
14170pub unsafe extern "C" fn getmntent(f: *mut FILE) -> *mut MntEnt {
14171 getmntent_r(f, core::ptr::addr_of_mut!(MNTENT_MNT), SENTINEL_PTR as *mut c_char, 0)
14172}
14173
14174#[no_mangle]
14175pub unsafe extern "C" fn addmntent(f: *mut FILE, mnt: *const MntEnt) -> c_int {
14176 fseek(f, 0, 2); let written = fprintf(
14178 f,
14179 b"%s\t%s\t%s\t%s\t%d\t%d\n\0".as_ptr() as *const c_char,
14180 (*mnt).mnt_fsname,
14181 (*mnt).mnt_dir,
14182 (*mnt).mnt_type,
14183 (*mnt).mnt_opts,
14184 (*mnt).mnt_freq,
14185 (*mnt).mnt_passno,
14186 );
14187 if written < 0 { 1 } else { 0 }
14188}
14189
14190#[no_mangle]
14191pub unsafe extern "C" fn hasmntopt(mnt: *const MntEnt, opt: *const c_char) -> *mut c_char {
14192 let l = strlen(opt as *const c_char);
14193 let mut p = (*mnt).mnt_opts;
14194 loop {
14195 if strncmp(p as *const u8, opt as *const u8, l) == 0 {
14196 let after = *p.add(l);
14197 if after == 0 || after == b',' as c_char || after == b'=' as c_char {
14198 return p;
14199 }
14200 }
14201 let comma = strchr(p as *const u8, b',' as c_int);
14202 if comma.is_null() {
14203 return core::ptr::null_mut();
14204 }
14205 p = comma.add(1) as *mut c_char;
14206 }
14207}
14208
14209const EEXIST: c_int = 17;
14217const ENAMETOOLONG: c_int = 36;
14218const EMFILE: c_int = 24;
14219const EIDRM: c_int = 43;
14220
14221#[inline]
14222unsafe fn sys_msgget(key: c_int, msgflg: c_int) -> i64 {
14223 <Arch as Syscalls>::syscall2(SYS_MSGGET, key as i64, msgflg as i64)
14224}
14225
14226#[inline]
14227unsafe fn sys_msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> i64 {
14228 <Arch as Syscalls>::syscall4(SYS_MSGSND, msqid as i64, msgp as i64, msgsz as i64, msgflg as i64)
14229}
14230
14231#[inline]
14232unsafe fn sys_msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> i64 {
14233 <Arch as Syscalls>::syscall5(SYS_MSGRCV, msqid as i64, msgp as i64, msgsz as i64, msgtyp as i64, msgflg as i64)
14234}
14235
14236#[inline]
14237unsafe fn sys_msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14238 <Arch as Syscalls>::syscall3(SYS_MSGCTL, msqid as i64, cmd as i64, buf as i64)
14239}
14240
14241#[inline]
14242unsafe fn sys_semget(key: c_int, nsems: c_int, semflg: c_int) -> i64 {
14243 <Arch as Syscalls>::syscall3(SYS_SEMGET, key as i64, nsems as i64, semflg as i64)
14244}
14245
14246#[inline]
14247unsafe fn sys_semop(semid: c_int, sops: *const c_void, nsops: usize) -> i64 {
14248 <Arch as Syscalls>::syscall3(SYS_SEMOP, semid as i64, sops as i64, nsops as i64)
14249}
14250
14251#[inline]
14252unsafe fn sys_semctl(semid: c_int, semnum: c_int, cmd: c_int, arg: *mut c_void) -> i64 {
14253 <Arch as Syscalls>::syscall4(SYS_SEMCTL, semid as i64, semnum as i64, cmd as i64, arg as i64)
14254}
14255
14256#[inline]
14257unsafe fn sys_shmget(key: c_int, size: usize, shmflg: c_int) -> i64 {
14258 <Arch as Syscalls>::syscall3(SYS_SHMGET, key as i64, size as i64, shmflg as i64)
14259}
14260
14261#[inline]
14262unsafe fn sys_shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> i64 {
14263 <Arch as Syscalls>::syscall3(SYS_SHMAT, shmid as i64, shmaddr as i64, shmflg as i64)
14264}
14265
14266#[inline]
14267unsafe fn sys_shmdt(shmaddr: *const c_void) -> i64 {
14268 <Arch as Syscalls>::syscall1(SYS_SHMDT, shmaddr as i64)
14269}
14270
14271#[inline]
14272unsafe fn sys_shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14273 <Arch as Syscalls>::syscall3(SYS_SHMCTL, shmid as i64, cmd as i64, buf as i64)
14274}
14275
14276#[no_mangle]
14278pub unsafe extern "C" fn ftok(path: *const c_char, id: c_int) -> c_int {
14279 let mut st: kernel_stat64 = core::mem::zeroed();
14280 let r = sys_stat(path as *const u8, &mut st);
14281 if r < 0 {
14282 ERRNO = (-r) as c_int;
14283 return -1;
14284 }
14285 ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | (((id as u32 & 0xff) << 24)) as u64) as c_int
14286}
14287
14288#[no_mangle]
14290pub unsafe extern "C" fn msgget(key: c_int, msgflg: c_int) -> c_int {
14291 let r = sys_msgget(key, msgflg);
14292 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14293}
14294
14295#[no_mangle]
14297pub unsafe extern "C" fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> c_int {
14298 let r = sys_msgsnd(msqid, msgp, msgsz, msgflg);
14299 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14300}
14301
14302#[no_mangle]
14304pub unsafe extern "C" fn msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> isize {
14305 let r = sys_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
14306 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
14307}
14308
14309#[no_mangle]
14311pub unsafe extern "C" fn msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
14312 let r = sys_msgctl(msqid, cmd, buf);
14313 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14314}
14315
14316#[no_mangle]
14318pub unsafe extern "C" fn semget(key: c_int, nsems: c_int, semflg: c_int) -> c_int {
14319 if nsems > 65535 { ERRNO = 22; return -1; }
14320 let r = sys_semget(key, nsems, semflg);
14321 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14322}
14323
14324#[no_mangle]
14326pub unsafe extern "C" fn semop(semid: c_int, sops: *const c_void, nsops: usize) -> c_int {
14327 let r = sys_semop(semid, sops, nsops);
14328 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14329}
14330
14331#[no_mangle]
14333pub unsafe extern "C" fn semctl(semid: c_int, semnum: c_int, cmd: c_int, mut args: ...) -> c_int {
14334 let mut arg: *mut c_void = core::ptr::null_mut();
14335 match cmd {
14337 16 | 13 | 17 | 1 | 3 | 2 | 0x102 | 0x104 | 0x106 => {
14338 arg = args.next_arg::<*mut c_void>();
14339 }
14340 _ => {}
14341 }
14342 let r = sys_semctl(semid, semnum, cmd, arg);
14343 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14344}
14345
14346#[no_mangle]
14348pub unsafe extern "C" fn shmget(key: c_int, size: usize, shmflg: c_int) -> c_int {
14349 let r = sys_shmget(key, size, shmflg);
14350 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14351}
14352
14353#[no_mangle]
14355pub unsafe extern "C" fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void {
14356 let r = sys_shmat(shmid, shmaddr, shmflg);
14357 if (r as usize) > (-(4096isize as isize)) as usize {
14358 ERRNO = (-r) as c_int;
14359 return core::ptr::null_mut();
14360 }
14361 r as *mut c_void
14362}
14363
14364#[no_mangle]
14366pub unsafe extern "C" fn shmdt(shmaddr: *const c_void) -> c_int {
14367 let r = sys_shmdt(shmaddr);
14368 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14369}
14370
14371#[no_mangle]
14373pub unsafe extern "C" fn shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
14374 let r = sys_shmctl(shmid, cmd, buf);
14375 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14376}
14377
14378#[no_mangle]
14388pub static mut __auxv: *const usize = core::ptr::null();
14389
14390#[no_mangle]
14391pub unsafe extern "C" fn getauxval(type_: c_ulong) -> c_ulong {
14392 let mut p = __auxv;
14393 if p.is_null() {
14394 return 0;
14395 }
14396 loop {
14397 let tag = *p;
14398 if tag == 0 {
14399 return 0;
14400 }
14401 if tag == type_ as usize {
14402 return *p.add(1) as c_ulong;
14403 }
14404 p = p.add(2);
14405 }
14406}
14407
14408type MainFn = unsafe extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int;
14409type InitFn = unsafe extern "C" fn();
14410
14411#[no_mangle]
14412pub unsafe extern "C" fn __libc_start_main(
14413 main: MainFn,
14414 argc: c_int,
14415 argv: *const *const c_char,
14416 _init: *const c_void,
14417 _fini: *const c_void,
14418 _rtld_fini: *const c_void,
14419 _stack_end: *const c_void,
14420) -> ! {
14421 let envp = argv.add((argc + 1) as usize);
14422 __environ = envp as *mut *mut c_char;
14423 environ = __environ; __stdio_init();
14425
14426 let mut set: SigSetT = 0;
14427 sigemptyset(&mut set);
14428 sigaddset(&mut set, SIGCANCEL);
14429 sigprocmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
14430
14431 if !_init.is_null() {
14432 let init_fn: InitFn = core::mem::transmute(_init);
14433 init_fn();
14434 }
14435
14436 #[cfg(target_arch = "aarch64")]
14440 {
14441 let random_ptr = getauxval(25) as *const u8; if !random_ptr.is_null() {
14443 let a = core::ptr::read_unaligned(random_ptr as *const u64);
14444 let b = core::ptr::read_unaligned(random_ptr.add(8) as *const u64);
14445 __stack_chk_guard = (a ^ b) as usize;
14446 } else {
14447 __stack_chk_guard = 0xdefaced_cafebeef;
14449 }
14450 }
14451
14452 let result = main(argc, argv, envp);
14453
14454 if !_fini.is_null() {
14455 let fini_fn: InitFn = core::mem::transmute(_fini);
14456 fini_fn();
14457 }
14458
14459 exit(result);
14460}
14461
14462type LdsoDlopenFn = unsafe extern "C" fn(*const c_char, c_int) -> *mut c_void;
14463type LdsoDlsymFn = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
14464type LdsoDlcloseFn = unsafe extern "C" fn(*mut c_void) -> c_int;
14465type LdsoDlerrorFn = unsafe extern "C" fn() -> *const c_char;
14466
14467static mut LDSO_DLOPEN: Option<LdsoDlopenFn> = None;
14468static mut LDSO_DLSYM: Option<LdsoDlsymFn> = None;
14469static mut LDSO_DLCLOSE: Option<LdsoDlcloseFn> = None;
14470static mut LDSO_DLERROR: Option<LdsoDlerrorFn> = None;
14471
14472#[no_mangle]
14473pub unsafe extern "C" fn __ldso_register_dlopen(f: LdsoDlopenFn) {
14474 LDSO_DLOPEN = Some(f);
14475}
14476
14477#[no_mangle]
14478pub unsafe extern "C" fn __ldso_register_dlsym(f: LdsoDlsymFn) {
14479 LDSO_DLSYM = Some(f);
14480}
14481
14482#[no_mangle]
14483pub unsafe extern "C" fn __ldso_register_dlclose(f: LdsoDlcloseFn) {
14484 LDSO_DLCLOSE = Some(f);
14485}
14486
14487#[no_mangle]
14488pub unsafe extern "C" fn __ldso_register_dlerror(f: LdsoDlerrorFn) {
14489 LDSO_DLERROR = Some(f);
14490}
14491
14492#[no_mangle]
14493pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c_void {
14494 if let Some(f) = LDSO_DLOPEN {
14495 f(filename, flags)
14496 } else {
14497 null_mut()
14498 }
14499}
14500
14501#[no_mangle]
14502pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
14503 if let Some(f) = LDSO_DLSYM {
14504 f(handle, symbol)
14505 } else {
14506 null_mut()
14507 }
14508}
14509
14510#[no_mangle]
14511pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
14512 if let Some(f) = LDSO_DLCLOSE {
14513 f(handle)
14514 } else {
14515 0
14516 }
14517}
14518
14519#[no_mangle]
14520pub unsafe extern "C" fn dlerror() -> *const c_char {
14521 if let Some(f) = LDSO_DLERROR {
14522 f()
14523 } else {
14524 core::ptr::null()
14525 }
14526}
14527
14528include!("crypt_impl.rs");
14529include!("statvfs.rs");
14530include!("daemon.rs");
14531include!("dn_expand.rs");
14532include!("lrand48.rs");
14533include!("strverscmp.rs");
14534include!("syscall.rs");
14535include!("pthread_atfork.rs");
14536include!("fenv.rs");
14537include!("locale_ctype.rs");
14538include!("regression_stubs.rs");
14539
14540type regoff_t = c_int;
14545
14546#[repr(C)]
14547pub struct regex_t {
14548 pub re_nsub: usize,
14549 pub __opaque: *mut c_void,
14550 pub __padding: [*mut c_void; 4],
14551 pub __nsub2: usize,
14552 pub __padding2: c_char,
14553}
14554
14555#[repr(C)]
14556pub struct regmatch_t {
14557 pub rm_so: regoff_t,
14558 pub rm_eo: regoff_t,
14559}
14560
14561include!("regex.rs");
14562
14563#[cfg(test)]
14564mod libc_unit_stub {
14565 #[test]
14566 fn stub() {
14567 assert!(true);
14568 }
14569}