mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make the Windows Console work better
The stdio reader thread now appears to be working recursively along cosmopolitan subprocesses. For example, it's now possible to launch vim.com from the unbourne.com bestline repl, thanks to hacks plus a bug fix to select() timeouts.
This commit is contained in:
parent
032b1f3449
commit
8bdaddd81d
68 changed files with 580 additions and 346 deletions
|
@ -21,13 +21,13 @@
|
|||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
16
examples/clear.c
Normal file
16
examples/clear.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
|
||||
// clears the teletypewriter display with empty cells
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
write(1, "\e[H", 3);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -15,7 +16,9 @@
|
|||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
|
@ -45,7 +48,7 @@ int main(int argc, char *argv[]) {
|
|||
// some programs are blocked on cpu rather than i/o
|
||||
// such programs shall rely on asynchronous signals
|
||||
printf("doing cpu task...\n");
|
||||
for (volatile int i = 0; i < INT_MAX / 20; ++i) {
|
||||
for (volatile int i = 0; i < INT_MAX / 5; ++i) {
|
||||
if (gotsig) {
|
||||
printf("\rgot ctrl+c asynchronously\n");
|
||||
exit(0);
|
||||
|
@ -55,7 +58,7 @@ int main(int argc, char *argv[]) {
|
|||
// posix guarantees atomic i/o if you use pipe_buf sized buffers
|
||||
// that way we don't need to worry about things like looping and
|
||||
// we can also be assured that multiple actors wont have tearing
|
||||
char buf[PIPE_BUF];
|
||||
char buf[4];
|
||||
|
||||
// read data from standard input
|
||||
//
|
||||
|
@ -107,5 +110,6 @@ int main(int argc, char *argv[]) {
|
|||
// operating system will send SIGPIPE if there's any problem
|
||||
// which kills the process by default
|
||||
write(1, buf, got);
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -26,6 +28,8 @@
|
|||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
|
||||
__static_yoink("WinMainStdin");
|
||||
|
||||
#define CTRL(C) ((C) ^ 0b01000000)
|
||||
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
||||
#define ENABLE_SAFE_PASTE "\e[?2004h"
|
||||
|
|
|
@ -93,6 +93,12 @@ o/$(MODE)/libc/calls/vdsofunc.greg.o: private \
|
|||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we can't use magic because:
|
||||
# this code is called by WinMain
|
||||
o/$(MODE)/libc/calls/winstdin1.o: private \
|
||||
COPTS += \
|
||||
$(NO_MAGIC)
|
||||
|
||||
# we can't use asan because:
|
||||
# ntspawn allocates 128kb of heap memory via win32
|
||||
o/$(MODE)/libc/calls/ntspawn.o \
|
||||
|
|
|
@ -17,12 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
textwindows int sys_fdatasync_nt(int fd, bool fake) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return einval();
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval();
|
||||
if (_check_interrupts(0)) return -1;
|
||||
if (fake) return 0;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -18,39 +18,46 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes non-metadata buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
|
||||
* @raise EINVAL if `fd` is a special file w/o synchronization
|
||||
* @raise ENOSPC if disk space was exhausted
|
||||
* @raise EBADF if `fd` isn't an open file
|
||||
* @raise EINTR if signal was delivered
|
||||
* @raise EIO if an i/o error happened
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
bool fake = __nosync == 0x5453455454534146;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = erofs();
|
||||
} else if (!IsWindows()) {
|
||||
if (!fake) {
|
||||
rc = sys_fdatasync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
rc = sys_fsync_fake(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
|
||||
rc = sys_fdatasync_nt(fd, fake);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fdatasync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
36
libc/calls/fsync-fake.c
Normal file
36
libc/calls/fsync-fake.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- 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 2023 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/stat.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fsync_fake(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (!(rc = sys_fstat(fd, &st))) {
|
||||
if (S_ISSOCK(st.st_mode) || //
|
||||
S_ISFIFO(st.st_mode) || //
|
||||
S_ISLNK(st.st_mode)) {
|
||||
rc = einval();
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -18,19 +18,25 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
|
||||
* @raise EINVAL if `fd` is a special file w/o synchronization
|
||||
* @raise ENOSPC if disk space was exhausted
|
||||
* @raise EBADF if `fd` isn't an open file
|
||||
* @raise EINTR if signal was delivered
|
||||
* @raise EIO if an i/o error happened
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
|
@ -38,19 +44,20 @@
|
|||
*/
|
||||
int fsync(int fd) {
|
||||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
bool fake = __nosync == 0x5453455454534146;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = erofs();
|
||||
} else if (!IsWindows()) {
|
||||
if (!fake) {
|
||||
rc = sys_fsync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
rc = sys_fsync_fake(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fsync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = fstat(fd, &st);
|
||||
STRACE("fsync_fake(%d) → %d% m", fd, rc);
|
||||
rc = sys_fdatasync_nt(fd, fake);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fsync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
@ -144,14 +145,20 @@ static textwindows int sys_open_nt_console(int dirfd,
|
|||
const struct NtMagicPaths *mp,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
|
||||
GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) {
|
||||
uint32_t cm;
|
||||
int input, output;
|
||||
if ((__isfdopen((input = STDIN_FILENO)) &&
|
||||
GetConsoleMode(g_fds.p[input].handle, &cm)) &&
|
||||
((__isfdopen((output = STDOUT_FILENO)) &&
|
||||
GetConsoleMode(g_fds.p[output].handle, &cm)) ||
|
||||
(__isfdopen((output = STDERR_FILENO)) &&
|
||||
GetConsoleMode(g_fds.p[output].handle, &cm)))) {
|
||||
// this is an ugly hack that works for observed usage patterns
|
||||
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle;
|
||||
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
|
||||
g_fds.p[STDOUT_FILENO].dontclose = true;
|
||||
g_fds.p[STDIN_FILENO].dontclose = true;
|
||||
g_fds.p[fd].handle = g_fds.p[input].handle;
|
||||
g_fds.p[fd].extra = g_fds.p[output].handle;
|
||||
g_fds.p[fd].dontclose = true;
|
||||
g_fds.p[input].dontclose = true;
|
||||
g_fds.p[output].dontclose = true;
|
||||
} else if ((g_fds.p[fd].handle = sys_open_nt_impl(
|
||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
|
||||
kNtFileFlagOverlapped)) != -1) {
|
||||
|
@ -187,7 +194,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
|||
ssize_t rc;
|
||||
__fds_lock();
|
||||
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
|
||||
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
||||
if (!strcmp(file, kNtMagicPaths.devtty)) {
|
||||
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
} else {
|
||||
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
|
||||
|
|
|
@ -74,7 +74,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
|||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = espipe();
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, offset);
|
||||
rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, offset);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
if (g_fds.p[fd].kind == kFdSocket) {
|
||||
return espipe();
|
||||
} else {
|
||||
return sys_read_nt(g_fds.p + fd, iov, iovlen, off);
|
||||
return sys_read_nt(fd, iov, iovlen, off);
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
|
@ -48,19 +49,24 @@
|
|||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
__static_yoink("WinMainStdin");
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||
|
||||
static textwindows void sys_read_nt_abort(int64_t handle,
|
||||
struct NtOverlapped *overlapped) {
|
||||
unassert(CancelIoEx(handle, overlapped) ||
|
||||
GetLastError() == kNtErrorNotFound);
|
||||
}
|
||||
|
||||
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
||||
size_t size, int64_t offset) {
|
||||
textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
|
||||
int64_t offset) {
|
||||
|
||||
// perform the read i/o operation
|
||||
bool32 ok;
|
||||
struct Fd *f;
|
||||
uint32_t got;
|
||||
int filetype;
|
||||
int64_t handle;
|
||||
|
@ -69,27 +75,28 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
uint32_t targetsize;
|
||||
bool is_console_input;
|
||||
int abort_errno = EAGAIN;
|
||||
f = g_fds.p + fd;
|
||||
StartOver:
|
||||
size = MIN(size, 0x7ffff000);
|
||||
handle = __resolve_stdin_handle(fd->handle);
|
||||
handle = __resolve_stdin_handle(f->handle);
|
||||
filetype = GetFileType(handle);
|
||||
is_console_input = g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
||||
: fd->handle == g_fds.p[0].handle;
|
||||
is_console_input = g_fds.stdin.handle ? f->handle == g_fds.stdin.handle
|
||||
: f->handle == g_fds.p[0].handle;
|
||||
|
||||
// the caller might be reading a single byte at a time. but we need to
|
||||
// be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0"
|
||||
if (size && fd->buflen) {
|
||||
if (size && f->buflen) {
|
||||
ReturnDataFromBuffer:
|
||||
got = MIN(size, fd->buflen);
|
||||
remain = fd->buflen - got;
|
||||
if (got) memcpy(data, fd->buf, got);
|
||||
if (remain) memmove(fd->buf, fd->buf + got, remain);
|
||||
fd->buflen = remain;
|
||||
got = MIN(size, f->buflen);
|
||||
remain = f->buflen - got;
|
||||
if (got) memcpy(data, f->buf, got);
|
||||
if (remain) memmove(f->buf, f->buf + got, remain);
|
||||
f->buflen = remain;
|
||||
return got;
|
||||
}
|
||||
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
|
||||
targetdata = fd->buf;
|
||||
targetsize = sizeof(fd->buf);
|
||||
targetdata = f->buf;
|
||||
targetsize = sizeof(f->buf);
|
||||
} else {
|
||||
targetdata = data;
|
||||
targetsize = size;
|
||||
|
@ -106,12 +113,11 @@ StartOver:
|
|||
// since for overlapped i/o, we always use GetOverlappedResult
|
||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||
if (!ok && GetLastError() == kNtErrorIoPending) {
|
||||
TryAgain:
|
||||
// the i/o operation is in flight; blocking is unavoidable
|
||||
// if we're in a non-blocking mode, then immediately abort
|
||||
// if an interrupt is pending then we abort before waiting
|
||||
// otherwise wait for i/o periodically checking interrupts
|
||||
if (fd->flags & O_NONBLOCK) {
|
||||
if (f->flags & O_NONBLOCK) {
|
||||
sys_read_nt_abort(handle, &overlap);
|
||||
} else if (_check_interrupts(kSigOpRestartable)) {
|
||||
Interrupted:
|
||||
|
@ -120,6 +126,9 @@ StartOver:
|
|||
} else {
|
||||
for (;;) {
|
||||
uint32_t i;
|
||||
if (g_fds.stdin.inisem) {
|
||||
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
|
||||
}
|
||||
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
|
||||
if (i == kNtWaitTimeout) {
|
||||
if (_check_interrupts(kSigOpRestartable)) {
|
||||
|
@ -138,10 +147,11 @@ StartOver:
|
|||
// for windows to acknowledge that it's done using that memory
|
||||
ok = GetOverlappedResult(handle, &overlap, &got, true);
|
||||
if (!ok && GetLastError() == kNtErrorIoIncomplete) {
|
||||
goto TryAgain;
|
||||
kprintf("you complete me\n");
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
CloseHandle(overlap.hEvent);
|
||||
__imp_CloseHandle(overlap.hEvent);
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
|
@ -153,7 +163,7 @@ StartOver:
|
|||
int64_t position;
|
||||
// save file pointer which windows clobbers, even for overlapped i/o
|
||||
if (!SetFilePointerEx(handle, 0, &position, SEEK_CUR)) {
|
||||
return __winerr(); // fd probably isn't seekable?
|
||||
return __winerr(); // f probably isn't seekable?
|
||||
}
|
||||
struct NtOverlapped overlap = {0};
|
||||
overlap.Pointer = (void *)(uintptr_t)offset;
|
||||
|
@ -179,11 +189,11 @@ StartOver:
|
|||
}
|
||||
}
|
||||
if (__ttymagic & kFdTtyEchoing) {
|
||||
_weaken(__echo_terminal_input)(fd, targetdata, got);
|
||||
_weaken(__echo_terminal_input)(f, targetdata, got);
|
||||
}
|
||||
}
|
||||
if (targetdata != data) {
|
||||
fd->buflen = got;
|
||||
f->buflen = got;
|
||||
goto ReturnDataFromBuffer;
|
||||
}
|
||||
return got;
|
||||
|
@ -204,8 +214,8 @@ StartOver:
|
|||
}
|
||||
}
|
||||
|
||||
textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
||||
size_t iovlen, int64_t opt_offset) {
|
||||
textwindows ssize_t sys_read_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||
int64_t opt_offset) {
|
||||
ssize_t rc;
|
||||
size_t i, total;
|
||||
if (opt_offset < -1) return einval();
|
||||
|
|
|
@ -80,9 +80,9 @@ ssize_t read(int fd, void *buf, size_t size) {
|
|||
} else if (fd >= g_fds.n) {
|
||||
rc = ebadf();
|
||||
} else if (IsMetal()) {
|
||||
rc = sys_readv_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
|
||||
rc = sys_readv_metal(fd, &(struct iovec){buf, size}, 1);
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_readv_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1);
|
||||
rc = sys_readv_nt(fd, &(struct iovec){buf, size}, 1);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
@ -28,11 +29,11 @@
|
|||
|
||||
#ifdef __x86_64__
|
||||
|
||||
ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
ssize_t sys_readv_metal(int fd, const struct iovec *iov, int iovlen) {
|
||||
int i;
|
||||
size_t got, toto;
|
||||
struct MetalFile *file;
|
||||
switch (fd->kind) {
|
||||
switch (g_fds.p[fd].kind) {
|
||||
case kFdConsole:
|
||||
/*
|
||||
* The VGA teletypewriter code may wish to send out "status report"
|
||||
|
@ -40,14 +41,14 @@ ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
|||
* Read & return these if they are available.
|
||||
*/
|
||||
if (_weaken(sys_readv_vga)) {
|
||||
ssize_t res = _weaken(sys_readv_vga)(fd, iov, iovlen);
|
||||
ssize_t res = _weaken(sys_readv_vga)(g_fds.p + fd, iov, iovlen);
|
||||
if (res > 0) return res;
|
||||
}
|
||||
/* fall through */
|
||||
case kFdSerial:
|
||||
return sys_readv_serial(fd, iov, iovlen);
|
||||
case kFdFile:
|
||||
file = (struct MetalFile *)fd->handle;
|
||||
file = (struct MetalFile *)g_fds.p[fd].handle;
|
||||
for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) {
|
||||
got = MIN(iov[i].iov_len, file->size - file->pos);
|
||||
if (got) memcpy(iov[i].iov_base, file->base, got);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
@ -24,9 +25,8 @@
|
|||
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov,
|
||||
int iovlen) {
|
||||
switch (fd->kind) {
|
||||
textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
|
||||
switch (g_fds.p[fd].kind) {
|
||||
case kFdFile:
|
||||
case kFdConsole:
|
||||
return sys_read_nt(fd, iov, iovlen, -1);
|
||||
|
|
|
@ -16,14 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
static bool IsDataAvailable(struct Fd *fd) {
|
||||
return inb(fd->handle + UART_LSR) & UART_TTYDA;
|
||||
static bool IsDataAvailable(int fd) {
|
||||
return inb(g_fds.p[fd].handle + UART_LSR) & UART_TTYDA;
|
||||
}
|
||||
|
||||
static int GetFirstIov(const struct iovec *iov, int iovlen) {
|
||||
|
@ -36,13 +37,13 @@ static int GetFirstIov(const struct iovec *iov, int iovlen) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
ssize_t sys_readv_serial(int fd, const struct iovec *iov, int iovlen) {
|
||||
size_t i;
|
||||
if ((i = GetFirstIov(iov, iovlen)) != -1) {
|
||||
while (!IsDataAvailable(fd)) {
|
||||
__builtin_ia32_pause();
|
||||
}
|
||||
((char *)iov[i].iov_base)[0] = inb(fd->handle);
|
||||
((char *)iov[i].iov_base)[0] = inb(g_fds.p[fd].handle);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
@ -68,9 +68,9 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
|||
} else if (fd >= g_fds.n) {
|
||||
rc = ebadf();
|
||||
} else if (IsMetal()) {
|
||||
rc = sys_readv_metal(g_fds.p + fd, iov, iovlen);
|
||||
rc = sys_readv_metal(fd, iov, iovlen);
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_readv_nt(g_fds.p + fd, iov, iovlen);
|
||||
rc = sys_readv_nt(fd, iov, iovlen);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ int64_t sys_pwritev(int, const struct iovec *, int, int64_t, int64_t);
|
|||
int64_t sys_readv(int32_t, const struct iovec *, int32_t);
|
||||
int64_t sys_vmsplice(int, const struct iovec *, int64_t, uint32_t);
|
||||
int64_t sys_writev(int32_t, const struct iovec *, int32_t);
|
||||
ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, int64_t);
|
||||
ssize_t sys_readv_metal(struct Fd *, const struct iovec *, int);
|
||||
ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int);
|
||||
ssize_t sys_readv_serial(struct Fd *, const struct iovec *, int);
|
||||
ssize_t sys_read_nt(int, const struct iovec *, size_t, int64_t);
|
||||
ssize_t sys_readv_metal(int, const struct iovec *, int);
|
||||
ssize_t sys_readv_nt(int, const struct iovec *, int);
|
||||
ssize_t sys_readv_serial(int, const struct iovec *, int);
|
||||
ssize_t sys_write_nt(int, const struct iovec *, size_t, ssize_t);
|
||||
ssize_t sys_writev_metal(struct Fd *, const struct iovec *, int);
|
||||
ssize_t sys_writev_nt(int, const struct iovec *, int);
|
||||
|
|
|
@ -31,6 +31,7 @@ struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
|
|||
struct timeval timeval_subz(struct timeval, struct timeval) pureconst;
|
||||
int64_t timeval_toseconds(struct timeval);
|
||||
int64_t timeval_tomicros(struct timeval);
|
||||
int64_t timeval_tomillis(struct timeval);
|
||||
struct timeval timespec_totimeval(struct timespec) pureconst;
|
||||
static inline struct timeval timeval_fromseconds(int64_t __x) {
|
||||
return (struct timeval){__x};
|
||||
|
|
|
@ -14,9 +14,10 @@ int sys_fadvise_nt(int, uint64_t, uint64_t, int);
|
|||
int sys_fchdir_nt(int);
|
||||
int sys_fchmodat_nt(int, const char *, uint32_t, int);
|
||||
int sys_fcntl_nt(int, int, uintptr_t);
|
||||
int sys_fdatasync_nt(int);
|
||||
int sys_fdatasync_nt(int, bool);
|
||||
int sys_flock_nt(int, int);
|
||||
int sys_fork_nt(uint32_t);
|
||||
int sys_fsync_fake(int);
|
||||
int sys_ftruncate_nt(int64_t, uint64_t);
|
||||
int sys_getloadavg_nt(double *, int);
|
||||
int sys_getppid_nt(void);
|
||||
|
@ -36,6 +37,7 @@ int sys_sync_nt(void);
|
|||
int sys_truncate_nt(const char *, uint64_t);
|
||||
int sys_unlinkat_nt(int, const char *, int);
|
||||
int64_t sys_lseek_nt(int, int64_t, int);
|
||||
ssize_t sys_read_nt_impl(int, void *, size_t, int64_t);
|
||||
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -23,10 +23,14 @@
|
|||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/comms.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -45,18 +49,48 @@ static const char *DescribeFlush(char buf[12], int action) {
|
|||
}
|
||||
|
||||
static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
||||
bool32 ok;
|
||||
int64_t h;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
ok = true;
|
||||
h = g_fds.p[fd].handle;
|
||||
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeRxclear);
|
||||
if (!__isfdopen(fd)) {
|
||||
return ebadf();
|
||||
}
|
||||
if (queue == TCOFLUSH || queue == TCIOFLUSH) {
|
||||
ok &= !!PurgeComm(h, kNtPurgeTxclear);
|
||||
int64_t hConin;
|
||||
if (__isfdkind(fd, kFdConsole)) {
|
||||
hConin = g_fds.p[fd].handle;
|
||||
} else if (fd == 0 || fd == 1 || fd == 2) {
|
||||
hConin = g_fds.p[(fd = 0)].handle;
|
||||
} else {
|
||||
return enotty();
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
uint32_t inmode;
|
||||
if (!GetConsoleMode(hConin, &inmode)) {
|
||||
return enotty();
|
||||
}
|
||||
if (queue == TCOFLUSH) {
|
||||
return 0; // windows console output is never buffered
|
||||
}
|
||||
FlushConsoleInputBuffer(hConin);
|
||||
int rc = 0;
|
||||
int e = errno;
|
||||
int oldflags = g_fds.p[fd].flags;
|
||||
g_fds.p[fd].flags |= O_NONBLOCK;
|
||||
for (;;) {
|
||||
char buf[512];
|
||||
ssize_t got = sys_read_nt_impl(fd, buf, 512, -1);
|
||||
if (!got) {
|
||||
break;
|
||||
} else if (got == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
errno = e;
|
||||
} else if (errno == EINTR) {
|
||||
errno = e;
|
||||
continue;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_fds.p[fd].flags = oldflags;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,7 +111,9 @@ static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
|||
*/
|
||||
int tcflush(int fd, int queue) {
|
||||
int rc;
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
if (queue != TCIFLUSH && queue != TCOFLUSH && queue != TCIOFLUSH) {
|
||||
rc = einval();
|
||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = enotty();
|
||||
} else if (IsLinux()) {
|
||||
rc = sys_ioctl(fd, TCFLSH, queue);
|
||||
|
|
|
@ -22,79 +22,87 @@
|
|||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/baud.internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int tcgetattr_nt(int ignored, struct termios *tio) {
|
||||
int64_t in, out;
|
||||
bool32 inok, outok;
|
||||
uint32_t inmode = 0, outmode = 0;
|
||||
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
|
||||
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
|
||||
if (inok | outok) {
|
||||
bzero(tio, sizeof(*tio));
|
||||
textwindows int tcgetattr_nt(int fd, struct termios *tio) {
|
||||
int64_t hInput, hOutput;
|
||||
uint32_t inmode, outmode;
|
||||
|
||||
tio->c_cc[VMIN] = 1;
|
||||
tio->c_cc[VINTR] = __vintr;
|
||||
tio->c_cc[VQUIT] = __vquit;
|
||||
tio->c_cc[VERASE] = CTRL('?');
|
||||
tio->c_cc[VWERASE] = CTRL('W');
|
||||
tio->c_cc[VKILL] = CTRL('U');
|
||||
tio->c_cc[VEOF] = CTRL('D');
|
||||
tio->c_cc[VMIN] = CTRL('A');
|
||||
tio->c_cc[VSTART] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VSTOP] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VSUSP] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VREPRINT] = CTRL('R');
|
||||
tio->c_cc[VDISCARD] = CTRL('O');
|
||||
tio->c_cc[VLNEXT] = CTRL('V');
|
||||
|
||||
tio->c_iflag = IUTF8;
|
||||
tio->c_lflag = ECHOE;
|
||||
tio->c_cflag = CS8 | CREAD;
|
||||
tio->_c_ispeed = B38400;
|
||||
tio->_c_ospeed = B38400;
|
||||
|
||||
if (inok) {
|
||||
if (inmode & kNtEnableLineInput) {
|
||||
tio->c_lflag |= ICANON;
|
||||
}
|
||||
// kNtEnableEchoInput only works with kNtEnableLineInput enabled.
|
||||
if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) {
|
||||
tio->c_lflag |= ECHO;
|
||||
}
|
||||
// The Windows console itself always echos control codes as ASCII.
|
||||
if ((inmode & kNtEnableEchoInput) || !(__ttymagic & kFdTtyEchoRaw)) {
|
||||
tio->c_lflag |= ECHOCTL;
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
|
||||
tio->c_iflag |= ICRNL;
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
||||
tio->c_lflag |= ISIG;
|
||||
}
|
||||
if ((inmode & kNtEnableProcessedInput) || (__ttymagic & kFdTtyMunging)) {
|
||||
tio->c_lflag |= IEXTEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (outok) {
|
||||
if (outmode & kNtEnableProcessedOutput) {
|
||||
tio->c_oflag |= OPOST;
|
||||
}
|
||||
if (!(outmode & kNtDisableNewlineAutoReturn)) {
|
||||
tio->c_oflag |= OPOST | ONLCR;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (__isfdkind(fd, kFdConsole)) {
|
||||
hInput = g_fds.p[fd].handle;
|
||||
hOutput = g_fds.p[fd].extra;
|
||||
} else if (fd == STDIN_FILENO || //
|
||||
fd == STDOUT_FILENO || //
|
||||
fd == STDERR_FILENO) {
|
||||
hInput = g_fds.p[STDIN_FILENO].handle;
|
||||
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
|
||||
} else {
|
||||
return enotty();
|
||||
}
|
||||
|
||||
if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
|
||||
return enotty();
|
||||
}
|
||||
|
||||
bzero(tio, sizeof(*tio));
|
||||
|
||||
tio->c_cc[VMIN] = 1;
|
||||
tio->c_cc[VINTR] = __vintr;
|
||||
tio->c_cc[VQUIT] = __vquit;
|
||||
tio->c_cc[VERASE] = CTRL('?');
|
||||
tio->c_cc[VWERASE] = CTRL('W');
|
||||
tio->c_cc[VKILL] = CTRL('U');
|
||||
tio->c_cc[VEOF] = CTRL('D');
|
||||
tio->c_cc[VMIN] = CTRL('A');
|
||||
tio->c_cc[VSTART] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VSTOP] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VSUSP] = _POSIX_VDISABLE;
|
||||
tio->c_cc[VREPRINT] = CTRL('R');
|
||||
tio->c_cc[VDISCARD] = CTRL('O');
|
||||
tio->c_cc[VLNEXT] = CTRL('V');
|
||||
|
||||
tio->c_iflag = IUTF8;
|
||||
tio->c_lflag = ECHOE;
|
||||
tio->c_cflag = CS8 | CREAD;
|
||||
tio->_c_ispeed = B38400;
|
||||
tio->_c_ospeed = B38400;
|
||||
|
||||
if (inmode & kNtEnableLineInput) {
|
||||
tio->c_lflag |= ICANON;
|
||||
}
|
||||
// kNtEnableEchoInput only works with kNtEnableLineInput enabled.
|
||||
if ((inmode & kNtEnableEchoInput) || (__ttymagic & kFdTtyEchoing)) {
|
||||
tio->c_lflag |= ECHO;
|
||||
}
|
||||
// The Windows console itself always echos control codes as ASCII.
|
||||
if ((inmode & kNtEnableEchoInput) || !(__ttymagic & kFdTtyEchoRaw)) {
|
||||
tio->c_lflag |= ECHOCTL;
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoCr2Nl)) {
|
||||
tio->c_iflag |= ICRNL;
|
||||
}
|
||||
if (!(__ttymagic & kFdTtyNoIsigs)) {
|
||||
tio->c_lflag |= ISIG;
|
||||
}
|
||||
if ((inmode & kNtEnableProcessedInput) || (__ttymagic & kFdTtyMunging)) {
|
||||
tio->c_lflag |= IEXTEN;
|
||||
}
|
||||
|
||||
if (outmode & kNtEnableProcessedOutput) {
|
||||
tio->c_oflag |= OPOST;
|
||||
}
|
||||
if (!(outmode & kNtDisableNewlineAutoReturn)) {
|
||||
tio->c_oflag |= OPOST | ONLCR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,15 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/metatermios.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/termios.internal.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
|
@ -32,6 +35,7 @@
|
|||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
@ -166,94 +170,92 @@ textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
|||
bool32 ok;
|
||||
int64_t hInput, hOutput;
|
||||
uint32_t inmode, outmode;
|
||||
|
||||
if (__isfdkind(fd, kFdConsole)) {
|
||||
// program manually opened /dev/tty in O_RDWR mode for cmd.exe
|
||||
hInput = g_fds.p[fd].handle;
|
||||
hOutput = g_fds.p[fd].extra;
|
||||
} else if (fd == 0 || fd == 1) {
|
||||
// otherwise just assume cmd.exe console stdio
|
||||
// there's no serial port support yet
|
||||
hInput = g_fds.p[0].handle;
|
||||
hOutput = g_fds.p[1].handle;
|
||||
fd = 0;
|
||||
} else if (fd == STDIN_FILENO || //
|
||||
fd == STDOUT_FILENO || //
|
||||
fd == STDERR_FILENO) {
|
||||
hInput = g_fds.p[STDIN_FILENO].handle;
|
||||
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
|
||||
} else {
|
||||
STRACE("tcsetattr(fd) must be 0, 1, or open'd /dev/tty");
|
||||
return enotty();
|
||||
}
|
||||
if (GetConsoleMode(hInput, &inmode) && GetConsoleMode(hOutput, &outmode)) {
|
||||
|
||||
if (opt == TCSAFLUSH) {
|
||||
FlushConsoleInputBuffer(hInput);
|
||||
}
|
||||
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
|
||||
inmode |= kNtEnableWindowInput;
|
||||
__ttymagic = 0;
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
|
||||
} else {
|
||||
__ttymagic |= kFdTtyMunging;
|
||||
if (tio->c_cc[VMIN] != 1) {
|
||||
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
|
||||
return einval();
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
// - keys like f1, up, etc. get turned into \e ansi codes
|
||||
// - totally destroys default console gui (e.g. up arrow)
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
}
|
||||
if (!(tio->c_iflag & ICRNL)) {
|
||||
__ttymagic |= kFdTtyNoCr2Nl;
|
||||
}
|
||||
if (!(tio->c_lflag & ECHOCTL)) {
|
||||
__ttymagic |= kFdTtyEchoRaw;
|
||||
}
|
||||
if (tio->c_lflag & ECHO) {
|
||||
// "kNtEnableEchoInput can be used only if the
|
||||
// kNtEnableLineInput mode is also enabled." -MSDN
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableEchoInput;
|
||||
} else {
|
||||
// If ECHO is enabled in raw mode, then read(0) needs to
|
||||
// magically write(1) to simulate echoing. This normally
|
||||
// visualizes control codes, e.g. \r → ^M unless ECHOCTL
|
||||
// hasn't been specified.
|
||||
__ttymagic |= kFdTtyEchoing;
|
||||
}
|
||||
}
|
||||
if (!(tio->c_lflag & ISIG)) {
|
||||
__ttymagic |= kFdTtyNoIsigs;
|
||||
}
|
||||
__vintr = tio->c_cc[VINTR];
|
||||
__vquit = tio->c_cc[VQUIT];
|
||||
if ((tio->c_lflag & ISIG) && //
|
||||
tio->c_cc[VINTR] == CTRL('C')) {
|
||||
// allows ctrl-c to be delivered asynchronously via win32
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
ok = SetConsoleMode(hInput, inmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hInput,
|
||||
DescribeNtConsoleInFlags(inmode), ok);
|
||||
if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
|
||||
return enotty();
|
||||
}
|
||||
|
||||
outmode &= ~kNtDisableNewlineAutoReturn;
|
||||
outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & ONLCR)) {
|
||||
outmode |= kNtDisableNewlineAutoReturn;
|
||||
if (opt == TCSAFLUSH) {
|
||||
tcflush(fd, TCIFLUSH);
|
||||
}
|
||||
inmode &= ~(kNtEnableLineInput | kNtEnableEchoInput |
|
||||
kNtEnableProcessedInput | kNtEnableVirtualTerminalInput);
|
||||
inmode |= kNtEnableWindowInput;
|
||||
__ttymagic = 0;
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableLineInput | kNtEnableProcessedInput;
|
||||
} else {
|
||||
__ttymagic |= kFdTtyMunging;
|
||||
if (tio->c_cc[VMIN] != 1) {
|
||||
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
|
||||
return einval();
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
// - keys like f1, up, etc. get turned into \e ansi codes
|
||||
// - totally destroys default console gui (e.g. up arrow)
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
ok = SetConsoleMode(hOutput, outmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hOutput,
|
||||
DescribeNtConsoleOutFlags(outmode), ok);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return enotty();
|
||||
}
|
||||
if (!(tio->c_iflag & ICRNL)) {
|
||||
__ttymagic |= kFdTtyNoCr2Nl;
|
||||
}
|
||||
if (!(tio->c_lflag & ECHOCTL)) {
|
||||
__ttymagic |= kFdTtyEchoRaw;
|
||||
}
|
||||
if (tio->c_lflag & ECHO) {
|
||||
// "kNtEnableEchoInput can be used only if the
|
||||
// kNtEnableLineInput mode is also enabled." -MSDN
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableEchoInput;
|
||||
} else {
|
||||
// If ECHO is enabled in raw mode, then read(0) needs to
|
||||
// magically write(1) to simulate echoing. This normally
|
||||
// visualizes control codes, e.g. \r → ^M unless ECHOCTL
|
||||
// hasn't been specified.
|
||||
__ttymagic |= kFdTtyEchoing;
|
||||
}
|
||||
}
|
||||
if (!(tio->c_lflag & ISIG)) {
|
||||
__ttymagic |= kFdTtyNoIsigs;
|
||||
}
|
||||
__vintr = tio->c_cc[VINTR];
|
||||
__vquit = tio->c_cc[VQUIT];
|
||||
if ((tio->c_lflag & ISIG) && //
|
||||
tio->c_cc[VINTR] == CTRL('C')) {
|
||||
// allows ctrl-c to be delivered asynchronously via win32
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
ok = SetConsoleMode(hInput, inmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hInput,
|
||||
DescribeNtConsoleInFlags(inmode), ok);
|
||||
|
||||
outmode &= ~kNtDisableNewlineAutoReturn;
|
||||
outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & ONLCR)) {
|
||||
outmode |= kNtDisableNewlineAutoReturn;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
}
|
||||
ok = SetConsoleMode(hOutput, outmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hOutput,
|
||||
DescribeNtConsoleOutFlags(outmode), ok);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void tcsetattr_nt_init(void) {
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
@ -60,6 +62,7 @@ __msabi extern typeof(CreateFile) *const __imp_CreateFileW;
|
|||
__msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW;
|
||||
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
|
||||
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
||||
__msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
|
||||
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
|
||||
|
@ -78,78 +81,97 @@ static void Log(const char *s) {
|
|||
#endif
|
||||
}
|
||||
|
||||
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t
|
||||
WinStdinThread(void *lpParameter) {
|
||||
char buf[4096];
|
||||
__msabi static textwindows uint32_t WinStdinThread(void *lpParameter) {
|
||||
char buf[4];
|
||||
uint32_t i, got, wrote;
|
||||
|
||||
// wait forever for semaphore to exceed 0
|
||||
//
|
||||
// this semaphore is unlocked the first time read or poll happens. we
|
||||
// need it so the prog has time to call functions like SetConsoleMode
|
||||
// before we begin performing i/o.
|
||||
__imp_WaitForSingleObject(g_fds.stdin.inisem, -1u);
|
||||
__imp_CloseHandle(g_fds.stdin.inisem);
|
||||
|
||||
// relay stdin to process
|
||||
Log("<stdin> activated\n");
|
||||
Log("<stdin> activated thread\n");
|
||||
for (;;) {
|
||||
Log("<stdin> wait\n");
|
||||
__imp_WaitForSingleObject(g_fds.stdin.inisem, -1u);
|
||||
Log("<stdin> read\n");
|
||||
if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) {
|
||||
Log("<stdin> read failed\n");
|
||||
goto Finish;
|
||||
}
|
||||
if (!got) {
|
||||
Log("<stdin> end of file\n");
|
||||
Log("<stdin> eof\n");
|
||||
goto Finish;
|
||||
}
|
||||
for (i = 0; i < got; i += wrote) {
|
||||
Log("<stdin> write");
|
||||
if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) {
|
||||
Log("<stdin> failed to write to pipe\n");
|
||||
Log("<stdin> write failed\n");
|
||||
goto Finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Finish:
|
||||
__imp_CloseHandle(g_fds.stdin.writer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows static char16_t *FixCpy(char16_t p[17], uint64_t x, uint8_t k) {
|
||||
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
textwindows static char16_t *CreateStdinPipeName(char16_t *a, int64_t h) {
|
||||
char16_t *p = a;
|
||||
const char *q = "\\\\?\\pipe\\cosmo\\stdin\\";
|
||||
while (*q) *p++ = *q++;
|
||||
p = FixCpy(p, h, 64);
|
||||
*p = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
// this makes it possible for our read() implementation to periodically
|
||||
// poll for signals while performing a blocking overlapped io operation
|
||||
dontasan dontubsan dontinstrument textwindows void WinMainStdin(void) {
|
||||
textwindows void WinMainStdin(void) {
|
||||
char16_t pipename[64];
|
||||
int64_t hStdin, hWriter, hReader, hThread, hSemaphore;
|
||||
if (!SupportsWindows()) return;
|
||||
// handle numbers stay the same when inherited by the subprocesses
|
||||
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
|
||||
if (hStdin == kNtInvalidHandleValue) {
|
||||
Log("<stdin> GetStdHandle failed\n");
|
||||
return;
|
||||
}
|
||||
// create non-inherited semaphore with initial value of 0
|
||||
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
|
||||
if (!hSemaphore) {
|
||||
Log("<stdin> CreateSemaphore failed\n");
|
||||
return;
|
||||
}
|
||||
__create_pipe_name(pipename);
|
||||
hReader = __imp_CreateNamedPipeW(
|
||||
pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped,
|
||||
kNtPipeTypeByte | kNtPipeReadmodeByte, 1, 4096, 4096, 0, 0);
|
||||
if (hReader == kNtInvalidHandleValue) {
|
||||
Log("<stdin> CreateNamedPipe failed\n");
|
||||
return;
|
||||
}
|
||||
hWriter = __imp_CreateFileW(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
|
||||
CreateStdinPipeName(pipename, hStdin);
|
||||
hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
|
||||
kNtFileFlagOverlapped, 0);
|
||||
if (hWriter == kNtInvalidHandleValue) {
|
||||
Log("<stdin> CreateFile failed\n");
|
||||
return;
|
||||
}
|
||||
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
|
||||
if (!hThread) {
|
||||
Log("<stdin> CreateThread failed\n");
|
||||
return;
|
||||
if (hReader == kNtInvalidHandleValue) {
|
||||
// we are the init process; create pipe server to dole out stdin
|
||||
hWriter = __imp_CreateNamedPipeW(
|
||||
pipename, kNtPipeAccessOutbound | kNtFileFlagOverlapped,
|
||||
kNtPipeTypeMessage | kNtPipeReadmodeMessage | kNtPipeNowait,
|
||||
kNtPipeUnlimitedInstances, 4096, 4096, 0, 0);
|
||||
if (hWriter == kNtInvalidHandleValue) {
|
||||
Log("<stdin> CreateNamedPipe failed\n");
|
||||
return;
|
||||
}
|
||||
hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
|
||||
kNtFileFlagOverlapped, 0);
|
||||
if (hReader == kNtInvalidHandleValue) {
|
||||
Log("<stdin> CreateFile failed\n");
|
||||
return;
|
||||
}
|
||||
// create non-inherited semaphore with initial value of 0
|
||||
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
|
||||
if (!hSemaphore) {
|
||||
Log("<stdin> CreateSemaphore failed\n");
|
||||
return;
|
||||
}
|
||||
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
|
||||
if (!hThread) {
|
||||
Log("<stdin> CreateThread failed\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// we are the child of a cosmo process with its own stdin thread
|
||||
hWriter = 0;
|
||||
hThread = 0;
|
||||
hSemaphore = 0;
|
||||
}
|
||||
g_fds.stdin.handle = hStdin;
|
||||
g_fds.stdin.thread = hThread;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
textwindows int64_t __resolve_stdin_handle(int64_t handle) {
|
||||
if (handle == g_fds.stdin.handle) {
|
||||
if (!atomic_exchange(&g_fds.stdin.once, 1)) {
|
||||
if (g_fds.stdin.inisem) {
|
||||
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
|
||||
}
|
||||
handle = g_fds.stdin.reader;
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § string formatting ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */
|
||||
|
@ -13,15 +10,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int snprintf(char *, size_t, const char *, ...)
|
||||
printfesque(3) dontthrow nocallback;
|
||||
int vsnprintf(char *, size_t, const char *, va_list)
|
||||
dontthrow nocallback;
|
||||
int sprintf(char *, const char *, ...) dontthrow nocallback;
|
||||
int vsprintf(char *, const char *, va_list)
|
||||
dontthrow nocallback;
|
||||
int sscanf(const char *, const char *, ...) scanfesque(2);
|
||||
int vsscanf(const char *, const char *, va_list);
|
||||
char *fcvt(double, int, int *, int *);
|
||||
char *ecvt(double, int, int *, int *);
|
||||
char *gcvt(double, int, char *);
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _POLLTRACE 1 /* not configurable w/ flag yet */
|
||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||
#define _STDIOTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
||||
|
||||
#define STRACE_PROLOGUE "%rSYS %6P %'18T "
|
||||
|
||||
|
|
19
libc/isystem/linux/param.h
Normal file
19
libc/isystem/linux/param.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _LINUX_PARAM_H
|
||||
#define _LINUX_PARAM_H
|
||||
#include "libc/runtime/clktck.h"
|
||||
|
||||
#ifndef HZ
|
||||
#define HZ CLK_TCK
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_PAGESIZE
|
||||
#define EXEC_PAGESIZE 65536
|
||||
#endif
|
||||
|
||||
#ifndef NOGROUP
|
||||
#define NOGROUP (-1)
|
||||
#endif
|
||||
|
||||
#define MAXHOSTNAMELEN 64
|
||||
|
||||
#endif
|
|
@ -1,3 +1,4 @@
|
|||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
#include "libc/stdio/stdio.h"
|
||||
#endif /* _STDARG_H */
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
#include "libc/sysv/consts/sio.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
static uint32_t *GetUnixIps(void) {
|
||||
int fd, n;
|
||||
uint64_t z;
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
||||
size_t iovlen, uint32_t flags) {
|
||||
textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||
uint32_t flags) {
|
||||
int err;
|
||||
ssize_t rc;
|
||||
uint32_t got;
|
||||
|
@ -37,17 +37,18 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
err = errno;
|
||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
||||
&overlapped, 0)) {
|
||||
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
|
||||
if (!WSARecv(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||
&flags, &overlapped, 0)) {
|
||||
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
|
||||
&flags)) {
|
||||
rc = got;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
errno = err;
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
|
||||
sockfd = (struct SockFd *)g_fds.p[fd].extra;
|
||||
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
|
||||
sockfd->rcvtimeo);
|
||||
}
|
||||
unassert(WSACloseEvent(overlapped.hEvent));
|
||||
|
|
|
@ -53,12 +53,12 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
|
|||
rc = sys_recvfrom(fd, buf, size, flags, 0, 0);
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_recv_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags);
|
||||
rc = sys_recv_nt(fd, (struct iovec[]){{buf, size}}, 1, flags);
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
if (flags) {
|
||||
rc = einval();
|
||||
} else {
|
||||
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, -1);
|
||||
rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, -1);
|
||||
}
|
||||
} else {
|
||||
rc = enotsock();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
|
||||
textwindows ssize_t sys_recvfrom_nt(int fd, const struct iovec *iov,
|
||||
size_t iovlen, uint32_t flags,
|
||||
void *opt_out_srcaddr,
|
||||
uint32_t *opt_inout_srcaddrsize) {
|
||||
|
@ -36,17 +36,19 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
err = errno;
|
||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
||||
opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) {
|
||||
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
|
||||
if (!WSARecvFrom(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
||||
NULL)) {
|
||||
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
|
||||
&flags)) {
|
||||
rc = got;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
errno = err;
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
|
||||
sockfd = (struct SockFd *)g_fds.p[fd].extra;
|
||||
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
|
||||
sockfd->rcvtimeo);
|
||||
}
|
||||
WSACloseEvent(overlapped.hEvent);
|
||||
|
|
|
@ -68,11 +68,11 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
|||
rc = sys_recvfrom(fd, buf, size, flags, &addr, &addrsize);
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
|
||||
flags, &addr, &addrsize);
|
||||
rc = sys_recvfrom_nt(fd, (struct iovec[]){{buf, size}}, 1, flags, &addr,
|
||||
&addrsize);
|
||||
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
|
||||
if (!flags) {
|
||||
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, -1);
|
||||
rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, -1);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
|
|
|
@ -74,12 +74,12 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
|||
} else if (__isfdopen(fd)) {
|
||||
if (!msg->msg_control) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_recvfrom_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen, flags,
|
||||
rc = sys_recvfrom_nt(fd, msg->msg_iov, msg->msg_iovlen, flags,
|
||||
msg->msg_name, &msg->msg_namelen);
|
||||
} else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */
|
||||
if (!flags) {
|
||||
if ((got = sys_read_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen,
|
||||
-1)) != -1) {
|
||||
if ((got = sys_read_nt(fd, msg->msg_iov, msg->msg_iovlen, -1)) !=
|
||||
-1) {
|
||||
msg->msg_flags = 0;
|
||||
rc = got;
|
||||
} else {
|
||||
|
|
|
@ -56,8 +56,10 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
|||
}
|
||||
|
||||
// convert the wait time to a word
|
||||
if (!timeout || ckd_add(&millis, timeout->tv_sec, timeout->tv_usec / 1000)) {
|
||||
if (!timeout) {
|
||||
millis = -1;
|
||||
} else {
|
||||
millis = timeval_tomillis(*timeout);
|
||||
}
|
||||
|
||||
// call our nt poll implementation
|
||||
|
@ -76,8 +78,7 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
|||
|
||||
// store remaining time back in caller's timeval
|
||||
if (timeout) {
|
||||
timeout->tv_sec = millis / 1000;
|
||||
timeout->tv_usec = millis % 1000 * 1000;
|
||||
*timeout = timeval_frommillis(millis);
|
||||
}
|
||||
|
||||
return fdcount;
|
||||
|
|
|
@ -17,9 +17,9 @@ int sys_getsockopt_nt(struct Fd *, int, int, void *, uint32_t *);
|
|||
int sys_listen_nt(struct Fd *, int);
|
||||
int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t);
|
||||
int sys_shutdown_nt(struct Fd *, int);
|
||||
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t);
|
||||
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
|
||||
void *, uint32_t *);
|
||||
ssize_t sys_recv_nt(int, const struct iovec *, size_t, uint32_t);
|
||||
ssize_t sys_recvfrom_nt(int, const struct iovec *, size_t, uint32_t, void *,
|
||||
uint32_t *);
|
||||
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/unicode.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Formats string to buffer.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* String decoder.
|
||||
|
|
|
@ -108,6 +108,14 @@ int vscanf(const char *, va_list);
|
|||
int fscanf(FILE *, const char *, ...) scanfesque(2);
|
||||
int vfscanf(FILE *, const char *, va_list);
|
||||
|
||||
int snprintf(char *, size_t, const char *, ...)
|
||||
printfesque(3) dontthrow nocallback;
|
||||
int vsnprintf(char *, size_t, const char *, va_list)
|
||||
dontthrow nocallback;
|
||||
int sprintf(char *, const char *, ...) dontthrow nocallback;
|
||||
int vsprintf(char *, const char *, va_list)
|
||||
dontthrow nocallback;
|
||||
|
||||
int fwprintf(FILE *, const wchar_t *, ...);
|
||||
int fwscanf(FILE *, const wchar_t *, ...);
|
||||
int swprintf(wchar_t *, size_t, const wchar_t *, ...);
|
||||
|
@ -122,6 +130,9 @@ int wprintf(const wchar_t *, ...);
|
|||
int wscanf(const wchar_t *, ...);
|
||||
int fwide(FILE *, int);
|
||||
|
||||
int sscanf(const char *, const char *, ...) scanfesque(2);
|
||||
int vsscanf(const char *, const char *, va_list);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § standard i/o » allocating ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
#define W sizeof(size_t)
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Formats string w/ dynamic memory allocation.
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Formats string to buffer hopefully large enough w/ vararg state.
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
static size_t sbufi_;
|
||||
|
|
37
test/libc/calls/fchdir_test.c
Normal file
37
test/libc/calls/fchdir_test.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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 2023 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/mem/gc.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
TEST(fchdir, test) {
|
||||
const char *a, *b;
|
||||
ASSERT_SYS(0, 0, mkdir("dog", 0755));
|
||||
ASSERT_SYS(0, 0, chdir("dog"));
|
||||
ASSERT_NE(NULL, (a = gc(getcwd(0, 0))));
|
||||
ASSERT_SYS(0, 3, open(".", O_RDONLY));
|
||||
ASSERT_SYS(0, 0, chdir("/"));
|
||||
ASSERT_SYS(0, 0, fchdir(3));
|
||||
ASSERT_NE(NULL, (b = gc(getcwd(0, 0))));
|
||||
ASSERT_STREQ(a, b);
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
|
@ -21,12 +21,12 @@
|
|||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -29,6 +28,7 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
|
|
@ -91,7 +91,7 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
|
|||
return;
|
||||
}
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
@ -191,7 +191,7 @@ TEST(ShowCrashReports, testDivideByZero) {
|
|||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
@ -315,7 +315,7 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
|
|||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
@ -393,7 +393,7 @@ TEST(ShowCrashReports, testNpeCrash) {
|
|||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
@ -452,7 +452,7 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
|||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
@ -506,7 +506,7 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
|||
int ws, pid, fds[2];
|
||||
char *output, buf[512];
|
||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
|
@ -34,6 +33,7 @@
|
|||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/ftw.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
│ THE SOFTWARE. │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/pushpop.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
|
@ -33,6 +32,7 @@
|
|||
#include "libc/math.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/temp.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/semaphore.h"
|
||||
|
@ -107,7 +107,7 @@ TEST(sem_close, withUnnamedSemaphore_isUndefinedBehavior) {
|
|||
SPAWN(fork);
|
||||
IgnoreStderr();
|
||||
sem_close(&sem);
|
||||
EXITS(128 + SIGABRT); // see __assert_fail
|
||||
TERMS(SIGABRT); // see __assert_fail
|
||||
ASSERT_SYS(0, 0, sem_destroy(&sem));
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ TEST(sem_destroy, withNamedSemaphore_isUndefinedBehavior) {
|
|||
SPAWN(fork);
|
||||
IgnoreStderr();
|
||||
sem_destroy(sem);
|
||||
EXITS(128 + SIGABRT); // see __assert_fail
|
||||
TERMS(SIGABRT); // see __assert_fail
|
||||
ASSERT_SYS(0, 0, sem_unlink("/boop"));
|
||||
ASSERT_SYS(0, 0, sem_close(sem));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/complex.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(complex, test) {
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/fenv.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
|
|
3
third_party/argon2/encoding.c
vendored
3
third_party/argon2/encoding.c
vendored
|
@ -15,11 +15,12 @@
|
|||
│ - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/argon2/encoding.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/argon2/core.h"
|
||||
#include "third_party/argon2/encoding.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
argon2 (CC0 or Apache2)\\n\
|
||||
|
|
2
third_party/finger/util.c
vendored
2
third_party/finger/util.c
vendored
|
@ -37,10 +37,10 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/stat.macros.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "third_party/finger/finger.h"
|
||||
|
|
2
third_party/lua/luaconf.h
vendored
2
third_party/lua/luaconf.h
vendored
|
@ -3,8 +3,8 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/unicode.h"
|
||||
|
||||
#define LUA_USE_POSIX
|
||||
|
|
2
third_party/musl/strfmon.c
vendored
2
third_party/musl/strfmon.c
vendored
|
@ -26,7 +26,7 @@
|
|||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/locale.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
|
2
third_party/regex/regerror.c
vendored
2
third_party/regex/regerror.c
vendored
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/regex/regex.h"
|
||||
|
||||
|
|
2
third_party/zlib/gz/gzlib.c
vendored
2
third_party/zlib/gz/gzlib.c
vendored
|
@ -6,9 +6,9 @@
|
|||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "third_party/zlib/gz/gzguts.inc"
|
||||
|
|
2
third_party/zlib/gz/gzwrite.c
vendored
2
third_party/zlib/gz/gzwrite.c
vendored
|
@ -6,8 +6,8 @@
|
|||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/zlib/gz/gzguts.inc"
|
||||
// clang-format off
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
#include "tool/build/lib/buffer.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/* TODO(jart): replace with new append*() library */
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue