diff options
Diffstat (limited to 'lib/libc/stdio')
44 files changed, 568 insertions, 623 deletions
diff --git a/lib/libc/stdio/Kbuild b/lib/libc/stdio/Kbuild index 36339313..0d1df566 100644 --- a/lib/libc/stdio/Kbuild +++ b/lib/libc/stdio/Kbuild @@ -1,33 +1,50 @@ obj-y += asprintf.o obj-y += clearerr.o +obj-y += clearerr_unlocked.o obj-y += dprintf.o obj-y += dtoa.o obj-y += fclose.o obj-y += fdopen.o obj-y += feof.o +obj-y += feof_unlocked.o obj-y += ferror.o +obj-y += ferror_unlocked.o obj-y += fflush.o +obj-y += fflush_unlocked.o obj-y += fgetc.o +obj-y += fgetc_unlocked.o obj-y += fgets.o +obj-y += fgets_unlocked.o obj-y += fileno.o +obj-y += fileno_unlocked.o +obj-y += flockfile.o obj-y += fmemopen.o obj-y += fopen.o obj-y += fprintf.o obj-y += fputc.o +obj-y += fputc_unlocked.o obj-y += fputs.o +obj-y += fputs_unlocked.o obj-y += fread.o +obj-y += fread_unlocked.o obj-y += fseek.o obj-y += ftell.o obj-y += ftello.o +obj-y += ftrylockfile.o +obj-y += funlockfile.o obj-y += fwrite.o +obj-y += fwrite_unlocked.o obj-y += getc.o +obj-y += getc_unlocked.o obj-y += getchar.o +obj-y += getchar_unlocked.o obj-y += pclose.o obj-y += perror.o obj-y += popen.o obj-y += printf.o obj-y += putc.o obj-y += putchar.o +obj-y += putchar_unlocked.o obj-y += puts.o obj-y += remove.o obj-y += rename.o @@ -37,9 +54,6 @@ obj-y += setbuf.o obj-y += setvbuf.o obj-y += snprintf.o obj-y += sprintf.o -obj-y += stderr.o -obj-y += stdin.o -obj-y += stdout.o obj-y += vasprintf.o obj-y += vdprintf.o obj-y += vfprintf.o diff --git a/lib/libc/stdio/clearerr.c b/lib/libc/stdio/clearerr.c index 02244466..8389a085 100644 --- a/lib/libc/stdio/clearerr.c +++ b/lib/libc/stdio/clearerr.c @@ -1,14 +1,9 @@ -#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR -#include "stddef.h" // for NULL - -#include <stdio.h> // for FILE, clearerr +#include <__stdio.h> +#include <stdio.h> void clearerr(FILE *stream) { - struct __FILE *stream_impl = __FILE(stream); - - if (stream == NULL) - return; - - stream_impl->flags &= ~(_IO_ERR | _IO_EOF); + flockfile(stream); + clearerr_unlocked(stream); + funlockfile(stream); } diff --git a/lib/libc/stdio/clearerr_unlocked.c b/lib/libc/stdio/clearerr_unlocked.c new file mode 100644 index 00000000..da4ea106 --- /dev/null +++ b/lib/libc/stdio/clearerr_unlocked.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <stdio.h> + +void clearerr_unlocked(FILE *stream) +{ + if (stream != NULL) + stream->flags &= ~(_IO_ERR | _IO_EOF); +} diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 4534715b..4fdf6495 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -8,7 +8,7 @@ int fclose(FILE *stream) return -1; if (stream != stdin && stream != stdout && stream != stderr) { - if (close((__FILE(stream))->fd) == -1) + if (close(fileno(stream)) == -1) return -1; } diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c index bded5f27..dc9da567 100644 --- a/lib/libc/stdio/fdopen.c +++ b/lib/libc/stdio/fdopen.c @@ -4,33 +4,30 @@ #include <sys/cdefs.h> #include <unistd.h> // for lseek, off_t -__weak void __stdio_cleanup(void) -{ -} - FILE *fdopen(int fildes, const char *mode) { - FILE *stream; + struct __FILE *stream; if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) { return NULL; } - stream = calloc(1, sizeof(FILE)); + stream = calloc(1, sizeof(struct __FILE)); if (stream == NULL) return NULL; - __FILE(stream)->fd = fildes; - atomic_flag_clear(&__FILE(stream)->lock); + stream->fd = fildes; + atomic_flag_clear(&stream->lock); + if (mode[0] == 'r') { - __FILE(stream)->type = _IONBF; + stream->type = _IONBF; } else if (mode[0] == 'w') { - __FILE(stream)->type = _IOLBF; + stream->type = _IOLBF; } else if (mode[0] == 'a') { - __FILE(stream)->type = _IONBF; - - off_t offset = lseek(fildes, 0, SEEK_END); - if (offset == (off_t)-1) { + off_t off; + stream->type = _IONBF; + off = lseek(fildes, 0, SEEK_END); + if (off == (off_t)-1) { free(stream); return NULL; } diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c index f9245d06..6a36172b 100644 --- a/lib/libc/stdio/feof.c +++ b/lib/libc/stdio/feof.c @@ -1,12 +1,13 @@ -#include "stddef.h" // for NULL - -#include <__stdio.h> // for __FILE -#include <stdio.h> // for FILE, feof +#include <__stdio.h> +#include <stdio.h> int feof(FILE *stream) { - if (stream == NULL) - return 0; + int r; + + flockfile(stream); + r = feof_unlocked(stream); + funlockfile(stream); - return (__FILE(stream))->eof; + return r; } diff --git a/lib/libc/stdio/feof_unlocked.c b/lib/libc/stdio/feof_unlocked.c new file mode 100644 index 00000000..4d7d9d53 --- /dev/null +++ b/lib/libc/stdio/feof_unlocked.c @@ -0,0 +1,7 @@ +#include <__stdio.h> +#include <stdio.h> + +int feof_unlocked(FILE *stream) +{ + return (stream) ? stream->eof : 0; +} diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c index 5e4b8dc4..9391a44a 100644 --- a/lib/libc/stdio/ferror.c +++ b/lib/libc/stdio/ferror.c @@ -1,12 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_ERR -#include "stddef.h" // for NULL - -#include <stdio.h> // for FILE, ferror +#include <stdio.h> int ferror(FILE *stream) { - if (stream == NULL) - return 0; + int r; + + flockfile(stream); + r = ferror_unlocked(stream); + funlockfile(stream); - return (__FILE(stream)->flags & _IO_ERR) != 0; + return r; } diff --git a/lib/libc/stdio/ferror_unlocked.c b/lib/libc/stdio/ferror_unlocked.c new file mode 100644 index 00000000..3c622dd9 --- /dev/null +++ b/lib/libc/stdio/ferror_unlocked.c @@ -0,0 +1,7 @@ +#include <__stdio.h> +#include <stdio.h> + +int ferror_unlocked(FILE *stream) +{ + return (stream) ? (stream->flags & _IO_ERR) != 0 : 0; +} diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index 1cf4b7bd..b3fca8bd 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -3,74 +3,15 @@ #include <atomic.h> // for LIBC_UNLOCK, LIBC_LOCK #include <errno.h> // for errno, EBADF, EIO -#include <fcntl.h> // for O_ACCMODE, O_RDONLY -#include <stdio.h> // for EOF, FILE, fflush -#include <string.h> // for memmove -#include <unistd.h> // for size_t, write, ssize_t +#include <stdio.h> -int fflush(FILE *stream) +int fflush(struct __FILE *stream) { - if (stream == NULL) { - // TODO: Implement flushing all open streams - // For now, just return success - return 0; - } + int r; - if (__FILE(stream)->buf_len == 0) { - return 0; - } + flockfile(stream); + r = fflush_unlocked(stream); + funlockfile(stream); - if (__FILE(stream)->fd == -1) { - __FILE(stream)->buf_len = 0; - return 0; - } - - if (__FILE(stream)->flags & _IO_ERR) { - errno = EIO; - return EOF; - } - - if ((__FILE(stream)->flags & O_ACCMODE) == O_RDONLY) { - errno = EBADF; - return EOF; - } - - LIBC_LOCK(__FILE(stream)->lock); - - size_t bytes_to_write = __FILE(stream)->buf_len; - size_t total_written = 0; - char *buf_ptr = __FILE(stream)->buf; - - while (total_written < bytes_to_write) { - ssize_t result = write(__FILE(stream)->fd, - buf_ptr + total_written, - bytes_to_write - total_written); - - if (result < 0) { - __FILE(stream)->flags |= _IO_ERR; - LIBC_UNLOCK(__FILE(stream)->lock); - return EOF; - } - - if (result == 0) { - break; - } - - total_written += result; - } - - if (total_written == bytes_to_write) { - __FILE(stream)->buf_len = 0; - __FILE(stream)->buf_pos = 0; - } else { - size_t remaining = bytes_to_write - total_written; - memmove(__FILE(stream)->buf, - __FILE(stream)->buf + total_written, remaining); - __FILE(stream)->buf_len = remaining; - __FILE(stream)->buf_pos = 0; - } - - LIBC_UNLOCK(__FILE(stream)->lock); - - return (total_written == bytes_to_write) ? 0 : EOF; + return r; } diff --git a/lib/libc/stdio/fflush_unlocked.c b/lib/libc/stdio/fflush_unlocked.c new file mode 100644 index 00000000..b4ee3e43 --- /dev/null +++ b/lib/libc/stdio/fflush_unlocked.c @@ -0,0 +1,64 @@ +#include <__stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/cdefs.h> +#include <unistd.h> + +int fflush_unlocked(struct __FILE *stream) +{ + if (stream == NULL) { + // TODO: flush all streams + return 0; + } + + if (__predict_false(stream->fd) == -1) { + stream->buf_len = 0; + return 0; + } + + if (__predict_false(stream->buf == 0)) { + return 0; + } + + if (stream->flags & _IO_ERR) { + errno = EIO; + return EOF; + } + + if ((stream->flags & O_ACCMODE) == O_RDONLY) { + errno = EBADF; + return EOF; + } + + size_t bytes_to_write = stream->buf_len; + size_t total_written = 0; + char *buf_ptr = stream->buf; + + while (total_written < bytes_to_write) { + ssize_t result = write(stream->fd, buf_ptr + total_written, bytes_to_write - total_written); + + if (result < 0) { + stream->flags |= _IO_ERR; + return EOF; + } + + if (result == 0) { + break; + } + + total_written += result; + } + + if (total_written == bytes_to_write) { + stream->buf_len = 0; + stream->buf_pos = 0; + } else { + size_t remaining = bytes_to_write - total_written; + memmove(stream->buf, stream->buf + total_written, remaining); + stream->buf_len = remaining; + stream->buf_pos = 0; + } + + return (total_written == bytes_to_write) ? 0 : EOF; +} diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c index a7612f42..f0642c30 100644 --- a/lib/libc/stdio/fgetc.c +++ b/lib/libc/stdio/fgetc.c @@ -1,11 +1,12 @@ -#include <stdio.h> // for fread, FILE, fgetc +#include <stdio.h> int fgetc(FILE *stream) { - int c; + int r; - if (fread(&c, 1, 1, stream) < 0) - return -1; + flockfile(stream); + r = fgetc_unlocked(stream); + funlockfile(stream); - return c; + return r; } diff --git a/lib/libc/stdio/fgetc_unlocked.c b/lib/libc/stdio/fgetc_unlocked.c new file mode 100644 index 00000000..5cccfd87 --- /dev/null +++ b/lib/libc/stdio/fgetc_unlocked.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +int fgetc_unlocked(FILE *stream) +{ + int c; + + if (fread_unlocked(&c, 1, 1, stream) < 0) + return -1; + + return c; +} diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c index adeae1b4..d0f7d2d9 100644 --- a/lib/libc/stdio/fgets.c +++ b/lib/libc/stdio/fgets.c @@ -1,11 +1,12 @@ -#include "stddef.h" // for NULL - -#include <libc.h> // for weak_reference -#include <stdio.h> // for fread, FILE, fgets +#include <stdio.h> char *fgets(char *restrict s, int n, FILE *restrict stream) { - return fread(s, 1, n, stream) ? s : NULL; -} + char *r; -weak_reference(fgets, fgets_unlocked); + flockfile(stream); + r = fgets_unlocked(s, n, stream); + funlockfile(stream); + + return r; +} diff --git a/lib/libc/stdio/fgets_unlocked.c b/lib/libc/stdio/fgets_unlocked.c new file mode 100644 index 00000000..9e2dca60 --- /dev/null +++ b/lib/libc/stdio/fgets_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +char *fgets_unlocked(char *s, int n, FILE *stream) +{ + return fread_unlocked(s, 1, n, stream) ? s : NULL; +} diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c index e27b56de..4fa47eb4 100644 --- a/lib/libc/stdio/fileno.c +++ b/lib/libc/stdio/fileno.c @@ -1,20 +1,12 @@ -#include <__stdio.h> // for __FILE -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <errno.h> // for EBADF, errno -#include <stdio.h> // for FILE, fileno +#include <stdio.h> int fileno(FILE *stream) { - int fd; + int r; - LIBC_LOCK(__FILE(stream)->lock); - fd = __FILE(stream)->fd; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fileno_unlocked(stream); + funlockfile(stream); - if (fd < 0) { - errno = EBADF; - return -1; - } - - return fd; + return r; } diff --git a/lib/libc/stdio/fileno_unlocked.c b/lib/libc/stdio/fileno_unlocked.c new file mode 100644 index 00000000..a3490686 --- /dev/null +++ b/lib/libc/stdio/fileno_unlocked.c @@ -0,0 +1,13 @@ +#include <__stdio.h> +#include <errno.h> +#include <stdio.h> + +int fileno_unlocked(FILE *stream) +{ + if (stream->fd < 0) { + errno = EBADF; + return -1; + } + + return stream->fd; +} diff --git a/lib/libc/stdio/flockfile.c b/lib/libc/stdio/flockfile.c new file mode 100644 index 00000000..788750b0 --- /dev/null +++ b/lib/libc/stdio/flockfile.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +void flockfile(FILE *file) +{ + LIBC_LOCK(file->lock); +} diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c index e1b2ccff..1e90b5ea 100644 --- a/lib/libc/stdio/fmemopen.c +++ b/lib/libc/stdio/fmemopen.c @@ -21,10 +21,10 @@ FILE *fmemopen(void *restrict buf, size_t max_size, const char *restrict mode) if (stream == NULL) return stream; - __FILE(stream)->fd = -1; - __FILE(stream)->buf = buf; - __FILE(stream)->buf_size = max_size; - __FILE(stream)->type = _IOFBF; + stream->fd = -1; + stream->buf = buf; + stream->buf_size = max_size; + stream->type = _IOFBF; if (mode[0] == 'r') { flags = O_RDONLY; @@ -42,7 +42,7 @@ FILE *fmemopen(void *restrict buf, size_t max_size, const char *restrict mode) flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; } - __FILE(stream)->flags = flags; + stream->flags = flags; __libc_fadd(stream); diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c index 5415e711..0265694a 100644 --- a/lib/libc/stdio/fopen.c +++ b/lib/libc/stdio/fopen.c @@ -8,10 +8,6 @@ #include <sys/cdefs.h> #include <unistd.h> // for close -__weak void __stdio_cleanup(void) -{ -} - FILE *fopen(const char *restrict pathname, const char *restrict mode) { int fd, flags, _mode; @@ -42,15 +38,15 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) if (stream == NULL) return NULL; - __FILE(stream)->fd = fd; - __FILE(stream)->buf_size = BUFSIZ; - __FILE(stream)->flags = flags; - __FILE(stream)->type = _IOLBF; - atomic_flag_clear(&__FILE(stream)->lock); + stream->fd = fd; + stream->buf_size = BUFSIZ; + stream->flags = flags; + stream->type = _IOLBF; + atomic_flag_clear(&stream->lock); - __FILE(stream)->buf = malloc(BUFSIZ); + stream->buf = malloc(BUFSIZ); - if (__FILE(stream)->buf == NULL) { + if (stream->buf == NULL) { close(fd); free(stream); return NULL; diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c index 922011f2..365fbb96 100644 --- a/lib/libc/stdio/fputc.c +++ b/lib/libc/stdio/fputc.c @@ -1,25 +1,12 @@ -#include "stddef.h" // for NULL - -#include <__stdio.h> // for __FILE -#include <errno.h> // for EINVAL, errno -#include <stdio.h> // for EOF, fwrite, FILE, fputc +#include <stdio.h> int fputc(int c, FILE *stream) { - if (stream == NULL) { - errno = EINVAL; - return EOF; - } - - if ((__FILE(stream))->fd == -1 && (__FILE(stream))->buf != NULL) { - if ((__FILE(stream))->buf_len >= - (__FILE(stream))->buf_size - 1) { - return EOF; - } + int r; - (__FILE(stream))->buf[(__FILE(stream))->buf_len++] = (char)c; - return (unsigned char)c; - } + flockfile(stream); + r = fputc_unlocked(c, stream); + funlockfile(stream); - return fwrite(&c, 1, 1, stream) ? c : EOF; + return r; } diff --git a/lib/libc/stdio/fputc_unlocked.c b/lib/libc/stdio/fputc_unlocked.c new file mode 100644 index 00000000..966721e7 --- /dev/null +++ b/lib/libc/stdio/fputc_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int fputc_unlocked(int c, FILE *stream) +{ + return fwrite_unlocked(&c, 1, 1, stream) ? c : EOF; +} diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c index 2ba0d4d1..ac5261e7 100644 --- a/lib/libc/stdio/fputs.c +++ b/lib/libc/stdio/fputs.c @@ -1,7 +1,12 @@ -#include <stdio.h> // for fwrite, EOF, FILE, fputs -#include <string.h> // for strlen +#include <stdio.h> int fputs(const char *restrict s, FILE *restrict stream) { - return fwrite(s, 1, strlen(s), stream) == strlen(s) ? 0 : EOF; + int r; + + flockfile(stream); + r = fputs_unlocked(s, stream); + funlockfile(stream); + + return r; } diff --git a/lib/libc/stdio/fputs_unlocked.c b/lib/libc/stdio/fputs_unlocked.c new file mode 100644 index 00000000..aeab8d32 --- /dev/null +++ b/lib/libc/stdio/fputs_unlocked.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <string.h> + +int fputs_unlocked(const char *s, FILE *stream) +{ + size_t len = strlen(s); + + return fwrite_unlocked(s, 1, len, stream) == len ? 0 : EOF; +} diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 443b4874..bcadbbdc 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -1,54 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR +#include <stdio.h> -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <stdio.h> // for fread, BUFSIZ, FILE -#include <string.h> // for memcpy -#include <unistd.h> // for size_t, read, ssize_t - -char __stdin_buffer[BUFSIZ]; - -size_t fread(void *restrict ptr, size_t size, size_t nitems, - FILE *restrict stream) +size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) { - if (size == 0 || nitems == 0) - return 0; - - size_t total = size * nitems; - size_t bytes_read = 0; - char *p = ptr; - - LIBC_LOCK(__FILE(stream)->lock); - - while (total > 0) { - if (__FILE(stream)->buf_pos < __FILE(stream)->buf_len) { - size_t available = __FILE(stream)->buf_len - - __FILE(stream)->buf_pos; - size_t to_copy = total < available ? total : available; - - memcpy(p, __FILE(stream)->buf + __FILE(stream)->buf_pos, - to_copy); - __FILE(stream)->buf_pos += to_copy; - p += to_copy; - bytes_read += to_copy; - total -= to_copy; - continue; - } - - ssize_t ret = read(__FILE(stream)->fd, __FILE(stream)->buf, - __FILE(stream)->buf_size); - if (ret <= 0) { - if (ret < 0) - __FILE(stream)->flags |= _IO_ERR; - else - __FILE(stream)->flags |= _IO_EOF; - break; - } - - __FILE(stream)->buf_len = ret; - __FILE(stream)->buf_pos = 0; - } + size_t r; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fread_unlocked(ptr, size, nitems, stream); + funlockfile(stream); - return bytes_read / size; + return r; } diff --git a/lib/libc/stdio/fread_unlocked.c b/lib/libc/stdio/fread_unlocked.c new file mode 100644 index 00000000..4251a7ed --- /dev/null +++ b/lib/libc/stdio/fread_unlocked.c @@ -0,0 +1,47 @@ +#include "__stdio.h" // for __FILE, _IO_EOF, _IO_ERR + +#include <atomic.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +extern void __libc_init_io(void); +void *__libc_force_io_init = (void *)__libc_init_io; + +size_t fread_unlocked(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) +{ + if (size == 0 || nitems == 0) + return 0; + + size_t total = size * nitems; + size_t bytes_read = 0; + char *p = ptr; + + while (total > 0) { + if (stream->buf_pos < stream->buf_len) { + size_t available = stream->buf_len - stream->buf_pos; + size_t to_copy = total < available ? total : available; + + memcpy(p, stream->buf + stream->buf_pos, to_copy); + stream->buf_pos += to_copy; + p += to_copy; + bytes_read += to_copy; + total -= to_copy; + continue; + } + + ssize_t ret = read(stream->fd, stream->buf, stream->buf_size); + if (ret <= 0) { + if (ret < 0) + stream->flags |= _IO_ERR; + else + stream->flags |= _IO_EOF; + break; + } + + stream->buf_len = ret; + stream->buf_pos = 0; + } + + return bytes_read / size; +} diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 7a6754f7..19459e7f 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -7,24 +7,21 @@ int fseek(FILE *stream, long offset, int whence) { - if (stream == NULL || __FILE(stream)->fd < 0) + if (stream == NULL || stream->fd < 0) return -1; - LIBC_LOCK(__FILE(stream)->lock); + stream->buf_pos = 0; + stream->buf_len = 0; + stream->flags &= ~_IO_EOF; - __FILE(stream)->buf_pos = 0; - __FILE(stream)->buf_len = 0; - __FILE(stream)->flags &= ~_IO_EOF; - - off_t result = lseek(__FILE(stream)->fd, offset, whence); - - LIBC_UNLOCK(__FILE(stream)->lock); + off_t result = lseek(stream->fd, offset, whence); if (result == (off_t)-1) { - __FILE(stream)->flags |= _IO_ERR; + stream->flags |= _IO_ERR; return -1; } - __FILE(stream)->offset = result; + stream->offset = result; + return 0; } diff --git a/lib/libc/stdio/ftrylockfile.c b/lib/libc/stdio/ftrylockfile.c new file mode 100644 index 00000000..b8f89e4b --- /dev/null +++ b/lib/libc/stdio/ftrylockfile.c @@ -0,0 +1,11 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +int ftrylockfile(FILE *file) +{ + if (file == NULL) + return -1; + + return atomic_flag_test_and_set_explicit(&file->lock, memory_order_acquire) ? 1 : 0; +} diff --git a/lib/libc/stdio/funlockfile.c b/lib/libc/stdio/funlockfile.c new file mode 100644 index 00000000..9d4154c7 --- /dev/null +++ b/lib/libc/stdio/funlockfile.c @@ -0,0 +1,8 @@ +#include <__stdio.h> +#include <atomic.h> +#include <stdio.h> + +void funlockfile(FILE *file) +{ + LIBC_UNLOCK(file->lock); +} diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index c21054da..8d81c7ac 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -1,134 +1,12 @@ -#include "__stdio.h" // for __FILE, _IO_ERR -#include "stddef.h" // for NULL +#include <stdio.h> -#include <atomic.h> // for LIBC_UNLOCK, LIBC_LOCK -#include <errno.h> // for errno, EOVERFLOW, EBADF, EINVAL, EIO -#include <fcntl.h> // for O_ACCMODE, O_RDONLY -#include <stdio.h> // for fflush, fwrite, BUFSIZ, FILE, _IOFBF, _IOLBF -#include <string.h> // for memcpy, memchr -#include <unistd.h> // for size_t, ssize_t, write - -char __stdout_buffer[BUFSIZ]; -void (*__stdio_cleanup)(void); - -size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, - FILE *restrict stream) +size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) { - size_t total_bytes; - size_t written = 0; - const char *data = (const char *)ptr; - - if (ptr == NULL || stream == NULL || size == 0) { - if (size == 0) { - return nitems; - } - errno = EINVAL; - return 0; - } - - if (__FILE(stream)->fd == -1 && __FILE(stream)->buf != NULL) { - if (__builtin_mul_overflow(size, nitems, &total_bytes)) { - errno = EOVERFLOW; - return 0; - } - - size_t space_left = - __FILE(stream)->buf_size > __FILE(stream)->buf_len ? - __FILE(stream)->buf_size - - __FILE(stream)->buf_len - 1 : - 0; - - if (space_left == 0) { - return 0; - } - - size_t to_copy = total_bytes < space_left ? total_bytes : - space_left; - - if (to_copy > 0) { - memcpy(__FILE(stream)->buf + __FILE(stream)->buf_len, - data, to_copy); - __FILE(stream)->buf_len += to_copy; - } - - return to_copy == total_bytes ? nitems : to_copy / size; - } - - if (__builtin_mul_overflow(size, nitems, &total_bytes)) { - errno = EOVERFLOW; - return 0; - } - - if ((__FILE(stream)->flags & O_ACCMODE) == O_RDONLY) { - errno = EBADF; - return 0; - } - - if (__FILE(stream)->flags & _IO_ERR) { - errno = EIO; - return 0; - } - - LIBC_LOCK(__FILE(stream)->lock); - - if (__FILE(stream)->type == _IONBF) { - ssize_t result = write(__FILE(stream)->fd, data, total_bytes); - LIBC_UNLOCK(__FILE(stream)->lock); - - if (result < 0) { - __FILE(stream)->flags |= _IO_ERR; - return 0; - } - - return result == (ssize_t)total_bytes ? nitems : result / size; - } - - size_t remaining = total_bytes; - - while (remaining > 0) { - size_t space_available = - __FILE(stream)->buf_size - __FILE(stream)->buf_len; - - if (space_available == 0) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - space_available = __FILE(stream)->buf_size; - } - - size_t to_copy = remaining < space_available ? remaining : - space_available; - - memcpy(__FILE(stream)->buf + __FILE(stream)->buf_len, - data + written, to_copy); - __FILE(stream)->buf_len += to_copy; - written += to_copy; - remaining -= to_copy; - - if (__FILE(stream)->type == _IOLBF) { - char *newline_pos = memchr( - __FILE(stream)->buf + __FILE(stream)->buf_len - - to_copy, - '\n', to_copy); - if (newline_pos != NULL) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - } - } - - else if (__FILE(stream)->type == _IOFBF && - __FILE(stream)->buf_len == __FILE(stream)->buf_size) { - LIBC_UNLOCK(__FILE(stream)->lock); - if (fflush(stream) != 0) { - return written / size; - } - } - } + size_t r; - LIBC_UNLOCK(__FILE(stream)->lock); + flockfile(stream); + r = fwrite_unlocked(ptr, size, nitems, stream); + funlockfile(stream); - return written == total_bytes ? nitems : written / size; + return r; } diff --git a/lib/libc/stdio/fwrite_unlocked.c b/lib/libc/stdio/fwrite_unlocked.c new file mode 100644 index 00000000..dd5f4c0b --- /dev/null +++ b/lib/libc/stdio/fwrite_unlocked.c @@ -0,0 +1,106 @@ +#include "__stdio.h" +#include <atomic.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +extern void __libc_init_io(void); +void *__libc_force_io_init = (void *)__libc_init_io; + +size_t fwrite_unlocked(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) +{ + size_t total_bytes; + size_t written = 0; + const char *data = (const char *)ptr; + + if (ptr == NULL || stream == NULL || size == 0) { + if (size == 0) { + return nitems; + } + errno = EINVAL; + return 0; + } + + if (__builtin_mul_overflow(size, nitems, &total_bytes)) { + errno = EOVERFLOW; + return 0; + } + + if ((stream->flags & O_ACCMODE) == O_RDONLY) { + errno = EBADF; + return 0; + } + + if (stream->flags & _IO_ERR) { + errno = EIO; + return 0; + } + + /* Handle in-memory buffer case (e.g., string streams) */ + if (stream->fd == -1 && stream->buf != NULL) { + size_t space_left = (stream->buf_size > stream->buf_len) ? + stream->buf_size - stream->buf_len - 1 /* Reserve for '\0' */ + : + 0; + if (space_left == 0) { + return 0; + } + size_t to_copy = (total_bytes < space_left) ? total_bytes : space_left; + if (to_copy > 0) { + memcpy(stream->buf + stream->buf_len, data, to_copy); + stream->buf_len += to_copy; + } + return (to_copy == total_bytes) ? nitems : to_copy / size; + } + + if (stream->type != _IONBF && stream->buf == NULL) { + errno = EIO; + return 0; + } + + /* Unbuffered mode: direct write */ + if (stream->type == _IONBF) { + ssize_t result = write(stream->fd, data, total_bytes); + if (result < 0) { + stream->flags |= _IO_ERR; + return 0; + } + return (result == (ssize_t)total_bytes) ? nitems : result / size; + } + + size_t remaining = total_bytes; + while (remaining > 0) { + size_t space_available = stream->buf_size - stream->buf_len; + if (space_available == 0) { + if (fflush_unlocked(stream) != 0) { + return written / size; + } + space_available = stream->buf_size; + } + size_t to_copy = (remaining < space_available) ? remaining : space_available; + memcpy(stream->buf + stream->buf_len, data + written, to_copy); + stream->buf_len += to_copy; + written += to_copy; + remaining -= to_copy; + + /* Line-buffered: flush on newline in the copied chunk */ + if (stream->type == _IOLBF) { + char *newline_pos = memchr(stream->buf + stream->buf_len - to_copy, '\n', to_copy); + if (newline_pos != NULL) { + if (fflush_unlocked(stream) != 0) { + return written / size; + } + } + } else if (stream->type == _IOFBF && stream->buf_len == stream->buf_size) { + /* Full-buffered: flush when buffer is full */ + if (fflush_unlocked(stream) != 0) { + return written / size; + } + } + } + + return (written == total_bytes) ? nitems : written / size; +} diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c index 242c8396..2f59ba5c 100644 --- a/lib/libc/stdio/getc.c +++ b/lib/libc/stdio/getc.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for fgetc, FILE, getc, getc_unlocked +#include <stdio.h> int getc(FILE *stream) { - return fgetc(stream); -} + int r; + + flockfile(stream); + r = getc_unlocked(stream); + funlockfile(stream); -weak_reference(getc, getc_unlocked); + return r; +} diff --git a/lib/libc/stdio/getc_unlocked.c b/lib/libc/stdio/getc_unlocked.c new file mode 100644 index 00000000..1fc46d0a --- /dev/null +++ b/lib/libc/stdio/getc_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int getc_unlocked(FILE *stream) +{ + return fgetc_unlocked(stream); +} diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c index d26c3c6b..d5e08cd1 100644 --- a/lib/libc/stdio/getchar.c +++ b/lib/libc/stdio/getchar.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for fgetc, getchar, getchar_unlocked, stdin +#include <stdio.h> int getchar(void) { - return fgetc(stdin); -} + int r; + + flockfile(stdin); + r = getchar_unlocked(); + funlockfile(stdin); -weak_reference(getchar, getchar_unlocked); + return r; +} diff --git a/lib/libc/stdio/getchar_unlocked.c b/lib/libc/stdio/getchar_unlocked.c new file mode 100644 index 00000000..e7b2fed2 --- /dev/null +++ b/lib/libc/stdio/getchar_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int getchar_unlocked(void) +{ + return fgetc_unlocked(stdin); +} diff --git a/lib/libc/stdio/pclose.c b/lib/libc/stdio/pclose.c index a515981c..1967b2c8 100644 --- a/lib/libc/stdio/pclose.c +++ b/lib/libc/stdio/pclose.c @@ -6,5 +6,5 @@ int pclose(FILE *stream) { int stat; fclose(stream); - return (waitpid(__FILE(stream)->pid, &stat, 0) < 0) ? -1 : stat; + return (waitpid(stream->pid, &stat, 0) < 0) ? -1 : stat; } diff --git a/lib/libc/stdio/popen.c b/lib/libc/stdio/popen.c index 1fd5f991..5720fba3 100644 --- a/lib/libc/stdio/popen.c +++ b/lib/libc/stdio/popen.c @@ -62,7 +62,7 @@ FILE *popen(const char *command, const char *mode) close(pipefd[0]); } - __FILE(stream)->pid = pid; + stream->pid = pid; return stream; } diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c index c9e3ba08..c0673473 100644 --- a/lib/libc/stdio/putchar.c +++ b/lib/libc/stdio/putchar.c @@ -1,9 +1,12 @@ -#include <libc.h> // for weak_reference -#include <stdio.h> // for putc, putchar, putchar_unlocked, stdout +#include <stdio.h> int putchar(int c) { - return putc(c, stdout); -} + int r; + + flockfile(stdout); + r = putchar_unlocked(c); + funlockfile(stdout); -weak_reference(putchar, putchar_unlocked); + return r; +} diff --git a/lib/libc/stdio/putchar_unlocked.c b/lib/libc/stdio/putchar_unlocked.c new file mode 100644 index 00000000..a8a5fc47 --- /dev/null +++ b/lib/libc/stdio/putchar_unlocked.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int putchar_unlocked(int c) +{ + return fputc_unlocked(c, stdout); +} diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c index 686640f4..d6b41d31 100644 --- a/lib/libc/stdio/setvbuf.c +++ b/lib/libc/stdio/setvbuf.c @@ -10,13 +10,13 @@ int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size) if (type != _IONBF && (buf == NULL || size == 0)) return -1; - if (__FILE(stream)->fd < 0) + if (stream->fd < 0) return -1; - __FILE(stream)->buf = buf; - __FILE(stream)->buf_size = size; - __FILE(stream)->buf_pos = 0; - __FILE(stream)->type = type; + stream->buf = buf; + stream->buf_size = size; + stream->buf_pos = 0; + stream->type = type; return 0; } diff --git a/lib/libc/stdio/stderr.c b/lib/libc/stdio/stderr.c deleted file mode 100644 index ec115fd0..00000000 --- a/lib/libc/stdio/stderr.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "__stdio.h" // for __FILE -#include "stdatomic.h" // for ATOMIC_FLAG_INIT - -#include <fcntl.h> // for O_WRONLY -#include <stdio.h> // for FILE, stderr -#include <unistd.h> // for STDERR_FILENO - -#define BUFSIZ 4096 - -struct __FILE __stderr = { .fd = STDERR_FILENO, - .flags = O_WRONLY, - .type = 0, - .buf = 0, - .buf_len = 0, - .buf_size = 0, - .buf_pos = 0, - .eof = 0, - .unget_cnt = 0, - .next = 0, - .offset = 0, - .lock = ATOMIC_FLAG_INIT }; - -FILE *const stderr = (FILE *)&__stderr; diff --git a/lib/libc/stdio/stdin.c b/lib/libc/stdio/stdin.c deleted file mode 100644 index 0d127efa..00000000 --- a/lib/libc/stdio/stdin.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "__stdio.h" // for __FILE - -#include <fcntl.h> // for O_RDONLY -#include <stdio.h> // for FILE, stdin -#include <sys/cdefs.h> -#include <unistd.h> // for STDOUT_FILENO - -#define BUFSIZ 4096 - -__weak char __stdin_buffer[0]; -struct __FILE __stdin = { .fd = STDOUT_FILENO, - .flags = O_RDONLY, - .buf = __stdin_buffer, - .type = 0x0, - .buf_size = BUFSIZ, - .buf_pos = 0, - .offset = 0 }; - -FILE *const stdin = (FILE *)&__stdin; diff --git a/lib/libc/stdio/stdout.c b/lib/libc/stdio/stdout.c deleted file mode 100644 index 471a54b9..00000000 --- a/lib/libc/stdio/stdout.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "__stdio.h" // for __FILE, __libc_fadd - -#include <atomic.h> // for LIBC_LOCK, LIBC_UNLOCK -#include <fcntl.h> // for O_WRONLY -#include <stddef.h> // for NULL -#include <stdio.h> // for stdout -#include <sys/cdefs.h> -#include <unistd.h> // for STDOUT_FILENO - -#define BUFSIZ 4096 - -__weak char __stdout_buffer[0]; -static atomic_flag __stdio_lock = ATOMIC_FLAG_INIT; -struct __FILE __stdout = { .fd = STDOUT_FILENO, - .flags = O_WRONLY, - .type = 1, - .buf = __stdout_buffer, - .buf_len = 0, - .buf_size = BUFSIZ, - .buf_pos = 0, - .eof = 0, - .unget_cnt = 0, - .offset = 0, - .next = NULL, - .lock = ATOMIC_FLAG_INIT }; - -struct __FILE *const stdout = (struct __FILE *)&__stdout; - -void __libc_fadd(struct __FILE *f) -{ - LIBC_LOCK(__stdio_lock); - struct __FILE *cur = &__stdout; - while (cur->next) - cur = cur->next; - cur->next = f; - LIBC_UNLOCK(__stdio_lock); -} diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 06609046..4dc1a4d2 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -1,13 +1,13 @@ -#include <ctype.h> // for isdigit -#include <errno.h> // for EINVAL, errno -#include <math.h> // for isinf, isnan -#include <stdarg.h> // for va_arg -#include <stddef.h> // for NULL, ptrdiff_t +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <stdarg.h> +#include <stddef.h> #include <stdint.h> -#include <stdint.h> // for uintptr_t, intmax_t, uintmax_t -#include <stdio.h> // for fwrite, fputc, vfprintf, FILE, va_list -#include <string.h> // for memmove, strlcpy, strlen -#include <sys/types.h> // for size_t, ssize_t +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> static double __frexp(double x, int *e) { @@ -35,8 +35,7 @@ static double __frexp(double x, int *e) return y.d; } -extern char *dtoa(double, int mode, int ndigits, int *decpt, int *sign, - char **rve); +extern char *dtoa(double, int mode, int ndigits, int *decpt, int *sign, char **rve); extern void freedtoa(char *s); static int utoa_base(unsigned long long v, char *s, int b, int p, int u) @@ -65,12 +64,14 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) const char *ptr; int total_printed; + flockfile(stream); + ptr = format; total_printed = 0; while (*ptr != '\0') { if (*ptr != '%') { - fputc(*ptr, stream); + fputc_unlocked(*ptr, stream); total_printed++; ptr++; } else { @@ -104,8 +105,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) LENGTH_CAPL } length = LENGTH_NONE; - while (*ptr == '-' || *ptr == '+' || *ptr == ' ' || - *ptr == '0' || *ptr == '#') { + while (*ptr == '-' || *ptr == '+' || *ptr == ' ' || *ptr == '0' || *ptr == '#') { if (*ptr == '-') flags |= FLAG_MINUS; else if (*ptr == '+') @@ -143,8 +143,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } else { precision = 0; while (isdigit(*ptr)) { - precision = precision * 10 + - (*ptr - '0'); + precision = precision * 10 + (*ptr - '0'); ptr++; } } @@ -196,7 +195,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) val = va_arg(ap, int); break; case LENGTH_HH: - val = (signed char)va_arg(ap, int); + val = (unsigned char)va_arg(ap, int); break; case LENGTH_H: val = (short)va_arg(ap, int); @@ -218,6 +217,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) break; case LENGTH_CAPL: errno = EINVAL; + funlockfile(stream); return -1; } @@ -261,12 +261,10 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) val = va_arg(ap, unsigned int); break; case LENGTH_HH: - val = (unsigned char)va_arg( - ap, unsigned int); + val = (unsigned char)va_arg(ap, unsigned int); break; case LENGTH_H: - val = (unsigned short)va_arg( - ap, unsigned int); + val = (unsigned short)va_arg(ap, unsigned int); break; case LENGTH_L: val = va_arg(ap, unsigned long); @@ -285,24 +283,20 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) break; case LENGTH_CAPL: errno = EINVAL; + funlockfile(stream); return -1; } if (fmt_char == 'o') { - l = utoa_base(val, buf, 8, precision, - 0); + l = utoa_base(val, buf, 8, precision, 0); } else if (fmt_char == 'u') { - l = utoa_base(val, buf, 10, precision, - 0); + l = utoa_base(val, buf, 10, precision, 0); } else if (fmt_char == 'x') { - l = utoa_base(val, buf, 16, precision, - 0); + l = utoa_base(val, buf, 16, precision, 0); } else if (fmt_char == 'X') { - l = utoa_base(val, buf, 16, precision, - 1); + l = utoa_base(val, buf, 16, precision, 1); } else { - l = utoa_base(val, buf, 10, precision, - 0); + l = utoa_base(val, buf, 10, precision, 0); } s = buf; @@ -350,11 +344,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) int pos = 0; if (isnan(val)) { - strlcpy(buf, - (*ptr == 'F' || *ptr == 'E' || - *ptr == 'G') ? - "NAN" : - "nan", + strlcpy(buf, (*ptr == 'F' || *ptr == 'E' || *ptr == 'G') ? "NAN" : "nan", sizeof(buf)); l = 3; break; @@ -367,11 +357,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } else if (flags & FLAG_SPACE) { buf[pos++] = ' '; } - strlcpy(buf + pos, - (*ptr == 'F' || *ptr == 'E' || - *ptr == 'G') ? - "INF" : - "inf", + strlcpy(buf + pos, (*ptr == 'F' || *ptr == 'E' || *ptr == 'G') ? "INF" : "inf", sizeof(buf) - pos); l = pos + 3; break; @@ -391,58 +377,40 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'F': { int decpt, sign; char *rve; - char *digits = dtoa(val, 3, precision, - &decpt, &sign, - &rve); + char *digits = dtoa(val, 3, precision, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; } - if (decpt <= 1 && digits[0] == '0' && - digits[1] == '\0') { + if (decpt <= 1 && digits[0] == '0' && digits[1] == '\0') { buf[pos++] = '0'; if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < precision; - i++) { - buf[pos++] = - '0'; + for (int i = 0; i < precision; i++) { + buf[pos++] = '0'; } } } else if (decpt <= 0) { buf[pos++] = '0'; if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < -decpt && - i < precision; - i++) { - buf[pos++] = - '0'; + for (int i = 0; i < -decpt && i < precision; i++) { + buf[pos++] = '0'; } - int remaining = - precision + - decpt; + int remaining = precision + decpt; char *d = digits; - while (*d && - remaining-- > - 0) { - buf[pos++] = - *d++; + while (*d && remaining-- > 0) { + buf[pos++] = *d++; } - while (remaining-- > - 0) { - buf[pos++] = - '0'; + while (remaining-- > 0) { + buf[pos++] = '0'; } } } else { char *d = digits; int digits_used = 0; - for (int i = 0; i < decpt && *d; - i++) { + for (int i = 0; i < decpt && *d; i++) { buf[pos++] = *d++; digits_used++; } @@ -452,15 +420,11 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; - i < precision; - i++) { + for (int i = 0; i < precision; i++) { if (*d) { - buf[pos++] = - *d++; + buf[pos++] = *d++; } else { - buf[pos++] = - '0'; + buf[pos++] = '0'; } } } @@ -475,9 +439,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'E': { int decpt, sign; char *rve; - char *digits = - dtoa(val, 2, precision + 1, - &decpt, &sign, &rve); + char *digits = dtoa(val, 2, precision + 1, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; @@ -491,14 +453,11 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (precision > 0) { buf[pos++] = '.'; - for (int i = 0; i < precision; - i++) { + for (int i = 0; i < precision; i++) { if (*digits) { - buf[pos++] = - *digits++; + buf[pos++] = *digits++; } else { - buf[pos++] = - '0'; + buf[pos++] = '0'; } } } @@ -510,8 +469,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) exp = -exp; if (exp < 10) buf[pos++] = '0'; - pos += utoa_base(exp, buf + pos, 10, 0, - 0); + pos += utoa_base(exp, buf + pos, 10, 0, 0); buf[pos] = '\0'; l = pos; @@ -522,9 +480,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'G': { int decpt, sign; char *rve; - char *digits = dtoa(val, 2, precision, - &decpt, &sign, - &rve); + char *digits = dtoa(val, 2, precision, &decpt, &sign, &rve); if (sign && val != 0.0) { buf[pos++] = '-'; @@ -538,63 +494,44 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (*digits) { buf[pos++] = '.'; while (*digits) { - buf[pos++] = - *digits++; + buf[pos++] = *digits++; } } - buf[pos++] = (*ptr == 'G') ? - 'E' : - 'e'; - buf[pos++] = (exp >= 0) ? '+' : - '-'; + buf[pos++] = (*ptr == 'G') ? 'E' : 'e'; + buf[pos++] = (exp >= 0) ? '+' : '-'; if (exp < 0) exp = -exp; if (exp < 10) buf[pos++] = '0'; - pos += utoa_base(exp, buf + pos, - 10, 0, 0); + pos += utoa_base(exp, buf + pos, 10, 0, 0); } else { if (decpt <= 0) { buf[pos++] = '0'; - if (*digits && - *digits != '0') { - buf[pos++] = - '.'; - for (int i = 0; - i < -decpt; - i++) { - buf[pos++] = - '0'; + if (*digits && *digits != '0') { + buf[pos++] = '.'; + for (int i = 0; i < -decpt; i++) { + buf[pos++] = '0'; } - char *d = - digits; - while (*d && - *d != '0') { - buf[pos++] = - *d++; + char *d = digits; + while (*d && *d != '0') { + buf[pos++] = *d++; } } } else { char *d = digits; - for (int i = 0; - i < decpt && *d; - i++) { - buf[pos++] = - *d++; + for (int i = 0; i < decpt && *d; i++) { + buf[pos++] = *d++; } if (*d) { - buf[pos++] = - '.'; + buf[pos++] = '.'; while (*d) { - buf[pos++] = - *d++; + buf[pos++] = *d++; } } } } - while (pos > 1 && buf[pos - 1] == '0' && - pos > 2 && buf[pos - 2] != 'e' && + while (pos > 1 && buf[pos - 1] == '0' && pos > 2 && buf[pos - 2] != 'e' && buf[pos - 2] != 'E') { pos--; } @@ -634,9 +571,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } if (val == 0.0) { - strlcpy(buf + pos, - upper ? "0X0P+0" : "0x0p+0", - sizeof(buf) - pos); + strlcpy(buf + pos, upper ? "0X0P+0" : "0x0p+0", sizeof(buf) - pos); l = pos + 6; break; } @@ -662,15 +597,9 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) int digit = (int)mant; if (digit > 15) digit = 15; - buf[pos++] = - (digit < 10) ? - ('0' + digit) : - (upper ? ('A' + - digit - - 10) : - ('a' + - digit - - 10)); + buf[pos++] = (digit < 10) ? + ('0' + digit) : + (upper ? ('A' + digit - 10) : ('a' + digit - 10)); mant -= digit; } @@ -728,9 +657,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) case 'p': { void *ptr_val = va_arg(ap, void *); uintptr_t uptr = (uintptr_t)ptr_val; - int len = utoa_base((unsigned long long)uptr, - buf + 2, 16, - sizeof(void *) * 2, 0); + int len = utoa_base((unsigned long long)uptr, buf + 2, 16, sizeof(void *) * 2, 0); buf[0] = '0'; buf[1] = 'x'; buf[len + 2] = '\0'; @@ -755,6 +682,7 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) } default: errno = EINVAL; + funlockfile(stream); return -1; } @@ -767,46 +695,39 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) char format_char = *(ptr - 1); char pad_char = ' '; if ((flags & FLAG_ZERO) && !(flags & FLAG_MINUS) && - (format_char == 'd' || format_char == 'i' || - format_char == 'u' || format_char == 'o' || - format_char == 'x' || format_char == 'X' || - format_char == 'f' || format_char == 'F' || - format_char == 'e' || format_char == 'E' || - format_char == 'g' || format_char == 'G') && + (format_char == 'd' || format_char == 'i' || format_char == 'u' || format_char == 'o' || + format_char == 'x' || format_char == 'X' || format_char == 'f' || format_char == 'F' || + format_char == 'e' || format_char == 'E' || format_char == 'g' || format_char == 'G') && precision < 0) { pad_char = '0'; } if ((flags & FLAG_MINUS) == 0) { if (pad_char == '0' && s != NULL) { - if (s[0] == '-' || s[0] == '+' || - s[0] == ' ') { - fwrite(s, 1, 1, stream); + if (s[0] == '-' || s[0] == '+' || s[0] == ' ') { + fwrite_unlocked(s, 1, 1, stream); total_printed++; s++; l--; } - if (l >= 2 && s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { - fwrite(s, 1, 2, stream); + if (l >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + fwrite_unlocked(s, 1, 2, stream); total_printed += 2; s += 2; l -= 2; } for (int i = 0; i < padding; i++) { - fwrite("0", 1, 1, stream); + fwrite_unlocked("0", 1, 1, stream); total_printed++; } } else { for (int i = 0; i < padding; i++) { if (pad_char == '0') { - fwrite("0", 1, 1, - stream); + fwrite_unlocked("0", 1, 1, stream); } else { - fwrite(" ", 1, 1, - stream); + fwrite_unlocked(" ", 1, 1, stream); } total_printed++; } @@ -815,18 +736,20 @@ int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap) if (l > 0) { if (s != NULL) - fwrite(s, 1, l, stream); + fwrite_unlocked(s, 1, l, stream); total_printed += l; } if (flags & FLAG_MINUS) { for (int i = 0; i < padding; i++) { - fwrite(" ", 1, 1, stream); + fwrite_unlocked(" ", 1, 1, stream); total_printed++; } } } } + funlockfile(stream); + return total_printed; } |
