summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/stdio
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
commit8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch)
treedf55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-top-half/musl/src/stdio
parentInitial commit. (diff)
downloadwasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.tar.xz
wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.zip
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libc-top-half/musl/src/stdio')
-rw-r--r--libc-top-half/musl/src/stdio/__fclose_ca.c6
-rw-r--r--libc-top-half/musl/src/stdio/__fdopen.c85
-rw-r--r--libc-top-half/musl/src/stdio/__fmodeflags.c16
-rw-r--r--libc-top-half/musl/src/stdio/__fopen_rb_ca.c32
-rw-r--r--libc-top-half/musl/src/stdio/__lockfile.c23
-rw-r--r--libc-top-half/musl/src/stdio/__overflow.c10
-rw-r--r--libc-top-half/musl/src/stdio/__stdio_close.c26
-rw-r--r--libc-top-half/musl/src/stdio/__stdio_exit.c25
-rw-r--r--libc-top-half/musl/src/stdio/__stdio_read.c33
-rw-r--r--libc-top-half/musl/src/stdio/__stdio_seek.c11
-rw-r--r--libc-top-half/musl/src/stdio/__stdio_write.c38
-rw-r--r--libc-top-half/musl/src/stdio/__stdout_write.c21
-rw-r--r--libc-top-half/musl/src/stdio/__toread.c19
-rw-r--r--libc-top-half/musl/src/stdio/__towrite.c23
-rw-r--r--libc-top-half/musl/src/stdio/__uflow.c11
-rw-r--r--libc-top-half/musl/src/stdio/asprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/clearerr.c10
-rw-r--r--libc-top-half/musl/src/stdio/dprintf.c12
-rw-r--r--libc-top-half/musl/src/stdio/ext.c57
-rw-r--r--libc-top-half/musl/src/stdio/ext2.c24
-rw-r--r--libc-top-half/musl/src/stdio/fclose.c38
-rw-r--r--libc-top-half/musl/src/stdio/feof.c14
-rw-r--r--libc-top-half/musl/src/stdio/ferror.c14
-rw-r--r--libc-top-half/musl/src/stdio/fflush.c47
-rw-r--r--libc-top-half/musl/src/stdio/fgetc.c7
-rw-r--r--libc-top-half/musl/src/stdio/fgetln.c21
-rw-r--r--libc-top-half/musl/src/stdio/fgetpos.c11
-rw-r--r--libc-top-half/musl/src/stdio/fgets.c48
-rw-r--r--libc-top-half/musl/src/stdio/fgetwc.c68
-rw-r--r--libc-top-half/musl/src/stdio/fgetws.c28
-rw-r--r--libc-top-half/musl/src/stdio/fileno.c16
-rw-r--r--libc-top-half/musl/src/stdio/flockfile.c9
-rw-r--r--libc-top-half/musl/src/stdio/fmemopen.c137
-rw-r--r--libc-top-half/musl/src/stdio/fopen.c51
-rw-r--r--libc-top-half/musl/src/stdio/fopencookie.c135
-rw-r--r--libc-top-half/musl/src/stdio/fprintf.c12
-rw-r--r--libc-top-half/musl/src/stdio/fputc.c7
-rw-r--r--libc-top-half/musl/src/stdio/fputs.c10
-rw-r--r--libc-top-half/musl/src/stdio/fputwc.c40
-rw-r--r--libc-top-half/musl/src/stdio/fputws.c29
-rw-r--r--libc-top-half/musl/src/stdio/fread.c38
-rw-r--r--libc-top-half/musl/src/stdio/freopen.c80
-rw-r--r--libc-top-half/musl/src/stdio/fscanf.c14
-rw-r--r--libc-top-half/musl/src/stdio/fseek.c50
-rw-r--r--libc-top-half/musl/src/stdio/fsetpos.c8
-rw-r--r--libc-top-half/musl/src/stdio/ftell.c41
-rw-r--r--libc-top-half/musl/src/stdio/ftrylockfile.c46
-rw-r--r--libc-top-half/musl/src/stdio/funlockfile.c13
-rw-r--r--libc-top-half/musl/src/stdio/fwide.c16
-rw-r--r--libc-top-half/musl/src/stdio/fwprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/fwrite.c38
-rw-r--r--libc-top-half/musl/src/stdio/fwscanf.c15
-rw-r--r--libc-top-half/musl/src/stdio/getc.c9
-rw-r--r--libc-top-half/musl/src/stdio/getc.h29
-rw-r--r--libc-top-half/musl/src/stdio/getc_unlocked.c9
-rw-r--r--libc-top-half/musl/src/stdio/getchar.c7
-rw-r--r--libc-top-half/musl/src/stdio/getchar_unlocked.c6
-rw-r--r--libc-top-half/musl/src/stdio/getdelim.c83
-rw-r--r--libc-top-half/musl/src/stdio/getline.c6
-rw-r--r--libc-top-half/musl/src/stdio/gets.c15
-rw-r--r--libc-top-half/musl/src/stdio/getw.c8
-rw-r--r--libc-top-half/musl/src/stdio/getwc.c7
-rw-r--r--libc-top-half/musl/src/stdio/getwchar.c9
-rw-r--r--libc-top-half/musl/src/stdio/ofl.c20
-rw-r--r--libc-top-half/musl/src/stdio/ofl_add.c11
-rw-r--r--libc-top-half/musl/src/stdio/open_memstream.c109
-rw-r--r--libc-top-half/musl/src/stdio/open_wmemstream.c112
-rw-r--r--libc-top-half/musl/src/stdio/pclose.c13
-rw-r--r--libc-top-half/musl/src/stdio/perror.c30
-rw-r--r--libc-top-half/musl/src/stdio/popen.c61
-rw-r--r--libc-top-half/musl/src/stdio/printf.c17
-rw-r--r--libc-top-half/musl/src/stdio/putc.c9
-rw-r--r--libc-top-half/musl/src/stdio/putc.h29
-rw-r--r--libc-top-half/musl/src/stdio/putc_unlocked.c9
-rw-r--r--libc-top-half/musl/src/stdio/putchar.c7
-rw-r--r--libc-top-half/musl/src/stdio/putchar_unlocked.c6
-rw-r--r--libc-top-half/musl/src/stdio/puts.c10
-rw-r--r--libc-top-half/musl/src/stdio/putw.c7
-rw-r--r--libc-top-half/musl/src/stdio/putwc.c7
-rw-r--r--libc-top-half/musl/src/stdio/putwchar.c9
-rw-r--r--libc-top-half/musl/src/stdio/remove.c19
-rw-r--r--libc-top-half/musl/src/stdio/rename.c14
-rw-r--r--libc-top-half/musl/src/stdio/rewind.c9
-rw-r--r--libc-top-half/musl/src/stdio/scanf.c14
-rw-r--r--libc-top-half/musl/src/stdio/setbuf.c6
-rw-r--r--libc-top-half/musl/src/stdio/setbuffer.c7
-rw-r--r--libc-top-half/musl/src/stdio/setlinebuf.c7
-rw-r--r--libc-top-half/musl/src/stdio/setvbuf.c29
-rw-r--r--libc-top-half/musl/src/stdio/snprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/sprintf.c12
-rw-r--r--libc-top-half/musl/src/stdio/sscanf.c14
-rw-r--r--libc-top-half/musl/src/stdio/stderr.c20
-rw-r--r--libc-top-half/musl/src/stdio/stdin.c19
-rw-r--r--libc-top-half/musl/src/stdio/stdout.c20
-rw-r--r--libc-top-half/musl/src/stdio/swprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/swscanf.c14
-rw-r--r--libc-top-half/musl/src/stdio/tempnam.c49
-rw-r--r--libc-top-half/musl/src/stdio/tmpfile.c31
-rw-r--r--libc-top-half/musl/src/stdio/tmpnam.c29
-rw-r--r--libc-top-half/musl/src/stdio/ungetc.c20
-rw-r--r--libc-top-half/musl/src/stdio/ungetwc.c35
-rw-r--r--libc-top-half/musl/src/stdio/vasprintf.c15
-rw-r--r--libc-top-half/musl/src/stdio/vdprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/vfprintf.c737
-rw-r--r--libc-top-half/musl/src/stdio/vfscanf.c351
-rw-r--r--libc-top-half/musl/src/stdio/vfwprintf.c414
-rw-r--r--libc-top-half/musl/src/stdio/vfwscanf.c332
-rw-r--r--libc-top-half/musl/src/stdio/vprintf.c6
-rw-r--r--libc-top-half/musl/src/stdio/vscanf.c9
-rw-r--r--libc-top-half/musl/src/stdio/vsnprintf.c57
-rw-r--r--libc-top-half/musl/src/stdio/vsprintf.c7
-rw-r--r--libc-top-half/musl/src/stdio/vsscanf.c31
-rw-r--r--libc-top-half/musl/src/stdio/vswprintf.c62
-rw-r--r--libc-top-half/musl/src/stdio/vswscanf.c42
-rw-r--r--libc-top-half/musl/src/stdio/vwprintf.c7
-rw-r--r--libc-top-half/musl/src/stdio/vwscanf.c10
-rw-r--r--libc-top-half/musl/src/stdio/wprintf.c13
-rw-r--r--libc-top-half/musl/src/stdio/wscanf.c15
118 files changed, 4778 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/stdio/__fclose_ca.c b/libc-top-half/musl/src/stdio/__fclose_ca.c
new file mode 100644
index 0000000..e0b12a1
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__fclose_ca.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int __fclose_ca(FILE *f)
+{
+ return f->close(f);
+}
diff --git a/libc-top-half/musl/src/stdio/__fdopen.c b/libc-top-half/musl/src/stdio/__fdopen.c
new file mode 100644
index 0000000..5c8df49
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__fdopen.c
@@ -0,0 +1,85 @@
+#include "stdio_impl.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "libc.h"
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+#else
+#include <__function___isatty.h>
+#endif
+
+FILE *__fdopen(int fd, const char *mode)
+{
+ FILE *f;
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ struct winsize wsz;
+#endif
+
+ /* Check for valid initial mode character */
+ if (!strchr("rwa", *mode)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* Allocate FILE+buffer or fail */
+ if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return 0;
+
+ /* Zero-fill only the struct, not the buffer */
+ memset(f, 0, sizeof *f);
+
+ /* Impose mode restrictions */
+ if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+ /* Apply close-on-exec flag */
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ if (strchr(mode, 'e')) __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
+#else
+ if (strchr(mode, 'e')) fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ /* Set append mode on fd if opened for append */
+ if (*mode == 'a') {
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ int flags = __syscall(SYS_fcntl, fd, F_GETFL);
+#else
+ int flags = fcntl(fd, F_GETFL);
+#endif
+ if (!(flags & O_APPEND))
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ __syscall(SYS_fcntl, fd, F_SETFL, flags | O_APPEND);
+#else
+ fcntl(fd, F_SETFL, flags | O_APPEND);
+#endif
+ f->flags |= F_APP;
+ }
+
+ f->fd = fd;
+ f->buf = (unsigned char *)f + sizeof *f + UNGET;
+ f->buf_size = BUFSIZ;
+
+ /* Activate line buffered mode for terminals */
+ f->lbf = EOF;
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ if (!(f->flags & F_NOWR) && !__syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz))
+#else
+ if (!(f->flags & F_NOWR) && __isatty(fd))
+#endif
+ f->lbf = '\n';
+
+ /* Initialize op ptrs. No problem if some are unneeded. */
+ f->read = __stdio_read;
+ f->write = __stdio_write;
+ f->seek = __stdio_seek;
+ f->close = __stdio_close;
+
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ if (!libc.threaded) f->lock = -1;
+#endif
+
+ /* Add new FILE to open file list */
+ return __ofl_add(f);
+}
+
+weak_alias(__fdopen, fdopen);
diff --git a/libc-top-half/musl/src/stdio/__fmodeflags.c b/libc-top-half/musl/src/stdio/__fmodeflags.c
new file mode 100644
index 0000000..da9f23b
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__fmodeflags.c
@@ -0,0 +1,16 @@
+#include <fcntl.h>
+#include <string.h>
+
+int __fmodeflags(const char *mode)
+{
+ int flags;
+ if (strchr(mode, '+')) flags = O_RDWR;
+ else if (*mode == 'r') flags = O_RDONLY;
+ else flags = O_WRONLY;
+ if (strchr(mode, 'x')) flags |= O_EXCL;
+ if (strchr(mode, 'e')) flags |= O_CLOEXEC;
+ if (*mode != 'r') flags |= O_CREAT;
+ if (*mode == 'w') flags |= O_TRUNC;
+ if (*mode == 'a') flags |= O_APPEND;
+ return flags;
+}
diff --git a/libc-top-half/musl/src/stdio/__fopen_rb_ca.c b/libc-top-half/musl/src/stdio/__fopen_rb_ca.c
new file mode 100644
index 0000000..192050b
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__fopen_rb_ca.c
@@ -0,0 +1,32 @@
+#include "stdio_impl.h"
+#include <fcntl.h>
+#include <string.h>
+
+FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t len)
+{
+ memset(f, 0, sizeof *f);
+
+#ifdef __wasilibc_unmodified_upstream // WASI has no sys_open
+ f->fd = sys_open(filename, O_RDONLY|O_CLOEXEC);
+#else
+ f->fd = open(filename, O_RDONLY|O_CLOEXEC);
+#endif
+ if (f->fd < 0) return 0;
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ __syscall(SYS_fcntl, f->fd, F_SETFD, FD_CLOEXEC);
+#else
+ fcntl(f->fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ f->flags = F_NOWR | F_PERM;
+ f->buf = buf + UNGET;
+ f->buf_size = len - UNGET;
+ f->read = __stdio_read;
+ f->seek = __stdio_seek;
+ f->close = __stdio_close;
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ f->lock = -1;
+#endif
+
+ return f;
+}
diff --git a/libc-top-half/musl/src/stdio/__lockfile.c b/libc-top-half/musl/src/stdio/__lockfile.c
new file mode 100644
index 0000000..0f60a14
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__lockfile.c
@@ -0,0 +1,23 @@
+#include "stdio_impl.h"
+#include "pthread_impl.h"
+
+int __lockfile(FILE *f)
+{
+ int owner = f->lock, tid = __pthread_self()->tid;
+ if ((owner & ~MAYBE_WAITERS) == tid)
+ return 0;
+ owner = a_cas(&f->lock, 0, tid);
+ if (!owner) return 1;
+ while ((owner = a_cas(&f->lock, 0, tid|MAYBE_WAITERS))) {
+ if ((owner & MAYBE_WAITERS) ||
+ a_cas(&f->lock, owner, owner|MAYBE_WAITERS)==owner)
+ __futexwait(&f->lock, owner|MAYBE_WAITERS, 1);
+ }
+ return 1;
+}
+
+void __unlockfile(FILE *f)
+{
+ if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
+ __wake(&f->lock, 1, 1);
+}
diff --git a/libc-top-half/musl/src/stdio/__overflow.c b/libc-top-half/musl/src/stdio/__overflow.c
new file mode 100644
index 0000000..e65a594
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__overflow.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int __overflow(FILE *f, int _c)
+{
+ unsigned char c = _c;
+ if (!f->wend && __towrite(f)) return EOF;
+ if (f->wpos != f->wend && c != f->lbf) return *f->wpos++ = c;
+ if (f->write(f, &c, 1)!=1) return EOF;
+ return c;
+}
diff --git a/libc-top-half/musl/src/stdio/__stdio_close.c b/libc-top-half/musl/src/stdio/__stdio_close.c
new file mode 100644
index 0000000..0d7c91e
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdio_close.c
@@ -0,0 +1,26 @@
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+#else
+#include <unistd.h>
+#endif
+#include "stdio_impl.h"
+#include "aio_impl.h"
+
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+static int dummy(int fd)
+{
+ return fd;
+}
+
+weak_alias(dummy, __aio_close);
+#else
+#define __aio_close(fd) (fd)
+#endif
+
+int __stdio_close(FILE *f)
+{
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ return syscall(SYS_close, __aio_close(f->fd));
+#else
+ return close(__aio_close(f->fd));
+#endif
+}
diff --git a/libc-top-half/musl/src/stdio/__stdio_exit.c b/libc-top-half/musl/src/stdio/__stdio_exit.c
new file mode 100644
index 0000000..a5e42c6
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdio_exit.c
@@ -0,0 +1,25 @@
+#include "stdio_impl.h"
+
+static FILE *volatile dummy_file = 0;
+weak_alias(dummy_file, __stdin_used);
+weak_alias(dummy_file, __stdout_used);
+weak_alias(dummy_file, __stderr_used);
+
+static void close_file(FILE *f)
+{
+ if (!f) return;
+ FFINALLOCK(f);
+ if (f->wpos != f->wbase) f->write(f, 0, 0);
+ if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
+}
+
+void __stdio_exit(void)
+{
+ FILE *f;
+ for (f=*__ofl_lock(); f; f=f->next) close_file(f);
+ close_file(__stdin_used);
+ close_file(__stdout_used);
+ close_file(__stderr_used);
+}
+
+weak_alias(__stdio_exit, __stdio_exit_needed);
diff --git a/libc-top-half/musl/src/stdio/__stdio_read.c b/libc-top-half/musl/src/stdio/__stdio_read.c
new file mode 100644
index 0000000..d701188
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdio_read.c
@@ -0,0 +1,33 @@
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+#else
+#include <unistd.h>
+#endif
+#include "stdio_impl.h"
+#include <sys/uio.h>
+
+size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
+{
+ struct iovec iov[2] = {
+ { .iov_base = buf, .iov_len = len - !!f->buf_size },
+ { .iov_base = f->buf, .iov_len = f->buf_size }
+ };
+ ssize_t cnt;
+
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ cnt = iov[0].iov_len ? syscall(SYS_readv, f->fd, iov, 2)
+ : syscall(SYS_read, f->fd, iov[1].iov_base, iov[1].iov_len);
+#else
+ cnt = iov[0].iov_len ? readv(f->fd, iov, 2)
+ : read(f->fd, iov[1].iov_base, iov[1].iov_len);
+#endif
+ if (cnt <= 0) {
+ f->flags |= cnt ? F_ERR : F_EOF;
+ return 0;
+ }
+ if (cnt <= iov[0].iov_len) return cnt;
+ cnt -= iov[0].iov_len;
+ f->rpos = f->buf;
+ f->rend = f->buf + cnt;
+ if (f->buf_size) buf[len-1] = *f->rpos++;
+ return len;
+}
diff --git a/libc-top-half/musl/src/stdio/__stdio_seek.c b/libc-top-half/musl/src/stdio/__stdio_seek.c
new file mode 100644
index 0000000..782c678
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdio_seek.c
@@ -0,0 +1,11 @@
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+#else
+#include <unistd.h>
+#endif
+#include "stdio_impl.h"
+#include "stdio_impl.h"
+
+off_t __stdio_seek(FILE *f, off_t off, int whence)
+{
+ return __lseek(f->fd, off, whence);
+}
diff --git a/libc-top-half/musl/src/stdio/__stdio_write.c b/libc-top-half/musl/src/stdio/__stdio_write.c
new file mode 100644
index 0000000..7537304
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdio_write.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+#include <sys/uio.h>
+
+size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
+{
+ struct iovec iovs[2] = {
+ { .iov_base = f->wbase, .iov_len = f->wpos-f->wbase },
+ { .iov_base = (void *)buf, .iov_len = len }
+ };
+ struct iovec *iov = iovs;
+ size_t rem = iov[0].iov_len + iov[1].iov_len;
+ int iovcnt = 2;
+ ssize_t cnt;
+ for (;;) {
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ cnt = syscall(SYS_writev, f->fd, iov, iovcnt);
+#else
+ cnt = writev(f->fd, iov, iovcnt);
+#endif
+ if (cnt == rem) {
+ f->wend = f->buf + f->buf_size;
+ f->wpos = f->wbase = f->buf;
+ return len;
+ }
+ if (cnt < 0) {
+ f->wpos = f->wbase = f->wend = 0;
+ f->flags |= F_ERR;
+ return iovcnt == 2 ? 0 : len-iov[0].iov_len;
+ }
+ rem -= cnt;
+ if (cnt > iov[0].iov_len) {
+ cnt -= iov[0].iov_len;
+ iov++; iovcnt--;
+ }
+ iov[0].iov_base = (char *)iov[0].iov_base + cnt;
+ iov[0].iov_len -= cnt;
+ }
+}
diff --git a/libc-top-half/musl/src/stdio/__stdout_write.c b/libc-top-half/musl/src/stdio/__stdout_write.c
new file mode 100644
index 0000000..8190ec5
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__stdout_write.c
@@ -0,0 +1,21 @@
+#include "stdio_impl.h"
+#include <sys/ioctl.h>
+#ifdef __wasilibc_unmodified_upstream // use isatty rather than manual ioctl
+#else
+#include <__function___isatty.h>
+#endif
+
+size_t __stdout_write(FILE *f, const unsigned char *buf, size_t len)
+{
+#ifdef __wasilibc_unmodified_upstream // use isatty rather than manual ioctl
+ struct winsize wsz;
+#endif
+ f->write = __stdio_write;
+#ifdef __wasilibc_unmodified_upstream // use isatty rather than manual ioctl
+ if (!(f->flags & F_SVB) && __syscall(SYS_ioctl, f->fd, TIOCGWINSZ, &wsz))
+#else
+ if (!(f->flags & F_SVB) && !__isatty(f->fd))
+#endif
+ f->lbf = -1;
+ return __stdio_write(f, buf, len);
+}
diff --git a/libc-top-half/musl/src/stdio/__toread.c b/libc-top-half/musl/src/stdio/__toread.c
new file mode 100644
index 0000000..f142ff0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__toread.c
@@ -0,0 +1,19 @@
+#include <stdio_impl.h>
+
+int __toread(FILE *f)
+{
+ f->mode |= f->mode-1;
+ if (f->wpos != f->wbase) f->write(f, 0, 0);
+ f->wpos = f->wbase = f->wend = 0;
+ if (f->flags & F_NORD) {
+ f->flags |= F_ERR;
+ return EOF;
+ }
+ f->rpos = f->rend = f->buf + f->buf_size;
+ return (f->flags & F_EOF) ? EOF : 0;
+}
+
+hidden void __toread_needs_stdio_exit()
+{
+ __stdio_exit_needed();
+}
diff --git a/libc-top-half/musl/src/stdio/__towrite.c b/libc-top-half/musl/src/stdio/__towrite.c
new file mode 100644
index 0000000..4c9c66a
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__towrite.c
@@ -0,0 +1,23 @@
+#include "stdio_impl.h"
+
+int __towrite(FILE *f)
+{
+ f->mode |= f->mode-1;
+ if (f->flags & F_NOWR) {
+ f->flags |= F_ERR;
+ return EOF;
+ }
+ /* Clear read buffer (easier than summoning nasal demons) */
+ f->rpos = f->rend = 0;
+
+ /* Activate write through the buffer. */
+ f->wpos = f->wbase = f->buf;
+ f->wend = f->buf + f->buf_size;
+
+ return 0;
+}
+
+hidden void __towrite_needs_stdio_exit()
+{
+ __stdio_exit_needed();
+}
diff --git a/libc-top-half/musl/src/stdio/__uflow.c b/libc-top-half/musl/src/stdio/__uflow.c
new file mode 100644
index 0000000..2a88bca
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/__uflow.c
@@ -0,0 +1,11 @@
+#include "stdio_impl.h"
+
+/* This function assumes it will never be called if there is already
+ * data buffered for reading. */
+
+int __uflow(FILE *f)
+{
+ unsigned char c;
+ if (!__toread(f) && f->read(f, &c, 1)==1) return c;
+ return EOF;
+}
diff --git a/libc-top-half/musl/src/stdio/asprintf.c b/libc-top-half/musl/src/stdio/asprintf.c
new file mode 100644
index 0000000..4ec8353
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/asprintf.c
@@ -0,0 +1,13 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+
+int asprintf(char **s, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vasprintf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/clearerr.c b/libc-top-half/musl/src/stdio/clearerr.c
new file mode 100644
index 0000000..3bf94d3
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/clearerr.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+void clearerr(FILE *f)
+{
+ FLOCK(f);
+ f->flags &= ~(F_EOF|F_ERR);
+ FUNLOCK(f);
+}
+
+weak_alias(clearerr, clearerr_unlocked);
diff --git a/libc-top-half/musl/src/stdio/dprintf.c b/libc-top-half/musl/src/stdio/dprintf.c
new file mode 100644
index 0000000..93082ee
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/dprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int dprintf(int fd, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vdprintf(fd, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/ext.c b/libc-top-half/musl/src/stdio/ext.c
new file mode 100644
index 0000000..1fd9549
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ext.c
@@ -0,0 +1,57 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <stdio_ext.h>
+
+void _flushlbf(void)
+{
+ fflush(0);
+}
+
+int __fsetlocking(FILE *f, int type)
+{
+ return 0;
+}
+
+int __fwriting(FILE *f)
+{
+ return (f->flags & F_NORD) || f->wend;
+}
+
+int __freading(FILE *f)
+{
+ return (f->flags & F_NOWR) || f->rend;
+}
+
+int __freadable(FILE *f)
+{
+ return !(f->flags & F_NORD);
+}
+
+int __fwritable(FILE *f)
+{
+ return !(f->flags & F_NOWR);
+}
+
+int __flbf(FILE *f)
+{
+ return f->lbf >= 0;
+}
+
+size_t __fbufsize(FILE *f)
+{
+ return f->buf_size;
+}
+
+size_t __fpending(FILE *f)
+{
+ return f->wend ? f->wpos - f->wbase : 0;
+}
+
+int __fpurge(FILE *f)
+{
+ f->wpos = f->wbase = f->wend = 0;
+ f->rpos = f->rend = 0;
+ return 0;
+}
+
+weak_alias(__fpurge, fpurge);
diff --git a/libc-top-half/musl/src/stdio/ext2.c b/libc-top-half/musl/src/stdio/ext2.c
new file mode 100644
index 0000000..3416278
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ext2.c
@@ -0,0 +1,24 @@
+#include "stdio_impl.h"
+#include <stdio_ext.h>
+
+size_t __freadahead(FILE *f)
+{
+ return f->rend ? f->rend - f->rpos : 0;
+}
+
+const char *__freadptr(FILE *f, size_t *sizep)
+{
+ if (f->rpos == f->rend) return 0;
+ *sizep = f->rend - f->rpos;
+ return (const char *)f->rpos;
+}
+
+void __freadptrinc(FILE *f, size_t inc)
+{
+ f->rpos += inc;
+}
+
+void __fseterr(FILE *f)
+{
+ f->flags |= F_ERR;
+}
diff --git a/libc-top-half/musl/src/stdio/fclose.c b/libc-top-half/musl/src/stdio/fclose.c
new file mode 100644
index 0000000..d594532
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fclose.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+#include <stdlib.h>
+
+static void dummy(FILE *f) { }
+weak_alias(dummy, __unlist_locked_file);
+
+int fclose(FILE *f)
+{
+ int r;
+
+ FLOCK(f);
+ r = fflush(f);
+ r |= f->close(f);
+ FUNLOCK(f);
+
+ /* Past this point, f is closed and any further explict access
+ * to it is undefined. However, it still exists as an entry in
+ * the open file list and possibly in the thread's locked files
+ * list, if it was closed while explicitly locked. Functions
+ * which process these lists must tolerate dead FILE objects
+ * (which necessarily have inactive buffer pointers) without
+ * producing any side effects. */
+
+ if (f->flags & F_PERM) return r;
+
+ __unlist_locked_file(f);
+
+ FILE **head = __ofl_lock();
+ if (f->prev) f->prev->next = f->next;
+ if (f->next) f->next->prev = f->prev;
+ if (*head == f) *head = f->next;
+ __ofl_unlock();
+
+ free(f->getln_buf);
+ free(f);
+
+ return r;
+}
diff --git a/libc-top-half/musl/src/stdio/feof.c b/libc-top-half/musl/src/stdio/feof.c
new file mode 100644
index 0000000..56da6b9
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/feof.c
@@ -0,0 +1,14 @@
+#include "stdio_impl.h"
+
+#undef feof
+
+int feof(FILE *f)
+{
+ FLOCK(f);
+ int ret = !!(f->flags & F_EOF);
+ FUNLOCK(f);
+ return ret;
+}
+
+weak_alias(feof, feof_unlocked);
+weak_alias(feof, _IO_feof_unlocked);
diff --git a/libc-top-half/musl/src/stdio/ferror.c b/libc-top-half/musl/src/stdio/ferror.c
new file mode 100644
index 0000000..d692eed
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ferror.c
@@ -0,0 +1,14 @@
+#include "stdio_impl.h"
+
+#undef ferror
+
+int ferror(FILE *f)
+{
+ FLOCK(f);
+ int ret = !!(f->flags & F_ERR);
+ FUNLOCK(f);
+ return ret;
+}
+
+weak_alias(ferror, ferror_unlocked);
+weak_alias(ferror, _IO_ferror_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fflush.c b/libc-top-half/musl/src/stdio/fflush.c
new file mode 100644
index 0000000..b009437
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fflush.c
@@ -0,0 +1,47 @@
+#include "stdio_impl.h"
+
+/* stdout.c will override this if linked */
+static FILE *volatile dummy = 0;
+weak_alias(dummy, __stdout_used);
+weak_alias(dummy, __stderr_used);
+
+int fflush(FILE *f)
+{
+ if (!f) {
+ int r = 0;
+ if (__stdout_used) r |= fflush(__stdout_used);
+ if (__stderr_used) r |= fflush(__stderr_used);
+
+ for (f=*__ofl_lock(); f; f=f->next) {
+ FLOCK(f);
+ if (f->wpos != f->wbase) r |= fflush(f);
+ FUNLOCK(f);
+ }
+ __ofl_unlock();
+
+ return r;
+ }
+
+ FLOCK(f);
+
+ /* If writing, flush output */
+ if (f->wpos != f->wbase) {
+ f->write(f, 0, 0);
+ if (!f->wpos) {
+ FUNLOCK(f);
+ return EOF;
+ }
+ }
+
+ /* If reading, sync position, per POSIX */
+ if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
+
+ /* Clear read and write modes */
+ f->wpos = f->wbase = f->wend = 0;
+ f->rpos = f->rend = 0;
+
+ FUNLOCK(f);
+ return 0;
+}
+
+weak_alias(fflush, fflush_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fgetc.c b/libc-top-half/musl/src/stdio/fgetc.c
new file mode 100644
index 0000000..2578afc
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgetc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "getc.h"
+
+int fgetc(FILE *f)
+{
+ return do_getc(f);
+}
diff --git a/libc-top-half/musl/src/stdio/fgetln.c b/libc-top-half/musl/src/stdio/fgetln.c
new file mode 100644
index 0000000..5748435
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgetln.c
@@ -0,0 +1,21 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <string.h>
+
+char *fgetln(FILE *f, size_t *plen)
+{
+ char *ret = 0, *z;
+ ssize_t l;
+ FLOCK(f);
+ ungetc(getc_unlocked(f), f);
+ if (f->rend && (z=memchr(f->rpos, '\n', f->rend - f->rpos))) {
+ ret = (char *)f->rpos;
+ *plen = ++z - ret;
+ f->rpos = (void *)z;
+ } else if ((l = getline(&f->getln_buf, (size_t[]){0}, f)) > 0) {
+ *plen = l;
+ ret = f->getln_buf;
+ }
+ FUNLOCK(f);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/fgetpos.c b/libc-top-half/musl/src/stdio/fgetpos.c
new file mode 100644
index 0000000..50813d2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgetpos.c
@@ -0,0 +1,11 @@
+#include "stdio_impl.h"
+
+int fgetpos(FILE *restrict f, fpos_t *restrict pos)
+{
+ off_t off = __ftello(f);
+ if (off < 0) return -1;
+ *(long long *)pos = off;
+ return 0;
+}
+
+weak_alias(fgetpos, fgetpos64);
diff --git a/libc-top-half/musl/src/stdio/fgets.c b/libc-top-half/musl/src/stdio/fgets.c
new file mode 100644
index 0000000..6171f39
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgets.c
@@ -0,0 +1,48 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+char *fgets(char *restrict s, int n, FILE *restrict f)
+{
+ char *p = s;
+ unsigned char *z;
+ size_t k;
+ int c;
+
+ FLOCK(f);
+
+ if (n--<=1) {
+ f->mode |= f->mode-1;
+ FUNLOCK(f);
+ if (n) return 0;
+ *s = 0;
+ return s;
+ }
+
+ while (n) {
+ if (f->rpos != f->rend) {
+ z = memchr(f->rpos, '\n', f->rend - f->rpos);
+ k = z ? z - f->rpos + 1 : f->rend - f->rpos;
+ k = MIN(k, n);
+ memcpy(p, f->rpos, k);
+ f->rpos += k;
+ p += k;
+ n -= k;
+ if (z || !n) break;
+ }
+ if ((c = getc_unlocked(f)) < 0) {
+ if (p==s || !feof(f)) s = 0;
+ break;
+ }
+ n--;
+ if ((*p++ = c) == '\n') break;
+ }
+ if (s) *p = 0;
+
+ FUNLOCK(f);
+
+ return s;
+}
+
+weak_alias(fgets, fgets_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fgetwc.c b/libc-top-half/musl/src/stdio/fgetwc.c
new file mode 100644
index 0000000..aa10b81
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgetwc.c
@@ -0,0 +1,68 @@
+#include "stdio_impl.h"
+#include "locale_impl.h"
+#include <wchar.h>
+#include <errno.h>
+
+static wint_t __fgetwc_unlocked_internal(FILE *f)
+{
+ wchar_t wc;
+ int c;
+ size_t l;
+
+ /* Convert character from buffer if possible */
+ if (f->rpos != f->rend) {
+ l = mbtowc(&wc, (void *)f->rpos, f->rend - f->rpos);
+ if (l+1 >= 1) {
+ f->rpos += l + !l; /* l==0 means 1 byte, null */
+ return wc;
+ }
+ }
+
+ /* Convert character byte-by-byte */
+ mbstate_t st = { 0 };
+ unsigned char b;
+ int first = 1;
+ do {
+ b = c = getc_unlocked(f);
+ if (c < 0) {
+ if (!first) {
+ f->flags |= F_ERR;
+ errno = EILSEQ;
+ }
+ return WEOF;
+ }
+ l = mbrtowc(&wc, (void *)&b, 1, &st);
+ if (l == -1) {
+ if (!first) {
+ f->flags |= F_ERR;
+ ungetc(b, f);
+ }
+ return WEOF;
+ }
+ first = 0;
+ } while (l == -2);
+
+ return wc;
+}
+
+wint_t __fgetwc_unlocked(FILE *f)
+{
+ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
+ if (f->mode <= 0) fwide(f, 1);
+ *ploc = f->locale;
+ wchar_t wc = __fgetwc_unlocked_internal(f);
+ *ploc = loc;
+ return wc;
+}
+
+wint_t fgetwc(FILE *f)
+{
+ wint_t c;
+ FLOCK(f);
+ c = __fgetwc_unlocked(f);
+ FUNLOCK(f);
+ return c;
+}
+
+weak_alias(__fgetwc_unlocked, fgetwc_unlocked);
+weak_alias(__fgetwc_unlocked, getwc_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fgetws.c b/libc-top-half/musl/src/stdio/fgetws.c
new file mode 100644
index 0000000..195cb43
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fgetws.c
@@ -0,0 +1,28 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+wint_t __fgetwc_unlocked(FILE *);
+
+wchar_t *fgetws(wchar_t *restrict s, int n, FILE *restrict f)
+{
+ wchar_t *p = s;
+
+ if (!n--) return s;
+
+ FLOCK(f);
+
+ for (; n; n--) {
+ wint_t c = __fgetwc_unlocked(f);
+ if (c == WEOF) break;
+ *p++ = c;
+ if (c == '\n') break;
+ }
+ *p = 0;
+ if (ferror(f)) p = s;
+
+ FUNLOCK(f);
+
+ return (p == s) ? NULL : s;
+}
+
+weak_alias(fgetws, fgetws_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fileno.c b/libc-top-half/musl/src/stdio/fileno.c
new file mode 100644
index 0000000..0bd0e98
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fileno.c
@@ -0,0 +1,16 @@
+#include "stdio_impl.h"
+#include <errno.h>
+
+int fileno(FILE *f)
+{
+ FLOCK(f);
+ int fd = f->fd;
+ FUNLOCK(f);
+ if (fd < 0) {
+ errno = EBADF;
+ return -1;
+ }
+ return fd;
+}
+
+weak_alias(fileno, fileno_unlocked);
diff --git a/libc-top-half/musl/src/stdio/flockfile.c b/libc-top-half/musl/src/stdio/flockfile.c
new file mode 100644
index 0000000..8e22065
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/flockfile.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+#include "pthread_impl.h"
+
+void flockfile(FILE *f)
+{
+ if (!ftrylockfile(f)) return;
+ __lockfile(f);
+ __register_locked_file(f, __pthread_self());
+}
diff --git a/libc-top-half/musl/src/stdio/fmemopen.c b/libc-top-half/musl/src/stdio/fmemopen.c
new file mode 100644
index 0000000..3ee57b9
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fmemopen.c
@@ -0,0 +1,137 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include "libc.h"
+
+struct cookie {
+ size_t pos, len, size;
+ unsigned char *buf;
+ int mode;
+};
+
+struct mem_FILE {
+ FILE f;
+ struct cookie c;
+ unsigned char buf[UNGET+BUFSIZ], buf2[];
+};
+
+static off_t mseek(FILE *f, off_t off, int whence)
+{
+ ssize_t base;
+ struct cookie *c = f->cookie;
+ if (whence>2U) {
+fail:
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef __wasilibc_unmodified_upstream // WASI's SEEK_* constants have different values.
+ base = (size_t [3]){0, c->pos, c->len}[whence];
+#else
+ base = (size_t [3]) {
+ [SEEK_SET] = 0,
+ [SEEK_CUR] = c->pos,
+ [SEEK_END] = c->len
+ }[whence];
+#endif
+ if (off < -base || off > (ssize_t)c->size-base) goto fail;
+ return c->pos = base+off;
+}
+
+static size_t mread(FILE *f, unsigned char *buf, size_t len)
+{
+ struct cookie *c = f->cookie;
+ size_t rem = c->len - c->pos;
+ if (c->pos > c->len) rem = 0;
+ if (len > rem) {
+ len = rem;
+ f->flags |= F_EOF;
+ }
+ memcpy(buf, c->buf+c->pos, len);
+ c->pos += len;
+ rem -= len;
+ if (rem > f->buf_size) rem = f->buf_size;
+ f->rpos = f->buf;
+ f->rend = f->buf + rem;
+ memcpy(f->rpos, c->buf+c->pos, rem);
+ c->pos += rem;
+ return len;
+}
+
+static size_t mwrite(FILE *f, const unsigned char *buf, size_t len)
+{
+ struct cookie *c = f->cookie;
+ size_t rem;
+ size_t len2 = f->wpos - f->wbase;
+ if (len2) {
+ f->wpos = f->wbase;
+ if (mwrite(f, f->wpos, len2) < len2) return 0;
+ }
+ if (c->mode == 'a') c->pos = c->len;
+ rem = c->size - c->pos;
+ if (len > rem) len = rem;
+ memcpy(c->buf+c->pos, buf, len);
+ c->pos += len;
+ if (c->pos > c->len) {
+ c->len = c->pos;
+ if (c->len < c->size) c->buf[c->len] = 0;
+ else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0;
+ }
+ return len;
+}
+
+static int mclose(FILE *m)
+{
+ return 0;
+}
+
+FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode)
+{
+ struct mem_FILE *f;
+ int plus = !!strchr(mode, '+');
+
+ if (!strchr("rwa", *mode)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (!buf && size > PTRDIFF_MAX) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ f = malloc(sizeof *f + (buf?0:size));
+ if (!f) return 0;
+ memset(f, 0, offsetof(struct mem_FILE, buf));
+ f->f.cookie = &f->c;
+ f->f.fd = -1;
+ f->f.lbf = EOF;
+ f->f.buf = f->buf + UNGET;
+ f->f.buf_size = sizeof f->buf - UNGET;
+ if (!buf) {
+ buf = f->buf2;
+ memset(buf, 0, size);
+ }
+
+ f->c.buf = buf;
+ f->c.size = size;
+ f->c.mode = *mode;
+
+ if (!plus) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
+ if (*mode == 'r') f->c.len = size;
+ else if (*mode == 'a') f->c.len = f->c.pos = strnlen(buf, size);
+ else if (plus) *f->c.buf = 0;
+
+ f->f.read = mread;
+ f->f.write = mwrite;
+ f->f.seek = mseek;
+ f->f.close = mclose;
+
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ if (!libc.threaded) f->f.lock = -1;
+#endif
+
+ return __ofl_add(&f->f);
+}
diff --git a/libc-top-half/musl/src/stdio/fopen.c b/libc-top-half/musl/src/stdio/fopen.c
new file mode 100644
index 0000000..670f438
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fopen.c
@@ -0,0 +1,51 @@
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+#else
+#include <unistd.h>
+#include <wasi/libc.h>
+#endif
+#include "stdio_impl.h"
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+FILE *fopen(const char *restrict filename, const char *restrict mode)
+{
+ FILE *f;
+ int fd;
+ int flags;
+
+ /* Check for valid initial mode character */
+ if (!strchr("rwa", *mode)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* Compute the flags to pass to open() */
+ flags = __fmodeflags(mode);
+
+#ifdef __wasilibc_unmodified_upstream // WASI has no sys_open
+ fd = sys_open(filename, flags, 0666);
+#else
+ // WASI libc ignores the mode parameter anyway, so skip the varargs.
+ fd = __wasilibc_open_nomode(filename, flags);
+#endif
+ if (fd < 0) return 0;
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ if (flags & O_CLOEXEC)
+ __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
+#else
+ /* Avoid __syscall, but also, FD_CLOEXEC is not supported in WASI. */
+#endif
+
+ f = __fdopen(fd, mode);
+ if (f) return f;
+
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ __syscall(SYS_close, fd);
+#else
+ close(fd);
+#endif
+ return 0;
+}
+
+weak_alias(fopen, fopen64);
diff --git a/libc-top-half/musl/src/stdio/fopencookie.c b/libc-top-half/musl/src/stdio/fopencookie.c
new file mode 100644
index 0000000..da042fe
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fopencookie.c
@@ -0,0 +1,135 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+struct fcookie {
+ void *cookie;
+ cookie_io_functions_t iofuncs;
+};
+
+struct cookie_FILE {
+ FILE f;
+ struct fcookie fc;
+ unsigned char buf[UNGET+BUFSIZ];
+};
+
+static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
+{
+ struct fcookie *fc = f->cookie;
+ ssize_t ret = -1;
+ size_t remain = len, readlen = 0;
+ size_t len2 = len - !!f->buf_size;
+
+ if (!fc->iofuncs.read) goto bail;
+
+ if (len2) {
+ ret = fc->iofuncs.read(fc->cookie, (char *) buf, len2);
+ if (ret <= 0) goto bail;
+
+ readlen += ret;
+ remain -= ret;
+ }
+
+ if (!f->buf_size || remain > !!f->buf_size) return readlen;
+
+ f->rpos = f->buf;
+ ret = fc->iofuncs.read(fc->cookie, (char *) f->rpos, f->buf_size);
+ if (ret <= 0) goto bail;
+ f->rend = f->rpos + ret;
+
+ buf[readlen++] = *f->rpos++;
+
+ return readlen;
+
+bail:
+ f->flags |= ret == 0 ? F_EOF : F_ERR;
+ f->rpos = f->rend = f->buf;
+ return readlen;
+}
+
+static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
+{
+ struct fcookie *fc = f->cookie;
+ ssize_t ret;
+ size_t len2 = f->wpos - f->wbase;
+ if (!fc->iofuncs.write) return len;
+ if (len2) {
+ f->wpos = f->wbase;
+ if (cookiewrite(f, f->wpos, len2) < len2) return 0;
+ }
+ ret = fc->iofuncs.write(fc->cookie, (const char *) buf, len);
+ if (ret < 0) {
+ f->wpos = f->wbase = f->wend = 0;
+ f->flags |= F_ERR;
+ return 0;
+ }
+ return ret;
+}
+
+static off_t cookieseek(FILE *f, off_t off, int whence)
+{
+ struct fcookie *fc = f->cookie;
+ int res;
+ if (whence > 2U) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!fc->iofuncs.seek) {
+ errno = ENOTSUP;
+ return -1;
+ }
+ res = fc->iofuncs.seek(fc->cookie, &off, whence);
+ if (res < 0)
+ return res;
+ return off;
+}
+
+static int cookieclose(FILE *f)
+{
+ struct fcookie *fc = f->cookie;
+ if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
+ return 0;
+}
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
+{
+ struct cookie_FILE *f;
+
+ /* Check for valid initial mode character */
+ if (!strchr("rwa", *mode)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* Allocate FILE+fcookie+buffer or fail */
+ if (!(f=malloc(sizeof *f))) return 0;
+
+ /* Zero-fill only the struct, not the buffer */
+ memset(&f->f, 0, sizeof f->f);
+
+ /* Impose mode restrictions */
+ if (!strchr(mode, '+')) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+ /* Set up our fcookie */
+ f->fc.cookie = cookie;
+ f->fc.iofuncs = iofuncs;
+
+ f->f.fd = -1;
+ f->f.cookie = &f->fc;
+ f->f.buf = f->buf + UNGET;
+ f->f.buf_size = sizeof f->buf - UNGET;
+ f->f.lbf = EOF;
+
+ /* Initialize op ptrs. No problem if some are unneeded. */
+ f->f.read = cookieread;
+ f->f.write = cookiewrite;
+ f->f.seek = cookieseek;
+ f->f.close = cookieclose;
+
+ /* Add new FILE to open file list */
+ return __ofl_add(&f->f);
+}
diff --git a/libc-top-half/musl/src/stdio/fprintf.c b/libc-top-half/musl/src/stdio/fprintf.c
new file mode 100644
index 0000000..948743f
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int fprintf(FILE *restrict f, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vfprintf(f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/fputc.c b/libc-top-half/musl/src/stdio/fputc.c
new file mode 100644
index 0000000..f364ed3
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fputc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "putc.h"
+
+int fputc(int c, FILE *f)
+{
+ return do_putc(c, f);
+}
diff --git a/libc-top-half/musl/src/stdio/fputs.c b/libc-top-half/musl/src/stdio/fputs.c
new file mode 100644
index 0000000..1cf344f
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fputs.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+int fputs(const char *restrict s, FILE *restrict f)
+{
+ size_t l = strlen(s);
+ return (fwrite(s, 1, l, f)==l) - 1;
+}
+
+weak_alias(fputs, fputs_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fputwc.c b/libc-top-half/musl/src/stdio/fputwc.c
new file mode 100644
index 0000000..789fe9c
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fputwc.c
@@ -0,0 +1,40 @@
+#include "stdio_impl.h"
+#include "locale_impl.h"
+#include <wchar.h>
+#include <limits.h>
+#include <ctype.h>
+
+wint_t __fputwc_unlocked(wchar_t c, FILE *f)
+{
+ char mbc[MB_LEN_MAX];
+ int l;
+ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
+
+ if (f->mode <= 0) fwide(f, 1);
+ *ploc = f->locale;
+
+ if (isascii(c)) {
+ c = putc_unlocked(c, f);
+ } else if (f->wpos + MB_LEN_MAX < f->wend) {
+ l = wctomb((void *)f->wpos, c);
+ if (l < 0) c = WEOF;
+ else f->wpos += l;
+ } else {
+ l = wctomb(mbc, c);
+ if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF;
+ }
+ if (c==WEOF) f->flags |= F_ERR;
+ *ploc = loc;
+ return c;
+}
+
+wint_t fputwc(wchar_t c, FILE *f)
+{
+ FLOCK(f);
+ c = __fputwc_unlocked(c, f);
+ FUNLOCK(f);
+ return c;
+}
+
+weak_alias(__fputwc_unlocked, fputwc_unlocked);
+weak_alias(__fputwc_unlocked, putwc_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fputws.c b/libc-top-half/musl/src/stdio/fputws.c
new file mode 100644
index 0000000..0ed02f1
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fputws.c
@@ -0,0 +1,29 @@
+#include "stdio_impl.h"
+#include "locale_impl.h"
+#include <wchar.h>
+
+int fputws(const wchar_t *restrict ws, FILE *restrict f)
+{
+ unsigned char buf[BUFSIZ];
+ size_t l=0;
+ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
+
+ FLOCK(f);
+
+ fwide(f, 1);
+ *ploc = f->locale;
+
+ while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
+ if (__fwritex(buf, l, f) < l) {
+ FUNLOCK(f);
+ *ploc = loc;
+ return -1;
+ }
+
+ FUNLOCK(f);
+
+ *ploc = loc;
+ return l; /* 0 or -1 */
+}
+
+weak_alias(fputws, fputws_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fread.c b/libc-top-half/musl/src/stdio/fread.c
new file mode 100644
index 0000000..a2116da
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fread.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
+{
+ unsigned char *dest = destv;
+ size_t len = size*nmemb, l = len, k;
+ if (!size) nmemb = 0;
+
+ FLOCK(f);
+
+ f->mode |= f->mode-1;
+
+ if (f->rpos != f->rend) {
+ /* First exhaust the buffer. */
+ k = MIN(f->rend - f->rpos, l);
+ memcpy(dest, f->rpos, k);
+ f->rpos += k;
+ dest += k;
+ l -= k;
+ }
+
+ /* Read the remainder directly */
+ for (; l; l-=k, dest+=k) {
+ k = __toread(f) ? 0 : f->read(f, dest, l);
+ if (!k) {
+ FUNLOCK(f);
+ return (len-l)/size;
+ }
+ }
+
+ FUNLOCK(f);
+ return nmemb;
+}
+
+weak_alias(fread, fread_unlocked);
diff --git a/libc-top-half/musl/src/stdio/freopen.c b/libc-top-half/musl/src/stdio/freopen.c
new file mode 100644
index 0000000..5331db0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/freopen.c
@@ -0,0 +1,80 @@
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall, dup
+#include "stdio_impl.h"
+#else
+#include <wasi/libc.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall, dup
+#else
+// Move this below fcntl.h and unistd.h so that the __syscall macro doesn't
+// cause trouble.
+#include "stdio_impl.h"
+#endif
+
+/* The basic idea of this implementation is to open a new FILE,
+ * hack the necessary parts of the new FILE into the old one, then
+ * close the new FILE. */
+
+/* Locking IS necessary because another thread may provably hold the
+ * lock, via flockfile or otherwise, when freopen is called, and in that
+ * case, freopen cannot act until the lock is released. */
+
+FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict f)
+{
+ int fl = __fmodeflags(mode);
+ FILE *f2;
+
+ FLOCK(f);
+
+ fflush(f);
+
+ if (!filename) {
+ if (fl&O_CLOEXEC)
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ __syscall(SYS_fcntl, f->fd, F_SETFD, FD_CLOEXEC);
+#else
+ fcntl(f->fd, F_SETFD, FD_CLOEXEC);
+#endif
+ fl &= ~(O_CREAT|O_EXCL|O_CLOEXEC);
+#ifdef __wasilibc_unmodified_upstream // WASI has no syscall
+ if (syscall(SYS_fcntl, f->fd, F_SETFL, fl) < 0)
+#else
+ if (fcntl(f->fd, F_SETFL, fl) < 0)
+#endif
+ goto fail;
+ } else {
+ f2 = fopen(filename, mode);
+ if (!f2) goto fail;
+ if (f2->fd == f->fd) f2->fd = -1; /* avoid closing in fclose */
+#ifdef __wasilibc_unmodified_upstream // WASI has no dup
+ else if (__dup3(f2->fd, f->fd, fl&O_CLOEXEC)<0) goto fail2;
+#else
+ // WASI doesn't have dup3, but does have a way to renumber
+ // an existing file descriptor.
+ else {
+ if (__wasilibc_fd_renumber(f2->fd, f->fd)<0) goto fail2;
+ f2->fd = -1; /* avoid closing in fclose */
+ }
+#endif
+
+ f->flags = (f->flags & F_PERM) | f2->flags;
+ f->read = f2->read;
+ f->write = f2->write;
+ f->seek = f2->seek;
+ f->close = f2->close;
+
+ fclose(f2);
+ }
+
+ FUNLOCK(f);
+ return f;
+
+fail2:
+ fclose(f2);
+fail:
+ fclose(f);
+ return NULL;
+}
+
+weak_alias(freopen, freopen64);
diff --git a/libc-top-half/musl/src/stdio/fscanf.c b/libc-top-half/musl/src/stdio/fscanf.c
new file mode 100644
index 0000000..f639e11
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fscanf.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int fscanf(FILE *restrict f, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vfscanf(f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(fscanf, __isoc99_fscanf);
diff --git a/libc-top-half/musl/src/stdio/fseek.c b/libc-top-half/musl/src/stdio/fseek.c
new file mode 100644
index 0000000..c07f7e9
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fseek.c
@@ -0,0 +1,50 @@
+#include "stdio_impl.h"
+#include <errno.h>
+
+int __fseeko_unlocked(FILE *f, off_t off, int whence)
+{
+ /* Fail immediately for invalid whence argument. */
+ if (whence != SEEK_CUR && whence != SEEK_SET && whence != SEEK_END) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Adjust relative offset for unread data in buffer, if any. */
+ if (whence == SEEK_CUR && f->rend) off -= f->rend - f->rpos;
+
+ /* Flush write buffer, and report error on failure. */
+ if (f->wpos != f->wbase) {
+ f->write(f, 0, 0);
+ if (!f->wpos) return -1;
+ }
+
+ /* Leave writing mode */
+ f->wpos = f->wbase = f->wend = 0;
+
+ /* Perform the underlying seek. */
+ if (f->seek(f, off, whence) < 0) return -1;
+
+ /* If seek succeeded, file is seekable and we discard read buffer. */
+ f->rpos = f->rend = 0;
+ f->flags &= ~F_EOF;
+
+ return 0;
+}
+
+int __fseeko(FILE *f, off_t off, int whence)
+{
+ int result;
+ FLOCK(f);
+ result = __fseeko_unlocked(f, off, whence);
+ FUNLOCK(f);
+ return result;
+}
+
+int fseek(FILE *f, long off, int whence)
+{
+ return __fseeko(f, off, whence);
+}
+
+weak_alias(__fseeko, fseeko);
+
+weak_alias(fseeko, fseeko64);
diff --git a/libc-top-half/musl/src/stdio/fsetpos.c b/libc-top-half/musl/src/stdio/fsetpos.c
new file mode 100644
index 0000000..77ab8d8
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fsetpos.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int fsetpos(FILE *f, const fpos_t *pos)
+{
+ return __fseeko(f, *(const long long *)pos, SEEK_SET);
+}
+
+weak_alias(fsetpos, fsetpos64);
diff --git a/libc-top-half/musl/src/stdio/ftell.c b/libc-top-half/musl/src/stdio/ftell.c
new file mode 100644
index 0000000..1a2afbb
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ftell.c
@@ -0,0 +1,41 @@
+#include "stdio_impl.h"
+#include <limits.h>
+#include <errno.h>
+
+off_t __ftello_unlocked(FILE *f)
+{
+ off_t pos = f->seek(f, 0,
+ (f->flags & F_APP) && f->wpos != f->wbase
+ ? SEEK_END : SEEK_CUR);
+ if (pos < 0) return pos;
+
+ /* Adjust for data in buffer. */
+ if (f->rend)
+ pos += f->rpos - f->rend;
+ else if (f->wbase)
+ pos += f->wpos - f->wbase;
+ return pos;
+}
+
+off_t __ftello(FILE *f)
+{
+ off_t pos;
+ FLOCK(f);
+ pos = __ftello_unlocked(f);
+ FUNLOCK(f);
+ return pos;
+}
+
+long ftell(FILE *f)
+{
+ off_t pos = __ftello(f);
+ if (pos > LONG_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return pos;
+}
+
+weak_alias(__ftello, ftello);
+
+weak_alias(ftello, ftello64);
diff --git a/libc-top-half/musl/src/stdio/ftrylockfile.c b/libc-top-half/musl/src/stdio/ftrylockfile.c
new file mode 100644
index 0000000..5065058
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ftrylockfile.c
@@ -0,0 +1,46 @@
+#include "stdio_impl.h"
+#include "pthread_impl.h"
+#include <limits.h>
+
+void __do_orphaned_stdio_locks()
+{
+ FILE *f;
+ for (f=__pthread_self()->stdio_locks; f; f=f->next_locked)
+ a_store(&f->lock, 0x40000000);
+}
+
+void __unlist_locked_file(FILE *f)
+{
+ if (f->lockcount) {
+ if (f->next_locked) f->next_locked->prev_locked = f->prev_locked;
+ if (f->prev_locked) f->prev_locked->next_locked = f->next_locked;
+ else __pthread_self()->stdio_locks = f->next_locked;
+ }
+}
+
+void __register_locked_file(FILE *f, pthread_t self)
+{
+ f->lockcount = 1;
+ f->prev_locked = 0;
+ f->next_locked = self->stdio_locks;
+ if (f->next_locked) f->next_locked->prev_locked = f;
+ self->stdio_locks = f;
+}
+
+int ftrylockfile(FILE *f)
+{
+ pthread_t self = __pthread_self();
+ int tid = self->tid;
+ int owner = f->lock;
+ if ((owner & ~MAYBE_WAITERS) == tid) {
+ if (f->lockcount == LONG_MAX)
+ return -1;
+ f->lockcount++;
+ return 0;
+ }
+ if (owner < 0) f->lock = owner = 0;
+ if (owner || a_cas(&f->lock, 0, tid))
+ return -1;
+ __register_locked_file(f, self);
+ return 0;
+}
diff --git a/libc-top-half/musl/src/stdio/funlockfile.c b/libc-top-half/musl/src/stdio/funlockfile.c
new file mode 100644
index 0000000..44d8b0d
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/funlockfile.c
@@ -0,0 +1,13 @@
+#include "stdio_impl.h"
+#include "pthread_impl.h"
+
+void funlockfile(FILE *f)
+{
+ if (f->lockcount == 1) {
+ __unlist_locked_file(f);
+ f->lockcount = 0;
+ __unlockfile(f);
+ } else {
+ f->lockcount--;
+ }
+}
diff --git a/libc-top-half/musl/src/stdio/fwide.c b/libc-top-half/musl/src/stdio/fwide.c
new file mode 100644
index 0000000..8bab634
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fwide.c
@@ -0,0 +1,16 @@
+#include <wchar.h>
+#include "stdio_impl.h"
+#include "locale_impl.h"
+
+int fwide(FILE *f, int mode)
+{
+ FLOCK(f);
+ if (mode) {
+ if (!f->locale) f->locale = MB_CUR_MAX==1
+ ? C_LOCALE : UTF8_LOCALE;
+ if (!f->mode) f->mode = mode>0 ? 1 : -1;
+ }
+ mode = f->mode;
+ FUNLOCK(f);
+ return mode;
+}
diff --git a/libc-top-half/musl/src/stdio/fwprintf.c b/libc-top-half/musl/src/stdio/fwprintf.c
new file mode 100644
index 0000000..9ce4f01
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fwprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int fwprintf(FILE *restrict f, const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vfwprintf(f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/fwrite.c b/libc-top-half/musl/src/stdio/fwrite.c
new file mode 100644
index 0000000..7a567b2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fwrite.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
+{
+ size_t i=0;
+
+ if (!f->wend && __towrite(f)) return 0;
+
+ if (l > f->wend - f->wpos) return f->write(f, s, l);
+
+ if (f->lbf >= 0) {
+ /* Match /^(.*\n|)/ */
+ for (i=l; i && s[i-1] != '\n'; i--);
+ if (i) {
+ size_t n = f->write(f, s, i);
+ if (n < i) return n;
+ s += i;
+ l -= i;
+ }
+ }
+
+ memcpy(f->wpos, s, l);
+ f->wpos += l;
+ return l+i;
+}
+
+size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
+{
+ size_t k, l = size*nmemb;
+ if (!size) nmemb = 0;
+ FLOCK(f);
+ k = __fwritex(src, l, f);
+ FUNLOCK(f);
+ return k==l ? nmemb : k/size;
+}
+
+weak_alias(fwrite, fwrite_unlocked);
diff --git a/libc-top-half/musl/src/stdio/fwscanf.c b/libc-top-half/musl/src/stdio/fwscanf.c
new file mode 100644
index 0000000..530bb7c
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/fwscanf.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int fwscanf(FILE *restrict f, const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vfwscanf(f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(fwscanf,__isoc99_fwscanf);
diff --git a/libc-top-half/musl/src/stdio/getc.c b/libc-top-half/musl/src/stdio/getc.c
new file mode 100644
index 0000000..8409fc2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getc.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include "getc.h"
+
+int getc(FILE *f)
+{
+ return do_getc(f);
+}
+
+weak_alias(getc, _IO_getc);
diff --git a/libc-top-half/musl/src/stdio/getc.h b/libc-top-half/musl/src/stdio/getc.h
new file mode 100644
index 0000000..e62e3f0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getc.h
@@ -0,0 +1,29 @@
+#include "stdio_impl.h"
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+#include "pthread_impl.h"
+
+#ifdef __GNUC__
+__attribute__((__noinline__))
+#endif
+static int locking_getc(FILE *f)
+{
+ if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f);
+ int c = getc_unlocked(f);
+ if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
+ __wake(&f->lock, 1, 1);
+ return c;
+}
+#endif
+
+static inline int do_getc(FILE *f)
+{
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ int l = f->lock;
+ if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
+ return getc_unlocked(f);
+ return locking_getc(f);
+#else
+ // With no threads, locking is unnecessary.
+ return getc_unlocked(f);
+#endif
+}
diff --git a/libc-top-half/musl/src/stdio/getc_unlocked.c b/libc-top-half/musl/src/stdio/getc_unlocked.c
new file mode 100644
index 0000000..b38dad1
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getc_unlocked.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+
+int (getc_unlocked)(FILE *f)
+{
+ return getc_unlocked(f);
+}
+
+weak_alias (getc_unlocked, fgetc_unlocked);
+weak_alias (getc_unlocked, _IO_getc_unlocked);
diff --git a/libc-top-half/musl/src/stdio/getchar.c b/libc-top-half/musl/src/stdio/getchar.c
new file mode 100644
index 0000000..df395ca
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getchar.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "getc.h"
+
+int getchar(void)
+{
+ return do_getc(stdin);
+}
diff --git a/libc-top-half/musl/src/stdio/getchar_unlocked.c b/libc-top-half/musl/src/stdio/getchar_unlocked.c
new file mode 100644
index 0000000..355ac31
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getchar_unlocked.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int getchar_unlocked(void)
+{
+ return getc_unlocked(stdin);
+}
diff --git a/libc-top-half/musl/src/stdio/getdelim.c b/libc-top-half/musl/src/stdio/getdelim.c
new file mode 100644
index 0000000..df11444
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getdelim.c
@@ -0,0 +1,83 @@
+#include "stdio_impl.h"
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+
+ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f)
+{
+ char *tmp;
+ unsigned char *z;
+ size_t k;
+ size_t i=0;
+ int c;
+
+ FLOCK(f);
+
+ if (!n || !s) {
+ f->mode |= f->mode-1;
+ f->flags |= F_ERR;
+ FUNLOCK(f);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!*s) *n=0;
+
+ for (;;) {
+ if (f->rpos != f->rend) {
+ z = memchr(f->rpos, delim, f->rend - f->rpos);
+ k = z ? z - f->rpos + 1 : f->rend - f->rpos;
+ } else {
+ z = 0;
+ k = 0;
+ }
+ if (i+k >= *n) {
+ size_t m = i+k+2;
+ if (!z && m < SIZE_MAX/4) m += m/2;
+ tmp = realloc(*s, m);
+ if (!tmp) {
+ m = i+k+2;
+ tmp = realloc(*s, m);
+ if (!tmp) {
+ /* Copy as much as fits and ensure no
+ * pushback remains in the FILE buf. */
+ k = *n-i;
+ memcpy(*s+i, f->rpos, k);
+ f->rpos += k;
+ f->mode |= f->mode-1;
+ f->flags |= F_ERR;
+ FUNLOCK(f);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ *s = tmp;
+ *n = m;
+ }
+ if (k) {
+ memcpy(*s+i, f->rpos, k);
+ f->rpos += k;
+ i += k;
+ }
+ if (z) break;
+ if ((c = getc_unlocked(f)) == EOF) {
+ if (!i || !feof(f)) {
+ FUNLOCK(f);
+ return -1;
+ }
+ break;
+ }
+ /* If the byte read by getc won't fit without growing the
+ * output buffer, push it back for next iteration. */
+ if (i+1 >= *n) *--f->rpos = c;
+ else if (((*s)[i++] = c) == delim) break;
+ }
+ (*s)[i] = 0;
+
+ FUNLOCK(f);
+
+ return i;
+}
+
+weak_alias(getdelim, __getdelim);
diff --git a/libc-top-half/musl/src/stdio/getline.c b/libc-top-half/musl/src/stdio/getline.c
new file mode 100644
index 0000000..476d0b0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getline.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+ssize_t getline(char **restrict s, size_t *restrict n, FILE *restrict f)
+{
+ return getdelim(s, n, '\n', f);
+}
diff --git a/libc-top-half/musl/src/stdio/gets.c b/libc-top-half/musl/src/stdio/gets.c
new file mode 100644
index 0000000..17963b9
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/gets.c
@@ -0,0 +1,15 @@
+#include "stdio_impl.h"
+#include <limits.h>
+#include <string.h>
+
+char *gets(char *s)
+{
+ size_t i=0;
+ int c;
+ FLOCK(stdin);
+ while ((c=getc_unlocked(stdin)) != EOF && c != '\n') s[i++] = c;
+ s[i] = 0;
+ if (c != '\n' && (!feof(stdin) || !i)) s = 0;
+ FUNLOCK(stdin);
+ return s;
+}
diff --git a/libc-top-half/musl/src/stdio/getw.c b/libc-top-half/musl/src/stdio/getw.c
new file mode 100644
index 0000000..73d2c0d
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getw.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+
+int getw(FILE *f)
+{
+ int x;
+ return fread(&x, sizeof x, 1, f) ? x : EOF;
+}
diff --git a/libc-top-half/musl/src/stdio/getwc.c b/libc-top-half/musl/src/stdio/getwc.c
new file mode 100644
index 0000000..a5008f0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getwc.c
@@ -0,0 +1,7 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+wint_t getwc(FILE *f)
+{
+ return fgetwc(f);
+}
diff --git a/libc-top-half/musl/src/stdio/getwchar.c b/libc-top-half/musl/src/stdio/getwchar.c
new file mode 100644
index 0000000..bd89e0e
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/getwchar.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+wint_t getwchar(void)
+{
+ return fgetwc(stdin);
+}
+
+weak_alias(getwchar, getwchar_unlocked);
diff --git a/libc-top-half/musl/src/stdio/ofl.c b/libc-top-half/musl/src/stdio/ofl.c
new file mode 100644
index 0000000..33a8aa5
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ofl.c
@@ -0,0 +1,20 @@
+#include "stdio_impl.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+static FILE *ofl_head;
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+static volatile int ofl_lock[1];
+volatile int *const __stdio_ofl_lockptr = ofl_lock;
+#endif
+
+FILE **__ofl_lock()
+{
+ LOCK(ofl_lock);
+ return &ofl_head;
+}
+
+void __ofl_unlock()
+{
+ UNLOCK(ofl_lock);
+}
diff --git a/libc-top-half/musl/src/stdio/ofl_add.c b/libc-top-half/musl/src/stdio/ofl_add.c
new file mode 100644
index 0000000..d7de9f1
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ofl_add.c
@@ -0,0 +1,11 @@
+#include "stdio_impl.h"
+
+FILE *__ofl_add(FILE *f)
+{
+ FILE **head = __ofl_lock();
+ f->next = *head;
+ if (*head) (*head)->prev = f;
+ *head = f;
+ __ofl_unlock();
+ return f;
+}
diff --git a/libc-top-half/musl/src/stdio/open_memstream.c b/libc-top-half/musl/src/stdio/open_memstream.c
new file mode 100644
index 0000000..aa50220
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/open_memstream.c
@@ -0,0 +1,109 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libc.h"
+
+struct cookie {
+ char **bufp;
+ size_t *sizep;
+ size_t pos;
+ char *buf;
+ size_t len;
+ size_t space;
+};
+
+struct ms_FILE {
+ FILE f;
+ struct cookie c;
+ unsigned char buf[BUFSIZ];
+};
+
+static off_t ms_seek(FILE *f, off_t off, int whence)
+{
+ ssize_t base;
+ struct cookie *c = f->cookie;
+ if (whence>2U) {
+fail:
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef __wasilibc_unmodified_upstream // WASI's SEEK_* constants have different values.
+ base = (size_t [3]){0, c->pos, c->len}[whence];
+#else
+ base = (size_t [3]) {
+ [SEEK_SET] = 0,
+ [SEEK_CUR] = c->pos,
+ [SEEK_END] = c->len
+ }[whence];
+#endif
+ if (off < -base || off > SSIZE_MAX-base) goto fail;
+ return c->pos = base+off;
+}
+
+static size_t ms_write(FILE *f, const unsigned char *buf, size_t len)
+{
+ struct cookie *c = f->cookie;
+ size_t len2 = f->wpos - f->wbase;
+ char *newbuf;
+ if (len2) {
+ f->wpos = f->wbase;
+ if (ms_write(f, f->wbase, len2) < len2) return 0;
+ }
+ if (len + c->pos >= c->space) {
+ len2 = 2*c->space+1 | c->pos+len+1;
+ newbuf = realloc(c->buf, len2);
+ if (!newbuf) return 0;
+ *c->bufp = c->buf = newbuf;
+ memset(c->buf + c->space, 0, len2 - c->space);
+ c->space = len2;
+ }
+ memcpy(c->buf+c->pos, buf, len);
+ c->pos += len;
+ if (c->pos >= c->len) c->len = c->pos;
+ *c->sizep = c->pos;
+ return len;
+}
+
+static int ms_close(FILE *f)
+{
+ return 0;
+}
+
+FILE *open_memstream(char **bufp, size_t *sizep)
+{
+ struct ms_FILE *f;
+ char *buf;
+
+ if (!(f=malloc(sizeof *f))) return 0;
+ if (!(buf=malloc(sizeof *buf))) {
+ free(f);
+ return 0;
+ }
+ memset(&f->f, 0, sizeof f->f);
+ memset(&f->c, 0, sizeof f->c);
+ f->f.cookie = &f->c;
+
+ f->c.bufp = bufp;
+ f->c.sizep = sizep;
+ f->c.pos = f->c.len = f->c.space = *sizep = 0;
+ f->c.buf = *bufp = buf;
+ *buf = 0;
+
+ f->f.flags = F_NORD;
+ f->f.fd = -1;
+ f->f.buf = f->buf;
+ f->f.buf_size = sizeof f->buf;
+ f->f.lbf = EOF;
+ f->f.write = ms_write;
+ f->f.seek = ms_seek;
+ f->f.close = ms_close;
+ f->f.mode = -1;
+
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ if (!libc.threaded) f->f.lock = -1;
+#endif
+
+ return __ofl_add(&f->f);
+}
diff --git a/libc-top-half/musl/src/stdio/open_wmemstream.c b/libc-top-half/musl/src/stdio/open_wmemstream.c
new file mode 100644
index 0000000..30ffcdf
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/open_wmemstream.c
@@ -0,0 +1,112 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libc.h"
+
+struct cookie {
+ wchar_t **bufp;
+ size_t *sizep;
+ size_t pos;
+ wchar_t *buf;
+ size_t len;
+ size_t space;
+ mbstate_t mbs;
+};
+
+struct wms_FILE {
+ FILE f;
+ struct cookie c;
+ unsigned char buf[1];
+};
+
+static off_t wms_seek(FILE *f, off_t off, int whence)
+{
+ ssize_t base;
+ struct cookie *c = f->cookie;
+ if (whence>2U) {
+fail:
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef __wasilibc_unmodified_upstream // WASI's SEEK_* constants have different values.
+ base = (size_t [3]){0, c->pos, c->len}[whence];
+#else
+ base = (size_t [3]) {
+ [SEEK_SET] = 0,
+ [SEEK_CUR] = c->pos,
+ [SEEK_END] = c->len
+ }[whence];
+#endif
+ if (off < -base || off > SSIZE_MAX/4-base) goto fail;
+ memset(&c->mbs, 0, sizeof c->mbs);
+ return c->pos = base+off;
+}
+
+static size_t wms_write(FILE *f, const unsigned char *buf, size_t len)
+{
+ struct cookie *c = f->cookie;
+ size_t len2;
+ wchar_t *newbuf;
+ if (len + c->pos >= c->space) {
+ len2 = 2*c->space+1 | c->pos+len+1;
+ if (len2 > SSIZE_MAX/4) return 0;
+ newbuf = realloc(c->buf, len2*4);
+ if (!newbuf) return 0;
+ *c->bufp = c->buf = newbuf;
+ memset(c->buf + c->space, 0, 4*(len2 - c->space));
+ c->space = len2;
+ }
+
+ len2 = mbsnrtowcs(c->buf+c->pos, (void *)&buf, len, c->space-c->pos, &c->mbs);
+ if (len2 == -1) return 0;
+ c->pos += len2;
+ if (c->pos >= c->len) c->len = c->pos;
+ *c->sizep = c->pos;
+ return len;
+}
+
+static int wms_close(FILE *f)
+{
+ return 0;
+}
+
+FILE *open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+ struct wms_FILE *f;
+ wchar_t *buf;
+
+ if (!(f=malloc(sizeof *f))) return 0;
+ if (!(buf=malloc(sizeof *buf))) {
+ free(f);
+ return 0;
+ }
+ memset(&f->f, 0, sizeof f->f);
+ memset(&f->c, 0, sizeof f->c);
+ f->f.cookie = &f->c;
+
+ f->c.bufp = bufp;
+ f->c.sizep = sizep;
+ f->c.pos = f->c.len = f->c.space = *sizep = 0;
+ f->c.buf = *bufp = buf;
+ *buf = 0;
+
+ f->f.flags = F_NORD;
+ f->f.fd = -1;
+ f->f.buf = f->buf;
+ f->f.buf_size = 0;
+ f->f.lbf = EOF;
+ f->f.write = wms_write;
+ f->f.seek = wms_seek;
+ f->f.close = wms_close;
+
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ if (!libc.threaded) f->f.lock = -1;
+#endif
+
+ fwide(&f->f, 1);
+
+ return __ofl_add(&f->f);
+}
diff --git a/libc-top-half/musl/src/stdio/pclose.c b/libc-top-half/musl/src/stdio/pclose.c
new file mode 100644
index 0000000..080a426
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/pclose.c
@@ -0,0 +1,13 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <unistd.h>
+
+int pclose(FILE *f)
+{
+ int status, r;
+ pid_t pid = f->pipe_pid;
+ fclose(f);
+ while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR);
+ if (r<0) return __syscall_ret(r);
+ return status;
+}
diff --git a/libc-top-half/musl/src/stdio/perror.c b/libc-top-half/musl/src/stdio/perror.c
new file mode 100644
index 0000000..d0943f2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/perror.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "stdio_impl.h"
+
+void perror(const char *msg)
+{
+ FILE *f = stderr;
+ char *errstr = strerror(errno);
+
+ FLOCK(f);
+
+ /* Save stderr's orientation and encoding rule, since perror is not
+ * permitted to change them. */
+ void *old_locale = f->locale;
+ int old_mode = f->mode;
+
+ if (msg && *msg) {
+ fwrite(msg, strlen(msg), 1, f);
+ fputc(':', f);
+ fputc(' ', f);
+ }
+ fwrite(errstr, strlen(errstr), 1, f);
+ fputc('\n', f);
+
+ f->mode = old_mode;
+ f->locale = old_locale;
+
+ FUNLOCK(f);
+}
diff --git a/libc-top-half/musl/src/stdio/popen.c b/libc-top-half/musl/src/stdio/popen.c
new file mode 100644
index 0000000..3ec8339
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/popen.c
@@ -0,0 +1,61 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <spawn.h>
+#include "stdio_impl.h"
+#include "syscall.h"
+
+extern char **__environ;
+
+FILE *popen(const char *cmd, const char *mode)
+{
+ int p[2], op, e;
+ pid_t pid;
+ FILE *f;
+ posix_spawn_file_actions_t fa;
+
+ if (*mode == 'r') {
+ op = 0;
+ } else if (*mode == 'w') {
+ op = 1;
+ } else {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (pipe2(p, O_CLOEXEC)) return NULL;
+ f = fdopen(p[op], mode);
+ if (!f) {
+ __syscall(SYS_close, p[0]);
+ __syscall(SYS_close, p[1]);
+ return NULL;
+ }
+
+ e = ENOMEM;
+ if (!posix_spawn_file_actions_init(&fa)) {
+ for (FILE *l = *__ofl_lock(); l; l=l->next)
+ if (l->pipe_pid && posix_spawn_file_actions_addclose(&fa, l->fd))
+ goto fail;
+ if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) {
+ if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0,
+ (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ))) {
+ posix_spawn_file_actions_destroy(&fa);
+ f->pipe_pid = pid;
+ if (!strchr(mode, 'e'))
+ fcntl(p[op], F_SETFD, 0);
+ __syscall(SYS_close, p[1-op]);
+ __ofl_unlock();
+ return f;
+ }
+ }
+fail:
+ __ofl_unlock();
+ posix_spawn_file_actions_destroy(&fa);
+ }
+ fclose(f);
+ __syscall(SYS_close, p[1-op]);
+
+ errno = e;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/stdio/printf.c b/libc-top-half/musl/src/stdio/printf.c
new file mode 100644
index 0000000..46cc6d8
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/printf.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int printf(const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+weak_alias(printf, iprintf);
+weak_alias(printf, __small_printf);
+#endif
diff --git a/libc-top-half/musl/src/stdio/putc.c b/libc-top-half/musl/src/stdio/putc.c
new file mode 100644
index 0000000..4744d97
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putc.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include "putc.h"
+
+int putc(int c, FILE *f)
+{
+ return do_putc(c, f);
+}
+
+weak_alias(putc, _IO_putc);
diff --git a/libc-top-half/musl/src/stdio/putc.h b/libc-top-half/musl/src/stdio/putc.h
new file mode 100644
index 0000000..2cc63d2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putc.h
@@ -0,0 +1,29 @@
+#include "stdio_impl.h"
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+#include "pthread_impl.h"
+
+#ifdef __GNUC__
+__attribute__((__noinline__))
+#endif
+static int locking_putc(int c, FILE *f)
+{
+ if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f);
+ c = putc_unlocked(c, f);
+ if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
+ __wake(&f->lock, 1, 1);
+ return c;
+}
+#endif
+
+static inline int do_putc(int c, FILE *f)
+{
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ int l = f->lock;
+ if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
+ return putc_unlocked(c, f);
+ return locking_putc(c, f);
+#else
+ // With no threads, locking is unnecessary.
+ return putc_unlocked(c, f);
+#endif
+}
diff --git a/libc-top-half/musl/src/stdio/putc_unlocked.c b/libc-top-half/musl/src/stdio/putc_unlocked.c
new file mode 100644
index 0000000..1007131
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putc_unlocked.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+
+int (putc_unlocked)(int c, FILE *f)
+{
+ return putc_unlocked(c, f);
+}
+
+weak_alias(putc_unlocked, fputc_unlocked);
+weak_alias(putc_unlocked, _IO_putc_unlocked);
diff --git a/libc-top-half/musl/src/stdio/putchar.c b/libc-top-half/musl/src/stdio/putchar.c
new file mode 100644
index 0000000..f044f16
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putchar.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "putc.h"
+
+int putchar(int c)
+{
+ return do_putc(c, stdout);
+}
diff --git a/libc-top-half/musl/src/stdio/putchar_unlocked.c b/libc-top-half/musl/src/stdio/putchar_unlocked.c
new file mode 100644
index 0000000..8b5d060
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putchar_unlocked.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int putchar_unlocked(int c)
+{
+ return putc_unlocked(c, stdout);
+}
diff --git a/libc-top-half/musl/src/stdio/puts.c b/libc-top-half/musl/src/stdio/puts.c
new file mode 100644
index 0000000..5a38a49
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/puts.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int puts(const char *s)
+{
+ int r;
+ FLOCK(stdout);
+ r = -(fputs(s, stdout) < 0 || putc_unlocked('\n', stdout) < 0);
+ FUNLOCK(stdout);
+ return r;
+}
diff --git a/libc-top-half/musl/src/stdio/putw.c b/libc-top-half/musl/src/stdio/putw.c
new file mode 100644
index 0000000..0ff9d7f
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putw.c
@@ -0,0 +1,7 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+
+int putw(int x, FILE *f)
+{
+ return (int)fwrite(&x, sizeof x, 1, f)-1;
+}
diff --git a/libc-top-half/musl/src/stdio/putwc.c b/libc-top-half/musl/src/stdio/putwc.c
new file mode 100644
index 0000000..4bb7473
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putwc.c
@@ -0,0 +1,7 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+wint_t putwc(wchar_t c, FILE *f)
+{
+ return fputwc(c, f);
+}
diff --git a/libc-top-half/musl/src/stdio/putwchar.c b/libc-top-half/musl/src/stdio/putwchar.c
new file mode 100644
index 0000000..b249c4a
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/putwchar.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+wint_t putwchar(wchar_t c)
+{
+ return fputwc(c, stdout);
+}
+
+weak_alias(putwchar, putwchar_unlocked);
diff --git a/libc-top-half/musl/src/stdio/remove.c b/libc-top-half/musl/src/stdio/remove.c
new file mode 100644
index 0000000..942e301
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/remove.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "syscall.h"
+
+int remove(const char *path)
+{
+#ifdef SYS_unlink
+ int r = __syscall(SYS_unlink, path);
+#else
+ int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0);
+#endif
+#ifdef SYS_rmdir
+ if (r==-EISDIR) r = __syscall(SYS_rmdir, path);
+#else
+ if (r==-EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
+#endif
+ return __syscall_ret(r);
+}
diff --git a/libc-top-half/musl/src/stdio/rename.c b/libc-top-half/musl/src/stdio/rename.c
new file mode 100644
index 0000000..f540adb
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/rename.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include "syscall.h"
+
+int rename(const char *old, const char *new)
+{
+#if defined(SYS_rename)
+ return syscall(SYS_rename, old, new);
+#elif defined(SYS_renameat)
+ return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new);
+#else
+ return syscall(SYS_renameat2, AT_FDCWD, old, AT_FDCWD, new, 0);
+#endif
+}
diff --git a/libc-top-half/musl/src/stdio/rewind.c b/libc-top-half/musl/src/stdio/rewind.c
new file mode 100644
index 0000000..6f4b58b
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/rewind.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+
+void rewind(FILE *f)
+{
+ FLOCK(f);
+ __fseeko_unlocked(f, 0, SEEK_SET);
+ f->flags &= ~F_ERR;
+ FUNLOCK(f);
+}
diff --git a/libc-top-half/musl/src/stdio/scanf.c b/libc-top-half/musl/src/stdio/scanf.c
new file mode 100644
index 0000000..bd77699
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/scanf.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int scanf(const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vscanf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(scanf,__isoc99_scanf);
diff --git a/libc-top-half/musl/src/stdio/setbuf.c b/libc-top-half/musl/src/stdio/setbuf.c
new file mode 100644
index 0000000..74ad783
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/setbuf.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void setbuf(FILE *restrict f, char *restrict buf)
+{
+ setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/libc-top-half/musl/src/stdio/setbuffer.c b/libc-top-half/musl/src/stdio/setbuffer.c
new file mode 100644
index 0000000..71233d2
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/setbuffer.c
@@ -0,0 +1,7 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+
+void setbuffer(FILE *f, char *buf, size_t size)
+{
+ setvbuf(f, buf, buf ? _IOFBF : _IONBF, size);
+}
diff --git a/libc-top-half/musl/src/stdio/setlinebuf.c b/libc-top-half/musl/src/stdio/setlinebuf.c
new file mode 100644
index 0000000..b93c4d6
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/setlinebuf.c
@@ -0,0 +1,7 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+
+void setlinebuf(FILE *f)
+{
+ setvbuf(f, 0, _IOLBF, 0);
+}
diff --git a/libc-top-half/musl/src/stdio/setvbuf.c b/libc-top-half/musl/src/stdio/setvbuf.c
new file mode 100644
index 0000000..523dddc
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/setvbuf.c
@@ -0,0 +1,29 @@
+#include "stdio_impl.h"
+
+/* The behavior of this function is undefined except when it is the first
+ * operation on the stream, so the presence or absence of locking is not
+ * observable in a program whose behavior is defined. Thus no locking is
+ * performed here. No allocation of buffers is performed, but a buffer
+ * provided by the caller is used as long as it is suitably sized. */
+
+int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size)
+{
+ f->lbf = EOF;
+
+ if (type == _IONBF) {
+ f->buf_size = 0;
+ } else if (type == _IOLBF || type == _IOFBF) {
+ if (buf && size >= UNGET) {
+ f->buf = (void *)(buf + UNGET);
+ f->buf_size = size - UNGET;
+ }
+ if (type == _IOLBF && f->buf_size)
+ f->lbf = '\n';
+ } else {
+ return -1;
+ }
+
+ f->flags |= F_SVB;
+
+ return 0;
+}
diff --git a/libc-top-half/musl/src/stdio/snprintf.c b/libc-top-half/musl/src/stdio/snprintf.c
new file mode 100644
index 0000000..771503b
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/snprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsnprintf(s, n, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
diff --git a/libc-top-half/musl/src/stdio/sprintf.c b/libc-top-half/musl/src/stdio/sprintf.c
new file mode 100644
index 0000000..9dff524
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/sprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int sprintf(char *restrict s, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsprintf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/sscanf.c b/libc-top-half/musl/src/stdio/sscanf.c
new file mode 100644
index 0000000..f2ac2f5
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/sscanf.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int sscanf(const char *restrict s, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsscanf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(sscanf,__isoc99_sscanf);
diff --git a/libc-top-half/musl/src/stdio/stderr.c b/libc-top-half/musl/src/stdio/stderr.c
new file mode 100644
index 0000000..5f24549
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/stderr.c
@@ -0,0 +1,20 @@
+#include "stdio_impl.h"
+
+#undef stderr
+
+static unsigned char buf[UNGET];
+hidden FILE __stderr_FILE = {
+ .buf = buf+UNGET,
+ .buf_size = 0,
+ .fd = 2,
+ .flags = F_PERM | F_NORD,
+ .lbf = -1,
+ .write = __stdio_write,
+ .seek = __stdio_seek,
+ .close = __stdio_close,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1,
+#endif
+};
+FILE *const stderr = &__stderr_FILE;
+FILE *volatile __stderr_used = &__stderr_FILE;
diff --git a/libc-top-half/musl/src/stdio/stdin.c b/libc-top-half/musl/src/stdio/stdin.c
new file mode 100644
index 0000000..68e1c3f
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/stdin.c
@@ -0,0 +1,19 @@
+#include "stdio_impl.h"
+
+#undef stdin
+
+static unsigned char buf[BUFSIZ+UNGET];
+hidden FILE __stdin_FILE = {
+ .buf = buf+UNGET,
+ .buf_size = sizeof buf-UNGET,
+ .fd = 0,
+ .flags = F_PERM | F_NOWR,
+ .read = __stdio_read,
+ .seek = __stdio_seek,
+ .close = __stdio_close,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1,
+#endif
+};
+FILE *const stdin = &__stdin_FILE;
+FILE *volatile __stdin_used = &__stdin_FILE;
diff --git a/libc-top-half/musl/src/stdio/stdout.c b/libc-top-half/musl/src/stdio/stdout.c
new file mode 100644
index 0000000..e0e2bce
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/stdout.c
@@ -0,0 +1,20 @@
+#include "stdio_impl.h"
+
+#undef stdout
+
+static unsigned char buf[BUFSIZ+UNGET];
+hidden FILE __stdout_FILE = {
+ .buf = buf+UNGET,
+ .buf_size = sizeof buf-UNGET,
+ .fd = 1,
+ .flags = F_PERM | F_NORD,
+ .lbf = '\n',
+ .write = __stdout_write,
+ .seek = __stdio_seek,
+ .close = __stdio_close,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1,
+#endif
+};
+FILE *const stdout = &__stdout_FILE;
+FILE *volatile __stdout_used = &__stdout_FILE;
diff --git a/libc-top-half/musl/src/stdio/swprintf.c b/libc-top-half/musl/src/stdio/swprintf.c
new file mode 100644
index 0000000..f75eb11
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/swprintf.c
@@ -0,0 +1,13 @@
+#include <stdarg.h>
+#include <wchar.h>
+
+int swprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vswprintf(s, n, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
diff --git a/libc-top-half/musl/src/stdio/swscanf.c b/libc-top-half/musl/src/stdio/swscanf.c
new file mode 100644
index 0000000..03d572d
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/swscanf.c
@@ -0,0 +1,14 @@
+#include <stdarg.h>
+#include <wchar.h>
+
+int swscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vswscanf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(swscanf,__isoc99_swscanf);
diff --git a/libc-top-half/musl/src/stdio/tempnam.c b/libc-top-half/musl/src/stdio/tempnam.c
new file mode 100644
index 0000000..565df6b
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/tempnam.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "syscall.h"
+#include "kstat.h"
+
+#define MAXTRIES 100
+
+char *tempnam(const char *dir, const char *pfx)
+{
+ char s[PATH_MAX];
+ size_t l, dl, pl;
+ int try;
+ int r;
+
+ if (!dir) dir = P_tmpdir;
+ if (!pfx) pfx = "temp";
+
+ dl = strlen(dir);
+ pl = strlen(pfx);
+ l = dl + 1 + pl + 1 + 6;
+
+ if (l >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+
+ memcpy(s, dir, dl);
+ s[dl] = '/';
+ memcpy(s+dl+1, pfx, pl);
+ s[dl+1+pl] = '_';
+ s[l] = 0;
+
+ for (try=0; try<MAXTRIES; try++) {
+ __randname(s+l-6);
+#ifdef SYS_lstat
+ r = __syscall(SYS_lstat, s, &(struct kstat){0});
+#else
+ r = __syscall(SYS_fstatat, AT_FDCWD, s,
+ &(struct kstat){0}, AT_SYMLINK_NOFOLLOW);
+#endif
+ if (r == -ENOENT) return strdup(s);
+ }
+ return 0;
+}
diff --git a/libc-top-half/musl/src/stdio/tmpfile.c b/libc-top-half/musl/src/stdio/tmpfile.c
new file mode 100644
index 0000000..ae49398
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/tmpfile.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "stdio_impl.h"
+
+#define MAXTRIES 100
+
+FILE *tmpfile(void)
+{
+ char s[] = "/tmp/tmpfile_XXXXXX";
+ int fd;
+ FILE *f;
+ int try;
+ for (try=0; try<MAXTRIES; try++) {
+ __randname(s+13);
+ fd = sys_open(s, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd >= 0) {
+#ifdef SYS_unlink
+ __syscall(SYS_unlink, s);
+#else
+ __syscall(SYS_unlinkat, AT_FDCWD, s, 0);
+#endif
+ f = __fdopen(fd, "w+");
+ if (!f) __syscall(SYS_close, fd);
+ return f;
+ }
+ }
+ return 0;
+}
+
+weak_alias(tmpfile, tmpfile64);
diff --git a/libc-top-half/musl/src/stdio/tmpnam.c b/libc-top-half/musl/src/stdio/tmpnam.c
new file mode 100644
index 0000000..d667a83
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/tmpnam.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include "syscall.h"
+#include "kstat.h"
+
+#define MAXTRIES 100
+
+char *tmpnam(char *buf)
+{
+ static char internal[L_tmpnam];
+ char s[] = "/tmp/tmpnam_XXXXXX";
+ int try;
+ int r;
+ for (try=0; try<MAXTRIES; try++) {
+ __randname(s+12);
+#ifdef SYS_lstat
+ r = __syscall(SYS_lstat, s, &(struct kstat){0});
+#else
+ r = __syscall(SYS_fstatat, AT_FDCWD, s,
+ &(struct kstat){0}, AT_SYMLINK_NOFOLLOW);
+#endif
+ if (r == -ENOENT) return strcpy(buf ? buf : internal, s);
+ }
+ return 0;
+}
diff --git a/libc-top-half/musl/src/stdio/ungetc.c b/libc-top-half/musl/src/stdio/ungetc.c
new file mode 100644
index 0000000..bc629d4
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ungetc.c
@@ -0,0 +1,20 @@
+#include "stdio_impl.h"
+
+int ungetc(int c, FILE *f)
+{
+ if (c == EOF) return c;
+
+ FLOCK(f);
+
+ if (!f->rpos) __toread(f);
+ if (!f->rpos || f->rpos <= f->buf - UNGET) {
+ FUNLOCK(f);
+ return EOF;
+ }
+
+ *--f->rpos = c;
+ f->flags &= ~F_EOF;
+
+ FUNLOCK(f);
+ return (unsigned char)c;
+}
diff --git a/libc-top-half/musl/src/stdio/ungetwc.c b/libc-top-half/musl/src/stdio/ungetwc.c
new file mode 100644
index 0000000..9edf366
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/ungetwc.c
@@ -0,0 +1,35 @@
+#include "stdio_impl.h"
+#include "locale_impl.h"
+#include <wchar.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+
+wint_t ungetwc(wint_t c, FILE *f)
+{
+ unsigned char mbc[MB_LEN_MAX];
+ int l;
+ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
+
+ FLOCK(f);
+
+ if (f->mode <= 0) fwide(f, 1);
+ *ploc = f->locale;
+
+ if (!f->rpos) __toread(f);
+ if (!f->rpos || c == WEOF || (l = wcrtomb((void *)mbc, c, 0)) < 0 ||
+ f->rpos < f->buf - UNGET + l) {
+ FUNLOCK(f);
+ *ploc = loc;
+ return WEOF;
+ }
+
+ if (isascii(c)) *--f->rpos = c;
+ else memcpy(f->rpos -= l, mbc, l);
+
+ f->flags &= ~F_EOF;
+
+ FUNLOCK(f);
+ *ploc = loc;
+ return c;
+}
diff --git a/libc-top-half/musl/src/stdio/vasprintf.c b/libc-top-half/musl/src/stdio/vasprintf.c
new file mode 100644
index 0000000..08251bc
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vasprintf.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+int vasprintf(char **s, const char *fmt, va_list ap)
+{
+ va_list ap2;
+ va_copy(ap2, ap);
+ int l = vsnprintf(0, 0, fmt, ap2);
+ va_end(ap2);
+
+ if (l<0 || !(*s=malloc(l+1U))) return -1;
+ return vsnprintf(*s, l+1U, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vdprintf.c b/libc-top-half/musl/src/stdio/vdprintf.c
new file mode 100644
index 0000000..cef0a1a
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vdprintf.c
@@ -0,0 +1,13 @@
+#include "stdio_impl.h"
+
+int vdprintf(int fd, const char *restrict fmt, va_list ap)
+{
+ FILE f = {
+ .fd = fd, .lbf = EOF, .write = __stdio_write,
+ .buf = (void *)fmt, .buf_size = 0,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1
+#endif
+ };
+ return vfprintf(&f, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vfprintf.c b/libc-top-half/musl/src/stdio/vfprintf.c
new file mode 100644
index 0000000..7da2e50
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vfprintf.c
@@ -0,0 +1,737 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <inttypes.h>
+#include <math.h>
+#include <float.h>
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+#include "printscan.h"
+#endif
+
+/* Some useful macros */
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM (1U<<'#'-' ')
+#define ZERO_PAD (1U<<'0'-' ')
+#define LEFT_ADJ (1U<<'-'-' ')
+#define PAD_POS (1U<<' '-' ')
+#define MARK_POS (1U<<'+'-' ')
+#define GROUPED (1U<<'\''-' ')
+
+#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
+
+/* State machine to accept length modifiers + conversion specifiers.
+ * Result is 0 on failure, or an argument type to pop on success. */
+
+enum {
+ BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
+ ZTPRE, JPRE,
+ STOP,
+ PTR, INT, UINT, ULLONG,
+ LONG, ULONG,
+ SHORT, USHORT, CHAR, UCHAR,
+ LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
+ DBL, LDBL,
+ NOARG,
+ MAXSTATE
+};
+
+#define S(x) [(x)-'A']
+
+static const unsigned char states[]['z'-'A'+1] = {
+ { /* 0: bare types */
+ S('d') = INT, S('i') = INT,
+ S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = CHAR, S('C') = INT,
+ S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
+ S('m') = NOARG,
+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
+ }, { /* 1: l-prefixed */
+ S('d') = LONG, S('i') = LONG,
+ S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('l') = LLPRE,
+ }, { /* 2: ll-prefixed */
+ S('d') = LLONG, S('i') = LLONG,
+ S('o') = ULLONG, S('u') = ULLONG,
+ S('x') = ULLONG, S('X') = ULLONG,
+ S('n') = PTR,
+ }, { /* 3: h-prefixed */
+ S('d') = SHORT, S('i') = SHORT,
+ S('o') = USHORT, S('u') = USHORT,
+ S('x') = USHORT, S('X') = USHORT,
+ S('n') = PTR,
+ S('h') = HHPRE,
+ }, { /* 4: hh-prefixed */
+ S('d') = CHAR, S('i') = CHAR,
+ S('o') = UCHAR, S('u') = UCHAR,
+ S('x') = UCHAR, S('X') = UCHAR,
+ S('n') = PTR,
+ }, { /* 5: L-prefixed */
+ S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
+ S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
+ S('n') = PTR,
+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
+ S('d') = PDIFF, S('i') = PDIFF,
+ S('o') = SIZET, S('u') = SIZET,
+ S('x') = SIZET, S('X') = SIZET,
+ S('n') = PTR,
+ }, { /* 7: j-prefixed */
+ S('d') = IMAX, S('i') = IMAX,
+ S('o') = UMAX, S('u') = UMAX,
+ S('x') = UMAX, S('X') = UMAX,
+ S('n') = PTR,
+ }
+};
+
+#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
+
+union arg
+{
+ uintmax_t i;
+#if !defined(__wasilibc_printscan_no_floating_point)
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double f;
+#else
+ long double f;
+#endif
+#endif
+ void *p;
+};
+
+static void pop_arg(union arg *arg, int type, va_list *ap)
+{
+ switch (type) {
+ case PTR: arg->p = va_arg(*ap, void *);
+ break; case INT: arg->i = va_arg(*ap, int);
+ break; case UINT: arg->i = va_arg(*ap, unsigned int);
+ break; case LONG: arg->i = va_arg(*ap, long);
+ break; case ULONG: arg->i = va_arg(*ap, unsigned long);
+ break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
+ break; case SHORT: arg->i = (short)va_arg(*ap, int);
+ break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
+ break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
+ break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
+ break; case LLONG: arg->i = va_arg(*ap, long long);
+ break; case SIZET: arg->i = va_arg(*ap, size_t);
+ break; case IMAX: arg->i = va_arg(*ap, intmax_t);
+ break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
+ break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
+ break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
+#if defined(__wasilibc_printscan_no_floating_point)
+ break; case DBL:
+ case LDBL:
+ floating_point_not_supported();
+#else
+ break; case DBL: arg->f = va_arg(*ap, double);
+#if defined(__wasilibc_printscan_no_long_double)
+ break; case LDBL: long_double_not_supported();
+#else
+ break; case LDBL: arg->f = va_arg(*ap, long double);
+#endif
+#endif
+ }
+}
+
+static void out(FILE *f, const char *s, size_t l)
+{
+ if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
+}
+
+static void pad(FILE *f, char c, int w, int l, int fl)
+{
+ char pad[256];
+ if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
+ l = w - l;
+ memset(pad, c, l>sizeof pad ? sizeof pad : l);
+ for (; l >= sizeof pad; l -= sizeof pad)
+ out(f, pad, sizeof pad);
+ out(f, pad, l);
+}
+
+static const char xdigits[16] = {
+ "0123456789ABCDEF"
+};
+
+static char *fmt_x(uintmax_t x, char *s, int lower)
+{
+ for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
+ return s;
+}
+
+static char *fmt_o(uintmax_t x, char *s)
+{
+ for (; x; x>>=3) *--s = '0' + (x&7);
+ return s;
+}
+
+static char *fmt_u(uintmax_t x, char *s)
+{
+ unsigned long y;
+ for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
+ for (y=x; y; y/=10) *--s = '0' + y%10;
+ return s;
+}
+
+#if !defined(__wasilibc_printscan_no_floating_point)
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+#if defined(__wasilibc_printscan_no_long_double)
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long_double)];
+#else
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+#endif
+
+#if defined(__wasilibc_printscan_no_long_double)
+static int fmt_fp(FILE *f, long_double y, int w, int p, int fl, int t)
+#else
+static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
+#endif
+{
+ uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
+ uint32_t *a, *d, *r, *z;
+ int e2=0, e, i, j, l;
+ char buf[9+LDBL_MANT_DIG/4], *s;
+ const char *prefix="-0X+0X 0X-0x+0x 0x";
+ int pl;
+ char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
+
+ pl=1;
+ if (signbit(y)) {
+ y=-y;
+ } else if (fl & MARK_POS) {
+ prefix+=3;
+ } else if (fl & PAD_POS) {
+ prefix+=6;
+ } else prefix++, pl=0;
+
+ if (!isfinite(y)) {
+ char *s = (t&32)?"inf":"INF";
+ if (y!=y) s=(t&32)?"nan":"NAN";
+ pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
+ out(f, prefix, pl);
+ out(f, s, 3);
+ pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
+ return MAX(w, 3+pl);
+ }
+
+ y = frexpl(y, &e2) * 2;
+ if (y) e2--;
+
+ if ((t|32)=='a') {
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double round = 8.0;
+#else
+ long double round = 8.0;
+#endif
+ int re;
+
+ if (t&32) prefix += 9;
+ pl += 2;
+
+ if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+ else re=LDBL_MANT_DIG/4-1-p;
+
+ if (re) {
+ round *= 1<<(LDBL_MANT_DIG%4);
+ while (re--) round*=16;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ } else {
+ y+=round;
+ y-=round;
+ }
+ }
+
+ estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
+ if (estr==ebuf) *--estr='0';
+ *--estr = (e2<0 ? '-' : '+');
+ *--estr = t+('p'-'a');
+
+ s=buf;
+ do {
+ int x=y;
+ *s++=xdigits[x]|(t&32);
+ y=16*(y-x);
+ if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+ } while (y);
+
+ if (p > INT_MAX-2-(ebuf-estr)-pl)
+ return -1;
+ if (p && s-buf-2 < p)
+ l = (p+2) + (ebuf-estr);
+ else
+ l = (s-buf) + (ebuf-estr);
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+ out(f, buf, s-buf);
+ pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
+ out(f, estr, ebuf-estr);
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+ return MAX(w, pl+l);
+ }
+ if (p<0) p=6;
+
+ if (y) y *= 0x1p28, e2-=28;
+
+ if (e2<0) a=r=z=big;
+ else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+ do {
+ *z = y;
+ y = 1000000000*(y-*z++);
+ } while (y);
+
+ while (e2>0) {
+ uint32_t carry=0;
+ int sh=MIN(29,e2);
+ for (d=z-1; d>=a; d--) {
+ uint64_t x = ((uint64_t)*d<<sh)+carry;
+ *d = x % 1000000000;
+ carry = x / 1000000000;
+ }
+ if (carry) *--a = carry;
+ while (z>a && !z[-1]) z--;
+ e2-=sh;
+ }
+ while (e2<0) {
+ uint32_t carry=0, *b;
+ int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9;
+ for (d=a; d<z; d++) {
+ uint32_t rm = *d & (1<<sh)-1;
+ *d = (*d>>sh) + carry;
+ carry = (1000000000>>sh) * rm;
+ }
+ if (!*a) a++;
+ if (carry) *z++ = carry;
+ /* Avoid (slow!) computation past requested precision */
+ b = (t|32)=='f' ? r : a;
+ if (z-b > need) z = b+need;
+ e2+=sh;
+ }
+
+ if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ else e=0;
+
+ /* Perform rounding: j is precision after the radix (possibly neg) */
+ j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
+ if (j < 9*(z-r-1)) {
+ uint32_t x;
+ /* We avoid C's broken division of negative numbers */
+ d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
+ j += 9*LDBL_MAX_EXP;
+ j %= 9;
+ for (i=10, j++; j<9; i*=10, j++);
+ x = *d % i;
+ /* Are there any significant digits past j? */
+ if (x || d+1!=z) {
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double round = 2/LDBL_EPSILON;
+ long_double small;
+#else
+ long double round = 2/LDBL_EPSILON;
+ long double small;
+#endif
+ if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1)))
+ round += 2;
+ if (x<i/2) small=0x0.8p0;
+ else if (x==i/2 && d+1==z) small=0x1.0p0;
+ else small=0x1.8p0;
+ if (pl && *prefix=='-') round*=-1, small*=-1;
+ *d -= x;
+ /* Decide whether to round by probing round+small */
+ if (round+small != round) {
+ *d = *d + i;
+ while (*d > 999999999) {
+ *d--=0;
+ if (d<a) *--a=0;
+ (*d)++;
+ }
+ for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ }
+ }
+ if (z>d+1) z=d+1;
+ }
+ for (; z>a && !z[-1]; z--);
+
+ if ((t|32)=='g') {
+ if (!p) p++;
+ if (p>e && e>=-4) {
+ t--;
+ p-=e+1;
+ } else {
+ t-=2;
+ p--;
+ }
+ if (!(fl&ALT_FORM)) {
+ /* Count trailing zeros in last place */
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ else j=9;
+ if ((t|32)=='f')
+ p = MIN(p,MAX(0,9*(z-r-1)-j));
+ else
+ p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ }
+ }
+ if (p > INT_MAX-1-(p || (fl&ALT_FORM)))
+ return -1;
+ l = 1 + p + (p || (fl&ALT_FORM));
+ if ((t|32)=='f') {
+ if (e > INT_MAX-l) return -1;
+ if (e>0) l+=e;
+ } else {
+ estr=fmt_u(e<0 ? -e : e, ebuf);
+ while(ebuf-estr<2) *--estr='0';
+ *--estr = (e<0 ? '-' : '+');
+ *--estr = t;
+ if (ebuf-estr > INT_MAX-l) return -1;
+ l += ebuf-estr;
+ }
+
+ if (l > INT_MAX-pl) return -1;
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+
+ if ((t|32)=='f') {
+ if (a>r) a=r;
+ for (d=a; d<=r; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (d!=a) while (s>buf) *--s='0';
+ else if (s==buf+9) *--s='0';
+ out(f, s, buf+9-s);
+ }
+ if (p || (fl&ALT_FORM)) out(f, ".", 1);
+ for (; d<z && p>0; d++, p-=9) {
+ char *s = fmt_u(*d, buf+9);
+ while (s>buf) *--s='0';
+ out(f, s, MIN(9,p));
+ }
+ pad(f, '0', p+9, 9, 0);
+ } else {
+ if (z<=a) z=a+1;
+ for (d=a; d<z && p>=0; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (s==buf+9) *--s='0';
+ if (d!=a) while (s>buf) *--s='0';
+ else {
+ out(f, s++, 1);
+ if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
+ }
+ out(f, s, MIN(buf+9-s, p));
+ p -= buf+9-s;
+ }
+ pad(f, '0', p+18, 18, 0);
+ out(f, estr, ebuf-estr);
+ }
+
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+
+ return MAX(w, pl+l);
+}
+#endif
+
+static int getint(char **s) {
+ int i;
+ for (i=0; isdigit(**s); (*s)++) {
+ if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
+ else i = 10*i + (**s-'0');
+ }
+ return i;
+}
+
+static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
+{
+ char *a, *z, *s=(char *)fmt;
+ unsigned l10n=0, fl;
+ int w, p, xp;
+ union arg arg;
+ int argpos;
+ unsigned st, ps;
+ int cnt=0, l=0;
+ size_t i;
+ char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+ const char *prefix;
+ int t, pl;
+ wchar_t wc[2], *ws;
+ char mb[4];
+
+ for (;;) {
+ /* This error is only specified for snprintf, but since it's
+ * unspecified for other forms, do the same. Stop immediately
+ * on overflow; otherwise %n could produce wrong results. */
+ if (l > INT_MAX - cnt) goto overflow;
+
+ /* Update output count, end loop when fmt is exhausted */
+ cnt += l;
+ if (!*s) break;
+
+ /* Handle literal text and %% format specifiers */
+ for (a=s; *s && *s!='%'; s++);
+ for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
+ if (z-a > INT_MAX-cnt) goto overflow;
+ l = z-a;
+ if (f) out(f, a, l);
+ if (l) continue;
+
+ if (isdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ argpos = s[1]-'0';
+ s+=3;
+ } else {
+ argpos = -1;
+ s++;
+ }
+
+ /* Read modifier flags */
+ for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
+ fl |= 1U<<*s-' ';
+
+ /* Read field width */
+ if (*s=='*') {
+ if (isdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ nl_type[s[1]-'0'] = INT;
+ w = nl_arg[s[1]-'0'].i;
+ s+=3;
+ } else if (!l10n) {
+ w = f ? va_arg(*ap, int) : 0;
+ s++;
+ } else goto inval;
+ if (w<0) fl|=LEFT_ADJ, w=-w;
+ } else if ((w=getint(&s))<0) goto overflow;
+
+ /* Read precision */
+ if (*s=='.' && s[1]=='*') {
+ if (isdigit(s[2]) && s[3]=='$') {
+ nl_type[s[2]-'0'] = INT;
+ p = nl_arg[s[2]-'0'].i;
+ s+=4;
+ } else if (!l10n) {
+ p = f ? va_arg(*ap, int) : 0;
+ s+=2;
+ } else goto inval;
+ xp = (p>=0);
+ } else if (*s=='.') {
+ s++;
+ p = getint(&s);
+ xp = 1;
+ } else {
+ p = -1;
+ xp = 0;
+ }
+
+ /* Format specifier state machine */
+ st=0;
+ do {
+ if (OOB(*s)) goto inval;
+ ps=st;
+ st=states[st]S(*s++);
+ } while (st-1<STOP);
+ if (!st) goto inval;
+
+ /* Check validity of argument type (nl/normal) */
+ if (st==NOARG) {
+ if (argpos>=0) goto inval;
+ } else {
+ if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
+ else if (f) pop_arg(&arg, st, ap);
+ else return 0;
+ }
+
+ if (!f) continue;
+
+ z = buf + sizeof(buf);
+ prefix = "-+ 0X0x";
+ pl = 0;
+ t = s[-1];
+
+ /* Transform ls,lc -> S,C */
+ if (ps && (t&15)==3) t&=~32;
+
+ /* - and 0 flags are mutually exclusive */
+ if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
+
+ switch(t) {
+ case 'n':
+ switch(ps) {
+ case BARE: *(int *)arg.p = cnt; break;
+ case LPRE: *(long *)arg.p = cnt; break;
+ case LLPRE: *(long long *)arg.p = cnt; break;
+ case HPRE: *(unsigned short *)arg.p = cnt; break;
+ case HHPRE: *(unsigned char *)arg.p = cnt; break;
+ case ZTPRE: *(size_t *)arg.p = cnt; break;
+ case JPRE: *(uintmax_t *)arg.p = cnt; break;
+ }
+ continue;
+ case 'p':
+ p = MAX(p, 2*sizeof(void*));
+ t = 'x';
+ fl |= ALT_FORM;
+ case 'x': case 'X':
+ a = fmt_x(arg.i, z, t&32);
+ if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
+ if (0) {
+ case 'o':
+ a = fmt_o(arg.i, z);
+ if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
+ } if (0) {
+ case 'd': case 'i':
+ pl=1;
+ if (arg.i>INTMAX_MAX) {
+ arg.i=-arg.i;
+ } else if (fl & MARK_POS) {
+ prefix++;
+ } else if (fl & PAD_POS) {
+ prefix+=2;
+ } else pl=0;
+ case 'u':
+ a = fmt_u(arg.i, z);
+ }
+ if (xp && p<0) goto overflow;
+ if (xp) fl &= ~ZERO_PAD;
+ if (!arg.i && !p) {
+ a=z;
+ break;
+ }
+ p = MAX(p, z-a + !arg.i);
+ break;
+ case 'c':
+ *(a=z-(p=1))=arg.i;
+ fl &= ~ZERO_PAD;
+ break;
+ case 'm':
+ if (1) a = strerror(errno); else
+ case 's':
+ a = arg.p ? arg.p : "(null)";
+ z = a + strnlen(a, p<0 ? INT_MAX : p);
+ if (p<0 && *z) goto overflow;
+ p = z-a;
+ fl &= ~ZERO_PAD;
+ break;
+ case 'C':
+ wc[0] = arg.i;
+ wc[1] = 0;
+ arg.p = wc;
+ p = -1;
+ case 'S':
+ ws = arg.p;
+ for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l);
+ if (l<0) return -1;
+ if (i > INT_MAX) goto overflow;
+ p = i;
+ pad(f, ' ', w, p, fl);
+ ws = arg.p;
+ for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
+ out(f, mb, l);
+ pad(f, ' ', w, p, fl^LEFT_ADJ);
+ l = w>p ? w : p;
+ continue;
+#if !defined(__wasilibc_printscan_no_floating_point)
+ case 'e': case 'f': case 'g': case 'a':
+ case 'E': case 'F': case 'G': case 'A':
+ if (xp && p<0) goto overflow;
+ l = fmt_fp(f, arg.f, w, p, fl, t);
+ if (l<0) goto overflow;
+ continue;
+#endif
+ }
+
+ if (p < z-a) p = z-a;
+ if (p > INT_MAX-pl) goto overflow;
+ if (w < pl+p) w = pl+p;
+ if (w > INT_MAX-cnt) goto overflow;
+
+ pad(f, ' ', w, pl+p, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+p, fl^ZERO_PAD);
+ pad(f, '0', p, z-a, 0);
+ out(f, a, z-a);
+ pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
+
+ l = w;
+ }
+
+ if (f) return cnt;
+ if (!l10n) return 0;
+
+ for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
+ pop_arg(nl_arg+i, nl_type[i], ap);
+ for (; i<=NL_ARGMAX && !nl_type[i]; i++);
+ if (i<=NL_ARGMAX) goto inval;
+ return 1;
+
+inval:
+ errno = EINVAL;
+ return -1;
+overflow:
+ errno = EOVERFLOW;
+ return -1;
+}
+
+int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
+{
+ va_list ap2;
+ int nl_type[NL_ARGMAX+1] = {0};
+ union arg nl_arg[NL_ARGMAX+1];
+ unsigned char internal_buf[80], *saved_buf = 0;
+ int olderr;
+ int ret;
+
+ /* the copy allows passing va_list* even if va_list is an array */
+ va_copy(ap2, ap);
+ if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
+ va_end(ap2);
+ return -1;
+ }
+
+ FLOCK(f);
+ olderr = f->flags & F_ERR;
+ if (f->mode < 1) f->flags &= ~F_ERR;
+ if (!f->buf_size) {
+ saved_buf = f->buf;
+ f->buf = internal_buf;
+ f->buf_size = sizeof internal_buf;
+ f->wpos = f->wbase = f->wend = 0;
+ }
+ if (!f->wend && __towrite(f)) ret = -1;
+ else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
+ if (saved_buf) {
+ f->write(f, 0, 0);
+ if (!f->wpos) ret = -1;
+ f->buf = saved_buf;
+ f->buf_size = 0;
+ f->wpos = f->wbase = f->wend = 0;
+ }
+ if (f->flags & F_ERR) ret = -1;
+ f->flags |= olderr;
+ FUNLOCK(f);
+ va_end(ap2);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/vfscanf.c b/libc-top-half/musl/src/stdio/vfscanf.c
new file mode 100644
index 0000000..b612bbd
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vfscanf.c
@@ -0,0 +1,351 @@
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+#include "printscan.h"
+#endif
+
+#include "stdio_impl.h"
+#include "shgetc.h"
+#include "intscan.h"
+#include "floatscan.h"
+
+#define SIZE_hh -2
+#define SIZE_h -1
+#define SIZE_def 0
+#define SIZE_l 1
+#define SIZE_L 2
+#define SIZE_ll 3
+
+static void store_int(void *dest, int size, unsigned long long i)
+{
+ if (!dest) return;
+ switch (size) {
+ case SIZE_hh:
+ *(char *)dest = i;
+ break;
+ case SIZE_h:
+ *(short *)dest = i;
+ break;
+ case SIZE_def:
+ *(int *)dest = i;
+ break;
+ case SIZE_l:
+ *(long *)dest = i;
+ break;
+ case SIZE_ll:
+ *(long long *)dest = i;
+ break;
+ }
+}
+
+static void *arg_n(va_list ap, unsigned int n)
+{
+ void *p;
+ unsigned int i;
+ va_list ap2;
+ va_copy(ap2, ap);
+ for (i=n; i>1; i--) va_arg(ap2, void *);
+ p = va_arg(ap2, void *);
+ va_end(ap2);
+ return p;
+}
+
+int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
+{
+ int width;
+ int size;
+ int alloc = 0;
+ int base;
+ const unsigned char *p;
+ int c, t;
+ char *s;
+ wchar_t *wcs;
+ mbstate_t st;
+ void *dest=NULL;
+ int invert;
+ int matches=0;
+ unsigned long long x;
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double y;
+#else
+ long double y;
+#endif
+ off_t pos = 0;
+ unsigned char scanset[257];
+ size_t i, k;
+ wchar_t wc;
+
+ FLOCK(f);
+
+ if (!f->rpos) __toread(f);
+ if (!f->rpos) goto input_fail;
+
+ for (p=(const unsigned char *)fmt; *p; p++) {
+
+ alloc = 0;
+
+ if (isspace(*p)) {
+ while (isspace(p[1])) p++;
+ shlim(f, 0);
+ while (isspace(shgetc(f)));
+ shunget(f);
+ pos += shcnt(f);
+ continue;
+ }
+ if (*p != '%' || p[1] == '%') {
+ shlim(f, 0);
+ if (*p == '%') {
+ p++;
+ while (isspace((c=shgetc(f))));
+ } else {
+ c = shgetc(f);
+ }
+ if (c!=*p) {
+ shunget(f);
+ if (c<0) goto input_fail;
+ goto match_fail;
+ }
+ pos += shcnt(f);
+ continue;
+ }
+
+ p++;
+ if (*p=='*') {
+ dest = 0; p++;
+ } else if (isdigit(*p) && p[1]=='$') {
+ dest = arg_n(ap, *p-'0'); p+=2;
+ } else {
+ dest = va_arg(ap, void *);
+ }
+
+ for (width=0; isdigit(*p); p++) {
+ width = 10*width + *p - '0';
+ }
+
+ if (*p=='m') {
+ wcs = 0;
+ s = 0;
+ alloc = !!dest;
+ p++;
+ } else {
+ alloc = 0;
+ }
+
+ size = SIZE_def;
+ switch (*p++) {
+ case 'h':
+ if (*p == 'h') p++, size = SIZE_hh;
+ else size = SIZE_h;
+ break;
+ case 'l':
+ if (*p == 'l') p++, size = SIZE_ll;
+ else size = SIZE_l;
+ break;
+ case 'j':
+ size = SIZE_ll;
+ break;
+ case 'z':
+ case 't':
+ size = SIZE_l;
+ break;
+ case 'L':
+ size = SIZE_L;
+ break;
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 's': case 'c': case '[':
+ case 'S': case 'C':
+ case 'p': case 'n':
+ p--;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ t = *p;
+
+ /* C or S */
+ if ((t&0x2f) == 3) {
+ t |= 32;
+ size = SIZE_l;
+ }
+
+ switch (t) {
+ case 'c':
+ if (width < 1) width = 1;
+ case '[':
+ break;
+ case 'n':
+ store_int(dest, size, pos);
+ /* do not increment match count, etc! */
+ continue;
+ default:
+ shlim(f, 0);
+ while (isspace(shgetc(f)));
+ shunget(f);
+ pos += shcnt(f);
+ }
+
+ shlim(f, width);
+ if (shgetc(f) < 0) goto input_fail;
+ shunget(f);
+
+ switch (t) {
+ case 's':
+ case 'c':
+ case '[':
+ if (t == 'c' || t == 's') {
+ memset(scanset, -1, sizeof scanset);
+ scanset[0] = 0;
+ if (t == 's') {
+ scanset[1+'\t'] = 0;
+ scanset[1+'\n'] = 0;
+ scanset[1+'\v'] = 0;
+ scanset[1+'\f'] = 0;
+ scanset[1+'\r'] = 0;
+ scanset[1+' '] = 0;
+ }
+ } else {
+ if (*++p == '^') p++, invert = 1;
+ else invert = 0;
+ memset(scanset, invert, sizeof scanset);
+ scanset[0] = 0;
+ if (*p == '-') p++, scanset[1+'-'] = 1-invert;
+ else if (*p == ']') p++, scanset[1+']'] = 1-invert;
+ for (; *p != ']'; p++) {
+ if (!*p) goto fmt_fail;
+ if (*p=='-' && p[1] && p[1] != ']')
+ for (c=p++[-1]; c<*p; c++)
+ scanset[1+c] = 1-invert;
+ scanset[1+*p] = 1-invert;
+ }
+ }
+ wcs = 0;
+ s = 0;
+ i = 0;
+ k = t=='c' ? width+1U : 31;
+ if (size == SIZE_l) {
+ if (alloc) {
+ wcs = malloc(k*sizeof(wchar_t));
+ if (!wcs) goto alloc_fail;
+ } else {
+ wcs = dest;
+ }
+ st = (mbstate_t){0};
+ while (scanset[(c=shgetc(f))+1]) {
+ switch (mbrtowc(&wc, &(char){c}, 1, &st)) {
+ case -1:
+ goto input_fail;
+ case -2:
+ continue;
+ }
+ if (wcs) wcs[i++] = wc;
+ if (alloc && i==k) {
+ k+=k+1;
+ wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
+ if (!tmp) goto alloc_fail;
+ wcs = tmp;
+ }
+ }
+ if (!mbsinit(&st)) goto input_fail;
+ } else if (alloc) {
+ s = malloc(k);
+ if (!s) goto alloc_fail;
+ while (scanset[(c=shgetc(f))+1]) {
+ s[i++] = c;
+ if (i==k) {
+ k+=k+1;
+ char *tmp = realloc(s, k);
+ if (!tmp) goto alloc_fail;
+ s = tmp;
+ }
+ }
+ } else if ((s = dest)) {
+ while (scanset[(c=shgetc(f))+1])
+ s[i++] = c;
+ } else {
+ while (scanset[(c=shgetc(f))+1]);
+ }
+ shunget(f);
+ if (!shcnt(f)) goto match_fail;
+ if (t == 'c' && shcnt(f) != width) goto match_fail;
+ if (alloc) {
+ if (size == SIZE_l) *(wchar_t **)dest = wcs;
+ else *(char **)dest = s;
+ }
+ if (t != 'c') {
+ if (wcs) wcs[i] = 0;
+ if (s) s[i] = 0;
+ }
+ break;
+ case 'p':
+ case 'X':
+ case 'x':
+ base = 16;
+ goto int_common;
+ case 'o':
+ base = 8;
+ goto int_common;
+ case 'd':
+ case 'u':
+ base = 10;
+ goto int_common;
+ case 'i':
+ base = 0;
+ int_common:
+ x = __intscan(f, base, 0, ULLONG_MAX);
+ if (!shcnt(f)) goto match_fail;
+ if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x;
+ else store_int(dest, size, x);
+ break;
+ case 'a': case 'A':
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'g': case 'G':
+ y = __floatscan(f, size, 0);
+ if (!shcnt(f)) goto match_fail;
+ if (dest) switch (size) {
+ case SIZE_def:
+ *(float *)dest = y;
+ break;
+ case SIZE_l:
+ *(double *)dest = y;
+ break;
+ case SIZE_L:
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double_not_supported();
+#else
+ *(long double *)dest = y;
+#endif
+ break;
+ }
+ break;
+ }
+
+ pos += shcnt(f);
+ if (dest) matches++;
+ }
+ if (0) {
+fmt_fail:
+alloc_fail:
+input_fail:
+ if (!matches) matches--;
+match_fail:
+ if (alloc) {
+ free(s);
+ free(wcs);
+ }
+ }
+ FUNLOCK(f);
+ return matches;
+}
+
+weak_alias(vfscanf,__isoc99_vfscanf);
diff --git a/libc-top-half/musl/src/stdio/vfwprintf.c b/libc-top-half/musl/src/stdio/vfwprintf.c
new file mode 100644
index 0000000..e660fcc
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vfwprintf.c
@@ -0,0 +1,414 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <inttypes.h>
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+#include "printscan.h"
+#endif
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM (1U<<'#'-' ')
+#define ZERO_PAD (1U<<'0'-' ')
+#define LEFT_ADJ (1U<<'-'-' ')
+#define PAD_POS (1U<<' '-' ')
+#define MARK_POS (1U<<'+'-' ')
+#define GROUPED (1U<<'\''-' ')
+
+#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
+
+/* State machine to accept length modifiers + conversion specifiers.
+ * Result is 0 on failure, or an argument type to pop on success. */
+
+enum {
+ BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
+ ZTPRE, JPRE,
+ STOP,
+ PTR, INT, UINT, ULLONG,
+ LONG, ULONG,
+ SHORT, USHORT, CHAR, UCHAR,
+ LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
+ DBL, LDBL,
+ NOARG,
+ MAXSTATE
+};
+
+#define S(x) [(x)-'A']
+
+static const unsigned char states[]['z'-'A'+1] = {
+ { /* 0: bare types */
+ S('d') = INT, S('i') = INT,
+ S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = CHAR, S('C') = INT,
+ S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
+ S('m') = NOARG,
+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
+ }, { /* 1: l-prefixed */
+ S('d') = LONG, S('i') = LONG,
+ S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('l') = LLPRE,
+ }, { /* 2: ll-prefixed */
+ S('d') = LLONG, S('i') = LLONG,
+ S('o') = ULLONG, S('u') = ULLONG,
+ S('x') = ULLONG, S('X') = ULLONG,
+ S('n') = PTR,
+ }, { /* 3: h-prefixed */
+ S('d') = SHORT, S('i') = SHORT,
+ S('o') = USHORT, S('u') = USHORT,
+ S('x') = USHORT, S('X') = USHORT,
+ S('n') = PTR,
+ S('h') = HHPRE,
+ }, { /* 4: hh-prefixed */
+ S('d') = CHAR, S('i') = CHAR,
+ S('o') = UCHAR, S('u') = UCHAR,
+ S('x') = UCHAR, S('X') = UCHAR,
+ S('n') = PTR,
+ }, { /* 5: L-prefixed */
+ S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
+ S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
+ S('n') = PTR,
+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
+ S('d') = PDIFF, S('i') = PDIFF,
+ S('o') = SIZET, S('u') = SIZET,
+ S('x') = SIZET, S('X') = SIZET,
+ S('n') = PTR,
+ }, { /* 7: j-prefixed */
+ S('d') = IMAX, S('i') = IMAX,
+ S('o') = UMAX, S('u') = UMAX,
+ S('x') = UMAX, S('X') = UMAX,
+ S('n') = PTR,
+ }
+};
+
+#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
+
+union arg
+{
+ uintmax_t i;
+#if !defined(__wasilibc_printscan_no_floating_point)
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double f;
+#else
+ long double f;
+#endif
+#endif
+ void *p;
+};
+
+static void pop_arg(union arg *arg, int type, va_list *ap)
+{
+ switch (type) {
+ case PTR: arg->p = va_arg(*ap, void *);
+ break; case INT: arg->i = va_arg(*ap, int);
+ break; case UINT: arg->i = va_arg(*ap, unsigned int);
+ break; case LONG: arg->i = va_arg(*ap, long);
+ break; case ULONG: arg->i = va_arg(*ap, unsigned long);
+ break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
+ break; case SHORT: arg->i = (short)va_arg(*ap, int);
+ break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
+ break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
+ break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
+ break; case LLONG: arg->i = va_arg(*ap, long long);
+ break; case SIZET: arg->i = va_arg(*ap, size_t);
+ break; case IMAX: arg->i = va_arg(*ap, intmax_t);
+ break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
+ break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
+ break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
+#if defined(__wasilibc_printscan_no_floating_point)
+ break; case DBL:
+ break; case LDBL: floating_point_not_supported();
+#else
+ break; case DBL: arg->f = va_arg(*ap, double);
+#if defined(__wasilibc_printscan_no_long_double)
+ break; case LDBL: long_double_not_supported();
+#else
+ break; case LDBL: arg->f = va_arg(*ap, long double);
+#endif
+#endif
+ }
+}
+
+static void out(FILE *f, const wchar_t *s, size_t l)
+{
+ while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f);
+}
+
+static int getint(wchar_t **s) {
+ int i;
+ for (i=0; iswdigit(**s); (*s)++) {
+ if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
+ else i = 10*i + (**s-'0');
+ }
+ return i;
+}
+
+static const char sizeprefix['y'-'a'] = {
+['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
+['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
+['p'-'a']='j'
+};
+
+static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
+{
+ wchar_t *a, *z, *s=(wchar_t *)fmt;
+ unsigned l10n=0, fl;
+ int w, p, xp;
+ union arg arg;
+ int argpos;
+ unsigned st, ps;
+ int cnt=0, l=0;
+ int i;
+ int t;
+ char *bs;
+ char charfmt[16];
+ wchar_t wc;
+
+ for (;;) {
+ /* This error is only specified for snprintf, but since it's
+ * unspecified for other forms, do the same. Stop immediately
+ * on overflow; otherwise %n could produce wrong results. */
+ if (l > INT_MAX - cnt) goto overflow;
+
+ /* Update output count, end loop when fmt is exhausted */
+ cnt += l;
+ if (!*s) break;
+
+ /* Handle literal text and %% format specifiers */
+ for (a=s; *s && *s!='%'; s++);
+ for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
+ if (z-a > INT_MAX-cnt) goto overflow;
+ l = z-a;
+ if (f) out(f, a, l);
+ if (l) continue;
+
+ if (iswdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ argpos = s[1]-'0';
+ s+=3;
+ } else {
+ argpos = -1;
+ s++;
+ }
+
+ /* Read modifier flags */
+ for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
+ fl |= 1U<<*s-' ';
+
+ /* Read field width */
+ if (*s=='*') {
+ if (iswdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ nl_type[s[1]-'0'] = INT;
+ w = nl_arg[s[1]-'0'].i;
+ s+=3;
+ } else if (!l10n) {
+ w = f ? va_arg(*ap, int) : 0;
+ s++;
+ } else goto inval;
+ if (w<0) fl|=LEFT_ADJ, w=-w;
+ } else if ((w=getint(&s))<0) goto overflow;
+
+ /* Read precision */
+ if (*s=='.' && s[1]=='*') {
+ if (isdigit(s[2]) && s[3]=='$') {
+ nl_type[s[2]-'0'] = INT;
+ p = nl_arg[s[2]-'0'].i;
+ s+=4;
+ } else if (!l10n) {
+ p = f ? va_arg(*ap, int) : 0;
+ s+=2;
+ } else goto inval;
+ xp = (p>=0);
+ } else if (*s=='.') {
+ s++;
+ p = getint(&s);
+ xp = 1;
+ } else {
+ p = -1;
+ xp = 0;
+ }
+
+ /* Format specifier state machine */
+ st=0;
+ do {
+ if (OOB(*s)) goto inval;
+ ps=st;
+ st=states[st]S(*s++);
+ } while (st-1<STOP);
+ if (!st) goto inval;
+
+ /* Check validity of argument type (nl/normal) */
+ if (st==NOARG) {
+ if (argpos>=0) goto inval;
+ } else {
+ if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
+ else if (f) pop_arg(&arg, st, ap);
+ else return 0;
+ }
+
+ if (!f) continue;
+ t = s[-1];
+ if (ps && (t&15)==3) t&=~32;
+
+ switch (t) {
+ case 'n':
+ switch(ps) {
+ case BARE: *(int *)arg.p = cnt; break;
+ case LPRE: *(long *)arg.p = cnt; break;
+ case LLPRE: *(long long *)arg.p = cnt; break;
+ case HPRE: *(unsigned short *)arg.p = cnt; break;
+ case HHPRE: *(unsigned char *)arg.p = cnt; break;
+ case ZTPRE: *(size_t *)arg.p = cnt; break;
+ case JPRE: *(uintmax_t *)arg.p = cnt; break;
+ }
+ continue;
+ case 'c':
+ if (w<1) w=1;
+ if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
+ fputwc(btowc(arg.i), f);
+ if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
+ l = w;
+ continue;
+ case 'C':
+ fputwc(arg.i, f);
+ l = 1;
+ continue;
+ case 'S':
+ a = arg.p;
+ z = a + wcsnlen(a, p<0 ? INT_MAX : p);
+ if (p<0 && *z) goto overflow;
+ p = z-a;
+ if (w<p) w=p;
+ if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ out(f, a, p);
+ if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ l=w;
+ continue;
+ case 'm':
+ arg.p = strerror(errno);
+ case 's':
+ if (!arg.p) arg.p = "(null)";
+ bs = arg.p;
+ for (i=l=0; l<(p<0?INT_MAX:p) && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
+ if (i<0) return -1;
+ if (p<0 && *bs) goto overflow;
+ p=l;
+ if (w<p) w=p;
+ if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ bs = arg.p;
+ while (l--) {
+ i=mbtowc(&wc, bs, MB_LEN_MAX);
+ bs+=i;
+ fputwc(wc, f);
+ }
+ if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+ l=w;
+ continue;
+ }
+
+ if (xp && p<0) goto overflow;
+#if defined(__wasilibc_printscan_no_long_double)
+ // Omit the 'L' modifier for floating-point cases.
+ switch (t|32) {
+ case 'a': case 'e': case 'f': case 'g':
+ snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c",
+ "#"+!(fl & ALT_FORM),
+ "+"+!(fl & MARK_POS),
+ "-"+!(fl & LEFT_ADJ),
+ " "+!(fl & PAD_POS),
+ "0"+!(fl & ZERO_PAD),
+ t);
+
+ l = fprintf(f, charfmt, w, p, arg.f);
+ break;
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
+ snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
+ "#"+!(fl & ALT_FORM),
+ "+"+!(fl & MARK_POS),
+ "-"+!(fl & LEFT_ADJ),
+ " "+!(fl & PAD_POS),
+ "0"+!(fl & ZERO_PAD),
+ sizeprefix[(t|32)-'a'], t);
+
+ l = fprintf(f, charfmt, w, p, arg.i);
+ break;
+ }
+#else
+ snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
+ "#"+!(fl & ALT_FORM),
+ "+"+!(fl & MARK_POS),
+ "-"+!(fl & LEFT_ADJ),
+ " "+!(fl & PAD_POS),
+ "0"+!(fl & ZERO_PAD),
+ sizeprefix[(t|32)-'a'], t);
+
+ switch (t|32) {
+#if !defined(__wasilibc_printscan_no_floating_point)
+ case 'a': case 'e': case 'f': case 'g':
+ l = fprintf(f, charfmt, w, p, arg.f);
+ break;
+#endif
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
+ l = fprintf(f, charfmt, w, p, arg.i);
+ break;
+ }
+#endif
+ }
+
+ if (f) return cnt;
+ if (!l10n) return 0;
+
+ for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
+ pop_arg(nl_arg+i, nl_type[i], ap);
+ for (; i<=NL_ARGMAX && !nl_type[i]; i++);
+ if (i<=NL_ARGMAX) return -1;
+ return 1;
+
+inval:
+ errno = EINVAL;
+ return -1;
+overflow:
+ errno = EOVERFLOW;
+ return -1;
+}
+
+int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
+{
+ va_list ap2;
+ int nl_type[NL_ARGMAX] = {0};
+ union arg nl_arg[NL_ARGMAX];
+ int olderr;
+ int ret;
+
+ /* the copy allows passing va_list* even if va_list is an array */
+ va_copy(ap2, ap);
+ if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
+ va_end(ap2);
+ return -1;
+ }
+
+ FLOCK(f);
+ fwide(f, 1);
+ olderr = f->flags & F_ERR;
+ f->flags &= ~F_ERR;
+ ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
+ if (f->flags & F_ERR) ret = -1;
+ f->flags |= olderr;
+ FUNLOCK(f);
+ va_end(ap2);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/vfwscanf.c b/libc-top-half/musl/src/stdio/vfwscanf.c
new file mode 100644
index 0000000..82f4860
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vfwscanf.c
@@ -0,0 +1,332 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <limits.h>
+#include <string.h>
+
+#include "stdio_impl.h"
+#include "shgetc.h"
+#include "intscan.h"
+#include "floatscan.h"
+
+#define SIZE_hh -2
+#define SIZE_h -1
+#define SIZE_def 0
+#define SIZE_l 1
+#define SIZE_L 2
+#define SIZE_ll 3
+
+static void store_int(void *dest, int size, unsigned long long i)
+{
+ if (!dest) return;
+ switch (size) {
+ case SIZE_hh:
+ *(char *)dest = i;
+ break;
+ case SIZE_h:
+ *(short *)dest = i;
+ break;
+ case SIZE_def:
+ *(int *)dest = i;
+ break;
+ case SIZE_l:
+ *(long *)dest = i;
+ break;
+ case SIZE_ll:
+ *(long long *)dest = i;
+ break;
+ }
+}
+
+static void *arg_n(va_list ap, unsigned int n)
+{
+ void *p;
+ unsigned int i;
+ va_list ap2;
+ va_copy(ap2, ap);
+ for (i=n; i>1; i--) va_arg(ap2, void *);
+ p = va_arg(ap2, void *);
+ va_end(ap2);
+ return p;
+}
+
+static int in_set(const wchar_t *set, int c)
+{
+ int j;
+ const wchar_t *p = set;
+ if (*p == '-') {
+ if (c=='-') return 1;
+ p++;
+ } else if (*p == ']') {
+ if (c==']') return 1;
+ p++;
+ }
+ for (; *p && *p != ']'; p++) {
+ if (*p=='-' && p[1] && p[1] != ']')
+ for (j=p++[-1]; j<*p; j++)
+ if (c==j) return 1;
+ if (c==*p) return 1;
+ }
+ return 0;
+}
+
+#if 1
+#undef getwc
+#define getwc(f) \
+ ((f)->rpos != (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f))
+
+#undef ungetwc
+#define ungetwc(c,f) \
+ ((f)->rend && (c)<128U ? *--(f)->rpos : ungetwc((c),(f)))
+#endif
+
+int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
+{
+ int width;
+ int size;
+ int alloc;
+ const wchar_t *p;
+ int c, t;
+ char *s;
+ wchar_t *wcs;
+ void *dest=NULL;
+ int invert;
+ int matches=0;
+ off_t pos = 0, cnt;
+ static const char size_pfx[][3] = { "hh", "h", "", "l", "L", "ll" };
+ char tmp[3*sizeof(int)+10];
+ const wchar_t *set;
+ size_t i, k;
+
+ FLOCK(f);
+
+ fwide(f, 1);
+
+ for (p=fmt; *p; p++) {
+
+ alloc = 0;
+
+ if (iswspace(*p)) {
+ while (iswspace(p[1])) p++;
+ while (iswspace((c=getwc(f)))) pos++;
+ ungetwc(c, f);
+ continue;
+ }
+ if (*p != '%' || p[1] == '%') {
+ if (*p == '%') {
+ p++;
+ while (iswspace((c=getwc(f)))) pos++;
+ } else {
+ c = getwc(f);
+ }
+ if (c!=*p) {
+ ungetwc(c, f);
+ if (c<0) goto input_fail;
+ goto match_fail;
+ }
+ pos++;
+ continue;
+ }
+
+ p++;
+ if (*p=='*') {
+ dest = 0; p++;
+ } else if (iswdigit(*p) && p[1]=='$') {
+ dest = arg_n(ap, *p-'0'); p+=2;
+ } else {
+ dest = va_arg(ap, void *);
+ }
+
+ for (width=0; iswdigit(*p); p++) {
+ width = 10*width + *p - '0';
+ }
+
+ if (*p=='m') {
+ wcs = 0;
+ s = 0;
+ alloc = !!dest;
+ p++;
+ } else {
+ alloc = 0;
+ }
+
+ size = SIZE_def;
+ switch (*p++) {
+ case 'h':
+ if (*p == 'h') p++, size = SIZE_hh;
+ else size = SIZE_h;
+ break;
+ case 'l':
+ if (*p == 'l') p++, size = SIZE_ll;
+ else size = SIZE_l;
+ break;
+ case 'j':
+ size = SIZE_ll;
+ break;
+ case 'z':
+ case 't':
+ size = SIZE_l;
+ break;
+ case 'L':
+ size = SIZE_L;
+ break;
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 's': case 'c': case '[':
+ case 'S': case 'C':
+ case 'p': case 'n':
+ p--;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ t = *p;
+
+ /* Transform S,C -> ls,lc */
+ if ((t&0x2f)==3) {
+ size = SIZE_l;
+ t |= 32;
+ }
+
+ if (t != 'n') {
+ if (t != '[' && (t|32) != 'c')
+ while (iswspace((c=getwc(f)))) pos++;
+ else
+ c=getwc(f);
+ if (c < 0) goto input_fail;
+ ungetwc(c, f);
+ }
+
+ switch (t) {
+ case 'n':
+ store_int(dest, size, pos);
+ /* do not increment match count, etc! */
+ continue;
+
+ case 's':
+ case 'c':
+ case '[':
+ if (t == 'c') {
+ if (width<1) width = 1;
+ invert = 1;
+ set = L"";
+ } else if (t == 's') {
+ invert = 1;
+ static const wchar_t spaces[] = {
+ ' ', '\t', '\n', '\r', 11, 12, 0x0085,
+ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
+ 0x2006, 0x2008, 0x2009, 0x200a,
+ 0x2028, 0x2029, 0x205f, 0x3000, 0 };
+ set = spaces;
+ } else {
+ if (*++p == '^') p++, invert = 1;
+ else invert = 0;
+ set = p;
+ if (*p==']') p++;
+ while (*p!=']') {
+ if (!*p) goto fmt_fail;
+ p++;
+ }
+ }
+
+ s = (size == SIZE_def) ? dest : 0;
+ wcs = (size == SIZE_l) ? dest : 0;
+
+ int gotmatch = 0;
+
+ if (width < 1) width = -1;
+
+ i = 0;
+ if (alloc) {
+ k = t=='c' ? width+1U : 31;
+ if (size == SIZE_l) {
+ wcs = malloc(k*sizeof(wchar_t));
+ if (!wcs) goto alloc_fail;
+ } else {
+ s = malloc(k);
+ if (!s) goto alloc_fail;
+ }
+ }
+ while (width) {
+ if ((c=getwc(f))<0) break;
+ if (in_set(set, c) == invert)
+ break;
+ if (wcs) {
+ wcs[i++] = c;
+ if (alloc && i==k) {
+ k += k+1;
+ wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
+ if (!tmp) goto alloc_fail;
+ wcs = tmp;
+ }
+ } else if (size != SIZE_l) {
+ int l = wctomb(s?s+i:tmp, c);
+ if (l<0) goto input_fail;
+ i += l;
+ if (alloc && i > k-4) {
+ k += k+1;
+ char *tmp = realloc(s, k);
+ if (!tmp) goto alloc_fail;
+ s = tmp;
+ }
+ }
+ pos++;
+ width-=(width>0);
+ gotmatch=1;
+ }
+ if (width) {
+ ungetwc(c, f);
+ if (t == 'c' || !gotmatch) goto match_fail;
+ }
+
+ if (alloc) {
+ if (size == SIZE_l) *(wchar_t **)dest = wcs;
+ else *(char **)dest = s;
+ }
+ if (t != 'c') {
+ if (wcs) wcs[i] = 0;
+ if (s) s[i] = 0;
+ }
+ break;
+
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 'p':
+ if (width < 1) width = 0;
+ snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln",
+ 1+!dest, "%*", width, size_pfx[size+2], t);
+ cnt = 0;
+ if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1)
+ goto input_fail;
+ else if (!cnt)
+ goto match_fail;
+ pos += cnt;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ if (dest) matches++;
+ }
+ if (0) {
+fmt_fail:
+alloc_fail:
+input_fail:
+ if (!matches) matches--;
+match_fail:
+ if (alloc) {
+ free(s);
+ free(wcs);
+ }
+ }
+ FUNLOCK(f);
+ return matches;
+}
+
+weak_alias(vfwscanf,__isoc99_vfwscanf);
diff --git a/libc-top-half/musl/src/stdio/vprintf.c b/libc-top-half/musl/src/stdio/vprintf.c
new file mode 100644
index 0000000..30d2bff
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vprintf.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int vprintf(const char *restrict fmt, va_list ap)
+{
+ return vfprintf(stdout, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vscanf.c b/libc-top-half/musl/src/stdio/vscanf.c
new file mode 100644
index 0000000..9d46ab0
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vscanf.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int vscanf(const char *restrict fmt, va_list ap)
+{
+ return vfscanf(stdin, fmt, ap);
+}
+
+weak_alias(vscanf,__isoc99_vscanf);
diff --git a/libc-top-half/musl/src/stdio/vsnprintf.c b/libc-top-half/musl/src/stdio/vsnprintf.c
new file mode 100644
index 0000000..08989d6
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vsnprintf.c
@@ -0,0 +1,57 @@
+#include "stdio_impl.h"
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+struct cookie {
+ char *s;
+ size_t n;
+};
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
+{
+ struct cookie *c = f->cookie;
+ size_t k = MIN(c->n, f->wpos - f->wbase);
+ if (k) {
+ memcpy(c->s, f->wbase, k);
+ c->s += k;
+ c->n -= k;
+ }
+ k = MIN(c->n, l);
+ if (k) {
+ memcpy(c->s, s, k);
+ c->s += k;
+ c->n -= k;
+ }
+ *c->s = 0;
+ f->wpos = f->wbase = f->buf;
+ /* pretend to succeed, even if we discarded extra data */
+ return l;
+}
+
+int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
+{
+ unsigned char buf[1];
+ char dummy[1];
+ struct cookie c = { .s = n ? s : dummy, .n = n ? n-1 : 0 };
+ FILE f = {
+ .lbf = EOF,
+ .write = sn_write,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1,
+#endif
+ .buf = buf,
+ .cookie = &c,
+ };
+
+ if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ *c.s = 0;
+ return vfprintf(&f, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vsprintf.c b/libc-top-half/musl/src/stdio/vsprintf.c
new file mode 100644
index 0000000..c57349d
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vsprintf.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <limits.h>
+
+int vsprintf(char *restrict s, const char *restrict fmt, va_list ap)
+{
+ return vsnprintf(s, INT_MAX, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vsscanf.c b/libc-top-half/musl/src/stdio/vsscanf.c
new file mode 100644
index 0000000..0e5b482
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vsscanf.c
@@ -0,0 +1,31 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+static size_t string_read(FILE *f, unsigned char *buf, size_t len)
+{
+ char *src = f->cookie;
+ size_t k = len+256;
+ char *end = memchr(src, 0, k);
+ if (end) k = end-src;
+ if (k < len) len = k;
+ memcpy(buf, src, len);
+ f->rpos = (void *)(src+len);
+ f->rend = (void *)(src+k);
+ f->cookie = src+k;
+ return len;
+}
+
+int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap)
+{
+ FILE f = {
+ .buf = (void *)s, .cookie = (void *)s,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .read = string_read, .lock = -1
+#else
+ .read = string_read
+#endif
+ };
+ return vfscanf(&f, fmt, ap);
+}
+
+weak_alias(vsscanf,__isoc99_vsscanf);
diff --git a/libc-top-half/musl/src/stdio/vswprintf.c b/libc-top-half/musl/src/stdio/vswprintf.c
new file mode 100644
index 0000000..bf9bcaf
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vswprintf.c
@@ -0,0 +1,62 @@
+#include "stdio_impl.h"
+#include <limits.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+struct cookie {
+ wchar_t *ws;
+ size_t l;
+};
+
+static size_t sw_write(FILE *f, const unsigned char *s, size_t l)
+{
+ size_t l0 = l;
+ int i = 0;
+ struct cookie *c = f->cookie;
+ if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1)
+ return -1;
+ while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) {
+ s+=i;
+ l-=i;
+ c->l--;
+ c->ws++;
+ }
+ *c->ws = 0;
+ if (i < 0) {
+ f->wpos = f->wbase = f->wend = 0;
+ f->flags |= F_ERR;
+ return i;
+ }
+ f->wend = f->buf + f->buf_size;
+ f->wpos = f->wbase = f->buf;
+ return l0;
+}
+
+int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap)
+{
+ int r;
+ unsigned char buf[256];
+ struct cookie c = { s, n-1 };
+ FILE f = {
+ .lbf = EOF,
+ .write = sw_write,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .lock = -1,
+#endif
+ .buf = buf,
+ .buf_size = sizeof buf,
+ .cookie = &c,
+ };
+
+ if (!n) {
+ return -1;
+ } else if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ r = vfwprintf(&f, fmt, ap);
+ sw_write(&f, 0, 0);
+ return r>=n ? -1 : r;
+}
diff --git a/libc-top-half/musl/src/stdio/vswscanf.c b/libc-top-half/musl/src/stdio/vswscanf.c
new file mode 100644
index 0000000..ea82710
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vswscanf.c
@@ -0,0 +1,42 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+static size_t wstring_read(FILE *f, unsigned char *buf, size_t len)
+{
+ const wchar_t *src = f->cookie;
+ size_t k;
+
+ if (!src) return 0;
+
+ k = wcsrtombs((void *)f->buf, &src, f->buf_size, 0);
+ if (k==(size_t)-1) {
+ f->rpos = f->rend = 0;
+ return 0;
+ }
+
+ f->rpos = f->buf;
+ f->rend = f->buf + k;
+ f->cookie = (void *)src;
+
+ if (!len || !k) return 0;
+
+ *buf = *f->rpos++;
+ return 1;
+}
+
+int vswscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, va_list ap)
+{
+ unsigned char buf[256];
+ FILE f = {
+ .buf = buf, .buf_size = sizeof buf,
+ .cookie = (void *)s,
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ .read = wstring_read, .lock = -1
+#else
+ .read = wstring_read
+#endif
+ };
+ return vfwscanf(&f, fmt, ap);
+}
+
+weak_alias(vswscanf,__isoc99_vswscanf);
diff --git a/libc-top-half/musl/src/stdio/vwprintf.c b/libc-top-half/musl/src/stdio/vwprintf.c
new file mode 100644
index 0000000..eeeecdc
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vwprintf.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <wchar.h>
+
+int vwprintf(const wchar_t *restrict fmt, va_list ap)
+{
+ return vfwprintf(stdout, fmt, ap);
+}
diff --git a/libc-top-half/musl/src/stdio/vwscanf.c b/libc-top-half/musl/src/stdio/vwscanf.c
new file mode 100644
index 0000000..5a3931e
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/vwscanf.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int vwscanf(const wchar_t *restrict fmt, va_list ap)
+{
+ return vfwscanf(stdin, fmt, ap);
+}
+
+weak_alias(vwscanf,__isoc99_vwscanf);
diff --git a/libc-top-half/musl/src/stdio/wprintf.c b/libc-top-half/musl/src/stdio/wprintf.c
new file mode 100644
index 0000000..342cd97
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/wprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int wprintf(const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vwprintf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/stdio/wscanf.c b/libc-top-half/musl/src/stdio/wscanf.c
new file mode 100644
index 0000000..4dfec25
--- /dev/null
+++ b/libc-top-half/musl/src/stdio/wscanf.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int wscanf(const wchar_t *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vwscanf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(wscanf,__isoc99_wscanf);