Apply even more fixups

- Finish cleaning up the stdio unlocked APIs
- Make __cxa_finalize() properly thread safe
- Don't log locks if threads aren't being used
- Add some more mutex guards to places using _mmi
- Specific lock names now appear in the --ftrace logs
- Fix mkdeps.com generating invalid Makefiles sometimes
- Simplify and fix bugs in the test runner infrastructure
- Fix issue where sometimes some functions wouldn't be logged
This commit is contained in:
Justine Tunney 2022-06-12 11:47:20 -07:00
parent 4ddfc47d6e
commit 8cdec62f5b
87 changed files with 955 additions and 899 deletions

View file

@ -11,13 +11,17 @@ struct StdioFlushHandles {
};
struct StdioFlush {
pthread_mutex_t lock;
struct StdioFlushHandles handles;
FILE *handles_initmem[8];
};
hidden extern struct StdioFlush __fflush;
void __fflush_lock(void);
void __fflush_unlock(void);
#define __fflush_lock() (__threaded ? __fflush_lock() : 0)
#define __fflush_unlock() (__threaded ? __fflush_unlock() : 0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_ */

View file

@ -31,6 +31,16 @@
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
static pthread_mutex_t __fflush_lock_obj;
void(__fflush_lock)(void) {
pthread_mutex_lock(&__fflush_lock_obj);
}
void(__fflush_unlock)(void) {
pthread_mutex_unlock(&__fflush_lock_obj);
}
/**
* Blocks until data from stream buffer is written out.
*
@ -41,7 +51,7 @@ int fflush_unlocked(FILE *f) {
int rc = 0;
size_t i;
if (!f) {
pthread_mutex_lock(&__fflush.lock);
__fflush_lock();
for (i = __fflush.handles.i; i; --i) {
if ((f = __fflush.handles.p[i - 1])) {
if (fflush(f) == -1) {
@ -49,7 +59,7 @@ int fflush_unlocked(FILE *f) {
}
}
}
pthread_mutex_unlock(&__fflush.lock);
__fflush_unlock();
} else if (f->fd != -1) {
if (__fflush_impl(f) == -1) {
rc = -1;
@ -64,7 +74,7 @@ textstartup int __fflush_register(FILE *f) {
int rc;
size_t i;
struct StdioFlush *sf;
pthread_mutex_lock(&__fflush.lock);
__fflush_lock();
sf = &__fflush;
if (!sf->handles.p) {
sf->handles.p = sf->handles_initmem;
@ -74,19 +84,19 @@ textstartup int __fflush_register(FILE *f) {
for (i = sf->handles.i; i; --i) {
if (!sf->handles.p[i - 1]) {
sf->handles.p[i - 1] = f;
pthread_mutex_unlock(&__fflush.lock);
__fflush_unlock();
return 0;
}
}
rc = append(&sf->handles, &f);
pthread_mutex_unlock(&__fflush.lock);
__fflush_unlock();
return rc;
}
void __fflush_unregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
pthread_mutex_lock(&__fflush.lock);
__fflush_lock();
sf = &__fflush;
sf = pushpop(sf);
for (i = sf->handles.i; i; --i) {
@ -95,5 +105,5 @@ void __fflush_unregister(FILE *f) {
break;
}
}
pthread_mutex_unlock(&__fflush.lock);
__fflush_unlock();
}

View file

@ -16,26 +16,25 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
* Reads UTF-8 content from stream into UTF-32 buffer.
*
* This function is similar to getline() except it'll truncate lines
* exceeding size. The line ending marker is included and may be removed
* using _chomp().
*
* @param s is is nul-terminated string that's non-null
* @param size is byte length of `s`
* @param f is file stream object pointer
* @see fgetws()
* @threadsafe
*/
wchar_t *fgetws_unlocked(wchar_t *s, int size, FILE *f) {
wint_t c;
wchar_t *p = s;
if (size > 0) {
while (--size > 0) {
if ((c = fgetwc_unlocked(f)) == -1) {
if (ferror_unlocked(f) == EINTR) continue;
break;
}
*p++ = c;
if (c == '\n') break;
}
*p = '\0';
}
return (intptr_t)p > (intptr_t)s ? s : NULL;
wchar_t *fgetws(wchar_t *s, int size, FILE *f) {
wchar_t *rc;
flockfile(f);
rc = fgetws_unlocked(s, size, f);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
* Reads UTF-8 content from stream into UTF-32 buffer.
*
* This function is similar to getline() except it'll truncate lines
* exceeding size. The line ending marker is included and may be removed
* using _chomp().
*
* @param s is is nul-terminated string that's non-null
* @param size is byte length of `s`
* @param f is file stream object pointer
* @see fgetws()
*/
wchar_t *fgetws_unlocked(wchar_t *s, int size, FILE *f) {
wint_t c;
wchar_t *p = s;
if (size > 0) {
while (--size > 0) {
if ((c = fgetwc_unlocked(f)) == -1) {
if (ferror_unlocked(f) == EINTR) continue;
break;
}
*p++ = c;
if (c == '\n') break;
}
*p = '\0';
}
return (intptr_t)p > (intptr_t)s ? s : NULL;
}

View file

@ -21,6 +21,6 @@
/**
* Acquires reentrant lock on stdio object, blocking if needed.
*/
void flockfile(FILE *f) {
void(flockfile)(FILE *f) {
pthread_mutex_lock(&f->lock);
}

View file

@ -29,7 +29,7 @@
void _flushlbf(void) {
int i;
FILE *f;
pthread_mutex_lock(&__fflush.lock);
__fflush_lock();
for (i = 0; i < __fflush.handles.i; ++i) {
if ((f = __fflush.handles.p[i])) {
flockfile(f);
@ -39,5 +39,5 @@ void _flushlbf(void) {
funlockfile(f);
}
}
pthread_mutex_unlock(&__fflush.lock);
__fflush_unlock();
}

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* Writes string to stream.
@ -29,11 +28,12 @@
* @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream
* @return bytes written, or -1 w/ errno
* @threadsafe
*/
int fputs_unlocked(const char *s, FILE *f) {
size_t n, r;
n = strlen(s);
r = fwrite_unlocked(s, 1, n, f);
if (!r && n) return -1;
return r;
int fputs(const char *s, FILE *f) {
int rc;
flockfile(f);
rc = fputs_unlocked(s, f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,24 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
// Writes string to stream.
//
// Writing stops at the NUL-terminator, which isn't included in output.
// This function blocks until the full string is written, unless an
// unrecoverable error happens.
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputs_unlocked()
// @threadsafe
fputs: mov %rsi,%r11
ezlea fputs_unlocked,ax
jmp stdio_unlock
.endfn fputs,globl
/**
* Writes string to stream.
*
* Writing stops at the NUL-terminator, which isn't included in output.
* This function blocks until the full string is written, unless an
* unrecoverable error happens.
*
* @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream
* @return bytes written, or -1 w/ errno
*/
int fputs_unlocked(const char *s, FILE *f) {
size_t n, r;
n = strlen(s);
r = fwrite_unlocked(s, 1, n, f);
if (!r && n) return -1;
return r;
}

View file

@ -17,24 +17,19 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/tpenc.h"
/**
* Writes wide character to stream.
*
* @return wc if written or -1 w/ errno
* @param wc has wide character
* @param f is file object stream pointer
* @return wide character if written or -1 w/ errno
* @threadsafe
*/
wint_t fputwc_unlocked(wchar_t wc, FILE *f) {
uint64_t w;
if (wc != -1) {
w = tpenc(wc);
do {
if (fputc_unlocked(w, f) == -1) {
return -1;
}
} while ((w >>= 8));
return wc;
} else {
return -1;
}
wint_t fputwc(wchar_t wc, FILE *f) {
wint_t rc;
flockfile(f);
rc = fputwc_unlocked(wc, f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,18 +16,27 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/tpenc.h"
// Writes data to stream.
//
// @param rdi has pointer to data to write
// @param rsi stride specifies the size of individual items
// @param rdx count is the number of strides to write
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fwrite_unlocked()
// @threadsafe
fwrite: mov %rcx,%r11
ezlea fwrite_unlocked,ax
jmp stdio_unlock
.endfn fwrite,globl
/**
* Writes wide character to stream.
*
* @param wc has wide character
* @param f is file object stream pointer
* @return wide character if written or -1 w/ errno
*/
wint_t fputwc_unlocked(wchar_t wc, FILE *f) {
uint64_t w;
if (wc != -1) {
w = tpenc(wc);
do {
if (fputc_unlocked(w, f) == -1) {
return -1;
}
} while ((w >>= 8));
return wc;
} else {
return -1;
}
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
@ -29,20 +28,12 @@
* @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream
* @return strlen(s) or -1 w/ errno on error
* @threadsafe
*/
int fputws_unlocked(const wchar_t *s, FILE *f) {
int res = 0;
while (*s) {
if (fputwc_unlocked(*s++, f) == -1) {
if (ferror_unlocked(f) == EINTR) {
continue;
}
if (feof_unlocked(f)) {
errno = f->state = EPIPE;
}
return -1;
}
++res;
}
return ++res;
int fputws(const wchar_t *s, FILE *f) {
int rc;
flockfile(f);
rc = fputws_unlocked(s, f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,33 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
// Writes wide character string to stream.
//
// Writing stops at the NUL-terminator, which isn't included in output.
// This function blocks until the full string is written, unless an
// unrecoverable error happens.
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputws_unlocked()
// @threadsafe
fputws: mov %rsi,%r11
ezlea fputws_unlocked,ax
jmp stdio_unlock
.endfn fputws,globl
/**
* Writes wide character string to stream.
*
* Writing stops at the NUL-terminator, which isn't included in output.
* This function blocks until the full string is written, unless an
* unrecoverable error happens.
*
* @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream
* @return strlen(s) or -1 w/ errno on error
*/
int fputws_unlocked(const wchar_t *s, FILE *f) {
int res = 0;
while (*s) {
if (fputwc_unlocked(*s++, f) == -1) {
if (ferror_unlocked(f) == EINTR) {
continue;
}
if (feof_unlocked(f)) {
errno = f->state = EPIPE;
}
return -1;
}
++res;
}
return ++res;
}

View file

@ -16,19 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Reads data from stream.
@ -36,64 +24,12 @@
* @param stride specifies the size of individual items
* @param count is the number of strides to fetch
* @return count on success, [0,count) on eof, or 0 on error or count==0
* @threadsafe
*/
size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
char *p;
ssize_t rc;
size_t n, m;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
f->state = errno = EBADF;
return 0;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return 0;
}
p = buf;
n = stride * count;
m = f->end - f->beg;
if (MIN(n, m)) memcpy(p, f->buf + f->beg, MIN(n, m));
if (n < m) {
f->beg += n;
return count;
}
if (n == m) {
f->beg = f->end = 0;
return count;
}
if (f->fd == -1) {
f->beg = 0;
f->end = 0;
f->state = -1;
return m / stride;
}
iov[0].iov_base = p + m;
iov[0].iov_len = n - m;
if (f->bufmode != _IONBF && n < f->size) {
iov[1].iov_base = f->buf;
if (f->size > PUSHBACK) {
iov[1].iov_len = f->size - PUSHBACK;
} else {
iov[1].iov_len = f->size;
}
} else {
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
}
if ((rc = readv(f->fd, iov, 2)) == -1) {
f->state = errno;
return 0;
}
n = rc;
f->beg = 0;
f->end = 0;
if (n > iov[0].iov_len) {
f->end += n - iov[0].iov_len;
return count;
} else {
n = (m + n) / stride;
if (n < count) f->state = -1;
return n;
}
size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
size_t rc;
flockfile(f);
rc = fread_unlocked(buf, stride, count, f);
funlockfile(f);
return rc;
}

104
libc/stdio/fread_unlocked.c Normal file
View file

@ -0,0 +1,104 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Reads data from stream.
*
* @param stride specifies the size of individual items
* @param count is the number of strides to fetch
* @return count on success, [0,count) on eof, or 0 on error or count==0
*/
size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
char *p;
ssize_t rc;
size_t n, m;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
f->state = errno = EBADF;
return 0;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return 0;
}
if (__builtin_mul_overflow(stride, count, &n)) {
f->state = errno = EOVERFLOW;
return 0;
}
p = buf;
m = f->end - f->beg;
if (MIN(n, m)) {
memcpy(p, f->buf + f->beg, MIN(n, m));
}
if (n < m) {
f->beg += n;
return count;
}
if (n == m) {
f->beg = f->end = 0;
return count;
}
if (f->fd == -1) {
f->beg = 0;
f->end = 0;
f->state = -1;
return m / stride;
}
iov[0].iov_base = p + m;
iov[0].iov_len = n - m;
if (f->bufmode != _IONBF && n < f->size) {
iov[1].iov_base = f->buf;
if (f->size > PUSHBACK) {
iov[1].iov_len = f->size - PUSHBACK;
} else {
iov[1].iov_len = f->size;
}
} else {
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
}
if ((rc = readv(f->fd, iov, 2)) == -1) {
f->state = errno;
return 0;
}
n = rc;
f->beg = 0;
f->end = 0;
if (n > iov[0].iov_len) {
f->end += n - iov[0].iov_len;
return count;
} else {
n = (m + n) / stride;
if (n < count) f->state = -1;
return n;
}
}

View file

@ -16,11 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/**
* Repositions open file stream.
@ -34,46 +30,12 @@
* @param offset is the byte delta
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
* @returns 0 on success or -1 on error
* @threadsafe
*/
int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
int res;
ssize_t rc;
int64_t pos;
if (f->fd != -1) {
if (__fflush_impl(f) == -1) return -1;
if (whence == SEEK_CUR && f->beg < f->end) {
offset -= f->end - f->beg;
}
if (lseek(f->fd, offset, whence) != -1) {
f->beg = 0;
f->end = 0;
res = 0;
} else {
f->state = errno == ESPIPE ? EBADF : errno;
res = -1;
}
} else {
switch (whence) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = f->beg + offset;
break;
case SEEK_END:
pos = f->end + offset;
break;
default:
pos = -1;
break;
}
if (0 <= pos && pos <= f->end) {
f->beg = pos;
res = 0;
} else {
f->state = errno = EINVAL;
res = -1;
}
}
return res;
int fseeko(FILE *f, int64_t offset, int whence) {
int rc;
flockfile(f);
rc = fseeko_unlocked(f, offset, whence);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,79 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/**
* Repositions open file stream.
*
* This function flushes the buffer (unless it's currently in the EOF
* state) and then calls lseek() on the underlying file. If the stream
* is in the EOF state, this function can be used to restore it without
* needing to reopen the file.
*
* @param f is a non-null stream handle
* @param offset is the byte delta
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
* @returns 0 on success or -1 on error
*/
int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
int res;
ssize_t rc;
int64_t pos;
if (f->fd != -1) {
if (__fflush_impl(f) == -1) return -1;
if (whence == SEEK_CUR && f->beg < f->end) {
offset -= f->end - f->beg;
}
if (lseek(f->fd, offset, whence) != -1) {
f->beg = 0;
f->end = 0;
res = 0;
} else {
f->state = errno == ESPIPE ? EBADF : errno;
res = -1;
}
} else {
switch (whence) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = f->beg + offset;
break;
case SEEK_END:
pos = f->end + offset;
break;
default:
pos = -1;
break;
}
if (0 <= pos && pos <= f->end) {
f->beg = pos;
res = 0;
} else {
f->state = errno = EINVAL;
res = -1;
}
}
return res;
}

View file

@ -23,7 +23,7 @@
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
static int64_t ftello_unlocked(FILE *f) {
static inline int64_t ftello_unlocked(FILE *f) {
int64_t pos;
uint32_t skew;
if (f->fd != -1) {
@ -45,6 +45,7 @@ static int64_t ftello_unlocked(FILE *f) {
*
* @param stream is a non-null stream handle
* @returns current byte offset from beginning, or -1 w/ errno
* @threadsafe
*/
int64_t ftello(FILE *f) {
int64_t rc;

View file

@ -23,6 +23,6 @@
*
* @return 0 on success, or non-zero if another thread owns the lock
*/
int ftrylockfile(FILE *f) {
int(ftrylockfile)(FILE *f) {
return pthread_mutex_trylock(&f->lock);
}

View file

@ -21,6 +21,6 @@
/**
* Releases lock on stdio object.
*/
void funlockfile(FILE *f) {
void(funlockfile)(FILE *f) {
pthread_mutex_unlock(&f->lock);
}

View file

@ -16,18 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
/**
* Writes data to stream.
@ -35,54 +24,12 @@
* @param stride specifies the size of individual items
* @param count is the number of strides to write
* @return count on success, [0,count) on EOF, 0 on error or count==0
* @threadsafe
*/
size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
ldiv_t d;
ssize_t rc;
size_t n, m;
const char *p;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
f->state = errno = EBADF;
return 0;
}
n = stride * count;
m = f->size - f->beg;
if (n <= m && f->bufmode != _IONBF) {
memcpy(f->buf + f->beg, data, n);
f->beg += n;
if (f->fd != -1 && f->bufmode == _IOLBF &&
(p = memrchr(f->buf, '\n', f->beg))) {
n = p + 1 - f->buf;
if ((rc = write(f->fd, f->buf, n)) == -1) {
if (errno == EINTR || errno == EAGAIN) return count;
f->state = errno;
return 0;
}
n = rc;
memmove(f->buf, f->buf + n, f->beg - n);
f->beg -= n;
}
return count;
}
if (f->fd == -1) {
n = MIN(n, m);
d = ldiv(n, stride);
n -= d.rem;
memcpy(f->buf + f->beg, data, n);
f->beg += n;
f->state = -1;
return d.quot;
}
iov[0].iov_base = f->buf;
iov[0].iov_len = f->beg;
iov[1].iov_base = data;
iov[1].iov_len = n;
n += f->beg;
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
f->state = errno;
return 0;
}
f->beg = 0;
return count;
size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
size_t rc;
flockfile(f);
rc = fwrite_unlocked(data, stride, count, f);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,113 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
/**
* Writes data to stream.
*
* @param stride specifies the size of individual items
* @param count is the number of strides to write
* @return count on success, [0,count) on EOF, 0 on error or count==0
*/
size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
ldiv_t d;
ssize_t rc;
size_t n, m;
const char *p;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
f->state = errno = EBADF;
return 0;
}
if (__builtin_mul_overflow(stride, count, &n)) {
f->state = errno = EOVERFLOW;
return 0;
}
m = f->size - f->beg;
if (n <= m && f->bufmode != _IONBF) {
// this isn't a fully buffered stream, and
// there's enough room in the buffer for the request
memcpy(f->buf + f->beg, data, n);
f->beg += n;
if (f->fd != -1 && f->bufmode == _IOLBF &&
(p = memrchr(f->buf, '\n', f->beg))) {
// write out as many lines as possible
n = p + 1 - f->buf;
if ((rc = write(f->fd, f->buf, n)) == -1) {
// the write() system call failed
if (errno == EINTR || errno == EAGAIN) {
return count;
} else {
f->state = errno;
return 0;
}
}
// copy backwards last line fragment or uncompleted data
n = rc;
if (f->beg - n) {
memmove(f->buf, f->buf + n, f->beg - n);
}
f->beg -= n;
}
return count;
}
// what's happening is either
// (1) a fully buffered stream, or
// (2) no room in buffer to hold full request
if (f->fd == -1) {
// this is an in-memory stream
// store as much of request as we can hold
n = MIN(n, m);
d = ldiv(n, stride);
n -= d.rem;
if (n) {
memcpy(f->buf + f->beg, data, n);
f->beg += n;
}
// trigger eof condition
f->state = EOF;
return d.quot;
}
// perform a fragmented write
// (1) we avoid needless copies in fully buffered mode
// (2) we avoid need for malloc() when it's out of room
iov[0].iov_base = f->buf;
iov[0].iov_len = f->beg;
iov[1].iov_base = data;
iov[1].iov_len = n;
n += f->beg;
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
f->state = errno;
return 0;
}
f->beg = 0;
return count;
}

View file

@ -21,7 +21,8 @@
/**
* Reads byte from stream.
* @return byte in range 0..255, or -1 w/ errno
* @threadsafe
*/
int(getc_unlocked)(FILE *f) {
return fgetc_unlocked(f);
int(getc)(FILE *f) {
return getc(f);
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
// Reads character from stdin.
//
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
// @threadsafe
getchar:
mov stdin(%rip),%rdi
mov %rdi,%r11
ezlea fgetc_unlocked,ax
jmp stdio_unlock
.endfn getchar,globl
/**
* Reads byte from stream.
* @return byte in range 0..255, or -1 w/ errno
*/
int(getc_unlocked)(FILE *f) {
return fgetc_unlocked(f);
}

View file

@ -21,7 +21,8 @@
/**
* Reads byte from stdin.
* @return byte in range 0..255, or -1 w/ errno
* @htreadsafe
*/
int getchar_unlocked(void) {
return fgetc_unlocked(stdin);
int getchar(void) {
return fgetc(stdin);
}

View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
/**
* Reads byte from stdin.
* @return byte in range 0..255, or -1 w/ errno
*/
int getchar_unlocked(void) {
return fgetc_unlocked(stdin);
}

View file

@ -21,7 +21,8 @@
/**
* Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error
* @threadsafe
*/
wint_t(getwc_unlocked)(FILE *f) {
return fgetwc_unlocked(f);
wint_t(getwc)(FILE *f) {
return fgetwc(f);
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
// Reads UTF-8 character from stdin.
//
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
// @threadsafe
getwchar:
mov stdin(%rip),%rdi
mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getwchar,globl
/**
* Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error
*/
wint_t(getwc_unlocked)(FILE *f) {
return fgetwc_unlocked(f);
}

View file

@ -21,7 +21,8 @@
/**
* Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error
* @threadsafe
*/
wint_t getwchar_unlocked(void) {
return fgetwc_unlocked(stdin);
wint_t getwchar(void) {
return fgetwc(stdin);
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,15 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
// Reads character from stream.
//
// @param rdi has file stream object pointer
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
// @threadsafe
getc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getc,globl
/**
* Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error
*/
wint_t getwchar_unlocked(void) {
return fgetwc_unlocked(stdin);
}

View file

@ -23,7 +23,8 @@
*
* @param c is byte to buffer or write, which is masked
* @return c as unsigned char if written or -1 w/ errno
* @threadsafe
*/
int(putc_unlocked)(int c, FILE *f) {
return fputc_unlocked(c, f);
int(putc)(int c, FILE *f) {
return fputc(c, f);
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,15 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
// Reads UTF-8 character from stream.
//
// @param rdi has file stream object pointer
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
// @threadsafe
getwc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getwc,globl
/**
* Writes byte to stream.
*
* @param c is byte to buffer or write, which is masked
* @return c as unsigned char if written or -1 w/ errno
*/
int(putc_unlocked)(int c, FILE *f) {
return fputc_unlocked(c, f);
}

View file

@ -22,7 +22,8 @@
* Writes byte to stdout.
*
* @return c (as unsigned char) if written or -1 w/ errno
* @threadsafe
*/
int putchar_unlocked(int c) {
return fputc_unlocked(c, stdout);
int putchar(int c) {
return fputc(c, stdout);
}

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
/**
* Writes byte to stdout.
*
* @return c (as unsigned char) if written or -1 w/ errno
*/
int putchar_unlocked(int c) {
return fputc_unlocked(c, stdout);
}

View file

@ -18,7 +18,7 @@
*/
#include "libc/stdio/stdio.h"
static int PutsImpl(const char *s, FILE *f) {
static inline int PutsImpl(const char *s, FILE *f) {
size_t n, r;
if ((n = strlen(s))) {
r = fwrite_unlocked(s, 1, n, f);

View file

@ -22,7 +22,8 @@
* Writes wide character to stream.
*
* @return wc if written or -1 w/ errno
* @threadsafe
*/
wint_t(putwc_unlocked)(wchar_t wc, FILE *f) {
return fputwc_unlocked(wc, f);
wint_t(putwc)(wchar_t wc, FILE *f) {
return fputwc(wc, f);
}

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
/**
* Writes wide character to stream.
*
* @return wc if written or -1 w/ errno
*/
wint_t(putwc_unlocked)(wchar_t wc, FILE *f) {
return fputwc_unlocked(wc, f);
}

View file

@ -21,7 +21,8 @@
/**
* Writes wide character to stdout.
* @return wc if written or -1 w/ errno
* @threadsafe
*/
wint_t putwchar_unlocked(wchar_t wc) {
return fputwc_unlocked(wc, stdout);
wint_t putwchar(wchar_t wc) {
return fputwc(wc, stdout);
}

View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
/**
* Writes wide character to stdout.
* @return wc if written or -1 w/ errno
*/
wint_t putwchar_unlocked(wchar_t wc) {
return fputwc_unlocked(wc, stdout);
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#include "libc/fmt/pflink.h"
#include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/symbolic.h"
#define FILENAME_MAX PATH_MAX
@ -157,20 +158,24 @@ int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
int vfprintf_unlocked(FILE *, const char *, va_list)
paramsnonnull() dontthrow nocallback;
#define getc_unlocked(f) fgetc_unlocked(f)
#define getwc_unlocked(f) fgetwc_unlocked(f)
#define putc_unlocked(c, f) fputc_unlocked(c, f)
#define putwc_unlocked(c, f) fputwc_unlocked(c, f)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » optimizations
*/
#define flockfile(f) (__threaded ? flockfile(f) : 0)
#define funlockfile(f) (__threaded ? funlockfile(f) : 0)
#define ftrylockfile(f) (__threaded ? ftrylockfile(f) : 0)
#define getc(f) fgetc(f)
#define getwc(f) fgetwc(f)
#define putc(c, f) fputc(c, f)
#define putwc(c, f) fputwc(c, f)
#define getc_unlocked(f) fgetc_unlocked(f)
#define getwc_unlocked(f) fgetwc_unlocked(f)
#define putc_unlocked(c, f) fputc_unlocked(c, f)
#define putwc_unlocked(c, f) fputwc_unlocked(c, f)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* clang-format off */
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)

View file

@ -17,20 +17,15 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* Pushes byte back to stream.
* @threadsafe
*/
int ungetc_unlocked(int c, FILE *f) {
if (c == -1) return -1;
if (f->beg) {
f->buf[--f->beg] = c;
} else if (f->end < f->size) {
memmove(f->buf + 1, f->buf, f->end++);
f->buf[0] = c;
} else {
return -1;
}
return c & 255;
int ungetc(int c, FILE *f) {
int rc;
flockfile(f);
rc = ungetc_unlocked(c, f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,21 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
// Writes wide character to stream.
//
// @param rdi has wide character
// @param rsi has file object stream pointer
// @return rax is wide character if written or -1 w/ errno
// @see fputwc_unlocked()
// @threadsafe
fputwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn fputwc,globl
/**
* Pushes byte back to stream.
*/
int ungetc_unlocked(int c, FILE *f) {
if (c == -1) return -1;
if (f->beg) {
f->buf[--f->beg] = c;
} else if (f->end < f->size) {
memmove(f->buf + 1, f->buf, f->end++);
f->buf[0] = c;
} else {
return -1;
}
return c & 255;
}

View file

@ -17,31 +17,15 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
/**
* Pushes wide character back to stream.
* @threadsafe
*/
wint_t ungetwc_unlocked(wint_t c, FILE *f) {
char b[6];
unsigned n;
uint64_t w;
if (c == -1) return -1;
n = 0;
w = tpenc(c);
do {
b[n++] = w;
} while ((w >>= 8));
if (f->beg >= n) {
f->beg -= n;
memcpy(f->buf + f->beg, b, n);
} else if (f->beg + f->end + n <= f->size) {
memmove(f->buf + f->beg + n, f->buf + f->beg, f->end - f->beg);
memcpy(f->buf + f->beg, b, n);
f->end += n;
} else {
return -1;
}
return c;
wint_t ungetwc(wint_t c, FILE *f) {
wint_t rc;
flockfile(f);
rc = ungetwc_unlocked(c, f);
funlockfile(f);
return rc;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,32 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
// Reads UTF-8 content from stream into UTF-32 buffer.
//
// This function is similar to getline() except it'll truncate lines
// exceeding size. The line ending marker is included and may be removed
// using _chomp().
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is size of rdi buffer
// @param rsi is file stream object pointer
// @see fgetws_unlocked()
// @threadsafe
fgetws: mov %rdx,%r11
ezlea fgetws_unlocked,ax
jmp stdio_unlock
.endfn fgetws,globl
/**
* Pushes wide character back to stream.
*/
wint_t ungetwc_unlocked(wint_t c, FILE *f) {
char b[6];
unsigned n;
uint64_t w;
if (c == -1) return -1;
n = 0;
w = tpenc(c);
do {
b[n++] = w;
} while ((w >>= 8));
if (f->beg >= n) {
f->beg -= n;
memcpy(f->buf + f->beg, b, n);
} else if (f->beg + f->end + n <= f->size) {
memmove(f->buf + f->beg + n, f->buf + f->beg, f->end - f->beg);
memcpy(f->buf + f->beg, b, n);
f->end += n;
} else {
return -1;
}
return c;
}

View file

@ -1,33 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Reads data from stream.
//
// @param rdi has pointer to data to read
// @param rsi stride specifies the size of individual items
// @param rdx count is the number of strides to read
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fread_unlocked()
// @threadsafe
fread: mov %rcx,%r11
ezlea fread_unlocked,ax
jmp stdio_unlock
.endfn fread,globl

View file

@ -1,37 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Repositions open file stream.
//
// This function flushes the buffer (unless it's currently in the EOF
// state) and then calls lseek() on the underlying file. If the stream
// is in the EOF state, this function can be used to restore it without
// needing to reopen the file.
//
// @param rdi is stream handle
// @param rsi is offset is the byte delta
// @param rdx is whence and can be SEET_SET, SEEK_CUR, or SEEK_END
// @return 0 on success or -1 w/ errno
// @see fflush_unlocked()
// @threadsafe
fseeko: mov %rdi,%r11
ezlea fseeko_unlocked,ax
jmp stdio_unlock
.endfn fseeko,globl

View file

@ -1,31 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Writes character to stream.
//
// @param rdi c is byte to buffer or write, which is masked
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
putc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn putc,globl

View file

@ -1,32 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Writes character to stdout.
//
// @param rdi has character
// @return c (as unsigned char) if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
putchar:
mov stdout(%rip),%rsi
mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn putchar,globl

View file

@ -1,31 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Writes wide character to stream.
//
// @param rdi has wide character
// @param rsi has file object
// @return wc if written or -1 w/ errno
// @see putwc_unlocked()
// @threadsafe
putwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn putwc,globl

View file

@ -1,32 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Writes wide character to stdout.
//
// @param rdi has wide character
// @return wc if written or -1 w/ errno
// @see fputwc_unlocked()
// @threadsafe
putwchar:
mov stdout(%rip),%rsi
mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn putwchar,globl

View file

@ -1,72 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Wrapper for applying locking to stdio functions.
//
// This function is intended to be called by thunks.
//
// @param rax is stdio function pointer
// @param rdi is passed along as an arg
// @param rsi is passed along as an arg
// @param rdx is passed along as an arg
// @param rcx is passed along as an arg
// @param r11 has the FILE* obj pointer
// @return rax is passed along as result
// @return rdx is passed along as result
// @threadsafe
stdio_unlock:
push %rbp
mov %rsp,%rbp
.profilable
// acquires mutex
push %rax
push %rdi
push %rsi
push %rdx
push %rcx
push %r11
mov %r11,%rdi
call flockfile
pop %r11
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
// calls delegate
push %r11
push %rsi # align stack
call *%rax
pop %rsi
pop %r11
// releases mutex
push %rax
push %rdx
mov %r11,%rdi
call funlockfile
pop %rdx
pop %rax
pop %rbp
ret
.endfn stdio_unlock,globl

View file

@ -1,31 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetc_unlocked()
// @threadsafe
ungetc: mov %rsi,%r11
ezlea ungetc_unlocked,ax
jmp stdio_unlock
.endfn ungetc,globl

View file

@ -1,32 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetwc_unlocked()
// @threadsafe
ungetwc:
mov %rsi,%r11
ezlea ungetwc_unlocked,ax
jmp stdio_unlock
.endfn ungetwc,globl