Compare commits

...
12 Commits
Author SHA1 Message Date
Justine Tunney 2f4ca71f26 Release Cosmopolitan v3.3.10 2024-05-26 22:13:45 -07:00
Justine Tunney 07004ebf04 Upgrade to superconfigure z0.0.42 2024-05-26 22:12:25 -07:00
Justine Tunney 086d7006da Improve crash handler on XNU
This avoids an issue where a crash signal could cause the MacOS process
to freeze and consume all CPU rather than dying as it rightfully should
2024-05-26 18:42:09 -07:00
Gavin Hayes 0a51241f7a ntspawn: fix initializing NtStartupInfoEx (#1190) 2024-05-26 20:54:09 -04:00
Justine Tunney c68f6599e5 Fix definition of getpeername on FreeBSD
We were using the COMPAT magic number, which was recently removed.
2024-05-26 17:03:22 -07:00
Justine Tunney af3f62a71a Ensure io requests are always capped at 0x7ffff000
This gives us the Linux behavior across platforms.

Fixes #1189
2024-05-26 16:53:13 -07:00
Justine Tunney 6cf9b9e0fc Release Cosmopolitan v3.3.9 2024-05-26 15:28:03 -07:00
Justine Tunney 1d4b452839 Refactor some code 2024-05-26 06:03:50 -07:00
Justine Tunney c2db3b703a Introduce --timelog=FILE flag to GNU Make 2024-05-25 14:50:20 -07:00
Justine Tunney edb03b89d8 Make stdin unbuffered when appropriate 2024-05-25 07:57:13 -07:00
Justine Tunney 7724664b13 Release Cosmopolitan v3.3.8 2024-05-25 05:59:20 -07:00
Justine Tunney 1df4296208 Fix stdio for character device regression
Caused by ed93fc3dd7
2024-05-25 05:58:09 -07:00
36 changed files with 1711 additions and 1266 deletions

No files matched your search

+1 -1
View File
@@ -133,7 +133,7 @@ endif
ifneq ($(findstring aarch64,$(MODE)),)
ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
HOSTS ?= pi studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
+1 -1
View File
@@ -177,9 +177,9 @@ static textwindows int ntspawn2(struct NtSpawnArgs *a, struct SpawnBlock *sb) {
if (ok) {
struct NtStartupInfoEx info = {
.StartupInfo = *a->lpStartupInfo,
.StartupInfo.cb = sizeof(info),
.lpAttributeList = alist,
};
info.StartupInfo.cb = sizeof(info);
if (ok) {
if (CreateProcess(sb->path, sb->cmdline, 0, 0, true,
a->dwCreationFlags | kNtCreateUnicodeEnvironment |
+6 -1
View File
@@ -30,6 +30,7 @@
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/errfuns.h"
/**
@@ -39,7 +40,7 @@
*
* @param fd is something open()'d earlier, noting pipes might not work
* @param buf is copied into, cf. copy_file_range(), sendfile(), etc.
* @param size in range [1..0x7ffff000] is reasonable
* @param size is always saturated to 0x7ffff000 automatically
* @param offset is bytes from start of file at which read begins
* @return [1..size] bytes on success, 0 on EOF, or -1 w/ errno; with
* exception of size==0, in which case return zero means no error
@@ -58,6 +59,10 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
size = MIN(size, 0x7ffff000);
if (offset < 0) {
rc = einval();
} else if (fd < 0) {
+43 -7
View File
@@ -28,24 +28,55 @@
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/stdckdint.h"
#include "libc/sysv/errfuns.h"
static size_t SumIovecBytes(const struct iovec *iov, int iovlen) {
size_t count = 0;
for (int i = 0; i < iovlen; ++i)
if (ckd_add(&count, count, iov[i].iov_len))
count = SIZE_MAX;
return count;
}
static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
int e, i;
size_t got;
ssize_t rc, toto;
if (fd < 0) {
if (fd < 0)
return ebadf();
}
if (iovlen < 0) {
if (iovlen < 0)
return einval();
}
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen))
return efault();
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
if (!IsLinux()) {
size_t sum, remain = 0x7ffff000;
if ((sum = SumIovecBytes(iov, iovlen)) > remain) {
struct iovec *iov2;
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
iov2 = alloca(iovlen * sizeof(struct iovec));
CheckLargeStackAllocation(iov2, iovlen * sizeof(struct iovec));
#pragma GCC pop_options
for (int i = 0; i < iovlen; ++i) {
iov2[i] = iov[i];
if (remain >= iov2[i].iov_len) {
remain -= iov2[i].iov_len;
} else {
iov2[i].iov_len = remain;
remain = 0;
}
}
iov = iov2;
}
}
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
@@ -112,6 +143,11 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
/**
* Reads with maximum generality.
*
* It's possible for file write request to be partially completed. For
* example, if the sum of `iov` lengths exceeds 0x7ffff000 then bytes
* beyond that will be ignored. This is a Linux behavior that Cosmo
* polyfills across platforms.
*
* @return number of bytes actually read, or -1 w/ errno
* @cancelationpoint
* @asyncsignalsafe
+6 -1
View File
@@ -28,6 +28,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/errfuns.h"
/**
@@ -37,7 +38,7 @@
*
* @param fd is something open()'d earlier, noting pipes might not work
* @param buf is copied from, cf. copy_file_range(), sendfile(), etc.
* @param size in range [1..0x7ffff000] is reasonable
* @param size is always saturated to 0x7ffff000 automatically
* @param offset is bytes from start of file at which write begins,
* which can exceed or overlap the end of file, in which case your
* file will be extended
@@ -53,6 +54,10 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
size_t wrote;
BEGIN_CANCELATION_POINT;
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
size = MIN(size, 0x7ffff000);
if (offset < 0) {
rc = einval();
} else if (fd == -1) {
+44 -10
View File
@@ -28,28 +28,57 @@
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/stack.h"
#include "libc/stdckdint.h"
#include "libc/sysv/errfuns.h"
static size_t SumIovecBytes(const struct iovec *iov, int iovlen) {
size_t count = 0;
for (int i = 0; i < iovlen; ++i)
if (ckd_add(&count, count, iov[i].iov_len))
count = SIZE_MAX;
return count;
}
static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
int64_t off) {
int i, e;
size_t sent;
ssize_t rc, toto;
if (fd < 0) {
if (fd < 0)
return ebadf();
}
if (iovlen < 0) {
if (iovlen < 0)
return einval();
}
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen))
return efault();
}
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)
return ebadf();
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
if (!IsLinux()) {
size_t sum, remain = 0x7ffff000;
if ((sum = SumIovecBytes(iov, iovlen)) > remain) {
struct iovec *iov2;
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
iov2 = alloca(iovlen * sizeof(struct iovec));
CheckLargeStackAllocation(iov2, iovlen * sizeof(struct iovec));
#pragma GCC pop_options
for (int i = 0; i < iovlen; ++i) {
iov2[i] = iov[i];
if (remain >= iov2[i].iov_len) {
remain -= iov2[i].iov_len;
} else {
iov2[i].iov_len = remain;
remain = 0;
}
}
iov = iov2;
}
}
if (IsWindows()) {
@@ -116,6 +145,11 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
* been committed. It can also happen if we need to polyfill this system
* call using pwrite().
*
* It's possible for file write request to be partially completed. For
* example, if the sum of `iov` lengths exceeds 0x7ffff000 then bytes
* beyond that will be ignored. This is a Linux behavior that Cosmo
* polyfills across platforms.
*
* @return number of bytes actually sent, or -1 w/ errno
* @cancelationpoint
* @asyncsignalsafe
+6 -1
View File
@@ -29,6 +29,7 @@
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/errfuns.h"
/**
@@ -41,7 +42,7 @@
*
* @param fd is something open()'d earlier
* @param buf is copied into, cf. copy_file_range(), sendfile(), etc.
* @param size in range [1..0x7ffff000] is reasonable
* @param size is always saturated to 0x7ffff000 automatically
* @return [1..size] bytes on success, 0 on EOF, or -1 w/ errno; with
* exception of size==0, in which case return zero means no error
* @raise EBADF if `fd` is negative or not an open file descriptor
@@ -67,6 +68,10 @@ ssize_t read(int fd, void *buf, size_t size) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
size = MIN(size, 0x7ffff000);
if (fd < 0) {
rc = ebadf();
} else if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) {
+70 -26
View File
@@ -28,10 +28,74 @@
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/internal.h"
#include "libc/stdckdint.h"
#include "libc/sysv/errfuns.h"
static size_t SumIovecBytes(const struct iovec *iov, int iovlen) {
size_t count = 0;
for (int i = 0; i < iovlen; ++i)
if (ckd_add(&count, count, iov[i].iov_len))
count = SIZE_MAX;
return count;
}
static ssize_t readv_impl(int fd, const struct iovec *iov, int iovlen) {
if (fd < 0)
return ebadf();
if (iovlen < 0)
return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen))
return efault();
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
if (!IsLinux()) {
size_t sum, remain = 0x7ffff000;
if ((sum = SumIovecBytes(iov, iovlen)) > remain) {
struct iovec *iov2;
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
iov2 = alloca(iovlen * sizeof(struct iovec));
CheckLargeStackAllocation(iov2, iovlen * sizeof(struct iovec));
#pragma GCC pop_options
for (int i = 0; i < iovlen; ++i) {
iov2[i] = iov[i];
if (remain >= iov2[i].iov_len) {
remain -= iov2[i].iov_len;
} else {
iov2[i].iov_len = remain;
remain = 0;
}
}
iov = iov2;
}
}
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return _weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
if (iovlen == 1) {
return sys_read(fd, iov[0].iov_base, iov[0].iov_len);
} else {
return sys_readv(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_readv_metal(fd, iov, iovlen);
} else if (IsWindows()) {
return sys_readv_nt(fd, iov, iovlen);
} else {
return enosys();
}
}
/**
* Reads data to multiple buffers.
*
@@ -42,6 +106,11 @@
* be passed to the kernel as read() instead. This yields a 100 cycle
* performance boost in the case of a single small iovec.
*
* It's possible for file write request to be partially completed. For
* example, if the sum of `iov` lengths exceeds 0x7ffff000 then bytes
* beyond that will be ignored. This is a Linux behavior that Cosmo
* polyfills across platforms.
*
* @return number of bytes actually read, or -1 w/ errno
* @cancelationpoint
* @restartable
@@ -49,32 +118,7 @@
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
if (fd < 0) {
rc = ebadf();
} else if (iovlen < 0) {
rc = einval();
} else if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = _weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
if (iovlen == 1) {
rc = sys_read(fd, iov[0].iov_base, iov[0].iov_len);
} else {
rc = sys_readv(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
rc = ebadf();
} else if (IsMetal()) {
rc = sys_readv_metal(fd, iov, iovlen);
} else if (IsWindows()) {
rc = sys_readv_nt(fd, iov, iovlen);
} else {
rc = enosys();
}
rc = readv_impl(fd, iov, iovlen);
END_CANCELATION_POINT;
STRACE("readv(%d, [%s], %d) → %'ld% m", fd, DescribeIovec(rc, iov, iovlen),
iovlen, rc);
+6
View File
@@ -27,6 +27,7 @@
#include "libc/intrin/weaken.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/sock.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/errfuns.h"
/**
@@ -39,6 +40,7 @@
*
* @param fd is open file descriptor
* @param buf is copied from, cf. copy_file_range(), sendfile(), etc.
* @param size is always saturated to 0x7ffff000 automatically
* @return [1..size] bytes on success, or -1 w/ errno; noting zero is
* impossible unless size was passed as zero to do an error check
* @raise EBADF if `fd` is negative or not an open file descriptor
@@ -68,6 +70,10 @@ ssize_t write(int fd, const void *buf, size_t size) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
size = MIN(size, 0x7ffff000);
if (fd < 0) {
rc = ebadf();
} else if (IsAsan() && !__asan_is_valid(buf, size)) {
+69 -25
View File
@@ -27,8 +27,71 @@
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/runtime/stack.h"
#include "libc/sock/internal.h"
#include "libc/stdckdint.h"
#include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
static size_t SumIovecBytes(const struct iovec *iov, int iovlen) {
size_t count = 0;
for (int i = 0; i < iovlen; ++i)
if (ckd_add(&count, count, iov[i].iov_len))
count = SIZE_MAX;
return count;
}
static ssize_t writev_impl(int fd, const struct iovec *iov, int iovlen) {
if (fd < 0)
return ebadf();
if (iovlen < 0)
return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen))
return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)
return ebadf(); // posix specifies this when not open()'d for writing
// XNU and BSDs will EINVAL if requested bytes exceeds INT_MAX
// this is inconsistent with Linux which ignores huge requests
if (!IsLinux()) {
size_t sum, remain = 0x7ffff000;
if ((sum = SumIovecBytes(iov, iovlen)) > remain) {
struct iovec *iov2;
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
iov2 = alloca(iovlen * sizeof(struct iovec));
CheckLargeStackAllocation(iov2, iovlen * sizeof(struct iovec));
#pragma GCC pop_options
for (int i = 0; i < iovlen; ++i) {
iov2[i] = iov[i];
if (remain >= iov2[i].iov_len) {
remain -= iov2[i].iov_len;
} else {
iov2[i].iov_len = remain;
remain = 0;
}
}
iov = iov2;
}
}
if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
if (iovlen == 1) {
return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
} else {
return sys_writev(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
} else if (IsWindows()) {
return sys_writev_nt(fd, iov, iovlen);
} else {
return enosys();
}
}
/**
* Writes data from multiple buffers.
@@ -45,6 +108,11 @@
* been committed. It can also happen if we need to polyfill this system
* call using write().
*
* It's possible for file write request to be partially completed. For
* example, if the sum of `iov` lengths exceeds 0x7ffff000 then bytes
* beyond that will be ignored. This is a Linux behavior that Cosmo
* polyfills across platforms.
*
* @return number of bytes actually handed off, or -1 w/ errno
* @cancelationpoint
* @restartable
@@ -52,31 +120,7 @@
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
if (fd < 0) {
rc = ebadf();
} else if (iovlen < 0) {
rc = einval();
} else if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = ebadf(); // posix specifies this when not open()'d for writing
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
if (iovlen == 1) {
rc = sys_write(fd, iov[0].iov_base, iov[0].iov_len);
} else {
rc = sys_writev(fd, iov, iovlen);
}
} else if (fd >= g_fds.n) {
rc = ebadf();
} else if (IsMetal()) {
rc = sys_writev_metal(g_fds.p + fd, iov, iovlen);
} else if (IsWindows()) {
rc = sys_writev_nt(fd, iov, iovlen);
} else {
rc = enosys();
}
rc = writev_impl(fd, iov, iovlen);
END_CANCELATION_POINT;
STRACE("writev(%d, %s, %d) → %'ld% m", fd,
DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, rc);
+15 -3
View File
@@ -66,9 +66,10 @@
#endif
#if (!defined(__llvm__) && !__has_builtin(__builtin_assume))
#define __builtin_assume(x) \
do { \
if (!(x)) __builtin_unreachable(); \
#define __builtin_assume(x) \
do { \
if (!(x)) \
__builtin_unreachable(); \
} while (0)
#endif
@@ -598,10 +599,21 @@ typedef struct {
#ifdef __x86_64__
#define DebugBreak() __asm__("int3")
#elif defined(__aarch64__)
#define DebugBreak() __asm__("brk\t#0x666")
#else
#define DebugBreak() __builtin_trap()
#endif
#ifdef __aarch64__
/* raise sigill (not sigtrap) like x86 does */
#define __builtin_trap() \
do { \
__asm__("udf\t#0x666"); \
__builtin_unreachable(); \
} while (0)
#endif
#endif /* _COSMO_SOURCE */
#define __veil(CONSTRAINT, EXPRESSION) \
+1 -1
View File
@@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 3
#define __COSMOPOLITAN_MINOR__ 3
#define __COSMOPOLITAN_PATCH__ 7
#define __COSMOPOLITAN_PATCH__ 10
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)
+15 -2
View File
@@ -192,8 +192,6 @@ void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
static relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
ucontext_t *ctx) {
if (sig != SIGTRAP && sig != SIGQUIT)
sigaddset(&ctx->uc_sigmask, sig);
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
long size = __get_safe_size(8192, 4096);
@@ -276,6 +274,21 @@ relegated void __oncrash(int sig, struct siginfo *si, void *arg) {
int err = errno;
__restore_tty();
ShowCrashReport(err, sig, si, arg);
// ensure execution doesn't resume for anything but SIGTRAP / SIGQUIT
if (arg && sig != SIGTRAP && sig != SIGQUIT) {
if (!IsXnu()) {
sigaddset(&((ucontext_t *)arg)->uc_sigmask, sig);
} else {
sigdelset(&((ucontext_t *)arg)->uc_sigmask, sig);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigaction(sig, &sa, 0);
}
}
SpinUnlock(&lock);
ALLOW_CANCELATION;
}
+21 -2
View File
@@ -191,8 +191,6 @@ static relegated char *GetSymbolName(struct SymbolTable *st, int symbol) {
static relegated void __oncrash_impl(int sig, struct siginfo *si,
ucontext_t *ctx) {
if (sig != SIGTRAP && sig != SIGQUIT)
sigaddset(&ctx->uc_sigmask, sig);
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Walloca-larger-than="
long size = __get_safe_size(10000, 4096);
@@ -396,6 +394,27 @@ relegated void __oncrash(int sig, struct siginfo *si, void *arg) {
BLOCK_CANCELATION;
SpinLock(&lock);
__oncrash_impl(sig, si, arg);
// unlike amd64, the instruction pointer on arm64 isn't advanced past
// the debugger breakpoint instruction automatically. we need this so
// execution can resume after __builtin_trap().
if (arg && sig == SIGTRAP)
((ucontext_t *)arg)->uc_mcontext.PC += 4;
// ensure execution doesn't resume for anything but SIGTRAP / SIGQUIT
if (arg && sig != SIGTRAP && sig != SIGQUIT) {
if (!IsXnu()) {
sigaddset(&((ucontext_t *)arg)->uc_sigmask, sig);
} else {
sigdelset(&((ucontext_t *)arg)->uc_sigmask, sig);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigaction(sig, &sa, 0);
}
}
SpinUnlock(&lock);
ALLOW_CANCELATION;
}
+6 -1
View File
@@ -17,9 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
@@ -33,9 +35,12 @@
*/
FILE *fdopen(int fd, const char *mode) {
FILE *f;
struct stat st;
if (fstat(fd, &st))
return 0;
if ((f = __stdio_alloc())) {
f->fd = fd;
f->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
f->bufmode = S_ISREG(st.st_mode) ? _IOFBF : _IONBF;
f->iomode = fopenflags(mode);
f->buf = f->mem;
f->size = BUFSIZ;
+10 -6
View File
@@ -29,16 +29,15 @@
#include "libc/sysv/errfuns.h"
static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
int olde;
ssize_t rc;
size_t got, toto;
toto = 0;
olde = errno;
do {
if ((rc = readv(fd, iov, iovlen)) == -1) {
if (toto && errno == EINTR) {
errno = olde;
continue;
if (toto) {
if (errno == EINTR)
continue;
return toto;
}
return -1;
}
@@ -135,7 +134,12 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
}
if ((rc = readvall(f->fd, iov, 2)) == -1) {
if (f->bufmode == _IONBF) {
rc = readv(f->fd, iov, 2);
} else {
rc = readvall(f->fd, iov, 2);
}
if (rc == -1) {
f->state = errno;
return 0;
}
+5
View File
@@ -17,10 +17,12 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/s.h"
#include "libc/thread/thread.h"
/**
@@ -31,11 +33,14 @@ FILE *stdin;
static FILE __stdin;
__attribute__((__constructor__(60))) static textstartup void initin(void) {
struct stat st;
stdin = &__stdin;
stdin->fd = STDIN_FILENO;
stdin->iomode = O_RDONLY;
stdin->buf = stdin->mem;
stdin->size = sizeof(stdin->mem);
stdin->lock._type = PTHREAD_MUTEX_RECURSIVE;
if (fstat(STDIN_FILENO, &st) || !S_ISREG(st.st_mode))
stdin->bufmode = _IONBF;
__fflush_register(stdin);
}
+1011 -1045
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,2 +1,2 @@
#include "libc/sysv/macros.internal.h"
.scall __sys_getpeername,0x01f01f08d201f034,205,31,141,globl,hidden
.scall __sys_getpeername,0x01f01f01f201f034,205,31,31,globl,hidden
+1 -1
View File
@@ -1598,7 +1598,7 @@ syscon nr __NR_shutdown 0x0030 0x00d2 0x2000086 0x0086 0x0086 0x0086
syscon nr __NR_bind 0x0031 0x00c8 0x2000068 0x0068 0x0068 0x0068 0x068 0xfff
syscon nr __NR_listen 0x0032 0x00c9 0x200006a 0x006a 0x006a 0x006a 0x06a 0xfff
syscon nr __NR_getsockname 0x0033 0x00cc 0x2000020 0x0020 0x0020 0x0020 0x020 0xfff
syscon nr __NR_getpeername 0x0034 0x00cd 0x200001f 0x001f 0x008d 0x001f 0x01f 0xfff
syscon nr __NR_getpeername 0x0034 0x00cd 0x200001f 0x001f 0x001f 0x001f 0x01f 0xfff
syscon nr __NR_socketpair 0x0035 0x00c7 0x2000087 0x0087 0x0087 0x0087 0x087 0xfff
syscon nr __NR_setsockopt 0x0036 0x00d0 0x2000069 0x0069 0x0069 0x0069 0x069 0xfff
syscon nr __NR_getsockopt 0x0037 0x00d1 0x2000076 0x0076 0x0076 0x0076 0x076 0xfff
+1 -1
View File
@@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon nr,__NR_getpeername,0x0034,0x00cd,0x200001f,0x001f,0x008d,0x001f,0x01f,0xfff
.syscon nr,__NR_getpeername,0x0034,0x00cd,0x200001f,0x001f,0x001f,0x001f,0x01f,0xfff
+1 -1
View File
@@ -86,7 +86,7 @@ scall sys_shutdown 0x0860860862086030 0x0d2 globl hidden
scall __sys_bind 0x0680680682068031 0x0c8 globl hidden
scall sys_listen 0x06a06a06a206a032 0x0c9 globl hidden
scall __sys_getsockname 0x0200200202020033 0x0cc globl hidden
scall __sys_getpeername 0x01f01f08d201f034 0x0cd globl hidden
scall __sys_getpeername 0x01f01f01f201f034 0x0cd globl hidden
scall __sys_socketpair 0x0870870872087035 0x0c7 globl hidden
scall sys_setsockopt 0x0690690692069036 0x0d0 globl hidden
scall sys_getsockopt 0x0760760762076037 0x0d1 globl hidden
+1 -1
View File
@@ -53,7 +53,7 @@ void OnSigTrap(int sig, struct siginfo *si, void *ctx) {
void TrapBench(int n) {
for (int i = 0; i < n; ++i) {
__builtin_trap();
DebugBreak();
}
}
+17 -9
View File
@@ -30,10 +30,14 @@ int setup(void) {
return 2;
if (pwrite(fd, "a", 1, 0) != 1)
return 3;
if (pwrite(fd, "z", 1, SIZE - 1) != 1)
if (pwrite(fd, "b", 1, 0x7fffefff) != 1)
return 4;
if (close(fd))
if (pwrite(fd, "c", 1, 0x7ffff000) != 1)
return 5;
if (pwrite(fd, "z", 1, SIZE - 1) != 1)
return 6;
if (close(fd))
return 7;
return 0;
}
@@ -42,17 +46,21 @@ int test(void) {
char *buf;
size_t rc;
if (!(f = fopen(path, "r")))
return 6;
if (!(buf = malloc(SIZE)))
return 7;
if ((rc = fread(buf, SIZE, 1, f)) != 1)
return 8;
if (buf[0] != 'a')
if (!(buf = malloc(SIZE)))
return 9;
if (buf[SIZE - 1] != 'z')
if ((rc = fread(buf, SIZE, 1, f)) != 1)
return 10;
if (fclose(f))
if (buf[0] != 'a')
return 11;
if (buf[0x7fffefff] != 'b')
return 12;
if (buf[0x7ffff000] != 'c')
return 13;
if (buf[SIZE - 1] != 'z')
return 14;
if (fclose(f))
return 15;
return 0;
}
+1 -1
View File
@@ -20,7 +20,7 @@ THIRD_PARTY_CHIBICC_TEST_FILES := $(wildcard third_party/chibicc/test/*)
THIRD_PARTY_CHIBICC_TEST_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_TEST_FILES))
THIRD_PARTY_CHIBICC_TEST_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_CHIBICC_TEST_SRCS))
THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES))
THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok)
# THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok)
THIRD_PARTY_CHIBICC_TEST_COMS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%_test.c=o/$(MODE)/%_test)
+3 -2
View File
@@ -867,8 +867,9 @@ if not _port then
-- {year=(1 << 31) + 1899, month=12, day=31, hour=23, min=59, sec=59}))
-- this is too much
checkerr("represented", os.time,
{year=(1 << 31) + 1899, month=12, day=31, hour=23, min=59, sec=60})
-- [jart] recent tz library upgrade seems to think it's ok
-- checkerr("represented", os.time,
-- {year=(1 << 31) + 1899, month=12, day=31, hour=23, min=59, sec=60})
end
-- internal 'int' fields cannot hold these values
+1
View File
@@ -15,6 +15,7 @@ LICENSE
LOCAL CHANGES
- Introduce -T FILE, --time-log=FILE flag
- Introduce $(uniq token...) native function
- Remove code that forces slow path if not using /bin/sh
+1
View File
@@ -1949,6 +1949,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
child.output.out = pipedes[1];
child.output.err = errfd;
child.timelog = timelog_begin (command_argv);
pid = child_execute_job (&child, 1, command_argv);
if (pid < 0)
+3
View File
@@ -1104,6 +1104,8 @@ reap_children (int block, int err)
void
free_childbase (struct childbase *child)
{
timelog_end (child->timelog);
if (child->environment != 0)
{
char **ep = child->environment;
@@ -1463,6 +1465,7 @@ start_job_command (struct child *child)
jobserver_pre_child (ANY_SET (flags, COMMANDS_RECURSE));
child->timelog = timelog_begin (argv);
child->pid = child_execute_job ((struct childbase *)child,
child->good_stdin, argv);
+2
View File
@@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
#include "output.h"
#include "timelog.h"
/* Structure describing a running or dead child process. */
@@ -31,6 +32,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#define CHILDBASE \
char *cmd_name; /* Allocated copy of command run. */ \
char **environment; /* Environment for commands. */ \
struct timelog *timelog; /* [jart] the lorde of all time. */ \
VMSCHILD \
struct output output /* Output for this child. */
+8
View File
@@ -27,6 +27,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "getopt.h"
#include "libc/runtime/runtime.h"
#include "shuffle.h"
#include "timelog.h"
#include <assert.h>
#ifdef HAVE_FCNTL_H
@@ -374,6 +375,8 @@ static const char *const usage[] =
N_("\
--trace Print tracing information.\n"),
N_("\
-T FILE, --time-log=FILE Log command invocation microseconds to FILE.\n"),
N_("\
-v, --version Print the version number of make and exit.\n"),
N_("\
-w, --print-directory Print the current directory.\n"),
@@ -471,6 +474,7 @@ static struct command_switch switches[] =
{ 'o', filename, &old_files, 0, 0, 0, 0, 0, 0, "old-file", 0 },
{ 'O', string, &output_sync_option, 1, 1, 0, 0, "target", 0, "output-sync", 0 },
{ 'W', filename, &new_files, 0, 0, 0, 0, 0, 0, "what-if", 0 },
{ 'T', string, &timelog_path, 0, 0, 0, 0, 0, 0, "timelog", 0 }, // [jart]
/* These are long-style options. */
{ CHAR_MAX+1, strlist, &db_flags, 1, 1, 0, 0, "basic", 0, "debug", 0 },
@@ -2258,6 +2262,10 @@ main (int argc, char **argv, char **envp)
}
#endif
/* [jart] Setup command latency log. */
timelog_init ();
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
define_makeflags (0);
+186
View File
@@ -0,0 +1,186 @@
/* Copyright 2024 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 "timelog.h"
#include <time.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
struct timelog
{
struct timespec started;
size_t command_length;
char command[4000];
};
char *timelog_path;
int timelog_fd = -1;
void timelog_init (void)
{
if (!timelog_path)
return;
if ((timelog_fd = open (timelog_path, O_APPEND | O_WRONLY | O_CREAT, 0644)) == -1)
{
perror (timelog_path);
exit (1);
}
}
static int is_shell_safe (int c)
{
if (c > 127)
return true;
if (isalnum(c))
return true;
switch (c)
{
case '+':
case '-':
case '.':
case '/':
case '_':
case '=':
case ':':
return true;
default:
return false;
}
}
static int needs_quotes (const char *s)
{
int c;
if (!*s)
return true;
while ((c = *s++ & 255))
if (!is_shell_safe (c))
return true;
return false;
}
static long long get_microseconds (struct timespec beg, struct timespec end)
{
end.tv_sec -= beg.tv_sec;
if (end.tv_nsec < beg.tv_nsec)
{
end.tv_nsec += 1000000000;
end.tv_sec--;
}
end.tv_nsec -= beg.tv_nsec;
return end.tv_sec * 1000000ll + end.tv_nsec / 1000ll;
}
struct timelog *timelog_begin (char **argv)
{
int i, j, q;
char *p, *pe;
/* don't bother if disabled */
if (timelog_fd == -1)
return NULL;
/* allocate object */
struct timelog *tl;
if (!(tl = malloc (sizeof (struct timelog))))
return NULL;
/* stringify command */
p = tl->command;
pe = tl->command + sizeof (tl->command) - 1;
for (i = 0; argv[i]; ++i)
{
if (i && p < pe)
*p++ = ' ';
q = needs_quotes (argv[i]);
if (q && p < pe)
*p++ = '\'';
for (j = 0; argv[i][j]; ++j)
{
if (isspace(argv[i][j]) ||
iscntrl(argv[i][j]))
{
if (p < pe)
*p++ = ' ';
}
else if (argv[i][j] == '\'')
{
if (p < pe)
*p++ = '\'';
if (p < pe)
*p++ = '"';
if (p < pe)
*p++ = '\'';
if (p < pe)
*p++ = '"';
if (p < pe)
*p++ = '\'';
}
else
{
if (p < pe)
*p++ = argv[i][j];
}
}
if (q && p < pe)
*p++ = '\'';
}
if (p == pe)
{
p[-3] = '.';
p[-2] = '.';
p[-1] = '.';
}
*p++ = '\n';
tl->command_length = p - tl->command;
/* record starting timestamp */
clock_gettime (CLOCK_REALTIME, &tl->started);
/* return object */
return tl;
}
void timelog_end (struct timelog *tl)
{
long long us;
char ibuf[22];
struct iovec iov[2];
struct timespec ended;
/* don't bother if disabled */
if (tl == NULL)
return;
/* get elapsed microseconds string */
clock_gettime (CLOCK_REALTIME, &ended);
us = get_microseconds (tl->started, ended);
snprintf (ibuf, sizeof(ibuf), "% 20lld ", us);
// write to log
iov[0].iov_base = ibuf;
iov[0].iov_len = 21;
iov[1].iov_base = tl->command;
iov[1].iov_len = tl->command_length;
writev (timelog_fd, iov, 2);
// free object
free (tl);
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef MAKE_TIMELOG_H_
#define MAKE_TIMELOG_H_
struct timelog;
extern int timelog_fd;
extern char *timelog_path;
void timelog_init (void);
struct timelog *timelog_begin (char **);
void timelog_end (struct timelog *);
#endif /* MAKE_TIMELOG_H_ */
+1 -1
View File
@@ -299,7 +299,7 @@ statements instead, so that Cosmopolitan Libc's system constants will
work as expected. Our modifications to GNU GCC are published under the
ISC license at <https://github.com/ahgamut/gcc/tree/portcosmo-12.3>. The
binaries you see here were first published at
<https://github.com/ahgamut/superconfigure/releases/tag/z0.0.35> which
<https://github.com/ahgamut/superconfigure/releases/tag/z0.0.42> which
is regularly updated.
## Legal
+2 -2
View File
@@ -90,10 +90,10 @@ fetch() {
OLD=$PWD
cd "$OUTDIR/"
if [ ! -x bin/x86_64-linux-cosmo-gcc ]; then
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.39/aarch64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.42/aarch64-gcc.zip
unzip aarch64-gcc.zip
rm -f aarch64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.39/x86_64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.42/x86_64-gcc.zip
unzip x86_64-gcc.zip
rm -f x86_64-gcc.zip
fi
+132 -113
View File
@@ -18,33 +18,39 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/scale/scale.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/fmt/conv.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/locale.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/termios.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/sysparam.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/stb/stb_image.h"
#define SQR(X) ((X) * (X))
#define UNCUBE(x) x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40
#define ORDIE(X) \
do { \
if (!(X)) \
perror(#X), exit(1); \
} while (0)
int want24bit_;
int wantfullsize_;
#define USAGE \
" IMAGE...\n\
\n\
SYNOPSIS\n\
\n\
Prints Image\n\
\n\
FLAGS\n\
\n\
-? help\n\
-t true color mode\n\
-f print image at full size\n\
-w INT specify printed width in pixels (or cols)\n\
-h INT specify printed height in pixels (or rows*2)\n\
\n"
int FLAG_width;
int FLAG_height;
bool FLAG_true;
bool FLAG_full;
const char *prog;
/**
* Quantizes 24-bit RGB to xterm256 code range [16,256).
@@ -58,11 +64,9 @@ int rgb2xterm256(int r, int g, int b) {
qg = cube[(ig = UNCUBE(g))];
qb = cube[(ib = UNCUBE(b))];
if (SQR(qr - r) + SQR(qg - g) + SQR(qb - b) <=
SQR(ql - r) + SQR(ql - g) + SQR(ql - b)) {
SQR(ql - r) + SQR(ql - g) + SQR(ql - b))
return ir * 36 + ig * 6 + ib + 020;
} else {
return il + 0350;
}
return il + 0350;
}
/**
@@ -72,7 +76,7 @@ void PrintImage(int yn, int xn, unsigned char rgb[yn][xn][3]) {
unsigned y, x;
for (y = 0; y < yn; y += 2) {
for (x = 0; x < xn; ++x) {
if (want24bit_) {
if (FLAG_true) {
printf("\033[48;2;%hhu;%hhu;%hhu;38;2;%hhu;%hhu;%hhum▄",
rgb[y + 0][x][0], rgb[y + 0][x][1], rgb[y + 0][x][2],
rgb[MIN(y + 1, yn - 1)][x][0], rgb[MIN(y + 1, yn - 1)][x][1],
@@ -90,102 +94,117 @@ void PrintImage(int yn, int xn, unsigned char rgb[yn][xn][3]) {
}
}
/**
* Determines dimensions of teletypewriter.
*/
void GetTermSize(int *out_rows, int *out_cols) {
struct winsize ws;
ws.ws_row = 20;
ws.ws_col = 80;
tcgetwinsize(STDOUT_FILENO, &ws);
tcgetwinsize(STDIN_FILENO, &ws);
*out_rows = ws.ws_row;
*out_cols = ws.ws_col;
}
void ReadAll(int fd, char *p, size_t n) {
ssize_t rc;
size_t got;
do {
ORDIE((rc = read(fd, p, n)) != -1);
got = rc;
if (!got && n) {
fprintf(stderr, "error: expected eof\n");
exit(EXIT_FAILURE);
}
p += got;
n -= got;
} while (n);
}
static void Deblinterlace(long zn, long yn, long xn,
unsigned char dst[zn][yn][xn],
const unsigned char src[yn][xn][zn]) {
long y, x, z;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
for (z = 0; z < zn; ++z) {
void Deblinterlace(int zn, int yn, int xn, unsigned char dst[zn][yn][xn],
const unsigned char src[yn][xn][zn]) {
int y, x, z;
for (y = 0; y < yn; ++y)
for (x = 0; x < xn; ++x)
for (z = 0; z < zn; ++z)
dst[z][y][x] = src[y][x][z];
}
}
}
}
static void Reblinterlace(long zn, long yn, long xn,
unsigned char dst[yn][xn][zn],
const unsigned char src[zn][yn][xn]) {
long y, x, z;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
for (z = 0; z < zn; ++z) {
void Reblinterlace(int zn, int yn, int xn, unsigned char dst[yn][xn][zn],
const unsigned char src[zn][yn][xn]) {
int y, x, z;
for (y = 0; y < yn; ++y)
for (x = 0; x < xn; ++x)
for (z = 0; z < zn; ++z)
dst[y][x][z] = src[z][y][x];
}
}
}
}
wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "usage: ", prog, USAGE, NULL);
exit(rc);
}
int main(int argc, char *argv[]) {
struct stat st;
void *map, *data, *data2;
int i, fd, tyn, txn, yn, xn, cn;
setlocale(LC_ALL, "C.UTF-8");
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-t") == 0) {
want24bit_ = 1;
} else if (strcmp(argv[i], "-f") == 0) {
wantfullsize_ = 1;
} else {
fd = open(argv[i], O_RDONLY);
if (fd == -1) {
perror(argv[i]);
exit(1);
}
fstat(fd, &st);
map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
data = stbi_load_from_memory(map, st.st_size, &xn, &yn, &cn, 3);
munmap(map, st.st_size);
close(fd);
if (!wantfullsize_) {
GetTermSize(&tyn, &txn);
--tyn;
tyn *= 2;
data2 = memalign(32, 3 * yn * xn);
Deblinterlace(3, yn, xn, data2, data);
free(data);
data = memalign(32, 3 * tyn * txn);
EzGyarados(3, tyn, txn, data, 3, yn, xn, data2, 0, 3, tyn, txn, yn, xn,
0, 0, 0, 0);
free(data2);
data2 = memalign(32, 3 * yn * xn);
Reblinterlace(3, tyn, txn, data2, data);
free(data);
data = data2;
yn = tyn;
xn = txn;
}
PrintImage(yn, xn, data);
free(data);
// get program name
prog = argv[0];
if (!prog)
prog = "basicidea";
// get flags
int opt;
while ((opt = getopt(argc, argv, "?tfw:h:")) != -1) {
switch (opt) {
case 't':
FLAG_true = true;
break;
case 'f':
FLAG_full = true;
break;
case 'w':
FLAG_width = atoi(optarg);
break;
case 'h':
FLAG_height = atoi(optarg);
break;
case '?':
PrintUsage(0, 1);
default:
PrintUsage(1, 2);
}
}
return 0;
if (argc == optind) {
tinyprint(2, prog, ": missing image path (pass -? for help)\n", NULL);
exit(1);
}
// process arguments
for (int i = optind; i < argc; ++i) {
const char *path = argv[i];
// open image
void *data;
int cn, iyn, ixn;
if (!(data = stbi_load(path, &ixn, &iyn, &cn, 3))) {
perror(path);
exit(1);
}
// determine size
int yn, xn;
struct winsize ws;
if (FLAG_full) {
yn = iyn;
xn = ixn;
} else if (FLAG_width > 0 || FLAG_height > 0) {
if (FLAG_width <= 0) {
yn = FLAG_height;
xn = (double)ixn / iyn * FLAG_height + .5;
} else if (FLAG_height <= 0) {
yn = (double)iyn / ixn * FLAG_width + .5;
xn = FLAG_width;
} else {
yn = FLAG_height;
xn = FLAG_width;
}
} else if (!tcgetwinsize(1, &ws)) {
yn = (ws.ws_row - 1) * 2;
xn = ws.ws_col;
} else {
yn = iyn;
xn = ixn;
}
// scale image
if (yn != iyn || xn != ixn) {
void *data2 = memalign(32, 3l * iyn * ixn);
Deblinterlace(3, iyn, ixn, data2, data);
free(data);
data = memalign(32, 3l * yn * xn);
EzGyarados(3, yn, xn, data, 3, iyn, ixn, data2, 0, 3, yn, xn, iyn, ixn, 0,
0, 0, 0);
free(data2);
data2 = memalign(32, 3l * yn * xn);
Reblinterlace(3, yn, xn, data2, data);
free(data);
data = data2;
}
// print image
PrintImage(yn, xn, data);
free(data);
}
}