summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/Kbuild44
-rw-r--r--lib/libc/arch/Kbuild1
-rw-r--r--lib/libc/arch/x86_64/Kbuild7
-rw-r--r--lib/libc/arch/x86_64/clock_gettime.c13
-rw-r--r--lib/libc/arch/x86_64/crt0.c59
-rw-r--r--lib/libc/arch/x86_64/fenv.s97
-rw-r--r--lib/libc/arch/x86_64/longjmp.c18
-rw-r--r--lib/libc/arch/x86_64/setjmp.c17
-rw-r--r--lib/libc/arch/x86_64/sigsetjmp.c33
-rw-r--r--lib/libc/arch/x86_64/vdso_setup.c62
-rw-r--r--lib/libc/arpa/Kbuild8
-rw-r--r--lib/libc/arpa/htonl.c12
-rw-r--r--lib/libc/arpa/htons.c12
-rw-r--r--lib/libc/arpa/inet_addr.c8
-rw-r--r--lib/libc/arpa/inet_ntoa.c8
-rw-r--r--lib/libc/arpa/inet_ntop.c0
-rw-r--r--lib/libc/arpa/inet_pton.c10
-rw-r--r--lib/libc/arpa/ntohl.c12
-rw-r--r--lib/libc/arpa/ntohs.c12
-rw-r--r--lib/libc/assert/assert.c12
-rw-r--r--lib/libc/ctype/isalnum.c12
-rw-r--r--lib/libc/ctype/isalpha.c8
-rw-r--r--lib/libc/ctype/isblank.c8
-rw-r--r--lib/libc/ctype/iscntrl.c8
-rw-r--r--lib/libc/ctype/isdigit.c8
-rw-r--r--lib/libc/ctype/isgraph.c8
-rw-r--r--lib/libc/ctype/islower.c8
-rw-r--r--lib/libc/ctype/isprint.c8
-rw-r--r--lib/libc/ctype/ispunct.c12
-rw-r--r--lib/libc/ctype/isspace.c8
-rw-r--r--lib/libc/ctype/isupper.c8
-rw-r--r--lib/libc/ctype/isxdigit.c6
-rw-r--r--lib/libc/ctype/tolower.c14
-rw-r--r--lib/libc/ctype/toupper.c14
-rw-r--r--lib/libc/devctl/posix_devctl.c17
-rw-r--r--lib/libc/dirent/closedir.c17
-rw-r--r--lib/libc/dirent/dirfd.c8
-rw-r--r--lib/libc/dirent/fdopendir.c24
-rw-r--r--lib/libc/dirent/opendir.c15
-rw-r--r--lib/libc/dirent/readdir.c16
-rw-r--r--lib/libc/dirent/readdir_r.c140
-rw-r--r--lib/libc/endian/be16toh.c10
-rw-r--r--lib/libc/endian/be32toh.c10
-rw-r--r--lib/libc/endian/be64toh.c10
-rw-r--r--lib/libc/endian/htobe16.c10
-rw-r--r--lib/libc/endian/htobe32.c10
-rw-r--r--lib/libc/endian/htobe64.c10
-rw-r--r--lib/libc/endian/htole16.c10
-rw-r--r--lib/libc/endian/htole32.c10
-rw-r--r--lib/libc/endian/htole64.c10
-rw-r--r--lib/libc/endian/le16toh.c10
-rw-r--r--lib/libc/endian/le32toh.c10
-rw-r--r--lib/libc/endian/le64toh.c10
-rw-r--r--lib/libc/errno/errno.c8
-rw-r--r--lib/libc/fcntl/creat.c7
-rw-r--r--lib/libc/fcntl/fcntl.c37
-rw-r--r--lib/libc/fcntl/open.c23
-rw-r--r--lib/libc/fcntl/openat.c17
-rw-r--r--lib/libc/fcntl/posix_fadvise.c7
-rw-r--r--lib/libc/fcntl/posix_fallocate.c7
-rw-r--r--lib/libc/grp/getgrgid.c15
-rw-r--r--lib/libc/grp/getgrgid_r.c74
-rw-r--r--lib/libc/include/__alpha.h233
-rw-r--r--lib/libc/include/__dirent.h25
-rw-r--r--lib/libc/include/__locale.h41
-rw-r--r--lib/libc/include/__select.h8
-rw-r--r--lib/libc/include/__signal.h12
-rw-r--r--lib/libc/include/__statvfs.h21
-rw-r--r--lib/libc/include/atomic.h23
-rw-r--r--lib/libc/include/byteswap.h8
-rw-r--r--lib/libc/include/features.h6
-rw-r--r--lib/libc/include/io.h55
-rw-r--r--lib/libc/include/libc.h27
-rw-r--r--lib/libc/include/libc/dirent.h6
-rw-r--r--lib/libc/include/malloc.h98
-rw-r--r--lib/libc/include/syscall.h59
-rw-r--r--lib/libc/include/thread.h9
-rw-r--r--lib/libc/inttypes/imaxabs.c6
-rw-r--r--lib/libc/inttypes/imaxdiv.c6
-rw-r--r--lib/libc/inttypes/strtoimax.c149
-rw-r--r--lib/libc/inttypes/strtoumax.c7
-rw-r--r--lib/libc/libgen/basename.c62
-rw-r--r--lib/libc/libgen/dirname.c66
-rw-r--r--lib/libc/mman/mlock.c7
-rw-r--r--lib/libc/mman/mlockall.c7
-rw-r--r--lib/libc/mman/mmap.c10
-rw-r--r--lib/libc/mman/mprotect.c7
-rw-r--r--lib/libc/mman/msync.c7
-rw-r--r--lib/libc/mman/munlock.c7
-rw-r--r--lib/libc/mman/munlockall.c7
-rw-r--r--lib/libc/mman/munmap.c8
-rw-r--r--lib/libc/mman/posix_madvise.c7
-rw-r--r--lib/libc/monetary/strfmon.c131
-rw-r--r--lib/libc/msg/msgctl.c8
-rw-r--r--lib/libc/poll/poll.c7
-rw-r--r--lib/libc/poll/ppoll.c9
-rw-r--r--lib/libc/pwd/getgrgid.c15
-rw-r--r--lib/libc/pwd/getgrgid_r.c72
-rw-r--r--lib/libc/select/pselect.c11
-rw-r--r--lib/libc/select/select.c9
-rw-r--r--lib/libc/sem/semctl.c24
-rw-r--r--lib/libc/sem/semget.c7
-rw-r--r--lib/libc/sem/semop.c7
-rw-r--r--lib/libc/setjmp/siglongjmp.c6
-rw-r--r--lib/libc/signal/kill.c7
-rw-r--r--lib/libc/signal/killpg.c13
-rw-r--r--lib/libc/signal/psiginfo.c6
-rw-r--r--lib/libc/signal/psignal.c9
-rw-r--r--lib/libc/signal/pthread_kill.c18
-rw-r--r--lib/libc/signal/pthread_sigmask.c23
-rw-r--r--lib/libc/signal/raise.c7
-rw-r--r--lib/libc/signal/sig2str.c33
-rw-r--r--lib/libc/signal/sigaction.c8
-rw-r--r--lib/libc/signal/sigaddset.c10
-rw-r--r--lib/libc/signal/sigemptyset.c10
-rw-r--r--lib/libc/signal/sigismember.c18
-rw-r--r--lib/libc/signal/signal.c14
-rw-r--r--lib/libc/signal/sigpending.c7
-rw-r--r--lib/libc/signal/sigprocmask.c17
-rw-r--r--lib/libc/signal/sigqueue.c15
-rw-r--r--lib/libc/signal/sigsuspend.c7
-rw-r--r--lib/libc/signal/sigtimedwait.c10
-rw-r--r--lib/libc/signal/sigwait.c14
-rw-r--r--lib/libc/signal/sigwaitinfo.c6
-rw-r--r--lib/libc/signal/str2sig.c52
-rw-r--r--lib/libc/socket/accept.c8
-rw-r--r--lib/libc/socket/accept4.c8
-rw-r--r--lib/libc/socket/bind.c7
-rw-r--r--lib/libc/socket/connect.c7
-rw-r--r--lib/libc/socket/getpeername.c8
-rw-r--r--lib/libc/socket/getsockname.c8
-rw-r--r--lib/libc/socket/getsockopt.c9
-rw-r--r--lib/libc/socket/listen.c7
-rw-r--r--lib/libc/socket/recv.c7
-rw-r--r--lib/libc/socket/recvfrom.c10
-rw-r--r--lib/libc/socket/recvmsg.c7
-rw-r--r--lib/libc/socket/send.c7
-rw-r--r--lib/libc/socket/sendmsg.c7
-rw-r--r--lib/libc/socket/sendto.c9
-rw-r--r--lib/libc/socket/setsockopt.c9
-rw-r--r--lib/libc/socket/shutdown.c6
-rw-r--r--lib/libc/socket/sockatmark.c8
-rw-r--r--lib/libc/socket/socket.c6
-rw-r--r--lib/libc/socket/socketpair.c6
-rw-r--r--lib/libc/stat/chmod.c7
-rw-r--r--lib/libc/stat/fchmod.c7
-rw-r--r--lib/libc/stat/fchmodat.c7
-rw-r--r--lib/libc/stat/fstat.c8
-rw-r--r--lib/libc/stat/fstatat.c46
-rw-r--r--lib/libc/stat/futimens.c7
-rw-r--r--lib/libc/stat/lstat.c7
-rw-r--r--lib/libc/stat/mkdir.c12
-rw-r--r--lib/libc/stat/mkdirat.c8
-rw-r--r--lib/libc/stat/mkfifo.c6
-rw-r--r--lib/libc/stat/mkfifoat.c6
-rw-r--r--lib/libc/stat/mknod.c8
-rw-r--r--lib/libc/stat/mknodat.c7
-rw-r--r--lib/libc/stat/stat.c7
-rw-r--r--lib/libc/stat/umask.c7
-rw-r--r--lib/libc/stat/utimensat.c8
-rw-r--r--lib/libc/statvfs/fstatvfs.c25
-rw-r--r--lib/libc/statvfs/statvfs.c25
-rw-r--r--lib/libc/stdio/asprintf.c12
-rw-r--r--lib/libc/stdio/clearerr.c10
-rw-r--r--lib/libc/stdio/dprintf.c12
-rw-r--r--lib/libc/stdio/dtoa.c6249
-rw-r--r--lib/libc/stdio/fclose.c16
-rw-r--r--lib/libc/stdio/fdopen.c39
-rw-r--r--lib/libc/stdio/feof.c10
-rw-r--r--lib/libc/stdio/ferror.c10
-rw-r--r--lib/libc/stdio/fflush.c84
-rw-r--r--lib/libc/stdio/fgetc.c11
-rw-r--r--lib/libc/stdio/fgets.c9
-rw-r--r--lib/libc/stdio/fileno.c20
-rw-r--r--lib/libc/stdio/fmemopen.c46
-rw-r--r--lib/libc/stdio/fopen.c56
-rw-r--r--lib/libc/stdio/fprintf.c12
-rw-r--r--lib/libc/stdio/fputc.c27
-rw-r--r--lib/libc/stdio/fputs.c7
-rw-r--r--lib/libc/stdio/fread.c50
-rw-r--r--lib/libc/stdio/fseek.c28
-rw-r--r--lib/libc/stdio/ftell.c15
-rw-r--r--lib/libc/stdio/ftello.c9
-rw-r--r--lib/libc/stdio/fwrite.c147
-rw-r--r--lib/libc/stdio/getc.c9
-rw-r--r--lib/libc/stdio/getchar.c9
-rw-r--r--lib/libc/stdio/pclose.c10
-rw-r--r--lib/libc/stdio/perror.c26
-rw-r--r--lib/libc/stdio/popen.c65
-rw-r--r--lib/libc/stdio/printf.c12
-rw-r--r--lib/libc/stdio/putc.c9
-rw-r--r--lib/libc/stdio/putchar.c9
-rw-r--r--lib/libc/stdio/puts.c9
-rw-r--r--lib/libc/stdio/remove.c16
-rw-r--r--lib/libc/stdio/rename.c6
-rw-r--r--lib/libc/stdio/renameat.c6
-rw-r--r--lib/libc/stdio/rewind.c7
-rw-r--r--lib/libc/stdio/setbuf.c7
-rw-r--r--lib/libc/stdio/setvbuf.c20
-rw-r--r--lib/libc/stdio/snprintf.c12
-rw-r--r--lib/libc/stdio/sprintf.c13
-rw-r--r--lib/libc/stdio/stderr.c20
-rw-r--r--lib/libc/stdio/stdin.c18
-rw-r--r--lib/libc/stdio/stdout.c34
-rw-r--r--lib/libc/stdio/vasprintf.c18
-rw-r--r--lib/libc/stdio/vdprintf.c12
-rw-r--r--lib/libc/stdio/vfprintf.c809
-rw-r--r--lib/libc/stdio/vprintf.c6
-rw-r--r--lib/libc/stdio/vsnprintf.c45
-rw-r--r--lib/libc/stdio/vsprintf.c7
-rw-r--r--lib/libc/stdlib/_Exit.c6
-rw-r--r--lib/libc/stdlib/__mb_cur_max.c6
-rw-r--r--lib/libc/stdlib/abort.c27
-rw-r--r--lib/libc/stdlib/abs.c4
-rw-r--r--lib/libc/stdlib/aligned_alloc.c39
-rw-r--r--lib/libc/stdlib/atexit.c16
-rw-r--r--lib/libc/stdlib/atof.c6
-rw-r--r--lib/libc/stdlib/atoi.c6
-rw-r--r--lib/libc/stdlib/atol.c6
-rw-r--r--lib/libc/stdlib/atoll.c6
-rw-r--r--lib/libc/stdlib/bsearch.c87
-rw-r--r--lib/libc/stdlib/btowc.c18
-rw-r--r--lib/libc/stdlib/calloc.c25
-rw-r--r--lib/libc/stdlib/div.c9
-rw-r--r--lib/libc/stdlib/exit.c69
-rw-r--r--lib/libc/stdlib/free.c101
-rw-r--r--lib/libc/stdlib/getenv.c33
-rw-r--r--lib/libc/stdlib/heapsort.c191
-rw-r--r--lib/libc/stdlib/heapsort_r.c191
-rw-r--r--lib/libc/stdlib/labs.c6
-rw-r--r--lib/libc/stdlib/ldiv.c9
-rw-r--r--lib/libc/stdlib/llabs.c6
-rw-r--r--lib/libc/stdlib/lldiv.c9
-rw-r--r--lib/libc/stdlib/malloc.c181
-rw-r--r--lib/libc/stdlib/posix_memalign.c31
-rw-r--r--lib/libc/stdlib/putenv.c17
-rw-r--r--lib/libc/stdlib/qsort.c12
-rw-r--r--lib/libc/stdlib/qsort_r.c243
-rw-r--r--lib/libc/stdlib/quick_exit.c6
-rw-r--r--lib/libc/stdlib/rand.c182
-rw-r--r--lib/libc/stdlib/realloc.c47
-rw-r--r--lib/libc/stdlib/reallocarray.c14
-rw-r--r--lib/libc/stdlib/setenv.c58
-rw-r--r--lib/libc/stdlib/strtox.c270
-rw-r--r--lib/libc/stdlib/system.c7
-rw-r--r--lib/libc/stdlib/unsetenv.c13
-rw-r--r--lib/libc/stdlib/wctomb.c9
-rw-r--r--lib/libc/string/memccpy.c13
-rw-r--r--lib/libc/string/memchr.c12
-rw-r--r--lib/libc/string/memcmp.c14
-rw-r--r--lib/libc/string/memcpy.c16
-rw-r--r--lib/libc/string/memmem.c15
-rw-r--r--lib/libc/string/memmove.c21
-rw-r--r--lib/libc/string/memset.c10
-rw-r--r--lib/libc/string/stpcpy.c8
-rw-r--r--lib/libc/string/stpncpy.c14
-rw-r--r--lib/libc/string/strcat.c14
-rw-r--r--lib/libc/string/strchr.c13
-rw-r--r--lib/libc/string/strcmp.c23
-rw-r--r--lib/libc/string/strcoll.c13
-rw-r--r--lib/libc/string/strcpy.c7
-rw-r--r--lib/libc/string/strcspn.c11
-rw-r--r--lib/libc/string/strdup.c12
-rw-r--r--lib/libc/string/strerror.c125
-rw-r--r--lib/libc/string/strlcat.c19
-rw-r--r--lib/libc/string/strlcpy.c16
-rw-r--r--lib/libc/string/strlen.c14
-rw-r--r--lib/libc/string/strncat.c19
-rw-r--r--lib/libc/string/strncmp.c16
-rw-r--r--lib/libc/string/strncpy.c16
-rw-r--r--lib/libc/string/strndup.c15
-rw-r--r--lib/libc/string/strnlen.c11
-rw-r--r--lib/libc/string/strpbrk.c16
-rw-r--r--lib/libc/string/strrchr.c12
-rw-r--r--lib/libc/string/strspn.c12
-rw-r--r--lib/libc/string/strstr.c27
-rw-r--r--lib/libc/string/strtok.c40
-rw-r--r--lib/libc/string/strtok_r.c37
-rw-r--r--lib/libc/string/strxfrm.c18
-rw-r--r--lib/libc/strings/ffs.c14
-rw-r--r--lib/libc/strings/ffsl.c14
-rw-r--r--lib/libc/strings/ffsll.c14
-rw-r--r--lib/libc/strings/strcasecmp.c24
-rw-r--r--lib/libc/strings/strncasecmp.c32
-rw-r--r--lib/libc/sys/ioctl.c13
-rw-r--r--lib/libc/sys/mount.c8
-rw-r--r--lib/libc/sys/umount.c6
-rw-r--r--lib/libc/sys/umount2.c6
-rw-r--r--lib/libc/syslog/closelog.c7
-rw-r--r--lib/libc/syslog/openlog.c7
-rw-r--r--lib/libc/syslog/setlogmask.c7
-rw-r--r--lib/libc/syslog/syslog.c7
-rw-r--r--lib/libc/termios/cfgetispeed.c6
-rw-r--r--lib/libc/termios/cfgetospeed.c6
-rw-r--r--lib/libc/termios/cfsetispeed.c14
-rw-r--r--lib/libc/termios/cfsetospeed.c13
-rw-r--r--lib/libc/termios/tcdrain.c7
-rw-r--r--lib/libc/termios/tcflow.c7
-rw-r--r--lib/libc/termios/tcflush.c8
-rw-r--r--lib/libc/termios/tcgetattr.c9
-rw-r--r--lib/libc/termios/tcgetsid.c13
-rw-r--r--lib/libc/termios/tcgetwinsize.c23
-rw-r--r--lib/libc/termios/tcsendbreak.c11
-rw-r--r--lib/libc/termios/tcsetattr.c14
-rw-r--r--lib/libc/termios/tcsetwinsize.c8
-rw-r--r--lib/libc/thread/thrd_current.c9
-rw-r--r--lib/libc/time/asctime.c19
-rw-r--r--lib/libc/time/clock.c16
-rw-r--r--lib/libc/time/clock_getcpuclockid.c18
-rw-r--r--lib/libc/time/clock_getres.c7
-rw-r--r--lib/libc/time/clock_nanosleep.c8
-rw-r--r--lib/libc/time/ctime.c6
-rw-r--r--lib/libc/time/difftime.c6
-rw-r--r--lib/libc/time/gmtime_r.c42
-rw-r--r--lib/libc/time/localtime.c7
-rw-r--r--lib/libc/time/localtime_r.c7
-rw-r--r--lib/libc/time/nanosleep.c7
-rw-r--r--lib/libc/time/strftime.c562
-rw-r--r--lib/libc/time/time.c20
-rw-r--r--lib/libc/time/tzset.c58
-rw-r--r--lib/libc/time/utimes.c25
-rw-r--r--lib/libc/times/times.c7
-rw-r--r--lib/libc/uio/readv.c55
-rw-r--r--lib/libc/uio/writev.c49
-rw-r--r--lib/libc/unistd/_Fork.c8
-rw-r--r--lib/libc/unistd/_exit.c7
-rw-r--r--lib/libc/unistd/access.c6
-rw-r--r--lib/libc/unistd/alarm.c6
-rw-r--r--lib/libc/unistd/chdir.c6
-rw-r--r--lib/libc/unistd/chown.c7
-rw-r--r--lib/libc/unistd/close.c6
-rw-r--r--lib/libc/unistd/dup.c6
-rw-r--r--lib/libc/unistd/dup2.c6
-rw-r--r--lib/libc/unistd/dup3.c6
-rw-r--r--lib/libc/unistd/execl.c26
-rw-r--r--lib/libc/unistd/execlp.c27
-rw-r--r--lib/libc/unistd/execv.c9
-rw-r--r--lib/libc/unistd/execve.c6
-rw-r--r--lib/libc/unistd/execvp.c55
-rw-r--r--lib/libc/unistd/faccessat.c6
-rw-r--r--lib/libc/unistd/fchdir.c6
-rw-r--r--lib/libc/unistd/fchown.c7
-rw-r--r--lib/libc/unistd/fchownat.c7
-rw-r--r--lib/libc/unistd/fdatasync.c6
-rw-r--r--lib/libc/unistd/fork.c6
-rw-r--r--lib/libc/unistd/fsync.c6
-rw-r--r--lib/libc/unistd/ftruncate.c7
-rw-r--r--lib/libc/unistd/getcwd.c7
-rw-r--r--lib/libc/unistd/getegid.c7
-rw-r--r--lib/libc/unistd/getentropy.c8
-rw-r--r--lib/libc/unistd/geteuid.c7
-rw-r--r--lib/libc/unistd/getgid.c7
-rw-r--r--lib/libc/unistd/getgroups.c7
-rw-r--r--lib/libc/unistd/gethostid.c7
-rw-r--r--lib/libc/unistd/gethostname.c8
-rw-r--r--lib/libc/unistd/getlogin.c7
-rw-r--r--lib/libc/unistd/getlogin_r.c8
-rw-r--r--lib/libc/unistd/getopt.c114
-rw-r--r--lib/libc/unistd/getpgid.c7
-rw-r--r--lib/libc/unistd/getpid.c7
-rw-r--r--lib/libc/unistd/getppid.c7
-rw-r--r--lib/libc/unistd/getresgid.c7
-rw-r--r--lib/libc/unistd/getresuid.c7
-rw-r--r--lib/libc/unistd/getsid.c7
-rw-r--r--lib/libc/unistd/getuid.c7
-rw-r--r--lib/libc/unistd/isatty.c10
-rw-r--r--lib/libc/unistd/lchown.c7
-rw-r--r--lib/libc/unistd/link.c7
-rw-r--r--lib/libc/unistd/linkat.c7
-rw-r--r--lib/libc/unistd/lockf.c8
-rw-r--r--lib/libc/unistd/lseek.c7
-rw-r--r--lib/libc/unistd/nice.c8
-rw-r--r--lib/libc/unistd/pause.c6
-rw-r--r--lib/libc/unistd/pipe.c6
-rw-r--r--lib/libc/unistd/pipe2.c6
-rw-r--r--lib/libc/unistd/posix_close.c7
-rw-r--r--lib/libc/unistd/pread.c7
-rw-r--r--lib/libc/unistd/pwrite.c7
-rw-r--r--lib/libc/unistd/read.c7
-rw-r--r--lib/libc/unistd/readlink.c7
-rw-r--r--lib/libc/unistd/readlinkat.c8
-rw-r--r--lib/libc/unistd/rmdir.c6
-rw-r--r--lib/libc/unistd/setegid.c7
-rw-r--r--lib/libc/unistd/seteuid.c7
-rw-r--r--lib/libc/unistd/setgid.c7
-rw-r--r--lib/libc/unistd/setpgid.c7
-rw-r--r--lib/libc/unistd/setregid.c7
-rw-r--r--lib/libc/unistd/setresgid.c7
-rw-r--r--lib/libc/unistd/setresuid.c7
-rw-r--r--lib/libc/unistd/setreuid.c7
-rw-r--r--lib/libc/unistd/setsid.c7
-rw-r--r--lib/libc/unistd/setuid.c7
-rw-r--r--lib/libc/unistd/sleep.c10
-rw-r--r--lib/libc/unistd/swab.c17
-rw-r--r--lib/libc/unistd/symlink.c6
-rw-r--r--lib/libc/unistd/symlinkat.c7
-rw-r--r--lib/libc/unistd/sync.c6
-rw-r--r--lib/libc/unistd/truncate.c7
-rw-r--r--lib/libc/unistd/unlink.c6
-rw-r--r--lib/libc/unistd/unlinkat.c6
-rw-r--r--lib/libc/unistd/write.c7
-rw-r--r--lib/libc/utsname/uname.c7
-rw-r--r--lib/libc/wait/wait.c7
-rw-r--r--lib/libc/wait/waitid.c7
-rw-r--r--lib/libc/wait/waitpid.c7
-rw-r--r--lib/libc/wchar/wctob.c16
-rw-r--r--lib/libc/wctype/iswalnum.c12
-rw-r--r--lib/libc/wctype/iswalpha.c22
-rw-r--r--lib/libc/wctype/iswblank.c13
-rw-r--r--lib/libc/wctype/iswdigit.c12
-rw-r--r--lib/libc/wctype/iswgraph.c12
-rw-r--r--lib/libc/wctype/iswlower.c12
-rw-r--r--lib/libc/wctype/iswprint.c14
-rw-r--r--lib/libc/wctype/iswpunct.c327
-rw-r--r--lib/libc/wctype/iswspace.c20
-rw-r--r--lib/libc/wctype/iswupper.c12
-rw-r--r--lib/libc/wctype/iswxdigit.c12
-rw-r--r--lib/libc/wctype/towctrans.c348
-rw-r--r--lib/libc/wctype/wctype.c32
419 files changed, 16626 insertions, 0 deletions
diff --git a/lib/libc/Kbuild b/lib/libc/Kbuild
new file mode 100644
index 00000000..dc0538a6
--- /dev/null
+++ b/lib/libc/Kbuild
@@ -0,0 +1,44 @@
+lib-y := libc.a
+
+cflags-y += -I $(src)/include
+
+obj-y += arch/
+obj-y += arpa/
+obj-y += assert/
+obj-y += ctype/
+obj-y += devctl/
+obj-y += dirent/
+obj-y += endian/
+obj-y += errno/
+obj-y += fcntl/
+obj-y += grp/
+obj-y += inttypes/
+obj-y += libgen/
+obj-y += mman/
+obj-y += monetary/
+obj-y += msg/
+obj-y += poll/
+obj-y += pwd/
+obj-y += select/
+obj-y += sem/
+obj-y += setjmp/
+obj-y += signal/
+obj-y += socket/
+obj-y += stat/
+obj-y += statvfs/
+obj-y += stdio/
+obj-y += stdlib/
+obj-y += string/
+obj-y += strings/
+obj-y += sys/
+obj-y += syslog/
+obj-y += termios/
+obj-y += thread/
+obj-y += time/
+obj-y += times/
+obj-y += uio/
+obj-y += unistd/
+obj-y += utsname/
+obj-y += wait/
+obj-y += wchar/
+obj-y += wctype/
diff --git a/lib/libc/arch/Kbuild b/lib/libc/arch/Kbuild
new file mode 100644
index 00000000..ad3a7486
--- /dev/null
+++ b/lib/libc/arch/Kbuild
@@ -0,0 +1 @@
+obj-y += $(ARCH)/
diff --git a/lib/libc/arch/x86_64/Kbuild b/lib/libc/arch/x86_64/Kbuild
new file mode 100644
index 00000000..fc8a2d3f
--- /dev/null
+++ b/lib/libc/arch/x86_64/Kbuild
@@ -0,0 +1,7 @@
+obj-y += clock_gettime.o
+obj-y += crt0.o
+obj-y += fenv.o
+obj-y += longjmp.o
+obj-y += setjmp.o
+obj-y += sigsetjmp.o
+obj-y += vdso_setup.o
diff --git a/lib/libc/arch/x86_64/clock_gettime.c b/lib/libc/arch/x86_64/clock_gettime.c
new file mode 100644
index 00000000..6a7a3874
--- /dev/null
+++ b/lib/libc/arch/x86_64/clock_gettime.c
@@ -0,0 +1,13 @@
+#include <asm/vdso.h>
+#include <syscall.h>
+#include <time.h>
+
+int clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+#if defined(__x86_64__)
+ if (__vdso_clock_gettime)
+ return __vdso_clock_gettime(clock_id, tp);
+#endif
+
+ return syscall(clock_gettime, clock_id, tp);
+}
diff --git a/lib/libc/arch/x86_64/crt0.c b/lib/libc/arch/x86_64/crt0.c
new file mode 100644
index 00000000..2c7943ff
--- /dev/null
+++ b/lib/libc/arch/x86_64/crt0.c
@@ -0,0 +1,59 @@
+#include <linux/auxvec.h>
+#include <linux/elf.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <thread.h>
+#include <unistd.h>
+
+#define weak_reference(old, new) \
+ extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
+
+extern int main(int, char *[]);
+char **environ;
+
+static struct __thread_self thread = { .tid = 0, ._errno = 0 };
+
+struct __attribute__((packed)) auxv_t {
+ uintptr_t a_type;
+ uintptr_t a_val;
+} *__auxv;
+
+static void __vdso_setup(Elf64_Ehdr *vdso_addr __attribute__((unused)))
+{
+}
+
+weak_reference(__vdso_setup, vdso_setup);
+
+__attribute__((used)) void __libc_start(uintptr_t *sp)
+{
+ char **argv;
+ int argc;
+
+ argc = (int)(*sp);
+ argv = (char **)(++sp);
+ sp += argc;
+ environ = (char **)(++sp);
+
+ while (*sp)
+ sp++;
+
+ __auxv = (struct auxv_t *)(++sp);
+ while (__auxv->a_type != AT_NULL) {
+ if (__auxv->a_type == AT_SYSINFO_EHDR) {
+ vdso_setup((Elf64_Ehdr *)__auxv->a_val);
+ }
+
+ __auxv++;
+ }
+
+ __asm__ volatile("wrfsbase %0" ::"r"(thread));
+
+ exit(main(argc, argv));
+}
+
+__attribute__((noreturn, naked)) void _start(void)
+{
+ __asm__ __volatile__("mov %rsp, %rdi\n"
+ "call __libc_start\n");
+}
diff --git a/lib/libc/arch/x86_64/fenv.s b/lib/libc/arch/x86_64/fenv.s
new file mode 100644
index 00000000..b9a46581
--- /dev/null
+++ b/lib/libc/arch/x86_64/fenv.s
@@ -0,0 +1,97 @@
+.global feclearexcept
+.type feclearexcept,@function
+feclearexcept:
+ mov %edi,%ecx
+ and $0x3f,%ecx
+ fnstsw %ax
+ test %eax,%ecx
+ jz 1f
+ fnclex
+1: stmxcsr -8(%rsp)
+ and $0x3f,%eax
+ or %eax,-8(%rsp)
+ test %ecx,-8(%rsp)
+ jz 1f
+ not %ecx
+ and %ecx,-8(%rsp)
+ ldmxcsr -8(%rsp)
+1: xor %eax,%eax
+ ret
+
+.global feraiseexcept
+.type feraiseexcept,@function
+feraiseexcept:
+ and $0x3f,%edi
+ stmxcsr -8(%rsp)
+ or %edi,-8(%rsp)
+ ldmxcsr -8(%rsp)
+ xor %eax,%eax
+ ret
+
+.global __fesetround
+.hidden __fesetround
+.type __fesetround,@function
+__fesetround:
+ push %rax
+ xor %eax,%eax
+ mov %edi,%ecx
+ fnstcw (%rsp)
+ andb $0xf3,1(%rsp)
+ or %ch,1(%rsp)
+ fldcw (%rsp)
+ stmxcsr (%rsp)
+ shl $3,%ch
+ andb $0x9f,1(%rsp)
+ or %ch,1(%rsp)
+ ldmxcsr (%rsp)
+ pop %rcx
+ ret
+
+.global fegetround
+.type fegetround,@function
+fegetround:
+ push %rax
+ stmxcsr (%rsp)
+ pop %rax
+ shr $3,%eax
+ and $0xc00,%eax
+ ret
+
+.global fegetenv
+.type fegetenv,@function
+fegetenv:
+ xor %eax,%eax
+ fnstenv (%rdi)
+ stmxcsr 28(%rdi)
+ ret
+
+.global fesetenv
+.type fesetenv,@function
+fesetenv:
+ xor %eax,%eax
+ inc %rdi
+ jz 1f
+ fldenv -1(%rdi)
+ ldmxcsr 27(%rdi)
+ ret
+1: push %rax
+ push %rax
+ pushq $0xffff
+ pushq $0x37f
+ fldenv (%rsp)
+ pushq $0x1f80
+ ldmxcsr (%rsp)
+ add $40,%rsp
+ ret
+
+.global fetestexcept
+.type fetestexcept,@function
+fetestexcept:
+ and $0x3f,%edi
+ push %rax
+ stmxcsr (%rsp)
+ pop %rsi
+ fnstsw %ax
+ or %esi,%eax
+ and %edi,%eax
+ ret
diff --git a/lib/libc/arch/x86_64/longjmp.c b/lib/libc/arch/x86_64/longjmp.c
new file mode 100644
index 00000000..6aed69a5
--- /dev/null
+++ b/lib/libc/arch/x86_64/longjmp.c
@@ -0,0 +1,18 @@
+#include <setjmp.h>
+
+__attribute__((noreturn, naked, returns_twice)) void longjmp(jmp_buf env,
+ int val)
+{
+ __asm__ __volatile__("mov 0(%rdi), %rbx\n"
+ "mov 8(%rdi), %rbp\n"
+ "mov 16(%rdi), %r12\n"
+ "mov 24(%rdi), %r13\n"
+ "mov 32(%rdi), %r14\n"
+ "mov 40(%rdi), %r15\n"
+ "mov 48(%rdi), %rsp\n"
+ "xor %rax, %rax\n"
+ "cmp $0, %esi\n"
+ "setne %al\n"
+ "mov %eax, %eax\n"
+ "jmp *56(%rdi)\n");
+}
diff --git a/lib/libc/arch/x86_64/setjmp.c b/lib/libc/arch/x86_64/setjmp.c
new file mode 100644
index 00000000..d268ae25
--- /dev/null
+++ b/lib/libc/arch/x86_64/setjmp.c
@@ -0,0 +1,17 @@
+#include <setjmp.h>
+
+__attribute__((naked, returns_twice)) int setjmp(jmp_buf env)
+{
+ __asm__ __volatile__("mov %rbx,(%rdi)\n"
+ "mov %rbp,8(%rdi)\n"
+ "mov %r12,16(%rdi)\n"
+ "mov %r13,24(%rdi)\n"
+ "mov %r14,32(%rdi)\n"
+ "mov %r15,40(%rdi)\n"
+ "lea 8(%rsp),%rdx\n"
+ "mov %rdx,48(%rdi)\n"
+ "mov (%rsp),%rdx\n"
+ "mov %rdx,56(%rdi)\n"
+ "xor %eax,%eax\n"
+ "ret\n");
+}
diff --git a/lib/libc/arch/x86_64/sigsetjmp.c b/lib/libc/arch/x86_64/sigsetjmp.c
new file mode 100644
index 00000000..d4c0a4db
--- /dev/null
+++ b/lib/libc/arch/x86_64/sigsetjmp.c
@@ -0,0 +1,33 @@
+#include <setjmp.h>
+
+int sigsetjmp(sigjmp_buf env, int savemask)
+{
+ __asm__ __volatile__("movq %%rbx, 0(%0)\n"
+ "movq %%rbp, 8(%0)\n"
+ "movq %%r12, 16(%0)\n"
+ "movq %%r13, 24(%0)\n"
+ "movq %%r14, 32(%0)\n"
+ "movq %%r15, 40(%0)\n"
+
+ "leaq 8(%%rsp), %%rax\n"
+ "movq %%rax, 48(%0)\n"
+ "movq (%%rsp), %%rax\n"
+ "movq %%rax, 56(%0)\n"
+
+ "testl %%esi, %%esi\n"
+ "jz 1f\n"
+ "movq $2, %%rdi\n"
+ "movq $0, %%rsi\n"
+ "leaq 64(%0), %%rdx\n"
+ "movq $128, %%r10\n"
+ "movq $14, %%rax\n"
+ "syscall\n"
+
+ "1:\n"
+ "xor %%eax, %%eax\n"
+ :
+ : "r"(env), "S"(savemask)
+ : "rax", "rdi", "rdx", "r10", "memory");
+
+ return 0;
+}
diff --git a/lib/libc/arch/x86_64/vdso_setup.c b/lib/libc/arch/x86_64/vdso_setup.c
new file mode 100644
index 00000000..c410995d
--- /dev/null
+++ b/lib/libc/arch/x86_64/vdso_setup.c
@@ -0,0 +1,62 @@
+#include <linux/auxvec.h>
+#include <linux/elf.h>
+#include <string.h>
+#include <time.h>
+
+int (*__vdso_clock_gettime)(int, struct timespec *) = NULL;
+int (*__vdso_getcpu)(unsigned *, unsigned *, void *) = NULL;
+int (*__vdso_time)(long *) = NULL;
+
+static __inline __attribute__((used)) void vdso_setup(Elf64_Ehdr *vdso_addr)
+{
+ Elf64_Phdr *phdr =
+ (Elf64_Phdr *)((char *)vdso_addr + vdso_addr->e_phoff);
+
+ for (int i = 0; i < vdso_addr->e_phnum; i++) {
+ if (phdr[i].p_type == PT_DYNAMIC) {
+ Elf64_Dyn *dyn = (Elf64_Dyn *)((char *)vdso_addr +
+ phdr[i].p_offset);
+ const char *strtab = NULL;
+ Elf64_Sym *symtab = NULL;
+ for (; dyn->d_tag != DT_NULL; dyn++) {
+ if (dyn->d_tag == DT_STRTAB) {
+ strtab = (const char *)vdso_addr +
+ dyn->d_un.d_ptr;
+ } else if (dyn->d_tag == DT_SYMTAB) {
+ symtab =
+ (Elf64_Sym *)((char *)vdso_addr +
+ dyn->d_un.d_ptr);
+ }
+ }
+
+ if (strtab == NULL || symtab == NULL) {
+ return;
+ }
+
+ Elf64_Sym *sym = symtab;
+ while ((char *)sym < (char *)strtab) {
+ if (sym->st_name != 0 && sym->st_value != 0) {
+ const char *name =
+ strtab + sym->st_name;
+ if (strcmp(name,
+ "__vdso_clock_gettime") == 0)
+ __vdso_clock_gettime =
+ (void *)(vdso_addr +
+ sym->st_value);
+ else if (strcmp(name,
+ "__vdso_getcpu") == 0)
+ __vdso_getcpu =
+ (void *)(vdso_addr +
+ sym->st_value);
+ else if (strcmp(name, "__vdso_time") ==
+ 0)
+ __vdso_time =
+ (void *)(vdso_addr +
+ sym->st_value);
+ }
+ sym = (Elf64_Sym *)((char *)sym +
+ sizeof(Elf64_Sym));
+ }
+ }
+ }
+}
diff --git a/lib/libc/arpa/Kbuild b/lib/libc/arpa/Kbuild
new file mode 100644
index 00000000..3714bea3
--- /dev/null
+++ b/lib/libc/arpa/Kbuild
@@ -0,0 +1,8 @@
+obj-y += htonl.o
+obj-y += htons.o
+obj-y += inet_addr.o
+obj-y += inet_ntoa.o
+obj-y += inet_ntop.o
+obj-y += inet_pton.o
+obj-y += ntohl.o
+obj-y += ntohs.o
diff --git a/lib/libc/arpa/htonl.c b/lib/libc/arpa/htonl.c
new file mode 100644
index 00000000..96f3ba4e
--- /dev/null
+++ b/lib/libc/arpa/htonl.c
@@ -0,0 +1,12 @@
+#include <arpa/inet.h>
+#include <byteswap.h>
+
+uint32_t htonl(uint32_t hostlong)
+{
+ union {
+ int i;
+ char c;
+ } u = { 1 };
+
+ return u.c ? bswap32(hostlong) : hostlong;
+}
diff --git a/lib/libc/arpa/htons.c b/lib/libc/arpa/htons.c
new file mode 100644
index 00000000..7c8dcc51
--- /dev/null
+++ b/lib/libc/arpa/htons.c
@@ -0,0 +1,12 @@
+#include <arpa/inet.h>
+#include <byteswap.h>
+
+uint16_t htons(uint16_t hostshort)
+{
+ union {
+ int i;
+ char c;
+ } u = { 1 };
+
+ return u.c ? bswap16(hostshort) : hostshort;
+}
diff --git a/lib/libc/arpa/inet_addr.c b/lib/libc/arpa/inet_addr.c
new file mode 100644
index 00000000..5514e966
--- /dev/null
+++ b/lib/libc/arpa/inet_addr.c
@@ -0,0 +1,8 @@
+#include <arpa/inet.h>
+
+in_addr_t inet_addr(const char *cp)
+{
+ (void)cp;
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/arpa/inet_ntoa.c b/lib/libc/arpa/inet_ntoa.c
new file mode 100644
index 00000000..9d4f9b23
--- /dev/null
+++ b/lib/libc/arpa/inet_ntoa.c
@@ -0,0 +1,8 @@
+#include <arpa/inet.h>
+
+char *inet_ntoa(struct in_addr in)
+{
+ (void)in;
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/arpa/inet_ntop.c b/lib/libc/arpa/inet_ntop.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/libc/arpa/inet_ntop.c
diff --git a/lib/libc/arpa/inet_pton.c b/lib/libc/arpa/inet_pton.c
new file mode 100644
index 00000000..7cbb37da
--- /dev/null
+++ b/lib/libc/arpa/inet_pton.c
@@ -0,0 +1,10 @@
+#include <arpa/inet.h>
+
+int inet_pton(int af, const char *restrict src, void *restrict dst)
+{
+ (void)af;
+ (void)src;
+ (void)dst;
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/arpa/ntohl.c b/lib/libc/arpa/ntohl.c
new file mode 100644
index 00000000..0adcbc5f
--- /dev/null
+++ b/lib/libc/arpa/ntohl.c
@@ -0,0 +1,12 @@
+#include <arpa/inet.h>
+#include <byteswap.h>
+
+uint32_t ntohl(uint32_t netlong)
+{
+ union {
+ int i;
+ char c;
+ } u = { 1 };
+
+ return u.c ? bswap32(netlong) : netlong;
+}
diff --git a/lib/libc/arpa/ntohs.c b/lib/libc/arpa/ntohs.c
new file mode 100644
index 00000000..c0f868bc
--- /dev/null
+++ b/lib/libc/arpa/ntohs.c
@@ -0,0 +1,12 @@
+#include <arpa/inet.h>
+#include <byteswap.h>
+
+uint16_t ntohs(uint16_t netshort)
+{
+ union {
+ int i;
+ char c;
+ } u = { 1 };
+
+ return u.c ? bswap16(netshort) : netshort;
+}
diff --git a/lib/libc/assert/assert.c b/lib/libc/assert/assert.c
new file mode 100644
index 00000000..a694da2c
--- /dev/null
+++ b/lib/libc/assert/assert.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+_Noreturn void __assert(const char *_Nonnull __file, int __line,
+ const char *_Nonnull __func,
+ const char *_Nonnull __expr)
+{
+ fprintf(stderr, "%s:%d: %s: assertion \"%s\" failed\n", __file, __line,
+ __func, __expr);
+ abort();
+}
diff --git a/lib/libc/ctype/isalnum.c b/lib/libc/ctype/isalnum.c
new file mode 100644
index 00000000..04e94fc6
--- /dev/null
+++ b/lib/libc/ctype/isalnum.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <ctype.h>
+
+int isalnum(int c)
+{
+ return isalpha(c) || isdigit(c);
+}
+
+weak int isalnum_l(int c, locale_t unused locale)
+{
+ return isalnum(c);
+}
diff --git a/lib/libc/ctype/isalpha.c b/lib/libc/ctype/isalpha.c
new file mode 100644
index 00000000..d046c09e
--- /dev/null
+++ b/lib/libc/ctype/isalpha.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isalpha(int c)
+{
+ return ((unsigned)c | 32) - 'a' < 26;
+}
+
+weak_reference(isalpha, isalpha_l);
diff --git a/lib/libc/ctype/isblank.c b/lib/libc/ctype/isblank.c
new file mode 100644
index 00000000..7ad08709
--- /dev/null
+++ b/lib/libc/ctype/isblank.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isblank(int c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+weak_reference(isblank, isblank_l);
diff --git a/lib/libc/ctype/iscntrl.c b/lib/libc/ctype/iscntrl.c
new file mode 100644
index 00000000..6d4ff5a8
--- /dev/null
+++ b/lib/libc/ctype/iscntrl.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int iscntrl(int c)
+{
+ return (unsigned)c < 0x20 || c == 0x7f;
+}
+
+weak_reference(iscntrl, iscntrl_l);
diff --git a/lib/libc/ctype/isdigit.c b/lib/libc/ctype/isdigit.c
new file mode 100644
index 00000000..445e1cdc
--- /dev/null
+++ b/lib/libc/ctype/isdigit.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isdigit(int c)
+{
+ return (unsigned)c - '0' < 10;
+}
+
+weak_reference(isdigit, isdigit_l);
diff --git a/lib/libc/ctype/isgraph.c b/lib/libc/ctype/isgraph.c
new file mode 100644
index 00000000..03919200
--- /dev/null
+++ b/lib/libc/ctype/isgraph.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isgraph(int c)
+{
+ return (unsigned)c - 0x21 < 0x5e;
+}
+
+weak_reference(isgraph, isgraph_l);
diff --git a/lib/libc/ctype/islower.c b/lib/libc/ctype/islower.c
new file mode 100644
index 00000000..34980da6
--- /dev/null
+++ b/lib/libc/ctype/islower.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int islower(int c)
+{
+ return (unsigned)c - 'a' < 26;
+}
+
+weak_reference(islower, islower_l);
diff --git a/lib/libc/ctype/isprint.c b/lib/libc/ctype/isprint.c
new file mode 100644
index 00000000..76524050
--- /dev/null
+++ b/lib/libc/ctype/isprint.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isprint(int c)
+{
+ return (unsigned)c - 0x20 < 0x5f;
+}
+
+weak_reference(isprint, isprint_l);
diff --git a/lib/libc/ctype/ispunct.c b/lib/libc/ctype/ispunct.c
new file mode 100644
index 00000000..2bd08c38
--- /dev/null
+++ b/lib/libc/ctype/ispunct.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <ctype.h>
+
+int ispunct(int c)
+{
+ return isgraph(c) && !isalnum(c);
+}
+
+weak int ispunct_l(int c, locale_t locale)
+{
+ return ispunct(c);
+}
diff --git a/lib/libc/ctype/isspace.c b/lib/libc/ctype/isspace.c
new file mode 100644
index 00000000..86630c66
--- /dev/null
+++ b/lib/libc/ctype/isspace.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isspace(int c)
+{
+ return c == ' ' || (unsigned)c - '\t' < 5;
+}
+
+weak_reference(isspace, isspace_l);
diff --git a/lib/libc/ctype/isupper.c b/lib/libc/ctype/isupper.c
new file mode 100644
index 00000000..458990df
--- /dev/null
+++ b/lib/libc/ctype/isupper.c
@@ -0,0 +1,8 @@
+#include <libc.h>
+
+int isupper(int c)
+{
+ return (unsigned)c - 'A' < 26;
+}
+
+weak_reference(isupper, isupper_l);
diff --git a/lib/libc/ctype/isxdigit.c b/lib/libc/ctype/isxdigit.c
new file mode 100644
index 00000000..588df77a
--- /dev/null
+++ b/lib/libc/ctype/isxdigit.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isxdigit(int c)
+{
+ return isdigit(c) || ((unsigned)c | 32) - 'a' < 6;
+}
diff --git a/lib/libc/ctype/tolower.c b/lib/libc/ctype/tolower.c
new file mode 100644
index 00000000..abeab42a
--- /dev/null
+++ b/lib/libc/ctype/tolower.c
@@ -0,0 +1,14 @@
+#include <libc.h>
+#include <ctype.h>
+
+int tolower(int c)
+{
+ if (isupper(c))
+ return c | 32;
+ return c;
+}
+
+weak int tolower_l(int c, locale_t unused locale)
+{
+ return tolower(c);
+}
diff --git a/lib/libc/ctype/toupper.c b/lib/libc/ctype/toupper.c
new file mode 100644
index 00000000..e952acd9
--- /dev/null
+++ b/lib/libc/ctype/toupper.c
@@ -0,0 +1,14 @@
+#include <libc.h>
+#include <ctype.h>
+
+int toupper(int c)
+{
+ if (islower(c))
+ return c & 0x5f;
+ return c;
+}
+
+int toupper_l(int c, locale_t unused locale)
+{
+ return toupper(c);
+}
diff --git a/lib/libc/devctl/posix_devctl.c b/lib/libc/devctl/posix_devctl.c
new file mode 100644
index 00000000..bc8e7331
--- /dev/null
+++ b/lib/libc/devctl/posix_devctl.c
@@ -0,0 +1,17 @@
+#include <libc.h>
+#include <devctl.h>
+#include <errno.h>
+#include <syscall.h>
+
+int posix_devctl(int fildes, int dcmd, void *restrict dev_data_ptr,
+ size_t unused nbyte, int *restrict dev_info_ptr)
+{
+ long r;
+
+ if ((r = syscall(ioctl, fildes, dcmd, dev_data_ptr)) < 0)
+ return errno;
+
+ *dev_info_ptr = r;
+
+ return 0;
+}
diff --git a/lib/libc/dirent/closedir.c b/lib/libc/dirent/closedir.c
new file mode 100644
index 00000000..8a4ef3a7
--- /dev/null
+++ b/lib/libc/dirent/closedir.c
@@ -0,0 +1,17 @@
+#include <errno.h>
+#include <__dirent.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+int closedir(DIR *dirp)
+{
+ if (dirp->fildes >= 0) {
+ errno = EBADF;
+ return -1;
+ }
+
+ close(dirp->fildes);
+ free(dirp);
+ return 0;
+}
diff --git a/lib/libc/dirent/dirfd.c b/lib/libc/dirent/dirfd.c
new file mode 100644
index 00000000..857303de
--- /dev/null
+++ b/lib/libc/dirent/dirfd.c
@@ -0,0 +1,8 @@
+#include <__dirent.h>
+#include <dirent.h>
+#include <stdint.h>
+
+int dirfd(DIR *dirp)
+{
+ return ~((intptr_t)dirp);
+}
diff --git a/lib/libc/dirent/fdopendir.c b/lib/libc/dirent/fdopendir.c
new file mode 100644
index 00000000..469992c1
--- /dev/null
+++ b/lib/libc/dirent/fdopendir.c
@@ -0,0 +1,24 @@
+#include <errno.h>
+#include <__dirent.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+DIR *fdopendir(int fildes)
+{
+ DIR *dir;
+
+ if (fildes < 0) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ if ((dir = calloc(1, sizeof(DIR))) == NULL) {
+ return NULL;
+ }
+
+ dir->fildes = fildes;
+
+ return dir;
+}
diff --git a/lib/libc/dirent/opendir.c b/lib/libc/dirent/opendir.c
new file mode 100644
index 00000000..2e250024
--- /dev/null
+++ b/lib/libc/dirent/opendir.c
@@ -0,0 +1,15 @@
+#include <__dirent.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+DIR *opendir(const char *dirname)
+{
+ int fildes = open(dirname, O_RDONLY);
+
+ if (fildes < 0)
+ return NULL;
+
+ return fdopendir(fildes);
+}
diff --git a/lib/libc/dirent/readdir.c b/lib/libc/dirent/readdir.c
new file mode 100644
index 00000000..e4ac8cbd
--- /dev/null
+++ b/lib/libc/dirent/readdir.c
@@ -0,0 +1,16 @@
+#include <__dirent.h>
+#include <dirent.h>
+
+struct dirent *readdir(DIR *dirp)
+{
+ static struct dirent entry;
+ struct dirent *result;
+ int err;
+
+ err = readdir_r(dirp, &entry, &result);
+ if (err != 0 || result == NULL) {
+ return NULL;
+ }
+
+ return &entry;
+}
diff --git a/lib/libc/dirent/readdir_r.c b/lib/libc/dirent/readdir_r.c
new file mode 100644
index 00000000..9d8bf49b
--- /dev/null
+++ b/lib/libc/dirent/readdir_r.c
@@ -0,0 +1,140 @@
+/* Maintainer: <contact@bellrise.net> */
+
+#include <__dirent.h>
+#include <errno.h>
+#include <dirent.h>
+#include <syscall.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <stdio.h>
+
+int readdir_r(DIR *restrict dirp, struct dirent *restrict entry,
+ struct dirent **restrict result)
+{
+ struct linux_dirent64 *ldir = (void *)dirp->buffer;
+ ssize_t nread;
+ int ret;
+
+ if (dirp == NULL || entry == NULL || result == NULL) {
+ return EINVAL;
+ }
+
+ /* Clear the result entry to prevent garbage data */
+ memset(entry, 0, sizeof(*entry));
+
+ if (dirp->cached) {
+ ldir = (void *)(dirp->buffer + dirp->offset);
+
+ /* Validate buffer bounds */
+ if (dirp->offset >= sizeof(dirp->buffer) ||
+ dirp->offset + sizeof(struct linux_dirent64) >
+ sizeof(dirp->buffer)) {
+ dirp->cached = 0;
+ *result = NULL;
+ return 0;
+ }
+
+ /* Validate record length */
+ if (ldir->d_reclen <
+ offsetof(struct linux_dirent64, d_name) + 1 ||
+ dirp->offset + ldir->d_reclen > sizeof(dirp->buffer) ||
+ ldir->d_reclen == 0) {
+ dirp->cached = 0;
+ *result = NULL;
+ return 0;
+ }
+
+ entry->d_ino = ldir->d_ino;
+
+ /* Calculate available space for name */
+ size_t max_name_len = ldir->d_reclen -
+ offsetof(struct linux_dirent64, d_name);
+ if (max_name_len > sizeof(entry->d_name) - 1) {
+ max_name_len = sizeof(entry->d_name) - 1;
+ }
+
+ /* Find actual string length, bounded by available space */
+ size_t name_len = 0;
+ while (name_len < max_name_len &&
+ ldir->d_name[name_len] != '\0') {
+ name_len++;
+ }
+
+ memcpy(entry->d_name, ldir->d_name, name_len);
+ entry->d_name[name_len] = '\0';
+
+ dirp->cached--;
+ dirp->offset += ldir->d_reclen;
+ *result = entry;
+ return 0;
+ }
+
+ /* Clear cached entries and reset offset */
+ dirp->cached = 0;
+ dirp->offset = 0;
+
+ ret = syscall(getdents64, dirp->fildes, dirp->buffer,
+ sizeof(dirp->buffer));
+ if (ret < 0)
+ return errno;
+
+ if (ret == 0) {
+ *result = NULL;
+ return 0;
+ }
+
+ /* Read first entry from buffer. */
+ nread = ret;
+
+ /* Validate first entry bounds */
+ if (nread < sizeof(struct linux_dirent64) ||
+ ldir->d_reclen < offsetof(struct linux_dirent64, d_name) + 1 ||
+ ldir->d_reclen > nread || ldir->d_reclen == 0) {
+ *result = NULL;
+ return EINVAL;
+ }
+
+ dirp->offset = ldir->d_reclen;
+ entry->d_ino = ldir->d_ino;
+
+ /* Calculate available space for name */
+ size_t max_name_len =
+ ldir->d_reclen - offsetof(struct linux_dirent64, d_name);
+ if (max_name_len > sizeof(entry->d_name) - 1) {
+ max_name_len = sizeof(entry->d_name) - 1;
+ }
+
+ /* Find actual string length, bounded by available space */
+ size_t name_len = 0;
+ while (name_len < max_name_len && ldir->d_name[name_len] != '\0') {
+ name_len++;
+ }
+
+ memcpy(entry->d_name, ldir->d_name, name_len);
+ entry->d_name[name_len] = '\0';
+ *result = entry;
+
+ /* Count the amount of remaining entries we have cached from getdents.
+ */
+ for (ssize_t buffer_offset = ldir->d_reclen; buffer_offset < nread;) {
+ struct linux_dirent64 *next_ldir =
+ (void *)(dirp->buffer + buffer_offset);
+
+ /* Validate entry bounds to prevent infinite loops */
+ if (buffer_offset + sizeof(struct linux_dirent64) > nread ||
+ next_ldir->d_reclen <
+ offsetof(struct linux_dirent64, d_name) + 1 ||
+ buffer_offset + next_ldir->d_reclen > nread ||
+ next_ldir->d_reclen == 0) {
+ break;
+ }
+
+ buffer_offset += next_ldir->d_reclen;
+ dirp->cached++;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/endian/be16toh.c b/lib/libc/endian/be16toh.c
new file mode 100644
index 00000000..40793f93
--- /dev/null
+++ b/lib/libc/endian/be16toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint16_t be16toh(uint16_t big_endian_16bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap16(big_endian_16bits);
+#else
+ return big_endian_16bits;
+#endif
+}
diff --git a/lib/libc/endian/be32toh.c b/lib/libc/endian/be32toh.c
new file mode 100644
index 00000000..bc7d4900
--- /dev/null
+++ b/lib/libc/endian/be32toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint32_t be32toh(uint32_t big_endian_32bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap32(big_endian_32bits);
+#else
+ return big_endian_32bits;
+#endif
+}
diff --git a/lib/libc/endian/be64toh.c b/lib/libc/endian/be64toh.c
new file mode 100644
index 00000000..c52cc8a6
--- /dev/null
+++ b/lib/libc/endian/be64toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint64_t be64toh(uint64_t big_endian_64bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap64(big_endian_64bits);
+#else
+ return big_endian_64bits;
+#endif
+}
diff --git a/lib/libc/endian/htobe16.c b/lib/libc/endian/htobe16.c
new file mode 100644
index 00000000..bb66595f
--- /dev/null
+++ b/lib/libc/endian/htobe16.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint16_t htobe16(uint16_t host_16bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap16(host_16bits);
+#else
+ return host_16bits;
+#endif
+}
diff --git a/lib/libc/endian/htobe32.c b/lib/libc/endian/htobe32.c
new file mode 100644
index 00000000..4e294a82
--- /dev/null
+++ b/lib/libc/endian/htobe32.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint32_t htobe32(uint32_t host_32bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap32(host_32bits);
+#else
+ return host_32bits;
+#endif
+}
diff --git a/lib/libc/endian/htobe64.c b/lib/libc/endian/htobe64.c
new file mode 100644
index 00000000..ef39de6a
--- /dev/null
+++ b/lib/libc/endian/htobe64.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint64_t htobe64(uint64_t host_64bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap64(host_64bits);
+#else
+ return host_64bits;
+#endif
+}
diff --git a/lib/libc/endian/htole16.c b/lib/libc/endian/htole16.c
new file mode 100644
index 00000000..c5b1caa7
--- /dev/null
+++ b/lib/libc/endian/htole16.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint16_t htole16(uint16_t host_16bits)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return __builtin_bswap16(host_16bits);
+#else
+ return host_16bits;
+#endif
+}
diff --git a/lib/libc/endian/htole32.c b/lib/libc/endian/htole32.c
new file mode 100644
index 00000000..6c9a3cdc
--- /dev/null
+++ b/lib/libc/endian/htole32.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint32_t htole32(uint32_t host_32bits)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return __builtin_bswap32(host_32bits);
+#else
+ return host_32bits;
+#endif
+}
diff --git a/lib/libc/endian/htole64.c b/lib/libc/endian/htole64.c
new file mode 100644
index 00000000..36af0bea
--- /dev/null
+++ b/lib/libc/endian/htole64.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint64_t htole64(uint64_t host_64bits)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return __builtin_bswap64(host_64bits);
+#else
+ return host_64bits;
+#endif
+}
diff --git a/lib/libc/endian/le16toh.c b/lib/libc/endian/le16toh.c
new file mode 100644
index 00000000..ea85b5f6
--- /dev/null
+++ b/lib/libc/endian/le16toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint16_t le16toh(uint16_t little_endian_16bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return little_endian_16bits;
+#else
+ return __builtin_bswap16(little_endian_16bits);
+#endif
+}
diff --git a/lib/libc/endian/le32toh.c b/lib/libc/endian/le32toh.c
new file mode 100644
index 00000000..f85f0f94
--- /dev/null
+++ b/lib/libc/endian/le32toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint32_t le32toh(uint32_t little_endian_32bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return little_endian_32bits;
+#else
+ return __builtin_bswap32(little_endian_32bits);
+#endif
+}
diff --git a/lib/libc/endian/le64toh.c b/lib/libc/endian/le64toh.c
new file mode 100644
index 00000000..4f2cb5fc
--- /dev/null
+++ b/lib/libc/endian/le64toh.c
@@ -0,0 +1,10 @@
+#include <endian.h>
+
+uint64_t le64toh(uint64_t little_endian_64bits)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return little_endian_64bits;
+#else
+ return __builtin_bswap64(little_endian_64bits);
+#endif
+}
diff --git a/lib/libc/errno/errno.c b/lib/libc/errno/errno.c
new file mode 100644
index 00000000..55423e22
--- /dev/null
+++ b/lib/libc/errno/errno.c
@@ -0,0 +1,8 @@
+// TODO: Should return the address of the calling thread's `errno` storage.
+// Currently, this is a stub implementation that returns the address of a
+// static variable.
+int *__errno(void)
+{
+ static int __thread_errno = 0;
+ return &__thread_errno;
+}
diff --git a/lib/libc/fcntl/creat.c b/lib/libc/fcntl/creat.c
new file mode 100644
index 00000000..fdcb6655
--- /dev/null
+++ b/lib/libc/fcntl/creat.c
@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <syscall.h>
+
+int creat(const char *path, mode_t mode)
+{
+ return syscall(creat, path, mode);
+}
diff --git a/lib/libc/fcntl/fcntl.c b/lib/libc/fcntl/fcntl.c
new file mode 100644
index 00000000..ae213df5
--- /dev/null
+++ b/lib/libc/fcntl/fcntl.c
@@ -0,0 +1,37 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <syscall.h>
+
+int fcntl(int fildes, int cmd, ...)
+{
+ unsigned long arg;
+ va_list ap;
+ va_start(ap, cmd);
+ arg = va_arg(ap, unsigned long);
+ va_end(ap);
+
+ if (cmd == F_DUPFD_CLOEXEC) {
+ int ret = syscall(fcntl, fildes, F_DUPFD_CLOEXEC, arg);
+ if (ret != -EINVAL) {
+ if (ret >= 0)
+ syscall(fcntl, ret, F_SETFD, FD_CLOEXEC);
+ return __syscall_ret(ret);
+ }
+
+ ret = syscall(fcntl, fildes, F_DUPFD_CLOEXEC, 0);
+ if (ret != -EINVAL) {
+ if (ret >= 0)
+ __syscall(close, ret);
+
+ return __syscall_ret(-EINVAL);
+ }
+
+ ret = syscall(fcntl, fildes, F_DUPFD, arg);
+ if (ret >= 0)
+ syscall(fcntl, ret, F_SETFD, FD_CLOEXEC);
+
+ return __syscall_ret(ret);
+ }
+
+ return syscall(fcntl, fildes, cmd);
+}
diff --git a/lib/libc/fcntl/open.c b/lib/libc/fcntl/open.c
new file mode 100644
index 00000000..dbdff8f9
--- /dev/null
+++ b/lib/libc/fcntl/open.c
@@ -0,0 +1,23 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <syscall.h>
+
+int open(const char *path, int oflag, ...)
+{
+ long ret;
+ mode_t mode = 0;
+
+ if ((oflag & O_CREAT)) {
+ va_list ap;
+ va_start(ap, oflag);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ ret = syscall(open, path, oflag, mode);
+
+ if (ret >= 0 && (oflag & O_CLOEXEC))
+ return syscall(fcntl, ret, F_SETFD, FD_CLOEXEC);
+
+ return ret;
+}
diff --git a/lib/libc/fcntl/openat.c b/lib/libc/fcntl/openat.c
new file mode 100644
index 00000000..bb34d600
--- /dev/null
+++ b/lib/libc/fcntl/openat.c
@@ -0,0 +1,17 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <syscall.h>
+
+int openat(int fd, const char *path, int oflag, ...)
+{
+ mode_t mode = 0;
+
+ if (oflag & O_CREAT) {
+ va_list ap;
+ va_start(ap, oflag);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ return syscall(openat, fd, path, oflag, mode);
+}
diff --git a/lib/libc/fcntl/posix_fadvise.c b/lib/libc/fcntl/posix_fadvise.c
new file mode 100644
index 00000000..dcf278fd
--- /dev/null
+++ b/lib/libc/fcntl/posix_fadvise.c
@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <syscall.h>
+
+int posix_fadvise(int fd, off_t offset, off_t len, int advice)
+{
+ return syscall(fadvise64, fd, offset, len, advice);
+}
diff --git a/lib/libc/fcntl/posix_fallocate.c b/lib/libc/fcntl/posix_fallocate.c
new file mode 100644
index 00000000..221f2d38
--- /dev/null
+++ b/lib/libc/fcntl/posix_fallocate.c
@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <syscall.h>
+
+int posix_fallocate(int fd, off_t offset, off_t len)
+{
+ return syscall(fallocate, fd, 0, offset, len);
+}
diff --git a/lib/libc/grp/getgrgid.c b/lib/libc/grp/getgrgid.c
new file mode 100644
index 00000000..66ccaff1
--- /dev/null
+++ b/lib/libc/grp/getgrgid.c
@@ -0,0 +1,15 @@
+#include <grp.h>
+#include <stddef.h>
+#include <limits.h>
+
+struct group *getgrgid(gid_t gid)
+{
+ static struct group grp;
+ static char buf[LINE_MAX * 2];
+ struct group *res;
+
+ if (getgrgid_r(gid, &grp, buf, sizeof(buf), &res) != 0)
+ return NULL;
+
+ return res;
+}
diff --git a/lib/libc/grp/getgrgid_r.c b/lib/libc/grp/getgrgid_r.c
new file mode 100644
index 00000000..b3449d14
--- /dev/null
+++ b/lib/libc/grp/getgrgid_r.c
@@ -0,0 +1,74 @@
+#include <grp.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen,
+ struct group **result)
+{
+ FILE *f = fopen("/etc/group", "r");
+ if (!f) {
+ *result = NULL;
+ return errno;
+ }
+
+ char line[LINE_MAX];
+ char *members[1024];
+
+ while (fgets(line, sizeof(line), f)) {
+ char *name = strtok(line, ":");
+ char *passwd = strtok(NULL, ":");
+ char *gid_str = strtok(NULL, ":");
+ char *mem_str = strtok(NULL, "\n");
+
+ if (!name || !passwd || !gid_str)
+ continue;
+
+ gid_t file_gid = (gid_t)strtoul(gid_str, NULL, 10);
+ if (file_gid != gid)
+ continue;
+
+ size_t len = strlen(name) + 1;
+ if (len > buflen) {
+ fclose(f);
+ *result = NULL;
+ return ERANGE;
+ }
+ memcpy(buf, name, len);
+ grp->gr_name = buf;
+ buf += len;
+ buflen -= len;
+
+ grp->gr_gid = file_gid;
+
+ int i = 0;
+ if (mem_str && *mem_str) {
+ char *tok = strtok(mem_str, ",");
+ while (tok && i < 1023) {
+ size_t l = strlen(tok) + 1;
+ if (l > buflen) {
+ fclose(f);
+ *result = NULL;
+ return ERANGE;
+ }
+ memcpy(buf, tok, l);
+ members[i++] = buf;
+ buf += l;
+ buflen -= l;
+ tok = strtok(NULL, ",");
+ }
+ }
+ members[i] = NULL;
+ grp->gr_mem = members;
+
+ fclose(f);
+ *result = grp;
+ return 0;
+ }
+
+ fclose(f);
+ *result = NULL;
+ return 0;
+}
diff --git a/lib/libc/include/__alpha.h b/lib/libc/include/__alpha.h
new file mode 100644
index 00000000..f2e8bfb1
--- /dev/null
+++ b/lib/libc/include/__alpha.h
@@ -0,0 +1,233 @@
+/* Alpha ISO8859-1 font data */
+18, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 17, 34, 35,
+ 36, 17, 37, 38, 39, 40, 41, 42, 43, 44, 17, 45, 46, 47, 16, 16, 48, 16,
+ 16, 16, 16, 16, 16, 16, 49, 50, 51, 16, 52, 53, 16, 16, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 54, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 55, 17, 17, 17, 17,
+ 56, 17, 57, 58, 59, 60, 61, 62, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 63, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 64, 65, 17, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 17, 75, 76, 77, 78, 79, 80, 81, 16, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 16, 94, 95, 96, 16, 17, 17,
+ 17, 97, 98, 99, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 100, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17,
+ 101, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17,
+ 102, 103, 16, 16, 104, 105, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 106, 17, 17, 107, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 108, 109, 16, 16, 16, 16, 16, 16, 16, 16, 16, 110, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 111, 112, 113, 114, 16, 16, 16, 16, 16, 16, 16, 16, 115, 116, 117,
+ 16, 16, 16, 16, 16, 118, 119, 16, 16, 16, 16, 120, 16, 16, 121, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 7, 254, 255,
+ 255, 7, 0, 0, 0, 0, 0, 4, 32, 4, 255, 255, 127, 255, 255, 255, 127, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 195, 255, 3, 0, 31,
+ 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 223, 188, 64, 215,
+ 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 3, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 127, 2,
+ 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 255, 191, 182, 0, 255, 255, 255,
+ 135, 7, 0, 0, 0, 255, 7, 255, 255, 255, 255, 255, 255, 255, 254, 255,
+ 195, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239,
+ 31, 254, 225, 255, 159, 0, 0, 255, 255, 255, 255, 255, 255, 0, 224, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 255, 255,
+ 255, 255, 255, 7, 48, 4, 255, 255, 255, 252, 255, 31, 0, 0, 255, 255,
+ 255, 1, 255, 7, 0, 0, 0, 0, 0, 0, 255, 255, 223, 63, 0, 0, 240, 255,
+ 248, 3, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 223, 225,
+ 255, 207, 255, 254, 255, 239, 159, 249, 255, 255, 253, 197, 227, 159,
+ 89, 128, 176, 207, 255, 3, 16, 238, 135, 249, 255, 255, 253, 109, 195,
+ 135, 25, 2, 94, 192, 255, 63, 0, 238, 191, 251, 255, 255, 253, 237, 227,
+ 191, 27, 1, 0, 207, 255, 0, 30, 238, 159, 249, 255, 255, 253, 237, 227,
+ 159, 25, 192, 176, 207, 255, 2, 0, 236, 199, 61, 214, 24, 199, 255, 195,
+ 199, 29, 129, 0, 192, 255, 0, 0, 239, 223, 253, 255, 255, 253, 255, 227,
+ 223, 29, 96, 7, 207, 255, 0, 0, 239, 223, 253, 255, 255, 253, 239, 227,
+ 223, 29, 96, 64, 207, 255, 6, 0, 239, 223, 253, 255, 255, 255, 255, 231,
+ 223, 93, 240, 128, 207, 255, 0, 252, 236, 255, 127, 252, 255, 255, 251,
+ 47, 127, 128, 95, 255, 192, 255, 12, 0, 254, 255, 255, 255, 255, 127,
+ 255, 7, 63, 32, 255, 3, 0, 0, 0, 0, 214, 247, 255, 255, 175, 255, 255,
+ 59, 95, 32, 255, 243, 0, 0, 0, 0, 1, 0, 0, 0, 255, 3, 0, 0, 255, 254,
+ 255, 255, 255, 31, 254, 255, 3, 255, 255, 254, 255, 255, 255, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 127, 249, 255, 3, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 63, 255, 255, 255, 255, 191, 32,
+ 255, 255, 255, 255, 255, 247, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 61, 127, 61, 255, 255, 255, 255, 255, 61, 255, 255, 255, 255, 61,
+ 127, 61, 255, 127, 255, 255, 255, 255, 255, 255, 255, 61, 255, 255, 255,
+ 255, 255, 255, 255, 255, 7, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 63, 63, 254, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 159, 255, 255,
+ 254, 255, 255, 7, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 255,
+ 1, 255, 223, 15, 0, 255, 255, 15, 0, 255, 255, 15, 0, 255, 223, 13, 0,
+ 255, 255, 255, 255, 255, 255, 207, 255, 255, 1, 128, 16, 255, 3, 0, 0,
+ 0, 0, 255, 3, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1,
+ 255, 255, 255, 255, 255, 7, 255, 255, 255, 255, 255, 255, 255, 255, 63,
+ 0, 255, 255, 255, 127, 255, 15, 255, 1, 192, 255, 255, 255, 255, 63, 31,
+ 0, 255, 255, 255, 255, 255, 15, 255, 255, 255, 3, 255, 3, 0, 0, 0, 0,
+ 255, 255, 255, 15, 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 31,
+ 0, 255, 3, 255, 3, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
+ 255, 255, 255, 239, 255, 239, 15, 255, 3, 0, 0, 0, 0, 255, 255, 255,
+ 255, 255, 243, 255, 255, 255, 255, 255, 255, 191, 255, 3, 0, 255, 255,
+ 255, 255, 255, 255, 127, 0, 255, 227, 255, 255, 255, 255, 255, 63, 255,
+ 1, 255, 255, 255, 255, 255, 231, 0, 0, 0, 0, 0, 222, 111, 4, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 128, 255, 31, 0,
+ 255, 255, 63, 63, 255, 255, 255, 255, 63, 63, 255, 170, 255, 255, 255,
+ 63, 255, 255, 255, 255, 255, 255, 223, 95, 220, 31, 207, 15, 255, 31,
+ 220, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 0, 255,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 252, 47, 62, 80, 189, 255,
+ 243, 224, 67, 0, 0, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 3, 0, 0, 255, 255, 255,
+ 255, 255, 127, 255, 255, 255, 255, 255, 127, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 120, 12, 0,
+ 255, 255, 255, 255, 191, 32, 255, 255, 255, 255, 255, 255, 255, 128, 0,
+ 0, 255, 255, 127, 0, 127, 127, 127, 127, 127, 127, 127, 127, 255, 255,
+ 255, 255, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 254, 3, 62, 31, 254,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 224, 254, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 247, 224, 255, 255, 255, 255,
+ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 0,
+ 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 63, 255, 31,
+ 255, 255, 255, 15, 0, 0, 255, 255, 255, 255, 255, 127, 240, 143, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0,
+ 0, 0, 128, 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 249, 255, 255, 255, 255, 255, 255, 124, 0, 0, 0, 0, 0, 128,
+ 255, 191, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, 15,
+ 0, 255, 255, 255, 255, 255, 255, 255, 255, 47, 0, 255, 3, 0, 0, 252,
+ 232, 255, 255, 255, 255, 255, 7, 255, 255, 255, 255, 7, 0, 255, 255,
+ 255, 31, 255, 255, 255, 255, 255, 255, 247, 255, 0, 128, 255, 3, 255,
+ 255, 255, 127, 255, 255, 255, 255, 255, 255, 127, 0, 255, 63, 255, 3,
+ 255, 255, 127, 252, 255, 255, 255, 255, 255, 255, 255, 127, 5, 0, 0, 56,
+ 255, 255, 60, 0, 126, 126, 126, 0, 127, 127, 255, 255, 255, 255, 255,
+ 247, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 7, 255, 3, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 255, 255,
+ 127, 248, 255, 255, 255, 255, 255, 15, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 63, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 3, 0, 0, 0, 0, 127, 0, 248, 224, 255,
+ 253, 127, 95, 219, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 3, 0, 0, 0, 248, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 63, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
+ 252, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 15, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 0, 255, 3, 254, 255,
+ 255, 7, 254, 255, 255, 7, 192, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 127, 252, 252, 252, 28, 0, 0, 0, 0, 255, 239, 255, 255, 127,
+ 255, 255, 183, 255, 63, 255, 63, 0, 0, 0, 0, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
+ 255, 255, 31, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 224, 255, 255, 255, 7, 255, 255, 255, 255, 255, 7, 255,
+ 255, 255, 63, 255, 255, 255, 255, 15, 255, 62, 0, 0, 0, 0, 0, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 63, 255, 3, 255, 255, 255, 255, 15, 255, 255, 255, 255,
+ 15, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 15, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 127, 0, 255, 255, 63, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 253, 255, 255, 255, 255, 191, 145, 255, 255,
+ 63, 0, 255, 255, 127, 0, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 55, 0, 255, 255, 63, 0, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 255, 255, 255, 255, 255, 255, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 111,
+ 240, 239, 254, 255, 255, 63, 0, 0, 0, 0, 0, 255, 255, 255, 31, 255, 255,
+ 255, 31, 0, 0, 0, 0, 255, 254, 255, 255, 31, 0, 0, 0, 255, 255, 255,
+ 255, 255, 255, 63, 0, 255, 255, 63, 0, 255, 255, 7, 0, 255, 255, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 1, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 7, 0, 255,
+ 255, 255, 255, 255, 255, 7, 0, 255, 255, 255, 255, 255, 0, 255, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
+ 255, 255, 31, 128, 0, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 255, 255, 255, 255, 255, 255,
+ 255, 255, 63, 0, 0, 0, 192, 255, 0, 0, 252, 255, 255, 255, 255, 255,
+ 255, 1, 0, 0, 255, 255, 255, 1, 255, 3, 255, 255, 255, 255, 255, 255,
+ 199, 255, 112, 0, 255, 255, 255, 255, 71, 0, 255, 255, 255, 255, 255,
+ 255, 255, 255, 30, 0, 255, 23, 0, 0, 0, 0, 255, 255, 251, 255, 255, 255,
+ 159, 64, 0, 0, 0, 0, 0, 0, 0, 0, 127, 189, 255, 191, 255, 1, 255, 255,
+ 255, 255, 255, 255, 255, 1, 255, 3, 239, 159, 249, 255, 255, 253, 237,
+ 227, 159, 25, 129, 224, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 187, 7, 255, 131, 0,
+ 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 179, 0, 255, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
+ 255, 255, 255, 63, 127, 0, 0, 0, 63, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 255, 127, 17, 0, 255, 3, 0, 0, 0, 0, 255, 255, 255, 255, 255,
+ 255, 63, 1, 255, 3, 0, 0, 0, 0, 0, 0, 255, 255, 255, 231, 255, 7, 255,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 255, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 128, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 252, 255, 255,
+ 255, 255, 255, 252, 26, 0, 0, 0, 255, 255, 255, 255, 255, 255, 231, 127,
+ 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32, 0, 0, 0, 0, 255,
+ 255, 255, 255, 255, 255, 255, 1, 255, 253, 255, 255, 255, 255, 127, 127,
+ 1, 0, 255, 3, 0, 0, 252, 255, 255, 255, 252, 255, 255, 254, 127, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 127, 251, 255, 255, 255, 255, 127, 180, 203, 0,
+ 255, 3, 191, 253, 255, 255, 255, 127, 123, 1, 255, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 127, 0, 0, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 1, 255, 255,
+ 255, 127, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 63,
+ 0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 15, 0, 255, 3, 248, 255, 255,
+ 224, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 135, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 255, 255, 255, 127,
+ 0, 0, 0, 0, 0, 0, 7, 0, 240, 0, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 255,
+ 31, 255, 1, 255, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 223, 255, 255, 255, 255, 255, 255,
+ 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255, 255, 255, 255,
+ 255, 191, 231, 223, 223, 255, 255, 255, 123, 95, 252, 253, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 255, 255,
+ 255, 253, 255, 255, 247, 255, 255, 255, 247, 255, 255, 223, 255, 255,
+ 255, 223, 255, 255, 127, 255, 255, 255, 127, 255, 255, 255, 253, 255,
+ 255, 255, 253, 255, 255, 247, 207, 255, 255, 255, 255, 255, 255, 127,
+ 255, 255, 249, 219, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 31, 128, 63, 255,
+ 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 255, 15, 255, 3, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255,
+ 255, 255, 143, 8, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 239, 255, 255, 255, 150, 254, 247, 10, 132, 234, 150,
+ 170, 150, 247, 247, 94, 255, 251, 255, 15, 238, 251, 255, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 3, 255, 255, 255, 3,
+ 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/lib/libc/include/__dirent.h b/lib/libc/include/__dirent.h
new file mode 100644
index 00000000..9b23c9d2
--- /dev/null
+++ b/lib/libc/include/__dirent.h
@@ -0,0 +1,25 @@
+#ifndef __LIBC_DIRENT_H
+#define __LIBC_DIRENT_H
+
+#include <libc.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+struct linux_dirent64 {
+ uint64_t d_ino;
+ int64_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[];
+};
+
+struct __DIR {
+ int fildes;
+ int cached;
+ off_t tell;
+ off_t offset;
+ char buffer[BUFSIZ] __attribute__((__aligned__(8)));
+};
+
+#endif
diff --git a/lib/libc/include/__locale.h b/lib/libc/include/__locale.h
new file mode 100644
index 00000000..0a709c78
--- /dev/null
+++ b/lib/libc/include/__locale.h
@@ -0,0 +1,41 @@
+#ifndef __LIBC_LOCALE_H
+#define __LIBC_LOCALE_H
+
+#include <locale.h>
+#include <stdint.h>
+
+typedef __SIZE_TYPE__ size_t;
+
+struct __locale_t {
+ struct __locale_map {
+ const void *map;
+ size_t map_size;
+ char name[24];
+ } maps[6];
+};
+
+typedef struct __locale_t *locale_t;
+
+static const struct __locale_t __c_locale = { 0 };
+
+static const struct __locale_t __utf8_locale = {
+ .maps[LC_CTYPE] = { .map = &((const uint32_t[]){ 0x950412de, 0, -1, -1,
+ -1 }),
+ .map_size = sizeof(uint32_t) * 5,
+ .name = "C.UTF-8" },
+};
+
+#undef MB_CUR_MAX
+#define MB_CUR_MAX (((locale_t) & __utf8_locale) ? 4 : 1)
+
+static inline int __mb_cur_max(void)
+{
+ return MB_CUR_MAX;
+}
+
+static inline int __locale_allocated(locale_t loc)
+{
+ return loc != (locale_t)&__c_locale && loc != (locale_t)&__utf8_locale;
+}
+
+#endif
diff --git a/lib/libc/include/__select.h b/lib/libc/include/__select.h
new file mode 100644
index 00000000..a38bbdce
--- /dev/null
+++ b/lib/libc/include/__select.h
@@ -0,0 +1,8 @@
+#ifndef __LIBC_SELECT_H
+#define __LIBC_SELECT_H
+
+struct __fd_set {
+ unsigned long fds_bits[16];
+};
+
+#endif
diff --git a/lib/libc/include/__signal.h b/lib/libc/include/__signal.h
new file mode 100644
index 00000000..6b762dee
--- /dev/null
+++ b/lib/libc/include/__signal.h
@@ -0,0 +1,12 @@
+#ifndef __LIBC_SIGNAL_H
+#define __LIBC_SIGNAL_H
+
+static const char *__sys_signame[] = {
+ "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT",
+ "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2",
+ "SIGPIPE", "SIGALRM", "SIGTERM", "SIGCHLD", "SIGCONT", "SIGSTOP",
+ "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ",
+ "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", "SIGSYS"
+};
+
+#endif
diff --git a/lib/libc/include/__statvfs.h b/lib/libc/include/__statvfs.h
new file mode 100644
index 00000000..c8a746d4
--- /dev/null
+++ b/lib/libc/include/__statvfs.h
@@ -0,0 +1,21 @@
+#ifndef __LIBC_STATVFS_H__
+#define __LIBC_STATVFS_H__
+
+typedef __UINT64_TYPE__ fsblkcnt_t;
+typedef __UINT64_TYPE__ fsfilcnt_t;
+
+struct __statvfs {
+ unsigned long f_bsize;
+ unsigned long f_frsize;
+ fsblkcnt_t f_blocks;
+ fsblkcnt_t f_bfree;
+ fsblkcnt_t f_bavail;
+ fsfilcnt_t f_files;
+ fsfilcnt_t f_ffree;
+ fsfilcnt_t f_favail;
+ unsigned long f_fsid;
+ unsigned long f_flag;
+ unsigned long f_namemax;
+};
+
+#endif
diff --git a/lib/libc/include/atomic.h b/lib/libc/include/atomic.h
new file mode 100644
index 00000000..94cd34db
--- /dev/null
+++ b/lib/libc/include/atomic.h
@@ -0,0 +1,23 @@
+#ifndef __LIBC_ATOMIC_H
+#define __LIBC_ATOMIC_H
+
+#include <stdatomic.h>
+
+#define LIBC_LOCK(__lock) __libc_lock(&__lock)
+#define LIBC_UNLOCK(__lock) atomic_flag_clear(&__lock)
+
+static __inline void __libc_lock(volatile atomic_flag *lock)
+{
+ while (atomic_flag_test_and_set_explicit(lock, memory_order_acquire)) {
+ unsigned int spins = 1;
+ do {
+ for (unsigned int i = 0; i < spins; i++)
+ __asm__ volatile("pause");
+ if (spins < 64)
+ spins *= 2;
+ } while (atomic_flag_test_and_set_explicit(
+ lock, memory_order_relaxed));
+ }
+}
+
+#endif
diff --git a/lib/libc/include/byteswap.h b/lib/libc/include/byteswap.h
new file mode 100644
index 00000000..9dfe6520
--- /dev/null
+++ b/lib/libc/include/byteswap.h
@@ -0,0 +1,8 @@
+#ifndef __LIBC_BYTESWAP_H
+#define __LIBC_BYTESWAP_H
+
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define bswap64(x) __builtin_bswap64(x)
+
+#endif
diff --git a/lib/libc/include/features.h b/lib/libc/include/features.h
new file mode 100644
index 00000000..62472259
--- /dev/null
+++ b/lib/libc/include/features.h
@@ -0,0 +1,6 @@
+#ifndef __LIBC_FEATURES_H
+#define __LIBC_FEATURES_H
+
+#define weak extern __attribute__((weak))
+
+#endif
diff --git a/lib/libc/include/io.h b/lib/libc/include/io.h
new file mode 100644
index 00000000..675a3cc3
--- /dev/null
+++ b/lib/libc/include/io.h
@@ -0,0 +1,55 @@
+#ifndef __LIBC_IO
+#define __LIBC_IO
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdatomic.h>
+
+typedef __SIZE_TYPE__ size_t;
+
+#define _IO_ERR 0x4
+#define _IO_EOF 0x8
+#define _IO_WIDE 0x10
+
+/* Buffering modes */
+#define _IOFBF 0 /* Full buffering */
+#define _IOLBF 1 /* Line buffering */
+#define _IONBF 2 /* No buffering */
+
+/* File access modes */
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#define O_ACCMODE 3
+#endif
+
+/* Atomic operations for threading */
+#define LIBC_LOCK(x) \
+ while (atomic_flag_test_and_set(&(x))) { \
+ }
+#define LIBC_UNLOCK(x) atomic_flag_clear(&(x))
+
+struct __FILE {
+ int fd;
+ uint32_t flags;
+ int type;
+ pid_t pid;
+ atomic_flag lock;
+ char *buf;
+ int eof;
+ size_t buf_size;
+ size_t buf_pos;
+ size_t buf_len;
+ unsigned char unget_buf[16];
+ size_t unget_cnt;
+ off_t offset;
+ struct __FILE *next;
+};
+
+void __libc_fadd(struct __FILE *f);
+
+#endif
diff --git a/lib/libc/include/libc.h b/lib/libc/include/libc.h
new file mode 100644
index 00000000..3f5f2644
--- /dev/null
+++ b/lib/libc/include/libc.h
@@ -0,0 +1,27 @@
+#ifndef __LIBC_LIBC_H
+#define __LIBC_LIBC_H
+
+#include <__locale.h>
+#include <stdatomic.h>
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define unused __attribute__((unused))
+#define aligned(type) __attribute__((aligned(__alignof__(type))))
+#define weak __attribute__((__weak__))
+#define weak_reference(old, new) \
+ extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
+
+static struct {
+ enum {
+ LIBC_ENVP_TOUCHED = 1 << 0,
+ } flags;
+ struct {
+ volatile atomic_flag abort;
+ volatile atomic_flag malloc;
+ volatile atomic_flag environ;
+ } lock;
+ struct __locale_t locale;
+} libc = { .lock = { ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT } };
+
+#endif
diff --git a/lib/libc/include/libc/dirent.h b/lib/libc/include/libc/dirent.h
new file mode 100644
index 00000000..296cc91e
--- /dev/null
+++ b/lib/libc/include/libc/dirent.h
@@ -0,0 +1,6 @@
+#ifndef __LIBC_DIRENT_H
+#define __LIBC_DIRENT_H
+
+struct __DIR {};
+
+#endif
diff --git a/lib/libc/include/malloc.h b/lib/libc/include/malloc.h
new file mode 100644
index 00000000..ba2755b0
--- /dev/null
+++ b/lib/libc/include/malloc.h
@@ -0,0 +1,98 @@
+#ifndef __LIBC_MALLOC_H
+#define __LIBC_MALLOC_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdatomic.h>
+
+struct class {
+ uint32_t size;
+ uint32_t count;
+};
+
+struct page {
+ volatile atomic_flag lock;
+
+ enum {
+ PAGE_SMALL = 0x0,
+ PAGE_MEDIUM = 0x1,
+ PAGE_LARGE = 0x2,
+ } flags;
+
+ struct {
+ uint32_t size;
+ uint32_t used;
+ uint32_t count;
+ } block;
+
+ uint8_t *bitmap;
+ uint8_t *heap;
+
+ struct page *next;
+ struct page *prev;
+};
+
+extern struct page *__malloc_pvec;
+
+#define SMALL_PAGE_SIZE_SHIFT 16
+#define SMALL_PAGE_SIZE (1 << SMALL_PAGE_SIZE_SHIFT)
+#define SMALL_PAGE_MASK (~((uintptr_t)SMALL_PAGE_SIZE - 1))
+
+#define MEDIUM_PAGE_SIZE_SHIFT 22
+#define MEDIUM_PAGE_SIZE (1 << MEDIUM_PAGE_SIZE_SHIFT)
+#define MEDIUM_PAGE_MASK (~((uintptr_t)MEDIUM_PAGE_SIZE - 1))
+
+#define LARGE_PAGE_SIZE_SHIFT 26
+#define LARGE_PAGE_SIZE (1 << LARGE_PAGE_SIZE_SHIFT)
+#define LARGE_PAGE_MASK (~((uintptr_t)LARGE_PAGE_SIZE - 1))
+
+#define SMALL_CLASS(n) \
+ { (n * 16), (SMALL_PAGE_SIZE - sizeof(struct page)) / (n * 16) }
+#define MEDIUM_CLASS(n) \
+ { (n * 16), (MEDIUM_PAGE_SIZE - sizeof(struct page)) / (n * 16) }
+#define LARGE_CLASS(n) \
+ { (n * 16), (LARGE_PAGE_SIZE - sizeof(struct page)) / (n * 16) }
+
+static const struct class global_size_class[] = {
+ SMALL_CLASS(1), SMALL_CLASS(1), SMALL_CLASS(2),
+ SMALL_CLASS(3), SMALL_CLASS(4), SMALL_CLASS(5),
+ SMALL_CLASS(6), SMALL_CLASS(7), SMALL_CLASS(8),
+ SMALL_CLASS(9), SMALL_CLASS(10), SMALL_CLASS(11),
+ SMALL_CLASS(12), SMALL_CLASS(13), SMALL_CLASS(14),
+ SMALL_CLASS(15), SMALL_CLASS(16), SMALL_CLASS(17),
+ SMALL_CLASS(18), SMALL_CLASS(19), SMALL_CLASS(20),
+ SMALL_CLASS(21), SMALL_CLASS(22), SMALL_CLASS(23),
+ SMALL_CLASS(24), SMALL_CLASS(25), SMALL_CLASS(26),
+ SMALL_CLASS(27), SMALL_CLASS(28), SMALL_CLASS(29),
+ SMALL_CLASS(30), SMALL_CLASS(31), SMALL_CLASS(32),
+ SMALL_CLASS(33), SMALL_CLASS(34), SMALL_CLASS(35),
+ SMALL_CLASS(36), SMALL_CLASS(37), SMALL_CLASS(38),
+ SMALL_CLASS(39), SMALL_CLASS(40), SMALL_CLASS(41),
+ SMALL_CLASS(42), SMALL_CLASS(43), SMALL_CLASS(44),
+ SMALL_CLASS(45), SMALL_CLASS(46), SMALL_CLASS(47),
+ SMALL_CLASS(48), SMALL_CLASS(49), SMALL_CLASS(50),
+ SMALL_CLASS(51), SMALL_CLASS(52), SMALL_CLASS(53),
+ SMALL_CLASS(54), SMALL_CLASS(55), SMALL_CLASS(56),
+ SMALL_CLASS(57), SMALL_CLASS(58), SMALL_CLASS(59),
+ SMALL_CLASS(60), SMALL_CLASS(61), SMALL_CLASS(62),
+ SMALL_CLASS(63), SMALL_CLASS(64), SMALL_CLASS(80),
+ SMALL_CLASS(96), SMALL_CLASS(112), SMALL_CLASS(128),
+ SMALL_CLASS(160), SMALL_CLASS(192), SMALL_CLASS(224),
+ SMALL_CLASS(256), MEDIUM_CLASS(320), MEDIUM_CLASS(384),
+ MEDIUM_CLASS(448), MEDIUM_CLASS(512), MEDIUM_CLASS(640),
+ MEDIUM_CLASS(768), MEDIUM_CLASS(896), MEDIUM_CLASS(1024),
+ MEDIUM_CLASS(1280), MEDIUM_CLASS(1536), MEDIUM_CLASS(1792),
+ MEDIUM_CLASS(2048), MEDIUM_CLASS(2560), MEDIUM_CLASS(3072),
+ MEDIUM_CLASS(3584), MEDIUM_CLASS(4096), MEDIUM_CLASS(5120),
+ MEDIUM_CLASS(6144), MEDIUM_CLASS(7168), MEDIUM_CLASS(8192),
+ MEDIUM_CLASS(10240), MEDIUM_CLASS(12288), MEDIUM_CLASS(14336),
+ MEDIUM_CLASS(16384), LARGE_CLASS(20480), LARGE_CLASS(24576),
+ LARGE_CLASS(28672), LARGE_CLASS(32768), LARGE_CLASS(40960),
+ LARGE_CLASS(49152), LARGE_CLASS(57344), LARGE_CLASS(65536),
+ LARGE_CLASS(81920), LARGE_CLASS(98304), LARGE_CLASS(114688),
+ LARGE_CLASS(131072), LARGE_CLASS(163840), LARGE_CLASS(196608),
+ LARGE_CLASS(229376), LARGE_CLASS(262144), LARGE_CLASS(327680),
+ LARGE_CLASS(393216), LARGE_CLASS(458752), LARGE_CLASS(524288)
+};
+
+#endif
diff --git a/lib/libc/include/syscall.h b/lib/libc/include/syscall.h
new file mode 100644
index 00000000..645c4bcd
--- /dev/null
+++ b/lib/libc/include/syscall.h
@@ -0,0 +1,59 @@
+#ifndef __LIBC_SYSCALL_H
+#define __LIBC_SYSCALL_H
+
+#include <asm/syscall.h>
+#include <asm/unistd_64.h>
+#include <errno.h>
+
+typedef long syscall_arg_t;
+
+#define __SYSCALL_NARGS_(a, b, c, d, e, f, g, h, n, ...) n
+#define __SYSCALL_NARGS(...) \
+ __SYSCALL_NARGS_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, )
+
+#define __SYSCALL_CONCAT_(a, b) a##b
+#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_(a, b)
+
+#define __SYSCALL_(b, ...) \
+ __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#define __syscall(...) __SYSCALL_(__syscall_, __VA_ARGS__)
+#define syscall(...) __syscall_ret(__syscall(__VA_ARGS__))
+
+#define __sa(x) ((syscall_arg_t)(x))
+
+#define __syscall_0(n) __syscall0(__NR_##n)
+#define __syscall_1(n, a) __syscall1(__NR_##n, __sa(a))
+#define __syscall_2(n, a, b) __syscall2(__NR_##n, __sa(a), __sa(b))
+#define __syscall_3(n, a, b, c) __syscall3(__NR_##n, __sa(a), __sa(b), __sa(c))
+#define __syscall_4(n, a, b, c, d) \
+ __syscall4(__NR_##n, __sa(a), __sa(b), __sa(c), __sa(d))
+#define __syscall_5(n, a, b, c, d, e) \
+ __syscall5(__NR_##n, __sa(a), __sa(b), __sa(c), __sa(d), __sa(e))
+#define __syscall_6(n, a, b, c, d, e, f) \
+ __syscall6(__NR_##n, __sa(a), __sa(b), __sa(c), __sa(d), __sa(e), \
+ __sa(f))
+#define __syscall_7(n, a, b, c, d, e, f, g) \
+ __syscall7(__NR_##n, __sa(a), __sa(b), __sa(c), __sa(d), __sa(e), \
+ __sa(f), __sa(g))
+
+static __inline long __syscall_ret(long ret)
+{
+ if (ret > -4096 && ret < 0) {
+ errno = -ret;
+ ret = -1;
+ }
+ return ret;
+}
+
+#ifdef __NR_pread64
+#undef __NR_pread
+#define __NR_pread __NR_pread64
+#endif
+
+#ifdef __NR_pwrite64
+#undef __NR_pwrite
+#define __NR_pwrite __NR_pwrite64
+#endif
+
+#endif
diff --git a/lib/libc/include/thread.h b/lib/libc/include/thread.h
new file mode 100644
index 00000000..662f1dc1
--- /dev/null
+++ b/lib/libc/include/thread.h
@@ -0,0 +1,9 @@
+#ifndef __LIBC_THREAD_H
+#define __LIBC_THREAD_H
+
+struct __thread_self {
+ int tid;
+ int _errno;
+};
+
+#endif
diff --git a/lib/libc/inttypes/imaxabs.c b/lib/libc/inttypes/imaxabs.c
new file mode 100644
index 00000000..3af1df67
--- /dev/null
+++ b/lib/libc/inttypes/imaxabs.c
@@ -0,0 +1,6 @@
+#include <stdint.h>
+
+intmax_t imaxabs(intmax_t j)
+{
+ return (j < 0) ? -j : j;
+}
diff --git a/lib/libc/inttypes/imaxdiv.c b/lib/libc/inttypes/imaxdiv.c
new file mode 100644
index 00000000..36fd6d20
--- /dev/null
+++ b/lib/libc/inttypes/imaxdiv.c
@@ -0,0 +1,6 @@
+#include <inttypes.h>
+
+imaxdiv_t imaxdiv(intmax_t num, intmax_t den)
+{
+ return (imaxdiv_t){ num / den, num % den };
+}
diff --git a/lib/libc/inttypes/strtoimax.c b/lib/libc/inttypes/strtoimax.c
new file mode 100644
index 00000000..f66e58a0
--- /dev/null
+++ b/lib/libc/inttypes/strtoimax.c
@@ -0,0 +1,149 @@
+/* $OpenBSD: strtoimax.c,v 1.4 2017/07/06 16:23:11 millert Exp $ */
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+
+/*
+ * Convert a string to an intmax_t
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+intmax_t strtoimax(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ intmax_t acc, cutoff;
+ int c;
+ int neg, any, cutlim;
+
+ /*
+ * Ensure that base is between 2 and 36 inclusive, or the special
+ * value of 0.
+ */
+ if (base < 0 || base == 1 || base > 36) {
+ if (endptr != 0)
+ *endptr = (char *)nptr;
+ errno = EINVAL;
+ return 0;
+ }
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = (unsigned char)*s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') &&
+ isxdigit((unsigned char)s[1])) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for intmax_t is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? INTMAX_MIN : INTMAX_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ if (neg) {
+ if (cutlim > 0) {
+ cutlim -= base;
+ cutoff += 1;
+ }
+ cutlim = -cutlim;
+ }
+ for (acc = 0, any = 0;; c = (unsigned char)*s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (neg) {
+ if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+ any = -1;
+ acc = INTMAX_MIN;
+ errno = ERANGE;
+ } else {
+ any = 1;
+ acc *= base;
+ acc -= c;
+ }
+ } else {
+ if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+ any = -1;
+ acc = INTMAX_MAX;
+ errno = ERANGE;
+ } else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ }
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/inttypes/strtoumax.c b/lib/libc/inttypes/strtoumax.c
new file mode 100644
index 00000000..500e255a
--- /dev/null
+++ b/lib/libc/inttypes/strtoumax.c
@@ -0,0 +1,7 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+uintmax_t strtoumax(const char *restrict s, char **restrict p, int base)
+{
+ return strtoull(s, p, base);
+}
diff --git a/lib/libc/libgen/basename.c b/lib/libc/libgen/basename.c
new file mode 100644
index 00000000..0de08da4
--- /dev/null
+++ b/lib/libc/libgen/basename.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: basename.c,v 1.17 2020/10/20 19:30:14 naddy Exp $ */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <millert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
+#include <string.h>
+
+char *basename(char *path)
+{
+ static char bname[PATH_MAX];
+ size_t len;
+ const char *endp, *startp;
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ bname[0] = '.';
+ bname[1] = '\0';
+ return (bname);
+ }
+
+ /* Strip any trailing slashes */
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/')
+ endp--;
+
+ /* All slashes becomes "/" */
+ if (endp == path && *endp == '/') {
+ bname[0] = '/';
+ bname[1] = '\0';
+ return (bname);
+ }
+
+ /* Find the start of the base */
+ startp = endp;
+ while (startp > path && *(startp - 1) != '/')
+ startp--;
+
+ len = endp - startp + 1;
+ if (len >= sizeof(bname)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(bname, startp, len);
+ bname[len] = '\0';
+ return (bname);
+}
diff --git a/lib/libc/libgen/dirname.c b/lib/libc/libgen/dirname.c
new file mode 100644
index 00000000..48860e2b
--- /dev/null
+++ b/lib/libc/libgen/dirname.c
@@ -0,0 +1,66 @@
+/* $OpenBSD: dirname.c,v 1.17 2020/10/20 19:30:14 naddy Exp $ */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <millert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
+#include <string.h>
+
+char *dirname(char *path)
+{
+ static char dname[PATH_MAX];
+ size_t len;
+ const char *endp;
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ dname[0] = '.';
+ dname[1] = '\0';
+ return (dname);
+ }
+
+ /* Strip any trailing slashes */
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/')
+ endp--;
+
+ /* Find the start of the dir */
+ while (endp > path && *endp != '/')
+ endp--;
+
+ /* Either the dir is "/" or there are no slashes */
+ if (endp == path) {
+ dname[0] = *endp == '/' ? '/' : '.';
+ dname[1] = '\0';
+ return (dname);
+ } else {
+ /* Move forward past the separating slashes */
+ do {
+ endp--;
+ } while (endp > path && *endp == '/');
+ }
+
+ len = endp - path + 1;
+ if (len >= sizeof(dname)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(dname, path, len);
+ dname[len] = '\0';
+ return (dname);
+}
diff --git a/lib/libc/mman/mlock.c b/lib/libc/mman/mlock.c
new file mode 100644
index 00000000..a7f48b27
--- /dev/null
+++ b/lib/libc/mman/mlock.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int mlock(const void *addr, size_t len)
+{
+ return syscall(mlock, addr, len);
+}
diff --git a/lib/libc/mman/mlockall.c b/lib/libc/mman/mlockall.c
new file mode 100644
index 00000000..df4dcbd1
--- /dev/null
+++ b/lib/libc/mman/mlockall.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int mlockall(int flags)
+{
+ return syscall(mlockall, flags);
+}
diff --git a/lib/libc/mman/mmap.c b/lib/libc/mman/mmap.c
new file mode 100644
index 00000000..d7918447
--- /dev/null
+++ b/lib/libc/mman/mmap.c
@@ -0,0 +1,10 @@
+#include <stddef.h>
+#include <linux/mman.h>
+#include <syscall.h>
+
+typedef __INT64_TYPE__ off_t;
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+{
+ return (void *)syscall(mmap, addr, len, prot, flags, fildes, off);
+}
diff --git a/lib/libc/mman/mprotect.c b/lib/libc/mman/mprotect.c
new file mode 100644
index 00000000..ab5c6059
--- /dev/null
+++ b/lib/libc/mman/mprotect.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int mprotect(void *addr, size_t len, int prot)
+{
+ return syscall(mprotect, addr, len, prot);
+}
diff --git a/lib/libc/mman/msync.c b/lib/libc/mman/msync.c
new file mode 100644
index 00000000..b8dab1a9
--- /dev/null
+++ b/lib/libc/mman/msync.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int msync(void *addr, size_t len, int flags)
+{
+ return syscall(msync, addr, len, flags);
+}
diff --git a/lib/libc/mman/munlock.c b/lib/libc/mman/munlock.c
new file mode 100644
index 00000000..b934c87d
--- /dev/null
+++ b/lib/libc/mman/munlock.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int munlock(const void *addr, size_t len)
+{
+ return syscall(munlock, addr, len);
+}
diff --git a/lib/libc/mman/munlockall.c b/lib/libc/mman/munlockall.c
new file mode 100644
index 00000000..c7f9c8d2
--- /dev/null
+++ b/lib/libc/mman/munlockall.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/mman.h>
+
+int munlockall(void)
+{
+ return syscall(munlockall);
+}
diff --git a/lib/libc/mman/munmap.c b/lib/libc/mman/munmap.c
new file mode 100644
index 00000000..6929fc64
--- /dev/null
+++ b/lib/libc/mman/munmap.c
@@ -0,0 +1,8 @@
+#include <sys/mman.h>
+#include <syscall.h>
+#include <features.h>
+
+int munmap(void *addr, size_t len)
+{
+ return syscall(munmap, addr, len);
+}
diff --git a/lib/libc/mman/posix_madvise.c b/lib/libc/mman/posix_madvise.c
new file mode 100644
index 00000000..a19adec2
--- /dev/null
+++ b/lib/libc/mman/posix_madvise.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include <syscall.h>
+
+int posix_madvise(void *addr, size_t len, int advice)
+{
+ return syscall(madvise, addr, len, advice);
+}
diff --git a/lib/libc/monetary/strfmon.c b/lib/libc/monetary/strfmon.c
new file mode 100644
index 00000000..8ba0d48d
--- /dev/null
+++ b/lib/libc/monetary/strfmon.c
@@ -0,0 +1,131 @@
+// Orginal source:
+// https://git.musl-libc.org/cgit/musl/tree/src/monetary/strfmon.c
+//
+// ----------------------------------------------------------------------
+// Copyright © 2005-2020 Rich Felker, et al.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ----------------------------------------------------------------------
+
+#include <libc.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <monetary.h>
+
+static ssize_t vstrfmon_l(char *s, size_t n, const char *fmt, va_list ap)
+{
+ size_t l;
+ double x;
+ int fill, nogrp, negpar, nosym, left, intl;
+ int lp, rp, w, fw;
+ char *s0 = s;
+ for (; n && *fmt;) {
+ if (*fmt != '%') {
+literal:
+ *s++ = *fmt++;
+ n--;
+ continue;
+ }
+ fmt++;
+ if (*fmt == '%')
+ goto literal;
+
+ fill = ' ';
+ nogrp = 0;
+ negpar = 0;
+ nosym = 0;
+ left = 0;
+ for (;; fmt++) {
+ switch (*fmt) {
+ case '=':
+ fill = *++fmt;
+ continue;
+ case '^':
+ nogrp = 1;
+ continue;
+ case '(':
+ negpar = 1;
+ case '+':
+ continue;
+ case '!':
+ nosym = 1;
+ continue;
+ case '-':
+ left = 1;
+ continue;
+ }
+ break;
+ }
+
+ for (fw = 0; isdigit(*fmt); fmt++)
+ fw = 10 * fw + (*fmt - '0');
+ lp = 0;
+ rp = 2;
+ if (*fmt == '#')
+ for (lp = 0, fmt++; isdigit(*fmt); fmt++)
+ lp = 10 * lp + (*fmt - '0');
+ if (*fmt == '.')
+ for (rp = 0, fmt++; isdigit(*fmt); fmt++)
+ rp = 10 * rp + (*fmt - '0');
+
+ intl = *fmt++ == 'i';
+
+ w = lp + 1 + rp;
+ if (!left && fw > w)
+ w = fw;
+
+ x = va_arg(ap, double);
+ l = snprintf(s, n, "%*.*f", w, rp, x);
+ if (l >= n) {
+ errno = E2BIG;
+ return -1;
+ }
+ s += l;
+ n -= l;
+ }
+ return s - s0;
+}
+
+ssize_t strfmon(char *restrict s, size_t n, const char *restrict fmt, ...)
+{
+ va_list ap;
+ ssize_t ret;
+
+ va_start(ap, fmt);
+ ret = vstrfmon_l(s, n, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+weak ssize_t strfmon_l(char *restrict s, size_t n, locale_t unused loc,
+ const char *restrict fmt, ...)
+{
+ va_list ap;
+ ssize_t ret;
+
+ va_start(ap, fmt);
+ ret = vstrfmon_l(s, n, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
diff --git a/lib/libc/msg/msgctl.c b/lib/libc/msg/msgctl.c
new file mode 100644
index 00000000..fd25cae4
--- /dev/null
+++ b/lib/libc/msg/msgctl.c
@@ -0,0 +1,8 @@
+#include <endian.h>
+#include <sys/msg.h>
+#include <syscall.h>
+
+int msgctl(int msqid, int cmd, struct msqid_ds *buf)
+{
+ return syscall(msgctl, msqid, cmd, buf);
+}
diff --git a/lib/libc/poll/poll.c b/lib/libc/poll/poll.c
new file mode 100644
index 00000000..4ff90aa6
--- /dev/null
+++ b/lib/libc/poll/poll.c
@@ -0,0 +1,7 @@
+#include <poll.h>
+#include <syscall.h>
+
+int poll(struct pollfd fds[], nfds_t nfds, int timeout)
+{
+ return syscall(poll, fds, nfds, timeout);
+}
diff --git a/lib/libc/poll/ppoll.c b/lib/libc/poll/ppoll.c
new file mode 100644
index 00000000..a5ab9d5e
--- /dev/null
+++ b/lib/libc/poll/ppoll.c
@@ -0,0 +1,9 @@
+#include <poll.h>
+#include <syscall.h>
+
+int ppoll(struct pollfd fds[], nfds_t nfds,
+ const struct timespec *restrict timeout,
+ const sigset_t *restrict sigmask)
+{
+ return syscall(ppoll, fds, nfds, timeout, sigmask, 8);
+}
diff --git a/lib/libc/pwd/getgrgid.c b/lib/libc/pwd/getgrgid.c
new file mode 100644
index 00000000..5e825c12
--- /dev/null
+++ b/lib/libc/pwd/getgrgid.c
@@ -0,0 +1,15 @@
+#include <pwd.h>
+#include <stddef.h>
+#include <limits.h>
+
+struct passwd *getpwuid(uid_t uid)
+{
+ static struct passwd pwd;
+ static char buf[LINE_MAX * 4];
+ struct passwd *res;
+
+ if (getpwuid_r(uid, &pwd, buf, sizeof(buf), &res) != 0)
+ return NULL;
+
+ return res;
+}
diff --git a/lib/libc/pwd/getgrgid_r.c b/lib/libc/pwd/getgrgid_r.c
new file mode 100644
index 00000000..33705fdf
--- /dev/null
+++ b/lib/libc/pwd/getgrgid_r.c
@@ -0,0 +1,72 @@
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+static char *copy_str(const char *src, char **buf, size_t *buflen)
+{
+ size_t len = strlen(src) + 1;
+ if (len > *buflen)
+ return NULL;
+ char *dst = *buf;
+ memcpy(dst, src, len);
+ *buf += len;
+ *buflen -= len;
+ return dst;
+}
+
+int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen,
+ struct passwd **result)
+{
+ FILE *stream = fopen("/etc/passwd", "r");
+ if (stream == NULL) {
+ *result = NULL;
+ return errno;
+ }
+
+ char line[LINE_MAX];
+
+ while (fgets(line, sizeof(line), stream)) {
+ char *name = strtok(line, ":");
+ char *passwd = strtok(NULL, ":");
+ char *uid_str = strtok(NULL, ":");
+ char *gid_str = strtok(NULL, ":");
+ strtok(NULL, ":");
+ char *dir = strtok(NULL, ":");
+ char *shell = strtok(NULL, "\n");
+
+ if (name == NULL || passwd == NULL || uid_str == NULL ||
+ gid_str == NULL)
+ continue;
+
+ uid_t file_uid = (uid_t)strtoul(uid_str, NULL, 10);
+ if (file_uid != uid)
+ continue;
+
+ size_t rem = buflen;
+
+ pwd->pw_name = copy_str(name, &buf, &rem);
+ pwd->pw_dir = copy_str(dir ? dir : "", &buf, &rem);
+ pwd->pw_shell = copy_str(shell ? shell : "", &buf, &rem);
+ pwd->pw_uid = file_uid;
+ pwd->pw_gid = (gid_t)strtoul(gid_str, NULL, 10);
+ pwd->pw_uid = file_uid;
+ pwd->pw_gid = (gid_t)strtoul(gid_str, NULL, 10);
+
+ if (pwd->pw_name == NULL || pwd->pw_dir == NULL ||
+ pwd->pw_shell == NULL) {
+ fclose(stream);
+ return ERANGE;
+ }
+
+ fclose(stream);
+ *result = pwd;
+ return 0;
+ }
+
+ fclose(stream);
+ *result = NULL;
+ return 0;
+}
diff --git a/lib/libc/select/pselect.c b/lib/libc/select/pselect.c
new file mode 100644
index 00000000..75d31d87
--- /dev/null
+++ b/lib/libc/select/pselect.c
@@ -0,0 +1,11 @@
+#include <sys/select.h>
+#include <stdint.h>
+#include <syscall.h>
+
+int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
+ fd_set *restrict errorfds, const struct timespec *restrict timeout,
+ const sigset_t *restrict sigmask)
+{
+ return syscall(pselect6, nfds, readfds, writefds, errorfds, timeout,
+ ((syscall_arg_t[]){ (uintptr_t)sigmask, 8 }));
+}
diff --git a/lib/libc/select/select.c b/lib/libc/select/select.c
new file mode 100644
index 00000000..4e9f2f99
--- /dev/null
+++ b/lib/libc/select/select.c
@@ -0,0 +1,9 @@
+#include <sys/select.h>
+#include <syscall.h>
+
+int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
+ fd_set *restrict errorfds, struct timeval *restrict timeout)
+{
+ return syscall(pselect6, nfds, readfds, writefds, errorfds, timeout,
+ ((syscall_arg_t[]){ 0, 8 }));
+}
diff --git a/lib/libc/sem/semctl.c b/lib/libc/sem/semctl.c
new file mode 100644
index 00000000..78a1adf8
--- /dev/null
+++ b/lib/libc/sem/semctl.c
@@ -0,0 +1,24 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <syscall.h>
+
+int semctl(int semid, int semnum, int cmd, ...)
+{
+ va_list ap;
+ struct semid_ds *buf = NULL;
+
+ switch (cmd) {
+ case SETVAL:
+ case GETALL:
+ case SETALL:
+ case IPC_SET:
+ case IPC_STAT:
+ va_start(ap, cmd);
+ buf = va_arg(ap, struct semid_ds *);
+ va_end(ap);
+ }
+
+ return syscall(semctl, semid, semnum, cmd, buf);
+}
diff --git a/lib/libc/sem/semget.c b/lib/libc/sem/semget.c
new file mode 100644
index 00000000..75e1bab9
--- /dev/null
+++ b/lib/libc/sem/semget.c
@@ -0,0 +1,7 @@
+#include <sys/sem.h>
+#include <syscall.h>
+
+int semget(key_t key, int nsems, int semflg)
+{
+ return syscall(semget, key, nsems, semflg);
+}
diff --git a/lib/libc/sem/semop.c b/lib/libc/sem/semop.c
new file mode 100644
index 00000000..82e956dc
--- /dev/null
+++ b/lib/libc/sem/semop.c
@@ -0,0 +1,7 @@
+#include <sys/sem.h>
+#include <syscall.h>
+
+int semop(int semid, struct sembuf *sops, size_t nsops)
+{
+ return syscall(semop, semid, sops, nsops);
+}
diff --git a/lib/libc/setjmp/siglongjmp.c b/lib/libc/setjmp/siglongjmp.c
new file mode 100644
index 00000000..4f39cc37
--- /dev/null
+++ b/lib/libc/setjmp/siglongjmp.c
@@ -0,0 +1,6 @@
+#include <setjmp.h>
+
+_Noreturn void siglongjmp(sigjmp_buf env, int val)
+{
+ longjmp(env, val);
+}
diff --git a/lib/libc/signal/kill.c b/lib/libc/signal/kill.c
new file mode 100644
index 00000000..d2a7ae68
--- /dev/null
+++ b/lib/libc/signal/kill.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include <syscall.h>
+
+int kill(pid_t pid, int sig)
+{
+ return syscall(kill, pid, sig);
+}
diff --git a/lib/libc/signal/killpg.c b/lib/libc/signal/killpg.c
new file mode 100644
index 00000000..27b7a76a
--- /dev/null
+++ b/lib/libc/signal/killpg.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+#include <signal.h>
+#include <syscall.h>
+
+int killpg(pid_t pgrp, int sig)
+{
+ if (pgrp < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return kill(-pgrp, sig);
+}
diff --git a/lib/libc/signal/psiginfo.c b/lib/libc/signal/psiginfo.c
new file mode 100644
index 00000000..47e10508
--- /dev/null
+++ b/lib/libc/signal/psiginfo.c
@@ -0,0 +1,6 @@
+#include <signal.h>
+
+void psiginfo(const siginfo_t *pinfo, const char *message)
+{
+ psignal(pinfo->si_signo, message);
+}
diff --git a/lib/libc/signal/psignal.c b/lib/libc/signal/psignal.c
new file mode 100644
index 00000000..200b353c
--- /dev/null
+++ b/lib/libc/signal/psignal.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+void psignal(int signum, const char *message)
+{
+ fprintf(stderr, "%s%s%s\n", message ? message : "", message ? ": " : "",
+ strsignal(signum));
+}
diff --git a/lib/libc/signal/pthread_kill.c b/lib/libc/signal/pthread_kill.c
new file mode 100644
index 00000000..9323a869
--- /dev/null
+++ b/lib/libc/signal/pthread_kill.c
@@ -0,0 +1,18 @@
+#include <thread.h>
+#include <asm-generic/signal.h>
+#include <syscall.h>
+
+typedef struct __thread_self *pthread_t;
+
+int pthread_kill(pthread_t thread, int sig)
+{
+ if (sig < 0 || sig > _NSIG) {
+ return EINVAL;
+ }
+
+ if (thread->tid == 0) {
+ return 0;
+ }
+
+ return syscall(tkill, thread->tid, sig);
+}
diff --git a/lib/libc/signal/pthread_sigmask.c b/lib/libc/signal/pthread_sigmask.c
new file mode 100644
index 00000000..1b83e1fe
--- /dev/null
+++ b/lib/libc/signal/pthread_sigmask.c
@@ -0,0 +1,23 @@
+#include <errno.h>
+#include <asm-generic/signal.h>
+#include <libc.h>
+
+int sigdelset(sigset_t *, int);
+int sigismember(const sigset_t *, int);
+int sigprocmask(int, const sigset_t *restrict, sigset_t *restrict);
+
+int pthread_sigmask(int how, const sigset_t *restrict set,
+ sigset_t *restrict oset)
+{
+ sigset_t lset;
+
+ if (set != NULL && (unlikely(sigismember(set, SIGRTMIN)) ||
+ unlikely(sigismember(set, SIGRTMIN + 1)))) {
+ lset = *set;
+ sigdelset(&lset, SIGRTMIN);
+ sigdelset(&lset, SIGRTMIN + 1);
+ set = &lset;
+ }
+
+ return sigprocmask(how, set, oset) == -1 ? errno : 0;
+}
diff --git a/lib/libc/signal/raise.c b/lib/libc/signal/raise.c
new file mode 100644
index 00000000..3bdbc9cc
--- /dev/null
+++ b/lib/libc/signal/raise.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <signal.h>
+
+int raise(int sig)
+{
+ return kill(getpid(), sig);
+}
diff --git a/lib/libc/signal/sig2str.c b/lib/libc/signal/sig2str.c
new file mode 100644
index 00000000..209cb4c3
--- /dev/null
+++ b/lib/libc/signal/sig2str.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <string.h>
+#include <asm-generic/signal.h>
+#include <__signal.h>
+
+int sig2str(int signum, char *str)
+{
+ if (signum >= SIGHUP && signum <= SIGSYS) {
+ strcpy(str, __sys_signame[signum - SIGHUP]);
+ return 0;
+ }
+
+ if (signum == SIGRTMIN) {
+ strcpy(str, "SIGRTMIN");
+ return 0;
+ }
+
+ if (signum == SIGRTMAX) {
+ strcpy(str, "RTMAX");
+ return 0;
+ }
+
+ if (signum > SIGRTMIN && signum < SIGRTMAX) {
+ if (signum - SIGRTMIN <= SIGRTMAX - signum) {
+ sprintf(str, "RTMIN+%d", signum - SIGRTMIN);
+ } else {
+ sprintf(str, "RTMAX-%d", SIGRTMAX - signum);
+ }
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/lib/libc/signal/sigaction.c b/lib/libc/signal/sigaction.c
new file mode 100644
index 00000000..f8377ebb
--- /dev/null
+++ b/lib/libc/signal/sigaction.c
@@ -0,0 +1,8 @@
+#include <signal.h>
+#include <syscall.h>
+
+int sigaction(int sig, const struct sigaction *restrict act,
+ struct sigaction *restrict oact)
+{
+ return syscall(rt_sigaction, sig, act, oact, sizeof(sigset_t));
+}
diff --git a/lib/libc/signal/sigaddset.c b/lib/libc/signal/sigaddset.c
new file mode 100644
index 00000000..33e74bd0
--- /dev/null
+++ b/lib/libc/signal/sigaddset.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+int sigaddset(sigset_t *set, int signo)
+{
+ if (signo < 1 || signo > 64) {
+ return -1;
+ }
+ *set |= (1ULL << (signo - 1));
+ return 0;
+}
diff --git a/lib/libc/signal/sigemptyset.c b/lib/libc/signal/sigemptyset.c
new file mode 100644
index 00000000..6552bf45
--- /dev/null
+++ b/lib/libc/signal/sigemptyset.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+int sigemptyset(sigset_t *set)
+{
+ if (!set)
+ return -1;
+ *set = 0;
+
+ return 0;
+}
diff --git a/lib/libc/signal/sigismember.c b/lib/libc/signal/sigismember.c
new file mode 100644
index 00000000..8adf5fab
--- /dev/null
+++ b/lib/libc/signal/sigismember.c
@@ -0,0 +1,18 @@
+#include <asm-generic/signal.h>
+
+typedef __UINT64_TYPE__ __sigset_t;
+
+#define __sigmask(sig) (((__sigset_t)1) << ((sig) - 1))
+#define __sigismember(set, sig) \
+ (__extension__({ \
+ __sigset_t __mask = __sigmask(sig); \
+ *(set) & __mask ? 1 : 0; \
+ }))
+
+int sigismember(const __sigset_t *set, int signo)
+{
+ if (signo < 1 || signo > _NSIG)
+ return -1;
+
+ return __sigismember((const __sigset_t *)set, signo);
+}
diff --git a/lib/libc/signal/signal.c b/lib/libc/signal/signal.c
new file mode 100644
index 00000000..c2f578eb
--- /dev/null
+++ b/lib/libc/signal/signal.c
@@ -0,0 +1,14 @@
+#include <signal.h>
+
+void (*signal(int sig, void (*func)(int)))(int)
+{
+ struct sigaction act, oact;
+
+ act.sa_handler = func;
+ act.sa_flags = SA_RESTART;
+
+ if (sigaction(sig, &act, &oact) < 0)
+ return SIG_ERR;
+
+ return oact.sa_handler;
+}
diff --git a/lib/libc/signal/sigpending.c b/lib/libc/signal/sigpending.c
new file mode 100644
index 00000000..b57f4adf
--- /dev/null
+++ b/lib/libc/signal/sigpending.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include <syscall.h>
+
+int sigpending(sigset_t *set)
+{
+ return syscall(rt_sigpending, set);
+}
diff --git a/lib/libc/signal/sigprocmask.c b/lib/libc/signal/sigprocmask.c
new file mode 100644
index 00000000..54063b9d
--- /dev/null
+++ b/lib/libc/signal/sigprocmask.c
@@ -0,0 +1,17 @@
+#include <signal.h>
+#include <syscall.h>
+
+int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
+{
+ long ret;
+ sigset_t oldset = { 0 };
+
+ ret = syscall(rt_sigprocmask, how, set, &oldset, sizeof(sigset_t));
+
+ if (ret < 0)
+ return -1;
+
+ if (oset)
+ *oset = oldset;
+ return 0;
+}
diff --git a/lib/libc/signal/sigqueue.c b/lib/libc/signal/sigqueue.c
new file mode 100644
index 00000000..9e5b6ddd
--- /dev/null
+++ b/lib/libc/signal/sigqueue.c
@@ -0,0 +1,15 @@
+#include <signal.h>
+#include <errno.h>
+
+int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict old)
+{
+ int r = pthread_sigmask(how, set, old);
+
+ if (r == 0) {
+ return r;
+ }
+
+ errno = r;
+
+ return -1;
+}
diff --git a/lib/libc/signal/sigsuspend.c b/lib/libc/signal/sigsuspend.c
new file mode 100644
index 00000000..1e6b88a6
--- /dev/null
+++ b/lib/libc/signal/sigsuspend.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include <syscall.h>
+
+int sigsuspend(const sigset_t *sigmask)
+{
+ return syscall(rt_sigsuspend, sigmask, sizeof(sigset_t));
+}
diff --git a/lib/libc/signal/sigtimedwait.c b/lib/libc/signal/sigtimedwait.c
new file mode 100644
index 00000000..d55a4310
--- /dev/null
+++ b/lib/libc/signal/sigtimedwait.c
@@ -0,0 +1,10 @@
+#include <signal.h>
+#include <syscall.h>
+
+#define _NSIG 64
+
+int sigtimedwait(const sigset_t *restrict set, siginfo_t *restrict info,
+ const struct timespec *restrict timeout)
+{
+ return syscall(rt_sigtimedwait, set, info, timeout, _NSIG / 8);
+}
diff --git a/lib/libc/signal/sigwait.c b/lib/libc/signal/sigwait.c
new file mode 100644
index 00000000..59b0dd6c
--- /dev/null
+++ b/lib/libc/signal/sigwait.c
@@ -0,0 +1,14 @@
+#include <signal.h>
+
+int sigwait(const sigset_t *restrict mask, int *restrict sig)
+{
+ siginfo_t si;
+
+ if (sigtimedwait(mask, &si, 0) < 0) {
+ return -1;
+ }
+
+ *sig = si.si_signo;
+
+ return 0;
+}
diff --git a/lib/libc/signal/sigwaitinfo.c b/lib/libc/signal/sigwaitinfo.c
new file mode 100644
index 00000000..bb51f8b5
--- /dev/null
+++ b/lib/libc/signal/sigwaitinfo.c
@@ -0,0 +1,6 @@
+#include <signal.h>
+
+int sigwaitinfo(const sigset_t *restrict mask, siginfo_t *restrict si)
+{
+ return sigtimedwait(mask, si, 0);
+}
diff --git a/lib/libc/signal/str2sig.c b/lib/libc/signal/str2sig.c
new file mode 100644
index 00000000..288948d7
--- /dev/null
+++ b/lib/libc/signal/str2sig.c
@@ -0,0 +1,52 @@
+#include <__signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <asm-generic/signal.h>
+
+int str2sig(const char *restrict str, int *restrict pnum)
+{
+ for (size_t i = SIGHUP; i <= SIGSYS; ++i) {
+ if (!strcmp(str, __sys_signame[i])) {
+ *pnum = i;
+ return 0;
+ }
+ }
+
+ if (strcmp(str, "RTMIN") == 0) {
+ *pnum = SIGRTMIN;
+ return 0;
+ }
+
+ if (strcmp(str, "RTMAX") == 0) {
+ *pnum = SIGRTMAX;
+ return 0;
+ }
+
+ int base = 0;
+ if (strncmp(str, "RTMIN+", 6) == 0) {
+ base = SIGRTMIN;
+ str += 5;
+ } else if (strncmp(str, "RTMAX-", 6) == 0) {
+ base = SIGRTMAX;
+ str += 5;
+ }
+
+ char *end = NULL;
+ errno = 0;
+ int offset = strtol(str, &end, 10);
+ if (errno || *end) {
+ return -1;
+ }
+
+ int result = base + offset;
+ bool regular = (base == 0 && result >= SIGHUP && result <= SIGSYS);
+ bool realtime = (result >= SIGRTMIN && result <= SIGRTMAX);
+ if (!regular && !realtime) {
+ return -1;
+ }
+
+ *pnum = result;
+ return 0;
+}
diff --git a/lib/libc/socket/accept.c b/lib/libc/socket/accept.c
new file mode 100644
index 00000000..61c469c8
--- /dev/null
+++ b/lib/libc/socket/accept.c
@@ -0,0 +1,8 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int accept(int socket, struct sockaddr *restrict address,
+ socklen_t *restrict address_len)
+{
+ return syscall(accept, socket, address, address_len);
+}
diff --git a/lib/libc/socket/accept4.c b/lib/libc/socket/accept4.c
new file mode 100644
index 00000000..8171098b
--- /dev/null
+++ b/lib/libc/socket/accept4.c
@@ -0,0 +1,8 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int accept4(int socket, struct sockaddr *restrict address,
+ socklen_t *restrict address_len, int flag)
+{
+ return syscall(accept4, socket, address, address_len, flag);
+}
diff --git a/lib/libc/socket/bind.c b/lib/libc/socket/bind.c
new file mode 100644
index 00000000..111ac321
--- /dev/null
+++ b/lib/libc/socket/bind.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int bind(int socket, const struct sockaddr *address, socklen_t address_len)
+{
+ return syscall(bind, socket, address, address_len);
+}
diff --git a/lib/libc/socket/connect.c b/lib/libc/socket/connect.c
new file mode 100644
index 00000000..fc4502cb
--- /dev/null
+++ b/lib/libc/socket/connect.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int connect(int socket, const struct sockaddr *address, socklen_t address_len)
+{
+ return syscall(connect, socket, address, address_len);
+}
diff --git a/lib/libc/socket/getpeername.c b/lib/libc/socket/getpeername.c
new file mode 100644
index 00000000..4b694220
--- /dev/null
+++ b/lib/libc/socket/getpeername.c
@@ -0,0 +1,8 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int getpeername(int socket, struct sockaddr *restrict address,
+ socklen_t *restrict address_len)
+{
+ return syscall(getpeername, socket, address, address_len);
+}
diff --git a/lib/libc/socket/getsockname.c b/lib/libc/socket/getsockname.c
new file mode 100644
index 00000000..d8b356fb
--- /dev/null
+++ b/lib/libc/socket/getsockname.c
@@ -0,0 +1,8 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int getsockname(int socket, struct sockaddr *restrict address,
+ socklen_t *restrict address_len)
+{
+ return syscall(getsockname, socket, address, address_len);
+}
diff --git a/lib/libc/socket/getsockopt.c b/lib/libc/socket/getsockopt.c
new file mode 100644
index 00000000..2ab56774
--- /dev/null
+++ b/lib/libc/socket/getsockopt.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int getsockopt(int socket, int level, int option_name,
+ void *restrict option_value, socklen_t *restrict option_len)
+{
+ return syscall(getsockopt, socket, level, option_name, option_value,
+ option_len);
+}
diff --git a/lib/libc/socket/listen.c b/lib/libc/socket/listen.c
new file mode 100644
index 00000000..3b107450
--- /dev/null
+++ b/lib/libc/socket/listen.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int listen(int socket, int backlog)
+{
+ return syscall(listen, backlog);
+}
diff --git a/lib/libc/socket/recv.c b/lib/libc/socket/recv.c
new file mode 100644
index 00000000..87bec811
--- /dev/null
+++ b/lib/libc/socket/recv.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+ssize_t recv(int socket, void *buffer, size_t length, int flags)
+{
+ return syscall(recvfrom, socket, buffer, length, flags, 0, 0);
+}
diff --git a/lib/libc/socket/recvfrom.c b/lib/libc/socket/recvfrom.c
new file mode 100644
index 00000000..a3faa0bb
--- /dev/null
+++ b/lib/libc/socket/recvfrom.c
@@ -0,0 +1,10 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags,
+ struct sockaddr *restrict address,
+ socklen_t *restrict address_len)
+{
+ return syscall(recvfrom, socket, buffer, length, flags, address,
+ address_len);
+}
diff --git a/lib/libc/socket/recvmsg.c b/lib/libc/socket/recvmsg.c
new file mode 100644
index 00000000..29183f35
--- /dev/null
+++ b/lib/libc/socket/recvmsg.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+ssize_t recvmsg(int socket, struct msghdr *message, int flags)
+{
+ return syscall(recvmsg, socket, message, flags);
+}
diff --git a/lib/libc/socket/send.c b/lib/libc/socket/send.c
new file mode 100644
index 00000000..a2760a2f
--- /dev/null
+++ b/lib/libc/socket/send.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+ssize_t send(int socket, const void *buffer, size_t length, int flags)
+{
+ return syscall(sendto, socket, buffer, length, flags, 0, 0);
+}
diff --git a/lib/libc/socket/sendmsg.c b/lib/libc/socket/sendmsg.c
new file mode 100644
index 00000000..6414021c
--- /dev/null
+++ b/lib/libc/socket/sendmsg.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/socket.h>
+
+ssize_t sendmsg(int socket, const struct msghdr *message, int flags)
+{
+ return syscall(sendmsg, socket, message, flags);
+}
diff --git a/lib/libc/socket/sendto.c b/lib/libc/socket/sendto.c
new file mode 100644
index 00000000..f9628f50
--- /dev/null
+++ b/lib/libc/socket/sendto.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+ssize_t sendto(int socket, const void *message, size_t length, int flags,
+ const struct sockaddr *dest_addr, socklen_t dest_len)
+{
+ return syscall(sendto, socket, message, length, flags, dest_addr,
+ dest_len);
+}
diff --git a/lib/libc/socket/setsockopt.c b/lib/libc/socket/setsockopt.c
new file mode 100644
index 00000000..8f25bab4
--- /dev/null
+++ b/lib/libc/socket/setsockopt.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include <syscall.h>
+
+int setsockopt(int socket, int level, int option_name, const void *option_value,
+ socklen_t option_len)
+{
+ return syscall(setsockopt, socket, level, option_name, option_value,
+ option_len);
+}
diff --git a/lib/libc/socket/shutdown.c b/lib/libc/socket/shutdown.c
new file mode 100644
index 00000000..96c8053c
--- /dev/null
+++ b/lib/libc/socket/shutdown.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int shutdown(int socket, int how)
+{
+ return syscall(shutdown, socket, how);
+}
diff --git a/lib/libc/socket/sockatmark.c b/lib/libc/socket/sockatmark.c
new file mode 100644
index 00000000..f7178aa0
--- /dev/null
+++ b/lib/libc/socket/sockatmark.c
@@ -0,0 +1,8 @@
+#include <syscall.h>
+#include <asm-generic/sockios.h>
+
+int sockatmark(int s)
+{
+ int arg = 0;
+ return syscall(ioctl, s, SIOCATMARK, &arg) < 0 ? -1 : arg;
+}
diff --git a/lib/libc/socket/socket.c b/lib/libc/socket/socket.c
new file mode 100644
index 00000000..34b5d67b
--- /dev/null
+++ b/lib/libc/socket/socket.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int socket(int domain, int type, int protocol)
+{
+ return syscall(socket, domain, type, protocol);
+}
diff --git a/lib/libc/socket/socketpair.c b/lib/libc/socket/socketpair.c
new file mode 100644
index 00000000..6e78b30b
--- /dev/null
+++ b/lib/libc/socket/socketpair.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int socketpair(int domain, int type, int protocol, int socket_vector[2])
+{
+ return syscall(socketpair, domain, type, protocol, socket_vector);
+}
diff --git a/lib/libc/stat/chmod.c b/lib/libc/stat/chmod.c
new file mode 100644
index 00000000..6b7283e2
--- /dev/null
+++ b/lib/libc/stat/chmod.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include <syscall.h>
+
+int chmod(const char *path, mode_t mode)
+{
+ return syscall(chmod, path, mode);
+}
diff --git a/lib/libc/stat/fchmod.c b/lib/libc/stat/fchmod.c
new file mode 100644
index 00000000..22593fd6
--- /dev/null
+++ b/lib/libc/stat/fchmod.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include <syscall.h>
+
+int fchmod(int fildes, mode_t mode)
+{
+ return syscall(fchmod, fildes, mode);
+}
diff --git a/lib/libc/stat/fchmodat.c b/lib/libc/stat/fchmodat.c
new file mode 100644
index 00000000..71a3c0c5
--- /dev/null
+++ b/lib/libc/stat/fchmodat.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include <syscall.h>
+
+int fchmodat(int fd, const char *path, mode_t mode, int flag)
+{
+ return syscall(fchmodat2, fd, path, mode, flag);
+}
diff --git a/lib/libc/stat/fstat.c b/lib/libc/stat/fstat.c
new file mode 100644
index 00000000..7a9fb4e4
--- /dev/null
+++ b/lib/libc/stat/fstat.c
@@ -0,0 +1,8 @@
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <syscall.h>
+
+int fstat(int fildes, struct stat *buf)
+{
+ return fstatat(fildes, "", buf, 0);
+}
diff --git a/lib/libc/stat/fstatat.c b/lib/libc/stat/fstatat.c
new file mode 100644
index 00000000..06b00163
--- /dev/null
+++ b/lib/libc/stat/fstatat.c
@@ -0,0 +1,46 @@
+#include <sys/stat.h>
+#include <syscall.h>
+
+#include <linux/stat.h>
+
+#define makedev(major, minor) \
+ ((((major) & 0xfffff000ULL) << 32) | \
+ (((major) & 0x00000fffULL) << 8) | \
+ (((minor) & 0xffffff00ULL) << 12) | (((minor) & 0x000000ffULL)))
+
+int fstatat(int fd, const char *restrict path, struct stat *restrict buf,
+ int flag)
+{
+ int ret;
+ struct statx stx = { 0 };
+
+ ret = syscall(statx, fd, path, flag, 0x7ff, &stx);
+
+ if (ret == 0) {
+ if (stx.stx_mask & STATX_BASIC_STATS) {
+ buf->st_dev =
+ makedev(stx.stx_dev_major, stx.stx_dev_minor);
+ buf->st_ino = stx.stx_ino;
+ buf->st_mode = stx.stx_mode;
+ buf->st_nlink = stx.stx_nlink;
+ buf->st_uid = stx.stx_uid;
+ buf->st_gid = stx.stx_gid;
+ buf->st_rdev =
+ makedev(stx.stx_rdev_major, stx.stx_rdev_minor);
+ buf->st_size = stx.stx_size;
+ buf->st_atim.tv_sec = stx.stx_atime.tv_sec;
+ buf->st_atim.tv_nsec = stx.stx_atime.tv_nsec;
+ buf->st_mtim.tv_sec = stx.stx_mtime.tv_sec;
+ buf->st_mtim.tv_nsec = stx.stx_mtime.tv_nsec;
+ buf->st_ctim.tv_sec = stx.stx_ctime.tv_sec;
+ buf->st_ctim.tv_nsec = stx.stx_ctime.tv_nsec;
+ buf->st_blksize = stx.stx_blksize;
+ buf->st_blocks = stx.stx_blocks;
+ } else {
+ ret = -1; // Indicate failure if STATX_BASIC_STATS is
+ // not set
+ }
+ }
+
+ return ret;
+}
diff --git a/lib/libc/stat/futimens.c b/lib/libc/stat/futimens.c
new file mode 100644
index 00000000..974d2eb7
--- /dev/null
+++ b/lib/libc/stat/futimens.c
@@ -0,0 +1,7 @@
+#include <stddef.h>
+#include <sys/stat.h>
+
+int futimens(int fd, const struct timespec times[2])
+{
+ return utimensat(fd, NULL, times, 0);
+}
diff --git a/lib/libc/stat/lstat.c b/lib/libc/stat/lstat.c
new file mode 100644
index 00000000..a188f78d
--- /dev/null
+++ b/lib/libc/stat/lstat.c
@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <sys/stat.h>
+
+int lstat(const char *restrict path, struct stat *restrict buf)
+{
+ return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+}
diff --git a/lib/libc/stat/mkdir.c b/lib/libc/stat/mkdir.c
new file mode 100644
index 00000000..1f97fb3f
--- /dev/null
+++ b/lib/libc/stat/mkdir.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <syscall.h>
+#include <sys/stat.h>
+
+int mkdir(const char *path, mode_t mode)
+{
+#ifdef __NR_mkdir
+ return syscall(mkdir, path, mode);
+#else
+ return syscall(mkdirat, AT_FDCWD, path, mode);
+#endif
+}
diff --git a/lib/libc/stat/mkdirat.c b/lib/libc/stat/mkdirat.c
new file mode 100644
index 00000000..d129008b
--- /dev/null
+++ b/lib/libc/stat/mkdirat.c
@@ -0,0 +1,8 @@
+#include <fcntl.h>
+#include <syscall.h>
+#include <sys/stat.h>
+
+int mkdirat(int fd, const char *path, mode_t mode)
+{
+ return syscall(mkdirat, fd, path, mode);
+}
diff --git a/lib/libc/stat/mkfifo.c b/lib/libc/stat/mkfifo.c
new file mode 100644
index 00000000..60efcf73
--- /dev/null
+++ b/lib/libc/stat/mkfifo.c
@@ -0,0 +1,6 @@
+#include <sys/stat.h>
+
+int mkfifo(const char *path, mode_t mode)
+{
+ return mknod(path, mode | S_IFIFO, 0);
+}
diff --git a/lib/libc/stat/mkfifoat.c b/lib/libc/stat/mkfifoat.c
new file mode 100644
index 00000000..d3a1f970
--- /dev/null
+++ b/lib/libc/stat/mkfifoat.c
@@ -0,0 +1,6 @@
+#include <sys/stat.h>
+
+int mkfifoat(int fd, const char *path, mode_t mode)
+{
+ return mknodat(fd, path, mode | S_IFIFO, 0);
+}
diff --git a/lib/libc/stat/mknod.c b/lib/libc/stat/mknod.c
new file mode 100644
index 00000000..1a4a5c6c
--- /dev/null
+++ b/lib/libc/stat/mknod.c
@@ -0,0 +1,8 @@
+#include <fcntl.h>
+#include <syscall.h>
+#include <sys/stat.h>
+
+int mknod(const char *path, mode_t mode, dev_t dev)
+{
+ return syscall(mknodat, AT_FDCWD, path, mode, dev);
+}
diff --git a/lib/libc/stat/mknodat.c b/lib/libc/stat/mknodat.c
new file mode 100644
index 00000000..9967248e
--- /dev/null
+++ b/lib/libc/stat/mknodat.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <sys/stat.h>
+
+int mknodat(int fd, const char *path, mode_t mode, dev_t dev)
+{
+ return syscall(mknodat, fd, path, mode, dev);
+}
diff --git a/lib/libc/stat/stat.c b/lib/libc/stat/stat.c
new file mode 100644
index 00000000..95bdf73d
--- /dev/null
+++ b/lib/libc/stat/stat.c
@@ -0,0 +1,7 @@
+#include <fcntl.h>
+#include <sys/stat.h>
+
+int stat(const char *restrict path, struct stat *restrict buf)
+{
+ return fstatat(AT_FDCWD, path, buf, 0);
+}
diff --git a/lib/libc/stat/umask.c b/lib/libc/stat/umask.c
new file mode 100644
index 00000000..2724317a
--- /dev/null
+++ b/lib/libc/stat/umask.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include <syscall.h>
+
+mode_t umask(mode_t cmask)
+{
+ return syscall(umask, cmask);
+}
diff --git a/lib/libc/stat/utimensat.c b/lib/libc/stat/utimensat.c
new file mode 100644
index 00000000..d51611a3
--- /dev/null
+++ b/lib/libc/stat/utimensat.c
@@ -0,0 +1,8 @@
+#include <time.h>
+#include <syscall.h>
+
+int utimensat(int fd, const char *path, const struct timespec times[2],
+ int flag)
+{
+ return syscall(utimensat, fd, path, times, flag);
+}
diff --git a/lib/libc/statvfs/fstatvfs.c b/lib/libc/statvfs/fstatvfs.c
new file mode 100644
index 00000000..8bf78d35
--- /dev/null
+++ b/lib/libc/statvfs/fstatvfs.c
@@ -0,0 +1,25 @@
+#include <__statvfs.h>
+#include <syscall.h>
+#include <asm-generic/statfs.h>
+
+int fstatvfs(int fildes, struct __statvfs *buf)
+{
+ struct statfs statfs;
+
+ if (syscall(fstatfs, fildes, &statfs) < 0)
+ return -1;
+
+ buf->f_bsize = statfs.f_bsize;
+ buf->f_frsize = statfs.f_frsize ? statfs.f_frsize : statfs.f_bsize;
+ buf->f_blocks = statfs.f_blocks;
+ buf->f_bfree = statfs.f_bfree;
+ buf->f_bavail = statfs.f_bavail;
+ buf->f_files = statfs.f_files;
+ buf->f_ffree = statfs.f_ffree;
+ buf->f_favail = statfs.f_ffree;
+ buf->f_fsid = statfs.f_fsid.val[0];
+ buf->f_flag = statfs.f_flags;
+ buf->f_namemax = statfs.f_namelen;
+
+ return 0;
+}
diff --git a/lib/libc/statvfs/statvfs.c b/lib/libc/statvfs/statvfs.c
new file mode 100644
index 00000000..df8c9544
--- /dev/null
+++ b/lib/libc/statvfs/statvfs.c
@@ -0,0 +1,25 @@
+#include <__statvfs.h>
+#include <syscall.h>
+#include <asm-generic/statfs.h>
+
+int statvfs(const char *restrict path, struct __statvfs *restrict buf)
+{
+ struct statfs statfs;
+
+ if (syscall(statfs, path, &statfs) < 0)
+ return -1;
+
+ buf->f_bsize = statfs.f_bsize;
+ buf->f_frsize = statfs.f_frsize ? statfs.f_frsize : statfs.f_bsize;
+ buf->f_blocks = statfs.f_blocks;
+ buf->f_bfree = statfs.f_bfree;
+ buf->f_bavail = statfs.f_bavail;
+ buf->f_files = statfs.f_files;
+ buf->f_ffree = statfs.f_ffree;
+ buf->f_favail = statfs.f_ffree;
+ buf->f_fsid = statfs.f_fsid.val[0];
+ buf->f_flag = statfs.f_flags;
+ buf->f_namemax = statfs.f_namelen;
+
+ return 0;
+}
diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c
new file mode 100644
index 00000000..b868cce1
--- /dev/null
+++ b/lib/libc/stdio/asprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int asprintf(char **restrict ptr, const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vasprintf(ptr, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/clearerr.c b/lib/libc/stdio/clearerr.c
new file mode 100644
index 00000000..a49e5c2d
--- /dev/null
+++ b/lib/libc/stdio/clearerr.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <io.h>
+
+void clearerr(FILE *stream)
+{
+ if (stream == NULL)
+ return;
+
+ stream->flags &= ~(_IO_ERR | _IO_EOF);
+}
diff --git a/lib/libc/stdio/dprintf.c b/lib/libc/stdio/dprintf.c
new file mode 100644
index 00000000..10877b22
--- /dev/null
+++ b/lib/libc/stdio/dprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int dprintf(int fildes, const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vdprintf(fildes, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/dtoa.c b/lib/libc/stdio/dtoa.c
new file mode 100644
index 00000000..9417fa8e
--- /dev/null
+++ b/lib/libc/stdio/dtoa.c
@@ -0,0 +1,6249 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file. When needed, this call avoids double rounding, which can
+ * cause one bit errors, e.g., with strtod on 8.3e26 or 6.3876e-16.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ * (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.)
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa. This will cause dtoa modes 4 and 5 to be
+ * treated the same as modes 2 and 3 for some inputs.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS
+ * is also #defined, fegetround() will be queried for the rounding mode.
+ * Note that both FLT_ROUNDS and fegetround() are specified by the C99
+ * standard (and are specified to be consistent, with fesetround()
+ * affecting the value of FLT_ROUNDS), but that some (Linux) systems
+ * do not work correctly in this regard, so using fegetround() is more
+ * portable than using FLT_ROUNDS directly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ * that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ * rounding when the underlying floating-point arithmetic uses
+ * unbiased rounding. This prevent using ordinary floating-point
+ * arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ * integer type (of >= 64 bits). On such machines, you can
+ * #define Just_16 to store 16 bits per 32-bit Long when doing
+ * high-precision integer arithmetic. Whether this speeds things
+ * up or slows things down depends on the machine and the number
+ * being converted. If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed. Similarly, if you
+ * want something other than the system's free() to be called to
+ * recycle memory acquired from MALLOC, #define FREE to be the
+ * name of the alternate routine. (FREE or free is only called in
+ * pathological cases, e.g., in a dtoa call after a dtoa return in
+ * mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ * memory allocations from a private pool of memory when possible.
+ * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
+ * unless #defined to be a different length. This default length
+ * suffices to get rid of MALLOC calls except for unusual cases,
+ * such as decimal-to-binary conversion of a very long string of
+ * digits. The longest string dtoa can return is about 751 bytes
+ * long. For conversions by strtod of strings of 800 digits and
+ * all dtoa conversions in single-threaded executions with 8-byte
+ * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ * pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ * #defined automatically on IEEE systems. On such systems,
+ * when INFNAN_CHECK is #defined, strtod checks
+ * for Infinity and NaN (case insensitively). On some systems
+ * (e.g., some HP systems), it may be necessary to #define NAN_WORD0
+ * appropriately -- to the most significant word of a quiet NaN.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ * strtod also accepts (case insensitively) strings of the form
+ * NaN(x), where x is a string of hexadecimal digits and spaces;
+ * if there is only one string of hexadecimal digits, it is taken
+ * for the 52 fraction bits of the resulting NaN; if there are two
+ * or more strings of hex digits, the first is for the high 20 bits,
+ * the second and subsequent for the low 32 bits, with intervening
+ * white space ignored; but if this results in none of the 52
+ * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ * and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+
+ * When MULTIPLE_THREADS is #defined, this source file provides
+ * void set_max_dtoa_threads(unsigned int n);
+ * and expects
+ * unsigned int dtoa_get_threadno(void);
+ * to be available (possibly provided by
+ * #define dtoa_get_threadno omp_get_thread_num
+ * if OpenMP is in use or by
+ * #define dtoa_get_threadno pthread_self
+ * if Pthreads is in use), to return the current thread number.
+ * If set_max_dtoa_threads(n) was called and the current thread
+ * number is k with k < n, then calls on ACQUIRE_DTOA_LOCK(...) and
+ * FREE_DTOA_LOCK(...) are avoided; instead each thread with thread
+ * number < n has a separate copy of relevant data structures.
+ * After set_max_dtoa_threads(n), a call set_max_dtoa_threads(m)
+ * with m <= n has has no effect, but a call with m > n is honored.
+ * Such a call invokes REALLOC (assumed to be "realloc" if REALLOC
+ * is not #defined) to extend the size of the relevant array.
+
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ * avoids underflows on inputs whose result does not underflow.
+ * If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ * floating-point numbers and flushes underflows to zero rather
+ * than implementing gradual underflow, then you must also #define
+ * Sudden_Underflow.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ * computation should be done to set the inexact flag when the
+ * result is inexact and avoid setting inexact when the result
+ * is exact. In this case, dtoa.c must be compiled in
+ * an environment, perhaps provided by #include "dtoa.c" in a
+ * suitable wrapper, that defines two functions,
+ * int get_inexact(void);
+ * void clear_inexact(void);
+ * such that get_inexact() returns a nonzero value if the
+ * inexact bit is already set, and clear_inexact() sets the
+ * inexact bit to 0. When SET_INEXACT is #defined, strtod
+ * also does extra computations to set the underflow and overflow
+ * flags when appropriate (i.e., when the result is tiny and
+ * inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ * the result overflows to +-Infinity or underflows to 0.
+ * When errno should be assigned, under seemingly rare conditions
+ * it may be necessary to define Set_errno(x) suitably, e.g., in
+ * a local errno.h, such as
+ * #include <errno.h>
+ * #define Set_errno(x) _set_errno(x)
+ * #define NO_HEX_FP to omit recognition of hexadecimal floating-point
+ * values by strtod.
+ * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now)
+ * to disable logic for "fast" testing of very long input strings
+ * to strtod. This testing proceeds by initially truncating the
+ * input string, then if necessary comparing the whole string with
+ * a decimal expansion to decide close cases. This logic is only
+ * used for input more than STRTOD_DIGLIM digits long (default 40).
+ */
+
+#include <thread.h>
+#include <threads.h>
+#include <atomic.h>
+
+static atomic_flag dtoa_lock[2] = { ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT };
+
+#define ACQUIRE_DTOA_LOCK(n) LIBC_LOCK(dtoa_lock[(n)])
+#define FREE_DTOA_LOCK(n) LIBC_UNLOCK(dtoa_lock[(n)])
+
+#define dtoa_get_threadno() thrd_current()->tid
+
+#define IEEE_8087
+#define Honor_FLT_ROUNDS
+#define MULTIPLE_THREADS
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include <assert.h>
+#include "stdio.h"
+#define Bug(x) \
+ { \
+ fprintf(stderr, "%s\n", x); \
+ exit(1); \
+ }
+#define Debug(x) x
+int dtoa_stats[7]; /* strtod_{64,96,bigcomp},dtoa_{exact,64,96,bigcomp} */
+#else
+#define assert(x) /*nothing*/
+#define Debug(x) /*nothing*/
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef Honor_FLT_ROUNDS
+#ifndef Trust_FLT_ROUNDS
+#include <fenv.h>
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef MALLOC
+extern void *MALLOC(size_t);
+#else
+#define MALLOC malloc
+#endif
+
+#ifdef REALLOC
+extern void *REALLOC(void *, size_t);
+#else
+#define REALLOC realloc
+#endif
+
+#ifndef FREE
+#define FREE free
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM + sizeof(double) - 1) / sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#else
+#undef INFNAN_CHECK
+#define NO_STRTOD_BIGCOMP
+#endif
+
+#include "errno.h"
+
+#ifdef NO_ERRNO /*{*/
+#undef Set_errno
+#define Set_errno(x)
+#else
+#ifndef Set_errno
+#define Set_errno(x) errno = x
+#endif
+#endif /*}*/
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX,
+ or IBM should be defined.
+#endif
+
+#undef USE_BF96
+
+#ifdef NO_LONG_LONG /*{{*/
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else /*}{ long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#ifndef NO_BF96 /*{*/
+#define USE_BF96
+
+#ifdef SET_INEXACT
+#define dtoa_divmax 27
+#else
+int dtoa_divmax = 2; /* Permit experimenting: on some systems, 64-bit integer */
+/* division is slow enough that we may sometimes want to */
+/* avoid using it. We assume (but do not check) that */
+/* dtoa_divmax <= 27.*/
+#endif
+
+typedef struct BF96 { /* Normalized 96-bit software floating point numbers */
+ unsigned int b0, b1, b2; /* b0 = most significant, binary point just to
+ its left */
+ int e; /* number represented = b * 2^e, with .5 <= b < 1 */
+} BF96;
+
+static BF96 pten[667] = { { 0xeef453d6, 0x923bd65a, 0x113faa29, -1136 },
+ { 0x9558b466, 0x1b6565f8, 0x4ac7ca59, -1132 },
+ { 0xbaaee17f, 0xa23ebf76, 0x5d79bcf0, -1129 },
+ { 0xe95a99df, 0x8ace6f53, 0xf4d82c2c, -1126 },
+ { 0x91d8a02b, 0xb6c10594, 0x79071b9b, -1122 },
+ { 0xb64ec836, 0xa47146f9, 0x9748e282, -1119 },
+ { 0xe3e27a44, 0x4d8d98b7, 0xfd1b1b23, -1116 },
+ { 0x8e6d8c6a, 0xb0787f72, 0xfe30f0f5, -1112 },
+ { 0xb208ef85, 0x5c969f4f, 0xbdbd2d33, -1109 },
+ { 0xde8b2b66, 0xb3bc4723, 0xad2c7880, -1106 },
+ { 0x8b16fb20, 0x3055ac76, 0x4c3bcb50, -1102 },
+ { 0xaddcb9e8, 0x3c6b1793, 0xdf4abe24, -1099 },
+ { 0xd953e862, 0x4b85dd78, 0xd71d6dad, -1096 },
+ { 0x87d4713d, 0x6f33aa6b, 0x8672648c, -1092 },
+ { 0xa9c98d8c, 0xcb009506, 0x680efdaf, -1089 },
+ { 0xd43bf0ef, 0xfdc0ba48, 0x0212bd1b, -1086 },
+ { 0x84a57695, 0xfe98746d, 0x014bb630, -1082 },
+ { 0xa5ced43b, 0x7e3e9188, 0x419ea3bd, -1079 },
+ { 0xcf42894a, 0x5dce35ea, 0x52064cac, -1076 },
+ { 0x818995ce, 0x7aa0e1b2, 0x7343efeb, -1072 },
+ { 0xa1ebfb42, 0x19491a1f, 0x1014ebe6, -1069 },
+ { 0xca66fa12, 0x9f9b60a6, 0xd41a26e0, -1066 },
+ { 0xfd00b897, 0x478238d0, 0x8920b098, -1063 },
+ { 0x9e20735e, 0x8cb16382, 0x55b46e5f, -1059 },
+ { 0xc5a89036, 0x2fddbc62, 0xeb2189f7, -1056 },
+ { 0xf712b443, 0xbbd52b7b, 0xa5e9ec75, -1053 },
+ { 0x9a6bb0aa, 0x55653b2d, 0x47b233c9, -1049 },
+ { 0xc1069cd4, 0xeabe89f8, 0x999ec0bb, -1046 },
+ { 0xf148440a, 0x256e2c76, 0xc00670ea, -1043 },
+ { 0x96cd2a86, 0x5764dbca, 0x38040692, -1039 },
+ { 0xbc807527, 0xed3e12bc, 0xc6050837, -1036 },
+ { 0xeba09271, 0xe88d976b, 0xf7864a44, -1033 },
+ { 0x93445b87, 0x31587ea3, 0x7ab3ee6a, -1029 },
+ { 0xb8157268, 0xfdae9e4c, 0x5960ea05, -1026 },
+ { 0xe61acf03, 0x3d1a45df, 0x6fb92487, -1023 },
+ { 0x8fd0c162, 0x06306bab, 0xa5d3b6d4, -1019 },
+ { 0xb3c4f1ba, 0x87bc8696, 0x8f48a489, -1016 },
+ { 0xe0b62e29, 0x29aba83c, 0x331acdab, -1013 },
+ { 0x8c71dcd9, 0xba0b4925, 0x9ff0c08b, -1009 },
+ { 0xaf8e5410, 0x288e1b6f, 0x07ecf0ae, -1006 },
+ { 0xdb71e914, 0x32b1a24a, 0xc9e82cd9, -1003 },
+ { 0x892731ac, 0x9faf056e, 0xbe311c08, -999 },
+ { 0xab70fe17, 0xc79ac6ca, 0x6dbd630a, -996 },
+ { 0xd64d3d9d, 0xb981787d, 0x092cbbcc, -993 },
+ { 0x85f04682, 0x93f0eb4e, 0x25bbf560, -989 },
+ { 0xa76c5823, 0x38ed2621, 0xaf2af2b8, -986 },
+ { 0xd1476e2c, 0x07286faa, 0x1af5af66, -983 },
+ { 0x82cca4db, 0x847945ca, 0x50d98d9f, -979 },
+ { 0xa37fce12, 0x6597973c, 0xe50ff107, -976 },
+ { 0xcc5fc196, 0xfefd7d0c, 0x1e53ed49, -973 },
+ { 0xff77b1fc, 0xbebcdc4f, 0x25e8e89c, -970 },
+ { 0x9faacf3d, 0xf73609b1, 0x77b19161, -966 },
+ { 0xc795830d, 0x75038c1d, 0xd59df5b9, -963 },
+ { 0xf97ae3d0, 0xd2446f25, 0x4b057328, -960 },
+ { 0x9becce62, 0x836ac577, 0x4ee367f9, -956 },
+ { 0xc2e801fb, 0x244576d5, 0x229c41f7, -953 },
+ { 0xf3a20279, 0xed56d48a, 0x6b435275, -950 },
+ { 0x9845418c, 0x345644d6, 0x830a1389, -946 },
+ { 0xbe5691ef, 0x416bd60c, 0x23cc986b, -943 },
+ { 0xedec366b, 0x11c6cb8f, 0x2cbfbe86, -940 },
+ { 0x94b3a202, 0xeb1c3f39, 0x7bf7d714, -936 },
+ { 0xb9e08a83, 0xa5e34f07, 0xdaf5ccd9, -933 },
+ { 0xe858ad24, 0x8f5c22c9, 0xd1b3400f, -930 },
+ { 0x91376c36, 0xd99995be, 0x23100809, -926 },
+ { 0xb5854744, 0x8ffffb2d, 0xabd40a0c, -923 },
+ { 0xe2e69915, 0xb3fff9f9, 0x16c90c8f, -920 },
+ { 0x8dd01fad, 0x907ffc3b, 0xae3da7d9, -916 },
+ { 0xb1442798, 0xf49ffb4a, 0x99cd11cf, -913 },
+ { 0xdd95317f, 0x31c7fa1d, 0x40405643, -910 },
+ { 0x8a7d3eef, 0x7f1cfc52, 0x482835ea, -906 },
+ { 0xad1c8eab, 0x5ee43b66, 0xda324365, -903 },
+ { 0xd863b256, 0x369d4a40, 0x90bed43e, -900 },
+ { 0x873e4f75, 0xe2224e68, 0x5a7744a6, -896 },
+ { 0xa90de353, 0x5aaae202, 0x711515d0, -893 },
+ { 0xd3515c28, 0x31559a83, 0x0d5a5b44, -890 },
+ { 0x8412d999, 0x1ed58091, 0xe858790a, -886 },
+ { 0xa5178fff, 0x668ae0b6, 0x626e974d, -883 },
+ { 0xce5d73ff, 0x402d98e3, 0xfb0a3d21, -880 },
+ { 0x80fa687f, 0x881c7f8e, 0x7ce66634, -876 },
+ { 0xa139029f, 0x6a239f72, 0x1c1fffc1, -873 },
+ { 0xc9874347, 0x44ac874e, 0xa327ffb2, -870 },
+ { 0xfbe91419, 0x15d7a922, 0x4bf1ff9f, -867 },
+ { 0x9d71ac8f, 0xada6c9b5, 0x6f773fc3, -863 },
+ { 0xc4ce17b3, 0x99107c22, 0xcb550fb4, -860 },
+ { 0xf6019da0, 0x7f549b2b, 0x7e2a53a1, -857 },
+ { 0x99c10284, 0x4f94e0fb, 0x2eda7444, -853 },
+ { 0xc0314325, 0x637a1939, 0xfa911155, -850 },
+ { 0xf03d93ee, 0xbc589f88, 0x793555ab, -847 },
+ { 0x96267c75, 0x35b763b5, 0x4bc1558b, -843 },
+ { 0xbbb01b92, 0x83253ca2, 0x9eb1aaed, -840 },
+ { 0xea9c2277, 0x23ee8bcb, 0x465e15a9, -837 },
+ { 0x92a1958a, 0x7675175f, 0x0bfacd89, -833 },
+ { 0xb749faed, 0x14125d36, 0xcef980ec, -830 },
+ { 0xe51c79a8, 0x5916f484, 0x82b7e127, -827 },
+ { 0x8f31cc09, 0x37ae58d2, 0xd1b2ecb8, -823 },
+ { 0xb2fe3f0b, 0x8599ef07, 0x861fa7e6, -820 },
+ { 0xdfbdcece, 0x67006ac9, 0x67a791e0, -817 },
+ { 0x8bd6a141, 0x006042bd, 0xe0c8bb2c, -813 },
+ { 0xaecc4991, 0x4078536d, 0x58fae9f7, -810 },
+ { 0xda7f5bf5, 0x90966848, 0xaf39a475, -807 },
+ { 0x888f9979, 0x7a5e012d, 0x6d8406c9, -803 },
+ { 0xaab37fd7, 0xd8f58178, 0xc8e5087b, -800 },
+ { 0xd5605fcd, 0xcf32e1d6, 0xfb1e4a9a, -797 },
+ { 0x855c3be0, 0xa17fcd26, 0x5cf2eea0, -793 },
+ { 0xa6b34ad8, 0xc9dfc06f, 0xf42faa48, -790 },
+ { 0xd0601d8e, 0xfc57b08b, 0xf13b94da, -787 },
+ { 0x823c1279, 0x5db6ce57, 0x76c53d08, -783 },
+ { 0xa2cb1717, 0xb52481ed, 0x54768c4b, -780 },
+ { 0xcb7ddcdd, 0xa26da268, 0xa9942f5d, -777 },
+ { 0xfe5d5415, 0x0b090b02, 0xd3f93b35, -774 },
+ { 0x9efa548d, 0x26e5a6e1, 0xc47bc501, -770 },
+ { 0xc6b8e9b0, 0x709f109a, 0x359ab641, -767 },
+ { 0xf867241c, 0x8cc6d4c0, 0xc30163d2, -764 },
+ { 0x9b407691, 0xd7fc44f8, 0x79e0de63, -760 },
+ { 0xc2109436, 0x4dfb5636, 0x985915fc, -757 },
+ { 0xf294b943, 0xe17a2bc4, 0x3e6f5b7b, -754 },
+ { 0x979cf3ca, 0x6cec5b5a, 0xa705992c, -750 },
+ { 0xbd8430bd, 0x08277231, 0x50c6ff78, -747 },
+ { 0xece53cec, 0x4a314ebd, 0xa4f8bf56, -744 },
+ { 0x940f4613, 0xae5ed136, 0x871b7795, -740 },
+ { 0xb9131798, 0x99f68584, 0x28e2557b, -737 },
+ { 0xe757dd7e, 0xc07426e5, 0x331aeada, -734 },
+ { 0x9096ea6f, 0x3848984f, 0x3ff0d2c8, -730 },
+ { 0xb4bca50b, 0x065abe63, 0x0fed077a, -727 },
+ { 0xe1ebce4d, 0xc7f16dfb, 0xd3e84959, -724 },
+ { 0x8d3360f0, 0x9cf6e4bd, 0x64712dd7, -720 },
+ { 0xb080392c, 0xc4349dec, 0xbd8d794d, -717 },
+ { 0xdca04777, 0xf541c567, 0xecf0d7a0, -714 },
+ { 0x89e42caa, 0xf9491b60, 0xf41686c4, -710 },
+ { 0xac5d37d5, 0xb79b6239, 0x311c2875, -707 },
+ { 0xd77485cb, 0x25823ac7, 0x7d633293, -704 },
+ { 0x86a8d39e, 0xf77164bc, 0xae5dff9c, -700 },
+ { 0xa8530886, 0xb54dbdeb, 0xd9f57f83, -697 },
+ { 0xd267caa8, 0x62a12d66, 0xd072df63, -694 },
+ { 0x8380dea9, 0x3da4bc60, 0x4247cb9e, -690 },
+ { 0xa4611653, 0x8d0deb78, 0x52d9be85, -687 },
+ { 0xcd795be8, 0x70516656, 0x67902e27, -684 },
+ { 0x806bd971, 0x4632dff6, 0x00ba1cd8, -680 },
+ { 0xa086cfcd, 0x97bf97f3, 0x80e8a40e, -677 },
+ { 0xc8a883c0, 0xfdaf7df0, 0x6122cd12, -674 },
+ { 0xfad2a4b1, 0x3d1b5d6c, 0x796b8057, -671 },
+ { 0x9cc3a6ee, 0xc6311a63, 0xcbe33036, -667 },
+ { 0xc3f490aa, 0x77bd60fc, 0xbedbfc44, -664 },
+ { 0xf4f1b4d5, 0x15acb93b, 0xee92fb55, -661 },
+ { 0x99171105, 0x2d8bf3c5, 0x751bdd15, -657 },
+ { 0xbf5cd546, 0x78eef0b6, 0xd262d45a, -654 },
+ { 0xef340a98, 0x172aace4, 0x86fb8971, -651 },
+ { 0x9580869f, 0x0e7aac0e, 0xd45d35e6, -647 },
+ { 0xbae0a846, 0xd2195712, 0x89748360, -644 },
+ { 0xe998d258, 0x869facd7, 0x2bd1a438, -641 },
+ { 0x91ff8377, 0x5423cc06, 0x7b6306a3, -637 },
+ { 0xb67f6455, 0x292cbf08, 0x1a3bc84c, -634 },
+ { 0xe41f3d6a, 0x7377eeca, 0x20caba5f, -631 },
+ { 0x8e938662, 0x882af53e, 0x547eb47b, -627 },
+ { 0xb23867fb, 0x2a35b28d, 0xe99e619a, -624 },
+ { 0xdec681f9, 0xf4c31f31, 0x6405fa00, -621 },
+ { 0x8b3c113c, 0x38f9f37e, 0xde83bc40, -617 },
+ { 0xae0b158b, 0x4738705e, 0x9624ab50, -614 },
+ { 0xd98ddaee, 0x19068c76, 0x3badd624, -611 },
+ { 0x87f8a8d4, 0xcfa417c9, 0xe54ca5d7, -607 },
+ { 0xa9f6d30a, 0x038d1dbc, 0x5e9fcf4c, -604 },
+ { 0xd47487cc, 0x8470652b, 0x7647c320, -601 },
+ { 0x84c8d4df, 0xd2c63f3b, 0x29ecd9f4, -597 },
+ { 0xa5fb0a17, 0xc777cf09, 0xf4681071, -594 },
+ { 0xcf79cc9d, 0xb955c2cc, 0x7182148d, -591 },
+ { 0x81ac1fe2, 0x93d599bf, 0xc6f14cd8, -587 },
+ { 0xa21727db, 0x38cb002f, 0xb8ada00e, -584 },
+ { 0xca9cf1d2, 0x06fdc03b, 0xa6d90811, -581 },
+ { 0xfd442e46, 0x88bd304a, 0x908f4a16, -578 },
+ { 0x9e4a9cec, 0x15763e2e, 0x9a598e4e, -574 },
+ { 0xc5dd4427, 0x1ad3cdba, 0x40eff1e1, -571 },
+ { 0xf7549530, 0xe188c128, 0xd12bee59, -568 },
+ { 0x9a94dd3e, 0x8cf578b9, 0x82bb74f8, -564 },
+ { 0xc13a148e, 0x3032d6e7, 0xe36a5236, -561 },
+ { 0xf18899b1, 0xbc3f8ca1, 0xdc44e6c3, -558 },
+ { 0x96f5600f, 0x15a7b7e5, 0x29ab103a, -554 },
+ { 0xbcb2b812, 0xdb11a5de, 0x7415d448, -551 },
+ { 0xebdf6617, 0x91d60f56, 0x111b495b, -548 },
+ { 0x936b9fce, 0xbb25c995, 0xcab10dd9, -544 },
+ { 0xb84687c2, 0x69ef3bfb, 0x3d5d514f, -541 },
+ { 0xe65829b3, 0x046b0afa, 0x0cb4a5a3, -538 },
+ { 0x8ff71a0f, 0xe2c2e6dc, 0x47f0e785, -534 },
+ { 0xb3f4e093, 0xdb73a093, 0x59ed2167, -531 },
+ { 0xe0f218b8, 0xd25088b8, 0x306869c1, -528 },
+ { 0x8c974f73, 0x83725573, 0x1e414218, -524 },
+ { 0xafbd2350, 0x644eeacf, 0xe5d1929e, -521 },
+ { 0xdbac6c24, 0x7d62a583, 0xdf45f746, -518 },
+ { 0x894bc396, 0xce5da772, 0x6b8bba8c, -514 },
+ { 0xab9eb47c, 0x81f5114f, 0x066ea92f, -511 },
+ { 0xd686619b, 0xa27255a2, 0xc80a537b, -508 },
+ { 0x8613fd01, 0x45877585, 0xbd06742c, -504 },
+ { 0xa798fc41, 0x96e952e7, 0x2c481138, -501 },
+ { 0xd17f3b51, 0xfca3a7a0, 0xf75a1586, -498 },
+ { 0x82ef8513, 0x3de648c4, 0x9a984d73, -494 },
+ { 0xa3ab6658, 0x0d5fdaf5, 0xc13e60d0, -491 },
+ { 0xcc963fee, 0x10b7d1b3, 0x318df905, -488 },
+ { 0xffbbcfe9, 0x94e5c61f, 0xfdf17746, -485 },
+ { 0x9fd561f1, 0xfd0f9bd3, 0xfeb6ea8b, -481 },
+ { 0xc7caba6e, 0x7c5382c8, 0xfe64a52e, -478 },
+ { 0xf9bd690a, 0x1b68637b, 0x3dfdce7a, -475 },
+ { 0x9c1661a6, 0x51213e2d, 0x06bea10c, -471 },
+ { 0xc31bfa0f, 0xe5698db8, 0x486e494f, -468 },
+ { 0xf3e2f893, 0xdec3f126, 0x5a89dba3, -465 },
+ { 0x986ddb5c, 0x6b3a76b7, 0xf8962946, -461 },
+ { 0xbe895233, 0x86091465, 0xf6bbb397, -458 },
+ { 0xee2ba6c0, 0x678b597f, 0x746aa07d, -455 },
+ { 0x94db4838, 0x40b717ef, 0xa8c2a44e, -451 },
+ { 0xba121a46, 0x50e4ddeb, 0x92f34d62, -448 },
+ { 0xe896a0d7, 0xe51e1566, 0x77b020ba, -445 },
+ { 0x915e2486, 0xef32cd60, 0x0ace1474, -441 },
+ { 0xb5b5ada8, 0xaaff80b8, 0x0d819992, -438 },
+ { 0xe3231912, 0xd5bf60e6, 0x10e1fff6, -435 },
+ { 0x8df5efab, 0xc5979c8f, 0xca8d3ffa, -431 },
+ { 0xb1736b96, 0xb6fd83b3, 0xbd308ff8, -428 },
+ { 0xddd0467c, 0x64bce4a0, 0xac7cb3f6, -425 },
+ { 0x8aa22c0d, 0xbef60ee4, 0x6bcdf07a, -421 },
+ { 0xad4ab711, 0x2eb3929d, 0x86c16c98, -418 },
+ { 0xd89d64d5, 0x7a607744, 0xe871c7bf, -415 },
+ { 0x87625f05, 0x6c7c4a8b, 0x11471cd7, -411 },
+ { 0xa93af6c6, 0xc79b5d2d, 0xd598e40d, -408 },
+ { 0xd389b478, 0x79823479, 0x4aff1d10, -405 },
+ { 0x843610cb, 0x4bf160cb, 0xcedf722a, -401 },
+ { 0xa54394fe, 0x1eedb8fe, 0xc2974eb4, -398 },
+ { 0xce947a3d, 0xa6a9273e, 0x733d2262, -395 },
+ { 0x811ccc66, 0x8829b887, 0x0806357d, -391 },
+ { 0xa163ff80, 0x2a3426a8, 0xca07c2dc, -388 },
+ { 0xc9bcff60, 0x34c13052, 0xfc89b393, -385 },
+ { 0xfc2c3f38, 0x41f17c67, 0xbbac2078, -382 },
+ { 0x9d9ba783, 0x2936edc0, 0xd54b944b, -378 },
+ { 0xc5029163, 0xf384a931, 0x0a9e795e, -375 },
+ { 0xf64335bc, 0xf065d37d, 0x4d4617b5, -372 },
+ { 0x99ea0196, 0x163fa42e, 0x504bced1, -368 },
+ { 0xc06481fb, 0x9bcf8d39, 0xe45ec286, -365 },
+ { 0xf07da27a, 0x82c37088, 0x5d767327, -362 },
+ { 0x964e858c, 0x91ba2655, 0x3a6a07f8, -358 },
+ { 0xbbe226ef, 0xb628afea, 0x890489f7, -355 },
+ { 0xeadab0ab, 0xa3b2dbe5, 0x2b45ac74, -352 },
+ { 0x92c8ae6b, 0x464fc96f, 0x3b0b8bc9, -348 },
+ { 0xb77ada06, 0x17e3bbcb, 0x09ce6ebb, -345 },
+ { 0xe5599087, 0x9ddcaabd, 0xcc420a6a, -342 },
+ { 0x8f57fa54, 0xc2a9eab6, 0x9fa94682, -338 },
+ { 0xb32df8e9, 0xf3546564, 0x47939822, -335 },
+ { 0xdff97724, 0x70297ebd, 0x59787e2b, -332 },
+ { 0x8bfbea76, 0xc619ef36, 0x57eb4edb, -328 },
+ { 0xaefae514, 0x77a06b03, 0xede62292, -325 },
+ { 0xdab99e59, 0x958885c4, 0xe95fab36, -322 },
+ { 0x88b402f7, 0xfd75539b, 0x11dbcb02, -318 },
+ { 0xaae103b5, 0xfcd2a881, 0xd652bdc2, -315 },
+ { 0xd59944a3, 0x7c0752a2, 0x4be76d33, -312 },
+ { 0x857fcae6, 0x2d8493a5, 0x6f70a440, -308 },
+ { 0xa6dfbd9f, 0xb8e5b88e, 0xcb4ccd50, -305 },
+ { 0xd097ad07, 0xa71f26b2, 0x7e2000a4, -302 },
+ { 0x825ecc24, 0xc873782f, 0x8ed40066, -298 },
+ { 0xa2f67f2d, 0xfa90563b, 0x72890080, -295 },
+ { 0xcbb41ef9, 0x79346bca, 0x4f2b40a0, -292 },
+ { 0xfea126b7, 0xd78186bc, 0xe2f610c8, -289 },
+ { 0x9f24b832, 0xe6b0f436, 0x0dd9ca7d, -285 },
+ { 0xc6ede63f, 0xa05d3143, 0x91503d1c, -282 },
+ { 0xf8a95fcf, 0x88747d94, 0x75a44c63, -279 },
+ { 0x9b69dbe1, 0xb548ce7c, 0xc986afbe, -275 },
+ { 0xc24452da, 0x229b021b, 0xfbe85bad, -272 },
+ { 0xf2d56790, 0xab41c2a2, 0xfae27299, -269 },
+ { 0x97c560ba, 0x6b0919a5, 0xdccd879f, -265 },
+ { 0xbdb6b8e9, 0x05cb600f, 0x5400e987, -262 },
+ { 0xed246723, 0x473e3813, 0x290123e9, -259 },
+ { 0x9436c076, 0x0c86e30b, 0xf9a0b672, -255 },
+ { 0xb9447093, 0x8fa89bce, 0xf808e40e, -252 },
+ { 0xe7958cb8, 0x7392c2c2, 0xb60b1d12, -249 },
+ { 0x90bd77f3, 0x483bb9b9, 0xb1c6f22b, -245 },
+ { 0xb4ecd5f0, 0x1a4aa828, 0x1e38aeb6, -242 },
+ { 0xe2280b6c, 0x20dd5232, 0x25c6da63, -239 },
+ { 0x8d590723, 0x948a535f, 0x579c487e, -235 },
+ { 0xb0af48ec, 0x79ace837, 0x2d835a9d, -232 },
+ { 0xdcdb1b27, 0x98182244, 0xf8e43145, -229 },
+ { 0x8a08f0f8, 0xbf0f156b, 0x1b8e9ecb, -225 },
+ { 0xac8b2d36, 0xeed2dac5, 0xe272467e, -222 },
+ { 0xd7adf884, 0xaa879177, 0x5b0ed81d, -219 },
+ { 0x86ccbb52, 0xea94baea, 0x98e94712, -215 },
+ { 0xa87fea27, 0xa539e9a5, 0x3f2398d7, -212 },
+ { 0xd29fe4b1, 0x8e88640e, 0x8eec7f0d, -209 },
+ { 0x83a3eeee, 0xf9153e89, 0x1953cf68, -205 },
+ { 0xa48ceaaa, 0xb75a8e2b, 0x5fa8c342, -202 },
+ { 0xcdb02555, 0x653131b6, 0x3792f412, -199 },
+ { 0x808e1755, 0x5f3ebf11, 0xe2bbd88b, -195 },
+ { 0xa0b19d2a, 0xb70e6ed6, 0x5b6aceae, -192 },
+ { 0xc8de0475, 0x64d20a8b, 0xf245825a, -189 },
+ { 0xfb158592, 0xbe068d2e, 0xeed6e2f0, -186 },
+ { 0x9ced737b, 0xb6c4183d, 0x55464dd6, -182 },
+ { 0xc428d05a, 0xa4751e4c, 0xaa97e14c, -179 },
+ { 0xf5330471, 0x4d9265df, 0xd53dd99f, -176 },
+ { 0x993fe2c6, 0xd07b7fab, 0xe546a803, -172 },
+ { 0xbf8fdb78, 0x849a5f96, 0xde985204, -169 },
+ { 0xef73d256, 0xa5c0f77c, 0x963e6685, -166 },
+ { 0x95a86376, 0x27989aad, 0xdde70013, -162 },
+ { 0xbb127c53, 0xb17ec159, 0x5560c018, -159 },
+ { 0xe9d71b68, 0x9dde71af, 0xaab8f01e, -156 },
+ { 0x92267121, 0x62ab070d, 0xcab39613, -152 },
+ { 0xb6b00d69, 0xbb55c8d1, 0x3d607b97, -149 },
+ { 0xe45c10c4, 0x2a2b3b05, 0x8cb89a7d, -146 },
+ { 0x8eb98a7a, 0x9a5b04e3, 0x77f3608e, -142 },
+ { 0xb267ed19, 0x40f1c61c, 0x55f038b2, -139 },
+ { 0xdf01e85f, 0x912e37a3, 0x6b6c46de, -136 },
+ { 0x8b61313b, 0xbabce2c6, 0x2323ac4b, -132 },
+ { 0xae397d8a, 0xa96c1b77, 0xabec975e, -129 },
+ { 0xd9c7dced, 0x53c72255, 0x96e7bd35, -126 },
+ { 0x881cea14, 0x545c7575, 0x7e50d641, -122 },
+ { 0xaa242499, 0x697392d2, 0xdde50bd1, -119 },
+ { 0xd4ad2dbf, 0xc3d07787, 0x955e4ec6, -116 },
+ { 0x84ec3c97, 0xda624ab4, 0xbd5af13b, -112 },
+ { 0xa6274bbd, 0xd0fadd61, 0xecb1ad8a, -109 },
+ { 0xcfb11ead, 0x453994ba, 0x67de18ed, -106 },
+ { 0x81ceb32c, 0x4b43fcf4, 0x80eacf94, -102 },
+ { 0xa2425ff7, 0x5e14fc31, 0xa1258379, -99 },
+ { 0xcad2f7f5, 0x359a3b3e, 0x096ee458, -96 },
+ { 0xfd87b5f2, 0x8300ca0d, 0x8bca9d6e, -93 },
+ { 0x9e74d1b7, 0x91e07e48, 0x775ea264, -89 },
+ { 0xc6120625, 0x76589dda, 0x95364afe, -86 },
+ { 0xf79687ae, 0xd3eec551, 0x3a83ddbd, -83 },
+ { 0x9abe14cd, 0x44753b52, 0xc4926a96, -79 },
+ { 0xc16d9a00, 0x95928a27, 0x75b7053c, -76 },
+ { 0xf1c90080, 0xbaf72cb1, 0x5324c68b, -73 },
+ { 0x971da050, 0x74da7bee, 0xd3f6fc16, -69 },
+ { 0xbce50864, 0x92111aea, 0x88f4bb1c, -66 },
+ { 0xec1e4a7d, 0xb69561a5, 0x2b31e9e3, -63 },
+ { 0x9392ee8e, 0x921d5d07, 0x3aff322e, -59 },
+ { 0xb877aa32, 0x36a4b449, 0x09befeb9, -56 },
+ { 0xe69594be, 0xc44de15b, 0x4c2ebe68, -53 },
+ { 0x901d7cf7, 0x3ab0acd9, 0x0f9d3701, -49 },
+ { 0xb424dc35, 0x095cd80f, 0x538484c1, -46 },
+ { 0xe12e1342, 0x4bb40e13, 0x2865a5f2, -43 },
+ { 0x8cbccc09, 0x6f5088cb, 0xf93f87b7, -39 },
+ { 0xafebff0b, 0xcb24aafe, 0xf78f69a5, -36 },
+ { 0xdbe6fece, 0xbdedd5be, 0xb573440e, -33 },
+ { 0x89705f41, 0x36b4a597, 0x31680a88, -29 },
+ { 0xabcc7711, 0x8461cefc, 0xfdc20d2b, -26 },
+ { 0xd6bf94d5, 0xe57a42bc, 0x3d329076, -23 },
+ { 0x8637bd05, 0xaf6c69b5, 0xa63f9a49, -19 },
+ { 0xa7c5ac47, 0x1b478423, 0x0fcf80dc, -16 },
+ { 0xd1b71758, 0xe219652b, 0xd3c36113, -13 },
+ { 0x83126e97, 0x8d4fdf3b, 0x645a1cac, -9 },
+ { 0xa3d70a3d, 0x70a3d70a, 0x3d70a3d7, -6 },
+ { 0xcccccccc, 0xcccccccc, 0xcccccccc, -3 },
+ { 0x80000000, 0x00000000, 0x00000000, 1 },
+ { 0xa0000000, 0x00000000, 0x00000000, 4 },
+ { 0xc8000000, 0x00000000, 0x00000000, 7 },
+ { 0xfa000000, 0x00000000, 0x00000000, 10 },
+ { 0x9c400000, 0x00000000, 0x00000000, 14 },
+ { 0xc3500000, 0x00000000, 0x00000000, 17 },
+ { 0xf4240000, 0x00000000, 0x00000000, 20 },
+ { 0x98968000, 0x00000000, 0x00000000, 24 },
+ { 0xbebc2000, 0x00000000, 0x00000000, 27 },
+ { 0xee6b2800, 0x00000000, 0x00000000, 30 },
+ { 0x9502f900, 0x00000000, 0x00000000, 34 },
+ { 0xba43b740, 0x00000000, 0x00000000, 37 },
+ { 0xe8d4a510, 0x00000000, 0x00000000, 40 },
+ { 0x9184e72a, 0x00000000, 0x00000000, 44 },
+ { 0xb5e620f4, 0x80000000, 0x00000000, 47 },
+ { 0xe35fa931, 0xa0000000, 0x00000000, 50 },
+ { 0x8e1bc9bf, 0x04000000, 0x00000000, 54 },
+ { 0xb1a2bc2e, 0xc5000000, 0x00000000, 57 },
+ { 0xde0b6b3a, 0x76400000, 0x00000000, 60 },
+ { 0x8ac72304, 0x89e80000, 0x00000000, 64 },
+ { 0xad78ebc5, 0xac620000, 0x00000000, 67 },
+ { 0xd8d726b7, 0x177a8000, 0x00000000, 70 },
+ { 0x87867832, 0x6eac9000, 0x00000000, 74 },
+ { 0xa968163f, 0x0a57b400, 0x00000000, 77 },
+ { 0xd3c21bce, 0xcceda100, 0x00000000, 80 },
+ { 0x84595161, 0x401484a0, 0x00000000, 84 },
+ { 0xa56fa5b9, 0x9019a5c8, 0x00000000, 87 },
+ { 0xcecb8f27, 0xf4200f3a, 0x00000000, 90 },
+ { 0x813f3978, 0xf8940984, 0x40000000, 94 },
+ { 0xa18f07d7, 0x36b90be5, 0x50000000, 97 },
+ { 0xc9f2c9cd, 0x04674ede, 0xa4000000, 100 },
+ { 0xfc6f7c40, 0x45812296, 0x4d000000, 103 },
+ { 0x9dc5ada8, 0x2b70b59d, 0xf0200000, 107 },
+ { 0xc5371912, 0x364ce305, 0x6c280000, 110 },
+ { 0xf684df56, 0xc3e01bc6, 0xc7320000, 113 },
+ { 0x9a130b96, 0x3a6c115c, 0x3c7f4000, 117 },
+ { 0xc097ce7b, 0xc90715b3, 0x4b9f1000, 120 },
+ { 0xf0bdc21a, 0xbb48db20, 0x1e86d400, 123 },
+ { 0x96769950, 0xb50d88f4, 0x13144480, 127 },
+ { 0xbc143fa4, 0xe250eb31, 0x17d955a0, 130 },
+ { 0xeb194f8e, 0x1ae525fd, 0x5dcfab08, 133 },
+ { 0x92efd1b8, 0xd0cf37be, 0x5aa1cae5, 137 },
+ { 0xb7abc627, 0x050305ad, 0xf14a3d9e, 140 },
+ { 0xe596b7b0, 0xc643c719, 0x6d9ccd05, 143 },
+ { 0x8f7e32ce, 0x7bea5c6f, 0xe4820023, 147 },
+ { 0xb35dbf82, 0x1ae4f38b, 0xdda2802c, 150 },
+ { 0xe0352f62, 0xa19e306e, 0xd50b2037, 153 },
+ { 0x8c213d9d, 0xa502de45, 0x4526f422, 157 },
+ { 0xaf298d05, 0x0e4395d6, 0x9670b12b, 160 },
+ { 0xdaf3f046, 0x51d47b4c, 0x3c0cdd76, 163 },
+ { 0x88d8762b, 0xf324cd0f, 0xa5880a69, 167 },
+ { 0xab0e93b6, 0xefee0053, 0x8eea0d04, 170 },
+ { 0xd5d238a4, 0xabe98068, 0x72a49045, 173 },
+ { 0x85a36366, 0xeb71f041, 0x47a6da2b, 177 },
+ { 0xa70c3c40, 0xa64e6c51, 0x999090b6, 180 },
+ { 0xd0cf4b50, 0xcfe20765, 0xfff4b4e3, 183 },
+ { 0x82818f12, 0x81ed449f, 0xbff8f10e, 187 },
+ { 0xa321f2d7, 0x226895c7, 0xaff72d52, 190 },
+ { 0xcbea6f8c, 0xeb02bb39, 0x9bf4f8a6, 193 },
+ { 0xfee50b70, 0x25c36a08, 0x02f236d0, 196 },
+ { 0x9f4f2726, 0x179a2245, 0x01d76242, 200 },
+ { 0xc722f0ef, 0x9d80aad6, 0x424d3ad2, 203 },
+ { 0xf8ebad2b, 0x84e0d58b, 0xd2e08987, 206 },
+ { 0x9b934c3b, 0x330c8577, 0x63cc55f4, 210 },
+ { 0xc2781f49, 0xffcfa6d5, 0x3cbf6b71, 213 },
+ { 0xf316271c, 0x7fc3908a, 0x8bef464e, 216 },
+ { 0x97edd871, 0xcfda3a56, 0x97758bf0, 220 },
+ { 0xbde94e8e, 0x43d0c8ec, 0x3d52eeed, 223 },
+ { 0xed63a231, 0xd4c4fb27, 0x4ca7aaa8, 226 },
+ { 0x945e455f, 0x24fb1cf8, 0x8fe8caa9, 230 },
+ { 0xb975d6b6, 0xee39e436, 0xb3e2fd53, 233 },
+ { 0xe7d34c64, 0xa9c85d44, 0x60dbbca8, 236 },
+ { 0x90e40fbe, 0xea1d3a4a, 0xbc8955e9, 240 },
+ { 0xb51d13ae, 0xa4a488dd, 0x6babab63, 243 },
+ { 0xe264589a, 0x4dcdab14, 0xc696963c, 246 },
+ { 0x8d7eb760, 0x70a08aec, 0xfc1e1de5, 250 },
+ { 0xb0de6538, 0x8cc8ada8, 0x3b25a55f, 253 },
+ { 0xdd15fe86, 0xaffad912, 0x49ef0eb7, 256 },
+ { 0x8a2dbf14, 0x2dfcc7ab, 0x6e356932, 260 },
+ { 0xacb92ed9, 0x397bf996, 0x49c2c37f, 263 },
+ { 0xd7e77a8f, 0x87daf7fb, 0xdc33745e, 266 },
+ { 0x86f0ac99, 0xb4e8dafd, 0x69a028bb, 270 },
+ { 0xa8acd7c0, 0x222311bc, 0xc40832ea, 273 },
+ { 0xd2d80db0, 0x2aabd62b, 0xf50a3fa4, 276 },
+ { 0x83c7088e, 0x1aab65db, 0x792667c6, 280 },
+ { 0xa4b8cab1, 0xa1563f52, 0x577001b8, 283 },
+ { 0xcde6fd5e, 0x09abcf26, 0xed4c0226, 286 },
+ { 0x80b05e5a, 0xc60b6178, 0x544f8158, 290 },
+ { 0xa0dc75f1, 0x778e39d6, 0x696361ae, 293 },
+ { 0xc913936d, 0xd571c84c, 0x03bc3a19, 296 },
+ { 0xfb587849, 0x4ace3a5f, 0x04ab48a0, 299 },
+ { 0x9d174b2d, 0xcec0e47b, 0x62eb0d64, 303 },
+ { 0xc45d1df9, 0x42711d9a, 0x3ba5d0bd, 306 },
+ { 0xf5746577, 0x930d6500, 0xca8f44ec, 309 },
+ { 0x9968bf6a, 0xbbe85f20, 0x7e998b13, 313 },
+ { 0xbfc2ef45, 0x6ae276e8, 0x9e3fedd8, 316 },
+ { 0xefb3ab16, 0xc59b14a2, 0xc5cfe94e, 319 },
+ { 0x95d04aee, 0x3b80ece5, 0xbba1f1d1, 323 },
+ { 0xbb445da9, 0xca61281f, 0x2a8a6e45, 326 },
+ { 0xea157514, 0x3cf97226, 0xf52d09d7, 329 },
+ { 0x924d692c, 0xa61be758, 0x593c2626, 333 },
+ { 0xb6e0c377, 0xcfa2e12e, 0x6f8b2fb0, 336 },
+ { 0xe498f455, 0xc38b997a, 0x0b6dfb9c, 339 },
+ { 0x8edf98b5, 0x9a373fec, 0x4724bd41, 343 },
+ { 0xb2977ee3, 0x00c50fe7, 0x58edec91, 346 },
+ { 0xdf3d5e9b, 0xc0f653e1, 0x2f2967b6, 349 },
+ { 0x8b865b21, 0x5899f46c, 0xbd79e0d2, 353 },
+ { 0xae67f1e9, 0xaec07187, 0xecd85906, 356 },
+ { 0xda01ee64, 0x1a708de9, 0xe80e6f48, 359 },
+ { 0x884134fe, 0x908658b2, 0x3109058d, 363 },
+ { 0xaa51823e, 0x34a7eede, 0xbd4b46f0, 366 },
+ { 0xd4e5e2cd, 0xc1d1ea96, 0x6c9e18ac, 369 },
+ { 0x850fadc0, 0x9923329e, 0x03e2cf6b, 373 },
+ { 0xa6539930, 0xbf6bff45, 0x84db8346, 376 },
+ { 0xcfe87f7c, 0xef46ff16, 0xe6126418, 379 },
+ { 0x81f14fae, 0x158c5f6e, 0x4fcb7e8f, 383 },
+ { 0xa26da399, 0x9aef7749, 0xe3be5e33, 386 },
+ { 0xcb090c80, 0x01ab551c, 0x5cadf5bf, 389 },
+ { 0xfdcb4fa0, 0x02162a63, 0x73d9732f, 392 },
+ { 0x9e9f11c4, 0x014dda7e, 0x2867e7fd, 396 },
+ { 0xc646d635, 0x01a1511d, 0xb281e1fd, 399 },
+ { 0xf7d88bc2, 0x4209a565, 0x1f225a7c, 402 },
+ { 0x9ae75759, 0x6946075f, 0x3375788d, 406 },
+ { 0xc1a12d2f, 0xc3978937, 0x0052d6b1, 409 },
+ { 0xf209787b, 0xb47d6b84, 0xc0678c5d, 412 },
+ { 0x9745eb4d, 0x50ce6332, 0xf840b7ba, 416 },
+ { 0xbd176620, 0xa501fbff, 0xb650e5a9, 419 },
+ { 0xec5d3fa8, 0xce427aff, 0xa3e51f13, 422 },
+ { 0x93ba47c9, 0x80e98cdf, 0xc66f336c, 426 },
+ { 0xb8a8d9bb, 0xe123f017, 0xb80b0047, 429 },
+ { 0xe6d3102a, 0xd96cec1d, 0xa60dc059, 432 },
+ { 0x9043ea1a, 0xc7e41392, 0x87c89837, 436 },
+ { 0xb454e4a1, 0x79dd1877, 0x29babe45, 439 },
+ { 0xe16a1dc9, 0xd8545e94, 0xf4296dd6, 442 },
+ { 0x8ce2529e, 0x2734bb1d, 0x1899e4a6, 446 },
+ { 0xb01ae745, 0xb101e9e4, 0x5ec05dcf, 449 },
+ { 0xdc21a117, 0x1d42645d, 0x76707543, 452 },
+ { 0x899504ae, 0x72497eba, 0x6a06494a, 456 },
+ { 0xabfa45da, 0x0edbde69, 0x0487db9d, 459 },
+ { 0xd6f8d750, 0x9292d603, 0x45a9d284, 462 },
+ { 0x865b8692, 0x5b9bc5c2, 0x0b8a2392, 466 },
+ { 0xa7f26836, 0xf282b732, 0x8e6cac77, 469 },
+ { 0xd1ef0244, 0xaf2364ff, 0x3207d795, 472 },
+ { 0x8335616a, 0xed761f1f, 0x7f44e6bd, 476 },
+ { 0xa402b9c5, 0xa8d3a6e7, 0x5f16206c, 479 },
+ { 0xcd036837, 0x130890a1, 0x36dba887, 482 },
+ { 0x80222122, 0x6be55a64, 0xc2494954, 486 },
+ { 0xa02aa96b, 0x06deb0fd, 0xf2db9baa, 489 },
+ { 0xc83553c5, 0xc8965d3d, 0x6f928294, 492 },
+ { 0xfa42a8b7, 0x3abbf48c, 0xcb772339, 495 },
+ { 0x9c69a972, 0x84b578d7, 0xff2a7604, 499 },
+ { 0xc38413cf, 0x25e2d70d, 0xfef51385, 502 },
+ { 0xf46518c2, 0xef5b8cd1, 0x7eb25866, 505 },
+ { 0x98bf2f79, 0xd5993802, 0xef2f773f, 509 },
+ { 0xbeeefb58, 0x4aff8603, 0xaafb550f, 512 },
+ { 0xeeaaba2e, 0x5dbf6784, 0x95ba2a53, 515 },
+ { 0x952ab45c, 0xfa97a0b2, 0xdd945a74, 519 },
+ { 0xba756174, 0x393d88df, 0x94f97111, 522 },
+ { 0xe912b9d1, 0x478ceb17, 0x7a37cd56, 525 },
+ { 0x91abb422, 0xccb812ee, 0xac62e055, 529 },
+ { 0xb616a12b, 0x7fe617aa, 0x577b986b, 532 },
+ { 0xe39c4976, 0x5fdf9d94, 0xed5a7e85, 535 },
+ { 0x8e41ade9, 0xfbebc27d, 0x14588f13, 539 },
+ { 0xb1d21964, 0x7ae6b31c, 0x596eb2d8, 542 },
+ { 0xde469fbd, 0x99a05fe3, 0x6fca5f8e, 545 },
+ { 0x8aec23d6, 0x80043bee, 0x25de7bb9, 549 },
+ { 0xada72ccc, 0x20054ae9, 0xaf561aa7, 552 },
+ { 0xd910f7ff, 0x28069da4, 0x1b2ba151, 555 },
+ { 0x87aa9aff, 0x79042286, 0x90fb44d2, 559 },
+ { 0xa99541bf, 0x57452b28, 0x353a1607, 562 },
+ { 0xd3fa922f, 0x2d1675f2, 0x42889b89, 565 },
+ { 0x847c9b5d, 0x7c2e09b7, 0x69956135, 569 },
+ { 0xa59bc234, 0xdb398c25, 0x43fab983, 572 },
+ { 0xcf02b2c2, 0x1207ef2e, 0x94f967e4, 575 },
+ { 0x8161afb9, 0x4b44f57d, 0x1d1be0ee, 579 },
+ { 0xa1ba1ba7, 0x9e1632dc, 0x6462d92a, 582 },
+ { 0xca28a291, 0x859bbf93, 0x7d7b8f75, 585 },
+ { 0xfcb2cb35, 0xe702af78, 0x5cda7352, 588 },
+ { 0x9defbf01, 0xb061adab, 0x3a088813, 592 },
+ { 0xc56baec2, 0x1c7a1916, 0x088aaa18, 595 },
+ { 0xf6c69a72, 0xa3989f5b, 0x8aad549e, 598 },
+ { 0x9a3c2087, 0xa63f6399, 0x36ac54e2, 602 },
+ { 0xc0cb28a9, 0x8fcf3c7f, 0x84576a1b, 605 },
+ { 0xf0fdf2d3, 0xf3c30b9f, 0x656d44a2, 608 },
+ { 0x969eb7c4, 0x7859e743, 0x9f644ae5, 612 },
+ { 0xbc4665b5, 0x96706114, 0x873d5d9f, 615 },
+ { 0xeb57ff22, 0xfc0c7959, 0xa90cb506, 618 },
+ { 0x9316ff75, 0xdd87cbd8, 0x09a7f124, 622 },
+ { 0xb7dcbf53, 0x54e9bece, 0x0c11ed6d, 625 },
+ { 0xe5d3ef28, 0x2a242e81, 0x8f1668c8, 628 },
+ { 0x8fa47579, 0x1a569d10, 0xf96e017d, 632 },
+ { 0xb38d92d7, 0x60ec4455, 0x37c981dc, 635 },
+ { 0xe070f78d, 0x3927556a, 0x85bbe253, 638 },
+ { 0x8c469ab8, 0x43b89562, 0x93956d74, 642 },
+ { 0xaf584166, 0x54a6babb, 0x387ac8d1, 645 },
+ { 0xdb2e51bf, 0xe9d0696a, 0x06997b05, 648 },
+ { 0x88fcf317, 0xf22241e2, 0x441fece3, 652 },
+ { 0xab3c2fdd, 0xeeaad25a, 0xd527e81c, 655 },
+ { 0xd60b3bd5, 0x6a5586f1, 0x8a71e223, 658 },
+ { 0x85c70565, 0x62757456, 0xf6872d56, 662 },
+ { 0xa738c6be, 0xbb12d16c, 0xb428f8ac, 665 },
+ { 0xd106f86e, 0x69d785c7, 0xe13336d7, 668 },
+ { 0x82a45b45, 0x0226b39c, 0xecc00246, 672 },
+ { 0xa34d7216, 0x42b06084, 0x27f002d7, 675 },
+ { 0xcc20ce9b, 0xd35c78a5, 0x31ec038d, 678 },
+ { 0xff290242, 0xc83396ce, 0x7e670471, 681 },
+ { 0x9f79a169, 0xbd203e41, 0x0f0062c6, 685 },
+ { 0xc75809c4, 0x2c684dd1, 0x52c07b78, 688 },
+ { 0xf92e0c35, 0x37826145, 0xa7709a56, 691 },
+ { 0x9bbcc7a1, 0x42b17ccb, 0x88a66076, 695 },
+ { 0xc2abf989, 0x935ddbfe, 0x6acff893, 698 },
+ { 0xf356f7eb, 0xf83552fe, 0x0583f6b8, 701 },
+ { 0x98165af3, 0x7b2153de, 0xc3727a33, 705 },
+ { 0xbe1bf1b0, 0x59e9a8d6, 0x744f18c0, 708 },
+ { 0xeda2ee1c, 0x7064130c, 0x1162def0, 711 },
+ { 0x9485d4d1, 0xc63e8be7, 0x8addcb56, 715 },
+ { 0xb9a74a06, 0x37ce2ee1, 0x6d953e2b, 718 },
+ { 0xe8111c87, 0xc5c1ba99, 0xc8fa8db6, 721 },
+ { 0x910ab1d4, 0xdb9914a0, 0x1d9c9892, 725 },
+ { 0xb54d5e4a, 0x127f59c8, 0x2503beb6, 728 },
+ { 0xe2a0b5dc, 0x971f303a, 0x2e44ae64, 731 },
+ { 0x8da471a9, 0xde737e24, 0x5ceaecfe, 735 },
+ { 0xb10d8e14, 0x56105dad, 0x7425a83e, 738 },
+ { 0xdd50f199, 0x6b947518, 0xd12f124e, 741 },
+ { 0x8a5296ff, 0xe33cc92f, 0x82bd6b70, 745 },
+ { 0xace73cbf, 0xdc0bfb7b, 0x636cc64d, 748 },
+ { 0xd8210bef, 0xd30efa5a, 0x3c47f7e0, 751 },
+ { 0x8714a775, 0xe3e95c78, 0x65acfaec, 755 },
+ { 0xa8d9d153, 0x5ce3b396, 0x7f1839a7, 758 },
+ { 0xd31045a8, 0x341ca07c, 0x1ede4811, 761 },
+ { 0x83ea2b89, 0x2091e44d, 0x934aed0a, 765 },
+ { 0xa4e4b66b, 0x68b65d60, 0xf81da84d, 768 },
+ { 0xce1de406, 0x42e3f4b9, 0x36251260, 771 },
+ { 0x80d2ae83, 0xe9ce78f3, 0xc1d72b7c, 775 },
+ { 0xa1075a24, 0xe4421730, 0xb24cf65b, 778 },
+ { 0xc94930ae, 0x1d529cfc, 0xdee033f2, 781 },
+ { 0xfb9b7cd9, 0xa4a7443c, 0x169840ef, 784 },
+ { 0x9d412e08, 0x06e88aa5, 0x8e1f2895, 788 },
+ { 0xc491798a, 0x08a2ad4e, 0xf1a6f2ba, 791 },
+ { 0xf5b5d7ec, 0x8acb58a2, 0xae10af69, 794 },
+ { 0x9991a6f3, 0xd6bf1765, 0xacca6da1, 798 },
+ { 0xbff610b0, 0xcc6edd3f, 0x17fd090a, 801 },
+ { 0xeff394dc, 0xff8a948e, 0xddfc4b4c, 804 },
+ { 0x95f83d0a, 0x1fb69cd9, 0x4abdaf10, 808 },
+ { 0xbb764c4c, 0xa7a4440f, 0x9d6d1ad4, 811 },
+ { 0xea53df5f, 0xd18d5513, 0x84c86189, 814 },
+ { 0x92746b9b, 0xe2f8552c, 0x32fd3cf5, 818 },
+ { 0xb7118682, 0xdbb66a77, 0x3fbc8c33, 821 },
+ { 0xe4d5e823, 0x92a40515, 0x0fabaf3f, 824 },
+ { 0x8f05b116, 0x3ba6832d, 0x29cb4d87, 828 },
+ { 0xb2c71d5b, 0xca9023f8, 0x743e20e9, 831 },
+ { 0xdf78e4b2, 0xbd342cf6, 0x914da924, 834 },
+ { 0x8bab8eef, 0xb6409c1a, 0x1ad089b6, 838 },
+ { 0xae9672ab, 0xa3d0c320, 0xa184ac24, 841 },
+ { 0xda3c0f56, 0x8cc4f3e8, 0xc9e5d72d, 844 },
+ { 0x88658996, 0x17fb1871, 0x7e2fa67c, 848 },
+ { 0xaa7eebfb, 0x9df9de8d, 0xddbb901b, 851 },
+ { 0xd51ea6fa, 0x85785631, 0x552a7422, 854 },
+ { 0x8533285c, 0x936b35de, 0xd53a8895, 858 },
+ { 0xa67ff273, 0xb8460356, 0x8a892aba, 861 },
+ { 0xd01fef10, 0xa657842c, 0x2d2b7569, 864 },
+ { 0x8213f56a, 0x67f6b29b, 0x9c3b2962, 868 },
+ { 0xa298f2c5, 0x01f45f42, 0x8349f3ba, 871 },
+ { 0xcb3f2f76, 0x42717713, 0x241c70a9, 874 },
+ { 0xfe0efb53, 0xd30dd4d7, 0xed238cd3, 877 },
+ { 0x9ec95d14, 0x63e8a506, 0xf4363804, 881 },
+ { 0xc67bb459, 0x7ce2ce48, 0xb143c605, 884 },
+ { 0xf81aa16f, 0xdc1b81da, 0xdd94b786, 887 },
+ { 0x9b10a4e5, 0xe9913128, 0xca7cf2b4, 891 },
+ { 0xc1d4ce1f, 0x63f57d72, 0xfd1c2f61, 894 },
+ { 0xf24a01a7, 0x3cf2dccf, 0xbc633b39, 897 },
+ { 0x976e4108, 0x8617ca01, 0xd5be0503, 901 },
+ { 0xbd49d14a, 0xa79dbc82, 0x4b2d8644, 904 },
+ { 0xec9c459d, 0x51852ba2, 0xddf8e7d6, 907 },
+ { 0x93e1ab82, 0x52f33b45, 0xcabb90e5, 911 },
+ { 0xb8da1662, 0xe7b00a17, 0x3d6a751f, 914 },
+ { 0xe7109bfb, 0xa19c0c9d, 0x0cc51267, 917 },
+ { 0x906a617d, 0x450187e2, 0x27fb2b80, 921 },
+ { 0xb484f9dc, 0x9641e9da, 0xb1f9f660, 924 },
+ { 0xe1a63853, 0xbbd26451, 0x5e7873f8, 927 },
+ { 0x8d07e334, 0x55637eb2, 0xdb0b487b, 931 },
+ { 0xb049dc01, 0x6abc5e5f, 0x91ce1a9a, 934 },
+ { 0xdc5c5301, 0xc56b75f7, 0x7641a140, 937 },
+ { 0x89b9b3e1, 0x1b6329ba, 0xa9e904c8, 941 },
+ { 0xac2820d9, 0x623bf429, 0x546345fa, 944 },
+ { 0xd732290f, 0xbacaf133, 0xa97c1779, 947 },
+ { 0x867f59a9, 0xd4bed6c0, 0x49ed8eab, 951 },
+ { 0xa81f3014, 0x49ee8c70, 0x5c68f256, 954 },
+ { 0xd226fc19, 0x5c6a2f8c, 0x73832eec, 957 },
+ { 0x83585d8f, 0xd9c25db7, 0xc831fd53, 961 },
+ { 0xa42e74f3, 0xd032f525, 0xba3e7ca8, 964 },
+ { 0xcd3a1230, 0xc43fb26f, 0x28ce1bd2, 967 },
+ { 0x80444b5e, 0x7aa7cf85, 0x7980d163, 971 },
+ { 0xa0555e36, 0x1951c366, 0xd7e105bc, 974 },
+ { 0xc86ab5c3, 0x9fa63440, 0x8dd9472b, 977 },
+ { 0xfa856334, 0x878fc150, 0xb14f98f6, 980 },
+ { 0x9c935e00, 0xd4b9d8d2, 0x6ed1bf9a, 984 },
+ { 0xc3b83581, 0x09e84f07, 0x0a862f80, 987 },
+ { 0xf4a642e1, 0x4c6262c8, 0xcd27bb61, 990 },
+ { 0x98e7e9cc, 0xcfbd7dbd, 0x8038d51c, 994 },
+ { 0xbf21e440, 0x03acdd2c, 0xe0470a63, 997 },
+ { 0xeeea5d50, 0x04981478, 0x1858ccfc, 1000 },
+ { 0x95527a52, 0x02df0ccb, 0x0f37801e, 1004 },
+ { 0xbaa718e6, 0x8396cffd, 0xd3056025, 1007 },
+ { 0xe950df20, 0x247c83fd, 0x47c6b82e, 1010 },
+ { 0x91d28b74, 0x16cdd27e, 0x4cdc331d, 1014 },
+ { 0xb6472e51, 0x1c81471d, 0xe0133fe4, 1017 },
+ { 0xe3d8f9e5, 0x63a198e5, 0x58180fdd, 1020 },
+ { 0x8e679c2f, 0x5e44ff8f, 0x570f09ea, 1024 },
+ { 0xb201833b, 0x35d63f73, 0x2cd2cc65, 1027 },
+ { 0xde81e40a, 0x034bcf4f, 0xf8077f7e, 1030 },
+ { 0x8b112e86, 0x420f6191, 0xfb04afaf, 1034 },
+ { 0xadd57a27, 0xd29339f6, 0x79c5db9a, 1037 },
+ { 0xd94ad8b1, 0xc7380874, 0x18375281, 1040 },
+ { 0x87cec76f, 0x1c830548, 0x8f229391, 1044 },
+ { 0xa9c2794a, 0xe3a3c69a, 0xb2eb3875, 1047 },
+ { 0xd433179d, 0x9c8cb841, 0x5fa60692, 1050 },
+ { 0x849feec2, 0x81d7f328, 0xdbc7c41b, 1054 },
+ { 0xa5c7ea73, 0x224deff3, 0x12b9b522, 1057 },
+ { 0xcf39e50f, 0xeae16bef, 0xd768226b, 1060 },
+ { 0x81842f29, 0xf2cce375, 0xe6a11583, 1064 },
+ { 0xa1e53af4, 0x6f801c53, 0x60495ae3, 1067 },
+ { 0xca5e89b1, 0x8b602368, 0x385bb19c, 1070 },
+ { 0xfcf62c1d, 0xee382c42, 0x46729e03, 1073 },
+ { 0x9e19db92, 0xb4e31ba9, 0x6c07a2c2, 1077 } };
+static short int Lhint[2098] = {
+ /*18,*/ 19, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22,
+ 22, 22, 23, 23, 23, 23, 24, 24, 24, 25, 25,
+ 25, 26, 26, 26, 26, 27, 27, 27, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
+ 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35,
+ 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38,
+ 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 41,
+ 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 45,
+ 45, 45, 46, 46, 46, 47, 47, 47, 47, 48, 48,
+ 48, 49, 49, 49, 50, 50, 50, 51, 51, 51, 51,
+ 52, 52, 52, 53, 53, 53, 54, 54, 54, 54, 55,
+ 55, 55, 56, 56, 56, 57, 57, 57, 57, 58, 58,
+ 58, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61,
+ 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 65,
+ 65, 65, 66, 66, 66, 66, 67, 67, 67, 68, 68,
+ 68, 69, 69, 69, 69, 70, 70, 70, 71, 71, 71,
+ 72, 72, 72, 72, 73, 73, 73, 74, 74, 74, 75,
+ 75, 75, 75, 76, 76, 76, 77, 77, 77, 78, 78,
+ 78, 78, 79, 79, 79, 80, 80, 80, 81, 81, 81,
+ 82, 82, 82, 82, 83, 83, 83, 84, 84, 84, 85,
+ 85, 85, 85, 86, 86, 86, 87, 87, 87, 88, 88,
+ 88, 88, 89, 89, 89, 90, 90, 90, 91, 91, 91,
+ 91, 92, 92, 92, 93, 93, 93, 94, 94, 94, 94,
+ 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 98,
+ 98, 98, 99, 99, 99, 100, 100, 100, 100, 101, 101,
+ 101, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104,
+ 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 108,
+ 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111,
+ 111, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114,
+ 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 118,
+ 118, 118, 119, 119, 119, 119, 120, 120, 120, 121, 121,
+ 121, 122, 122, 122, 122, 123, 123, 123, 124, 124, 124,
+ 125, 125, 125, 125, 126, 126, 126, 127, 127, 127, 128,
+ 128, 128, 128, 129, 129, 129, 130, 130, 130, 131, 131,
+ 131, 131, 132, 132, 132, 133, 133, 133, 134, 134, 134,
+ 134, 135, 135, 135, 136, 136, 136, 137, 137, 137, 137,
+ 138, 138, 138, 139, 139, 139, 140, 140, 140, 141, 141,
+ 141, 141, 142, 142, 142, 143, 143, 143, 144, 144, 144,
+ 144, 145, 145, 145, 146, 146, 146, 147, 147, 147, 147,
+ 148, 148, 148, 149, 149, 149, 150, 150, 150, 150, 151,
+ 151, 151, 152, 152, 152, 153, 153, 153, 153, 154, 154,
+ 154, 155, 155, 155, 156, 156, 156, 156, 157, 157, 157,
+ 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 161,
+ 161, 161, 162, 162, 162, 162, 163, 163, 163, 164, 164,
+ 164, 165, 165, 165, 165, 166, 166, 166, 167, 167, 167,
+ 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 171,
+ 171, 171, 172, 172, 172, 172, 173, 173, 173, 174, 174,
+ 174, 175, 175, 175, 175, 176, 176, 176, 177, 177, 177,
+ 178, 178, 178, 178, 179, 179, 179, 180, 180, 180, 181,
+ 181, 181, 181, 182, 182, 182, 183, 183, 183, 184, 184,
+ 184, 184, 185, 185, 185, 186, 186, 186, 187, 187, 187,
+ 187, 188, 188, 188, 189, 189, 189, 190, 190, 190, 190,
+ 191, 191, 191, 192, 192, 192, 193, 193, 193, 193, 194,
+ 194, 194, 195, 195, 195, 196, 196, 196, 197, 197, 197,
+ 197, 198, 198, 198, 199, 199, 199, 200, 200, 200, 200,
+ 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204,
+ 204, 204, 205, 205, 205, 206, 206, 206, 206, 207, 207,
+ 207, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210,
+ 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, 214,
+ 214, 214, 215, 215, 215, 215, 216, 216, 216, 217, 217,
+ 217, 218, 218, 218, 218, 219, 219, 219, 220, 220, 220,
+ 221, 221, 221, 221, 222, 222, 222, 223, 223, 223, 224,
+ 224, 224, 224, 225, 225, 225, 226, 226, 226, 227, 227,
+ 227, 228, 228, 228, 228, 229, 229, 229, 230, 230, 230,
+ 231, 231, 231, 231, 232, 232, 232, 233, 233, 233, 234,
+ 234, 234, 234, 235, 235, 235, 236, 236, 236, 237, 237,
+ 237, 237, 238, 238, 238, 239, 239, 239, 240, 240, 240,
+ 240, 241, 241, 241, 242, 242, 242, 243, 243, 243, 243,
+ 244, 244, 244, 245, 245, 245, 246, 246, 246, 246, 247,
+ 247, 247, 248, 248, 248, 249, 249, 249, 249, 250, 250,
+ 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253,
+ 254, 254, 254, 255, 255, 255, 256, 256, 256, 256, 257,
+ 257, 257, 258, 258, 258, 259, 259, 259, 259, 260, 260,
+ 260, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263,
+ 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 267,
+ 267, 267, 268, 268, 268, 268, 269, 269, 269, 270, 270,
+ 270, 271, 271, 271, 271, 272, 272, 272, 273, 273, 273,
+ 274, 274, 274, 274, 275, 275, 275, 276, 276, 276, 277,
+ 277, 277, 277, 278, 278, 278, 279, 279, 279, 280, 280,
+ 280, 280, 281, 281, 281, 282, 282, 282, 283, 283, 283,
+ 283, 284, 284, 284, 285, 285, 285, 286, 286, 286, 287,
+ 287, 287, 287, 288, 288, 288, 289, 289, 289, 290, 290,
+ 290, 290, 291, 291, 291, 292, 292, 292, 293, 293, 293,
+ 293, 294, 294, 294, 295, 295, 295, 296, 296, 296, 296,
+ 297, 297, 297, 298, 298, 298, 299, 299, 299, 299, 300,
+ 300, 300, 301, 301, 301, 302, 302, 302, 302, 303, 303,
+ 303, 304, 304, 304, 305, 305, 305, 305, 306, 306, 306,
+ 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, 310,
+ 310, 310, 311, 311, 311, 311, 312, 312, 312, 313, 313,
+ 313, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316,
+ 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, 320,
+ 320, 320, 321, 321, 321, 321, 322, 322, 322, 323, 323,
+ 323, 324, 324, 324, 324, 325, 325, 325, 326, 326, 326,
+ 327, 327, 327, 327, 328, 328, 328, 329, 329, 329, 330,
+ 330, 330, 330, 331, 331, 331, 332, 332, 332, 333, 333,
+ 333, 333, 334, 334, 334, 335, 335, 335, 336, 336, 336,
+ 336, 337, 337, 337, 338, 338, 338, 339, 339, 339, 339,
+ 340, 340, 340, 341, 341, 341, 342, 342, 342, 342, 343,
+ 343, 343, 344, 344, 344, 345, 345, 345, 346, 346, 346,
+ 346, 347, 347, 347, 348, 348, 348, 349, 349, 349, 349,
+ 350, 350, 350, 351, 351, 351, 352, 352, 352, 352, 353,
+ 353, 353, 354, 354, 354, 355, 355, 355, 355, 356, 356,
+ 356, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359,
+ 360, 360, 360, 361, 361, 361, 361, 362, 362, 362, 363,
+ 363, 363, 364, 364, 364, 364, 365, 365, 365, 366, 366,
+ 366, 367, 367, 367, 367, 368, 368, 368, 369, 369, 369,
+ 370, 370, 370, 370, 371, 371, 371, 372, 372, 372, 373,
+ 373, 373, 374, 374, 374, 374, 375, 375, 375, 376, 376,
+ 376, 377, 377, 377, 377, 378, 378, 378, 379, 379, 379,
+ 380, 380, 380, 380, 381, 381, 381, 382, 382, 382, 383,
+ 383, 383, 383, 384, 384, 384, 385, 385, 385, 386, 386,
+ 386, 386, 387, 387, 387, 388, 388, 388, 389, 389, 389,
+ 389, 390, 390, 390, 391, 391, 391, 392, 392, 392, 392,
+ 393, 393, 393, 394, 394, 394, 395, 395, 395, 395, 396,
+ 396, 396, 397, 397, 397, 398, 398, 398, 398, 399, 399,
+ 399, 400, 400, 400, 401, 401, 401, 402, 402, 402, 402,
+ 403, 403, 403, 404, 404, 404, 405, 405, 405, 405, 406,
+ 406, 406, 407, 407, 407, 408, 408, 408, 408, 409, 409,
+ 409, 410, 410, 410, 411, 411, 411, 411, 412, 412, 412,
+ 413, 413, 413, 414, 414, 414, 414, 415, 415, 415, 416,
+ 416, 416, 417, 417, 417, 417, 418, 418, 418, 419, 419,
+ 419, 420, 420, 420, 420, 421, 421, 421, 422, 422, 422,
+ 423, 423, 423, 423, 424, 424, 424, 425, 425, 425, 426,
+ 426, 426, 426, 427, 427, 427, 428, 428, 428, 429, 429,
+ 429, 429, 430, 430, 430, 431, 431, 431, 432, 432, 432,
+ 433, 433, 433, 433, 434, 434, 434, 435, 435, 435, 436,
+ 436, 436, 436, 437, 437, 437, 438, 438, 438, 439, 439,
+ 439, 439, 440, 440, 440, 441, 441, 441, 442, 442, 442,
+ 442, 443, 443, 443, 444, 444, 444, 445, 445, 445, 445,
+ 446, 446, 446, 447, 447, 447, 448, 448, 448, 448, 449,
+ 449, 449, 450, 450, 450, 451, 451, 451, 451, 452, 452,
+ 452, 453, 453, 453, 454, 454, 454, 454, 455, 455, 455,
+ 456, 456, 456, 457, 457, 457, 457, 458, 458, 458, 459,
+ 459, 459, 460, 460, 460, 461, 461, 461, 461, 462, 462,
+ 462, 463, 463, 463, 464, 464, 464, 464, 465, 465, 465,
+ 466, 466, 466, 467, 467, 467, 467, 468, 468, 468, 469,
+ 469, 469, 470, 470, 470, 470, 471, 471, 471, 472, 472,
+ 472, 473, 473, 473, 473, 474, 474, 474, 475, 475, 475,
+ 476, 476, 476, 476, 477, 477, 477, 478, 478, 478, 479,
+ 479, 479, 479, 480, 480, 480, 481, 481, 481, 482, 482,
+ 482, 482, 483, 483, 483, 484, 484, 484, 485, 485, 485,
+ 485, 486, 486, 486, 487, 487, 487, 488, 488, 488, 488,
+ 489, 489, 489, 490, 490, 490, 491, 491, 491, 492, 492,
+ 492, 492, 493, 493, 493, 494, 494, 494, 495, 495, 495,
+ 495, 496, 496, 496, 497, 497, 497, 498, 498, 498, 498,
+ 499, 499, 499, 500, 500, 500, 501, 501, 501, 501, 502,
+ 502, 502, 503, 503, 503, 504, 504, 504, 504, 505, 505,
+ 505, 506, 506, 506, 507, 507, 507, 507, 508, 508, 508,
+ 509, 509, 509, 510, 510, 510, 510, 511, 511, 511, 512,
+ 512, 512, 513, 513, 513, 513, 514, 514, 514, 515, 515,
+ 515, 516, 516, 516, 516, 517, 517, 517, 518, 518, 518,
+ 519, 519, 519, 520, 520, 520, 520, 521, 521, 521, 522,
+ 522, 522, 523, 523, 523, 523, 524, 524, 524, 525, 525,
+ 525, 526, 526, 526, 526, 527, 527, 527, 528, 528, 528,
+ 529, 529, 529, 529, 530, 530, 530, 531, 531, 531, 532,
+ 532, 532, 532, 533, 533, 533, 534, 534, 534, 535, 535,
+ 535, 535, 536, 536, 536, 537, 537, 537, 538, 538, 538,
+ 538, 539, 539, 539, 540, 540, 540, 541, 541, 541, 541,
+ 542, 542, 542, 543, 543, 543, 544, 544, 544, 544, 545,
+ 545, 545, 546, 546, 546, 547, 547, 547, 548, 548, 548,
+ 548, 549, 549, 549, 550, 550, 550, 551, 551, 551, 551,
+ 552, 552, 552, 553, 553, 553, 554, 554, 554, 554, 555,
+ 555, 555, 556, 556, 556, 557, 557, 557, 557, 558, 558,
+ 558, 559, 559, 559, 560, 560, 560, 560, 561, 561, 561,
+ 562, 562, 562, 563, 563, 563, 563, 564, 564, 564, 565,
+ 565, 565, 566, 566, 566, 566, 567, 567, 567, 568, 568,
+ 568, 569, 569, 569, 569, 570, 570, 570, 571, 571, 571,
+ 572, 572, 572, 572, 573, 573, 573, 574, 574, 574, 575,
+ 575, 575, 575, 576, 576, 576, 577, 577, 577, 578, 578,
+ 578, 579, 579, 579, 579, 580, 580, 580, 581, 581, 581,
+ 582, 582, 582, 582, 583, 583, 583, 584, 584, 584, 585,
+ 585, 585, 585, 586, 586, 586, 587, 587, 587, 588, 588,
+ 588, 588, 589, 589, 589, 590, 590, 590, 591, 591, 591,
+ 591, 592, 592, 592, 593, 593, 593, 594, 594, 594, 594,
+ 595, 595, 595, 596, 596, 596, 597, 597, 597, 597, 598,
+ 598, 598, 599, 599, 599, 600, 600, 600, 600, 601, 601,
+ 601, 602, 602, 602, 603, 603, 603, 603, 604, 604, 604,
+ 605, 605, 605, 606, 606, 606, 607, 607, 607, 607, 608,
+ 608, 608, 609, 609, 609, 610, 610, 610, 610, 611, 611,
+ 611, 612, 612, 612, 613, 613, 613, 613, 614, 614, 614,
+ 615, 615, 615, 616, 616, 616, 616, 617, 617, 617, 618,
+ 618, 618, 619, 619, 619, 619, 620, 620, 620, 621, 621,
+ 621, 622, 622, 622, 622, 623, 623, 623, 624, 624, 624,
+ 625, 625, 625, 625, 626, 626, 626, 627, 627, 627, 628,
+ 628, 628, 628, 629, 629, 629, 630, 630, 630, 631, 631,
+ 631, 631, 632, 632, 632, 633, 633, 633, 634, 634, 634,
+ 634, 635, 635, 635, 636, 636, 636, 637, 637, 637, 638,
+ 638, 638, 638, 639, 639, 639, 640, 640, 640, 641, 641,
+ 641, 641, 642, 642, 642, 643, 643, 643, 644, 644, 644,
+ 644, 645, 645, 645, 646, 646, 646, 647, 647, 647, 647,
+ 648, 648, 648, 649, 649, 649, 650, 650
+};
+static ULLong pfive[27] = { 5ll,
+ 25ll,
+ 125ll,
+ 625ll,
+ 3125ll,
+ 15625ll,
+ 78125ll,
+ 390625ll,
+ 1953125ll,
+ 9765625ll,
+ 48828125ll,
+ 244140625ll,
+ 1220703125ll,
+ 6103515625ll,
+ 30517578125ll,
+ 152587890625ll,
+ 762939453125ll,
+ 3814697265625ll,
+ 19073486328125ll,
+ 95367431640625ll,
+ 476837158203125ll,
+ 2384185791015625ll,
+ 11920928955078125ll,
+ 59604644775390625ll,
+ 298023223876953125ll,
+ 1490116119384765625ll,
+ 7450580596923828125ll };
+
+static int pfivebits[25] = { 3, 5, 7, 10, 12, 14, 17, 19, 21, 24, 26, 28, 31,
+ 33, 35, 38, 40, 42, 45, 47, 49, 52, 54, 56, 59 };
+#endif /*}*/
+#endif /*}} NO_LONG_LONG */
+
+ typedef union {
+ double d;
+ ULong L[2];
+#ifdef USE_BF96
+ ULLong LL;
+#endif
+} U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+#define LLval(x) (x)->LL
+
+#ifndef STRTOD_DIGLIM
+#define STRTOD_DIGLIM 40
+#endif
+
+#ifdef DIGLIM_DEBUG
+extern int strtod_diglim;
+#else
+#define strtod_diglim STRTOD_DIGLIM
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a, b, c) \
+ (((unsigned short *)a)[1] = (unsigned short)b, \
+ ((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a, b, c) \
+ (((unsigned short *)a)[0] = (unsigned short)b, \
+ ((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Nbits 53
+#define Bias 1023
+#define Emax 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm /* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Nbits 56
+#define Bias 65
+#define Emax 248
+#define Emin (-260)
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Nbits 56
+#define Bias 129
+#define Emax 126
+#define Emin (-129)
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a, b) a = rnd_prod(a, b)
+#define rounded_quotient(a, b) a = rnd_quot(a, b)
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a, b) a *= b
+#define rounded_quotient(a, b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+typedef struct BCinfo BCinfo;
+struct BCinfo {
+ int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale,
+ uflchk;
+};
+
+#define FFFFFFFF 0xffffffffUL
+
+#ifdef MULTIPLE_THREADS
+#define MTa , PTI
+#define MTb , &TI
+#define MTd , ThInfo **PTI
+static unsigned int maxthreads = 0;
+#else
+#define MTa /*nothing*/
+#define MTb /*nothing*/
+#define MTd /*nothing*/
+#endif
+
+#define Kmax 7
+
+#ifdef __cplusplus
+extern "C" double strtod(const char *s00, char **se);
+extern "C" char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign,
+ char **rve);
+#endif
+
+struct Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+};
+
+typedef struct Bigint Bigint;
+typedef struct ThInfo {
+ Bigint *Freelist[Kmax + 1];
+ Bigint *P5s;
+} ThInfo;
+
+static ThInfo TI0;
+
+#ifdef MULTIPLE_THREADS
+static ThInfo *TI1;
+static int TI0_used;
+
+void set_max_dtoa_threads(unsigned int n)
+{
+ size_t L;
+
+ if (n > maxthreads) {
+ L = n * sizeof(ThInfo);
+ if (TI1) {
+ TI1 = (ThInfo *)REALLOC(TI1, L);
+ memset(TI1 + maxthreads, 0,
+ (n - maxthreads) * sizeof(ThInfo));
+ } else {
+ TI1 = (ThInfo *)MALLOC(L);
+ if (TI0_used) {
+ memcpy(TI1, &TI0, sizeof(ThInfo));
+ if (n > 1)
+ memset(TI1 + 1, 0, L - sizeof(ThInfo));
+ memset(&TI0, 0, sizeof(ThInfo));
+ } else
+ memset(TI1, 0, L);
+ }
+ maxthreads = n;
+ }
+}
+
+static ThInfo *get_TI(void)
+{
+ unsigned int thno = dtoa_get_threadno();
+ if (thno < maxthreads)
+ return TI1 + thno;
+ if (thno == 0)
+ TI0_used = 1;
+ return &TI0;
+}
+#define freelist TI->Freelist
+#define p5s TI->P5s
+#else
+#define freelist TI0.Freelist
+#define p5s TI0.P5s
+#endif
+
+static Bigint *Balloc(int k MTd)
+{
+ int x;
+ Bigint *rv;
+#ifndef Omit_Private_Memory
+ unsigned int len;
+#endif
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI;
+
+ if (!(TI = *PTI))
+ *PTI = TI = get_TI();
+ if (TI == &TI0)
+ ACQUIRE_DTOA_LOCK(0);
+#endif
+ /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+ /* but this case seems very unlikely. */
+ if (k <= Kmax && (rv = freelist[k]))
+ freelist[k] = rv->next;
+ else {
+ x = 1 << k;
+#ifdef Omit_Private_Memory
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x - 1) * sizeof(ULong));
+#else
+ len = (sizeof(Bigint) + (x - 1) * sizeof(ULong) +
+ sizeof(double) - 1) /
+ sizeof(double);
+ if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem
+#ifdef MULTIPLE_THREADS
+ && TI == TI1
+#endif
+ ) {
+ rv = (Bigint *)pmem_next;
+ pmem_next += len;
+ } else
+ rv = (Bigint *)MALLOC(len * sizeof(double));
+#endif
+ rv->k = k;
+ rv->maxwds = x;
+ }
+#ifdef MULTIPLE_THREADS
+ if (TI == &TI0)
+ FREE_DTOA_LOCK(0);
+#endif
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+static void Bfree(Bigint *v MTd)
+{
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI;
+#endif
+ if (v) {
+ if (v->k > Kmax)
+ FREE((void *)v);
+ else {
+#ifdef MULTIPLE_THREADS
+ if (!(TI = *PTI))
+ *PTI = TI = get_TI();
+ if (TI == &TI0)
+ ACQUIRE_DTOA_LOCK(0);
+#endif
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+#ifdef MULTIPLE_THREADS
+ if (TI == &TI0)
+ FREE_DTOA_LOCK(0);
+#endif
+ }
+ }
+}
+
+#define Bcopy(x, y) \
+ memcpy((char *)&x->sign, (char *)&y->sign, \
+ y->wds * sizeof(Long) + 2 * sizeof(int))
+
+static Bigint *multadd(Bigint *b, int m, int a MTd) /* multiply by m and add a
+ */
+{
+ int i, wds;
+#ifdef ULLong
+ ULong *x;
+ ULLong carry, y;
+#else
+ ULong carry, *x, y;
+#ifdef Pack_32
+ ULong xi, z;
+#endif
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ } while (++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k + 1 MTa);
+ Bcopy(b1, b);
+ Bfree(b MTa);
+ b = b1;
+ }
+ b->x[wds++] = carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, int dplen MTd)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for (k = 0, y = 1; x > y; y <<= 1, k++)
+ ;
+#ifdef Pack_32
+ b = Balloc(k MTa);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k + 1 MTa);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do
+ b = multadd(b, 10, *s++ - '0' MTa);
+ while (++i < nd0);
+ s += dplen;
+ } else
+ s += dplen + 9;
+ for (; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0' MTa);
+ return b;
+}
+
+static int hi0bits(ULong x)
+{
+ int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+static int lo0bits(ULong *y)
+{
+ int k;
+ ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+static Bigint *i2b(int i MTd)
+{
+ Bigint *b;
+
+ b = Balloc(1 MTa);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+static Bigint *mult(Bigint *a, Bigint *b MTd)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+#ifdef Pack_32
+ ULong z2;
+#endif
+#endif
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k MTa);
+ for (x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for (; xb < xbe; xc0++) {
+ if ((y = *xb++)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = z & FFFFFFFF;
+ } while (x < xae);
+ *xc = carry;
+ }
+ }
+#else
+#ifdef Pack_32
+ for (; xb < xbe; xb++, xc0++) {
+ if ((y = *xb & 0xffff)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ } while (x < xae);
+ *xc = carry;
+ }
+ if ((y = *xb >> 16)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while (x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for (; xb < xbe; xc0++) {
+ if (y = *xb++) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ } while (x < xae);
+ *xc = carry;
+ }
+ }
+#endif
+#endif
+ for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc)
+ ;
+ c->wds = wc;
+ return c;
+}
+
+static Bigint *pow5mult(Bigint *b, int k MTd)
+{
+ Bigint *b1, *p5, *p51;
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI;
+#endif
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3))
+ b = multadd(b, p05[i - 1], 0 MTa);
+
+ if (!(k >>= 2))
+ return b;
+#ifdef MULTIPLE_THREADS
+ if (!(TI = *PTI))
+ *PTI = TI = get_TI();
+#endif
+ if (!(p5 = p5s)) {
+ /* first time */
+#ifdef MULTIPLE_THREADS
+ if (!(TI = *PTI))
+ *PTI = TI = get_TI();
+ if (TI == &TI0)
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p5 = p5s)) {
+ p5 = p5s = i2b(625 MTa);
+ p5->next = 0;
+ }
+ if (TI == &TI0)
+ FREE_DTOA_LOCK(1);
+#else
+ p5 = p5s = i2b(625 MTa);
+ p5->next = 0;
+#endif
+ }
+ for (;;) {
+ if (k & 1) {
+ b1 = mult(b, p5 MTa);
+ Bfree(b MTa);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+#ifdef MULTIPLE_THREADS
+ if (!TI && !(TI = *PTI))
+ *PTI = TI = get_TI();
+ if (TI == &TI0)
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5, p5 MTa);
+ p51->next = 0;
+ }
+ if (TI == &TI0)
+ FREE_DTOA_LOCK(1);
+#else
+ p51 = p5->next = mult(p5, p5);
+ p51->next = 0;
+#endif
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+static Bigint *lshift(Bigint *b, int k MTd)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+ n = k >> 5;
+#else
+ n = k >> 4;
+#endif
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for (i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1 MTa);
+ x1 = b1->x;
+ for (i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if ((*x1 = z))
+ ++n1;
+ }
+#else
+ if (k &= 0xf) {
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#endif
+ else
+ do
+ *x1++ = *x++;
+ while (x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b MTa);
+ return b1;
+}
+
+static int cmp(Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i - 1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j - 1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for (;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+static Bigint *diff(Bigint *a, Bigint *b MTd)
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+#endif
+
+ i = cmp(a, b);
+ if (!i) {
+ c = Balloc(0 MTa);
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ } else
+ i = 0;
+ c = Balloc(a->k MTa);
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = y & FFFFFFFF;
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = y & FFFFFFFF;
+ }
+#else
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while (!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+static double ulp(U *x)
+{
+ Long L;
+ U u;
+
+ L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+ L |= Exp_msk1 >> 4;
+#endif
+ word0(&u) = L;
+ word1(&u) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ } else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(&u) = 0x80000 >> L;
+ word1(&u) = 0;
+ } else {
+ word0(&u) = 0;
+ L -= Exp_shift;
+ word1(&u) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+#endif
+ return dval(&u);
+}
+
+static double b2d(Bigint *a, int *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ U d;
+#ifdef VAX
+ ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y)
+ Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> (Ebits - k);
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << ((32 - Ebits) + k) | w >> (Ebits - k);
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> (32 - k);
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> (32 - k);
+ } else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ret_d:
+#ifdef VAX
+ word0(&d) = d0 >> 16 | d0 << 16;
+ word1(&d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+ return dval(&d);
+}
+
+static Bigint *d2b(U *d, int *e, int *bits MTd)
+{
+ Bigint *b;
+ int de, k;
+ ULong *x, y, z;
+#ifndef Sudden_Underflow
+ int i;
+#endif
+#ifdef VAX
+ ULong d0, d1;
+ d0 = word0(d) >> 16 | word0(d) << 16;
+ d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+ b = Balloc(1 MTa);
+#else
+ b = Balloc(2 MTa);
+#endif
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+ z |= Exp_msk11;
+#endif
+#else
+ if ((de = (int)(d0 >> Exp_shift)))
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if ((y = d1)) {
+ if ((k = lo0bits(&y))) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ } else
+ x[0] = y;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = (x[1] = z) ? 2 : 1;
+ } else {
+ k = lo0bits(&z);
+ x[0] = z;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = 1;
+ k += 32;
+ }
+#else
+ if (y = d1) {
+ if (k = lo0bits(&y))
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ } else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k + 16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ } else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ } else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while (!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+#ifdef IBM
+ *e = (de - Bias - (P - 1) << 2) + k;
+ *bits = 4 * P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+ *e = de - Bias - (P - 1) + k;
+ *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+ } else {
+ *e = de - Bias - (P - 1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32 * i - hi0bits(x[i - 1]);
+#else
+ *bits = (i + 2) * 16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+}
+#undef d0
+#undef d1
+
+static double ratio(Bigint *a, Bigint *b)
+{
+ U da, db;
+ int k, ka, kb;
+
+ dval(&da) = b2d(a, &ka);
+ dval(&db) = b2d(b, &kb);
+#ifdef Pack_32
+ k = ka - kb + 32 * (a->wds - b->wds);
+#else
+ k = ka - kb + 16 * (a->wds - b->wds);
+#endif
+#ifdef IBM
+ if (k > 0) {
+ word0(&da) += (k >> 2) * Exp_msk1;
+ if (k &= 3)
+ dval(&da) *= 1 << k;
+ } else {
+ k = -k;
+ word0(&db) += (k >> 2) * Exp_msk1;
+ if (k &= 3)
+ dval(&db) *= 1 << k;
+ }
+#else
+ if (k > 0)
+ word0(&da) += k * Exp_msk1;
+ else {
+ k = -k;
+ word0(&db) += k * Exp_msk1;
+ }
+#endif
+ return dval(&da) / dval(&db);
+}
+
+static const double tens[] = { 1e0,
+ 1e1,
+ 1e2,
+ 1e3,
+ 1e4,
+ 1e5,
+ 1e6,
+ 1e7,
+ 1e8,
+ 1e9,
+ 1e10,
+ 1e11,
+ 1e12,
+ 1e13,
+ 1e14,
+ 1e15,
+ 1e16,
+ 1e17,
+ 1e18,
+ 1e19,
+ 1e20,
+ 1e21,
+ 1e22
+#ifdef VAX
+ ,
+ 1e23,
+ 1e24
+#endif
+};
+
+static const double
+#ifdef IEEE_Arith
+ bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+ 9007199254740992. * 9007199254740992.e-256
+/* = 2^106 * 1e-256 */
+#else
+ 1e-256
+#endif
+};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+ bigtens[] = { 1e16, 1e32, 1e64 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+ bigtens[] = { 1e16, 1e32 };
+static const double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#undef Need_Hexdig
+#ifdef INFNAN_CHECK
+#ifndef No_Hex_NaN
+#define Need_Hexdig
+#endif
+#endif
+
+#ifndef Need_Hexdig
+#ifndef NO_HEX_FP
+#define Need_Hexdig
+#endif
+#endif
+
+#ifdef Need_Hexdig /*{*/
+#if 0
+static unsigned char hexdig[256];
+
+ static void
+htinit(unsigned char *h, unsigned char *s, int inc)
+{
+ int i, j;
+ for(i = 0; (j = s[i]) !=0; i++)
+ h[j] = i + inc;
+ }
+
+ static void
+hexdig_init(void) /* Use of hexdig_init omitted 20121220 to avoid a */
+ /* race condition when multiple threads are used. */
+{
+#define USC (unsigned char *)
+ htinit(hexdig, USC "0123456789", 0x10);
+ htinit(hexdig, USC "abcdef", 0x10 + 10);
+ htinit(hexdig, USC "ABCDEF", 0x10 + 10);
+ }
+#else
+static unsigned char hexdig[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+#endif
+#endif /* } Need_Hexdig */
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+static int match(const char **sp, const char *t)
+{
+ int c, d;
+ const char *s = *sp;
+
+ while ((d = *t++)) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+}
+
+#ifndef No_Hex_NaN
+static void hexnan(U *rvp, const char **sp)
+{
+ ULong c, x[2];
+ const char *s;
+ int c1, havedig, udx0, xshift;
+
+ /**** if (!hexdig['0']) hexdig_init(); ****/
+ x[0] = x[1] = 0;
+ havedig = xshift = 0;
+ udx0 = 1;
+ s = *sp;
+ /* allow optional initial 0x or 0X */
+ while ((c = *(const unsigned char *)(s + 1)) && c <= ' ')
+ ++s;
+ if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+ s += 2;
+ while ((c = *(const unsigned char *)++s)) {
+ if ((c1 = hexdig[c]))
+ c = c1 & 0xf;
+ else if (c <= ' ') {
+ if (udx0 && havedig) {
+ udx0 = 0;
+ xshift = 1;
+ }
+ continue;
+ }
+#ifdef GDTOA_NON_PEDANTIC_NANCHECK
+ else if (/*(*/ c == ')' && havedig) {
+ *sp = s + 1;
+ break;
+ } else
+ return; /* invalid form: don't change *sp */
+#else
+ else {
+ do {
+ if (/*(*/ c == ')') {
+ *sp = s + 1;
+ break;
+ }
+ } while ((c = *++s));
+ break;
+ }
+#endif
+ havedig = 1;
+ if (xshift) {
+ xshift = 0;
+ x[0] = x[1];
+ x[1] = 0;
+ }
+ if (udx0)
+ x[0] = (x[0] << 4) | (x[1] >> 28);
+ x[1] = (x[1] << 4) | c;
+ }
+ if ((x[0] &= 0xfffff) || x[1]) {
+ word0(rvp) = Exp_mask | x[0];
+ word1(rvp) = x[1];
+ }
+}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#endif
+
+#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/
+static Bigint *increment(Bigint *b MTd)
+{
+ ULong *x, *xe;
+ Bigint *b1;
+
+ x = b->x;
+ xe = x + b->wds;
+ do {
+ if (*x < (ULong)0xffffffffL) {
+ ++*x;
+ return b;
+ }
+ *x++ = 0;
+ } while (x < xe);
+ {
+ if (b->wds >= b->maxwds) {
+ b1 = Balloc(b->k + 1 MTa);
+ Bcopy(b1, b);
+ Bfree(b MTa);
+ b = b1;
+ }
+ b->x[b->wds++] = 1;
+ }
+ return b;
+}
+
+#endif /*}*/
+
+#ifndef NO_HEX_FP /*{*/
+
+static void rshift(Bigint *b, int k)
+{
+ ULong *x, *x1, *xe, y;
+ int n;
+
+ x = x1 = b->x;
+ n = k >> kshift;
+ if (n < b->wds) {
+ xe = x + b->wds;
+ x += n;
+ if (k &= kmask) {
+ n = 32 - k;
+ y = *x++ >> k;
+ while (x < xe) {
+ *x1++ = (y | (*x << n)) & 0xffffffff;
+ y = *x++ >> k;
+ }
+ if ((*x1 = y) != 0)
+ x1++;
+ } else
+ while (x < xe)
+ *x1++ = *x++;
+ }
+ if ((b->wds = x1 - b->x) == 0)
+ b->x[0] = 0;
+}
+
+static ULong any_on(Bigint *b, int k)
+{
+ int n, nwds;
+ ULong *x, *x0, x1, x2;
+
+ x = b->x;
+ nwds = b->wds;
+ n = k >> kshift;
+ if (n > nwds)
+ n = nwds;
+ else if (n < nwds && (k &= kmask)) {
+ x1 = x2 = x[n];
+ x1 >>= k;
+ x1 <<= k;
+ if (x1 != x2)
+ return 1;
+ }
+ x0 = x;
+ x += n;
+ while (x > x0)
+ if (*--x)
+ return 1;
+ return 0;
+}
+
+enum { /* rounding values: same as FLT_ROUNDS */
+ Round_zero = 0,
+ Round_near = 1,
+ Round_up = 2,
+ Round_down = 3
+};
+
+void gethex(const char **sp, U *rvp, int rounding, int sign MTd)
+{
+ Bigint *b;
+ char d;
+ const unsigned char *decpt, *s0, *s, *s1;
+ Long e, e1;
+ ULong L, lostbits, *x;
+ int big, denorm, esign, havedig, k, n, nb, nbits, nz, up, zret;
+#ifdef IBM
+ int j;
+#endif
+ enum {
+#ifdef IEEE_Arith /*{{*/
+ emax = 0x7fe - Bias - P + 1,
+ emin = Emin - P + 1
+#else /*}{*/
+ emin = Emin - P,
+#ifdef VAX
+ emax = 0x7ff - Bias - P +
+ 1
+#endif
+#ifdef IBM
+ emax = 0x7f - Bias - P
+#endif
+#endif /*}}*/
+ };
+#ifdef IEEE_Arith
+ int check_denorm = 0;
+#endif
+#ifdef USE_LOCALE
+ int i;
+#ifdef NO_LOCALE_CACHE
+ const unsigned char *decimalpoint =
+ (unsigned char *)localeconv()->decimal_point;
+#else
+ const unsigned char *decimalpoint;
+ static unsigned char *decimalpoint_cache;
+ if (!(s0 = decimalpoint_cache)) {
+ s0 = (unsigned char *)localeconv()->decimal_point;
+ if ((decimalpoint_cache = (unsigned char *)MALLOC(
+ strlen((const char *)s0) + 1))) {
+ strcpy((char *)decimalpoint_cache, (const char *)s0);
+ s0 = decimalpoint_cache;
+ }
+ }
+ decimalpoint = s0;
+#endif
+#endif
+
+ /**** if (!hexdig['0']) hexdig_init(); ****/
+ havedig = 0;
+ s0 = *(const unsigned char **)sp + 2;
+ while (s0[havedig] == '0')
+ havedig++;
+ s0 += havedig;
+ s = s0;
+ decpt = 0;
+ zret = 0;
+ e = 0;
+ if (hexdig[*s])
+ havedig++;
+ else {
+ zret = 1;
+#ifdef USE_LOCALE
+ for (i = 0; decimalpoint[i]; ++i) {
+ if (s[i] != decimalpoint[i])
+ goto pcheck;
+ }
+ decpt = s += i;
+#else
+ if (*s != '.')
+ goto pcheck;
+ decpt = ++s;
+#endif
+ if (!hexdig[*s])
+ goto pcheck;
+ while (*s == '0')
+ s++;
+ if (hexdig[*s])
+ zret = 0;
+ havedig = 1;
+ s0 = s;
+ }
+ while (hexdig[*s])
+ s++;
+#ifdef USE_LOCALE
+ if (*s == *decimalpoint && !decpt) {
+ for (i = 1; decimalpoint[i]; ++i) {
+ if (s[i] != decimalpoint[i])
+ goto pcheck;
+ }
+ decpt = s += i;
+#else
+ if (*s == '.' && !decpt) {
+ decpt = ++s;
+#endif
+ while (hexdig[*s])
+ s++;
+ } /*}*/
+ if (decpt)
+ e = -(((Long)(s - decpt)) << 2);
+pcheck:
+ s1 = s;
+ big = esign = 0;
+ switch (*s) {
+ case 'p':
+ case 'P':
+ switch (*++s) {
+ case '-':
+ esign = 1;
+ /* no break */
+ case '+':
+ s++;
+ }
+ if ((n = hexdig[*s]) == 0 || n > 0x19) {
+ s = s1;
+ break;
+ }
+ e1 = n - 0x10;
+ while ((n = hexdig[*++s]) != 0 && n <= 0x19) {
+ if (e1 & 0xf8000000)
+ big = 1;
+ e1 = 10 * e1 + n - 0x10;
+ }
+ if (esign)
+ e1 = -e1;
+ e += e1;
+ }
+ *sp = (char *)s;
+ if (!havedig)
+ *sp = (char *)s0 - 1;
+ if (zret)
+ goto retz1;
+ if (big) {
+ if (esign) {
+#ifdef IEEE_Arith
+ switch (rounding) {
+ case Round_up:
+ if (sign)
+ break;
+ goto ret_tiny;
+ case Round_down:
+ if (!sign)
+ break;
+ goto ret_tiny;
+ }
+#endif
+ goto retz;
+#ifdef IEEE_Arith
+ret_tinyf:
+ Bfree(b MTa);
+ret_tiny:
+ Set_errno(ERANGE);
+ word0(rvp) = 0;
+ word1(rvp) = 1;
+ return;
+#endif /* IEEE_Arith */
+ }
+ switch (rounding) {
+ case Round_near:
+ goto ovfl1;
+ case Round_up:
+ if (!sign)
+ goto ovfl1;
+ goto ret_big;
+ case Round_down:
+ if (sign)
+ goto ovfl1;
+ goto ret_big;
+ }
+ret_big:
+ word0(rvp) = Big0;
+ word1(rvp) = Big1;
+ return;
+ }
+ n = s1 - s0 - 1;
+ for (k = 0; n > (1 << (kshift - 2)) - 1; n >>= 1)
+ k++;
+ b = Balloc(k MTa);
+ x = b->x;
+ havedig = n = nz = 0;
+ L = 0;
+#ifdef USE_LOCALE
+ for (i = 0; decimalpoint[i + 1]; ++i)
+ ;
+#endif
+ while (s1 > s0) {
+#ifdef USE_LOCALE
+ if (*--s1 == decimalpoint[i]) {
+ s1 -= i;
+ continue;
+ }
+#else
+ if (*--s1 == '.')
+ continue;
+#endif
+ if ((d = hexdig[*s1]))
+ havedig = 1;
+ else if (!havedig) {
+ e += 4;
+ continue;
+ }
+ if (n == ULbits) {
+ *x++ = L;
+ L = 0;
+ n = 0;
+ }
+ L |= (d & 0x0f) << n;
+ n += 4;
+ }
+ *x++ = L;
+ b->wds = n = x - b->x;
+ nb = ULbits * n - hi0bits(L);
+ nbits = Nbits;
+ lostbits = 0;
+ x = b->x;
+ if (nb > nbits) {
+ n = nb - nbits;
+ if (any_on(b, n)) {
+ lostbits = 1;
+ k = n - 1;
+ if (x[k >> kshift] & 1 << (k & kmask)) {
+ lostbits = 2;
+ if (k > 0 && any_on(b, k))
+ lostbits = 3;
+ }
+ }
+ rshift(b, n);
+ e += n;
+ } else if (nb < nbits) {
+ n = nbits - nb;
+ b = lshift(b, n MTa);
+ e -= n;
+ x = b->x;
+ }
+ if (e > emax) {
+ovfl:
+ Bfree(b MTa);
+ovfl1:
+ Set_errno(ERANGE);
+#ifdef Honor_FLT_ROUNDS
+ switch (rounding) {
+ case Round_zero:
+ goto ret_big;
+ case Round_down:
+ if (!sign)
+ goto ret_big;
+ break;
+ case Round_up:
+ if (sign)
+ goto ret_big;
+ }
+#endif
+ word0(rvp) = Exp_mask;
+ word1(rvp) = 0;
+ return;
+ }
+ denorm = 0;
+ if (e < emin) {
+ denorm = 1;
+ n = emin - e;
+ if (n >= nbits) {
+#ifdef IEEE_Arith /*{*/
+ switch (rounding) {
+ case Round_near:
+ if (n == nbits &&
+ (n < 2 || lostbits || any_on(b, n - 1)))
+ goto ret_tinyf;
+ break;
+ case Round_up:
+ if (!sign)
+ goto ret_tinyf;
+ break;
+ case Round_down:
+ if (sign)
+ goto ret_tinyf;
+ }
+#endif /* } IEEE_Arith */
+ Bfree(b MTa);
+retz:
+ Set_errno(ERANGE);
+retz1:
+ rvp->d = 0.;
+ return;
+ }
+ k = n - 1;
+#ifdef IEEE_Arith
+ if (!k) {
+ switch (rounding) {
+ case Round_near:
+ if (((b->x[0] & 3) == 3) ||
+ (lostbits && (b->x[0] & 1))) {
+ multadd(b, 1, 1 MTa);
+emin_check:
+ if (b->x[1] == (1 << (Exp_shift + 1))) {
+ rshift(b, 1);
+ e = emin;
+ goto normal;
+ }
+ }
+ break;
+ case Round_up:
+ if (!sign && (lostbits || (b->x[0] & 1))) {
+incr_denorm:
+ multadd(b, 1, 2 MTa);
+ check_denorm = 1;
+ lostbits = 0;
+ goto emin_check;
+ }
+ break;
+ case Round_down:
+ if (sign && (lostbits || (b->x[0] & 1)))
+ goto incr_denorm;
+ break;
+ }
+ }
+#endif
+ if (lostbits)
+ lostbits = 1;
+ else if (k > 0)
+ lostbits = any_on(b, k);
+#ifdef IEEE_Arith
+ else if (check_denorm)
+ goto no_lostbits;
+#endif
+ if (x[k >> kshift] & 1 << (k & kmask))
+ lostbits |= 2;
+#ifdef IEEE_Arith
+no_lostbits:
+#endif
+ nbits -= n;
+ rshift(b, n);
+ e = emin;
+ }
+ if (lostbits) {
+ up = 0;
+ switch (rounding) {
+ case Round_zero:
+ break;
+ case Round_near:
+ if (lostbits & 2 && (lostbits & 1) | (x[0] & 1))
+ up = 1;
+ break;
+ case Round_up:
+ up = 1 - sign;
+ break;
+ case Round_down:
+ up = sign;
+ }
+ if (up) {
+ k = b->wds;
+ b = increment(b MTa);
+ x = b->x;
+ if (!denorm &&
+ (b->wds > k || ((n = nbits & kmask) != 0 &&
+ hi0bits(x[k - 1]) < 32 - n))) {
+ rshift(b, 1);
+ if (++e > Emax)
+ goto ovfl;
+ }
+ }
+ }
+#ifdef IEEE_Arith
+ if (denorm)
+ word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0;
+ else {
+normal:
+ word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20);
+ }
+ word1(rvp) = b->x[0];
+#endif
+#ifdef IBM
+ if ((j = e & 3)) {
+ k = b->x[0] & ((1 << j) - 1);
+ rshift(b, j);
+ if (k) {
+ switch (rounding) {
+ case Round_up:
+ if (!sign)
+ increment(b);
+ break;
+ case Round_down:
+ if (sign)
+ increment(b);
+ break;
+ case Round_near:
+ j = 1 << (j - 1);
+ if (k & j && ((k & (j - 1)) | lostbits))
+ increment(b);
+ }
+ }
+ }
+ e >>= 2;
+ word0(rvp) = b->x[1] | ((e + 65 + 13) << 24);
+ word1(rvp) = b->x[0];
+#endif
+#ifdef VAX
+ /* The next two lines ignore swap of low- and high-order 2 bytes. */
+ /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */
+ /* word1(rvp) = b->x[0]; */
+ word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) |
+ (b->x[1] << 16);
+ word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16);
+#endif
+ Bfree(b MTa);
+}
+#endif /*!NO_HEX_FP}*/
+
+static int dshift(Bigint *b, int p2)
+{
+ int rv = hi0bits(b->x[b->wds - 1]) - 4;
+ if (p2 > 0)
+ rv -= p2;
+ return rv & kmask;
+}
+
+static int quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+#ifdef Pack_32
+ ULong si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+#ifdef NO_STRTOD_BIGCOMP
+ /*debug*/ if (q > 9)
+#else
+ /* An oversized q is possible when quorem is called from bigcomp and */
+ /* the input is near, e.g., twice the smallest denormalized number. */
+ /*debug*/ if (q > 15)
+#endif
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/
+static double sulp(U *x, BCinfo *bc)
+{
+ U u;
+ double rv;
+ int i;
+
+ rv = ulp(x);
+ if (!bc->scale ||
+ (i = 2 * P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0)
+ return rv; /* Is there an example where i <= 0 ? */
+ word0(&u) = Exp_1 + (i << Exp_shift);
+ word1(&u) = 0;
+ return rv * u.d;
+}
+#endif /*}*/
+
+#ifndef NO_STRTOD_BIGCOMP
+static void bigcomp(U *rv, const char *s0, BCinfo *bc MTd)
+{
+ Bigint *b, *d;
+ int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase;
+
+ dsign = bc->dsign;
+ nd = bc->nd;
+ nd0 = bc->nd0;
+ p5 = nd + bc->e0 - 1;
+ speccase = 0;
+#ifndef Sudden_Underflow
+ if (rv->d == 0.) { /* special case: value near underflow-to-zero */
+ /* threshold was rounded to zero */
+ b = i2b(1 MTa);
+ p2 = Emin - P + 1;
+ bbits = 1;
+#ifdef Avoid_Underflow
+ word0(rv) = (P + 2) << Exp_shift;
+#else
+ word1(rv) = 1;
+#endif
+ i = 0;
+#ifdef Honor_FLT_ROUNDS
+ if (bc->rounding == 1)
+#endif
+ {
+ speccase = 1;
+ --p2;
+ dsign = 0;
+ goto have_i;
+ }
+ } else
+#endif
+ b = d2b(rv, &p2, &bbits MTa);
+#ifdef Avoid_Underflow
+ p2 -= bc->scale;
+#endif
+ /* floor(log2(rv)) == bbits - 1 + p2 */
+ /* Check for denormal case. */
+ i = P - bbits;
+ if (i > (j = P - Emin - 1 + p2)) {
+#ifdef Sudden_Underflow
+ Bfree(b MTa);
+ b = i2b(1 MTa);
+ p2 = Emin;
+ i = P - 1;
+#ifdef Avoid_Underflow
+ word0(rv) = (1 + bc->scale) << Exp_shift;
+#else
+ word0(rv) = Exp_msk1;
+#endif
+ word1(rv) = 0;
+#else
+ i = j;
+#endif
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (bc->rounding != 1) {
+ if (i > 0)
+ b = lshift(b, i MTa);
+ if (dsign)
+ b = increment(b MTa);
+ } else
+#endif
+ {
+ b = lshift(b, ++i MTa);
+ b->x[0] |= 1;
+ }
+#ifndef Sudden_Underflow
+have_i:
+#endif
+ p2 -= p5 + i;
+ d = i2b(1 MTa);
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ */
+ if (p5 > 0)
+ d = pow5mult(d, p5 MTa);
+ else if (p5 < 0)
+ b = pow5mult(b, -p5 MTa);
+ if (p2 > 0) {
+ b2 = p2;
+ d2 = 0;
+ } else {
+ b2 = 0;
+ d2 = -p2;
+ }
+ i = dshift(d, d2);
+ if ((b2 += i) > 0)
+ b = lshift(b, b2 MTa);
+ if ((d2 += i) > 0)
+ d = lshift(d, d2 MTa);
+
+ /* Now b/d = exactly half-way between the two floating-point values */
+ /* on either side of the input string. Compute first digit of b/d. */
+
+ if (!(dig = quorem(b, d))) {
+ b = multadd(b, 10, 0 MTa); /* very unlikely */
+ dig = quorem(b, d);
+ }
+
+ /* Compare b/d with s0 */
+
+ for (i = 0; i < nd0;) {
+ if ((dd = s0[i++] - '0' - dig))
+ goto ret;
+ if (!b->x[0] && b->wds == 1) {
+ if (i < nd)
+ dd = 1;
+ goto ret;
+ }
+ b = multadd(b, 10, 0 MTa);
+ dig = quorem(b, d);
+ }
+ for (j = bc->dp1; i++ < nd;) {
+ if ((dd = s0[j++] - '0' - dig))
+ goto ret;
+ if (!b->x[0] && b->wds == 1) {
+ if (i < nd)
+ dd = 1;
+ goto ret;
+ }
+ b = multadd(b, 10, 0 MTa);
+ dig = quorem(b, d);
+ }
+ if (dig > 0 || b->x[0] || b->wds > 1)
+ dd = -1;
+ret:
+ Bfree(b MTa);
+ Bfree(d MTa);
+#ifdef Honor_FLT_ROUNDS
+ if (bc->rounding != 1) {
+ if (dd < 0) {
+ if (bc->rounding == 0) {
+ if (!dsign)
+ goto retlow1;
+ } else if (dsign)
+ goto rethi1;
+ } else if (dd > 0) {
+ if (bc->rounding == 0) {
+ if (dsign)
+ goto rethi1;
+ goto ret1;
+ }
+ if (!dsign)
+ goto rethi1;
+ dval(rv) += 2. * sulp(rv, bc);
+ } else {
+ bc->inexact = 0;
+ if (dsign)
+ goto rethi1;
+ }
+ } else
+#endif
+ if (speccase) {
+ if (dd <= 0)
+ rv->d = 0.;
+ } else if (dd < 0) {
+ if (!dsign) /* does not happen for round-near */
+retlow1:
+ dval(rv) -= sulp(rv, bc);
+ } else if (dd > 0) {
+ if (dsign) {
+rethi1:
+ dval(rv) += sulp(rv, bc);
+ }
+ } else {
+ /* Exact half-way case: apply round-even rule. */
+ if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <=
+ 0) {
+ i = 1 - j;
+ if (i <= 31) {
+ if (word1(rv) & (0x1 << i))
+ goto odd;
+ } else if (word0(rv) & (0x1 << (i - 32)))
+ goto odd;
+ } else if (word1(rv) & 1) {
+odd:
+ if (dsign)
+ goto rethi1;
+ goto retlow1;
+ }
+ }
+
+#ifdef Honor_FLT_ROUNDS
+ret1:
+#endif
+ return;
+}
+#endif /* NO_STRTOD_BIGCOMP */
+
+double strtod(const char *s00, char **se)
+{
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
+ int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign;
+ const char *s, *s0, *s1;
+ double aadj, aadj1;
+ Long L;
+ U aadj2, adj, rv, rv0;
+ ULong y, z;
+ BCinfo bc;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef USE_BF96
+ ULLong bhi, blo, brv, t00, t01, t02, t10, t11, terv, tg, tlo, yz;
+ const BF96 *p10;
+ int bexact, erv;
+#endif
+#ifdef Avoid_Underflow
+ ULong Lsb, Lsb1;
+#endif
+#ifdef SET_INEXACT
+ int oldinexact;
+#endif
+#ifndef NO_STRTOD_BIGCOMP
+ int req_bigcomp = 0;
+#endif
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+ bc.rounding = Flt_Rounds;
+#else /*}{*/
+ bc.rounding = 1;
+ switch (fegetround()) {
+ case FE_TOWARDZERO:
+ bc.rounding = 0;
+ break;
+ case FE_UPWARD:
+ bc.rounding = 2;
+ break;
+ case FE_DOWNWARD:
+ bc.rounding = 3;
+ }
+#endif /*}}*/
+#endif /*}*/
+#ifdef USE_LOCALE
+ const char *s2;
+#endif
+
+ sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0;
+ dval(&rv) = 0.;
+ for (s = s00;; s++)
+ switch (*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ goto ret0;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+break2:
+ if (*s == '0') {
+#ifndef NO_HEX_FP /*{*/
+ switch (s[1]) {
+ case 'x':
+ case 'X':
+#ifdef Honor_FLT_ROUNDS
+ gethex(&s, &rv, bc.rounding, sign MTb);
+#else
+ gethex(&s, &rv, 1, sign MTb);
+#endif
+ goto ret;
+ }
+#endif /*}*/
+ nz0 = 1;
+ while (*++s == '0')
+ ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ nd = nf = 0;
+#ifdef USE_BF96
+ yz = 0;
+ for (; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 19)
+ yz = 10 * yz + c - '0';
+#else
+ y = z = 0;
+ for (; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10 * y + c - '0';
+ else if (nd < DBL_DIG + 2)
+ z = 10 * z + c - '0';
+#endif
+ nd0 = nd;
+ bc.dp0 = bc.dp1 = s - s0;
+ for (s1 = s; s1 > s0 && *--s1 == '0';)
+ ++nz1;
+#ifdef USE_LOCALE
+ s1 = localeconv()->decimal_point;
+ if (c == *s1) {
+ c = '.';
+ if (*++s1) {
+ s2 = s;
+ for (;;) {
+ if (*++s2 != *s1) {
+ c = 0;
+ break;
+ }
+ if (!*++s1) {
+ s = s2;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ if (c == '.') {
+ c = *++s;
+ bc.dp1 = s - s0;
+ bc.dplen = bc.dp1 - bc.dp0;
+ if (!nd) {
+ for (; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ bc.dp0 = s0 - s;
+ bc.dp1 = bc.dp0 + bc.dplen;
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for (; c >= '0' && c <= '9'; c = *++s) {
+have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ i = 1;
+#ifdef USE_BF96
+ for (; i < nz; ++i) {
+ if (++nd <= 19)
+ yz *= 10;
+ }
+ if (++nd <= 19)
+ yz = 10 * yz + c;
+#else
+ for (; i < nz; ++i) {
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 2)
+ z *= 10;
+ }
+ if (nd++ < 9)
+ y = 10 * y + c;
+ else if (nd <= DBL_DIG + 2)
+ z = 10 * z + c;
+#endif
+ nz = nz1 = 0;
+ }
+ }
+ }
+dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ goto ret0;
+ }
+ s00 = s;
+ esign = 0;
+ switch (c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while (c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ while ((c = *++s) >= '0' && c <= '9') {
+ if (L <= 19999)
+ L = 10 * L + c - '0';
+ }
+ if (L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ } else
+ e = 0;
+ } else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK /*{*/
+ /* Check for Nan and Infinity */
+ if (!bc.dplen)
+ switch (c) {
+ case 'i':
+ case 'I':
+ if (match(&s, "nf")) {
+ --s;
+ if (!match(&s, "inity"))
+ ++s;
+ word0(&rv) = 0x7ff00000;
+ word1(&rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(&rv) = NAN_WORD0;
+ word1(&rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+ if (*s == '(') /*)*/
+ hexnan(&rv, &s);
+#endif
+ goto ret;
+ }
+ }
+#endif /*} INFNAN_CHECK */
+ret0:
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+ bc.e0 = e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+#ifndef USE_BF96
+ k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2;
+ dval(&rv) = y;
+ if (k > 9) {
+#ifdef SET_INEXACT
+ if (k > DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+ dval(&rv) = tens[k - 9] * dval(&rv) + z;
+ }
+#endif
+ bd0 = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+ && Flt_Rounds == 1
+#endif
+#endif
+ ) {
+#ifdef USE_BF96
+ dval(&rv) = yz;
+#endif
+ if (!e)
+ goto ret;
+#ifndef ROUND_BIASED_without_Round_Up
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+#ifdef SET_INEXACT
+ bc.inexact = 0;
+ oldinexact = 1;
+#endif
+#ifdef VAX
+ goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv.d = -rv.d;
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+ goto ret;
+#endif
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+#ifdef SET_INEXACT
+ bc.inexact = 0;
+ oldinexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv.d = -rv.d;
+ sign = 0;
+ }
+#endif
+ e -= i;
+ dval(&rv) *= tens[i];
+#ifdef VAX
+ /* VAX exponent range is so narrow we must
+ * worry about overflow here...
+ */
+vax_ovfl_check:
+ word0(&rv) -= P * Exp_msk1;
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+ if ((word0(&rv) & Exp_mask) >
+ Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P))
+ goto ovfl;
+ word0(&rv) += P * Exp_msk1;
+#else
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+#endif
+ goto ret;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+#ifdef SET_INEXACT
+ bc.inexact = 0;
+ oldinexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv.d = -rv.d;
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+ goto ret;
+ }
+#endif
+#endif /* ROUND_BIASED_without_Round_Up */
+ }
+#ifdef USE_BF96
+ k = nd < 19 ? nd : 19;
+#endif
+ e1 += nd - k; /* scale factor = 10^e1 */
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+ bc.inexact = 1;
+#ifndef USE_BF96
+ if (k <= DBL_DIG)
+#endif
+ oldinexact = get_inexact();
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if (bc.rounding >= 2) {
+ if (sign)
+ bc.rounding = bc.rounding == 2 ? 0 : 2;
+ else if (bc.rounding != 2)
+ bc.rounding = 0;
+ }
+#endif
+#endif /*IEEE_Arith*/
+
+#ifdef USE_BF96 /*{*/
+ Debug(++dtoa_stats[0]);
+ i = e1 + 342;
+ if (i < 0)
+ goto undfl;
+ if (i > 650)
+ goto ovfl;
+ p10 = &pten[i];
+ brv = yz;
+ /* shift brv left, with i = number of bits shifted */
+ i = 0;
+ if (!(brv & 0xffffffff00000000ull)) {
+ i = 32;
+ brv <<= 32;
+ }
+ if (!(brv & 0xffff000000000000ull)) {
+ i += 16;
+ brv <<= 16;
+ }
+ if (!(brv & 0xff00000000000000ull)) {
+ i += 8;
+ brv <<= 8;
+ }
+ if (!(brv & 0xf000000000000000ull)) {
+ i += 4;
+ brv <<= 4;
+ }
+ if (!(brv & 0xc000000000000000ull)) {
+ i += 2;
+ brv <<= 2;
+ }
+ if (!(brv & 0x8000000000000000ull)) {
+ i += 1;
+ brv <<= 1;
+ }
+ erv = (64 + 0x3fe) + p10->e - i;
+ if (erv <= 0 && nd > 19)
+ goto many_digits; /* denormal: may need to look at all digits */
+ bhi = brv >> 32;
+ blo = brv & 0xffffffffull;
+ /* Unsigned 32-bit ints lie in [0,2^32-1] and */
+ /* unsigned 64-bit ints lie in [0, 2^64-1]. The product of two unsigned
+ */
+ /* 32-bit ints is <= 2^64 - 2*2^32-1 + 1 = 2^64 - 1 - 2*(2^32 - 1), so
+ */
+ /* we can add two unsigned 32-bit ints to the product of two such ints,
+ */
+ /* and 64 bits suffice to contain the result. */
+ t01 = bhi * p10->b1;
+ t10 = blo * p10->b0 + (t01 & 0xffffffffull);
+ t00 = bhi * p10->b0 + (t01 >> 32) + (t10 >> 32);
+ if (t00 & 0x8000000000000000ull) {
+ if ((t00 & 0x3ff) && (~t00 & 0x3fe)) { /* unambiguous result? */
+ if (nd > 19 &&
+ ((t00 + (1 << i) + 2) & 0x400) ^ (t00 & 0x400))
+ goto many_digits;
+ if (erv <= 0)
+ goto denormal;
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround;
+ case 2:
+ goto roundup;
+ }
+#endif
+ if (t00 & 0x400 && t00 & 0xbff)
+ goto roundup;
+ goto noround;
+ }
+ } else {
+ if ((t00 & 0x1ff) && (~t00 & 0x1fe)) { /* unambiguous result? */
+ if (nd > 19 &&
+ ((t00 + (1 << i) + 2) & 0x200) ^ (t00 & 0x200))
+ goto many_digits;
+ if (erv <= 1)
+ goto denormal1;
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround1;
+ case 2:
+ goto roundup1;
+ }
+#endif
+ if (t00 & 0x200)
+ goto roundup1;
+ goto noround1;
+ }
+ }
+ /* 3 multiplies did not suffice; try a 96-bit approximation */
+ Debug(++dtoa_stats[1]);
+ t02 = bhi * p10->b2;
+ t11 = blo * p10->b1 + (t02 & 0xffffffffull);
+ bexact = 1;
+ if (e1 < 0 || e1 > 41 || (t10 | t11) & 0xffffffffull || nd > 19)
+ bexact = 0;
+ tlo = (t10 & 0xffffffffull) + (t02 >> 32) + (t11 >> 32);
+ if (!bexact && (tlo + 0x10) >> 32 > tlo >> 32)
+ goto many_digits;
+ t00 += tlo >> 32;
+ if (t00 & 0x8000000000000000ull) {
+ if (erv <= 0) { /* denormal result */
+ if (nd >= 20 || !((tlo & 0xfffffff0) | (t00 & 0x3ff)))
+ goto many_digits;
+denormal:
+ if (erv <= -52) {
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto undfl;
+ case 2:
+ goto tiniest;
+ }
+#endif
+ if (erv < -52 || !(t00 & 0x7fffffffffffffffull))
+ goto undfl;
+ goto tiniest;
+ }
+ tg = 1ull << (11 - erv);
+ t00 &= ~(tg - 1); /* clear low bits */
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround_den;
+ case 2:
+ goto roundup_den;
+ }
+#endif
+ if (t00 & tg) {
+#ifdef Honor_FLT_ROUNDS
+roundup_den:
+#endif
+ t00 += tg << 1;
+ if (!(t00 & 0x8000000000000000ull)) {
+ if (++erv > 0)
+ goto smallest_normal;
+ t00 = 0x8000000000000000ull;
+ }
+ }
+#ifdef Honor_FLT_ROUNDS
+noround_den:
+#endif
+ LLval(&rv) = t00 >> (12 - erv);
+ Set_errno(ERANGE);
+ goto ret;
+ }
+ if (bexact) {
+#ifdef SET_INEXACT
+ if (!(t00 & 0x7ff) && !(tlo & 0xffffffffull)) {
+ bc.inexact = 0;
+ goto noround;
+ }
+#endif
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 2:
+ if (t00 & 0x7ff)
+ goto roundup;
+ case 0:
+ goto noround;
+ }
+#endif
+ if (t00 & 0x400 && (tlo & 0xffffffff) | (t00 & 0xbff))
+ goto roundup;
+ goto noround;
+ }
+ if ((tlo & 0xfffffff0) | (t00 & 0x3ff) &&
+ (nd <= 19 ||
+ ((t00 + (1ull << i)) & 0xfffffffffffffc00ull) ==
+ (t00 & 0xfffffffffffffc00ull))) {
+ /* Unambiguous result. */
+ /* If nd > 19, then incrementing the 19th digit */
+ /* does not affect rv. */
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround;
+ case 2:
+ goto roundup;
+ }
+#endif
+ if (t00 & 0x400) { /* round up */
+roundup:
+ t00 += 0x800;
+ if (!(t00 & 0x8000000000000000ull)) {
+ /* rounded up to a power of 2 */
+ if (erv >= 0x7fe)
+ goto ovfl;
+ terv = erv + 1;
+ LLval(&rv) = terv << 52;
+ goto ret;
+ }
+ }
+noround:
+ if (erv >= 0x7ff)
+ goto ovfl;
+ terv = erv;
+ LLval(&rv) = (terv << 52) |
+ ((t00 & 0x7ffffffffffff800ull) >> 11);
+ goto ret;
+ }
+ } else {
+ if (erv <= 1) { /* denormal result */
+ if (nd >= 20 || !((tlo & 0xfffffff0) | (t00 & 0x1ff)))
+ goto many_digits;
+denormal1:
+ if (erv <= -51) {
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto undfl;
+ case 2:
+ goto tiniest;
+ }
+#endif
+ if (erv < -51 || !(t00 & 0x3fffffffffffffffull))
+ goto undfl;
+tiniest:
+ LLval(&rv) = 1;
+ Set_errno(ERANGE);
+ goto ret;
+ }
+ tg = 1ull << (11 - erv);
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround1_den;
+ case 2:
+ goto roundup1_den;
+ }
+#endif
+ if (t00 & tg) {
+#ifdef Honor_FLT_ROUNDS
+roundup1_den:
+#endif
+ if (0x8000000000000000ull &
+ (t00 += (tg << 1)) &&
+ erv == 1) {
+smallest_normal:
+ LLval(&rv) = 0x0010000000000000ull;
+ goto ret;
+ }
+ }
+#ifdef Honor_FLT_ROUNDS
+noround1_den:
+#endif
+ if (erv <= -52)
+ goto undfl;
+ LLval(&rv) = t00 >> (12 - erv);
+ Set_errno(ERANGE);
+ goto ret;
+ }
+ if (bexact) {
+#ifdef SET_INEXACT
+ if (!(t00 & 0x3ff) && !(tlo & 0xffffffffull)) {
+ bc.inexact = 0;
+ goto noround1;
+ }
+#endif
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 2:
+ if (t00 & 0x3ff)
+ goto roundup1;
+ case 0:
+ goto noround1;
+ }
+#endif
+ if (t00 & 0x200 && (t00 & 0x5ff || tlo))
+ goto roundup1;
+ goto noround1;
+ }
+ if ((tlo & 0xfffffff0) | (t00 & 0x1ff) &&
+ (nd <= 19 ||
+ ((t00 + (1ull << i)) & 0x7ffffffffffffe00ull) ==
+ (t00 & 0x7ffffffffffffe00ull))) {
+ /* Unambiguous result. */
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0:
+ goto noround1;
+ case 2:
+ goto roundup1;
+ }
+#endif
+ if (t00 & 0x200) { /* round up */
+roundup1:
+ t00 += 0x400;
+ if (!(t00 & 0x4000000000000000ull)) {
+ /* rounded up to a power of 2 */
+ if (erv >= 0x7ff)
+ goto ovfl;
+ terv = erv;
+ LLval(&rv) = terv << 52;
+ goto ret;
+ }
+ }
+noround1:
+ if (erv >= 0x800)
+ goto ovfl;
+ terv = erv - 1;
+ LLval(&rv) = (terv << 52) |
+ ((t00 & 0x3ffffffffffffc00ull) >> 10);
+ goto ret;
+ }
+ }
+many_digits:
+ Debug(++dtoa_stats[2]);
+ if (nd > 17) {
+ if (nd > 18) {
+ yz /= 100;
+ e1 += 2;
+ } else {
+ yz /= 10;
+ e1 += 1;
+ }
+ y = yz / 100000000;
+ } else if (nd > 9) {
+ i = nd - 9;
+ y = (yz >> i) / pfive[i - 1];
+ } else
+ y = yz;
+ dval(&rv) = yz;
+#endif /*}*/
+
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+ bc.scale = 0;
+#endif
+#endif /*IEEE_Arith*/
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15))
+ dval(&rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+ /* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 0: /* toward 0 */
+ case 3: /* toward -infinity */
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ break;
+ default:
+ word0(&rv) = Exp_mask;
+ word1(&rv) = 0;
+ }
+#else /*Honor_FLT_ROUNDS*/
+ word0(&rv) = Exp_mask;
+ word1(&rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+ /* set overflow bit */
+ dval(&rv0) = 1e300;
+ dval(&rv0) *= dval(&rv0);
+#endif
+#else /*IEEE_Arith*/
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+#endif /*IEEE_Arith*/
+range_err:
+ if (bd0) {
+ Bfree(bb MTb);
+ Bfree(bd MTb);
+ Bfree(bs MTb);
+ Bfree(bd0 MTb);
+ Bfree(delta MTb);
+ }
+ Set_errno(ERANGE);
+ goto ret;
+ }
+ e1 >>= 4;
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(&rv) -= P * Exp_msk1;
+ dval(&rv) *= bigtens[j];
+ if ((z = word0(&rv) & Exp_mask) >
+ Exp_msk1 * (DBL_MAX_EXP + Bias - P))
+ goto ovfl;
+ if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ } else
+ word0(&rv) += P * Exp_msk1;
+ }
+ } else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15))
+ dval(&rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+#ifdef Avoid_Underflow
+ if (e1 & Scale_Bit)
+ bc.scale = 2 * P;
+ for (j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= tinytens[j];
+ if (bc.scale &&
+ (j = 2 * P + 1 -
+ ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; clear j low bits */
+ if (j >= 32) {
+ if (j > 54)
+ goto undfl;
+ word1(&rv) = 0;
+ if (j >= 53)
+ word0(&rv) = (P + 2) * Exp_msk1;
+ else
+ word0(&rv) &= 0xffffffff
+ << (j - 32);
+ } else
+ word1(&rv) &= 0xffffffff << j;
+ }
+#else
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= tinytens[j];
+ /* The last multiplication could underflow. */
+ dval(&rv0) = dval(&rv);
+ dval(&rv) *= tinytens[j];
+ if (!dval(&rv)) {
+ dval(&rv) = 2. * dval(&rv0);
+ dval(&rv) *= tinytens[j];
+#endif
+ if (!dval(&rv)) {
+undfl:
+ dval(&rv) = 0.;
+#ifdef Honor_FLT_ROUNDS
+ if (bc.rounding == 2)
+ word1(&rv) = 1;
+#endif
+ goto range_err;
+ }
+#ifndef Avoid_Underflow
+ word0(&rv) = Tiny0;
+ word1(&rv) = Tiny1;
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+#endif
+ }
+}
+
+/* Now the hard part -- adjusting rv to the correct value.*/
+
+/* Put digits into bd: true value = bd * 10^e */
+
+bc.nd = nd - nz1;
+#ifndef NO_STRTOD_BIGCOMP
+bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */
+/* to silence an erroneous warning about bc.nd0 */
+/* possibly not being initialized. */
+if (nd > strtod_diglim) {
+ /* ASSERT(strtod_diglim >= 18); 18 == one more than the */
+ /* minimum number of decimal digits to distinguish double values */
+ /* in IEEE arithmetic. */
+ i = j = 18;
+ if (i > nd0)
+ j += bc.dplen;
+ for (;;) {
+ if (--j < bc.dp1 && j >= bc.dp0)
+ j = bc.dp0 - 1;
+ if (s0[j] != '0')
+ break;
+ --i;
+ }
+ e += nd - i;
+ nd = i;
+ if (nd0 > nd)
+ nd0 = nd;
+ if (nd < 9) { /* must recompute y */
+ y = 0;
+ for (i = 0; i < nd0; ++i)
+ y = 10 * y + s0[i] - '0';
+ for (j = bc.dp1; i < nd; ++i)
+ y = 10 * y + s0[j++] - '0';
+ }
+}
+#endif
+bd0 = s2b(s0, nd0, nd, y, bc.dplen MTb);
+
+for (;;) {
+ bd = Balloc(bd0->k MTb);
+ Bcopy(bd, bd0);
+ bb = d2b(&rv, &bbe, &bbbits MTb); /* rv = bb * 2^bbe */
+ bs = i2b(1 MTb);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ } else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+ if (bc.rounding != 1)
+ bs2++;
+#endif
+#ifdef Avoid_Underflow
+ Lsb = LSB;
+ Lsb1 = 0;
+ j = bbe - bc.scale;
+ i = j + bbbits - 1; /* logb(rv) */
+ j = P + 1 - bbbits;
+ if (i < Emin) { /* denormal */
+ i = Emin - i;
+ j -= i;
+ if (i < 32)
+ Lsb <<= i;
+ else if (i < 52)
+ Lsb1 = Lsb << (i - 32);
+ else
+ Lsb1 = Exp_mask;
+ }
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+ j = 1 + 4 * P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+ j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+ j = bbe;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ bb2 += j;
+ bd2 += j;
+#ifdef Avoid_Underflow
+ bd2 += bc.scale;
+#endif
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5 MTb);
+ bb1 = mult(bs, bb MTb);
+ Bfree(bb MTb);
+ bb = bb1;
+ }
+ if (bb2 > 0)
+ bb = lshift(bb, bb2 MTb);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5 MTb);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2 MTb);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2 MTb);
+ delta = diff(bb, bd MTb);
+ bc.dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+#ifndef NO_STRTOD_BIGCOMP /*{*/
+ if (bc.nd > nd && i <= 0) {
+ if (bc.dsign) {
+ /* Must use bigcomp(). */
+ req_bigcomp = 1;
+ break;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (bc.rounding != 1) {
+ if (i < 0) {
+ req_bigcomp = 1;
+ break;
+ }
+ } else
+#endif
+ i = -1; /* Discarded digits make delta smaller. */
+ }
+#endif /*}*/
+#ifdef Honor_FLT_ROUNDS /*{*/
+ if (bc.rounding != 1) {
+ if (i < 0) {
+ /* Error is less than an ulp */
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact */
+#ifdef SET_INEXACT
+ bc.inexact = 0;
+#endif
+ break;
+ }
+ if (bc.rounding) {
+ if (bc.dsign) {
+ adj.d = 1.;
+ goto apply_adj;
+ }
+ } else if (!bc.dsign) {
+ adj.d = -1.;
+ if (!word1(&rv) && !(word0(&rv) & Frac_mask)) {
+ y = word0(&rv) & Exp_mask;
+#ifdef Avoid_Underflow
+ if (!bc.scale || y > 2 * P * Exp_msk1)
+#else
+ if (y)
+#endif
+ {
+ delta = lshift(delta,
+ Log2P MTb);
+ if (cmp(delta, bs) <= 0)
+ adj.d = -0.5;
+ }
+ }
+apply_adj:
+#ifdef Avoid_Underflow /*{*/
+ if (bc.scale && (y = word0(&rv) & Exp_mask) <=
+ 2 * P * Exp_msk1)
+ word0(&adj) +=
+ (2 * P + 1) * Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) {
+ word0(&rv) += P * Exp_msk1;
+ dval(&rv) += adj.d * ulp(dval(&rv));
+ word0(&rv) -= P * Exp_msk1;
+ } else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow}*/
+ dval(&rv) += adj.d * ulp(&rv);
+ }
+ break;
+ }
+ adj.d = ratio(delta, bs);
+ if (adj.d < 1.)
+ adj.d = 1.;
+ if (adj.d <= 0x7ffffffe) {
+ /* adj = rounding ? ceil(adj) : floor(adj); */
+ y = adj.d;
+ if (y != adj.d) {
+ if (!((bc.rounding >> 1) ^ bc.dsign))
+ y++;
+ adj.d = y;
+ }
+ }
+#ifdef Avoid_Underflow /*{*/
+ if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
+ word0(&adj) += (2 * P + 1) * Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) {
+ word0(&rv) += P * Exp_msk1;
+ adj.d *= ulp(dval(&rv));
+ if (bc.dsign)
+ dval(&rv) += adj.d;
+ else
+ dval(&rv) -= adj.d;
+ word0(&rv) -= P * Exp_msk1;
+ goto cont;
+ }
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow}*/
+ adj.d *= ulp(&rv);
+ if (bc.dsign) {
+ if (word0(&rv) == Big0 && word1(&rv) == Big1)
+ goto ovfl;
+ dval(&rv) += adj.d;
+ } else
+ dval(&rv) -= adj.d;
+ goto cont;
+ }
+#endif /*}Honor_FLT_ROUNDS*/
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
+#ifdef IEEE_Arith /*{*/
+#ifdef Avoid_Underflow
+ || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1
+#else
+ || (word0(&rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif /*}*/
+ ) {
+#ifdef SET_INEXACT
+ if (!delta->x[0] && delta->wds <= 1)
+ bc.inexact = 0;
+#endif
+ break;
+ }
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact result */
+#ifdef SET_INEXACT
+ bc.inexact = 0;
+#endif
+ break;
+ }
+ delta = lshift(delta, Log2P MTb);
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (bc.dsign) {
+ if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 &&
+ word1(&rv) ==
+ (
+#ifdef Avoid_Underflow
+ (bc.scale &&
+ (y = word0(&rv) & Exp_mask) <=
+ 2 * P * Exp_msk1) ?
+ (0xffffffff &
+ (0xffffffff
+ << (2 * P + 1 -
+ (y >> Exp_shift)))) :
+#endif
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ if (word0(&rv) == Big0 && word1(&rv) == Big1)
+ goto ovfl;
+ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1
+#ifdef IBM
+ | Exp_msk1 >> 4
+#endif
+ ;
+ word1(&rv) = 0;
+#ifdef Avoid_Underflow
+ bc.dsign = 0;
+#endif
+ break;
+ }
+ } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+ L = word0(&rv) & Exp_mask;
+#ifdef IBM
+ if (L < Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+ if (L <= (bc.scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1))
+#else
+ if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+ {
+ if (bc.nd > nd) {
+ bc.uflchk = 1;
+ break;
+ }
+ goto undfl;
+ }
+ L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+ if (bc.scale) {
+ L = word0(&rv) & Exp_mask;
+ if (L <=
+ (2 * P + 1) * Exp_msk1) {
+ if (L >
+ (P + 2) * Exp_msk1)
+ /* round even
+ * ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest
+ * denormal */
+ if (bc.nd > nd) {
+ bc.uflchk = 1;
+ break;
+ }
+ goto undfl;
+ }
+ }
+#endif /*Avoid_Underflow*/
+ L = (word0(&rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+ word0(&rv) = L | Bndry_mask1;
+ word1(&rv) = 0xffffffff;
+#ifdef IBM
+ goto cont;
+#else
+#ifndef NO_STRTOD_BIGCOMP
+ if (bc.nd > nd)
+ goto cont;
+#endif
+ break;
+#endif
+ }
+#ifndef ROUND_BIASED
+#ifdef Avoid_Underflow
+ if (Lsb1) {
+ if (!(word0(&rv) & Lsb1))
+ break;
+ } else if (!(word1(&rv) & Lsb))
+ break;
+#else
+ if (!(word1(&rv) & LSB))
+ break;
+#endif
+#endif
+ if (bc.dsign)
+#ifdef Avoid_Underflow
+ dval(&rv) += sulp(&rv, &bc);
+#else
+ dval(&rv) += ulp(&rv);
+#endif
+#ifndef ROUND_BIASED
+ else {
+#ifdef Avoid_Underflow
+ dval(&rv) -= sulp(&rv, &bc);
+#else
+ dval(&rv) -= ulp(&rv);
+#endif
+#ifndef Sudden_Underflow
+ if (!dval(&rv)) {
+ if (bc.nd > nd) {
+ bc.uflchk = 1;
+ break;
+ }
+ goto undfl;
+ }
+#endif
+ }
+#ifdef Avoid_Underflow
+ bc.dsign = 1 - bc.dsign;
+#endif
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (bc.dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(&rv) == Tiny1 && !word0(&rv)) {
+ if (bc.nd > nd) {
+ bc.uflchk = 1;
+ break;
+ }
+ goto undfl;
+ }
+#endif
+ aadj = 1.;
+ aadj1 = -1.;
+ } else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2. / FLT_RADIX)
+ aadj = 1. / FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ } else {
+ aadj *= 0.5;
+ aadj1 = bc.dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch (bc.rounding) {
+ case 2: /* towards +infinity */
+ aadj1 -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ aadj1 += 0.5;
+ }
+#else
+ if (Flt_Rounds == 0)
+ aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+ }
+ y = word0(&rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) {
+ dval(&rv0) = dval(&rv);
+ word0(&rv) -= P * Exp_msk1;
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ if ((word0(&rv) & Exp_mask) >=
+ Exp_msk1 * (DBL_MAX_EXP + Bias - P)) {
+ if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
+ goto ovfl;
+ word0(&rv) = Big0;
+ word1(&rv) = Big1;
+ goto cont;
+ } else
+ word0(&rv) += P * Exp_msk1;
+ } else {
+#ifdef Avoid_Underflow
+ if (bc.scale && y <= 2 * P * Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = aadj) <= 0)
+ z = 1;
+ aadj = z;
+ aadj1 = bc.dsign ? aadj : -aadj;
+ }
+ dval(&aadj2) = aadj1;
+ word0(&aadj2) += (2 * P + 1) * Exp_msk1 - y;
+ aadj1 = dval(&aadj2);
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ if (rv.d == 0.)
+#ifdef NO_STRTOD_BIGCOMP
+ goto undfl;
+#else
+ {
+ req_bigcomp = 1;
+ break;
+ }
+#endif
+ } else {
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ }
+#else
+#ifdef Sudden_Underflow
+ if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) {
+ dval(&rv0) = dval(&rv);
+ word0(&rv) += P * Exp_msk1;
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+#ifdef IBM
+ if ((word0(&rv) & Exp_mask) <
+ P * Exp_msk1)
+#else
+ if ((word0(&rv) & Exp_mask) <=
+ P * Exp_msk1)
+#endif
+ {
+ if (word0(&rv0) == Tiny0 &&
+ word1(&rv0) == Tiny1) {
+ if (bc.nd > nd) {
+ bc.uflchk = 1;
+ break;
+ }
+ goto undfl;
+ }
+ word0(&rv) = Tiny0;
+ word1(&rv) = Tiny1;
+ goto cont;
+ } else
+ word0(&rv) -= P * Exp_msk1;
+ } else {
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+ }
+#else /*Sudden_Underflow*/
+ /* Compute adj so that the IEEE rounding rules
+ * will correctly round rv + adj in some
+ * half-way cases. If rv * ulp(rv) is
+ * denormalized (i.e., y <= (P-1)*Exp_msk1), we
+ * must adjust aadj to avoid trouble from bits
+ * lost to denormalization; example: 1.2e-307 .
+ */
+ if (y <= (P - 1) * Exp_msk1 && aadj > 1.) {
+ aadj1 = (double)(int)(aadj + 0.5);
+ if (!bc.dsign)
+ aadj1 = -aadj1;
+ }
+ adj.d = aadj1 * ulp(&rv);
+ dval(&rv) += adj.d;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ }
+ z = word0(&rv) & Exp_mask;
+#ifndef SET_INEXACT
+ if (bc.nd == nd) {
+#ifdef Avoid_Underflow
+ if (!bc.scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (bc.dsign || word1(&rv) ||
+ word0(&rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ } else if (aadj < .4999999 / FLT_RADIX)
+ break;
+ }
+ }
+#endif
+cont:
+ Bfree(bb MTb);
+ Bfree(bd MTb);
+ Bfree(bs MTb);
+ Bfree(delta MTb);
+}
+Bfree(bb MTb);
+Bfree(bd MTb);
+Bfree(bs MTb);
+Bfree(bd0 MTb);
+Bfree(delta MTb);
+#ifndef NO_STRTOD_BIGCOMP
+if (req_bigcomp) {
+ bd0 = 0;
+ bc.e0 += nz1;
+ bigcomp(&rv, s0, &bc MTb);
+ y = word0(&rv) & Exp_mask;
+ if (y == Exp_mask)
+ goto ovfl;
+ if (y == 0 && rv.d == 0.)
+ goto undfl;
+}
+#endif
+#ifdef Avoid_Underflow
+if (bc.scale) {
+ word0(&rv0) = Exp_1 - 2 * P * Exp_msk1;
+ word1(&rv0) = 0;
+ dval(&rv) *= dval(&rv0);
+#ifndef NO_ERRNO
+ /* try to avoid the bug of testing an 8087 register value */
+#ifdef IEEE_Arith
+ if (!(word0(&rv) & Exp_mask))
+#else
+ if (word0(&rv) == 0 && word1(&rv) == 0)
+#endif
+ Set_errno(ERANGE);
+#endif
+}
+#endif /* Avoid_Underflow */
+ret:
+#ifdef SET_INEXACT
+ if (bc.inexact)
+{
+ if (!(word0(&rv) & Exp_mask)) {
+ /* set underflow and inexact bits */
+ dval(&rv0) = 1e-300;
+ dval(&rv0) *= dval(&rv0);
+ } else if (!oldinexact) {
+ word0(&rv0) = Exp_1 + (70 << Exp_shift);
+ word1(&rv0) = 0;
+ dval(&rv0) += 1.;
+ }
+}
+else if (!oldinexact) clear_inexact();
+#endif
+if (se)
+ *se = (char *)s;
+return sign ? -dval(&rv) : dval(&rv);
+}
+
+#ifndef MULTIPLE_THREADS
+static char *dtoa_result;
+#endif
+
+static char *rv_alloc(int i MTd)
+{
+ int j, k, *r;
+
+ j = sizeof(ULong);
+ for (k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+ j <<= 1)
+ k++;
+ r = (int *)Balloc(k MTa);
+ *r = k;
+ return
+#ifndef MULTIPLE_THREADS
+ dtoa_result =
+#endif
+ (char *)(r + 1);
+}
+
+static char *nrv_alloc(const char *s, char *s0, size_t s0len, char **rve,
+ int n MTd)
+{
+ char *rv, *t;
+
+ if (!s0)
+ s0 = rv_alloc(n MTa);
+ else if (s0len <= n) {
+ rv = 0;
+ t = rv + n;
+ goto rve_chk;
+ }
+ t = rv = s0;
+ while ((*t = *s++))
+ ++t;
+rve_chk:
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+void freedtoa(char *s)
+{
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI = 0;
+#endif
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int *)b);
+ Bfree(b MTb);
+#ifndef MULTIPLE_THREADS
+ if (s == dtoa_result)
+ dtoa_result = 0;
+#endif
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign,
+ char **rve, char *buf, size_t blen)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ When not NULL, buf is an output buffer of length blen, which must
+ be large enough to accommodate suppressed trailing zeros and a trailing
+ null byte. If blen is too small, rv = NULL is returned, in which case
+ if rve is not NULL, a subsequent call with blen >= (*rve - rv) + 1
+ should succeed in returning buf.
+
+ When buf is NULL, sufficient space is allocated for the return value,
+ which, when done using, the caller should pass to freedtoa().
+
+ USE_BF is automatically defined when neither NO_LONG_LONG nor NO_BF96
+ is defined.
+ */
+
+#ifdef MULTIPLE_THREADS
+ ThInfo *TI = 0;
+#endif
+ int bbits, b2, b5, be, dig, i, ilim, ilim1, j, j1, k, leftright, m2, m5,
+ s2, s5, spec_case;
+#if !defined(Sudden_Underflow) || defined(USE_BF96)
+ int denorm;
+#endif
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+ U u;
+ char *s;
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+#ifdef USE_BF96 /*{{*/
+ BF96 *p10;
+ ULLong dbhi, dbits, dblo, den, hb, rb, rblo, res, res0, res3, reslo,
+ sres, sulp, tv0, tv1, tv2, tv3, ulp, ulplo, ulpmask, ures,
+ ureslo, zb;
+ int eulp, k1, n2, ulpadj, ulpshift;
+#else /*}{*/
+#ifndef Sudden_Underflow
+ ULong x;
+#endif
+ Long L;
+ U d2, eps;
+ double ds;
+ int ieps, ilim0, k0, k_check, try_quick;
+#ifndef No_leftright
+#ifdef IEEE_Arith
+ U eps1;
+#endif
+#endif
+#endif /*}}*/
+#ifdef Honor_FLT_ROUNDS /*{*/
+ int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+ Rounding = Flt_Rounds;
+#else /*}{*/
+ Rounding = 1;
+ switch (fegetround()) {
+ case FE_TOWARDZERO:
+ Rounding = 0;
+ break;
+ case FE_UPWARD:
+ Rounding = 2;
+ break;
+ case FE_DOWNWARD:
+ Rounding = 3;
+ }
+#endif /*}}*/
+#endif /*}*/
+
+ u.d = dd;
+ if (word0(&u) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(&u) &= ~Sign_bit; /* clear sign bit */
+ } else
+ *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(&u) & Exp_mask) == Exp_mask)
+#else
+ if (word0(&u) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+#ifdef IEEE_Arith
+ if (!word1(&u) && !(word0(&u) & 0xfffff))
+ return nrv_alloc("Infinity", buf, blen, rve, 8 MTb);
+#endif
+ return nrv_alloc("NaN", buf, blen, rve, 3 MTb);
+ }
+#endif
+#ifdef IBM
+ dval(&u) += 0; /* normalize */
+#endif
+ if (!dval(&u)) {
+ *decpt = 1;
+ return nrv_alloc("0", buf, blen, rve, 1 MTb);
+ }
+
+#ifdef SET_INEXACT
+#ifndef USE_BF96
+ try_quick =
+#endif
+ oldinexact = get_inexact();
+ inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding >= 2) {
+ if (*sign)
+ Rounding = Rounding == 2 ? 0 : 2;
+ else if (Rounding != 2)
+ Rounding = 0;
+ }
+#endif
+#ifdef USE_BF96 /*{{*/
+ dbits = (u.LL & 0xfffffffffffffull) << 11; /* fraction bits */
+ if ((be = u.LL >> 52)) /* biased exponent; nonzero ==> normal */ {
+ dbits |= 0x8000000000000000ull;
+ denorm = ulpadj = 0;
+ } else {
+ denorm = 1;
+ ulpadj = be + 1;
+ dbits <<= 1;
+ if (!(dbits & 0xffffffff00000000ull)) {
+ dbits <<= 32;
+ be -= 32;
+ }
+ if (!(dbits & 0xffff000000000000ull)) {
+ dbits <<= 16;
+ be -= 16;
+ }
+ if (!(dbits & 0xff00000000000000ull)) {
+ dbits <<= 8;
+ be -= 8;
+ }
+ if (!(dbits & 0xf000000000000000ull)) {
+ dbits <<= 4;
+ be -= 4;
+ }
+ if (!(dbits & 0xc000000000000000ull)) {
+ dbits <<= 2;
+ be -= 2;
+ }
+ if (!(dbits & 0x8000000000000000ull)) {
+ dbits <<= 1;
+ be -= 1;
+ }
+ assert(be >= -51);
+ ulpadj -= be;
+ }
+ j = Lhint[be + 51];
+ p10 = &pten[j];
+ dbhi = dbits >> 32;
+ dblo = dbits & 0xffffffffull;
+ i = be - 0x3fe;
+ if (i < p10->e || (i == p10->e && (dbhi < p10->b0 || (dbhi == p10->b0 &&
+ dblo < p10->b1))))
+ --j;
+ k = j - 342;
+
+ /* now 10^k <= dd < 10^(k+1) */
+
+#else /*}{*/
+
+ b = d2b(&u, &be, &bbits MTb);
+#ifdef Sudden_Underflow
+ i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1));
+#else
+ if ((i = (int)(word0(&u) >> Exp_shift1 &
+ (Exp_mask >> Exp_shift1)))) {
+#endif
+ dval(&d2) = dval(&u);
+ word0(&d2) &= Frac_mask1;
+ word0(&d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(&d2) & Frac_mask))
+ dval(&d2) /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else
+ {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P - 1) - 1);
+ x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) :
+ word1(&u) << (32 - i);
+ dval(&d2) = x;
+ word0(&d2) -= 31 * Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P - 1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 +
+ i * 0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(&u) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ } else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ } else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+#endif /*}}*/
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+#ifndef USE_BF96
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+ try_quick = Rounding == 1;
+#else
+ try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+#endif /*USE_BF96*/
+
+ if (mode > 5) {
+ mode -= 4;
+#ifndef USE_BF96
+ try_quick = 0;
+#endif
+ }
+ leftright = 1;
+ ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
+ /* silence erroneous "gcc -Wall" warning. */
+ switch (mode) {
+ case 0:
+ case 1:
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ if (!buf) {
+ buf = rv_alloc(i MTb);
+ blen = sizeof(Bigint) +
+ ((1 << ((int *)buf)[-1]) - 1) * sizeof(ULong) -
+ sizeof(int);
+ } else if (blen <= i) {
+ buf = 0;
+ if (rve)
+ *rve = buf + i;
+ return buf;
+ }
+ s = buf;
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if (mode < 2 || (leftright
+#ifdef Honor_FLT_ROUNDS
+ && Rounding == 1
+#endif
+ )) {
+ if (!word1(&u) && !(word0(&u) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(&u) & (Exp_mask & ~Exp_msk1)
+#endif
+ ) {
+ /* The special case */
+ spec_case = 1;
+ }
+ }
+
+#ifdef USE_BF96 /*{*/
+ b = 0;
+ if (ilim < 0 && (mode == 3 || mode == 5)) {
+ S = mhi = 0;
+ goto no_digits;
+ }
+ i = 1;
+ j = 52 + 0x3ff - be;
+ ulpshift = 0;
+ ulplo = 0;
+ /* Can we do an exact computation with 64-bit integer arithmetic? */
+ if (k < 0) {
+ if (k < -25)
+ goto toobig;
+ res = dbits >> 11;
+ n2 = pfivebits[k1 = -(k + 1)] + 53;
+ j1 = j;
+ if (n2 > 61) {
+ ulpshift = n2 - 61;
+ if (res & (ulpmask = (1ull << ulpshift) - 1))
+ goto toobig;
+ j -= ulpshift;
+ res >>= ulpshift;
+ }
+ /* Yes. */
+ res *= ulp = pfive[k1];
+ if (ulpshift) {
+ ulplo = ulp;
+ ulp >>= ulpshift;
+ }
+ j += k;
+ if (ilim == 0) {
+ S = mhi = 0;
+ if (res > (5ull << j))
+ goto one_digit;
+ goto no_digits;
+ }
+ goto no_div;
+ }
+ if (ilim == 0 && j + k >= 0) {
+ S = mhi = 0;
+ if ((dbits >> 11) > (pfive[k - 1] << j))
+ goto one_digit;
+ goto no_digits;
+ }
+ if (k <= dtoa_divmax && j + k >= 0) {
+ /* Another "yes" case -- we will use exact integer arithmetic.
+ */
+use_exact:
+ Debug(++dtoa_stats[3]);
+ res = dbits >> 11; /* residual */
+ ulp = 1;
+ if (k <= 0)
+ goto no_div;
+ j1 = j + k + 1;
+ den = pfive[k - i] << (j1 - i);
+ for (;;) {
+ dig = res / den;
+ *s++ = '0' + dig;
+ if (!(res -= dig * den)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+ oldinexact = 1;
+#endif
+ goto retc;
+ }
+ if (ilim < 0) {
+ ures = den - res;
+ if (2 * res <= ulp &&
+ (spec_case ? 4 * res <= ulp :
+ (2 * res < ulp || dig & 1)))
+ goto ulp_reached;
+ if (2 * ures < ulp)
+ goto Roundup;
+ } else if (i == ilim) {
+ switch (Rounding) {
+ case 0:
+ goto retc;
+ case 2:
+ goto Roundup;
+ }
+ ures = 2 * res;
+ if (ures > den || (ures == den && dig & 1) ||
+ (spec_case && res <= ulp && 2 * res >= ulp))
+ goto Roundup;
+ goto retc;
+ }
+ if (j1 < ++i) {
+ res *= 10;
+ ulp *= 10;
+ } else {
+ if (i > k)
+ break;
+ den = pfive[k - i] << (j1 - i);
+ }
+ }
+no_div:
+ for (;;) {
+ dig = den = res >> j;
+ *s++ = '0' + dig;
+ if (!(res -= den << j)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+ oldinexact = 1;
+#endif
+ goto retc;
+ }
+ if (ilim < 0) {
+ ures = (1ull << j) - res;
+ if (2 * res <= ulp &&
+ (spec_case ? 4 * res <= ulp :
+ (2 * res < ulp || dig & 1))) {
+ulp_reached:
+ if (ures < res ||
+ (ures == res && dig & 1) ||
+ (dig == 9 && 2 * ures <= ulp))
+ goto Roundup;
+ goto retc;
+ }
+ if (2 * ures < ulp)
+ goto Roundup;
+ }
+ --j;
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ switch (Rounding) {
+ case 0:
+ goto retc;
+ case 2:
+ goto Roundup;
+ }
+#endif
+ hb = 1ull << j;
+ if (res & hb && (dig & 1 || res & (hb - 1)))
+ goto Roundup;
+ if (spec_case && res <= ulp && 2 * res >= ulp) {
+Roundup:
+ while (*--s == '9')
+ if (s == buf) {
+ ++k;
+ *s++ = '1';
+ goto ret1;
+ }
+ ++*s++;
+ goto ret1;
+ }
+ goto retc;
+ }
+ ++i;
+ res *= 5;
+ if (ulpshift) {
+ ulplo = 5 * (ulplo & ulpmask);
+ ulp = 5 * ulp + (ulplo >> ulpshift);
+ } else
+ ulp *= 5;
+ }
+ }
+toobig:
+ if (ilim > 28)
+ goto Fast_failed1;
+ /* Scale by 10^-k */
+ p10 = &pten[342 - k];
+ tv0 = p10->b2 * dblo; /* rarely matters, but does, e.g.,
+ for 9.862818194192001e18 */
+ tv1 = p10->b1 * dblo + (tv0 >> 32);
+ tv2 = p10->b2 * dbhi + (tv1 & 0xffffffffull);
+ tv3 = p10->b0 * dblo + (tv1 >> 32) + (tv2 >> 32);
+ res3 = p10->b1 * dbhi + (tv3 & 0xffffffffull);
+ res = p10->b0 * dbhi + (tv3 >> 32) + (res3 >> 32);
+ be += p10->e - 0x3fe;
+ eulp = j1 = be - 54 + ulpadj;
+ if (!(res & 0x8000000000000000ull)) {
+ --be;
+ res3 <<= 1;
+ res = (res << 1) | ((res3 & 0x100000000ull) >> 32);
+ }
+ res0 = res; /* save for Fast_failed */
+#if !defined(SET_INEXACT) && !defined(NO_DTOA_64) /*{*/
+ if (ilim > 19)
+ goto Fast_failed;
+ Debug(++dtoa_stats[4]);
+ assert(be >= 0 && be <= 4); /* be = 0 is rare, but possible, e.g., for
+ 1e20 */
+ res >>= 4 - be;
+ ulp = p10->b0; /* ulp */
+ ulp = (ulp << 29) | (p10->b1 >> 3);
+ /* scaled ulp = ulp * 2^(eulp - 60) */
+ /* We maintain 61 bits of the scaled ulp. */
+ if (ilim == 0) {
+ if (!(res & 0x7fffffffffffffeull) ||
+ !((~res) & 0x7fffffffffffffeull))
+ goto Fast_failed1;
+ S = mhi = 0;
+ if (res >= 0x5000000000000000ull)
+ goto one_digit;
+ goto no_digits;
+ }
+ rb = 1; /* upper bound on rounding error */
+ for (;; ++i) {
+ dig = res >> 60;
+ *s++ = '0' + dig;
+ res &= 0xfffffffffffffffull;
+ if (ilim < 0) {
+ ures = 0x1000000000000000ull - res;
+ if (eulp > 0) {
+ assert(eulp <= 4);
+ sulp = ulp << (eulp - 1);
+ if (res <= ures) {
+ if (res + rb > ures - rb)
+ goto Fast_failed;
+ if (res < sulp)
+ goto retc;
+ } else {
+ if (res - rb <= ures + rb)
+ goto Fast_failed;
+ if (ures < sulp)
+ goto Roundup;
+ }
+ } else {
+ zb = -(1ull << (eulp + 63));
+ if (!(zb & res)) {
+ sres = res << (1 - eulp);
+ if (sres < ulp &&
+ (!spec_case || 2 * sres < ulp)) {
+ if ((res + rb) << (1 - eulp) >=
+ ulp)
+ goto Fast_failed;
+ if (ures < res) {
+ if (ures + rb >=
+ res - rb)
+ goto Fast_failed;
+ goto Roundup;
+ }
+ if (ures - rb < res + rb)
+ goto Fast_failed;
+ goto retc;
+ }
+ }
+ if (!(zb & ures) && ures << -eulp < ulp) {
+ if (ures << (1 - eulp) < ulp)
+ goto Roundup;
+ goto Fast_failed;
+ }
+ }
+ } else if (i == ilim) {
+ ures = 0x1000000000000000ull - res;
+ if (ures < res) {
+ if (ures <= rb || res - rb <= ures + rb) {
+ if (j + k >= 0 && k >= 0 && k <= 27)
+ goto use_exact1;
+ goto Fast_failed;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding == 0)
+ goto retc;
+#endif
+ goto Roundup;
+ }
+ if (res <= rb || ures - rb <= res + rb) {
+ if (j + k >= 0 && k >= 0 && k <= 27) {
+use_exact1:
+ s = buf;
+ i = 1;
+ goto use_exact;
+ }
+ goto Fast_failed;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding == 2)
+ goto Roundup;
+#endif
+ goto retc;
+ }
+ rb *= 10;
+ if (rb >= 0x1000000000000000ull)
+ goto Fast_failed;
+ res *= 10;
+ ulp *= 5;
+ if (ulp & 0x8000000000000000ull) {
+ eulp += 4;
+ ulp >>= 3;
+ } else {
+ eulp += 3;
+ ulp >>= 2;
+ }
+ }
+#endif /*}*/
+#ifndef NO_BF96
+Fast_failed:
+#endif
+ Debug(++dtoa_stats[5]);
+ s = buf;
+ i = 4 - be;
+ res = res0 >> i;
+ reslo = 0xffffffffull & res3;
+ if (i)
+ reslo = (res0 << (64 - i)) >> 32 | (reslo >> i);
+ rb = 0;
+ rblo = 4; /* roundoff bound */
+ ulp = p10->b0; /* ulp */
+ ulp = (ulp << 29) | (p10->b1 >> 3);
+ eulp = j1;
+ for (i = 1;; ++i) {
+ dig = res >> 60;
+ *s++ = '0' + dig;
+ res &= 0xfffffffffffffffull;
+#ifdef SET_INEXACT
+ if (!res && !reslo) {
+ if (!(res3 & 0xffffffffull)) {
+ inexact = 0;
+ oldinexact = 1;
+ }
+ goto retc;
+ }
+#endif
+ if (ilim < 0) {
+ ures = 0x1000000000000000ull - res;
+ ureslo = 0;
+ if (reslo) {
+ ureslo = 0x100000000ull - reslo;
+ --ures;
+ }
+ if (eulp > 0) {
+ assert(eulp <= 4);
+ sulp = (ulp << (eulp - 1)) - rb;
+ if (res <= ures) {
+ if (res < sulp) {
+ if (res + rb < ures - rb)
+ goto retc;
+ }
+ } else if (ures < sulp) {
+ if (res - rb > ures + rb)
+ goto Roundup;
+ }
+ goto Fast_failed1;
+ } else {
+ zb = -(1ull << (eulp + 60));
+ if (!(zb & (res + rb))) {
+ sres = (res - rb) << (1 - eulp);
+ if (sres < ulp &&
+ (!spec_case || 2 * sres < ulp)) {
+ sres = res << (1 - eulp);
+ if ((j = eulp + 31) > 0)
+ sres += (rblo +
+ reslo) >>
+ j;
+ else
+ sres += (rblo + reslo)
+ << -j;
+ if (sres + (rb << (1 - eulp)) >=
+ ulp)
+ goto Fast_failed1;
+ if (sres >= ulp)
+ goto more96;
+ if (ures < res ||
+ (ures == res &&
+ ureslo < reslo)) {
+ if (ures + rb >=
+ res - rb)
+ goto Fast_failed1;
+ goto Roundup;
+ }
+ if (ures - rb <= res + rb)
+ goto Fast_failed1;
+ goto retc;
+ }
+ }
+ if (!(zb & ures) &&
+ (ures - rb) << (1 - eulp) < ulp) {
+ if ((ures + rb) << (2 - eulp) < ulp)
+ goto Roundup;
+ goto Fast_failed1;
+ }
+ }
+ } else if (i == ilim) {
+ ures = 0x1000000000000000ull - res;
+ sres = ureslo = 0;
+ if (reslo) {
+ ureslo = 0x100000000ull - reslo;
+ --ures;
+ sres = (reslo + rblo) >> 31;
+ }
+ sres += 2 * rb;
+ if (ures <= res) {
+ if (ures <= sres || res - ures <= sres)
+ goto Fast_failed1;
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding == 0)
+ goto retc;
+#endif
+ goto Roundup;
+ }
+ if (res <= sres || ures - res <= sres)
+ goto Fast_failed1;
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding == 2)
+ goto Roundup;
+#endif
+ goto retc;
+ }
+more96:
+ rblo *= 10;
+ rb = 10 * rb + (rblo >> 32);
+ rblo &= 0xffffffffull;
+ if (rb >= 0x1000000000000000ull)
+ goto Fast_failed1;
+ reslo *= 10;
+ res = 10 * res + (reslo >> 32);
+ reslo &= 0xffffffffull;
+ ulp *= 5;
+ if (ulp & 0x8000000000000000ull) {
+ eulp += 4;
+ ulp >>= 3;
+ } else {
+ eulp += 3;
+ ulp >>= 2;
+ }
+ }
+Fast_failed1:
+ Debug(++dtoa_stats[6]);
+ S = mhi = mlo = 0;
+#ifdef USE_BF96
+ b = d2b(&u, &be, &bbits MTb);
+#endif
+ s = buf;
+ i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1));
+ i -= Bias;
+ if (ulpadj)
+ i -= ulpadj - 1;
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ } else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ } else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+#endif /*}*/
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1 && Rounding != 1)
+ leftright = 0;
+#endif
+
+#ifndef USE_BF96 /*{*/
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(&d2) = dval(&u);
+ j1 = -(k0 = k);
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k & 0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(&u) /= bigtens[n_bigtens - 1];
+ ieps++;
+ }
+ for (; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(&u) /= ds;
+ } else if (j1 > 0) {
+ dval(&u) *= tens[j1 & 0xf];
+ for (j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(&u) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(&u) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(&u) *= 10.;
+ ieps++;
+ }
+ dval(&eps) = ieps * dval(&u) + 7.;
+ word0(&eps) -= (P - 1) * Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(&u) -= 5.;
+ if (dval(&u) > dval(&eps))
+ goto one_digit;
+ if (dval(&u) < -dval(&eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(&eps) = 0.5 / tens[ilim - 1] - dval(&eps);
+#ifdef IEEE_Arith
+ if (j1 >= 307) {
+ eps1.d = 1.01e256; /* 1.01 allows roundoff in
+ the next few lines */
+ word0(&eps1) -= Exp_msk1 * (Bias + P - 1);
+ dval(&eps1) *= tens[j1 & 0xf];
+ for (i = 0, j = (j1 - 256) >> 4; j;
+ j >>= 1, i++)
+ if (j & 1)
+ dval(&eps1) *= bigtens[i];
+ if (eps.d < eps1.d)
+ eps.d = eps1.d;
+ if (10. - u.d < 10. * eps.d && eps.d < 1.) {
+ /* eps.d < 1. excludes trouble with the
+ * tiniest denormal */
+ *s++ = '1';
+ ++k;
+ goto ret1;
+ }
+ }
+#endif
+ for (i = 0;;) {
+ L = dval(&u);
+ dval(&u) -= L;
+ *s++ = '0' + (int)L;
+ if (1. - dval(&u) < dval(&eps))
+ goto bump_up;
+ if (dval(&u) < dval(&eps))
+ goto retc;
+ if (++i >= ilim)
+ break;
+ dval(&eps) *= 10.;
+ dval(&u) *= 10.;
+ }
+ } else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(&eps) *= tens[ilim - 1];
+ for (i = 1;; i++, dval(&u) *= 10.) {
+ L = (Long)(dval(&u));
+ if (!(dval(&u) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(&u) > 0.5 + dval(&eps))
+ goto bump_up;
+ else if (dval(&u) < 0.5 - dval(&eps))
+ goto retc;
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+fast_failed:
+ s = buf;
+ dval(&u) = dval(&d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(&u) <= 5 * ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for (i = 1;; i++, dval(&u) *= 10.) {
+ L = (Long)(dval(&u) / ds);
+ dval(&u) -= L * ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(&u) < 0) {
+ L--;
+ dval(&u) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (!dval(&u)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (Rounding) {
+ case 0:
+ goto retc;
+ case 2:
+ goto bump_up;
+ }
+#endif
+ dval(&u) += dval(&u);
+#ifdef ROUND_BIASED
+ if (dval(&u) >= ds)
+#else
+ if (dval(&u) > ds || (dval(&u) == ds && L & 1))
+#endif
+ {
+bump_up:
+ while (*--s == '9')
+ if (s == buf) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto retc;
+ }
+
+#endif /*}*/
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P - 1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4 * P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 1 + P - bbits;
+#endif
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1 MTb);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5 MTb);
+ b1 = mult(mhi, b MTb);
+ Bfree(b MTb);
+ b = b1;
+ }
+ if ((j = b5 - m5))
+ b = pow5mult(b, j MTb);
+ } else
+ b = pow5mult(b, b5 MTb);
+ }
+ S = i2b(1 MTb);
+ if (s5 > 0)
+ S = pow5mult(S, s5 MTb);
+
+ if (spec_case) {
+ b2 += Log2P;
+ s2 += Log2P;
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+ i = dshift(S, s2);
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ if (b2 > 0)
+ b = lshift(b, b2 MTb);
+ if (s2 > 0)
+ S = lshift(S, s2 MTb);
+#ifndef USE_BF96
+ if (k_check) {
+ if (cmp(b, S) < 0) {
+ k--;
+ b = multadd(b, 10, 0 MTb); /* we botched the k estimate
+ */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0 MTb);
+ ilim = ilim1;
+ }
+ }
+#endif
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0 || cmp(b, S = multadd(S, 5, 0 MTb)) <= 0) {
+ /* no digits, fcvt style */
+no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+one_digit:
+ *s++ = '1';
+ ++k;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2 MTb);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k MTb);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P MTb);
+ }
+
+ for (i = 1;; i++) {
+ dig = quorem(b, S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi MTb);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta MTb);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && mode != 1 && !(word1(&u) & 1)
+#ifdef Honor_FLT_ROUNDS
+ && (mode <= 1 || Rounding >= 1)
+#endif
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+#ifdef SET_INEXACT
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+ && !(word1(&u) & 1)
+#endif
+ )) {
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (Rounding) {
+ case 0:
+ goto accept_dig;
+ case 2:
+ goto keep_dig;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+ if (j1 > 0) {
+ b = lshift(b, 1 MTb);
+ j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j1 >= 0 /*)*/
+#else
+ if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+ && dig++ == '9')
+ goto round_9_up;
+ }
+accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+ if (!Rounding && mode > 1)
+ goto accept_dig;
+#endif
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+#ifdef Honor_FLT_ROUNDS
+keep_dig:
+#endif
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0 MTb);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0 MTb);
+ else {
+ mlo = multadd(mlo, 10, 0 MTb);
+ mhi = multadd(mhi, 10, 0 MTb);
+ }
+ }
+ } else
+ for (i = 1;; i++) {
+ dig = quorem(b, S) + '0';
+ *s++ = dig;
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0 MTb);
+ }
+
+ /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (Rounding) {
+ case 0:
+ goto ret;
+ case 2:
+ goto roundoff;
+ }
+#endif
+ b = lshift(b, 1 MTb);
+ j = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j >= 0)
+#else
+ if (j > 0 || (j == 0 && dig & 1))
+#endif
+ {
+roundoff:
+ while (*--s == '9')
+ if (s == buf) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ret:
+ Bfree(S MTb);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo MTb);
+ Bfree(mhi MTb);
+ }
+retc:
+ while (s > buf && s[-1] == '0')
+ --s;
+ret1:
+ if (b)
+ Bfree(b MTb);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(&u) = Exp_1 + (70 << Exp_shift);
+ word1(&u) = 0;
+ dval(&u) += 1.;
+ }
+ } else if (!oldinexact)
+ clear_inexact();
+#endif
+ return buf;
+}
+
+char *dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ See dtoa_r() above for details on the other arguments.
+ */
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result)
+ freedtoa(dtoa_result);
+#endif
+ return dtoa_r(dd, mode, ndigits, decpt, sign, rve, 0, 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
new file mode 100644
index 00000000..8f0b4cef
--- /dev/null
+++ b/lib/libc/stdio/fclose.c
@@ -0,0 +1,16 @@
+#include <io.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fclose(FILE *stream)
+{
+ if (fflush(stream) == -1)
+ return -1;
+
+ if (stream != stdin && stream != stdout && stream != stderr) {
+ if (close(stream->fd) == -1)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
new file mode 100644
index 00000000..f2ce0693
--- /dev/null
+++ b/lib/libc/stdio/fdopen.c
@@ -0,0 +1,39 @@
+#include <io.h>
+#include <libc.h>
+#include <unistd.h>
+#include <stdio.h>
+
+weak void __stdio_cleanup(void)
+{
+}
+
+FILE *fdopen(int fildes, const char *mode)
+{
+ FILE *fp;
+
+ if (mode == NULL ||
+ (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) {
+ return NULL;
+ }
+
+ if ((fp = calloc(1, sizeof(FILE))) == NULL)
+ return NULL;
+
+ fp->fd = fildes;
+ atomic_flag_clear(&fp->lock);
+ if (mode[0] == 'r') {
+ fp->type = _IONBF;
+ } else if (mode[0] == 'w') {
+ fp->type = _IOLBF;
+ } else if (mode[0] == 'a') {
+ fp->type = _IONBF;
+ off_t offset = lseek(fildes, 0, SEEK_END);
+ if (offset == (off_t)-1) {
+ free(fp);
+ return NULL;
+ }
+ }
+
+ __libc_fadd(fp);
+ return fp;
+}
diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c
new file mode 100644
index 00000000..0b3eb1ec
--- /dev/null
+++ b/lib/libc/stdio/feof.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <io.h>
+
+int feof(FILE *stream)
+{
+ if (!stream)
+ return 0;
+
+ return stream->eof;
+}
diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c
new file mode 100644
index 00000000..b4e438b3
--- /dev/null
+++ b/lib/libc/stdio/ferror.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <io.h>
+
+int ferror(FILE *stream)
+{
+ if (!stream)
+ return 0;
+
+ return (stream->flags & _IO_ERR) != 0;
+}
diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c
new file mode 100644
index 00000000..f9a2004d
--- /dev/null
+++ b/lib/libc/stdio/fflush.c
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <atomic.h>
+#include <io.h>
+#include <errno.h>
+#include <string.h>
+
+int fflush(FILE *stream)
+{
+ // Handle NULL stream - flush all open streams
+ if (stream == NULL) {
+ // TODO: Implement flushing all open streams
+ // For now, just return success
+ return 0;
+ }
+
+ // Nothing to flush if buffer is empty
+ if (stream->buf_len == 0) {
+ return 0;
+ }
+
+ // Handle special case of invalid file descriptor
+ if (stream->fd == -1) {
+ stream->buf_len = 0;
+ return 0;
+ }
+
+ // Check if stream is in error state
+ if (stream->flags & _IO_ERR) {
+ errno = EIO;
+ return EOF;
+ }
+
+ // Check if stream is writable
+ if ((stream->flags & O_ACCMODE) == O_RDONLY) {
+ errno = EBADF;
+ return EOF;
+ }
+
+ LIBC_LOCK(stream->lock);
+
+ size_t bytes_to_write = stream->buf_len;
+ size_t total_written = 0;
+ char *buf_ptr = stream->buf;
+
+ // Write all buffered data
+ while (total_written < bytes_to_write) {
+ ssize_t result = write(stream->fd, buf_ptr + total_written,
+ bytes_to_write - total_written);
+
+ if (result < 0) {
+ // Write error occurred
+ stream->flags |= _IO_ERR;
+ LIBC_UNLOCK(stream->lock);
+ return EOF;
+ }
+
+ if (result == 0) {
+ // No progress made (shouldn't happen with regular
+ // files)
+ break;
+ }
+
+ total_written += result;
+ }
+
+ // Update buffer state
+ if (total_written == bytes_to_write) {
+ // All data was written successfully
+ stream->buf_len = 0;
+ stream->buf_pos = 0;
+ } else {
+ // Partial write - move remaining data to beginning of buffer
+ size_t remaining = bytes_to_write - total_written;
+ memmove(stream->buf, stream->buf + total_written, remaining);
+ stream->buf_len = remaining;
+ stream->buf_pos = 0;
+ }
+
+ LIBC_UNLOCK(stream->lock);
+
+ // Return success if all data was written, error otherwise
+ return (total_written == bytes_to_write) ? 0 : EOF;
+}
diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c
new file mode 100644
index 00000000..658eaffe
--- /dev/null
+++ b/lib/libc/stdio/fgetc.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int fgetc(FILE *stream)
+{
+ int c;
+
+ if (fread(&c, 1, 1, stream) < 0)
+ return -1;
+
+ return c;
+}
diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c
new file mode 100644
index 00000000..75ffb064
--- /dev/null
+++ b/lib/libc/stdio/fgets.c
@@ -0,0 +1,9 @@
+#include <libc.h>
+#include <stdio.h>
+
+char *fgets(char *restrict s, int n, FILE *restrict stream)
+{
+ return fread(s, 1, n, stream) ? s : NULL;
+}
+
+weak_reference(fgets, fgets_unlocked);
diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c
new file mode 100644
index 00000000..09db0ad5
--- /dev/null
+++ b/lib/libc/stdio/fileno.c
@@ -0,0 +1,20 @@
+#include <io.h>
+#include <errno.h>
+#include <atomic.h>
+#include <stdio.h>
+
+int fileno(FILE *stream)
+{
+ int fd;
+
+ LIBC_LOCK(stream->lock);
+ fd = stream->fd;
+ LIBC_UNLOCK(stream->lock);
+
+ if (fd < 0) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return fd;
+}
diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c
new file mode 100644
index 00000000..1ad86f7b
--- /dev/null
+++ b/lib/libc/stdio/fmemopen.c
@@ -0,0 +1,46 @@
+#include <io.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libc.h>
+
+weak void __stdio_cleanup(void)
+{
+}
+
+FILE *fmemopen(void *restrict buf, size_t max_size, const char *restrict mode)
+{
+ int flags;
+ FILE *f = calloc(1, sizeof(FILE));
+
+ if (f == NULL)
+ return f;
+
+ f->fd = -1;
+ f->buf = buf;
+ f->buf_size = max_size;
+ f->type = _IOFBF;
+
+ if (mode[0] == 'r') {
+ flags = O_RDONLY;
+ } else if (mode[0] == 'w') {
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ } else if (mode[0] == 'a') {
+ flags = O_WRONLY | O_CREAT | O_APPEND;
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (strchr(mode, '+')) {
+ flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+ }
+
+ f->flags = flags;
+
+ __libc_fadd(f);
+
+ return f;
+}
diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c
new file mode 100644
index 00000000..7d01fd38
--- /dev/null
+++ b/lib/libc/stdio/fopen.c
@@ -0,0 +1,56 @@
+#include <io.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libc.h>
+
+weak void __stdio_cleanup(void)
+{
+}
+
+FILE *fopen(const char *restrict pathname, const char *restrict mode)
+{
+ int fd, flags, _mode;
+ FILE *fp;
+
+ _mode = 0;
+ if (mode[0] == 'r') {
+ flags = O_RDONLY;
+ } else if (mode[0] == 'w') {
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ } else if (mode[0] == 'a') {
+ flags = O_WRONLY | O_CREAT | O_APPEND;
+ _mode = 0666;
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (strchr(mode, '+')) {
+ flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+ }
+
+ if ((fd = open(pathname, flags, _mode)) < 0)
+ return NULL;
+
+ if ((fp = calloc(1, sizeof(FILE))) == NULL)
+ return NULL;
+
+ fp->fd = fd;
+ fp->buf_size = BUFSIZ;
+ fp->flags = flags;
+ fp->type = _IOLBF;
+ atomic_flag_clear(&fp->lock);
+ if ((fp->buf = malloc(BUFSIZ)) == NULL) {
+ close(fd);
+ free(fp);
+ return NULL;
+ }
+
+ __libc_fadd(fp);
+
+ return fp;
+}
diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c
new file mode 100644
index 00000000..4283b424
--- /dev/null
+++ b/lib/libc/stdio/fprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int fprintf(FILE *restrict stream, const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vfprintf(stdout, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c
new file mode 100644
index 00000000..c544d5dd
--- /dev/null
+++ b/lib/libc/stdio/fputc.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+
+int fputc(int c, FILE *stream)
+{
+ if (!stream) {
+ errno = EINVAL;
+ return EOF;
+ }
+
+ // Special case for string buffer operations (snprintf)
+ // When fd is -1, we're writing to a string buffer
+ if (stream->fd == -1 && stream->buf != NULL) {
+ // Check if there's space (leave room for null terminator)
+ if (stream->buf_len >= stream->buf_size - 1) {
+ return EOF;
+ }
+
+ stream->buf[stream->buf_len++] = (char)c;
+ return (unsigned char)c;
+ }
+
+ // For regular file operations, use fwrite
+ return fwrite(&c, 1, 1, stream) ? c : EOF;
+}
diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c
new file mode 100644
index 00000000..8538b9c2
--- /dev/null
+++ b/lib/libc/stdio/fputs.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <string.h>
+
+int fputs(const char *restrict s, FILE *restrict stream)
+{
+ return fwrite(s, 1, strlen(s), stream) == strlen(s) ? 0 : EOF;
+}
diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c
new file mode 100644
index 00000000..a27b64c4
--- /dev/null
+++ b/lib/libc/stdio/fread.c
@@ -0,0 +1,50 @@
+#include <io.h>
+#include <unistd.h>
+#include <string.h>
+#include <atomic.h>
+#include <stdio.h>
+
+char __stdin_buffer[BUFSIZ];
+
+size_t fread(void *restrict ptr, size_t size, size_t nitems,
+ FILE *restrict stream)
+{
+ if (size == 0 || nitems == 0)
+ return 0;
+
+ size_t total = size * nitems;
+ size_t bytes_read = 0;
+ char *p = ptr;
+
+ LIBC_LOCK(stream->lock);
+
+ while (total > 0) {
+ if (stream->buf_pos < stream->buf_len) {
+ size_t available = stream->buf_len - stream->buf_pos;
+ size_t to_copy = total < available ? total : available;
+
+ memcpy(p, stream->buf + stream->buf_pos, to_copy);
+ stream->buf_pos += to_copy;
+ p += to_copy;
+ bytes_read += to_copy;
+ total -= to_copy;
+ continue;
+ }
+
+ ssize_t ret = read(stream->fd, stream->buf, stream->buf_size);
+ if (ret <= 0) {
+ if (ret < 0)
+ stream->flags |= _IO_ERR;
+ else
+ stream->flags |= _IO_EOF;
+ break;
+ }
+
+ stream->buf_len = ret;
+ stream->buf_pos = 0;
+ }
+
+ LIBC_UNLOCK(stream->lock);
+
+ return bytes_read / size;
+}
diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c
new file mode 100644
index 00000000..af12cd2c
--- /dev/null
+++ b/lib/libc/stdio/fseek.c
@@ -0,0 +1,28 @@
+#include <unistd.h>
+#include <io.h>
+#include <stdio.h>
+#include <atomic.h>
+
+int fseek(FILE *stream, long offset, int whence)
+{
+ if (stream == NULL || stream->fd < 0)
+ return -1;
+
+ LIBC_LOCK(stream->lock);
+
+ stream->buf_pos = 0;
+ stream->buf_len = 0;
+ stream->flags &= ~_IO_EOF;
+
+ off_t result = lseek(stream->fd, offset, whence);
+
+ LIBC_UNLOCK(stream->lock);
+
+ if (result == (off_t)-1) {
+ stream->flags |= _IO_ERR;
+ return -1;
+ }
+
+ stream->offset = result;
+ return 0;
+}
diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c
new file mode 100644
index 00000000..c28fe143
--- /dev/null
+++ b/lib/libc/stdio/ftell.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+
+long ftell(FILE *stream)
+{
+ off_t pos;
+
+ if ((pos = ftello(stream)) > LONG_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ return pos;
+}
diff --git a/lib/libc/stdio/ftello.c b/lib/libc/stdio/ftello.c
new file mode 100644
index 00000000..d0e5dfa1
--- /dev/null
+++ b/lib/libc/stdio/ftello.c
@@ -0,0 +1,9 @@
+#include <io.h>
+#include <atomic.h>
+#include <stdio.h>
+#include <unistd.h>
+
+off_t ftello(FILE *stream)
+{
+ return fseek(stream, 0, SEEK_CUR);
+}
diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c
new file mode 100644
index 00000000..709b1c72
--- /dev/null
+++ b/lib/libc/stdio/fwrite.c
@@ -0,0 +1,147 @@
+#include <io.h>
+#include <libc.h>
+#include <atomic.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+char __stdout_buffer[BUFSIZ];
+void (*__stdio_cleanup)(void);
+
+size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
+ FILE *restrict stream)
+{
+ size_t total_bytes;
+ size_t written = 0;
+ const char *data = (const char *)ptr;
+
+ // Validate parameters
+ if (!ptr || !stream || size == 0) {
+ if (size == 0)
+ return nitems;
+ errno = EINVAL;
+ return 0;
+ }
+
+ // Special case for string buffer operations (snprintf)
+ // When fd is -1, we're writing to a string buffer
+ if (stream->fd == -1 && stream->buf != NULL) {
+ // Calculate total bytes with overflow check
+ if (__builtin_mul_overflow(size, nitems, &total_bytes)) {
+ errno = EOVERFLOW;
+ return 0;
+ }
+
+ // Check remaining buffer space (leave room for null terminator)
+ size_t space_left =
+ stream->buf_size > stream->buf_len ?
+ stream->buf_size - stream->buf_len - 1 :
+ 0;
+
+ if (space_left == 0) {
+ return 0;
+ }
+
+ // Copy as much as fits
+ size_t to_copy = total_bytes < space_left ? total_bytes :
+ space_left;
+
+ if (to_copy > 0) {
+ memcpy(stream->buf + stream->buf_len, data, to_copy);
+ stream->buf_len += to_copy;
+ }
+
+ // Return number of complete items written
+ return to_copy == total_bytes ? nitems : to_copy / size;
+ }
+
+ // Calculate total bytes with overflow check
+ if (__builtin_mul_overflow(size, nitems, &total_bytes)) {
+ errno = EOVERFLOW;
+ return 0;
+ }
+
+ // Check if stream is writable (fix the flag check)
+ if ((stream->flags & O_ACCMODE) == O_RDONLY) {
+ errno = EBADF;
+ return 0;
+ }
+
+ // Check for error state
+ if (stream->flags & _IO_ERR) {
+ errno = EIO;
+ return 0;
+ }
+
+ LIBC_LOCK(stream->lock);
+
+ // Handle unbuffered I/O
+ if (stream->type == _IONBF) {
+ ssize_t result = write(stream->fd, data, total_bytes);
+ LIBC_UNLOCK(stream->lock);
+
+ if (result < 0) {
+ stream->flags |= _IO_ERR;
+ return 0;
+ }
+
+ return result == (ssize_t)total_bytes ? nitems : result / size;
+ }
+
+ // Handle buffered I/O (both _IOFBF and _IOLBF)
+ size_t remaining = total_bytes;
+
+ while (remaining > 0) {
+ // Check if buffer is full
+ size_t space_available = stream->buf_size - stream->buf_len;
+
+ if (space_available == 0) {
+ // Flush the buffer
+ LIBC_UNLOCK(stream->lock);
+ if (fflush(stream) != 0) {
+ return written / size;
+ }
+ space_available = stream->buf_size;
+ }
+
+ // Determine how much to copy this iteration
+ size_t to_copy = remaining < space_available ? remaining :
+ space_available;
+
+ // Copy data to buffer
+ memcpy(stream->buf + stream->buf_len, data + written, to_copy);
+ stream->buf_len += to_copy;
+ written += to_copy;
+ remaining -= to_copy;
+
+ // For line buffered streams, check if we need to flush
+ if (stream->type == _IOLBF) {
+ // Look for newlines in the data we just added
+ char *newline_pos =
+ memchr(stream->buf + stream->buf_len - to_copy,
+ '\n', to_copy);
+ if (newline_pos != NULL) {
+ LIBC_UNLOCK(stream->lock);
+ if (fflush(stream) != 0) {
+ return written / size;
+ }
+ }
+ }
+
+ // For fully buffered streams, flush if buffer is full
+ else if (stream->type == _IOFBF &&
+ stream->buf_len == stream->buf_size) {
+ LIBC_UNLOCK(stream->lock);
+ if (fflush(stream) != 0) {
+ return written / size;
+ }
+ }
+ }
+
+ LIBC_UNLOCK(stream->lock);
+
+ // Return number of complete items written
+ return written == total_bytes ? nitems : written / size;
+}
diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c
new file mode 100644
index 00000000..251675aa
--- /dev/null
+++ b/lib/libc/stdio/getc.c
@@ -0,0 +1,9 @@
+#include <libc.h>
+#include <stdio.h>
+
+int getc(FILE *stream)
+{
+ return fgetc(stream);
+}
+
+weak_reference(getc, getc_unlocked);
diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c
new file mode 100644
index 00000000..8c690d56
--- /dev/null
+++ b/lib/libc/stdio/getchar.c
@@ -0,0 +1,9 @@
+#include <libc.h>
+#include <stdio.h>
+
+int getchar(void)
+{
+ return fgetc(stdin);
+}
+
+weak_reference(getchar, getchar_unlocked);
diff --git a/lib/libc/stdio/pclose.c b/lib/libc/stdio/pclose.c
new file mode 100644
index 00000000..daae5bf5
--- /dev/null
+++ b/lib/libc/stdio/pclose.c
@@ -0,0 +1,10 @@
+#include <io.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+int pclose(FILE *stream)
+{
+ int stat;
+ fclose(stream);
+ return (waitpid(stream->pid, &stat, 0) < 0) ? -1 : stat;
+}
diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c
new file mode 100644
index 00000000..f3f4bb19
--- /dev/null
+++ b/lib/libc/stdio/perror.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+void perror(const char *s)
+{
+ struct iovec iov[4];
+
+ char *errstr = strerror(errno);
+
+ if (s != NULL && *s != '\0') {
+ iov[0].iov_base = (void *)s;
+ iov[0].iov_len = strlen(s);
+ iov[1].iov_base = ": ";
+ iov[1].iov_len = 2;
+ }
+
+ iov[s != NULL && *s != '\0' ? 2 : 0].iov_base = errstr;
+ iov[s != NULL && *s != '\0' ? 2 : 0].iov_len = strlen(errstr);
+ iov[s != NULL && *s != '\0' ? 3 : 1].iov_base = "\n";
+ iov[s != NULL && *s != '\0' ? 3 : 1].iov_len = 1;
+
+ writev(STDERR_FILENO, iov, s != NULL && *s != '\0' ? 4 : 2);
+}
diff --git a/lib/libc/stdio/popen.c b/lib/libc/stdio/popen.c
new file mode 100644
index 00000000..92b6a099
--- /dev/null
+++ b/lib/libc/stdio/popen.c
@@ -0,0 +1,65 @@
+#include <io.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+FILE *popen(const char *command, const char *mode)
+{
+ FILE *stream;
+ int oflag;
+ int pipefd[2];
+
+ switch (*mode) {
+ case 'r':
+ oflag = O_RDONLY;
+ break;
+ case 'w':
+ oflag = O_WRONLY;
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (pipe2(pipefd, O_CLOEXEC) < 0)
+ return NULL;
+
+ stream = fdopen(pipefd[oflag], mode);
+ if (stream == NULL) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return NULL;
+ }
+
+ pid_t pid = fork();
+
+ if (pid < 0) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ fclose(stream);
+ return NULL;
+ } else if (pid == 0) {
+ if (oflag == O_RDONLY) {
+ dup2(pipefd[1], STDOUT_FILENO);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ } else {
+ dup2(pipefd[0], STDIN_FILENO);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ }
+ execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ } else {
+ if (oflag == O_RDONLY) {
+ close(pipefd[1]);
+ } else {
+ close(pipefd[0]);
+ }
+
+ stream->pid = pid;
+
+ return stream;
+ }
+}
diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c
new file mode 100644
index 00000000..e8e7c388
--- /dev/null
+++ b/lib/libc/stdio/printf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int printf(const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vfprintf(stdout, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/putc.c b/lib/libc/stdio/putc.c
new file mode 100644
index 00000000..2486926a
--- /dev/null
+++ b/lib/libc/stdio/putc.c
@@ -0,0 +1,9 @@
+#include <libc.h>
+#include <stdio.h>
+
+int putc(int c, FILE *stream)
+{
+ return fputc(c, stream);
+}
+
+weak_reference(putc, putc_unlocked);
diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c
new file mode 100644
index 00000000..f54bb9d7
--- /dev/null
+++ b/lib/libc/stdio/putchar.c
@@ -0,0 +1,9 @@
+#include <libc.h>
+#include <stdio.h>
+
+int putchar(int c)
+{
+ return putc(c, stdout);
+}
+
+weak_reference(putchar, putchar_unlocked);
diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c
new file mode 100644
index 00000000..41024337
--- /dev/null
+++ b/lib/libc/stdio/puts.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <string.h>
+
+int puts(const char *s)
+{
+ fwrite(s, 1, strlen(s), stdout);
+ fwrite("\n", 1, 1, stdout);
+ return 0;
+}
diff --git a/lib/libc/stdio/remove.c b/lib/libc/stdio/remove.c
new file mode 100644
index 00000000..9aec52e9
--- /dev/null
+++ b/lib/libc/stdio/remove.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <syscall.h>
+
+int remove(const char *path)
+{
+ if (syscall(unlinkat, AT_FDCWD, path, 0) < 0) {
+ if (errno == EISDIR) {
+ return syscall(unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
+ } else {
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/libc/stdio/rename.c b/lib/libc/stdio/rename.c
new file mode 100644
index 00000000..612326e8
--- /dev/null
+++ b/lib/libc/stdio/rename.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int rename(const char *old, const char *new)
+{
+ return syscall(rename, old, new);
+}
diff --git a/lib/libc/stdio/renameat.c b/lib/libc/stdio/renameat.c
new file mode 100644
index 00000000..93d435fa
--- /dev/null
+++ b/lib/libc/stdio/renameat.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int renameat(int oldfd, const char *old, int newfd, const char *new)
+{
+ return syscall(renameat, oldfd, old, newfd, new);
+}
diff --git a/lib/libc/stdio/rewind.c b/lib/libc/stdio/rewind.c
new file mode 100644
index 00000000..b047fa41
--- /dev/null
+++ b/lib/libc/stdio/rewind.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void rewind(FILE *stream)
+{
+ fseek(stream, 0L, SEEK_SET);
+ clearerr(stream);
+}
diff --git a/lib/libc/stdio/setbuf.c b/lib/libc/stdio/setbuf.c
new file mode 100644
index 00000000..a1ef7b31
--- /dev/null
+++ b/lib/libc/stdio/setbuf.c
@@ -0,0 +1,7 @@
+#include <io.h>
+#include <stdio.h>
+
+void setbuf(FILE *restrict stream, char *restrict buf)
+{
+ setvbuf(stream, buf, buf != NULL ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c
new file mode 100644
index 00000000..56d7196c
--- /dev/null
+++ b/lib/libc/stdio/setvbuf.c
@@ -0,0 +1,20 @@
+#include <io.h>
+#include <stdio.h>
+
+int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size)
+{
+ if (type != _IOFBF && type != _IOLBF && type != _IONBF)
+ return -1;
+ if (type != _IONBF && (buf == NULL || size == 0))
+ return -1;
+
+ if (stream->fd < 0)
+ return -1;
+
+ stream->buf = buf;
+ stream->buf_size = size;
+ stream->buf_pos = 0;
+ stream->type = type;
+
+ return 0;
+}
diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c
new file mode 100644
index 00000000..81f2c5b6
--- /dev/null
+++ b/lib/libc/stdio/snprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int snprintf(char *restrict s, size_t n, const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vsnprintf(s, n, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c
new file mode 100644
index 00000000..057c162d
--- /dev/null
+++ b/lib/libc/stdio/sprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+int sprintf(char *restrict s, const char *restrict format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vsprintf(s, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/lib/libc/stdio/stderr.c b/lib/libc/stdio/stderr.c
new file mode 100644
index 00000000..42098960
--- /dev/null
+++ b/lib/libc/stdio/stderr.c
@@ -0,0 +1,20 @@
+#include <io.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define BUFSIZ 4096
+
+struct __FILE __stderr = { .fd = STDERR_FILENO,
+ .flags = O_WRONLY,
+ .type = 0,
+ .buf = 0,
+ .buf_len = 0,
+ .buf_size = 0,
+ .buf_pos = 0,
+ .eof = 0,
+ .unget_cnt = 0,
+ .next = 0,
+ .offset = 0,
+ .lock = ATOMIC_FLAG_INIT };
+
+struct FILE *const stderr = (struct FILE *)&__stderr;
diff --git a/lib/libc/stdio/stdin.c b/lib/libc/stdio/stdin.c
new file mode 100644
index 00000000..bcc2eca6
--- /dev/null
+++ b/lib/libc/stdio/stdin.c
@@ -0,0 +1,18 @@
+#include <io.h>
+#include <libc.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define BUFSIZ 4096
+#define _IOLBF 0x1
+
+weak char __stdin_buffer[0];
+struct __FILE __stdin = { .fd = STDOUT_FILENO,
+ .flags = O_RDONLY,
+ .buf = __stdin_buffer,
+ .type = 0x0,
+ .buf_size = BUFSIZ,
+ .buf_pos = 0,
+ .offset = 0 };
+
+struct FILE *const stdin = (struct FILE *)&__stdin;
diff --git a/lib/libc/stdio/stdout.c b/lib/libc/stdio/stdout.c
new file mode 100644
index 00000000..7d55c3e7
--- /dev/null
+++ b/lib/libc/stdio/stdout.c
@@ -0,0 +1,34 @@
+#include <io.h>
+#include <libc.h>
+#include <fcntl.h>
+#include <atomic.h>
+#include <unistd.h>
+
+#define BUFSIZ 4096
+
+weak char __stdout_buffer[0];
+static atomic_flag __stdio_lock = ATOMIC_FLAG_INIT;
+struct __FILE __stdout = { .fd = STDOUT_FILENO,
+ .flags = O_WRONLY,
+ .type = 1,
+ .buf = __stdout_buffer,
+ .buf_len = 0,
+ .buf_size = BUFSIZ,
+ .buf_pos = 0,
+ .eof = 0,
+ .unget_cnt = 0,
+ .offset = 0,
+ .next = NULL,
+ .lock = ATOMIC_FLAG_INIT };
+
+struct __FILE *const stdout = (struct __FILE *)&__stdout;
+
+void __libc_fadd(struct __FILE *f)
+{
+ LIBC_LOCK(__stdio_lock);
+ struct __FILE *cur = &__stdout;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = f;
+ LIBC_UNLOCK(__stdio_lock);
+}
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
new file mode 100644
index 00000000..128d4ee3
--- /dev/null
+++ b/lib/libc/stdio/vasprintf.c
@@ -0,0 +1,18 @@
+#include <io.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+// TODO: maybe use memstream in future??
+int vasprintf(char **restrict ptr, const char *restrict format, va_list ap)
+{
+ int l;
+ va_list ap2;
+ va_copy(ap2, ap);
+ l = vsnprintf(0, 0, format, ap2);
+ va_end(ap2);
+
+ if (l < 0 || !(*ptr = malloc(l + 1U)))
+ return -1;
+
+ return vsnprintf(*ptr, l + 1U, format, ap);
+}
diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c
new file mode 100644
index 00000000..66a041cc
--- /dev/null
+++ b/lib/libc/stdio/vdprintf.c
@@ -0,0 +1,12 @@
+#include <io.h>
+#include <stdio.h>
+
+int vdprintf(int fildes, const char *restrict format, va_list ap)
+{
+ int r;
+ FILE f;
+ f.fd = fildes;
+ f.type = _IONBF;
+ r = vfprintf(&f, format, ap);
+ return r;
+}
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
new file mode 100644
index 00000000..fb4c200e
--- /dev/null
+++ b/lib/libc/stdio/vfprintf.c
@@ -0,0 +1,809 @@
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <math.h>
+#include <unistd.h>
+#include <wchar.h>
+
+extern char *dtoa(double, int mode, int ndigits, int *decpt, int *sign,
+ char **rve);
+extern void freedtoa(char *s);
+
+static int utoa_base(unsigned long long v, char *s, int b, int p, int u)
+{
+ const char *d = u ? "0123456789ABCDEF" : "0123456789abcdef";
+ char buf[65];
+ int i = 0, j;
+ if (p < 0)
+ p = 0;
+ if (p > 64)
+ p = 64;
+ do {
+ buf[i++] = d[v % b];
+ v /= b;
+ } while (v && i < 64);
+ while (i < p && i < 64)
+ buf[i++] = '0';
+ for (j = 0; j < i; ++j)
+ s[j] = buf[i - j - 1];
+ s[i] = 0;
+ return i;
+}
+
+int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap)
+{
+ const char *ptr;
+ int total_printed;
+
+ ptr = format;
+ total_printed = 0;
+
+ while (*ptr != '\0') {
+ if (*ptr != '%') {
+ fputc(*ptr, stream);
+ total_printed++;
+ ptr++;
+ } else {
+ char *s = NULL;
+ char buf[128];
+ int l = 0;
+ int width = 0;
+ int padding = 0;
+ int precision = -1;
+
+ ptr++;
+
+ enum {
+ FLAG_NONE = 0,
+ FLAG_MINUS = 1 << 0,
+ FLAG_PLUS = 1 << 1,
+ FLAG_HASH = 1 << 2,
+ FLAG_ZERO = 1 << 3,
+ FLAG_SPACE = 1 << 4
+ } flags = FLAG_NONE;
+
+ enum {
+ LENGTH_NONE,
+ LENGTH_HH,
+ LENGTH_H,
+ LENGTH_L,
+ LENGTH_LL,
+ LENGTH_J,
+ LENGTH_Z,
+ LENGTH_T,
+ LENGTH_CAPL
+ } length = LENGTH_NONE;
+
+ while (*ptr == '-' || *ptr == '+' || *ptr == ' ' ||
+ *ptr == '0' || *ptr == '#') {
+ if (*ptr == '-')
+ flags |= FLAG_MINUS;
+ else if (*ptr == '+')
+ flags |= FLAG_PLUS;
+ else if (*ptr == ' ')
+ flags |= FLAG_SPACE;
+ else if (*ptr == '0')
+ flags |= FLAG_ZERO;
+ else if (*ptr == '#')
+ flags |= FLAG_HASH;
+ ptr++;
+ }
+
+ if (*ptr == '*') {
+ width = va_arg(ap, int);
+ if (width < 0) {
+ flags |= FLAG_MINUS;
+ width = -width;
+ }
+ ptr++;
+ } else {
+ while (isdigit(*ptr)) {
+ width = width * 10 + (*ptr - '0');
+ ptr++;
+ }
+ }
+
+ if (*ptr == '.') {
+ ptr++;
+ if (*ptr == '*') {
+ precision = va_arg(ap, int);
+ if (precision < 0)
+ precision = -1;
+ ptr++;
+ } else {
+ precision = 0;
+ while (isdigit(*ptr)) {
+ precision = precision * 10 +
+ (*ptr - '0');
+ ptr++;
+ }
+ }
+ }
+
+ switch (*ptr) {
+ case 'h':
+ if (*(ptr + 1) == 'h') {
+ length = LENGTH_HH;
+ ptr++;
+ } else
+ length = LENGTH_H;
+ ptr++;
+ break;
+ case 'l':
+ if (*(ptr + 1) == 'l') {
+ length = LENGTH_LL;
+ ptr++;
+ } else
+ length = LENGTH_L;
+ ptr++;
+ break;
+ case 'L':
+ length = LENGTH_CAPL;
+ ptr++;
+ break;
+ case 'j':
+ length = LENGTH_J;
+ ptr++;
+ break;
+ case 'z':
+ length = LENGTH_Z;
+ ptr++;
+ break;
+ case 't':
+ length = LENGTH_T;
+ ptr++;
+ break;
+ }
+
+ switch (*ptr) {
+ case 'i':
+ case 'd': {
+ long long val;
+ int negative = 0;
+
+ switch (length) {
+ case LENGTH_NONE:
+ val = va_arg(ap, int);
+ break;
+ case LENGTH_HH:
+ val = (signed char)va_arg(ap, int);
+ break;
+ case LENGTH_H:
+ val = (short)va_arg(ap, int);
+ break;
+ case LENGTH_L:
+ val = va_arg(ap, long);
+ break;
+ case LENGTH_LL:
+ val = va_arg(ap, long long);
+ break;
+ case LENGTH_J:
+ val = va_arg(ap, intmax_t);
+ break;
+ case LENGTH_Z:
+ val = va_arg(ap, ssize_t);
+ break;
+ case LENGTH_T:
+ val = va_arg(ap, ptrdiff_t);
+ break;
+ case LENGTH_CAPL:
+ errno = EINVAL;
+ return -1;
+ }
+
+ unsigned long long uval;
+
+ if (val < 0) {
+ uval = (unsigned long long)(-val);
+ negative = 1;
+ } else {
+ uval = (unsigned long long)val;
+ }
+
+ l = utoa_base(uval, buf, 10, precision, 0);
+
+ s = buf;
+ if (negative) {
+ memmove(s + 1, s, l);
+ s[0] = '-';
+ s[++l] = '\0';
+ } else if (flags & FLAG_PLUS) {
+ memmove(s + 1, s, l);
+ s[0] = '+';
+ s[++l] = '\0';
+ } else if (flags & FLAG_SPACE) {
+ memmove(s + 1, s, l);
+ s[0] = ' ';
+ s[++l] = '\0';
+ }
+
+ break;
+ }
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X': {
+ unsigned long long val;
+ char fmt_char = *ptr;
+
+ switch (length) {
+ case LENGTH_NONE:
+ val = va_arg(ap, unsigned int);
+ break;
+ case LENGTH_HH:
+ val = (unsigned char)va_arg(
+ ap, unsigned int);
+ break;
+ case LENGTH_H:
+ val = (unsigned short)va_arg(
+ ap, unsigned int);
+ break;
+ case LENGTH_L:
+ val = va_arg(ap, unsigned long);
+ break;
+ case LENGTH_LL:
+ val = va_arg(ap, unsigned long long);
+ break;
+ case LENGTH_J:
+ val = va_arg(ap, uintmax_t);
+ break;
+ case LENGTH_Z:
+ val = va_arg(ap, size_t);
+ break;
+ case LENGTH_T:
+ val = (ptrdiff_t)va_arg(ap, ptrdiff_t);
+ break;
+ case LENGTH_CAPL:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fmt_char == 'o') {
+ l = utoa_base(val, buf, 8, precision,
+ 0);
+ } else if (fmt_char == 'u') {
+ l = utoa_base(val, buf, 10, precision,
+ 0);
+ } else if (fmt_char == 'x') {
+ l = utoa_base(val, buf, 16, precision,
+ 0);
+ } else if (fmt_char == 'X') {
+ l = utoa_base(val, buf, 16, precision,
+ 1);
+ } else {
+ l = utoa_base(val, buf, 10, precision,
+ 0);
+ }
+
+ s = buf;
+
+ if ((flags & FLAG_HASH) && val != 0) {
+ if (fmt_char == 'o') {
+ memmove(s + 1, s, l);
+ s[0] = '0';
+ s[++l] = '\0';
+ } else if (fmt_char == 'x') {
+ memmove(s + 2, s, l);
+ s[0] = '0';
+ s[1] = 'x';
+ l += 2;
+ s[l] = '\0';
+ } else if (fmt_char == 'X') {
+ memmove(s + 2, s, l);
+ s[0] = '0';
+ s[1] = 'X';
+ l += 2;
+ s[l] = '\0';
+ }
+ }
+
+ break;
+ }
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G': {
+ double val;
+
+ if (length == LENGTH_CAPL)
+ val = (double)va_arg(ap, long double);
+ else
+ val = va_arg(ap, double);
+
+ if (precision == -1)
+ precision = 6;
+
+ s = buf;
+ int pos = 0;
+
+ if (isnan(val)) {
+ strcpy(buf,
+ (*ptr == 'F' || *ptr == 'E' ||
+ *ptr == 'G') ?
+ "NAN" :
+ "nan");
+ l = 3;
+ break;
+ }
+ if (isinf(val)) {
+ if (val < 0) {
+ buf[pos++] = '-';
+ } else if (flags & FLAG_PLUS) {
+ buf[pos++] = '+';
+ } else if (flags & FLAG_SPACE) {
+ buf[pos++] = ' ';
+ }
+ strcpy(buf + pos,
+ (*ptr == 'F' || *ptr == 'E' ||
+ *ptr == 'G') ?
+ "INF" :
+ "inf");
+ l = pos + 3;
+ break;
+ }
+
+ if (val < 0) {
+ buf[pos++] = '-';
+ val = -val;
+ } else if (flags & FLAG_PLUS) {
+ buf[pos++] = '+';
+ } else if (flags & FLAG_SPACE) {
+ buf[pos++] = ' ';
+ }
+
+ switch (*ptr) {
+ case 'f':
+ case 'F': {
+ int decpt, sign;
+ char *rve;
+ char *digits = dtoa(val, 3, precision,
+ &decpt, &sign,
+ &rve);
+
+ if (sign && val != 0.0) {
+ buf[pos++] = '-';
+ }
+
+ if (decpt <= 1 && digits[0] == '0' &&
+ digits[1] == '\0') {
+ buf[pos++] = '0';
+ if (precision > 0) {
+ buf[pos++] = '.';
+ for (int i = 0;
+ i < precision;
+ i++) {
+ buf[pos++] =
+ '0';
+ }
+ }
+ } else if (decpt <= 0) {
+ buf[pos++] = '0';
+ if (precision > 0) {
+ buf[pos++] = '.';
+ for (int i = 0;
+ i < -decpt &&
+ i < precision;
+ i++) {
+ buf[pos++] =
+ '0';
+ }
+ int remaining =
+ precision +
+ decpt;
+ char *d = digits;
+ while (*d &&
+ remaining-- >
+ 0) {
+ buf[pos++] =
+ *d++;
+ }
+ while (remaining-- >
+ 0) {
+ buf[pos++] =
+ '0';
+ }
+ }
+ } else {
+ char *d = digits;
+ int digits_used = 0;
+ for (int i = 0; i < decpt && *d;
+ i++) {
+ buf[pos++] = *d++;
+ digits_used++;
+ }
+ while (digits_used < decpt) {
+ buf[pos++] = '0';
+ digits_used++;
+ }
+ if (precision > 0) {
+ buf[pos++] = '.';
+ for (int i = 0;
+ i < precision;
+ i++) {
+ if (*d) {
+ buf[pos++] =
+ *d++;
+ } else {
+ buf[pos++] =
+ '0';
+ }
+ }
+ }
+ }
+
+ buf[pos] = '\0';
+ l = pos;
+ freedtoa(digits);
+ break;
+ }
+ case 'e':
+ case 'E': {
+ int decpt, sign;
+ char *rve;
+ char *digits =
+ dtoa(val, 2, precision + 1,
+ &decpt, &sign, &rve);
+
+ if (sign && val != 0.0) {
+ buf[pos++] = '-';
+ }
+
+ if (*digits) {
+ buf[pos++] = *digits++;
+ } else {
+ buf[pos++] = '0';
+ }
+
+ if (precision > 0) {
+ buf[pos++] = '.';
+ for (int i = 0; i < precision;
+ i++) {
+ if (*digits) {
+ buf[pos++] =
+ *digits++;
+ } else {
+ buf[pos++] =
+ '0';
+ }
+ }
+ }
+
+ buf[pos++] = (*ptr == 'E') ? 'E' : 'e';
+ int exp = decpt - 1;
+ buf[pos++] = (exp >= 0) ? '+' : '-';
+ if (exp < 0)
+ exp = -exp;
+ if (exp < 10)
+ buf[pos++] = '0';
+ pos += utoa_base(exp, buf + pos, 10, 0,
+ 0);
+
+ buf[pos] = '\0';
+ l = pos;
+ freedtoa(digits);
+ break;
+ }
+ case 'g':
+ case 'G': {
+ int decpt, sign;
+ char *rve;
+ char *digits = dtoa(val, 2, precision,
+ &decpt, &sign,
+ &rve);
+
+ if (sign && val != 0.0) {
+ buf[pos++] = '-';
+ }
+
+ int exp = decpt - 1;
+ if (exp < -4 || exp >= precision) {
+ if (*digits) {
+ buf[pos++] = *digits++;
+ }
+ if (*digits) {
+ buf[pos++] = '.';
+ while (*digits) {
+ buf[pos++] =
+ *digits++;
+ }
+ }
+ buf[pos++] = (*ptr == 'G') ?
+ 'E' :
+ 'e';
+ buf[pos++] = (exp >= 0) ? '+' :
+ '-';
+ if (exp < 0)
+ exp = -exp;
+ if (exp < 10)
+ buf[pos++] = '0';
+ pos += utoa_base(exp, buf + pos,
+ 10, 0, 0);
+ } else {
+ if (decpt <= 0) {
+ buf[pos++] = '0';
+ if (*digits &&
+ *digits != '0') {
+ buf[pos++] =
+ '.';
+ for (int i = 0;
+ i < -decpt;
+ i++) {
+ buf[pos++] =
+ '0';
+ }
+ char *d =
+ digits;
+ while (*d &&
+ *d != '0') {
+ buf[pos++] =
+ *d++;
+ }
+ }
+ } else {
+ char *d = digits;
+ for (int i = 0;
+ i < decpt && *d;
+ i++) {
+ buf[pos++] =
+ *d++;
+ }
+ if (*d) {
+ buf[pos++] =
+ '.';
+ while (*d) {
+ buf[pos++] =
+ *d++;
+ }
+ }
+ }
+ }
+
+ while (pos > 1 && buf[pos - 1] == '0' &&
+ pos > 2 && buf[pos - 2] != 'e' &&
+ buf[pos - 2] != 'E') {
+ pos--;
+ }
+ if (pos > 1 && buf[pos - 1] == '.') {
+ pos--;
+ }
+
+ buf[pos] = '\0';
+ l = pos;
+ freedtoa(digits);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 'a':
+ case 'A': {
+ double val;
+
+ if (length == LENGTH_CAPL)
+ val = (double)va_arg(ap, long double);
+ else
+ val = va_arg(ap, double);
+
+ int upper = (*ptr == 'A');
+ int pos = 0;
+
+ if (val < 0) {
+ buf[pos++] = '-';
+ val = -val;
+ } else if (flags & FLAG_PLUS) {
+ buf[pos++] = '+';
+ } else if (flags & FLAG_SPACE) {
+ buf[pos++] = ' ';
+ }
+
+ if (val == 0.0) {
+ strcpy(buf + pos,
+ upper ? "0X0P+0" : "0x0p+0");
+ l = pos + 6;
+ break;
+ }
+
+ int exp;
+ double mant = frexp(val, &exp);
+ mant *= 2.0;
+ exp--;
+
+ buf[pos++] = '0';
+ buf[pos++] = upper ? 'X' : 'x';
+ buf[pos++] = '1';
+
+ if (precision == -1) {
+ precision = 13;
+ }
+
+ if (precision > 0) {
+ buf[pos++] = '.';
+ mant -= 1.0;
+ for (int i = 0; i < precision; i++) {
+ mant *= 16.0;
+ int digit = (int)mant;
+ if (digit > 15)
+ digit = 15;
+ buf[pos++] =
+ (digit < 10) ?
+ ('0' + digit) :
+ (upper ? ('A' +
+ digit -
+ 10) :
+ ('a' +
+ digit -
+ 10));
+ mant -= digit;
+ }
+
+ while (pos > 0 && buf[pos - 1] == '0') {
+ pos--;
+ }
+ if (pos > 0 && buf[pos - 1] == '.') {
+ pos--;
+ }
+ }
+
+ buf[pos++] = upper ? 'P' : 'p';
+ if (exp >= 0) {
+ buf[pos++] = '+';
+ } else {
+ buf[pos++] = '-';
+ exp = -exp;
+ }
+ pos += utoa_base(exp, buf + pos, 10, 0, 0);
+
+ buf[pos] = '\0';
+ s = buf;
+ l = pos;
+ break;
+ }
+
+ case 'C':
+ length = LENGTH_L;
+ /* fallthrough */
+ case 'c': {
+ if (length == LENGTH_L) {
+ } else {
+ char c = (char)va_arg(ap, int);
+ buf[0] = c;
+ buf[1] = '\0';
+ s = buf;
+ l = 1;
+ }
+ break;
+ }
+
+ case 'S':
+ length = LENGTH_L;
+ /* fallthrough */
+ case 's':
+ if (length == LENGTH_L) {
+ } else {
+ s = va_arg(ap, char *);
+ l = strlen(s);
+ if (precision >= 0 && precision < l)
+ l = precision;
+ }
+ break;
+
+ case 'p': {
+ void *ptr_val = va_arg(ap, void *);
+ uintptr_t uptr = (uintptr_t)ptr_val;
+ int len = utoa_base((unsigned long long)uptr,
+ buf + 2, 16,
+ sizeof(void *) * 2, 0);
+ buf[0] = '0';
+ buf[1] = 'x';
+ buf[len + 2] = '\0';
+ l = len + 2;
+ s = buf;
+ break;
+ }
+
+ case 'n': {
+ int *ip = va_arg(ap, int *);
+ if (ip != NULL) {
+ *ip = total_printed;
+ }
+ l = 0;
+ break;
+ }
+ case '%': {
+ buf[0] = '%';
+ s = buf;
+ l = 1;
+ break;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ptr++;
+
+ if (l < width) {
+ padding = width - l;
+ }
+
+ char format_char = *(ptr - 1);
+ char pad_char = ' ';
+ if ((flags & FLAG_ZERO) && !(flags & FLAG_MINUS) &&
+ (format_char == 'd' || format_char == 'i' ||
+ format_char == 'u' || format_char == 'o' ||
+ format_char == 'x' || format_char == 'X' ||
+ format_char == 'f' || format_char == 'F' ||
+ format_char == 'e' || format_char == 'E' ||
+ format_char == 'g' || format_char == 'G') &&
+ precision < 0) {
+ pad_char = '0';
+ }
+
+ if ((flags & FLAG_MINUS) == 0) {
+ if (pad_char == '0' && s != NULL) {
+ int prefix_len = 0;
+
+ if (s[0] == '-' || s[0] == '+' ||
+ s[0] == ' ') {
+ fwrite(s, 1, 1, stream);
+ total_printed++;
+ s++;
+ l--;
+ prefix_len++;
+ }
+
+ if (l >= 2 && s[0] == '0' &&
+ (s[1] == 'x' || s[1] == 'X')) {
+ fwrite(s, 1, 2, stream);
+ total_printed += 2;
+ s += 2;
+ l -= 2;
+ prefix_len += 2;
+ }
+
+ for (int i = 0; i < padding; i++) {
+ fwrite("0", 1, 1, stream);
+ total_printed++;
+ }
+ } else {
+ for (int i = 0; i < padding; i++) {
+ if (pad_char == '0') {
+ fwrite("0", 1, 1,
+ stream);
+ } else {
+ fwrite(" ", 1, 1,
+ stream);
+ }
+ total_printed++;
+ }
+ }
+ }
+
+ if (l > 0) {
+ if (s != NULL)
+ fwrite(s, 1, l, stream);
+ total_printed += l;
+ }
+
+ if (flags & FLAG_MINUS) {
+ for (int i = 0; i < padding; i++) {
+ fwrite(" ", 1, 1, stream);
+ total_printed++;
+ }
+ }
+ }
+ }
+
+ return total_printed;
+}
diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c
new file mode 100644
index 00000000..10e938b7
--- /dev/null
+++ b/lib/libc/stdio/vprintf.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int vprintf(const char *restrict format, va_list ap)
+{
+ return vfprintf(stdout, format, ap);
+}
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
new file mode 100644
index 00000000..b7a59064
--- /dev/null
+++ b/lib/libc/stdio/vsnprintf.c
@@ -0,0 +1,45 @@
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdatomic.h>
+
+int vsnprintf(char *restrict s, size_t n, const char *restrict format,
+ va_list ap)
+{
+ int r;
+ FILE f;
+
+ if (n == 0) {
+ return 0;
+ }
+
+ if (!s) {
+ return -1;
+ }
+
+ memset(&f, 0, sizeof(f));
+ f.fd = -1;
+ f.flags = O_WRONLY;
+ f.type = _IONBF;
+ atomic_flag_clear(&f.lock);
+ f.buf = s;
+ f.buf_size = n;
+ f.buf_len = 0;
+ f.buf_pos = 0;
+ f.eof = 0;
+ f.unget_cnt = 0;
+ f.offset = 0;
+ f.next = NULL;
+
+ r = vfprintf(&f, format, ap);
+
+ if (f.buf_len < n) {
+ s[f.buf_len] = '\0';
+ } else if (n > 0) {
+ s[n - 1] = '\0';
+ r = n - 1;
+ }
+
+ return r;
+}
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
new file mode 100644
index 00000000..eec52313
--- /dev/null
+++ b/lib/libc/stdio/vsprintf.c
@@ -0,0 +1,7 @@
+#include <stdarg.h>
+#include <stdio.h>
+
+int vsprintf(char *restrict s, const char *restrict format, va_list ap)
+{
+ return vsnprintf(s, (size_t)-1, format, ap);
+}
diff --git a/lib/libc/stdlib/_Exit.c b/lib/libc/stdlib/_Exit.c
new file mode 100644
index 00000000..beb53e34
--- /dev/null
+++ b/lib/libc/stdlib/_Exit.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+_Noreturn void _Exit(int status)
+{
+ _exit(status);
+}
diff --git a/lib/libc/stdlib/__mb_cur_max.c b/lib/libc/stdlib/__mb_cur_max.c
new file mode 100644
index 00000000..2f8affa2
--- /dev/null
+++ b/lib/libc/stdlib/__mb_cur_max.c
@@ -0,0 +1,6 @@
+int __mb_cur_max(void)
+{
+ // TODO: if locale (c/utf8) will be implemented
+ // then return the correct value here if c then 1 else if utf8 then 4
+ return 1;
+}
diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c
new file mode 100644
index 00000000..3d022e70
--- /dev/null
+++ b/lib/libc/stdlib/abort.c
@@ -0,0 +1,27 @@
+#include <atomic.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <asm-generic/signal.h>
+#include <thread.h>
+#include <threads.h>
+#include <unistd.h>
+#include <libc.h>
+
+int raise(int);
+
+_Noreturn void abort(void)
+{
+ struct sigaction sa;
+
+ raise(SIGABRT);
+
+ LIBC_LOCK(libc.lock.abort);
+ sa.sa_handler = SIG_DFL;
+
+ __syscall(rt_sigaction, SIGABRT, &sa, NULL, _NSIG / 8);
+ __syscall(tkill, thrd_current()->tid, SIGABRT);
+
+ // This point should never be reached
+ raise(SIGKILL);
+ _exit(127);
+}
diff --git a/lib/libc/stdlib/abs.c b/lib/libc/stdlib/abs.c
new file mode 100644
index 00000000..ac2bc605
--- /dev/null
+++ b/lib/libc/stdlib/abs.c
@@ -0,0 +1,4 @@
+int abs(int i)
+{
+ return (i < 0) ? -i : i;
+}
diff --git a/lib/libc/stdlib/aligned_alloc.c b/lib/libc/stdlib/aligned_alloc.c
new file mode 100644
index 00000000..f978dfa9
--- /dev/null
+++ b/lib/libc/stdlib/aligned_alloc.c
@@ -0,0 +1,39 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+void *aligned_alloc(size_t alignment, size_t size)
+{
+ if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (size % alignment != 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ size_t total_size = size + alignment - 1 + sizeof(void *);
+
+ void *raw_ptr = malloc(total_size);
+ if (raw_ptr == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ uintptr_t raw_addr = (uintptr_t)raw_ptr;
+ uintptr_t aligned_addr = (raw_addr + sizeof(void *) + alignment - 1) &
+ ~(alignment - 1);
+
+ void **orig_ptr_slot = (void **)(aligned_addr - sizeof(void *));
+ *orig_ptr_slot = raw_ptr;
+
+ return (void *)aligned_addr;
+}
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
new file mode 100644
index 00000000..6c84fd4a
--- /dev/null
+++ b/lib/libc/stdlib/atexit.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+
+static void (*__atexit_fvec[32])(void) = { NULL };
+
+int atexit(void (*func)(void))
+{
+ for (int i = 0; i < 32; i++) {
+ if (__atexit_fvec[i] == NULL) {
+ __atexit_fvec[i] = func;
+ __atexit_fvec[i + 1] = NULL;
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c
new file mode 100644
index 00000000..5f5fc91f
--- /dev/null
+++ b/lib/libc/stdlib/atof.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+double atof(const char *str)
+{
+ return strtod(str, (char **)NULL);
+}
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
new file mode 100644
index 00000000..97b663d1
--- /dev/null
+++ b/lib/libc/stdlib/atoi.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int atoi(const char *str)
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c
new file mode 100644
index 00000000..976f9997
--- /dev/null
+++ b/lib/libc/stdlib/atol.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long atol(const char *nptr)
+{
+ return strtol(nptr, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
new file mode 100644
index 00000000..bea1a031
--- /dev/null
+++ b/lib/libc/stdlib/atoll.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long long atoll(const char *nptr)
+{
+ return strtoll(nptr, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c
new file mode 100644
index 00000000..a2793b0d
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. [rescinded 22 July 1999]
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+
+@deftypefn Supplemental void* bsearch (const void *@var{key}, @
+ const void *@var{base}, size_t @var{nmemb}, size_t @var{size}, @
+ int (*@var{compar})(const void *, const void *))
+
+Performs a search over an array of @var{nmemb} elements pointed to by
+@var{base} for a member that matches the object pointed to by @var{key}.
+The size of each member is specified by @var{size}. The array contents
+should be sorted in ascending order according to the @var{compar}
+comparison function. This routine should take two arguments pointing to
+the @var{key} and to an array member, in that order, and should return an
+integer less than, equal to, or greater than zero if the @var{key} object
+is respectively less than, matching, or greater than the array member.
+
+@end deftypefn
+
+*/
+
+#include <sys/types.h> /* size_t */
+#include <stdio.h>
+
+/*
+ * Perform a binary search.
+ *
+ * The code below is a bit sneaky. After a comparison fails, we
+ * divide the work in half by moving either left or right. If lim
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1. If lim is even, the same applies. If lim
+ * is odd, moving right again involes halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+ * halving: e.g., when lim is 4, we still looked at item 2, so we
+ * have to make lim 3, then halve, obtaining 1, so that we will only
+ * look at item 3.
+ */
+void *bsearch(const void *key, const void *base0, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
+{
+ const char *base = (const char *)base0;
+ int lim, cmp;
+ const void *p;
+
+ for (lim = nmemb; lim != 0; lim >>= 1) {
+ p = base + (lim >> 1) * size;
+ cmp = (*compar)(key, p);
+ if (cmp == 0)
+ return (void *)p;
+ if (cmp > 0) { /* key > p: move right */
+ base = (const char *)p + size;
+ lim--;
+ } /* else move left */
+ }
+ return (NULL);
+}
diff --git a/lib/libc/stdlib/btowc.c b/lib/libc/stdlib/btowc.c
new file mode 100644
index 00000000..f16865b7
--- /dev/null
+++ b/lib/libc/stdlib/btowc.c
@@ -0,0 +1,18 @@
+#include <wchar.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CODEUNIT(c) (0xdfff & (signed char)(c))
+
+wint_t btowc(int c)
+{
+ if ((unsigned char)c < 128U) {
+ return c;
+ }
+
+ if (MB_CUR_MAX == 1 && c != EOF) {
+ return CODEUNIT(c);
+ }
+
+ return WEOF;
+}
diff --git a/lib/libc/stdlib/calloc.c b/lib/libc/stdlib/calloc.c
new file mode 100644
index 00000000..408eef5e
--- /dev/null
+++ b/lib/libc/stdlib/calloc.c
@@ -0,0 +1,25 @@
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+void *calloc(size_t nelem, size_t elsize)
+{
+ void *ptr;
+ size_t total;
+
+ if (nelem == 0 || elsize == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (__builtin_mul_overflow(nelem, elsize, &total)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if ((ptr = malloc(total)) != NULL) {
+ memset(ptr, 0, total);
+ }
+
+ return ptr;
+}
diff --git a/lib/libc/stdlib/div.c b/lib/libc/stdlib/div.c
new file mode 100644
index 00000000..cadc292e
--- /dev/null
+++ b/lib/libc/stdlib/div.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+div_t div(int numer, int denom)
+{
+ div_t result;
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+ return result;
+}
diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c
new file mode 100644
index 00000000..34b8a0f2
--- /dev/null
+++ b/lib/libc/stdlib/exit.c
@@ -0,0 +1,69 @@
+#include <io.h>
+#include <libc.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void (*__dummy_atexit_fvec)(void);
+weak_reference(__dummy_atexit_fvec, __atexit_fvec);
+
+void (*__dummy_stdio_cleanup)(void);
+weak_reference(__dummy_stdio_cleanup, __stdio_cleanup);
+
+static void __fclose(FILE *fp)
+{
+ if (fp == NULL) {
+ return;
+ }
+
+ if (fp->buf_len > 0) {
+ fflush(fp);
+ }
+
+ if (fp->fd > STDERR_FILENO) {
+ close(fp->fd);
+ }
+
+ if (fp->buf) {
+ free(fp->buf);
+ }
+
+ if (fp != stdout && fp != stderr && fp != stdin) {
+ free(fp);
+ }
+}
+
+static void __stdio_cleanup_impl(void)
+{
+ write(1, "HELLO\n", 6);
+ fflush(stdout);
+
+ if (stdout->next != NULL) {
+ FILE *cur = stdout->next;
+ while (cur) {
+ struct __FILE *next = cur->next;
+ __fclose(cur);
+ cur = next;
+ }
+ }
+}
+
+void exit(int status)
+{
+ void (*fptr)(void);
+
+ /* Only do stdio cleanup if it was referenced (meaning stdio was used)
+ */
+ if (__stdio_cleanup) {
+ __stdio_cleanup_impl();
+ }
+
+ if (__atexit_fvec) {
+ fptr = __atexit_fvec;
+ while (fptr) {
+ fptr();
+ fptr++;
+ }
+ }
+
+ _exit(status);
+}
diff --git a/lib/libc/stdlib/free.c b/lib/libc/stdlib/free.c
new file mode 100644
index 00000000..40320dc7
--- /dev/null
+++ b/lib/libc/stdlib/free.c
@@ -0,0 +1,101 @@
+#include <libc.h>
+#include <sys/mman.h>
+#include <atomic.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+void free(void *ptr)
+{
+ if (ptr == NULL) {
+ return;
+ }
+
+ LIBC_LOCK(libc.lock.malloc);
+
+ struct page *p = __malloc_pvec;
+ int found_in_pages = 0;
+
+ while (p) {
+ if ((uintptr_t)ptr >= (uintptr_t)p->heap &&
+ (uintptr_t)ptr < (uintptr_t)(p->heap + (p->block.size *
+ p->block.count))) {
+ size_t offset = (uintptr_t)ptr - (uintptr_t)p->heap;
+ size_t index = offset / p->block.size;
+ size_t byte_index = index / 8;
+ size_t bit_index = index % 8;
+
+ LIBC_LOCK(p->lock);
+ if (p->bitmap[byte_index] & (1 << bit_index)) {
+ p->bitmap[byte_index] &= ~(1 << bit_index);
+ p->block.used--;
+ found_in_pages = 1;
+ }
+ LIBC_UNLOCK(p->lock);
+
+ if (found_in_pages && p->block.used == 0) {
+ if (p->prev)
+ p->prev->next = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ if (p == __malloc_pvec)
+ __malloc_pvec = p->next;
+
+ munmap(p, (p->flags == PAGE_SMALL) ?
+ SMALL_PAGE_SIZE :
+ (p->flags == PAGE_MEDIUM) ?
+ MEDIUM_PAGE_SIZE :
+ LARGE_PAGE_SIZE);
+ }
+
+ LIBC_UNLOCK(libc.lock.malloc);
+ return;
+ }
+ p = p->next;
+ }
+
+ void **orig_ptr_slot = (void **)((uintptr_t)ptr - sizeof(void *));
+ void *potential_orig = *orig_ptr_slot;
+
+ p = __malloc_pvec;
+ while (p) {
+ if ((uintptr_t)potential_orig >= (uintptr_t)p->heap &&
+ (uintptr_t)potential_orig <
+ (uintptr_t)(p->heap +
+ (p->block.size * p->block.count))) {
+ size_t offset =
+ (uintptr_t)potential_orig - (uintptr_t)p->heap;
+ size_t index = offset / p->block.size;
+ size_t byte_index = index / 8;
+ size_t bit_index = index % 8;
+
+ LIBC_LOCK(p->lock);
+ if (p->bitmap[byte_index] & (1 << bit_index)) {
+ p->bitmap[byte_index] &= ~(1 << bit_index);
+ p->block.used--;
+ }
+ LIBC_UNLOCK(p->lock);
+
+ if (p->block.used == 0) {
+ if (p->prev)
+ p->prev->next = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ if (p == __malloc_pvec)
+ __malloc_pvec = p->next;
+
+ munmap(p, (p->flags == PAGE_SMALL) ?
+ SMALL_PAGE_SIZE :
+ (p->flags == PAGE_MEDIUM) ?
+ MEDIUM_PAGE_SIZE :
+ LARGE_PAGE_SIZE);
+ }
+
+ LIBC_UNLOCK(libc.lock.malloc);
+ return;
+ }
+ p = p->next;
+ }
+
+ LIBC_UNLOCK(libc.lock.malloc);
+}
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
new file mode 100644
index 00000000..deb2b5f7
--- /dev/null
+++ b/lib/libc/stdlib/getenv.c
@@ -0,0 +1,33 @@
+#include <libc.h>
+#include <stddef.h>
+#include <atomic.h>
+
+extern char **environ;
+
+char *getenv(const char *name)
+{
+ LIBC_LOCK(libc.lock.environ);
+
+ for (char **env = environ; *env; env++) {
+ char *eq = NULL;
+ for (char *p = *env; *p; p++) {
+ if (*p == '=') {
+ eq = p;
+ break;
+ }
+ if (name[p - *env] != *p) {
+ break;
+ }
+ }
+ if (eq && name[eq - *env] == '\0') {
+ LIBC_UNLOCK(libc.lock.environ);
+ return eq + 1;
+ }
+ }
+
+ LIBC_UNLOCK(libc.lock.environ);
+
+ return NULL;
+}
+
+weak_reference(getenv, secure_getenv);
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
new file mode 100644
index 00000000..101720bb
--- /dev/null
+++ b/lib/libc/stdlib/heapsort.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Swap two areas of size number of bytes. Although qsort(3) permits random
+ * blocks of memory to be sorted, sorting pointers is almost certainly the
+ * common case (and, were it not, could easily be made so). Regardless, it
+ * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
+ * arithmetic gets lost in the time required for comparison function calls.
+ */
+#define SWAP(a, b, count, size, tmp) \
+ { \
+ count = size; \
+ do { \
+ tmp = *a; \
+ *a++ = *b; \
+ *b++ = tmp; \
+ } while (--count); \
+ }
+
+/* Copy one block of size size to another. */
+#define COPY(a, b, count, size, tmp1, tmp2) \
+ { \
+ count = size; \
+ tmp1 = a; \
+ tmp2 = b; \
+ do { \
+ *tmp1++ = *tmp2++; \
+ } while (--count); \
+ }
+
+/*
+ * Build the list into a heap, where a heap is defined such that for
+ * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.
+ *
+ * There two cases. If j == nmemb, select largest of Ki and Kj. If
+ * j < nmemb, select largest of Ki, Kj and Kj+1.
+ */
+#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) \
+ { \
+ for (par_i = initval; (child_i = par_i * 2) <= nmemb; \
+ par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && \
+ compar(child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ if (compar(child, par) <= 0) \
+ break; \
+ SWAP(par, child, count, size, tmp); \
+ } \
+ }
+
+/*
+ * Select the top of the heap and 'heapify'. Since by far the most expensive
+ * action is the call to the compar function, a considerable optimization
+ * in the average case can be achieved due to the fact that k, the displaced
+ * elememt, is ususally quite small, so it would be preferable to first
+ * heapify, always maintaining the invariant that the larger child is copied
+ * over its parent's record.
+ *
+ * Then, starting from the *bottom* of the heap, finding k's correct place,
+ * again maintianing the invariant. As a result of the invariant no element
+ * is 'lost' when k is assigned its correct place in the heap.
+ *
+ * The time savings from this optimization are on the order of 15-20% for the
+ * average case. See Knuth, Vol. 3, page 158, problem 18.
+ *
+ * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.
+ */
+#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) \
+ { \
+ for (par_i = 1; (child_i = par_i * 2) <= nmemb; \
+ par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && \
+ compar(child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ COPY(par, child, count, size, tmp1, tmp2); \
+ } \
+ for (;;) { \
+ child_i = par_i; \
+ par_i = child_i / 2; \
+ child = base + child_i * size; \
+ par = base + par_i * size; \
+ if (child_i == 1 || compar(k, par) < 0) { \
+ COPY(child, k, count, size, tmp1, tmp2); \
+ break; \
+ } \
+ COPY(child, par, count, size, tmp1, tmp2); \
+ } \
+ }
+
+/*
+ * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average
+ * and worst. While heapsort is faster than the worst case of quicksort,
+ * the BSD quicksort does median selection so that the chance of finding
+ * a data set that will trigger the worst case is nonexistent. Heapsort's
+ * only advantage over quicksort is that it requires little additional memory.
+ */
+int heapsort(void *vbase, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
+{
+ size_t cnt;
+ size_t i;
+ size_t j;
+ size_t l;
+ char tmp;
+ char *tmp1;
+ char *tmp2;
+ char *base;
+ char *k;
+ char *p;
+ char *t;
+
+ if (nmemb <= 1) {
+ return (0);
+ }
+
+ if (!size) {
+ // errno = EINVAL;
+ return (-1);
+ }
+
+ if ((k = malloc(size)) == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Items are numbered from 1 to nmemb, so offset from size bytes
+ * below the starting address.
+ */
+ base = (char *)vbase - size;
+
+ for (l = nmemb / 2 + 1; --l;) {
+ CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);
+ }
+
+ /*
+ * For each element of the heap, save the largest element into its
+ * final slot, save the displaced element (k), then recreate the
+ * heap.
+ */
+ while (nmemb > 1) {
+ COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);
+ COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);
+ --nmemb;
+ SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);
+ }
+
+ free(k);
+
+ return (0);
+}
diff --git a/lib/libc/stdlib/heapsort_r.c b/lib/libc/stdlib/heapsort_r.c
new file mode 100644
index 00000000..645f63b0
--- /dev/null
+++ b/lib/libc/stdlib/heapsort_r.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Swap two areas of size number of bytes. Although qsort(3) permits random
+ * blocks of memory to be sorted, sorting pointers is almost certainly the
+ * common case (and, were it not, could easily be made so). Regardless, it
+ * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
+ * arithmetic gets lost in the time required for comparison function calls.
+ */
+#define SWAP(a, b, count, size, tmp) \
+ { \
+ count = size; \
+ do { \
+ tmp = *a; \
+ *a++ = *b; \
+ *b++ = tmp; \
+ } while (--count); \
+ }
+
+/* Copy one block of size size to another. */
+#define COPY(a, b, count, size, tmp1, tmp2) \
+ { \
+ count = size; \
+ tmp1 = a; \
+ tmp2 = b; \
+ do { \
+ *tmp1++ = *tmp2++; \
+ } while (--count); \
+ }
+
+/*
+ * Build the list into a heap, where a heap is defined such that for
+ * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.
+ *
+ * There two cases. If j == nmemb, select largest of Ki and Kj. If
+ * j < nmemb, select largest of Ki, Kj and Kj+1.
+ */
+#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) \
+ { \
+ for (par_i = initval; (child_i = par_i * 2) <= nmemb; \
+ par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && \
+ compar(thunk, child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ if (compar(thunk, child, par) <= 0) \
+ break; \
+ SWAP(par, child, count, size, tmp); \
+ } \
+ }
+
+/*
+ * Select the top of the heap and 'heapify'. Since by far the most expensive
+ * action is the call to the compar function, a considerable optimization
+ * in the average case can be achieved due to the fact that k, the displaced
+ * elememt, is ususally quite small, so it would be preferable to first
+ * heapify, always maintaining the invariant that the larger child is copied
+ * over its parent's record.
+ *
+ * Then, starting from the *bottom* of the heap, finding k's correct place,
+ * again maintianing the invariant. As a result of the invariant no element
+ * is 'lost' when k is assigned its correct place in the heap.
+ *
+ * The time savings from this optimization are on the order of 15-20% for the
+ * average case. See Knuth, Vol. 3, page 158, problem 18.
+ *
+ * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.
+ */
+#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) \
+ { \
+ for (par_i = 1; (child_i = par_i * 2) <= nmemb; \
+ par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && \
+ compar(thunk, child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ COPY(par, child, count, size, tmp1, tmp2); \
+ } \
+ for (;;) { \
+ child_i = par_i; \
+ par_i = child_i / 2; \
+ child = base + child_i * size; \
+ par = base + par_i * size; \
+ if (child_i == 1 || compar(thunk, k, par) < 0) { \
+ COPY(child, k, count, size, tmp1, tmp2); \
+ break; \
+ } \
+ COPY(child, par, count, size, tmp1, tmp2); \
+ } \
+ }
+
+/*
+ * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average
+ * and worst. While heapsort is faster than the worst case of quicksort,
+ * the BSD quicksort does median selection so that the chance of finding
+ * a data set that will trigger the worst case is nonexistent. Heapsort's
+ * only advantage over quicksort is that it requires little additional memory.
+ */
+int heapsort_r(void *vbase, size_t nmemb, size_t size, void *thunk,
+ int (*compar)(void *, const void *, const void *))
+{
+ size_t cnt;
+ size_t i;
+ size_t j;
+ size_t l;
+ char tmp;
+ char *tmp1;
+ char *tmp2;
+ char *base;
+ char *k;
+ char *p;
+ char *t;
+
+ if (nmemb <= 1) {
+ return (0);
+ }
+
+ if (!size) {
+ // errno = EINVAL;
+ return (-1);
+ }
+
+ if ((k = malloc(size)) == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Items are numbered from 1 to nmemb, so offset from size bytes
+ * below the starting address.
+ */
+ base = (char *)vbase - size;
+
+ for (l = nmemb / 2 + 1; --l;) {
+ CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);
+ }
+
+ /*
+ * For each element of the heap, save the largest element into its
+ * final slot, save the displaced element (k), then recreate the
+ * heap.
+ */
+ while (nmemb > 1) {
+ COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);
+ COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);
+ --nmemb;
+ SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);
+ }
+
+ free(k);
+
+ return (0);
+}
diff --git a/lib/libc/stdlib/labs.c b/lib/libc/stdlib/labs.c
new file mode 100644
index 00000000..1413af3a
--- /dev/null
+++ b/lib/libc/stdlib/labs.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long labs(long i)
+{
+ return i < 0 ? -i : i;
+}
diff --git a/lib/libc/stdlib/ldiv.c b/lib/libc/stdlib/ldiv.c
new file mode 100644
index 00000000..9fc62b8d
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+ldiv_t ldiv(long numer, long denom)
+{
+ ldiv_t result;
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+ return result;
+}
diff --git a/lib/libc/stdlib/llabs.c b/lib/libc/stdlib/llabs.c
new file mode 100644
index 00000000..1fadcb98
--- /dev/null
+++ b/lib/libc/stdlib/llabs.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long long llabs(long long i)
+{
+ return (i < 0 ? -i : i);
+}
diff --git a/lib/libc/stdlib/lldiv.c b/lib/libc/stdlib/lldiv.c
new file mode 100644
index 00000000..6df419b3
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+lldiv_t lldiv(long long numer, long long denom)
+{
+ lldiv_t result;
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+ return result;
+}
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
new file mode 100644
index 00000000..3d29e6a8
--- /dev/null
+++ b/lib/libc/stdlib/malloc.c
@@ -0,0 +1,181 @@
+#include <atomic.h>
+#include <features.h>
+#include <libc.h>
+#include <malloc.h>
+#include <linux/errno.h>
+#include <stdatomic.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+struct page *__malloc_pvec = NULL;
+
+static __inline uint32_t get_size_class(size_t size)
+{
+ uintptr_t minblock_count = (size + (16 - 1)) / 16;
+
+ if (size <= (16 * 64)) {
+ return (uint32_t)(minblock_count ? minblock_count : 1);
+ }
+
+ const uint32_t most_significant_bit =
+ (uint32_t)(63 - (int)__builtin_clzll(minblock_count));
+
+ const uint32_t subclass_bits =
+ (minblock_count >> (most_significant_bit - 2)) & 0x03;
+
+ return (uint32_t)((most_significant_bit << 2) + subclass_bits) + 41;
+}
+
+weak void *malloc(size_t size);
+
+void *malloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ LIBC_LOCK(libc.lock.malloc);
+
+ uint32_t class_index = get_size_class(size);
+ if (class_index >=
+ sizeof(global_size_class) / sizeof(global_size_class[0])) {
+ LIBC_UNLOCK(libc.lock.malloc);
+ return NULL;
+ }
+ const struct class *cls = &global_size_class[class_index];
+
+ struct page *p = __malloc_pvec;
+ while (p) {
+ if (p->flags == PAGE_SMALL && cls->size <= 16 * 64) {
+ LIBC_LOCK(p->lock);
+ if (p->block.used < p->block.count &&
+ p->block.size == cls->size) {
+ for (uint32_t i = 0; i < p->block.count; i++) {
+ int byte_index = i / 8;
+ int bit_index = i % 8;
+ if (!(p->bitmap[byte_index] &
+ (1 << bit_index))) {
+ p->bitmap[byte_index] |=
+ (1 << bit_index);
+ p->block.used++;
+ LIBC_UNLOCK(p->lock);
+ LIBC_UNLOCK(libc.lock.malloc);
+ if (p->heap == NULL)
+ return NULL;
+ return p->heap +
+ (i * p->block.size);
+ }
+ }
+ }
+ LIBC_UNLOCK(p->lock);
+ } else if (p->flags == PAGE_MEDIUM && cls->size > 16 * 64 &&
+ cls->size <= 16 * 8192) {
+ LIBC_LOCK(p->lock);
+ if (p->block.used < p->block.count &&
+ p->block.size == cls->size) {
+ for (uint32_t i = 0; i < p->block.count; i++) {
+ int byte_index = i / 8;
+ int bit_index = i % 8;
+ if (!(p->bitmap[byte_index] &
+ (1 << bit_index))) {
+ // Mark block as used
+ p->bitmap[byte_index] |=
+ (1 << bit_index);
+ p->block.used++;
+ LIBC_UNLOCK(p->lock);
+ LIBC_UNLOCK(libc.lock.malloc);
+ if (p->heap == NULL)
+ return NULL;
+ return p->heap +
+ (i * p->block.size);
+ }
+ }
+ }
+ LIBC_UNLOCK(p->lock);
+ } else if (p->flags == PAGE_LARGE && cls->size > 16 * 8192) {
+ LIBC_LOCK(p->lock);
+ if (p->block.used < p->block.count &&
+ p->block.size == cls->size) {
+ // Find free block
+ for (uint32_t i = 0; i < p->block.count; i++) {
+ int byte_index = i / 8;
+ int bit_index = i % 8;
+ if (!(p->bitmap[byte_index] &
+ (1 << bit_index))) {
+ p->bitmap[byte_index] |=
+ (1 << bit_index);
+ p->block.used++;
+ LIBC_UNLOCK(p->lock);
+ LIBC_UNLOCK(libc.lock.malloc);
+
+ if (p->heap == NULL)
+ return NULL;
+ return p->heap +
+ (i * p->block.size);
+ }
+ }
+ }
+ LIBC_UNLOCK(p->lock);
+ }
+ p = p->next;
+ }
+
+ size_t page_size;
+ enum { PAGE_TYPE_SMALL, PAGE_TYPE_MEDIUM, PAGE_TYPE_LARGE } page_type;
+
+ if (cls->size <= 16 * 64) {
+ page_size = SMALL_PAGE_SIZE;
+ page_type = PAGE_TYPE_SMALL;
+ } else if (cls->size <= 16 * 8192) {
+ page_size = MEDIUM_PAGE_SIZE;
+ page_type = PAGE_TYPE_MEDIUM;
+ } else {
+ page_size = LARGE_PAGE_SIZE;
+ page_type = PAGE_TYPE_LARGE;
+ }
+
+ size_t bitmap_size = (cls->count + 7) / 8;
+ void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ if (mem == MAP_FAILED) {
+ LIBC_UNLOCK(libc.lock.malloc);
+ return NULL;
+ }
+
+ struct page *new_page = (struct page *)mem;
+ new_page->flags = (page_type == PAGE_TYPE_SMALL) ? PAGE_SMALL :
+ (page_type == PAGE_TYPE_MEDIUM) ? PAGE_MEDIUM :
+ PAGE_LARGE;
+
+ new_page->block.size = cls->size;
+ new_page->block.used = 0;
+ new_page->block.count = cls->count;
+ new_page->bitmap = (uint8_t *)mem + sizeof(struct page);
+ memset(new_page->bitmap, 0, bitmap_size);
+ new_page->heap = (uint8_t *)mem + sizeof(struct page) + bitmap_size;
+
+ if (new_page->heap == NULL || new_page->bitmap == NULL) {
+ munmap(mem, page_size);
+ LIBC_UNLOCK(libc.lock.malloc);
+ return NULL;
+ }
+ atomic_flag_clear(&new_page->lock);
+ new_page->next = __malloc_pvec;
+ new_page->prev = NULL;
+
+ if (__malloc_pvec) {
+ __malloc_pvec->prev = new_page;
+ }
+
+ __malloc_pvec = new_page;
+
+ // Mark the first block as used and return it
+ new_page->bitmap[0] |= 1;
+ new_page->block.used = 1;
+
+ LIBC_UNLOCK(libc.lock.malloc);
+
+ return new_page->heap;
+}
diff --git a/lib/libc/stdlib/posix_memalign.c b/lib/libc/stdlib/posix_memalign.c
new file mode 100644
index 00000000..a7cbd2a2
--- /dev/null
+++ b/lib/libc/stdlib/posix_memalign.c
@@ -0,0 +1,31 @@
+#include <errno.h>
+#include <stdlib.h>
+
+int posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+ if (memptr == NULL) {
+ return EINVAL;
+ }
+
+ *memptr = NULL;
+
+ if (alignment < sizeof(void *) || alignment % sizeof(void *) != 0 ||
+ (alignment & (alignment - 1)) != 0) {
+ return EINVAL;
+ }
+
+ if (size == 0) {
+ *memptr = NULL;
+ return 0;
+ }
+
+ size_t aligned_size = (size + alignment - 1) & ~(alignment - 1);
+
+ void *ptr = aligned_alloc(alignment, aligned_size);
+ if (ptr == NULL) {
+ return ENOMEM;
+ }
+
+ *memptr = ptr;
+ return 0;
+}
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
new file mode 100644
index 00000000..b070cc4d
--- /dev/null
+++ b/lib/libc/stdlib/putenv.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include <string.h>
+
+int putenv(char *string)
+{
+ const char *const name_end = strchr(string, '=');
+
+ if (name_end) {
+ char name[name_end - string + 1];
+ memcpy(name, string, name_end - string);
+ name[name_end - string] = '\0';
+ return setenv(name, name_end + 1, 1);
+ }
+
+ unsetenv(string);
+ return 0;
+}
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
new file mode 100644
index 00000000..896c79a1
--- /dev/null
+++ b/lib/libc/stdlib/qsort.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+
+static int wrapper(const void *a, const void *b, void *compar)
+{
+ return ((int (*)(const void *, const void *))compar)(a, b);
+}
+
+void qsort(void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *))
+{
+ qsort_r(base, nel, width, wrapper, compar);
+}
diff --git a/lib/libc/stdlib/qsort_r.c b/lib/libc/stdlib/qsort_r.c
new file mode 100644
index 00000000..2fc39a6f
--- /dev/null
+++ b/lib/libc/stdlib/qsort_r.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 2011 by Lynn Ochs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Minor changes by Rich Felker for integration in musl, 2011-04-27. */
+
+/* Smoothsort, an adaptive variant of Heapsort. Memory usage: O(1).
+ Run time: Worst case O(n log n), close to O(n) in the mostly-sorted case. */
+
+#define _BSD_SOURCE
+#include <stdlib.h>
+#include <string.h>
+
+#define ntz(x) __builtin_ctzl((x))
+
+typedef int (*cmpfun)(const void *, const void *, void *);
+
+static inline int pntz(size_t p[2])
+{
+ int r = ntz(p[0] - 1);
+ if (r != 0 ||
+ (r = 8 * sizeof(size_t) + ntz(p[1])) != 8 * sizeof(size_t)) {
+ return r;
+ }
+ return 0;
+}
+
+static void cycle(size_t width, unsigned char *ar[], int n)
+{
+ unsigned char tmp[256];
+ size_t l;
+ int i;
+
+ if (n < 2) {
+ return;
+ }
+
+ ar[n] = tmp;
+ while (width) {
+ l = sizeof(tmp) < width ? sizeof(tmp) : width;
+ memcpy(ar[n], ar[0], l);
+ for (i = 0; i < n; i++) {
+ memcpy(ar[i], ar[i + 1], l);
+ ar[i] += l;
+ }
+ width -= l;
+ }
+ ar[n] = NULL;
+}
+
+/* shl() and shr() need n > 0 */
+static inline void shl(size_t p[2], int n)
+{
+ if (n >= 8 * sizeof(size_t)) {
+ n -= 8 * sizeof(size_t);
+ p[1] = p[0];
+ p[0] = 0;
+ }
+ p[1] <<= n;
+ p[1] |= (n < sizeof(size_t) * 8) ? p[0] >> (sizeof(size_t) * 8 - n) : 0;
+ p[0] <<= n;
+}
+
+static inline void shr(size_t p[2], int n)
+{
+ size_t bits = sizeof(size_t) * 8;
+
+ if (n >= 8 * sizeof(size_t)) {
+ n -= 8 * sizeof(size_t);
+ p[0] = p[1];
+ p[1] = 0;
+ }
+
+ p[0] >>= n;
+ p[0] |= (n > 0 && n < bits) ? p[1] << (bits - n) : 0;
+ p[1] >>= n;
+}
+
+static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg,
+ int pshift, size_t lp[])
+{
+ unsigned char *rt, *lf;
+ unsigned char *ar[14 * sizeof(size_t) + 1];
+ int i = 1;
+
+ ar[0] = head;
+ while (pshift > 1) {
+ rt = head - width;
+ lf = head - width - lp[pshift - 2];
+
+ if (cmp(ar[0], lf, arg) >= 0 && cmp(ar[0], rt, arg) >= 0) {
+ break;
+ }
+ if (cmp(lf, rt, arg) >= 0) {
+ ar[i++] = lf;
+ head = lf;
+ pshift -= 1;
+ } else {
+ ar[i++] = rt;
+ head = rt;
+ pshift -= 2;
+ }
+ }
+ cycle(width, ar, i);
+}
+
+static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg,
+ size_t pp[2], int pshift, int trusty, size_t lp[],
+ int max_lp_index)
+{
+ unsigned char *stepson, *rt, *lf;
+ size_t p[2];
+ unsigned char *ar[14 * sizeof(size_t) + 1];
+ int i = 1;
+ int trail;
+
+ p[0] = pp[0];
+ p[1] = pp[1];
+
+ ar[0] = head;
+ while (p[0] != 1 || p[1] != 0) {
+ if (pshift < 0 || pshift > max_lp_index || pshift >= 64)
+ break;
+
+ stepson = head - lp[pshift];
+ if (cmp(stepson, ar[0], arg) <= 0) {
+ break;
+ }
+ if (!trusty && pshift > 1 && pshift - 2 >= 0 &&
+ pshift - 2 <= max_lp_index) {
+ rt = head - width;
+ lf = head - width - lp[pshift - 2];
+ if (cmp(rt, stepson, arg) >= 0 ||
+ cmp(lf, stepson, arg) >= 0) {
+ break;
+ }
+ }
+
+ ar[i++] = stepson;
+ head = stepson;
+ trail = pntz(p);
+ shr(p, trail);
+ pshift += trail;
+ trusty = 0;
+ }
+ if (!trusty) {
+ cycle(width, ar, i);
+ sift(head, width, cmp, arg, pshift, lp);
+ }
+}
+
+void qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg)
+{
+ size_t lp[64];
+ size_t i, size = width * nel;
+ unsigned char *head, *high;
+ size_t p[2] = { 1, 0 };
+ int pshift = 1;
+ int trail;
+ int max_lp_index;
+
+ if (!size)
+ return;
+
+ head = base;
+ high = head + size - width;
+
+ /* Precompute Leonardo numbers, scaled by element width */
+ for (lp[0] = lp[1] = width, i = 2;
+ (lp[i] = lp[i - 2] + lp[i - 1] + width) < size && i < 63; i++)
+ ;
+ max_lp_index = i - 1;
+
+ while (head < high) {
+ if ((p[0] & 3) == 3) {
+ sift(head, width, cmp, arg, pshift, lp);
+ shr(p, 2);
+ pshift += 2;
+ } else {
+ if (pshift - 1 >= 0 && pshift - 1 <= max_lp_index &&
+ lp[pshift - 1] >= high - head) {
+ trinkle(head, width, cmp, arg, p, pshift, 0, lp,
+ max_lp_index);
+ } else {
+ sift(head, width, cmp, arg, pshift, lp);
+ }
+
+ if (pshift == 1) {
+ shl(p, 1);
+ pshift = 0;
+ } else {
+ shl(p, pshift - 1);
+ pshift = 1;
+ }
+ }
+
+ p[0] |= 1;
+ head += width;
+ }
+
+ trinkle(head, width, cmp, arg, p, pshift, 0, lp, max_lp_index);
+
+ while (pshift != 1 || p[0] != 1 || p[1] != 0) {
+ if (pshift <= 1) {
+ trail = pntz(p);
+ shr(p, trail);
+ pshift += trail;
+ } else {
+ shl(p, 2);
+ pshift -= 2;
+ p[0] ^= 7;
+ shr(p, 1);
+ if (pshift >= 0 && pshift <= max_lp_index &&
+ pshift < 64) {
+ trinkle(head - lp[pshift] - width, width, cmp,
+ arg, p, pshift + 1, 1, lp,
+ max_lp_index);
+ }
+ shl(p, 1);
+ p[0] |= 1;
+ trinkle(head - width, width, cmp, arg, p, pshift, 1, lp,
+ max_lp_index);
+ }
+ head -= width;
+ }
+}
diff --git a/lib/libc/stdlib/quick_exit.c b/lib/libc/stdlib/quick_exit.c
new file mode 100644
index 00000000..15587d17
--- /dev/null
+++ b/lib/libc/stdlib/quick_exit.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+_Noreturn void quick_exit(int status)
+{
+ _Exit(status);
+}
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
new file mode 100644
index 00000000..878aa0e2
--- /dev/null
+++ b/lib/libc/stdlib/rand.c
@@ -0,0 +1,182 @@
+/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
+
+To the extent possible under law, the author has dedicated all copyright
+and related and neighboring rights to this software to the public domain
+worldwide.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#define UINT64_C(c) ((uint64_t)(c##ULL))
+
+typedef struct {
+ uint64_t s[4];
+} xoshiro256_state;
+
+typedef struct {
+ uint64_t s[4];
+} erand48_state;
+
+static xoshiro256_state __xoshiro256_state;
+static erand48_state __erand48_state;
+
+/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
+ generators. It has excellent (sub-ns) speed, a state (256 bits) that is
+ large enough for any parallel application, and it passes all tests we
+ are aware of.
+
+ For generating just floating-point numbers, xoshiro256+ is even faster.
+
+ The state must be seeded so that it is not everywhere zero. If you have
+ a 64-bit seed, we suggest to seed a splitmix64 generator and use its
+ output to fill s. */
+
+static inline uint64_t rotl(const uint64_t x, int k)
+{
+ return (x << k) | (x >> (64 - k));
+}
+
+uint64_t xoshiro256_next(xoshiro256_state *st)
+{
+ const uint64_t result = rotl(st->s[1] * 5, 7) * 9;
+
+ const uint64_t t = st->s[1] << 17;
+
+ st->s[2] ^= st->s[0];
+ st->s[3] ^= st->s[1];
+ st->s[1] ^= st->s[2];
+ st->s[0] ^= st->s[3];
+
+ st->s[2] ^= t;
+
+ st->s[3] = rotl(st->s[3], 45);
+
+ return result;
+}
+
+/* Written in 2015 by Sebastiano Vigna (vigna@acm.org)
+
+To the extent possible under law, the author has dedicated all copyright
+and related and neighboring rights to this software to the public domain
+worldwide. This software is distributed without any warranty.
+
+See <http://creativecommons.org/publicdomain/zero/1.0/>. */
+
+/* This is a fixed-increment version of Java 8's SplittableRandom generator
+ See http://dx.doi.org/10.1145/2714064.2660195 and
+ http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
+
+ It is a very fast generator passing BigCrush, and it can be useful if
+ for some reason you absolutely want 64 bits of state; otherwise, we
+ rather suggest to use a xoroshiro128+ (for moderately parallel
+ computations) or xorshift1024* (for massively parallel computations)
+ generator. */
+
+uint64_t splitmix64(uint64_t *x)
+{
+ uint64_t z = (*x += UINT64_C(0x9E3779B97F4A7C15));
+ z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
+ z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
+ return z ^ (z >> 31);
+}
+
+void srand(unsigned int seed)
+{
+ uint64_t z = (uint64_t)seed;
+ __xoshiro256_state.s[0] = splitmix64(&z);
+ __xoshiro256_state.s[1] = splitmix64(&z);
+ __xoshiro256_state.s[2] = splitmix64(&z);
+ __xoshiro256_state.s[3] = splitmix64(&z);
+}
+
+int rand(void)
+{
+ return (int)(xoshiro256_next(&__xoshiro256_state) & (uint64_t)RAND_MAX);
+}
+
+void srandom(unsigned seed)
+{
+ srand(seed);
+}
+
+long random(void)
+{
+ return (long)rand();
+}
+
+void srand48(long seedval)
+{
+ uint64_t z = (uint64_t)seedval;
+ __erand48_state.s[0] = splitmix64(&z);
+ __erand48_state.s[1] = splitmix64(&z);
+ __erand48_state.s[2] = splitmix64(&z);
+ __erand48_state.s[3] = splitmix64(&z);
+}
+
+double drand48(void)
+{
+ uint64_t v = xoshiro256_next((xoshiro256_state *)&__erand48_state);
+ return (double)(v >> 11) * (1.0 / 9007199254740992.0); // 53-bit
+ // mantissa
+}
+
+long lrand48(void)
+{
+ uint64_t v = xoshiro256_next((xoshiro256_state *)&__erand48_state);
+ return (long)(v & 0x7FFFFFFF); // 31-bit
+}
+
+long mrand48(void)
+{
+ uint64_t v = xoshiro256_next((xoshiro256_state *)&__erand48_state);
+ return (long)(v & 0xFFFFFFFF); // 32-bit signed
+}
+
+double erand48(unsigned short xsubi[3])
+{
+ xoshiro256_state st = { 0 };
+ for (int i = 0; i < 3; i++)
+ st.s[i] = xsubi[i];
+ st.s[3] = 0xdeadbeef;
+ uint64_t v = xoshiro256_next(&st);
+ return (double)(v >> 11) * (1.0 / 9007199254740992.0);
+}
+
+long nrand48(unsigned short xsubi[3])
+{
+ xoshiro256_state st = { 0 };
+ for (int i = 0; i < 3; i++)
+ st.s[i] = xsubi[i];
+ st.s[3] = 0xdeadbeef;
+ uint64_t v = xoshiro256_next(&st);
+ return (long)(v & 0x7FFFFFFF);
+}
+
+long jrand48(unsigned short xsubi[3])
+{
+ xoshiro256_state st = { 0 };
+ for (int i = 0; i < 3; i++)
+ st.s[i] = xsubi[i];
+ st.s[3] = 0xdeadbeef;
+ uint64_t v = xoshiro256_next(&st);
+ return (long)(v & 0xFFFFFFFF);
+}
+
+unsigned short *seed48(unsigned short seed16v[3])
+{
+ for (int i = 0; i < 3; i++)
+ __erand48_state.s[i] = seed16v[i];
+ __erand48_state.s[3] = 0xdeadbeef;
+ return seed16v;
+}
diff --git a/lib/libc/stdlib/realloc.c b/lib/libc/stdlib/realloc.c
new file mode 100644
index 00000000..d90af70d
--- /dev/null
+++ b/lib/libc/stdlib/realloc.c
@@ -0,0 +1,47 @@
+#include <errno.h>
+#include <string.h>
+#include <atomic.h>
+#include <libc.h>
+#include <malloc.h>
+#include <linux/errno.h>
+#include <stdlib.h>
+
+void *realloc(void *ptr, size_t size)
+{
+ if (ptr == NULL) {
+ return malloc(size);
+ }
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ }
+
+ LIBC_LOCK(libc.lock.malloc);
+
+ struct page *p = __malloc_pvec;
+ while (p) {
+ if ((uintptr_t)ptr >= (uintptr_t)p->heap &&
+ (uintptr_t)ptr < (uintptr_t)(p->heap + (p->block.size *
+ p->block.count))) {
+ size_t old_size = p->block.size;
+ LIBC_UNLOCK(libc.lock.malloc);
+
+ if (size <= old_size) {
+ return ptr;
+ } else {
+ void *new_ptr = malloc(size);
+ if (new_ptr) {
+ memcpy(new_ptr, ptr, old_size);
+ free(ptr);
+ }
+ return new_ptr;
+ }
+ }
+ p = p->next;
+ }
+
+ LIBC_UNLOCK(libc.lock.malloc);
+
+ errno = EINVAL;
+ return NULL;
+}
diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c
new file mode 100644
index 00000000..4dd1a6c8
--- /dev/null
+++ b/lib/libc/stdlib/reallocarray.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/errno.h>
+#include <malloc.h>
+
+void *reallocarray(void *ptr, size_t nmemb, size_t size)
+{
+ size_t total = nmemb * size;
+ if (nmemb != 0 && total / nmemb != size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(ptr, total);
+}
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
new file mode 100644
index 00000000..1464fc1b
--- /dev/null
+++ b/lib/libc/stdlib/setenv.c
@@ -0,0 +1,58 @@
+#include <libc.h>
+#include <atomic.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char **environ;
+
+int setenv(const char *var, const char *value, int overwrite)
+{
+ char **env = environ;
+ size_t var_len = strlen(var);
+
+ for (; *env; env++) {
+ char *eq = strchr(*env, '=');
+ if (eq && ((size_t)(eq - *env) == var_len) &&
+ !strncmp(*env, var, var_len)) {
+ if (overwrite) {
+ size_t value_len = strlen(value);
+ char *new_env =
+ malloc(var_len + 1 + value_len + 1);
+ if (!new_env)
+ return -1;
+ memcpy(new_env, var, var_len);
+ new_env[var_len] = '=';
+ memcpy(new_env + var_len + 1, value,
+ value_len + 1);
+ *env = new_env;
+ }
+ return 0;
+ }
+ }
+
+ size_t env_count = 0;
+ while (environ[env_count])
+ env_count++;
+
+ char **new_envp = realloc(environ, (env_count + 2) * sizeof(char *));
+ if (!new_envp)
+ return -1;
+
+ size_t value_len = strlen(value);
+ char *new_var = malloc(var_len + 1 + value_len + 1);
+ if (!new_var)
+ return -1;
+
+ memcpy(new_var, var, var_len);
+ new_var[var_len] = '=';
+ memcpy(new_var + var_len + 1, value, value_len + 1);
+
+ new_envp[env_count] = new_var;
+ new_envp[env_count + 1] = NULL;
+ LIBC_LOCK(libc.lock.environ);
+ environ = new_envp;
+ LIBC_UNLOCK(libc.lock.environ);
+ libc.flags |= LIBC_ENVP_TOUCHED;
+
+ return 0;
+}
diff --git a/lib/libc/stdlib/strtox.c b/lib/libc/stdlib/strtox.c
new file mode 100644
index 00000000..9d72954a
--- /dev/null
+++ b/lib/libc/stdlib/strtox.c
@@ -0,0 +1,270 @@
+#include <ctype.h>
+#include <float.h>
+#include <errno.h>
+#include <strings.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+
+static unsigned long long
+__scanint(const char *s, int base, unsigned long long lim, int *neg, char **end)
+{
+ unsigned long long res = 0;
+ int digit, any = 0;
+
+ while (isspace((unsigned char)*s))
+ s++;
+
+ *neg = 0;
+ if (*s == '+' || *s == '-') {
+ *neg = (*s == '-');
+ s++;
+ }
+
+ if ((base == 0 || base == 16) && s[0] == '0' &&
+ (s[1] == 'x' || s[1] == 'X')) {
+ base = 16;
+ s += 2;
+ } else if (base == 0 && *s == '0') {
+ base = 8;
+ s++;
+ } else if (base == 0) {
+ base = 10;
+ }
+
+ for (; *s; s++) {
+ unsigned char c = *s;
+ if (isdigit(c))
+ digit = c - '0';
+ else if (isalpha(c))
+ digit = toupper(c) - 'A' + 10;
+ else
+ break;
+
+ if (digit >= base)
+ break;
+ if (res > (lim - digit) / base) {
+ errno = ERANGE;
+ res = lim;
+ any = 1;
+ while (1) {
+ if (isalnum((unsigned char)*++s) == 0)
+ break;
+ }
+ break;
+ }
+ res = res * base + digit;
+ any = 1;
+ }
+
+ if (end)
+ *end = (char *)(any ? s : s - 1);
+
+ return res;
+}
+
+static long double __scanfloat(const char *s, char **end)
+{
+ long double value = 0.0;
+ long double frac = 0.0;
+ long double sign = 1.0;
+ long double scale = 1.0;
+ int exp_sign = 1;
+ long exp_val = 0;
+ int got_digit = 0;
+
+ while (isspace((unsigned char)*s))
+ s++;
+
+ if (*s == '+' || *s == '-') {
+ if (*s == '-')
+ sign = -1.0;
+ s++;
+ }
+
+ if (strncasecmp(s, "inf", 3) == 0) {
+ s += 3;
+ if (strncasecmp(s, "inity", 5) == 0)
+ s += 5;
+ if (end)
+ *end = (char *)s;
+ return sign * INFINITY;
+ }
+ if (strncasecmp(s, "nan", 3) == 0) {
+ s += 3;
+ if (*s == '(') {
+ s++;
+ while (*s && *s != ')')
+ s++;
+ if (*s == ')')
+ s++;
+ }
+ if (end)
+ *end = (char *)s;
+ return NAN;
+ }
+
+ while (isdigit((unsigned char)*s)) {
+ value = value * 10.0 + (*s - '0');
+ s++;
+ got_digit = 1;
+ }
+
+ if (*s == '.') {
+ s++;
+ while (isdigit((unsigned char)*s)) {
+ value = value * 10.0 + (*s - '0');
+ scale *= 10.0;
+ s++;
+ got_digit = 1;
+ }
+ }
+
+ if (!got_digit) {
+ if (end)
+ *end = (char *)s;
+ return 0.0;
+ }
+
+ value = value / scale;
+
+ if (*s == 'e' || *s == 'E') {
+ const char *p = ++s;
+ if (*p == '+' || *p == '-') {
+ exp_sign = (*p == '-') ? -1 : 1;
+ p++;
+ }
+ while (isdigit((unsigned char)*p)) {
+ exp_val = exp_val * 10 + (*p - '0');
+ p++;
+ }
+ s = p;
+ value *= powl(10.0, exp_sign * exp_val);
+ }
+
+ if (end)
+ *end = (char *)s;
+
+ return sign * value;
+}
+
+long strtol(const char *restrict nptr, char **restrict endptr, int base)
+{
+ int neg;
+ unsigned long long lim;
+ unsigned long long v;
+
+ const char *p = nptr;
+ while (isspace((unsigned char)*p))
+ p++;
+ int is_neg = (*p == '-');
+ lim = is_neg ? (unsigned long long)LONG_MAX + 1ULL : LONG_MAX;
+
+ v = __scanint(nptr, base, lim, &neg, endptr);
+
+ if (neg)
+ return (v == lim) ? LONG_MIN : -(long)v;
+ else
+ return (v > LONG_MAX) ? (errno = ERANGE, LONG_MAX) : (long)v;
+}
+
+long long strtoll(const char *restrict nptr, char **restrict endptr, int base)
+{
+ int neg;
+ unsigned long long lim;
+ unsigned long long v;
+
+ const char *p = nptr;
+ while (isspace((unsigned char)*p))
+ p++;
+ int is_neg = (*p == '-');
+
+ lim = is_neg ? (unsigned long long)LLONG_MAX + 1ULL : LLONG_MAX;
+
+ v = __scanint(nptr, base, lim, &neg, endptr);
+
+ if (neg) {
+ if (v == lim)
+ return LLONG_MIN;
+ else
+ return -(long long)v;
+ } else {
+ if (v > LLONG_MAX) {
+ errno = ERANGE;
+ return LLONG_MAX;
+ } else
+ return (long long)v;
+ }
+}
+
+unsigned long strtoul(const char *restrict nptr, char **restrict endptr,
+ int base)
+{
+ int neg;
+ unsigned long long v;
+
+ v = __scanint(nptr, base, ULONG_MAX, &neg, endptr);
+
+ if (neg) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (v > ULONG_MAX) {
+ errno = ERANGE;
+ return ULONG_MAX;
+ }
+
+ return (unsigned long)v;
+}
+
+unsigned long long strtoull(const char *restrict nptr, char **restrict endptr,
+ int base)
+{
+ int neg;
+ unsigned long long v;
+
+ v = __scanint(nptr, base, ULLONG_MAX, &neg, endptr);
+
+ if (neg) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (v > ULLONG_MAX) {
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+
+ return v;
+}
+
+float strtof(const char *restrict nptr, char **restrict endptr)
+{
+ long double val = __scanfloat(nptr, endptr);
+
+ if (val > FLT_MAX) {
+ errno = ERANGE;
+ return HUGE_VALF;
+ } else if (val < -FLT_MAX) {
+ errno = ERANGE;
+ return -HUGE_VALF;
+ }
+
+ return (float)val;
+}
+
+long double strtold(const char *restrict nptr, char **restrict endptr)
+{
+ long double val = __scanfloat(nptr, endptr);
+
+ if (val > LDBL_MAX) {
+ errno = ERANGE;
+ return LDBL_MAX;
+ } else if (val < -LDBL_MAX) {
+ errno = ERANGE;
+ return -LDBL_MAX;
+ }
+
+ return val;
+}
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
new file mode 100644
index 00000000..4f560ce1
--- /dev/null
+++ b/lib/libc/stdlib/system.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+int system(const char *command)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/stdlib/unsetenv.c b/lib/libc/stdlib/unsetenv.c
new file mode 100644
index 00000000..4eb11d57
--- /dev/null
+++ b/lib/libc/stdlib/unsetenv.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+int unsetenv(const char *name)
+{
+ if (name == NULL || *name == '\0' || strchr(name, '=')) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return setenv(name, NULL, 1);
+}
diff --git a/lib/libc/stdlib/wctomb.c b/lib/libc/stdlib/wctomb.c
new file mode 100644
index 00000000..d971ffae
--- /dev/null
+++ b/lib/libc/stdlib/wctomb.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <wchar.h>
+
+int wctomb(char *s, wchar_t wc)
+{
+ if (s == NULL)
+ return 0;
+ return wcrtomb(s, wc, 0);
+}
diff --git a/lib/libc/string/memccpy.c b/lib/libc/string/memccpy.c
new file mode 100644
index 00000000..29828182
--- /dev/null
+++ b/lib/libc/string/memccpy.c
@@ -0,0 +1,13 @@
+#include <stddef.h>
+
+void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n)
+{
+ const unsigned char *p2 = s2;
+ unsigned char *p1 = s1;
+ while (n--) {
+ if (*p2 == (unsigned char)c)
+ return p1 + 1;
+ *p1++ = *p2++;
+ }
+ return NULL;
+}
diff --git a/lib/libc/string/memchr.c b/lib/libc/string/memchr.c
new file mode 100644
index 00000000..38850aed
--- /dev/null
+++ b/lib/libc/string/memchr.c
@@ -0,0 +1,12 @@
+#include <stddef.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+ const unsigned char *p = s;
+ while (n--) {
+ if (*p == (unsigned char)c)
+ return (void *)p;
+ p++;
+ }
+ return NULL;
+}
diff --git a/lib/libc/string/memcmp.c b/lib/libc/string/memcmp.c
new file mode 100644
index 00000000..5efb282f
--- /dev/null
+++ b/lib/libc/string/memcmp.c
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *p1 = s1;
+ const unsigned char *p2 = s2;
+ while (n--) {
+ if (*p1 != *p2)
+ return *p1 - *p2;
+ p1++;
+ p2++;
+ }
+ return 0;
+}
diff --git a/lib/libc/string/memcpy.c b/lib/libc/string/memcpy.c
new file mode 100644
index 00000000..505cc622
--- /dev/null
+++ b/lib/libc/string/memcpy.c
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <features.h>
+
+weak void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
+
+void *memcpy(void *restrict s1, const void *restrict s2, size_t n)
+{
+ unsigned char *dest = (unsigned char *)s1;
+ const unsigned char *src = (const unsigned char *)s2;
+
+ while (n--) {
+ *dest++ = *src++;
+ }
+
+ return s1;
+}
diff --git a/lib/libc/string/memmem.c b/lib/libc/string/memmem.c
new file mode 100644
index 00000000..7a450cf7
--- /dev/null
+++ b/lib/libc/string/memmem.c
@@ -0,0 +1,15 @@
+#include <string.h>
+
+void *memmem(const void *haystack, size_t haystacklen, const void *needle,
+ size_t needlelen)
+{
+ const unsigned char *p1 = haystack;
+ const unsigned char *p2 = needle;
+ while (haystacklen >= needlelen) {
+ if (!memcmp(p1, p2, needlelen))
+ return (void *)p1;
+ p1++;
+ haystacklen--;
+ }
+ return NULL;
+}
diff --git a/lib/libc/string/memmove.c b/lib/libc/string/memmove.c
new file mode 100644
index 00000000..88968185
--- /dev/null
+++ b/lib/libc/string/memmove.c
@@ -0,0 +1,21 @@
+#include <stddef.h>
+#include <stdint.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ uint8_t *d = dst;
+ const uint8_t *s = src;
+
+ if (d == s || n == 0)
+ return dst;
+
+ if ((uintptr_t)d < (uintptr_t)s) {
+ for (size_t i = 0; i < n; i++)
+ d[i] = s[i];
+ } else {
+ for (size_t i = n; i != 0; i--)
+ d[i - 1] = s[i - 1];
+ }
+
+ return dst;
+}
diff --git a/lib/libc/string/memset.c b/lib/libc/string/memset.c
new file mode 100644
index 00000000..da969d16
--- /dev/null
+++ b/lib/libc/string/memset.c
@@ -0,0 +1,10 @@
+#include <string.h>
+
+void *memset(void *s, int c, size_t n)
+{
+ unsigned char *p = s;
+ while (n--) {
+ *p++ = (unsigned char)c;
+ }
+ return s;
+}
diff --git a/lib/libc/string/stpcpy.c b/lib/libc/string/stpcpy.c
new file mode 100644
index 00000000..04c3a17f
--- /dev/null
+++ b/lib/libc/string/stpcpy.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+char *stpcpy(char *restrict s1, const char *restrict s2)
+{
+ while ((*s1++ = *s2++))
+ ;
+ return s1 - 1;
+}
diff --git a/lib/libc/string/stpncpy.c b/lib/libc/string/stpncpy.c
new file mode 100644
index 00000000..8f7ebd01
--- /dev/null
+++ b/lib/libc/string/stpncpy.c
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+char *strncpy(char *restrict s1, const char *restrict s2, size_t n)
+{
+ char *d = s1;
+
+ while (n-- && *s2)
+ *d++ = *s2++;
+
+ while (n--)
+ *d++ = '\0';
+
+ return s1;
+}
diff --git a/lib/libc/string/strcat.c b/lib/libc/string/strcat.c
new file mode 100644
index 00000000..6caf8c78
--- /dev/null
+++ b/lib/libc/string/strcat.c
@@ -0,0 +1,14 @@
+char *strcat(char *restrict s1, const char *restrict s2)
+{
+ char *d = s1;
+
+ while (*d)
+ d++;
+
+ while (*s2)
+ *d++ = *s2++;
+
+ *d = '\0';
+
+ return s1;
+}
diff --git a/lib/libc/string/strchr.c b/lib/libc/string/strchr.c
new file mode 100644
index 00000000..db632a2e
--- /dev/null
+++ b/lib/libc/string/strchr.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *strchr(const char *s, int c)
+{
+ while (*s) {
+ if (*s == (char)c)
+ return (char *)s;
+ s++;
+ }
+ if (c == 0)
+ return (char *)s;
+ return NULL;
+}
diff --git a/lib/libc/string/strcmp.c b/lib/libc/string/strcmp.c
new file mode 100644
index 00000000..836522f1
--- /dev/null
+++ b/lib/libc/string/strcmp.c
@@ -0,0 +1,23 @@
+#include <stddef.h>
+
+int strcmp(const char *s1, const char *s2)
+{
+ const unsigned char *p1 = (const unsigned char *)s1;
+ const unsigned char *p2 = (const unsigned char *)s2;
+
+ if (p1 == NULL && p2 == NULL)
+ return 0;
+
+ if (p1 == NULL)
+ return -1;
+
+ if (p2 == NULL)
+ return 1;
+
+ while (*p1 == *p2 && *p1 != '\0') {
+ p1++;
+ p2++;
+ }
+
+ return *p1 - *p2;
+}
diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c
new file mode 100644
index 00000000..6b2e532a
--- /dev/null
+++ b/lib/libc/string/strcoll.c
@@ -0,0 +1,13 @@
+#include <libc.h>
+#include <string.h>
+#include <locale.h>
+
+int strcoll(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+weak int strcoll_l(const char *s1, const char *s2, locale_t unused locale)
+{
+ return strcoll(s1, s2);
+}
diff --git a/lib/libc/string/strcpy.c b/lib/libc/string/strcpy.c
new file mode 100644
index 00000000..8e1dab69
--- /dev/null
+++ b/lib/libc/string/strcpy.c
@@ -0,0 +1,7 @@
+char *strcpy(char *restrict s1, const char *restrict s2)
+{
+ char *p = s1;
+ while ((*p++ = *s2++) != '\0')
+ ;
+ return s1;
+}
diff --git a/lib/libc/string/strcspn.c b/lib/libc/string/strcspn.c
new file mode 100644
index 00000000..9f1f2bcd
--- /dev/null
+++ b/lib/libc/string/strcspn.c
@@ -0,0 +1,11 @@
+#include <string.h>
+
+size_t strcspn(const char *s1, const char *s2)
+{
+ size_t len = 0;
+ while (*s1 != '\0' && strchr(s2, *s1) == NULL) {
+ s1++;
+ len++;
+ }
+ return len;
+}
diff --git a/lib/libc/string/strdup.c b/lib/libc/string/strdup.c
new file mode 100644
index 00000000..1210bfdc
--- /dev/null
+++ b/lib/libc/string/strdup.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <string.h>
+
+char *strdup(const char *s)
+{
+ size_t len = strlen(s) + 1;
+ char *dup = malloc(len);
+ if (dup == NULL)
+ return NULL;
+ memcpy(dup, s, len);
+ return dup;
+}
diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c
new file mode 100644
index 00000000..1d5903cb
--- /dev/null
+++ b/lib/libc/string/strerror.c
@@ -0,0 +1,125 @@
+#include <libc.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+
+char *strerror(int errnum)
+{
+ char *table[] = {
+ [0] = "No error information",
+ [EILSEQ] = "Illegal byte sequence",
+ [EDOM] = "Domain error",
+ [ERANGE] = "Result not representable",
+ [ENOTTY] = "Not a tty",
+ [EACCES] = "Permission denied",
+ [EPERM] = "Operation not permitted",
+ [ENOENT] = "No such file or directory",
+ [ESRCH] = "No such process",
+ [EEXIST] = "File exists",
+ [EOVERFLOW] = "Value too large for data type",
+ [ENOSPC] = "No space left on device",
+ [ENOMEM] = "Out of memory",
+ [EBUSY] = "Resource busy",
+ [EINTR] = "Interrupted system call",
+ [EAGAIN] = "Resource temporarily unavailable",
+ [ESPIPE] = "Invalid seek",
+ [EXDEV] = "Cross-device link",
+ [EROFS] = "Read-only file system",
+ [ENOTEMPTY] = "Directory not empty",
+ [ECONNRESET] = "Connection reset by peer",
+ [ETIMEDOUT] = "Operation timed out",
+ [ECONNREFUSED] = "Connection refused",
+ [EHOSTDOWN] = "Host is down",
+ [EHOSTUNREACH] = "Host is unreachable",
+ [EADDRINUSE] = "Address in use",
+ [EPIPE] = "Broken pipe",
+ [EIO] = "I/O error",
+ [ENXIO] = "No such device or address",
+ [ENOTBLK] = "Block device required",
+ [ENODEV] = "No such device",
+ [ENOTDIR] = "Not a directory",
+ [EISDIR] = "Is a directory",
+ [ETXTBSY] = "Text file busy",
+ [ENOEXEC] = "Exec format error",
+ [EINVAL] = "Invalid argument",
+ [E2BIG] = "Argument list too long",
+ [ELOOP] = "Symbolic link loop",
+ [ENAMETOOLONG] = "Filename too long",
+ [ENFILE] = "Too many open files in system",
+ [EMFILE] = "No file descriptors available",
+ [EBADF] = "Bad file descriptor",
+ [ECHILD] = "No child process",
+ [EFAULT] = "Bad address",
+ [EFBIG] = "File too large",
+ [EMLINK] = "Too many links",
+ [ENOLCK] = "No locks available",
+ [EDEADLK] = "Resource deadlock would occur",
+ [ENOTRECOVERABLE] = "State not recoverable",
+ [EOWNERDEAD] = "Previous owner died",
+ [ECANCELED] = "Operation canceled",
+ [ENOSYS] = "Function not implemented",
+ [ENOMSG] = "No message of desired type",
+ [EIDRM] = "Identifier removed",
+ [ENOSTR] = "Device not a stream",
+ [ENODATA] = "No data available",
+ [ETIME] = "Device timeout",
+ [ENOSR] = "Out of streams resources",
+ [ENOLINK] = "Link has been severed",
+ [EPROTO] = "Protocol error",
+ [EBADMSG] = "Bad message",
+ [EBADFD] = "File descriptor in bad state",
+ [ENOTSOCK] = "Not a socket",
+ [EDESTADDRREQ] = "Destination address required",
+ [EMSGSIZE] = "Message too large",
+ [EPROTOTYPE] = "Protocol wrong type for socket",
+ [ENOPROTOOPT] = "Protocol not available",
+ [EPROTONOSUPPORT] = "Not supported",
+ [ESOCKTNOSUPPORT] = "Type not supported",
+ [ENOTSUP] = "Not supported",
+ [EPFNOSUPPORT] = "Protocol family not supported",
+ [EAFNOSUPPORT] = "Address family not supported by protocol",
+ [EADDRNOTAVAIL] = "Address not available",
+ [ENETDOWN] = "Network is down",
+ [ENETUNREACH] = "Network unreachable",
+ [ENETRESET] = "Connection reset by network",
+ [ECONNABORTED] = "Connection aborted",
+ [ENOBUFS] = "No buffer space available",
+ [EISCONN] = "Socket is connected",
+ [ENOTCONN] = "Socket not connected",
+ [ESHUTDOWN] = "Cannot send after socket shutdown",
+ [EALREADY] = "Operation already in progress",
+ [EINPROGRESS] = "Operation in progress",
+ [ESTALE] = "Stale file handle",
+ [EUCLEAN] = "Data consistency error",
+ [ENAVAIL] = "Resource not available",
+ [EREMOTEIO] = "Remote I/O error",
+ [EDQUOT] = "Quota exceeded",
+ [ENOMEDIUM] = "No medium found",
+ [EMEDIUMTYPE] = "Wrong medium type",
+ [EMULTIHOP] = "Multihop attempted",
+ [ENOKEY] = "Required key not available",
+ [EKEYEXPIRED] = "Key has expired",
+ [EKEYREVOKED] = "Key has been revoked",
+ [EKEYREJECTED] = "Key was rejected by service",
+ };
+
+ return table[errnum];
+}
+
+int strerror_r(int errnum, char *buf, size_t buflen)
+{
+ const char *msg = strerror(errnum);
+ size_t msglen = strlen(msg) + 1;
+
+ if (buflen < msglen) {
+ return ERANGE;
+ }
+
+ memcpy(buf, msg, msglen);
+ return 0;
+}
+
+weak char *strerror_l(int errnum, locale_t unused locale)
+{
+ return strerror(errnum);
+}
diff --git a/lib/libc/string/strlcat.c b/lib/libc/string/strlcat.c
new file mode 100644
index 00000000..a2c333e0
--- /dev/null
+++ b/lib/libc/string/strlcat.c
@@ -0,0 +1,19 @@
+#include <string.h>
+
+size_t strlcat(char *restrict dst, const char *restrict src, size_t dstsize)
+{
+ size_t dlen = strlen(dst);
+ size_t slen = strlen(src);
+ size_t n = dstsize - dlen - 1;
+
+ if (n == 0)
+ return dlen + slen;
+
+ if (n > slen)
+ n = slen;
+
+ memcpy(dst + dlen, src, n);
+ dst[dlen + n] = '\0';
+
+ return dlen + n;
+}
diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c
new file mode 100644
index 00000000..2f2f6a3b
--- /dev/null
+++ b/lib/libc/string/strlcpy.c
@@ -0,0 +1,16 @@
+#include <string.h>
+
+size_t strlcpy(char *restrict dst, const char *restrict src, size_t dstsize)
+{
+ size_t srclen = strlen(src);
+
+ if (dstsize == 0) {
+ return srclen;
+ }
+
+ size_t copylen = srclen < dstsize - 1 ? srclen : dstsize - 1;
+ memcpy(dst, src, copylen);
+ dst[copylen] = '\0';
+
+ return srclen;
+}
diff --git a/lib/libc/string/strlen.c b/lib/libc/string/strlen.c
new file mode 100644
index 00000000..0eb222fa
--- /dev/null
+++ b/lib/libc/string/strlen.c
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+size_t strlen(const char *str)
+{
+ size_t len = 0;
+
+ if (str == NULL)
+ return 0;
+
+ while (*str++)
+ len++;
+
+ return len;
+}
diff --git a/lib/libc/string/strncat.c b/lib/libc/string/strncat.c
new file mode 100644
index 00000000..ce0d8e24
--- /dev/null
+++ b/lib/libc/string/strncat.c
@@ -0,0 +1,19 @@
+#include <string.h>
+
+char *strncat(char *restrict s1, const char *restrict s2, size_t n)
+{
+ char *dest = s1;
+ const char *src = s2;
+
+ while (*dest != '\0')
+ dest++;
+
+ while (*src != '\0' && n > 0) {
+ *dest++ = *src++;
+ n--;
+ }
+
+ *dest = '\0';
+
+ return s1;
+}
diff --git a/lib/libc/string/strncmp.c b/lib/libc/string/strncmp.c
new file mode 100644
index 00000000..2fbc2395
--- /dev/null
+++ b/lib/libc/string/strncmp.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *p1 = (const unsigned char *)s1;
+ const unsigned char *p2 = (const unsigned char *)s2;
+
+ while (n-- > 0) {
+ if (*p1 != *p2 || *p1 == '\0')
+ return *p1 - *p2;
+ p1++;
+ p2++;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/string/strncpy.c b/lib/libc/string/strncpy.c
new file mode 100644
index 00000000..c43b88c8
--- /dev/null
+++ b/lib/libc/string/strncpy.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+
+char *strncpy(char *restrict s1, const char *restrict s2, size_t n)
+{
+ char *result = s1;
+
+ while (n > 0 && *s2 != '\0') {
+ *s1++ = *s2++;
+ n--;
+ }
+
+ if (n > 0)
+ *s1 = '\0';
+
+ return result;
+}
diff --git a/lib/libc/string/strndup.c b/lib/libc/string/strndup.c
new file mode 100644
index 00000000..70e10501
--- /dev/null
+++ b/lib/libc/string/strndup.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <string.h>
+
+char *strndup(const char *s, size_t size)
+{
+ char *result = malloc(size + 1);
+
+ if (result == NULL)
+ return NULL;
+
+ memcpy(result, s, size);
+ result[size] = '\0';
+
+ return result;
+}
diff --git a/lib/libc/string/strnlen.c b/lib/libc/string/strnlen.c
new file mode 100644
index 00000000..11da22ec
--- /dev/null
+++ b/lib/libc/string/strnlen.c
@@ -0,0 +1,11 @@
+#include <stddef.h>
+
+size_t strnlen(const char *s, size_t maxlen)
+{
+ size_t len = 0;
+
+ while (*s++ && len < maxlen)
+ len++;
+
+ return len;
+}
diff --git a/lib/libc/string/strpbrk.c b/lib/libc/string/strpbrk.c
new file mode 100644
index 00000000..21d6507f
--- /dev/null
+++ b/lib/libc/string/strpbrk.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+
+char *strpbrk(const char *s1, const char *s2)
+{
+ while (*s1 != '\0') {
+ const char *p = s2;
+ while (*p != '\0') {
+ if (*s1 == *p)
+ return (char *)s1;
+ p++;
+ }
+ s1++;
+ }
+
+ return NULL;
+}
diff --git a/lib/libc/string/strrchr.c b/lib/libc/string/strrchr.c
new file mode 100644
index 00000000..d2807569
--- /dev/null
+++ b/lib/libc/string/strrchr.c
@@ -0,0 +1,12 @@
+#include <stddef.h>
+
+char *strrchr(const char *s, int c)
+{
+ const char *last = NULL;
+ while (*s != '\0') {
+ if (*s == c)
+ last = s;
+ s++;
+ }
+ return (char *)last;
+}
diff --git a/lib/libc/string/strspn.c b/lib/libc/string/strspn.c
new file mode 100644
index 00000000..78277ae7
--- /dev/null
+++ b/lib/libc/string/strspn.c
@@ -0,0 +1,12 @@
+#include <stddef.h>
+#include <string.h>
+
+size_t strspn(const char *s1, const char *s2)
+{
+ size_t count = 0;
+ while (*s1 != '\0' && strchr(s2, *s1) != NULL) {
+ count++;
+ s1++;
+ }
+ return count;
+}
diff --git a/lib/libc/string/strstr.c b/lib/libc/string/strstr.c
new file mode 100644
index 00000000..c3e2d5dd
--- /dev/null
+++ b/lib/libc/string/strstr.c
@@ -0,0 +1,27 @@
+#include <stddef.h>
+
+char *strstr(const char *s1, const char *s2)
+{
+ const char *p = s1;
+ const char *q = s2;
+
+ if (*q == '\0')
+ return (char *)p;
+
+ while (*p != '\0') {
+ const char *pp = p;
+ const char *qq = q;
+
+ while (*pp == *qq && *pp != '\0') {
+ pp++;
+ qq++;
+ }
+
+ if (*qq == '\0')
+ return (char *)p;
+
+ p++;
+ }
+
+ return NULL;
+}
diff --git a/lib/libc/string/strtok.c b/lib/libc/string/strtok.c
new file mode 100644
index 00000000..33d0d685
--- /dev/null
+++ b/lib/libc/string/strtok.c
@@ -0,0 +1,40 @@
+#include <stddef.h>
+#include <string.h>
+
+char *strtok(char *restrict s, const char *restrict sep)
+{
+ static _Thread_local char *state = NULL;
+
+ if (s != NULL) {
+ state = s;
+ }
+
+ if (state == NULL) {
+ return NULL;
+ }
+
+ char *token = state;
+ while (*token && strchr(sep, *token)) {
+ token++;
+ }
+
+ if (*token == '\0') {
+ state = NULL;
+ return NULL;
+ }
+
+ char *start = token;
+
+ while (*token && strchr(sep, *token) == NULL) {
+ token++;
+ }
+
+ if (*token) {
+ *token = '\0';
+ state = token + 1;
+ } else {
+ state = NULL;
+ }
+
+ return start;
+}
diff --git a/lib/libc/string/strtok_r.c b/lib/libc/string/strtok_r.c
new file mode 100644
index 00000000..57555b14
--- /dev/null
+++ b/lib/libc/string/strtok_r.c
@@ -0,0 +1,37 @@
+#include <string.h>
+
+char *strtok_r(char *restrict s, const char *restrict sep,
+ char **restrict state)
+{
+ if (s == NULL) {
+ s = *state;
+ }
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ while (*s && strchr(sep, *s)) {
+ s++;
+ }
+
+ if (*s == '\0') {
+ *state = NULL;
+ return NULL;
+ }
+
+ char *start = s;
+
+ while (*s && strchr(sep, *s) == NULL) {
+ s++;
+ }
+
+ if (*s) {
+ *s = '\0';
+ *state = s + 1;
+ } else {
+ *state = NULL;
+ }
+
+ return start;
+}
diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c
new file mode 100644
index 00000000..d62d0a96
--- /dev/null
+++ b/lib/libc/string/strxfrm.c
@@ -0,0 +1,18 @@
+#include <libc.h>
+#include <string.h>
+
+size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n)
+{
+ size_t len = strlen(s2);
+
+ if (n > len)
+ strcpy(s1, s2);
+
+ return len;
+}
+
+weak size_t strxfrm_l(char *restrict s1, const char *restrict s2, size_t n,
+ locale_t unused locale)
+{
+ return strxfrm(s1, s2, n);
+}
diff --git a/lib/libc/strings/ffs.c b/lib/libc/strings/ffs.c
new file mode 100644
index 00000000..3b836021
--- /dev/null
+++ b/lib/libc/strings/ffs.c
@@ -0,0 +1,14 @@
+int ffs(int i)
+{
+ if (i == 0)
+ return 0;
+
+ int pos = 1;
+ unsigned int u = (unsigned int)i;
+
+ while ((u & 1U) == 0U) {
+ u >>= 1;
+ pos++;
+ }
+ return pos;
+}
diff --git a/lib/libc/strings/ffsl.c b/lib/libc/strings/ffsl.c
new file mode 100644
index 00000000..2f2e7d44
--- /dev/null
+++ b/lib/libc/strings/ffsl.c
@@ -0,0 +1,14 @@
+int ffsl(long i)
+{
+ if (i == 0)
+ return 0;
+
+ int pos = 1;
+ unsigned long u = (unsigned long)i;
+
+ while ((u & 1UL) == 0UL) {
+ u >>= 1;
+ pos++;
+ }
+ return pos;
+}
diff --git a/lib/libc/strings/ffsll.c b/lib/libc/strings/ffsll.c
new file mode 100644
index 00000000..acfacb87
--- /dev/null
+++ b/lib/libc/strings/ffsll.c
@@ -0,0 +1,14 @@
+int ffsll(long long i)
+{
+ if (i == 0)
+ return 0;
+
+ int pos = 1;
+ unsigned long long u = (unsigned long long)i;
+
+ while ((u & 1ULL) == 0ULL) {
+ u >>= 1;
+ pos++;
+ }
+ return pos;
+}
diff --git a/lib/libc/strings/strcasecmp.c b/lib/libc/strings/strcasecmp.c
new file mode 100644
index 00000000..90ccc59b
--- /dev/null
+++ b/lib/libc/strings/strcasecmp.c
@@ -0,0 +1,24 @@
+#include <libc.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ unsigned char c1, c2;
+
+ while (*s1 && *s2) {
+ c1 = (unsigned char)tolower((unsigned char)*s1);
+ c2 = (unsigned char)tolower((unsigned char)*s2);
+ if (c1 != c2)
+ return c1 - c2;
+ s1++;
+ s2++;
+ }
+
+ return (unsigned char)tolower((unsigned char)*s1) -
+ (unsigned char)tolower((unsigned char)*s2);
+}
+
+weak int strcasecmp_l(const char *s1, const char *s2, locale_t unused locale)
+{
+ return strcasecmp(s1, s2);
+}
diff --git a/lib/libc/strings/strncasecmp.c b/lib/libc/strings/strncasecmp.c
new file mode 100644
index 00000000..679cf245
--- /dev/null
+++ b/lib/libc/strings/strncasecmp.c
@@ -0,0 +1,32 @@
+#include <libc.h>
+#include <ctype.h>
+#include <stddef.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ unsigned char c1, c2;
+
+ if (n == 0)
+ return 0;
+
+ while (n-- > 0 && *s1 && *s2) {
+ c1 = (unsigned char)tolower((unsigned char)*s1);
+ c2 = (unsigned char)tolower((unsigned char)*s2);
+ if (c1 != c2)
+ return c1 - c2;
+ s1++;
+ s2++;
+ }
+
+ if (n == (size_t)-1)
+ return 0;
+
+ return (unsigned char)tolower((unsigned char)*s1) -
+ (unsigned char)tolower((unsigned char)*s2);
+}
+
+weak int strncasecmp_l(const char *s1, const char *s2, size_t n,
+ locale_t unused locale)
+{
+ return strncasecmp(s1, s2, n);
+}
diff --git a/lib/libc/sys/ioctl.c b/lib/libc/sys/ioctl.c
new file mode 100644
index 00000000..9d7cde36
--- /dev/null
+++ b/lib/libc/sys/ioctl.c
@@ -0,0 +1,13 @@
+#include <stdarg.h>
+#include <syscall.h>
+
+int ioctl(int fildes, unsigned long request, ...)
+{
+ void *arg;
+ va_list ap;
+ va_start(ap, request);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+
+ return syscall(ioctl, fildes, request, arg);
+}
diff --git a/lib/libc/sys/mount.c b/lib/libc/sys/mount.c
new file mode 100644
index 00000000..0cb95fcf
--- /dev/null
+++ b/lib/libc/sys/mount.c
@@ -0,0 +1,8 @@
+#include <syscall.h>
+#include <sys/mount.h>
+
+int mount(const char *source, const char *target, const char *filesystemtype,
+ unsigned long mountflags, const void *_Nullable data)
+{
+ return syscall(mount, source, target, filesystemtype, mountflags, data);
+}
diff --git a/lib/libc/sys/umount.c b/lib/libc/sys/umount.c
new file mode 100644
index 00000000..ae1ecf8a
--- /dev/null
+++ b/lib/libc/sys/umount.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int umount(const char *target)
+{
+ return syscall(umount2, target, 0);
+}
diff --git a/lib/libc/sys/umount2.c b/lib/libc/sys/umount2.c
new file mode 100644
index 00000000..a75588a8
--- /dev/null
+++ b/lib/libc/sys/umount2.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int umount2(const char *target, int flags)
+{
+ return syscall(umount2, target, flags);
+}
diff --git a/lib/libc/syslog/closelog.c b/lib/libc/syslog/closelog.c
new file mode 100644
index 00000000..df9b5a49
--- /dev/null
+++ b/lib/libc/syslog/closelog.c
@@ -0,0 +1,7 @@
+#include <syslog.h>
+
+void closelog(void)
+{
+ // TODO
+ return;
+}
diff --git a/lib/libc/syslog/openlog.c b/lib/libc/syslog/openlog.c
new file mode 100644
index 00000000..84c4797f
--- /dev/null
+++ b/lib/libc/syslog/openlog.c
@@ -0,0 +1,7 @@
+#include <syslog.h>
+
+int setlogmask(int maskpri)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/syslog/setlogmask.c b/lib/libc/syslog/setlogmask.c
new file mode 100644
index 00000000..84c4797f
--- /dev/null
+++ b/lib/libc/syslog/setlogmask.c
@@ -0,0 +1,7 @@
+#include <syslog.h>
+
+int setlogmask(int maskpri)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/syslog/syslog.c b/lib/libc/syslog/syslog.c
new file mode 100644
index 00000000..a9a41fbb
--- /dev/null
+++ b/lib/libc/syslog/syslog.c
@@ -0,0 +1,7 @@
+#include <syslog.h>
+
+void syslog(int priority, const char *message, ... /* arguments */)
+{
+ // TODO
+ return;
+}
diff --git a/lib/libc/termios/cfgetispeed.c b/lib/libc/termios/cfgetispeed.c
new file mode 100644
index 00000000..f06ec65e
--- /dev/null
+++ b/lib/libc/termios/cfgetispeed.c
@@ -0,0 +1,6 @@
+#include <asm-generic/termbits.h>
+
+speed_t cfgetispeed(const struct termios *termios_p)
+{
+ return (termios_p->c_cflag & CIBAUD) / (CIBAUD / CBAUD);
+}
diff --git a/lib/libc/termios/cfgetospeed.c b/lib/libc/termios/cfgetospeed.c
new file mode 100644
index 00000000..e36befc3
--- /dev/null
+++ b/lib/libc/termios/cfgetospeed.c
@@ -0,0 +1,6 @@
+#include <asm-generic/termbits.h>
+
+speed_t cfgetospeed(const struct termios *termios_p)
+{
+ return termios_p->c_cflag & CBAUD;
+}
diff --git a/lib/libc/termios/cfsetispeed.c b/lib/libc/termios/cfsetispeed.c
new file mode 100644
index 00000000..b990d598
--- /dev/null
+++ b/lib/libc/termios/cfsetispeed.c
@@ -0,0 +1,14 @@
+#include <errno.h>
+#include <asm-generic/termbits.h>
+
+int cfsetispeed(struct termios *termios_p, speed_t speed)
+{
+ if (speed & ~CBAUD) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ termios_p->c_cflag &= ~CIBAUD;
+ termios_p->c_cflag |= speed * (CIBAUD / CBAUD);
+ return 0;
+}
diff --git a/lib/libc/termios/cfsetospeed.c b/lib/libc/termios/cfsetospeed.c
new file mode 100644
index 00000000..3f46b5c4
--- /dev/null
+++ b/lib/libc/termios/cfsetospeed.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+#include <asm-generic/termbits.h>
+
+int cfsetospeed(struct termios *termios_p, speed_t speed)
+{
+ if (speed & ~CBAUD) {
+ errno = EINVAL;
+ return -1;
+ }
+ termios_p->c_cflag &= ~CBAUD;
+ termios_p->c_cflag |= speed;
+ return 0;
+}
diff --git a/lib/libc/termios/tcdrain.c b/lib/libc/termios/tcdrain.c
new file mode 100644
index 00000000..9eefedf2
--- /dev/null
+++ b/lib/libc/termios/tcdrain.c
@@ -0,0 +1,7 @@
+#include <asm-generic/ioctls.h>
+#include <syscall.h>
+
+int tcdrain(int fildes)
+{
+ return syscall(ioctl, fildes, TCSBRK, 1);
+}
diff --git a/lib/libc/termios/tcflow.c b/lib/libc/termios/tcflow.c
new file mode 100644
index 00000000..a10455d1
--- /dev/null
+++ b/lib/libc/termios/tcflow.c
@@ -0,0 +1,7 @@
+#include <asm-generic/ioctls.h>
+#include <syscall.h>
+
+int tcflow(int fildes, int action)
+{
+ return syscall(ioctl, fildes, TCXONC, action);
+}
diff --git a/lib/libc/termios/tcflush.c b/lib/libc/termios/tcflush.c
new file mode 100644
index 00000000..b37b218d
--- /dev/null
+++ b/lib/libc/termios/tcflush.c
@@ -0,0 +1,8 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+int tcflush(int fildes, int queue_selector)
+{
+ return syscall(ioctl, fildes, TCFLSH, queue_selector);
+}
diff --git a/lib/libc/termios/tcgetattr.c b/lib/libc/termios/tcgetattr.c
new file mode 100644
index 00000000..a52eeedf
--- /dev/null
+++ b/lib/libc/termios/tcgetattr.c
@@ -0,0 +1,9 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+int tcgetattr(int fildes, struct termios *termios_p)
+
+{
+ return syscall(ioctl, fildes, TCGETS, termios_p);
+}
diff --git a/lib/libc/termios/tcgetsid.c b/lib/libc/termios/tcgetsid.c
new file mode 100644
index 00000000..076cf360
--- /dev/null
+++ b/lib/libc/termios/tcgetsid.c
@@ -0,0 +1,13 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+pid_t tcgetsid(int fildes)
+{
+ pid_t sid = 0;
+
+ if (syscall(ioctl, fildes, TIOCGSID, &sid) < 0)
+ return -1;
+
+ return sid;
+}
diff --git a/lib/libc/termios/tcgetwinsize.c b/lib/libc/termios/tcgetwinsize.c
new file mode 100644
index 00000000..2c7c5786
--- /dev/null
+++ b/lib/libc/termios/tcgetwinsize.c
@@ -0,0 +1,23 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+struct __winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+int tcgetwinsize(int fildes, struct winsize *winsize_p)
+{
+ long ret;
+ struct __winsize winsize = { 0 };
+
+ ret = syscall(ioctl, fildes, TIOCGWINSZ, &winsize);
+
+ winsize_p->ws_row = winsize.ws_row;
+ winsize_p->ws_col = winsize.ws_col;
+
+ return ret;
+}
diff --git a/lib/libc/termios/tcsendbreak.c b/lib/libc/termios/tcsendbreak.c
new file mode 100644
index 00000000..a6ed420d
--- /dev/null
+++ b/lib/libc/termios/tcsendbreak.c
@@ -0,0 +1,11 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+int tcsendbreak(int fildes, int duration)
+{
+ // IEEE Std 1003.1-2024
+ // If duration is not 0, it shall send zero-valued
+ // bits for an implementation-defined period of time.
+ return syscall(ioctl, fildes, TCSBRK, 0);
+}
diff --git a/lib/libc/termios/tcsetattr.c b/lib/libc/termios/tcsetattr.c
new file mode 100644
index 00000000..a76e77a5
--- /dev/null
+++ b/lib/libc/termios/tcsetattr.c
@@ -0,0 +1,14 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+#include <errno.h>
+
+int tcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
+{
+ if (optional_actions < 0 || optional_actions > 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return syscall(ioctl, fildes, TCSETS + optional_actions, termios_p);
+}
diff --git a/lib/libc/termios/tcsetwinsize.c b/lib/libc/termios/tcsetwinsize.c
new file mode 100644
index 00000000..10a705d0
--- /dev/null
+++ b/lib/libc/termios/tcsetwinsize.c
@@ -0,0 +1,8 @@
+#include <termios.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+int tcsetwinsize(int fildes, const struct winsize *winsize_p)
+{
+ return syscall(ioctl, fildes, TIOCSWINSZ, winsize_p);
+}
diff --git a/lib/libc/thread/thrd_current.c b/lib/libc/thread/thrd_current.c
new file mode 100644
index 00000000..adbb4191
--- /dev/null
+++ b/lib/libc/thread/thrd_current.c
@@ -0,0 +1,9 @@
+#include <thread.h>
+#include <threads.h>
+#include <unistd.h>
+
+thrd_t thrd_current(void)
+{
+ static _Thread_local struct __thread_self self = { 0 };
+ return &self;
+}
diff --git a/lib/libc/time/asctime.c b/lib/libc/time/asctime.c
new file mode 100644
index 00000000..54729a77
--- /dev/null
+++ b/lib/libc/time/asctime.c
@@ -0,0 +1,19 @@
+#include <time.h>
+#include <stdio.h>
+
+char *asctime(const struct tm *timeptr)
+{
+ static char wday_name[7][3] = { "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat" };
+ static char mon_name[12][3] = { "Jan", "Feb", "Mar", "Apr",
+ "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec" };
+ static char result[26];
+
+ snprintf(result, sizeof(result), "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+ wday_name[timeptr->tm_wday], mon_name[timeptr->tm_mon],
+ timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min,
+ timeptr->tm_sec, 1900 + timeptr->tm_year);
+
+ return result;
+}
diff --git a/lib/libc/time/clock.c b/lib/libc/time/clock.c
new file mode 100644
index 00000000..ec2e6084
--- /dev/null
+++ b/lib/libc/time/clock.c
@@ -0,0 +1,16 @@
+#include <time.h>
+#include <limits.h>
+
+clock_t clock(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts))
+ return -1;
+
+ if (ts.tv_sec > LONG_MAX / 1000000 ||
+ ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec)
+ return -1;
+
+ return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}
diff --git a/lib/libc/time/clock_getcpuclockid.c b/lib/libc/time/clock_getcpuclockid.c
new file mode 100644
index 00000000..5bb53221
--- /dev/null
+++ b/lib/libc/time/clock_getcpuclockid.c
@@ -0,0 +1,18 @@
+#include <time.h>
+#include <syscall.h>
+
+int clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
+{
+ int ret;
+ clockid_t id;
+ struct timespec ts;
+
+ id = (-pid - 1) * 8U + 2;
+ ret = syscall(clock_getres, id, &ts);
+
+ if (ret >= 0) {
+ *clock_id = id;
+ }
+
+ return ret;
+}
diff --git a/lib/libc/time/clock_getres.c b/lib/libc/time/clock_getres.c
new file mode 100644
index 00000000..5af37e8d
--- /dev/null
+++ b/lib/libc/time/clock_getres.c
@@ -0,0 +1,7 @@
+#include <time.h>
+#include <syscall.h>
+
+int clock_getres(clockid_t clock_id, struct timespec *res)
+{
+ return syscall(clock_getres, clock_id, res);
+}
diff --git a/lib/libc/time/clock_nanosleep.c b/lib/libc/time/clock_nanosleep.c
new file mode 100644
index 00000000..63190d06
--- /dev/null
+++ b/lib/libc/time/clock_nanosleep.c
@@ -0,0 +1,8 @@
+#include <time.h>
+#include <syscall.h>
+
+int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
+ struct timespec *rmtp)
+{
+ return __syscall(nanosleep, clock_id, flags, rqtp, rmtp) * -1;
+}
diff --git a/lib/libc/time/ctime.c b/lib/libc/time/ctime.c
new file mode 100644
index 00000000..bddd30cf
--- /dev/null
+++ b/lib/libc/time/ctime.c
@@ -0,0 +1,6 @@
+#include <time.h>
+
+char *ctime(const time_t *clock)
+{
+ return asctime(localtime(clock));
+}
diff --git a/lib/libc/time/difftime.c b/lib/libc/time/difftime.c
new file mode 100644
index 00000000..e7b567c1
--- /dev/null
+++ b/lib/libc/time/difftime.c
@@ -0,0 +1,6 @@
+#include <time.h>
+
+double difftime(time_t time1, time_t time0)
+{
+ return time1 - time0;
+}
diff --git a/lib/libc/time/gmtime_r.c b/lib/libc/time/gmtime_r.c
new file mode 100644
index 00000000..8d441549
--- /dev/null
+++ b/lib/libc/time/gmtime_r.c
@@ -0,0 +1,42 @@
+#include <time.h>
+
+struct tm *gmtime_r(const time_t *timer, struct tm *result)
+{
+ time_t t = *timer;
+ int days, rem;
+ int year, month;
+
+ rem = t % 86400;
+ days = t / 86400;
+ if (rem < 0) {
+ rem += 86400;
+ days--;
+ }
+
+ result->tm_hour = rem / 3600;
+ rem %= 3600;
+ result->tm_min = rem / 60;
+ result->tm_sec = rem % 60;
+ result->tm_isdst = 0;
+
+ result->tm_wday = (4 + days) % 7;
+ if (result->tm_wday < 0)
+ result->tm_wday += 7;
+
+ long z = days + 719468;
+ long era = (z >= 0 ? z : z - 146096) / 146097;
+ long day_of_era = z - era * 146097;
+ long yoe = (day_of_era - day_of_era / 1460 + day_of_era / 36524 -
+ day_of_era / 146096) /
+ 365;
+ year = (int)(yoe + era * 400);
+ long doy = day_of_era - (365 * yoe + yoe / 4 - yoe / 100);
+ result->tm_yday = (int)doy;
+
+ int mp = (5 * doy + 2) / 153;
+ result->tm_mday = (int)(doy - (153 * mp + 2) / 5 + 1);
+ result->tm_mon = (mp + 2) % 12;
+ result->tm_year = year - 1900 + (mp / 10);
+
+ return result;
+}
diff --git a/lib/libc/time/localtime.c b/lib/libc/time/localtime.c
new file mode 100644
index 00000000..44029920
--- /dev/null
+++ b/lib/libc/time/localtime.c
@@ -0,0 +1,7 @@
+#include <time.h>
+
+struct tm *localtime(const time_t *timer)
+{
+ static struct tm result;
+ return localtime_r(timer, &result);
+}
diff --git a/lib/libc/time/localtime_r.c b/lib/libc/time/localtime_r.c
new file mode 100644
index 00000000..1fb620a4
--- /dev/null
+++ b/lib/libc/time/localtime_r.c
@@ -0,0 +1,7 @@
+#include <time.h>
+
+struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result)
+{
+ time_t local = *timer - timezone;
+ return gmtime_r(&local, result);
+}
diff --git a/lib/libc/time/nanosleep.c b/lib/libc/time/nanosleep.c
new file mode 100644
index 00000000..f5c5f7c9
--- /dev/null
+++ b/lib/libc/time/nanosleep.c
@@ -0,0 +1,7 @@
+#include <time.h>
+#include <syscall.h>
+
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ return syscall(nanosleep, rqtp, rmtp);
+}
diff --git a/lib/libc/time/strftime.c b/lib/libc/time/strftime.c
new file mode 100644
index 00000000..d359140b
--- /dev/null
+++ b/lib/libc/time/strftime.c
@@ -0,0 +1,562 @@
+#include <time.h>
+#include <libc.h>
+#include <string.h>
+
+static size_t append_string(char *restrict *s, size_t *remaining,
+ const char *str)
+{
+ size_t len = strlen(str);
+ if (len >= *remaining) {
+ return 0;
+ }
+ strcpy(*s, str);
+ *s += len;
+ *remaining -= len;
+ return len;
+}
+
+static size_t append_char(char *restrict *s, size_t *remaining, char c)
+{
+ if (*remaining <= 1) {
+ return 0;
+ }
+ **s = c;
+ (*s)++;
+ (*remaining)--;
+ return 1;
+}
+
+static size_t format_int(char *restrict *s, size_t *remaining, int value,
+ int width, char pad, int show_sign)
+{
+ char buffer[32];
+ char *ptr = buffer + sizeof(buffer) - 1;
+ *ptr = '\0';
+
+ int negative = 0;
+ if (value < 0) {
+ negative = 1;
+ value = -value;
+ }
+
+ do {
+ *--ptr = '0' + (value % 10);
+ value /= 10;
+ } while (value > 0);
+
+ if (negative) {
+ *--ptr = '-';
+ } else if (show_sign && value >= 0) {
+ *--ptr = '+';
+ }
+
+ int len = (buffer + sizeof(buffer) - 1) - ptr;
+
+ while (len < width) {
+ *--ptr = pad;
+ len++;
+ }
+
+ return append_string(s, remaining, ptr);
+}
+
+static const char *weekday_abbr[] = { "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat" };
+static const char *weekday_full[] = { "Sunday", "Monday", "Tuesday",
+ "Wednesday", "Thursday", "Friday",
+ "Saturday" };
+
+static const char *month_abbr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static const char *month_full[] = { "January", "February", "March",
+ "April", "May", "June",
+ "July", "August", "September",
+ "October", "November", "December" };
+
+static int day_of_year(const struct tm *tm)
+{
+ static const int days_to_month[] = { 0, 31, 59, 90, 120, 151,
+ 181, 212, 243, 273, 304, 334 };
+ int days = days_to_month[tm->tm_mon] + tm->tm_mday;
+
+ if (tm->tm_mon > 1) {
+ int year = tm->tm_year + 1900;
+ if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
+ days++;
+ }
+ }
+ return days;
+}
+
+static int iso_week_number(const struct tm *tm, int *week_year)
+{
+ int year = tm->tm_year + 1900;
+ int yday = tm->tm_yday + 1;
+ int wday;
+
+ int jan4_wday = (4 + year + (year - 1) / 4 - (year - 1) / 100 +
+ (year - 1) / 400) %
+ 7;
+ if (jan4_wday == 0)
+ jan4_wday = 7;
+
+ int week1_start = 4 - jan4_wday + 1;
+
+ int week = (yday - week1_start + 7) / 7;
+
+ if (week < 1) {
+ *week_year = year - 1;
+
+ int prev_jan4_wday = (jan4_wday - 1 + 7) % 7;
+ if (prev_jan4_wday == 0)
+ prev_jan4_wday = 7;
+ int prev_week1_start = 4 - prev_jan4_wday + 1;
+ int prev_year_days = 365;
+ if (((year - 1) % 4 == 0 && (year - 1) % 100 != 0) ||
+ ((year - 1) % 400 == 0)) {
+ prev_year_days = 366;
+ }
+ week = (prev_year_days - prev_week1_start + 8) / 7;
+ } else {
+ *week_year = year;
+
+ int year_days = 365;
+ if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
+ year_days = 366;
+ }
+ if (week1_start + (week - 1) * 7 > year_days - 3) {
+ if (yday > year_days - (7 - jan4_wday)) {
+ *week_year = year + 1;
+ week = 1;
+ }
+ }
+ }
+
+ return week;
+}
+
+size_t strftime(char *restrict s, size_t maxsize, const char *restrict format,
+ const struct tm *restrict timeptr)
+{
+ if (maxsize == 0)
+ return 0;
+
+ char *orig_s = s;
+ size_t remaining = maxsize - 1;
+ const char *ptr = format;
+
+ while (*ptr && remaining > 0) {
+ if (*ptr != '%') {
+ if (!append_char(&s, &remaining, *ptr)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ ptr++;
+ continue;
+ }
+
+ ptr++;
+ if (!*ptr)
+ break;
+
+ char pad_char = ' ';
+ int show_sign = 0;
+ int min_width = 0;
+
+ if (*ptr == '0') {
+ pad_char = '0';
+ ptr++;
+ } else if (*ptr == '+') {
+ pad_char = '0';
+ show_sign = 1;
+ ptr++;
+ }
+
+ while (*ptr >= '0' && *ptr <= '9') {
+ min_width = min_width * 10 + (*ptr - '0');
+ ptr++;
+ }
+
+ if (*ptr == 'E' || *ptr == 'O') {
+ ptr++;
+ }
+
+ switch (*ptr) {
+ case 'a':
+ if (!append_string(&s, &remaining,
+ weekday_abbr[timeptr->tm_wday])) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'A':
+ if (!append_string(&s, &remaining,
+ weekday_full[timeptr->tm_wday])) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'b':
+ case 'h':
+ if (!append_string(&s, &remaining,
+ month_abbr[timeptr->tm_mon])) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'B':
+ if (!append_string(&s, &remaining,
+ month_full[timeptr->tm_mon])) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'c':
+ if (!append_string(&s, &remaining,
+ weekday_abbr[timeptr->tm_wday]) ||
+ !append_char(&s, &remaining, ' ') ||
+ !append_string(&s, &remaining,
+ month_abbr[timeptr->tm_mon]) ||
+ !append_char(&s, &remaining, ' ') ||
+ !format_int(&s, &remaining, timeptr->tm_mday, 2,
+ ' ', 0) ||
+ !append_char(&s, &remaining, ' ') ||
+ !format_int(&s, &remaining, timeptr->tm_hour, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_sec, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ' ') ||
+ !format_int(&s, &remaining, timeptr->tm_year + 1900,
+ 4, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'C':
+ if (!format_int(&s, &remaining,
+ (timeptr->tm_year + 1900) / 100,
+ min_width ? min_width : 2, pad_char,
+ show_sign)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'd':
+ if (!format_int(&s, &remaining, timeptr->tm_mday, 2,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'D':
+ if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, '/') ||
+ !format_int(&s, &remaining, timeptr->tm_mday, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, '/') ||
+ !format_int(&s, &remaining, timeptr->tm_year % 100,
+ 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'e':
+ if (!format_int(&s, &remaining, timeptr->tm_mday, 2,
+ ' ', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'F': {
+ int width = min_width ? min_width - 6 : 4;
+ if (width < 4)
+ width = 4;
+ if (!format_int(&s, &remaining, timeptr->tm_year + 1900,
+ width, pad_char, show_sign) ||
+ !append_char(&s, &remaining, '-') ||
+ !format_int(&s, &remaining, timeptr->tm_mon + 1, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, '-') ||
+ !format_int(&s, &remaining, timeptr->tm_mday, 2,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'g': {
+ int week_year;
+ iso_week_number(timeptr, &week_year);
+ if (!format_int(&s, &remaining, week_year % 100, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'G': {
+ int week_year;
+ iso_week_number(timeptr, &week_year);
+ if (!format_int(&s, &remaining, week_year,
+ min_width ? min_width : 4, pad_char,
+ show_sign)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'H':
+ if (!format_int(&s, &remaining, timeptr->tm_hour, 2,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'I': {
+ int hour12 = timeptr->tm_hour % 12;
+ if (hour12 == 0)
+ hour12 = 12;
+ if (!format_int(&s, &remaining, hour12, 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'j':
+ if (!format_int(&s, &remaining, timeptr->tm_yday + 1, 3,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'm':
+ if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'M':
+ if (!format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'n':
+ if (!append_char(&s, &remaining, '\n')) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'p':
+ if (!append_string(&s, &remaining,
+ timeptr->tm_hour < 12 ? "AM" :
+ "PM")) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'r': {
+ int hour12 = timeptr->tm_hour % 12;
+ if (hour12 == 0)
+ hour12 = 12;
+ if (!format_int(&s, &remaining, hour12, 2, '0', 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_sec, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ' ') ||
+ !append_string(&s, &remaining,
+ timeptr->tm_hour < 12 ? "AM" :
+ "PM")) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'R':
+ if (!format_int(&s, &remaining, timeptr->tm_hour, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 's':
+
+ if (!append_char(&s, &remaining, '0')) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'S':
+ if (!format_int(&s, &remaining, timeptr->tm_sec, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 't':
+ if (!append_char(&s, &remaining, '\t')) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'T':
+ if (!format_int(&s, &remaining, timeptr->tm_hour, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_sec, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'u': {
+ int wday = timeptr->tm_wday;
+ if (wday == 0)
+ wday = 7;
+ if (!format_int(&s, &remaining, wday, 1, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'U': {
+ int week =
+ (timeptr->tm_yday + 7 - timeptr->tm_wday) / 7;
+ if (!format_int(&s, &remaining, week, 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'V': {
+ int week_year;
+ int week = iso_week_number(timeptr, &week_year);
+ if (!format_int(&s, &remaining, week, 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'w':
+ if (!format_int(&s, &remaining, timeptr->tm_wday, 1,
+ '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'W': {
+ int wday = timeptr->tm_wday;
+ if (wday == 0)
+ wday = 7;
+ int week = (timeptr->tm_yday + 7 - wday + 1) / 7;
+ if (!format_int(&s, &remaining, week, 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'x':
+ if (!format_int(&s, &remaining, timeptr->tm_mon + 1, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, '/') ||
+ !format_int(&s, &remaining, timeptr->tm_mday, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, '/') ||
+ !format_int(&s, &remaining, timeptr->tm_year % 100,
+ 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'X':
+ if (!format_int(&s, &remaining, timeptr->tm_hour, 2,
+ '0', 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_min, 2, '0',
+ 0) ||
+ !append_char(&s, &remaining, ':') ||
+ !format_int(&s, &remaining, timeptr->tm_sec, 2, '0',
+ 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'y':
+ if (!format_int(&s, &remaining, timeptr->tm_year % 100,
+ 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'Y':
+ if (!format_int(&s, &remaining, timeptr->tm_year + 1900,
+ min_width ? min_width : 4, pad_char,
+ show_sign)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ case 'z': {
+ if (timeptr->tm_isdst < 0) {
+ break;
+ }
+ long offset = timeptr->tm_gmtoff;
+ char sign = '+';
+ if (offset < 0) {
+ sign = '-';
+ offset = -offset;
+ }
+ int hours = offset / 3600;
+ int minutes = (offset % 3600) / 60;
+ if (!append_char(&s, &remaining, sign) ||
+ !format_int(&s, &remaining, hours, 2, '0', 0) ||
+ !format_int(&s, &remaining, minutes, 2, '0', 0)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ } break;
+ case 'Z':
+ if (timeptr->tm_zone) {
+ if (!append_string(&s, &remaining,
+ timeptr->tm_zone)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ }
+ break;
+ case '%':
+ if (!append_char(&s, &remaining, '%')) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ default:
+
+ if (!append_char(&s, &remaining, '%') ||
+ !append_char(&s, &remaining, *ptr)) {
+ *orig_s = '\0';
+ return 0;
+ }
+ break;
+ }
+ ptr++;
+ }
+
+ *s = '\0';
+ return s - orig_s;
+}
+
+weak size_t strftime_l(char *restrict s, size_t maxsize,
+ const char *restrict format,
+ const struct tm *restrict timeptr,
+ locale_t unused locale)
+{
+ return strftime(s, maxsize, format, timeptr);
+}
diff --git a/lib/libc/time/time.c b/lib/libc/time/time.c
new file mode 100644
index 00000000..134eed7b
--- /dev/null
+++ b/lib/libc/time/time.c
@@ -0,0 +1,20 @@
+#include <time.h>
+#include <asm/vdso.h>
+#include <syscall.h>
+
+time_t time(time_t *tloc)
+{
+ struct timespec ts;
+
+#if defined(__x86_64__)
+ if (__vdso_time)
+ return __vdso_time(tloc);
+#endif
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ if (tloc)
+ *tloc = ts.tv_sec;
+
+ return ts.tv_sec;
+}
diff --git a/lib/libc/time/tzset.c b/lib/libc/time/tzset.c
new file mode 100644
index 00000000..96f33702
--- /dev/null
+++ b/lib/libc/time/tzset.c
@@ -0,0 +1,58 @@
+#include <time.h>
+#include <ctype.h>
+
+int daylight = 0;
+long timezone = 0;
+char *tzname[2] = { "UTC", "UTC" };
+
+void tzset(void)
+{
+ const char *tz = NULL; // getenv("TZ");
+
+ if (tz == NULL || *tz == '\0') {
+ timezone = 0;
+ daylight = 0;
+ tzname[0] = tzname[1] = "UTC";
+ return;
+ }
+
+ const char *p = tz;
+ char sign = 0;
+ int hours = 0, mins = 0;
+
+ static char stdname[8];
+ int i = 0;
+ while (*p && !isdigit((unsigned char)*p) && *p != '+' && *p != '-' &&
+ i < 7) {
+ stdname[i++] = *p++;
+ }
+
+ stdname[i] = '\0';
+ if (stdname[0])
+ tzname[0] = stdname;
+ else
+ tzname[0] = "LCL";
+
+ if (*p == '+' || *p == '-')
+ sign = *p++;
+
+ while (isdigit((unsigned char)*p))
+ hours = hours * 10 + (*p++ - '0');
+
+ if (*p == ':') {
+ p++;
+ while (isdigit((unsigned char)*p))
+ mins = mins * 10 + (*p++ - '0');
+ }
+
+ int total = hours * 3600 + mins * 60;
+ if (sign == '+')
+ timezone = -total;
+ else if (sign == '-')
+ timezone = total;
+ else
+ timezone = 0;
+
+ daylight = 0;
+ tzname[1] = tzname[0];
+}
diff --git a/lib/libc/time/utimes.c b/lib/libc/time/utimes.c
new file mode 100644
index 00000000..d6448c76
--- /dev/null
+++ b/lib/libc/time/utimes.c
@@ -0,0 +1,25 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+int utimes(const char *path, const struct timeval times[2])
+{
+ struct timespec ts[2];
+
+ if (times) {
+ if (times[0].tv_usec >= 1000000ULL ||
+ times[1].tv_usec >= 1000000ULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ts[0].tv_sec = times[0].tv_sec;
+ ts[0].tv_nsec = times[0].tv_usec * 1000;
+ ts[1].tv_sec = times[1].tv_sec;
+ ts[1].tv_nsec = times[1].tv_usec * 1000;
+ }
+
+ return utimensat(AT_FDCWD, path, times ? ts : NULL, 0);
+}
diff --git a/lib/libc/times/times.c b/lib/libc/times/times.c
new file mode 100644
index 00000000..bd850215
--- /dev/null
+++ b/lib/libc/times/times.c
@@ -0,0 +1,7 @@
+#include <sys/times.h>
+#include <syscall.h>
+
+clock_t times(struct tms *buffer)
+{
+ return syscall(times, buffer);
+}
diff --git a/lib/libc/uio/readv.c b/lib/libc/uio/readv.c
new file mode 100644
index 00000000..8a2d9216
--- /dev/null
+++ b/lib/libc/uio/readv.c
@@ -0,0 +1,55 @@
+#include <unistd.h>
+#include <linux/uio.h>
+#include <syscall.h>
+#include <errno.h>
+#include <string.h>
+
+ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t total = 0;
+
+ if (iovcnt == 0) {
+ return 0;
+ }
+
+ if (iovcnt < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (iovcnt > 0) {
+ int chunk = iovcnt > UIO_MAXIOV ? UIO_MAXIOV : iovcnt;
+
+ struct iovec local[UIO_MAXIOV];
+ memcpy(local, iov, chunk * sizeof(struct iovec));
+
+ ssize_t ret = syscall(readv, fd, local, chunk);
+ if (ret < 0) {
+ if (total > 0 && (errno == EAGAIN || errno == EINTR))
+ return total;
+ return ret;
+ }
+ if (ret == 0)
+ break; // EOF
+
+ total += ret;
+
+ ssize_t remaining = ret;
+ while (remaining > 0 && iovcnt > 0) {
+ if ((size_t)remaining >= iov->iov_len) {
+ remaining -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ } else {
+ struct iovec tmp = *iov;
+ tmp.iov_base = (char *)tmp.iov_base + remaining;
+ tmp.iov_len -= remaining;
+ memcpy(local, &tmp, sizeof(tmp));
+ remaining = 0;
+ break;
+ }
+ }
+ }
+
+ return total;
+}
diff --git a/lib/libc/uio/writev.c b/lib/libc/uio/writev.c
new file mode 100644
index 00000000..4e304336
--- /dev/null
+++ b/lib/libc/uio/writev.c
@@ -0,0 +1,49 @@
+#include <unistd.h>
+#include <syscall.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/uio.h>
+
+ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t total = 0;
+
+ if (iovcnt < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (iovcnt > 0) {
+ int chunk = iovcnt > UIO_MAXIOV ? UIO_MAXIOV : iovcnt;
+
+ struct iovec local[UIO_MAXIOV];
+ memcpy(local, iov, chunk * sizeof(struct iovec));
+
+ ssize_t ret = syscall(writev, fd, local, chunk);
+ if (ret < 0) {
+ if (total > 0 && (errno == EAGAIN || errno == EINTR))
+ return total;
+ return ret;
+ }
+
+ total += ret;
+
+ ssize_t remaining = ret;
+ while (remaining > 0 && iovcnt > 0) {
+ if ((size_t)remaining >= iov->iov_len) {
+ remaining -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ } else {
+ struct iovec tmp = *iov;
+ tmp.iov_base = (char *)tmp.iov_base + remaining;
+ tmp.iov_len -= remaining;
+ memcpy(local, &tmp, sizeof(tmp));
+ remaining = 0;
+ break;
+ }
+ }
+ }
+
+ return total;
+}
diff --git a/lib/libc/unistd/_Fork.c b/lib/libc/unistd/_Fork.c
new file mode 100644
index 00000000..080dd880
--- /dev/null
+++ b/lib/libc/unistd/_Fork.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+#include <linux/signal.h>
+
+pid_t _Fork(void)
+{
+ return syscall(clone, SIGCHLD, 0);
+}
diff --git a/lib/libc/unistd/_exit.c b/lib/libc/unistd/_exit.c
new file mode 100644
index 00000000..ffd502c4
--- /dev/null
+++ b/lib/libc/unistd/_exit.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+
+void _exit(int status)
+{
+ __syscall(exit, status);
+ __builtin_unreachable();
+}
diff --git a/lib/libc/unistd/access.c b/lib/libc/unistd/access.c
new file mode 100644
index 00000000..7735d8c4
--- /dev/null
+++ b/lib/libc/unistd/access.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int access(const char *path, int amode)
+{
+ return syscall(access, path, amode);
+}
diff --git a/lib/libc/unistd/alarm.c b/lib/libc/unistd/alarm.c
new file mode 100644
index 00000000..5d171cc7
--- /dev/null
+++ b/lib/libc/unistd/alarm.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+unsigned alarm(unsigned seconds)
+{
+ return syscall(alarm, seconds);
+}
diff --git a/lib/libc/unistd/chdir.c b/lib/libc/unistd/chdir.c
new file mode 100644
index 00000000..5c66cc0c
--- /dev/null
+++ b/lib/libc/unistd/chdir.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int chdir(const char *path)
+{
+ return syscall(chdir, path);
+}
diff --git a/lib/libc/unistd/chown.c b/lib/libc/unistd/chown.c
new file mode 100644
index 00000000..fa7e0e7b
--- /dev/null
+++ b/lib/libc/unistd/chown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+ return syscall(chown, path, owner, group);
+}
diff --git a/lib/libc/unistd/close.c b/lib/libc/unistd/close.c
new file mode 100644
index 00000000..57e45c33
--- /dev/null
+++ b/lib/libc/unistd/close.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int close(int fildes)
+{
+ return syscall(close, fildes);
+}
diff --git a/lib/libc/unistd/dup.c b/lib/libc/unistd/dup.c
new file mode 100644
index 00000000..764c16f6
--- /dev/null
+++ b/lib/libc/unistd/dup.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int dup(int fildes)
+{
+ return syscall(dup, fildes);
+}
diff --git a/lib/libc/unistd/dup2.c b/lib/libc/unistd/dup2.c
new file mode 100644
index 00000000..ce1125ac
--- /dev/null
+++ b/lib/libc/unistd/dup2.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int dup2(int fildes, int fildes2)
+{
+ return syscall(dup2, fildes, fildes2);
+}
diff --git a/lib/libc/unistd/dup3.c b/lib/libc/unistd/dup3.c
new file mode 100644
index 00000000..aa9c0fab
--- /dev/null
+++ b/lib/libc/unistd/dup3.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int dup3(int fildes, int fildes2, int flag)
+{
+ return syscall(dup3, fildes, fildes2, flag);
+}
diff --git a/lib/libc/unistd/execl.c b/lib/libc/unistd/execl.c
new file mode 100644
index 00000000..5dc7bc74
--- /dev/null
+++ b/lib/libc/unistd/execl.c
@@ -0,0 +1,26 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int execl(const char *path, const char *argv0, ...)
+{
+ int argc;
+ va_list ap;
+ va_start(ap, argv0);
+
+ argc = 1;
+ while (va_arg(ap, const char *) != NULL) {
+ argc++;
+ }
+ va_end(ap);
+
+ char *argv[argc + 1];
+ va_start(ap, argv0);
+ for (int i = 1; i < argc; i++) {
+ argv[i] = (char *)va_arg(ap, const char *);
+ }
+ argv[argc] = NULL;
+ va_end(ap);
+
+ return execvp(path, argv);
+}
diff --git a/lib/libc/unistd/execlp.c b/lib/libc/unistd/execlp.c
new file mode 100644
index 00000000..4613a7ee
--- /dev/null
+++ b/lib/libc/unistd/execlp.c
@@ -0,0 +1,27 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <syscall.h>
+
+// TODO: need to find in path and call execl
+int execlp(const char *path, const char *argv0, ...)
+{
+ int argc;
+ va_list ap;
+ va_start(ap, argv0);
+
+ argc = 1;
+ while (va_arg(ap, const char *) != NULL) {
+ argc++;
+ }
+ va_end(ap);
+
+ char *argv[argc + 1];
+ va_start(ap, argv0);
+ for (int i = 1; i < argc; i++) {
+ argv[i] = (char *)va_arg(ap, const char *);
+ }
+ argv[argc] = NULL;
+ va_end(ap);
+
+ return syscall(execve, path, argv, 0);
+}
diff --git a/lib/libc/unistd/execv.c b/lib/libc/unistd/execv.c
new file mode 100644
index 00000000..60ee6d87
--- /dev/null
+++ b/lib/libc/unistd/execv.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include <syscall.h>
+
+extern char **environ;
+
+int execv(const char *path, char *const argv[])
+{
+ return syscall(execve, path, argv, environ);
+}
diff --git a/lib/libc/unistd/execve.c b/lib/libc/unistd/execve.c
new file mode 100644
index 00000000..43226d98
--- /dev/null
+++ b/lib/libc/unistd/execve.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int execve(const char *file, char *const argv[], char *const envp[])
+{
+ return syscall(execve, file, argv, envp);
+}
diff --git a/lib/libc/unistd/execvp.c b/lib/libc/unistd/execvp.c
new file mode 100644
index 00000000..2ce69354
--- /dev/null
+++ b/lib/libc/unistd/execvp.c
@@ -0,0 +1,55 @@
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+extern char **environ;
+
+int execvp(const char *file, char *const argv[])
+{
+ if (*file == '\0') {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (strchr(file, '/') != NULL) {
+ return execv(file, argv);
+ } else {
+ char *ptr;
+ char *path = NULL; // TODO: getenv
+
+ if (path == NULL || *path == '\0') {
+ path = "/bin";
+ }
+
+ do {
+ char buf[PATH_MAX];
+
+ if ((ptr = strchr(path, ':')) == NULL) {
+ if (snprintf(buf, PATH_MAX, "%s/%s", path,
+ file) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ execv(buf, argv);
+ break;
+ }
+
+ if (snprintf(buf, PATH_MAX, "%.*s/%s",
+ (int)(ptr - path), path,
+ file) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ execv(buf, argv);
+ } while (*ptr != '\0');
+
+ errno = ENOENT;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/unistd/faccessat.c b/lib/libc/unistd/faccessat.c
new file mode 100644
index 00000000..61680aea
--- /dev/null
+++ b/lib/libc/unistd/faccessat.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int faccessat(int fd, const char *path, int amode, int flag)
+{
+ return syscall(faccessat, fd, path, amode, flag);
+}
diff --git a/lib/libc/unistd/fchdir.c b/lib/libc/unistd/fchdir.c
new file mode 100644
index 00000000..9c0ed172
--- /dev/null
+++ b/lib/libc/unistd/fchdir.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int fchdir(int fildes)
+{
+ return syscall(fchdir, fildes);
+}
diff --git a/lib/libc/unistd/fchown.c b/lib/libc/unistd/fchown.c
new file mode 100644
index 00000000..ba0ff964
--- /dev/null
+++ b/lib/libc/unistd/fchown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int fchown(int fildes, uid_t owner, gid_t group)
+{
+ return syscall(fchown, fildes, owner, group);
+}
diff --git a/lib/libc/unistd/fchownat.c b/lib/libc/unistd/fchownat.c
new file mode 100644
index 00000000..3e08472b
--- /dev/null
+++ b/lib/libc/unistd/fchownat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
+{
+ return syscall(fchownat, fd, path, owner, group, flag);
+}
diff --git a/lib/libc/unistd/fdatasync.c b/lib/libc/unistd/fdatasync.c
new file mode 100644
index 00000000..e65c79f0
--- /dev/null
+++ b/lib/libc/unistd/fdatasync.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int fdatasync(int fildes)
+{
+ return syscall(fdatasync, fildes);
+}
diff --git a/lib/libc/unistd/fork.c b/lib/libc/unistd/fork.c
new file mode 100644
index 00000000..38657406
--- /dev/null
+++ b/lib/libc/unistd/fork.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+pid_t fork(void)
+{
+ return _Fork();
+}
diff --git a/lib/libc/unistd/fsync.c b/lib/libc/unistd/fsync.c
new file mode 100644
index 00000000..e92e1cc1
--- /dev/null
+++ b/lib/libc/unistd/fsync.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int fsync(int fildes)
+{
+ return syscall(fsync, fildes);
+}
diff --git a/lib/libc/unistd/ftruncate.c b/lib/libc/unistd/ftruncate.c
new file mode 100644
index 00000000..f032ed1b
--- /dev/null
+++ b/lib/libc/unistd/ftruncate.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int ftruncate(int fildes, off_t length)
+{
+ return syscall(ftruncate, fildes, length);
+}
diff --git a/lib/libc/unistd/getcwd.c b/lib/libc/unistd/getcwd.c
new file mode 100644
index 00000000..5494f6e3
--- /dev/null
+++ b/lib/libc/unistd/getcwd.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+char *getcwd(char *buf, size_t size)
+{
+ return (char *)syscall(getcwd, buf, size);
+}
diff --git a/lib/libc/unistd/getegid.c b/lib/libc/unistd/getegid.c
new file mode 100644
index 00000000..b50e5839
--- /dev/null
+++ b/lib/libc/unistd/getegid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+gid_t getegid(void)
+{
+ return syscall(getegid);
+}
diff --git a/lib/libc/unistd/getentropy.c b/lib/libc/unistd/getentropy.c
new file mode 100644
index 00000000..f55fed7a
--- /dev/null
+++ b/lib/libc/unistd/getentropy.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int getentropy(void *buffer, size_t length)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/geteuid.c b/lib/libc/unistd/geteuid.c
new file mode 100644
index 00000000..aee26a42
--- /dev/null
+++ b/lib/libc/unistd/geteuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+gid_t geteuid(void)
+{
+ return syscall(geteuid);
+}
diff --git a/lib/libc/unistd/getgid.c b/lib/libc/unistd/getgid.c
new file mode 100644
index 00000000..7d19d58e
--- /dev/null
+++ b/lib/libc/unistd/getgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+gid_t getgid(void)
+{
+ return syscall(getgid);
+}
diff --git a/lib/libc/unistd/getgroups.c b/lib/libc/unistd/getgroups.c
new file mode 100644
index 00000000..fb1346e5
--- /dev/null
+++ b/lib/libc/unistd/getgroups.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int getgroups(int gidsetsize, gid_t grouplist[])
+{
+ return syscall(getgroups, gidsetsize, grouplist);
+}
diff --git a/lib/libc/unistd/gethostid.c b/lib/libc/unistd/gethostid.c
new file mode 100644
index 00000000..e3079534
--- /dev/null
+++ b/lib/libc/unistd/gethostid.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+
+long gethostid(void)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/gethostname.c b/lib/libc/unistd/gethostname.c
new file mode 100644
index 00000000..a20808e1
--- /dev/null
+++ b/lib/libc/unistd/gethostname.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int gethostname(char *name, size_t namelen)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/getlogin.c b/lib/libc/unistd/getlogin.c
new file mode 100644
index 00000000..04355db1
--- /dev/null
+++ b/lib/libc/unistd/getlogin.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+
+char *getlogin(void)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/getlogin_r.c b/lib/libc/unistd/getlogin_r.c
new file mode 100644
index 00000000..3dea2dff
--- /dev/null
+++ b/lib/libc/unistd/getlogin_r.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int getlogin_r(char *name, size_t namesize)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/getopt.c b/lib/libc/unistd/getopt.c
new file mode 100644
index 00000000..8ef18d37
--- /dev/null
+++ b/lib/libc/unistd/getopt.c
@@ -0,0 +1,114 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/uio.h>
+
+char *optarg;
+int optind = 1, opterr = 1, optopt;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+ char *optchar;
+ char c, d;
+ int i;
+ static int optpos;
+
+ if (optind == 0) {
+ optpos = 0;
+ optind = 1;
+ }
+
+ if (optind >= argc || !argv[optind]) {
+ return -1;
+ }
+
+ if (argv[optind][0] != '-') {
+ if (optstring[0] == '-') {
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ return -1;
+ }
+
+ if (argv[optind][1] == 0) {
+ return -1;
+ }
+
+ if (argv[optind][1] == '-' && argv[optind][2] == 0) {
+ return optind++, -1;
+ }
+
+ if (optpos == 0)
+ optpos++;
+
+ c = argv[optind][optpos];
+ optchar = argv[optind] + optpos++;
+
+ if (argv[optind][optpos] == 0) {
+ optind++;
+ optpos = 0;
+ }
+
+ i = 0;
+
+ do {
+ d = optstring[i++];
+ } while (d && d != c);
+
+ if (d != c || c == ':') {
+ optopt = c;
+ if (optstring[0] != ':' && opterr) {
+ struct iovec iov[4];
+ char opt_char[2] = { *optchar, '\0' };
+
+ iov[0].iov_base = argv[0];
+ iov[0].iov_len = strlen(argv[0]);
+ iov[1].iov_base = ": invalid option -- ";
+ iov[1].iov_len = 20;
+ iov[2].iov_base = opt_char;
+ iov[2].iov_len = 1;
+ iov[3].iov_base = "\n";
+ iov[3].iov_len = 1;
+
+ writev(STDERR_FILENO, iov, 4);
+ }
+ return '?';
+ }
+
+ if (optstring[i] == ':') {
+ optarg = 0;
+ if (optstring[i + 1] != ':' || optpos) {
+ optarg = argv[optind++];
+ if (optpos) {
+ optarg += optpos;
+ }
+ optpos = 0;
+ }
+ if (optind > argc) {
+ optopt = c;
+ if (optstring[0] == ':') {
+ return ':';
+ }
+ if (opterr) {
+ struct iovec iov[4];
+ char opt_char[2] = { *optchar, '\0' };
+
+ iov[0].iov_base = argv[0];
+ iov[0].iov_len = strlen(argv[0]);
+ iov[1].iov_base =
+ ": option requires an argument -- ";
+ iov[1].iov_len = 33;
+ iov[2].iov_base = opt_char;
+ iov[2].iov_len = 1;
+ iov[3].iov_base = "\n";
+ iov[3].iov_len = 1;
+
+ writev(STDERR_FILENO, iov, 4);
+ }
+ return '?';
+ }
+ }
+
+ return c;
+}
diff --git a/lib/libc/unistd/getpgid.c b/lib/libc/unistd/getpgid.c
new file mode 100644
index 00000000..aed55bb9
--- /dev/null
+++ b/lib/libc/unistd/getpgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+pid_t getpgid(pid_t pid)
+{
+ return syscall(getpgid, pid);
+}
diff --git a/lib/libc/unistd/getpid.c b/lib/libc/unistd/getpid.c
new file mode 100644
index 00000000..46562867
--- /dev/null
+++ b/lib/libc/unistd/getpid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+pid_t getpid(void)
+{
+ return syscall(getpid);
+}
diff --git a/lib/libc/unistd/getppid.c b/lib/libc/unistd/getppid.c
new file mode 100644
index 00000000..16bf101e
--- /dev/null
+++ b/lib/libc/unistd/getppid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+pid_t getppid(void)
+{
+ return syscall(getppid);
+}
diff --git a/lib/libc/unistd/getresgid.c b/lib/libc/unistd/getresgid.c
new file mode 100644
index 00000000..ccdbabaa
--- /dev/null
+++ b/lib/libc/unistd/getresgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int getresgid(gid_t *restrict rgid, gid_t *restrict egid, gid_t *restrict sgid)
+{
+ return syscall(getresgid, rgid, egid, sgid);
+}
diff --git a/lib/libc/unistd/getresuid.c b/lib/libc/unistd/getresuid.c
new file mode 100644
index 00000000..a9a405ae
--- /dev/null
+++ b/lib/libc/unistd/getresuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int getresuid(uid_t *restrict ruid, uid_t *restrict euid, uid_t *restrict suid)
+{
+ return syscall(getresuid, ruid, euid, suid);
+}
diff --git a/lib/libc/unistd/getsid.c b/lib/libc/unistd/getsid.c
new file mode 100644
index 00000000..e0a06780
--- /dev/null
+++ b/lib/libc/unistd/getsid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+pid_t getsid(pid_t pid)
+{
+ return syscall(getsid, pid);
+}
diff --git a/lib/libc/unistd/getuid.c b/lib/libc/unistd/getuid.c
new file mode 100644
index 00000000..9223ae6f
--- /dev/null
+++ b/lib/libc/unistd/getuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+uid_t getuid(void)
+{
+ return syscall(getuid);
+}
diff --git a/lib/libc/unistd/isatty.c b/lib/libc/unistd/isatty.c
new file mode 100644
index 00000000..afb15460
--- /dev/null
+++ b/lib/libc/unistd/isatty.c
@@ -0,0 +1,10 @@
+#include <termios.h>
+#include <unistd.h>
+#include <syscall.h>
+#include <asm-generic/ioctls.h>
+
+int isatty(int fildes)
+{
+ struct winsize winsize;
+ return 1 + syscall(ioctl, fildes, TIOCGWINSZ, &winsize);
+}
diff --git a/lib/libc/unistd/lchown.c b/lib/libc/unistd/lchown.c
new file mode 100644
index 00000000..a18be4c6
--- /dev/null
+++ b/lib/libc/unistd/lchown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int lchown(const char *path, uid_t owner, gid_t group)
+{
+ return syscall(lchown, path, owner, group);
+}
diff --git a/lib/libc/unistd/link.c b/lib/libc/unistd/link.c
new file mode 100644
index 00000000..07204ed0
--- /dev/null
+++ b/lib/libc/unistd/link.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int link(const char *path1, const char *path2)
+{
+ return syscall(link, path1, path2);
+}
diff --git a/lib/libc/unistd/linkat.c b/lib/libc/unistd/linkat.c
new file mode 100644
index 00000000..72dca11e
--- /dev/null
+++ b/lib/libc/unistd/linkat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag)
+{
+ return syscall(linkat, fd1, path1, fd2, path2, flag);
+}
diff --git a/lib/libc/unistd/lockf.c b/lib/libc/unistd/lockf.c
new file mode 100644
index 00000000..8b807c34
--- /dev/null
+++ b/lib/libc/unistd/lockf.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int lockf(int fildes, int function, off_t size)
+{
+ // TODO
+ return 0;
+}
diff --git a/lib/libc/unistd/lseek.c b/lib/libc/unistd/lseek.c
new file mode 100644
index 00000000..d8b41f88
--- /dev/null
+++ b/lib/libc/unistd/lseek.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+off_t lseek(int fildes, off_t offset, int whence)
+{
+ return syscall(lseek, fildes, offset, whence);
+}
diff --git a/lib/libc/unistd/nice.c b/lib/libc/unistd/nice.c
new file mode 100644
index 00000000..3b240c93
--- /dev/null
+++ b/lib/libc/unistd/nice.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int nice(int incr)
+{
+ // TODO: needs getpriority and setpriority from sys/resouce.h
+ return 0;
+}
diff --git a/lib/libc/unistd/pause.c b/lib/libc/unistd/pause.c
new file mode 100644
index 00000000..bd959bc5
--- /dev/null
+++ b/lib/libc/unistd/pause.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int pause(void)
+{
+ return syscall(pause);
+}
diff --git a/lib/libc/unistd/pipe.c b/lib/libc/unistd/pipe.c
new file mode 100644
index 00000000..4f8e0e98
--- /dev/null
+++ b/lib/libc/unistd/pipe.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int pipe(int fildes[2])
+{
+ return syscall(pipe, fildes);
+}
diff --git a/lib/libc/unistd/pipe2.c b/lib/libc/unistd/pipe2.c
new file mode 100644
index 00000000..a28aecdd
--- /dev/null
+++ b/lib/libc/unistd/pipe2.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int pipe2(int fildes[2], int flag)
+{
+ return syscall(pipe2, fildes, flag);
+}
diff --git a/lib/libc/unistd/posix_close.c b/lib/libc/unistd/posix_close.c
new file mode 100644
index 00000000..fe44a7b9
--- /dev/null
+++ b/lib/libc/unistd/posix_close.c
@@ -0,0 +1,7 @@
+#include <libc.h>
+#include <syscall.h>
+
+int posix_close(int fildes, int unused flag)
+{
+ return syscall(close, fildes);
+}
diff --git a/lib/libc/unistd/pread.c b/lib/libc/unistd/pread.c
new file mode 100644
index 00000000..ad8e71b0
--- /dev/null
+++ b/lib/libc/unistd/pread.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
+{
+ return syscall(pread, fildes, buf, nbyte, offset);
+}
diff --git a/lib/libc/unistd/pwrite.c b/lib/libc/unistd/pwrite.c
new file mode 100644
index 00000000..8a2eadbe
--- /dev/null
+++ b/lib/libc/unistd/pwrite.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
+{
+ return syscall(pwrite, fildes, buf, nbyte, offset);
+}
diff --git a/lib/libc/unistd/read.c b/lib/libc/unistd/read.c
new file mode 100644
index 00000000..54c29586
--- /dev/null
+++ b/lib/libc/unistd/read.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+#include <unistd.h>
+
+ssize_t read(int fildes, void *buf, size_t nbyte)
+{
+ return syscall(read, fildes, buf, nbyte);
+}
diff --git a/lib/libc/unistd/readlink.c b/lib/libc/unistd/readlink.c
new file mode 100644
index 00000000..8587f526
--- /dev/null
+++ b/lib/libc/unistd/readlink.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
+{
+ return syscall(readlink, path, buf, bufsize);
+}
diff --git a/lib/libc/unistd/readlinkat.c b/lib/libc/unistd/readlinkat.c
new file mode 100644
index 00000000..d2a87b2b
--- /dev/null
+++ b/lib/libc/unistd/readlinkat.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf,
+ size_t bufsize)
+{
+ return syscall(readlinkat, fd, path, buf, bufsize);
+}
diff --git a/lib/libc/unistd/rmdir.c b/lib/libc/unistd/rmdir.c
new file mode 100644
index 00000000..5aab225c
--- /dev/null
+++ b/lib/libc/unistd/rmdir.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int rmdir(const char *path)
+{
+ return syscall(rmdir, path);
+}
diff --git a/lib/libc/unistd/setegid.c b/lib/libc/unistd/setegid.c
new file mode 100644
index 00000000..7fd9adb6
--- /dev/null
+++ b/lib/libc/unistd/setegid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setegid(gid_t gid)
+{
+ return syscall(setresgid, -1, gid, -1);
+}
diff --git a/lib/libc/unistd/seteuid.c b/lib/libc/unistd/seteuid.c
new file mode 100644
index 00000000..6d86bee5
--- /dev/null
+++ b/lib/libc/unistd/seteuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int seteuid(uid_t uid)
+{
+ return syscall(setresuid, -1, uid, -1);
+}
diff --git a/lib/libc/unistd/setgid.c b/lib/libc/unistd/setgid.c
new file mode 100644
index 00000000..aa07c330
--- /dev/null
+++ b/lib/libc/unistd/setgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setgid(gid_t gid)
+{
+ return syscall(setgid, gid);
+}
diff --git a/lib/libc/unistd/setpgid.c b/lib/libc/unistd/setpgid.c
new file mode 100644
index 00000000..e4fd6efd
--- /dev/null
+++ b/lib/libc/unistd/setpgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setpgid(pid_t pid, pid_t pgid)
+{
+ return syscall(setpgid, pid, pgid);
+}
diff --git a/lib/libc/unistd/setregid.c b/lib/libc/unistd/setregid.c
new file mode 100644
index 00000000..633f22a6
--- /dev/null
+++ b/lib/libc/unistd/setregid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setregid(gid_t rgid, gid_t egid)
+{
+ return syscall(setregid, rgid, egid);
+}
diff --git a/lib/libc/unistd/setresgid.c b/lib/libc/unistd/setresgid.c
new file mode 100644
index 00000000..6de609fa
--- /dev/null
+++ b/lib/libc/unistd/setresgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ return syscall(setresgid, rgid, egid, sgid);
+}
diff --git a/lib/libc/unistd/setresuid.c b/lib/libc/unistd/setresuid.c
new file mode 100644
index 00000000..1fd74baa
--- /dev/null
+++ b/lib/libc/unistd/setresuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+ return syscall(setresuid, ruid, euid, suid);
+}
diff --git a/lib/libc/unistd/setreuid.c b/lib/libc/unistd/setreuid.c
new file mode 100644
index 00000000..5f277ba3
--- /dev/null
+++ b/lib/libc/unistd/setreuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setreuid(uid_t ruid, uid_t euid)
+{
+ return syscall(setreuid, ruid, euid);
+}
diff --git a/lib/libc/unistd/setsid.c b/lib/libc/unistd/setsid.c
new file mode 100644
index 00000000..16b812e0
--- /dev/null
+++ b/lib/libc/unistd/setsid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+pid_t setsid(void)
+{
+ return syscall(setsid);
+}
diff --git a/lib/libc/unistd/setuid.c b/lib/libc/unistd/setuid.c
new file mode 100644
index 00000000..ab8ff73f
--- /dev/null
+++ b/lib/libc/unistd/setuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int setuid(uid_t uid)
+{
+ return syscall(setuid, uid);
+}
diff --git a/lib/libc/unistd/sleep.c b/lib/libc/unistd/sleep.c
new file mode 100644
index 00000000..b2aef854
--- /dev/null
+++ b/lib/libc/unistd/sleep.c
@@ -0,0 +1,10 @@
+#include <time.h>
+#include <unistd.h>
+
+unsigned sleep(unsigned seconds)
+{
+ struct timespec tv = { .tv_sec = seconds, .tv_nsec = 0 };
+ if (nanosleep(&tv, &tv))
+ return tv.tv_sec;
+ return 0;
+}
diff --git a/lib/libc/unistd/swab.c b/lib/libc/unistd/swab.c
new file mode 100644
index 00000000..5e4e7e3b
--- /dev/null
+++ b/lib/libc/unistd/swab.c
@@ -0,0 +1,17 @@
+#include <unistd.h>
+
+void swab(const void *restrict src, void *restrict dest, ssize_t nbytes)
+{
+ const char *s = src;
+ char *d = dest;
+
+ if (nbytes <= 0)
+ return;
+
+ ssize_t n = nbytes & ~1;
+
+ for (ssize_t i = 0; i < n; i += 2) {
+ d[i] = s[i + 1];
+ d[i + 1] = s[i];
+ }
+}
diff --git a/lib/libc/unistd/symlink.c b/lib/libc/unistd/symlink.c
new file mode 100644
index 00000000..0b84148e
--- /dev/null
+++ b/lib/libc/unistd/symlink.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int symlink(const char *path1, const char *path2)
+{
+ return syscall(symlink, path1, path2);
+}
diff --git a/lib/libc/unistd/symlinkat.c b/lib/libc/unistd/symlinkat.c
new file mode 100644
index 00000000..d4dd2ee0
--- /dev/null
+++ b/lib/libc/unistd/symlinkat.c
@@ -0,0 +1,7 @@
+#include <syscall.h>
+
+int symlinkat(const char *path1, int fd, const char *path2)
+
+{
+ return syscall(symlinkat, path1, fd, path2);
+}
diff --git a/lib/libc/unistd/sync.c b/lib/libc/unistd/sync.c
new file mode 100644
index 00000000..e655213b
--- /dev/null
+++ b/lib/libc/unistd/sync.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+void sync(void)
+{
+ syscall(sync);
+}
diff --git a/lib/libc/unistd/truncate.c b/lib/libc/unistd/truncate.c
new file mode 100644
index 00000000..2611d40a
--- /dev/null
+++ b/lib/libc/unistd/truncate.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+int truncate(const char *path, off_t length)
+{
+ return syscall(truncate, path, length);
+}
diff --git a/lib/libc/unistd/unlink.c b/lib/libc/unistd/unlink.c
new file mode 100644
index 00000000..1d3859f9
--- /dev/null
+++ b/lib/libc/unistd/unlink.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int unlink(const char *path)
+{
+ return syscall(unlink, path);
+}
diff --git a/lib/libc/unistd/unlinkat.c b/lib/libc/unistd/unlinkat.c
new file mode 100644
index 00000000..837105a1
--- /dev/null
+++ b/lib/libc/unistd/unlinkat.c
@@ -0,0 +1,6 @@
+#include <syscall.h>
+
+int unlinkat(int fd, const char *path, int flag)
+{
+ return syscall(unlinkat, fd, path, flag);
+}
diff --git a/lib/libc/unistd/write.c b/lib/libc/unistd/write.c
new file mode 100644
index 00000000..c7bd5dbc
--- /dev/null
+++ b/lib/libc/unistd/write.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <syscall.h>
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+ return syscall(write, fd, buf, count);
+}
diff --git a/lib/libc/utsname/uname.c b/lib/libc/utsname/uname.c
new file mode 100644
index 00000000..babf5685
--- /dev/null
+++ b/lib/libc/utsname/uname.c
@@ -0,0 +1,7 @@
+#include <sys/utsname.h>
+#include <syscall.h>
+
+int uname(struct utsname *name)
+{
+ return syscall(uname, name);
+}
diff --git a/lib/libc/wait/wait.c b/lib/libc/wait/wait.c
new file mode 100644
index 00000000..f0583bfc
--- /dev/null
+++ b/lib/libc/wait/wait.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include <syscall.h>
+
+pid_t wait(int *stat_loc)
+{
+ return syscall(wait4, -1, stat_loc, 0, 0);
+}
diff --git a/lib/libc/wait/waitid.c b/lib/libc/wait/waitid.c
new file mode 100644
index 00000000..5b6237b8
--- /dev/null
+++ b/lib/libc/wait/waitid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include <syscall.h>
+
+int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)
+{
+ return syscall(waitid, idtype, id, infop, options);
+}
diff --git a/lib/libc/wait/waitpid.c b/lib/libc/wait/waitpid.c
new file mode 100644
index 00000000..a5746efc
--- /dev/null
+++ b/lib/libc/wait/waitpid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include <syscall.h>
+
+pid_t waitpid(pid_t pid, int *stat_loc, int options)
+{
+ return syscall(wait4, pid, stat_loc, options, 0);
+}
diff --git a/lib/libc/wchar/wctob.c b/lib/libc/wchar/wctob.c
new file mode 100644
index 00000000..702e3f75
--- /dev/null
+++ b/lib/libc/wchar/wctob.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+#define IS_CODEUNIT(c) ((unsigned)(c) - 0xdf80 < 0x80)
+
+int wctob(wint_t c)
+{
+ if (c < 128U)
+ return (int)c;
+
+ if (MB_CUR_MAX == 1 && IS_CODEUNIT(c))
+ return (unsigned char)c;
+
+ return EOF;
+}
diff --git a/lib/libc/wctype/iswalnum.c b/lib/libc/wctype/iswalnum.c
new file mode 100644
index 00000000..3eb2f14f
--- /dev/null
+++ b/lib/libc/wctype/iswalnum.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswalnum(wint_t wc)
+{
+ return iswdigit(wc) || iswalpha(wc);
+}
+
+weak int iswalnum_l(wint_t wc, locale_t unused locale)
+{
+ return iswalnum(wc);
+}
diff --git a/lib/libc/wctype/iswalpha.c b/lib/libc/wctype/iswalpha.c
new file mode 100644
index 00000000..17c8508c
--- /dev/null
+++ b/lib/libc/wctype/iswalpha.c
@@ -0,0 +1,22 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswalpha(wint_t wc)
+{
+ const unsigned char t[] = {
+#include <__alpha.h>
+ };
+
+ if (wc < 0x20000U)
+ return (t[t[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1;
+
+ if (wc < 0x2fffeU)
+ return 1;
+
+ return 0;
+}
+
+weak int iswalpha_l(wint_t wc, locale_t unused locale)
+{
+ return iswalpha(wc);
+}
diff --git a/lib/libc/wctype/iswblank.c b/lib/libc/wctype/iswblank.c
new file mode 100644
index 00000000..61664162
--- /dev/null
+++ b/lib/libc/wctype/iswblank.c
@@ -0,0 +1,13 @@
+#include <libc.h>
+#include <wctype.h>
+#include <ctype.h>
+
+int iwsblank(wint_t wc)
+{
+ return isblank((unsigned char)wc);
+}
+
+weak int iswblank_l(wint_t c, locale_t unused locale)
+{
+ return iswblank(c);
+}
diff --git a/lib/libc/wctype/iswdigit.c b/lib/libc/wctype/iswdigit.c
new file mode 100644
index 00000000..e775f561
--- /dev/null
+++ b/lib/libc/wctype/iswdigit.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswdigit(wint_t wc)
+{
+ return (wc >= L'0' && wc <= L'9');
+}
+
+weak int iswdigit_l(wint_t wc, locale_t unused locale)
+{
+ return iswdigit(wc);
+}
diff --git a/lib/libc/wctype/iswgraph.c b/lib/libc/wctype/iswgraph.c
new file mode 100644
index 00000000..00ab6cca
--- /dev/null
+++ b/lib/libc/wctype/iswgraph.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswgraph(wint_t wc)
+{
+ return iswprint(wc) && !iswspace(wc);
+}
+
+weak int iswgraph_l(wint_t wc, locale_t unused locale)
+{
+ return iswgraph(wc);
+}
diff --git a/lib/libc/wctype/iswlower.c b/lib/libc/wctype/iswlower.c
new file mode 100644
index 00000000..dea58f3a
--- /dev/null
+++ b/lib/libc/wctype/iswlower.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswlower(wint_t wc)
+{
+ return towupper(wc) != wc;
+}
+
+weak int islower_l(wint_t wc, locale_t unused locale)
+{
+ return iswlower(wc);
+}
diff --git a/lib/libc/wctype/iswprint.c b/lib/libc/wctype/iswprint.c
new file mode 100644
index 00000000..f0b26fbf
--- /dev/null
+++ b/lib/libc/wctype/iswprint.c
@@ -0,0 +1,14 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswprint(wint_t wc)
+{
+ return (wc >= 0x20 && wc <= 0x7E) ||
+ (wc >= 0xA0 && wc <= 0x10FFFF && (wc < 0xFDD0 || wc > 0xFDEF) &&
+ (wc & 0xFFFE) != 0xFFFE);
+}
+
+weak int iswprint_l(wint_t wc, locale_t unused locale)
+{
+ return iswprint(wc);
+}
diff --git a/lib/libc/wctype/iswpunct.c b/lib/libc/wctype/iswpunct.c
new file mode 100644
index 00000000..d7ed6487
--- /dev/null
+++ b/lib/libc/wctype/iswpunct.c
@@ -0,0 +1,327 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswpunct(wint_t wc)
+{
+ const unsigned char t[] = {
+ 18, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 16, 16, 34, 35, 16, 36, 37, 38, 39,
+ 40, 41, 42, 43, 16, 44, 45, 46, 17, 17, 47, 17, 17,
+ 17, 17, 17, 17, 48, 49, 50, 51, 52, 53, 54, 55, 17,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 56,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 57, 16, 58, 59, 60,
+ 61, 62, 63, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 64, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 65, 16, 16, 66, 16, 67, 68, 69, 16, 70, 71, 72,
+ 16, 73, 16, 16, 74, 75, 76, 77, 78, 16, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 16, 92, 93,
+ 94, 95, 16, 16, 16, 16, 96, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 97, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 98, 99,
+ 16, 16, 100, 101, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 102, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 103, 104, 105, 106,
+ 16, 16, 107, 108, 17, 17, 109, 16, 16, 16, 16, 16, 16,
+ 110, 111, 16, 16, 16, 16, 16, 112, 113, 16, 16, 114, 115,
+ 116, 16, 117, 118, 119, 17, 17, 17, 120, 121, 122, 123, 124,
+ 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 0, 0, 0, 0, 254, 255, 0, 252, 1,
+ 0, 0, 248, 1, 0, 0, 120, 0, 0, 0, 0, 255, 251,
+ 223, 251, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 252, 255, 224,
+ 175, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 223, 255,
+ 255, 255, 255, 255, 32, 64, 176, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 252, 0, 0, 0, 0, 0, 230, 254, 255, 255, 255, 0, 64,
+ 73, 0, 0, 0, 0, 0, 24, 0, 255, 255, 0, 216, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 16, 224, 1, 30, 0,
+ 96, 255, 191, 0, 0, 0, 0, 0, 0, 255, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 248, 207, 227, 0, 0, 0, 3, 0, 32,
+ 255, 127, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 8, 0, 7, 252, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 30, 0, 48,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32,
+ 0, 0, 0, 0, 252, 111, 0, 0, 0, 0, 0, 0, 0,
+ 16, 0, 32, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 16, 0, 32, 0, 0, 0, 0, 3, 224, 0,
+ 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0, 0,
+ 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0,
+ 0, 0, 0, 255, 7, 16, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 0, 0, 0, 0, 128, 255, 16, 0, 0, 0, 0,
+ 0, 0, 16, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 24, 0, 160, 0, 127, 0, 0, 255,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 16, 0, 0, 0, 0, 0, 0, 128, 0, 128, 192,
+ 223, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 0, 31, 0, 0, 0, 0, 0, 0, 254, 255, 255,
+ 255, 0, 252, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 252, 0, 0, 0, 0, 0, 0, 192, 255, 223, 255, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 6, 0, 252,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 255, 31, 0,
+ 0, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 1, 0,
+ 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0,
+ 0, 0, 0, 16, 0, 0, 0, 112, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0,
+ 254, 127, 47, 0, 0, 255, 3, 255, 127, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 14, 49, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 196, 255, 255, 255, 255, 0, 0, 0, 192, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 224, 159, 0, 0, 0, 0,
+ 127, 63, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, 252, 255, 255,
+ 255, 31, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0,
+ 0, 64, 0, 12, 240, 0, 0, 0, 0, 0, 0, 128, 248,
+ 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 0, 255, 255, 255, 33, 144, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 127, 0, 224, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 160, 3, 224, 0, 224, 0, 224, 0, 96, 128, 248, 255,
+ 255, 255, 252, 255, 255, 255, 255, 255, 127, 223, 255, 241, 127,
+ 255, 127, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255,
+ 255, 1, 0, 123, 3, 208, 193, 175, 66, 0, 12, 31, 188,
+ 255, 255, 0, 0, 0, 0, 0, 14, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 127, 0, 0, 0, 255, 7, 0, 0, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 252,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 207, 255, 255, 255, 63, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 135, 3,
+ 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 127,
+ 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255,
+ 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 63, 0, 0, 0, 255, 15, 30, 255, 255, 255, 1, 252, 193,
+ 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 255,
+ 255, 15, 0, 0, 0, 255, 255, 255, 127, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 127, 0, 0, 0, 0, 0, 0, 192, 0, 224, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 15, 112,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 255, 0, 255, 255, 127, 0, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
+ 0, 15, 255, 3, 0, 0, 0, 0, 0, 0, 240, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 16, 192, 0, 0, 255, 255,
+ 3, 23, 0, 0, 0, 0, 0, 248, 0, 0, 0, 0, 8,
+ 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,
+ 255, 63, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 240, 0, 0, 128, 3, 0, 0,
+ 0, 0, 0, 0, 0, 128, 2, 0, 0, 192, 0, 0, 67,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 56, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 252, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 255, 255, 255, 3, 255, 255, 255, 255,
+ 255, 255, 247, 255, 127, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 254, 255,
+ 0, 252, 1, 0, 0, 248, 1, 0, 0, 248, 63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 127, 127, 0, 48, 135, 255, 255, 255, 255, 255, 143, 255, 0,
+ 0, 0, 0, 0, 0, 224, 255, 255, 127, 255, 15, 1, 0,
+ 0, 0, 0, 0, 255, 255, 255, 255, 255, 63, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
+ 255, 255, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128,
+ 255, 0, 0, 128, 255, 0, 0, 0, 0, 128, 255, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 248, 0, 0, 192, 143, 0,
+ 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 255, 255, 252, 255, 255, 255, 255,
+ 255, 0, 0, 0, 0, 0, 0, 0, 135, 255, 1, 255, 1,
+ 0, 0, 0, 224, 0, 0, 0, 224, 0, 0, 0, 0, 0,
+ 1, 0, 0, 96, 248, 127, 0, 0, 0, 0, 0, 0, 0,
+ 0, 254, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0,
+ 30, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 224, 127, 0, 0, 0, 192, 255, 255, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 192, 63, 252, 255, 63, 0, 0, 128, 3, 0, 0, 0, 0,
+ 0, 0, 254, 3, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 0, 15, 0, 0, 0, 0, 0, 56,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 63, 0, 232,
+ 254, 255, 31, 0, 0, 0, 0, 0, 0, 0, 96, 63, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 0, 32, 0, 0, 192, 31, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 248,
+ 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 14, 0, 0,
+ 0, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 0, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 252, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 24, 128, 255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 223, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 62, 0, 0, 252, 255, 31, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
+ 255, 255, 3, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0,
+ 0, 0, 255, 255, 48, 0, 0, 248, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 255, 255, 255, 7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 176, 15, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0,
+ 255, 255, 255, 255, 127, 254, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 1, 0, 0, 255, 255, 255, 255, 255, 255, 255,
+ 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 15, 0, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 255, 255,
+ 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 8, 0, 0, 0, 8, 0, 0,
+ 32, 0, 0, 0, 32, 0, 0, 128, 0, 0, 0, 128, 0,
+ 0, 0, 2, 0, 0, 0, 2, 0, 0, 8, 0, 0, 0,
+ 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 248, 254, 255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 127, 0, 0, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 240, 0, 128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 128, 255, 127, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 7, 0,
+ 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255,
+ 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 254, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
+ 255, 255, 255, 255, 255, 15, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 15, 0, 255, 127, 254, 255, 254, 255,
+ 254, 255, 255, 255, 63, 0, 255, 31, 255, 255, 255, 255, 0,
+ 0, 0, 252, 0, 0, 0, 28, 0, 0, 0, 252, 255, 255,
+ 255, 31, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 7,
+ 0, 255, 255, 255, 255, 255, 15, 255, 1, 3, 0, 63, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 63, 0, 255, 31, 255, 7, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15,
+ 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1,
+ 255, 15, 0, 0, 255, 15, 255, 255, 255, 255, 255, 255, 255,
+ 0, 255, 3, 255, 255, 255, 255, 255, 0, 255, 255, 255, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 239, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 123, 252,
+ 255, 255, 255, 255, 231, 199, 255, 255, 255, 231, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 15, 0, 255, 63, 15, 7, 7, 0, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ };
+
+ if (wc < 0x20000U)
+ return (t[t[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1;
+
+ return 0;
+}
+
+weak int iswctype_l(wint_t wc, wctype_t charclass, locale_t unused locale)
+{
+ return iswctype(wc, charclass);
+}
diff --git a/lib/libc/wctype/iswspace.c b/lib/libc/wctype/iswspace.c
new file mode 100644
index 00000000..3b6806af
--- /dev/null
+++ b/lib/libc/wctype/iswspace.c
@@ -0,0 +1,20 @@
+#include <libc.h>
+#include <wchar.h>
+#include <wctype.h>
+
+int iswspace(wint_t wc)
+{
+ const wchar_t t[] = { L' ', L'\t', L'\n', L'\r', 11, 12,
+ 0x0085, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004,
+ 0x2005, 0x2006, 0x2008, 0x2009, 0x200a, 0x2028,
+ 0x2029, 0x205f, 0x3000, 0
+
+ };
+
+ return wc && wcschr(t, (wchar_t)wc) != NULL;
+}
+
+weak int iswspace_l(wint_t wc, locale_t unused locale)
+{
+ return iswspace(wc);
+}
diff --git a/lib/libc/wctype/iswupper.c b/lib/libc/wctype/iswupper.c
new file mode 100644
index 00000000..afe12049
--- /dev/null
+++ b/lib/libc/wctype/iswupper.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswupper(wint_t wc)
+{
+ return towlower(wc) != wc;
+}
+
+weak int iswupper_l(wint_t wc, locale_t unused locale)
+{
+ return iswupper(wc);
+}
diff --git a/lib/libc/wctype/iswxdigit.c b/lib/libc/wctype/iswxdigit.c
new file mode 100644
index 00000000..fae88730
--- /dev/null
+++ b/lib/libc/wctype/iswxdigit.c
@@ -0,0 +1,12 @@
+#include <libc.h>
+#include <wctype.h>
+
+int iswxdigit(wint_t wc)
+{
+ return (unsigned)(wc - '0') < 10 || (unsigned)((wc | 32) - 'a') < 6;
+}
+
+weak int iswxdigit_l(wint_t wc, locale_t unused locale)
+{
+ return iswxdigit(wc);
+}
diff --git a/lib/libc/wctype/towctrans.c b/lib/libc/wctype/towctrans.c
new file mode 100644
index 00000000..9e7f3b63
--- /dev/null
+++ b/lib/libc/wctype/towctrans.c
@@ -0,0 +1,348 @@
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/* From embeddedartistry/libc */
+#define CASEMAP(u1, u2, l) { (u1), (l) - (u1), (u2) - (u1) + 1 }
+#define CASELACE(u1, u2) CASEMAP((u1), (u2), (u1) + 1)
+
+static const struct {
+ unsigned short upper;
+ signed char lower;
+ unsigned char len;
+} casemaps[] = {
+ CASEMAP(0xc0, 0xde, 0xe0),
+
+ CASELACE(0x0100, 0x012e), CASELACE(0x0132, 0x0136),
+ CASELACE(0x0139, 0x0147), CASELACE(0x014a, 0x0176),
+ CASELACE(0x0179, 0x017d),
+
+ CASELACE(0x370, 0x372), CASEMAP(0x391, 0x3a1, 0x3b1),
+ CASEMAP(0x3a3, 0x3ab, 0x3c3), CASEMAP(0x400, 0x40f, 0x450),
+ CASEMAP(0x410, 0x42f, 0x430),
+
+ CASELACE(0x460, 0x480), CASELACE(0x48a, 0x4be),
+ CASELACE(0x4c1, 0x4cd), CASELACE(0x4d0, 0x50e),
+
+ CASELACE(0x514, 0x52e), CASEMAP(0x531, 0x556, 0x561),
+
+ CASELACE(0x01a0, 0x01a4), CASELACE(0x01b3, 0x01b5),
+ CASELACE(0x01cd, 0x01db), CASELACE(0x01de, 0x01ee),
+ CASELACE(0x01f8, 0x021e), CASELACE(0x0222, 0x0232),
+ CASELACE(0x03d8, 0x03ee),
+
+ CASELACE(0x1e00, 0x1e94), CASELACE(0x1ea0, 0x1efe),
+
+ CASEMAP(0x1f08, 0x1f0f, 0x1f00), CASEMAP(0x1f18, 0x1f1d, 0x1f10),
+ CASEMAP(0x1f28, 0x1f2f, 0x1f20), CASEMAP(0x1f38, 0x1f3f, 0x1f30),
+ CASEMAP(0x1f48, 0x1f4d, 0x1f40),
+
+ CASEMAP(0x1f68, 0x1f6f, 0x1f60), CASEMAP(0x1f88, 0x1f8f, 0x1f80),
+ CASEMAP(0x1f98, 0x1f9f, 0x1f90), CASEMAP(0x1fa8, 0x1faf, 0x1fa0),
+ CASEMAP(0x1fb8, 0x1fb9, 0x1fb0), CASEMAP(0x1fba, 0x1fbb, 0x1f70),
+ CASEMAP(0x1fc8, 0x1fcb, 0x1f72), CASEMAP(0x1fd8, 0x1fd9, 0x1fd0),
+ CASEMAP(0x1fda, 0x1fdb, 0x1f76), CASEMAP(0x1fe8, 0x1fe9, 0x1fe0),
+ CASEMAP(0x1fea, 0x1feb, 0x1f7a), CASEMAP(0x1ff8, 0x1ff9, 0x1f78),
+ CASEMAP(0x1ffa, 0x1ffb, 0x1f7c),
+
+ CASEMAP(0x13f0, 0x13f5, 0x13f8), CASELACE(0xa698, 0xa69a),
+ CASELACE(0xa796, 0xa79e),
+
+ CASELACE(0x246, 0x24e), CASELACE(0x510, 0x512),
+ CASEMAP(0x2160, 0x216f, 0x2170), CASEMAP(0x2c00, 0x2c2e, 0x2c30),
+ CASELACE(0x2c67, 0x2c6b), CASELACE(0x2c80, 0x2ce2),
+ CASELACE(0x2ceb, 0x2ced),
+
+ CASELACE(0xa640, 0xa66c), CASELACE(0xa680, 0xa696),
+
+ CASELACE(0xa722, 0xa72e), CASELACE(0xa732, 0xa76e),
+ CASELACE(0xa779, 0xa77b), CASELACE(0xa77e, 0xa786),
+
+ CASELACE(0xa790, 0xa792), CASELACE(0xa7a0, 0xa7a8),
+
+ CASELACE(0xa7b4, 0xa7b6),
+
+ CASEMAP(0xff21, 0xff3a, 0xff41), { 0, 0, 0 }
+};
+
+static const unsigned short pairs[][2] = { { 'I', 0x0131 },
+ { 'S', 0x017f },
+ { 0x0130, 'i' },
+ { 0x0178, 0x00ff },
+ { 0x0181, 0x0253 },
+ { 0x0182, 0x0183 },
+ { 0x0184, 0x0185 },
+ { 0x0186, 0x0254 },
+ { 0x0187, 0x0188 },
+ { 0x0189, 0x0256 },
+ { 0x018a, 0x0257 },
+ { 0x018b, 0x018c },
+ { 0x018e, 0x01dd },
+ { 0x018f, 0x0259 },
+ { 0x0190, 0x025b },
+ { 0x0191, 0x0192 },
+ { 0x0193, 0x0260 },
+ { 0x0194, 0x0263 },
+ { 0x0196, 0x0269 },
+ { 0x0197, 0x0268 },
+ { 0x0198, 0x0199 },
+ { 0x019c, 0x026f },
+ { 0x019d, 0x0272 },
+ { 0x019f, 0x0275 },
+ { 0x01a6, 0x0280 },
+ { 0x01a7, 0x01a8 },
+ { 0x01a9, 0x0283 },
+ { 0x01ac, 0x01ad },
+ { 0x01ae, 0x0288 },
+ { 0x01af, 0x01b0 },
+ { 0x01b1, 0x028a },
+ { 0x01b2, 0x028b },
+ { 0x01b7, 0x0292 },
+ { 0x01b8, 0x01b9 },
+ { 0x01bc, 0x01bd },
+ { 0x01c4, 0x01c6 },
+ { 0x01c4, 0x01c5 },
+ { 0x01c5, 0x01c6 },
+ { 0x01c7, 0x01c9 },
+ { 0x01c7, 0x01c8 },
+ { 0x01c8, 0x01c9 },
+ { 0x01ca, 0x01cc },
+ { 0x01ca, 0x01cb },
+ { 0x01cb, 0x01cc },
+ { 0x01f1, 0x01f3 },
+ { 0x01f1, 0x01f2 },
+ { 0x01f2, 0x01f3 },
+ { 0x01f4, 0x01f5 },
+ { 0x01f6, 0x0195 },
+ { 0x01f7, 0x01bf },
+ { 0x0220, 0x019e },
+ { 0x0386, 0x03ac },
+ { 0x0388, 0x03ad },
+ { 0x0389, 0x03ae },
+ { 0x038a, 0x03af },
+ { 0x038c, 0x03cc },
+ { 0x038e, 0x03cd },
+ { 0x038f, 0x03ce },
+ { 0x0399, 0x0345 },
+ { 0x0399, 0x1fbe },
+ { 0x03a3, 0x03c2 },
+ { 0x03f7, 0x03f8 },
+ { 0x03fa, 0x03fb },
+ { 0x1e60, 0x1e9b },
+ { 0x1e9e, 0xdf },
+
+ { 0x1f59, 0x1f51 },
+ { 0x1f5b, 0x1f53 },
+ { 0x1f5d, 0x1f55 },
+ { 0x1f5f, 0x1f57 },
+ { 0x1fbc, 0x1fb3 },
+ { 0x1fcc, 0x1fc3 },
+ { 0x1fec, 0x1fe5 },
+ { 0x1ffc, 0x1ff3 },
+
+ { 0x23a, 0x2c65 },
+ { 0x23b, 0x23c },
+ { 0x23d, 0x19a },
+ { 0x23e, 0x2c66 },
+ { 0x241, 0x242 },
+ { 0x243, 0x180 },
+ { 0x244, 0x289 },
+ { 0x245, 0x28c },
+ { 0x3f4, 0x3b8 },
+ { 0x3f9, 0x3f2 },
+ { 0x3fd, 0x37b },
+ { 0x3fe, 0x37c },
+ { 0x3ff, 0x37d },
+ { 0x4c0, 0x4cf },
+
+ { 0x2126, 0x3c9 },
+ { 0x212a, 'k' },
+ { 0x212b, 0xe5 },
+ { 0x2132, 0x214e },
+ { 0x2183, 0x2184 },
+ { 0x2c60, 0x2c61 },
+ { 0x2c62, 0x26b },
+ { 0x2c63, 0x1d7d },
+ { 0x2c64, 0x27d },
+ { 0x2c6d, 0x251 },
+ { 0x2c6e, 0x271 },
+ { 0x2c6f, 0x250 },
+ { 0x2c70, 0x252 },
+ { 0x2c72, 0x2c73 },
+ { 0x2c75, 0x2c76 },
+ { 0x2c7e, 0x23f },
+ { 0x2c7f, 0x240 },
+ { 0x2cf2, 0x2cf3 },
+
+ { 0xa77d, 0x1d79 },
+ { 0xa78b, 0xa78c },
+ { 0xa78d, 0x265 },
+ { 0xa7aa, 0x266 },
+
+ { 0x10c7, 0x2d27 },
+ { 0x10cd, 0x2d2d },
+
+ /* bogus greek 'symbol' letters */
+ { 0x376, 0x377 },
+ { 0x39c, 0xb5 },
+ { 0x392, 0x3d0 },
+ { 0x398, 0x3d1 },
+ { 0x3a6, 0x3d5 },
+ { 0x3a0, 0x3d6 },
+ { 0x39a, 0x3f0 },
+ { 0x3a1, 0x3f1 },
+ { 0x395, 0x3f5 },
+ { 0x3cf, 0x3d7 },
+
+ { 0xa7ab, 0x25c },
+ { 0xa7ac, 0x261 },
+ { 0xa7ad, 0x26c },
+ { 0xa7ae, 0x26a },
+ { 0xa7b0, 0x29e },
+ { 0xa7b1, 0x287 },
+ { 0xa7b2, 0x29d },
+ { 0xa7b3, 0xab53 },
+
+ /* special cyrillic lowercase forms
+ */
+ { 0x412, 0x1c80 },
+ { 0x414, 0x1c81 },
+ { 0x41e, 0x1c82 },
+ { 0x421, 0x1c83 },
+ { 0x422, 0x1c84 },
+ { 0x422, 0x1c85 },
+ { 0x42a, 0x1c86 },
+ { 0x462, 0x1c87 },
+ { 0xa64a, 0x1c88 },
+
+ { 0, 0 } };
+
+wchar_t __towcase(wchar_t wc, int lower)
+{
+ int i;
+ int lmul = 2 * lower - 1;
+ int lmask = lower - 1;
+ /* no letters with case in these large ranges */
+ if (!iswalpha((wint_t)wc) || (unsigned)wc - 0x0600 <= 0x0fff - 0x0600 ||
+ (unsigned)wc - 0x2e00 <= 0xa63f - 0x2e00 ||
+ (unsigned)wc - 0xa800 <= 0xab52 - 0xa800 ||
+ (unsigned)wc - 0xabc0 <= 0xfeff - 0xabc0) {
+ return wc;
+ }
+
+ /* special case because the diff between upper/lower is too big */
+ if (lower && (unsigned)wc - 0x10a0 < 0x2e) {
+ if (wc > 0x10c5 && wc != 0x10c7 && wc != 0x10cd) {
+ return wc;
+ }
+
+ return wc + 0x2d00 - 0x10a0;
+ }
+
+ if (!lower && (unsigned)wc - 0x2d00 < 0x26) {
+ if (wc > 0x2d25 && wc != 0x2d27 && wc != 0x2d2d) {
+ return wc;
+ }
+
+ return wc + 0x10a0 - 0x2d00;
+ }
+
+ if (lower && (unsigned)wc - 0x13a0 < 0x50) {
+ return wc + 0xab70 - 0x13a0;
+ }
+
+ if (!lower && (unsigned)wc - 0xab70 < 0x50) {
+ return wc + 0x13a0 - 0xab70;
+ }
+
+ for (i = 0; casemaps[i].len; i++) {
+ int base = casemaps[i].upper + (lmask & casemaps[i].lower);
+ if (wc - (wchar_t)base < casemaps[i].len) {
+ if (casemaps[i].lower == 1) {
+ return wc + (wchar_t)lower -
+ ((wc - casemaps[i].upper) & 1);
+ }
+ return wc + (wchar_t)(lmul * casemaps[i].lower);
+ }
+ }
+
+ for (i = 0; pairs[i][1 - lower]; i++) {
+ if (pairs[i][1 - lower] == wc) {
+ return pairs[i][lower];
+ }
+ }
+
+ if (wc - (wchar_t)(0x10428 - 0x28 * lower) < 0x28) {
+ return wc - (wchar_t)(0x28 + 0x50 * lower);
+ }
+
+ if (wc - (wchar_t)(0x104d8 - 0x28 * lower) < 0x24) {
+ return wc - (wchar_t)(0x28 + 0x50 * lower);
+ }
+
+ if (wc - (wchar_t)(0x10cc0 - 0x40 * lower) < 0x33) {
+ return wc - (wchar_t)(0x40 + 0x80 * lower);
+ }
+
+ if (wc - (wchar_t)(0x118c0 - 0x20 * lower) < 0x20) {
+ return wc - (wchar_t)(0x20 + 0x40 * lower);
+ }
+
+ if (wc - (wchar_t)(0x1e922 - 0x22 * lower) < 0x22) {
+ return wc - (wchar_t)(0x22 + 0x44 * lower);
+ }
+
+ return wc;
+}
+
+wint_t towlower(wint_t wc)
+{
+ return (wint_t)(wc < 128 ? (wint_t)tolower((int)wc) :
+ (wint_t)__towcase((wchar_t)wc, 1));
+}
+
+weak wint_t towlower_l(wint_t wc, locale_t unused locale)
+{
+ return towlower(wc);
+}
+
+wint_t towupper(wint_t wc)
+{
+ return (wint_t)(wc < 128 ? (wint_t)toupper((int)wc) :
+ (wint_t)__towcase((wchar_t)wc, 0));
+}
+
+weak wint_t towupper_l(wint_t wc, locale_t unused locale)
+{
+ return towupper(wc);
+}
+
+wctrans_t wctrans(const char *class)
+{
+ if (!strcmp(class, "toupper"))
+ return (wctrans_t)1;
+ if (!strcmp(class, "tolower"))
+ return (wctrans_t)2;
+ return 0;
+}
+
+weak wctrans_t wctrans_l(const char *class, locale_t unused locale)
+{
+ return wctrans(class);
+}
+
+wint_t towctrans(wint_t wc, wctrans_t desc)
+{
+ if (desc == (wctrans_t)1)
+ return towupper(wc);
+ if (desc == (wctrans_t)2)
+ return towlower(wc);
+ return wc;
+}
+
+weak wint_t towctrans_l(wint_t wc, wctrans_t desc, locale_t unused locale)
+{
+ return towctrans(wc, desc);
+}
diff --git a/lib/libc/wctype/wctype.c b/lib/libc/wctype/wctype.c
new file mode 100644
index 00000000..0495ba8c
--- /dev/null
+++ b/lib/libc/wctype/wctype.c
@@ -0,0 +1,32 @@
+#include <libc.h>
+#include <wctype.h>
+#include <string.h>
+
+wctype_t wctype(const char *property)
+{
+ int i;
+ const char *ptr;
+ static const char n[] = "alnum\0"
+ "alpha\0"
+ "blank\0"
+ "cntrl\0"
+ "digit\0"
+ "graph\0"
+ "lower\0"
+ "print\0"
+ "punct\0"
+ "space\0"
+ "upper\0"
+ "xdigit";
+
+ for (i = 1, ptr = n; *ptr; i++, ptr += strlen(ptr) + 1)
+ if (!strcmp(property, ptr))
+ return i;
+
+ return 0;
+}
+
+weak wctype_t wctype_l(const char *property, locale_t unused locale)
+{
+ return wctype(property);
+}