diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
commit | 8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch) | |
tree | df55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-top-half/musl/src/stdio | |
parent | Initial commit. (diff) | |
download | wasi-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')
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); |