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/calls/termios.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/sock/struct/pollfd.h"
|
#include "libc/sock/struct/pollfd.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/errfuns.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/ │
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
@ -15,7 +16,9 @@
|
||||||
#include "libc/sock/struct/pollfd.h"
|
#include "libc/sock/struct/pollfd.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/limits.h"
|
#include "libc/sysv/consts/limits.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/sig.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
|
// some programs are blocked on cpu rather than i/o
|
||||||
// such programs shall rely on asynchronous signals
|
// such programs shall rely on asynchronous signals
|
||||||
printf("doing cpu task...\n");
|
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) {
|
if (gotsig) {
|
||||||
printf("\rgot ctrl+c asynchronously\n");
|
printf("\rgot ctrl+c asynchronously\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -55,7 +58,7 @@ int main(int argc, char *argv[]) {
|
||||||
// posix guarantees atomic i/o if you use pipe_buf sized buffers
|
// 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
|
// that way we don't need to worry about things like looping and
|
||||||
// we can also be assured that multiple actors wont have tearing
|
// we can also be assured that multiple actors wont have tearing
|
||||||
char buf[PIPE_BUF];
|
char buf[4];
|
||||||
|
|
||||||
// read data from standard input
|
// 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
|
// operating system will send SIGPIPE if there's any problem
|
||||||
// which kills the process by default
|
// which kills the process by default
|
||||||
write(1, buf, got);
|
write(1, buf, got);
|
||||||
|
write(1, "\n", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sock/select.h"
|
||||||
#include "libc/stdio/dprintf.h"
|
#include "libc/stdio/dprintf.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -26,6 +28,8 @@
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/x/xsigaction.h"
|
#include "libc/x/xsigaction.h"
|
||||||
|
|
||||||
|
__static_yoink("WinMainStdin");
|
||||||
|
|
||||||
#define CTRL(C) ((C) ^ 0b01000000)
|
#define CTRL(C) ((C) ^ 0b01000000)
|
||||||
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
||||||
#define ENABLE_SAFE_PASTE "\e[?2004h"
|
#define ENABLE_SAFE_PASTE "\e[?2004h"
|
||||||
|
|
|
@ -93,6 +93,12 @@ o/$(MODE)/libc/calls/vdsofunc.greg.o: private \
|
||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-fno-sanitize=address
|
-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:
|
# we can't use asan because:
|
||||||
# ntspawn allocates 128kb of heap memory via win32
|
# ntspawn allocates 128kb of heap memory via win32
|
||||||
o/$(MODE)/libc/calls/ntspawn.o \
|
o/$(MODE)/libc/calls/ntspawn.o \
|
||||||
|
|
|
@ -17,12 +17,15 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int sys_fdatasync_nt(int fd) {
|
textwindows int sys_fdatasync_nt(int fd, bool fake) {
|
||||||
// TODO(jart): what should we do with worker pipes?
|
if (!__isfdopen(fd)) return ebadf();
|
||||||
if (!__isfdkind(fd, kFdFile)) 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 (_check_interrupts(0)) return -1;
|
||||||
|
if (fake) return 0;
|
||||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,39 +18,46 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/cp.internal.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-nt.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until kernel flushes non-metadata buffers for fd to disk.
|
* Blocks until kernel flushes non-metadata buffers for fd to disk.
|
||||||
*
|
*
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @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 sync(), fsync(), sync_file_range()
|
||||||
* @see __nosync to secretly disable
|
* @see __nosync to secretly disable
|
||||||
* @raise ECANCELED if thread was cancelled in masked mode
|
|
||||||
* @raise EINTR if signal was delivered
|
|
||||||
* @cancellationpoint
|
* @cancellationpoint
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int fdatasync(int fd) {
|
int fdatasync(int fd) {
|
||||||
int rc;
|
int rc;
|
||||||
struct stat st;
|
bool fake = __nosync == 0x5453455454534146;
|
||||||
if (__nosync != 0x5453455454534146) {
|
BEGIN_CANCELLATION_POINT;
|
||||||
BEGIN_CANCELLATION_POINT;
|
if (__isfdkind(fd, kFdZip)) {
|
||||||
if (!IsWindows()) {
|
rc = erofs();
|
||||||
|
} else if (!IsWindows()) {
|
||||||
|
if (!fake) {
|
||||||
rc = sys_fdatasync(fd);
|
rc = sys_fdatasync(fd);
|
||||||
} else {
|
} else {
|
||||||
rc = sys_fdatasync_nt(fd);
|
rc = sys_fsync_fake(fd);
|
||||||
}
|
}
|
||||||
END_CANCELLATION_POINT;
|
|
||||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
|
||||||
} else {
|
} else {
|
||||||
rc = fstat(fd, &st);
|
rc = sys_fdatasync_nt(fd, fake);
|
||||||
STRACE("fdatasync_fake(%d) → %d% m", fd, rc);
|
|
||||||
}
|
}
|
||||||
|
END_CANCELLATION_POINT;
|
||||||
|
STRACE("fdatasync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
|
||||||
return 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/calls.h"
|
||||||
#include "libc/calls/cp.internal.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-nt.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until kernel flushes buffers for fd to disk.
|
* Blocks until kernel flushes buffers for fd to disk.
|
||||||
*
|
*
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @raise ECANCELED if thread was cancelled in masked mode
|
* @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 EINTR if signal was delivered
|
||||||
|
* @raise EIO if an i/o error happened
|
||||||
* @see fdatasync(), sync_file_range()
|
* @see fdatasync(), sync_file_range()
|
||||||
* @see __nosync to secretly disable
|
* @see __nosync to secretly disable
|
||||||
* @cancellationpoint
|
* @cancellationpoint
|
||||||
|
@ -38,19 +44,20 @@
|
||||||
*/
|
*/
|
||||||
int fsync(int fd) {
|
int fsync(int fd) {
|
||||||
int rc;
|
int rc;
|
||||||
struct stat st;
|
bool fake = __nosync == 0x5453455454534146;
|
||||||
if (__nosync != 0x5453455454534146) {
|
BEGIN_CANCELLATION_POINT;
|
||||||
BEGIN_CANCELLATION_POINT;
|
if (__isfdkind(fd, kFdZip)) {
|
||||||
if (!IsWindows()) {
|
rc = erofs();
|
||||||
|
} else if (!IsWindows()) {
|
||||||
|
if (!fake) {
|
||||||
rc = sys_fsync(fd);
|
rc = sys_fsync(fd);
|
||||||
} else {
|
} else {
|
||||||
rc = sys_fdatasync_nt(fd);
|
rc = sys_fsync_fake(fd);
|
||||||
}
|
}
|
||||||
END_CANCELLATION_POINT;
|
|
||||||
STRACE("fsync(%d) → %d% m", fd, rc);
|
|
||||||
} else {
|
} else {
|
||||||
rc = fstat(fd, &st);
|
rc = sys_fdatasync_nt(fd, fake);
|
||||||
STRACE("fsync_fake(%d) → %d% m", fd, rc);
|
|
||||||
}
|
}
|
||||||
|
END_CANCELLATION_POINT;
|
||||||
|
STRACE("fsync%s(%d) → %d% m", fake ? "_fake" : "", fd, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/createfile.h"
|
#include "libc/nt/createfile.h"
|
||||||
#include "libc/nt/enum/accessmask.h"
|
#include "libc/nt/enum/accessmask.h"
|
||||||
#include "libc/nt/enum/creationdisposition.h"
|
#include "libc/nt/enum/creationdisposition.h"
|
||||||
|
@ -144,14 +145,20 @@ static textwindows int sys_open_nt_console(int dirfd,
|
||||||
const struct NtMagicPaths *mp,
|
const struct NtMagicPaths *mp,
|
||||||
uint32_t flags, int32_t mode,
|
uint32_t flags, int32_t mode,
|
||||||
size_t fd) {
|
size_t fd) {
|
||||||
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
|
uint32_t cm;
|
||||||
GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) {
|
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
|
// 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].handle = g_fds.p[input].handle;
|
||||||
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
|
g_fds.p[fd].extra = g_fds.p[output].handle;
|
||||||
g_fds.p[STDOUT_FILENO].dontclose = true;
|
|
||||||
g_fds.p[STDIN_FILENO].dontclose = true;
|
|
||||||
g_fds.p[fd].dontclose = true;
|
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(
|
} else if ((g_fds.p[fd].handle = sys_open_nt_impl(
|
||||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
|
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
|
||||||
kNtFileFlagOverlapped)) != -1) {
|
kNtFileFlagOverlapped)) != -1) {
|
||||||
|
@ -187,7 +194,7 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
__fds_lock();
|
__fds_lock();
|
||||||
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
|
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);
|
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||||
} else {
|
} else {
|
||||||
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
|
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)) {
|
} else if (__isfdkind(fd, kFdSocket)) {
|
||||||
rc = espipe();
|
rc = espipe();
|
||||||
} else if (__isfdkind(fd, kFdFile)) {
|
} 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 {
|
} else {
|
||||||
rc = ebadf();
|
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) {
|
if (g_fds.p[fd].kind == kFdSocket) {
|
||||||
return espipe();
|
return espipe();
|
||||||
} else {
|
} else {
|
||||||
return sys_read_nt(g_fds.p + fd, iov, iovlen, off);
|
return sys_read_nt(fd, iov, iovlen, off);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ebadf();
|
return ebadf();
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "libc/nt/struct/overlapped.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
|
#include "libc/nt/thunk/msabi.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
|
@ -48,19 +49,24 @@
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
__static_yoink("WinMainStdin");
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
|
||||||
|
|
||||||
static textwindows void sys_read_nt_abort(int64_t handle,
|
static textwindows void sys_read_nt_abort(int64_t handle,
|
||||||
struct NtOverlapped *overlapped) {
|
struct NtOverlapped *overlapped) {
|
||||||
unassert(CancelIoEx(handle, overlapped) ||
|
unassert(CancelIoEx(handle, overlapped) ||
|
||||||
GetLastError() == kNtErrorNotFound);
|
GetLastError() == kNtErrorNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
|
||||||
size_t size, int64_t offset) {
|
int64_t offset) {
|
||||||
|
|
||||||
// perform the read i/o operation
|
// perform the read i/o operation
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
|
struct Fd *f;
|
||||||
uint32_t got;
|
uint32_t got;
|
||||||
int filetype;
|
int filetype;
|
||||||
int64_t handle;
|
int64_t handle;
|
||||||
|
@ -69,27 +75,28 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
||||||
uint32_t targetsize;
|
uint32_t targetsize;
|
||||||
bool is_console_input;
|
bool is_console_input;
|
||||||
int abort_errno = EAGAIN;
|
int abort_errno = EAGAIN;
|
||||||
|
f = g_fds.p + fd;
|
||||||
StartOver:
|
StartOver:
|
||||||
size = MIN(size, 0x7ffff000);
|
size = MIN(size, 0x7ffff000);
|
||||||
handle = __resolve_stdin_handle(fd->handle);
|
handle = __resolve_stdin_handle(f->handle);
|
||||||
filetype = GetFileType(handle);
|
filetype = GetFileType(handle);
|
||||||
is_console_input = g_fds.stdin.handle ? fd->handle == g_fds.stdin.handle
|
is_console_input = g_fds.stdin.handle ? f->handle == g_fds.stdin.handle
|
||||||
: fd->handle == g_fds.p[0].handle;
|
: f->handle == g_fds.p[0].handle;
|
||||||
|
|
||||||
// the caller might be reading a single byte at a time. but we need to
|
// 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"
|
// be able to munge three bytes into just 1 e.g. "\342\220\200" → "\0"
|
||||||
if (size && fd->buflen) {
|
if (size && f->buflen) {
|
||||||
ReturnDataFromBuffer:
|
ReturnDataFromBuffer:
|
||||||
got = MIN(size, fd->buflen);
|
got = MIN(size, f->buflen);
|
||||||
remain = fd->buflen - got;
|
remain = f->buflen - got;
|
||||||
if (got) memcpy(data, fd->buf, got);
|
if (got) memcpy(data, f->buf, got);
|
||||||
if (remain) memmove(fd->buf, fd->buf + got, remain);
|
if (remain) memmove(f->buf, f->buf + got, remain);
|
||||||
fd->buflen = remain;
|
f->buflen = remain;
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
|
if (is_console_input && size && size < 3 && (__ttymagic & kFdTtyMunging)) {
|
||||||
targetdata = fd->buf;
|
targetdata = f->buf;
|
||||||
targetsize = sizeof(fd->buf);
|
targetsize = sizeof(f->buf);
|
||||||
} else {
|
} else {
|
||||||
targetdata = data;
|
targetdata = data;
|
||||||
targetsize = size;
|
targetsize = size;
|
||||||
|
@ -106,12 +113,11 @@ StartOver:
|
||||||
// since for overlapped i/o, we always use GetOverlappedResult
|
// since for overlapped i/o, we always use GetOverlappedResult
|
||||||
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
ok = ReadFile(handle, targetdata, targetsize, 0, &overlap);
|
||||||
if (!ok && GetLastError() == kNtErrorIoPending) {
|
if (!ok && GetLastError() == kNtErrorIoPending) {
|
||||||
TryAgain:
|
|
||||||
// the i/o operation is in flight; blocking is unavoidable
|
// the i/o operation is in flight; blocking is unavoidable
|
||||||
// if we're in a non-blocking mode, then immediately abort
|
// if we're in a non-blocking mode, then immediately abort
|
||||||
// if an interrupt is pending then we abort before waiting
|
// if an interrupt is pending then we abort before waiting
|
||||||
// otherwise wait for i/o periodically checking interrupts
|
// otherwise wait for i/o periodically checking interrupts
|
||||||
if (fd->flags & O_NONBLOCK) {
|
if (f->flags & O_NONBLOCK) {
|
||||||
sys_read_nt_abort(handle, &overlap);
|
sys_read_nt_abort(handle, &overlap);
|
||||||
} else if (_check_interrupts(kSigOpRestartable)) {
|
} else if (_check_interrupts(kSigOpRestartable)) {
|
||||||
Interrupted:
|
Interrupted:
|
||||||
|
@ -120,6 +126,9 @@ StartOver:
|
||||||
} else {
|
} else {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
if (g_fds.stdin.inisem) {
|
||||||
|
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
|
||||||
|
}
|
||||||
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
|
i = WaitForSingleObject(overlap.hEvent, __SIG_POLLING_INTERVAL_MS);
|
||||||
if (i == kNtWaitTimeout) {
|
if (i == kNtWaitTimeout) {
|
||||||
if (_check_interrupts(kSigOpRestartable)) {
|
if (_check_interrupts(kSigOpRestartable)) {
|
||||||
|
@ -138,10 +147,11 @@ StartOver:
|
||||||
// for windows to acknowledge that it's done using that memory
|
// for windows to acknowledge that it's done using that memory
|
||||||
ok = GetOverlappedResult(handle, &overlap, &got, true);
|
ok = GetOverlappedResult(handle, &overlap, &got, true);
|
||||||
if (!ok && GetLastError() == kNtErrorIoIncomplete) {
|
if (!ok && GetLastError() == kNtErrorIoIncomplete) {
|
||||||
goto TryAgain;
|
kprintf("you complete me\n");
|
||||||
|
ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(overlap.hEvent);
|
__imp_CloseHandle(overlap.hEvent);
|
||||||
} else {
|
} else {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +163,7 @@ StartOver:
|
||||||
int64_t position;
|
int64_t position;
|
||||||
// save file pointer which windows clobbers, even for overlapped i/o
|
// save file pointer which windows clobbers, even for overlapped i/o
|
||||||
if (!SetFilePointerEx(handle, 0, &position, SEEK_CUR)) {
|
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};
|
struct NtOverlapped overlap = {0};
|
||||||
overlap.Pointer = (void *)(uintptr_t)offset;
|
overlap.Pointer = (void *)(uintptr_t)offset;
|
||||||
|
@ -179,11 +189,11 @@ StartOver:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (__ttymagic & kFdTtyEchoing) {
|
if (__ttymagic & kFdTtyEchoing) {
|
||||||
_weaken(__echo_terminal_input)(fd, targetdata, got);
|
_weaken(__echo_terminal_input)(f, targetdata, got);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (targetdata != data) {
|
if (targetdata != data) {
|
||||||
fd->buflen = got;
|
f->buflen = got;
|
||||||
goto ReturnDataFromBuffer;
|
goto ReturnDataFromBuffer;
|
||||||
}
|
}
|
||||||
return got;
|
return got;
|
||||||
|
@ -204,8 +214,8 @@ StartOver:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
|
textwindows ssize_t sys_read_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||||
size_t iovlen, int64_t opt_offset) {
|
int64_t opt_offset) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t i, total;
|
size_t i, total;
|
||||||
if (opt_offset < -1) return einval();
|
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) {
|
} else if (fd >= g_fds.n) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
} else if (IsMetal()) {
|
} 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()) {
|
} 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 {
|
} else {
|
||||||
rc = enosys();
|
rc = enosys();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/metalfile.internal.h"
|
#include "libc/calls/metalfile.internal.h"
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
|
@ -28,11 +29,11 @@
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#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;
|
int i;
|
||||||
size_t got, toto;
|
size_t got, toto;
|
||||||
struct MetalFile *file;
|
struct MetalFile *file;
|
||||||
switch (fd->kind) {
|
switch (g_fds.p[fd].kind) {
|
||||||
case kFdConsole:
|
case kFdConsole:
|
||||||
/*
|
/*
|
||||||
* The VGA teletypewriter code may wish to send out "status report"
|
* 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.
|
* Read & return these if they are available.
|
||||||
*/
|
*/
|
||||||
if (_weaken(sys_readv_vga)) {
|
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;
|
if (res > 0) return res;
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case kFdSerial:
|
case kFdSerial:
|
||||||
return sys_readv_serial(fd, iov, iovlen);
|
return sys_readv_serial(fd, iov, iovlen);
|
||||||
case kFdFile:
|
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) {
|
for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) {
|
||||||
got = MIN(iov[i].iov_len, file->size - file->pos);
|
got = MIN(iov[i].iov_len, file->size - file->pos);
|
||||||
if (got) memcpy(iov[i].iov_base, file->base, got);
|
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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/iovec.internal.h"
|
#include "libc/calls/struct/iovec.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
@ -24,9 +25,8 @@
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov,
|
textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
|
||||||
int iovlen) {
|
switch (g_fds.p[fd].kind) {
|
||||||
switch (fd->kind) {
|
|
||||||
case kFdFile:
|
case kFdFile:
|
||||||
case kFdConsole:
|
case kFdConsole:
|
||||||
return sys_read_nt(fd, iov, iovlen, -1);
|
return sys_read_nt(fd, iov, iovlen, -1);
|
||||||
|
|
|
@ -16,14 +16,15 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/fd.internal.h"
|
#include "libc/calls/struct/fd.internal.h"
|
||||||
#include "libc/calls/struct/iovec.internal.h"
|
#include "libc/calls/struct/iovec.internal.h"
|
||||||
#include "libc/nexgen32e/uart.internal.h"
|
#include "libc/nexgen32e/uart.internal.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
static bool IsDataAvailable(struct Fd *fd) {
|
static bool IsDataAvailable(int fd) {
|
||||||
return inb(fd->handle + UART_LSR) & UART_TTYDA;
|
return inb(g_fds.p[fd].handle + UART_LSR) & UART_TTYDA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetFirstIov(const struct iovec *iov, int iovlen) {
|
static int GetFirstIov(const struct iovec *iov, int iovlen) {
|
||||||
|
@ -36,13 +37,13 @@ static int GetFirstIov(const struct iovec *iov, int iovlen) {
|
||||||
return -1;
|
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;
|
size_t i;
|
||||||
if ((i = GetFirstIov(iov, iovlen)) != -1) {
|
if ((i = GetFirstIov(iov, iovlen)) != -1) {
|
||||||
while (!IsDataAvailable(fd)) {
|
while (!IsDataAvailable(fd)) {
|
||||||
__builtin_ia32_pause();
|
__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;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -68,9 +68,9 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||||
} else if (fd >= g_fds.n) {
|
} else if (fd >= g_fds.n) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
rc = sys_readv_metal(g_fds.p + fd, iov, iovlen);
|
rc = sys_readv_metal(fd, iov, iovlen);
|
||||||
} else if (IsWindows()) {
|
} else if (IsWindows()) {
|
||||||
rc = sys_readv_nt(g_fds.p + fd, iov, iovlen);
|
rc = sys_readv_nt(fd, iov, iovlen);
|
||||||
} else {
|
} else {
|
||||||
rc = enosys();
|
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_readv(int32_t, const struct iovec *, int32_t);
|
||||||
int64_t sys_vmsplice(int, const struct iovec *, int64_t, uint32_t);
|
int64_t sys_vmsplice(int, const struct iovec *, int64_t, uint32_t);
|
||||||
int64_t sys_writev(int32_t, const struct iovec *, int32_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_read_nt(int, const struct iovec *, size_t, int64_t);
|
||||||
ssize_t sys_readv_metal(struct Fd *, const struct iovec *, int);
|
ssize_t sys_readv_metal(int, const struct iovec *, int);
|
||||||
ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int);
|
ssize_t sys_readv_nt(int, const struct iovec *, int);
|
||||||
ssize_t sys_readv_serial(struct Fd *, 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_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_metal(struct Fd *, const struct iovec *, int);
|
||||||
ssize_t sys_writev_nt(int, 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;
|
struct timeval timeval_subz(struct timeval, struct timeval) pureconst;
|
||||||
int64_t timeval_toseconds(struct timeval);
|
int64_t timeval_toseconds(struct timeval);
|
||||||
int64_t timeval_tomicros(struct timeval);
|
int64_t timeval_tomicros(struct timeval);
|
||||||
|
int64_t timeval_tomillis(struct timeval);
|
||||||
struct timeval timespec_totimeval(struct timespec) pureconst;
|
struct timeval timespec_totimeval(struct timespec) pureconst;
|
||||||
static inline struct timeval timeval_fromseconds(int64_t __x) {
|
static inline struct timeval timeval_fromseconds(int64_t __x) {
|
||||||
return (struct timeval){__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_fchdir_nt(int);
|
||||||
int sys_fchmodat_nt(int, const char *, uint32_t, int);
|
int sys_fchmodat_nt(int, const char *, uint32_t, int);
|
||||||
int sys_fcntl_nt(int, int, uintptr_t);
|
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_flock_nt(int, int);
|
||||||
int sys_fork_nt(uint32_t);
|
int sys_fork_nt(uint32_t);
|
||||||
|
int sys_fsync_fake(int);
|
||||||
int sys_ftruncate_nt(int64_t, uint64_t);
|
int sys_ftruncate_nt(int64_t, uint64_t);
|
||||||
int sys_getloadavg_nt(double *, int);
|
int sys_getloadavg_nt(double *, int);
|
||||||
int sys_getppid_nt(void);
|
int sys_getppid_nt(void);
|
||||||
|
@ -36,6 +37,7 @@ int sys_sync_nt(void);
|
||||||
int sys_truncate_nt(const char *, uint64_t);
|
int sys_truncate_nt(const char *, uint64_t);
|
||||||
int sys_unlinkat_nt(int, const char *, int);
|
int sys_unlinkat_nt(int, const char *, int);
|
||||||
int64_t sys_lseek_nt(int, int64_t, 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);
|
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -23,10 +23,14 @@
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/termios.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/nt/comms.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/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.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) {
|
static dontinline textwindows int sys_tcflush_nt(int fd, int queue) {
|
||||||
bool32 ok;
|
if (!__isfdopen(fd)) {
|
||||||
int64_t h;
|
return ebadf();
|
||||||
if (!__isfdopen(fd)) return ebadf();
|
|
||||||
ok = true;
|
|
||||||
h = g_fds.p[fd].handle;
|
|
||||||
if (queue == TCIFLUSH || queue == TCIOFLUSH) {
|
|
||||||
ok &= !!PurgeComm(h, kNtPurgeRxclear);
|
|
||||||
}
|
}
|
||||||
if (queue == TCOFLUSH || queue == TCIOFLUSH) {
|
int64_t hConin;
|
||||||
ok &= !!PurgeComm(h, kNtPurgeTxclear);
|
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 tcflush(int fd, int queue) {
|
||||||
int rc;
|
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();
|
rc = enotty();
|
||||||
} else if (IsLinux()) {
|
} else if (IsLinux()) {
|
||||||
rc = sys_ioctl(fd, TCFLSH, queue);
|
rc = sys_ioctl(fd, TCFLSH, queue);
|
||||||
|
|
|
@ -22,79 +22,87 @@
|
||||||
#include "libc/calls/struct/termios.h"
|
#include "libc/calls/struct/termios.h"
|
||||||
#include "libc/calls/ttydefaults.h"
|
#include "libc/calls/ttydefaults.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
#include "libc/nt/struct/consolescreenbufferinfoex.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/baud.internal.h"
|
#include "libc/sysv/consts/baud.internal.h"
|
||||||
|
#include "libc/sysv/consts/fileno.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int tcgetattr_nt(int ignored, struct termios *tio) {
|
textwindows int tcgetattr_nt(int fd, struct termios *tio) {
|
||||||
int64_t in, out;
|
int64_t hInput, hOutput;
|
||||||
bool32 inok, outok;
|
uint32_t inmode, outmode;
|
||||||
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));
|
|
||||||
|
|
||||||
tio->c_cc[VMIN] = 1;
|
if (__isfdkind(fd, kFdConsole)) {
|
||||||
tio->c_cc[VINTR] = __vintr;
|
hInput = g_fds.p[fd].handle;
|
||||||
tio->c_cc[VQUIT] = __vquit;
|
hOutput = g_fds.p[fd].extra;
|
||||||
tio->c_cc[VERASE] = CTRL('?');
|
} else if (fd == STDIN_FILENO || //
|
||||||
tio->c_cc[VWERASE] = CTRL('W');
|
fd == STDOUT_FILENO || //
|
||||||
tio->c_cc[VKILL] = CTRL('U');
|
fd == STDERR_FILENO) {
|
||||||
tio->c_cc[VEOF] = CTRL('D');
|
hInput = g_fds.p[STDIN_FILENO].handle;
|
||||||
tio->c_cc[VMIN] = CTRL('A');
|
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
return enotty();
|
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/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/struct/metatermios.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/termios.internal.h"
|
||||||
#include "libc/calls/ttydefaults.h"
|
#include "libc/calls/ttydefaults.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
|
@ -32,6 +35,7 @@
|
||||||
#include "libc/nt/version.h"
|
#include "libc/nt/version.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/fileno.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
#include "libc/sysv/consts/sig.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;
|
bool32 ok;
|
||||||
int64_t hInput, hOutput;
|
int64_t hInput, hOutput;
|
||||||
uint32_t inmode, outmode;
|
uint32_t inmode, outmode;
|
||||||
|
|
||||||
if (__isfdkind(fd, kFdConsole)) {
|
if (__isfdkind(fd, kFdConsole)) {
|
||||||
// program manually opened /dev/tty in O_RDWR mode for cmd.exe
|
|
||||||
hInput = g_fds.p[fd].handle;
|
hInput = g_fds.p[fd].handle;
|
||||||
hOutput = g_fds.p[fd].extra;
|
hOutput = g_fds.p[fd].extra;
|
||||||
} else if (fd == 0 || fd == 1) {
|
} else if (fd == STDIN_FILENO || //
|
||||||
// otherwise just assume cmd.exe console stdio
|
fd == STDOUT_FILENO || //
|
||||||
// there's no serial port support yet
|
fd == STDERR_FILENO) {
|
||||||
hInput = g_fds.p[0].handle;
|
hInput = g_fds.p[STDIN_FILENO].handle;
|
||||||
hOutput = g_fds.p[1].handle;
|
hOutput = g_fds.p[MAX(STDOUT_FILENO, fd)].handle;
|
||||||
fd = 0;
|
|
||||||
} else {
|
} else {
|
||||||
STRACE("tcsetattr(fd) must be 0, 1, or open'd /dev/tty");
|
|
||||||
return enotty();
|
return enotty();
|
||||||
}
|
}
|
||||||
if (GetConsoleMode(hInput, &inmode) && GetConsoleMode(hOutput, &outmode)) {
|
|
||||||
|
|
||||||
if (opt == TCSAFLUSH) {
|
if (!GetConsoleMode(hInput, &inmode) || !GetConsoleMode(hOutput, &outmode)) {
|
||||||
FlushConsoleInputBuffer(hInput);
|
return enotty();
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
|
|
||||||
outmode &= ~kNtDisableNewlineAutoReturn;
|
if (opt == TCSAFLUSH) {
|
||||||
outmode |= kNtEnableProcessedOutput;
|
tcflush(fd, TCIFLUSH);
|
||||||
if (!(tio->c_oflag & ONLCR)) {
|
}
|
||||||
outmode |= kNtDisableNewlineAutoReturn;
|
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()) {
|
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) {
|
__attribute__((__constructor__)) static void tcsetattr_nt_init(void) {
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/atomic.h"
|
#include "libc/intrin/atomic.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/createfile.h"
|
#include "libc/nt/createfile.h"
|
||||||
#include "libc/nt/enum/accessmask.h"
|
#include "libc/nt/enum/accessmask.h"
|
||||||
#include "libc/nt/enum/creationdisposition.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(CreateNamedPipe) *const __imp_CreateNamedPipeW;
|
||||||
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
|
__msabi extern typeof(CreateSemaphore) *const __imp_CreateSemaphoreW;
|
||||||
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
__msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
||||||
|
__msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode;
|
||||||
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||||
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
|
||||||
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
|
__msabi extern typeof(ReadFile) *const __imp_ReadFile;
|
||||||
|
@ -78,78 +81,97 @@ static void Log(const char *s) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
__msabi static dontasan dontubsan dontinstrument textwindows uint32_t
|
__msabi static textwindows uint32_t WinStdinThread(void *lpParameter) {
|
||||||
WinStdinThread(void *lpParameter) {
|
char buf[4];
|
||||||
char buf[4096];
|
|
||||||
uint32_t i, got, wrote;
|
uint32_t i, got, wrote;
|
||||||
|
Log("<stdin> activated thread\n");
|
||||||
// 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");
|
|
||||||
for (;;) {
|
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)) {
|
if (!__imp_ReadFile(g_fds.stdin.handle, buf, sizeof(buf), &got, 0)) {
|
||||||
Log("<stdin> read failed\n");
|
Log("<stdin> read failed\n");
|
||||||
goto Finish;
|
goto Finish;
|
||||||
}
|
}
|
||||||
if (!got) {
|
if (!got) {
|
||||||
Log("<stdin> end of file\n");
|
Log("<stdin> eof\n");
|
||||||
goto Finish;
|
goto Finish;
|
||||||
}
|
}
|
||||||
for (i = 0; i < got; i += wrote) {
|
for (i = 0; i < got; i += wrote) {
|
||||||
|
Log("<stdin> write");
|
||||||
if (!__imp_WriteFile(g_fds.stdin.writer, buf + i, got - i, &wrote, 0)) {
|
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;
|
goto Finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Finish:
|
Finish:
|
||||||
__imp_CloseHandle(g_fds.stdin.writer);
|
__imp_CloseHandle(g_fds.stdin.writer);
|
||||||
return 0;
|
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
|
// this makes it possible for our read() implementation to periodically
|
||||||
// poll for signals while performing a blocking overlapped io operation
|
// 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];
|
char16_t pipename[64];
|
||||||
int64_t hStdin, hWriter, hReader, hThread, hSemaphore;
|
int64_t hStdin, hWriter, hReader, hThread, hSemaphore;
|
||||||
if (!SupportsWindows()) return;
|
if (!SupportsWindows()) return;
|
||||||
|
// handle numbers stay the same when inherited by the subprocesses
|
||||||
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
|
hStdin = __imp_GetStdHandle(kNtStdInputHandle);
|
||||||
if (hStdin == kNtInvalidHandleValue) {
|
if (hStdin == kNtInvalidHandleValue) {
|
||||||
Log("<stdin> GetStdHandle failed\n");
|
Log("<stdin> GetStdHandle failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// create non-inherited semaphore with initial value of 0
|
CreateStdinPipeName(pipename, hStdin);
|
||||||
hSemaphore = __imp_CreateSemaphoreW(0, 0, 1, 0);
|
hReader = __imp_CreateFileW(pipename, kNtGenericRead, 0, 0, kNtOpenExisting,
|
||||||
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,
|
|
||||||
kNtFileFlagOverlapped, 0);
|
kNtFileFlagOverlapped, 0);
|
||||||
if (hWriter == kNtInvalidHandleValue) {
|
if (hReader == kNtInvalidHandleValue) {
|
||||||
Log("<stdin> CreateFile failed\n");
|
// we are the init process; create pipe server to dole out stdin
|
||||||
return;
|
hWriter = __imp_CreateNamedPipeW(
|
||||||
}
|
pipename, kNtPipeAccessOutbound | kNtFileFlagOverlapped,
|
||||||
hThread = __imp_CreateThread(0, 65536, WinStdinThread, 0, 0, 0);
|
kNtPipeTypeMessage | kNtPipeReadmodeMessage | kNtPipeNowait,
|
||||||
if (!hThread) {
|
kNtPipeUnlimitedInstances, 4096, 4096, 0, 0);
|
||||||
Log("<stdin> CreateThread failed\n");
|
if (hWriter == kNtInvalidHandleValue) {
|
||||||
return;
|
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.handle = hStdin;
|
||||||
g_fds.stdin.thread = hThread;
|
g_fds.stdin.thread = hThread;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
textwindows int64_t __resolve_stdin_handle(int64_t handle) {
|
textwindows int64_t __resolve_stdin_handle(int64_t handle) {
|
||||||
if (handle == g_fds.stdin.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);
|
ReleaseSemaphore(g_fds.stdin.inisem, 1, 0);
|
||||||
}
|
}
|
||||||
handle = g_fds.stdin.reader;
|
handle = g_fds.stdin.reader;
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
|
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||||
#define COSMOPOLITAN_LIBC_FMT_FMT_H_
|
#define COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ cosmopolitan § string formatting ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
||||||
|
|
||||||
#if __SIZEOF_POINTER__ == 8
|
#if __SIZEOF_POINTER__ == 8
|
||||||
#define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */
|
#define POINTER_XDIGITS 12 /* math.log(2**48-1,16) */
|
||||||
|
@ -13,15 +10,6 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
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 *fcvt(double, int, int *, int *);
|
||||||
char *ecvt(double, int, int *, int *);
|
char *ecvt(double, int, int *, int *);
|
||||||
char *gcvt(double, int, char *);
|
char *gcvt(double, int, char *);
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
#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 _DATATRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _STDIOTRACE 0 /* not configurable w/ flag yet */
|
#define _STDIOTRACE 0 /* not configurable w/ flag yet */
|
||||||
#define _LOCKTRACE 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 "
|
#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
|
#ifndef _STDARG_H
|
||||||
#define _STDARG_H
|
#define _STDARG_H
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#endif /* _STDARG_H */
|
#endif /* _STDARG_H */
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
#include "libc/sysv/consts/sio.h"
|
#include "libc/sysv/consts/sio.h"
|
||||||
#include "libc/sysv/consts/sock.h"
|
#include "libc/sysv/consts/sock.h"
|
||||||
|
|
||||||
/* TODO(jart): DELETE */
|
|
||||||
|
|
||||||
static uint32_t *GetUnixIps(void) {
|
static uint32_t *GetUnixIps(void) {
|
||||||
int fd, n;
|
int fd, n;
|
||||||
uint64_t z;
|
uint64_t z;
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
#include "libc/sock/syscall_fd.internal.h"
|
#include "libc/sock/syscall_fd.internal.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||||
size_t iovlen, uint32_t flags) {
|
uint32_t flags) {
|
||||||
int err;
|
int err;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t got;
|
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 NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
err = errno;
|
err = errno;
|
||||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
if (!WSARecv(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||||
&overlapped, 0)) {
|
&flags, &overlapped, 0)) {
|
||||||
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
|
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
|
||||||
|
&flags)) {
|
||||||
rc = got;
|
rc = got;
|
||||||
} else {
|
} else {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errno = err;
|
errno = err;
|
||||||
sockfd = (struct SockFd *)fd->extra;
|
sockfd = (struct SockFd *)g_fds.p[fd].extra;
|
||||||
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
|
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
|
||||||
sockfd->rcvtimeo);
|
sockfd->rcvtimeo);
|
||||||
}
|
}
|
||||||
unassert(WSACloseEvent(overlapped.hEvent));
|
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);
|
rc = sys_recvfrom(fd, buf, size, flags, 0, 0);
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
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)) {
|
} else if (__isfdkind(fd, kFdFile)) {
|
||||||
if (flags) {
|
if (flags) {
|
||||||
rc = einval();
|
rc = einval();
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
rc = enotsock();
|
rc = enotsock();
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "libc/sock/syscall_fd.internal.h"
|
#include "libc/sock/syscall_fd.internal.h"
|
||||||
#include "libc/sysv/errfuns.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,
|
size_t iovlen, uint32_t flags,
|
||||||
void *opt_out_srcaddr,
|
void *opt_out_srcaddr,
|
||||||
uint32_t *opt_inout_srcaddrsize) {
|
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 NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
err = errno;
|
err = errno;
|
||||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
if (!WSARecvFrom(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||||
opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) {
|
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
||||||
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
|
NULL)) {
|
||||||
|
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &got, false,
|
||||||
|
&flags)) {
|
||||||
rc = got;
|
rc = got;
|
||||||
} else {
|
} else {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errno = err;
|
errno = err;
|
||||||
sockfd = (struct SockFd *)fd->extra;
|
sockfd = (struct SockFd *)g_fds.p[fd].extra;
|
||||||
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
|
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
|
||||||
sockfd->rcvtimeo);
|
sockfd->rcvtimeo);
|
||||||
}
|
}
|
||||||
WSACloseEvent(overlapped.hEvent);
|
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);
|
rc = sys_recvfrom(fd, buf, size, flags, &addr, &addrsize);
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
if (__isfdkind(fd, kFdSocket)) {
|
||||||
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
|
rc = sys_recvfrom_nt(fd, (struct iovec[]){{buf, size}}, 1, flags, &addr,
|
||||||
flags, &addr, &addrsize);
|
&addrsize);
|
||||||
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
|
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
|
||||||
if (!flags) {
|
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 {
|
} else {
|
||||||
rc = einval();
|
rc = einval();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,12 +74,12 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (!msg->msg_control) {
|
if (!msg->msg_control) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
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);
|
msg->msg_name, &msg->msg_namelen);
|
||||||
} else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */
|
} else if (__isfdkind(fd, kFdFile) && !msg->msg_name) { /* socketpair */
|
||||||
if (!flags) {
|
if (!flags) {
|
||||||
if ((got = sys_read_nt(&g_fds.p[fd], msg->msg_iov, msg->msg_iovlen,
|
if ((got = sys_read_nt(fd, msg->msg_iov, msg->msg_iovlen, -1)) !=
|
||||||
-1)) != -1) {
|
-1) {
|
||||||
msg->msg_flags = 0;
|
msg->msg_flags = 0;
|
||||||
rc = got;
|
rc = got;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -56,8 +56,10 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds,
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the wait time to a word
|
// convert the wait time to a word
|
||||||
if (!timeout || ckd_add(&millis, timeout->tv_sec, timeout->tv_usec / 1000)) {
|
if (!timeout) {
|
||||||
millis = -1;
|
millis = -1;
|
||||||
|
} else {
|
||||||
|
millis = timeval_tomillis(*timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// call our nt poll implementation
|
// 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
|
// store remaining time back in caller's timeval
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
timeout->tv_sec = millis / 1000;
|
*timeout = timeval_frommillis(millis);
|
||||||
timeout->tv_usec = millis % 1000 * 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdcount;
|
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_listen_nt(struct Fd *, int);
|
||||||
int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t);
|
int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t);
|
||||||
int sys_shutdown_nt(struct Fd *, int);
|
int sys_shutdown_nt(struct Fd *, int);
|
||||||
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t);
|
ssize_t sys_recv_nt(int, const struct iovec *, size_t, uint32_t);
|
||||||
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
|
ssize_t sys_recvfrom_nt(int, const struct iovec *, size_t, uint32_t, void *,
|
||||||
void *, uint32_t *);
|
uint32_t *);
|
||||||
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
|
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/unicode.h"
|
#include "libc/str/unicode.h"
|
||||||
#include "third_party/gdtoa/gdtoa.h"
|
#include "third_party/gdtoa/gdtoa.h"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats string to buffer.
|
* Formats string to buffer.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String decoder.
|
* String decoder.
|
||||||
|
|
|
@ -108,6 +108,14 @@ int vscanf(const char *, va_list);
|
||||||
int fscanf(FILE *, const char *, ...) scanfesque(2);
|
int fscanf(FILE *, const char *, ...) scanfesque(2);
|
||||||
int vfscanf(FILE *, const char *, va_list);
|
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 fwprintf(FILE *, const wchar_t *, ...);
|
||||||
int fwscanf(FILE *, const wchar_t *, ...);
|
int fwscanf(FILE *, const wchar_t *, ...);
|
||||||
int swprintf(wchar_t *, size_t, 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 wscanf(const wchar_t *, ...);
|
||||||
int fwide(FILE *, int);
|
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 ─╬─│┼
|
│ cosmopolitan § standard i/o » allocating ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/stdio/append.h"
|
#include "libc/stdio/append.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
#define W sizeof(size_t)
|
#define W sizeof(size_t)
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats string w/ dynamic memory allocation.
|
* Formats string w/ dynamic memory allocation.
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats string to buffer hopefully large enough w/ vararg state.
|
* 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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
static size_t sbufi_;
|
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/calls/struct/rlimit.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/directmap.internal.h"
|
#include "libc/intrin/directmap.internal.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/auxv.h"
|
#include "libc/sysv/consts/auxv.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/consts/s.h"
|
#include "libc/sysv/consts/s.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
@ -29,6 +28,7 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
|
|
@ -91,7 +91,7 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
@ -191,7 +191,7 @@ TEST(ShowCrashReports, testDivideByZero) {
|
||||||
int ws, pid, fds[2];
|
int ws, pid, fds[2];
|
||||||
char *output, buf[512];
|
char *output, buf[512];
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
@ -315,7 +315,7 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
|
||||||
int ws, pid, fds[2];
|
int ws, pid, fds[2];
|
||||||
char *output, buf[512];
|
char *output, buf[512];
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
@ -393,7 +393,7 @@ TEST(ShowCrashReports, testNpeCrash) {
|
||||||
int ws, pid, fds[2];
|
int ws, pid, fds[2];
|
||||||
char *output, buf[512];
|
char *output, buf[512];
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
@ -452,7 +452,7 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
||||||
int ws, pid, fds[2];
|
int ws, pid, fds[2];
|
||||||
char *output, buf[512];
|
char *output, buf[512];
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
@ -506,7 +506,7 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
||||||
int ws, pid, fds[2];
|
int ws, pid, fds[2];
|
||||||
char *output, buf[512];
|
char *output, buf[512];
|
||||||
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
@ -34,6 +33,7 @@
|
||||||
#include "libc/stdio/append.h"
|
#include "libc/stdio/append.h"
|
||||||
#include "libc/stdio/ftw.h"
|
#include "libc/stdio/ftw.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/dt.h"
|
#include "libc/sysv/consts/dt.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
│ THE SOFTWARE. │
|
│ THE SOFTWARE. │
|
||||||
└─────────────────────────────────────────────────────────────────────────────*/
|
└─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/pushpop.internal.h"
|
#include "libc/intrin/pushpop.internal.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
@ -33,6 +32,7 @@
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
#include "libc/mem/gc.h"
|
#include "libc/mem/gc.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
#include "libc/mem/gc.h"
|
#include "libc/mem/gc.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/clock.h"
|
#include "libc/sysv/consts/clock.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
#include "libc/testlib/subprocess.h"
|
#include "libc/testlib/subprocess.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/thread/semaphore.h"
|
#include "libc/thread/semaphore.h"
|
||||||
|
@ -107,7 +107,7 @@ TEST(sem_close, withUnnamedSemaphore_isUndefinedBehavior) {
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
IgnoreStderr();
|
IgnoreStderr();
|
||||||
sem_close(&sem);
|
sem_close(&sem);
|
||||||
EXITS(128 + SIGABRT); // see __assert_fail
|
TERMS(SIGABRT); // see __assert_fail
|
||||||
ASSERT_SYS(0, 0, sem_destroy(&sem));
|
ASSERT_SYS(0, 0, sem_destroy(&sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ TEST(sem_destroy, withNamedSemaphore_isUndefinedBehavior) {
|
||||||
SPAWN(fork);
|
SPAWN(fork);
|
||||||
IgnoreStderr();
|
IgnoreStderr();
|
||||||
sem_destroy(sem);
|
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_unlink("/boop"));
|
||||||
ASSERT_SYS(0, 0, sem_close(sem));
|
ASSERT_SYS(0, 0, sem_close(sem));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/complex.h"
|
#include "libc/complex.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
TEST(complex, test) {
|
TEST(complex, test) {
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/gc.h"
|
#include "libc/mem/gc.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/fenv.h"
|
#include "libc/runtime/fenv.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/xasprintf.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 │
|
│ - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 │
|
||||||
│ │
|
│ │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "third_party/argon2/encoding.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "third_party/argon2/core.h"
|
#include "third_party/argon2/core.h"
|
||||||
#include "third_party/argon2/encoding.h"
|
|
||||||
|
|
||||||
asm(".ident\t\"\\n\\n\
|
asm(".ident\t\"\\n\\n\
|
||||||
argon2 (CC0 or Apache2)\\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.h"
|
||||||
#include "libc/calls/struct/stat.macros.h"
|
#include "libc/calls/struct/stat.macros.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/paths.h"
|
#include "libc/paths.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "third_party/finger/finger.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/assert.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/unicode.h"
|
#include "libc/str/unicode.h"
|
||||||
|
|
||||||
#define LUA_USE_POSIX
|
#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/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/locale.h"
|
#include "libc/str/locale.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/thread/tls.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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "third_party/regex/regex.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
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "third_party/zlib/gz/gzguts.inc"
|
#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
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "third_party/zlib/gz/gzguts.inc"
|
#include "third_party/zlib/gz/gzguts.inc"
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
#include "tool/build/lib/buffer.h"
|
#include "tool/build/lib/buffer.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/arraylist2.internal.h"
|
#include "libc/mem/arraylist2.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/* TODO(jart): replace with new append*() library */
|
/* TODO(jart): replace with new append*() library */
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "tool/decode/lib/flagger.h"
|
#include "tool/decode/lib/flagger.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/mem/arraylist2.internal.h"
|
#include "libc/mem/arraylist2.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue