1#![cfg_attr(not(test), no_std)]
2#![feature(c_variadic)]
3#![feature(linkage)]
4#![allow(dead_code, non_camel_case_types)]
5
6use core::ffi::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong, c_void, VaList};
7use core::ptr::null_mut;
8use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
9
10include!("encoding_tables.rs");
11include!("math_helpers.rs");
12include!("math_bitmanip.rs");
13include!("math_sqrtfmod.rs");
14include!("math_trig.rs");
15include!("math_exp.rs");
16include!("math_log.rs");
17include!("math_pow.rs");
18include!("math_hypot.rs");
19include!("math_hyperbolic.rs");
20include!("math_invtrig.rs");
21include!("math_lrint.rs");
22
23const EILSEQ: c_int = 84;
28const EINVAL: c_int = 22;
29const EFAULT: c_int = 14;
30const E2BIG: c_int = 7;
31
32const LC_CTYPE: c_int = 0;
33const LC_NUMERIC: c_int = 1;
34const LC_TIME: c_int = 2;
35const LC_COLLATE: c_int = 3;
36const LC_MONETARY: c_int = 4;
37const LC_MESSAGES: c_int = 5;
38const LC_ALL: c_int = 6;
39const ENOMEM: c_int = 12;
40const EINTR: c_int = 4;
41const EPERM: c_int = 1;
42const EAGAIN: c_int = 11;
43const EBUSY: c_int = 16;
44const EDEADLK: c_int = 35;
45const ETIMEDOUT: c_int = 110;
46const ECANCELED: c_int = 125;
47const EOVERFLOW: c_int = 75;
48const EOWNERDEAD: c_int = 130;
49const ENOTRECOVERABLE: c_int = 131;
50
51static mut ERRNO: c_int = 0;
52
53#[no_mangle]
54pub unsafe extern "C" fn __errno_location() -> *mut c_int {
55 core::ptr::addr_of_mut!(ERRNO)
56}
57
58#[cfg(not(test))]
59#[panic_handler]
60fn panic(_: &core::panic::PanicInfo) -> ! {
61 loop {}
62}
63
64#[cfg(not(test))]
66#[no_mangle]
67pub extern "C" fn rust_eh_personality() {}
68
69const PROT_READ: i32 = 1;
74const PROT_WRITE: i32 = 2;
75const MAP_SHARED: i32 = 0x01;
76const MAP_PRIVATE: i32 = 0x02;
77const MAP_ANONYMOUS: i32 = 0x20;
78
79trait Syscalls {
84 unsafe fn syscall0(n: i64) -> i64;
85 unsafe fn syscall1(n: i64, a1: i64) -> i64;
86 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64;
87 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64;
88 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64;
89 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64;
90 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64;
91 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> !;
92}
93
94struct X86_64;
95struct Aarch64;
96
97#[cfg(target_arch = "x86_64")]
98impl Syscalls for X86_64 {
99 #[inline(always)]
100 unsafe fn syscall0(n: i64) -> i64 {
101 let result: i64;
102 core::arch::asm!(
103 "syscall",
104 inlateout("rax") n => result,
105 lateout("rcx") _,
106 lateout("r11") _,
107 );
108 result
109 }
110 #[inline(always)]
111 unsafe fn syscall1(n: i64, a1: i64) -> i64 {
112 let result: i64;
113 core::arch::asm!(
114 "syscall",
115 inlateout("rax") n => result,
116 in("rdi") a1,
117 lateout("rcx") _,
118 lateout("r11") _,
119 );
120 result
121 }
122 #[inline(always)]
123 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
124 let result: i64;
125 core::arch::asm!(
126 "syscall",
127 inlateout("rax") n => result,
128 in("rdi") a1,
129 in("rsi") a2,
130 lateout("rcx") _,
131 lateout("r11") _,
132 );
133 result
134 }
135 #[inline(always)]
136 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
137 let result: i64;
138 core::arch::asm!(
139 "syscall",
140 inlateout("rax") n => result,
141 in("rdi") a1,
142 in("rsi") a2,
143 in("rdx") a3,
144 lateout("rcx") _,
145 lateout("r11") _,
146 );
147 result
148 }
149 #[inline(always)]
150 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
151 let result: i64;
152 core::arch::asm!(
153 "syscall",
154 inlateout("rax") n => result,
155 in("rdi") a1,
156 in("rsi") a2,
157 in("rdx") a3,
158 in("r10") a4,
159 lateout("rcx") _,
160 lateout("r11") _,
161 );
162 result
163 }
164 #[inline(always)]
165 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
166 let result: i64;
167 core::arch::asm!(
168 "syscall",
169 inlateout("rax") n => result,
170 in("rdi") a1,
171 in("rsi") a2,
172 in("rdx") a3,
173 in("r10") a4,
174 in("r8") a5,
175 lateout("rcx") _,
176 lateout("r11") _,
177 );
178 result
179 }
180 #[inline(always)]
181 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
182 let result: i64;
183 core::arch::asm!(
184 "syscall",
185 inlateout("rax") n => result,
186 in("rdi") a1,
187 in("rsi") a2,
188 in("rdx") a3,
189 in("r10") a4,
190 in("r8") a5,
191 in("r9") a6,
192 lateout("rcx") _,
193 lateout("r11") _,
194 );
195 result
196 }
197 #[inline(always)]
198 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
199 core::arch::asm!(
200 "syscall",
201 in("rax") n,
202 in("rdi") a1,
203 options(noreturn)
204 );
205 }
206}
207
208#[cfg(target_arch = "aarch64")]
209impl Syscalls for Aarch64 {
210 #[inline(always)]
211 unsafe fn syscall0(n: i64) -> i64 {
212 let result: i64;
213 core::arch::asm!(
214 "svc #0",
215 inlateout("x8") n => _,
216 lateout("x0") result,
217 options(nostack),
218 );
219 result
220 }
221 #[inline(always)]
222 unsafe fn syscall1(n: i64, a1: i64) -> i64 {
223 let result: i64;
224 core::arch::asm!(
225 "svc #0",
226 inlateout("x8") n => _,
227 inlateout("x0") a1 => result,
228 options(nostack),
229 );
230 result
231 }
232 #[inline(always)]
233 unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
234 let result: i64;
235 core::arch::asm!(
236 "svc #0",
237 inlateout("x8") n => _,
238 inlateout("x0") a1 => result,
239 inlateout("x1") a2 => _,
240 options(nostack),
241 );
242 result
243 }
244 #[inline(always)]
245 unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
246 let result: i64;
247 core::arch::asm!(
248 "svc #0",
249 inlateout("x8") n => _,
250 inlateout("x0") a1 => result,
251 inlateout("x1") a2 => _,
252 inlateout("x2") a3 => _,
253 options(nostack),
254 );
255 result
256 }
257 #[inline(always)]
258 unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
259 let result: i64;
260 core::arch::asm!(
261 "svc #0",
262 inlateout("x8") n => _,
263 inlateout("x0") a1 => result,
264 inlateout("x1") a2 => _,
265 inlateout("x2") a3 => _,
266 inlateout("x3") a4 => _,
267 options(nostack),
268 );
269 result
270 }
271 #[inline(always)]
272 unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
273 let result: i64;
274 core::arch::asm!(
275 "svc #0",
276 inlateout("x8") n => _,
277 inlateout("x0") a1 => result,
278 inlateout("x1") a2 => _,
279 inlateout("x2") a3 => _,
280 inlateout("x3") a4 => _,
281 inlateout("x4") a5 => _,
282 options(nostack),
283 );
284 result
285 }
286 #[inline(always)]
287 unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
288 let result: i64;
289 core::arch::asm!(
290 "svc #0",
291 inlateout("x8") n => _,
292 inlateout("x0") a1 => result,
293 inlateout("x1") a2 => _,
294 inlateout("x2") a3 => _,
295 inlateout("x3") a4 => _,
296 inlateout("x4") a5 => _,
297 inlateout("x5") a6 => _,
298 options(nostack),
299 );
300 result
301 }
302 #[inline(always)]
303 unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
304 core::arch::asm!(
305 "svc #0",
306 in("x8") n,
307 in("x0") a1,
308 options(noreturn, nostack),
309 );
310 }
311}
312
313#[cfg(target_arch = "x86_64")]
314type Arch = X86_64;
315#[cfg(target_arch = "aarch64")]
316type Arch = Aarch64;
317
318
319
320#[cfg(target_arch = "x86_64")]
322mod sysnr {
323 pub const SYS_READ: i64 = 0;
324 pub const SYS_WRITE: i64 = 1;
325 pub const SYS_OPEN: i64 = 2;
326 pub const SYS_CLOSE: i64 = 3;
327 pub const SYS_STAT: i64 = 4;
328 pub const SYS_FSTAT: i64 = 5;
329 pub const SYS_LSEEK: i64 = 8;
330 pub const SYS_MMAP: i64 = 9;
331 pub const SYS_MUNMAP: i64 = 11;
332 pub const SYS_RT_SIGACTION: i64 = 13;
333 pub const SYS_RT_SIGPROCMASK: i64 = 14;
334 pub const SYS_IOCTL: i64 = 16;
335 pub const SYS_ACCESS: i64 = 21;
336 pub const SYS_SHMGET: i64 = 29;
337 pub const SYS_SHMAT: i64 = 30;
338 pub const SYS_SHMCTL: i64 = 31;
339 pub const SYS_DUP: i64 = 32;
340 pub const SYS_NANOSLEEP: i64 = 35;
341 pub const SYS_SETITIMER: i64 = 38;
342 pub const SYS_ALARM: i64 = 37;
343 pub const SYS_SOCKET: i64 = 41;
344 pub const SYS_CONNECT: i64 = 42;
345 pub const SYS_ACCEPT: i64 = 43;
346 pub const SYS_SENDTO: i64 = 44;
347 pub const SYS_RECVFROM: i64 = 45;
348 pub const SYS_SHUTDOWN: i64 = 48;
349 pub const SYS_BIND: i64 = 49;
350 pub const SYS_LISTEN: i64 = 50;
351 pub const SYS_GETSOCKNAME: i64 = 51;
352 pub const SYS_SOCKETPAIR: i64 = 53;
353 pub const SYS_SETSOCKOPT: i64 = 54;
354 pub const SYS_EXECVE: i64 = 59;
355 pub const SYS_WAIT4: i64 = 61;
356 pub const SYS_KILL: i64 = 62;
357 pub const SYS_UNAME: i64 = 63;
358 pub const SYS_SEMGET: i64 = 64;
359 pub const SYS_SEMOP: i64 = 65;
360 pub const SYS_SEMCTL: i64 = 66;
361 pub const SYS_SHMDT: i64 = 67;
362 pub const SYS_MSGGET: i64 = 68;
363 pub const SYS_MSGSND: i64 = 69;
364 pub const SYS_MSGRCV: i64 = 70;
365 pub const SYS_MSGCTL: i64 = 71;
366 pub const SYS_FCNTL: i64 = 72;
367 pub const SYS_FSYNC: i64 = 74;
368 pub const SYS_TRUNCATE: i64 = 76;
369 pub const SYS_FTRUNCATE: i64 = 77;
370 pub const SYS_GETCWD: i64 = 79;
371 pub const SYS_CHDIR: i64 = 80;
372 pub const SYS_SYMLINK: i64 = 88;
373 pub const SYS_FCHMOD: i64 = 91;
374 pub const SYS_UMASK: i64 = 95;
375 pub const SYS_GETRLIMIT: i64 = 97;
376 pub const SYS_SETUID: i64 = 105;
377 pub const SYS_SETGID: i64 = 106;
378 pub const SYS_SETPGID: i64 = 109;
379 pub const SYS_GETGROUPS: i64 = 115;
380 pub const SYS_GETPGID: i64 = 121;
381 pub const SYS_GETSID: i64 = 124;
382 pub const SYS_RT_SIGPENDING: i64 = 127;
383 pub const SYS_RT_SIGTIMEDWAIT: i64 = 128;
384 pub const SYS_RT_SIGSUSPEND: i64 = 130;
385 pub const SYS_SIGALTSTACK: i64 = 131;
386 pub const SYS_SETRLIMIT: i64 = 160;
387 pub const SYS_SETHOSTNAME: i64 = 170;
388 pub const SYS_FUTEX: i64 = 202;
389 pub const SYS_CLOCK_GETTIME: i64 = 228;
390 pub const SYS_CLOCK_GETRES: i64 = 229;
391 pub const SYS_CLOCK_NANOSLEEP: i64 = 230;
392 pub const SYS_EXIT_GROUP: i64 = 231;
393 pub const SYS_TGKILL: i64 = 234;
394 pub const SYS_MKDIRAT: i64 = 258;
395 pub const SYS_NEWFSTATAT: i64 = 262;
396 pub const SYS_UNLINKAT: i64 = 263;
397 pub const SYS_LINKAT: i64 = 265;
398 pub const SYS_SYMLINKAT: i64 = 266;
399 pub const SYS_READLINKAT: i64 = 267;
400 pub const SYS_FCHMODAT: i64 = 268;
401 pub const SYS_SET_ROBUST_LIST: i64 = 273;
402 pub const SYS_UTIMENSAT: i64 = 280;
403 pub const SYS_OPENAT: i64 = 257;
404 pub const SYS_FACCESSAT: i64 = 269;
405 pub const SYS_DUP3: i64 = 292;
406 pub const SYS_PIPE2: i64 = 293;
407 pub const SYS_SYNCFS: i64 = 306;
408 pub const SYS_RENAMEAT2: i64 = 316;
409 pub const SYS_STATFS: i64 = 137;
410 pub const SYS_FSTATFS: i64 = 138;
411 pub const SYS_FDATASYNC: i64 = 75;
412 pub const SYS_PAUSE: i64 = 34;
413 pub const SYS_GETPID: i64 = 39;
414 pub const SYS_FORK: i64 = 57;
415 pub const SYS_EXIT: i64 = 60;
416 pub const SYS_GETPPID: i64 = 110;
417 pub const SYS_SETSID: i64 = 112;
418 pub const SYS_SYNC: i64 = 162;
419 pub const SYS_GETUID: i64 = 102;
420 pub const SYS_GETGID: i64 = 104;
421 pub const SYS_GETEUID: i64 = 107;
422 pub const SYS_GETEGID: i64 = 108;
423 pub const SYS_GETTID: i64 = 186;
424 pub const SYS_CLOCK_SETTIME: i64 = 227;
425 pub const SYS_CLONE: i64 = 56;
426 pub const SYS_PPOLL: i64 = 271;
427 pub const SYS_PREAD64: i64 = 17;
428}
429#[cfg(target_arch = "aarch64")]
430mod sysnr {
431 pub const SYS_READ: i64 = 63;
432 pub const SYS_WRITE: i64 = 64;
433 pub const SYS_CLOSE: i64 = 57;
435 pub const SYS_FSTAT: i64 = 80;
437 pub const SYS_LSEEK: i64 = 62;
438 pub const SYS_MMAP: i64 = 222;
439 pub const SYS_MUNMAP: i64 = 215;
440 pub const SYS_RT_SIGACTION: i64 = 134;
441 pub const SYS_RT_SIGPROCMASK: i64 = 135;
442 pub const SYS_IOCTL: i64 = 29;
443 pub const SYS_SHMGET: i64 = 194;
445 pub const SYS_SHMAT: i64 = 196;
446 pub const SYS_SHMCTL: i64 = 195;
447 pub const SYS_DUP: i64 = 23;
448 pub const SYS_NANOSLEEP: i64 = 101;
449 pub const SYS_SETITIMER: i64 = 103;
450 pub const SYS_SOCKET: i64 = 198;
452 pub const SYS_CONNECT: i64 = 203;
453 pub const SYS_ACCEPT: i64 = 202;
454 pub const SYS_SENDTO: i64 = 206;
455 pub const SYS_RECVFROM: i64 = 207;
456 pub const SYS_SHUTDOWN: i64 = 210;
457 pub const SYS_BIND: i64 = 200;
458 pub const SYS_LISTEN: i64 = 201;
459 pub const SYS_GETSOCKNAME: i64 = 204;
460 pub const SYS_SOCKETPAIR: i64 = 199;
461 pub const SYS_SETSOCKOPT: i64 = 208;
462 pub const SYS_EXECVE: i64 = 221;
463 pub const SYS_WAIT4: i64 = 260;
464 pub const SYS_KILL: i64 = 129;
465 pub const SYS_UNAME: i64 = 160;
466 pub const SYS_SEMGET: i64 = 190;
467 pub const SYS_SEMOP: i64 = 193;
468 pub const SYS_SEMCTL: i64 = 191;
469 pub const SYS_SHMDT: i64 = 197;
470 pub const SYS_MSGGET: i64 = 186;
471 pub const SYS_MSGSND: i64 = 189;
472 pub const SYS_MSGRCV: i64 = 188;
473 pub const SYS_MSGCTL: i64 = 187;
474 pub const SYS_FCNTL: i64 = 25;
475 pub const SYS_FSYNC: i64 = 82;
476 pub const SYS_TRUNCATE: i64 = 45;
477 pub const SYS_FTRUNCATE: i64 = 46;
478 pub const SYS_GETCWD: i64 = 17;
479 pub const SYS_CHDIR: i64 = 49;
480 pub const SYS_FCHMOD: i64 = 52;
482 pub const SYS_UMASK: i64 = 166;
483 pub const SYS_GETRLIMIT: i64 = 163;
484 pub const SYS_SETUID: i64 = 146;
485 pub const SYS_SETGID: i64 = 144;
486 pub const SYS_SETPGID: i64 = 154;
487 pub const SYS_GETGROUPS: i64 = 158;
488 pub const SYS_GETPGID: i64 = 155;
489 pub const SYS_GETSID: i64 = 156;
490 pub const SYS_RT_SIGPENDING: i64 = 136;
491 pub const SYS_RT_SIGTIMEDWAIT: i64 = 137;
492 pub const SYS_RT_SIGSUSPEND: i64 = 133;
493 pub const SYS_SIGALTSTACK: i64 = 132;
494 pub const SYS_SETRLIMIT: i64 = 164;
495 pub const SYS_SETHOSTNAME: i64 = 161;
496 pub const SYS_FUTEX: i64 = 98;
497 pub const SYS_CLOCK_GETTIME: i64 = 113;
498 pub const SYS_CLOCK_GETRES: i64 = 114;
499 pub const SYS_CLOCK_NANOSLEEP: i64 = 115;
500 pub const SYS_EXIT_GROUP: i64 = 94;
501 pub const SYS_TGKILL: i64 = 131;
502 pub const SYS_MKDIRAT: i64 = 34;
503 pub const SYS_NEWFSTATAT: i64 = 79;
504 pub const SYS_UNLINKAT: i64 = 35;
505 pub const SYS_LINKAT: i64 = 37;
506 pub const SYS_SYMLINKAT: i64 = 36;
507 pub const SYS_READLINKAT: i64 = 78;
508 pub const SYS_FCHMODAT: i64 = 53;
509 pub const SYS_SET_ROBUST_LIST: i64 = 99;
510 pub const SYS_UTIMENSAT: i64 = 88;
511 pub const SYS_OPENAT: i64 = 56;
512 pub const SYS_FACCESSAT: i64 = 48;
513 pub const SYS_DUP3: i64 = 24;
514 pub const SYS_PIPE2: i64 = 59;
515 pub const SYS_SYNCFS: i64 = 267;
516 pub const SYS_RENAMEAT2: i64 = 276;
517 pub const SYS_STATFS: i64 = 43;
518 pub const SYS_FSTATFS: i64 = 44;
519 pub const SYS_FDATASYNC: i64 = 83;
520 pub const SYS_GETPID: i64 = 172;
521 pub const SYS_EXIT: i64 = 93;
522 pub const SYS_GETPPID: i64 = 173;
523 pub const SYS_SETSID: i64 = 157;
524 pub const SYS_SYNC: i64 = 81;
525 pub const SYS_GETUID: i64 = 174;
526 pub const SYS_GETGID: i64 = 176;
527 pub const SYS_GETEUID: i64 = 175;
528 pub const SYS_GETEGID: i64 = 177;
529 pub const SYS_GETTID: i64 = 178;
530 pub const SYS_CLOCK_SETTIME: i64 = 112;
531 pub const SYS_CLONE: i64 = 220;
532 pub const SYS_PPOLL: i64 = 73;
533 pub const SYS_PREAD64: i64 = 67;
534}
535pub use sysnr::*;
536
537#[inline]
542unsafe fn sys_write(fd: i64, buf: *const u8, count: usize) -> i64 {
543 <Arch as Syscalls>::syscall3(SYS_WRITE, fd as i64, buf as i64, count as i64)
544}
545
546#[inline]
547unsafe fn sys_read(fd: i64, buf: *mut u8, count: usize) -> i64 {
548 <Arch as Syscalls>::syscall3(SYS_READ, fd as i64, buf as i64, count as i64)
549}
550
551#[inline]
552unsafe fn sys_open(path: *const u8, flags: i64, mode: i64) -> i64 {
553 <Arch as Syscalls>::syscall4(SYS_OPENAT, AT_FDCWD as i64, path as i64, flags as i64, mode as i64)
554}
555
556#[inline]
557unsafe fn sys_close(fd: i64) {
558 let _ = <Arch as Syscalls>::syscall1(SYS_CLOSE, fd as i64);
559}
560
561#[inline]
562unsafe fn sys_lseek(fd: i64, offset: i64, whence: i64) -> i64 {
563 <Arch as Syscalls>::syscall3(SYS_LSEEK, fd as i64, offset as i64, whence as i64)
564}
565
566unsafe fn sys_mmap(
567 addr: *mut u8,
568 length: usize,
569 prot: i32,
570 flags: i32,
571 fd: i32,
572 offset: i64,
573) -> *mut u8 {
574 let result = <Arch as Syscalls>::syscall6(SYS_MMAP, addr as i64, length as i64, prot as i64, flags as i64, fd as i64, offset);
575 if result < 0 && result > -4096 {
576 ERRNO = (-result) as c_int;
577 return MMAP_FAILED;
578 }
579 result as *mut u8
580}
581
582unsafe fn sys_munmap(addr: *mut u8, length: usize) -> i64 {
583 <Arch as Syscalls>::syscall2(SYS_MUNMAP, addr as i64, length as i64)
584}
585
586#[no_mangle]
591pub unsafe extern "C" fn strlen(s: *const c_char) -> usize {
592 let s = s as *const u8;
593 let mut len = 0;
594 while *s.add(len) != 0 {
595 len += 1;
596 }
597 len
598}
599
600#[no_mangle]
601pub unsafe extern "C" fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
602 let dst = dst as *mut u8;
603 let src = src as *const u8;
604 let mut i = 0;
605 while i < n {
606 *dst.add(i) = *src.add(i);
607 i += 1;
608 }
609 dst as *mut c_void
610}
611
612#[no_mangle]
613pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void {
614 let s = s as *mut u8;
615 let mut i = 0;
616 while i < n {
617 *s.add(i) = c as u8;
618 i += 1;
619 }
620 s as *mut c_void
621}
622
623#[no_mangle]
624pub unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
625 let dst = dst as *mut u8;
626 let src = src as *const u8;
627 if (dst as usize) < (src as usize) {
628 let mut i = 0;
629 while i < n {
630 *dst.add(i) = *src.add(i);
631 i += 1;
632 }
633 } else {
634 let mut i = n;
635 while i > 0 {
636 i -= 1;
637 *dst.add(i) = *src.add(i);
638 }
639 }
640 dst as *mut c_void
641}
642
643#[no_mangle]
644pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
645 let s1 = s1 as *const u8;
646 let s2 = s2 as *const u8;
647 let mut i = 0;
648 while i < n {
649 let a = *s1.add(i);
650 let b = *s2.add(i);
651 if a != b {
652 return a as c_int - b as c_int;
653 }
654 i += 1;
655 }
656 0
657}
658
659#[no_mangle]
660pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
661 memcmp(s1, s2, n)
662}
663
664#[no_mangle]
665pub unsafe extern "C" fn strcmp(s1: *const u8, s2: *const u8) -> c_int {
666 let mut i = 0;
667 loop {
668 let a = *s1.add(i);
669 let b = *s2.add(i);
670 if a != b {
671 return a as c_int - b as c_int;
672 }
673 if a == 0 {
674 return 0;
675 }
676 i += 1;
677 }
678}
679
680#[no_mangle]
681pub unsafe extern "C" fn strncmp(s1: *const u8, s2: *const u8, n: usize) -> c_int {
682 let mut i = 0;
683 while i < n {
684 let a = *s1.add(i);
685 let b = *s2.add(i);
686 if a != b {
687 return a as c_int - b as c_int;
688 }
689 if a == 0 {
690 return 0;
691 }
692 i += 1;
693 }
694 0
695}
696
697#[no_mangle]
698pub unsafe extern "C" fn strcpy(dst: *mut u8, src: *const u8) -> *mut u8 {
699 let mut i = 0;
700 loop {
701 let c = *src.add(i);
702 *dst.add(i) = c;
703 if c == 0 {
704 break;
705 }
706 i += 1;
707 }
708 dst
709}
710
711#[no_mangle]
712pub unsafe extern "C" fn strncpy(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
713 let mut i = 0;
714 while i < n && *src.add(i) != 0 {
715 *dst.add(i) = *src.add(i);
716 i += 1;
717 }
718 while i < n {
719 *dst.add(i) = 0;
720 i += 1;
721 }
722 dst
723}
724
725#[no_mangle]
726pub unsafe extern "C" fn strcat(dst: *mut u8, src: *const u8) -> *mut u8 {
727 let mut i = 0;
728 while *dst.add(i) != 0 {
729 i += 1;
730 }
731 let mut j = 0;
732 loop {
733 let c = *src.add(j);
734 *dst.add(i + j) = c;
735 if c == 0 {
736 break;
737 }
738 j += 1;
739 }
740 dst
741}
742
743#[no_mangle]
744pub unsafe extern "C" fn strncat(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
745 let mut i = 0;
746 while *dst.add(i) != 0 {
747 i += 1;
748 }
749 let mut j = 0;
750 while j < n && *src.add(j) != 0 {
751 *dst.add(i + j) = *src.add(j);
752 j += 1;
753 }
754 *dst.add(i + j) = 0;
755 dst
756}
757
758#[no_mangle]
759pub unsafe extern "C" fn strlcpy(dst: *mut u8, src: *const u8, n: usize) -> usize {
760 let l = strlen(src as *const c_char);
761 if n > 0 {
762 let c = if l < n { l } else { n - 1 };
763 core::ptr::copy_nonoverlapping(src, dst, c);
764 *dst.add(c) = 0;
765 }
766 l
767}
768
769#[no_mangle]
770pub unsafe extern "C" fn strlcat(dst: *mut u8, src: *const u8, n: usize) -> usize {
771 let dl = strlen(dst as *const c_char);
772 let sl = strlen(src as *const c_char);
773 if dl >= n { return n + sl; }
774 let c = if sl < n - dl { sl } else { n - dl - 1 };
775 core::ptr::copy_nonoverlapping(src, dst.add(dl), c);
776 *dst.add(dl + c) = 0;
777 dl + sl
778}
779
780#[no_mangle]
781pub unsafe extern "C" fn strchr(s: *const u8, c: c_int) -> *mut u8 {
782 let target = c as u8;
783 let mut i = 0;
784 loop {
785 let ch = *s.add(i);
786 if ch == target {
787 return s.add(i) as *mut u8;
788 }
789 if ch == 0 {
790 return null_mut();
791 }
792 i += 1;
793 }
794}
795
796#[no_mangle]
797pub unsafe extern "C" fn strrchr(s: *const u8, c: c_int) -> *mut u8 {
798 let target = c as u8;
799 let mut i = 0;
800 let mut last: *mut u8 = null_mut();
801 loop {
802 let ch = *s.add(i);
803 if ch == target {
804 last = s.add(i) as *mut u8;
805 }
806 if ch == 0 {
807 return last;
808 }
809 i += 1;
810 }
811}
812
813#[no_mangle]
814pub unsafe extern "C" fn strnlen(s: *const u8, maxlen: usize) -> usize {
815 let mut i = 0;
816 while i < maxlen && *s.add(i) != 0 {
817 i += 1;
818 }
819 i
820}
821
822#[no_mangle]
823pub unsafe extern "C" fn strcspn(s: *const u8, reject: *const u8) -> usize {
824 let mut i = 0;
825 loop {
826 let c = *s.add(i);
827 if c == 0 {
828 return i;
829 }
830 let mut j = 0;
831 loop {
832 let r = *reject.add(j);
833 if r == 0 {
834 break;
835 }
836 if c == r {
837 return i;
838 }
839 j += 1;
840 }
841 i += 1;
842 }
843}
844
845#[no_mangle]
846pub unsafe extern "C" fn strspn(s: *const u8, accept: *const u8) -> usize {
847 let mut i = 0;
848 loop {
849 let c = *s.add(i);
850 if c == 0 {
851 return i;
852 }
853 let mut found = false;
854 let mut j = 0;
855 loop {
856 let a = *accept.add(j);
857 if a == 0 {
858 break;
859 }
860 if c == a {
861 found = true;
862 break;
863 }
864 j += 1;
865 }
866 if !found {
867 return i;
868 }
869 i += 1;
870 }
871}
872
873#[no_mangle]
874pub unsafe extern "C" fn strpbrk(s: *const u8, accept: *const u8) -> *mut u8 {
875 let mut i = 0;
876 loop {
877 let c = *s.add(i);
878 if c == 0 {
879 return null_mut();
880 }
881 let mut j = 0;
882 loop {
883 let a = *accept.add(j);
884 if a == 0 {
885 break;
886 }
887 if c == a {
888 return s.add(i) as *mut u8;
889 }
890 j += 1;
891 }
892 i += 1;
893 }
894}
895
896#[no_mangle]
897pub unsafe extern "C" fn strstr(haystack: *const u8, needle: *const u8) -> *mut u8 {
898 if *needle == 0 {
899 return haystack as *mut u8;
900 }
901 let mut i = 0;
902 loop {
903 let h = *haystack.add(i);
904 if h == 0 {
905 return null_mut();
906 }
907 if h == *needle {
908 let mut j = 0;
909 loop {
910 let n = *needle.add(j);
911 if n == 0 {
912 return haystack.add(i) as *mut u8;
913 }
914 if *haystack.add(i + j) != n {
915 break;
916 }
917 j += 1;
918 }
919 }
920 i += 1;
921 }
922}
923
924#[no_mangle]
925pub unsafe extern "C" fn memchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
926 let target = c as u8;
927 let mut i = 0;
928 while i < n {
929 if *s.add(i) == target {
930 return s.add(i) as *mut u8;
931 }
932 i += 1;
933 }
934 null_mut()
935}
936
937#[no_mangle]
938pub unsafe extern "C" fn memrchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
939 let target = c as u8;
940 let mut i = n;
941 while i > 0 {
942 i -= 1;
943 if *s.add(i) == target {
944 return s.add(i) as *mut u8;
945 }
946 }
947 null_mut()
948}
949
950#[no_mangle]
951pub unsafe extern "C" fn memmem(
952 haystack: *const c_void, haystacklen: usize,
953 needle: *const c_void, needlelen: usize,
954) -> *mut c_void {
955 if needlelen == 0 { return haystack as *mut c_void; }
956 if haystacklen < needlelen { return null_mut(); }
957 let h = haystack as *const u8;
958 let n = needle as *const u8;
959 let last = haystacklen - needlelen;
960 for i in 0..=last {
961 if *h.add(i) == *n && memcmp(h.add(i) as *const c_void, n as *const c_void, needlelen) == 0 {
962 return h.add(i) as *mut c_void;
963 }
964 }
965 null_mut()
966}
967
968#[no_mangle]
969pub unsafe extern "C" fn strtok(s: *mut u8, delim: *const u8) -> *mut u8 {
970 static mut STATE: *mut u8 = core::ptr::null_mut();
971 let mut p = if s.is_null() { STATE } else { s };
972 if p.is_null() {
973 return core::ptr::null_mut();
974 }
975 loop {
976 let c = *p;
977 if c == 0 {
978 STATE = core::ptr::null_mut();
979 return core::ptr::null_mut();
980 }
981 let mut is_delim = false;
982 let mut i = 0;
983 loop {
984 let d = *delim.add(i);
985 if d == 0 {
986 break;
987 }
988 if c == d {
989 is_delim = true;
990 break;
991 }
992 i += 1;
993 }
994 if !is_delim {
995 break;
996 }
997 p = p.add(1);
998 }
999 let start = p;
1000 loop {
1001 let c = *p;
1002 if c == 0 {
1003 STATE = core::ptr::null_mut();
1004 return start;
1005 }
1006 let mut is_delim = false;
1007 let mut i = 0;
1008 loop {
1009 let d = *delim.add(i);
1010 if d == 0 {
1011 break;
1012 }
1013 if c == d {
1014 is_delim = true;
1015 break;
1016 }
1017 i += 1;
1018 }
1019 if is_delim {
1020 *p = 0;
1021 STATE = p.add(1);
1022 return start;
1023 }
1024 p = p.add(1);
1025 }
1026}
1027
1028type SizeT = usize;
1033type SSizeT = isize;
1034type mode_t = c_uint;
1035type TimeT = c_long;
1036type ClockT = c_long;
1037type wchar_t = c_int;
1038type wint_t = c_uint;
1039type wctype_t = *const c_int;
1040type wctrans_t = *const c_int;
1041
1042const WEOF: wint_t = 0xffffffff;
1043
1044#[repr(C)]
1045pub struct tm {
1046 pub tm_sec: c_int,
1047 pub tm_min: c_int,
1048 pub tm_hour: c_int,
1049 pub tm_mday: c_int,
1050 pub tm_mon: c_int,
1051 pub tm_year: c_int,
1052 pub tm_wday: c_int,
1053 pub tm_yday: c_int,
1054 pub tm_isdst: c_int,
1055 pub tm_gmtoff: c_long,
1056 pub tm_zone: *const c_char,
1057}
1058
1059#[repr(C)]
1060pub struct timeval {
1061 pub tv_sec: TimeT,
1062 pub tv_usec: c_long,
1063}
1064
1065const CT_UPPER: u8 = 1 << 0;
1070const CT_LOWER: u8 = 1 << 1;
1071const CT_DIGIT: u8 = 1 << 2;
1072const CT_SPACE: u8 = 1 << 3;
1073const CT_PUNCT: u8 = 1 << 4;
1074const CT_CNTRL: u8 = 1 << 5;
1075const CT_BLANK: u8 = 1 << 6;
1076const CT_XDIGIT: u8 = 1 << 7;
1077
1078const CT_TABLE: [u8; 128] = {
1079 let mut t = [0u8; 128];
1080 let mut i = 0;
1081 while i < 128 {
1082 let c = i as u8;
1083 let mut flags = 0u8;
1084 if c >= b'A' && c <= b'Z' {
1085 flags |= CT_UPPER;
1086 }
1087 if c >= b'a' && c <= b'z' {
1088 flags |= CT_LOWER;
1089 }
1090 if c >= b'0' && c <= b'9' {
1091 flags |= CT_DIGIT;
1092 }
1093 if c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == b'\x0c' || c == b'\x0b' {
1094 flags |= CT_SPACE;
1095 }
1096 if (c >= b'!' && c <= b'/')
1097 || (c >= b':' && c <= b'@')
1098 || (c >= b'[' && c <= b'`')
1099 || (c >= b'{' && c <= b'~')
1100 {
1101 flags |= CT_PUNCT;
1102 }
1103 if c < 0x20 || c == 0x7f {
1104 flags |= CT_CNTRL;
1105 }
1106 if c == b' ' || c == b'\t' {
1107 flags |= CT_BLANK;
1108 }
1109 if (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'F') || (c >= b'a' && c <= b'f') {
1110 flags |= CT_XDIGIT;
1111 }
1112 t[i] = flags;
1113 i += 1;
1114 }
1115 t
1116};
1117
1118#[inline]
1119fn ct_flags(c: c_int) -> u8 {
1120 if c < 0 || c > 127 {
1121 0
1122 } else {
1123 CT_TABLE[c as usize]
1124 }
1125}
1126
1127#[no_mangle]
1128pub extern "C" fn isalnum(c: c_int) -> c_int {
1129 (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT) != 0) as c_int
1130}
1131
1132#[no_mangle]
1133pub extern "C" fn isalpha(c: c_int) -> c_int {
1134 (ct_flags(c) & (CT_UPPER | CT_LOWER) != 0) as c_int
1135}
1136
1137#[no_mangle]
1138pub extern "C" fn isascii(c: c_int) -> c_int {
1139 ((c as u32) <= 127) as c_int
1140}
1141
1142#[no_mangle]
1143pub extern "C" fn isblank(c: c_int) -> c_int {
1144 (ct_flags(c) & CT_BLANK != 0) as c_int
1145}
1146
1147#[no_mangle]
1148pub extern "C" fn iscntrl(c: c_int) -> c_int {
1149 (ct_flags(c) & CT_CNTRL != 0) as c_int
1150}
1151
1152#[no_mangle]
1153pub extern "C" fn isdigit(c: c_int) -> c_int {
1154 (ct_flags(c) & CT_DIGIT != 0) as c_int
1155}
1156
1157#[no_mangle]
1158pub extern "C" fn isgraph(c: c_int) -> c_int {
1159 (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT) != 0) as c_int
1160}
1161
1162#[no_mangle]
1163pub extern "C" fn islower(c: c_int) -> c_int {
1164 (ct_flags(c) & CT_LOWER != 0) as c_int
1165}
1166
1167#[no_mangle]
1168pub extern "C" fn isprint(c: c_int) -> c_int {
1169 let flags = ct_flags(c);
1170 (flags & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT | CT_BLANK) != 0) as c_int
1171}
1172
1173#[no_mangle]
1174pub extern "C" fn ispunct(c: c_int) -> c_int {
1175 (ct_flags(c) & CT_PUNCT != 0) as c_int
1176}
1177
1178#[no_mangle]
1179pub extern "C" fn isspace(c: c_int) -> c_int {
1180 (ct_flags(c) & CT_SPACE != 0) as c_int
1181}
1182
1183#[no_mangle]
1184pub extern "C" fn isupper(c: c_int) -> c_int {
1185 (ct_flags(c) & CT_UPPER != 0) as c_int
1186}
1187
1188#[no_mangle]
1189pub extern "C" fn isxdigit(c: c_int) -> c_int {
1190 (ct_flags(c) & CT_XDIGIT != 0) as c_int
1191}
1192
1193#[no_mangle]
1194pub extern "C" fn tolower(c: c_int) -> c_int {
1195 if (ct_flags(c) & CT_UPPER) != 0 {
1196 c + (b'a' as c_int - b'A' as c_int)
1197 } else {
1198 c
1199 }
1200}
1201
1202#[no_mangle]
1203pub extern "C" fn toupper(c: c_int) -> c_int {
1204 if (ct_flags(c) & CT_LOWER) != 0 {
1205 c - (b'a' as c_int - b'A' as c_int)
1206 } else {
1207 c
1208 }
1209}
1210
1211unsafe fn parse_digit(c: u8, base: c_int) -> Option<u8> {
1216 if c == 0 { return None; }
1217 let d = if c >= b'0' && c <= b'9' {
1218 c - b'0'
1219 } else if c >= b'a' && c <= b'z' {
1220 c - b'a' + 10
1221 } else if c >= b'A' && c <= b'Z' {
1222 c - b'A' + 10
1223 } else {
1224 return None;
1225 };
1226 if (d as c_int) < base {
1227 Some(d)
1228 } else {
1229 None
1230 }
1231}
1232
1233unsafe fn parse_prefix(s: *const u8, base: *mut c_int) -> *const u8 {
1234 let mut p = s;
1235 if *base == 0 {
1236 if *p == b'0' {
1237 if (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1238 *base = 16;
1239 p = p.add(2);
1240 } else {
1241 *base = 8;
1242 }
1243 } else {
1244 *base = 10;
1245 }
1246 } else if *base == 16 {
1247 if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1248 p = p.add(2);
1249 }
1250 }
1251 p
1252}
1253
1254unsafe fn strtox(
1255 s: *const c_char,
1256 endptr: *mut *mut c_char,
1257 mut base: c_int,
1258 pos_limit: u64,
1259 neg_limit: u64,
1260) -> (u64, bool, bool) {
1261 let s0 = s as *const u8;
1262 let mut p = s0;
1263 while isspace(*p as c_int) != 0 {
1264 p = p.add(1);
1265 }
1266
1267 if base < 0 || base == 1 || base > 36 {
1268 if !endptr.is_null() {
1269 *endptr = s as *mut c_char;
1270 }
1271 ERRNO = EINVAL;
1272 return (0, false, false);
1273 }
1274
1275 let mut neg = false;
1276 match *p {
1277 b'-' => { neg = true; p = p.add(1); }
1278 b'+' => p = p.add(1),
1279 _ => {}
1280 }
1281
1282 p = parse_prefix(p, &mut base);
1283
1284 let limit = if neg { neg_limit } else { pos_limit };
1285 let mut val: u64 = 0;
1286 let mut any = false;
1287 while let Some(d) = parse_digit(*p, base) {
1288 any = true;
1289 if val > (limit - d as u64) / base as u64 {
1290 while parse_digit(*p, base).is_some() { p = p.add(1); }
1291 if !endptr.is_null() { *endptr = p as *mut c_char; }
1292 ERRNO = ERANGE_VAL;
1293 return (limit, true, neg);
1294 }
1295 val = val * base as u64 + d as u64;
1296 p = p.add(1);
1297 }
1298
1299 if !endptr.is_null() {
1300 *endptr = if any { p as *mut c_char } else { s as *mut c_char };
1301 }
1302 (val, false, neg)
1303}
1304
1305#[no_mangle]
1306pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
1307 let pos_limit = c_long::MAX as u64;
1308 let neg_limit = pos_limit.wrapping_add(1);
1309 let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1310 if overflow {
1311 return if neg { c_long::MIN } else { c_long::MAX };
1312 }
1313 if neg { val.wrapping_neg() as c_long } else { val as c_long }
1314}
1315
1316#[no_mangle]
1317pub unsafe extern "C" fn strtoul(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong {
1318 let limit = c_ulong::MAX as u64;
1319 let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1320 if overflow {
1321 return c_ulong::MAX;
1322 }
1323 if neg { val.wrapping_neg() as c_ulong } else { val as c_ulong }
1324}
1325
1326#[no_mangle]
1327pub unsafe extern "C" fn strtoll(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_longlong {
1328 let pos_limit = c_longlong::MAX as u64;
1329 let neg_limit = pos_limit.wrapping_add(1);
1330 let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1331 if overflow {
1332 return if neg { c_longlong::MIN } else { c_longlong::MAX };
1333 }
1334 if neg { val.wrapping_neg() as c_longlong } else { val as c_longlong }
1335}
1336
1337#[no_mangle]
1338pub unsafe extern "C" fn strtoull(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulonglong {
1339 let limit = c_ulonglong::MAX as u64;
1340 let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1341 if overflow {
1342 return c_ulonglong::MAX;
1343 }
1344 if neg { val.wrapping_neg() as c_ulonglong } else { val as c_ulonglong }
1345}
1346
1347#[no_mangle]
1348pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
1349 strtol(s, core::ptr::null_mut(), 10) as c_int
1350}
1351
1352#[no_mangle]
1353pub unsafe extern "C" fn atol(s: *const c_char) -> c_long {
1354 strtol(s, core::ptr::null_mut(), 10)
1355}
1356
1357#[no_mangle]
1358pub unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
1359 strtoll(s, core::ptr::null_mut(), 10)
1360}
1361
1362#[no_mangle]
1363pub extern "C" fn abs(n: c_int) -> c_int {
1364 if n < 0 {
1365 -n
1366 } else {
1367 n
1368 }
1369}
1370
1371#[no_mangle]
1372pub extern "C" fn labs(n: c_long) -> c_long {
1373 if n < 0 {
1374 -n
1375 } else {
1376 n
1377 }
1378}
1379
1380#[no_mangle]
1381pub extern "C" fn llabs(n: c_longlong) -> c_longlong {
1382 if n < 0 {
1383 -n
1384 } else {
1385 n
1386 }
1387}
1388
1389static mut RAND_STATE: c_uint = 1;
1390
1391#[no_mangle]
1392pub extern "C" fn srand(seed: c_uint) {
1393 unsafe {
1394 RAND_STATE = seed;
1395 }
1396}
1397
1398#[no_mangle]
1399pub extern "C" fn rand() -> c_int {
1400 unsafe {
1401 RAND_STATE = RAND_STATE.wrapping_mul(1103515245).wrapping_add(12345);
1402 ((RAND_STATE >> 16) & 0x7fff) as c_int
1403 }
1404}
1405
1406#[repr(C)]
1411pub struct div_t { pub quot: c_int, pub rem: c_int }
1412#[repr(C)]
1413pub struct ldiv_t { pub quot: c_long, pub rem: c_long }
1414#[repr(C)]
1415pub struct lldiv_t { pub quot: c_longlong, pub rem: c_longlong }
1416
1417#[no_mangle]
1418pub extern "C" fn div(num: c_int, den: c_int) -> div_t {
1419 div_t { quot: num / den, rem: num % den }
1420}
1421
1422#[no_mangle]
1423pub extern "C" fn ldiv(num: c_long, den: c_long) -> ldiv_t {
1424 ldiv_t { quot: num / den, rem: num % den }
1425}
1426
1427#[no_mangle]
1428pub extern "C" fn lldiv(num: c_longlong, den: c_longlong) -> lldiv_t {
1429 lldiv_t { quot: num / den, rem: num % den }
1430}
1431
1432type CmpFn = unsafe extern "C" fn(*const c_void, *const c_void) -> c_int;
1437
1438#[no_mangle]
1439pub unsafe extern "C" fn bsearch(
1440 key: *const c_void,
1441 base: *const c_void,
1442 nel: usize,
1443 width: usize,
1444 cmp: CmpFn,
1445) -> *mut c_void {
1446 let mut base = base as *const u8;
1447 let mut nel = nel;
1448 while nel > 0 {
1449 let trial = base.add(width * (nel / 2));
1450 let sign = cmp(key, trial as *const c_void);
1451 if sign < 0 {
1452 nel /= 2;
1453 } else if sign > 0 {
1454 base = trial.add(width);
1455 nel -= nel / 2 + 1;
1456 } else {
1457 return trial as *mut c_void;
1458 }
1459 }
1460 null_mut()
1461}
1462
1463pub const SA_RESTORER: c_ulong = 0x04000000;
1468
1469pub const SIG_DFL: usize = 0;
1470pub const SIG_IGN: usize = 1;
1471pub const SIG_ERR: usize = !0usize;
1472
1473pub const SIGHUP: c_int = 1;
1474pub const SIGINT: c_int = 2;
1475pub const SIGQUIT: c_int = 3;
1476pub const SIGILL: c_int = 4;
1477pub const SIGTRAP: c_int = 5;
1478pub const SIGABRT: c_int = 6;
1479pub const SIGIOT: c_int = 6;
1480pub const SIGBUS: c_int = 7;
1481pub const SIGFPE: c_int = 8;
1482pub const SIGKILL: c_int = 9;
1483pub const SIGUSR1: c_int = 10;
1484pub const SIGSEGV: c_int = 11;
1485pub const SIGUSR2: c_int = 12;
1486pub const SIGPIPE: c_int = 13;
1487pub const SIGALRM: c_int = 14;
1488pub const SIGTERM: c_int = 15;
1489pub const SIGSTKFLT: c_int = 16;
1490pub const SIGCHLD: c_int = 17;
1491pub const SIGCONT: c_int = 18;
1492pub const SIGSTOP: c_int = 19;
1493pub const SIGTSTP: c_int = 20;
1494pub const SIGTTIN: c_int = 21;
1495pub const SIGTTOU: c_int = 22;
1496pub const SIGURG: c_int = 23;
1497pub const SIGXCPU: c_int = 24;
1498pub const SIGXFSZ: c_int = 25;
1499pub const SIGVTALRM: c_int = 26;
1500pub const SIGPROF: c_int = 27;
1501pub const SIGWINCH: c_int = 28;
1502pub const SIGIO: c_int = 29;
1503pub const SIGPOLL: c_int = 29;
1504pub const SIGPWR: c_int = 30;
1505pub const SIGSYS: c_int = 31;
1506pub const SIGUNUSED: c_int = 31;
1507pub const _NSIG: c_int = 65;
1508
1509pub const SIG_BLOCK: c_int = 0;
1510pub const SIG_UNBLOCK: c_int = 1;
1511pub const SIG_SETMASK: c_int = 2;
1512
1513pub const SA_NOCLDSTOP: c_ulong = 1;
1514pub const SA_NOCLDWAIT: c_ulong = 2;
1515pub const SA_SIGINFO: c_ulong = 4;
1516pub const SA_ONSTACK: c_ulong = 0x08000000;
1517pub const SA_RESTART: c_ulong = 0x10000000;
1518pub const SA_NODEFER: c_ulong = 0x40000000;
1519pub const SA_RESETHAND: c_ulong = 0x80000000;
1520
1521pub const SS_ONSTACK: c_int = 1;
1522pub const SS_DISABLE: c_int = 2;
1523pub const MINSIGSTKSZ: usize = 2048;
1524pub const SIGSTKSZ: usize = 8192;
1525
1526pub const SI_USER: c_int = 0;
1527pub const SI_TKILL: c_int = -6;
1528
1529#[repr(C)]
1530pub struct timespec {
1531 pub tv_sec: c_long,
1532 pub tv_nsec: c_long,
1533}
1534
1535#[repr(C)]
1536pub struct siginfo_t {
1537 pub si_signo: c_int,
1538 pub si_errno: c_int,
1539 pub si_code: c_int,
1540 _pad: [u8; 128 - 3 * core::mem::size_of::<c_int>()],
1542}
1543
1544#[repr(C)]
1545pub struct stack_t {
1546 pub ss_sp: *mut c_void,
1547 pub ss_flags: c_int,
1548 pub ss_size: usize,
1549}
1550
1551#[repr(C)]
1552pub struct sigaction {
1553 pub sa_handler: usize,
1554 pub sa_flags: c_ulong,
1555 pub sa_restorer: usize,
1556 pub sa_mask: [c_ulong; 1],
1557}
1558
1559pub type SigSetT = c_ulong;
1560
1561#[cfg(target_arch = "x86_64")]
1562core::arch::global_asm!(
1563 ".global sig_restorer",
1564 ".type sig_restorer, @function",
1565 "sig_restorer:",
1566 "mov eax, 15",
1567 "syscall",
1568);
1569
1570#[cfg(target_arch = "aarch64")]
1571core::arch::global_asm!(
1572 ".global sig_restorer",
1573 ".type sig_restorer, @function",
1574 "sig_restorer:",
1575 "mov x8, #139",
1576 "svc #0",
1577);
1578
1579extern "C" {
1580 fn sig_restorer();
1581}
1582
1583#[inline]
1584unsafe fn sys_rt_sigaction(sig: c_int,
1585 act: *const sigaction,
1586 oldact: *mut sigaction,
1587 sigsetsize: usize,) -> i64 {
1588 <Arch as Syscalls>::syscall4(SYS_RT_SIGACTION, sig as i64, act as i64, oldact as i64, sigsetsize as i64)
1589}
1590
1591#[inline]
1592unsafe fn sys_rt_sigprocmask(how: c_int,
1593 set: *const SigSetT,
1594 oldset: *mut SigSetT,
1595 sigsetsize: usize,) -> i64 {
1596 <Arch as Syscalls>::syscall4(SYS_RT_SIGPROCMASK, how as i64, set as i64, oldset as i64, sigsetsize as i64)
1597}
1598
1599#[inline]
1600unsafe fn sys_rt_sigpending(set: *mut SigSetT, sigsetsize: usize) -> i64 {
1601 <Arch as Syscalls>::syscall2(SYS_RT_SIGPENDING, set as i64, sigsetsize as i64)
1602}
1603
1604#[inline]
1605unsafe fn sys_rt_sigsuspend(mask: *const SigSetT, sigsetsize: usize) -> i64 {
1606 <Arch as Syscalls>::syscall2(SYS_RT_SIGSUSPEND, mask as i64, sigsetsize as i64)
1607}
1608
1609#[inline]
1610unsafe fn sys_rt_sigtimedwait(set: *const SigSetT,
1611 info: *mut siginfo_t,
1612 timeout: *const timespec,
1613 sigsetsize: usize,) -> i64 {
1614 <Arch as Syscalls>::syscall4(SYS_RT_SIGTIMEDWAIT, set as i64, info as i64, timeout as i64, sigsetsize as i64)
1615}
1616
1617#[inline]
1618unsafe fn sys_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> i64 {
1619 <Arch as Syscalls>::syscall2(SYS_SIGALTSTACK, ss as i64, old_ss as i64)
1620}
1621
1622#[inline]
1623unsafe fn sys_tgkill(tgid: c_int, tid: c_int, sig: c_int) -> i64 {
1624 <Arch as Syscalls>::syscall3(SYS_TGKILL, tgid as i64, tid as i64, sig as i64)
1625}
1626
1627const CLOCK_REALTIME: c_int = 0;
1628const CLOCK_MONOTONIC: c_int = 1;
1629
1630#[inline]
1631unsafe fn sys_clock_gettime(clockid: c_int, ts: *mut timespec) -> i64 {
1632 <Arch as Syscalls>::syscall2(SYS_CLOCK_GETTIME, clockid as i64, ts as i64)
1633}
1634
1635#[no_mangle]
1636pub unsafe extern "C" fn clock_gettime(clockid: c_int, ts: *mut timespec) -> c_int {
1637 if sys_clock_gettime(clockid, ts) < 0 { -1 } else { 0 }
1638}
1639
1640#[no_mangle]
1641pub unsafe extern "C" fn sigprocmask(
1642 how: c_int,
1643 set: *const SigSetT,
1644 oldset: *mut SigSetT,
1645) -> c_int {
1646 let internal_mask: SigSetT = (1u64 << 31) | (1u64 << 32);
1648 let filtered: SigSetT;
1649 let set_ptr: *const SigSetT = if set.is_null() {
1650 set
1651 } else {
1652 filtered = *set & !internal_mask;
1653 &filtered
1654 };
1655 let r = sys_rt_sigprocmask(how, set_ptr, oldset, core::mem::size_of::<SigSetT>());
1656 if !oldset.is_null() {
1657 *oldset &= !internal_mask;
1658 }
1659 if r < 0 { -1 } else { 0 }
1660}
1661
1662#[inline]
1663unsafe fn sys_kill(pid: c_int, sig: c_int) -> i64 {
1664 <Arch as Syscalls>::syscall2(SYS_KILL, pid as i64, sig as i64)
1665}
1666
1667#[inline]
1668unsafe fn sys_getpid() -> i64 {
1669 <Arch as Syscalls>::syscall0(SYS_GETPID)
1670}
1671
1672#[no_mangle]
1673pub unsafe extern "C" fn sigaction(
1674 signum: c_int,
1675 act: *const sigaction,
1676 oldact: *mut sigaction,
1677) -> c_int {
1678 let kact: sigaction;
1679 let act_ptr = if act.is_null() {
1680 core::ptr::null()
1681 } else {
1682 kact = sigaction {
1683 sa_handler: (*act).sa_handler,
1684 sa_flags: (*act).sa_flags | SA_RESTORER,
1685 sa_restorer: sig_restorer as *const () as usize,
1686 sa_mask: (*act).sa_mask,
1687 };
1688 &kact as *const sigaction
1689 };
1690 let r = sys_rt_sigaction(signum, act_ptr, oldact, core::mem::size_of::<SigSetT>());
1691 if r < 0 {
1692 ERRNO = (-r) as c_int;
1693 -1
1694 } else {
1695 0
1696 }
1697}
1698
1699#[no_mangle]
1700pub unsafe extern "C" fn signal(signum: c_int, handler: usize) -> usize {
1701 let act = sigaction {
1702 sa_handler: handler,
1703 sa_flags: SA_RESTORER,
1704 sa_restorer: sig_restorer as *const () as usize,
1705 sa_mask: [0],
1706 };
1707 let mut old = sigaction {
1708 sa_handler: 0,
1709 sa_flags: 0,
1710 sa_restorer: 0,
1711 sa_mask: [0],
1712 };
1713 if sigaction(signum, &act, &mut old) == -1 {
1714 SIG_ERR
1715 } else {
1716 old.sa_handler
1717 }
1718}
1719
1720#[no_mangle]
1721pub unsafe extern "C" fn kill(pid: c_int, sig: c_int) -> c_int {
1722 sys_kill(pid, sig) as c_int
1723}
1724
1725#[no_mangle]
1726pub unsafe extern "C" fn tgkill(tgid: c_int, tid: c_int, sig: c_int) -> c_int {
1727 if sys_tgkill(tgid, tid, sig) < 0 { -1 } else { 0 }
1728}
1729
1730#[no_mangle]
1731pub unsafe extern "C" fn getpid() -> c_int {
1732 sys_getpid() as c_int
1733}
1734
1735#[no_mangle]
1736pub unsafe extern "C" fn raise(sig: c_int) -> c_int {
1737 if sys_tgkill(sys_getpid() as c_int, sys_gettid() as c_int, sig) < 0 {
1738 -1
1739 } else {
1740 0
1741 }
1742}
1743
1744#[no_mangle]
1745pub unsafe extern "C" fn sigemptyset(set: *mut SigSetT) -> c_int {
1746 *set = 0;
1747 0
1748}
1749
1750#[no_mangle]
1751pub unsafe extern "C" fn sigfillset(set: *mut SigSetT) -> c_int {
1752 *set = 0xFFFF_FFFC_7FFF_FFFFu64;
1754 0
1755}
1756
1757#[no_mangle]
1758pub unsafe extern "C" fn sigaddset(set: *mut SigSetT, signum: c_int) -> c_int {
1759 let s = (signum as c_uint).wrapping_sub(1);
1760 if s as usize >= 64 {
1761 ERRNO = EINVAL;
1762 return -1;
1763 }
1764 if signum >= 32 && signum < __libc_current_sigrtmin() {
1766 return 0;
1767 }
1768 *set |= 1u64 << s;
1769 0
1770}
1771
1772#[no_mangle]
1773pub unsafe extern "C" fn sigdelset(set: *mut SigSetT, signum: c_int) -> c_int {
1774 let s = (signum as c_uint).wrapping_sub(1);
1775 if s as usize >= 64 {
1776 ERRNO = EINVAL;
1777 return -1;
1778 }
1779 if signum >= 32 && signum < __libc_current_sigrtmin() {
1781 return 0;
1782 }
1783 *set &= !(1u64 << s);
1784 0
1785}
1786
1787#[no_mangle]
1788pub unsafe extern "C" fn sigismember(set: *const SigSetT, signum: c_int) -> c_int {
1789 let s = (signum as c_uint).wrapping_sub(1);
1790 if s as usize >= 64 { return 0; }
1791 if signum >= 32 && signum < __libc_current_sigrtmin() {
1793 return 0;
1794 }
1795 ((*set & (1u64 << s)) != 0) as c_int
1796}
1797
1798#[no_mangle]
1799pub unsafe extern "C" fn sigpending(set: *mut SigSetT) -> c_int {
1800 let r = sys_rt_sigpending(set, core::mem::size_of::<SigSetT>());
1801 if r < 0 {
1802 ERRNO = (-r) as c_int;
1803 return -1;
1804 }
1805 0
1806}
1807
1808#[no_mangle]
1809pub unsafe extern "C" fn sigsuspend(mask: *const SigSetT) -> c_int {
1810 let r = sys_rt_sigsuspend(mask, core::mem::size_of::<SigSetT>());
1811 if r < 0 {
1812 ERRNO = (-r) as c_int;
1813 }
1814 -1
1815}
1816
1817#[no_mangle]
1818pub unsafe extern "C" fn sigtimedwait(
1819 mask: *const SigSetT,
1820 info: *mut siginfo_t,
1821 timeout: *const timespec,
1822) -> c_int {
1823 loop {
1824 let r = sys_rt_sigtimedwait(mask, info, timeout, core::mem::size_of::<SigSetT>());
1825 if r >= 0 {
1826 return r as c_int;
1827 }
1828 let e = (-r) as c_int;
1829 if e != EINTR {
1830 ERRNO = e;
1831 return -1;
1832 }
1833 }
1834}
1835
1836#[no_mangle]
1837pub unsafe extern "C" fn sigwaitinfo(
1838 mask: *const SigSetT,
1839 info: *mut siginfo_t,
1840) -> c_int {
1841 sigtimedwait(mask, info, core::ptr::null())
1842}
1843
1844#[no_mangle]
1845pub unsafe extern "C" fn sigwait(
1846 mask: *const SigSetT,
1847 sig: *mut c_int,
1848) -> c_int {
1849 let mut info: siginfo_t = core::mem::zeroed();
1850 if sigtimedwait(mask, &mut info, core::ptr::null()) < 0 {
1851 return ERRNO;
1852 }
1853 *sig = info.si_signo;
1854 0
1855}
1856
1857#[no_mangle]
1858pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
1859 if !ss.is_null() {
1860 if (*ss).ss_flags & SS_ONSTACK != 0 {
1861 ERRNO = EINVAL;
1862 return -1;
1863 }
1864 if (*ss).ss_flags & SS_DISABLE == 0 && (*ss).ss_size < MINSIGSTKSZ {
1865 ERRNO = ENOMEM;
1866 return -1;
1867 }
1868 }
1869 let r = sys_sigaltstack(ss, old_ss);
1870 if r < 0 {
1871 ERRNO = (-r) as c_int;
1872 return -1;
1873 }
1874 0
1875}
1876
1877#[no_mangle]
1883#[inline(never)]
1884#[cfg(target_arch = "x86_64")]
1885pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
1886 core::arch::asm!(
1887 "mov rax, [rsp]",
1888 "lea rcx, [rsp + 8]",
1889 "mov [r8], rbx",
1890 "mov [r8 + 8], rbp",
1891 "mov [r8 + 16], r12",
1892 "mov [r8 + 24], r13",
1893 "mov [r8 + 32], r14",
1894 "mov [r8 + 40], r15",
1895 "mov [r8 + 48], rcx",
1896 "mov [r8 + 56], rax",
1897 in("r8") env,
1898 lateout("rax") _,
1899 lateout("rcx") _,
1900 options(nostack),
1901 );
1902 0
1903}
1904
1905#[no_mangle]
1906#[inline(never)]
1907#[cfg(target_arch = "x86_64")]
1908pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
1909 let ret = if val == 0 { 1 } else { val } as u32;
1910 core::arch::asm!(
1911 "mov rbx, [r8]",
1912 "mov rbp, [r8 + 8]",
1913 "mov r12, [r8 + 16]",
1914 "mov r13, [r8 + 24]",
1915 "mov r14, [r8 + 32]",
1916 "mov r15, [r8 + 40]",
1917 "mov rsp, [r8 + 48]",
1918 "mov eax, edx",
1919 "jmp [r8 + 56]",
1920 in("r8") env,
1921 in("edx") ret,
1922 options(noreturn),
1923 );
1924}
1925
1926#[cfg(all(target_arch = "aarch64", not(test)))]
1927core::arch::global_asm!(
1928 ".global setjmp",
1929 ".type setjmp, @function",
1930 "setjmp:",
1931 "stp x19, x20, [x0, #0]",
1932 "stp x21, x22, [x0, #16]",
1933 "stp x23, x24, [x0, #32]",
1934 "stp x25, x26, [x0, #48]",
1935 "stp x27, x28, [x0, #64]",
1936 "stp x29, x30, [x0, #80]",
1937 "mov x2, sp",
1938 "str x2, [x0, #104]",
1939 "stp d8, d9, [x0, #112]",
1940 "stp d10, d11, [x0, #128]",
1941 "stp d12, d13, [x0, #144]",
1942 "stp d14, d15, [x0, #160]",
1943 "mov x0, #0",
1944 "ret",
1945);
1946
1947#[no_mangle]
1948#[inline(never)]
1949#[cfg(target_arch = "aarch64")]
1950pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
1951 let ret = if val == 0 { 1 } else { val } as u64;
1952 core::arch::asm!(
1953 "ldp x19, x20, [x0]",
1954 "ldp x21, x22, [x0, #16]",
1955 "ldp x23, x24, [x0, #32]",
1956 "ldp x25, x26, [x0, #48]",
1957 "ldp x27, x28, [x0, #64]",
1958 "ldp x29, x30, [x0, #80]",
1959 "ldr x2, [x0, #104]",
1960 "mov sp, x2",
1961 "ldp d8, d9, [x0, #112]",
1962 "ldp d10, d11, [x0, #128]",
1963 "ldp d12, d13, [x0, #144]",
1964 "ldp d14, d15, [x0, #160]",
1965 "mov x0, x1",
1966 "br x30",
1967 in("x0") env,
1968 in("x1") ret,
1969 options(noreturn),
1970 );
1971}
1972
1973#[no_mangle]
1981#[unsafe(naked)]
1982#[cfg(target_arch = "x86_64")]
1983pub unsafe extern "C" fn sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
1984 core::arch::naked_asm!("jmp sigsetjmp_real");
1985}
1986
1987#[no_mangle]
1988#[unsafe(naked)]
1989#[cfg(target_arch = "x86_64")]
1990pub unsafe extern "C" fn __sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
1991 core::arch::naked_asm!("jmp sigsetjmp_real");
1992}
1993
1994#[cfg(target_arch = "x86_64")]
1995core::arch::global_asm!(
1996 ".type sigsetjmp_real, @function",
1997 "sigsetjmp_real:",
1998 " test esi, esi",
1999 " jz 1f",
2000 " pop qword ptr [rdi + 64]",
2001 " mov qword ptr [rdi + 80], rbx",
2002 " push rbx",
2003 " mov rbx, rdi",
2004 " call setjmp",
2005 " push qword ptr [rbx + 64]",
2006 " mov rdi, rbx",
2007 " mov esi, eax",
2008 " mov rbx, qword ptr [rbx + 80]",
2009 " lea rdx, [rdi + 72]",
2010 " test esi, esi",
2011 " jz 2f",
2012 " mov rsi, rdx",
2013 " xor rdx, rdx",
2014 " mov edi, 2",
2015 " jmp 3f",
2016 "2:",
2017 " xor rsi, rsi",
2018 " mov edi, 2",
2019 "3:",
2020 " mov eax, 14",
2021 " mov r10d, 8",
2022 " syscall",
2023 " test esi, esi",
2024 " jnz 4f",
2025 " mov rax, 0xfffffffe7fffffff",
2026 " and qword ptr [rdx], rax",
2027 "4:",
2028 " mov eax, esi",
2029 " ret",
2030 "1:",
2031 " jmp setjmp",
2032);
2033
2034#[no_mangle]
2035#[inline(never)]
2036#[cfg(target_arch = "x86_64")]
2037pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2038 longjmp(env, val);
2039}
2040
2041#[no_mangle]
2042#[cfg(target_arch = "aarch64")]
2043pub unsafe extern "C" fn __sigsetjmp_tail(env: *mut c_ulong, ret: c_int) -> c_int {
2044 const SIG_SETMASK: c_int = 2;
2045 let ss = env.add(24) as *mut SigSetT;
2046 let set = if ret != 0 { ss as *const SigSetT } else { core::ptr::null() };
2047 let old = if ret != 0 { core::ptr::null_mut() } else { ss };
2048 let _ = sys_rt_sigprocmask(SIG_SETMASK, set, old, core::mem::size_of::<SigSetT>());
2049 ret
2050}
2051
2052#[cfg(all(target_arch = "aarch64", not(test)))]
2053core::arch::global_asm!(
2054 ".global sigsetjmp",
2055 ".global __sigsetjmp",
2056 ".type sigsetjmp, @function",
2057 ".type __sigsetjmp, @function",
2058 "sigsetjmp:",
2059 "__sigsetjmp:",
2060 "cbz x1, setjmp",
2061 "str x30, [x0, #176]",
2062 "str x19, [x0, #184]",
2063 "mov x19, x0",
2064 "bl setjmp",
2065 "mov w1, w0",
2066 "mov x0, x19",
2067 "ldr x30, [x0, #176]",
2068 "ldr x19, [x0, #184]",
2069 "b __sigsetjmp_tail",
2070);
2071
2072#[no_mangle]
2073#[inline(never)]
2074#[cfg(target_arch = "aarch64")]
2075pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2076 longjmp(env, val);
2077}
2078
2079#[inline]
2084unsafe fn sys_newfstatat(dirfd: i32, path: *const c_char, buf: *mut u8, flags: i32) -> i64 {
2085 <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, dirfd as i64, path as i64, buf as i64, flags as i64)
2086}
2087
2088#[inline]
2089unsafe fn sys_fstat(fd: i32, buf: *mut u8) -> i64 {
2090 <Arch as Syscalls>::syscall2(SYS_FSTAT, fd as i64, buf as i64)
2091}
2092
2093#[inline]
2094unsafe fn sys_getrlimit(resource: i32, rlim: *mut u8) -> i64 {
2095 <Arch as Syscalls>::syscall2(SYS_GETRLIMIT, resource as i64, rlim as i64)
2096}
2097
2098#[inline]
2099unsafe fn sys_setrlimit(resource: i32, rlim: *const u8) -> i64 {
2100 <Arch as Syscalls>::syscall2(SYS_SETRLIMIT, resource as i64, rlim as i64)
2101}
2102
2103#[inline]
2104unsafe fn sys_utimensat(dirfd: i32, path: *const c_char, times: *const u8, flags: i32) -> i64 {
2105 <Arch as Syscalls>::syscall4(SYS_UTIMENSAT, dirfd as i64, path as i64, times as i64, flags as i64)
2106}
2107
2108#[inline]
2113unsafe fn sys_fork() -> i64 {
2114 #[cfg(target_arch = "x86_64")]
2115 { <Arch as Syscalls>::syscall0(SYS_FORK) }
2116 #[cfg(target_arch = "aarch64")]
2117 { <Arch as Syscalls>::syscall2(SYS_CLONE, 17, 0) }
2118}
2119
2120#[inline]
2121unsafe fn sys_execve(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> i64 {
2122 <Arch as Syscalls>::syscall3(SYS_EXECVE, path as i64, argv as i64, envp as i64)
2123}
2124
2125#[inline]
2126unsafe fn sys_wait4(pid: c_int, status: *mut c_int, options: c_int, rusage: *mut c_void) -> i64 {
2127 <Arch as Syscalls>::syscall4(SYS_WAIT4, pid as i64, status as i64, options as i64, rusage as i64)
2128}
2129
2130#[inline]
2131unsafe fn sys_getppid() -> i64 {
2132 <Arch as Syscalls>::syscall0(SYS_GETPPID)
2133}
2134
2135#[inline]
2136unsafe fn sys_getuid() -> i64 {
2137 <Arch as Syscalls>::syscall0(SYS_GETUID)
2138}
2139
2140#[inline]
2141unsafe fn sys_getgid() -> i64 {
2142 <Arch as Syscalls>::syscall0(SYS_GETGID)
2143}
2144
2145#[inline]
2146unsafe fn sys_geteuid() -> i64 {
2147 <Arch as Syscalls>::syscall0(SYS_GETEUID)
2148}
2149
2150#[inline]
2151unsafe fn sys_getegid() -> i64 {
2152 <Arch as Syscalls>::syscall0(SYS_GETEGID)
2153}
2154
2155#[no_mangle]
2156pub unsafe extern "C" fn fork() -> c_int {
2157 __fork_handler(-1);
2158 let mut rlim: Rlimit = core::mem::zeroed();
2162 let nproc_limit = sys_getrlimit(RLIMIT_NPROC, &mut rlim as *mut _ as *mut u8);
2163 let nproc_limited = nproc_limit == 0
2164 && rlim.rlim_cur != RLIM_INFINITY
2165 && rlim.rlim_cur == 0;
2166 let ret = if nproc_limited {
2167 -EAGAIN as i64
2168 } else {
2169 sys_fork()
2170 };
2171 let errno_save = if ret < 0 { EAGAIN } else { ERRNO };
2172 if ret == 0 {
2173 __fork_handler(1);
2174 } else {
2175 __fork_handler(0);
2176 }
2177 if ret < 0 {
2178 ERRNO = errno_save;
2179 return -1;
2180 }
2181 ret as c_int
2182}
2183
2184#[no_mangle]
2185pub unsafe extern "C" fn execve(
2186 path: *const c_char,
2187 argv: *const *const c_char,
2188 envp: *const *const c_char,
2189) -> c_int {
2190 sys_execve(path, argv, envp) as c_int
2191}
2192
2193#[no_mangle]
2194pub unsafe extern "C" fn wait(status: *mut c_int) -> c_int {
2195 sys_wait4(-1, status, 0, core::ptr::null_mut()) as c_int
2196}
2197
2198#[no_mangle]
2199pub unsafe extern "C" fn waitpid(pid: c_int, status: *mut c_int, options: c_int) -> c_int {
2200 sys_wait4(pid, status, options, core::ptr::null_mut()) as c_int
2201}
2202
2203#[no_mangle]
2204pub unsafe extern "C" fn getppid() -> c_int {
2205 sys_getppid() as c_int
2206}
2207
2208#[no_mangle]
2209pub unsafe extern "C" fn getuid() -> c_uint {
2210 sys_getuid() as c_uint
2211}
2212
2213#[no_mangle]
2214pub unsafe extern "C" fn getgid() -> c_uint {
2215 sys_getgid() as c_uint
2216}
2217
2218#[no_mangle]
2219pub unsafe extern "C" fn geteuid() -> c_uint {
2220 sys_geteuid() as c_uint
2221}
2222
2223#[no_mangle]
2224pub unsafe extern "C" fn getegid() -> c_uint {
2225 sys_getegid() as c_uint
2226}
2227
2228#[no_mangle]
2230pub unsafe extern "C" fn vfork() -> c_int {
2231 sys_fork() as c_int
2232}
2233
2234#[no_mangle]
2235pub unsafe extern "C" fn execl(path: *const c_char, arg: *const c_char, mut args: ...) -> c_int {
2236 let mut argv: [*const c_char; 256] = [core::ptr::null(); 256];
2237 argv[0] = arg;
2238 let mut n: usize = 1;
2239 loop {
2240 let a: *const c_char = args.next_arg();
2241 if a.is_null() { break; }
2242 if n >= 255 { return -1; }
2243 argv[n] = a;
2244 n += 1;
2245 }
2246 argv[n] = core::ptr::null();
2247 sys_execve(path, argv.as_ptr(), __environ as *const *const c_char) as c_int
2248}
2249
2250const SPAWN_FA_MAX: usize = 5;
2258
2259#[repr(C)]
2260pub struct posix_spawn_file_actions_t {
2261 __pad0: [c_int; 2],
2262 __actions: *mut c_void,
2263 __pad: [c_int; 16],
2264}
2265
2266#[repr(C)]
2267pub struct posix_spawnattr_t {
2268 __flags: c_int,
2269 __pgrp: c_int,
2270 __def: [c_ulong; 16],
2271 __mask: [c_ulong; 16],
2272 __prio: c_int,
2273 __pol: c_int,
2274 __fn: *mut c_void,
2275 __pad: [u8; 64 - core::mem::size_of::<*mut c_void>()],
2276}
2277
2278#[no_mangle]
2279pub unsafe extern "C" fn posix_spawn_file_actions_init(fa: *mut posix_spawn_file_actions_t) -> c_int {
2280 core::ptr::write_bytes(fa, 0, 1);
2281 0
2282}
2283
2284#[no_mangle]
2285pub unsafe extern "C" fn posix_spawn_file_actions_destroy(_fa: *mut posix_spawn_file_actions_t) -> c_int {
2286 0
2287}
2288
2289unsafe fn spawn_fa_add(fa: *mut posix_spawn_file_actions_t, action_type: c_int, fd: c_int, newfd: c_int) -> c_int {
2290 let count = (*fa).__pad0[0] as usize;
2291 if count >= SPAWN_FA_MAX { return ENOMEM; }
2292 let base = count * 3;
2293 (*fa).__pad[base] = action_type;
2294 (*fa).__pad[base + 1] = fd;
2295 (*fa).__pad[base + 2] = newfd;
2296 (*fa).__pad0[0] += 1;
2297 0
2298}
2299
2300#[no_mangle]
2301pub unsafe extern "C" fn posix_spawn_file_actions_addclose(fa: *mut posix_spawn_file_actions_t, fd: c_int) -> c_int {
2302 spawn_fa_add(fa, 0, fd, 0)
2303}
2304
2305#[no_mangle]
2306pub unsafe extern "C" fn posix_spawn_file_actions_adddup2(fa: *mut posix_spawn_file_actions_t, oldfd: c_int, newfd: c_int) -> c_int {
2307 spawn_fa_add(fa, 1, oldfd, newfd)
2308}
2309
2310unsafe fn spawn_apply_actions(fa: *const posix_spawn_file_actions_t) {
2311 if fa.is_null() { return; }
2312 let count = (*fa).__pad0[0] as usize;
2313 for i in 0..count {
2314 let base = i * 3;
2315 match (*fa).__pad[base] {
2316 0 => { sys_close((*fa).__pad[base + 1] as i64); }
2317 1 => { sys_dup2((*fa).__pad[base + 1], (*fa).__pad[base + 2]); }
2318 _ => {}
2319 }
2320 }
2321}
2322
2323unsafe fn spawn_execvp(file: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> ! {
2325 let flen = strlen(file as *const c_char);
2326 let f = file as *const u8;
2327 let mut has_slash = false;
2328 for i in 0..flen {
2329 if *f.add(i) == b'/' { has_slash = true; break; }
2330 }
2331 if has_slash {
2332 sys_execve(file, argv, envp);
2333 _exit(127);
2334 }
2335 let path = getenv(b"PATH\0".as_ptr() as *const c_char);
2336 let default_path = b"/usr/local/bin:/usr/bin:/bin\0";
2337 let p = if path.is_null() { default_path.as_ptr() } else { path as *const u8 };
2338 let plen = strlen(p as *const c_char);
2339 let mut buf: [u8; 4096] = [0; 4096];
2340 let mut i: usize = 0;
2341 while i <= plen {
2342 let start = i;
2343 while i < plen && *p.add(i) != b':' { i += 1; }
2344 let dlen = i - start;
2345 if dlen > 0 && dlen + 1 + flen < 4096 {
2346 core::ptr::copy_nonoverlapping(p.add(start), buf.as_mut_ptr(), dlen);
2347 *buf.as_mut_ptr().add(dlen) = b'/';
2348 core::ptr::copy_nonoverlapping(f, buf.as_mut_ptr().add(dlen + 1), flen + 1);
2349 sys_execve(buf.as_ptr() as *const c_char, argv, envp);
2350 }
2352 i += 1; }
2354 _exit(127);
2355}
2356
2357#[no_mangle]
2358pub unsafe extern "C" fn posix_spawnp(
2359 pid: *mut c_int,
2360 file: *const c_char,
2361 fa: *const posix_spawn_file_actions_t,
2362 _attrp: *const posix_spawnattr_t,
2363 argv: *const *const c_char,
2364 envp: *const *const c_char,
2365) -> c_int {
2366 let child = sys_fork();
2367 if child < 0 {
2368 ERRNO = EAGAIN;
2369 return -1;
2370 }
2371 if child == 0 {
2372 spawn_apply_actions(fa);
2374 let actual_envp = if envp.is_null() { __environ as *const *const c_char } else { envp };
2375 spawn_execvp(file, argv, actual_envp);
2376 }
2378 *pid = child as c_int;
2379 0
2380}
2381
2382#[no_mangle]
2383pub unsafe extern "C" fn posix_spawn(
2384 pid: *mut c_int,
2385 path: *const c_char,
2386 fa: *const posix_spawn_file_actions_t,
2387 attrp: *const posix_spawnattr_t,
2388 argv: *const *const c_char,
2389 envp: *const *const c_char,
2390) -> c_int {
2391 posix_spawnp(pid, path, fa, attrp, argv, envp)
2394}
2395
2396#[no_mangle]
2397pub unsafe extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int {
2398 core::ptr::write_bytes(attr, 0, 1);
2399 0
2400}
2401
2402#[no_mangle]
2403pub unsafe extern "C" fn posix_spawnattr_destroy(_attr: *mut posix_spawnattr_t) -> c_int {
2404 0
2405}
2406
2407#[repr(C)]
2412pub struct Stat {
2413 pub st_dev: u64,
2414 pub st_ino: u64,
2415 pub st_nlink: u64,
2416 pub st_mode: u32,
2417 pub st_uid: u32,
2418 pub st_gid: u32,
2419 _pad0: u32,
2420 pub st_rdev: u64,
2421 pub st_size: i64,
2422 pub st_blksize: i64,
2423 pub st_blocks: i64,
2424 pub st_atim: timespec,
2425 pub st_mtim: timespec,
2426 pub st_ctim: timespec,
2427 _unused: [i64; 3],
2428}
2429
2430pub const S_IFMT: u32 = 0o170000;
2431pub const S_IFDIR: u32 = 0o040000;
2432pub const S_IFCHR: u32 = 0o020000;
2433pub const S_IFBLK: u32 = 0o060000;
2434pub const S_IFREG: u32 = 0o100000;
2435pub const S_IFLNK: u32 = 0o120000;
2436pub const S_IFIFO: u32 = 0o010000;
2437pub const S_IFSOCK: u32 = 0o140000;
2438
2439pub const AT_FDCWD: i32 = -100;
2440
2441#[no_mangle]
2442pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut Stat) -> c_int {
2443 let r = sys_newfstatat(AT_FDCWD, path, buf as *mut u8, 0);
2444 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2445 if *path == b'/' as c_char && strcmp(path as *const u8, b"/dev/null\0".as_ptr()) == 0 {
2446 (*buf).st_mode = ((*buf).st_mode & !0o170000) | 0o020000;
2447 }
2448 0
2449}
2450
2451#[no_mangle]
2452pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut Stat) -> c_int {
2453 let r = sys_fstat(fd, buf as *mut u8);
2454 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2455}
2456
2457#[repr(C)]
2462pub struct Rlimit {
2463 pub rlim_cur: u64,
2464 pub rlim_max: u64,
2465}
2466
2467pub const RLIMIT_NOFILE: c_int = 7;
2468pub const RLIMIT_STACK: c_int = 3;
2469pub const RLIMIT_DATA: c_int = 2;
2470pub const RLIMIT_AS: c_int = 9;
2471pub const RLIMIT_CPU: c_int = 0;
2472pub const RLIMIT_FSIZE: c_int = 1;
2473pub const RLIMIT_CORE: c_int = 4;
2474pub const RLIMIT_RSS: c_int = 5;
2475pub const RLIMIT_NPROC: c_int = 6;
2476pub const RLIMIT_MEMLOCK: c_int = 8;
2477pub const RLIMIT_LOCKS: c_int = 10;
2478pub const RLIMIT_SIGPENDING: c_int = 11;
2479pub const RLIMIT_MSGQUEUE: c_int = 12;
2480pub const RLIMIT_NICE: c_int = 13;
2481pub const RLIMIT_RTPRIO: c_int = 14;
2482pub const RLIMIT_RTTIME: c_int = 15;
2483pub const RLIM_INFINITY: u64 = !0u64;
2484
2485#[no_mangle]
2486pub unsafe extern "C" fn getrlimit(resource: c_int, rlim: *mut Rlimit) -> c_int {
2487 let r = sys_getrlimit(resource, rlim as *mut u8);
2488 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2489}
2490
2491#[no_mangle]
2492pub unsafe extern "C" fn setrlimit(resource: c_int, rlim: *const Rlimit) -> c_int {
2493 let r = sys_setrlimit(resource, rlim as *const u8);
2494 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2495}
2496
2497#[no_mangle]
2502pub unsafe extern "C" fn utimensat(dirfd: c_int, path: *const c_char, times: *const timespec, flags: c_int) -> c_int {
2503 let r = sys_utimensat(dirfd, path, times as *const u8, flags);
2504 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2505}
2506
2507#[no_mangle]
2508pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
2509 let r = sys_utimensat(fd, core::ptr::null(), times as *const u8, 0);
2510 if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2511}
2512
2513pub const AF_UNIX: c_int = 1;
2518pub const AF_INET: c_int = 2;
2519pub const AF_INET6: c_int = 10;
2520
2521pub const SOCK_STREAM: c_int = 1;
2522pub const SOCK_DGRAM: c_int = 2;
2523
2524pub const SHUT_RD: c_int = 0;
2525pub const SHUT_WR: c_int = 1;
2526pub const SHUT_RDWR: c_int = 2;
2527
2528pub const SOL_SOCKET: c_int = 1;
2529pub const SO_REUSEADDR: c_int = 2;
2530
2531#[repr(C)]
2532pub struct sockaddr {
2533 pub sa_family: u16,
2534 pub sa_data: [u8; 14],
2535}
2536
2537#[inline]
2538unsafe fn sys_socket(domain: c_int, ty: c_int, protocol: c_int) -> i64 {
2539 <Arch as Syscalls>::syscall3(SYS_SOCKET, domain as i64, ty as i64, protocol as i64)
2540}
2541
2542#[inline]
2543unsafe fn sys_socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> i64 {
2544 <Arch as Syscalls>::syscall4(SYS_SOCKETPAIR, domain as i64, ty as i64, protocol as i64, sv as i64)
2545}
2546
2547#[inline]
2548unsafe fn sys_bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
2549 <Arch as Syscalls>::syscall3(SYS_BIND, fd as i64, addr as i64, len as i64)
2550}
2551
2552#[inline]
2553unsafe fn sys_listen(fd: c_int, backlog: c_int) -> i64 {
2554 <Arch as Syscalls>::syscall2(SYS_LISTEN, fd as i64, backlog as i64)
2555}
2556
2557#[inline]
2558unsafe fn sys_accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
2559 <Arch as Syscalls>::syscall3(SYS_ACCEPT, fd as i64, addr as i64, len as i64)
2560}
2561
2562#[inline]
2563unsafe fn sys_connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
2564 <Arch as Syscalls>::syscall3(SYS_CONNECT, fd as i64, addr as i64, len as i64)
2565}
2566
2567#[inline]
2568unsafe fn sys_sendto(fd: c_int,
2569 buf: *const c_void,
2570 len: usize,
2571 flags: c_int,
2572 addr: *const sockaddr,
2573 addrlen: c_uint,) -> i64 {
2574 <Arch as Syscalls>::syscall6(SYS_SENDTO, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
2575}
2576
2577#[inline]
2578unsafe fn sys_recvfrom(fd: c_int,
2579 buf: *mut c_void,
2580 len: usize,
2581 flags: c_int,
2582 addr: *mut sockaddr,
2583 addrlen: *mut c_uint,) -> i64 {
2584 <Arch as Syscalls>::syscall6(SYS_RECVFROM, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
2585}
2586
2587#[inline]
2588unsafe fn sys_shutdown(fd: c_int, how: c_int) -> i64 {
2589 <Arch as Syscalls>::syscall2(SYS_SHUTDOWN, fd as i64, how as i64)
2590}
2591
2592#[inline]
2593unsafe fn sys_setsockopt(fd: c_int,
2594 level: c_int,
2595 optname: c_int,
2596 optval: *const c_void,
2597 optlen: c_uint,) -> i64 {
2598 <Arch as Syscalls>::syscall5(SYS_SETSOCKOPT, fd as i64, level as i64, optname as i64, optval as i64, optlen as i64)
2599}
2600
2601#[inline]
2602unsafe fn sys_getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
2603 <Arch as Syscalls>::syscall3(SYS_GETSOCKNAME, fd as i64, addr as i64, len as i64)
2604}
2605
2606#[no_mangle]
2607pub unsafe extern "C" fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int {
2608 let r = sys_socket(domain, ty, protocol);
2609 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2610 r as c_int
2611}
2612
2613#[no_mangle]
2614pub unsafe extern "C" fn socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> c_int {
2615 let r = sys_socketpair(domain, ty, protocol, sv);
2616 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2617 0
2618}
2619
2620#[no_mangle]
2621pub unsafe extern "C" fn bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
2622 let r = sys_bind(fd, addr, len);
2623 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2624 0
2625}
2626
2627#[no_mangle]
2628pub unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> c_int {
2629 let r = sys_listen(fd, backlog);
2630 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2631 0
2632}
2633
2634#[no_mangle]
2635pub unsafe extern "C" fn accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
2636 let r = sys_accept(fd, addr, len);
2637 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2638 r as c_int
2639}
2640
2641#[no_mangle]
2642pub unsafe extern "C" fn connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
2643 let r = sys_connect(fd, addr, len);
2644 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2645 0
2646}
2647
2648#[no_mangle]
2649pub unsafe extern "C" fn send(fd: c_int, buf: *const c_void, len: usize, flags: c_int) -> isize {
2650 let r = sys_sendto(fd, buf, len, flags, core::ptr::null(), 0);
2651 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2652 r as isize
2653}
2654
2655#[no_mangle]
2656pub unsafe extern "C" fn recv(fd: c_int, buf: *mut c_void, len: usize, flags: c_int) -> isize {
2657 let r = sys_recvfrom(fd, buf, len, flags, core::ptr::null_mut(), core::ptr::null_mut());
2658 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2659 r as isize
2660}
2661
2662#[no_mangle]
2663pub unsafe extern "C" fn sendto(
2664 fd: c_int,
2665 buf: *const c_void,
2666 len: usize,
2667 flags: c_int,
2668 addr: *const sockaddr,
2669 addrlen: c_uint,
2670) -> isize {
2671 let r = sys_sendto(fd, buf, len, flags, addr, addrlen);
2672 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2673 r as isize
2674}
2675
2676#[no_mangle]
2677pub unsafe extern "C" fn recvfrom(
2678 fd: c_int,
2679 buf: *mut c_void,
2680 len: usize,
2681 flags: c_int,
2682 addr: *mut sockaddr,
2683 addrlen: *mut c_uint,
2684) -> isize {
2685 let r = sys_recvfrom(fd, buf, len, flags, addr, addrlen);
2686 if r < 0 { ERRNO = (-r) as c_int; return -1; }
2687 r as isize
2688}
2689
2690#[no_mangle]
2691pub unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> c_int {
2692 sys_shutdown(fd, how) as c_int
2693}
2694
2695#[no_mangle]
2696pub unsafe extern "C" fn setsockopt(
2697 fd: c_int,
2698 level: c_int,
2699 optname: c_int,
2700 optval: *const c_void,
2701 optlen: c_uint,
2702) -> c_int {
2703 sys_setsockopt(fd, level, optname, optval, optlen) as c_int
2704}
2705
2706#[no_mangle]
2707pub unsafe extern "C" fn getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
2708 sys_getsockname(fd, addr, len) as c_int
2709}
2710
2711#[no_mangle]
2712pub extern "C" fn htonl(hostlong: c_uint) -> c_uint {
2713 hostlong.to_be()
2714}
2715
2716#[no_mangle]
2717pub extern "C" fn ntohl(netlong: c_uint) -> c_uint {
2718 c_uint::from_be(netlong)
2719}
2720
2721#[no_mangle]
2722pub extern "C" fn htons(hostshort: u16) -> u16 {
2723 hostshort.to_be()
2724}
2725
2726#[no_mangle]
2727pub extern "C" fn ntohs(netshort: u16) -> u16 {
2728 u16::from_be(netshort)
2729}
2730
2731pub type PthreadT = c_ulong;
2732
2733#[repr(C)]
2735pub struct pthread_attr_t {
2736 __i: [c_int; 14],
2737}
2738
2739#[repr(C)]
2742pub struct pthread_mutex_t {
2743 __i: [c_int; 10],
2744}
2745
2746#[repr(C)]
2747pub struct pthread_mutexattr_t {
2748 __attr: c_uint,
2749}
2750
2751#[repr(C)]
2754pub struct pthread_cond_t {
2755 __i: [c_int; 12],
2756}
2757
2758#[repr(C)]
2759pub struct pthread_condattr_t {
2760 __attr: c_uint,
2761}
2762
2763#[repr(C)]
2766pub struct pthread_rwlock_t {
2767 __i: [c_int; 14],
2768}
2769
2770#[repr(C)]
2771pub struct pthread_rwlockattr_t {
2772 __attr: [c_uint; 2],
2773}
2774
2775#[repr(C)]
2777pub struct pthread_barrier_t {
2778 __i: [c_int; 8],
2779}
2780
2781#[repr(C)]
2782pub struct pthread_barrierattr_t {
2783 __attr: c_uint,
2784}
2785
2786pub type pthread_spinlock_t = c_int;
2787pub type pthread_once_t = c_int;
2788pub type pthread_key_t = c_uint;
2789
2790#[repr(C)]
2792pub struct sem_t {
2793 __val: [c_int; 8],
2794}
2795
2796#[repr(C)]
2797pub struct sched_param {
2798 pub sched_priority: c_int,
2799}
2800
2801const CLONE_VM: c_ulong = 0x00000100;
2802const CLONE_FS: c_ulong = 0x00000200;
2803const CLONE_FILES: c_ulong = 0x00000400;
2804const CLONE_SIGHAND: c_ulong = 0x00000800;
2805const CLONE_THREAD: c_ulong = 0x00010000;
2806const CLONE_SYSVSEM: c_ulong = 0x00040000;
2807const CLONE_SETTLS: c_ulong = 0x00080000;
2808const CLONE_PARENT_SETTID: c_ulong = 0x00100000;
2809const CLONE_CHILD_CLEARTID: c_ulong = 0x00200000;
2810
2811const FUTEX_WAIT: c_int = 0;
2812const FUTEX_WAKE: c_int = 1;
2813const FUTEX_LOCK_PI: c_int = 6;
2814const FUTEX_UNLOCK_PI: c_int = 7;
2815const FUTEX_TRYLOCK_PI: c_int = 8;
2816
2817const SIGCANCEL: c_int = 32;
2819
2820const PTHREAD_MUTEX_NORMAL: c_int = 0;
2821const PTHREAD_MUTEX_DEFAULT: c_int = 0;
2822const PTHREAD_MUTEX_RECURSIVE: c_int = 1;
2823const PTHREAD_MUTEX_ERRORCHECK: c_int = 2;
2824
2825const PTHREAD_CREATE_JOINABLE: c_int = 0;
2826const PTHREAD_CREATE_DETACHED: c_int = 1;
2827
2828const PTHREAD_CANCEL_ENABLE: c_int = 0;
2829const PTHREAD_CANCEL_DISABLE: c_int = 1;
2830const PTHREAD_CANCEL_DEFERRED: c_int = 0;
2831const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 1;
2832
2833const PTHREAD_SCOPE_SYSTEM: c_int = 0;
2834const PTHREAD_PROCESS_PRIVATE: c_int = 0;
2835const PTHREAD_PROCESS_SHARED: c_int = 1;
2836const PTHREAD_INHERIT_SCHED: c_int = 0;
2837const PTHREAD_EXPLICIT_SCHED: c_int = 1;
2838
2839const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1;
2840
2841const PTHREAD_KEYS_MAX: usize = 128;
2842const PTHREAD_DESTRUCTOR_ITERATIONS: usize = 4;
2843const SEM_VALUE_MAX: c_int = 0x7fffffff;
2844
2845const DT_EXITED: c_int = 0;
2846const DT_EXITING: c_int = 1;
2847const DT_JOINABLE: c_int = 2;
2848const DT_DETACHED: c_int = 3;
2849
2850#[repr(C)]
2852#[derive(Copy, Clone)]
2853pub struct __ptcb {
2854 __f: Option<unsafe extern "C" fn(*mut c_void)>,
2855 __x: *mut c_void,
2856 __next: *mut __ptcb,
2857}
2858
2859#[repr(C)]
2861#[derive(Copy, Clone)]
2862struct robust_list {
2863 next: *mut robust_list,
2864}
2865
2866#[repr(C)]
2867#[derive(Copy, Clone)]
2868struct robust_list_head {
2869 list: robust_list,
2870 futex_offset: c_long,
2871 pending: *mut robust_list,
2872}
2873
2874#[cfg(all(target_arch = "x86_64", not(test)))]
2876core::arch::global_asm!(
2877 ".global __rc_clone",
2878 ".type __rc_clone, @function",
2879 "__rc_clone:",
2880 "mov rax, rdi",
2881 "mov rdi, rdx",
2882 "mov rdx, r8",
2883 "mov r10, [rsp + 8]",
2884 "mov r8, r9",
2885 "mov r9, rax",
2886 "and rsi, -16",
2887 "sub rsi, 8",
2888 "mov [rsi], rcx",
2889 "mov eax, 56",
2890 "syscall",
2891 "test rax, rax",
2892 "jnz 1f",
2893 "pop rdi",
2894 "call r9",
2895 "hlt",
2896 "1:",
2897 "ret",
2898);
2899
2900#[cfg(all(target_arch = "aarch64", not(test)))]
2902core::arch::global_asm!(
2903 ".global __rc_clone",
2904 ".type __rc_clone, @function",
2905 "__rc_clone:",
2906 "and x1, x1, #-16",
2907 "stp x0, x3, [x1, #-16]!",
2908 "uxtw x0, w2",
2909 "mov x2, x4",
2910 "mov x3, x5",
2911 "mov x4, x6",
2912 "mov x8, #220",
2913 "svc #0",
2914 "cbz x0, 1f",
2915 "ret",
2916 "1:",
2917 "mov x29, #0",
2918 "ldp x1, x0, [sp], #16",
2919 "blr x1",
2920 "mov x8, #93",
2921 "svc #0",
2922);
2923
2924#[cfg(test)]
2925#[inline(never)]
2926unsafe fn __rc_clone(
2927 _fn_: usize,
2928 _stack: *mut u8,
2929 _flags: c_ulong,
2930 _arg: *mut c_void,
2931 _ptid: *mut c_int,
2932 _tls: c_ulong,
2933 _ctid: *mut c_int,
2934) -> i64 {
2935 -1
2936}
2937
2938#[cfg(all(target_arch = "x86_64", not(test)))]
2939extern "C" {
2940 fn __rc_clone(
2941 fn_: usize,
2942 stack: *mut u8,
2943 flags: c_ulong,
2944 arg: *mut c_void,
2945 ptid: *mut c_int,
2946 tls: c_ulong,
2947 ctid: *mut c_int,
2948 ) -> i64;
2949}
2950
2951#[cfg(all(target_arch = "aarch64", not(test)))]
2952extern "C" {
2953 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}
2963
2964#[inline(never)]
2965#[linkage = "weak"]
2966#[no_mangle]
2967pub extern "C" fn __rc_create_thread_tls() -> *mut u8 {
2968 core::ptr::null_mut()
2969}
2970
2971#[inline(never)]
2972#[linkage = "weak"]
2973#[no_mangle]
2974pub extern "C" fn __rc_tls_block_size() -> usize {
2975 0
2976}
2977
2978#[inline(never)]
2979#[linkage = "weak"]
2980#[no_mangle]
2981pub extern "C" fn __rc_tls_base_offset() -> usize {
2982 0
2983}
2984
2985#[inline]
2986unsafe fn sys_gettid() -> i64 {
2987 <Arch as Syscalls>::syscall0(SYS_GETTID)
2988}
2989
2990#[inline]
2991unsafe fn sys_futex(uaddr: *mut c_int,
2992 futex_op: c_int,
2993 val: c_int,
2994 timeout: *mut c_void,
2995 uaddr2: *mut c_int,
2996 val3: c_int,) -> i64 {
2997 <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)
2998}
2999
3000const MAX_THREADS: usize = 64;
3001const STACK_SIZE: usize = 1024 * 1024;
3002
3003#[repr(C)]
3004#[derive(Copy, Clone)]
3005struct Thread {
3006 tid: c_int,
3007 detach_state: c_int,
3008 result: *mut c_void,
3009 cancel: c_int,
3010 cancel_state: c_int,
3011 cancel_type: c_int,
3012 user_fn: usize,
3013 user_arg: *mut c_void,
3014 stack: *mut u8,
3015 stack_size: usize,
3016 fs_base: *mut u8,
3017 tsd: [*mut c_void; PTHREAD_KEYS_MAX],
3018 cancelbuf: *mut __ptcb,
3019 robust_list: robust_list_head,
3020}
3021
3022static mut THREADS: [Thread; MAX_THREADS] = [Thread {
3023 tid: -1,
3024 detach_state: DT_JOINABLE,
3025 result: core::ptr::null_mut(),
3026 cancel: 0,
3027 cancel_state: PTHREAD_CANCEL_ENABLE,
3028 cancel_type: PTHREAD_CANCEL_DEFERRED,
3029 user_fn: 0,
3030 user_arg: core::ptr::null_mut(),
3031 stack: core::ptr::null_mut(),
3032 stack_size: 0,
3033 fs_base: core::ptr::null_mut(),
3034 tsd: [core::ptr::null_mut(); PTHREAD_KEYS_MAX],
3035 cancelbuf: core::ptr::null_mut(),
3036 robust_list: robust_list_head {
3037 list: robust_list { next: core::ptr::null_mut() },
3038 futex_offset: 0,
3039 pending: core::ptr::null_mut(),
3040 },
3041}; MAX_THREADS];
3042static NEXT_SLOT: AtomicUsize = AtomicUsize::new(0);
3043static mut KEY_DTORS: [Option<unsafe extern "C" fn(*mut c_void)>; PTHREAD_KEYS_MAX] = [None; PTHREAD_KEYS_MAX];
3044static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
3045
3046unsafe fn futex_wait(addr: *mut c_int, expected: c_int) -> c_int {
3048 let r = sys_futex(addr, FUTEX_WAIT, expected, null_mut(), null_mut(), 0);
3049 if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3050}
3051
3052unsafe fn futex_wake(addr: *mut c_int, count: c_int) {
3053 let c = if count < 0 { c_int::MAX } else { count };
3054 sys_futex(addr, FUTEX_WAKE, c, null_mut(), null_mut(), 0);
3055}
3056
3057unsafe fn futex_lock_pi(addr: *mut c_int, abs_timeout: *const timespec) -> c_int {
3058 let timeout_ptr = if abs_timeout.is_null() { null_mut() } else { abs_timeout as *mut c_void };
3059 let r = sys_futex(addr, FUTEX_LOCK_PI, 0, timeout_ptr, null_mut(), 0);
3060 if r < 0 { (-r) as c_int } else { 0 }
3061}
3062
3063unsafe fn futex_unlock_pi(addr: *mut c_int) -> c_int {
3064 let r = sys_futex(addr, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
3065 if r < 0 { (-r) as c_int } else { 0 }
3066}
3067
3068#[inline]
3069unsafe fn sys_set_robust_list(head: *mut robust_list_head, len: usize) -> i64 {
3070 <Arch as Syscalls>::syscall2(SYS_SET_ROBUST_LIST, head as i64, len as i64)
3071}
3072
3073unsafe fn futex_timedwait(addr: *mut c_int, expected: c_int, abs_timeout: *const timespec) -> c_int {
3074 if abs_timeout.is_null() { return futex_wait(addr, expected); }
3075 let mut now: timespec = core::mem::zeroed();
3076 if sys_clock_gettime(CLOCK_REALTIME, &mut now) < 0 { return EINVAL; }
3077 let mut rel: timespec = core::mem::zeroed();
3078 rel.tv_sec = (*abs_timeout).tv_sec - now.tv_sec;
3079 rel.tv_nsec = (*abs_timeout).tv_nsec - now.tv_nsec;
3080 if rel.tv_nsec < 0 { rel.tv_sec -= 1; rel.tv_nsec += 1_000_000_000; }
3081 if rel.tv_sec < 0 { return ETIMEDOUT; }
3082 let r = sys_futex(addr, FUTEX_WAIT, expected, &mut rel as *mut timespec as *mut c_void, null_mut(), 0);
3083 if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3084}
3085
3086unsafe fn a_cas(addr: *mut c_int, expected: c_int, desired: c_int) -> c_int {
3088 let a = &*(addr as *const AtomicI32);
3089 match a.compare_exchange(expected, desired, Ordering::AcqRel, Ordering::Acquire) {
3090 Ok(v) | Err(v) => v,
3091 }
3092}
3093
3094unsafe fn a_store(addr: *mut c_int, val: c_int) {
3095 (*(addr as *const AtomicI32)).store(val, Ordering::Release);
3096}
3097
3098unsafe fn a_load(addr: *const c_int) -> c_int {
3099 (*(addr as *const AtomicI32)).load(Ordering::Acquire)
3100}
3101
3102unsafe fn a_swap(addr: *mut c_int, val: c_int) -> c_int {
3103 (*(addr as *const AtomicI32)).swap(val, Ordering::AcqRel)
3104}
3105
3106unsafe fn a_fetch_add(addr: *mut c_int, val: c_int) -> c_int {
3107 (*(addr as *const AtomicI32)).fetch_add(val, Ordering::AcqRel)
3108}
3109
3110unsafe fn a_fetch_sub(addr: *mut c_int, val: c_int) -> c_int {
3111 (*(addr as *const AtomicI32)).fetch_sub(val, Ordering::AcqRel)
3112}
3113
3114unsafe fn spinlock_lock(lock: *mut c_int, waiters: *mut c_int) {
3115 while a_swap(lock, 1) != 0 {
3116 let mut spins = 100;
3117 while spins > 0 && a_load(lock) != 0 { core::hint::spin_loop(); spins -= 1; }
3118 if a_load(lock) == 0 { continue; }
3119 a_fetch_add(waiters, 1);
3120 futex_wait(lock, 1);
3121 a_fetch_sub(waiters, 1);
3122 }
3123}
3124
3125unsafe fn spinlock_unlock(lock: *mut c_int, waiters: *mut c_int) {
3126 a_store(lock, 0);
3127 if a_load(waiters) > 0 { futex_wake(lock, 1); }
3128}
3129
3130unsafe fn alloc_thread_slot() -> Option<&'static mut Thread> {
3131 let idx = NEXT_SLOT.fetch_add(1, Ordering::SeqCst);
3132 if idx >= MAX_THREADS { return None; }
3133 Some(&mut THREADS[idx])
3134}
3135
3136unsafe fn run_key_dtors(slot: &mut Thread) {
3137 for _ in 0..PTHREAD_DESTRUCTOR_ITERATIONS {
3138 let mut any = false;
3139 for i in 0..PTHREAD_KEYS_MAX {
3140 let val = slot.tsd[i];
3141 if !val.is_null() {
3142 if let Some(dtor) = KEY_DTORS[i] {
3143 slot.tsd[i] = core::ptr::null_mut();
3144 any = true;
3145 dtor(val);
3146 }
3147 }
3148 }
3149 if !any { break; }
3150 }
3151}
3152
3153unsafe extern "C" fn thread_entry(slot: *mut c_void) -> *mut c_void {
3154 let slot = &mut *(slot as *mut Thread);
3155 let mut set: SigSetT = 0;
3156 sigemptyset(&mut set);
3157 sigaddset(&mut set, SIGCANCEL);
3158 pthread_sigmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
3159 let user_fn: unsafe extern "C" fn(*mut c_void) -> *mut c_void =
3160 core::mem::transmute::<usize, _>(slot.user_fn);
3161 let ret = user_fn(slot.user_arg);
3162 run_key_dtors(slot);
3163 slot.result = ret;
3164 a_store(&raw mut slot.detach_state, DT_EXITED);
3165 futex_wake(&raw mut slot.detach_state, 1);
3166 sys_exit_thread(0)
3167}
3168
3169unsafe fn find_thread() -> Option<&'static mut Thread> {
3170 let me = sys_gettid() as c_int;
3171 let base = core::ptr::addr_of_mut!(THREADS[0]);
3172 for i in 0..MAX_THREADS {
3173 let slot = base.add(i);
3174 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3175 return Some(&mut *slot);
3176 }
3177 }
3178 pthread_self();
3180 for i in 0..MAX_THREADS {
3181 let slot = base.add(i);
3182 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3183 return Some(&mut *slot);
3184 }
3185 }
3186 None
3187}
3188
3189#[no_mangle]
3190pub unsafe extern "C" fn pthread_self() -> PthreadT {
3191 let me = sys_gettid() as c_int;
3192 let base = core::ptr::addr_of_mut!(THREADS[0]);
3193 for i in 0..MAX_THREADS {
3194 let slot = base.add(i);
3195 if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3196 return slot as PthreadT;
3197 }
3198 }
3199 let idx = NEXT_SLOT.fetch_add(1, Ordering::SeqCst);
3201 if idx < MAX_THREADS {
3202 let slot = &raw mut THREADS[idx];
3203 (*slot).tid = me;
3204 (*slot).detach_state = DT_JOINABLE;
3205 return slot as PthreadT;
3206 }
3207 0
3208}
3209
3210#[no_mangle]
3211pub unsafe extern "C" fn pthread_equal(t1: PthreadT, t2: PthreadT) -> c_int {
3212 (t1 == t2) as c_int
3213}
3214
3215#[no_mangle]
3216pub unsafe extern "C" fn pthread_create(
3217 thread: *mut PthreadT,
3218 attr: *const pthread_attr_t,
3219 start_routine: usize,
3220 arg: *mut c_void,
3221) -> c_int {
3222 if start_routine == 0 || thread.is_null() { return EINVAL; }
3223 let Some(slot_ref) = alloc_thread_slot() else { return EAGAIN; };
3224 let slot = slot_ref as *mut Thread;
3225 let stack_size = if !attr.is_null() {
3226 let s = *((*attr).__i.as_ptr() as *const usize);
3227 if s > 0 { s } else { STACK_SIZE }
3228 } else { STACK_SIZE };
3229 let stack = sys_mmap(null_mut(), stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
3230 if stack == MMAP_FAILED { return EAGAIN; }
3231 let fs_base = __rc_create_thread_tls();
3232 if fs_base.is_null() { sys_munmap(stack, stack_size); return EAGAIN; }
3233 (*slot).detach_state = DT_JOINABLE;
3234 (*slot).result = core::ptr::null_mut();
3235 (*slot).cancel = 0;
3236 (*slot).cancel_state = PTHREAD_CANCEL_ENABLE;
3237 (*slot).cancel_type = PTHREAD_CANCEL_DEFERRED;
3238 core::ptr::write_bytes((*slot).tsd.as_mut_ptr(), 0, PTHREAD_KEYS_MAX);
3239 (*slot).tid = 1;
3240 (*slot).user_fn = start_routine;
3241 (*slot).user_arg = arg;
3242 (*slot).stack = stack;
3243 (*slot).stack_size = stack_size;
3244 (*slot).fs_base = fs_base;
3245 let stack_top = stack.add(stack_size);
3246 let tid_ptr = &raw mut (*slot).tid;
3247 let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD
3248 | CLONE_SYSVSEM | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS;
3249 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);
3250 if tid < 0 {
3251 (*slot).tid = -1;
3252 sys_munmap(stack, stack_size);
3253 sys_munmap(fs_base.sub(__rc_tls_base_offset()), __rc_tls_block_size());
3254 return EAGAIN;
3255 }
3256 if !attr.is_null() && (*attr).__i[6] == PTHREAD_CREATE_DETACHED {
3257 (*slot).detach_state = DT_DETACHED;
3258 }
3259 *thread = slot as PthreadT;
3260 0
3261}
3262
3263#[no_mangle]
3264pub unsafe extern "C" fn pthread_join(thread: PthreadT, retval: *mut *mut c_void) -> c_int {
3265 let slot = thread as *mut Thread;
3266 if slot.is_null() { return EINVAL; }
3267 if (*slot).detach_state == DT_DETACHED { return EINVAL; }
3268 let tid_ptr = &raw mut (*slot).tid;
3269 loop {
3270 pthread_testcancel();
3271 let tid = core::ptr::read_volatile(tid_ptr);
3272 if tid == 0 { break; }
3273 if tid < 0 { return EINVAL; }
3274 sys_futex(tid_ptr, FUTEX_WAIT, tid, null_mut(), null_mut(), 0);
3275 pthread_testcancel();
3276 }
3277 if !retval.is_null() { *retval = (*slot).result; }
3278 let stack = (*slot).stack;
3279 let stack_size = (*slot).stack_size;
3280 let fs_base = (*slot).fs_base;
3281 (*slot).tid = -1;
3282 (*slot).detach_state = DT_JOINABLE;
3283 (*slot).result = core::ptr::null_mut();
3284 (*slot).stack = core::ptr::null_mut();
3285 (*slot).stack_size = 0;
3286 (*slot).fs_base = core::ptr::null_mut();
3287 if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3288 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); } }
3289 0
3290}
3291
3292#[no_mangle]
3293pub unsafe extern "C" fn pthread_detach(thread: PthreadT) -> c_int {
3294 let slot = thread as *mut Thread;
3295 if slot.is_null() { return EINVAL; }
3296 let old = a_cas(&raw mut (*slot).detach_state, DT_JOINABLE, DT_DETACHED);
3297 if old == DT_EXITED {
3298 let stack = (*slot).stack;
3299 let stack_size = (*slot).stack_size;
3300 let fs_base = (*slot).fs_base;
3301 (*slot).tid = -1;
3302 (*slot).stack = core::ptr::null_mut();
3303 (*slot).stack_size = 0;
3304 (*slot).fs_base = core::ptr::null_mut();
3305 if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3306 if !fs_base.is_null() { let bs = __rc_tls_block_size(); let bo = __rc_tls_base_offset(); sys_munmap(fs_base.sub(bo), bs); }
3307 }
3308 0
3309}
3310
3311#[no_mangle]
3312pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! {
3313 if let Some(slot) = find_thread() {
3314 run_cleanup_handlers(slot);
3315 run_key_dtors(slot);
3316 slot.result = retval;
3317 slot.detach_state = DT_EXITED;
3318 futex_wake(&slot.detach_state as *const c_int as *mut c_int, 1);
3319
3320 let mut active = 0usize;
3322 for i in 0..MAX_THREADS {
3323 if THREADS[i].tid > 0 {
3324 active += 1;
3325 }
3326 }
3327 if active == 1 {
3328 exit(0);
3329 }
3330 }
3331 sys_exit_thread(0);
3332}
3333
3334#[no_mangle]
3336pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int {
3337 core::ptr::write_bytes(attr, 0, 1);
3338 *((*attr).__i.as_mut_ptr() as *mut usize) = STACK_SIZE;
3339 *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = 4096;
3340 (*attr).__i[6] = PTHREAD_CREATE_JOINABLE;
3341 (*attr).__i[7] = PTHREAD_INHERIT_SCHED;
3342 0
3343}
3344#[no_mangle]
3345pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut pthread_attr_t) -> c_int { 0 }
3346#[no_mangle]
3347pub unsafe extern "C" fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, s: c_int) -> c_int {
3348 if s != PTHREAD_CREATE_JOINABLE && s != PTHREAD_CREATE_DETACHED { return EINVAL; }
3349 (*attr).__i[6] = s; 0
3350}
3351#[no_mangle]
3352pub unsafe extern "C" fn pthread_attr_getdetachstate(attr: *const pthread_attr_t, s: *mut c_int) -> c_int {
3353 *s = (*attr).__i[6]; 0
3354}
3355#[no_mangle]
3356pub unsafe extern "C" fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3357 if sz < 16384 { return EINVAL; }
3358 *((*attr).__i.as_mut_ptr() as *mut usize) = sz; 0
3359}
3360#[no_mangle]
3361pub unsafe extern "C" fn pthread_attr_getstacksize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3362 *sz = *((*attr).__i.as_ptr() as *const usize); 0
3363}
3364#[no_mangle]
3365pub unsafe extern "C" fn pthread_attr_setstack(attr: *mut pthread_attr_t, addr: *mut c_void, sz: usize) -> c_int {
3366 if sz < 16384 { return EINVAL; }
3367 *((*attr).__i.as_mut_ptr() as *mut usize) = sz;
3368 *((*attr).__i.as_mut_ptr().add(4) as *mut *mut c_void) = addr; 0
3369}
3370#[no_mangle]
3371pub unsafe extern "C" fn pthread_attr_getstack(attr: *const pthread_attr_t, addr: *mut *mut c_void, sz: *mut usize) -> c_int {
3372 *sz = *((*attr).__i.as_ptr() as *const usize);
3373 *addr = *((*attr).__i.as_ptr().add(4) as *const *mut c_void); 0
3374}
3375#[no_mangle]
3376pub unsafe extern "C" fn pthread_attr_setguardsize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3377 *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = sz; 0
3378}
3379#[no_mangle]
3380pub unsafe extern "C" fn pthread_attr_getguardsize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3381 *sz = *((*attr).__i.as_ptr().add(2) as *const usize); 0
3382}
3383#[no_mangle]
3384pub unsafe extern "C" fn pthread_attr_setscope(_attr: *mut pthread_attr_t, scope: c_int) -> c_int {
3385 if scope != PTHREAD_SCOPE_SYSTEM { return EINVAL; }
3386 0
3387}
3388#[no_mangle]
3389pub unsafe extern "C" fn pthread_attr_getscope(_attr: *const pthread_attr_t, scope: *mut c_int) -> c_int {
3390 *scope = PTHREAD_SCOPE_SYSTEM; 0
3391}
3392#[no_mangle]
3393pub unsafe extern "C" fn pthread_attr_setinheritsched(attr: *mut pthread_attr_t, inh: c_int) -> c_int {
3394 if inh != PTHREAD_INHERIT_SCHED && inh != PTHREAD_EXPLICIT_SCHED { return EINVAL; }
3395 (*attr).__i[7] = inh; 0
3396}
3397#[no_mangle]
3398pub unsafe extern "C" fn pthread_attr_getinheritsched(attr: *const pthread_attr_t, inh: *mut c_int) -> c_int {
3399 *inh = (*attr).__i[7]; 0
3400}
3401#[no_mangle]
3402pub unsafe extern "C" fn pthread_attr_setschedpolicy(attr: *mut pthread_attr_t, p: c_int) -> c_int {
3403 (*attr).__i[8] = p; 0
3404}
3405#[no_mangle]
3406pub unsafe extern "C" fn pthread_attr_getschedpolicy(attr: *const pthread_attr_t, p: *mut c_int) -> c_int {
3407 *p = (*attr).__i[8]; 0
3408}
3409#[no_mangle]
3410pub unsafe extern "C" fn pthread_attr_setschedparam(attr: *mut pthread_attr_t, param: *const sched_param) -> c_int {
3411 (*attr).__i[9] = (*param).sched_priority; 0
3412}
3413#[no_mangle]
3414pub unsafe extern "C" fn pthread_attr_getschedparam(attr: *const pthread_attr_t, param: *mut sched_param) -> c_int {
3415 (*param).sched_priority = (*attr).__i[9]; 0
3416}
3417
3418#[no_mangle]
3420pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
3421 (*attr).__attr = 0; 0
3422}
3423#[no_mangle]
3424pub unsafe extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int { 0 }
3425#[no_mangle]
3426pub unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, t: c_int) -> c_int {
3427 if (t as c_uint) > 2 { return EINVAL; }
3428 (*attr).__attr = ((*attr).__attr & !3) | t as c_uint; 0
3429}
3430#[no_mangle]
3431pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, t: *mut c_int) -> c_int {
3432 *t = ((*attr).__attr & 3) as c_int; 0
3433}
3434#[no_mangle]
3435pub unsafe extern "C" fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, p: c_int) -> c_int {
3436 if (p as c_uint) > 1 { return EINVAL; }
3437 (*attr).__attr = ((*attr).__attr & !128) | ((p as c_uint) << 7); 0
3438}
3439#[no_mangle]
3440pub unsafe extern "C" fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, p: *mut c_int) -> c_int {
3441 *p = (((*attr).__attr >> 7) & 1) as c_int; 0
3442}
3443
3444#[no_mangle]
3445pub unsafe extern "C" fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int {
3446 match protocol {
3447 0 => { (*attr).__attr &= !(MUTEX_PI as c_uint); 0 }
3448 1 => {
3449 let mut lk: c_int = 0;
3450 let r = sys_futex(&raw mut lk, FUTEX_LOCK_PI, 0, null_mut(), null_mut(), 0);
3451 if r < 0 { return (-r) as c_int; }
3452 sys_futex(&raw mut lk, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
3453 (*attr).__attr |= MUTEX_PI as c_uint;
3454 0
3455 }
3456 2 => ENOTSUP,
3457 _ => EINVAL,
3458 }
3459}
3460#[no_mangle]
3461pub unsafe extern "C" fn pthread_mutexattr_getprotocol(attr: *const pthread_mutexattr_t, protocol: *mut c_int) -> c_int {
3462 *protocol = (((*attr).__attr >> 3) & 3) as c_int; 0
3463}
3464
3465const ENOTSUP: c_int = 95;
3466
3467#[no_mangle]
3468pub unsafe extern "C" fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robust: c_int) -> c_int {
3469 if (robust as c_uint) > 1 { return EINVAL; }
3470 if robust != 0 {
3471 (*attr).__attr |= MUTEX_ROBUST as c_uint;
3472 } else {
3473 (*attr).__attr &= !(MUTEX_ROBUST as c_uint);
3474 }
3475 0
3476}
3477#[no_mangle]
3478pub unsafe extern "C" fn pthread_mutexattr_getrobust(attr: *const pthread_mutexattr_t, robust: *mut c_int) -> c_int {
3479 *robust = (((*attr).__attr >> 2) & 1) as c_int; 0
3480}
3481
3482#[no_mangle]
3483pub unsafe extern "C" fn pthread_mutex_consistent(m: *mut pthread_mutex_t) -> c_int {
3484 let old = a_load(&raw const (*m).__i[1]);
3485 let own = old & 0x3fffffff;
3486 if ((*m).__i[0] & MUTEX_ROBUST) == 0 || own == 0 || (old & 0x40000000) == 0 {
3487 return EINVAL;
3488 }
3489 let self_tid = sys_gettid() as c_int;
3490 if own != self_tid { return EPERM; }
3491 a_and(&raw mut (*m).__i[1], !(0x40000000i32));
3492 0
3493}
3494
3495unsafe fn a_and(addr: *mut c_int, val: c_int) {
3496 let a = &*(addr as *const AtomicI32);
3497 a.fetch_and(val, Ordering::AcqRel);
3498}
3499
3500const MUTEX_TYPE_MASK: c_int = 3;
3502const MUTEX_ROBUST: c_int = 4;
3503const MUTEX_PI: c_int = 8;
3504const MUTEX_PSHARED: c_int = 128;
3505
3506unsafe fn ensure_robust_list(slot: &mut Thread) {
3507 if slot.robust_list.futex_offset == 0 {
3508 slot.robust_list.futex_offset = -28;
3509 slot.robust_list.pending = core::ptr::null_mut();
3510 sys_set_robust_list(&mut slot.robust_list, 24);
3511 }
3512}
3513
3514unsafe fn mutex_trylock(m: *mut pthread_mutex_t) -> c_int {
3515 let type_ = (*m).__i[0];
3516 if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL {
3518 return a_cas(&raw mut (*m).__i[1], 0, EBUSY) & EBUSY;
3519 }
3520 let base_type = type_ & MUTEX_TYPE_MASK;
3521 let self_tid = sys_gettid() as c_int;
3522 let old = a_load(&raw const (*m).__i[1]);
3523 let own = old & 0x3fffffff;
3524 if own == self_tid {
3525 if (type_ & MUTEX_PI) != 0 && (*m).__i[5] < 0 {
3526 (*m).__i[5] = 0;
3527 return 0;
3528 }
3529 if base_type == PTHREAD_MUTEX_RECURSIVE {
3530 if (*m).__i[5] >= c_int::MAX { return EAGAIN; }
3531 (*m).__i[5] += 1;
3532 return 0;
3533 }
3534 if base_type == PTHREAD_MUTEX_ERRORCHECK { return EDEADLK; }
3535 return EBUSY;
3536 }
3537 if own == 0x3fffffff { return ENOTRECOVERABLE; }
3538 if own != 0 || (old != 0 && (type_ & MUTEX_ROBUST) == 0) { return EBUSY; }
3539 let mut newtid = self_tid;
3540 if (type_ & MUTEX_ROBUST) != 0 {
3541 if (*m).__i[2] != 0 { newtid |= 1i32 << 31; }
3542 newtid |= old & 0x40000000;
3543 }
3544 if a_cas(&raw mut (*m).__i[1], old, newtid) == old {
3545 (*m).__i[5] = 0;
3546 if (type_ & MUTEX_ROBUST) != 0 {
3547 if let Some(slot) = find_thread() {
3548 ensure_robust_list(slot);
3549 let m_next = &raw mut (*m).__i[8] as *mut robust_list;
3550 let head = &mut slot.robust_list.list;
3551 (*m_next).next = head.next;
3552 head.next = m_next;
3553 }
3554 }
3555 if old != 0 { return EOWNERDEAD; }
3556 0
3557 } else { EBUSY }
3558}
3559
3560unsafe fn mutex_lock_internal(m: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3561 let type_ = (*m).__i[0];
3562 if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL && a_cas(&raw mut (*m).__i[1], 0, EBUSY) == 0 {
3563 return 0;
3564 }
3565 let r = mutex_trylock(m);
3566 if r != EBUSY { return r; }
3567 if (type_ & MUTEX_PI) != 0 {
3568 let timeout_ptr = if abs_timeout.is_null() { core::ptr::null() } else { abs_timeout };
3569 loop {
3570 let e = futex_lock_pi(&raw mut (*m).__i[1], timeout_ptr);
3571 match e {
3572 0 => {
3573 if (type_ & MUTEX_ROBUST) != 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
3574 (*m).__i[5] = -1;
3575 let _ = mutex_trylock(m);
3576 return EOWNERDEAD;
3577 }
3578 if (type_ & MUTEX_ROBUST) == 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
3579 (*m).__i[2] = -1;
3580 futex_unlock_pi(&raw mut (*m).__i[1]);
3581 return EBUSY;
3582 }
3583 (*m).__i[5] = -1;
3584 let r2 = mutex_trylock(m);
3585 if r2 == 0 { return 0; }
3586 return r2;
3587 }
3588 EINTR => continue,
3589 EDEADLK => {
3590 if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK { return e; }
3591 loop { pause(); }
3592 }
3593 EOWNERDEAD => {
3594 (*m).__i[5] = -1;
3595 let _ = mutex_trylock(m);
3596 return EOWNERDEAD;
3597 }
3598 _ => return e,
3599 }
3600 }
3601 }
3602 let mut spins = 100;
3603 while spins > 0 {
3604 let r = mutex_trylock(m);
3605 if r != EBUSY { return r; }
3606 core::hint::spin_loop();
3607 spins -= 1;
3608 }
3609 loop {
3610 let r = mutex_trylock(m);
3611 if r != EBUSY { return r; }
3612 if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK {
3613 let self_tid = sys_gettid() as c_int;
3614 if (a_load(&raw const (*m).__i[1]) & 0x3fffffff) == self_tid { return EDEADLK; }
3615 }
3616 a_fetch_add(&raw mut (*m).__i[2], 1);
3617 let val = a_load(&raw const (*m).__i[1]);
3618 a_cas(&raw mut (*m).__i[1], val, val | (1i32 << 31));
3619 let e = futex_timedwait(&raw mut (*m).__i[1], val | (1i32 << 31), abs_timeout);
3620 a_fetch_sub(&raw mut (*m).__i[2], 1);
3621 if e != 0 && e != EINTR { return e; }
3622 }
3623}
3624
3625#[no_mangle]
3626pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) -> c_int {
3627 core::ptr::write_bytes(mutex, 0, 1);
3628 if !attr.is_null() { (*mutex).__i[0] = (*attr).__attr as c_int; }
3629 0
3630}
3631#[no_mangle]
3632pub unsafe extern "C" fn pthread_mutex_destroy(_mutex: *mut pthread_mutex_t) -> c_int { 0 }
3633#[no_mangle]
3634pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
3635 mutex_lock_internal(mutex, core::ptr::null())
3636}
3637#[no_mangle]
3638pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int {
3639 mutex_trylock(mutex)
3640}
3641#[no_mangle]
3642pub unsafe extern "C" fn pthread_mutex_timedlock(mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3643 mutex_lock_internal(mutex, abs_timeout)
3644}
3645#[no_mangle]
3646pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
3647 let type_ = (*mutex).__i[0];
3648 let base_type = type_ & MUTEX_TYPE_MASK;
3649 let old = a_load(&raw const (*mutex).__i[1]);
3650 if base_type != PTHREAD_MUTEX_NORMAL {
3651 let self_tid = sys_gettid() as c_int;
3652 if (old & 0x3fffffff) != self_tid { return EPERM; }
3653 if base_type == PTHREAD_MUTEX_RECURSIVE && (*mutex).__i[5] > 0 {
3654 (*mutex).__i[5] -= 1;
3655 return 0;
3656 }
3657 }
3658 let mut new = 0;
3659 if (type_ & MUTEX_ROBUST) != 0 && (old & 0x40000000) != 0 {
3660 new = 0x7fffffff;
3661 }
3662 if (type_ & MUTEX_PI) != 0 {
3663 if old < 0 || a_cas(&raw mut (*mutex).__i[1], old, new) != old {
3664 if new != 0 { a_store(&raw mut (*mutex).__i[2], -1); }
3665 return futex_unlock_pi(&raw mut (*mutex).__i[1]);
3666 }
3667 return 0;
3668 }
3669 a_store(&raw mut (*mutex).__i[1], new);
3670 if new == 0 && (a_load(&raw const (*mutex).__i[2]) > 0 || old < 0) {
3671 futex_wake(&raw mut (*mutex).__i[1], 1);
3672 }
3673 0
3674}
3675
3676#[no_mangle]
3678pub unsafe extern "C" fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int {
3679 (*attr).__attr = 0; 0
3680}
3681#[no_mangle]
3682pub unsafe extern "C" fn pthread_condattr_destroy(_attr: *mut pthread_condattr_t) -> c_int { 0 }
3683#[no_mangle]
3684pub unsafe extern "C" fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clk: c_int) -> c_int {
3685 if clk != CLOCK_REALTIME && clk != CLOCK_MONOTONIC { return EINVAL; }
3686 (*attr).__attr = ((*attr).__attr & 0x80000000) | clk as c_uint; 0
3687}
3688#[no_mangle]
3689pub unsafe extern "C" fn pthread_condattr_getclock(attr: *const pthread_condattr_t, clk: *mut c_int) -> c_int {
3690 *clk = ((*attr).__attr & 0x7fffffff) as c_int; 0
3691}
3692#[no_mangle]
3693pub unsafe extern "C" fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, p: c_int) -> c_int {
3694 if (p as c_uint) > 1 { return EINVAL; }
3695 (*attr).__attr = ((*attr).__attr & 0x7fffffff) | ((p as c_uint) << 31); 0
3696}
3697#[no_mangle]
3698pub unsafe extern "C" fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, p: *mut c_int) -> c_int {
3699 *p = ((*attr).__attr >> 31) as c_int; 0
3700}
3701
3702#[no_mangle]
3704pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int {
3705 core::ptr::write_bytes(cond, 0, 1);
3706 if !attr.is_null() {
3707 (*cond).__i[4] = ((*attr).__attr & 0x7fffffff) as c_int;
3708 }
3709 0
3710}
3711#[no_mangle]
3712pub unsafe extern "C" fn pthread_cond_destroy(_cond: *mut pthread_cond_t) -> c_int { 0 }
3713#[no_mangle]
3714pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int {
3715 pthread_cond_timedwait(cond, mutex, core::ptr::null())
3716}
3717#[no_mangle]
3718pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
3719 pthread_testcancel();
3720 let seq_ptr = &raw mut (*cond).__i[2];
3721 let waiters_ptr = &raw mut (*cond).__i[3];
3722 let seq = a_load(seq_ptr);
3723 a_fetch_add(waiters_ptr, 1);
3724 pthread_mutex_unlock(mutex);
3725 let e = futex_timedwait(seq_ptr, seq, abs_timeout);
3726 a_fetch_sub(waiters_ptr, 1);
3727 let r = pthread_mutex_lock(mutex);
3728 if r != 0 { return r; }
3729 if e == EINTR {
3730 pthread_testcancel();
3731 }
3732 if e != 0 && e != EINTR { return e; }
3733 0
3734}
3735#[no_mangle]
3736pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int {
3737 if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
3738 a_fetch_add(&raw mut (*cond).__i[2], 1);
3739 futex_wake(&raw mut (*cond).__i[2], 1);
3740 0
3741}
3742#[no_mangle]
3743pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int {
3744 if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
3745 a_fetch_add(&raw mut (*cond).__i[2], 1);
3746 futex_wake(&raw mut (*cond).__i[2], -1);
3747 0
3748}
3749
3750#[no_mangle]
3752pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
3753 (*attr).__attr = [0; 2]; 0
3754}
3755#[no_mangle]
3756pub unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut pthread_rwlockattr_t) -> c_int { 0 }
3757#[no_mangle]
3758pub unsafe extern "C" fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, p: c_int) -> c_int {
3759 if (p as c_uint) > 1 { return EINVAL; }
3760 (*attr).__attr[0] = ((*attr).__attr[0] & !128) | ((p as c_uint) << 7); 0
3761}
3762#[no_mangle]
3763pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, p: *mut c_int) -> c_int {
3764 *p = (((*attr).__attr[0] >> 7) & 1) as c_int; 0
3765}
3766
3767unsafe fn rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int {
3769 loop {
3770 let val = a_load(&raw const (*rw).__i[0]);
3771 let cnt = val & 0x7fffffff;
3772 if cnt == 0x7fffffff { return EBUSY; }
3773 if cnt == 0x7ffffffe { return EAGAIN; }
3774 if a_cas(&raw mut (*rw).__i[0], val, val + 1) == val { return 0; }
3775 }
3776}
3777unsafe fn rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int {
3778 if a_cas(&raw mut (*rw).__i[0], 0, 0x7fffffff) == 0 { 0 } else { EBUSY }
3779}
3780unsafe fn rwlock_timedrdlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
3781 let r = rwlock_tryrdlock(rw);
3782 if r != EBUSY { return r; }
3783 let mut spins = 100;
3784 while spins > 0 { let r = rwlock_tryrdlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
3785 loop {
3786 let r = rwlock_tryrdlock(rw);
3787 if r != EBUSY { return r; }
3788 let val = a_load(&raw const (*rw).__i[0]);
3789 if val & 0x7fffffff != 0x7fffffff { continue; }
3790 a_fetch_add(&raw mut (*rw).__i[1], 1);
3791 a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
3792 let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
3793 a_fetch_sub(&raw mut (*rw).__i[1], 1);
3794 if e != 0 && e != EINTR { return e; }
3795 }
3796}
3797unsafe fn rwlock_timedwrlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
3798 let r = rwlock_trywrlock(rw);
3799 if r != EBUSY { return r; }
3800 let mut spins = 100;
3801 while spins > 0 { let r = rwlock_trywrlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
3802 loop {
3803 let r = rwlock_trywrlock(rw);
3804 if r != EBUSY { return r; }
3805 let val = a_load(&raw const (*rw).__i[0]);
3806 if val == 0 { continue; }
3807 a_fetch_add(&raw mut (*rw).__i[1], 1);
3808 a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
3809 let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
3810 a_fetch_sub(&raw mut (*rw).__i[1], 1);
3811 if e != 0 && e != EINTR { return e; }
3812 }
3813}
3814
3815#[no_mangle]
3816pub unsafe extern "C" fn pthread_rwlock_init(rw: *mut pthread_rwlock_t, attr: *const pthread_rwlockattr_t) -> c_int {
3817 core::ptr::write_bytes(rw, 0, 1);
3818 if !attr.is_null() { (*rw).__i[2] = (*attr).__attr[0] as c_int & 128; }
3819 0
3820}
3821#[no_mangle]
3822pub unsafe extern "C" fn pthread_rwlock_destroy(_rw: *mut pthread_rwlock_t) -> c_int { 0 }
3823#[no_mangle]
3824pub unsafe extern "C" fn pthread_rwlock_rdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedrdlock(rw, core::ptr::null()) }
3825#[no_mangle]
3826pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_tryrdlock(rw) }
3827#[no_mangle]
3828pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedrdlock(rw, t) }
3829#[no_mangle]
3830pub unsafe extern "C" fn pthread_rwlock_wrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedwrlock(rw, core::ptr::null()) }
3831#[no_mangle]
3832pub unsafe extern "C" fn pthread_rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_trywrlock(rw) }
3833#[no_mangle]
3834pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedwrlock(rw, t) }
3835#[no_mangle]
3836pub unsafe extern "C" fn pthread_rwlock_unlock(rw: *mut pthread_rwlock_t) -> c_int {
3837 loop {
3838 let val = a_load(&raw const (*rw).__i[0]);
3839 let cnt = val & 0x7fffffff;
3840 let new_val = if cnt == 0x7fffffff || cnt == 1 { 0 } else { val - 1 };
3841 if a_cas(&raw mut (*rw).__i[0], val, new_val) == val {
3842 if new_val == 0 && (a_load(&raw const (*rw).__i[1]) > 0 || val < 0) {
3843 futex_wake(&raw mut (*rw).__i[0], cnt);
3844 }
3845 return 0;
3846 }
3847 }
3848}
3849
3850#[no_mangle]
3852pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int { (*attr).__attr = 0; 0 }
3853#[no_mangle]
3854pub unsafe extern "C" fn pthread_barrierattr_destroy(_attr: *mut pthread_barrierattr_t) -> c_int { 0 }
3855#[no_mangle]
3856pub unsafe extern "C" fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, p: c_int) -> c_int {
3857 if (p as c_uint) > 1 { return EINVAL; }
3858 (*attr).__attr = p as c_uint; 0
3859}
3860#[no_mangle]
3861pub unsafe extern "C" fn pthread_barrierattr_getpshared(attr: *const pthread_barrierattr_t, p: *mut c_int) -> c_int {
3862 *p = (*attr).__attr as c_int; 0
3863}
3864
3865#[no_mangle]
3867pub unsafe extern "C" fn pthread_barrier_init(b: *mut pthread_barrier_t, _attr: *const pthread_barrierattr_t, count: c_uint) -> c_int {
3868 if count == 0 { return EINVAL; }
3869 core::ptr::write_bytes(b, 0, 1);
3870 (*b).__i[2] = count as c_int - 1;
3871 0
3872}
3873#[no_mangle]
3874pub unsafe extern "C" fn pthread_barrier_destroy(_b: *mut pthread_barrier_t) -> c_int { 0 }
3875#[no_mangle]
3876pub unsafe extern "C" fn pthread_barrier_wait(b: *mut pthread_barrier_t) -> c_int {
3877 let limit = (*b).__i[2];
3878 if limit == 0 { return PTHREAD_BARRIER_SERIAL_THREAD; }
3879 spinlock_lock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3880 let arrived = a_load(&raw const (*b).__i[3]) + 1;
3881 a_store(&raw mut (*b).__i[3], arrived);
3882 if arrived > limit {
3883 a_store(&raw mut (*b).__i[3], 0);
3884 let gen = a_load(&raw const (*b).__i[4]);
3885 a_store(&raw mut (*b).__i[4], gen + 1);
3886 spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3887 futex_wake(&raw mut (*b).__i[4], -1);
3888 return PTHREAD_BARRIER_SERIAL_THREAD;
3889 }
3890 let gen = a_load(&raw const (*b).__i[4]);
3891 spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
3892 while a_load(&raw const (*b).__i[4]) == gen {
3893 futex_wait(&raw mut (*b).__i[4], gen);
3894 }
3895 0
3896}
3897
3898#[no_mangle]
3900pub unsafe extern "C" fn pthread_spin_init(s: *mut pthread_spinlock_t, _pshared: c_int) -> c_int { a_store(s, 0); 0 }
3901#[no_mangle]
3902pub unsafe extern "C" fn pthread_spin_destroy(_s: *mut pthread_spinlock_t) -> c_int { 0 }
3903#[no_mangle]
3904pub unsafe extern "C" fn pthread_spin_lock(s: *mut pthread_spinlock_t) -> c_int {
3905 while a_load(s) != 0 || a_cas(s, 0, EBUSY) != 0 { core::hint::spin_loop(); }
3906 0
3907}
3908#[no_mangle]
3909pub unsafe extern "C" fn pthread_spin_trylock(s: *mut pthread_spinlock_t) -> c_int { a_cas(s, 0, EBUSY) }
3910#[no_mangle]
3911pub unsafe extern "C" fn pthread_spin_unlock(s: *mut pthread_spinlock_t) -> c_int { a_store(s, 0); 0 }
3912
3913#[no_mangle]
3915pub unsafe extern "C" fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int {
3916 if value > SEM_VALUE_MAX as c_uint { return EINVAL; }
3917 (*sem).__val[0] = value as c_int;
3918 (*sem).__val[1] = 0;
3919 (*sem).__val[2] = if pshared != 0 { 0 } else { 128 };
3920 0
3921}
3922#[no_mangle]
3923pub unsafe extern "C" fn sem_destroy(_sem: *mut sem_t) -> c_int { 0 }
3924
3925unsafe fn sem_trywait_internal(sem: *mut sem_t) -> c_int {
3926 loop {
3927 let val = a_load(&raw const (*sem).__val[0]);
3928 if val & SEM_VALUE_MAX == 0 { return EAGAIN; }
3929 if a_cas(&raw mut (*sem).__val[0], val, val - 1) == val { return 0; }
3930 }
3931}
3932
3933#[no_mangle]
3934pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
3935 if sem_trywait_internal(sem) == 0 { 0 } else { ERRNO = EAGAIN; -1 }
3936}
3937#[no_mangle]
3938pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int {
3939 pthread_testcancel();
3940 if sem_trywait_internal(sem) == 0 { return 0; }
3941 let mut spins = 100;
3942 while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
3943 loop {
3944 pthread_testcancel();
3945 if sem_trywait_internal(sem) == 0 { return 0; }
3946 let val = a_load(&raw const (*sem).__val[0]);
3947 if val & SEM_VALUE_MAX != 0 { continue; }
3948 a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
3949 a_fetch_add(&raw mut (*sem).__val[1], 1);
3950 futex_wait(&raw mut (*sem).__val[0], 1i32 << 31);
3951 a_fetch_sub(&raw mut (*sem).__val[1], 1);
3952 }
3953}
3954#[no_mangle]
3955pub unsafe extern "C" fn sem_timedwait(sem: *mut sem_t, abs_timeout: *const timespec) -> c_int {
3956 pthread_testcancel();
3957 if sem_trywait_internal(sem) == 0 { return 0; }
3958 let mut spins = 100;
3959 while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
3960 loop {
3961 pthread_testcancel();
3962 if sem_trywait_internal(sem) == 0 { return 0; }
3963 let val = a_load(&raw const (*sem).__val[0]);
3964 if val & SEM_VALUE_MAX != 0 { continue; }
3965 a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
3966 a_fetch_add(&raw mut (*sem).__val[1], 1);
3967 let e = futex_timedwait(&raw mut (*sem).__val[0], 1i32 << 31, abs_timeout);
3968 a_fetch_sub(&raw mut (*sem).__val[1], 1);
3969 if e != 0 && e != EINTR { ERRNO = e; return -1; }
3970 }
3971}
3972#[no_mangle]
3973pub unsafe extern "C" fn sem_post(sem: *mut sem_t) -> c_int {
3974 loop {
3975 let val = a_load(&raw const (*sem).__val[0]);
3976 if (val & SEM_VALUE_MAX) == SEM_VALUE_MAX { ERRNO = EOVERFLOW; return -1; }
3977 let mut new = val + 1;
3978 let waiters = a_load(&raw const (*sem).__val[1]);
3979 if waiters <= 1 { new &= !(1i32 << 31); }
3980 if a_cas(&raw mut (*sem).__val[0], val, new) == val {
3981 if val < 0 || waiters > 0 {
3982 futex_wake(&raw mut (*sem).__val[0], if waiters > 1 { 1 } else { -1 });
3983 }
3984 return 0;
3985 }
3986 }
3987}
3988#[no_mangle]
3989pub unsafe extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int {
3990 *sval = a_load(&raw const (*sem).__val[0]) & SEM_VALUE_MAX;
3991 0
3992}
3993
3994const NAME_MAX: usize = 255;
3999const SEM_NSEMS_MAX: usize = 256;
4000
4001static SEMTAB_LOCK: AtomicI32 = AtomicI32::new(0);
4003
4004struct SemEntry {
4005 ino: u64,
4006 sem: *mut sem_t,
4007 refcnt: u32,
4008}
4009
4010static mut SEMTAB: [SemEntry; SEM_NSEMS_MAX] = {
4012 const ZERO: SemEntry = SemEntry { ino: 0, sem: core::ptr::null_mut(), refcnt: 0 };
4013 [ZERO; SEM_NSEMS_MAX]
4014};
4015
4016unsafe fn semtab_lock() {
4017 while SEMTAB_LOCK.compare_exchange_weak(0, 1, Ordering::Acquire, Ordering::Relaxed).is_err() {
4018 core::hint::spin_loop();
4019 }
4020}
4021
4022unsafe fn semtab_unlock() {
4023 SEMTAB_LOCK.store(0, Ordering::Release);
4024}
4025
4026unsafe fn shm_mapname(name: *const c_char, buf: *mut u8) -> c_int {
4029 let mut p = name;
4030 while *p == b'/' as c_char { p = p.add(1); }
4032 let start = p;
4033 while *p != 0 && *p != b'/' as c_char { p = p.add(1); }
4035 let len = p.offset_from(start) as usize;
4036 if len == 0 || *p != 0 {
4038 ERRNO = EINVAL;
4039 return -1;
4040 }
4041 if len == 1 && *start == b'.' as c_char {
4042 ERRNO = EINVAL;
4043 return -1;
4044 }
4045 if len == 2 && *start == b'.' as c_char && *start.add(1) == b'.' as c_char {
4046 ERRNO = EINVAL;
4047 return -1;
4048 }
4049 if len > NAME_MAX {
4050 ERRNO = ENAMETOOLONG;
4051 return -1;
4052 }
4053 let prefix = b"/dev/shm/\0";
4055 let mut i = 0;
4056 while prefix[i] != 0 {
4057 *buf.add(i) = prefix[i];
4058 i += 1;
4059 }
4060 let mut j = 0;
4061 while j < len {
4062 *buf.add(i + j) = *start.add(j) as u8;
4063 j += 1;
4064 }
4065 *buf.add(i + j) = 0;
4066 (i + j) as c_int
4067}
4068
4069#[no_mangle]
4070pub unsafe extern "C" fn shm_open(name: *const c_char, flags: c_int, mode: mode_t) -> c_int {
4071 let mut buf = [0u8; 16 + NAME_MAX + 1];
4072 if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4073 let fd = sys_open(buf.as_ptr(), (flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4074 if fd < 0 { ERRNO = (-fd) as c_int; return -1; }
4075 fd as c_int
4076}
4077
4078#[no_mangle]
4079pub unsafe extern "C" fn shm_unlink(name: *const c_char) -> c_int {
4080 let mut buf = [0u8; 16 + NAME_MAX + 1];
4081 if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4082 let r = sys_unlink(buf.as_ptr());
4083 if r < 0 { ERRNO = (-r) as c_int; return -1; }
4084 0
4085}
4086
4087#[no_mangle]
4088pub unsafe extern "C" fn sem_open(name: *const c_char, flags: c_int, mut args: ...) -> *mut sem_t {
4089 let mut buf = [0u8; 16 + NAME_MAX + 1];
4090 if shm_mapname(name, buf.as_mut_ptr()).is_negative() {
4091 return core::ptr::null_mut(); }
4093
4094 let oflags = flags & (O_CREAT | O_EXCL);
4095
4096 semtab_lock();
4097
4098 let mut slot: c_int = -1;
4100 for i in 0..SEMTAB_LEN {
4101 if SEMTAB[i].sem.is_null() && slot < 0 { slot = i as c_int; }
4102 }
4103 if slot < 0 {
4104 ERRNO = EMFILE;
4105 semtab_unlock();
4106 return core::ptr::null_mut();
4107 }
4108 SEMTAB[slot as usize].sem = !0usize as *mut sem_t; semtab_unlock();
4111
4112 let mut mode: mode_t = 0;
4114 let mut value: c_uint = 0;
4115 if oflags & O_CREAT != 0 {
4116 mode = args.next_arg::<mode_t>() & 0o666;
4117 value = args.next_arg::<c_uint>();
4118 if value > SEM_VALUE_MAX as c_uint {
4119 ERRNO = EINVAL;
4120 semtab_lock();
4121 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4122 semtab_unlock();
4123 return core::ptr::null_mut();
4124 }
4125 }
4126
4127 if oflags != O_CREAT | O_EXCL {
4129 let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4130 if fd >= 0 {
4131 let map = sys_mmap(
4132 core::ptr::null_mut(),
4133 core::mem::size_of::<sem_t>(),
4134 PROT_READ | PROT_WRITE,
4135 MAP_SHARED,
4136 fd as i32,
4137 0,
4138 );
4139 sys_close(fd);
4140 if map != MMAP_FAILED {
4141 let st_ino = get_ino(fd as c_int, buf.as_ptr());
4142 return sem_register(map as *mut sem_t, st_ino, slot);
4143 }
4144 }
4145 if oflags == 0 {
4146 semtab_lock();
4148 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4149 semtab_unlock();
4150 return core::ptr::null_mut();
4151 }
4152 }
4153
4154 let mut tmp = [0u8; 32];
4156 let tmpname = b"/dev/shm/tmp-XXXXXX\0";
4157 tmp[..tmpname.len()].copy_from_slice(tmpname);
4158 let mut ts: timespec = core::mem::zeroed();
4160 sys_clock_gettime(0, &mut ts);
4161 let mut n = ts.tv_nsec;
4163 let mut pos = tmpname.len() - 1;
4164 tmp[pos] = 0;
4165 pos -= 1;
4166 loop {
4167 tmp[pos] = b'0' + (n % 10) as u8;
4168 n /= 10;
4169 if n == 0 || pos == 0 { break; }
4170 pos -= 1;
4171 }
4172 let tmp_path = tmp.as_ptr();
4174
4175 let mut newsem: sem_t = core::mem::zeroed();
4176 newsem.__val[0] = value as c_int;
4177 newsem.__val[1] = 0;
4178 newsem.__val[2] = 128; loop {
4181 let fd = sys_open(tmp_path as *const u8, (O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4182 if fd < 0 {
4183 if (-fd) as c_int == EEXIST { continue; }
4184 semtab_lock();
4185 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4186 semtab_unlock();
4187 return core::ptr::null_mut();
4188 }
4189 let written = sys_write(fd, &newsem as *const sem_t as *const u8, core::mem::size_of::<sem_t>());
4190 if written != core::mem::size_of::<sem_t>() as i64 {
4191 sys_close(fd);
4192 sys_unlink(tmp_path);
4193 semtab_lock();
4194 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4195 semtab_unlock();
4196 return core::ptr::null_mut();
4197 }
4198 let map = sys_mmap(
4199 core::ptr::null_mut(),
4200 core::mem::size_of::<sem_t>(),
4201 PROT_READ | PROT_WRITE,
4202 MAP_SHARED,
4203 fd as i32,
4204 0,
4205 );
4206 sys_close(fd);
4207 if map == MMAP_FAILED {
4208 sys_unlink(tmp_path);
4209 semtab_lock();
4210 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4211 semtab_unlock();
4212 return core::ptr::null_mut();
4213 }
4214 let r = sys_linkat(AT_FDCWD, tmp_path, AT_FDCWD, buf.as_ptr(), 0);
4216 let e = if r < 0 { (-r) as c_int } else { 0 };
4217 sys_unlink(tmp_path);
4218 if e == 0 {
4219 let st_ino = get_ino(-1, buf.as_ptr());
4220 return sem_register(map as *mut sem_t, st_ino, slot);
4221 }
4222 sys_munmap(map, core::mem::size_of::<sem_t>());
4223 if e != EEXIST || oflags == O_CREAT | O_EXCL {
4224 ERRNO = e;
4225 semtab_lock();
4226 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4227 semtab_unlock();
4228 return core::ptr::null_mut();
4229 }
4230 break;
4232 }
4233
4234 let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4236 if fd < 0 {
4237 semtab_lock();
4238 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4239 semtab_unlock();
4240 return core::ptr::null_mut();
4241 }
4242 let map = sys_mmap(
4243 core::ptr::null_mut(),
4244 core::mem::size_of::<sem_t>(),
4245 PROT_READ | PROT_WRITE,
4246 MAP_SHARED,
4247 fd as i32,
4248 0,
4249 );
4250 sys_close(fd);
4251 if map == MMAP_FAILED {
4252 semtab_lock();
4253 SEMTAB[slot as usize].sem = core::ptr::null_mut();
4254 semtab_unlock();
4255 return core::ptr::null_mut();
4256 }
4257 let st_ino = get_ino(-1, buf.as_ptr());
4258 sem_register(map as *mut sem_t, st_ino, slot)
4259}
4260
4261unsafe fn get_ino(_fd_hint: c_int, path: *const u8) -> u64 {
4262 let mut st: Stat = core::mem::zeroed();
4263 if sys_newfstatat(AT_FDCWD, path as *const c_char, &mut st as *mut Stat as *mut u8, 0) == 0 {
4264 st.st_ino
4265 } else {
4266 0
4267 }
4268}
4269
4270unsafe fn sem_register(map: *mut sem_t, ino: u64, slot_hint: c_int) -> *mut sem_t {
4271 semtab_lock();
4272 for i in 0..SEMTAB_LEN {
4274 if SEMTAB[i].ino == ino && !SEMTAB[i].sem.is_null() && SEMTAB[i].sem != !0usize as *mut sem_t {
4275 sys_munmap(map as *mut u8, core::mem::size_of::<sem_t>());
4277 SEMTAB[slot_hint as usize].sem = core::ptr::null_mut();
4278 SEMTAB[i].refcnt += 1;
4279 let ret = SEMTAB[i].sem;
4280 semtab_unlock();
4281 return ret;
4282 }
4283 }
4284 SEMTAB[slot_hint as usize].sem = map;
4286 SEMTAB[slot_hint as usize].ino = ino;
4287 SEMTAB[slot_hint as usize].refcnt = 1;
4288 semtab_unlock();
4289 map
4290}
4291
4292const SEMTAB_LEN: usize = SEM_NSEMS_MAX;
4293
4294#[no_mangle]
4295pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
4296 semtab_lock();
4297 for i in 0..SEMTAB_LEN {
4298 if SEMTAB[i].sem == sem {
4299 SEMTAB[i].refcnt -= 1;
4300 if SEMTAB[i].refcnt == 0 {
4301 SEMTAB[i].sem = core::ptr::null_mut();
4302 SEMTAB[i].ino = 0;
4303 semtab_unlock();
4304 sys_munmap(sem as *mut u8, core::mem::size_of::<sem_t>());
4305 return 0;
4306 }
4307 semtab_unlock();
4308 return 0;
4309 }
4310 }
4311 semtab_unlock();
4312 0
4313}
4314
4315#[no_mangle]
4316pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
4317 shm_unlink(name)
4318}
4319
4320#[no_mangle]
4322pub unsafe extern "C" fn pthread_once(control: *mut pthread_once_t, init_routine: Option<unsafe extern "C" fn()>) -> c_int {
4323 if a_load(control) == 2 { return 0; }
4324 loop {
4325 match a_cas(control, 0, 1) {
4326 0 => {
4327 if let Some(f) = init_routine { f(); }
4328 if a_swap(control, 2) == 3 { futex_wake(control, -1); }
4329 return 0;
4330 }
4331 1 => { a_cas(control, 1, 3); }
4332 3 => { futex_wait(control, 3); }
4333 _ => { return 0; }
4334 }
4335 }
4336}
4337
4338#[no_mangle]
4340pub unsafe extern "C" fn pthread_key_create(key: *mut pthread_key_t, dtor: Option<unsafe extern "C" fn(*mut c_void)>) -> c_int {
4341 let start = NEXT_KEY.load(Ordering::Relaxed);
4342 let mut j = start;
4343 loop {
4344 if KEY_DTORS[j].is_none() {
4345 KEY_DTORS[j] = dtor;
4346 NEXT_KEY.store((j + 1) % PTHREAD_KEYS_MAX, Ordering::Relaxed);
4347 *key = j as pthread_key_t;
4348 return 0;
4349 }
4350 j = (j + 1) % PTHREAD_KEYS_MAX;
4351 if j == start { return EAGAIN; }
4352 }
4353}
4354#[no_mangle]
4355pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int {
4356 KEY_DTORS[key as usize] = None;
4357 for i in 0..MAX_THREADS {
4358 if THREADS[i].tid > 0 { THREADS[i].tsd[key as usize] = core::ptr::null_mut(); }
4359 }
4360 0
4361}
4362#[no_mangle]
4363pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
4364 if let Some(slot) = find_thread() { slot.tsd[key as usize] } else { core::ptr::null_mut() }
4365}
4366#[no_mangle]
4367pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int {
4368 if let Some(slot) = find_thread() {
4369 slot.tsd[key as usize] = value as *mut c_void;
4370 0
4371 } else { EINVAL }
4372}
4373
4374unsafe fn run_cleanup_handlers(slot: &mut Thread) {
4376 let mut cb = slot.cancelbuf;
4377 while !cb.is_null() {
4378 let cur = &*cb;
4379 let f = cur.__f;
4380 let x = cur.__x;
4381 cb = cur.__next;
4382 if let Some(func) = f {
4383 func(x);
4384 }
4385 }
4386 slot.cancelbuf = core::ptr::null_mut();
4387}
4388
4389unsafe fn do_cancel() -> ! {
4390 if let Some(slot) = find_thread() {
4391 run_cleanup_handlers(slot);
4392 slot.result = !0usize as *mut c_void; slot.detach_state = DT_EXITED;
4394 futex_wake(&raw mut slot.detach_state, 1);
4395 }
4396 sys_exit_thread(0);
4397}
4398
4399extern "C" fn cancel_handler(_sig: c_int) {
4400 unsafe {
4401 if let Some(slot) = find_thread() {
4402 if slot.cancel != 0
4406 && slot.cancel_state == PTHREAD_CANCEL_ENABLE
4407 && slot.cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS
4408 {
4409 do_cancel();
4410 }
4411 }
4412 }
4413}
4414
4415static CANCEL_INIT: AtomicI32 = AtomicI32::new(0);
4416
4417unsafe fn ensure_cancel_handler() {
4418 if CANCEL_INIT.swap(1, Ordering::AcqRel) == 0 {
4419 let act = sigaction {
4420 sa_handler: cancel_handler as *const () as usize,
4421 sa_flags: SA_RESTORER,
4422 sa_restorer: sig_restorer as *const () as usize,
4423 sa_mask: [!0u64],
4424 };
4425 sys_rt_sigaction(SIGCANCEL, &act as *const sigaction, core::ptr::null_mut(), 8);
4426 }
4427}
4428
4429#[no_mangle]
4430pub unsafe extern "C" fn pthread_cancel(thread: PthreadT) -> c_int {
4431 let slot = thread as *mut Thread;
4432 if slot.is_null() { return EINVAL; }
4433 ensure_cancel_handler();
4434 a_store(&raw mut (*slot).cancel, 1);
4435 let tid = (*slot).tid;
4436 if tid > 0 {
4437 sys_tgkill(sys_getpid() as c_int, tid, SIGCANCEL);
4438 }
4439 0
4440}
4441#[no_mangle]
4442pub unsafe extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
4443 if state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE { return EINVAL; }
4444 if let Some(slot) = find_thread() {
4445 if !oldstate.is_null() { *oldstate = slot.cancel_state; }
4446 slot.cancel_state = state;
4447 0
4448 } else { EINVAL }
4449}
4450#[no_mangle]
4451pub unsafe extern "C" fn pthread_setcanceltype(type_: c_int, oldtype: *mut c_int) -> c_int {
4452 if type_ != PTHREAD_CANCEL_DEFERRED && type_ != PTHREAD_CANCEL_ASYNCHRONOUS { return EINVAL; }
4453 if let Some(slot) = find_thread() {
4454 if !oldtype.is_null() { *oldtype = slot.cancel_type; }
4455 slot.cancel_type = type_;
4456 0
4457 } else { EINVAL }
4458}
4459#[no_mangle]
4460pub unsafe extern "C" fn pthread_testcancel() {
4461 if let Some(slot) = find_thread() {
4462 if slot.cancel != 0 && slot.cancel_state == PTHREAD_CANCEL_ENABLE {
4463 do_cancel();
4464 }
4465 }
4466}
4467
4468#[no_mangle]
4469pub unsafe extern "C" fn _pthread_cleanup_push(cb: *mut __ptcb, f: Option<unsafe extern "C" fn(*mut c_void)>, x: *mut c_void) {
4470 (*cb).__f = f;
4471 (*cb).__x = x;
4472 if let Some(slot) = find_thread() {
4473 (*cb).__next = slot.cancelbuf;
4474 slot.cancelbuf = cb;
4475 } else {
4476 (*cb).__next = core::ptr::null_mut();
4477 }
4478}
4479
4480#[no_mangle]
4481pub unsafe extern "C" fn _pthread_cleanup_pop(cb: *mut __ptcb, run: c_int) {
4482 if let Some(slot) = find_thread() {
4483 slot.cancelbuf = (*cb).__next;
4484 }
4485 if run != 0 {
4486 if let Some(f) = (*cb).__f {
4487 f((*cb).__x);
4488 }
4489 }
4490}
4491
4492#[no_mangle]
4493pub unsafe extern "C" fn pthread_kill(thread: PthreadT, sig: c_int) -> c_int {
4494 let slot = thread as *mut Thread;
4495 if slot.is_null() { return EINVAL; }
4496 let tid = (*slot).tid;
4497 if tid <= 0 { return EINVAL; }
4498 if sys_tgkill(sys_getpid() as c_int, tid, sig) < 0 { -1 } else { 0 }
4499}
4500
4501#[no_mangle]
4502pub unsafe extern "C" fn pthread_sigmask(how: c_int, set: *const SigSetT, oldset: *mut SigSetT) -> c_int {
4503 sigprocmask(how, set, oldset)
4504}
4505
4506
4507#[repr(C)]
4508pub struct lconv {
4509 pub decimal_point: *mut c_char,
4510 pub thousands_sep: *mut c_char,
4511 pub grouping: *mut c_char,
4512 pub int_curr_symbol: *mut c_char,
4513 pub currency_symbol: *mut c_char,
4514 pub mon_decimal_point: *mut c_char,
4515 pub mon_thousands_sep: *mut c_char,
4516 pub mon_grouping: *mut c_char,
4517 pub positive_sign: *mut c_char,
4518 pub negative_sign: *mut c_char,
4519 pub int_frac_digits: c_char,
4520 pub frac_digits: c_char,
4521 pub p_cs_precedes: c_char,
4522 pub p_sep_by_space: c_char,
4523 pub n_cs_precedes: c_char,
4524 pub n_sep_by_space: c_char,
4525 pub p_sign_posn: c_char,
4526 pub n_sign_posn: c_char,
4527 pub int_p_cs_precedes: c_char,
4528 pub int_p_sep_by_space: c_char,
4529 pub int_n_cs_precedes: c_char,
4530 pub int_n_sep_by_space: c_char,
4531 pub int_p_sign_posn: c_char,
4532 pub int_n_sign_posn: c_char,
4533}
4534
4535static UTF8_NAME: [u8; 6] = [b'U', b'T', b'F', b'-', b'8', 0];
4536static C_NAME: [u8; 2] = [b'C', 0];
4537static mut LOCALE_NAME: *const c_char = C_NAME.as_ptr() as *const c_char;
4538static mut LOCALE_CTYPE_UTF8: bool = true;
4539static mut EMPTY_STR: [c_char; 1] = [0];
4540static mut DECIMAL_POINT: [c_char; 2] = [b'.' as c_char, 0];
4541static mut LCONV: lconv = lconv {
4542 decimal_point: core::ptr::null_mut(),
4543 thousands_sep: core::ptr::null_mut(),
4544 grouping: core::ptr::null_mut(),
4545 int_curr_symbol: core::ptr::null_mut(),
4546 currency_symbol: core::ptr::null_mut(),
4547 mon_decimal_point: core::ptr::null_mut(),
4548 mon_thousands_sep: core::ptr::null_mut(),
4549 mon_grouping: core::ptr::null_mut(),
4550 positive_sign: core::ptr::null_mut(),
4551 negative_sign: core::ptr::null_mut(),
4552 int_frac_digits: (-1i32) as c_char,
4553 frac_digits: (-1i32) as c_char,
4554 p_cs_precedes: (-1i32) as c_char,
4555 p_sep_by_space: (-1i32) as c_char,
4556 n_cs_precedes: (-1i32) as c_char,
4557 n_sep_by_space: (-1i32) as c_char,
4558 p_sign_posn: (-1i32) as c_char,
4559 n_sign_posn: (-1i32) as c_char,
4560 int_p_cs_precedes: (-1i32) as c_char,
4561 int_p_sep_by_space: (-1i32) as c_char,
4562 int_n_cs_precedes: (-1i32) as c_char,
4563 int_n_sep_by_space: (-1i32) as c_char,
4564 int_p_sign_posn: (-1i32) as c_char,
4565 int_n_sign_posn: (-1i32) as c_char,
4566};
4567
4568unsafe fn cstr_contains_ci(s: *const u8, needle: &[u8]) -> bool {
4569 let len = strlen(s as *const c_char) as usize;
4570 let s_slice = core::slice::from_raw_parts(s, len);
4571 if needle.len() > len { return false; }
4572 for i in 0..=len - needle.len() {
4573 if s_slice[i..i + needle.len()].eq_ignore_ascii_case(needle) {
4574 return true;
4575 }
4576 }
4577 false
4578}
4579
4580#[no_mangle]
4581pub unsafe extern "C" fn setlocale(_category: c_int, locale: *const c_char) -> *mut c_char {
4582 if locale.is_null() || *locale == 0 {
4583 return LOCALE_NAME as *mut c_char;
4584 }
4585 let name = locale as *const u8;
4586 if strcmp(name, b"C\0".as_ptr()) == 0 || strcmp(name, b"POSIX\0".as_ptr()) == 0 {
4587 LOCALE_CTYPE_UTF8 = false;
4588 return LOCALE_NAME as *mut c_char;
4589 }
4590 if cstr_contains_ci(name, b"UTF-8") || cstr_contains_ci(name, b"UTF8") {
4591 LOCALE_CTYPE_UTF8 = true;
4592 return LOCALE_NAME as *mut c_char;
4593 }
4594 core::ptr::null_mut()
4595}
4596
4597#[no_mangle]
4598pub unsafe extern "C" fn localeconv() -> *mut lconv {
4599 let empty = core::ptr::addr_of_mut!(EMPTY_STR) as *mut c_char;
4600 let lconv = core::ptr::addr_of_mut!(LCONV);
4601 (*lconv).decimal_point = core::ptr::addr_of_mut!(DECIMAL_POINT) as *mut c_char;
4602 (*lconv).thousands_sep = empty;
4603 (*lconv).grouping = empty;
4604 (*lconv).int_curr_symbol = empty;
4605 (*lconv).currency_symbol = empty;
4606 (*lconv).mon_decimal_point = empty;
4607 (*lconv).mon_thousands_sep = empty;
4608 (*lconv).mon_grouping = empty;
4609 (*lconv).positive_sign = empty;
4610 (*lconv).negative_sign = empty;
4611 lconv
4612}
4613
4614pub type locale_t = *mut c_void;
4615static mut CURRENT_LOCALE: locale_t = LC_GLOBAL_LOCALE;
4616
4617static mut C_LOCALE_STORAGE: c_int = 0;
4618const C_LOCALE: locale_t = core::ptr::addr_of_mut!(C_LOCALE_STORAGE) as locale_t;
4619const LC_GLOBAL_LOCALE: locale_t = usize::MAX as locale_t;
4620
4621#[no_mangle]
4622pub unsafe extern "C" fn newlocale(_mask: c_int, name: *const c_char, base: locale_t) -> locale_t {
4623 if !name.is_null() && *name != 0 {
4624 let n = name as *const u8;
4625 if strcmp(n, b"C\0".as_ptr()) != 0
4626 && strcmp(n, b"POSIX\0".as_ptr()) != 0
4627 {
4628 return core::ptr::null_mut();
4629 }
4630 }
4631 if base.is_null() || base == C_LOCALE || base == LC_GLOBAL_LOCALE {
4632 C_LOCALE
4633 } else {
4634 core::ptr::null_mut()
4635 }
4636}
4637
4638#[no_mangle]
4639pub unsafe extern "C" fn freelocale(_loc: locale_t) {}
4640
4641#[no_mangle]
4642pub unsafe extern "C" fn uselocale(loc: locale_t) -> locale_t {
4643 let old = CURRENT_LOCALE;
4644 if !loc.is_null() {
4645 CURRENT_LOCALE = loc;
4646 }
4647 old
4648}
4649
4650#[no_mangle]
4651pub unsafe extern "C" fn duplocale(loc: locale_t) -> locale_t {
4652 if loc.is_null() {
4653 return core::ptr::null_mut();
4654 }
4655 C_LOCALE
4656}
4657
4658const NL_ITEM_CODESET: c_int = 14;
4659const NL_ITEM_RADIXCHAR: c_int = 0x10000;
4660const NL_ITEM_THOUSEP: c_int = 0x10001;
4661const NL_ITEM_YESEXPR: c_int = 0x50000;
4662const NL_ITEM_NOEXPR: c_int = 0x50001;
4663
4664const C_TIME_STRINGS: &[u8] = b"Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0\
4665Sunday\0Monday\0Tuesday\0Wednesday\0Thursday\0Friday\0Saturday\0\
4666Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0\
4667January\0February\0March\0April\0May\0June\0July\0August\0\
4668September\0October\0November\0December\0\
4669AM\0PM\0\
4670%a %b %e %T %Y\0%m/%d/%y\0%H:%M:%S\0%I:%M:%S %p\0\
4671\0\0%m/%d/%y\00123456789\0%a %b %e %T %Y\0%H:%M:%S\0";
4672
4673const C_NUMERIC_STRINGS: &[u8] = b".\0\0";
4674const C_MESSAGES_STRINGS: &[u8] = b"^[yY]\0^[nN]\0";
4675
4676unsafe fn langinfo_str(table: *const u8, mut idx: c_int) -> *mut c_char {
4677 let mut p = table;
4678 while idx > 0 {
4679 while *p != 0 { p = p.add(1); }
4680 p = p.add(1);
4681 idx -= 1;
4682 }
4683 p as *mut c_char
4684}
4685
4686#[no_mangle]
4687pub unsafe extern "C" fn nl_langinfo(item: c_int) -> *mut c_char {
4688 if item == NL_ITEM_CODESET {
4689 return if LOCALE_CTYPE_UTF8 {
4690 b"UTF-8\0".as_ptr() as *mut c_char
4691 } else {
4692 b"US-ASCII\0".as_ptr() as *mut c_char
4693 };
4694 }
4695 let cat = item >> 16;
4696 let idx = item & 0xFFFF;
4697 match cat {
4698 1 => {
4699 if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
4700 langinfo_str(C_NUMERIC_STRINGS.as_ptr(), idx)
4701 }
4702 2 => {
4703 if idx > 49 { return b"\0".as_ptr() as *mut c_char; }
4704 langinfo_str(C_TIME_STRINGS.as_ptr(), idx)
4705 }
4706 5 => {
4707 if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
4708 langinfo_str(C_MESSAGES_STRINGS.as_ptr(), idx)
4709 }
4710 _ => b"\0".as_ptr() as *mut c_char,
4711 }
4712}
4713
4714pub type nl_catd = *mut c_void;
4715
4716#[no_mangle]
4717pub unsafe extern "C" fn catopen(_name: *const c_char, _oflag: c_int) -> nl_catd {
4718 !0usize as nl_catd
4719}
4720
4721#[no_mangle]
4722pub unsafe extern "C" fn catclose(_catd: nl_catd) -> c_int { 0 }
4723
4724#[no_mangle]
4725pub unsafe extern "C" fn catgets(catd: nl_catd, _set_id: c_int, _msg_id: c_int, s: *const c_char) -> *mut c_char {
4726 if catd == !0usize as nl_catd { return s as *mut c_char; }
4727 s as *mut c_char
4728}
4729
4730pub type IconvT = *mut c_void;
4731
4732const ENC_UTF8: i32 = 1;
4733const ENC_UTF16LE: i32 = 2;
4734const ENC_UTF16BE: i32 = 3;
4735const ENC_UTF32LE: i32 = 4;
4736const ENC_UTF32BE: i32 = 5;
4737const ENC_WCHAR_T: i32 = 6;
4738const ENC_ASCII: i32 = 7;
4739const ENC_LATIN1: i32 = 8;
4740const ENC_WIN1252: i32 = 9;
4741const ENC_WIN1251: i32 = 10;
4742const ENC_KOI8R: i32 = 11;
4743const ENC_GBK: i32 = 12;
4744const ENC_GB2312: i32 = 13;
4745const ENC_BIG5: i32 = 14;
4746const ENC_EUCJP: i32 = 15;
4747const ENC_SHIFTJIS: i32 = 16;
4748const ENC_ISO8859_2: i32 = 17;
4749const ENC_ISO8859_3: i32 = 18;
4750const ENC_ISO8859_4: i32 = 19;
4751const ENC_ISO8859_5: i32 = 20;
4752const ENC_ISO8859_6: i32 = 21;
4753const ENC_ISO8859_7: i32 = 22;
4754const ENC_ISO8859_8: i32 = 23;
4755const ENC_ISO8859_9: i32 = 24;
4756const ENC_ISO8859_10: i32 = 25;
4757const ENC_ISO8859_11: i32 = 26;
4758const ENC_ISO8859_13: i32 = 27;
4759const ENC_ISO8859_14: i32 = 28;
4760const ENC_ISO8859_15: i32 = 29;
4761const ENC_ISO8859_16: i32 = 30;
4762
4763include!("iconv_iso8859.rs");
4764
4765fn make_cd(from: i32, to: i32) -> IconvT {
4766 ((from as usize) << 16 | (to as usize) << 1 | 1) as IconvT
4767}
4768fn extract_from(cd: IconvT) -> i32 {
4769 ((cd as usize) >> 16) as i32
4770}
4771fn extract_to(cd: IconvT) -> i32 {
4772 (((cd as usize) >> 1) & 0x7fff) as i32
4773}
4774
4775unsafe fn match_name(input: *const u8, target: &[u8]) -> bool {
4776 let mut i = input;
4777 let mut j = 0;
4778 while *i != 0 && j < target.len() {
4779 let mut c = *i;
4780 if !c.is_ascii_alphanumeric() { i = i.add(1); continue; }
4781 c = c.to_ascii_lowercase();
4782 if c != target[j] { return false; }
4783 i = i.add(1);
4784 j += 1;
4785 }
4786 while *i != 0 && !(*i).is_ascii_alphanumeric() { i = i.add(1); }
4787 *i == 0 && j == target.len()
4788}
4789
4790unsafe fn find_encoding(name: *const u8) -> i32 {
4791 if name.is_null() { return -1; }
4792 if match_name(name, b"utf8") || match_name(name, b"utf-8") || match_name(name, b"char") { return ENC_UTF8; }
4793 if match_name(name, b"utf16le") || match_name(name, b"utf-16le") { return ENC_UTF16LE; }
4794 if match_name(name, b"utf16be") || match_name(name, b"utf-16be") { return ENC_UTF16BE; }
4795 if match_name(name, b"utf32le") || match_name(name, b"utf-32le") || match_name(name, b"ucs4le") { return ENC_UTF32LE; }
4796 if match_name(name, b"utf32be") || match_name(name, b"utf-32be") || match_name(name, b"ucs4be") { return ENC_UTF32BE; }
4797 if match_name(name, b"wchart") || match_name(name, b"wchar-t") { return ENC_WCHAR_T; }
4798 if match_name(name, b"ascii") || match_name(name, b"usascii") || match_name(name, b"iso646") { return ENC_ASCII; }
4799 if match_name(name, b"iso88591") || match_name(name, b"iso-8859-1") || match_name(name, b"latin1") { return ENC_LATIN1; }
4800 if match_name(name, b"iso88592") || match_name(name, b"iso-8859-2") { return ENC_ISO8859_2; }
4801 if match_name(name, b"iso88593") || match_name(name, b"iso-8859-3") { return ENC_ISO8859_3; }
4802 if match_name(name, b"iso88594") || match_name(name, b"iso-8859-4") { return ENC_ISO8859_4; }
4803 if match_name(name, b"iso88595") || match_name(name, b"iso-8859-5") { return ENC_ISO8859_5; }
4804 if match_name(name, b"iso88596") || match_name(name, b"iso-8859-6") { return ENC_ISO8859_6; }
4805 if match_name(name, b"iso88597") || match_name(name, b"iso-8859-7") { return ENC_ISO8859_7; }
4806 if match_name(name, b"iso88598") || match_name(name, b"iso-8859-8") { return ENC_ISO8859_8; }
4807 if match_name(name, b"iso88599") || match_name(name, b"iso-8859-9") { return ENC_ISO8859_9; }
4808 if match_name(name, b"iso885910") || match_name(name, b"iso-8859-10") { return ENC_ISO8859_10; }
4809 if match_name(name, b"iso885911") || match_name(name, b"iso-8859-11") || match_name(name, b"tis620") { return ENC_ISO8859_11; }
4810 if match_name(name, b"iso885913") || match_name(name, b"iso-8859-13") { return ENC_ISO8859_13; }
4811 if match_name(name, b"iso885914") || match_name(name, b"iso-8859-14") { return ENC_ISO8859_14; }
4812 if match_name(name, b"iso885915") || match_name(name, b"iso-8859-15") { return ENC_ISO8859_15; }
4813 if match_name(name, b"iso885916") || match_name(name, b"iso-8859-16") { return ENC_ISO8859_16; }
4814 if match_name(name, b"cp1252") || match_name(name, b"windows1252") || match_name(name, b"windows-1252") { return ENC_WIN1252; }
4815 if match_name(name, b"cp1251") || match_name(name, b"windows1251") || match_name(name, b"windows-1251") { return ENC_WIN1251; }
4816 if match_name(name, b"koi8r") || match_name(name, b"koi8-r") { return ENC_KOI8R; }
4817 if match_name(name, b"gbk") || match_name(name, b"cp936") { return ENC_GBK; }
4818 if match_name(name, b"gb2312") { return ENC_GB2312; }
4819 if match_name(name, b"big5") || match_name(name, b"bigfive") || match_name(name, b"cp950") { return ENC_BIG5; }
4820 if match_name(name, b"eucjp") || match_name(name, b"euc-jp") { return ENC_EUCJP; }
4821 if match_name(name, b"shiftjis") || match_name(name, b"sjis") || match_name(name, b"cp932") { return ENC_SHIFTJIS; }
4822 -1
4823}
4824
4825fn uni_to_jis(c: u32) -> u16 {
4826 let mut b = 0usize;
4827 let mut nel = REV_JIS.len();
4828 loop {
4829 let i = nel / 2;
4830 let j = REV_JIS[b + i] as usize;
4831 let row = j / 256;
4832 let col = j % 256;
4833 let d = JIS0208[row * 94 + col] as u32;
4834 if d == c { return (j as u16) + 0x2121; }
4835 if nel == 1 { return 0; }
4836 if c < d { nel /= 2; }
4837 else { b += i; nel -= nel / 2; }
4838 }
4839}
4840
4841unsafe fn iconv_decode(enc: i32, src: *const u8, src_left: usize) -> (u32, usize, c_int) {
4842 if src_left == 0 { return (0, 0, EINVAL); }
4843 match enc {
4844 ENC_UTF8 => {
4845 let c = *src;
4846 if c < 128 { return (c as u32, 1, 0); }
4847 if c < 0xC2 { return (0, 0, EILSEQ); }
4848 if c < 0xE0 {
4849 if src_left < 2 || (*src.add(1) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4850 return (((c as u32 & 0x1F) << 6) | (*src.add(1) as u32 & 0x3F), 2, 0);
4851 }
4852 if c < 0xF0 {
4853 if src_left < 3 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4854 let cp = ((c as u32 & 0x0F) << 12) | ((*src.add(1) as u32 & 0x3F) << 6) | (*src.add(2) as u32 & 0x3F);
4855 if cp < 0x800 { return (0, 0, EILSEQ); }
4856 return (cp, 3, 0);
4857 }
4858 if c < 0xF8 {
4859 if src_left < 4 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 || (*src.add(3) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
4860 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);
4861 if cp < 0x10000 || cp >= 0x110000 { return (0, 0, EILSEQ); }
4862 return (cp, 4, 0);
4863 }
4864 (0, 0, EILSEQ)
4865 }
4866 ENC_UTF16LE => {
4867 if src_left < 2 { return (0, 0, EINVAL); }
4868 let c = (*src as u32) | ((*src.add(1) as u32) << 8);
4869 if c >= 0xD800 && c <= 0xDBFF {
4870 if src_left < 4 { return (0, 0, EINVAL); }
4871 let d = (*src.add(2) as u32) | ((*src.add(3) as u32) << 8);
4872 if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
4873 return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
4874 }
4875 if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
4876 (c, 2, 0)
4877 }
4878 ENC_UTF16BE => {
4879 if src_left < 2 { return (0, 0, EINVAL); }
4880 let c = ((*src as u32) << 8) | (*src.add(1) as u32);
4881 if c >= 0xD800 && c <= 0xDBFF {
4882 if src_left < 4 { return (0, 0, EINVAL); }
4883 let d = ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
4884 if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
4885 return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
4886 }
4887 if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
4888 (c, 2, 0)
4889 }
4890 ENC_UTF32LE => {
4891 if src_left < 4 { return (0, 0, EINVAL); }
4892 let c = (*src as u32) | ((*src.add(1) as u32) << 8) | ((*src.add(2) as u32) << 16) | ((*src.add(3) as u32) << 24);
4893 if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
4894 if c >= 0x110000 { return (0, 0, EILSEQ); }
4895 (c, 4, 0)
4896 }
4897 ENC_UTF32BE => {
4898 if src_left < 4 { return (0, 0, EINVAL); }
4899 let c = ((*src as u32) << 24) | ((*src.add(1) as u32) << 16) | ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
4900 if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
4901 if c >= 0x110000 { return (0, 0, EILSEQ); }
4902 (c, 4, 0)
4903 }
4904 ENC_WCHAR_T => {
4905 if src_left < 4 { return (0, 0, EINVAL); }
4906 let c = *(src as *const u32);
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_ASCII => {
4912 let c = *src as u32;
4913 if c >= 128 { return (0, 0, EILSEQ); }
4914 (c, 1, 0)
4915 }
4916 ENC_LATIN1 => (*src as u32, 1, 0),
4917 ENC_ISO8859_2 => (iso8859_to_u(&ISO8859_2_TO_U, *src), 1, 0),
4918 ENC_ISO8859_3 => (iso8859_to_u(&ISO8859_3_TO_U, *src), 1, 0),
4919 ENC_ISO8859_4 => (iso8859_to_u(&ISO8859_4_TO_U, *src), 1, 0),
4920 ENC_ISO8859_5 => (iso8859_to_u(&ISO8859_5_TO_U, *src), 1, 0),
4921 ENC_ISO8859_6 => (iso8859_to_u(&ISO8859_6_TO_U, *src), 1, 0),
4922 ENC_ISO8859_7 => (iso8859_to_u(&ISO8859_7_TO_U, *src), 1, 0),
4923 ENC_ISO8859_8 => (iso8859_to_u(&ISO8859_8_TO_U, *src), 1, 0),
4924 ENC_ISO8859_9 => (iso8859_to_u(&ISO8859_9_TO_U, *src), 1, 0),
4925 ENC_ISO8859_10 => (iso8859_to_u(&ISO8859_10_TO_U, *src), 1, 0),
4926 ENC_ISO8859_11 => (iso8859_to_u(&ISO8859_11_TO_U, *src), 1, 0),
4927 ENC_ISO8859_13 => (iso8859_to_u(&ISO8859_13_TO_U, *src), 1, 0),
4928 ENC_ISO8859_14 => (iso8859_to_u(&ISO8859_14_TO_U, *src), 1, 0),
4929 ENC_ISO8859_15 => (iso8859_to_u(&ISO8859_15_TO_U, *src), 1, 0),
4930 ENC_ISO8859_16 => (iso8859_to_u(&ISO8859_16_TO_U, *src), 1, 0),
4931 ENC_WIN1252 => {
4932 let b = *src;
4933 if b < 128 { return (b as u32, 1, 0); }
4934 (WIN1252_TO_U[b as usize - 128], 1, 0)
4935 }
4936 ENC_WIN1251 => {
4937 let b = *src;
4938 if b < 128 { return (b as u32, 1, 0); }
4939 (WIN1251_TO_U[b as usize - 128], 1, 0)
4940 }
4941 ENC_KOI8R => {
4942 let b = *src;
4943 if b < 128 { return (b as u32, 1, 0); }
4944 (KOI8R_TO_U[b as usize - 128], 1, 0)
4945 }
4946 ENC_GBK | ENC_GB2312 => {
4947 let c = *src;
4948 if c < 128 { return (c as u32, 1, 0); }
4949 if c == 128 { return (0x20AC, 1, 0); }
4950 if src_left < 2 { return (0, 0, EINVAL); }
4951 let d = *src.add(1);
4952 if d < 0x40 || d == 0x7F || d > 0xFE { return (0, 0, EILSEQ); }
4953 let row = (c as usize).wrapping_sub(0x81);
4954 if row >= 126 { return (0, 0, EILSEQ); }
4955 let mut col = (d as usize) - 0x40;
4956 if col > 63 { col -= 1; }
4957 let cp = GB18030_TABLE[row * 190 + col] as u32;
4958 if cp == 0 { return (0, 0, EILSEQ); }
4959 (cp, 2, 0)
4960 }
4961 ENC_BIG5 => {
4962 let c = *src;
4963 if c < 128 { return (c as u32, 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 mut col = (d as usize) - 0x40;
4968 if col > 0x3E { col -= 0x22; }
4969 if c >= 0xA1 && c < 0xFA {
4970 let row = (c as usize) - 0xA1;
4971 if row >= 89 { return (0, 0, EILSEQ); }
4972 let cp = BIG5_TABLE[row * 157 + col] as u32;
4973 if cp == 0 { return (0, 0, EILSEQ); }
4974 return (cp, 2, 0);
4975 }
4976 (0, 0, EILSEQ)
4977 }
4978 ENC_EUCJP => {
4979 let c = *src;
4980 if c < 128 { return (c as u32, 1, 0); }
4981 if c == 0x8E {
4982 if src_left < 2 { return (0, 0, EINVAL); }
4983 let d = *src.add(1);
4984 if d < 0xA1 || d > 0xDF { return (0, 0, EILSEQ); }
4985 return ((d as u32) + 0xFF61 - 0xA1, 2, 0);
4986 }
4987 if c < 0xA1 { return (0, 0, EILSEQ); }
4988 if src_left < 2 { return (0, 0, EINVAL); }
4989 let d = *src.add(1);
4990 if d < 0xA1 || d > 0xFE { return (0, 0, EILSEQ); }
4991 let row = (c as usize) - 0xA1;
4992 let col = (d as usize) - 0xA1;
4993 if row >= 84 || col >= 94 { return (0, 0, EILSEQ); }
4994 let cp = JIS0208[row * 94 + col] as u32;
4995 if cp == 0 { return (0, 0, EILSEQ); }
4996 (cp, 2, 0)
4997 }
4998 ENC_SHIFTJIS => {
4999 let c = *src;
5000 if c < 128 { return (c as u32, 1, 0); }
5001 if c >= 0xA1 && c <= 0xDF { return ((c as u32) + 0xFF61 - 0xA1, 1, 0); }
5002 if src_left < 2 { return (0, 0, EINVAL); }
5003 let d = *src.add(1);
5004 if d < 0x40 || d == 0x7F || d > 0xFC { return (0, 0, EILSEQ); }
5005 let row = if c >= 129 && c <= 159 { (c as usize) - 129 }
5006 else if c >= 224 && c <= 239 { (c as usize) - 193 }
5007 else { return (0, 0, EILSEQ); };
5008 let (col, row_adj) = if d >= 64 && d <= 158 && d != 127 {
5009 let mut dd = d as usize;
5010 if dd > 127 { dd -= 1; }
5011 (dd - 64, row * 2)
5012 } else if d >= 159 && d <= 252 {
5013 ((d as usize) - 159, row * 2 + 1)
5014 } else {
5015 return (0, 0, EILSEQ);
5016 };
5017 if row_adj >= 84 { return (0, 0, EILSEQ); }
5018 let cp = JIS0208[row_adj * 94 + col] as u32;
5019 if cp == 0 { return (0, 0, EILSEQ); }
5020 (cp, 2, 0)
5021 }
5022 _ => (0, 0, EILSEQ),
5023 }
5024}
5025
5026unsafe fn iconv_encode(enc: i32, c: u32, dst: *mut u8, dst_left: usize) -> (usize, c_int) {
5027 match enc {
5028 ENC_UTF8 => {
5029 if c < 0x80 {
5030 if dst_left < 1 { return (0, E2BIG); }
5031 *dst = c as u8; return (1, 0);
5032 }
5033 if c < 0x800 {
5034 if dst_left < 2 { return (0, E2BIG); }
5035 *dst = (0xC0 | (c >> 6)) as u8;
5036 *dst.add(1) = (0x80 | (c & 0x3F)) as u8;
5037 return (2, 0);
5038 }
5039 if c < 0x10000 {
5040 if dst_left < 3 { return (0, E2BIG); }
5041 *dst = (0xE0 | (c >> 12)) as u8;
5042 *dst.add(1) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5043 *dst.add(2) = (0x80 | (c & 0x3F)) as u8;
5044 return (3, 0);
5045 }
5046 if dst_left < 4 { return (0, E2BIG); }
5047 *dst = (0xF0 | (c >> 18)) as u8;
5048 *dst.add(1) = (0x80 | ((c >> 12) & 0x3F)) as u8;
5049 *dst.add(2) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5050 *dst.add(3) = (0x80 | (c & 0x3F)) as u8;
5051 (4, 0)
5052 }
5053 ENC_UTF16LE => {
5054 if c < 0x10000 {
5055 if dst_left < 2 { return (0, E2BIG); }
5056 *dst = (c & 0xFF) as u8;
5057 *dst.add(1) = (c >> 8) as u8;
5058 return (2, 0);
5059 }
5060 if dst_left < 4 { return (0, E2BIG); }
5061 let c = c - 0x10000;
5062 let hi = ((c >> 10) + 0xD800) as u16;
5063 let lo = ((c & 0x3FF) + 0xDC00) as u16;
5064 *dst = (hi & 0xFF) as u8; *dst.add(1) = (hi >> 8) as u8;
5065 *dst.add(2) = (lo & 0xFF) as u8; *dst.add(3) = (lo >> 8) as u8;
5066 (4, 0)
5067 }
5068 ENC_UTF16BE => {
5069 if c < 0x10000 {
5070 if dst_left < 2 { return (0, E2BIG); }
5071 *dst = (c >> 8) as u8;
5072 *dst.add(1) = (c & 0xFF) as u8;
5073 return (2, 0);
5074 }
5075 if dst_left < 4 { return (0, E2BIG); }
5076 let c = c - 0x10000;
5077 let hi = ((c >> 10) + 0xD800) as u16;
5078 let lo = ((c & 0x3FF) + 0xDC00) as u16;
5079 *dst = (hi >> 8) as u8; *dst.add(1) = (hi & 0xFF) as u8;
5080 *dst.add(2) = (lo >> 8) as u8; *dst.add(3) = (lo & 0xFF) as u8;
5081 (4, 0)
5082 }
5083 ENC_UTF32LE => {
5084 if dst_left < 4 { return (0, E2BIG); }
5085 *dst = (c & 0xFF) as u8; *dst.add(1) = ((c >> 8) & 0xFF) as u8;
5086 *dst.add(2) = ((c >> 16) & 0xFF) as u8; *dst.add(3) = (c >> 24) as u8;
5087 (4, 0)
5088 }
5089 ENC_UTF32BE => {
5090 if dst_left < 4 { return (0, E2BIG); }
5091 *dst = (c >> 24) as u8; *dst.add(1) = ((c >> 16) & 0xFF) as u8;
5092 *dst.add(2) = ((c >> 8) & 0xFF) as u8; *dst.add(3) = (c & 0xFF) as u8;
5093 (4, 0)
5094 }
5095 ENC_WCHAR_T => {
5096 if dst_left < 4 { return (0, E2BIG); }
5097 *(dst as *mut u32) = c;
5098 (4, 0)
5099 }
5100 ENC_ASCII => {
5101 if c < 128 {
5102 if dst_left < 1 { return (0, E2BIG); }
5103 *dst = c as u8; return (1, 0);
5104 }
5105 (0, EILSEQ)
5106 }
5107 ENC_LATIN1 => {
5108 if c < 256 {
5109 if dst_left < 1 { return (0, E2BIG); }
5110 *dst = c as u8; return (1, 0);
5111 }
5112 (0, EILSEQ)
5113 }
5114 ENC_ISO8859_2 => {
5115 if let Some(b) = u_to_iso8859(&ISO8859_2_TO_U, c) {
5116 if dst_left < 1 { return (0, E2BIG); }
5117 *dst = b; return (1, 0);
5118 }
5119 (0, EILSEQ)
5120 }
5121 ENC_ISO8859_3 => {
5122 if let Some(b) = u_to_iso8859(&ISO8859_3_TO_U, c) {
5123 if dst_left < 1 { return (0, E2BIG); }
5124 *dst = b; return (1, 0);
5125 }
5126 (0, EILSEQ)
5127 }
5128 ENC_ISO8859_4 => {
5129 if let Some(b) = u_to_iso8859(&ISO8859_4_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_5 => {
5136 if let Some(b) = u_to_iso8859(&ISO8859_5_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_6 => {
5143 if let Some(b) = u_to_iso8859(&ISO8859_6_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_7 => {
5150 if let Some(b) = u_to_iso8859(&ISO8859_7_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_8 => {
5157 if let Some(b) = u_to_iso8859(&ISO8859_8_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_9 => {
5164 if let Some(b) = u_to_iso8859(&ISO8859_9_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_10 => {
5171 if let Some(b) = u_to_iso8859(&ISO8859_10_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_11 => {
5178 if let Some(b) = u_to_iso8859(&ISO8859_11_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_13 => {
5185 if let Some(b) = u_to_iso8859(&ISO8859_13_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_14 => {
5192 if let Some(b) = u_to_iso8859(&ISO8859_14_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_15 => {
5199 if let Some(b) = u_to_iso8859(&ISO8859_15_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_16 => {
5206 if let Some(b) = u_to_iso8859(&ISO8859_16_TO_U, c) {
5207 if dst_left < 1 { return (0, E2BIG); }
5208 *dst = b; return (1, 0);
5209 }
5210 (0, EILSEQ)
5211 }
5212 ENC_WIN1252 => {
5213 if c < 128 {
5214 if dst_left < 1 { return (0, E2BIG); }
5215 *dst = c as u8; return (1, 0);
5216 }
5217 if c >= 0xA0 && c <= 0xFF && WIN1252_TO_U[c as usize - 128] == c {
5218 if dst_left < 1 { return (0, E2BIG); }
5219 *dst = c as u8; return (1, 0);
5220 }
5221 for i in 0..128usize {
5222 if WIN1252_TO_U[i] == c {
5223 if dst_left < 1 { return (0, E2BIG); }
5224 *dst = (i + 128) as u8; return (1, 0);
5225 }
5226 }
5227 (0, EILSEQ)
5228 }
5229 ENC_WIN1251 => {
5230 if c < 128 {
5231 if dst_left < 1 { return (0, E2BIG); }
5232 *dst = c as u8; return (1, 0);
5233 }
5234 for i in 0..128usize {
5235 if WIN1251_TO_U[i] == c {
5236 if dst_left < 1 { return (0, E2BIG); }
5237 *dst = (i + 128) as u8; return (1, 0);
5238 }
5239 }
5240 (0, EILSEQ)
5241 }
5242 ENC_KOI8R => {
5243 if c < 128 {
5244 if dst_left < 1 { return (0, E2BIG); }
5245 *dst = c as u8; return (1, 0);
5246 }
5247 for i in 0..128usize {
5248 if KOI8R_TO_U[i] == c {
5249 if dst_left < 1 { return (0, E2BIG); }
5250 *dst = (i + 128) as u8; return (1, 0);
5251 }
5252 }
5253 (0, EILSEQ)
5254 }
5255 ENC_GBK | ENC_GB2312 => {
5256 if c < 128 {
5257 if dst_left < 1 { return (0, E2BIG); }
5258 *dst = c as u8; return (1, 0);
5259 }
5260 if c == 0x20AC {
5261 if dst_left < 1 { return (0, E2BIG); }
5262 *dst = 128; return (1, 0);
5263 }
5264 for row in 0..126usize {
5265 for col in 0..190usize {
5266 if GB18030_TABLE[row * 190 + col] as u32 == c {
5267 if dst_left < 2 { return (0, E2BIG); }
5268 *dst = (row + 0x81) as u8;
5269 *dst.add(1) = if col <= 62 { (col + 0x40) as u8 } else { (col + 0x41) as u8 };
5270 return (2, 0);
5271 }
5272 }
5273 }
5274 (0, EILSEQ)
5275 }
5276 ENC_BIG5 => {
5277 if c < 128 {
5278 if dst_left < 1 { return (0, E2BIG); }
5279 *dst = c as u8; return (1, 0);
5280 }
5281 for row in 0..89usize {
5282 for col in 0..157usize {
5283 if BIG5_TABLE[row * 157 + col] as u32 == c {
5284 if dst_left < 2 { return (0, E2BIG); }
5285 *dst = (row + 0xA1) as u8;
5286 *dst.add(1) = if col <= 0x3E { (col + 0x40) as u8 } else { (col + 0x62) as u8 };
5287 return (2, 0);
5288 }
5289 }
5290 }
5291 (0, EILSEQ)
5292 }
5293 ENC_EUCJP => {
5294 if c < 128 {
5295 if dst_left < 1 { return (0, E2BIG); }
5296 *dst = c as u8; return (1, 0);
5297 }
5298 if c >= 0xFF61 && c <= 0xFF9F {
5299 if dst_left < 2 { return (0, E2BIG); }
5300 *dst = 0x8E;
5301 *dst.add(1) = (c - 0xFF61 + 0xA1) as u8;
5302 return (2, 0);
5303 }
5304 let jis = uni_to_jis(c);
5305 if jis == 0 { return (0, EILSEQ); }
5306 if dst_left < 2 { return (0, E2BIG); }
5307 *dst = ((jis >> 8) as u8).wrapping_add(0x80);
5308 *dst.add(1) = ((jis & 0xFF) as u8).wrapping_add(0x80);
5309 (2, 0)
5310 }
5311 ENC_SHIFTJIS => {
5312 if c < 128 {
5313 if dst_left < 1 { return (0, E2BIG); }
5314 *dst = c as u8; return (1, 0);
5315 }
5316 if c >= 0xFF61 && c <= 0xFF9F {
5317 if dst_left < 1 { return (0, E2BIG); }
5318 *dst = (c - 0xFF61 + 0xA1) as u8;
5319 return (1, 0);
5320 }
5321 let jis = uni_to_jis(c);
5322 if jis == 0 { return (0, EILSEQ); }
5323 if dst_left < 2 { return (0, E2BIG); }
5324 let r = (jis >> 8) as usize;
5325 let d = (jis & 0xFF) as usize;
5326 *dst = ((r + 1) / 2 + if r < 95 { 112 } else { 176 }) as u8;
5327 *dst.add(1) = if r % 2 == 1 { (d + 31 + d / 96) as u8 } else { (d + 126) as u8 };
5328 (2, 0)
5329 }
5330 _ => (0, EILSEQ),
5331 }
5332}
5333
5334#[no_mangle]
5335pub unsafe extern "C" fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> IconvT {
5336 let to = find_encoding(tocode as *const u8);
5337 let from = find_encoding(fromcode as *const u8);
5338 if to < 0 || from < 0 {
5339 ERRNO = EINVAL;
5340 return !0usize as IconvT;
5341 }
5342 make_cd(from, to)
5343}
5344
5345#[no_mangle]
5346pub unsafe extern "C" fn iconv(
5347 cd: IconvT,
5348 inbuf: *mut *mut c_char,
5349 inbytesleft: *mut SizeT,
5350 outbuf: *mut *mut c_char,
5351 outbytesleft: *mut SizeT,
5352) -> SizeT {
5353 if cd == !0usize as IconvT {
5354 ERRNO = EINVAL;
5355 return !0usize;
5356 }
5357 if inbuf.is_null() || outbuf.is_null() { return 0; }
5358 let from = extract_from(cd);
5359 let to = extract_to(cd);
5360 let mut src = *inbuf as *const u8;
5361 let mut dst = *outbuf as *mut u8;
5362 let mut src_left = *inbytesleft;
5363 let mut dst_left = *outbytesleft;
5364 let mut subst = 0usize;
5365 while src_left > 0 {
5366 let (cp, consumed, err) = iconv_decode(from, src, src_left);
5367 if err != 0 {
5368 if err == EINVAL { break; }
5369 ERRNO = err;
5370 return !0usize;
5371 }
5372 let (written, err) = iconv_encode(to, cp, dst, dst_left);
5373 if err != 0 {
5374 if err == E2BIG {
5375 ERRNO = E2BIG;
5376 return !0usize;
5377 }
5378 if dst_left < 1 {
5379 ERRNO = E2BIG;
5380 return !0usize;
5381 }
5382 *dst = b'*';
5383 dst = dst.add(1);
5384 dst_left -= 1;
5385 subst += 1;
5386 } else {
5387 dst = dst.add(written);
5388 dst_left -= written;
5389 }
5390 src = src.add(consumed);
5391 src_left -= consumed;
5392 }
5393 *inbuf = src as *mut c_char;
5394 *outbuf = dst as *mut c_char;
5395 *inbytesleft = src_left;
5396 *outbytesleft = dst_left;
5397 subst
5398}
5399
5400#[no_mangle]
5401pub unsafe extern "C" fn iconv_close(_cd: IconvT) -> c_int { 0 }
5402
5403#[no_mangle]
5408pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: SizeT) -> SSizeT {
5409 sys_write(fd as i64, buf as *const u8, count) as SSizeT
5410}
5411
5412#[no_mangle]
5413pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: SizeT) -> SSizeT {
5414 sys_read(fd as i64, buf as *mut u8, count) as SSizeT
5415}
5416
5417#[no_mangle]
5418pub unsafe extern "C" fn open(path: *const c_char, flags: c_int, mode: c_int) -> c_int {
5419 sys_open(path as *const u8, flags as i64, mode as i64) as c_int
5420}
5421
5422#[no_mangle]
5423pub unsafe extern "C" fn close(fd: c_int) -> c_int {
5424 sys_close(fd as i64);
5425 0
5426}
5427
5428#[no_mangle]
5429pub unsafe extern "C" fn lseek(fd: c_int, offset: i64, whence: c_int) -> i64 {
5430 sys_lseek(fd as i64, offset, whence as i64)
5431}
5432
5433const O_RDONLY: i32 = 0;
5438const O_WRONLY: i32 = 1;
5439const O_RDWR: i32 = 2;
5440const O_CREAT: i32 = 64;
5441const O_TRUNC: i32 = 512;
5442const O_APPEND: i32 = 1024;
5443const O_EXCL: i32 = 128;
5444const O_NONBLOCK: i32 = 2048;
5445const O_NOFOLLOW: i32 = 0x40000;
5446const O_CLOEXEC: i32 = 0x80000;
5447
5448const F_GETFD: i32 = 1;
5449const F_SETFD: i32 = 2;
5450const F_GETFL: i32 = 3;
5451const F_SETFL: i32 = 4;
5452const F_GETLK: i32 = 5;
5453const F_SETLK: i32 = 6;
5454const F_SETLKW: i32 = 7;
5455const F_DUPFD: i32 = 0;
5456const F_DUPFD_CLOEXEC: i32 = 1030;
5457const FD_CLOEXEC: i32 = 1;
5458
5459const TIOCGWINSZ: u32 = 0x5413;
5460
5461#[repr(C)]
5462struct winsize {
5463 ws_row: u16,
5464 ws_col: u16,
5465 ws_xpixel: u16,
5466 ws_ypixel: u16,
5467}
5468
5469#[inline]
5470unsafe fn sys_pipe2(fds: *mut c_int, flags: i32) -> i64 {
5471 <Arch as Syscalls>::syscall2(SYS_PIPE2, fds as i64, flags as i64)
5472}
5473
5474#[inline]
5475unsafe fn sys_dup3(oldfd: i32, newfd: i32, flags: i32) -> i64 {
5476 <Arch as Syscalls>::syscall3(SYS_DUP3, oldfd as i64, newfd as i64, flags as i64)
5477}
5478
5479#[inline]
5480unsafe fn sys_fcntl(fd: i32, cmd: i32, arg: i64) -> i64 {
5481 <Arch as Syscalls>::syscall3(SYS_FCNTL, fd as i64, cmd as i64, arg as i64)
5482}
5483
5484#[inline]
5485unsafe fn sys_ioctl(fd: c_int, request: u32, arg: *mut u8) -> i64 {
5486 <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, request as i64, arg as i64)
5487}
5488
5489#[inline]
5490unsafe fn sys_unlinkat(dirfd: i32, path: *const u8, flags: i32) -> i64 {
5491 <Arch as Syscalls>::syscall3(SYS_UNLINKAT, dirfd as i64, path as i64, flags as i64)
5492}
5493
5494#[inline]
5495unsafe fn sys_renameat2(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: u32) -> i64 {
5496 <Arch as Syscalls>::syscall5(SYS_RENAMEAT2, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
5497}
5498
5499const UNGET: usize = 8;
5504const F_PERM: u32 = 1;
5505const F_NORD: u32 = 4;
5506const F_NOWR: u32 = 8;
5507const F_EOF: u32 = 16;
5508const F_ERR: u32 = 32;
5509const F_SVB: u32 = 64;
5510const F_APP: u32 = 128;
5511
5512const BUFSIZ: usize = 1024;
5513
5514const _IOFBF: c_int = 0;
5515const _IOLBF: c_int = 1;
5516const _IONBF: c_int = 2;
5517
5518const SEEK_SET: c_int = 0;
5519const SEEK_CUR: c_int = 1;
5520const SEEK_END: c_int = 2;
5521
5522#[repr(C)]
5524pub struct FILE {
5525 flags: c_uint,
5526 rpos: *mut u8,
5527 rend: *mut u8,
5528 close: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
5529 wend: *mut u8,
5530 wpos: *mut u8,
5531 mustbezero_1: *mut u8,
5532 wbase: *mut u8,
5533 read_fn: Option<unsafe extern "C" fn(*mut FILE, *mut u8, usize) -> usize>,
5534 write_fn: Option<unsafe extern "C" fn(*mut FILE, *const u8, usize) -> usize>,
5535 seek_fn: Option<unsafe extern "C" fn(*mut FILE, i64, c_int) -> i64>,
5536 buf: *mut u8,
5537 buf_size: usize,
5538 prev: *mut FILE,
5539 next: *mut FILE,
5540 fd: c_int,
5541 pipe_pid: c_int,
5542 lockcount: c_long,
5543 mode: c_int,
5544 lock: c_int,
5545 lbf: c_int,
5546 cookie: *mut c_void,
5547 off: i64,
5548 getln_buf: *mut c_char,
5549 mustbezero_2: *mut c_void,
5550 shend: *mut u8,
5551 shlim: i64,
5552 shcnt: i64,
5553 ungotten: [c_int; UNGET],
5554 ungotten_count: c_int,
5555 _eof: c_int,
5556 _err: c_int,
5557}
5558
5559static mut STDIN_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5560static mut STDOUT_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5561static mut STDERR_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
5562
5563static mut STDIN_FILE: FILE = FILE {
5564 flags: 0, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5565 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5566 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5567 read_fn: None, write_fn: None, seek_fn: None,
5568 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5569 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5570 fd: 0, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5571 cookie: core::ptr::null_mut(), off: 0,
5572 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5573 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5574 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5575};
5576static mut STDOUT_FILE: FILE = FILE {
5577 flags: F_NOWR as u32 + F_SVB as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5578 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5579 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5580 read_fn: None, write_fn: None, seek_fn: None,
5581 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5582 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5583 fd: 1, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5584 cookie: core::ptr::null_mut(), off: 0,
5585 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5586 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5587 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5588};
5589static mut STDERR_FILE: FILE = FILE {
5590 flags: F_NOWR as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
5591 close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
5592 mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
5593 read_fn: None, write_fn: None, seek_fn: None,
5594 buf: core::ptr::null_mut(), buf_size: BUFSIZ,
5595 prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
5596 fd: 2, pipe_pid: 0, lockcount: 0, mode: 0, lock: -1, lbf: -1,
5597 cookie: core::ptr::null_mut(), off: 0,
5598 getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
5599 shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
5600 ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
5601};
5602
5603#[no_mangle]
5604pub static mut stdin: *mut FILE = &raw mut STDIN_FILE as *mut FILE;
5605#[no_mangle]
5606pub static mut stdout: *mut FILE = &raw mut STDOUT_FILE as *mut FILE;
5607#[no_mangle]
5608pub static mut stderr: *mut FILE = &raw mut STDERR_FILE as *mut FILE;
5609
5610unsafe fn __stdio_init() {
5615 STDIN_FILE.buf = core::ptr::addr_of_mut!(STDIN_BUF) as *mut u8;
5616 STDIN_FILE.buf_size = BUFSIZ;
5617 STDIN_FILE.read_fn = Some(__stdio_read);
5618 STDIN_FILE.write_fn = Some(__stdio_write);
5619 STDIN_FILE.seek_fn = Some(__stdio_seek);
5620 STDOUT_FILE.buf = core::ptr::addr_of_mut!(STDOUT_BUF) as *mut u8;
5621 STDOUT_FILE.buf_size = BUFSIZ;
5622 STDOUT_FILE.lbf = b'\n' as c_int;
5623 STDOUT_FILE.read_fn = Some(__stdio_read);
5624 STDOUT_FILE.write_fn = Some(__stdio_write);
5625 STDOUT_FILE.seek_fn = Some(__stdio_seek);
5626 STDERR_FILE.buf = core::ptr::addr_of_mut!(STDERR_BUF) as *mut u8;
5627 STDERR_FILE.buf_size = BUFSIZ;
5628 STDERR_FILE.read_fn = Some(__stdio_read);
5629 STDERR_FILE.write_fn = Some(__stdio_write);
5630 STDERR_FILE.seek_fn = Some(__stdio_seek);
5631}
5632
5633unsafe fn buf_ptr(f: *mut FILE) -> *mut u8 {
5634 (f as *mut u8).add(core::mem::size_of::<FILE>())
5635}
5636
5637unsafe extern "C" fn __stdio_read(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
5638 let n = sys_read((*f).fd as i64, buf, len);
5639 if n <= 0 {
5640 if n == 0 { (*f).flags |= F_EOF; } else { (*f).flags |= F_ERR; (*f)._err = 1; }
5641 return 0;
5642 }
5643 n as usize
5644}
5645
5646unsafe extern "C" fn __stdio_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
5647 let l = (*f).wpos as usize - (*f).wbase as usize;
5648 let mut iov = [
5649 ((*f).wbase as *const u8, l),
5650 (buf, len),
5651 ];
5652 if iov[0].1 == 0 { iov = [iov[1], (core::ptr::null(), 0)]; }
5653 if (*f).flags & F_APP != 0 {
5654 let _ = sys_lseek((*f).fd as i64, 0, SEEK_END as i64);
5655 }
5656 let mut rem = iov[0].1 + iov[1].1;
5657 let mut idx = 0usize;
5658 while rem > 0 {
5659 let ptr = iov[idx].0;
5660 let cnt = iov[idx].1;
5661 if cnt == 0 { idx += 1; continue; }
5662 let n = sys_write((*f).fd as i64, ptr, cnt);
5663 if n <= 0 {
5664 (*f).wpos = core::ptr::null_mut();
5665 (*f).wbase = core::ptr::null_mut();
5666 (*f).wend = core::ptr::null_mut();
5667 (*f).flags |= F_ERR;
5668 return if iov[idx].0 == buf { 0 } else { len };
5669 }
5670 rem -= n as usize;
5671 iov[idx].0 = iov[idx].0.add(n as usize);
5672 iov[idx].1 -= n as usize;
5673 if iov[idx].1 == 0 { idx += 1; }
5674 }
5675 (*f).wend = (*f).buf.add((*f).buf_size);
5676 (*f).wbase = (*f).buf;
5677 (*f).wpos = (*f).buf;
5678 len
5679}
5680
5681unsafe extern "C" fn __stdio_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
5682 sys_lseek((*f).fd as i64, off, whence as i64)
5683}
5684
5685unsafe fn init_file(
5686 f: *mut FILE,
5687 fd: c_int,
5688 mode: *const c_char,
5689 close_fn: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
5690 buf_area: *mut u8,
5691 buf_sz: usize,
5692) {
5693 core::ptr::write_bytes(f as *mut u8, 0, core::mem::size_of::<FILE>());
5694 (*f).fd = fd;
5695 (*f).close = close_fn;
5696 (*f).lock = -1;
5697 (*f).lbf = -1;
5698 (*f).buf = buf_area;
5699 (*f).buf_size = buf_sz;
5700 (*f).read_fn = Some(__stdio_read);
5701 (*f).write_fn = Some(__stdio_write);
5702 (*f).seek_fn = Some(__stdio_seek);
5703 let m = *mode;
5704 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
5705 if m == b'r' as c_char && !has_plus {
5706 (*f).flags = F_NORD;
5707 } else if !has_plus {
5708 (*f).flags = F_NOWR;
5709 }
5710}
5711
5712unsafe extern "C" fn __stdio_close(f: *mut FILE) -> c_int {
5713 sys_close((*f).fd as i64);
5714 0
5715}
5716
5717unsafe fn fmodeflags(mode: *const c_char) -> c_int {
5718 let mut flags: c_int;
5719 let m = *mode;
5720 if !strchr(mode as *const u8, b'+' as c_int).is_null() {
5721 flags = O_RDWR;
5722 } else if m == b'r' as c_char {
5723 flags = O_RDONLY;
5724 } else {
5725 flags = O_WRONLY;
5726 }
5727 if !strchr(mode as *const u8, b'x' as c_int).is_null() { flags |= O_EXCL; }
5728 if !strchr(mode as *const u8, b'e' as c_int).is_null() { flags |= O_CLOEXEC; }
5729 if m != b'r' as c_char { flags |= O_CREAT; }
5730 if m == b'w' as c_char { flags |= O_TRUNC; }
5731 if m == b'a' as c_char { flags |= O_APPEND; }
5732 flags
5733}
5734
5735const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR;
5736
5737unsafe fn flush_buf(f: *mut FILE) -> c_int {
5738 if (*f).wpos == (*f).wbase {
5739 if !(*f).wpos.is_null() {
5740 (*f).wend = (*f).buf.add((*f).buf_size);
5741 (*f).wpos = (*f).wbase;
5742 }
5743 return 0;
5744 }
5745 if let Some(wfunc) = (*f).write_fn {
5746 let ret = wfunc(f, core::ptr::null(), 0);
5747 if ret == 0 && (*f).wpos.is_null() { return -1; }
5748 return 0;
5749 }
5750 (*f).flags |= F_ERR;
5751 -1
5752}
5753
5754#[no_mangle]
5759pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
5760 if filename.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
5761 let m = *mode;
5762 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
5763 ERRNO = EINVAL; return core::ptr::null_mut();
5764 }
5765 let flags = fmodeflags(mode);
5766 let fd = sys_open(filename as *const u8, flags as i64, 0o666);
5767 if fd < 0 { ERRNO = (-fd) as c_int; return core::ptr::null_mut(); }
5768 fdopen(fd as c_int, mode)
5769}
5770
5771#[no_mangle]
5772pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE {
5773 if fd < 0 || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
5774 let m = *mode;
5775 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
5776 ERRNO = EINVAL; return core::ptr::null_mut();
5777 }
5778 let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
5779 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
5780 let buf = buf_ptr(f);
5781 init_file(f, fd, mode, Some(__stdio_close), buf, BUFSIZ);
5782 if !strchr(mode as *const u8, b'a' as c_int).is_null() { (*f).flags |= F_APP; }
5783 if !strchr(mode as *const u8, b'e' as c_int).is_null() { sys_fcntl(fd, F_SETFD, FD_CLOEXEC as i64); }
5784 if (*f).flags & F_NOWR == 0 {
5785 let mut ws: winsize = core::mem::zeroed();
5786 if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 {
5787 (*f).lbf = b'\n' as c_int;
5788 }
5789 }
5790 f
5791}
5792
5793#[no_mangle]
5794pub unsafe extern "C" fn freopen(
5795 filename: *const c_char, mode: *const c_char, f: *mut FILE,
5796) -> *mut FILE {
5797 fflush(f);
5798 if (*f).pipe_pid > 0 { let _ = __stdio_close(f); }
5799 if filename.is_null() {
5800 let flags = fmodeflags(mode);
5801 if flags == 0 { return core::ptr::null_mut(); }
5802 let mut fl = flags & !(O_CREAT | O_EXCL | O_CLOEXEC);
5803 if (*f).flags & F_APP != 0 { fl = (fl & !O_ACCMODE) | O_WRONLY | O_APPEND; }
5804 if sys_fcntl((*f).fd, F_SETFL, fl as i64) < 0 { return core::ptr::null_mut(); }
5805 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
5806 if has_plus {
5807 (*f).flags &= !(F_NORD | F_NOWR);
5808 } else if *mode == b'r' as c_char {
5809 (*f).flags = ((*f).flags & !F_NOWR) | F_NORD;
5810 } else {
5811 (*f).flags = ((*f).flags & !F_NORD) | F_NOWR;
5812 }
5813 return f;
5814 }
5815 let new_f = fopen(filename, mode);
5816 if new_f.is_null() { let _ = __stdio_close(f); return core::ptr::null_mut(); }
5817 if (*new_f).fd == (*f).fd {
5818 (*new_f).fd = -1;
5819 } else {
5820 sys_dup3((*new_f).fd, (*f).fd, 0);
5821 let _ = __stdio_close(new_f);
5822 }
5823 (*f).flags = (*new_f).flags;
5824 (*f).rpos = core::ptr::null_mut();
5825 (*f).rend = core::ptr::null_mut();
5826 (*f).wpos = core::ptr::null_mut();
5827 (*f).wbase = core::ptr::null_mut();
5828 (*f).wend = core::ptr::null_mut();
5829 (*f).lbf = (*new_f).lbf;
5830 (*f).pipe_pid = 0;
5831 free(new_f as *mut c_void);
5832 f
5833}
5834
5835#[no_mangle]
5836pub unsafe extern "C" fn fclose(f: *mut FILE) -> c_int {
5837 if f.is_null() { return -1; }
5838 let r = fflush(f);
5839 if let Some(close_fn) = (*f).close { let _ = close_fn(f); }
5840 if r != 0 { -1 } else { 0 }
5841}
5842
5843#[no_mangle]
5848pub unsafe extern "C" fn setvbuf(f: *mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int {
5849 if mode != _IOFBF && mode != _IOLBF && mode != _IONBF { return -1; }
5850 fflush(f);
5851 (*f).rpos = core::ptr::null_mut();
5852 (*f).rend = core::ptr::null_mut();
5853 (*f).wpos = core::ptr::null_mut();
5854 (*f).wbase = core::ptr::null_mut();
5855 (*f).wend = core::ptr::null_mut();
5856 if mode == _IONBF {
5857 (*f).buf_size = 0;
5858 } else if !buf.is_null() && size > 0 {
5859 (*f).buf = buf as *mut u8;
5860 (*f).buf_size = size;
5861 }
5862 (*f).lbf = if mode == _IOLBF { b'\n' as c_int } else { -1 };
5863 0
5864}
5865
5866#[no_mangle]
5867pub unsafe extern "C" fn setbuf(f: *mut FILE, buf: *mut c_char) {
5868 if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
5869 else { setvbuf(f, buf, _IOFBF, BUFSIZ); }
5870}
5871
5872#[no_mangle]
5873pub unsafe extern "C" fn setbuffer(f: *mut FILE, buf: *mut c_char, size: usize) {
5874 if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
5875 else { setvbuf(f, buf, _IOFBF, size); }
5876}
5877
5878#[no_mangle]
5879pub unsafe extern "C" fn fflush(f: *mut FILE) -> c_int {
5880 if f.is_null() {
5881 let mut r = 0;
5882 if !stdout.is_null() && !(*stdout).wpos.is_null() && (*stdout).wpos != (*stdout).wbase {
5883 if flush_buf(stdout) != 0 { r = -1; }
5884 }
5885 if !stderr.is_null() && !(*stderr).wpos.is_null() && (*stderr).wpos != (*stderr).wbase {
5886 if flush_buf(stderr) != 0 { r = -1; }
5887 }
5888 return r;
5889 }
5890 if !(*f).wpos.is_null() && (*f).wpos != (*f).wbase {
5891 return flush_buf(f);
5892 }
5893 0
5894}
5895
5896#[no_mangle]
5901pub unsafe extern "C" fn fwide(_f: *mut FILE, mode: c_int) -> c_int { mode }
5902
5903#[no_mangle]
5904pub unsafe extern "C" fn feof(f: *mut FILE) -> c_int { if (*f)._eof != 0 { 1 } else { 0 } }
5905
5906#[no_mangle]
5907pub unsafe extern "C" fn ferror(f: *mut FILE) -> c_int { if (*f)._err != 0 { 1 } else { 0 } }
5908
5909#[no_mangle]
5910pub unsafe extern "C" fn clearerr(f: *mut FILE) { (*f)._eof = 0; (*f)._err = 0; }
5911
5912#[no_mangle]
5913pub unsafe extern "C" fn fileno(f: *mut FILE) -> c_int { (*f).fd }
5914
5915#[no_mangle]
5920pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
5921 fseeko(stream, offset as i64, whence)
5922}
5923
5924#[no_mangle]
5925pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
5926 ftello(stream) as c_long
5927}
5928
5929#[no_mangle]
5930pub unsafe extern "C" fn rewind(stream: *mut FILE) {
5931 fseek(stream, 0, SEEK_SET);
5932 (*stream)._eof = 0;
5933 (*stream)._err = 0;
5934}
5935
5936#[no_mangle]
5937pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: i64, whence: c_int) -> c_int {
5938 if whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END {
5939 ERRNO = EINVAL;
5940 return -1;
5941 }
5942 let f = &mut *stream;
5943 let mut adj_offset = offset;
5944 if whence == SEEK_CUR {
5945 if !f.rpos.is_null() {
5946 adj_offset -= f.rend as i64 - f.rpos as i64;
5947 }
5948 adj_offset -= f.ungotten_count as i64;
5949 }
5950 if !f.wpos.is_null() && f.wpos != f.wbase {
5951 if flush_buf(stream) != 0 { return -1; }
5952 }
5953 f.wpos = core::ptr::null_mut();
5954 f.wbase = core::ptr::null_mut();
5955 f.wend = core::ptr::null_mut();
5956 if let Some(sfunc) = f.seek_fn {
5957 let r = sfunc(stream, adj_offset, whence);
5958 if r < 0 { return -1; }
5959 } else {
5960 ERRNO = EINVAL;
5961 return -1;
5962 }
5963 f.rpos = core::ptr::null_mut();
5964 f.rend = core::ptr::null_mut();
5965 f._eof = 0;
5966 f.ungotten_count = 0;
5967 0
5968}
5969
5970#[no_mangle]
5971pub unsafe extern "C" fn ftello(stream: *mut FILE) -> i64 {
5972 let f = &mut *stream;
5973 if f.flags & F_APP != 0 && !f.wpos.is_null() && f.wpos != f.wbase {
5974 if fflush(stream) != 0 { return -1; }
5975 }
5976 let sfunc = match f.seek_fn { Some(s) => s, None => return -1 };
5977 let pos = sfunc(stream, 0,
5978 if (f.flags & F_APP) != 0 && !f.wpos.is_null() && f.wpos != f.wbase { SEEK_END } else { SEEK_CUR });
5979 if pos < 0 { return -1; }
5980 let mut pos = pos;
5981 if !f.rpos.is_null() {
5982 pos += f.rpos as i64 - f.rend as i64;
5983 } else if !f.wbase.is_null() {
5984 pos += f.wpos as i64 - f.wbase as i64;
5985 }
5986 pos - f.ungotten_count as i64
5987}
5988
5989#[no_mangle]
5990pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut i64) -> c_int {
5991 let off = ftello(stream);
5992 if off < 0 { return -1; }
5993 *pos = off;
5994 0
5995}
5996
5997#[no_mangle]
5998pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const i64) -> c_int {
5999 fseeko(stream, *pos, SEEK_SET)
6000}
6001
6002#[no_mangle]
6007pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
6008 let f = &mut *stream;
6009 if f.ungotten_count > 0 {
6010 f.ungotten_count -= 1;
6011 return f.ungotten[f.ungotten_count as usize];
6012 }
6013 if !f.rpos.is_null() && f.rpos < f.rend {
6014 let c = *f.rpos;
6015 f.rpos = f.rpos.add(1);
6016 return c as c_int;
6017 }
6018 if f._eof != 0 { return -1; }
6019 if let Some(rfunc) = f.read_fn {
6020 let mut buf = [0u8; 1];
6021 let n = rfunc(stream, buf.as_mut_ptr(), 1);
6022 if n == 0 {
6023 if f.flags & F_ERR != 0 { f._err = 1; } else { f._eof = 1; }
6024 return -1;
6025 }
6026 buf[0] as c_int
6027 } else {
6028 f._eof = 1;
6029 -1
6030 }
6031}
6032
6033#[no_mangle]
6034pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { fgetc(stream) }
6035
6036#[no_mangle]
6037pub unsafe extern "C" fn getchar() -> c_int { fgetc(stdin) }
6038
6039#[no_mangle]
6040pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
6041 if c == -1 { return -1; }
6042 let f = &mut *stream;
6043 if f.ungotten_count >= UNGET as c_int { return -1; }
6044 f.ungotten[f.ungotten_count as usize] = c;
6045 f.ungotten_count += 1;
6046 f._eof = 0;
6047 c
6048}
6049
6050#[no_mangle]
6055pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char {
6056 if n <= 0 { return null_mut(); }
6057 let max = (n - 1) as usize;
6058 let mut i = 0usize;
6059 while i < max {
6060 let c = fgetc(stream);
6061 if c == -1 { if i == 0 { return null_mut(); } break; }
6062 *s.add(i) = c as c_char;
6063 i += 1;
6064 if c == b'\n' as c_int { break; }
6065 }
6066 *s.add(i) = 0;
6067 s
6068}
6069
6070#[no_mangle]
6072pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char {
6073 let mut i = 0usize;
6074 loop {
6075 let c = fgetc(stdin);
6076 if c == -1 { if i == 0 { return null_mut(); } break; }
6077 if c == b'\n' as c_int { break; }
6078 *s.add(i) = c as c_char;
6079 i += 1;
6080 }
6081 *s.add(i) = 0;
6082 s
6083}
6084
6085#[no_mangle]
6086pub unsafe extern "C" fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut FILE {
6087 fopen(filename, mode)
6088}
6089
6090const PERROR_BUF_SIZE: usize = 64;
6092static mut PERROR_BUF: [u8; PERROR_BUF_SIZE] = [0; PERROR_BUF_SIZE];
6093
6094#[no_mangle]
6095pub unsafe extern "C" fn perror(msg: *const c_char) {
6096 let fd = (*stderr).fd;
6097 if !msg.is_null() && *msg != 0 {
6098 let len = strlen(msg as *const c_char);
6099 write_str(fd, msg as *const u8, len);
6100 write_str(fd, b": ".as_ptr(), 2);
6101 }
6102 let e = ERRNO;
6103 if e != 0 {
6105 let (buf, len) = format_i64(e as i64);
6106 write_str(fd, buf.as_ptr().add(21 - len), len);
6107 }
6108 write_str(fd, b"\n".as_ptr(), 1);
6109}
6110
6111#[no_mangle]
6112pub unsafe extern "C" fn fread(
6113 ptr: *mut c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6114) -> SizeT {
6115 if size == 0 || nmemb == 0 { return 0; }
6116 let total = size * nmemb;
6117 let mut rd = 0usize;
6118 while rd < total {
6119 let c = fgetc(stream);
6120 if c == -1 { break; }
6121 *(ptr as *mut u8).add(rd) = c as u8;
6122 rd += 1;
6123 }
6124 rd / size
6125}
6126
6127unsafe fn write_str(fd: c_int, s: *const u8, len: usize) {
6132 let mut written = 0usize;
6133 while written < len {
6134 let n = sys_write(fd as i64, s.add(written), len - written);
6135 if n <= 0 { break; }
6136 written += n as usize;
6137 }
6138}
6139
6140unsafe fn __overflow(f: *mut FILE, c: c_int) -> c_int {
6141 if (*f).wpos.is_null() {
6142 (*f).wbase = (*f).buf;
6143 (*f).wpos = (*f).buf;
6144 (*f).wend = (*f).buf.add((*f).buf_size);
6145 }
6146 if flush_buf(f) == -1 { return -1; }
6147 if (*f).wpos >= (*f).wend {
6148 if let Some(wfunc) = (*f).write_fn {
6149 let byte = c as u8;
6150 let ret = wfunc(f, &byte as *const u8, 1);
6151 if ret == 0 { return -1; }
6152 }
6153 return c;
6154 }
6155 *(*f).wpos = c as u8;
6156 (*f).wpos = (*f).wpos.add(1);
6157 if c == (*f).lbf || (*f).wpos >= (*f).wend { let _ = flush_buf(f); }
6158 c
6159}
6160
6161#[no_mangle]
6162pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
6163 let len = strlen(s as *const c_char);
6164 let _ = fwrite(s as *const c_void, 1, len, stdout);
6165 let _ = fwrite(b"\n".as_ptr() as *const c_void, 1, 1, stdout);
6166 let f = &mut *stdout;
6167 if f.lbf >= 0 { let _ = flush_buf(stdout); }
6168 (len + 1) as c_int
6169}
6170
6171#[no_mangle]
6172pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
6173 let len = strlen(s as *const c_char);
6174 fwrite(s as *const c_void, 1, len, stream) as c_int
6175}
6176
6177#[no_mangle]
6178pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
6179 let f = &mut *stream;
6180 if f.wpos.is_null() || f.wpos >= f.wend {
6181 if __overflow(f, c) == -1 { return -1; }
6182 return c;
6183 }
6184 *f.wpos = c as u8;
6185 f.wpos = f.wpos.add(1);
6186 if c == f.lbf || f.wpos >= f.wend { let _ = flush_buf(f); }
6187 c
6188}
6189
6190#[no_mangle]
6191pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { fputc(c, stream) }
6192
6193#[no_mangle]
6194pub unsafe extern "C" fn putchar(c: c_int) -> c_int { fputc(c, stdout) }
6195
6196#[no_mangle]
6197pub unsafe extern "C" fn fwrite(
6198 ptr: *const c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6199) -> SizeT {
6200 if size == 0 || nmemb == 0 { return 0; }
6201 let total = size * nmemb;
6202 let f = &mut *stream;
6203 if f.buf_size == 0 {
6204 if let Some(wfunc) = f.write_fn {
6205 let ret = wfunc(stream, ptr as *const u8, total);
6206 return ret / size;
6207 }
6208 return 0;
6209 }
6210 if f.wpos.is_null() {
6211 f.wbase = f.buf;
6212 f.wpos = f.buf;
6213 f.wend = f.buf.add(f.buf_size);
6214 }
6215 let mut remaining = total;
6216 let mut src = ptr as *const u8;
6217 while remaining > 0 {
6218 let space = f.wend as usize - f.wpos as usize;
6219 if space == 0 {
6220 if flush_buf(f as *mut FILE) == -1 { break; }
6221 continue;
6222 }
6223 let n = if remaining < space { remaining } else { space };
6224 core::ptr::copy_nonoverlapping(src, f.wpos, n);
6225 f.wpos = f.wpos.add(n);
6226 src = src.add(n);
6227 remaining -= n;
6228 if f.wpos >= f.wend { let _ = flush_buf(f as *mut FILE); }
6229 }
6230 if f.lbf >= 0 { let _ = flush_buf(f as *mut FILE); }
6231 (total - remaining) / size
6232}
6233
6234macro_rules! impl_format {
6239 ($fmt:expr, $args:expr, $write_char:expr, $write_str:expr) => {{
6240 let fmt = $fmt;
6241 let args = &mut $args;
6242 let mut count: usize = 0;
6243 let mut i = 0usize;
6244 loop {
6245 let c = *fmt.add(i) as u8;
6246 if c == 0 { break; }
6247 if c != b'%' {
6248 ($write_char)(c);
6249 count += 1; i += 1; continue;
6250 }
6251 i += 1;
6252 let mut flags: u8 = 0;
6254 loop {
6255 let fc = *fmt.add(i) as u8;
6256 match fc {
6257 b'-' => { flags |= FLAG_MINUS; i += 1; }
6258 b'+' => { flags |= FLAG_PLUS; i += 1; }
6259 b' ' => { flags |= FLAG_SPACE; i += 1; }
6260 b'0' => { flags |= FLAG_ZERO; i += 1; }
6261 b'#' => { flags |= FLAG_HASH; i += 1; }
6262 _ => break,
6263 }
6264 }
6265 let mut width: usize = 0;
6267 if *fmt.add(i) as u8 == b'*' {
6268 width = args.next_arg::<c_int>() as usize; i += 1;
6269 } else {
6270 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6271 width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
6272 }
6273 }
6274 let mut precision: i32 = -1;
6276 if *fmt.add(i) as u8 == b'.' {
6277 i += 1;
6278 if *fmt.add(i) as u8 == b'*' {
6279 precision = args.next_arg::<c_int>(); i += 1;
6280 } else {
6281 precision = 0;
6282 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6283 precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
6284 }
6285 }
6286 }
6287 let len_mod = *fmt.add(i) as u8;
6289 let spec: u8;
6290 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' {
6291 i += 1;
6292 let len_mod2 = *fmt.add(i) as u8;
6293 if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
6294 i += 1;
6295 spec = *fmt.add(i) as u8;
6296 match (len_mod, len_mod2, spec) {
6298 (b'h', b'h', b'n') => {
6299 let p = args.next_arg::<*mut c_void>();
6300 if !p.is_null() { *(p as *mut u8) = count as u8; }
6301 }
6302 (b'l', b'l', b'n') => {
6303 let p = args.next_arg::<*mut c_void>();
6304 if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
6305 }
6306 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
6307 let val = args.next_arg::<c_longlong>();
6308 let neg = val < 0;
6309 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6310 let b = format_u64(abs);
6311 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6312 let mut fbuf = [0u8; 32];
6313 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6314 ($write_str)(fbuf.as_ptr(), len); count += len;
6315 }
6316 (b'l', b'l', b'u') => {
6317 let val = args.next_arg::<c_ulonglong>();
6318 let b = format_u64(val as u64);
6319 let mut fbuf = [0u8; 32];
6320 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6321 ($write_str)(fbuf.as_ptr(), len); count += len;
6322 }
6323 (b'l', b'l', b'o') => {
6324 let val = args.next_arg::<c_ulonglong>();
6325 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
6326 let mut fbuf = [0u8; 32];
6327 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6328 ($write_str)(fbuf.as_ptr(), len); count += len;
6329 }
6330 _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(len_mod2); ($write_char)(spec); count += 4; }
6331 }
6332 } else {
6333 spec = len_mod2;
6334 match (len_mod, spec) {
6335 (b'h', b'n') => {
6336 let p = args.next_arg::<*mut c_void>();
6337 if !p.is_null() { *(p as *mut u16) = count as u16; }
6338 }
6339 (b'l', b'n') => {
6340 let p = args.next_arg::<*mut c_void>();
6341 if !p.is_null() { *(p as *mut c_long) = count as c_long; }
6342 }
6343 (b'z', b'n') | (b't', b'n') => {
6344 let p = args.next_arg::<*mut c_void>();
6345 if !p.is_null() { *(p as *mut usize) = count; }
6346 }
6347 (b'j', b'n') => {
6348 let p = args.next_arg::<*mut c_void>();
6349 if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
6350 }
6351 (b'l', b'd') | (b'l', b'i') => {
6352 let val = args.next_arg::<c_long>();
6353 let neg = val < 0;
6354 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6355 let b = format_u64(abs);
6356 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6357 let mut fbuf = [0u8; 32];
6358 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6359 ($write_str)(fbuf.as_ptr(), len); count += len;
6360 }
6361 (b'l', b'u') => {
6362 let val = args.next_arg::<c_ulong>();
6363 let b = format_u64(val as u64);
6364 let mut fbuf = [0u8; 32];
6365 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6366 ($write_str)(fbuf.as_ptr(), len); count += len;
6367 }
6368 (b'l', b'x') => {
6369 let val = args.next_arg::<c_ulong>();
6370 let b = format_hex(val as u64, false);
6371 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
6372 let mut fbuf = [0u8; 32];
6373 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6374 ($write_str)(fbuf.as_ptr(), len); count += len;
6375 }
6376 (b'l', b'X') => {
6377 let val = args.next_arg::<c_ulong>();
6378 let b = format_hex(val as u64, true);
6379 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
6380 let mut fbuf = [0u8; 32];
6381 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6382 ($write_str)(fbuf.as_ptr(), len); count += len;
6383 }
6384 (b'l', b'o') => {
6385 let val = args.next_arg::<c_ulong>();
6386 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
6387 let mut fbuf = [0u8; 32];
6388 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6389 ($write_str)(fbuf.as_ptr(), len); count += len;
6390 }
6391 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
6392 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
6393 let val = args.next_arg::<f64>();
6394 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6395 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6396 let mut fbuf = [0u8; 4224];
6397 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6398 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6399 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6400 ($write_str)(fbuf.as_ptr(), total); count += total;
6401 }
6402 (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
6403 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
6404 let val = args.next_arg::<f64>();
6406 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6407 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6408 let mut fbuf = [0u8; 4224];
6409 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6410 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6411 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6412 ($write_str)(fbuf.as_ptr(), total); count += total;
6413 }
6414 _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(spec); count += 3; }
6415 }
6416 }
6417 } else {
6418 spec = *fmt.add(i) as u8;
6419 match spec {
6420 b's' => {
6421 let s = args.next_arg::<*const c_char>();
6422 if s.is_null() {
6423 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
6424 let padded_len = if width > slen { width } else { slen };
6425 let pad = padded_len - slen;
6426 if flags & FLAG_MINUS != 0 {
6427 ($write_str)(b"(null)".as_ptr(), slen);
6428 for _ in 0..pad { ($write_char)(b' '); }
6429 } else {
6430 for _ in 0..pad { ($write_char)(b' '); }
6431 ($write_str)(b"(null)".as_ptr(), slen);
6432 }
6433 count += padded_len;
6434 } else {
6435 let full_len = strlen(s as *const c_char);
6436 let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
6437 let padded_len = if width > slen { width } else { slen };
6438 let pad = padded_len - slen;
6439 if flags & FLAG_MINUS != 0 {
6440 ($write_str)(s as *const u8, slen);
6441 for _ in 0..pad { ($write_char)(b' '); }
6442 } else {
6443 for _ in 0..pad { ($write_char)(b' '); }
6444 ($write_str)(s as *const u8, slen);
6445 }
6446 count += padded_len;
6447 }
6448 }
6449 b'd' | b'i' => {
6450 let d = args.next_arg::<c_int>();
6451 let neg = d < 0;
6452 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
6453 let b = format_u64(abs);
6454 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6455 let mut fbuf = [0u8; 32];
6456 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6457 ($write_str)(fbuf.as_ptr(), len); count += len;
6458 }
6459 b'u' => {
6460 let u = args.next_arg::<c_uint>();
6461 let b = format_u64(u as u64);
6462 let mut fbuf = [0u8; 32];
6463 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6464 ($write_str)(fbuf.as_ptr(), len); count += len;
6465 }
6466 b'x' => {
6467 let x = args.next_arg::<c_uint>();
6468 let b = format_hex(x as u64, false);
6469 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
6470 let mut fbuf = [0u8; 32];
6471 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6472 ($write_str)(fbuf.as_ptr(), len); count += len;
6473 }
6474 b'X' => {
6475 let x = args.next_arg::<c_uint>();
6476 let b = format_hex(x as u64, true);
6477 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
6478 let mut fbuf = [0u8; 32];
6479 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6480 ($write_str)(fbuf.as_ptr(), len); count += len;
6481 }
6482 b'o' => {
6483 let o = args.next_arg::<c_uint>();
6484 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
6485 let mut fbuf = [0u8; 32];
6486 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6487 ($write_str)(fbuf.as_ptr(), len); count += len;
6488 }
6489 b'c' => {
6490 let ch = args.next_arg::<c_int>();
6491 if width > 1 {
6492 let pad = width - 1;
6493 if flags & FLAG_MINUS != 0 {
6494 ($write_char)(ch as u8); count += 1;
6495 for _ in 0..pad { ($write_char)(b' '); count += 1; }
6496 } else {
6497 for _ in 0..pad { ($write_char)(b' '); count += 1; }
6498 ($write_char)(ch as u8); count += 1;
6499 }
6500 } else {
6501 ($write_char)(ch as u8); count += 1;
6502 }
6503 }
6504 b'p' => {
6505 let p = args.next_arg::<*const c_void>();
6506 let mut fbuf = [0u8; 20];
6507 fbuf[0] = b'0'; fbuf[1] = b'x';
6508 let b = format_hex(p as u64, false);
6509 core::ptr::copy_nonoverlapping(b.0.as_ptr(), fbuf.as_mut_ptr().add(2), b.1);
6510 ($write_str)(fbuf.as_ptr(), b.1 + 2); count += b.1 + 2;
6511 }
6512 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
6513 let val = args.next_arg::<f64>();
6514 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
6515 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
6516 let mut fbuf = [0u8; 4224];
6517 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
6518 let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
6519 core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
6520 ($write_str)(fbuf.as_ptr(), total); count += total;
6521 }
6522 b'%' => { ($write_char)(b'%'); count += 1; }
6523 b'n' => {
6524 let p = args.next_arg::<*mut c_void>();
6525 if !p.is_null() { *(p as *mut c_int) = count as c_int; }
6526 }
6527 _ => { ($write_char)(b'%'); ($write_char)(spec); count += 2; }
6528 }
6529 }
6530 i += 1;
6531 }
6532 count as c_int
6533 }};
6534}
6535
6536unsafe fn format_u64(mut val: u64) -> ([u8; 20], usize) {
6537 let mut buf = [0u8; 20];
6538 if val == 0 { buf[0] = b'0'; return (buf, 1); }
6539 let mut tmp = [0u8; 20];
6540 let mut pos = 20;
6541 while val > 0 { pos -= 1; tmp[pos] = b'0' + (val % 10) as u8; val /= 10; }
6542 let len = 20 - pos;
6543 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6544 (buf, len)
6545}
6546
6547unsafe fn format_i64(val: i64) -> ([u8; 21], usize) {
6548 let mut buf = [0u8; 21];
6549 if val < 0 {
6550 buf[0] = b'-';
6551 let (inner, len) = format_u64((-(val as i128)) as u64);
6552 core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr().add(1), len);
6553 (buf, len + 1)
6554 } else {
6555 let (inner, len) = format_u64(val as u64);
6556 core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr(), len);
6557 (buf, len)
6558 }
6559}
6560
6561unsafe fn format_hex(mut val: u64, uppercase: bool) -> ([u8; 16], usize) {
6562 let digits = if uppercase { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
6563 let mut buf = [0u8; 16];
6564 if val == 0 { buf[0] = b'0'; return (buf, 1); }
6565 let mut tmp = [0u8; 16];
6566 let mut pos = 16;
6567 while val > 0 { pos -= 1; tmp[pos] = digits[(val & 0xf) as usize]; val >>= 4; }
6568 let len = 16 - pos;
6569 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6570 (buf, len)
6571}
6572
6573unsafe fn format_octal(mut val: u64, alt: bool) -> ([u8; 24], usize) {
6574 let mut buf = [0u8; 24];
6575 if val == 0 {
6576 buf[0] = b'0';
6577 return (buf, 1);
6578 }
6579 let mut tmp = [0u8; 24];
6580 let mut pos = 24;
6581 while val > 0 {
6582 pos -= 1;
6583 tmp[pos] = b'0' + (val & 7) as u8;
6584 val >>= 3;
6585 }
6586 let len = 24 - pos;
6587 if alt {
6588 tmp[pos - 1] = b'0';
6589 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos - 1), buf.as_mut_ptr(), len + 1);
6590 (buf, len + 1)
6591 } else {
6592 core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
6593 (buf, len)
6594 }
6595}
6596
6597unsafe fn format_int(
6598 dst: *mut u8,
6599 digits: *const u8,
6600 digits_len: usize,
6601 sign: Option<u8>,
6602 prefix: Option<u8>,
6603 precision: i32,
6604 width: usize,
6605 flags: u8,
6606 octal_alt: bool,
6607) -> usize {
6608 let num_digits = if precision == 0 && digits_len == 1 && *digits == b'0' && !octal_alt {
6609 0
6610 } else {
6611 digits_len
6612 };
6613 let prec = precision as usize;
6614 let zero_pad = if precision >= 0 && prec > num_digits { prec - num_digits } else { 0 };
6615
6616 let sign_len = sign.map_or(0, |_| 1);
6617 let prefix_len = prefix.map_or(0, |_| 2);
6618 let content_len = sign_len + prefix_len + zero_pad + num_digits;
6619
6620 let mut buf = [0u8; 32];
6621 let mut pos = 0usize;
6622 if let Some(c) = sign { buf[pos] = c; pos += 1; }
6623 if let Some(c) = prefix { buf[pos] = b'0'; pos += 1; buf[pos] = c; pos += 1; }
6624 for _ in 0..zero_pad { buf[pos] = b'0'; pos += 1; }
6625 if num_digits > 0 {
6626 core::ptr::copy_nonoverlapping(digits, buf.as_mut_ptr().add(pos), num_digits);
6627 }
6628
6629 if content_len >= width {
6630 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
6631 return content_len;
6632 }
6633 let pad = width - content_len;
6634 if flags & FLAG_MINUS != 0 {
6635 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
6636 for i in 0..pad { *dst.add(content_len + i) = b' '; }
6637 } else if flags & FLAG_ZERO != 0 && precision < 0 {
6638 let fixed = sign_len + prefix_len;
6639 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, fixed);
6640 for i in fixed..width - num_digits { *dst.add(i) = b'0'; }
6641 if num_digits > 0 {
6642 core::ptr::copy_nonoverlapping(digits, dst.add(width - num_digits), num_digits);
6643 }
6644 } else {
6645 for i in 0..pad { *dst.add(i) = b' '; }
6646 core::ptr::copy_nonoverlapping(buf.as_ptr(), dst.add(pad), content_len);
6647 }
6648 width
6649}
6650
6651unsafe fn format_f64(val: f64) -> ([u8; 64], usize) {
6652 let mut buf = [0u8; 64];
6653 let mut pos = 0usize;
6654 let mut v = val;
6655 if v.is_nan() {
6656 let nan = b"nan";
6657 core::ptr::copy_nonoverlapping(nan.as_ptr(), buf.as_mut_ptr(), 3);
6658 return (buf, 3);
6659 }
6660 if v < 0.0 { buf[pos] = b'-'; pos += 1; v = -v; }
6661 if v.is_infinite() {
6662 let inf = b"inf";
6663 core::ptr::copy_nonoverlapping(inf.as_ptr(), buf.as_mut_ptr().add(pos), 3);
6664 return (buf, pos + 3);
6665 }
6666 let int_part = v as u64;
6667 let frac = v - int_part as f64;
6668 let (ibuf, ilen) = format_u64(int_part);
6669 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), buf.as_mut_ptr().add(pos), ilen);
6670 pos += ilen;
6671 buf[pos] = b'.';
6672 pos += 1;
6673 let mut f = frac;
6674 for _ in 0..6 { f *= 10.0; let digit = f as u8; buf[pos] = b'0' + digit; pos += 1; f -= digit as f64; }
6675 (buf, pos)
6676}
6677
6678const FMT_F: u8 = 0;
6680const FMT_E: u8 = 1;
6681const FMT_G: u8 = 2;
6682const FMT_A: u8 = 3;
6683
6684const FLAG_HASH: u8 = 1;
6685const FLAG_PLUS: u8 = 2;
6686const FLAG_SPACE: u8 = 4;
6687const FLAG_ZERO: u8 = 8;
6688const FLAG_MINUS: u8 = 16;
6689
6690unsafe fn bigint_to_decimal(buf: *mut u8, mant: u64, shift: u32) -> usize {
6695 let nlimbs = (2 + (shift + 31) / 32) as usize;
6697 let mut limbs = [0u32; 36];
6698 limbs[0] = mant as u32;
6699 limbs[1] = (mant >> 32) as u32;
6700
6701 let ws = (shift / 32) as usize;
6702 let bs = shift % 32;
6703
6704 if ws > 0 {
6706 let mut i = 1usize;
6707 loop {
6708 limbs[i + ws] = limbs[i];
6709 if i == 0 { break; }
6710 i -= 1;
6711 }
6712 for j in 0..ws { limbs[j] = 0; }
6713 }
6714 if bs > 0 {
6716 let mut carry = 0u32;
6717 let end = nlimbs.min(ws + 3);
6718 for i in ws..end {
6719 let new_val = (limbs[i] << bs) | carry;
6720 carry = limbs[i] >> (32 - bs);
6721 limbs[i] = new_val;
6722 }
6723 }
6724
6725 let mut used = nlimbs;
6727 while used > 0 && limbs[used - 1] == 0 { used -= 1; }
6728 if used == 0 { *buf = b'0'; return 1; }
6729
6730 let mut digits = [0u8; 400];
6732 let mut nd = 0usize;
6733 loop {
6734 let mut all_zero = true;
6735 for i in 0..used { if limbs[i] != 0 { all_zero = false; break; } }
6736 if all_zero { break; }
6737 let mut rem = 0u64;
6738 for i in (0..used).rev() {
6739 let val = (rem << 32) | limbs[i] as u64;
6740 limbs[i] = (val / 10) as u32;
6741 rem = val % 10;
6742 }
6743 digits[nd] = rem as u8;
6744 nd += 1;
6745 }
6746 for i in 0..nd { *buf.add(i) = b'0' + digits[nd - 1 - i]; }
6748 nd
6749}
6750
6751unsafe fn frac_digits_u128(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
6754 let mask: u128 = (1u128 << shift) - 1;
6755 let mut rem = frac_bits as u128;
6756 for i in 0..count {
6757 rem *= 10;
6758 let digit = (rem >> shift) as u8;
6759 rem &= mask;
6760 *buf.add(i) = digit;
6761 }
6762 rem != 0
6763}
6764
6765unsafe fn frac_digits_bigint(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
6768 let nlimbs = ((shift + 31) / 32) as usize;
6769 let mut rem = [0u32; 36]; rem[0] = frac_bits as u32;
6771 if nlimbs > 1 { rem[1] = (frac_bits >> 32) as u32; }
6772 let hi_word = (shift / 32) as usize;
6774 let hi_bit = shift % 32;
6775 if hi_bit > 0 && hi_word < nlimbs {
6776 rem[hi_word] &= (1u32 << hi_bit) - 1;
6777 }
6778 let clear_from = if hi_bit > 0 { hi_word + 1 } else { hi_word };
6780 for j in clear_from..nlimbs { rem[j] = 0; }
6781
6782 for i in 0..count {
6783 let mut carry = 0u64;
6785 for j in 0..nlimbs {
6786 let val = rem[j] as u64 * 10 + carry;
6787 rem[j] = val as u32;
6788 carry = val >> 32;
6789 }
6790 let digit: u32;
6792 if hi_bit == 0 {
6793 digit = if hi_word < nlimbs { rem[hi_word] } else { carry as u32 };
6794 } else {
6795 let mut d = if hi_word < nlimbs { rem[hi_word] >> hi_bit } else { 0 };
6796 if hi_word + 1 < nlimbs {
6797 d |= rem[hi_word + 1] << (32 - hi_bit);
6798 } else if carry > 0 {
6799 d |= (carry as u32) << (32 - hi_bit);
6800 }
6801 digit = d;
6802 }
6803 *buf.add(i) = digit.min(9) as u8;
6804 if hi_bit == 0 {
6806 if hi_word < nlimbs { rem[hi_word] = 0; }
6807 } else {
6808 if hi_word < nlimbs {
6809 rem[hi_word] &= (1u32 << hi_bit) - 1;
6810 }
6811 for j in (hi_word + 1)..nlimbs { rem[j] = 0; }
6812 }
6813 }
6814 for i in 0..nlimbs { if rem[i] != 0 { return true; } }
6816 false
6817}
6818
6819unsafe fn increment_decimal(buf: *mut u8, len: &mut usize) {
6821 let mut j = *len;
6822 loop {
6823 if j == 0 {
6824 let l = *len;
6826 for i in (0..l).rev() { *buf.add(i + 1) = *buf.add(i); }
6827 *buf = b'1';
6828 *len = l + 1;
6829 return;
6830 }
6831 j -= 1;
6832 let d = *buf.add(j);
6833 if d < b'9' { *buf.add(j) = d + 1; return; }
6834 *buf.add(j) = b'0';
6835 }
6836}
6837
6838unsafe fn format_f64_full(
6840 dst: *mut u8, val: f64, fmt_type: u8, precision: i32, flags: u8, uppercase: bool,
6841) -> usize {
6842 let mut pos = 0usize;
6843
6844 if val.is_nan() {
6846 let nan_s: &[u8] = if uppercase { b"NAN" } else { b"nan" };
6847 core::ptr::copy_nonoverlapping(nan_s.as_ptr(), dst, 3);
6848 return 3;
6849 }
6850 let neg = val.is_sign_negative();
6851 let v = if neg { -val } else { val };
6852
6853 if v.is_infinite() {
6855 if neg { *dst.add(pos) = b'-'; pos += 1; }
6856 else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
6857 else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
6858 let inf_s: &[u8] = if uppercase { b"INF" } else { b"inf" };
6859 core::ptr::copy_nonoverlapping(inf_s.as_ptr(), dst.add(pos), 3);
6860 return pos + 3;
6861 }
6862
6863 if neg { *dst.add(pos) = b'-'; pos += 1; }
6865 else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
6866 else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
6867
6868 if fmt_type == FMT_A {
6870 return pos + fmt_hex_float(dst.add(pos), val, precision, flags, uppercase);
6871 }
6872
6873 let p: usize;
6875 let mut exp: i32;
6876 let use_f: bool;
6877
6878 match fmt_type {
6879 FMT_G => {
6880 let gp = if precision < 0 { 6usize } else if precision == 0 { 1usize } else { precision as usize };
6881 exp = if v > 0.0 { compute_exp10(v) } else { 0 };
6882 use_f = exp >= -4 && exp < gp as i32;
6883 if use_f {
6884 p = if exp < 0 { gp + ((-exp) as usize - 1) }
6885 else if (exp as usize) < gp { gp - exp as usize - 1 }
6886 else { 0 };
6887 } else {
6888 p = gp - 1;
6889 }
6890 }
6891 FMT_E => {
6892 p = if precision < 0 { 6usize } else { precision as usize };
6893 exp = if v > 0.0 { compute_exp10(v) } else { 0 };
6894 use_f = false;
6895 }
6896 _ => {
6897 p = if precision < 0 { 6usize } else { precision as usize };
6898 exp = 0;
6899 use_f = true;
6900 }
6901 }
6902
6903 if v == 0.0 {
6904 *dst.add(pos) = b'0'; pos += 1;
6905 if !(fmt_type == FMT_G && flags & FLAG_HASH == 0) {
6906 if p > 0 || flags & FLAG_HASH != 0 {
6907 *dst.add(pos) = b'.'; pos += 1;
6908 for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
6909 }
6910 }
6911 if !use_f {
6912 let ec = if uppercase { b'E' } else { b'e' };
6913 *dst.add(pos) = ec; pos += 1;
6914 *dst.add(pos) = b'+'; pos += 1;
6915 *dst.add(pos) = b'0'; pos += 1;
6916 *dst.add(pos) = b'0'; pos += 1;
6917 }
6918 return pos;
6919 }
6920
6921 if use_f {
6923 let bits = v.to_bits();
6924 let raw_mant = bits & 0x000FFFFFFFFFFFFF;
6925 let raw_exp_bits = ((bits >> 52) & 0x7FF) as i32;
6926 let (mant_b, bin_exp) = if raw_exp_bits == 0 {
6927 (raw_mant, -1022i32)
6928 } else {
6929 (raw_mant | (1u64 << 52), raw_exp_bits - 1023)
6930 };
6931
6932 let mut ibuf = [0u8; 400];
6934 let mut ilen: usize;
6935 if bin_exp < 0 {
6936 ibuf[0] = b'0'; ilen = 1;
6937 } else if bin_exp <= 63 {
6938 let int_val = if bin_exp <= 52 { mant_b >> (52 - bin_exp) }
6939 else { mant_b << (bin_exp - 52) };
6940 let (buf2, len2) = format_u64(int_val);
6941 ibuf[..len2].copy_from_slice(&buf2[..len2]);
6942 ilen = len2;
6943 } else {
6944 ilen = bigint_to_decimal(ibuf.as_mut_ptr(), mant_b, (bin_exp - 52) as u32);
6945 }
6946
6947 let mut fbuf = [0u8; 1100];
6949 let mut has_rest = false;
6950 if p > 0 && bin_exp < 52 {
6951 let shift = (52 - bin_exp) as u32;
6952 let frac_bits = if bin_exp >= 0 { mant_b & ((1u64 << shift) - 1) } else { mant_b };
6953 if shift <= 124 {
6954 has_rest = frac_digits_u128(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
6955 } else {
6956 has_rest = frac_digits_bigint(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
6957 }
6958 }
6959
6960 if p > 0 && bin_exp < 52 {
6962 let next_d = fbuf[p];
6963 let last_d = fbuf[p - 1];
6964 if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
6965 let mut carry = true;
6966 for j in (0..p).rev() {
6967 if !carry { break; }
6968 fbuf[j] += 1;
6969 if fbuf[j] < 10 { carry = false; break; }
6970 fbuf[j] = 0;
6971 }
6972 if carry { increment_decimal(ibuf.as_mut_ptr(), &mut ilen); }
6973 }
6974 } else if p == 0 {
6975 if bin_exp >= 0 && bin_exp < 52 {
6977 let shift = (52 - bin_exp) as u32;
6978 let frac_bits = mant_b & ((1u64 << shift) - 1);
6979 let half = 1u64 << (shift - 1);
6980 let last_d = ibuf[ilen - 1] - b'0';
6981 if frac_bits > half || (frac_bits == half && last_d & 1 != 0) {
6982 increment_decimal(ibuf.as_mut_ptr(), &mut ilen);
6983 }
6984 }
6985 }
6986
6987 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
6989 pos += ilen;
6990 if p > 0 || flags & FLAG_HASH != 0 {
6991 *dst.add(pos) = b'.'; pos += 1;
6992 for i in 0..p { *dst.add(pos) = b'0' + fbuf[i]; pos += 1; }
6993 }
6994 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
6995 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
6996 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
6997 }
6998 return pos;
6999 }
7000
7001 let mut fbuf = [0u8; 20];
7004 let mut int_part: u64;
7005 {
7006 let bits_v = v.to_bits();
7007 let raw_mant_v = bits_v & 0x000FFFFFFFFFFFFF;
7008 let raw_exp_v = ((bits_v >> 52) & 0x7FF) as i32;
7009 let (mant_b_v, bin_exp_v) = if raw_exp_v == 0 {
7010 (raw_mant_v, -1022i32)
7011 } else {
7012 (raw_mant_v | (1u64 << 52), raw_exp_v - 1023)
7013 };
7014
7015 let s: i32 = (p as i32) + 1 - exp;
7016 let bs: i32 = bin_exp_v - 52 + s;
7017
7018 let mut limbs = [0u32; 40];
7019 limbs[0] = mant_b_v as u32;
7020 limbs[1] = (mant_b_v >> 32) as u32;
7021 let mut nlimbs: usize = if limbs[1] != 0 { 2 } else { 1 };
7022
7023 if s > 0 {
7024 for _ in 0..(s as usize) {
7025 let mut carry = 0u64;
7026 for j in 0..nlimbs {
7027 let val = limbs[j] as u64 * 5 + carry;
7028 limbs[j] = val as u32;
7029 carry = val >> 32;
7030 }
7031 if carry > 0 { limbs[nlimbs] = carry as u32; nlimbs += 1; }
7032 }
7033 }
7034
7035 if bs > 0 {
7036 let ws = (bs as u32 / 32) as usize;
7037 let bit = bs as u32 % 32;
7038 if ws > 0 {
7039 let mut i = nlimbs;
7040 while i > 0 { i -= 1; if i + ws < 40 { limbs[i + ws] = limbs[i]; } limbs[i] = 0; }
7041 nlimbs += ws;
7042 }
7043 if bit > 0 {
7044 let mut carry = 0u32;
7045 for i in ws..nlimbs {
7046 let new_val = (limbs[i] << bit) | carry;
7047 carry = limbs[i] >> (32 - bit);
7048 limbs[i] = new_val;
7049 }
7050 if carry > 0 && nlimbs < 40 { limbs[nlimbs] = carry; nlimbs += 1; }
7051 }
7052 }
7053
7054 let mut has_rest = false;
7055 if s < 0 {
7056 for _ in 0..(-s as usize) {
7057 let mut rem = 0u64;
7058 for i in (0..nlimbs).rev() {
7059 let val = (rem << 32) | limbs[i] as u64;
7060 limbs[i] = (val / 5) as u32;
7061 rem = val % 5;
7062 }
7063 if rem != 0 { has_rest = true; }
7064 }
7065 }
7066
7067 if bs < 0 {
7068 let rshift = (-bs) as u32;
7069 let ws = (rshift / 32) as usize;
7070 let bit = rshift % 32;
7071 if ws > 0 {
7072 for j in 0..ws.min(nlimbs) { if limbs[j] != 0 { has_rest = true; } }
7073 for i in ws..nlimbs { limbs[i - ws] = limbs[i]; }
7074 nlimbs = nlimbs.saturating_sub(ws);
7075 }
7076 if bit > 0 && nlimbs > 0 {
7077 let mask = (1u32 << bit) - 1;
7078 if limbs[0] & mask != 0 { has_rest = true; }
7079 for i in 0..nlimbs - 1 {
7080 limbs[i] = (limbs[i] >> bit) | (limbs[i + 1] << (32 - bit));
7081 }
7082 limbs[nlimbs - 1] >>= bit;
7083 }
7084 }
7085
7086 while nlimbs > 0 && limbs[nlimbs - 1] == 0 { nlimbs -= 1; }
7087
7088 let ndigits = p + 2;
7089 let mut all_digits = [0u8; 25];
7090 let mut nd = 0usize;
7091 if nlimbs > 0 {
7092 loop {
7093 let mut all_zero = true;
7094 for i in 0..nlimbs { if limbs[i] != 0 { all_zero = false; break; } }
7095 if all_zero { break; }
7096 let mut rem64 = 0u64;
7097 for i in (0..nlimbs).rev() {
7098 let val = (rem64 << 32) | limbs[i] as u64;
7099 limbs[i] = (val / 10) as u32;
7100 rem64 = val % 10;
7101 }
7102 if nd < 25 { all_digits[nd] = rem64 as u8; }
7103 nd += 1;
7104 }
7105 }
7106
7107 if nd >= ndigits {
7108 for i in 0..ndigits { fbuf[ndigits - 1 - i] = all_digits[i]; }
7109 } else {
7110 for i in 0..nd { fbuf[ndigits - 1 - i] = all_digits[i]; }
7111 for i in nd..ndigits { fbuf[ndigits - 1 - i] = 0; }
7112 }
7113
7114 int_part = fbuf[0] as u64;
7115
7116 if p > 0 {
7118 let next_d = fbuf[p + 1];
7119 let last_d = fbuf[p];
7120 if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
7121 let mut carry = true;
7122 for j in (1..=p).rev() {
7123 if !carry { break; }
7124 let d = fbuf[j] + 1;
7125 if d < 10 { fbuf[j] = d; carry = false; break; }
7126 fbuf[j] = 0;
7127 }
7128 if carry { int_part += 1; }
7129 }
7130 } else {
7131 let next_d = fbuf[1];
7132 if next_d > 5 || (next_d == 5 && (has_rest || int_part & 1 != 0)) {
7133 int_part += 1;
7134 }
7135 }
7136
7137 for i in 0..p { fbuf[i] = fbuf[i + 1]; }
7140 }
7141
7142 if !use_f && int_part >= 10 {
7143 exp += 1;
7144 int_part = 1;
7145 }
7146
7147 if use_f {
7149 let (ibuf, ilen) = format_u64(int_part);
7151 core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
7152 pos += ilen;
7153 if p > 0 || flags & FLAG_HASH != 0 {
7154 *dst.add(pos) = b'.'; pos += 1;
7155 for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7156 }
7157 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7158 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7159 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7160 }
7161 } else {
7162 *dst.add(pos) = b'0' + int_part as u8; pos += 1;
7164 if p > 0 || flags & FLAG_HASH != 0 {
7165 *dst.add(pos) = b'.'; pos += 1;
7166 for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7167 }
7168 if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7169 while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7170 if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7171 }
7172 let ec = if uppercase { b'E' } else { b'e' };
7173 *dst.add(pos) = ec; pos += 1;
7174 *dst.add(pos) = if exp < 0 { b'-' } else { b'+' }; pos += 1;
7175 let eabs = if exp < 0 { (-exp) as u32 } else { exp as u32 };
7176 if eabs < 10 { *dst.add(pos) = b'0'; pos += 1; }
7177 let (ebuf, elen) = format_u64(eabs as u64);
7178 core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7179 pos += elen;
7180 }
7181
7182 pos
7183}
7184
7185unsafe fn compute_exp10(v: f64) -> i32 {
7187 let e = libm::floor(libm::log10(v)) as i32;
7188 let probe = v / libm::pow(10.0, e as f64);
7189 if probe >= 10.0 { e + 1 }
7190 else if probe < 1.0 { e - 1 }
7191 else { e }
7192}
7193
7194unsafe fn fmt_hex_float(dst: *mut u8, val: f64, precision: i32, _flags: u8, uppercase: bool) -> usize {
7196 if val.to_bits() & 0x7FFFFFFFFFFFFFFF == 0 {
7198 let lc = !uppercase;
7199 let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7200 let p = if precision < 0 { 0usize } else { precision as usize };
7201 let mut pos = 0usize;
7202 core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7203 *dst.add(pos) = b'0'; pos += 1;
7204 if p > 0 {
7205 *dst.add(pos) = b'.'; pos += 1;
7206 for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
7207 }
7208 let pc = if lc { b'p' } else { b'P' };
7209 *dst.add(pos) = pc; pos += 1;
7210 *dst.add(pos) = b'+'; pos += 1;
7211 *dst.add(pos) = b'0'; pos += 1;
7212 return pos;
7213 }
7214 let bits = val.to_bits();
7215 let exp_bits = ((bits >> 52) & 0x7FF) as i32;
7216 let mant_bits = bits & 0x000FFFFFFFFFFFFF;
7217 let (e, m) = if exp_bits == 0 { (1 - 1023, mant_bits) } else { (exp_bits - 1023, mant_bits | (1u64 << 52)) };
7218 let p = if precision < 0 { 13usize } else { precision as usize };
7219 let mut pos = 0usize;
7220 let lc = !uppercase;
7221 let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7222 core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7223
7224 let lead = ((m >> 52) & 0xF) as u8;
7226 *dst.add(pos) = hex_digit_char(lead, lc); pos += 1;
7227 if p > 0 {
7228 *dst.add(pos) = b'.'; pos += 1;
7229 }
7230
7231 let frac_start = pos;
7233 let mut rm = m << 4; for _ in 0..p {
7235 let nib = ((rm >> 48) & 0xF) as u8;
7236 *dst.add(pos) = hex_digit_char(nib, lc); pos += 1;
7237 rm <<= 4;
7238 }
7239
7240 if p > 0 {
7242 let round_nib = ((rm >> 48) & 0xF) as u8;
7243 let rest = rm & 0x0000FFFFFFFFFFFF;
7244 let last_nib = if p > 0 {
7245 let c = *dst.add(pos - 1);
7246 hex_char_val(c)
7247 } else { lead };
7248 let should_round = round_nib > 8 || (round_nib == 8 && (rest != 0 || (last_nib & 1) != 0));
7249 if should_round {
7250 let mut j = pos - 1;
7251 loop {
7252 if j < frac_start { break; }
7253 let v = hex_char_val(*dst.add(j));
7254 if v < 15 {
7255 *dst.add(j) = hex_digit_char(v + 1, lc);
7256 break;
7257 } else {
7258 *dst.add(j) = b'0';
7259 if j == frac_start { break; }
7260 j -= 1;
7261 }
7262 }
7263 }
7264 }
7265
7266 let pc = if lc { b'p' } else { b'P' };
7268 *dst.add(pos) = pc; pos += 1;
7269 *dst.add(pos) = if e < 0 { b'-' } else { b'+' }; pos += 1;
7270 let eabs = if e < 0 { (-e) as u32 } else { e as u32 };
7271 let (ebuf, elen) = format_u64(eabs as u64);
7272 core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7273 pos += elen;
7274 pos
7275}
7276
7277#[inline]
7278fn hex_digit_char(v: u8, lowercase: bool) -> u8 {
7279 if v < 10 { b'0' + v }
7280 else if lowercase { b'a' + v - 10 }
7281 else { b'A' + v - 10 }
7282}
7283
7284#[inline]
7285fn hex_char_val(c: u8) -> u8 {
7286 if c >= b'0' && c <= b'9' { c - b'0' }
7287 else if c >= b'a' && c <= b'f' { c - b'a' + 10 }
7288 else if c >= b'A' && c <= b'F' { c - b'A' + 10 }
7289 else { 0 }
7290}
7291
7292unsafe fn apply_width_flags(
7295 dst: *mut u8, buf: *const u8, len: usize, width: usize, flags: u8,
7296) -> usize {
7297 if len >= width {
7298 core::ptr::copy_nonoverlapping(buf, dst, len);
7299 return len;
7300 }
7301 let pad = width - len;
7302 let pad_char = if flags & FLAG_ZERO != 0 && flags & FLAG_MINUS == 0 { b'0' } else { b' ' };
7303 if flags & FLAG_MINUS != 0 {
7304 core::ptr::copy_nonoverlapping(buf, dst, len);
7306 for i in 0..pad { *dst.add(len + i) = pad_char; }
7307 } else {
7308 if flags & FLAG_ZERO != 0 && len > 0 {
7311 let first = *buf;
7312 if first == b'-' || first == b'+' || first == b' ' {
7313 *dst = first;
7314 for i in 0..pad { *dst.add(1 + i) = pad_char; }
7315 core::ptr::copy_nonoverlapping(buf.add(1), dst.add(1 + pad), len - 1);
7316 return width;
7317 }
7318 }
7319 for i in 0..pad { *dst.add(i) = pad_char; }
7320 core::ptr::copy_nonoverlapping(buf, dst.add(pad), len);
7321 }
7322 width
7323}
7324
7325#[no_mangle]
7326pub unsafe extern "C" fn vprintf(fmt: *const c_char, mut args: VaList) -> c_int {
7327 impl_format!(fmt, args,
7328 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
7329 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
7330 )
7331}
7332
7333#[no_mangle]
7334pub unsafe extern "C" fn vfprintf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
7335 impl_format!(fmt, args,
7336 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
7337 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
7338 )
7339}
7340
7341#[no_mangle]
7342pub unsafe extern "C" fn printf(fmt: *const c_char, mut args: ...) -> c_int {
7343 impl_format!(fmt, args,
7344 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
7345 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
7346 )
7347}
7348
7349#[no_mangle]
7350pub unsafe extern "C" fn fprintf(stream: *mut FILE, fmt: *const c_char, mut args: ...) -> c_int {
7351 impl_format!(fmt, args,
7352 |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
7353 |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
7354 )
7355}
7356
7357#[no_mangle]
7358pub unsafe extern "C" fn dprintf(fd: c_int, fmt: *const c_char, mut args: ...) -> c_int {
7359 impl_format!(fmt, args,
7360 |c: u8| { write_str(fd, &c as *const u8, 1); },
7361 |s: *const u8, len: usize| { write_str(fd, s, len); }
7362 )
7363}
7364
7365#[no_mangle]
7366pub unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, mut args: VaList) -> c_int {
7367 impl_format!(fmt, args,
7368 |c: u8| { write_str(fd, &c as *const u8, 1); },
7369 |s: *const u8, len: usize| { write_str(fd, s, len); }
7370 )
7371}
7372
7373unsafe fn format_to_buf(buf: *mut u8, cap: usize, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
7378 let mut pos = 0usize;
7379 let mut i = 0usize;
7380 let mut count = 0usize;
7381 macro_rules! wc {
7382 ($c:expr) => { if pos < cap { *buf.add(pos) = $c; } pos += 1; count += 1; }
7383 }
7384 macro_rules! ws {
7385 ($s:expr, $len:expr) => {{
7386 let __len = $len;
7387 for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$s.add(k); } }
7388 pos += __len; count += __len;
7389 }}
7390 }
7391 macro_rules! ws_buf {
7393 ($src:expr, $len:expr) => {{
7394 let __len = $len;
7395 for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$src.add(k); } }
7396 pos += __len; count += __len;
7397 }}
7398 }
7399 loop {
7400 let c = *fmt.add(i) as u8;
7401 if c == 0 { break; }
7402 if c != b'%' { wc!(c); i += 1; continue; }
7403 i += 1;
7404 let mut flags: u8 = 0;
7406 loop {
7407 let fc = *fmt.add(i) as u8;
7408 match fc {
7409 b'-' => { flags |= FLAG_MINUS; i += 1; }
7410 b'+' => { flags |= FLAG_PLUS; i += 1; }
7411 b' ' => { flags |= FLAG_SPACE; i += 1; }
7412 b'0' => { flags |= FLAG_ZERO; i += 1; }
7413 b'#' => { flags |= FLAG_HASH; i += 1; }
7414 _ => break,
7415 }
7416 }
7417 let mut width: usize = 0;
7419 if *fmt.add(i) as u8 == b'*' {
7420 width = args.next_arg::<c_int>() as usize; i += 1;
7421 } else {
7422 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
7423 width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
7424 }
7425 }
7426 let mut precision: i32 = -1;
7428 if *fmt.add(i) as u8 == b'.' {
7429 i += 1;
7430 if *fmt.add(i) as u8 == b'*' {
7431 precision = args.next_arg::<c_int>(); i += 1;
7432 } else {
7433 precision = 0;
7434 while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
7435 precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
7436 }
7437 }
7438 }
7439 let len_mod = *fmt.add(i) as u8;
7441 let spec: u8;
7442 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' {
7443 i += 1;
7444 let len_mod2 = *fmt.add(i) as u8;
7445 if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
7446 i += 1;
7447 spec = *fmt.add(i) as u8;
7448 match (len_mod, len_mod2, spec) {
7449 (b'h', b'h', b'n') => {
7450 let p = args.next_arg::<*mut c_void>();
7451 if !p.is_null() { *(p as *mut u8) = count as u8; }
7452 }
7453 (b'l', b'l', b'n') => {
7454 let p = args.next_arg::<*mut c_void>();
7455 if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
7456 }
7457 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
7458 let val = args.next_arg::<c_longlong>();
7459 let neg = val < 0;
7460 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
7461 let b = format_u64(abs);
7462 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7463 let mut fbuf = [0u8; 32];
7464 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7465 ws_buf!(fbuf.as_ptr(), len);
7466 }
7467 (b'l', b'l', b'u') => {
7468 let val = args.next_arg::<c_ulonglong>();
7469 let b = format_u64(val as u64);
7470 let mut fbuf = [0u8; 32];
7471 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7472 ws_buf!(fbuf.as_ptr(), len);
7473 }
7474 (b'l', b'l', b'o') => {
7475 let val = args.next_arg::<c_ulonglong>();
7476 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
7477 let mut fbuf = [0u8; 32];
7478 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7479 ws_buf!(fbuf.as_ptr(), len);
7480 }
7481 _ => { wc!(b'%'); wc!(len_mod); wc!(len_mod2); wc!(spec); }
7482 }
7483 } else {
7484 spec = len_mod2;
7485 match (len_mod, spec) {
7486 (b'h', b'n') => {
7487 let p = args.next_arg::<*mut c_void>();
7488 if !p.is_null() { *(p as *mut u16) = count as u16; }
7489 }
7490 (b'l', b'n') => {
7491 let p = args.next_arg::<*mut c_void>();
7492 if !p.is_null() { *(p as *mut c_long) = count as c_long; }
7493 }
7494 (b'z', b'n') | (b't', b'n') => {
7495 let p = args.next_arg::<*mut c_void>();
7496 if !p.is_null() { *(p as *mut usize) = count; }
7497 }
7498 (b'j', b'n') => {
7499 let p = args.next_arg::<*mut c_void>();
7500 if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
7501 }
7502 (b'l', b'd') | (b'l', b'i') => {
7503 let val = args.next_arg::<c_long>();
7504 let neg = val < 0;
7505 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
7506 let b = format_u64(abs);
7507 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7508 let mut fbuf = [0u8; 32];
7509 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7510 ws_buf!(fbuf.as_ptr(), len);
7511 }
7512 (b'l', b'u') => {
7513 let val = args.next_arg::<c_ulong>();
7514 let b = format_u64(val as u64);
7515 let mut fbuf = [0u8; 32];
7516 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7517 ws_buf!(fbuf.as_ptr(), len);
7518 }
7519 (b'l', b'x') => {
7520 let val = args.next_arg::<c_ulong>();
7521 let b = format_hex(val as u64, false);
7522 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7523 let mut fbuf = [0u8; 32];
7524 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7525 ws_buf!(fbuf.as_ptr(), len);
7526 }
7527 (b'l', b'X') => {
7528 let val = args.next_arg::<c_ulong>();
7529 let b = format_hex(val as u64, true);
7530 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7531 let mut fbuf = [0u8; 32];
7532 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7533 ws_buf!(fbuf.as_ptr(), len);
7534 }
7535 (b'l', b'o') => {
7536 let val = args.next_arg::<c_ulong>();
7537 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
7538 let mut fbuf = [0u8; 32];
7539 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7540 ws_buf!(fbuf.as_ptr(), len);
7541 }
7542 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
7543 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A')
7544 | (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
7545 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
7546 let val = args.next_arg::<f64>();
7547 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7548 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7549 let mut fbuf = [0u8; 4224];
7550 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7551 let mut wbuf = [0u8; 4224];
7552 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
7553 ws_buf!(wbuf.as_ptr(), wlen);
7554 }
7555 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
7556 }
7557 }
7558 } else {
7559 spec = *fmt.add(i) as u8;
7560 match spec {
7561 b's' => {
7562 let s = args.next_arg::<*const c_char>();
7563 if s.is_null() {
7564 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
7565 let padded_len = if width > slen { width } else { slen };
7566 let pad = padded_len - slen;
7567 if flags & FLAG_MINUS != 0 {
7568 ws!(b"(null)".as_ptr(), slen);
7569 for _ in 0..pad { wc!(b' '); }
7570 } else {
7571 for _ in 0..pad { wc!(b' '); }
7572 ws!(b"(null)".as_ptr(), slen);
7573 }
7574 } else {
7575 let full_len = strlen(s as *const c_char);
7576 let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
7577 let padded_len = if width > slen { width } else { slen };
7578 let pad = padded_len - slen;
7579 if flags & FLAG_MINUS != 0 {
7580 ws!(s as *const u8, slen);
7581 for _ in 0..pad { wc!(b' '); }
7582 } else {
7583 for _ in 0..pad { wc!(b' '); }
7584 ws!(s as *const u8, slen);
7585 }
7586 }
7587 }
7588 b'd' | b'i' => {
7589 let d = args.next_arg::<c_int>();
7590 let neg = d < 0;
7591 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
7592 let b = format_u64(abs);
7593 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7594 let mut fbuf = [0u8; 32];
7595 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7596 ws_buf!(fbuf.as_ptr(), len);
7597 }
7598 b'u' => {
7599 let u = args.next_arg::<c_uint>();
7600 let b = format_u64(u as u64);
7601 let mut fbuf = [0u8; 32];
7602 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7603 ws_buf!(fbuf.as_ptr(), len);
7604 }
7605 b'x' => {
7606 let x = args.next_arg::<c_uint>();
7607 let b = format_hex(x as u64, false);
7608 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7609 let mut fbuf = [0u8; 32];
7610 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7611 ws_buf!(fbuf.as_ptr(), len);
7612 }
7613 b'X' => {
7614 let x = args.next_arg::<c_uint>();
7615 let b = format_hex(x as u64, true);
7616 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7617 let mut fbuf = [0u8; 32];
7618 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7619 ws_buf!(fbuf.as_ptr(), len);
7620 }
7621 b'o' => {
7622 let o = args.next_arg::<c_uint>();
7623 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
7624 let mut fbuf = [0u8; 32];
7625 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7626 ws_buf!(fbuf.as_ptr(), len);
7627 }
7628 b'c' => {
7629 let ch = args.next_arg::<c_int>();
7630 if width > 1 {
7631 let pad = width - 1;
7632 if flags & FLAG_MINUS != 0 {
7633 wc!(ch as u8);
7634 for _ in 0..pad { wc!(b' '); }
7635 } else {
7636 for _ in 0..pad { wc!(b' '); }
7637 wc!(ch as u8);
7638 }
7639 } else {
7640 wc!(ch as u8);
7641 }
7642 }
7643 b'p' => {
7644 wc!(b'0'); wc!(b'x');
7645 let p = args.next_arg::<*const c_void>();
7646 let b = format_hex(p as u64, false);
7647 ws!(b.0.as_ptr(), b.1);
7648 }
7649 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
7650 let val = args.next_arg::<f64>();
7651 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7652 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7653 let mut fbuf = [0u8; 4224];
7654 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7655 let mut wbuf = [0u8; 4224];
7656 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
7657 ws_buf!(wbuf.as_ptr(), wlen);
7658 }
7659 b'%' => { wc!(b'%'); }
7660 b'n' => {
7661 let p = args.next_arg::<*mut c_void>();
7662 if !p.is_null() { *(p as *mut c_int) = count as c_int; }
7663 }
7664 _ => { wc!(b'%'); wc!(spec); }
7665 }
7666 }
7667 i += 1;
7668 }
7669 if cap > 0 { let null_pos = if pos < cap { pos } else { cap - 1 }; *buf.add(null_pos) = 0; }
7670 count as c_int
7671}
7672
7673#[no_mangle]
7674pub unsafe extern "C" fn vsprintf(buf: *mut c_char, fmt: *const c_char, mut args: VaList) -> c_int {
7675 format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
7676}
7677
7678#[no_mangle]
7679pub unsafe extern "C" fn vsnprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: VaList) -> c_int {
7680 format_to_buf(buf as *mut u8, size, fmt, &mut args)
7681}
7682
7683#[no_mangle]
7684pub unsafe extern "C" fn sprintf(buf: *mut c_char, fmt: *const c_char, mut args: ...) -> c_int {
7685 format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
7686}
7687
7688#[no_mangle]
7689pub unsafe extern "C" fn snprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: ...) -> c_int {
7690 format_to_buf(buf as *mut u8, size, fmt, &mut args)
7691}
7692
7693unsafe fn skip_ws(p: *const u8) -> *const u8 {
7698 let mut q = p;
7699 while *q == b' ' || *q == b'\t' || *q == b'\n' || *q == b'\r' { q = q.add(1); }
7700 q
7701}
7702
7703#[inline]
7704fn is_ws_byte(c: u8) -> bool {
7705 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0b || c == 0x0c
7706}
7707
7708unsafe fn scan_int_val(
7711 buf: *const u8, pos: &mut usize, buf_len: usize, base: u32, width: usize,
7712) -> (u64, bool, bool) {
7713 let start = *pos;
7714 let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
7715 let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
7716 else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
7717 else { false };
7718 if *pos >= max { *pos = start; return (0, false, false); }
7719 let mut base = base;
7720 let mut val: u64 = 0;
7721 if (base == 0 || base == 16) && *pos < max && *buf.add(*pos) == b'0' {
7723 *pos += 1;
7724 if *pos < max && (*buf.add(*pos) == b'x' || *buf.add(*pos) == b'X') {
7725 *pos += 1;
7726 if *pos < max {
7727 if let Some(d) = hex_val(*buf.add(*pos)) {
7728 val = d as u64; *pos += 1;
7729 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; } }
7730 return (val, neg, true);
7731 }
7732 }
7733 return (0, neg, false);
7734 } else if base == 0 {
7735 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; } }
7736 return (val, neg, true);
7737 } else {
7738 return (0, neg, true); }
7740 }
7741 if base == 0 { base = 10; }
7742 let mut found = false;
7743 while *pos < max {
7744 let c = *buf.add(*pos);
7745 let d: Option<u64> = match base {
7746 8 => if c >= b'0' && c <= b'7' { Some((c - b'0') as u64) } else { None },
7747 10 => if c >= b'0' && c <= b'9' { Some((c - b'0') as u64) } else { None },
7748 16 => hex_val(c).map(|v| v as u64),
7749 _ => None,
7750 };
7751 match d { Some(digit) => { val = val.wrapping_mul(base as u64).wrapping_add(digit); *pos += 1; found = true; } None => break }
7752 }
7753 if !found { *pos = start; return (0, false, false); }
7754 (val, neg, true)
7755}
7756
7757unsafe fn scan_float_val(
7759 buf: *const u8, pos: &mut usize, buf_len: usize, width: usize,
7760) -> (f64, bool) {
7761 let start = *pos;
7762 let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
7763 let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
7764 else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
7765 else { false };
7766 if *pos + 2 < max {
7768 let (c0,c1,c2) = (*buf.add(*pos), *buf.add(*pos+1), *buf.add(*pos+2));
7769 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); }
7770 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); }
7771 }
7772 if *pos+1 < max && *buf.add(*pos)==b'0' && (*buf.add(*pos+1)==b'x'||*buf.add(*pos+1)==b'X') {
7774 *pos += 2;
7775 let mut val: f64 = 0.0; let mut found = false; let mut frac_scale = 1.0f64; let mut in_frac = false;
7776 while *pos < max {
7777 if let Some(d) = hex_val(*buf.add(*pos)) {
7778 if in_frac { frac_scale /= 16.0; val += d as f64 * frac_scale; } else { val = val * 16.0 + d as f64; }
7779 *pos += 1; found = true;
7780 } else if *buf.add(*pos)==b'.' && !in_frac { in_frac = true; *pos += 1; } else { break; }
7781 }
7782 if !found { *pos = start; return (0.0, false); }
7783 if *pos < max && (*buf.add(*pos)==b'p'||*buf.add(*pos)==b'P') {
7785 *pos += 1;
7786 let mut eneg = false;
7787 if *pos<max && *buf.add(*pos)==b'-' { eneg=true; *pos+=1; }
7788 else if *pos<max && *buf.add(*pos)==b'+' { *pos+=1; }
7789 let mut ev: i32 = 0; let mut ef = false;
7790 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; }
7791 if !ef { return (0.0, false); }
7792 if eneg { ev = -ev; }
7793 val *= libm::pow(2.0, ev as f64);
7794 }
7795 return (if neg{-val}else{val}, true);
7796 }
7797 let token_start = start;
7798 let mut i = start;
7799 let mut saw_digit = false;
7800 let mut saw_dot = false;
7801 let mut saw_exp = false;
7802 let mut first = true;
7803 while i < max {
7804 let c = *buf.add(i);
7805 if (c == b'+' || c == b'-') && first {
7806 i += 1; first = false; continue;
7807 }
7808 if c >= b'0' && c <= b'9' {
7809 saw_digit = true; i += 1; first = false; continue;
7810 }
7811 if c == b'.' && !saw_dot && !saw_exp {
7812 saw_dot = true; i += 1; first = false; continue;
7813 }
7814 if (c == b'e' || c == b'E') && !saw_exp && saw_digit {
7815 saw_exp = true; i += 1; first = true; continue;
7816 }
7817 break;
7818 }
7819 if !saw_digit { return (0.0, false); }
7820 let s = core::str::from_utf8_unchecked(core::slice::from_raw_parts(buf.add(token_start), i - token_start));
7821 match <f64 as core::str::FromStr>::from_str(s) {
7822 Ok(v) => { *pos = i; return (v, true); }
7823 Err(_) => { return (0.0, false); }
7824 }
7825}
7826
7827unsafe fn do_vsscanf(
7830 buf: *const u8, buf_len: usize, fmt: *const c_char, args: &mut VaList<'_>, consumed: *mut usize,
7831) -> c_int {
7832 let mut p = 0usize;
7833 let mut fi = 0usize;
7834 let mut assigned = 0i32;
7835 let mut input_eof = false;
7836 loop {
7837 let fc = *fmt.add(fi) as u8;
7838 if fc == 0 { break; }
7839 if is_ws_byte(fc) {
7840 while is_ws_byte(*fmt.add(fi) as u8) { fi += 1; }
7841 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7842 continue;
7843 }
7844 if fc != b'%' {
7845 if p >= buf_len { input_eof = true; break; }
7846 if *buf.add(p) != fc { break; }
7847 p += 1; fi += 1; continue;
7848 }
7849 fi += 1;
7850 if *fmt.add(fi) as u8 == b'%' {
7852 if p >= buf_len { input_eof = true; break; }
7853 if *buf.add(p) != b'%' { break; }
7854 p += 1; fi += 1; continue;
7855 }
7856 let suppress = if *fmt.add(fi) as u8 == b'*' { fi += 1; true } else { false };
7857 let mut width: usize = 0;
7858 while (*fmt.add(fi) as u8) >= b'0' && (*fmt.add(fi) as u8) <= b'9' {
7859 width = width * 10 + ((*fmt.add(fi) as u8) - b'0') as usize; fi += 1;
7860 }
7861 if *fmt.add(fi) as u8 == b'm' { fi += 1; }
7862 let mut len_mod = 0u8;
7863 match *fmt.add(fi) as u8 {
7864 b'h' => { fi += 1; if *fmt.add(fi) as u8 == b'h' { fi += 1; len_mod = 2; } else { len_mod = 1; } }
7865 b'l' => { fi += 1; if *fmt.add(fi) as u8 == b'l' { fi += 1; len_mod = 4; } else { len_mod = 3; } }
7866 b'j' => { fi += 1; len_mod = 4; }
7867 b'z' | b't' => { fi += 1; len_mod = 3; }
7868 b'L' => { fi += 1; len_mod = 5; }
7869 _ => {}
7870 }
7871 let spec = *fmt.add(fi) as u8;
7872 let (real_spec, _real_len) = if spec==b'C' {(b'c',3u8)} else if spec==b'S' {(b's',3u8)} else {(spec,len_mod)};
7873 match real_spec {
7874 b'n' => {
7875 if !suppress { let out = args.next_arg::<*mut c_int>(); if !out.is_null() { *out = p as c_int; } }
7876 }
7877 b'd' | b'u' => {
7878 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7879 if p >= buf_len { input_eof = true; break; }
7880 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7881 let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 10, width);
7882 if !ok { break; }
7883 if let Some(out) = dest { if !out.is_null() {
7884 *out = if real_spec==b'd' && neg { -(val as i64) as c_int } else { val as c_int };
7885 }}
7886 if !suppress { assigned += 1; }
7887 }
7888 b'i' => {
7889 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7890 if p >= buf_len { input_eof = true; break; }
7891 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7892 let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 0, width);
7893 if !ok { break; }
7894 if let Some(out) = dest { if !out.is_null() { *out = if neg { -(val as i64) as c_int } else { val as c_int }; } }
7895 if !suppress { assigned += 1; }
7896 }
7897 b'o' => {
7898 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7899 if p >= buf_len { input_eof = true; break; }
7900 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7901 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 8, width);
7902 if !ok { break; }
7903 if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
7904 if !suppress { assigned += 1; }
7905 }
7906 b'x' | b'X' => {
7907 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7908 if p >= buf_len { input_eof = true; break; }
7909 let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
7910 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
7911 if !ok { break; }
7912 if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
7913 if !suppress { assigned += 1; }
7914 }
7915 b'p' => {
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 *mut c_void>()) } else { None };
7919 let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
7920 if !ok { break; }
7921 if let Some(out) = dest { if !out.is_null() { *out = val as usize as *mut c_void; } }
7922 if !suppress { assigned += 1; }
7923 }
7924 b'a' | b'e' | b'f' | b'g' | b'A' | b'E' | b'F' | b'G' => {
7925 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7926 if p >= buf_len { input_eof = true; break; }
7927 let (val, ok) = scan_float_val(buf, &mut p, buf_len, width);
7928 if !ok { break; }
7929 if !suppress {
7930 if _real_len == 3 || _real_len == 5 {
7932 let out = args.next_arg::<*mut f64>(); if !out.is_null() { *out = val; }
7933 } else {
7934 let out = args.next_arg::<*mut f32>(); if !out.is_null() { *out = val as f32; }
7935 }
7936 }
7937 if !suppress { assigned += 1; }
7938 }
7939 b'c' => {
7940 let w = if width > 0 { width } else { 1 };
7941 if p >= buf_len { input_eof = true; break; }
7942 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
7943 let start_p = p;
7944 let mut j = 0usize;
7945 while j < w && p < buf_len {
7946 if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
7947 p += 1; j += 1;
7948 }
7949 if j != w { p = start_p; input_eof = true; break; }
7950 if !suppress { assigned += 1; }
7951 }
7952 b's' => {
7953 while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
7954 if p >= buf_len { input_eof = true; break; }
7955 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
7956 let w = if width > 0 { width } else { usize::MAX };
7957 let mut j = 0usize;
7958 while p < buf_len && *buf.add(p) != 0 && !is_ws_byte(*buf.add(p)) && j < w {
7959 if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
7960 p += 1; j += 1;
7961 }
7962 if j == 0 { break; }
7963 if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
7964 if !suppress { assigned += 1; }
7965 }
7966 b'[' => {
7967 fi += 1;
7968 let negate = if *fmt.add(fi) as u8 == b'^' { fi += 1; true } else { false };
7969 let mut charset = [0u8; 256];
7970 if *fmt.add(fi) as u8 == b']' { charset[b']' as usize] = 1; fi += 1; }
7971 loop { let c = *fmt.add(fi) as u8; if c == b']' || c == 0 { break; } charset[c as usize] = 1; fi += 1; }
7972 if *fmt.add(fi) as u8 == b']' { fi += 1; }
7973 fi -= 1; if p >= buf_len { input_eof = true; break; }
7975 let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
7976 let w = if width > 0 { width } else { usize::MAX };
7977 let mut j = 0usize;
7978 while p < buf_len && *buf.add(p) != 0 && j < w {
7979 let c = *buf.add(p);
7980 let in_set = charset[c as usize] != 0;
7981 if negate { if in_set { break; } } else { if !in_set { break; } }
7982 if !dest_ptr.is_null() { *dest_ptr.add(j) = c as c_char; }
7983 p += 1; j += 1;
7984 }
7985 if j == 0 { break; }
7986 if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
7987 if !suppress { assigned += 1; }
7988 }
7989 _ => break,
7990 }
7991 fi += 1;
7992 }
7993 if !consumed.is_null() { *consumed = p; }
7994 if assigned == 0 && input_eof { -1 } else { assigned }
7995}
7996
7997unsafe fn vsscanf_inner(buf: *const u8, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
7998 let len = strlen(buf as *const c_char);
7999 do_vsscanf(buf, len, fmt, args, core::ptr::null_mut())
8000}
8001
8002#[no_mangle]
8003pub unsafe extern "C" fn vsscanf(buf: *const c_char, fmt: *const c_char, mut args: VaList) -> c_int {
8004 vsscanf_inner(buf as *const u8, fmt, &mut args)
8005}
8006
8007#[no_mangle]
8008pub unsafe extern "C" fn vfscanf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
8009 let f = &mut *stream;
8010 let start_ungotten_count = f.ungotten_count as usize;
8011 let sfunc = f.seek_fn;
8012 let start_pos = sfunc.map(|s| s(stream, 0, SEEK_CUR)).unwrap_or(-1);
8013
8014 let mut line = [0u8; 4096];
8015 let mut pos = 0usize;
8016
8017 if start_pos >= 0 {
8018 while pos < line.len() - 1 {
8020 let c = fgetc(stream);
8021 if c == -1 { break; }
8022 line[pos] = c as u8;
8023 pos += 1;
8024 if c == b'\n' as c_int { break; }
8025 }
8026 } else {
8027 while f.ungotten_count > 0 && pos < line.len() - 1 {
8032 f.ungotten_count -= 1;
8033 line[pos] = f.ungotten[f.ungotten_count as usize] as u8;
8034 pos += 1;
8035 }
8036 while !f.rpos.is_null() && f.rpos < f.rend && pos < line.len() - 1 {
8038 line[pos] = *f.rpos;
8039 f.rpos = f.rpos.add(1);
8040 pos += 1;
8041 }
8042 let fd = f.fd;
8044 let old_flags = sys_fcntl(fd, F_GETFL, 0);
8045 if old_flags >= 0 {
8046 let _ = sys_fcntl(fd, F_SETFL, old_flags | O_NONBLOCK as i64);
8047 }
8048 while pos < line.len() - 1 {
8049 let n = sys_read(fd as i64, line.as_mut_ptr().add(pos), line.len() - 1 - pos);
8050 if n <= 0 { break; }
8051 pos += n as usize;
8052 }
8053 if old_flags >= 0 {
8054 let _ = sys_fcntl(fd, F_SETFL, old_flags);
8055 }
8056 f._eof = 0;
8058 f._err = 0;
8059 f.flags &= !(F_EOF | F_ERR);
8060 }
8061
8062 line[pos] = 0;
8063 if pos == 0 { return 0; }
8064
8065 let mut consumed = 0usize;
8066 let assigned = do_vsscanf(line.as_ptr(), pos, fmt, &mut args, &mut consumed);
8067
8068 if start_pos >= 0 {
8069 let file_consumed = consumed.saturating_sub(start_ungotten_count);
8071 let target = start_pos + file_consumed as i64;
8072 if let Some(sfunc) = sfunc {
8073 sfunc(stream, target, SEEK_SET);
8074 }
8075 f.rpos = core::ptr::null_mut();
8076 f.rend = core::ptr::null_mut();
8077 if consumed < pos { f._eof = 0; }
8078 let remaining = start_ungotten_count.saturating_sub(consumed);
8079 f.ungotten_count = remaining as c_int;
8080 } else {
8081 let unconsumed = pos.saturating_sub(consumed);
8083 if unconsumed > 0 && !f.buf.is_null() {
8084 let copy_count = core::cmp::min(unconsumed, f.buf_size);
8085 core::ptr::copy(
8086 line.as_ptr().add(consumed),
8087 f.buf,
8088 copy_count,
8089 );
8090 f.rpos = f.buf;
8091 f.rend = f.buf.add(copy_count);
8092 }
8093 f.ungotten_count = 0;
8094 f._eof = 0;
8095 f.flags &= !F_EOF;
8096 }
8097 assigned
8098}
8099
8100#[no_mangle]
8101pub unsafe extern "C" fn vscanf(fmt: *const c_char, args: VaList) -> c_int {
8102 vfscanf(stdin, fmt, args)
8103}
8104
8105#[no_mangle]
8106pub unsafe extern "C" fn sscanf(buf: *const c_char, fmt: *const c_char, mut args: ...) -> c_int {
8107 vsscanf_inner(buf as *const u8, fmt, &mut args)
8108}
8109
8110#[no_mangle]
8111pub unsafe extern "C" fn fscanf(stream: *mut FILE, fmt: *const c_char, args: ...) -> c_int {
8112 vfscanf(stream, fmt, args)
8113}
8114
8115#[no_mangle]
8116pub unsafe extern "C" fn scanf(fmt: *const c_char, args: ...) -> c_int {
8117 vfscanf(stdin, fmt, args)
8118}
8119
8120#[no_mangle]
8125pub unsafe extern "C" fn getdelim(
8126 lineptr: *mut *mut c_char, n: *mut usize, delim: c_int, stream: *mut FILE,
8127) -> isize {
8128 if lineptr.is_null() || n.is_null() { return -1; }
8129 let mut cap = *n;
8130 let mut buf = *lineptr;
8131 if buf.is_null() || cap == 0 {
8132 cap = 128;
8133 buf = realloc(buf as *mut c_void, cap) as *mut c_char;
8134 if buf.is_null() { return -1; }
8135 *lineptr = buf;
8136 *n = cap;
8137 }
8138 let mut len = 0usize;
8139 loop {
8140 let c = fgetc(stream);
8141 if c == -1 { if len == 0 { return -1; } break; }
8142 if len + 1 >= cap {
8143 let new_cap = cap.wrapping_mul(2);
8144 let new_buf = realloc(buf as *mut c_void, new_cap) as *mut c_char;
8145 if new_buf.is_null() { return -1; }
8146 buf = new_buf; cap = new_cap;
8147 *lineptr = buf; *n = cap;
8148 }
8149 *buf.add(len) = c as c_char;
8150 len += 1;
8151 if c == delim { break; }
8152 }
8153 *buf.add(len) = 0;
8154 len as isize
8155}
8156
8157#[no_mangle]
8158pub unsafe extern "C" fn getline(lineptr: *mut *mut c_char, n: *mut usize, stream: *mut FILE) -> isize {
8159 getdelim(lineptr, n, b'\n' as c_int, stream)
8160}
8161
8162#[no_mangle]
8167pub unsafe extern "C" fn popen(cmd: *const c_char, mode: *const c_char) -> *mut FILE {
8168 if cmd.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
8169 let m = *mode;
8170 if m != b'r' as c_char && m != b'w' as c_char { ERRNO = EINVAL; return core::ptr::null_mut(); }
8171 let mut p: [c_int; 2] = [0; 2];
8172 if sys_pipe2(p.as_mut_ptr(), O_CLOEXEC) < 0 { return core::ptr::null_mut(); }
8173 let op = if m == b'r' as c_char { 0 } else { 1 };
8174 let child_fd = p[1 - op];
8175 let f = fdopen(p[op], mode);
8176 if f.is_null() { sys_close(p[0] as i64); sys_close(p[1] as i64); return core::ptr::null_mut(); }
8177 let pid = sys_fork();
8178 if pid < 0 { fclose(f); sys_close(child_fd as i64); return core::ptr::null_mut(); }
8179 if pid == 0 {
8180 sys_close(p[op] as i64);
8181 if child_fd != (1 - op) as c_int { sys_dup3(child_fd, (1 - op) as c_int, 0); sys_close(child_fd as i64); }
8182 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
8183 let argv = [b"sh\0".as_ptr() as *const c_char, b"-c\0".as_ptr() as *const c_char, cmd, core::ptr::null()];
8184 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
8185 _exit(127);
8186 }
8187 sys_close(child_fd as i64);
8188 (*f).pipe_pid = pid as c_int;
8189 f
8190}
8191
8192#[no_mangle]
8193pub unsafe extern "C" fn pclose(f: *mut FILE) -> c_int {
8194 let pid = (*f).pipe_pid;
8195 let r = fclose(f);
8196 if pid <= 0 { return -1; }
8197 let mut status: c_int = 0;
8198 let mut w: c_int;
8199 loop {
8200 w = waitpid(pid, &mut status, 0);
8201 if w >= 0 || w != -EINTR { break; }
8202 }
8203 if w < 0 || r != 0 { return -1; }
8204 status
8205}
8206
8207const L_TMPNAM: usize = 20;
8212static mut TMPNAM_COUNTER: c_uint = 0;
8213
8214unsafe fn fill_tmpname(out: *mut c_char, seed: c_uint) {
8215 let prefix = b"/tmp/tmp\0";
8216 let mut k = 0;
8217 while k < prefix.len() - 1 { *out.add(k) = prefix[k] as c_char; k += 1; }
8218 let (buf, len) = format_hex(seed as u64, false);
8219 for j in 0..len.min(L_TMPNAM - k - 1) { *out.add(k + j) = buf[j] as c_char; k += 1; }
8220 *out.add(k) = 0;
8221}
8222
8223#[no_mangle]
8224pub unsafe extern "C" fn tmpfile() -> *mut FILE {
8225 let mut name = [0u8; L_TMPNAM];
8226 let mut ctr: c_uint = 0;
8227 loop {
8228 ctr = ctr.wrapping_add(1);
8229 let mut ts: timespec = core::mem::zeroed();
8230 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8231 let seed = (ts.tv_nsec as c_uint).wrapping_add(ctr);
8232 fill_tmpname(name.as_mut_ptr() as *mut c_char, seed);
8233 let fd = sys_open(name.as_ptr(), (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
8234 if fd >= 0 {
8235 sys_unlinkat(AT_FDCWD, name.as_ptr(), 0);
8236 let f = fdopen(fd as c_int, b"w+\0".as_ptr() as *const c_char);
8237 if f.is_null() { sys_close(fd); }
8238 return f;
8239 }
8240 if ctr > 100 { return core::ptr::null_mut(); }
8241 }
8242}
8243
8244#[no_mangle]
8245pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char {
8246 static mut BUF: [c_char; L_TMPNAM] = [0; L_TMPNAM];
8247 let out = if s.is_null() { core::ptr::addr_of_mut!(BUF) as *mut c_char } else { s };
8248 TMPNAM_COUNTER = TMPNAM_COUNTER.wrapping_add(1);
8249 let mut ts: timespec = core::mem::zeroed();
8250 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8251 let seed = (ts.tv_nsec as c_uint).wrapping_add(TMPNAM_COUNTER);
8252 fill_tmpname(out, seed);
8253 out
8254}
8255
8256#[no_mangle]
8257pub unsafe extern "C" fn remove(path: *const c_char) -> c_int {
8258 if path.is_null() { ERRNO = EINVAL; return -1; }
8259 let r = sys_unlinkat(AT_FDCWD, path as *const u8, 0);
8260 if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
8261}
8262
8263#[no_mangle]
8264pub unsafe extern "C" fn rename(old: *const c_char, new_: *const c_char) -> c_int {
8265 if old.is_null() || new_.is_null() { ERRNO = EINVAL; return -1; }
8266 let r = sys_renameat2(AT_FDCWD, old as *const u8, AT_FDCWD, new_ as *const u8, 0);
8267 if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
8268}
8269
8270const MMAP_FAILED: *mut u8 = !0usize as *mut u8;
8276const PAGE: usize = 4096;
8277
8278#[no_mangle]
8279pub unsafe extern "C" fn malloc(size: SizeT) -> *mut c_void {
8280 let alloc_size = if size == 0 { 1 } else { size };
8283 let total = alloc_size + core::mem::size_of::<usize>();
8285 let pages = (total + PAGE - 1) & !(PAGE - 1);
8286 let ptr = sys_mmap(
8287 null_mut(),
8288 pages,
8289 PROT_READ | PROT_WRITE,
8290 MAP_PRIVATE | MAP_ANONYMOUS,
8291 -1,
8292 0,
8293 );
8294 if ptr == MMAP_FAILED {
8295 return null_mut();
8296 }
8297 *(ptr as *mut usize) = pages;
8298 ptr.add(core::mem::size_of::<usize>()) as *mut c_void
8299}
8300
8301#[no_mangle]
8302pub unsafe extern "C" fn free(ptr: *mut c_void) {
8303 if ptr.is_null() {
8304 return;
8305 }
8306 let header = (ptr as *mut u8).sub(core::mem::size_of::<usize>());
8307 let pages = *(header as *const usize);
8308 sys_munmap(header, pages);
8309}
8310
8311#[no_mangle]
8312pub unsafe extern "C" fn calloc(count: SizeT, size: SizeT) -> *mut c_void {
8313 let total = count.saturating_mul(size);
8314 let ptr = malloc(total);
8315 if !ptr.is_null() {
8316 core::ptr::write_bytes(ptr as *mut u8, 0, total);
8317 }
8318 ptr
8319}
8320
8321#[no_mangle]
8322pub unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: SizeT) -> *mut c_void {
8323 if ptr.is_null() {
8324 return malloc(new_size);
8325 }
8326 if new_size == 0 {
8327 free(ptr);
8328 return null_mut();
8329 }
8330 let header = (ptr as *mut u8).sub(core::mem::size_of::<usize>());
8331 let old_pages = *(header as *const usize);
8332 let old_data_size = old_pages - core::mem::size_of::<usize>();
8333 let new_ptr = malloc(new_size);
8334 if new_ptr.is_null() {
8335 return null_mut();
8336 }
8337 let copy_size = if old_data_size < new_size {
8338 old_data_size
8339 } else {
8340 new_size
8341 };
8342 core::ptr::copy_nonoverlapping(ptr as *const u8, new_ptr as *mut u8, copy_size);
8343 free(ptr);
8344 new_ptr
8345}
8346
8347#[no_mangle]
8352pub unsafe extern "C" fn _exit(code: c_int) -> ! {
8353 sys_exit_group(code)
8354}
8355
8356#[inline]
8357unsafe fn sys_exit_group(code: c_int) -> ! {
8358 <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT_GROUP, code as i64)
8359}
8360
8361#[inline]
8362unsafe fn sys_exit_thread(code: c_int) -> ! {
8363 <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT, code as i64)
8364}
8365
8366#[no_mangle]
8367pub unsafe extern "C" fn _Exit(code: c_int) -> ! {
8368 _exit(code);
8369}
8370
8371#[no_mangle]
8372pub unsafe extern "C" fn exit(code: c_int) -> ! {
8373 fflush(core::ptr::null_mut());
8374 __funcs_on_exit();
8375 _exit(code);
8376}
8377
8378#[no_mangle]
8379pub unsafe extern "C" fn abort() -> ! {
8380 raise(6); _exit(128 + 6);
8382}
8383
8384#[no_mangle]
8387pub static mut __stack_chk_guard: usize = 0;
8388
8389#[no_mangle]
8390pub unsafe extern "C" fn __stack_chk_fail() -> ! {
8391 const MSG: &[u8] = b"*** stack smashing detected ***: terminated\n";
8392 let _ = sys_write(2, MSG.as_ptr(), MSG.len());
8393 abort();
8394}
8395
8396type CmpRfn = unsafe extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
8401
8402const AR_LEN: usize = 16 * core::mem::size_of::<usize>();
8403const AR_MASK: usize = AR_LEN - 1;
8404
8405unsafe fn qsort_pntz(p: &[usize; 2]) -> i32 {
8406 if p[0] != 1 {
8407 p[0].wrapping_sub(1).trailing_zeros() as i32
8408 } else if p[1] != 0 {
8409 (8 * core::mem::size_of::<usize>()) as i32 + p[1].trailing_zeros() as i32
8410 } else {
8411 0
8412 }
8413}
8414
8415unsafe fn qsort_cycle(width: usize, ar: &mut [*mut u8; AR_LEN], n: usize) {
8416 if n < 2 { return; }
8417 let mut tmp = [0u8; 256];
8418 ar[n] = tmp.as_mut_ptr();
8419 let mut w = width;
8420 while w > 0 {
8421 let l = if 256 < w { 256 } else { w };
8422 core::ptr::copy_nonoverlapping(ar[0], ar[n], l);
8423 for i in 0..n {
8424 core::ptr::copy_nonoverlapping(ar[i + 1], ar[i], l);
8425 ar[i] = ar[i].add(l);
8426 }
8427 w -= l;
8428 }
8429}
8430
8431unsafe fn qsort_shl(p: &mut [usize; 2], n: i32) {
8432 let bits = (8 * core::mem::size_of::<usize>()) as i32;
8433 if n >= bits {
8434 p[1] = p[0];
8435 p[0] = 0;
8436 let n = n - bits;
8437 if n == 0 { return; }
8438 }
8439 p[1] = (p[1] << n) | (p[0] >> (bits - n));
8440 p[0] <<= n;
8441}
8442
8443unsafe fn qsort_shr(p: &mut [usize; 2], n: i32) {
8444 let bits = (8 * core::mem::size_of::<usize>()) as i32;
8445 if n >= bits {
8446 p[0] = p[1];
8447 p[1] = 0;
8448 let n = n - bits;
8449 if n == 0 { return; }
8450 }
8451 p[0] = (p[0] >> n) | (p[1] << (bits - n));
8452 p[1] >>= n;
8453}
8454
8455unsafe fn qsort_sift(
8456 head: *mut u8, width: usize,
8457 cmp: CmpRfn, arg: *mut c_void,
8458 pshift: i32, lp: &[usize],
8459) {
8460 let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
8461 ar[0] = head;
8462 let mut i = 1usize;
8463 let mut h = head;
8464 let mut ps = pshift;
8465
8466 while ps > 1 {
8467 let rt = h.sub(width);
8468 let lf = h.sub(width + lp[(ps - 2) as usize]);
8469
8470 if cmp(ar[0] as *const c_void, lf as *const c_void, arg) >= 0
8471 && cmp(ar[0] as *const c_void, rt as *const c_void, arg) >= 0
8472 {
8473 break;
8474 }
8475 if cmp(lf as *const c_void, rt as *const c_void, arg) >= 0 {
8476 ar[i & AR_MASK] = lf;
8477 i += 1;
8478 h = lf;
8479 ps -= 1;
8480 } else {
8481 ar[i & AR_MASK] = rt;
8482 i += 1;
8483 h = rt;
8484 ps -= 2;
8485 }
8486 }
8487 qsort_cycle(width, &mut ar, i & AR_MASK);
8488}
8489
8490unsafe fn qsort_trinkle(
8491 head: *mut u8, width: usize,
8492 cmp: CmpRfn, arg: *mut c_void,
8493 pp: &[usize; 2], pshift: i32, trusty: i32,
8494 lp: &[usize],
8495) {
8496 let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
8497 let mut p = *pp;
8498 ar[0] = head;
8499 let mut i = 1usize;
8500 let mut h = head;
8501 let mut ps = pshift;
8502 let mut t = trusty;
8503
8504 while p[0] != 1 || p[1] != 0 {
8505 let stepson = h.sub(lp[ps as usize]);
8506 if cmp(stepson as *const c_void, ar[0] as *const c_void, arg) <= 0 {
8507 break;
8508 }
8509 if t == 0 && ps > 1 {
8510 let rt = h.sub(width);
8511 let lf = h.sub(width + lp[(ps - 2) as usize]);
8512 if cmp(rt as *const c_void, stepson as *const c_void, arg) >= 0
8513 || cmp(lf as *const c_void, stepson as *const c_void, arg) >= 0
8514 {
8515 break;
8516 }
8517 }
8518
8519 ar[i & AR_MASK] = stepson;
8520 i += 1;
8521 h = stepson;
8522 let trail = qsort_pntz(&p);
8523 qsort_shr(&mut p, trail);
8524 ps += trail;
8525 t = 0;
8526 }
8527 if t == 0 {
8528 qsort_cycle(width, &mut ar, i & AR_MASK);
8529 qsort_sift(h, width, cmp, arg, ps, lp);
8530 }
8531}
8532
8533#[no_mangle]
8534pub unsafe extern "C" fn __qsort_r(
8535 base: *mut c_void,
8536 nel: usize,
8537 width: usize,
8538 cmp: CmpRfn,
8539 arg: *mut c_void,
8540) {
8541 let size = width * nel;
8542 if size == 0 { return; }
8543
8544 let mut lp = [0usize; 96];
8545 lp[0] = width;
8546 lp[1] = width;
8547 let mut li = 2;
8548 while {
8549 lp[li] = lp[li - 2] + lp[li - 1] + width;
8550 lp[li] < size
8551 } {
8552 li += 1;
8553 }
8554
8555 let mut head = base as *mut u8;
8556 let high = head.add(size - width);
8557 let mut p: [usize; 2] = [1, 0];
8558 let mut pshift: i32 = 1;
8559
8560 while head < high {
8561 if (p[0] & 3) == 3 {
8562 qsort_sift(head, width, cmp, arg, pshift, &lp);
8563 qsort_shr(&mut p, 2);
8564 pshift += 2;
8565 } else {
8566 if lp[(pshift - 1) as usize] >= (high as usize) - (head as usize) {
8567 qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
8568 } else {
8569 qsort_sift(head, width, cmp, arg, pshift, &lp);
8570 }
8571
8572 if pshift == 1 {
8573 qsort_shl(&mut p, 1);
8574 pshift = 0;
8575 } else {
8576 qsort_shl(&mut p, pshift - 1);
8577 pshift = 1;
8578 }
8579 }
8580
8581 p[0] |= 1;
8582 head = head.add(width);
8583 }
8584
8585 qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
8586
8587 while pshift != 1 || p[0] != 1 || p[1] != 0 {
8588 if pshift <= 1 {
8589 let trail = qsort_pntz(&p);
8590 qsort_shr(&mut p, trail);
8591 pshift += trail;
8592 } else {
8593 qsort_shl(&mut p, 2);
8594 pshift -= 2;
8595 p[0] ^= 7;
8596 qsort_shr(&mut p, 1);
8597 qsort_trinkle(
8598 head.sub(lp[pshift as usize] + width),
8599 width, cmp, arg, &p, pshift + 1, 1, &lp,
8600 );
8601 qsort_shl(&mut p, 1);
8602 p[0] |= 1;
8603 qsort_trinkle(head.sub(width), width, cmp, arg, &p, pshift, 1, &lp);
8604 }
8605 head = head.sub(width);
8606 }
8607}
8608
8609#[no_mangle]
8610pub unsafe extern "C" fn qsort_r(
8611 base: *mut c_void,
8612 nel: usize,
8613 width: usize,
8614 cmp: CmpRfn,
8615 arg: *mut c_void,
8616) {
8617 __qsort_r(base, nel, width, cmp, arg);
8618}
8619
8620unsafe extern "C" fn qsort_wrap_cmp(
8621 a: *const c_void,
8622 b: *const c_void,
8623 cmp_ctx: *mut c_void,
8624) -> c_int {
8625 let cmp: CmpFn = core::mem::transmute(cmp_ctx);
8626 cmp(a, b)
8627}
8628
8629#[no_mangle]
8630pub unsafe extern "C" fn qsort(
8631 base: *mut c_void,
8632 nel: usize,
8633 width: usize,
8634 cmp: CmpFn,
8635) {
8636 __qsort_r(base, nel, width, qsort_wrap_cmp, cmp as *mut c_void);
8637}
8638
8639const ATEXIT_COUNT: usize = 32;
8644
8645#[repr(C)]
8646struct AtExitBlock {
8647 next: *mut AtExitBlock,
8648 f: [Option<unsafe extern "C" fn(*mut c_void)>; ATEXIT_COUNT],
8649 a: [*mut c_void; ATEXIT_COUNT],
8650}
8651
8652static mut ATEXIT_BUILTIN: AtExitBlock = AtExitBlock {
8653 next: core::ptr::null_mut(),
8654 f: [None; ATEXIT_COUNT],
8655 a: [core::ptr::null_mut(); ATEXIT_COUNT],
8656};
8657static mut ATEXIT_HEAD: *mut AtExitBlock = core::ptr::null_mut();
8658static mut ATEXIT_SLOT: usize = 0;
8659static mut ATEXIT_FINISHED: bool = false;
8660
8661#[no_mangle]
8662pub unsafe extern "C" fn __funcs_on_exit() {
8663 while !ATEXIT_HEAD.is_null() {
8664 let head = ATEXIT_HEAD;
8665 while ATEXIT_SLOT > 0 {
8666 ATEXIT_SLOT -= 1;
8667 if let Some(f) = (*head).f[ATEXIT_SLOT] {
8668 let a = (*head).a[ATEXIT_SLOT];
8669 f(a);
8670 }
8671 }
8672 ATEXIT_HEAD = (*head).next;
8673 ATEXIT_SLOT = ATEXIT_COUNT;
8674 }
8675 ATEXIT_FINISHED = true;
8676}
8677
8678#[no_mangle]
8679pub unsafe extern "C" fn __cxa_atexit(
8680 func: unsafe extern "C" fn(*mut c_void),
8681 arg: *mut c_void,
8682 _dso: *mut c_void,
8683) -> c_int {
8684 if ATEXIT_FINISHED {
8685 return -1;
8686 }
8687 if ATEXIT_HEAD.is_null() {
8688 ATEXIT_HEAD = core::ptr::addr_of_mut!(ATEXIT_BUILTIN);
8689 }
8690 if ATEXIT_SLOT == ATEXIT_COUNT {
8691 let new = calloc(1, core::mem::size_of::<AtExitBlock>()) as *mut AtExitBlock;
8692 if new.is_null() {
8693 return -1;
8694 }
8695 (*new).next = ATEXIT_HEAD;
8696 ATEXIT_HEAD = new;
8697 ATEXIT_SLOT = 0;
8698 }
8699 (*ATEXIT_HEAD).f[ATEXIT_SLOT] = Some(func);
8700 (*ATEXIT_HEAD).a[ATEXIT_SLOT] = arg;
8701 ATEXIT_SLOT += 1;
8702 0
8703}
8704
8705unsafe extern "C" fn atexit_caller(arg: *mut c_void) {
8706 let func: unsafe extern "C" fn() = core::mem::transmute(arg);
8707 func();
8708}
8709
8710#[no_mangle]
8711pub unsafe extern "C" fn atexit(func: unsafe extern "C" fn()) -> c_int {
8712 __cxa_atexit(atexit_caller, func as *mut c_void, core::ptr::null_mut())
8713}
8714
8715#[no_mangle]
8716pub unsafe extern "C" fn __cxa_finalize(_dso: *mut c_void) {}
8717
8718#[no_mangle]
8723pub static mut __environ: *mut *mut c_char = core::ptr::null_mut();
8724
8725const ENV_MAX_ALLOCED: usize = 256;
8727static mut ENV_ALLOCED: [*mut c_char; ENV_MAX_ALLOCED] = [core::ptr::null_mut(); ENV_MAX_ALLOCED];
8728static mut ENV_ALLOCED_N: usize = 0;
8729
8730unsafe fn env_rm_add(old: *mut c_char, mut new: *mut c_char) {
8731 for i in 0..ENV_ALLOCED_N {
8732 if ENV_ALLOCED[i] == old {
8733 ENV_ALLOCED[i] = new;
8734 if !old.is_null() {
8735 free(old as *mut c_void);
8736 }
8737 return;
8738 } else if ENV_ALLOCED[i].is_null() && !new.is_null() {
8739 ENV_ALLOCED[i] = new;
8740 new = core::ptr::null_mut();
8741 }
8742 }
8743 if !new.is_null() && ENV_ALLOCED_N < ENV_MAX_ALLOCED {
8744 ENV_ALLOCED[ENV_ALLOCED_N] = new;
8745 ENV_ALLOCED_N += 1;
8746 }
8747}
8748
8749unsafe fn strchrnul(s: *const u8, c: u8) -> *const u8 {
8750 let mut p = s;
8751 while *p != 0 && *p != c {
8752 p = p.add(1);
8753 }
8754 p
8755}
8756
8757#[no_mangle]
8758pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
8759 if __environ.is_null() || name.is_null() {
8760 return core::ptr::null_mut();
8761 }
8762 let name = name as *const u8;
8763 let l = strchrnul(name, b'=') as usize - name as usize;
8764 if l == 0 || *name.add(l) != 0 {
8765 return core::ptr::null_mut();
8766 }
8767 let mut e = __environ;
8768 while !(*e).is_null() {
8769 let entry = *e as *const u8;
8770 if strncmp(entry, name, l) == 0 && *entry.add(l) == b'=' {
8771 return entry.add(l + 1) as *mut c_char;
8772 }
8773 e = e.add(1);
8774 }
8775 core::ptr::null_mut()
8776}
8777
8778#[no_mangle]
8779pub unsafe extern "C" fn setenv(
8780 var: *const c_char,
8781 value: *const c_char,
8782 overwrite: c_int,
8783) -> c_int {
8784 if var.is_null() || value.is_null() {
8785 ERRNO = EINVAL;
8786 return -1;
8787 }
8788 let var = var as *const u8;
8789 let l1 = strchrnul(var, b'=') as usize - var as usize;
8790 if l1 == 0 || *var.add(l1) != 0 {
8791 ERRNO = EINVAL;
8792 return -1;
8793 }
8794 if overwrite == 0 && !getenv(var as *const c_char).is_null() {
8795 return 0;
8796 }
8797 let l2 = strlen(value as *const c_char);
8798 let s = malloc(l1 + l2 + 2) as *mut u8;
8799 if s.is_null() {
8800 return -1;
8801 }
8802 core::ptr::copy_nonoverlapping(var, s, l1);
8803 *s.add(l1) = b'=';
8804 core::ptr::copy_nonoverlapping(value as *const u8, s.add(l1 + 1), l2 + 1);
8805 putenv_internal(s as *mut c_char, l1, s as *mut c_char)
8806}
8807
8808unsafe fn putenv_internal(s: *mut c_char, l: usize, r: *mut c_char) -> c_int {
8809 let mut i = 0;
8810 if !__environ.is_null() {
8811 let mut e = __environ;
8812 while !(*e).is_null() {
8813 if strncmp(s as *const u8, *e as *const u8, l + 1) == 0 {
8814 let tmp = *e;
8815 *e = s;
8816 env_rm_add(tmp, r);
8817 return 0;
8818 }
8819 e = e.add(1);
8820 i += 1;
8821 }
8822 }
8823 let newenv = malloc(core::mem::size_of::<*mut c_char>() * (i + 2)) as *mut *mut c_char;
8824 if newenv.is_null() {
8825 if !r.is_null() { free(r as *mut c_void); }
8826 return -1;
8827 }
8828 if i > 0 && !__environ.is_null() {
8829 core::ptr::copy_nonoverlapping(__environ, newenv, i);
8830 }
8831 *newenv.add(i) = s;
8832 *newenv.add(i + 1) = core::ptr::null_mut();
8833 __environ = newenv;
8835 environ = __environ;
8836 if !r.is_null() {
8837 env_rm_add(core::ptr::null_mut(), r);
8838 }
8839 0
8840}
8841
8842#[no_mangle]
8843pub unsafe extern "C" fn putenv(s: *mut c_char) -> c_int {
8844 if s.is_null() { return -1; }
8845 let l = strchrnul(s as *const u8, b'=') as usize - s as *const u8 as usize;
8846 if l == 0 || *s.add(l) as u8 == 0 {
8847 return unsetenv(s);
8848 }
8849 putenv_internal(s, l, core::ptr::null_mut())
8850}
8851
8852#[no_mangle]
8853pub unsafe extern "C" fn unsetenv(name: *const c_char) -> c_int {
8854 if name.is_null() {
8855 ERRNO = EINVAL;
8856 return -1;
8857 }
8858 let name = name as *const u8;
8859 let l = strchrnul(name, b'=') as usize - name as usize;
8860 if l == 0 || *name.add(l) != 0 {
8861 ERRNO = EINVAL;
8862 return -1;
8863 }
8864 if __environ.is_null() {
8865 return 0;
8866 }
8867 let mut e = __environ;
8868 let mut eo = e;
8869 while !(*e).is_null() {
8870 if strncmp(name, *e as *const u8, l) == 0 && *(*e as *const u8).add(l) == b'=' {
8871 env_rm_add(*e, core::ptr::null_mut());
8872 } else {
8873 if eo != e {
8874 *eo = *e;
8875 }
8876 eo = eo.add(1);
8877 }
8878 e = e.add(1);
8879 }
8880 if eo != e {
8881 *eo = core::ptr::null_mut();
8882 }
8883 environ = __environ;
8884 0
8885}
8886
8887#[no_mangle]
8888pub unsafe extern "C" fn clearenv() -> c_int {
8889 let e = __environ;
8890 __environ = core::ptr::null_mut();
8891 environ = core::ptr::null_mut();
8892 if !e.is_null() {
8893 let mut p = e;
8894 while !(*p).is_null() {
8895 env_rm_add(*p, core::ptr::null_mut());
8896 p = p.add(1);
8897 }
8898 }
8899 0
8900}
8901
8902static mut RANDOM_INIT: [u32; 32] = [
8908 0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646,
8909 0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78,
8910 0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff,
8911 0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc,
8912 0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09,
8913 0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74,
8914 0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115,
8915 0x0cab8628,0xf043bfa4,0x398150e9,0x37521657,
8916];
8917
8918static mut RANDOM_N: i32 = 31;
8919static mut RANDOM_I: i32 = 3;
8920static mut RANDOM_J: i32 = 0;
8921static mut RANDOM_X: *mut u32 = unsafe { core::ptr::addr_of_mut!(RANDOM_INIT).cast::<u32>().add(1) };
8922
8923unsafe fn random_lcg31(x: u32) -> u32 {
8924 (1103515245u32.wrapping_mul(x).wrapping_add(12345)) & 0x7fffffff
8925}
8926
8927unsafe fn random_lcg64(x: u64) -> u64 {
8928 6364136223846793005u64.wrapping_mul(x).wrapping_add(1)
8929}
8930
8931unsafe fn random_savestate() -> *mut u8 {
8932 (*RANDOM_X.offset(-1)) = ((RANDOM_N as u32) << 16) | ((RANDOM_I as u32) << 8) | (RANDOM_J as u32);
8933 RANDOM_X.offset(-1) as *mut u8
8934}
8935
8936unsafe fn random_loadstate(state: *mut u32) {
8937 RANDOM_X = state.add(1);
8938 RANDOM_N = ((*RANDOM_X.offset(-1)) >> 16) as i32;
8939 RANDOM_I = (((*RANDOM_X.offset(-1)) >> 8) & 0xff) as i32;
8940 RANDOM_J = ((*RANDOM_X.offset(-1)) & 0xff) as i32;
8941}
8942
8943unsafe fn random_srandom_inner(seed: u32) {
8944 let mut s = seed as u64;
8945 if RANDOM_N == 0 {
8946 *RANDOM_X = s as u32;
8947 return;
8948 }
8949 RANDOM_I = if RANDOM_N == 31 || RANDOM_N == 7 { 3 } else { 1 };
8950 RANDOM_J = 0;
8951 for k in 0..RANDOM_N as usize {
8952 s = random_lcg64(s);
8953 *RANDOM_X.add(k) = (s >> 32) as u32;
8954 }
8955 *RANDOM_X |= 1;
8956}
8957
8958#[no_mangle]
8959pub unsafe extern "C" fn srandom(seed: c_uint) {
8960 random_srandom_inner(seed);
8961}
8962
8963#[no_mangle]
8964pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: usize) -> *mut c_char {
8965 if size < 8 { return core::ptr::null_mut(); }
8966 let old = random_savestate();
8967 RANDOM_N = if size < 32 { 0 }
8968 else if size < 64 { 7 }
8969 else if size < 128 { 15 }
8970 else if size < 256 { 31 }
8971 else { 63 };
8972 RANDOM_X = (state as *mut u32).add(1);
8973 random_srandom_inner(seed);
8974 random_savestate();
8975 old as *mut c_char
8976}
8977
8978#[no_mangle]
8979pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
8980 let old = random_savestate();
8981 random_loadstate(state as *mut u32);
8982 old as *mut c_char
8983}
8984
8985#[no_mangle]
8986pub unsafe extern "C" fn random() -> c_long {
8987 let k: c_long;
8988 if RANDOM_N == 0 {
8989 *RANDOM_X = random_lcg31(*RANDOM_X);
8990 k = *RANDOM_X as c_long;
8991 } else {
8992 *RANDOM_X.add(RANDOM_I as usize) = (*RANDOM_X.add(RANDOM_I as usize)).wrapping_add(*RANDOM_X.add(RANDOM_J as usize));
8993 k = (*RANDOM_X.add(RANDOM_I as usize) >> 1) as c_long;
8994 RANDOM_I += 1;
8995 if RANDOM_I == RANDOM_N { RANDOM_I = 0; }
8996 RANDOM_J += 1;
8997 if RANDOM_J == RANDOM_N { RANDOM_J = 0; }
8998 }
8999 k
9000}
9001
9002const SA: u8 = 0xC2;
9007const SB: u8 = 0xF4;
9008
9009const BITTAB: [u32; 51] = [
9010 0xC000_0002, 0xC000_0003, 0xC000_0004, 0xC000_0005, 0xC000_0006, 0xC000_0007,
9011 0xC000_0008, 0xC000_0009, 0xC000_000A, 0xC000_000B, 0xC000_000C, 0xC000_000D,
9012 0xC000_000E, 0xC000_000F, 0xC000_0010, 0xC000_0011, 0xC000_0012, 0xC000_0013,
9013 0xC000_0014, 0xC000_0015, 0xC000_0016, 0xC000_0017, 0xC000_0018, 0xC000_0019,
9014 0xC000_001A, 0xC000_001B, 0xC000_001C, 0xC000_001D, 0xC000_001E, 0xC000_001F,
9015 0xB300_0000, 0xC300_0001, 0xC300_0002, 0xC300_0003, 0xC300_0004, 0xC300_0005,
9016 0xC300_0006, 0xC300_0007, 0xC300_0008, 0xC300_0009, 0xC300_000A, 0xC300_000B,
9017 0xC300_000C, 0xD300_000D, 0xC300_000E, 0xC300_000F, 0xBB0C_0000, 0xC30C_0001,
9018 0xC30C_0002, 0xC30C_0003, 0xDB0C_0004,
9019];
9020
9021#[inline]
9022fn mb_oob(c: u32, b: u8) -> u32 {
9023 let b3 = (b >> 3) as u32;
9024 ((b3.wrapping_sub(0x10)) | (b3.wrapping_add((c as i32 >> 26) as u32))) & !7
9025}
9026
9027static mut MB_STATE: c_uint = 0;
9028
9029const MB_CUR_MAX_VAL_UTF8: usize = 4;
9030const MB_CUR_MAX_VAL_C: usize = 1;
9031
9032#[no_mangle]
9033pub extern "C" fn __ctype_get_mb_cur_max() -> usize {
9034 unsafe { if LOCALE_CTYPE_UTF8 { MB_CUR_MAX_VAL_UTF8 } else { MB_CUR_MAX_VAL_C } }
9035}
9036
9037#[no_mangle]
9038pub unsafe extern "C" fn mbrtowc(
9039 wc: *mut c_int,
9040 src: *const c_char,
9041 n: usize,
9042 st: *mut c_uint,
9043) -> usize {
9044 let s = src as *const u8;
9045 let n0 = n;
9046 let mut dummy: c_int = 0;
9047 let wc = if wc.is_null() { &mut dummy } else { &mut *wc };
9048 let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9049
9050 let mut c: u32 = *st;
9051 let mut s = s;
9052 let mut n = n;
9053
9054 if s.is_null() {
9055 if c != 0 { *st = 0; ERRNO = EILSEQ; return !0usize; }
9056 return 0;
9057 }
9058
9059 if n == 0 { return !1usize; }
9060
9061 if unsafe { !LOCALE_CTYPE_UTF8 } {
9062 let b = *s;
9063 *wc = b as c_int;
9064 return if b == 0 { 0 } else { 1 };
9065 }
9066
9067 if c == 0 {
9068 if *s < 0x80 {
9069 let r = if *s == 0 { 0 } else { 1 };
9070 *wc = *s as c_int;
9071 return r;
9072 }
9073 if (*s).wrapping_sub(SA) as u32 > (SB - SA) as u32 {
9074 *st = 0; ERRNO = EILSEQ; return !0usize;
9075 }
9076 c = BITTAB[*s as usize - SA as usize];
9077 s = s.add(1);
9078 n -= 1;
9079 }
9080
9081 if n > 0 {
9082 if mb_oob(c, *s) != 0 {
9083 *st = 0; ERRNO = EILSEQ; return !0usize;
9084 }
9085 loop {
9086 c = (c << 6) | (*s as u32).wrapping_sub(0x80);
9087 s = s.add(1);
9088 n -= 1;
9089 if c & (1u32 << 31) == 0 {
9090 *st = 0;
9091 *wc = c as c_int;
9092 return n0 - n;
9093 }
9094 if n == 0 { break; }
9095 if (*s).wrapping_sub(0x80) >= 0x40 {
9096 *st = 0; ERRNO = EILSEQ; return !0usize;
9097 }
9098 }
9099 }
9100
9101 *st = c;
9102 !1usize
9103}
9104
9105#[no_mangle]
9106pub unsafe extern "C" fn wcrtomb(
9107 s: *mut c_char,
9108 wc: c_int,
9109 _st: *mut c_uint,
9110) -> usize {
9111 if s.is_null() { return 1; }
9112 let wc_u = wc as u32;
9113 if unsafe { !LOCALE_CTYPE_UTF8 } {
9114 if wc_u > 0xFF {
9115 ERRNO = EILSEQ;
9116 return !0usize;
9117 }
9118 *s = wc as c_char;
9119 return 1;
9120 }
9121 if wc_u < 0x80 {
9122 *s = wc as c_char;
9123 return 1;
9124 }
9125 if wc_u < 0x800 {
9126 *s = (0xC0 | (wc_u >> 6)) as c_char;
9127 *s.add(1) = (0x80 | (wc_u & 0x3F)) as c_char;
9128 return 2;
9129 }
9130 if wc_u < 0xD800 || wc_u.wrapping_sub(0xE000) < 0x2000 {
9131 *s = (0xE0 | (wc_u >> 12)) as c_char;
9132 *s.add(1) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9133 *s.add(2) = (0x80 | (wc_u & 0x3F)) as c_char;
9134 return 3;
9135 }
9136 if wc_u.wrapping_sub(0x10000) < 0x100000 {
9137 *s = (0xF0 | (wc_u >> 18)) as c_char;
9138 *s.add(1) = (0x80 | ((wc_u >> 12) & 0x3F)) as c_char;
9139 *s.add(2) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9140 *s.add(3) = (0x80 | (wc_u & 0x3F)) as c_char;
9141 return 4;
9142 }
9143 ERRNO = EILSEQ;
9144 !0usize
9145}
9146
9147#[no_mangle]
9148pub unsafe extern "C" fn mblen(s: *const c_char, n: usize) -> c_int {
9149 if s.is_null() { return 0; }
9150 mbtowc(core::ptr::null_mut(), s, n)
9151}
9152
9153#[no_mangle]
9154pub unsafe extern "C" fn mbtowc(
9155 wc: *mut c_int,
9156 src: *const c_char,
9157 n: usize,
9158) -> c_int {
9159 if src.is_null() { return 0; }
9160 if n == 0 { ERRNO = EILSEQ; return -1; }
9161 let mut state: c_uint = 0;
9162 let mut w: c_int = 0;
9163 let r = mbrtowc(&mut w, src, n, &mut state);
9164 if r == !0usize { return -1; }
9165 if !wc.is_null() { *wc = w; }
9166 r as c_int
9167}
9168
9169#[no_mangle]
9170pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: c_int) -> c_int {
9171 if s.is_null() { return 0; }
9172 wcrtomb(s, wc, core::ptr::null_mut()) as c_int
9173}
9174
9175#[no_mangle]
9176pub unsafe extern "C" fn mbsrtowcs(
9177 ws: *mut c_int,
9178 src: *mut *const c_char,
9179 wn: usize,
9180 st: *mut c_uint,
9181) -> usize {
9182 let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9183 let mut s = *src as *const u8;
9184 let wn0 = wn;
9185 let mut wn = wn;
9186
9187 if ws.is_null() {
9188 while *s != 0 {
9189 if *s < 0x80 {
9190 s = s.add(1);
9191 wn = wn.wrapping_sub(1);
9192 continue;
9193 }
9194 let mut wc: c_int = 0;
9195 let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9196 if r == !0usize { return !0usize; }
9197 if r == !1usize { return wn0 - wn; }
9198 s = s.add(r);
9199 wn = wn.wrapping_sub(1);
9200 }
9201 wn0 - wn
9202 } else {
9203 let mut w = ws;
9204 while wn > 0 {
9205 if *s < 0x80 {
9206 let c = *s as c_int;
9207 *w = c;
9208 if c == 0 {
9209 *src = core::ptr::null();
9210 return wn0 - wn;
9211 }
9212 w = w.add(1);
9213 s = s.add(1);
9214 wn -= 1;
9215 continue;
9216 }
9217 let mut wc: c_int = 0;
9218 let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9219 if r == !0usize {
9220 *src = s as *const c_char;
9221 return !0usize;
9222 }
9223 if r == !1usize {
9224 *src = s as *const c_char;
9225 return wn0 - wn;
9226 }
9227 *w = wc;
9228 w = w.add(1);
9229 s = s.add(r);
9230 wn -= 1;
9231 }
9232 *src = s as *const c_char;
9233 wn0 - wn
9234 }
9235}
9236
9237#[no_mangle]
9238pub unsafe extern "C" fn wcsrtombs(
9239 s: *mut c_char,
9240 ws: *mut *const c_int,
9241 n: usize,
9242 _st: *mut c_uint,
9243) -> usize {
9244 let mut w = *ws;
9245 let n0 = n;
9246 let mut n = n;
9247
9248 if s.is_null() {
9249 let mut count = 0usize;
9250 while *w != 0 {
9251 if (*w as u32) < 0x80 {
9252 count += 1;
9253 } else {
9254 let mut buf = [0u8; 4];
9255 let r = wcrtomb(buf.as_mut_ptr() as *mut c_char, *w, core::ptr::null_mut());
9256 if r == !0usize { return !0usize; }
9257 count += r;
9258 }
9259 w = w.add(1);
9260 }
9261 return count;
9262 }
9263
9264 let mut dst = s;
9265 while n > 0 {
9266 if (*w as u32) < 0x80 {
9267 *dst = *w as c_char;
9268 if *w == 0 {
9269 *ws = core::ptr::null();
9270 return n0 - n;
9271 }
9272 dst = dst.add(1);
9273 n -= 1;
9274 } else {
9275 let r = wcrtomb(dst, *w, core::ptr::null_mut());
9276 if r == !0usize {
9277 *ws = w;
9278 return !0usize;
9279 }
9280 if r > n {
9281 *ws = w;
9282 return n0 - n;
9283 }
9284 dst = dst.add(r);
9285 n -= r;
9286 }
9287 w = w.add(1);
9288 }
9289 *ws = w;
9290 n0
9291}
9292
9293#[no_mangle]
9294pub unsafe extern "C" fn mbstowcs(
9295 ws: *mut c_int,
9296 src: *const c_char,
9297 wn: usize,
9298) -> usize {
9299 let mut src_ptr = src;
9300 mbsrtowcs(ws, &mut src_ptr, wn, core::ptr::null_mut())
9301}
9302
9303#[no_mangle]
9304pub unsafe extern "C" fn wcstombs(
9305 s: *mut c_char,
9306 ws: *const c_int,
9307 n: usize,
9308) -> usize {
9309 let mut ws_ptr = ws;
9310 wcsrtombs(s, &mut ws_ptr, n, core::ptr::null_mut())
9311}
9312
9313#[no_mangle]
9318pub extern "C" fn btowc(c: c_int) -> wint_t {
9319 if c == -1 { return WEOF; }
9320 unsafe {
9321 if LOCALE_CTYPE_UTF8 {
9322 if (c as u32) < 128 { c as wint_t } else { WEOF }
9323 } else {
9324 (c as u8) as wint_t
9325 }
9326 }
9327}
9328
9329#[no_mangle]
9330pub extern "C" fn wctob(c: wint_t) -> c_int {
9331 unsafe {
9332 if LOCALE_CTYPE_UTF8 {
9333 if c < 128 { c as c_int } else { -1 }
9334 } else {
9335 if c <= 0xFF { c as c_int } else { -1 }
9336 }
9337 }
9338}
9339
9340#[no_mangle]
9341pub unsafe extern "C" fn mbsinit(s: *const c_uint) -> c_int {
9342 if s.is_null() || *s == 0 { 1 } else { 0 }
9343}
9344
9345#[no_mangle]
9346pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut c_uint) -> usize {
9347 mbrtowc(core::ptr::null_mut(), s, n, ps)
9348}
9349
9350#[no_mangle]
9355pub unsafe extern "C" fn wcslen(s: *const wchar_t) -> usize {
9356 let mut len = 0;
9357 while *s.add(len) != 0 { len += 1; }
9358 len
9359}
9360
9361#[no_mangle]
9362pub unsafe extern "C" fn wcschr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
9363 let mut i = 0;
9364 loop {
9365 let ch = *s.add(i);
9366 if ch == c { return s.add(i) as *mut wchar_t; }
9367 if ch == 0 { return null_mut(); }
9368 i += 1;
9369 }
9370}
9371
9372#[no_mangle]
9373pub unsafe extern "C" fn wcsrchr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
9374 let mut i = 0;
9375 let mut last: *mut wchar_t = null_mut();
9376 loop {
9377 let ch = *s.add(i);
9378 if ch == c { last = s.add(i) as *mut wchar_t; }
9379 if ch == 0 { return last; }
9380 i += 1;
9381 }
9382}
9383
9384#[no_mangle]
9385pub unsafe extern "C" fn wcsstr(haystack: *const wchar_t, needle: *const wchar_t) -> *mut wchar_t {
9386 if *needle == 0 { return haystack as *mut wchar_t; }
9387 let mut i = 0;
9388 loop {
9389 let h = *haystack.add(i);
9390 if h == 0 { return null_mut(); }
9391 if h == *needle {
9392 let mut j = 0;
9393 loop {
9394 let n = *needle.add(j);
9395 if n == 0 { return haystack.add(i) as *mut wchar_t; }
9396 if *haystack.add(i + j) != n { break; }
9397 j += 1;
9398 }
9399 }
9400 i += 1;
9401 }
9402}
9403
9404#[no_mangle]
9405pub unsafe extern "C" fn wcscmp(s1: *const wchar_t, s2: *const wchar_t) -> c_int {
9406 let mut i = 0;
9407 loop {
9408 let a = *s1.add(i);
9409 let b = *s2.add(i);
9410 if a != b { return a - b; }
9411 if a == 0 { return 0; }
9412 i += 1;
9413 }
9414}
9415
9416#[no_mangle]
9417pub unsafe extern "C" fn wcsncmp(s1: *const wchar_t, s2: *const wchar_t, n: usize) -> c_int {
9418 let mut i = 0;
9419 while i < n {
9420 let a = *s1.add(i);
9421 let b = *s2.add(i);
9422 if a != b { return a - b; }
9423 if a == 0 { return 0; }
9424 i += 1;
9425 }
9426 0
9427}
9428
9429#[no_mangle]
9430pub unsafe extern "C" fn wcscpy(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
9431 let mut i = 0;
9432 loop {
9433 let c = *src.add(i);
9434 *dst.add(i) = c;
9435 if c == 0 { break; }
9436 i += 1;
9437 }
9438 dst
9439}
9440
9441#[no_mangle]
9442pub unsafe extern "C" fn wcsncpy(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
9443 let mut i = 0;
9444 while i < n && *src.add(i) != 0 { *dst.add(i) = *src.add(i); i += 1; }
9445 while i < n { *dst.add(i) = 0; i += 1; }
9446 dst
9447}
9448
9449#[no_mangle]
9450pub unsafe extern "C" fn wcscat(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
9451 let mut i = 0;
9452 while *dst.add(i) != 0 { i += 1; }
9453 let mut j = 0;
9454 loop {
9455 let c = *src.add(j);
9456 *dst.add(i + j) = c;
9457 if c == 0 { break; }
9458 j += 1;
9459 }
9460 dst
9461}
9462
9463#[no_mangle]
9464pub unsafe extern "C" fn wcsncat(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
9465 let mut i = 0;
9466 while *dst.add(i) != 0 { i += 1; }
9467 let mut j = 0;
9468 while j < n && *src.add(j) != 0 { *dst.add(i + j) = *src.add(j); j += 1; }
9469 *dst.add(i + j) = 0;
9470 dst
9471}
9472
9473#[no_mangle]
9474pub unsafe extern "C" fn wcsdup(s: *const wchar_t) -> *mut wchar_t {
9475 let len = wcslen(s);
9476 let p = malloc((len + 1) * core::mem::size_of::<wchar_t>()) as *mut wchar_t;
9477 if p.is_null() { return null_mut(); }
9478 core::ptr::copy_nonoverlapping(s, p, len + 1);
9479 p
9480}
9481
9482#[no_mangle]
9483pub unsafe extern "C" fn wcsnlen(s: *const wchar_t, maxlen: usize) -> usize {
9484 let mut i = 0;
9485 while i < maxlen && *s.add(i) != 0 { i += 1; }
9486 i
9487}
9488
9489#[no_mangle]
9490pub unsafe extern "C" fn wcsspn(s: *const wchar_t, accept: *const wchar_t) -> usize {
9491 let mut i = 0;
9492 loop {
9493 let c = *s.add(i);
9494 if c == 0 { return i; }
9495 let mut found = false;
9496 let mut j = 0;
9497 loop {
9498 let a = *accept.add(j);
9499 if a == 0 { break; }
9500 if c == a { found = true; break; }
9501 j += 1;
9502 }
9503 if !found { return i; }
9504 i += 1;
9505 }
9506}
9507
9508#[no_mangle]
9509pub unsafe extern "C" fn wcscspn(s: *const wchar_t, reject: *const wchar_t) -> usize {
9510 let mut i = 0;
9511 loop {
9512 let c = *s.add(i);
9513 if c == 0 { return i; }
9514 let mut j = 0;
9515 loop {
9516 let r = *reject.add(j);
9517 if r == 0 { break; }
9518 if c == r { return i; }
9519 j += 1;
9520 }
9521 i += 1;
9522 }
9523}
9524
9525#[no_mangle]
9526pub unsafe extern "C" fn wcspbrk(s: *const wchar_t, accept: *const wchar_t) -> *mut wchar_t {
9527 let mut i = 0;
9528 loop {
9529 let c = *s.add(i);
9530 if c == 0 { return null_mut(); }
9531 let mut j = 0;
9532 loop {
9533 let a = *accept.add(j);
9534 if a == 0 { break; }
9535 if c == a { return s.add(i) as *mut wchar_t; }
9536 j += 1;
9537 }
9538 i += 1;
9539 }
9540}
9541
9542#[no_mangle]
9543pub unsafe extern "C" fn wcsxfrm(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> usize {
9544 let len = wcslen(src);
9545 if !dst.is_null() {
9546 let copy = if len < n { len } else { if n > 0 { n - 1 } else { 0 } };
9547 for i in 0..copy { *dst.add(i) = *src.add(i); }
9548 if n > 0 { *dst.add(copy) = 0; }
9549 }
9550 len
9551}
9552
9553unsafe fn wcs_to_bytes(ws: *const wchar_t, buf: *mut u8, bufsz: usize) -> usize {
9558 let mut i = 0;
9559 while i < bufsz - 1 {
9560 let c = *ws.add(i);
9561 if c == 0 { break; }
9562 if (c as u32) > 127 { break; }
9563 *buf.add(i) = c as u8;
9564 i += 1;
9565 }
9566 *buf.add(i) = 0;
9567 i
9568}
9569
9570#[no_mangle]
9571pub unsafe extern "C" fn wcstol(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_long {
9572 let mut buf = [0u8; 256];
9573 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9574 let mut end: *mut c_char = core::ptr::null_mut();
9575 let r = strtol(buf.as_ptr() as *const c_char, &mut end, base);
9576 if !endptr.is_null() {
9577 let offset = end as usize - buf.as_ptr() as usize;
9578 *endptr = s.add(offset) as *mut wchar_t;
9579 }
9580 r
9581}
9582
9583#[no_mangle]
9584pub unsafe extern "C" fn wcstoul(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulong {
9585 let mut buf = [0u8; 256];
9586 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9587 let mut end: *mut c_char = core::ptr::null_mut();
9588 let r = strtoul(buf.as_ptr() as *const c_char, &mut end, base);
9589 if !endptr.is_null() {
9590 let offset = end as usize - buf.as_ptr() as usize;
9591 *endptr = s.add(offset) as *mut wchar_t;
9592 }
9593 r
9594}
9595
9596#[no_mangle]
9597pub unsafe extern "C" fn wcstoll(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong {
9598 let mut buf = [0u8; 256];
9599 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9600 let mut end: *mut c_char = core::ptr::null_mut();
9601 let r = strtoll(buf.as_ptr() as *const c_char, &mut end, base);
9602 if !endptr.is_null() {
9603 let offset = end as usize - buf.as_ptr() as usize;
9604 *endptr = s.add(offset) as *mut wchar_t;
9605 }
9606 r
9607}
9608
9609#[no_mangle]
9610pub unsafe extern "C" fn wcstoull(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong {
9611 let mut buf = [0u8; 256];
9612 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9613 let mut end: *mut c_char = core::ptr::null_mut();
9614 let r = strtoull(buf.as_ptr() as *const c_char, &mut end, base);
9615 if !endptr.is_null() {
9616 let offset = end as usize - buf.as_ptr() as usize;
9617 *endptr = s.add(offset) as *mut wchar_t;
9618 }
9619 r
9620}
9621
9622#[no_mangle]
9623pub unsafe extern "C" fn wcstod(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 {
9624 let mut buf = [0u8; 256];
9625 wcs_to_bytes(s, buf.as_mut_ptr(), 256);
9626 let mut end: *mut c_char = core::ptr::null_mut();
9627 let r = strtod(buf.as_ptr() as *const c_char, &mut end);
9628 if !endptr.is_null() {
9629 let offset = end as usize - buf.as_ptr() as usize;
9630 *endptr = s.add(offset) as *mut wchar_t;
9631 }
9632 r
9633}
9634
9635#[no_mangle]
9636pub unsafe extern "C" fn wcstof(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f32 { wcstod(s, endptr) as f32 }
9637
9638#[no_mangle]
9639pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 { wcstod(s, endptr) }
9640
9641#[no_mangle]
9642pub unsafe extern "C" fn wcstoimax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong { wcstoll(s, endptr, base) }
9643
9644#[no_mangle]
9645pub unsafe extern "C" fn wcstoumax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong { wcstoull(s, endptr, base) }
9646
9647const WC_ALPHA: c_int = 1;
9652const WC_DIGIT: c_int = 2;
9653const WC_SPACE: c_int = 4;
9654const WC_UPPER: c_int = 8;
9655const WC_LOWER: c_int = 16;
9656const WC_ALNUM: c_int = WC_ALPHA | WC_DIGIT;
9657const WC_BLANK: c_int = 32;
9658const WC_CNTRL: c_int = 64;
9659const WC_PUNCT: c_int = 128;
9660const WC_GRAPH: c_int = WC_ALNUM | WC_PUNCT;
9661const WC_PRINT: c_int = WC_GRAPH | WC_BLANK;
9662const WC_XDIGIT: c_int = 256;
9663
9664fn wc_flags(c: wint_t) -> c_int {
9665 if c < 128 {
9666 let f = CT_TABLE[c as usize];
9667 let mut r = 0;
9668 if f & (CT_UPPER | CT_LOWER) != 0 { r |= WC_ALPHA; }
9669 if f & CT_DIGIT != 0 { r |= WC_DIGIT; }
9670 if f & CT_SPACE != 0 { r |= WC_SPACE; }
9671 if f & CT_UPPER != 0 { r |= WC_UPPER; }
9672 if f & CT_LOWER != 0 { r |= WC_LOWER; }
9673 if f & CT_BLANK != 0 { r |= WC_BLANK; }
9674 if f & CT_CNTRL != 0 { r |= WC_CNTRL; }
9675 if f & CT_PUNCT != 0 { r |= WC_PUNCT; }
9676 if f & CT_XDIGIT != 0 { r |= WC_XDIGIT; }
9677 r
9678 } else {
9679 if c < 0x100 { 0 }
9680 else { WC_PRINT | WC_ALPHA }
9681 }
9682}
9683
9684#[no_mangle]
9685pub extern "C" fn iswalnum(c: wint_t) -> c_int { (wc_flags(c) & WC_ALNUM != 0) as c_int }
9686#[no_mangle]
9687pub extern "C" fn iswalpha(c: wint_t) -> c_int { (wc_flags(c) & WC_ALPHA != 0) as c_int }
9688#[no_mangle]
9689pub extern "C" fn iswblank(c: wint_t) -> c_int { (wc_flags(c) & WC_BLANK != 0) as c_int }
9690#[no_mangle]
9691pub extern "C" fn iswcntrl(c: wint_t) -> c_int { (wc_flags(c) & WC_CNTRL != 0) as c_int }
9692#[no_mangle]
9693pub extern "C" fn iswdigit(c: wint_t) -> c_int { ((c >= b'0' as wint_t) && (c <= b'9' as wint_t)) as c_int }
9694#[no_mangle]
9695pub extern "C" fn iswgraph(c: wint_t) -> c_int { (wc_flags(c) & WC_GRAPH != 0) as c_int }
9696#[no_mangle]
9697pub extern "C" fn iswlower(c: wint_t) -> c_int { (wc_flags(c) & WC_LOWER != 0) as c_int }
9698#[no_mangle]
9699pub extern "C" fn iswprint(c: wint_t) -> c_int {
9700 if c < 128 { (wc_flags(c) & WC_PRINT != 0) as c_int }
9701 else if c >= 0x100 && c < 0x110000 { 1 }
9702 else { 0 }
9703}
9704#[no_mangle]
9705pub extern "C" fn iswpunct(c: wint_t) -> c_int { (wc_flags(c) & WC_PUNCT != 0) as c_int }
9706#[no_mangle]
9707pub extern "C" fn iswspace(c: wint_t) -> c_int {
9708 if c < 128 { (wc_flags(c) & WC_SPACE != 0) as c_int }
9709 else {
9710 match c {
9711 0x1680 | 0x2000..=0x200A | 0x2028 | 0x2029 | 0x202F | 0x205F | 0x3000 => 1,
9712 _ => 0,
9713 }
9714 }
9715}
9716#[no_mangle]
9717pub extern "C" fn iswupper(c: wint_t) -> c_int { (wc_flags(c) & WC_UPPER != 0) as c_int }
9718#[no_mangle]
9719pub extern "C" fn iswxdigit(c: wint_t) -> c_int { (wc_flags(c) & WC_XDIGIT != 0) as c_int }
9720
9721static WCTYPE_ALNUM: c_int = WC_ALNUM;
9722static WCTYPE_ALPHA: c_int = WC_ALPHA;
9723static WCTYPE_BLANK: c_int = WC_BLANK;
9724static WCTYPE_CNTRL: c_int = WC_CNTRL;
9725static WCTYPE_DIGIT: c_int = WC_DIGIT;
9726static WCTYPE_GRAPH: c_int = WC_GRAPH;
9727static WCTYPE_LOWER: c_int = WC_LOWER;
9728static WCTYPE_PRINT: c_int = WC_PRINT;
9729static WCTYPE_PUNCT: c_int = WC_PUNCT;
9730static WCTYPE_SPACE: c_int = WC_SPACE;
9731static WCTYPE_UPPER: c_int = WC_UPPER;
9732static WCTYPE_XDIGIT: c_int = WC_XDIGIT;
9733
9734#[no_mangle]
9735pub unsafe extern "C" fn wctype(name: *const c_char) -> wctype_t {
9736 if name.is_null() { return core::ptr::null(); }
9737 let n = name as *const u8;
9738 if strcmp(n, b"alnum\0".as_ptr()) == 0 { return &WCTYPE_ALNUM; }
9739 if strcmp(n, b"alpha\0".as_ptr()) == 0 { return &WCTYPE_ALPHA; }
9740 if strcmp(n, b"blank\0".as_ptr()) == 0 { return &WCTYPE_BLANK; }
9741 if strcmp(n, b"cntrl\0".as_ptr()) == 0 { return &WCTYPE_CNTRL; }
9742 if strcmp(n, b"digit\0".as_ptr()) == 0 { return &WCTYPE_DIGIT; }
9743 if strcmp(n, b"graph\0".as_ptr()) == 0 { return &WCTYPE_GRAPH; }
9744 if strcmp(n, b"lower\0".as_ptr()) == 0 { return &WCTYPE_LOWER; }
9745 if strcmp(n, b"print\0".as_ptr()) == 0 { return &WCTYPE_PRINT; }
9746 if strcmp(n, b"punct\0".as_ptr()) == 0 { return &WCTYPE_PUNCT; }
9747 if strcmp(n, b"space\0".as_ptr()) == 0 { return &WCTYPE_SPACE; }
9748 if strcmp(n, b"upper\0".as_ptr()) == 0 { return &WCTYPE_UPPER; }
9749 if strcmp(n, b"xdigit\0".as_ptr()) == 0 { return &WCTYPE_XDIGIT; }
9750 core::ptr::null()
9751}
9752
9753#[no_mangle]
9754pub unsafe extern "C" fn iswctype(c: wint_t, desc: wctype_t) -> c_int {
9755 if desc.is_null() { return 0; }
9756 (wc_flags(c) & *desc != 0) as c_int
9757}
9758
9759static WCTRANS_LOWER: c_int = 1;
9760static WCTRANS_UPPER: c_int = 2;
9761
9762#[no_mangle]
9763pub unsafe extern "C" fn towlower(c: wint_t) -> wint_t {
9764 if c < 128 { tolower(c as c_int) as wint_t } else { c }
9765}
9766
9767#[no_mangle]
9768pub unsafe extern "C" fn towupper(c: wint_t) -> wint_t {
9769 if c < 128 { toupper(c as c_int) as wint_t } else { c }
9770}
9771
9772#[no_mangle]
9773pub unsafe extern "C" fn wctrans(name: *const c_char) -> wctrans_t {
9774 if name.is_null() { return core::ptr::null(); }
9775 let n = name as *const u8;
9776 if strcmp(n, b"tolower\0".as_ptr()) == 0 { return &WCTRANS_LOWER; }
9777 if strcmp(n, b"toupper\0".as_ptr()) == 0 { return &WCTRANS_UPPER; }
9778 core::ptr::null()
9779}
9780
9781#[no_mangle]
9782pub unsafe extern "C" fn towctrans(c: wint_t, desc: wctrans_t) -> wint_t {
9783 if desc.is_null() { return c; }
9784 match *desc {
9785 1 => towlower(c),
9786 2 => towupper(c),
9787 _ => c,
9788 }
9789}
9790
9791#[no_mangle]
9796pub unsafe extern "C" fn fgetwc(f: *mut FILE) -> wint_t {
9797 let mut state: c_uint = 0;
9798 let mut wc: wchar_t = 0;
9799 let mut buf = [0u8; 4];
9800 let c = fgetc(f);
9801 if c == -1 { return WEOF; }
9802 buf[0] = c as u8;
9803 if buf[0] < 0x80 { return buf[0] as wint_t; }
9804 let len = if buf[0] < 0xE0 { 2 } else if buf[0] < 0xF0 { 3 } else { 4 };
9805 let mut n = 1usize;
9806 while n < len {
9807 let c2 = fgetc(f);
9808 if c2 == -1 { return WEOF; }
9809 buf[n] = c2 as u8;
9810 n += 1;
9811 }
9812 let r = mbrtowc(&mut wc, buf.as_ptr() as *const c_char, n, &mut state);
9813 if r == !0usize || r == !1usize { WEOF } else { wc as wint_t }
9814}
9815
9816#[no_mangle]
9817pub unsafe extern "C" fn fputwc(c: wchar_t, f: *mut FILE) -> wint_t {
9818 let mut buf = [0u8; 4];
9819 let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c, core::ptr::null_mut());
9820 if n == !0usize || n == 0 { return WEOF; }
9821 if fwrite(buf.as_ptr() as *const c_void, 1, n, f) != n { return WEOF; }
9822 c as wint_t
9823}
9824
9825#[no_mangle]
9826pub unsafe extern "C" fn fputws(s: *const wchar_t, f: *mut FILE) -> c_int {
9827 let mut i = 0;
9828 while *s.add(i) != 0 {
9829 if fputwc(*s.add(i), f) == WEOF { return -1; }
9830 i += 1;
9831 }
9832 0
9833}
9834
9835#[no_mangle]
9836pub unsafe extern "C" fn ungetwc(c: wint_t, f: *mut FILE) -> wint_t {
9837 if c == WEOF { return WEOF; }
9838 let mut buf = [0u8; 4];
9839 let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c as wchar_t, core::ptr::null_mut());
9840 if n == !0usize || n == 0 { return WEOF; }
9841 let mut i = n;
9842 while i > 0 {
9843 i -= 1;
9844 if ungetc(buf[i] as c_int, f) == -1 { return WEOF; }
9845 }
9846 c
9847}
9848
9849#[no_mangle]
9850pub unsafe extern "C" fn getwchar() -> wint_t { fgetwc(stdin) }
9851
9852#[no_mangle]
9853pub unsafe extern "C" fn putwchar(c: wchar_t) -> wint_t { fputwc(c, stdout) }
9854
9855unsafe fn wfmt_write_str(dst: *mut wchar_t, pos: usize, cap: usize, s: *const u8, len: usize) -> usize {
9860 let mut i = 0;
9861 while i < len {
9862 if pos + i < cap { *dst.add(pos + i) = *s.add(i) as wchar_t; }
9863 i += 1;
9864 }
9865 pos + len
9866}
9867
9868#[no_mangle]
9869pub unsafe extern "C" fn vswprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, mut args: VaList) -> c_int {
9870 if n == 0 { return -1; }
9871 let cap = n - 1;
9872 let mut pos = 0usize;
9873 let mut fmt_narrow = [0u8; 256];
9875 let mut flen = 0usize;
9876 loop {
9877 let ch = *fmt.add(flen) as u32;
9878 if ch == 0 || flen >= 255 { break; }
9879 fmt_narrow[flen] = if ch < 128 { ch as u8 } else { b'?' };
9880 flen += 1;
9881 }
9882 fmt_narrow[flen] = 0;
9883 let mut fi = 0usize;
9884 macro_rules! wc {
9885 ($c:expr) => { if pos < cap { *s.add(pos) = $c as wchar_t; } pos += 1; }
9886 }
9887 loop {
9888 let c = fmt_narrow[fi];
9889 if c == 0 { break; }
9890 if c != b'%' { wc!(c); fi += 1; continue; }
9891 fi += 1;
9892 let mut flags: u8 = 0;
9893 loop {
9894 match fmt_narrow[fi] {
9895 b'-' => { flags |= FLAG_MINUS; fi += 1; }
9896 b'+' => { flags |= FLAG_PLUS; fi += 1; }
9897 b' ' => { flags |= FLAG_SPACE; fi += 1; }
9898 b'0' => { flags |= FLAG_ZERO; fi += 1; }
9899 b'#' => { flags |= FLAG_HASH; fi += 1; }
9900 _ => break,
9901 }
9902 }
9903 let mut width: usize = 0;
9904 if fmt_narrow[fi] == b'*' {
9905 let w = args.next_arg::<c_int>();
9906 if w < 0 { flags |= FLAG_MINUS; width = (-w) as usize; } else { width = w as usize; }
9907 fi += 1;
9908 } else {
9909 while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
9910 width = width * 10 + (fmt_narrow[fi] - b'0') as usize; fi += 1;
9911 }
9912 }
9913 let mut precision: i32 = -1;
9914 if fmt_narrow[fi] == b'.' {
9915 fi += 1;
9916 if fmt_narrow[fi] == b'*' {
9917 let p = args.next_arg::<c_int>();
9918 precision = if p < 0 { -1 } else { p }; fi += 1;
9919 } else {
9920 precision = 0;
9921 while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
9922 precision = precision * 10 + (fmt_narrow[fi] - b'0') as i32; fi += 1;
9923 }
9924 }
9925 }
9926 let len_mod = fmt_narrow[fi];
9927 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' {
9928 fi += 1;
9929 let spec = fmt_narrow[fi];
9930 if (len_mod == b'h' && spec == b'h') || (len_mod == b'l' && spec == b'l') {
9931 fi += 1;
9932 let spec2 = fmt_narrow[fi];
9933 match (len_mod, spec, spec2) {
9934 (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; } }
9935 (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; } }
9936 (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
9937 let val = args.next_arg::<c_longlong>();
9938 let neg = val < 0;
9939 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
9940 let b = format_u64(abs);
9941 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
9942 let mut fbuf = [0u8; 32];
9943 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
9944 for k in 0..len { wc!(fbuf[k]); }
9945 }
9946 (b'l', b'l', b'u') => {
9947 let val = args.next_arg::<c_ulonglong>();
9948 let b = format_u64(val as u64);
9949 let mut fbuf = [0u8; 32];
9950 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
9951 for k in 0..len { wc!(fbuf[k]); }
9952 }
9953 (b'l', b'l', b'x') => {
9954 let val = args.next_arg::<c_ulonglong>();
9955 let b = format_hex(val as u64, false);
9956 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
9957 let mut fbuf = [0u8; 32];
9958 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
9959 for k in 0..len { wc!(fbuf[k]); }
9960 }
9961 (b'l', b'l', b'X') => {
9962 let val = args.next_arg::<c_ulonglong>();
9963 let b = format_hex(val as u64, true);
9964 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
9965 let mut fbuf = [0u8; 32];
9966 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
9967 for k in 0..len { wc!(fbuf[k]); }
9968 }
9969 (b'l', b'l', b'o') => {
9970 let val = args.next_arg::<c_ulonglong>();
9971 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
9972 let mut fbuf = [0u8; 32];
9973 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
9974 for k in 0..len { wc!(fbuf[k]); }
9975 }
9976 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); wc!(spec2); }
9977 }
9978 } else {
9979 match (len_mod, spec) {
9980 (b'h', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut u16) = pos as u16; } }
9981 (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; } }
9982 (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; } }
9983 (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; } }
9984 (b'l', b'd') | (b'l', b'i') => {
9985 let val = args.next_arg::<c_long>();
9986 let neg = val < 0;
9987 let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
9988 let b = format_u64(abs);
9989 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
9990 let mut fbuf = [0u8; 32];
9991 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
9992 for k in 0..len { wc!(fbuf[k]); }
9993 }
9994 (b'l', b'u') => {
9995 let val = args.next_arg::<c_ulong>();
9996 let b = format_u64(val as u64);
9997 let mut fbuf = [0u8; 32];
9998 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
9999 for k in 0..len { wc!(fbuf[k]); }
10000 }
10001 (b'l', b'x') => {
10002 let val = args.next_arg::<c_ulong>();
10003 let b = format_hex(val as u64, false);
10004 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10005 let mut fbuf = [0u8; 32];
10006 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10007 for k in 0..len { wc!(fbuf[k]); }
10008 }
10009 (b'l', b'X') => {
10010 let val = args.next_arg::<c_ulong>();
10011 let b = format_hex(val as u64, true);
10012 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10013 let mut fbuf = [0u8; 32];
10014 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10015 for k in 0..len { wc!(fbuf[k]); }
10016 }
10017 (b'l', b'o') => {
10018 let val = args.next_arg::<c_ulong>();
10019 let b = format_octal(val as u64, flags & FLAG_HASH != 0);
10020 let mut fbuf = [0u8; 32];
10021 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10022 for k in 0..len { wc!(fbuf[k]); }
10023 }
10024 (b'l', b'c') => {
10025 let ch = args.next_arg::<wint_t>();
10026 wc!(ch);
10027 }
10028 (b'l', b's') => {
10029 let ws_arg = args.next_arg::<*const wchar_t>();
10030 if ws_arg.is_null() {
10031 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10032 if flags & FLAG_MINUS != 0 {
10033 for k in 0..slen { wc!(b"(null)"[k]); }
10034 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10035 } else {
10036 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10037 for k in 0..slen { wc!(b"(null)"[k]); }
10038 }
10039 } else {
10040 let mut wlen = 0usize;
10041 loop {
10042 let ch = *ws_arg.add(wlen);
10043 if ch == 0 { break; }
10044 if precision >= 0 && wlen >= precision as usize { break; }
10045 wlen += 1;
10046 }
10047 if flags & FLAG_MINUS != 0 {
10048 for k in 0..wlen { wc!(*ws_arg.add(k)); }
10049 for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10050 } else {
10051 for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10052 for k in 0..wlen { wc!(*ws_arg.add(k)); }
10053 }
10054 }
10055 }
10056 (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
10057 | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A')
10058 | (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
10059 | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
10060 let val = args.next_arg::<f64>();
10061 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10062 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10063 let mut fbuf = [0u8; 4224];
10064 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10065 let mut wbuf = [0u8; 4224];
10066 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10067 for k in 0..wlen { wc!(wbuf[k]); }
10068 }
10069 _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
10070 }
10071 }
10072 } else {
10073 let spec = fmt_narrow[fi];
10074 match spec {
10075 b'd' | b'i' => {
10076 let d = args.next_arg::<c_int>();
10077 let neg = d < 0;
10078 let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
10079 let b = format_u64(abs);
10080 let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10081 let mut fbuf = [0u8; 32];
10082 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10083 for k in 0..len { wc!(fbuf[k]); }
10084 }
10085 b'u' => {
10086 let u = args.next_arg::<c_uint>();
10087 let b = format_u64(u as u64);
10088 let mut fbuf = [0u8; 32];
10089 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10090 for k in 0..len { wc!(fbuf[k]); }
10091 }
10092 b'x' => {
10093 let x = args.next_arg::<c_uint>();
10094 let b = format_hex(x as u64, false);
10095 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10096 let mut fbuf = [0u8; 32];
10097 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10098 for k in 0..len { wc!(fbuf[k]); }
10099 }
10100 b'X' => {
10101 let x = args.next_arg::<c_uint>();
10102 let b = format_hex(x as u64, true);
10103 let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10104 let mut fbuf = [0u8; 32];
10105 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10106 for k in 0..len { wc!(fbuf[k]); }
10107 }
10108 b'o' => {
10109 let o = args.next_arg::<c_uint>();
10110 let b = format_octal(o as u64, flags & FLAG_HASH != 0);
10111 let mut fbuf = [0u8; 32];
10112 let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10113 for k in 0..len { wc!(fbuf[k]); }
10114 }
10115 b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
10116 let val = args.next_arg::<f64>();
10117 let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10118 let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10119 let mut fbuf = [0u8; 4224];
10120 let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10121 let mut wbuf = [0u8; 4224];
10122 let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10123 for k in 0..wlen { wc!(wbuf[k]); }
10124 }
10125 b'c' => {
10126 let ch = args.next_arg::<c_int>();
10127 wc!(ch as u8);
10128 }
10129 b's' => {
10130 let p = args.next_arg::<*const c_char>();
10131 if p.is_null() {
10132 let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10133 if flags & FLAG_MINUS != 0 {
10134 for k in 0..slen { wc!(b"(null)"[k]); }
10135 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10136 } else {
10137 for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10138 for k in 0..slen { wc!(b"(null)"[k]); }
10139 }
10140 } else {
10141 let mut wbuf_local = [0i32; 256];
10142 let mut wcount = 0usize;
10143 let mut byte_pos = 0usize;
10144 let pbytes = p as *const u8;
10145 loop {
10146 if precision >= 0 && wcount >= precision as usize { break; }
10147 if wcount >= 256 { break; }
10148 let mut wc_val: c_int = 0;
10149 let consumed = mbrtowc(&mut wc_val as *mut c_int, p.add(byte_pos) as *const c_char, 256, core::ptr::null_mut());
10150 if consumed == !0usize || consumed == !1usize {
10151 wbuf_local[wcount] = *pbytes.add(byte_pos) as c_int;
10152 byte_pos += 1;
10153 wcount += 1;
10154 } else if consumed == 0 {
10155 break;
10156 } else {
10157 wbuf_local[wcount] = wc_val;
10158 byte_pos += consumed;
10159 wcount += 1;
10160 }
10161 }
10162 if flags & FLAG_MINUS != 0 {
10163 for k in 0..wcount { wc!(wbuf_local[k]); }
10164 for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10165 } else {
10166 for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10167 for k in 0..wcount { wc!(wbuf_local[k]); }
10168 }
10169 }
10170 }
10171 b'p' => {
10172 wc!(b'0'); wc!(b'x');
10173 let p = args.next_arg::<*const c_void>();
10174 let b = format_hex(p as u64, false);
10175 for k in 0..b.1 { wc!(b.0[k]); }
10176 }
10177 b'n' => {
10178 let p = args.next_arg::<*mut c_void>();
10179 if !p.is_null() { *(p as *mut c_int) = pos as c_int; }
10180 }
10181 b'%' => { wc!(b'%'); }
10182 _ => { wc!(b'%'); wc!(spec); }
10183 }
10184 }
10185 fi += 1;
10186 }
10187 let null_pos = if pos < cap { pos } else { cap };
10188 *s.add(null_pos) = 0;
10189 if pos > cap { -1 } else { pos as c_int }
10190}
10191
10192#[no_mangle]
10193pub unsafe extern "C" fn swprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, args: ...) -> c_int {
10194 vswprintf(s, n, fmt, args)
10195}
10196
10197#[no_mangle]
10198pub unsafe extern "C" fn vfwprintf(f: *mut FILE, fmt: *const wchar_t, args: VaList) -> c_int {
10199 let mut buf = [0i32; 4096];
10200 let r = vswprintf(buf.as_mut_ptr(), 4096, fmt, args);
10201 if r < 0 { return r; }
10202 let mut i = 0;
10203 while i < r as usize {
10204 let mut mb = [0u8; 4];
10205 let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, buf[i], core::ptr::null_mut());
10206 if n == !0usize { return -1; }
10207 if fwrite(mb.as_ptr() as *const c_void, 1, n, f) != n { return -1; }
10208 i += 1;
10209 }
10210 r
10211}
10212
10213#[no_mangle]
10214pub unsafe extern "C" fn fwprintf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10215 vfwprintf(f, fmt, args)
10216}
10217
10218unsafe fn wcsfmt_to_mbs(dst: *mut u8, dst_len: usize, src: *const wchar_t) {
10224 let mut i = 0usize;
10225 loop {
10226 let ch = *src.add(i) as u32;
10227 if ch == 0 || i >= dst_len - 1 { break; }
10228 *dst.add(i) = if ch < 128 { ch as u8 } else { b'?' };
10229 i += 1;
10230 }
10231 *dst.add(i) = 0;
10232}
10233
10234#[no_mangle]
10235pub unsafe extern "C" fn vswscanf(s: *const wchar_t, fmt: *const wchar_t, mut args: VaList) -> c_int {
10236 let mut mbs_buf = [0u8; 4096];
10237 let mut i = 0usize;
10238 let mut mb_pos = 0usize;
10239 loop {
10240 let wc = *s.add(i) as c_int;
10241 if wc == 0 { break; }
10242 let mut mb = [0u8; 4];
10243 let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, wc, core::ptr::null_mut());
10244 if n == !0usize || n == 0 { break; }
10245 if mb_pos + n >= mbs_buf.len() { break; }
10246 let mut k = 0usize;
10247 while k < n { mbs_buf[mb_pos + k] = mb[k]; k += 1; }
10248 mb_pos += n;
10249 i += 1;
10250 }
10251 mbs_buf[mb_pos] = 0;
10252 let mut mbs_fmt = [0u8; 4096];
10253 wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10254 do_vsscanf(mbs_buf.as_ptr(), mb_pos, mbs_fmt.as_ptr() as *const c_char, &mut args, core::ptr::null_mut())
10255}
10256
10257#[no_mangle]
10258pub unsafe extern "C" fn swscanf(s: *const wchar_t, fmt: *const wchar_t, args: ...) -> c_int {
10259 vswscanf(s, fmt, args)
10260}
10261
10262#[no_mangle]
10263pub unsafe extern "C" fn vfwscanf(f: *mut FILE, fmt: *const wchar_t, mut args: VaList) -> c_int {
10264 let start_pos = ftello(f);
10265 if start_pos < 0 { return -1; }
10266 let mut buf = [0u8; 4096];
10267 let mut n = 0usize;
10268 loop {
10269 if n >= buf.len() - 1 { break; }
10270 let c = fgetc(f);
10271 if c == -1 { break; }
10272 buf[n] = c as u8;
10273 n += 1;
10274 }
10275 buf[n] = 0;
10276 let mut mbs_fmt = [0u8; 4096];
10277 wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10278 let mut consumed = 0usize;
10279 let hit_eof = (*f)._eof != 0;
10280 let result = do_vsscanf(buf.as_ptr(), n, mbs_fmt.as_ptr() as *const c_char, &mut args, &mut consumed);
10281 let _ = fseeko(f, start_pos + consumed as i64, SEEK_SET);
10282 if hit_eof && consumed == n {
10283 (*f)._eof = 1;
10284 }
10285 result
10286}
10287
10288#[no_mangle]
10289pub unsafe extern "C" fn fwscanf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10290 vfwscanf(f, fmt, args)
10291}
10292
10293#[no_mangle]
10294pub unsafe extern "C" fn vwscanf(fmt: *const wchar_t, args: VaList) -> c_int {
10295 vfwscanf(stdin, fmt, args)
10296}
10297
10298#[no_mangle]
10299pub unsafe extern "C" fn wscanf(fmt: *const wchar_t, args: ...) -> c_int {
10300 vfwscanf(stdin, fmt, args)
10301}
10302
10303const LEAPOCH: i64 = 946684800 + 86400 * (31 + 29);
10308const DAYS_PER_400Y: i64 = 365 * 400 + 97;
10309const DAYS_PER_100Y: i64 = 365 * 100 + 24;
10310const DAYS_PER_4Y: i64 = 365 * 4 + 1;
10311
10312const SECS_THROUGH_MONTH: [i32; 12] = [
10313 0, 31*86400, 59*86400, 90*86400, 120*86400, 151*86400,
10314 181*86400, 212*86400, 243*86400, 273*86400, 304*86400, 334*86400,
10315];
10316
10317const DAYS_IN_MONTH: [i32; 12] = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29];
10318
10319unsafe fn year_to_secs(year: i64, is_leap: &mut bool) -> i64 {
10320 if year - 2 <= 136 {
10321 let y = year as i32;
10322 let mut leaps = (y - 68) >> 2;
10323 if (y - 68) & 3 == 0 { leaps -= 1; *is_leap = true; } else { *is_leap = false; }
10324 return 31536000 * (y as i64 - 70) + 86400 * leaps as i64;
10325 }
10326 let mut cycles = ((year - 100) / 400) as i32;
10327 let mut rem = ((year - 100) % 400) as i32;
10328 if rem < 0 { cycles -= 1; rem += 400; }
10329 let (centuries, leaps);
10330 if rem == 0 { *is_leap = true; centuries = 0; leaps = 0; }
10331 else {
10332 let c;
10333 if rem >= 200 { if rem >= 300 { c = 3; rem -= 300; } else { c = 2; rem -= 200; } }
10334 else { if rem >= 100 { c = 1; rem -= 100; } else { c = 0; } }
10335 centuries = c;
10336 if rem == 0 { *is_leap = false; leaps = 0; }
10337 else { leaps = rem / 4; rem %= 4; *is_leap = rem == 0; }
10338 }
10339 let total_leaps = leaps + 97 * cycles + 24 * centuries - (*is_leap as i32);
10340 (year - 100) * 31536000 + total_leaps as i64 * 86400 + 946684800 + 86400
10341}
10342
10343fn month_to_secs(month: i32, is_leap: bool) -> i32 {
10344 let mut t = SECS_THROUGH_MONTH[month as usize];
10345 if is_leap && month >= 2 { t += 86400; }
10346 t
10347}
10348
10349unsafe fn secs_to_tm(t: i64, tm: &mut tm) -> bool {
10350 if t < (i32::MIN as i64) * 31622400 || t > (i32::MAX as i64) * 31622400 { return false; }
10351 let secs = t - LEAPOCH;
10352 let mut days = secs / 86400;
10353 let mut remsecs = (secs % 86400) as i32;
10354 if remsecs < 0 { remsecs += 86400; days -= 1; }
10355 let mut wday = ((3 + days) % 7) as i32;
10356 if wday < 0 { wday += 7; }
10357 let mut qc_cycles = (days / DAYS_PER_400Y) as i32;
10358 let mut remdays = (days % DAYS_PER_400Y) as i32;
10359 if remdays < 0 { remdays += DAYS_PER_400Y as i32; qc_cycles -= 1; }
10360 let mut c_cycles = remdays / DAYS_PER_100Y as i32;
10361 if c_cycles == 4 { c_cycles -= 1; }
10362 remdays -= c_cycles * DAYS_PER_100Y as i32;
10363 let mut q_cycles = remdays / DAYS_PER_4Y as i32;
10364 if q_cycles == 25 { q_cycles -= 1; }
10365 remdays -= q_cycles * DAYS_PER_4Y as i32;
10366 let mut remyears = remdays / 365;
10367 if remyears == 4 { remyears -= 1; }
10368 remdays -= remyears * 365;
10369 let leap = remyears == 0 && (q_cycles != 0 || c_cycles == 0);
10370 let mut yday = remdays + 31 + 28 + leap as i32;
10371 if yday >= 365 + leap as i32 { yday -= 365 + leap as i32; }
10372 let years = remyears as i64 + 4 * q_cycles as i64 + 100 * c_cycles as i64 + 400 * qc_cycles as i64;
10373 let mut months = 0i32;
10374 let mut rd = remdays;
10375 for m in 0..12 {
10376 if DAYS_IN_MONTH[m] <= rd { rd -= DAYS_IN_MONTH[m]; } else { months = m as i32; break; }
10377 }
10378 let mut adj_years = years;
10379 if months >= 10 { months -= 12; adj_years += 1; }
10380 if adj_years + 100 > i32::MAX as i64 || adj_years + 100 < i32::MIN as i64 { return false; }
10381 tm.tm_year = (adj_years + 100) as c_int;
10382 tm.tm_mon = months + 2;
10383 tm.tm_mday = rd + 1;
10384 tm.tm_wday = wday;
10385 tm.tm_yday = yday;
10386 tm.tm_hour = remsecs / 3600;
10387 tm.tm_min = remsecs / 60 % 60;
10388 tm.tm_sec = remsecs % 60;
10389 true
10390}
10391
10392unsafe fn tm_to_secs(tm: *const tm) -> i64 {
10393 let mut year = (*tm).tm_year as i64;
10394 let mut month = (*tm).tm_mon;
10395 if month >= 12 || month < 0 {
10396 let adj = month / 12;
10397 month %= 12;
10398 if month < 0 { month += 12; }
10399 year += adj as i64;
10400 }
10401 let mut is_leap = false;
10402 let mut t = year_to_secs(year, &mut is_leap);
10403 t += month_to_secs(month, is_leap) as i64;
10404 t += 86400 * ((*tm).tm_mday - 1) as i64;
10405 t += 3600 * (*tm).tm_hour as i64;
10406 t += 60 * (*tm).tm_min as i64;
10407 t += (*tm).tm_sec as i64;
10408 t
10409}
10410
10411static mut TM_BUF: tm = tm {
10412 tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0,
10413 tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0,
10414 tm_gmtoff: 0, tm_zone: core::ptr::null(),
10415};
10416
10417static mut UTC_STR: [c_char; 4] = [b'U' as c_char, b'T' as c_char, b'C' as c_char, 0];
10418
10419const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
10420
10421#[no_mangle]
10426pub unsafe extern "C" fn time(t: *mut TimeT) -> TimeT {
10427 let mut ts: timespec = core::mem::zeroed();
10428 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
10429 if !t.is_null() { *t = ts.tv_sec; }
10430 ts.tv_sec
10431}
10432
10433#[no_mangle]
10434pub unsafe extern "C" fn difftime(t1: TimeT, t0: TimeT) -> f64 {
10435 (t1 as i64 - t0 as i64) as f64
10436}
10437
10438#[no_mangle]
10439pub unsafe extern "C" fn clock() -> ClockT {
10440 let mut ts: timespec = core::mem::zeroed();
10441 let _ = sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mut ts);
10442 ts.tv_sec * 1000000 + ts.tv_nsec / 1000
10443}
10444
10445#[no_mangle]
10446pub unsafe extern "C" fn gmtime(t: *const TimeT) -> *mut tm {
10447 gmtime_r(t, &raw mut TM_BUF)
10448}
10449
10450#[no_mangle]
10451pub unsafe extern "C" fn gmtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm {
10452 if !secs_to_tm(*t as i64, &mut *tm) { ERRNO = EOVERFLOW; return core::ptr::null_mut(); }
10453 (*tm).tm_isdst = 0;
10454 (*tm).tm_gmtoff = 0;
10455 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10456 tm
10457}
10458
10459#[no_mangle]
10460pub unsafe extern "C" fn localtime(t: *const TimeT) -> *mut tm { gmtime(t) }
10461
10462#[no_mangle]
10463pub unsafe extern "C" fn localtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm { gmtime_r(t, tm) }
10464
10465#[no_mangle]
10466pub unsafe extern "C" fn mktime(tm: *mut tm) -> TimeT {
10467 let t = tm_to_secs(tm as *const tm);
10468 if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
10469 (*tm).tm_isdst = 0;
10470 (*tm).tm_gmtoff = 0;
10471 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10472 t as TimeT
10473}
10474
10475#[no_mangle]
10476pub unsafe extern "C" fn timegm(tm: *mut tm) -> TimeT {
10477 let t = tm_to_secs(tm as *const tm);
10478 if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
10479 (*tm).tm_isdst = 0;
10480 (*tm).tm_gmtoff = 0;
10481 (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
10482 t as TimeT
10483}
10484
10485static mut ASCTIME_BUF: [c_char; 26] = [0; 26];
10486
10487const 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"];
10488const 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"];
10489
10490#[no_mangle]
10491pub unsafe extern "C" fn asctime(tm: *const tm) -> *mut c_char {
10492 asctime_r(tm, core::ptr::addr_of_mut!(ASCTIME_BUF).cast::<c_char>())
10493}
10494
10495#[no_mangle]
10496pub unsafe extern "C" fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char {
10497 let wday = if (*tm).tm_wday >= 0 && (*tm).tm_wday < 7 { (*tm).tm_wday as usize } else { 0 };
10498 let mon = if (*tm).tm_mon >= 0 && (*tm).tm_mon < 12 { (*tm).tm_mon as usize } else { 0 };
10499 let dn = DAY_NAMES[wday];
10500 let mn = MON_NAMES[mon];
10501 let mut p = 0;
10502 for k in 0..3 { *buf.add(p) = *dn.as_ptr().add(k) as c_char; p += 1; }
10503 *buf.add(p) = b' ' as c_char; p += 1;
10504 for k in 0..3 { *buf.add(p) = *mn.as_ptr().add(k) as c_char; p += 1; }
10505 *buf.add(p) = b' ' as c_char; p += 1;
10506 let v = (*tm).tm_mday;
10507 *buf.add(p) = (b'0' + (v / 10) as u8) as c_char; p += 1;
10508 *buf.add(p) = (b'0' + (v % 10) as u8) as c_char; p += 1;
10509 *buf.add(p) = b' ' as c_char; p += 1;
10510 let hh = (*tm).tm_hour;
10511 *buf.add(p) = (b'0' + (hh / 10) as u8) as c_char; p += 1;
10512 *buf.add(p) = (b'0' + (hh % 10) as u8) as c_char; p += 1;
10513 *buf.add(p) = b':' as c_char; p += 1;
10514 let mm = (*tm).tm_min;
10515 *buf.add(p) = (b'0' + (mm / 10) as u8) as c_char; p += 1;
10516 *buf.add(p) = (b'0' + (mm % 10) as u8) as c_char; p += 1;
10517 *buf.add(p) = b':' as c_char; p += 1;
10518 let ss = (*tm).tm_sec;
10519 *buf.add(p) = (b'0' + (ss / 10) as u8) as c_char; p += 1;
10520 *buf.add(p) = (b'0' + (ss % 10) as u8) as c_char; p += 1;
10521 *buf.add(p) = b' ' as c_char; p += 1;
10522 let yr = (*tm).tm_year + 1900;
10523 let mut tmp = [0u8; 4];
10524 let mut v2 = yr;
10525 for k in (0..4).rev() { tmp[k] = b'0' + (v2 % 10) as u8; v2 /= 10; }
10526 for k in 0..4 { *buf.add(p) = tmp[k] as c_char; p += 1; }
10527 *buf.add(p) = b'\n' as c_char; p += 1;
10528 *buf.add(p) = 0;
10529 buf
10530}
10531
10532#[no_mangle]
10533pub unsafe extern "C" fn ctime(t: *const TimeT) -> *mut c_char { asctime(gmtime(t)) }
10534
10535#[no_mangle]
10536pub unsafe extern "C" fn ctime_r(t: *const TimeT, buf: *mut c_char) -> *mut c_char {
10537 let mut tmp: tm = core::mem::zeroed();
10538 gmtime_r(t, &mut tmp);
10539 asctime_r(&tmp, buf)
10540}
10541
10542unsafe fn sys_clock_getres(clockid: c_int, ts: *mut timespec) -> i64 {
10547 <Arch as Syscalls>::syscall2(SYS_CLOCK_GETRES, clockid as i64, ts as i64)
10548}
10549
10550unsafe fn sys_clock_settime(clockid: c_int, ts: *const timespec) -> i64 {
10551 <Arch as Syscalls>::syscall2(SYS_CLOCK_SETTIME, clockid as i64, ts as i64)
10552}
10553
10554unsafe fn sys_clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> i64 {
10555 <Arch as Syscalls>::syscall4(SYS_CLOCK_NANOSLEEP, clockid as i64, flags as i64, req as i64, rem as i64)
10556}
10557
10558#[no_mangle]
10559pub unsafe extern "C" fn clock_getres(clockid: c_int, ts: *mut timespec) -> c_int { if sys_clock_getres(clockid, ts) < 0 { -1 } else { 0 } }
10560
10561#[no_mangle]
10562pub unsafe extern "C" fn clock_settime(clockid: c_int, ts: *const timespec) -> c_int { if sys_clock_settime(clockid, ts) < 0 { -1 } else { 0 } }
10563
10564#[no_mangle]
10565pub unsafe extern "C" fn clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> c_int {
10566 let r = sys_clock_nanosleep(clockid, flags, req, rem);
10567 if r < 0 { (-r) as c_int } else { 0 }
10568}
10569
10570#[no_mangle]
10571pub unsafe extern "C" fn gettimeofday(tv: *mut timeval, _tz: *mut c_void) -> c_int {
10572 if tv.is_null() { return 0; }
10573 let mut ts: timespec = core::mem::zeroed();
10574 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
10575 (*tv).tv_sec = ts.tv_sec;
10576 (*tv).tv_usec = ts.tv_nsec / 1000;
10577 0
10578}
10579
10580fn is_leap_year(y: i32) -> bool {
10585 let yr = if y > i32::MAX - 1900 { y - 2000 } else { y + 1900 };
10586 yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0)
10587}
10588
10589fn week_num(tm: &tm) -> i32 {
10590 let mut val = (tm.tm_yday + 7 - ((tm.tm_wday + 6) % 7)) / 7;
10591 if (tm.tm_wday + 371 - tm.tm_yday - 2).rem_euclid(7) <= 2 { val += 1; }
10592 if val == 0 {
10593 val = 52;
10594 let dec31 = (tm.tm_wday + 7 - tm.tm_yday - 1).rem_euclid(7);
10595 if dec31 == 4 || (dec31 == 5 && is_leap_year(tm.tm_year % 400 - 1)) { val += 1; }
10596 } else if val == 53 {
10597 let jan1 = (tm.tm_wday + 371 - tm.tm_yday).rem_euclid(7);
10598 if jan1 != 4 && (jan1 != 3 || !is_leap_year(tm.tm_year)) { val = 1; }
10599 }
10600 val
10601}
10602
10603const ABDAY_1: c_int = 0x20000;
10605const DAY_1: c_int = 0x20007;
10606const ABMON_1: c_int = 0x2000E;
10607const MON_1: c_int = 0x2001A;
10608const AM_STR_LI: c_int = 0x20026;
10609const PM_STR_LI: c_int = 0x20027;
10610const D_T_FMT: c_int = 0x20028;
10611const D_FMT: c_int = 0x20029;
10612const T_FMT: c_int = 0x2002A;
10613const T_FMT_AMPM: c_int = 0x2002B;
10614
10615unsafe fn num_fmt(buf: &mut [u8; 100], val: i64, pad: u8, width: usize) -> (*const u8, usize) {
10618 let negative = val < 0;
10619 let mut v = if negative { -val as u64 } else { val as u64 };
10620 let mut tmp = [0u8; 24];
10621 let mut pos = 24usize;
10622 if v == 0 { pos -= 1; tmp[pos] = b'0'; }
10623 while v > 0 { pos -= 1; tmp[pos] = b'0' + (v % 10) as u8; v /= 10; }
10624 let digits = 24 - pos;
10625 let sign_chars = if negative { 1 } else { 0 };
10626 let needed = sign_chars + digits;
10627 let fill = if width > needed { width - needed } else { 0 };
10628 let total = fill + needed;
10629 let mut p = 0usize;
10630 match pad {
10631 b'-' => { }
10632 b'_' => {
10633 for _ in 0..fill { buf[p] = b' '; p += 1; }
10634 if negative { buf[p] = b'-'; p += 1; }
10635 }
10636 _ => {
10637 if negative { buf[p] = b'-'; p += 1; }
10638 for _ in 0..fill { buf[p] = b'0'; p += 1; }
10639 }
10640 }
10641 for i in 0..digits { buf[p] = tmp[pos + i]; p += 1; }
10642 (buf.as_ptr(), total)
10643}
10644
10645unsafe fn str_to_buf(buf: &mut [u8; 100], s: *const c_char) -> (*const u8, usize) {
10647 let mut k = 0usize;
10648 while *s.add(k) != 0 {
10649 buf[k] = *s.add(k) as u8;
10650 k += 1;
10651 }
10652 (buf.as_ptr(), k)
10653}
10654
10655unsafe fn __strftime_fmt_1(buf: &mut [u8; 100], f: u8, tm: *const tm, pad: u8) -> (*const u8, usize) {
10658 let mut val: i64;
10659 let mut width: usize = 2;
10660 let mut def_pad: u8 = b'0';
10661 let fmt: *const c_char;
10662
10663 match f {
10664 b'a' => {
10665 if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
10666 let p = nl_langinfo(ABDAY_1 + (*tm).tm_wday);
10667 return str_to_buf(buf, p);
10668 }
10669 b'A' => {
10670 if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
10671 let p = nl_langinfo(DAY_1 + (*tm).tm_wday);
10672 return str_to_buf(buf, p);
10673 }
10674 b'h' | b'b' => {
10675 if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
10676 let p = nl_langinfo(ABMON_1 + (*tm).tm_mon);
10677 return str_to_buf(buf, p);
10678 }
10679 b'B' => {
10680 if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
10681 let p = nl_langinfo(MON_1 + (*tm).tm_mon);
10682 return str_to_buf(buf, p);
10683 }
10684 b'c' => {
10685 let p = nl_langinfo(D_T_FMT);
10686 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10687 return (buf.as_ptr(), l);
10688 }
10689 b'C' => {
10690 val = (1900i64 + (*tm).tm_year as i64) / 100;
10691 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10692 }
10693 b'e' => { def_pad = b'_'; }
10694 b'd' => {
10695 val = (*tm).tm_mday as i64;
10696 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10697 }
10698 b'D' => {
10699 fmt = b"%m/%d/%y\0".as_ptr() as *const c_char;
10700 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10701 return (buf.as_ptr(), l);
10702 }
10703 b'F' => {
10704 fmt = b"%Y-%m-%d\0".as_ptr() as *const c_char;
10705 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10706 return (buf.as_ptr(), l);
10707 }
10708 b'g' | b'G' => {
10709 val = (*tm).tm_year as i64 + 1900;
10710 if (*tm).tm_yday < 3 && week_num(&*tm) != 1 { val -= 1; }
10711 else if (*tm).tm_yday > 360 && week_num(&*tm) == 1 { val += 1; }
10712 if f == b'g' { val %= 100; }
10713 else { width = 4; }
10714 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10715 }
10716 b'H' => {
10717 val = (*tm).tm_hour as i64;
10718 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10719 }
10720 b'I' => {
10721 val = (*tm).tm_hour as i64;
10722 if val == 0 { val = 12; }
10723 else if val > 12 { val -= 12; }
10724 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10725 }
10726 b'j' => {
10727 val = (*tm).tm_yday as i64 + 1;
10728 width = 3;
10729 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10730 }
10731 b'm' => {
10732 val = (*tm).tm_mon as i64 + 1;
10733 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10734 }
10735 b'M' => {
10736 val = (*tm).tm_min as i64;
10737 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10738 }
10739 b'n' => { buf[0] = b'\n'; return (buf.as_ptr(), 1); }
10740 b'p' => {
10741 let p = if (*tm).tm_hour >= 12 { nl_langinfo(PM_STR_LI) } else { nl_langinfo(AM_STR_LI) };
10742 return str_to_buf(buf, p);
10743 }
10744 b'r' => {
10745 let p = nl_langinfo(T_FMT_AMPM);
10746 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10747 return (buf.as_ptr(), l);
10748 }
10749 b'R' => {
10750 fmt = b"%H:%M\0".as_ptr() as *const c_char;
10751 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10752 return (buf.as_ptr(), l);
10753 }
10754 b's' => {
10755 val = tm_to_secs(tm) - (*tm).tm_gmtoff as i64;
10756 width = 1;
10757 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10758 }
10759 b'S' => {
10760 val = (*tm).tm_sec as i64;
10761 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10762 }
10763 b't' => { buf[0] = b'\t'; return (buf.as_ptr(), 1); }
10764 b'T' => {
10765 fmt = b"%H:%M:%S\0".as_ptr() as *const c_char;
10766 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
10767 return (buf.as_ptr(), l);
10768 }
10769 b'u' => {
10770 val = if (*tm).tm_wday != 0 { (*tm).tm_wday as i64 } else { 7 };
10771 width = 1;
10772 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10773 }
10774 b'U' => {
10775 val = ((*tm).tm_yday as u64 + 7 - (*tm).tm_wday as u64) as i64 / 7;
10776 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10777 }
10778 b'W' => {
10779 val = ((*tm).tm_yday as u64 + 7 - ((*tm).tm_wday as u64 + 6) % 7) as i64 / 7;
10780 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10781 }
10782 b'V' => {
10783 val = week_num(&*tm) as i64;
10784 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10785 }
10786 b'w' => {
10787 val = (*tm).tm_wday as i64;
10788 width = 1;
10789 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10790 }
10791 b'x' => {
10792 let p = nl_langinfo(D_FMT);
10793 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10794 return (buf.as_ptr(), l);
10795 }
10796 b'X' => {
10797 let p = nl_langinfo(T_FMT);
10798 let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
10799 return (buf.as_ptr(), l);
10800 }
10801 b'y' => {
10802 val = (1900i64 + (*tm).tm_year as i64) % 100;
10803 if val < 0 { val = -val; }
10804 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10805 }
10806 b'Y' => {
10807 val = (*tm).tm_year as i64 + 1900;
10808 if val >= 10000 {
10809 let mut tmp = [0u8; 100];
10810 let (_, k) = num_fmt(&mut tmp, val, b'-', 1);
10811 buf[0] = b'+';
10812 for i in 0..k { buf[1 + i] = tmp[i]; }
10813 return (buf.as_ptr(), 1 + k);
10814 }
10815 width = 4;
10816 return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
10817 }
10818 b'z' => {
10819 if (*tm).tm_isdst < 0 { return (b"\0".as_ptr(), 0); }
10820 let gmtoff = (*tm).tm_gmtoff as i64;
10821 let sign = if gmtoff >= 0 { b'+' } else { b'-' };
10822 let off = if gmtoff < 0 { -gmtoff } else { gmtoff };
10823 let hh = (off / 3600) as i32;
10824 let mm = ((off % 3600) / 60) as i32;
10825 buf[0] = sign;
10826 buf[1] = b'0' + (hh / 10) as u8;
10827 buf[2] = b'0' + (hh % 10) as u8;
10828 buf[3] = b'0' + (mm / 10) as u8;
10829 buf[4] = b'0' + (mm % 10) as u8;
10830 return (buf.as_ptr(), 5);
10831 }
10832 b'Z' => {
10833 if (*tm).tm_isdst < 0 || (*tm).tm_zone.is_null() { return (b"\0".as_ptr(), 0); }
10834 return str_to_buf(buf, (*tm).tm_zone);
10835 }
10836 b'%' => { buf[0] = b'%'; return (buf.as_ptr(), 1); }
10837 _ => { return (core::ptr::null(), 0); }
10838 }
10839 val = (*tm).tm_mday as i64;
10841 num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width)
10842}
10843
10844unsafe fn __strftime_l(s: *mut c_char, n: usize, f: *const c_char, tm: *const tm) -> usize {
10845 let mut l: usize = 0;
10846 let mut fi: usize = 0;
10847 while l < n {
10848 let ch = *f.add(fi) as u8;
10849 if ch == 0 {
10850 *s.add(l) = 0;
10851 return l;
10852 }
10853 if ch != b'%' {
10854 *s.add(l) = ch as c_char;
10855 l += 1;
10856 fi += 1;
10857 continue;
10858 }
10859 fi += 1;
10860 let mut pad: u8 = 0;
10862 let fc = *f.add(fi) as u8;
10863 if fc == b'-' || fc == b'_' || fc == b'0' { pad = fc; fi += 1; }
10864 let plus = *f.add(fi) as u8 == b'+';
10865 if plus { fi += 1; }
10866 let mut width: usize = 0;
10868 let mut p_idx = fi;
10869 {
10870 let fc2 = *f.add(fi) as u8;
10871 if fc2 >= b'0' && fc2 <= b'9' {
10872 let mut w: usize = 0;
10873 while { let c = *f.add(p_idx) as u8; c >= b'0' && c <= b'9' } {
10874 w = w * 10 + (*f.add(p_idx) as usize - b'0' as usize);
10875 p_idx += 1;
10876 }
10877 width = w;
10878 }
10879 }
10880 let spec_ch = *f.add(p_idx) as u8;
10881 if spec_ch == b'C' || spec_ch == b'F' || spec_ch == b'G' || spec_ch == b'Y' {
10882 if width == 0 && p_idx != fi { width = 1; }
10883 } else {
10884 width = 0;
10885 }
10886 fi = p_idx;
10887 let fc3 = *f.add(fi) as u8;
10889 if fc3 == b'E' || fc3 == b'O' { fi += 1; }
10890 let fch = *f.add(fi) as u8;
10891 let mut buf = [0u8; 100];
10893 let (t, k) = __strftime_fmt_1(&mut buf, fch, tm, pad);
10894 if t.is_null() { break; }
10895 let mut k = k;
10896 let mut t = t;
10897 if width != 0 {
10898 if *t == b'+' || *t == b'-' { t = t.add(1); k -= 1; }
10900 while k > 0 && *t == b'0' && k > 1 && *t.add(1) >= b'0' && *t.add(1) <= b'9' {
10901 t = t.add(1); k -= 1;
10902 }
10903 if width < k { width = k; }
10904 let mut d: usize = 0;
10905 while d < k && *t.add(d) >= b'0' && *t.add(d) <= b'9' { d += 1; }
10906 if (*tm).tm_year < -1900 {
10907 if l < n { *s.add(l) = b'-' as c_char; }
10908 l += 1;
10909 width -= 1;
10910 } else if plus && d + (width - k) >= (if spec_ch == b'C' { 3 } else { 5 }) {
10911 if l < n { *s.add(l) = b'+' as c_char; }
10912 l += 1;
10913 width -= 1;
10914 }
10915 while width > k && l < n {
10916 *s.add(l) = b'0' as c_char;
10917 l += 1;
10918 width -= 1;
10919 }
10920 }
10921 let copy = if k > n - l { n - l } else { k };
10922 core::ptr::copy_nonoverlapping(t, s.add(l) as *mut u8, copy);
10923 l += copy;
10924 fi += 1;
10925 }
10926 if n > 0 {
10927 if l == n { l = n - 1; }
10928 *s.add(l) = 0;
10929 }
10930 0
10931}
10932
10933#[no_mangle]
10934pub unsafe extern "C" fn strftime(s: *mut c_char, maxsize: usize, fmt: *const c_char, tm: *const tm) -> usize {
10935 __strftime_l(s, maxsize, fmt, tm)
10936}
10937
10938unsafe fn match_prefix(s: *const u8, prefix: &[u8]) -> bool {
10943 for i in 0..prefix.len() {
10944 if *s.add(i) == 0 || *s.add(i) != prefix[i] { return false; }
10945 }
10946 true
10947}
10948
10949unsafe fn match_ci_prefix(s: *const u8, prefix: &[u8]) -> bool {
10950 for i in 0..prefix.len() {
10951 let c = *s.add(i);
10952 if c == 0 { return false; }
10953 if c.to_ascii_lowercase() != prefix[i].to_ascii_lowercase() { return false; }
10954 }
10955 true
10956}
10957
10958unsafe fn parse_int(p: *const u8, max_digits: usize) -> (i32, *const u8) {
10959 let mut val = 0i32;
10960 let mut np = p;
10961 let mut count = 0;
10962 while *np >= b'0' && *np <= b'9' && count < max_digits {
10963 val = val * 10 + (*np - b'0') as i32;
10964 np = np.add(1);
10965 count += 1;
10966 }
10967 if count == 0 { (0, p) } else { (val, np) }
10968}
10969
10970unsafe fn parse_range(p: *const u8, min: i32, max: i32) -> (i32, *const u8) {
10971 let (val, np) = parse_int(p, 4);
10972 if np == p || val < min || val > max { (0, p) } else { (val, np) }
10973}
10974
10975fn is_ascii_space(c: u8) -> bool {
10976 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0c || c == 0x0b
10977}
10978
10979#[no_mangle]
10980pub unsafe extern "C" fn strptime(s: *const c_char, fmt: *const c_char, tm: *mut tm) -> *mut c_char {
10981 let mut p = s as *const u8;
10982 let mut f = fmt as *const u8;
10983 let mut want_century = 0i32;
10984 let mut century = 0i32;
10985 let mut relyear = 0i32;
10986 while *f != 0 {
10987 if *f != b'%' {
10988 if is_ascii_space(*f) {
10989 while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
10990 } else {
10991 if *p != *f { return core::ptr::null_mut(); }
10992 p = p.add(1);
10993 }
10994 f = f.add(1);
10995 continue;
10996 }
10997 f = f.add(1);
10998 if *f == b'+' { f = f.add(1); }
10999 while *f >= b'0' && *f <= b'9' { f = f.add(1); }
11000 if *f == b'E' || *f == b'O' { f = f.add(1); }
11001 match *f {
11002 b'a' | b'A' => {
11003 let mut found = false;
11004 for i in 0..7 {
11005 let names: [&[u8]; 7] = [b"Sunday", b"Monday", b"Tuesday", b"Wednesday", b"Thursday", b"Friday", b"Saturday"];
11006 let snames: [&[u8]; 7] = [b"Sun", b"Mon", b"Tue", b"Wed", b"Thu", b"Fri", b"Sat"];
11007 if match_prefix(p, names[i]) { (*tm).tm_wday = i as c_int; p = p.add(names[i].len()); found = true; break; }
11008 if match_prefix(p, snames[i]) { (*tm).tm_wday = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11009 }
11010 if !found { return core::ptr::null_mut(); }
11011 }
11012 b'b' | b'B' | b'h' => {
11013 let mut found = false;
11014 for i in 0..12 {
11015 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"];
11016 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"];
11017 if match_prefix(p, names[i]) { (*tm).tm_mon = i as c_int; p = p.add(names[i].len()); found = true; break; }
11018 if match_prefix(p, snames[i]) { (*tm).tm_mon = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11019 }
11020 if !found { return core::ptr::null_mut(); }
11021 }
11022 b'C' => {
11023 let (v, np) = parse_int(p, 2);
11024 if np == p { return core::ptr::null_mut(); }
11025 century = v;
11026 want_century |= 2;
11027 p = np;
11028 }
11029 b'd' | b'e' => {
11030 let (v, np) = parse_range(p, 1, 31);
11031 if np == p { return core::ptr::null_mut(); }
11032 (*tm).tm_mday = v;
11033 p = np;
11034 }
11035 b'D' => {
11036 let r = strptime(p as *const c_char, b"%m/%d/%y\0".as_ptr() as *const c_char, tm);
11037 if r.is_null() { return core::ptr::null_mut(); }
11038 p = r as *const u8;
11039 }
11040 b'F' => {
11041 let (yv, ynp) = parse_int(p, 4);
11042 if ynp == p { return core::ptr::null_mut(); }
11043 (*tm).tm_year = yv - 1900;
11044 p = ynp;
11045 if *p != b'-' { return core::ptr::null_mut(); }
11046 p = p.add(1);
11047 let (mv, mnp) = parse_range(p, 1, 12);
11048 if mnp == p { return core::ptr::null_mut(); }
11049 (*tm).tm_mon = mv - 1;
11050 p = mnp;
11051 if *p != b'-' { return core::ptr::null_mut(); }
11052 p = p.add(1);
11053 let (dv, dnp) = parse_range(p, 1, 31);
11054 if dnp == p { return core::ptr::null_mut(); }
11055 (*tm).tm_mday = dv;
11056 p = dnp;
11057 }
11058 b'H' | b'I' => {
11059 let (v, np) = parse_range(p, 0, 23);
11060 if np == p { return core::ptr::null_mut(); }
11061 (*tm).tm_hour = v;
11062 p = np;
11063 }
11064 b'j' => {
11065 let (v, np) = parse_range(p, 1, 366);
11066 if np == p { return core::ptr::null_mut(); }
11067 (*tm).tm_yday = v - 1;
11068 p = np;
11069 }
11070 b'm' => {
11071 let (v, np) = parse_range(p, 1, 12);
11072 if np == p { return core::ptr::null_mut(); }
11073 (*tm).tm_mon = v - 1;
11074 p = np;
11075 }
11076 b'M' => {
11077 let (v, np) = parse_range(p, 0, 59);
11078 if np == p { return core::ptr::null_mut(); }
11079 (*tm).tm_min = v;
11080 p = np;
11081 }
11082 b'n' | b't' => {
11083 while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
11084 }
11085 b'p' => {
11086 if match_ci_prefix(p, b"AM") {
11087 if (*tm).tm_hour == 12 { (*tm).tm_hour = 0; }
11088 p = p.add(2);
11089 } else if match_ci_prefix(p, b"PM") {
11090 if (*tm).tm_hour < 12 { (*tm).tm_hour += 12; }
11091 p = p.add(2);
11092 } else { return core::ptr::null_mut(); }
11093 }
11094 b'r' => {
11095 let r = strptime(p as *const c_char, b"%I:%M:%S %p\0".as_ptr() as *const c_char, tm);
11096 if r.is_null() { return core::ptr::null_mut(); }
11097 p = r as *const u8;
11098 }
11099 b'R' => {
11100 let r = strptime(p as *const c_char, b"%H:%M\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's' => {
11105 let neg = if *p == b'-' { p = p.add(1); true } else { false };
11106 if *p < b'0' || *p > b'9' { return core::ptr::null_mut(); }
11107 let mut val = 0i64;
11108 while *p >= b'0' && *p <= b'9' {
11109 val = val * 10 + (*p - b'0') as i64;
11110 p = p.add(1);
11111 }
11112 if neg { val = -val; }
11113 secs_to_tm(val, &mut *tm);
11114 }
11115 b'S' => {
11116 let (v, np) = parse_range(p, 0, 60);
11117 if np == p { return core::ptr::null_mut(); }
11118 (*tm).tm_sec = v;
11119 p = np;
11120 }
11121 b'T' => {
11122 let r = strptime(p as *const c_char, b"%H:%M:%S\0".as_ptr() as *const c_char, tm);
11123 if r.is_null() { return core::ptr::null_mut(); }
11124 p = r as *const u8;
11125 }
11126 b'U' | b'W' => {
11127 let (_, np) = parse_range(p, 0, 53);
11128 if np == p { return core::ptr::null_mut(); }
11129 p = np;
11130 }
11131 b'V' => {
11132 let (_, np) = parse_range(p, 1, 53);
11133 if np == p { return core::ptr::null_mut(); }
11134 p = np;
11135 }
11136 b'w' => {
11137 let (v, np) = parse_range(p, 0, 6);
11138 if np == p { return core::ptr::null_mut(); }
11139 (*tm).tm_wday = v;
11140 p = np;
11141 }
11142 b'y' => {
11143 let (v, np) = parse_int(p, 2);
11144 if np == p { return core::ptr::null_mut(); }
11145 relyear = v;
11146 want_century |= 1;
11147 p = np;
11148 }
11149 b'Y' => {
11150 let neg = if *p == b'-' { p = p.add(1); true } else { false };
11151 let (v, np) = parse_int(p, 4);
11152 if np == p { return core::ptr::null_mut(); }
11153 (*tm).tm_year = if neg { -(v + 1900) } else { v - 1900 };
11154 want_century = 0;
11155 p = np;
11156 }
11157 b'z' => {
11158 if *p != b'+' && *p != b'-' { return core::ptr::null_mut(); }
11159 let neg = *p == b'-';
11160 p = p.add(1);
11161 let mut off = 0i64;
11162 let mut digits = 0;
11163 while digits < 4 && *p >= b'0' && *p <= b'9' {
11164 off = off * 10 + (*p - b'0') as i64;
11165 p = p.add(1);
11166 digits += 1;
11167 }
11168 if digits == 0 { return core::ptr::null_mut(); }
11169 let (hh, mm) = if digits <= 2 { (off, 0i64) } else { (off / 100, off % 100) };
11170 (*tm).tm_gmtoff = (hh * 3600 + mm * 60) * if neg { -1 } else { 1 };
11171 }
11172 b'%' => {
11173 if *p != b'%' { return core::ptr::null_mut(); }
11174 p = p.add(1);
11175 }
11176 _ => { return core::ptr::null_mut(); }
11177 }
11178 f = f.add(1);
11179 }
11180 if want_century != 0 {
11181 (*tm).tm_year = relyear;
11182 if want_century & 2 != 0 { (*tm).tm_year += century * 100 - 1900; }
11183 else if (*tm).tm_year <= 68 { (*tm).tm_year += 100; }
11184 }
11185 p as *mut c_char
11186}
11187
11188#[no_mangle]
11193pub static mut daylight: c_int = 0;
11194#[no_mangle]
11195pub static mut timezone: c_long = 0;
11196#[no_mangle]
11197pub 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];
11198
11199#[no_mangle]
11200pub unsafe extern "C" fn tzset() {
11201 daylight = 0;
11202 timezone = 0;
11203}
11204
11205#[no_mangle]
11210pub unsafe extern "C" fn system(cmd: *const c_char) -> c_int {
11211 if cmd.is_null() {
11212 let pid = sys_fork();
11214 if pid == 0 {
11215 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11216 let dash_c = b"-c\0".as_ptr() as *const c_char;
11217 let exit0 = b"exit 0\0".as_ptr() as *const c_char;
11218 let argv = [b"sh\0".as_ptr() as *const c_char, dash_c, exit0, core::ptr::null()];
11219 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11220 _exit(127);
11221 }
11222 if pid < 0 { return -1; }
11223 let mut status: c_int = 0;
11224 loop {
11225 let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11226 if r >= 0 { return status; }
11227 if r != -4 { return -1; } }
11229 }
11230
11231 let sa_ignore = sigaction {
11232 sa_handler: SIG_IGN,
11233 sa_flags: SA_RESTORER,
11234 sa_restorer: sig_restorer as *const () as usize,
11235 sa_mask: [0],
11236 };
11237 let mut oldint: sigaction = core::mem::zeroed();
11238 let mut oldquit: sigaction = core::mem::zeroed();
11239
11240 sys_rt_sigaction(SIGINT, &sa_ignore, &mut oldint, 8);
11241 sys_rt_sigaction(SIGQUIT, &sa_ignore, &mut oldquit, 8);
11242
11243 let mut block_set: SigSetT = 0;
11244 block_set |= 1u64 << (SIGCHLD - 1);
11245 let mut oldmask: SigSetT = 0;
11246 sys_rt_sigprocmask(SIG_BLOCK, &block_set, &mut oldmask, 8);
11247
11248 let pid = sys_fork();
11249
11250 if pid == 0 {
11251 sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11252 sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11253 sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11254
11255 let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11256 let argv = [
11257 b"sh\0".as_ptr() as *const c_char,
11258 b"-c\0".as_ptr() as *const c_char,
11259 cmd,
11260 core::ptr::null(),
11261 ];
11262 sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11263 _exit(127);
11264 }
11265
11266 let mut status: c_int = -1;
11267 if pid > 0 {
11268 loop {
11269 let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11270 if r >= 0 { break; }
11271 if r != -4 { break; } }
11273 }
11274
11275 sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11276 sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11277 sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11278
11279 status
11280}
11281
11282const EPERM_VAL: c_int = 1;
11287const ENOENT_VAL: c_int = 2;
11288const ESRCH_VAL: c_int = 3;
11289const EINTR_VAL: c_int = 4;
11290const EIO_VAL: c_int = 5;
11291const ENXIO_VAL: c_int = 6;
11292const E2BIG_VAL: c_int = 7;
11293const ENOEXEC_VAL: c_int = 8;
11294const EBADF_VAL: c_int = 9;
11295const ECHILD_VAL: c_int = 10;
11296const EAGAIN_VAL: c_int = 11;
11297const ENOMEM_VAL: c_int = 12;
11298const EACCES_VAL: c_int = 13;
11299const EFAULT_VAL: c_int = 14;
11300const ENOTBLK_VAL: c_int = 15;
11301const EBUSY_VAL: c_int = 16;
11302const EEXIST_VAL: c_int = 17;
11303const EXDEV_VAL: c_int = 18;
11304const ENODEV_VAL: c_int = 19;
11305const ENOTDIR_VAL: c_int = 20;
11306const EISDIR_VAL: c_int = 21;
11307const EINVAL_VAL: c_int = 22;
11308const ENFILE_VAL: c_int = 23;
11309const EMFILE_VAL: c_int = 24;
11310const ENOTTY_VAL: c_int = 25;
11311const ETXTBSY_VAL: c_int = 26;
11312const EFBIG_VAL: c_int = 27;
11313const ENOSPC_VAL: c_int = 28;
11314const ESPIPE_VAL: c_int = 29;
11315const EROFS_VAL: c_int = 30;
11316const EMLINK_VAL: c_int = 31;
11317const EPIPE_VAL: c_int = 32;
11318const EDOM_VAL: c_int = 33;
11319const ERANGE_VAL: c_int = 34;
11320const EDEADLK_VAL: c_int = 35;
11321const ENAMETOOLONG_VAL: c_int = 36;
11322const ENOLCK_VAL: c_int = 37;
11323const ENOSYS_VAL: c_int = 38;
11324const ENOTEMPTY_VAL: c_int = 39;
11325const ELOOP_VAL: c_int = 40;
11326const EWOULDBLOCK_VAL: c_int = 11;
11327const ENOMSG_VAL: c_int = 42;
11328const EIDRM_VAL: c_int = 43;
11329const ECHRNG_VAL: c_int = 44;
11330const EL2NSYNC_VAL: c_int = 45;
11331const EL3HLT_VAL: c_int = 46;
11332const EL3RST_VAL: c_int = 47;
11333const ELNRNG_VAL: c_int = 48;
11334const EUNATCH_VAL: c_int = 49;
11335const ENOCSI_VAL: c_int = 50;
11336const EL2HLT_VAL: c_int = 51;
11337const EBADE_VAL: c_int = 52;
11338const EBADR_VAL: c_int = 53;
11339const EXFULL_VAL: c_int = 54;
11340const ENOANO_VAL: c_int = 55;
11341const EBADRQC_VAL: c_int = 56;
11342const EBADSLT_VAL: c_int = 57;
11343const EBFONT_VAL: c_int = 59;
11344const ENOSTR_VAL: c_int = 60;
11345const ENODATA_VAL: c_int = 61;
11346const ETIME_VAL: c_int = 62;
11347const ENOSR_VAL: c_int = 63;
11348const ENONET_VAL: c_int = 64;
11349const ENOPKG_VAL: c_int = 65;
11350const EREMOTE_VAL: c_int = 66;
11351const ENOLINK_VAL: c_int = 67;
11352const EADV_VAL: c_int = 68;
11353const ESRMNT_VAL: c_int = 69;
11354const ECOMM_VAL: c_int = 70;
11355const EPROTO_VAL: c_int = 71;
11356const EMULTIHOP_VAL: c_int = 72;
11357const EDOTDOT_VAL: c_int = 73;
11358const EBADMSG_VAL: c_int = 74;
11359const EOVERFLOW_VAL: c_int = 75;
11360const ENOTUNIQ_VAL: c_int = 76;
11361const EBADFD_VAL: c_int = 77;
11362const EREMCHG_VAL: c_int = 78;
11363const ELIBACC_VAL: c_int = 79;
11364const ELIBBAD_VAL: c_int = 80;
11365const ELIBSCN_VAL: c_int = 81;
11366const ELIBMAX_VAL: c_int = 82;
11367const ELIBEXEC_VAL: c_int = 83;
11368const EILSEQ_VAL: c_int = 84;
11369const ERESTART_VAL: c_int = 85;
11370const ESTRPIPE_VAL: c_int = 86;
11371const EUSERS_VAL: c_int = 87;
11372const ENOTSOCK_VAL: c_int = 88;
11373const EDESTADDRREQ_VAL: c_int = 89;
11374const EMSGSIZE_VAL: c_int = 90;
11375const EPROTOTYPE_VAL: c_int = 91;
11376const ENOPROTOOPT_VAL: c_int = 92;
11377const EPROTONOSUPPORT_VAL: c_int = 93;
11378const ESOCKTNOSUPPORT_VAL: c_int = 94;
11379const EOPNOTSUPP_VAL: c_int = 95;
11380const ENOTSUP_VAL: c_int = 95;
11381const EPFNOSUPPORT_VAL: c_int = 96;
11382const EAFNOSUPPORT_VAL: c_int = 97;
11383const EADDRINUSE_VAL: c_int = 98;
11384const EADDRNOTAVAIL_VAL: c_int = 99;
11385const ENETDOWN_VAL: c_int = 100;
11386const ENETUNREACH_VAL: c_int = 101;
11387const ENETRESET_VAL: c_int = 102;
11388const ECONNABORTED_VAL: c_int = 103;
11389const ECONNRESET_VAL: c_int = 104;
11390const ENOBUFS_VAL: c_int = 105;
11391const EISCONN_VAL: c_int = 106;
11392const ENOTCONN_VAL: c_int = 107;
11393const ESHUTDOWN_VAL: c_int = 108;
11394const ETOOMANYREFS_VAL: c_int = 109;
11395const ETIMEDOUT_VAL: c_int = 110;
11396const ECONNREFUSED_VAL: c_int = 111;
11397const EHOSTDOWN_VAL: c_int = 112;
11398const EHOSTUNREACH_VAL: c_int = 113;
11399const EALREADY_VAL: c_int = 114;
11400const EINPROGRESS_VAL: c_int = 115;
11401const ESTALE_VAL: c_int = 116;
11402const EUCLEAN_VAL: c_int = 117;
11403const ENOTNAM_VAL: c_int = 118;
11404const ENAVAIL_VAL: c_int = 119;
11405const EISNAM_VAL: c_int = 120;
11406const EREMOTEIO_VAL: c_int = 121;
11407const EDQUOT_VAL: c_int = 122;
11408const ENOMEDIUM_VAL: c_int = 123;
11409const EMEDIUMTYPE_VAL: c_int = 124;
11410const ECANCELED_VAL: c_int = 125;
11411const ENOKEY_VAL: c_int = 126;
11412const EKEYEXPIRED_VAL: c_int = 127;
11413const EKEYREVOKED_VAL: c_int = 128;
11414const EKEYREJECTED_VAL: c_int = 129;
11415const EOWNERDEAD_VAL: c_int = 130;
11416const ENOTRECOVERABLE_VAL: c_int = 131;
11417const ERFKILL_VAL: c_int = 132;
11418const EHWPOISON_VAL: c_int = 133;
11419
11420static ERR_STRS: [&[u8]; 134] = [
11422 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", ];
11557
11558#[no_mangle]
11559pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
11560 if errnum < 0 || errnum as usize >= ERR_STRS.len() {
11561 static mut UNKNOWN_BUF: [c_char; 32] = [0; 32];
11563 let prefix = b"Unknown error \0";
11564 let mut i = 0;
11565 while prefix[i] != 0 {
11566 UNKNOWN_BUF[i] = prefix[i] as c_char;
11567 i += 1;
11568 }
11569 let (buf, len) = format_u64(errnum as u64);
11570 for j in 0..len {
11571 UNKNOWN_BUF[i] = buf[20 - len + j] as c_char;
11572 i += 1;
11573 }
11574 UNKNOWN_BUF[i] = 0;
11575 return core::ptr::addr_of_mut!(UNKNOWN_BUF).cast::<c_char>();
11576 }
11577 ERR_STRS[errnum as usize].as_ptr() as *mut c_char
11578}
11579
11580#[no_mangle]
11581pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: usize) -> c_int {
11582 let s = strerror(errnum);
11583 let slen = strlen(s as *const c_char);
11584 if slen >= buflen {
11585 if buflen > 0 {
11586 core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, buflen - 1);
11587 *buf.add(buflen - 1) = 0;
11588 }
11589 return 34; }
11591 core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, slen + 1);
11592 0
11593}
11594
11595#[no_mangle]
11597pub static mut environ: *mut *mut c_char = core::ptr::null_mut();
11598
11599unsafe fn sync_environ() {
11601 environ = __environ;
11602}
11603
11604#[inline]
11609unsafe fn sys_dup(oldfd: i32) -> i64 {
11610 <Arch as Syscalls>::syscall1(SYS_DUP, oldfd as i64)
11611}
11612
11613#[inline]unsafe fn sys_dup2(oldfd: i32, newfd: i32) -> i64 {
11614 sys_dup3(oldfd, newfd, 0)
11616}
11617
11618#[inline]
11619unsafe fn sys_access(path: *const u8, mode: i32) -> i64 {
11620 <Arch as Syscalls>::syscall4(SYS_FACCESSAT, AT_FDCWD as i64, path as i64, mode as i64, 0)
11621}
11622
11623#[inline]unsafe fn sys_unlink(path: *const u8) -> i64 {
11624 sys_unlinkat(AT_FDCWD, path, 0)
11625}
11626
11627#[inline]unsafe fn sys_rmdir(path: *const u8) -> i64 {
11628 sys_unlinkat(AT_FDCWD, path, 512) }
11630
11631#[inline]
11632unsafe fn sys_chdir(path: *const u8) -> i64 {
11633 <Arch as Syscalls>::syscall1(SYS_CHDIR, path as i64)
11634}
11635
11636#[inline]
11637unsafe fn sys_getcwd(buf: *mut u8, size: usize) -> i64 {
11638 <Arch as Syscalls>::syscall2(SYS_GETCWD, buf as i64, size as i64)
11639}
11640
11641#[inline]
11642unsafe fn sys_sethostname(name: *const u8, len: usize) -> i64 {
11643 <Arch as Syscalls>::syscall2(SYS_SETHOSTNAME, name as i64, len as i64)
11644}
11645
11646#[inline]
11647unsafe fn sys_gethostname(buf: *mut u8, len: usize) -> i64 {
11648 #[repr(C)]
11649 struct UtsName {
11650 sysname: [u8; 65],
11651 nodename: [u8; 65],
11652 release: [u8; 65],
11653 version: [u8; 65],
11654 machine: [u8; 65],
11655 domainname: [u8; 65],
11656 }
11657 let mut uts: UtsName = core::mem::zeroed();
11658 let result = <Arch as Syscalls>::syscall1(SYS_UNAME, &mut uts as *mut UtsName as i64);
11659 if result < 0 {
11660 return result;
11661 }
11662 let nlen = strlen(uts.nodename.as_ptr() as *const c_char);
11663 let copylen = if nlen < len { nlen } else { if len > 0 { len - 1 } else { 0 } };
11664 core::ptr::copy_nonoverlapping(uts.nodename.as_ptr(), buf, copylen);
11665 if len > 0 { *buf.add(copylen) = 0; }
11666 0
11667}
11668
11669unsafe fn sys_truncate(path: *const u8, length: i64) -> i64 {
11670 <Arch as Syscalls>::syscall2(SYS_TRUNCATE, path as i64, length as i64)
11671}
11672
11673unsafe fn sys_ftruncate(fd: i32, length: i64) -> i64 {
11674 <Arch as Syscalls>::syscall2(SYS_FTRUNCATE, fd as i64, length as i64)
11675}
11676
11677unsafe fn sys_nanosleep(req: *const timespec, rem: *mut timespec) -> i64 {
11678 <Arch as Syscalls>::syscall2(SYS_NANOSLEEP, req as i64, rem as i64)
11679}
11680
11681const ITIMER_REAL: i32 = 0;
11682
11683#[repr(C)]
11684struct itimerval {
11685 it_interval: timeval,
11686 it_value: timeval,
11687}
11688
11689unsafe fn sys_alarm(seconds: c_uint) -> i64 {
11690 let mut new: itimerval = core::mem::zeroed();
11691 new.it_value.tv_sec = seconds as c_long;
11692 let mut old: itimerval = core::mem::zeroed();
11693 let r = <Arch as Syscalls>::syscall3(
11694 SYS_SETITIMER,
11695 ITIMER_REAL as i64,
11696 &new as *const _ as i64,
11697 &mut old as *mut _ as i64,
11698 );
11699 if r < 0 {
11700 return r;
11701 }
11702 old.it_value.tv_sec as i64
11703}
11704
11705unsafe fn sys_pause() -> i64 {
11706 #[cfg(target_arch = "x86_64")]
11707 { <Arch as Syscalls>::syscall0(SYS_PAUSE) }
11708 #[cfg(target_arch = "aarch64")]
11709 { <Arch as Syscalls>::syscall4(SYS_PPOLL, 0, 0, 0, 0) }
11710}
11711
11712unsafe fn sys_fsync(fd: i32) -> i64 {
11713 <Arch as Syscalls>::syscall1(SYS_FSYNC, fd as i64)
11714}
11715
11716unsafe fn sys_fdatasync(fd: i32) -> i64 {
11717 <Arch as Syscalls>::syscall1(SYS_FDATASYNC, fd as i64)
11718}
11719
11720unsafe fn sys_sync() {
11721 let _ = <Arch as Syscalls>::syscall0(SYS_SYNC);
11722}
11723
11724unsafe fn sys_symlink(target: *const u8, linkpath: *const u8) -> i64 {
11725 <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, AT_FDCWD as i64, linkpath as i64)
11726}
11727
11728unsafe fn sys_symlinkat(target: *const u8, newdirfd: i32, linkpath: *const u8) -> i64 {
11729 <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, newdirfd as i64, linkpath as i64)
11730}
11731
11732unsafe fn sys_readlinkat(dirfd: i32, path: *const u8, buf: *mut u8, bufsiz: usize) -> i64 {
11733 <Arch as Syscalls>::syscall4(SYS_READLINKAT, dirfd as i64, path as i64, buf as i64, bufsiz as i64)
11734}
11735
11736unsafe fn sys_linkat(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: i32) -> i64 {
11737 <Arch as Syscalls>::syscall5(SYS_LINKAT, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
11738}
11739
11740unsafe fn sys_fchmod(fd: i32, mode: u32) -> i64 {
11741 <Arch as Syscalls>::syscall2(SYS_FCHMOD, fd as i64, mode as i64)
11742}
11743
11744unsafe fn sys_fchmodat(dirfd: i32, path: *const u8, mode: u32, flags: i32) -> i64 {
11745 <Arch as Syscalls>::syscall4(SYS_FCHMODAT, dirfd as i64, path as i64, mode as i64, flags as i64)
11746}
11747
11748unsafe fn sys_umask(mask: u32) -> u32 {
11749 <Arch as Syscalls>::syscall1(SYS_UMASK, mask as i64) as u32
11750}
11751
11752unsafe fn sys_getgroups(size: i32, list: *mut c_uint) -> i64 {
11753 <Arch as Syscalls>::syscall2(SYS_GETGROUPS, size as i64, list as i64)
11754}
11755
11756unsafe fn sys_setuid(uid: c_uint) -> i64 {
11757 <Arch as Syscalls>::syscall1(SYS_SETUID, uid as i64)
11758}
11759
11760unsafe fn sys_setgid(gid: c_uint) -> i64 {
11761 <Arch as Syscalls>::syscall1(SYS_SETGID, gid as i64)
11762}
11763
11764unsafe fn sys_setsid() -> i64 {
11765 <Arch as Syscalls>::syscall0(SYS_SETSID)
11766}
11767
11768unsafe fn sys_setpgid(pid: c_int, pgid: c_int) -> i64 {
11769 <Arch as Syscalls>::syscall2(SYS_SETPGID, pid as i64, pgid as i64)
11770}
11771
11772unsafe fn sys_getpgid(pid: c_int) -> i64 {
11773 <Arch as Syscalls>::syscall1(SYS_GETPGID, pid as i64)
11774}
11775
11776unsafe fn sys_getsid(pid: c_int) -> i64 {
11777 <Arch as Syscalls>::syscall1(SYS_GETSID, pid as i64)
11778}
11779
11780unsafe fn sys_mkdirat(dirfd: i32, path: *const u8, mode: u32) -> i64 {
11781 <Arch as Syscalls>::syscall3(SYS_MKDIRAT, dirfd as i64, path as i64, mode as i64)
11782}
11783
11784#[no_mangle]
11787pub unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int {
11788 let r = sys_pipe2(fds, 0);
11789 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11790 0
11791}
11792
11793#[no_mangle]
11794pub unsafe extern "C" fn pipe2(fds: *mut c_int, flags: c_int) -> c_int {
11795 let r = sys_pipe2(fds, flags);
11796 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11797 0
11798}
11799
11800#[no_mangle]
11801pub unsafe extern "C" fn dup(oldfd: c_int) -> c_int {
11802 let r = sys_dup(oldfd);
11803 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11804 r as c_int
11805}
11806
11807#[no_mangle]
11808pub unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> c_int {
11809 let r = sys_dup2(oldfd, newfd);
11810 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11811 r as c_int
11812}
11813
11814#[no_mangle]
11815pub unsafe extern "C" fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int {
11816 let r = sys_dup3(oldfd, newfd, flags);
11817 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11818 r as c_int
11819}
11820
11821#[no_mangle]
11822pub unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, mut args: ...) -> c_int {
11823 let r = match cmd {
11824 F_GETFD | F_GETFL => sys_fcntl(fd, cmd, 0),
11825 F_SETFD | F_SETFL | F_DUPFD | F_DUPFD_CLOEXEC => {
11826 let arg = args.next_arg::<c_int>();
11827 sys_fcntl(fd, cmd, arg as i64)
11828 }
11829 F_GETLK | F_SETLK | F_SETLKW => {
11830 let arg = args.next_arg::<*mut c_void>();
11831 sys_fcntl(fd, cmd, arg as i64)
11832 }
11833 _ => sys_fcntl(fd, cmd, 0),
11834 };
11835 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11836 r as c_int
11837}
11838
11839#[no_mangle]
11840pub unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int {
11841 let r = sys_access(path as *const u8, mode);
11842 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11843 0
11844}
11845
11846#[no_mangle]
11847pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
11848 let r = sys_unlink(path as *const u8);
11849 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11850 0
11851}
11852
11853#[no_mangle]
11854pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int {
11855 let r = sys_rmdir(path as *const u8);
11856 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11857 0
11858}
11859
11860#[no_mangle]
11861pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int {
11862 let r = sys_chdir(path as *const u8);
11863 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11864 0
11865}
11866
11867#[no_mangle]
11868pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
11869 if buf.is_null() {
11870 let alloc_size = if size == 0 { 256 } else { size };
11872 let p = malloc(alloc_size) as *mut c_char;
11873 if p.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
11874 let r = sys_getcwd(p as *mut u8, alloc_size);
11875 if r < 0 { free(p as *mut c_void); ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
11876 return p;
11877 }
11878 if size == 0 { ERRNO = EINVAL; return core::ptr::null_mut(); }
11879 let r = sys_getcwd(buf as *mut u8, size);
11880 if r < 0 { ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
11881 buf
11882}
11883
11884#[no_mangle]
11885pub unsafe extern "C" fn gethostname(name: *mut c_char, len: usize) -> c_int {
11886 let r = sys_gethostname(name as *mut u8, len);
11887 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11888 0
11889}
11890
11891#[no_mangle]
11893pub extern "C" fn getpagesize() -> c_int {
11894 4096
11895}
11896
11897#[no_mangle]
11898pub unsafe extern "C" fn truncate(path: *const c_char, length: i64) -> c_int {
11899 let r = sys_truncate(path as *const u8, length);
11900 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11901 0
11902}
11903
11904#[no_mangle]
11905pub unsafe extern "C" fn ftruncate(fd: c_int, length: i64) -> c_int {
11906 let r = sys_ftruncate(fd, length);
11907 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11908 0
11909}
11910
11911#[no_mangle]
11912pub unsafe extern "C" fn nanosleep(req: *const timespec, rem: *mut timespec) -> c_int {
11913 pthread_testcancel();
11914 let r = sys_nanosleep(req, rem);
11915 pthread_testcancel();
11916 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11917 0
11918}
11919
11920#[no_mangle]
11921pub unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
11922 let req = timespec { tv_sec: seconds as c_long, tv_nsec: 0 };
11923 let mut rem: timespec = core::mem::zeroed();
11924 pthread_testcancel();
11925 let r = sys_nanosleep(&req, &mut rem);
11926 pthread_testcancel();
11927 if r < 0 {
11928 let e = (-r) as c_int;
11929 if e == EINTR { return rem.tv_sec as c_uint; }
11930 }
11931 0
11932}
11933
11934#[no_mangle]
11935pub unsafe extern "C" fn usleep(usec: c_uint) -> c_int {
11936 let req = timespec { tv_sec: (usec / 1000000) as c_long, tv_nsec: ((usec % 1000000) * 1000) as c_long };
11937 pthread_testcancel();
11938 let r = sys_nanosleep(&req, core::ptr::null_mut());
11939 pthread_testcancel();
11940 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11941 0
11942}
11943
11944#[no_mangle]
11945pub unsafe extern "C" fn alarm(seconds: c_uint) -> c_uint {
11946 sys_alarm(seconds) as c_uint
11947}
11948
11949#[no_mangle]
11950pub unsafe extern "C" fn pause() -> c_int {
11951 pthread_testcancel();
11952 sys_pause();
11953 pthread_testcancel();
11954 ERRNO = EINTR;
11955 -1
11956}
11957
11958#[no_mangle]
11959pub unsafe extern "C" fn fsync(fd: c_int) -> c_int {
11960 let r = sys_fsync(fd);
11961 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11962 0
11963}
11964
11965#[no_mangle]
11966pub unsafe extern "C" fn fdatasync(fd: c_int) -> c_int {
11967 let r = sys_fdatasync(fd);
11968 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11969 0
11970}
11971
11972#[no_mangle]
11973pub unsafe extern "C" fn sync() {
11974 sys_sync();
11975}
11976
11977#[no_mangle]
11978pub unsafe extern "C" fn symlink(target: *const c_char, linkpath: *const c_char) -> c_int {
11979 let r = sys_symlinkat(target as *const u8, AT_FDCWD, linkpath as *const u8);
11980 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11981 0
11982}
11983
11984#[no_mangle]
11985pub unsafe extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsiz: usize) -> isize {
11986 let r = sys_readlinkat(AT_FDCWD, path as *const u8, buf as *mut u8, bufsiz);
11987 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11988 r as isize
11989}
11990
11991#[no_mangle]
11992pub unsafe extern "C" fn link(oldpath: *const c_char, newpath: *const c_char) -> c_int {
11993 let r = sys_linkat(AT_FDCWD, oldpath as *const u8, AT_FDCWD, newpath as *const u8, 0);
11994 if r < 0 { ERRNO = (-r) as c_int; return -1; }
11995 0
11996}
11997
11998#[no_mangle]
11999pub unsafe extern "C" fn chmod(path: *const c_char, mode: c_uint) -> c_int {
12000 let r = sys_fchmodat(AT_FDCWD, path as *const u8, mode, 0);
12001 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12002 0
12003}
12004
12005#[no_mangle]
12006pub unsafe extern "C" fn fchmod(fd: c_int, mode: c_uint) -> c_int {
12007 let r = sys_fchmod(fd, mode);
12008 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12009 0
12010}
12011
12012#[no_mangle]
12013pub unsafe extern "C" fn umask(mask: c_uint) -> c_uint {
12014 sys_umask(mask) as c_uint
12015}
12016
12017#[no_mangle]
12018pub unsafe extern "C" fn isatty(fd: c_int) -> c_int {
12019 let mut ws: winsize = core::mem::zeroed();
12020 if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 { 1 } else { 0 }
12021}
12022
12023#[no_mangle]
12025pub unsafe extern "C" fn ttyname(_fd: c_int) -> *mut c_char {
12026 core::ptr::null_mut()
12027}
12028
12029#[no_mangle]
12031pub unsafe extern "C" fn getlogin() -> *mut c_char {
12032 b"root\0".as_ptr() as *mut c_char
12033}
12034
12035#[no_mangle]
12036pub unsafe extern "C" fn getgroups(size: c_int, list: *mut c_uint) -> c_int {
12037 let r = sys_getgroups(size, list);
12038 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12039 r as c_int
12040}
12041
12042#[no_mangle]
12043pub unsafe extern "C" fn setuid(uid: c_uint) -> c_int {
12044 let r = sys_setuid(uid);
12045 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12046 0
12047}
12048
12049#[no_mangle]
12050pub unsafe extern "C" fn setgid(gid: c_uint) -> c_int {
12051 let r = sys_setgid(gid);
12052 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12053 0
12054}
12055
12056#[no_mangle]
12057pub unsafe extern "C" fn seteuid(euid: c_uint) -> c_int {
12058 let r = sys_setuid(euid);
12060 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12061 0
12062}
12063
12064#[no_mangle]
12065pub unsafe extern "C" fn setegid(egid: c_uint) -> c_int {
12066 let r = sys_setgid(egid);
12067 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12068 0
12069}
12070
12071#[no_mangle]
12072pub unsafe extern "C" fn setreuid(_ruid: c_uint, _euid: c_uint) -> c_int {
12073 0
12075}
12076
12077#[no_mangle]
12078pub unsafe extern "C" fn setregid(_rgid: c_uint, _egid: c_uint) -> c_int {
12079 0
12080}
12081
12082#[no_mangle]
12083pub unsafe extern "C" fn setsid() -> c_int {
12084 let r = sys_setsid();
12085 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12086 r as c_int
12087}
12088
12089#[no_mangle]
12090pub unsafe extern "C" fn setpgid(pid: c_int, pgid: c_int) -> c_int {
12091 let r = sys_setpgid(pid, pgid);
12092 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12093 0
12094}
12095
12096#[no_mangle]
12097pub unsafe extern "C" fn getpgid(pid: c_int) -> c_int {
12098 let r = sys_getpgid(pid);
12099 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12100 r as c_int
12101}
12102
12103#[no_mangle]
12104pub unsafe extern "C" fn getsid(pid: c_int) -> c_int {
12105 let r = sys_getsid(pid);
12106 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12107 r as c_int
12108}
12109
12110#[no_mangle]
12111pub unsafe extern "C" fn getpgrp() -> c_int {
12112 sys_getpgid(0) as c_int
12113}
12114
12115#[no_mangle]
12116pub unsafe extern "C" fn setpgrp() -> c_int {
12117 setpgid(0, 0)
12118}
12119
12120#[no_mangle]
12121pub unsafe extern "C" fn mkstemp(template: *mut c_char) -> c_int {
12122 if template.is_null() { ERRNO = EINVAL; return -1; }
12123 let len = strlen(template as *const c_char);
12124 if len < 6 { ERRNO = EINVAL; return -1; }
12125 let x_start = len - 6;
12126 for i in x_start..len {
12128 if *template.add(i) != b'X' as c_char { ERRNO = EINVAL; return -1; }
12129 }
12130 let mut ts: timespec = core::mem::zeroed();
12131 let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
12132 let mut ctr: u32 = ts.tv_nsec as u32;
12133 for _ in 0..100 {
12134 ctr = ctr.wrapping_mul(1103515245).wrapping_add(12345);
12135 let seed = ctr;
12136 let hex = b"0123456789abcdef";
12138 let mut s = seed;
12139 for i in x_start..len {
12140 *template.add(i) = hex[(s & 0xf) as usize] as c_char;
12141 s >>= 4;
12142 }
12143 let fd = sys_open(template as *const u8, (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
12144 if fd >= 0 { return fd as c_int; }
12145 let e = (-fd) as c_int;
12146 if e != EEXIST_VAL { ERRNO = e; return -1; }
12147 }
12148 ERRNO = EEXIST_VAL;
12149 -1
12150}
12151
12152#[no_mangle]
12153pub unsafe extern "C" fn mkdir(path: *const c_char, mode: c_uint) -> c_int {
12154 let r = sys_mkdirat(AT_FDCWD, path as *const u8, mode);
12155 if r < 0 { ERRNO = (-r) as c_int; return -1; }
12156 0
12157}
12158
12159#[no_mangle]
12164pub unsafe extern "C" fn dirname(s: *mut c_char) -> *mut c_char {
12165 if s.is_null() || *s == 0 {
12166 return b".\0".as_ptr() as *mut c_char;
12167 }
12168 let mut i = strlen(s as *const c_char);
12169 i = i.wrapping_sub(1);
12170 while i > 0 && *s.add(i) == b'/' as c_char {
12172 i = i.wrapping_sub(1);
12173 }
12174 if i == 0 && *s.add(0) == b'/' as c_char {
12175 return b"/\0".as_ptr() as *mut c_char;
12176 }
12177 while i > 0 && *s.add(i) != b'/' as c_char {
12179 i = i.wrapping_sub(1);
12180 }
12181 if i == 0 {
12182 if *s.add(0) == b'/' as c_char {
12183 return b"/\0".as_ptr() as *mut c_char;
12184 }
12185 return b".\0".as_ptr() as *mut c_char;
12186 }
12187 while i > 0 && *s.add(i - 1) == b'/' as c_char {
12189 i = i.wrapping_sub(1);
12190 }
12191 if i == 0 {
12192 return b"/\0".as_ptr() as *mut c_char;
12193 }
12194 *s.add(i) = 0;
12195 s
12196}
12197
12198#[no_mangle]
12199pub unsafe extern "C" fn basename(s: *mut c_char) -> *mut c_char {
12200 if s.is_null() || *s == 0 {
12201 return b".\0".as_ptr() as *mut c_char;
12202 }
12203 let mut i = strlen(s as *const c_char);
12204 i = i.wrapping_sub(1);
12205 while i > 0 && *s.add(i) == b'/' as c_char {
12207 *s.add(i) = 0;
12208 i = i.wrapping_sub(1);
12209 }
12210 while i > 0 && *s.add(i - 1) != b'/' as c_char {
12212 i = i.wrapping_sub(1);
12213 }
12214 s.add(i)
12215}
12216
12217const AF_INET_VAL: c_int = 2;
12222const AF_INET6_VAL: c_int = 10;
12223const EAFNOSUPPORT: c_int = 97;
12224const ENOSPC_VAL2: c_int = 28;
12225
12226unsafe fn inet_pton_v4(s: *const u8, a: *mut u8) -> c_int {
12227 let mut p = s;
12228 let mut i = 0;
12229 while i < 4 {
12230 let oct_start = p;
12231 let mut v: u32 = 0;
12232 let mut j: u32 = 0;
12233 while j < 3 && *p >= b'0' && *p <= b'9' {
12234 v = v * 10 + (*p - b'0') as u32;
12235 p = p.add(1);
12236 j += 1;
12237 }
12238 if j == 0 || (j > 1 && *oct_start == b'0') || v > 255 { return 0; }
12239 *a.add(i) = v as u8;
12240 if *p == 0 && i == 3 { return 1; }
12241 if *p != b'.' { return 0; }
12242 p = p.add(1);
12243 i += 1;
12244 }
12245 0
12246}
12247
12248unsafe fn inet_pton_v6(s: *const u8, a: *mut u8) -> c_int {
12249 let mut ip = [0u16; 8];
12250 let mut p = s;
12251 let mut i: usize = 0;
12252 let mut brk: isize = -1;
12253 let mut need_v4 = false;
12254 let mut v4_start: *const u8 = core::ptr::null();
12255
12256 if *p == b':' {
12257 p = p.add(1);
12258 if *p != b':' { return 0; }
12259 }
12260
12261 loop {
12262 if *p == b':' && brk < 0 {
12263 brk = i as isize;
12264 ip[i & 7] = 0;
12265 p = p.add(1);
12266 if *p == 0 { break; }
12267 if i == 7 { return 0; }
12268 i += 1;
12269 continue;
12270 }
12271 v4_start = p;
12272 let mut v: u16 = 0;
12273 let mut j = 0;
12274 while j < 4 {
12275 let d = hex_digit(*p);
12276 if d < 0 { break; }
12277 v = v * 16 + d as u16;
12278 p = p.add(1);
12279 j += 1;
12280 }
12281 if j == 0 { return 0; }
12282 ip[i & 7] = v;
12283 if *p == 0 && (brk >= 0 || i == 7) { break; }
12284 if i == 7 { return 0; }
12285 if *p != b':' {
12286 if *p != b'.' || (i < 6 && brk < 0) { return 0; }
12287 need_v4 = true;
12288 i += 1;
12289 ip[i & 7] = 0;
12290 break;
12291 }
12292 p = p.add(1);
12293 i += 1;
12294 }
12295
12296 if brk >= 0 {
12297 let trail_count = i + 1 - brk as usize;
12299 let dest_start = brk as usize + 7 - i;
12300 for j in (0..trail_count).rev() {
12302 ip[dest_start + j] = ip[brk as usize + j];
12303 }
12304 for j in 0..(7 - i) {
12305 ip[brk as usize + j] = 0;
12306 }
12307 }
12308
12309 for k in 0..8 {
12310 *a.add(k * 2) = (ip[k] >> 8) as u8;
12311 *a.add(k * 2 + 1) = (ip[k] & 0xff) as u8;
12312 }
12313
12314 if need_v4 {
12315 if inet_pton_v4(v4_start, a.add(12)) <= 0 { return 0; }
12316 }
12317 1
12318}
12319
12320unsafe fn hex_digit(c: u8) -> i32 {
12321 if c >= b'0' && c <= b'9' { (c - b'0') as i32 }
12322 else if c >= b'a' && c <= b'f' { (c - b'a' + 10) as i32 }
12323 else if c >= b'A' && c <= b'F' { (c - b'A' + 10) as i32 }
12324 else { -1 }
12325}
12326
12327#[no_mangle]
12328pub unsafe extern "C" fn inet_pton(af: c_int, s: *const c_char, a: *mut c_void) -> c_int {
12329 if af == AF_INET_VAL {
12330 inet_pton_v4(s as *const u8, a as *mut u8)
12331 } else if af == AF_INET6_VAL {
12332 inet_pton_v6(s as *const u8, a as *mut u8)
12333 } else {
12334 ERRNO = EAFNOSUPPORT;
12335 -1
12336 }
12337}
12338
12339#[no_mangle]
12340pub unsafe extern "C" fn inet_ntop(af: c_int, a: *const c_void, s: *mut c_char, size: u32) -> *mut c_char {
12341 if af == AF_INET_VAL {
12342 let b = a as *const u8;
12343 let needed = 16; if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
12345 let mut pos = 0;
12346 for i in 0..4 {
12347 if i > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
12348 let (buf, len) = format_u64(*b.add(i) as u64);
12349 for j in 0..len { *s.add(pos) = buf[j] as c_char; pos += 1; }
12350 }
12351 *s.add(pos) = 0;
12352 s
12353 } else if af == AF_INET6_VAL {
12354 let b = a as *const u8;
12355 let needed = 46; if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
12357 let mut words = [0u16; 8];
12358 for i in 0..8 {
12359 words[i] = ((*b.add(i * 2) as u16) << 8) | (*b.add(i * 2 + 1) as u16);
12360 }
12361 let mut pos = 0usize;
12363 if words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0
12364 && words[4] == 0 && words[5] == 0xffff
12365 {
12366 let prefix = b"::ffff:";
12367 for k in 0..prefix.len() { *s.add(pos) = prefix[k] as c_char; pos += 1; }
12368 for idx in 0..4 {
12369 if idx > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
12370 let octet = *b.add(12 + idx);
12371 if octet >= 100 {
12372 *s.add(pos) = (b'0' + octet / 100) as c_char; pos += 1;
12373 *s.add(pos) = (b'0' + (octet / 10) % 10) as c_char; pos += 1;
12374 } else if octet >= 10 {
12375 *s.add(pos) = (b'0' + octet / 10) as c_char; pos += 1;
12376 }
12377 *s.add(pos) = (b'0' + octet % 10) as c_char; pos += 1;
12378 }
12379 *s.add(pos) = 0;
12380 return s;
12381 }
12382 let mut best_start: isize = -1;
12384 let mut best_len: usize = 0;
12385 let mut j: usize = 0;
12386 while j < 8 {
12387 if words[j] == 0 {
12388 let mut k = j;
12389 while k < 8 && words[k] == 0 { k += 1; }
12390 let run = k - j;
12391 if run > best_len { best_start = j as isize; best_len = run; }
12392 j = k;
12393 } else {
12394 j += 1;
12395 }
12396 }
12397 let mut i: usize = 0;
12398 let mut prev_in_run = false;
12399 while i < 8 {
12400 let in_run = best_len >= 2 && i >= best_start as usize && i < best_start as usize + best_len;
12401 if in_run {
12402 if i == best_start as usize {
12403 *s.add(pos) = b':' as c_char; pos += 1;
12404 *s.add(pos) = b':' as c_char; pos += 1;
12405 }
12406 i += 1;
12407 prev_in_run = true;
12408 continue;
12409 }
12410 if i > 0 && !prev_in_run {
12411 *s.add(pos) = b':' as c_char; pos += 1;
12412 }
12413 let (buf, len) = format_hex(words[i] as u64, false);
12414 for k in 0..len { *s.add(pos) = buf[k] as c_char; pos += 1; }
12415 i += 1;
12416 prev_in_run = false;
12417 }
12418 *s.add(pos) = 0;
12419 s
12420 } else {
12421 ERRNO = EAFNOSUPPORT;
12422 core::ptr::null_mut()
12423 }
12424}
12425
12426#[no_mangle]
12427pub unsafe extern "C" fn inet_aton(s: *const c_char, dest: *mut c_void) -> c_int {
12428 let a = dest as *mut u8;
12429 let mut p = s as *const u8;
12430 let mut vals = [0u64; 4];
12431 let mut i = 0usize;
12432 while i < 4 {
12433 if *p < b'0' || *p > b'9' { return 0; }
12434 let mut base = 10u32;
12435 if *p == b'0' {
12436 let c = *p.add(1);
12437 if c == b'x' || c == b'X' {
12438 base = 16;
12439 p = p.add(2);
12440 if !((*p >= b'0' && *p <= b'9')
12441 || (*p >= b'a' && *p <= b'f')
12442 || (*p >= b'A' && *p <= b'F')) {
12443 return 0;
12444 }
12445 } else {
12446 base = 8;
12447 }
12448 }
12449 let mut v: u64 = 0;
12450 let start = p;
12451 loop {
12452 let c = *p;
12453 let d = if c >= b'0' && c <= b'9' {
12454 (c - b'0') as u64
12455 } else if base == 16 && c >= b'a' && c <= b'f' {
12456 (c - b'a' + 10) as u64
12457 } else if base == 16 && c >= b'A' && c <= b'F' {
12458 (c - b'A' + 10) as u64
12459 } else {
12460 break;
12461 };
12462 v = v * (base as u64) + d;
12463 p = p.add(1);
12464 }
12465 if p == start { return 0; }
12466 vals[i] = v;
12467 if *p == 0 {
12468 break;
12469 }
12470 if *p != b'.' || i == 3 { return 0; }
12471 p = p.add(1);
12472 i += 1;
12473 }
12474 if i == 4 { return 0; }
12475 if i < 1 { vals[1] = vals[0] & 0xffffff; vals[0] >>= 24; }
12476 if i < 2 { vals[2] = vals[1] & 0xffff; vals[1] >>= 16; }
12477 if i < 3 { vals[3] = vals[2] & 0xff; vals[2] >>= 8; }
12478 for j in 0..4 {
12479 if vals[j] > 255 { return 0; }
12480 *a.add(j) = vals[j] as u8;
12481 }
12482 1
12483}
12484
12485#[no_mangle]
12486pub unsafe extern "C" fn inet_addr(s: *const c_char) -> u32 {
12487 let mut a = [0u8; 4];
12488 if inet_aton(s, a.as_mut_ptr() as *mut c_void) == 1 {
12489 u32::from_ne_bytes(a)
12490 } else {
12491 !0u32 }
12493}
12494
12495#[no_mangle]
12496pub unsafe extern "C" fn inet_ntoa(addr: u32) -> *mut c_char {
12497 static mut NTOA_BUF: [c_char; 16] = [0; 16];
12498 let b = addr.to_ne_bytes();
12499 let mut pos = 0;
12500 for i in 0..4 {
12501 if i > 0 { NTOA_BUF[pos] = b'.' as c_char; pos += 1; }
12502 let (buf, len) = format_u64(b[i] as u64);
12503 for j in 0..len { NTOA_BUF[pos] = buf[j] as c_char; pos += 1; }
12504 }
12505 NTOA_BUF[pos] = 0;
12506 core::ptr::addr_of_mut!(NTOA_BUF).cast::<c_char>()
12507}
12508
12509#[no_mangle]
12511pub unsafe extern "C" fn inet_network(s: *const c_char) -> u32 {
12512 inet_addr(s).to_be()
12513}
12514
12515#[no_mangle]
12516pub extern "C" fn inet_makeaddr(net: c_int, host: c_int) -> u32 {
12517 let addr: u32;
12518 if (net as u32) < 128 {
12519 addr = (net as u32) << 24;
12520 } else if (net as u32) < 0x10000 {
12521 addr = (net as u32) << 16;
12522 } else if (net as u32) < 0x1000000 {
12523 addr = (net as u32) << 8;
12524 } else {
12525 addr = net as u32;
12526 }
12527 addr | (host as u32 & 0xffffffff)
12528}
12529
12530#[no_mangle]
12531pub extern "C" fn inet_lnaof(addr: u32) -> c_int {
12532 let h = u32::from_be(addr);
12533 if h < 0x80000000 { (h & 0x00ffffff) as c_int }
12534 else if h < 0xc0000000 { (h & 0x0000ffff) as c_int }
12535 else { (h & 0x000000ff) as c_int }
12536}
12537
12538#[no_mangle]
12539pub extern "C" fn inet_netof(addr: u32) -> c_int {
12540 let h = u32::from_be(addr);
12541 if h < 0x80000000 { (h >> 24) as c_int }
12542 else if h < 0xc0000000 { (h >> 16) as c_int }
12543 else { (h >> 8) as c_int }
12544}
12545
12546unsafe fn parse_float(s: *const u8, endptr: *mut *mut u8, is_f32: bool) -> f64 {
12555 let mut p = s;
12556 while *p == b' ' || *p == b'\t' || *p == b'\n' || *p == b'\r' { p = p.add(1); }
12558 let mut neg = false;
12559 if *p == b'-' { neg = true; p = p.add(1); }
12560 else if *p == b'+' { p = p.add(1); }
12561
12562 if (*p | 0x20) == b'i'
12564 && (*p.add(1) | 0x20) == b'n'
12565 && (*p.add(2) | 0x20) == b'f'
12566 {
12567 p = p.add(3);
12568 if (*p | 0x20) == b'i'
12570 && (*p.add(1) | 0x20) == b't'
12571 && (*p.add(2) | 0x20) == b'y'
12572 {
12573 p = p.add(3);
12574 }
12575 if !endptr.is_null() { *endptr = p as *mut u8; }
12576 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12577 }
12578 if (*p | 0x20) == b'n'
12580 && (*p.add(1) | 0x20) == b'a'
12581 && (*p.add(2) | 0x20) == b'n'
12582 {
12583 p = p.add(3);
12584 if *p == b'(' {
12586 p = p.add(1);
12587 while *p != 0 && *p != b')' { p = p.add(1); }
12588 if *p == b')' { p = p.add(1); }
12589 }
12590 if !endptr.is_null() { *endptr = p as *mut u8; }
12591 return if neg { -f64::NAN } else { f64::NAN };
12592 }
12593
12594 if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') {
12596 p = p.add(2);
12597 let mut mant: u128 = 0;
12598 let mut frac_hex: u32 = 0;
12599 let mut found = false;
12600 let mut in_frac = false;
12601
12602 loop {
12603 if let Some(d) = hex_val(*p) {
12604 if mant <= u128::MAX / 16 {
12605 mant = mant * 16 + d as u128;
12606 }
12607 if in_frac { frac_hex += 1; }
12608 p = p.add(1);
12609 found = true;
12610 } else if *p == b'.' && !in_frac {
12611 in_frac = true;
12612 p = p.add(1);
12613 } else {
12614 break;
12615 }
12616 }
12617
12618 if !found {
12619 if !endptr.is_null() { *endptr = s as *mut u8; }
12620 return 0.0;
12621 }
12622
12623 let mut bin_exp: i32 = 0;
12625 if *p == b'p' || *p == b'P' {
12626 p = p.add(1);
12627 let mut exp_neg = false;
12628 if *p == b'-' { exp_neg = true; p = p.add(1); }
12629 else if *p == b'+' { p = p.add(1); }
12630 while *p >= b'0' && *p <= b'9' {
12631 if bin_exp < 100000 {
12632 bin_exp = bin_exp * 10 + (*p - b'0') as i32;
12633 }
12634 p = p.add(1);
12635 }
12636 if exp_neg { bin_exp = -bin_exp; }
12637 }
12638
12639 if !endptr.is_null() { *endptr = p as *mut u8; }
12640 if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
12641
12642 let total_exp = bin_exp as i64 - 4 * frac_hex as i64;
12643 return hex_mant_to_f64(mant, total_exp, neg);
12644 }
12645
12646 let mut buf = [0u8; 65536];
12648 let mut n = 0usize;
12649 let mut found_digit = false;
12650
12651 while *p >= b'0' && *p <= b'9' {
12652 if n < 65535 { buf[n] = *p; n += 1; }
12653 p = p.add(1);
12654 found_digit = true;
12655 }
12656 if *p == b'.' {
12657 if n < 65535 { buf[n] = b'.'; n += 1; }
12658 p = p.add(1);
12659 while *p >= b'0' && *p <= b'9' {
12660 if n < 65535 { buf[n] = *p; n += 1; }
12661 p = p.add(1);
12662 found_digit = true;
12663 }
12664 }
12665 if !found_digit {
12666 if !endptr.is_null() { *endptr = s as *mut u8; }
12667 return 0.0;
12668 }
12669 if *p == b'e' || *p == b'E' {
12670 if n < 65535 { buf[n] = b'e'; n += 1; }
12671 p = p.add(1);
12672 if *p == b'-' || *p == b'+' {
12673 if n < 65535 { buf[n] = *p; n += 1; }
12674 p = p.add(1);
12675 }
12676 while *p >= b'0' && *p <= b'9' {
12677 if n < 65535 { buf[n] = *p; n += 1; }
12678 p = p.add(1);
12679 }
12680 }
12681
12682 if !endptr.is_null() { *endptr = p as *mut u8; }
12683 let s_str = core::str::from_utf8_unchecked(
12684 core::slice::from_raw_parts(buf.as_ptr(), n),
12685 );
12686 if is_f32 {
12687 match <f32 as core::str::FromStr>::from_str(s_str) {
12688 Ok(v) => { let r = v as f64; if neg { -r } else { r } }
12689 Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
12690 }
12691 } else {
12692 match <f64 as core::str::FromStr>::from_str(s_str) {
12693 Ok(v) => if neg { -v } else { v },
12694 Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
12695 }
12696 }
12697}
12698
12699fn hex_mant_to_f64(mant: u128, total_exp: i64, neg: bool) -> f64 {
12703 if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
12704
12705 let msb = (127 - mant.leading_zeros()) as i64;
12706 let unbiased_exp = msb + total_exp;
12707 let biased_exp = unbiased_exp + 1023;
12708
12709 if biased_exp >= 2047 {
12711 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12712 }
12713
12714 if biased_exp <= 0 {
12716 let shift = total_exp + 1074;
12719 if shift < 0 {
12720 return if neg { -0.0 } else { 0.0 };
12721 }
12722 if shift > 128 {
12723 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12724 }
12725 let shifted = mant << (shift as u32);
12726 let mantissa52 = (shifted as u64) & 0x000FFFFFFFFFFFFF;
12727 let guard = ((shifted >> 52) & 1) != 0;
12728 let sticky = (shifted >> 53) != 0;
12729 let mut result = mantissa52;
12730 if guard && (sticky || (result & 1) != 0) {
12731 result += 1;
12732 if result > 0x000FFFFFFFFFFFFF {
12733 return if neg { -f64::from_bits(1u64 << 52) } else { f64::from_bits(1u64 << 52) };
12735 }
12736 }
12737 return if neg { -f64::from_bits(result) } else { f64::from_bits(result) };
12738 }
12739
12740 let shift = msb - 52;
12742
12743 if shift <= 0 {
12744 let mantissa = ((mant as u64) & ((1u64 << msb as u32) - 1)) << ((-shift) as u32);
12746 let bits = ((biased_exp as u64) << 52) | mantissa;
12747 return if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) };
12748 }
12749
12750 let mantissa = ((mant >> shift as u32) as u64) & 0x000FFFFFFFFFFFFF;
12752 let guard = ((mant >> (shift as u32 - 1)) & 1) != 0;
12753 let sticky = if shift > 1 {
12754 (mant & ((1u128 << (shift as u32 - 1)) - 1)) != 0
12755 } else { false };
12756
12757 let mut result_mant = mantissa;
12758 let mut result_exp = biased_exp;
12759 if guard && (sticky || (result_mant & 1) != 0) {
12760 result_mant += 1;
12761 if result_mant > 0x000FFFFFFFFFFFFF {
12762 result_mant = 0;
12763 result_exp += 1;
12764 if result_exp >= 2047 {
12765 return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
12766 }
12767 }
12768 }
12769
12770 let bits = ((result_exp as u64) << 52) | result_mant;
12771 if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) }
12772}
12773
12774unsafe fn hex_val(c: u8) -> Option<u8> {
12775 if c >= b'0' && c <= b'9' { Some(c - b'0') }
12776 else if c >= b'a' && c <= b'f' { Some(c - b'a' + 10) }
12777 else if c >= b'A' && c <= b'F' { Some(c - b'A' + 10) }
12778 else { None }
12779}
12780
12781#[no_mangle]
12782pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
12783 let mut end: *mut u8 = s as *mut u8;
12784 let r = parse_float(s as *const u8, &mut end, false);
12785 if !endptr.is_null() { *endptr = end as *mut c_char; }
12786 r
12787}
12788
12789#[no_mangle]
12790pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> f32 {
12791 let mut end: *mut u8 = s as *mut u8;
12792 let r = parse_float(s as *const u8, &mut end, true);
12793 if !endptr.is_null() { *endptr = end as *mut c_char; }
12794 r as f32
12795}
12796
12797#[no_mangle]
12798pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
12799 strtod(s, endptr)
12801}
12802
12803#[no_mangle]
12804pub unsafe extern "C" fn atof(s: *const c_char) -> f64 {
12805 strtod(s, core::ptr::null_mut())
12806}
12807
12808#[repr(C)]
12813struct MsCookie {
12814 bufp: *mut *mut c_char,
12815 sizep: *mut usize,
12816 pos: usize,
12817 len: usize,
12818 buf: *mut u8,
12819 space: usize,
12820}
12821
12822#[repr(C)]
12823struct MfCookie {
12824 pos: usize,
12825 len: usize,
12826 size: usize,
12827 buf: *mut u8,
12828 mode: c_char,
12829}
12830
12831unsafe extern "C" fn ms_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
12832 let c = (*f).cookie as *mut MsCookie;
12833 if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
12834 let base: i64 = match whence {
12835 0 => 0,
12836 1 => (*c).pos as i64,
12837 2 => (*c).len as i64,
12838 _ => { ERRNO = EINVAL; return -1; }
12839 };
12840 if off < -base || off > isize::MAX as i64 - base { ERRNO = EINVAL; return -1; }
12841 (*c).pos = (base + off) as usize;
12842 (*c).pos as i64
12843}
12844
12845unsafe extern "C" fn ms_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
12846 let c = (*f).cookie as *mut MsCookie;
12847 let buffered = (*f).wpos as usize - (*f).wbase as usize;
12848 if buffered > 0 {
12849 (*f).wpos = (*f).wbase;
12850 if ms_write(f, (*f).wbase, buffered) < buffered { return 0; }
12851 }
12852 if len == 0 { return 0; }
12853 if (*c).pos + len >= (*c).space {
12854 let new_space = 2 * (*c).space + 1 | (*c).pos + len + 1;
12855 let newbuf = realloc((*c).buf as *mut c_void, new_space) as *mut u8;
12856 if newbuf.is_null() { return 0; }
12857 *(*c).bufp = newbuf as *mut c_char;
12858 core::ptr::write_bytes(newbuf.add((*c).space), 0, new_space - (*c).space);
12859 (*c).buf = newbuf;
12860 (*c).space = new_space;
12861 }
12862 core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), len);
12863 (*c).pos += len;
12864 if (*c).pos >= (*c).len { (*c).len = (*c).pos; }
12865 *(*c).sizep = (*c).pos;
12866 len
12867}
12868
12869unsafe extern "C" fn ms_close(_f: *mut FILE) -> c_int {
12870 0
12871}
12872
12873#[no_mangle]
12874pub unsafe extern "C" fn open_memstream(bufp: *mut *mut c_char, sizep: *mut usize) -> *mut FILE {
12875 if bufp.is_null() || sizep.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
12876 let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
12877 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
12878 let buf_area = buf_ptr(f);
12879 init_file(f, -1, b"w\0".as_ptr() as *const c_char, Some(ms_close), buf_area, BUFSIZ);
12880 (*f).flags = F_NORD | F_SVB;
12881 (*f).lbf = -1;
12882 let c = calloc(1, core::mem::size_of::<MsCookie>()) as *mut MsCookie;
12883 if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
12884 (*c).bufp = bufp;
12885 (*c).sizep = sizep;
12886 (*c).pos = 0;
12887 (*c).len = 0;
12888 (*c).buf = core::ptr::null_mut();
12889 (*c).space = 0;
12890 (*f).cookie = c as *mut c_void;
12891 (*f).write_fn = Some(ms_write);
12892 (*f).seek_fn = Some(ms_seek);
12893 *bufp = core::ptr::null_mut();
12894 *sizep = 0;
12895 f
12896}
12897
12898unsafe extern "C" fn mseek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
12899 let c = (*f).cookie as *mut MfCookie;
12900 if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
12901 let base: i64 = match whence {
12902 0 => 0,
12903 1 => (*c).pos as i64,
12904 2 => (*c).len as i64,
12905 _ => { ERRNO = EINVAL; return -1; }
12906 };
12907 if off < -base || off > (*c).size as i64 - base { ERRNO = EINVAL; return -1; }
12908 (*c).pos = (base + off) as usize;
12909 (*c).pos as i64
12910}
12911
12912unsafe extern "C" fn mread(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
12913 let c = (*f).cookie as *mut MfCookie;
12914 let mut rem = if (*c).pos <= (*c).len { (*c).len - (*c).pos } else { 0 };
12915 let mut l = len;
12916 if l > rem {
12917 l = rem;
12918 (*f).flags |= F_EOF;
12919 }
12920 core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), buf, l);
12921 (*c).pos += l;
12922 rem -= l;
12923 if rem > (*f).buf_size { rem = (*f).buf_size; }
12924 (*f).rpos = (*f).buf;
12925 (*f).rend = (*f).buf.add(rem);
12926 core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), (*f).rpos, rem);
12927 (*c).pos += rem;
12928 l
12929}
12930
12931unsafe extern "C" fn mwrite(f: *mut FILE, buf: *const u8, len: usize) -> usize {
12932 let c = (*f).cookie as *mut MfCookie;
12933 let buffered = (*f).wpos as usize - (*f).wbase as usize;
12934 if buffered > 0 {
12935 (*f).wpos = (*f).wbase;
12936 if mwrite(f, (*f).wbase, buffered) < buffered { return 0; }
12937 }
12938 if len == 0 { return 0; }
12939 if (*c).mode == b'a' as c_char { (*c).pos = (*c).len; }
12940 let rem = (*c).size - (*c).pos;
12941 let mut l = len;
12942 if l > rem { l = rem; }
12943 core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), l);
12944 (*c).pos += l;
12945 if (*c).pos > (*c).len {
12946 (*c).len = (*c).pos;
12947 if (*c).len < (*c).size {
12948 *(*c).buf.add((*c).len) = 0;
12949 } else if ((*f).flags & F_NORD) != 0 && (*c).size > 0 {
12950 *(*c).buf.add((*c).size - 1) = 0;
12951 }
12952 }
12953 l
12954}
12955
12956unsafe extern "C" fn mclose(_f: *mut FILE) -> c_int {
12957 0
12958}
12959
12960#[no_mangle]
12961pub unsafe extern "C" fn fmemopen(buf: *mut c_void, size: usize, mode: *const c_char) -> *mut FILE {
12962 if mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
12963 let m = *mode;
12964 if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
12965 ERRNO = EINVAL; return core::ptr::null_mut();
12966 }
12967 let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
12968 let need_alloc = buf.is_null();
12969 let alloc_size = core::mem::size_of::<FILE>() + UNGET + BUFSIZ + if need_alloc { size } else { 0 };
12970 let f = calloc(1, alloc_size) as *mut FILE;
12971 if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
12972 let buf_area = buf_ptr(f);
12973 init_file(f, -1, mode, Some(mclose), buf_area, BUFSIZ);
12974 (*f).flags |= F_SVB;
12975 let actual_buf: *mut u8 = if need_alloc {
12976 (f as *mut u8).add(alloc_size - size)
12977 } else {
12978 buf as *mut u8
12979 };
12980 if need_alloc { core::ptr::write_bytes(actual_buf, 0, size); }
12981 let c = calloc(1, core::mem::size_of::<MfCookie>()) as *mut MfCookie;
12982 if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
12983 (*c).buf = actual_buf;
12984 (*c).size = size;
12985 (*c).mode = m;
12986 (*f).cookie = c as *mut c_void;
12987 (*f).read_fn = Some(mread);
12988 (*f).write_fn = Some(mwrite);
12989 (*f).seek_fn = Some(mseek);
12990 if !has_plus { (*f).flags = if m == b'r' as c_char { F_NOWR } else { F_NORD }; }
12991 if m == b'r' as c_char {
12992 (*c).len = size;
12993 } else if m == b'a' as c_char {
12994 (*c).len = strnlen(actual_buf, size);
12995 (*c).pos = (*c).len;
12996 } else if has_plus {
12997 *actual_buf = 0;
12998 }
12999 f
13000}
13001
13002#[repr(C)]
13007struct kernel_stat64 {
13008 st_dev: u64,
13009 st_ino: u64,
13010 st_nlink: u64,
13011 st_mode: u32,
13012 st_uid: u32,
13013 st_gid: u32,
13014 __pad0: c_int,
13015 st_rdev: u64,
13016 st_size: i64,
13017 st_blksize: i64,
13018 st_blocks: i64,
13019 st_atime: i64,
13020 st_atime_nsec: i64,
13021 st_mtime: i64,
13022 st_mtime_nsec: i64,
13023 st_ctime: i64,
13024 st_ctime_nsec: i64,
13025 __unused: [i64; 3],
13026}
13027
13028#[inline]
13030unsafe fn sys_stat(path: *const u8, statbuf: *mut kernel_stat64) -> i64 {
13031 <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, AT_FDCWD as i64, path as i64, statbuf as i64, 0)
13032}
13033
13034const HSEARCH_MINSIZE: usize = 8;
13039
13040#[repr(C)]
13041#[derive(Copy, Clone)]
13042pub struct HSearchEntry {
13043 key: *mut c_char,
13044 data: *mut c_void,
13045}
13046
13047#[repr(C)]
13048struct HTab {
13049 entries: *mut HSearchEntry,
13050 mask: usize,
13051 used: usize,
13052}
13053
13054#[repr(C)]
13055pub struct HSearchData {
13056 tab: *mut HTab,
13057 __unused1: c_uint,
13058 __unused2: c_uint,
13059}
13060
13061static mut HTAB_DATA: HSearchData = HSearchData {
13063 tab: core::ptr::null_mut(),
13064 __unused1: 0,
13065 __unused2: 0,
13066};
13067
13068unsafe fn keyhash(k: *const c_char) -> usize {
13069 let mut h: usize = 0;
13070 let mut p = k;
13071 while *p != 0 {
13072 h = h.wrapping_mul(31).wrapping_add(*p as usize);
13073 p = p.add(1);
13074 }
13075 h
13076}
13077
13078unsafe fn htab_lookup(key: *const c_char, hash: usize, htab: *mut HSearchData) -> *mut HSearchEntry {
13079 let tab = (*htab).tab;
13080 let mask = (*tab).mask;
13081 let entries = (*tab).entries;
13082 let mut i = hash;
13083 let mut j: usize = 1;
13084 loop {
13085 let e = entries.add(i & mask);
13086 if (*e).key.is_null() || strcmp((*e).key as *const u8, key as *const u8) == 0 {
13087 return e;
13088 }
13089 i = i.wrapping_add(j);
13090 j += 1;
13091 }
13092}
13093
13094unsafe fn htab_resize(nel: usize, htab: *mut HSearchData) -> c_int {
13095 let tab = (*htab).tab;
13096 let old_entries = (*tab).entries;
13097 let old_size = (*tab).mask + 1;
13098
13099 let mut newsize: usize = HSEARCH_MINSIZE;
13100 while newsize < nel {
13101 let Some(next) = newsize.checked_mul(2) else {
13102 ERRNO = ENOMEM;
13103 return 0;
13104 };
13105 newsize = next;
13106 }
13107
13108 let new_entries = calloc(newsize, core::mem::size_of::<HSearchEntry>()) as *mut HSearchEntry;
13109 if new_entries.is_null() {
13110 ERRNO = ENOMEM;
13111 return 0;
13112 }
13113 (*tab).entries = new_entries;
13114 (*tab).mask = newsize - 1;
13115
13116 if !old_entries.is_null() {
13117 for idx in 0..old_size {
13118 let old_e = old_entries.add(idx);
13119 if !(*old_e).key.is_null() {
13120 let h = keyhash((*old_e).key);
13121 let mut i = h;
13122 let mut j: usize = 1;
13123 loop {
13124 let e = new_entries.add(i & (*tab).mask);
13125 if (*e).key.is_null() {
13126 *e = *old_e;
13127 break;
13128 }
13129 i = i.wrapping_add(j);
13130 j += 1;
13131 }
13132 }
13133 }
13134 free(old_entries as *mut c_void);
13135 }
13136 1
13137}
13138
13139unsafe fn hcreate_r_impl(nel: usize, htab: *mut HSearchData) -> c_int {
13140 if nel == 0 || nel > (1usize << 30) {
13141 ERRNO = ENOMEM;
13142 return 0;
13143 }
13144 (*htab).tab = calloc(1, core::mem::size_of::<HTab>()) as *mut HTab;
13145 if (*htab).tab.is_null() {
13146 ERRNO = ENOMEM;
13147 return 0;
13148 }
13149 if htab_resize(nel, htab) == 0 {
13150 free((*htab).tab as *mut c_void);
13151 (*htab).tab = core::ptr::null_mut();
13152 return 0;
13153 }
13154 1
13155}
13156
13157unsafe fn hdestroy_r_impl(htab: *mut HSearchData) {
13158 if !(*htab).tab.is_null() {
13159 if !(*(*htab).tab).entries.is_null() {
13160 free((*(*htab).tab).entries as *mut c_void);
13161 }
13162 free((*htab).tab as *mut c_void);
13163 (*htab).tab = core::ptr::null_mut();
13164 }
13165}
13166
13167unsafe fn hsearch_r_impl(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13168 let hash = keyhash(item.key);
13169 let e = htab_lookup(item.key, hash, htab);
13170
13171 if !(*e).key.is_null() {
13172 *retval = e;
13173 return 1;
13174 }
13175 if action == 0 { *retval = core::ptr::null_mut();
13177 return 0;
13178 }
13179 let item_key = item.key;
13181 *e = item;
13182 (*(*htab).tab).used += 1;
13183 if (*(*htab).tab).used > (*(*htab).tab).mask - (*(*htab).tab).mask / 4 {
13184 if htab_resize(2 * (*(*htab).tab).used, htab) == 0 {
13185 (*(*htab).tab).used -= 1;
13186 (*e).key = core::ptr::null_mut();
13187 *retval = core::ptr::null_mut();
13188 return 0;
13189 }
13190 let e2 = htab_lookup(item_key, hash, htab);
13191 *retval = e2;
13192 return 1;
13193 }
13194 *retval = e;
13195 1
13196}
13197
13198#[no_mangle]
13199pub unsafe extern "C" fn hcreate(nel: usize) -> c_int {
13200 hcreate_r_impl(nel, core::ptr::addr_of_mut!(HTAB_DATA))
13201}
13202
13203#[no_mangle]
13204pub unsafe extern "C" fn hdestroy() {
13205 hdestroy_r_impl(core::ptr::addr_of_mut!(HTAB_DATA));
13206}
13207
13208#[no_mangle]
13209pub unsafe extern "C" fn hsearch(item: HSearchEntry, action: c_int) -> *mut HSearchEntry {
13210 let mut e: *mut HSearchEntry = core::ptr::null_mut();
13211 hsearch_r_impl(item, action, &mut e, core::ptr::addr_of_mut!(HTAB_DATA));
13212 e
13213}
13214
13215#[no_mangle]
13216pub unsafe extern "C" fn hcreate_r(nel: usize, htab: *mut HSearchData) -> c_int {
13217 hcreate_r_impl(nel, htab)
13218}
13219
13220#[no_mangle]
13221pub unsafe extern "C" fn hdestroy_r(htab: *mut HSearchData) {
13222 hdestroy_r_impl(htab);
13223}
13224
13225#[no_mangle]
13226pub unsafe extern "C" fn hsearch_r(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13227 hsearch_r_impl(item, action, retval, htab)
13228}
13229
13230#[repr(C)]
13235struct QueNode {
13236 next: *mut QueNode,
13237 prev: *mut QueNode,
13238}
13239
13240#[no_mangle]
13241pub unsafe extern "C" fn insque(element: *mut c_void, pred: *mut c_void) {
13242 let e = element as *mut QueNode;
13243 let p = pred as *mut QueNode;
13244 if p.is_null() {
13245 (*e).next = core::ptr::null_mut();
13246 (*e).prev = core::ptr::null_mut();
13247 return;
13248 }
13249 (*e).next = (*p).next;
13250 (*e).prev = p;
13251 (*p).next = e;
13252 if !(*e).next.is_null() {
13253 (*(*e).next).prev = e;
13254 }
13255}
13256
13257#[no_mangle]
13258pub unsafe extern "C" fn remque(element: *mut c_void) {
13259 let e = element as *mut QueNode;
13260 if !(*e).next.is_null() {
13261 (*(*e).next).prev = (*e).prev;
13262 }
13263 if !(*e).prev.is_null() {
13264 (*(*e).prev).next = (*e).next;
13265 }
13266}
13267
13268#[no_mangle]
13273pub unsafe extern "C" fn lsearch(
13274 key: *const c_void,
13275 base: *mut c_void,
13276 nelp: *mut usize,
13277 width: usize,
13278 compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
13279) -> *mut c_void {
13280 let n = *nelp;
13281 let p = base as *mut u8;
13282 for i in 0..n {
13283 let elem = p.add(i * width);
13284 if compar.unwrap()(key, elem as *const c_void) == 0 {
13285 return elem as *mut c_void;
13286 }
13287 }
13288 let dest = p.add(n * width);
13289 memcpy(dest as *mut c_void, key as *const c_void, width);
13290 *nelp = n + 1;
13291 dest as *mut c_void
13292}
13293
13294#[no_mangle]
13295pub unsafe extern "C" fn lfind(
13296 key: *const c_void,
13297 base: *const c_void,
13298 nelp: *mut usize,
13299 width: usize,
13300 compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
13301) -> *mut c_void {
13302 let n = *nelp;
13303 let p = base as *const u8;
13304 for i in 0..n {
13305 let elem = p.add(i * width);
13306 if compar.unwrap()(key, elem as *const c_void) == 0 {
13307 return elem as *mut c_void;
13308 }
13309 }
13310 core::ptr::null_mut()
13311}
13312
13313#[repr(C)]
13319pub struct TreeNode {
13320 key: *const c_void,
13321 left: *mut TreeNode,
13322 right: *mut TreeNode,
13323}
13324
13325type ComparFn = Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>;
13326
13327unsafe fn bst_new(key: *const c_void) -> *mut TreeNode {
13328 let n = calloc(1, core::mem::size_of::<TreeNode>()) as *mut TreeNode;
13329 if !n.is_null() {
13330 (*n).key = key;
13331 (*n).left = core::ptr::null_mut();
13332 (*n).right = core::ptr::null_mut();
13333 }
13334 n
13335}
13336
13337#[no_mangle]
13338pub unsafe extern "C" fn tsearch(
13339 key: *const c_void,
13340 rootp: *mut *mut TreeNode,
13341 compar: ComparFn,
13342) -> *mut c_void {
13343 if rootp.is_null() {
13344 return core::ptr::null_mut();
13345 }
13346 let mut pp = rootp;
13347 loop {
13348 let n = *pp;
13349 if n.is_null() {
13350 let r = bst_new(key);
13351 if r.is_null() {
13352 return core::ptr::null_mut();
13353 }
13354 *pp = r;
13355 return r as *mut c_void;
13356 }
13357 let c = compar.unwrap()(key, (*n).key);
13358 if c == 0 {
13359 return n as *mut c_void;
13360 }
13361 if c < 0 {
13362 pp = &mut (*n).left;
13363 } else {
13364 pp = &mut (*n).right;
13365 }
13366 }
13367}
13368
13369#[no_mangle]
13370pub unsafe extern "C" fn tfind(
13371 key: *const c_void,
13372 rootp: *const *mut TreeNode,
13373 compar: ComparFn,
13374) -> *mut c_void {
13375 if rootp.is_null() {
13376 return core::ptr::null_mut();
13377 }
13378 let mut n = *rootp;
13379 loop {
13380 if n.is_null() {
13381 return core::ptr::null_mut();
13382 }
13383 let c = compar.unwrap()(key, (*n).key);
13384 if c == 0 {
13385 return n as *mut c_void;
13386 }
13387 if c < 0 {
13388 n = (*n).left;
13389 } else {
13390 n = (*n).right;
13391 }
13392 }
13393}
13394
13395#[no_mangle]
13396pub unsafe extern "C" fn tdelete(
13397 key: *const c_void,
13398 rootp: *mut *mut TreeNode,
13399 compar: ComparFn,
13400) -> *mut c_void {
13401 if rootp.is_null() {
13402 return core::ptr::null_mut();
13403 }
13404 let mut pp = rootp;
13405 loop {
13406 let n = *pp;
13407 if n.is_null() {
13408 return core::ptr::null_mut();
13409 }
13410 let c = compar.unwrap()(key, (*n).key);
13411 if c == 0 {
13412 break;
13413 }
13414 if c < 0 {
13415 pp = &mut (*n).left;
13416 } else {
13417 pp = &mut (*n).right;
13418 }
13419 }
13420 let n = *pp;
13421 let parent = *rootp;
13423 if !(*n).left.is_null() {
13424 let mut q = &mut (*n).left;
13426 while !(*(*q)).right.is_null() {
13427 q = &mut (*(*q)).right;
13428 }
13429 let pred = *q;
13430 (*n).key = (*pred).key;
13432 *q = (*pred).left;
13434 free(pred as *mut c_void);
13435 } else {
13436 *pp = (*n).right;
13438 free(n as *mut c_void);
13439 }
13440 parent as *mut c_void
13441}
13442
13443#[no_mangle]
13444pub unsafe extern "C" fn twalk(
13445 root: *const TreeNode,
13446 action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
13447) {
13448 unsafe fn walk(
13449 node: *const TreeNode,
13450 action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
13451 depth: c_int,
13452 ) {
13453 if node.is_null() {
13454 return;
13455 }
13456 let is_leaf = (*node).left.is_null() && (*node).right.is_null();
13457 if is_leaf {
13458 action.unwrap()(node as *const c_void, 3, depth); } else {
13460 action.unwrap()(node as *const c_void, 0, depth); walk((*node).left, action, depth + 1);
13462 action.unwrap()(node as *const c_void, 1, depth); walk((*node).right, action, depth + 1);
13464 action.unwrap()(node as *const c_void, 2, depth); }
13466 }
13467 walk(root, action, 0);
13468}
13469
13470#[no_mangle]
13471pub unsafe extern "C" fn tdestroy(root: *mut TreeNode, freekey: Option<unsafe extern "C" fn(*mut c_void)>) {
13472 if root.is_null() {
13473 return;
13474 }
13475 tdestroy((*root).left, freekey);
13476 tdestroy((*root).right, freekey);
13477 if let Some(f) = freekey {
13478 f((*root).key as *mut c_void);
13479 }
13480 free(root as *mut c_void);
13481}
13482
13483const FNM_PATHNAME: c_int = 0x1;
13488const FNM_NOESCAPE: c_int = 0x2;
13489const FNM_PERIOD: c_int = 0x4;
13490const FNM_LEADING_DIR: c_int = 0x8;
13491const FNM_CASEFOLD: c_int = 0x10;
13492const FNM_NOMATCH: c_int = 1;
13493
13494const FNM_END: c_int = 0;
13495const FNM_STAR: c_int = -5;
13496const FNM_QUESTION: c_int = -4;
13497const FNM_BRACKET: c_int = -3;
13498const FNM_UNMATCHABLE: c_int = -2;
13499
13500fn ascii_tolower(c: u8) -> u8 {
13501 if c >= b'A' && c <= b'Z' { c + 32 } else { c }
13502}
13503
13504fn ascii_toupper(c: u8) -> u8 {
13505 if c >= b'a' && c <= b'z' { c - 32 } else { c }
13506}
13507
13508fn ascii_casefold(k: u8) -> u8 {
13509 let upper = ascii_toupper(k);
13510 if upper != k { upper } else { ascii_tolower(k) }
13511}
13512
13513unsafe fn pat_next(pat: *const u8, m: usize, flags: c_int) -> (c_int, usize) {
13516 if m == 0 || *pat == 0 {
13517 return (FNM_END, 0);
13518 }
13519 let mut p = pat;
13520 let mut step = 1usize;
13521 let mut esc = false;
13522 if *p == b'\\' && !(flags & FNM_NOESCAPE != 0) && *p.add(1) != 0 {
13523 p = p.add(1);
13524 step = 2;
13525 esc = true;
13526 }
13527 if *p == b'[' && !esc {
13528 let mut k = 1usize;
13530 if k < m && (*pat.add(k) == b'^' || *pat.add(k) == b'!') { k += 1; }
13531 if k < m && *pat.add(k) == b']' { k += 1; }
13532 while k < m && *pat.add(k) != 0 && *pat.add(k) != b']' {
13533 if k + 1 < m && *pat.add(k) == b'[' &&
13534 (*pat.add(k+1) == b':' || *pat.add(k+1) == b'.' || *pat.add(k+1) == b'=') {
13535 let z = *pat.add(k+1);
13536 k += 2;
13537 if k < m { k += 1; }
13538 while k < m && *pat.add(k) != 0 && (*pat.add(k-1) != z || *pat.add(k) != b']') { k += 1; }
13539 if k == m || *pat.add(k) == 0 { break; }
13540 }
13541 k += 1;
13542 }
13543 if k == m || *pat.add(k) == 0 {
13544 return (b'[' as c_int, 1);
13546 }
13547 return (FNM_BRACKET, k + 1);
13548 }
13549 if *p == b'*' && !esc {
13550 return (FNM_STAR, 1);
13551 }
13552 if *p == b'?' && !esc {
13553 return (FNM_QUESTION, 1);
13554 }
13555 (*p as c_int, step)
13556}
13557
13558unsafe fn match_class(name: &[u8], k: u8, kfold: u8) -> bool {
13559 let eq = |c: u8| k == c || kfold == c;
13560 let in_range = |lo: u8, hi: u8| (k >= lo && k <= hi) || (kfold >= lo && kfold <= hi);
13561 match name {
13562 b"alnum" => in_range(b'0', b'9') || in_range(b'A', b'Z') || in_range(b'a', b'z'),
13563 b"alpha" => in_range(b'A', b'Z') || in_range(b'a', b'z'),
13564 b"blank" => eq(b' ') || eq(b'\t'),
13565 b"cntrl" => k < 0x20 || k == 0x7f,
13566 b"digit" => in_range(b'0', b'9'),
13567 b"graph" => k >= 0x21 && k <= 0x7e,
13568 b"lower" => in_range(b'a', b'z'),
13569 b"print" => k >= 0x20 && k <= 0x7e,
13570 b"punct" =>
13571 (k >= 0x21 && k <= 0x2f) ||
13572 (k >= 0x3a && k <= 0x40) ||
13573 (k >= 0x5b && k <= 0x60) ||
13574 (k >= 0x7b && k <= 0x7e),
13575 b"space" => eq(b' ') || eq(b'\t') || eq(b'\n') || eq(b'\r') || eq(0x0c) || eq(0x0b),
13576 b"upper" => in_range(b'A', b'Z'),
13577 b"xdigit" => in_range(b'0', b'9') || in_range(b'A', b'F') || in_range(b'a', b'f'),
13578 _ => false,
13579 }
13580}
13581
13582unsafe fn match_bracket(mut p: *const u8, k: u8, kfold: u8) -> bool {
13584 let mut inv = false;
13585 p = p.add(1); if *p == b'^' || *p == b'!' {
13587 inv = true;
13588 p = p.add(1);
13589 }
13590 if *p == b']' {
13592 if k == b']' { return !inv; }
13593 p = p.add(1);
13594 } else if *p == b'-' {
13595 if k == b'-' { return !inv; }
13596 p = p.add(1);
13597 }
13598 while *p != b']' && *p != 0 {
13599 if *p == b'-' && *p.add(1) != b']' && *p.add(1) != 0 {
13600 let lo = *p.sub(1);
13602 let hi = *p.add(1);
13603 if lo <= hi && (k >= lo && k <= hi || kfold >= lo && kfold <= hi) {
13604 return !inv;
13605 }
13606 p = p.add(2);
13607 } else if *p == b'[' && (*p.add(1) == b':' || *p.add(1) == b'.' || *p.add(1) == b'=') {
13608 let z = *p.add(1);
13609 let start = p.add(2);
13610 let mut q = start;
13611 while *q != 0 && (*q != z || *q.add(1) != b']') { q = q.add(1); }
13612 if *q != 0 {
13613 let len = (q as usize) - (start as usize);
13614 if len > 0 {
13615 let inner = core::slice::from_raw_parts(start, len);
13616 let matched =
13617 if z == b':' { match_class(inner, k, kfold) }
13618 else { len == 1 && (inner[0] == k || inner[0] == kfold) };
13619 if matched { return !inv; }
13620 }
13621 p = q.add(2);
13622 continue;
13623 }
13624 } else {
13625 if *p == k || *p == kfold {
13626 return !inv;
13627 }
13628 p = p.add(1);
13629 }
13630 }
13631 inv
13632}
13633
13634unsafe fn fnmatch_internal(pat: *const u8, str: *const u8, flags: c_int) -> c_int {
13636 if flags & FNM_PERIOD != 0 && *str == b'.' && *pat != b'.' {
13638 return FNM_NOMATCH;
13639 }
13640
13641 let mut p = pat;
13642 let mut s = str;
13643
13644 loop {
13646 let (tok, step) = pat_next(p, usize::MAX, flags);
13647 match tok {
13648 FNM_END => {
13649 return if *s == 0 { 0 } else { FNM_NOMATCH };
13650 }
13651 FNM_STAR => {
13652 p = p.add(1);
13653 break;
13654 }
13655 FNM_QUESTION => {
13656 if *s == 0 { return FNM_NOMATCH; }
13657 s = s.add(1);
13658 p = p.add(step);
13659 }
13660 FNM_BRACKET => {
13661 if *s == 0 { return FNM_NOMATCH; }
13662 let k = *s;
13663 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13664 if !match_bracket(p, k, kfold) { return FNM_NOMATCH; }
13665 p = p.add(step);
13666 s = s.add(1);
13667 }
13668 c => {
13669 if *s == 0 { return FNM_NOMATCH; }
13670 let k = *s;
13671 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13672 if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
13673 p = p.add(step);
13674 s = s.add(1);
13675 }
13676 }
13677 }
13678
13679 let mut ptail = p;
13682 let mut tailcnt: usize = 0;
13683 let mut pp = p;
13684 loop {
13685 let (tok, step) = pat_next(pp, usize::MAX, flags);
13686 if tok == FNM_END { break; }
13687 if tok == FNM_STAR {
13688 tailcnt = 0;
13689 ptail = pp.add(1);
13690 } else {
13691 tailcnt += 1;
13692 }
13693 pp = pp.add(step);
13694 }
13695
13696 let slen = strlen(s as *const c_char);
13698 if slen < tailcnt { return FNM_NOMATCH; }
13699
13700 let stail = s.add(slen - tailcnt);
13702 let mut tp = ptail;
13703 let mut ts = stail;
13704 loop {
13705 let (tok, step) = pat_next(tp, usize::MAX, flags);
13706 tp = tp.add(step);
13707 if tok == FNM_END {
13708 break;
13709 }
13710 let k = *ts;
13711 if k == 0 { return FNM_NOMATCH; }
13712 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13713 match tok {
13714 FNM_QUESTION => { ts = ts.add(1); }
13715 FNM_BRACKET => {
13716 if !match_bracket(tp.sub(step), k, kfold) { return FNM_NOMATCH; }
13717 ts = ts.add(1);
13718 }
13719 c => {
13720 if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
13721 ts = ts.add(1);
13722 }
13723 }
13724 }
13725
13726 let endstr = stail;
13727 let endpat = ptail;
13728
13729 let mut cp = p;
13730 let mut cs = s;
13731 while cp < endpat {
13732 let (tok, step) = pat_next(cp, usize::MAX, flags);
13733 if tok == FNM_STAR {
13734 cp = cp.add(step);
13735 cs = s;
13736 continue;
13737 }
13738 let comp_start = cp;
13739 let mut ok = false;
13740 let mut try_s = cs;
13741 while try_s < endstr {
13742 let mut tmp_p = comp_start;
13743 let mut tmp_s = try_s;
13744 let mut matched = true;
13745 loop {
13746 let (t, st) = pat_next(tmp_p, usize::MAX, flags);
13747 if t == FNM_STAR || t == FNM_END {
13748 cp = tmp_p;
13749 cs = tmp_s;
13750 ok = true;
13751 break;
13752 }
13753 if *tmp_s == 0 {
13754 matched = false;
13755 break;
13756 }
13757 let k = *tmp_s;
13758 let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
13759 match t {
13760 FNM_QUESTION => {
13761 tmp_s = tmp_s.add(1);
13762 }
13763 FNM_BRACKET => {
13764 if !match_bracket(tmp_p, k, kfold) {
13765 matched = false;
13766 break;
13767 }
13768 tmp_s = tmp_s.add(1);
13769 }
13770 c => {
13771 if k as c_int != c && kfold as c_int != c {
13772 matched = false;
13773 break;
13774 }
13775 tmp_s = tmp_s.add(1);
13776 }
13777 }
13778 tmp_p = tmp_p.add(st);
13779 }
13780 if ok { break; }
13781 if !matched {
13782 try_s = try_s.add(1);
13783 }
13784 }
13785 if !ok {
13786 return FNM_NOMATCH;
13787 }
13788 }
13789 0
13790}
13791
13792#[no_mangle]
13793pub unsafe extern "C" fn fnmatch(pat: *const c_char, str: *const c_char, flags: c_int) -> c_int {
13794 let pat = pat as *const u8;
13795 let str = str as *const u8;
13796
13797 if flags & FNM_PATHNAME != 0 {
13798 let mut s = str;
13800 let mut p = pat;
13801 loop {
13802 let mut send = s;
13804 while *send != 0 && *send != b'/' { send = send.add(1); }
13805 let mut pend = p;
13807 loop {
13808 let (tok, step) = pat_next(pend, usize::MAX, flags);
13809 if tok == FNM_END || (tok >= 0 && tok as u8 == b'/') {
13810 break;
13811 }
13812 pend = pend.add(step);
13813 }
13814 let (ptok, pstep) = pat_next(pend, usize::MAX, flags);
13815 let pat_is_slash = ptok >= 0 && ptok as u8 == b'/';
13816 let str_is_slash = *send == b'/';
13817 if pat_is_slash != str_is_slash && (*send != 0 || !(flags & FNM_LEADING_DIR != 0)) {
13818 return FNM_NOMATCH;
13819 }
13820 let plen = (pend as usize) - (p as usize);
13823 let slen = (send as usize) - (s as usize);
13824 if plen > 1024 || slen > 1024 { return FNM_NOMATCH; }
13827 let mut pbuf = [0u8; 1025];
13828 let mut sbuf = [0u8; 1025];
13829 core::ptr::copy_nonoverlapping(p, pbuf.as_mut_ptr(), plen);
13830 pbuf[plen] = 0;
13831 core::ptr::copy_nonoverlapping(s, sbuf.as_mut_ptr(), slen);
13832 sbuf[slen] = 0;
13833 if fnmatch_internal(pbuf.as_ptr(), sbuf.as_ptr(), flags & !FNM_LEADING_DIR) != 0 {
13834 return FNM_NOMATCH;
13835 }
13836 if !pat_is_slash {
13837 return 0;
13838 }
13839 s = send.add(1);
13840 p = pend.add(pstep);
13841 }
13842 }
13843
13844 if flags & FNM_LEADING_DIR != 0 {
13845 let mut s = str;
13847 while *s != 0 {
13848 if *s == b'/' {
13849 let len = (s as usize) - (str as usize);
13852 if len < 4096 {
13854 let mut buf = [0u8; 4096];
13855 core::ptr::copy_nonoverlapping(str, buf.as_mut_ptr(), len);
13856 buf[len] = 0;
13857 if fnmatch_internal(pat, buf.as_ptr(), flags) == 0 {
13858 return 0;
13859 }
13860 }
13861 }
13862 s = s.add(1);
13863 }
13864 }
13865
13866 fnmatch_internal(pat, str, flags)
13867}
13868
13869#[no_mangle]
13874pub unsafe extern "C" fn setmntent(name: *const c_char, mode: *const c_char) -> *mut FILE {
13875 fopen(name, mode)
13876}
13877
13878#[no_mangle]
13879pub unsafe extern "C" fn endmntent(f: *mut FILE) -> c_int {
13880 if !f.is_null() {
13881 fclose(f);
13882 }
13883 1
13884}
13885
13886static mut MNTENT_MNT: MntEnt = MntEnt {
13888 mnt_fsname: core::ptr::null_mut(),
13889 mnt_dir: core::ptr::null_mut(),
13890 mnt_type: core::ptr::null_mut(),
13891 mnt_opts: core::ptr::null_mut(),
13892 mnt_freq: 0,
13893 mnt_passno: 0,
13894};
13895
13896#[repr(C)]
13897pub struct MntEnt {
13898 mnt_fsname: *mut c_char,
13899 mnt_dir: *mut c_char,
13900 mnt_type: *mut c_char,
13901 mnt_opts: *mut c_char,
13902 mnt_freq: c_int,
13903 mnt_passno: c_int,
13904}
13905
13906unsafe fn unescape_ent(beg: *mut c_char) -> *mut c_char {
13907 let mut dest = beg;
13908 let mut src = beg;
13909 while *src != 0 {
13910 if *src != b'\\' as c_char {
13911 *dest = *src;
13912 dest = dest.add(1);
13913 src = src.add(1);
13914 continue;
13915 }
13916 if *src.add(1) == b'\\' as c_char {
13918 src = src.add(1);
13919 *dest = *src;
13920 dest = dest.add(1);
13921 src = src.add(1);
13922 continue;
13923 }
13924 let mut val: u8 = 0;
13926 let mut cnt = 0;
13927 let mut sp = src.add(1);
13928 while cnt < 3 && *sp >= b'0' as c_char && *sp <= b'7' as c_char {
13929 val = val * 8 + (*sp as u8 - b'0');
13930 sp = sp.add(1);
13931 cnt += 1;
13932 }
13933 if cnt > 0 {
13934 *dest = val as c_char;
13935 dest = dest.add(1);
13936 src = sp;
13937 } else {
13938 *dest = *src;
13939 dest = dest.add(1);
13940 src = src.add(1);
13941 }
13942 }
13943 *dest = 0;
13944 beg
13945}
13946
13947unsafe fn parse_mntent_line(
13948 linebuf: *mut c_char,
13949 mnt: *mut MntEnt,
13950) -> *mut MntEnt {
13951 let _len = strlen(linebuf as *const c_char);
13952 let mut p = linebuf;
13955 while *p == b' ' as c_char || *p == b'\t' as c_char || *p == b'\n' as c_char || *p == b'\r' as c_char {
13957 p = p.add(1);
13958 }
13959 if *p == 0 || *p == b'#' as c_char {
13960 return core::ptr::null_mut();
13961 }
13962
13963 (*mnt).mnt_fsname = p;
13965 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
13966 p = p.add(1);
13967 }
13968 if *p == 0 { return core::ptr::null_mut(); }
13969 *p = 0;
13970 p = p.add(1);
13971 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
13972
13973 (*mnt).mnt_dir = p;
13975 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
13976 p = p.add(1);
13977 }
13978 if *p == 0 { return core::ptr::null_mut(); }
13979 *p = 0;
13980 p = p.add(1);
13981 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
13982
13983 (*mnt).mnt_type = p;
13985 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
13986 p = p.add(1);
13987 }
13988 if *p == 0 { return core::ptr::null_mut(); }
13989 *p = 0;
13990 p = p.add(1);
13991 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
13992
13993 (*mnt).mnt_opts = p;
13995 while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
13996 p = p.add(1);
13997 }
13998 if *p != 0 {
13999 *p = 0;
14000 p = p.add(1);
14001 }
14002 if *(*mnt).mnt_opts == 0 {
14003 (*mnt).mnt_opts = b"defaults\0".as_ptr() as *mut c_char;
14004 }
14005
14006 (*mnt).mnt_freq = 0;
14008 (*mnt).mnt_passno = 0;
14009 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14011 if *p >= b'0' as c_char && *p <= b'9' as c_char {
14012 (*mnt).mnt_freq = (*p - b'0' as c_char) as c_int;
14013 p = p.add(1);
14014 while *p >= b'0' as c_char && *p <= b'9' as c_char {
14015 (*mnt).mnt_freq = (*mnt).mnt_freq * 10 + (*p - b'0' as c_char) as c_int;
14016 p = p.add(1);
14017 }
14018 }
14019 while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14020 if *p >= b'0' as c_char && *p <= b'9' as c_char {
14021 (*mnt).mnt_passno = (*p - b'0' as c_char) as c_int;
14022 p = p.add(1);
14023 while *p >= b'0' as c_char && *p <= b'9' as c_char {
14024 (*mnt).mnt_passno = (*mnt).mnt_passno * 10 + (*p - b'0' as c_char) as c_int;
14025 p = p.add(1);
14026 }
14027 }
14028
14029 unescape_ent((*mnt).mnt_fsname);
14031 unescape_ent((*mnt).mnt_dir);
14032 unescape_ent((*mnt).mnt_type);
14033 unescape_ent((*mnt).mnt_opts);
14034
14035 mnt
14036}
14037
14038static SENTINEL_PTR: usize = 1;
14041
14042unsafe fn mntent_fgetc(f: *mut FILE) -> c_int {
14044 fgetc(f)
14045}
14046
14047unsafe fn mntent_fgets(buf: *mut c_char, n: usize, f: *mut FILE) -> *mut c_char {
14048 if n == 0 { return core::ptr::null_mut(); }
14049 let max = n - 1;
14050 let mut i = 0usize;
14051 while i < max {
14052 let c = mntent_fgetc(f);
14053 if c == -1 { if i == 0 { return core::ptr::null_mut(); } break; }
14054 *buf.add(i) = c as c_char;
14055 i += 1;
14056 if c == b'\n' as c_int { break; }
14057 }
14058 *buf.add(i) = 0;
14059 buf
14060}
14061
14062#[no_mangle]
14063pub unsafe extern "C" fn getmntent_r(
14064 f: *mut FILE,
14065 mnt: *mut MntEnt,
14066 mut linebuf: *mut c_char,
14067 _buflen: c_int,
14068) -> *mut MntEnt {
14069 let use_internal = linebuf as usize == SENTINEL_PTR;
14070
14071 (*mnt).mnt_freq = 0;
14072 (*mnt).mnt_passno = 0;
14073
14074 static mut INTERNAL_BUF: [c_char; 4096] = [0; 4096];
14076
14077 loop {
14078 if use_internal {
14079 linebuf = core::ptr::addr_of_mut!(INTERNAL_BUF).cast::<c_char>();
14080 }
14081 let res = mntent_fgets(linebuf, 4096, f);
14082 if res.is_null() {
14083 return core::ptr::null_mut();
14084 }
14085 let mut has_newline = false;
14086 let mut p = linebuf;
14087 while *p != 0 { if *p == b'\n' as c_char { has_newline = true; break; } p = p.add(1); }
14088 if !has_newline {
14089 ERRNO = 34;
14090 return core::ptr::null_mut();
14091 }
14092 let result = parse_mntent_line(linebuf, mnt);
14093 if !result.is_null() {
14094 return result;
14095 }
14096 }
14097}
14098
14099#[no_mangle]
14100pub unsafe extern "C" fn getmntent(f: *mut FILE) -> *mut MntEnt {
14101 getmntent_r(f, core::ptr::addr_of_mut!(MNTENT_MNT), SENTINEL_PTR as *mut c_char, 0)
14102}
14103
14104#[no_mangle]
14105pub unsafe extern "C" fn addmntent(f: *mut FILE, mnt: *const MntEnt) -> c_int {
14106 fseek(f, 0, 2); let written = fprintf(
14108 f,
14109 b"%s\t%s\t%s\t%s\t%d\t%d\n\0".as_ptr() as *const c_char,
14110 (*mnt).mnt_fsname,
14111 (*mnt).mnt_dir,
14112 (*mnt).mnt_type,
14113 (*mnt).mnt_opts,
14114 (*mnt).mnt_freq,
14115 (*mnt).mnt_passno,
14116 );
14117 if written < 0 { 1 } else { 0 }
14118}
14119
14120#[no_mangle]
14121pub unsafe extern "C" fn hasmntopt(mnt: *const MntEnt, opt: *const c_char) -> *mut c_char {
14122 let l = strlen(opt as *const c_char);
14123 let mut p = (*mnt).mnt_opts;
14124 loop {
14125 if strncmp(p as *const u8, opt as *const u8, l) == 0 {
14126 let after = *p.add(l);
14127 if after == 0 || after == b',' as c_char || after == b'=' as c_char {
14128 return p;
14129 }
14130 }
14131 let comma = strchr(p as *const u8, b',' as c_int);
14132 if comma.is_null() {
14133 return core::ptr::null_mut();
14134 }
14135 p = comma.add(1) as *mut c_char;
14136 }
14137}
14138
14139const EEXIST: c_int = 17;
14147const ENAMETOOLONG: c_int = 36;
14148const EMFILE: c_int = 24;
14149const EIDRM: c_int = 43;
14150
14151#[inline]
14152unsafe fn sys_msgget(key: c_int, msgflg: c_int) -> i64 {
14153 <Arch as Syscalls>::syscall2(SYS_MSGGET, key as i64, msgflg as i64)
14154}
14155
14156#[inline]
14157unsafe fn sys_msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> i64 {
14158 <Arch as Syscalls>::syscall4(SYS_MSGSND, msqid as i64, msgp as i64, msgsz as i64, msgflg as i64)
14159}
14160
14161#[inline]
14162unsafe fn sys_msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> i64 {
14163 <Arch as Syscalls>::syscall5(SYS_MSGRCV, msqid as i64, msgp as i64, msgsz as i64, msgtyp as i64, msgflg as i64)
14164}
14165
14166#[inline]
14167unsafe fn sys_msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14168 <Arch as Syscalls>::syscall3(SYS_MSGCTL, msqid as i64, cmd as i64, buf as i64)
14169}
14170
14171#[inline]
14172unsafe fn sys_semget(key: c_int, nsems: c_int, semflg: c_int) -> i64 {
14173 <Arch as Syscalls>::syscall3(SYS_SEMGET, key as i64, nsems as i64, semflg as i64)
14174}
14175
14176#[inline]
14177unsafe fn sys_semop(semid: c_int, sops: *const c_void, nsops: usize) -> i64 {
14178 <Arch as Syscalls>::syscall3(SYS_SEMOP, semid as i64, sops as i64, nsops as i64)
14179}
14180
14181#[inline]
14182unsafe fn sys_semctl(semid: c_int, semnum: c_int, cmd: c_int, arg: *mut c_void) -> i64 {
14183 <Arch as Syscalls>::syscall4(SYS_SEMCTL, semid as i64, semnum as i64, cmd as i64, arg as i64)
14184}
14185
14186#[inline]
14187unsafe fn sys_shmget(key: c_int, size: usize, shmflg: c_int) -> i64 {
14188 <Arch as Syscalls>::syscall3(SYS_SHMGET, key as i64, size as i64, shmflg as i64)
14189}
14190
14191#[inline]
14192unsafe fn sys_shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> i64 {
14193 <Arch as Syscalls>::syscall3(SYS_SHMAT, shmid as i64, shmaddr as i64, shmflg as i64)
14194}
14195
14196#[inline]
14197unsafe fn sys_shmdt(shmaddr: *const c_void) -> i64 {
14198 <Arch as Syscalls>::syscall1(SYS_SHMDT, shmaddr as i64)
14199}
14200
14201#[inline]
14202unsafe fn sys_shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14203 <Arch as Syscalls>::syscall3(SYS_SHMCTL, shmid as i64, cmd as i64, buf as i64)
14204}
14205
14206#[no_mangle]
14208pub unsafe extern "C" fn ftok(path: *const c_char, id: c_int) -> c_int {
14209 let mut st: kernel_stat64 = core::mem::zeroed();
14210 let r = sys_stat(path as *const u8, &mut st);
14211 if r < 0 {
14212 ERRNO = (-r) as c_int;
14213 return -1;
14214 }
14215 ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | (((id as u32 & 0xff) << 24)) as u64) as c_int
14216}
14217
14218#[no_mangle]
14220pub unsafe extern "C" fn msgget(key: c_int, msgflg: c_int) -> c_int {
14221 let r = sys_msgget(key, msgflg);
14222 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14223}
14224
14225#[no_mangle]
14227pub unsafe extern "C" fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> c_int {
14228 let r = sys_msgsnd(msqid, msgp, msgsz, msgflg);
14229 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14230}
14231
14232#[no_mangle]
14234pub unsafe extern "C" fn msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> isize {
14235 let r = sys_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
14236 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
14237}
14238
14239#[no_mangle]
14241pub unsafe extern "C" fn msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
14242 let r = sys_msgctl(msqid, cmd, buf);
14243 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14244}
14245
14246#[no_mangle]
14248pub unsafe extern "C" fn semget(key: c_int, nsems: c_int, semflg: c_int) -> c_int {
14249 if nsems > 65535 { ERRNO = 22; return -1; }
14250 let r = sys_semget(key, nsems, semflg);
14251 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14252}
14253
14254#[no_mangle]
14256pub unsafe extern "C" fn semop(semid: c_int, sops: *const c_void, nsops: usize) -> c_int {
14257 let r = sys_semop(semid, sops, nsops);
14258 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14259}
14260
14261#[no_mangle]
14263pub unsafe extern "C" fn semctl(semid: c_int, semnum: c_int, cmd: c_int, mut args: ...) -> c_int {
14264 let mut arg: *mut c_void = core::ptr::null_mut();
14265 match cmd {
14267 16 | 13 | 17 | 1 | 3 | 2 | 0x102 | 0x104 | 0x106 => {
14268 arg = args.next_arg::<*mut c_void>();
14269 }
14270 _ => {}
14271 }
14272 let r = sys_semctl(semid, semnum, cmd, arg);
14273 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14274}
14275
14276#[no_mangle]
14278pub unsafe extern "C" fn shmget(key: c_int, size: usize, shmflg: c_int) -> c_int {
14279 let r = sys_shmget(key, size, shmflg);
14280 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14281}
14282
14283#[no_mangle]
14285pub unsafe extern "C" fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void {
14286 let r = sys_shmat(shmid, shmaddr, shmflg);
14287 if (r as usize) > (-(4096isize as isize)) as usize {
14288 ERRNO = (-r) as c_int;
14289 return core::ptr::null_mut();
14290 }
14291 r as *mut c_void
14292}
14293
14294#[no_mangle]
14296pub unsafe extern "C" fn shmdt(shmaddr: *const c_void) -> c_int {
14297 let r = sys_shmdt(shmaddr);
14298 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14299}
14300
14301#[no_mangle]
14303pub unsafe extern "C" fn shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
14304 let r = sys_shmctl(shmid, cmd, buf);
14305 if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14306}
14307
14308#[no_mangle]
14318pub static mut __auxv: *const usize = core::ptr::null();
14319
14320#[no_mangle]
14321pub unsafe extern "C" fn getauxval(type_: c_ulong) -> c_ulong {
14322 let mut p = __auxv;
14323 if p.is_null() {
14324 return 0;
14325 }
14326 loop {
14327 let tag = *p;
14328 if tag == 0 {
14329 return 0;
14330 }
14331 if tag == type_ as usize {
14332 return *p.add(1) as c_ulong;
14333 }
14334 p = p.add(2);
14335 }
14336}
14337
14338type MainFn = unsafe extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int;
14339type InitFn = unsafe extern "C" fn();
14340
14341#[no_mangle]
14342pub unsafe extern "C" fn __libc_start_main(
14343 main: MainFn,
14344 argc: c_int,
14345 argv: *const *const c_char,
14346 _init: *const c_void,
14347 _fini: *const c_void,
14348 _rtld_fini: *const c_void,
14349 _stack_end: *const c_void,
14350) -> ! {
14351 let envp = argv.add((argc + 1) as usize);
14352 __environ = envp as *mut *mut c_char;
14353 environ = __environ; __stdio_init();
14355
14356 let mut set: SigSetT = 0;
14357 sigemptyset(&mut set);
14358 sigaddset(&mut set, SIGCANCEL);
14359 sigprocmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
14360
14361 if !_init.is_null() {
14362 let init_fn: InitFn = core::mem::transmute(_init);
14363 init_fn();
14364 }
14365
14366 #[cfg(target_arch = "aarch64")]
14370 {
14371 let random_ptr = getauxval(25) as *const u8; if !random_ptr.is_null() {
14373 let a = core::ptr::read_unaligned(random_ptr as *const u64);
14374 let b = core::ptr::read_unaligned(random_ptr.add(8) as *const u64);
14375 __stack_chk_guard = (a ^ b) as usize;
14376 } else {
14377 __stack_chk_guard = 0xdefaced_cafebeef;
14379 }
14380 }
14381
14382 let result = main(argc, argv, envp);
14383
14384 if !_fini.is_null() {
14385 let fini_fn: InitFn = core::mem::transmute(_fini);
14386 fini_fn();
14387 }
14388
14389 exit(result);
14390}
14391
14392type LdsoDlopenFn = unsafe extern "C" fn(*const c_char, c_int) -> *mut c_void;
14393type LdsoDlsymFn = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
14394type LdsoDlcloseFn = unsafe extern "C" fn(*mut c_void) -> c_int;
14395type LdsoDlerrorFn = unsafe extern "C" fn() -> *const c_char;
14396
14397static mut LDSO_DLOPEN: Option<LdsoDlopenFn> = None;
14398static mut LDSO_DLSYM: Option<LdsoDlsymFn> = None;
14399static mut LDSO_DLCLOSE: Option<LdsoDlcloseFn> = None;
14400static mut LDSO_DLERROR: Option<LdsoDlerrorFn> = None;
14401
14402#[no_mangle]
14403pub unsafe extern "C" fn __ldso_register_dlopen(f: LdsoDlopenFn) {
14404 LDSO_DLOPEN = Some(f);
14405}
14406
14407#[no_mangle]
14408pub unsafe extern "C" fn __ldso_register_dlsym(f: LdsoDlsymFn) {
14409 LDSO_DLSYM = Some(f);
14410}
14411
14412#[no_mangle]
14413pub unsafe extern "C" fn __ldso_register_dlclose(f: LdsoDlcloseFn) {
14414 LDSO_DLCLOSE = Some(f);
14415}
14416
14417#[no_mangle]
14418pub unsafe extern "C" fn __ldso_register_dlerror(f: LdsoDlerrorFn) {
14419 LDSO_DLERROR = Some(f);
14420}
14421
14422#[no_mangle]
14423pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c_void {
14424 if let Some(f) = LDSO_DLOPEN {
14425 f(filename, flags)
14426 } else {
14427 null_mut()
14428 }
14429}
14430
14431#[no_mangle]
14432pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
14433 if let Some(f) = LDSO_DLSYM {
14434 f(handle, symbol)
14435 } else {
14436 null_mut()
14437 }
14438}
14439
14440#[no_mangle]
14441pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
14442 if let Some(f) = LDSO_DLCLOSE {
14443 f(handle)
14444 } else {
14445 0
14446 }
14447}
14448
14449#[no_mangle]
14450pub unsafe extern "C" fn dlerror() -> *const c_char {
14451 if let Some(f) = LDSO_DLERROR {
14452 f()
14453 } else {
14454 core::ptr::null()
14455 }
14456}
14457
14458include!("crypt_impl.rs");
14459include!("statvfs.rs");
14460include!("daemon.rs");
14461include!("dn_expand.rs");
14462include!("lrand48.rs");
14463include!("strverscmp.rs");
14464include!("syscall.rs");
14465include!("pthread_atfork.rs");
14466include!("fenv.rs");
14467include!("locale_ctype.rs");
14468include!("regression_stubs.rs");
14469
14470type regoff_t = c_int;
14475
14476#[repr(C)]
14477pub struct regex_t {
14478 pub re_nsub: usize,
14479 pub __opaque: *mut c_void,
14480 pub __padding: [*mut c_void; 4],
14481 pub __nsub2: usize,
14482 pub __padding2: c_char,
14483}
14484
14485#[repr(C)]
14486pub struct regmatch_t {
14487 pub rm_so: regoff_t,
14488 pub rm_eo: regoff_t,
14489}
14490
14491include!("regex.rs");
14492
14493#[cfg(test)]
14494mod libc_unit_stub {
14495 #[test]
14496 fn stub() {
14497 assert!(true);
14498 }
14499}