mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-09 17:20:11 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
130fd66f9e | ||
|
|
8a44f913ae | ||
|
|
5488f0b2ca | ||
|
|
deff138e7e | ||
|
|
b6e40a3a58 | ||
|
|
8f6bc9dabc | ||
|
|
181cd4cbe8 | ||
|
|
5c6877b02b | ||
|
|
403bc25412 | ||
|
|
3bcd40be12 | ||
|
|
fcfdd26b72 | ||
|
|
2b00ee8723 | ||
|
|
ff2b6fc0b0 | ||
|
|
0eef971494 | ||
|
|
2bfd6b37c1 | ||
|
|
69db501c68 | ||
|
|
6e6fc38935 | ||
|
|
342d0c81e5 | ||
|
|
cec4c04aa1 | ||
|
|
f8c0186221 | ||
|
|
6992d8c195 | ||
|
|
1a6b4ab627 | ||
|
|
9e848abad9 | ||
|
|
223eb358c4 | ||
|
|
ea3cc4ea0b | ||
|
|
01267ea0f5 | ||
|
|
bc6c18368f | ||
|
|
06839ab301 | ||
|
|
39dde41516 | ||
|
|
3e16e59f72 | ||
|
|
cf9a1f7f33 | ||
|
|
49a32136f8 | ||
|
|
b9d6e6e348 | ||
|
|
b431ca4449 |
No files matched your search
@@ -6,6 +6,8 @@ AlignConsecutiveMacros: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
IncludeBlocks: Merge
|
||||
|
||||
@@ -149,9 +149,9 @@ export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.3.2
|
||||
COSMOCC = .cosmocc/3.3.3
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.2 a695012ffbeac5e26e3c4a740debc15273f47e9a8bdc55e8b76a623154d5914b)
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.3 e4d0fa63cd79cc3bfff6c2d015f1776db081409907625aea8ad40cefc1996d08)
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
|
||||
+74
-28
@@ -31,6 +31,8 @@
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -39,7 +41,7 @@
|
||||
/* maximum path size that cosmo can take */
|
||||
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
|
||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||
#define SYSLIB_VERSION 9 /* sync with libc/runtime/syslib.internal.h */
|
||||
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
|
||||
|
||||
struct Syslib {
|
||||
int magic;
|
||||
@@ -106,6 +108,10 @@ struct Syslib {
|
||||
OPTIONAL (cosmo lib should check __syslib->version) */
|
||||
/* v9 (2024-01-31) */
|
||||
int (*pthread_cpu_number_np)(size_t *);
|
||||
/* v10 (2024-05-02) */
|
||||
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
|
||||
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
|
||||
long (*sysctlnametomib)(const char *, int *, size_t *);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
@@ -148,8 +154,8 @@ struct Syslib {
|
||||
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
|
||||
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
|
||||
|
||||
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
@@ -221,13 +227,15 @@ struct ApeLoader {
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
@@ -276,7 +284,8 @@ static char *Utoa(char p[21], unsigned long x) {
|
||||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
@@ -312,7 +321,8 @@ static int GetIndirectOffset(const char *arg0) {
|
||||
static void Perror(const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
|
||||
ibuf, "\n", 0l);
|
||||
}
|
||||
@@ -327,7 +337,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
|
||||
return 0;
|
||||
}
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !access(ps->path, X_OK);
|
||||
@@ -377,8 +388,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
|
||||
const char *syspath) {
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
ps->name = name;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
|
||||
return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (FindCommand(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
@@ -545,6 +558,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
|
||||
return sysret(sysctlnametomib(name, mibp, sizep));
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
long *sp, struct ElfEhdr *e,
|
||||
struct ElfPhdr *p,
|
||||
@@ -585,10 +612,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
a = p[i].p_vaddr & -pagesz;
|
||||
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
if (Max(a, c) < Min(b, d)) {
|
||||
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
|
||||
}
|
||||
}
|
||||
@@ -614,7 +642,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
if (e->e_type == ET_DYN) {
|
||||
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
@@ -630,14 +659,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
@@ -657,7 +690,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
wipe = MIN(b - a, c - a);
|
||||
wipe = Min(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
@@ -687,24 +720,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
as the default strategy which is slow but it works for both */
|
||||
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap anon");
|
||||
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
|
||||
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
|
||||
if (rc != p[i].p_filesz)
|
||||
Pexit(exe, -errno, "prog pread");
|
||||
#endif
|
||||
} else {
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap");
|
||||
}
|
||||
if (wipe) memset((void *)(dynbase + a), 0, wipe);
|
||||
if (wipe)
|
||||
memset((void *)(dynbase + a), 0, wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = sys_mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
@@ -712,7 +751,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,8 +830,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
|
||||
/* read program headers */
|
||||
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
@@ -948,6 +990,9 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.dlclose = dlclose;
|
||||
M->lib.dlerror = dlerror;
|
||||
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
|
||||
M->lib.sysctl = sys_sysctl;
|
||||
M->lib.sysctlbyname = sys_sysctlbyname;
|
||||
M->lib.sysctlnametomib = sys_sysctlnametomib;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = 0;
|
||||
@@ -970,7 +1015,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ -x build/bootstrap/make.com ]; then
|
||||
MAKE=build/bootstrap/make.com
|
||||
if [ -x build/bootstrap/make ]; then
|
||||
MAKE=build/bootstrap/make
|
||||
else
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
+60
-30
@@ -228,13 +228,15 @@ extern char _end[];
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
@@ -353,7 +355,8 @@ static char *Utoa(char p[20], unsigned long x) {
|
||||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
@@ -362,7 +365,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
|
||||
long arg5, long arg6,
|
||||
long arg7, int numba,
|
||||
char os) {
|
||||
if (IsXnu()) numba |= 0x2000000;
|
||||
if (IsXnu())
|
||||
numba |= 0x2000000;
|
||||
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
|
||||
}
|
||||
|
||||
@@ -529,7 +533,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
switch ((c = *fmt++)) {
|
||||
case 's':
|
||||
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
|
||||
if (k < 512) b[k++] = *s;
|
||||
if (k < 512)
|
||||
b[k++] = *s;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
@@ -542,16 +547,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
u -= 10;
|
||||
c = 'a' + u;
|
||||
}
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -560,7 +568,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
static void Perror(int os, const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(os, 2, "ape error: ", thing, ": ", reason,
|
||||
rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
|
||||
}
|
||||
@@ -572,8 +581,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
|
||||
}
|
||||
|
||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
MemMove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !Access(ps->path, X_OK, ps->os);
|
||||
@@ -600,11 +611,14 @@ static char SearchPath(struct PathSearcher *ps) {
|
||||
|
||||
static char *Commandv(struct PathSearcher *ps, int os, char *name,
|
||||
const char *syspath) {
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
|
||||
if (!(ps->namelen = StrLen((ps->name = name))))
|
||||
return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
|
||||
return name;
|
||||
ps->os = os;
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
ps->path[0] = 0;
|
||||
if (SearchPath(ps)) {
|
||||
return ps->path;
|
||||
@@ -661,7 +675,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
Pexit(os, exe, 0, "ELF segments overlap your APE loader");
|
||||
}
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
@@ -694,7 +709,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
if (e->e_type == ET_DYN) {
|
||||
rc = Mmap(0, virtmax - virtmin, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
@@ -710,14 +726,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
if (p[i].p_filesz) {
|
||||
/* load from file */
|
||||
@@ -744,17 +764,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe)
|
||||
Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = Mprotect(addr, size, prot2, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
@@ -762,7 +786,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap(addr, size, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +808,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
struct ElfPhdr *p;
|
||||
|
||||
/* validate page size */
|
||||
if (!pagesz) pagesz = 4096;
|
||||
if (!pagesz)
|
||||
pagesz = 4096;
|
||||
if (pagesz & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
|
||||
}
|
||||
@@ -818,8 +844,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
|
||||
/* read program headers */
|
||||
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
@@ -949,7 +977,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
|
||||
/* determine ape loader program name */
|
||||
ape = argv[0];
|
||||
if (!ape) ape = "ape";
|
||||
if (!ape)
|
||||
ape = "ape";
|
||||
|
||||
/* detect openbsd */
|
||||
if (SupportsOpenbsd() && !os && !auxv[0]) {
|
||||
@@ -1021,7 +1050,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (endp - sp + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ ifeq ($(ARCH), aarch64)
|
||||
DEFAULT_COPTS += \
|
||||
-ffixed-x18 \
|
||||
-ffixed-x28 \
|
||||
-fsigned-char \
|
||||
-mno-outline-atomics
|
||||
endif
|
||||
|
||||
|
||||
+24
-12
@@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
|
||||
}
|
||||
|
||||
static char *FormatInt32(char *p, int32_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(uint32_t)x;
|
||||
return FormatUint32(p, x);
|
||||
}
|
||||
|
||||
@@ -205,7 +206,8 @@ static size_t StrCat(char *dst, const char *src, size_t dsize) {
|
||||
size_t m, n = dsize;
|
||||
const char *p = dst;
|
||||
const char *q = src;
|
||||
while (n-- != 0 && *dst != '\0') dst++;
|
||||
while (n-- != 0 && *dst != '\0')
|
||||
dst++;
|
||||
m = dst - p;
|
||||
n = dsize - m;
|
||||
if (n-- == 0) {
|
||||
@@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
|
||||
for (i = 0;; ++i) {
|
||||
switch (path[i]) {
|
||||
case 0:
|
||||
if (i) return true;
|
||||
if (i)
|
||||
return true;
|
||||
// fallthrough
|
||||
case '\r':
|
||||
case '\n':
|
||||
@@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
|
||||
char hexdigest[65];
|
||||
char mode[2] = {g_mode};
|
||||
unsigned char digest[32];
|
||||
if (!IsSupportedPath(path)) return false;
|
||||
if (!GetDigest(path, f, digest)) return false;
|
||||
if (!IsSupportedPath(path))
|
||||
return false;
|
||||
if (!GetDigest(path, f, digest))
|
||||
return false;
|
||||
CopyHex(hexdigest, digest, 32);
|
||||
Write(1, hexdigest, " ", mode, path, "\n", NULL);
|
||||
return true;
|
||||
@@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
|
||||
uint8_t wantdigest[32], gotdigest[32];
|
||||
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
|
||||
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
|
||||
if (!*Chomp(buf)) continue;
|
||||
if (!*Chomp(buf))
|
||||
continue;
|
||||
for (p = buf, i = 0; i < 32; ++i) {
|
||||
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
if ((a = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
wantdigest[i] = a << 4 | b;
|
||||
}
|
||||
if (*p++ != ' ') goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++)) goto InvalidLine;
|
||||
if (*p++ != ' ')
|
||||
goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++))
|
||||
goto InvalidLine;
|
||||
path2 = p;
|
||||
if (!*path2) goto InvalidLine;
|
||||
if (!IsSupportedPath(path2)) continue;
|
||||
if (!*path2)
|
||||
goto InvalidLine;
|
||||
if (!IsSupportedPath(path2))
|
||||
continue;
|
||||
if ((f2 = fopen(path2, "rb"))) {
|
||||
if (GetDigest(path2, f2, gotdigest)) {
|
||||
if (!memcmp(wantdigest, gotdigest, 32)) {
|
||||
|
||||
+4
-2
@@ -27,7 +27,8 @@
|
||||
*/
|
||||
int alaw(int x) {
|
||||
int a, b, i;
|
||||
if ((a = x) < 0) a = ~a;
|
||||
if ((a = x) < 0)
|
||||
a = ~a;
|
||||
a >>= 4;
|
||||
if (a > 15) {
|
||||
if ((i = a >> 5)) {
|
||||
@@ -40,6 +41,7 @@ int alaw(int x) {
|
||||
a += 16;
|
||||
}
|
||||
}
|
||||
if (x >= 0) a |= 128;
|
||||
if (x >= 0)
|
||||
a |= 128;
|
||||
return a ^ 85;
|
||||
}
|
||||
+4
-2
@@ -28,13 +28,15 @@
|
||||
int mulaw(int x) {
|
||||
int b, i, a, s, l, h;
|
||||
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
|
||||
if (a > 8191) a = 8191;
|
||||
if (a > 8191)
|
||||
a = 8191;
|
||||
i = a >> 6;
|
||||
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
|
||||
h = 8 - s;
|
||||
l = (a >> s) & 15;
|
||||
l = 15 - l;
|
||||
b = (h << 4) | l;
|
||||
if (x >= 0) b |= 128;
|
||||
if (x >= 0)
|
||||
b |= 128;
|
||||
return b;
|
||||
}
|
||||
@@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
||||
/* TODO(jart): This isn't acceptable. */
|
||||
size_t i, j;
|
||||
if (p > 0) {
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] =
|
||||
@@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
||||
}
|
||||
} else if (p < 0) {
|
||||
p = -p;
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] = pcm[i][j] >> p;
|
||||
|
||||
+4
-2
@@ -31,8 +31,10 @@ int unalaw(int x) {
|
||||
i = (x ^ 85) & 127;
|
||||
e = i >> 4;
|
||||
m = i & 15;
|
||||
if (e > 0) m += 16;
|
||||
if (e > 0)
|
||||
m += 16;
|
||||
m = (m << 4) + 8;
|
||||
if (e > 1) m = m << (e - 1);
|
||||
if (e > 1)
|
||||
m = m << (e - 1);
|
||||
return x & 128 ? m : -m;
|
||||
}
|
||||
@@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
|
||||
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
|
||||
di = (self->mb_row * dw + self->mb_col) * BW;
|
||||
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
|
||||
if (si > max_address || di > max_address) return;
|
||||
if (si > max_address || di > max_address)
|
||||
return;
|
||||
d += di;
|
||||
s += si;
|
||||
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
|
||||
|
||||
+10
-5
@@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
|
||||
static bool IsNormalized(int n, double A[n]) {
|
||||
int i;
|
||||
double x;
|
||||
for (x = i = 0; i < n; ++i) x += A[i];
|
||||
for (x = i = 0; i < n; ++i)
|
||||
x += A[i];
|
||||
return fabs(x - 1) < 1e-4;
|
||||
}
|
||||
|
||||
@@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
||||
short *weights, *indices;
|
||||
struct SamplingSolution *res;
|
||||
long j, i, k, n, min, max, s, N[6];
|
||||
if (!dar) dar = sn, dar /= dn;
|
||||
if (!off) off = (dar - 1) / 2;
|
||||
if (!dar)
|
||||
dar = sn, dar /= dn;
|
||||
if (!off)
|
||||
off = (dar - 1) / 2;
|
||||
f = dar < 1 ? 1 / dar : dar;
|
||||
s = 3 * f + 4;
|
||||
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
|
||||
@@ -114,8 +117,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
||||
for (k = 0, j = min; j <= max; ++j) {
|
||||
fweights[k++] = ComputeWeight((j - x) / (f / par));
|
||||
}
|
||||
for (sum = k = 0; k < n; ++k) sum += fweights[k];
|
||||
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum;
|
||||
for (sum = k = 0; k < n; ++k)
|
||||
sum += fweights[k];
|
||||
for (j = 0; j < n; ++j)
|
||||
fweights[j] *= 1 / sum;
|
||||
DCHECK(IsNormalized(n, fweights));
|
||||
for (j = 0; j < n; ++j) {
|
||||
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (__nocolor) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (__nocolor)
|
||||
return 0;
|
||||
if (visible)
|
||||
code[5] = 'h';
|
||||
if (IsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
ntcursor.bVisible = visible;
|
||||
|
||||
+8
-4
@@ -21,16 +21,20 @@
|
||||
#include "libc/limits.h"
|
||||
|
||||
static char *ansitoa(char *p, unsigned xt, unsigned base) {
|
||||
if (xt >= 8) xt -= 8, base += 60;
|
||||
if (xt >= 8)
|
||||
xt -= 8, base += 60;
|
||||
return itoa8(p, xt + base);
|
||||
}
|
||||
|
||||
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
if (bg != -1u) p = ansitoa(p, bg, 40);
|
||||
if (bg != -1u && fg != -1u) *p++ = ';';
|
||||
if (fg != -1u) p = ansitoa(p, fg, 30);
|
||||
if (bg != -1u)
|
||||
p = ansitoa(p, bg, 40);
|
||||
if (bg != -1u && fg != -1u)
|
||||
*p++ = ';';
|
||||
if (fg != -1u)
|
||||
p = ansitoa(p, fg, 30);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
+4
-2
@@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
|
||||
struct Glyph *glyph) {
|
||||
unsigned i;
|
||||
CHECK_LT(pick.bg, 4);
|
||||
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4);
|
||||
if (pick.fg != 0xff)
|
||||
CHECK_LT(pick.fg, 4);
|
||||
i = 0;
|
||||
if (pick.fg == 0xff) {
|
||||
if (!ttyeq(*bg, chunk[pick.bg])) {
|
||||
@@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
|
||||
v = CopyGlyph(v, *glyph);
|
||||
*x += 2;
|
||||
*c += 2;
|
||||
if (*x >= n) break;
|
||||
if (*x >= n)
|
||||
break;
|
||||
CopyChunk(chunk, *c, n);
|
||||
} while (ChunkEq(chunk, lastchunk));
|
||||
*x -= 2;
|
||||
|
||||
+8
-4
@@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
|
||||
}
|
||||
|
||||
static textstartup void ttyraw_hidecursor(void) {
|
||||
if (!g_ttyraw.setup) return;
|
||||
if (g_ttyraw.flags & kTtyCursor) return;
|
||||
if (!g_ttyraw.setup)
|
||||
return;
|
||||
if (g_ttyraw.flags & kTtyCursor)
|
||||
return;
|
||||
ttyhidecursor(FD);
|
||||
}
|
||||
|
||||
static textexit int ttyraw_disable(void) {
|
||||
if (!g_ttyraw.setup) return 0;
|
||||
if (!g_ttyraw.setup)
|
||||
return 0;
|
||||
ttyshowcursor(FD);
|
||||
return ttyrestore(FD, &g_ttyraw.old);
|
||||
}
|
||||
@@ -87,7 +90,8 @@ static textexit void ttyraw_onexit(void) {
|
||||
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
|
||||
struct ucontext *ctx) {
|
||||
size_t i;
|
||||
if (g_ttyraw.noreentry) _Exit(128 + sig);
|
||||
if (g_ttyraw.noreentry)
|
||||
_Exit(128 + sig);
|
||||
g_ttyraw.noreentry = true;
|
||||
if (g_ttyraw.flags != -1) {
|
||||
if (sig == SIGCONT) {
|
||||
|
||||
+14
-7
@@ -104,8 +104,10 @@ void *Worker(void *id) {
|
||||
if (client == -1) {
|
||||
// accept() errors are generally ephemeral or recoverable
|
||||
// it'd potentially be a good idea to exponential backoff here
|
||||
if (errno == ECANCELED) continue; // pthread_cancel() was called
|
||||
if (errno == EMFILE) ExplainPrlimit();
|
||||
if (errno == ECANCELED)
|
||||
continue; // pthread_cancel() was called
|
||||
if (errno == EMFILE)
|
||||
ExplainPrlimit();
|
||||
LOG("accept() returned %m");
|
||||
SomethingHappened();
|
||||
continue;
|
||||
@@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
|
||||
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
|
||||
--a_workers;
|
||||
kprintf("pthread_create failed: %s\n", strerror(rc));
|
||||
if (rc == EAGAIN) ExplainPrlimit();
|
||||
if (!i) exit(1);
|
||||
if (rc == EAGAIN)
|
||||
ExplainPrlimit();
|
||||
if (!i)
|
||||
exit(1);
|
||||
threads = i;
|
||||
break;
|
||||
}
|
||||
@@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
|
||||
PrintEphemeralStatusLine();
|
||||
unassert(!pthread_cond_wait(&statuscond, &statuslock));
|
||||
// limit status line updates to sixty frames per second
|
||||
do tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
|
||||
do
|
||||
tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
|
||||
while (timespec_cmp(tick, timespec_real()) < 0);
|
||||
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0);
|
||||
}
|
||||
@@ -378,7 +383,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// on windows this is the only way accept() can be canceled
|
||||
if (IsWindows()) close(server);
|
||||
if (IsWindows())
|
||||
close(server);
|
||||
|
||||
// print status in terminal as the shutdown progresses
|
||||
unassert(!pthread_mutex_lock(&statuslock));
|
||||
@@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// close the server socket
|
||||
if (!IsWindows()) close(server);
|
||||
if (!IsWindows())
|
||||
close(server);
|
||||
|
||||
// clean up terminal line
|
||||
LOG("thank you for choosing \e[32mgreenbean\e[0m");
|
||||
|
||||
+92
-46
@@ -212,10 +212,13 @@ void editorAtExit(void) {
|
||||
int enableRawMode(int64_t fd) {
|
||||
struct termios raw;
|
||||
|
||||
if (E.rawmode) return 0; /* Already enabled. */
|
||||
if (!isatty(STDIN_FILENO)) goto fatal;
|
||||
if (E.rawmode)
|
||||
return 0; /* Already enabled. */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
goto fatal;
|
||||
atexit(editorAtExit);
|
||||
if (tcgetattr(fd, &orig_termios) == -1) goto fatal;
|
||||
if (tcgetattr(fd, &orig_termios) == -1)
|
||||
goto fatal;
|
||||
|
||||
raw = orig_termios; /* modify the original mode */
|
||||
/* input modes: no break, no CR to NL, no parity check, no strip char,
|
||||
@@ -233,7 +236,8 @@ int enableRawMode(int64_t fd) {
|
||||
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
|
||||
|
||||
/* put terminal in raw mode after flushing */
|
||||
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal;
|
||||
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
|
||||
goto fatal;
|
||||
E.rawmode = 1;
|
||||
return 0;
|
||||
|
||||
@@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
|
||||
char c, seq[3];
|
||||
do {
|
||||
nread = read(fd, &c, 1);
|
||||
if (nread == -1) exit(1);
|
||||
if (nread == -1)
|
||||
exit(1);
|
||||
} while (!nread);
|
||||
|
||||
while (1) {
|
||||
@@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
|
||||
return PAGE_DOWN;
|
||||
case '\e': /* escape sequence */
|
||||
/* If this is just an ESC, we'll timeout here. */
|
||||
if (read(fd, seq, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[0] == '[') {
|
||||
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 1, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||
/* Extended escape, read additional byte. */
|
||||
if (read(fd, seq + 2, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 2, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[2] == '~') {
|
||||
switch (seq[1]) {
|
||||
case '1':
|
||||
@@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
|
||||
} else if (seq[0] == 'v') {
|
||||
return PAGE_UP;
|
||||
} else if (seq[0] == 'O') {
|
||||
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 1, 1) == 0)
|
||||
return CTRL('[');
|
||||
/* ESC O sequences. */
|
||||
switch (seq[1]) {
|
||||
case 'H':
|
||||
@@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
unsigned i = 0;
|
||||
|
||||
/* Report cursor location */
|
||||
if (write(ofd, "\e[6n", 4) != 4) return -1;
|
||||
if (write(ofd, "\e[6n", 4) != 4)
|
||||
return -1;
|
||||
|
||||
/* Read the response: ESC [ rows ; cols R */
|
||||
while (i < sizeof(buf) - 1) {
|
||||
if (read(ifd, buf + i, 1) != 1) break;
|
||||
if (buf[i] == 'R') break;
|
||||
if (read(ifd, buf + i, 1) != 1)
|
||||
break;
|
||||
if (buf[i] == 'R')
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
/* Parse it. */
|
||||
if (buf[0] != CTRL('[') || buf[1] != '[') return -1;
|
||||
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1;
|
||||
if (buf[0] != CTRL('[') || buf[1] != '[')
|
||||
return -1;
|
||||
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -359,12 +373,15 @@ int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
|
||||
/* Get the initial position so we can restore it later. */
|
||||
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
|
||||
if (retval == -1) goto failed;
|
||||
if (retval == -1)
|
||||
goto failed;
|
||||
|
||||
/* Go to right/bottom margin and get position. */
|
||||
if (write(ofd, "\e[999C\e[999B", 12) != 12) goto failed;
|
||||
if (write(ofd, "\e[999C\e[999B", 12) != 12)
|
||||
goto failed;
|
||||
retval = getCursorPosition(ifd, ofd, rows, cols);
|
||||
if (retval == -1) goto failed;
|
||||
if (retval == -1)
|
||||
goto failed;
|
||||
|
||||
/* Restore position. */
|
||||
char seq[32];
|
||||
@@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
row->hl = realloc(row->hl, row->rsize);
|
||||
memset(row->hl, HL_NORMAL, row->rsize);
|
||||
|
||||
if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */
|
||||
if (E.syntax == NULL)
|
||||
return; /* No syntax, everything is HL_NORMAL. */
|
||||
|
||||
int i, prev_sep, in_string, in_comment;
|
||||
char *p;
|
||||
@@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
prev_sep = 0;
|
||||
continue;
|
||||
}
|
||||
if (*p == in_string) in_string = 0;
|
||||
if (*p == in_string)
|
||||
in_string = 0;
|
||||
p++;
|
||||
i++;
|
||||
continue;
|
||||
@@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
for (j = 0; keywords[j]; j++) {
|
||||
int klen = strlen(keywords[j]);
|
||||
int kw2 = keywords[j][klen - 1] == '|';
|
||||
if (kw2) klen--;
|
||||
if (kw2)
|
||||
klen--;
|
||||
|
||||
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
|
||||
/* Keyword */
|
||||
@@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
|
||||
* respecting tabs, substituting non printable characters with '?'. */
|
||||
free(row->render);
|
||||
for (j = 0; j < row->size; j++) {
|
||||
if (row->chars[j] == '\t') tabs++;
|
||||
if (row->chars[j] == '\t')
|
||||
tabs++;
|
||||
}
|
||||
|
||||
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
|
||||
@@ -626,11 +647,13 @@ void editorUpdateRow(erow *row) {
|
||||
/* Insert a row at the specified position, shifting the other rows on the bottom
|
||||
* if required. */
|
||||
void editorInsertRow(int at, char *s, size_t len) {
|
||||
if (at > E.numrows) return;
|
||||
if (at > E.numrows)
|
||||
return;
|
||||
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
|
||||
if (at != E.numrows) {
|
||||
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
|
||||
for (int j = at + 1; j <= E.numrows; j++) E.row[j].idx++;
|
||||
for (int j = at + 1; j <= E.numrows; j++)
|
||||
E.row[j].idx++;
|
||||
}
|
||||
E.row[at].size = len;
|
||||
E.row[at].chars = malloc(len + 1);
|
||||
@@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
|
||||
void editorDelRow(int at) {
|
||||
erow *row;
|
||||
|
||||
if (at >= E.numrows) return;
|
||||
if (at >= E.numrows)
|
||||
return;
|
||||
row = E.row + at;
|
||||
editorFreeRow(row);
|
||||
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
|
||||
for (int j = at; j < E.numrows - 1; j++) E.row[j].idx++;
|
||||
for (int j = at; j < E.numrows - 1; j++)
|
||||
E.row[j].idx++;
|
||||
E.numrows--;
|
||||
E.dirty++;
|
||||
}
|
||||
@@ -729,7 +754,8 @@ void editorRowAppendString(erow *row, char *s, size_t len) {
|
||||
|
||||
/* Delete the character at offset 'at' from the specified row. */
|
||||
void editorRowDelChar(erow *row, int at) {
|
||||
if (row->size <= at) return;
|
||||
if (row->size <= at)
|
||||
return;
|
||||
memmove(row->chars + at, row->chars + at + 1, row->size - at);
|
||||
editorUpdateRow(row);
|
||||
row->size--;
|
||||
@@ -745,7 +771,8 @@ void editorInsertChar(int c) {
|
||||
/* If the row where the cursor is currently located does not exist in our
|
||||
* logical representation of the file, add enough empty rows as needed. */
|
||||
if (!row) {
|
||||
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0);
|
||||
while (E.numrows <= filerow)
|
||||
editorInsertRow(E.numrows, "", 0);
|
||||
}
|
||||
row = &E.row[filerow];
|
||||
editorRowInsertChar(row, filecol, c);
|
||||
@@ -773,7 +800,8 @@ void editorInsertNewline(void) {
|
||||
}
|
||||
/* If the cursor is over the current line size, we want to conceptually
|
||||
* think it's just over the last character. */
|
||||
if (filecol >= row->size) filecol = row->size;
|
||||
if (filecol >= row->size)
|
||||
filecol = row->size;
|
||||
if (filecol == 0) {
|
||||
editorInsertRow(filerow, "", 0);
|
||||
} else {
|
||||
@@ -800,7 +828,8 @@ void editorDelChar(void) {
|
||||
int filecol = E.coloff + E.cx;
|
||||
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
|
||||
|
||||
if (!row || (filecol == 0 && filerow == 0)) return;
|
||||
if (!row || (filecol == 0 && filerow == 0))
|
||||
return;
|
||||
if (filecol == 0) {
|
||||
/* Handle the case of column 0, we need to move the current line
|
||||
* on the right of the previous one. */
|
||||
@@ -825,7 +854,8 @@ void editorDelChar(void) {
|
||||
else
|
||||
E.cx--;
|
||||
}
|
||||
if (row) editorUpdateRow(row);
|
||||
if (row)
|
||||
editorUpdateRow(row);
|
||||
E.dirty++;
|
||||
}
|
||||
|
||||
@@ -868,12 +898,15 @@ int editorSave(void) {
|
||||
int len;
|
||||
char *buf = editorRowsToString(&len);
|
||||
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644);
|
||||
if (fd == -1) goto writeerr;
|
||||
if (fd == -1)
|
||||
goto writeerr;
|
||||
|
||||
/* Use truncate + a single write(2) call in order to make saving
|
||||
* a bit safer, under the limits of what we can do in a small editor. */
|
||||
if (ftruncate(fd, len) == -1) goto writeerr;
|
||||
if (write(fd, buf, len) != len) goto writeerr;
|
||||
if (ftruncate(fd, len) == -1)
|
||||
goto writeerr;
|
||||
if (write(fd, buf, len) != len)
|
||||
goto writeerr;
|
||||
|
||||
close(fd);
|
||||
free(buf);
|
||||
@@ -883,7 +916,8 @@ int editorSave(void) {
|
||||
|
||||
writeerr:
|
||||
free(buf);
|
||||
if (fd != -1) close(fd);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
@@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
|
||||
abAppend(&ab, "~", 1);
|
||||
padding--;
|
||||
}
|
||||
while (padding--) abAppend(&ab, " ", 1);
|
||||
while (padding--)
|
||||
abAppend(&ab, " ", 1);
|
||||
abAppend(&ab, welcome, welcomelen);
|
||||
} else {
|
||||
abAppend(&ab, "~\e[0K\r\n", 7);
|
||||
@@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
|
||||
int current_color = -1;
|
||||
#endif
|
||||
if (len > 0) {
|
||||
if (len > E.screencols) len = E.screencols;
|
||||
if (len > E.screencols)
|
||||
len = E.screencols;
|
||||
char *c = r->render + E.coloff;
|
||||
#if SYNTAX
|
||||
unsigned char *hl = r->hl + E.coloff;
|
||||
@@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
|
||||
E.numrows, E.dirty ? "(modified)" : "");
|
||||
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
|
||||
E.numrows);
|
||||
if (len > E.screencols) len = E.screencols;
|
||||
if (len > E.screencols)
|
||||
len = E.screencols;
|
||||
abAppend(&ab, status, len);
|
||||
while (len < E.screencols) {
|
||||
if (E.screencols - len == rlen) {
|
||||
@@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
|
||||
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
|
||||
if (row) {
|
||||
for (j = E.coloff; j < (E.cx + E.coloff); j++) {
|
||||
if (j < row->size && row->chars[j] == CTRL('I')) cx += 7 - ((cx) % 8);
|
||||
if (j < row->size && row->chars[j] == CTRL('I'))
|
||||
cx += 7 - ((cx) % 8);
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
@@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
|
||||
|
||||
int c = editorReadKey(fd);
|
||||
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
|
||||
if (qlen != 0) query[--qlen] = '\0';
|
||||
if (qlen != 0)
|
||||
query[--qlen] = '\0';
|
||||
last_match = -1;
|
||||
} else if (c == CTRL('G')) {
|
||||
break;
|
||||
@@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
|
||||
}
|
||||
|
||||
/* Search occurrence. */
|
||||
if (last_match == -1) find_next = 1;
|
||||
if (last_match == -1)
|
||||
find_next = 1;
|
||||
if (find_next) {
|
||||
char *match = NULL;
|
||||
int match_offset = 0;
|
||||
@@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
|
||||
break;
|
||||
case ARROW_UP:
|
||||
if (E.cy == 0) {
|
||||
if (E.rowoff) E.rowoff--;
|
||||
if (E.rowoff)
|
||||
E.rowoff--;
|
||||
} else {
|
||||
E.cy -= 1;
|
||||
}
|
||||
@@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
|
||||
|
||||
case CTRL('L'):
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
break;
|
||||
|
||||
case PAGE_UP:
|
||||
@@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
|
||||
E.cy = E.screenrows - 1;
|
||||
}
|
||||
times = E.screenrows;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
break;
|
||||
|
||||
case HOME_KEY:
|
||||
case CTRL('A'):
|
||||
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT);
|
||||
while (E.cx || E.coloff)
|
||||
editorMoveCursor(ARROW_LEFT);
|
||||
break;
|
||||
case END_KEY:
|
||||
case CTRL('E'):
|
||||
|
||||
+129
-65
@@ -492,7 +492,8 @@ void TransmitVideo(void) {
|
||||
ssize_t rc;
|
||||
struct Frame* f;
|
||||
f = &vf_[frame_];
|
||||
if (!HasVideo(f)) f = FlipFrameBuffer();
|
||||
if (!HasVideo(f))
|
||||
f = FlipFrameBuffer();
|
||||
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
|
||||
f->w += rc;
|
||||
} else if (errno == EAGAIN) {
|
||||
@@ -504,9 +505,12 @@ void TransmitVideo(void) {
|
||||
|
||||
void TransmitAudio(void) {
|
||||
ssize_t rc;
|
||||
if (!playpid_) return;
|
||||
if (!audio_.i) return;
|
||||
if (playfd_ == -1) return;
|
||||
if (!playpid_)
|
||||
return;
|
||||
if (!audio_.i)
|
||||
return;
|
||||
if (playfd_ == -1)
|
||||
return;
|
||||
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
|
||||
rc /= sizeof(short);
|
||||
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
|
||||
@@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
|
||||
void PollAndSynchronize(void) {
|
||||
do {
|
||||
if (ReadKeyboard() == -1) {
|
||||
if (errno != EINTR) Exit(1);
|
||||
if (exited_) Exit(0);
|
||||
if (resized_) GetTermSize();
|
||||
if (errno != EINTR)
|
||||
Exit(1);
|
||||
if (exited_)
|
||||
Exit(0);
|
||||
if (resized_)
|
||||
GetTermSize();
|
||||
}
|
||||
} while (!timeout_);
|
||||
TransmitVideo();
|
||||
@@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF];
|
||||
if ((addr >> 13) == 3)
|
||||
return PRAM[addr & 0x1FFF];
|
||||
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
|
||||
}
|
||||
|
||||
@@ -828,7 +836,8 @@ bool offset_toggle = false;
|
||||
u8& NesMmap(int i) {
|
||||
i &= 0x3FFF;
|
||||
if (i >= 0x3F00) {
|
||||
if (i % 4 == 0) i &= 0x0F;
|
||||
if (i % 4 == 0)
|
||||
i &= 0x0F;
|
||||
return palette[i & 0x1F];
|
||||
}
|
||||
if (i < 0x2000) {
|
||||
@@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
return open_bus_decay_timer = 77777, open_bus = v;
|
||||
};
|
||||
u8 res = open_bus;
|
||||
if (write) RefreshOpenBus(v);
|
||||
if (write)
|
||||
RefreshOpenBus(v);
|
||||
switch (index) { // Which port from $200x?
|
||||
case 0:
|
||||
if (write) {
|
||||
@@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (write) break;
|
||||
if (write)
|
||||
break;
|
||||
res = reg.status | (open_bus & 0x1F);
|
||||
reg.InVBlank = false; // Reading $2002 clears the vblank flag.
|
||||
offset_toggle = false; // Also resets the toggle for address updates.
|
||||
@@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (write) reg.OAMaddr = v;
|
||||
if (write)
|
||||
reg.OAMaddr = v;
|
||||
break; // Index into Object Attribute Memory
|
||||
case 4:
|
||||
if (write) {
|
||||
@@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!write) break; // Set background scrolling offset
|
||||
if (!write)
|
||||
break; // Set background scrolling offset
|
||||
if (offset_toggle) {
|
||||
scroll.yfine = v & 7;
|
||||
scroll.ycoarse = v >> 3;
|
||||
@@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
offset_toggle = !offset_toggle;
|
||||
break;
|
||||
case 6:
|
||||
if (!write) break; // Set video memory position for reads/writes
|
||||
if (!write)
|
||||
break; // Set video memory position for reads/writes
|
||||
if (offset_toggle) {
|
||||
scroll.vaddrlo = v;
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
@@ -926,17 +940,21 @@ void RenderingTick() {
|
||||
case 2: // Point to attribute table
|
||||
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
|
||||
(vaddr.xcoarse / 4);
|
||||
if (tile_decode_mode) break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
if (tile_decode_mode)
|
||||
break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
|
||||
// Reset sprite data
|
||||
if (x_ == 0) {
|
||||
sprinpos = sproutpos = 0;
|
||||
if (reg.ShowSP) reg.OAMaddr = 0;
|
||||
if (reg.ShowSP)
|
||||
reg.OAMaddr = 0;
|
||||
}
|
||||
if (!reg.ShowBG) break;
|
||||
if (!reg.ShowBG)
|
||||
break;
|
||||
// Reset scrolling (vertical once, horizontal each scanline)
|
||||
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 304 && scanline == -1)
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 256) {
|
||||
vaddr.xcoarse = (unsigned)scroll.xcoarse;
|
||||
vaddr.basenta_h = (unsigned)scroll.basenta_h;
|
||||
@@ -949,7 +967,8 @@ void RenderingTick() {
|
||||
}
|
||||
// Name table access
|
||||
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
|
||||
if (!tile_decode_mode) break;
|
||||
if (!tile_decode_mode)
|
||||
break;
|
||||
// Push the current tile into shift registers.
|
||||
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
|
||||
// 8 times.
|
||||
@@ -976,7 +995,8 @@ void RenderingTick() {
|
||||
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
|
||||
memcpy(&o, &OAM2[sprrenpos], sizeof(o));
|
||||
unsigned y = (scanline)-o.y;
|
||||
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7);
|
||||
if (o.attr & 0x80)
|
||||
y ^= (reg.SPsize ? 15 : 7);
|
||||
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
|
||||
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
|
||||
pat_addr += (y & 7) + (y & 8) * 2;
|
||||
@@ -1011,8 +1031,10 @@ void RenderingTick() {
|
||||
break;
|
||||
}
|
||||
++sprinpos; // next sprite
|
||||
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
y1 = sprtmp;
|
||||
y2 = sprtmp + (reg.SPsize ? 16 : 8);
|
||||
if (!(scanline >= y1 && scanline < y2)) {
|
||||
@@ -1020,19 +1042,23 @@ void RenderingTick() {
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].index = sprtmp;
|
||||
break;
|
||||
case 2:
|
||||
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].attr = sprtmp;
|
||||
break;
|
||||
case 3:
|
||||
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8) {
|
||||
++sproutpos;
|
||||
} else {
|
||||
reg.SPoverflow = true;
|
||||
}
|
||||
if (sprinpos == 2) reg.OAMaddr = 8;
|
||||
if (sprinpos == 2)
|
||||
reg.OAMaddr = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1060,13 +1086,17 @@ void RenderPixel() {
|
||||
auto& s = OAM3[sno];
|
||||
// Check if this sprite is horizontally in range
|
||||
unsigned xdiff = x_ - s.x_;
|
||||
if (xdiff >= 8) continue; // Also matches negative values
|
||||
if (xdiff >= 8)
|
||||
continue; // Also matches negative values
|
||||
// Determine which pixel to display; skip transparent pixels
|
||||
if (!(s.attr & 0x40)) xdiff = 7 - xdiff;
|
||||
if (!(s.attr & 0x40))
|
||||
xdiff = 7 - xdiff;
|
||||
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
|
||||
if (!spritepixel) continue;
|
||||
if (!spritepixel)
|
||||
continue;
|
||||
// Register sprite-0 hit if applicable
|
||||
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true;
|
||||
if (x_ < 255 && pixel && s.sprindex == 0)
|
||||
reg.SP0hit = true;
|
||||
// Render the pixel unless behind-background placement wanted
|
||||
if (!(s.attr & 0x20) || !pixel) {
|
||||
attr = (s.attr & 3) + 4;
|
||||
@@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
|
||||
}
|
||||
if (ctrlmask & 0x80) {
|
||||
joy_next_[0] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[0] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[0] = 0;
|
||||
}
|
||||
if (ctrlmask & 0x40) {
|
||||
joy_next_[1] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[1] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1144,18 +1176,23 @@ void Tick() {
|
||||
CPU::nmi = reg.InVBlank && reg.NMIenabled;
|
||||
break;
|
||||
}
|
||||
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0;
|
||||
if (VBlankState != 0)
|
||||
VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer)
|
||||
open_bus = 0;
|
||||
|
||||
// Graphics processing scanline?
|
||||
if (scanline < DYN) {
|
||||
/* Process graphics for this cycle */
|
||||
if (reg.ShowBGSP) RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256) RenderPixel();
|
||||
if (reg.ShowBGSP)
|
||||
RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256)
|
||||
RenderPixel();
|
||||
}
|
||||
|
||||
// Done with the cycle. Check for end of scanline.
|
||||
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++cycle_counter == 3)
|
||||
cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++x_ >= scanline_end) {
|
||||
// Begin new scanline
|
||||
FlushScanline(scanline);
|
||||
@@ -1242,30 +1279,36 @@ struct channel {
|
||||
template <unsigned c>
|
||||
int Tick() {
|
||||
channel& ch = *this;
|
||||
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8;
|
||||
if (!ChannelsEnabled[c])
|
||||
return c == 4 ? 64 : 8;
|
||||
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
|
||||
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
if (c == 3)
|
||||
wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
int volume = ch.length_counter
|
||||
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
|
||||
: 0;
|
||||
// Sample may change at wavelen intervals.
|
||||
auto& S = ch.level;
|
||||
if (!count(ch.wave_counter, wl)) return S;
|
||||
if (!count(ch.wave_counter, wl))
|
||||
return S;
|
||||
switch (c) {
|
||||
default: // Square wave. With four different 8-step binary waveforms (32
|
||||
// bits of data total).
|
||||
if (wl < 8) return S = 8;
|
||||
if (wl < 8)
|
||||
return S = 8;
|
||||
return S = (0xF33C0C04u &
|
||||
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
|
||||
? volume
|
||||
: 0;
|
||||
|
||||
case 2: // Triangle wave
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase;
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3)
|
||||
++ch.phase;
|
||||
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
|
||||
|
||||
case 3: // Noise: Linear feedback shift register
|
||||
if (!ch.hold) ch.hold = 1;
|
||||
if (!ch.hold)
|
||||
ch.hold = 1;
|
||||
ch.hold =
|
||||
(ch.hold >> 1) |
|
||||
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
|
||||
@@ -1302,7 +1345,8 @@ struct channel {
|
||||
} else {
|
||||
v -= 2;
|
||||
}
|
||||
if (v >= 0 && v <= 0x7F) ch.linear_counter = v;
|
||||
if (v >= 0 && v <= 0x7F)
|
||||
ch.linear_counter = v;
|
||||
}
|
||||
return S = ch.linear_counter;
|
||||
}
|
||||
@@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
|
||||
ch.linear_counter = ch.reg.LinearCounterInit;
|
||||
ch.env_delay = ch.reg.EnvDecayRate;
|
||||
ch.envelope = 15;
|
||||
if (index < 8) ch.phase = 0;
|
||||
if (index < 8)
|
||||
ch.phase = 0;
|
||||
break;
|
||||
case 0x10:
|
||||
ch.reg.reg3 = value;
|
||||
@@ -1384,9 +1429,11 @@ u8 Read() {
|
||||
for (c = 0; c < 5; ++c) {
|
||||
res |= channels[c].length_counter ? 1 << c : 0;
|
||||
}
|
||||
if (PeriodicIRQ) res |= 0x40;
|
||||
if (PeriodicIRQ)
|
||||
res |= 0x40;
|
||||
PeriodicIRQ = false;
|
||||
if (DMC_IRQ) res |= 0x80;
|
||||
if (DMC_IRQ)
|
||||
res |= 0x80;
|
||||
DMC_IRQ = false;
|
||||
CPU::intr = false;
|
||||
return res;
|
||||
@@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
|
||||
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
|
||||
if ((hz240counter.lo += 2) >= 14915) {
|
||||
hz240counter.lo -= 14915;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider)
|
||||
hz240counter.hi = 0;
|
||||
|
||||
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
|
||||
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
|
||||
@@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
|
||||
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
|
||||
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
|
||||
wl += d[ch.reg.SweepDecrease * 2 + c];
|
||||
if (wl < 0x800) ch.reg.WaveLength = wl;
|
||||
if (wl < 0x800)
|
||||
ch.reg.WaveLength = wl;
|
||||
}
|
||||
|
||||
// Linear tick (triangle wave only)
|
||||
@@ -1464,20 +1513,24 @@ namespace CPU {
|
||||
|
||||
void Tick() {
|
||||
// PPU clock: 3 times the CPU rate
|
||||
for (unsigned n = 0; n < 3; ++n) PPU::Tick();
|
||||
for (unsigned n = 0; n < 3; ++n)
|
||||
PPU::Tick();
|
||||
// APU clock: 1 times the CPU rate
|
||||
for (unsigned n = 0; n < 1; ++n) APU::Tick();
|
||||
for (unsigned n = 0; n < 1; ++n)
|
||||
APU::Tick();
|
||||
}
|
||||
|
||||
template <bool write>
|
||||
u8 MemAccess(u16 addr, u8 v) {
|
||||
// Memory writes are turned into reads while reset is being signalled
|
||||
if (reset && write) return MemAccess<0>(addr);
|
||||
if (reset && write)
|
||||
return MemAccess<0>(addr);
|
||||
Tick();
|
||||
// Map the memory from CPU's viewpoint.
|
||||
/**/ if (addr < 0x2000) {
|
||||
u8& r = RAM[addr & 0x7FF];
|
||||
if (!write) return r;
|
||||
if (!write)
|
||||
return r;
|
||||
r = v;
|
||||
} else if (addr < 0x4000) {
|
||||
return PPU::PpuAccess(addr & 7, v, write);
|
||||
@@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
|
||||
WB(0x2004, RB((v & 7) * 0x0100 + b));
|
||||
return 0;
|
||||
case 0x15:
|
||||
if (!write) return APU::Read();
|
||||
if (!write)
|
||||
return APU::Read();
|
||||
APU::Write(0x15, v);
|
||||
break;
|
||||
case 0x16:
|
||||
if (!write) return JoyRead(0);
|
||||
if (!write)
|
||||
return JoyRead(0);
|
||||
JoyStrobe(v);
|
||||
break;
|
||||
case 0x17:
|
||||
if (!write) return JoyRead(1); // write:passthru
|
||||
if (!write)
|
||||
return JoyRead(1); // write:passthru
|
||||
default:
|
||||
if (!write) break;
|
||||
if (!write)
|
||||
break;
|
||||
APU::Write(addr & 0x1F, v);
|
||||
}
|
||||
} else {
|
||||
@@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
|
||||
}
|
||||
void Misfire(u16 old, u16 addr) {
|
||||
u16 q = wrap(old, addr);
|
||||
if (q != addr) RB(q);
|
||||
if (q != addr)
|
||||
RB(q);
|
||||
}
|
||||
u8 Pop() {
|
||||
return RB(0x100 | u8(++S));
|
||||
@@ -1655,7 +1713,8 @@ void Op() {
|
||||
} else if (intr && !P.I) {
|
||||
op = 0x102;
|
||||
}
|
||||
if (!nmi_now) nmi_edge_detected = false;
|
||||
if (!nmi_now)
|
||||
nmi_edge_detected = false;
|
||||
|
||||
// Define function pointers for each opcode (00..FF) and each interrupt
|
||||
// (100,101,102)
|
||||
@@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
|
||||
fgetc(fp);
|
||||
fgetc(fp);
|
||||
|
||||
if (mappernum >= 0x40) mappernum &= 15;
|
||||
if (mappernum >= 0x40)
|
||||
mappernum &= 15;
|
||||
GamePak::mappernum = mappernum;
|
||||
|
||||
// Read the ROM data
|
||||
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
if (rom16count)
|
||||
GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count)
|
||||
GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
|
||||
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
|
||||
|
||||
@@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
|
||||
PPU::reg.value = 0;
|
||||
|
||||
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
|
||||
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
for (unsigned a = 0; a < 0x800; ++a)
|
||||
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
|
||||
// Run the CPU until the program is killed.
|
||||
for (;;) CPU::Op();
|
||||
for (;;)
|
||||
CPU::Op();
|
||||
}
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE* f) {
|
||||
|
||||
+62
-31
@@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
|
||||
} else if (*p->p == '[' && blevel == 0) {
|
||||
level++;
|
||||
} else if (*p->p == ']' && blevel == 0) {
|
||||
if (!--level) break;
|
||||
if (!--level)
|
||||
break;
|
||||
} else if (*p->p == '\\') {
|
||||
p->p++;
|
||||
p->len--;
|
||||
} else if (*p->p == '{') {
|
||||
blevel++;
|
||||
} else if (*p->p == '}') {
|
||||
if (blevel != 0) blevel--;
|
||||
if (blevel != 0)
|
||||
blevel--;
|
||||
}
|
||||
p->p++;
|
||||
p->len--;
|
||||
@@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
if (p->insidequote) return picolParseString(p);
|
||||
if (p->insidequote)
|
||||
return picolParseString(p);
|
||||
return picolParseSep(p);
|
||||
case '\n':
|
||||
case ';':
|
||||
if (p->insidequote) return picolParseString(p);
|
||||
if (p->insidequote)
|
||||
return picolParseString(p);
|
||||
return picolParseEol(p);
|
||||
case '[':
|
||||
return picolParseCommand(p);
|
||||
@@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
|
||||
struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
|
||||
struct picolVar *v = i->callframe->vars;
|
||||
while (v) {
|
||||
if (strcmp(v->name, name) == 0) return v;
|
||||
if (strcmp(v->name, name) == 0)
|
||||
return v;
|
||||
v = v->next;
|
||||
}
|
||||
return NULL;
|
||||
@@ -334,7 +339,8 @@ int picolSetVar(struct picolInterp *i, char *name, char *val) {
|
||||
struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) {
|
||||
struct picolCmd *c = i->commands;
|
||||
while (c) {
|
||||
if (strcmp(c->name, name) == 0) return c;
|
||||
if (strcmp(c->name, name) == 0)
|
||||
return c;
|
||||
c = c->next;
|
||||
}
|
||||
return NULL;
|
||||
@@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
int tlen;
|
||||
int prevtype = p.type;
|
||||
picolGetToken(&p);
|
||||
if (p.type == PT_EOF) break;
|
||||
if (p.type == PT_EOF)
|
||||
break;
|
||||
tlen = p.end - p.start + 1;
|
||||
if (tlen < 0) tlen = 0;
|
||||
if (tlen < 0)
|
||||
tlen = 0;
|
||||
t = malloc(tlen + 1);
|
||||
memcpy(t, p.start, tlen);
|
||||
t[tlen] = '\0';
|
||||
@@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
} else if (p.type == PT_CMD) {
|
||||
retcode = picolEval(i, t);
|
||||
free(t);
|
||||
if (retcode != PICOL_OK) goto err;
|
||||
if (retcode != PICOL_OK)
|
||||
goto err;
|
||||
t = strdup(i->result);
|
||||
} else if (p.type == PT_ESC) {
|
||||
/* XXX: escape handling missing! */
|
||||
@@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
goto err;
|
||||
}
|
||||
retcode = c->func(i, argc, argv, c->privdata);
|
||||
if (retcode != PICOL_OK) goto err;
|
||||
if (retcode != PICOL_OK)
|
||||
goto err;
|
||||
}
|
||||
/* Prepare for the next command */
|
||||
for (j = 0; j < argc; j++) free(argv[j]);
|
||||
for (j = 0; j < argc; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
argv = NULL;
|
||||
argc = 0;
|
||||
@@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
prevtype = p.type;
|
||||
}
|
||||
err:
|
||||
for (j = 0; j < argc; j++) free(argv[j]);
|
||||
for (j = 0; j < argc; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
return retcode;
|
||||
}
|
||||
@@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
|
||||
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
char buf[64];
|
||||
int a, b, c;
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
a = atoi(argv[1]);
|
||||
b = atoi(argv[2]);
|
||||
if (argv[0][0] == '+')
|
||||
@@ -485,22 +498,26 @@ int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
}
|
||||
|
||||
int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
picolSetVar(i, argv[1], argv[2]);
|
||||
picolSetResult(i, argv[2]);
|
||||
return PICOL_OK;
|
||||
}
|
||||
|
||||
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 2) return picolArityErr(i, argv[0]);
|
||||
if (argc != 2)
|
||||
return picolArityErr(i, argv[0]);
|
||||
printf("%s\n", argv[1]);
|
||||
return PICOL_OK;
|
||||
}
|
||||
|
||||
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
int retcode;
|
||||
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]);
|
||||
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode;
|
||||
if (argc != 3 && argc != 5)
|
||||
return picolArityErr(i, argv[0]);
|
||||
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
|
||||
return retcode;
|
||||
if (atoi(i->result))
|
||||
return picolEval(i, argv[2]);
|
||||
else if (argc == 5)
|
||||
@@ -509,10 +526,12 @@ int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
}
|
||||
|
||||
int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
while (1) {
|
||||
int retcode = picolEval(i, argv[1]);
|
||||
if (retcode != PICOL_OK) return retcode;
|
||||
if (retcode != PICOL_OK)
|
||||
return retcode;
|
||||
if (atoi(i->result)) {
|
||||
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
|
||||
continue;
|
||||
@@ -530,7 +549,8 @@ int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
|
||||
int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
|
||||
void *pd) {
|
||||
if (argc != 1) return picolArityErr(i, argv[0]);
|
||||
if (argc != 1)
|
||||
return picolArityErr(i, argv[0]);
|
||||
if (strcmp(argv[0], "break") == 0)
|
||||
return PICOL_BREAK;
|
||||
else if (strcmp(argv[0], "continue") == 0)
|
||||
@@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
|
||||
tofree = p;
|
||||
while (1) {
|
||||
char *start = p;
|
||||
while (*p != ' ' && *p != '\0') p++;
|
||||
while (*p != ' ' && *p != '\0')
|
||||
p++;
|
||||
if (*p != '\0' && p == start) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (p == start) break;
|
||||
if (p == start)
|
||||
break;
|
||||
if (*p == '\0')
|
||||
done = 1;
|
||||
else
|
||||
*p = '\0';
|
||||
if (++arity > argc - 1) goto arityerr;
|
||||
if (++arity > argc - 1)
|
||||
goto arityerr;
|
||||
picolSetVar(i, start, argv[arity]);
|
||||
p++;
|
||||
if (done) break;
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
free(tofree);
|
||||
if (arity != argc - 1) goto arityerr;
|
||||
if (arity != argc - 1)
|
||||
goto arityerr;
|
||||
errcode = picolEval(i, body);
|
||||
if (errcode == PICOL_RETURN) errcode = PICOL_OK;
|
||||
if (errcode == PICOL_RETURN)
|
||||
errcode = PICOL_OK;
|
||||
picolDropCallFrame(i); /* remove the called proc callframe */
|
||||
return errcode;
|
||||
arityerr:
|
||||
@@ -594,14 +620,16 @@ arityerr:
|
||||
|
||||
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
char **procdata = malloc(sizeof(char *) * 2);
|
||||
if (argc != 4) return picolArityErr(i, argv[0]);
|
||||
if (argc != 4)
|
||||
return picolArityErr(i, argv[0]);
|
||||
procdata[0] = strdup(argv[2]); /* arguments list */
|
||||
procdata[1] = strdup(argv[3]); /* procedure body */
|
||||
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
|
||||
}
|
||||
|
||||
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 1 && argc != 2) return picolArityErr(i, argv[0]);
|
||||
if (argc != 1 && argc != 2)
|
||||
return picolArityErr(i, argv[0]);
|
||||
picolSetResult(i, (argc == 2) ? argv[1] : "");
|
||||
return PICOL_RETURN;
|
||||
}
|
||||
@@ -631,9 +659,11 @@ int main(int argc, char **argv) {
|
||||
int retcode;
|
||||
printf("picol> ");
|
||||
fflush(stdout);
|
||||
if (fgets(clibuf, 1024, stdin) == NULL) return 0;
|
||||
if (fgets(clibuf, 1024, stdin) == NULL)
|
||||
return 0;
|
||||
retcode = picolEval(&interp, clibuf);
|
||||
if (interp.result[0] != '\0') printf("[%d] %s\n", retcode, interp.result);
|
||||
if (interp.result[0] != '\0')
|
||||
printf("[%d] %s\n", retcode, interp.result);
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
char buf[1024 * 16];
|
||||
@@ -644,7 +674,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
|
||||
fclose(fp);
|
||||
if (picolEval(&interp, buf) != PICOL_OK) printf("%s\n", interp.result);
|
||||
if (picolEval(&interp, buf) != PICOL_OK)
|
||||
printf("%s\n", interp.result);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
const char *prog = argv[0];
|
||||
if (!prog) prog = "rusage";
|
||||
if (!prog)
|
||||
prog = "rusage";
|
||||
|
||||
if (argc < 2) {
|
||||
tinyprint(2, prog, ": missing command\n", NULL);
|
||||
|
||||
@@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
|
||||
} while (x);
|
||||
for (;;) {
|
||||
*p++ = m[--i];
|
||||
if (!i) break;
|
||||
if (!(i % 3)) *p++ = ',';
|
||||
if (!i)
|
||||
break;
|
||||
if (!(i % 3))
|
||||
*p++ = ',';
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
||||
@@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
|
||||
int Compare(const void *a, const void *b) {
|
||||
struct Thing *x = (struct Thing *)a;
|
||||
struct Thing *y = (struct Thing *)b;
|
||||
if (x->i < y->i) return +1;
|
||||
if (x->i > y->i) return -1;
|
||||
if (x->i < y->i)
|
||||
return +1;
|
||||
if (x->i > y->i)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
|
||||
Append((uintptr_t)__oldstack, "__oldstack");
|
||||
for (int i = 0;; ++i) {
|
||||
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i]));
|
||||
if (!argv[i]) break;
|
||||
if (!argv[i])
|
||||
break;
|
||||
Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
|
||||
}
|
||||
for (int i = 0;; ++i) {
|
||||
Append((uintptr_t)&environ[i],
|
||||
xasprintf("&environ[%d] = %`'s", i, environ[i]));
|
||||
if (!environ[i]) break;
|
||||
if (!environ[i])
|
||||
break;
|
||||
Append((uintptr_t)environ[i],
|
||||
xasprintf("environ[%d] = %`'s", i, environ[i]));
|
||||
}
|
||||
for (int i = 0;; i += 2) {
|
||||
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i]));
|
||||
if (!__auxv[i]) break;
|
||||
if (!__auxv[i])
|
||||
break;
|
||||
Append((uintptr_t)&__auxv[i + 1],
|
||||
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <fenv.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
#include "libc/calls/struct/aarch64.internal.h"
|
||||
|
||||
/*
|
||||
Do you put lots of assert(!isnan(x)) in your code??
|
||||
Your microprocessor has a feature to automate this.
|
||||
|
||||
Uncaught SIGFPE (FPE_FLTINV)
|
||||
__math_invalidf at libc/tinymath/math_errf.c:88
|
||||
logf at libc/tinymath/logf.c:100
|
||||
main at examples/trapping.c:29
|
||||
cosmo at libc/runtime/cosmo.S:105
|
||||
_start at libc/crt/crt.S:116
|
||||
|
||||
This file shows how to use floating point exception
|
||||
trapping with Cosmopolitan Libc.
|
||||
*/
|
||||
|
||||
#define TRAPS (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
|
||||
|
||||
void spring_trap(int sig, siginfo_t *si, void *arg) {
|
||||
|
||||
// print signal safely
|
||||
const char *msg;
|
||||
int sic = si->si_code;
|
||||
if (sic == FPE_INTDIV)
|
||||
msg = "FPE_INTDIV: "; // integer divide by zero
|
||||
else if (sic == FPE_INTOVF)
|
||||
msg = "FPE_INTOVF: "; // integer overflow
|
||||
else if (sic == FPE_FLTDIV)
|
||||
msg = "FPE_FLTDIV: "; // floating point divide by zero
|
||||
else if (sic == FPE_FLTOVF)
|
||||
msg = "FPE_FLTOVF: "; // floating point overflow
|
||||
else if (sic == FPE_FLTUND)
|
||||
msg = "FPE_FLTUND: "; // floating point underflow
|
||||
else if (sic == FPE_FLTRES)
|
||||
msg = "FPE_FLTRES: "; // floating point inexact
|
||||
else if (sic == FPE_FLTINV)
|
||||
msg = "FPE_FLTINV: "; // invalid floating point operation
|
||||
else if (sic == FPE_FLTSUB)
|
||||
msg = "FPE_FLTSUB: "; // subscript out of range
|
||||
else
|
||||
msg = "SIGFPE: ";
|
||||
write(1, msg, strlen(msg));
|
||||
|
||||
// recover from trap so that execution may resume
|
||||
// without this the same signal will just keep getting raised
|
||||
ucontext_t *ctx = arg;
|
||||
#ifdef __x86_64__
|
||||
if (ctx->uc_mcontext.fpregs) {
|
||||
ctx->uc_mcontext.fpregs->mxcsr |= TRAPS << 7; // disable traps
|
||||
ctx->uc_mcontext.fpregs->mxcsr &= ~TRAPS; // clear cages
|
||||
return;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
struct _aarch64_ctx *ac;
|
||||
for (ac = (struct _aarch64_ctx *)ctx->uc_mcontext.__reserved; ac->magic;
|
||||
ac = (struct _aarch64_ctx *)((char *)ac + ac->size)) {
|
||||
if (ac->magic == FPSIMD_MAGIC) {
|
||||
struct fpsimd_context *sm = (struct fpsimd_context *)ac;
|
||||
sm->fpcr &= ~(TRAPS << 8); // disable traps
|
||||
sm->fpsr &= ~TRAPS; // clear cages
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// exit if we can't recover execution
|
||||
msg = "cannot recover from signal\n";
|
||||
write(1, msg, strlen(msg));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
void setup_trap(void) {
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = spring_trap;
|
||||
sigaction(SIGFPE, &sa, 0);
|
||||
}
|
||||
|
||||
void activate_trap(void) {
|
||||
feclearexcept(TRAPS);
|
||||
if (feenableexcept(TRAPS)) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
fprintf(stderr, "warning: trapping math isn't supported on this cpu\n");
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float ident(float x) {
|
||||
return x;
|
||||
}
|
||||
float (*veil)(float) = ident;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
float x;
|
||||
setup_trap();
|
||||
|
||||
// test illegal math
|
||||
activate_trap();
|
||||
x = 0 / veil(0);
|
||||
printf("0/0 = %g\n", x);
|
||||
|
||||
// test divide by zero
|
||||
activate_trap();
|
||||
x = 1 / veil(0);
|
||||
printf("1/0 = %g\n", x);
|
||||
|
||||
// test divide by zero again
|
||||
activate_trap();
|
||||
x = -1 / veil(0);
|
||||
printf("-1/0 = %g\n", x);
|
||||
|
||||
// test domain error
|
||||
activate_trap();
|
||||
x = logf(veil(-1));
|
||||
printf("log(-1) = %g\n", x);
|
||||
|
||||
// test imaginary number
|
||||
activate_trap();
|
||||
x = sqrtf(veil(-1));
|
||||
printf("sqrt(-1) = %g\n", x);
|
||||
|
||||
// test overflow
|
||||
activate_trap();
|
||||
x = expf(veil(88.8));
|
||||
printf("expf(88.8) = %g\n", x);
|
||||
|
||||
// test underflow
|
||||
activate_trap();
|
||||
x = expf(veil(-104));
|
||||
printf("expf(-104) = %g\n", x);
|
||||
}
|
||||
+2
-1
@@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
|
||||
dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
|
||||
if (iscntrl(code[0]) && !code[1]) {
|
||||
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D'))
|
||||
break;
|
||||
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
||||
yn = 1, xn = 1;
|
||||
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct utsname names;
|
||||
if (uname(&names)) return 1;
|
||||
if (uname(&names))
|
||||
return 1;
|
||||
printf("%-10s %`'s\n", "sysname", names.sysname);
|
||||
printf("%-10s %`'s\n", "release", names.release);
|
||||
printf("%-10s %`'s\n", "version", names.version);
|
||||
|
||||
+973
-496
File diff suppressed because it is too large.
Load diff
+4
-2
@@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
|
||||
int main(int argc, char *argv[]) {
|
||||
int flags = 0;
|
||||
const char *dir;
|
||||
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH;
|
||||
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS;
|
||||
if (argc > 2 && strchr(argv[2], 'd') != NULL)
|
||||
flags |= FTW_DEPTH;
|
||||
if (argc > 2 && strchr(argv[2], 'p') != NULL)
|
||||
flags |= FTW_PHYS;
|
||||
dir = argc < 2 ? "." : argv[1];
|
||||
if (nftw(dir, display_info, 20, flags) == -1) {
|
||||
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);
|
||||
|
||||
+8
-4
@@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
if (isatty(0) && (s = ttyname(0)))
|
||||
appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
@@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
if (i)
|
||||
appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
@@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) continue;
|
||||
if (g_verbose) perror(pts);
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
if (g_verbose)
|
||||
perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
|
||||
@@ -242,6 +242,7 @@ libc/isystem/system_error \
|
||||
libc/isystem/termios.h \
|
||||
libc/isystem/tgmath.h \
|
||||
libc/isystem/thread \
|
||||
libc/isystem/threads.h \
|
||||
libc/isystem/time.h \
|
||||
libc/isystem/tmmintrin.h \
|
||||
libc/isystem/tuple \
|
||||
|
||||
@@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
|
||||
t.sn[5] = 0;
|
||||
|
||||
if (IsLinux()) {
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty))
|
||||
return -1;
|
||||
t.sn[5] = 'p';
|
||||
t.sn[6] = 't';
|
||||
t.sn[7] = 's';
|
||||
|
||||
+3
-1
@@ -237,7 +237,9 @@ int sys_munlock(const void *, size_t) libcesque;
|
||||
int sys_munlockall(void) libcesque;
|
||||
int sys_personality(uint64_t) libcesque;
|
||||
int sys_ptrace(int, ...) libcesque;
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque;
|
||||
int sysctlbyname(const char *, void *, size_t *, void *, size_t) libcesque;
|
||||
int sysctlnametomib(const char *, int *, size_t *) libcesque;
|
||||
int tmpfd(void) libcesque;
|
||||
int touch(const char *, unsigned) libcesque;
|
||||
int unveil(const char *, const char *) libcesque;
|
||||
|
||||
@@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetspeed(struct termios *t, uint32_t speed) {
|
||||
if (cfsetispeed(t, speed) == -1) return -1;
|
||||
if (cfsetospeed(t, speed) == -1) return -1;
|
||||
if (cfsetispeed(t, speed) == -1)
|
||||
return -1;
|
||||
if (cfsetospeed(t, speed) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -33,7 +33,8 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
|
||||
char16_t var[4];
|
||||
|
||||
if (len && path[len - 1] != u'\\') {
|
||||
if (len + 2 > PATH_MAX) return enametoolong();
|
||||
if (len + 2 > PATH_MAX)
|
||||
return enametoolong();
|
||||
path[len + 0] = u'\\';
|
||||
path[len + 1] = u'\0';
|
||||
}
|
||||
@@ -84,7 +85,9 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
int len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (!len) return enoent();
|
||||
if ((len = __mkntpath(path, path16)) == -1)
|
||||
return -1;
|
||||
if (!len)
|
||||
return enoent();
|
||||
return sys_chdir_nt_impl(path16, len);
|
||||
}
|
||||
@@ -24,11 +24,16 @@
|
||||
|
||||
textwindows int _check_signal(bool restartable) {
|
||||
int status;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (!_weaken(__sig_check)) return 0;
|
||||
if (!(status = _weaken(__sig_check)())) return 0;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (status == 2 && restartable) return 0;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (!_weaken(__sig_check))
|
||||
return 0;
|
||||
if (!(status = _weaken(__sig_check)()))
|
||||
return 0;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (status == 2 && restartable)
|
||||
return 0;
|
||||
return eintr();
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -53,7 +53,7 @@ static dontinline int __clk_tck_init(void) {
|
||||
cmd[0] = 1; // CTL_KERN
|
||||
cmd[1] = 12; // KERN_CLOCKRATE
|
||||
len = sizeof(clock);
|
||||
if (sys_sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
|
||||
if (sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
|
||||
x = clock.hz;
|
||||
} else {
|
||||
x = -1;
|
||||
@@ -61,7 +61,8 @@ static dontinline int __clk_tck_init(void) {
|
||||
} else {
|
||||
x = __getauxval(AT_CLKTCK).value;
|
||||
}
|
||||
if (x < 1) x = 100;
|
||||
if (x < 1)
|
||||
x = 100;
|
||||
clk_tck = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
||||
#ifdef __x86_64__
|
||||
// intel architecture guarantees that a mapping exists between rdtsc &
|
||||
// nanoseconds only if the cpu advertises invariant timestamps support
|
||||
if (!X86_HAVE(INVTSC)) return -EINVAL;
|
||||
if (!X86_HAVE(INVTSC))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
|
||||
@@ -60,14 +60,17 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
|
||||
}
|
||||
return 0;
|
||||
} else if (clock == CLOCK_MONOTONIC) {
|
||||
if (!ts) return 0;
|
||||
if (!ts)
|
||||
return 0;
|
||||
return sys_clock_gettime_mono(ts);
|
||||
} else if (clock == CLOCK_BOOTTIME) {
|
||||
struct timeval x;
|
||||
size_t n = sizeof(x);
|
||||
int mib[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1;
|
||||
if (ts) *ts = timeval_totimespec(timeval_sub(timeval_real(), x));
|
||||
if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1)
|
||||
return -1;
|
||||
if (ts)
|
||||
*ts = timeval_totimespec(timeval_sub(timeval_real(), x));
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
@@ -57,7 +57,8 @@ int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
|
||||
clock_gettime(time_clock, &start);
|
||||
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req);
|
||||
if (timespec_cmp(start, deadline) >= 0) return 0;
|
||||
if (timespec_cmp(start, deadline) >= 0)
|
||||
return 0;
|
||||
remain = timespec_sub(deadline, start);
|
||||
if (timespec_cmp(remain, quantum) > 0) {
|
||||
waitfor = timespec_sub(remain, quantum);
|
||||
|
||||
@@ -32,10 +32,13 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
|
||||
uint32_t msdelay;
|
||||
struct timespec now;
|
||||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (sys_clock_gettime_nt(clock, &now))
|
||||
return -1;
|
||||
if (timespec_cmp(now, abs) >= 0)
|
||||
return 0;
|
||||
msdelay = timespec_tomillis(timespec_sub(abs, now));
|
||||
if (_park_norestart(msdelay, waitmask)) return -1;
|
||||
if (_park_norestart(msdelay, waitmask))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +51,8 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = *req;
|
||||
} else {
|
||||
if ((rc = sys_clock_gettime_nt(clock, &now))) goto BailOut;
|
||||
if ((rc = sys_clock_gettime_nt(clock, &now)))
|
||||
goto BailOut;
|
||||
abs = timespec_add(now, *req);
|
||||
}
|
||||
rc = sys_clock_nanosleep_nt_impl(clock, abs, m);
|
||||
|
||||
@@ -46,7 +46,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
||||
} else {
|
||||
int rc;
|
||||
struct timespec beg;
|
||||
if (rem) sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
|
||||
if (rem)
|
||||
sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
|
||||
struct timeval rel = timespec_totimeval(*req); // rounds up
|
||||
rc = sys_select(0, 0, 0, 0, &rel);
|
||||
if (rc == -1 && rem && errno == EINTR) {
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_close_nt(int fd, int fildes) {
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
switch (f->kind) {
|
||||
case kFdZip:
|
||||
|
||||
+4
-2
@@ -97,12 +97,14 @@ int close(int fd) {
|
||||
BLOCK_SIGNALS;
|
||||
__fds_lock();
|
||||
rc = close_impl(fd);
|
||||
if (!__vforked) __releasefd(fd);
|
||||
if (!__vforked)
|
||||
__releasefd(fd);
|
||||
__fds_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
} else {
|
||||
rc = close_impl(fd);
|
||||
if (!__vforked) __releasefd(fd);
|
||||
if (!__vforked)
|
||||
__releasefd(fd);
|
||||
}
|
||||
STRACE("close(%d) → %d% m", fd, rc);
|
||||
return rc;
|
||||
|
||||
+6
-3
@@ -37,10 +37,13 @@ ssize_t copyfd(int in, int out, size_t n) {
|
||||
ssize_t dr, dw;
|
||||
for (i = 0; i < n; i += dr) {
|
||||
dr = read(in, buf, MIN(n - i, sizeof(buf)));
|
||||
if (dr == -1) return -1;
|
||||
if (!dr) break;
|
||||
if (dr == -1)
|
||||
return -1;
|
||||
if (!dr)
|
||||
break;
|
||||
dw = write(out, buf, dr);
|
||||
if (dw == -1) return -1;
|
||||
if (dw == -1)
|
||||
return -1;
|
||||
if (dw != dr) {
|
||||
// POSIX requires atomic IO up to PIPE_BUF
|
||||
// The minimum permissible PIPE_BUF is 512
|
||||
|
||||
@@ -156,9 +156,12 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
}
|
||||
|
||||
// Not certain yet what benefit these flags offer.
|
||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||
if (flags & _O_SEQUENTIAL)
|
||||
attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM)
|
||||
attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT)
|
||||
attr |= kNtFileFlagNoBuffering;
|
||||
|
||||
// TODO(jart): Should we *always* open with write permission if the
|
||||
// kernel will give it to us? We'd then deny write access
|
||||
@@ -172,9 +175,13 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
// writing to a file across a network can occasionally return
|
||||
// kNtErrorAccessDenied." -Quoth MSDN
|
||||
|
||||
if (out_perm) *out_perm = perm;
|
||||
if (out_share) *out_share = share;
|
||||
if (out_disp) *out_disp = disp;
|
||||
if (out_attr) *out_attr = attr;
|
||||
if (out_perm)
|
||||
*out_perm = perm;
|
||||
if (out_share)
|
||||
*out_share = share;
|
||||
if (out_disp)
|
||||
*out_disp = disp;
|
||||
if (out_attr)
|
||||
*out_attr = attr;
|
||||
return 0;
|
||||
}
|
||||
@@ -42,7 +42,8 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
|
||||
char16_t *p = a;
|
||||
const char *q = "\\\\?\\pipe\\cosmo\\";
|
||||
static atomic_uint x;
|
||||
while (*q) *p++ = *q++;
|
||||
while (*q)
|
||||
*p++ = *q++;
|
||||
p = itoa16(p, __pid);
|
||||
*p++ = '-';
|
||||
p = itoa16(p, atomic_fetch_add(&x, 1));
|
||||
|
||||
+4
-2
@@ -66,12 +66,14 @@
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (_weaken(kloghandle))
|
||||
_weaken(kloghandle)();
|
||||
#ifdef __aarch64__
|
||||
if (oldfd == newfd) {
|
||||
// linux aarch64 defines dup3() but not dup2(), which wasn't such a
|
||||
// great decision, since the two syscalls don't behave the same way
|
||||
if (!(rc = read(oldfd, 0, 0))) rc = oldfd;
|
||||
if (!(rc = read(oldfd, 0, 0)))
|
||||
rc = oldfd;
|
||||
} else
|
||||
#endif
|
||||
if (!IsWindows()) {
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (_weaken(kloghandle))
|
||||
_weaken(kloghandle)();
|
||||
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
|
||||
rc = einval(); // NetBSD doesn't do this
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
|
||||
uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1)
|
||||
return -1;
|
||||
return __fix_enotdir(ntaccesscheck(path16, mode), path16);
|
||||
}
|
||||
@@ -64,7 +64,8 @@ int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
rc = _weaken(__zipos_access)(&zipname, amode);
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if (!flags) goto NoFlags;
|
||||
if (!flags)
|
||||
goto NoFlags;
|
||||
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = e;
|
||||
|
||||
@@ -37,8 +37,10 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset,
|
||||
int rc, flags, mode;
|
||||
uint32_t perm, share, attr;
|
||||
|
||||
if ((int64_t)len < 0) return einval();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if ((int64_t)len < 0)
|
||||
return einval();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return ebadf();
|
||||
h1 = g_fds.p[fd].handle;
|
||||
mode = g_fds.p[fd].mode;
|
||||
flags = g_fds.p[fd].flags;
|
||||
|
||||
@@ -27,7 +27,8 @@ int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
|
||||
|
||||
textwindows int sys_fchdir_nt(int dirfd) {
|
||||
char16_t dir[PATH_MAX];
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(dirfd, kFdFile))
|
||||
return ebadf();
|
||||
return sys_chdir_nt_impl(
|
||||
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos));
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
|
||||
|
||||
// validate file descriptor
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (g_fds.p[fd].kind == kFdEmpty) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
if (g_fds.p[fd].kind == kFdEmpty)
|
||||
return ebadf();
|
||||
|
||||
// get current information
|
||||
struct NtFileBasicInfo fbi;
|
||||
|
||||
@@ -26,7 +26,8 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
|
||||
int flags) {
|
||||
uint32_t attr;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1)
|
||||
return -1;
|
||||
if ((attr = GetFileAttributes(path16)) != -1u) {
|
||||
if (mode & 0222) {
|
||||
attr &= ~kNtFileAttributeReadonly;
|
||||
|
||||
+10
-5
@@ -129,7 +129,8 @@ textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
|
||||
static textwindows int64_t GetfileSize(int64_t handle) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!GetFileInformationByHandle(handle, &wst)) return __winerr();
|
||||
if (!GetFileInformationByHandle(handle, &wst))
|
||||
return __winerr();
|
||||
return (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
|
||||
}
|
||||
|
||||
@@ -156,7 +157,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
break;
|
||||
case SEEK_END: {
|
||||
int64_t size;
|
||||
if ((size = GetfileSize(f->handle)) == -1) return -1;
|
||||
if ((size = GetfileSize(f->handle)) == -1)
|
||||
return -1;
|
||||
off = size - off;
|
||||
break;
|
||||
}
|
||||
@@ -254,7 +256,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
if (cmd == F_GETLK)
|
||||
return einval();
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
@@ -318,7 +321,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
if (start < 0)
|
||||
return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
@@ -328,7 +332,8 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdSocket) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdDevNull)) {
|
||||
__isfdkind(fd, kFdDevNull) || //
|
||||
__isfdkind(fd, kFdDevRandom)) {
|
||||
if (cmd == F_GETFL) {
|
||||
rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT |
|
||||
_O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL);
|
||||
|
||||
@@ -27,17 +27,23 @@
|
||||
|
||||
textwindows int sys_fdatasync_nt(int fd, bool fake) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return einval();
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval();
|
||||
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst)) return __winerr();
|
||||
if (!__isfdopen(fd))
|
||||
return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return einval();
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk)
|
||||
return einval();
|
||||
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst))
|
||||
return __winerr();
|
||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
// Flushing a directory handle is possible, but it needs
|
||||
// kNtGenericWrite access, and MSDN doesn't document it.
|
||||
return 0;
|
||||
}
|
||||
if (fake) return 0;
|
||||
if (_check_signal(false) == -1) return -1;
|
||||
if (fake)
|
||||
return 0;
|
||||
if (_check_signal(false) == -1)
|
||||
return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
textwindows int sys_flock_nt(int fd, int op) {
|
||||
int64_t h;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return ebadf();
|
||||
h = g_fds.p[fd].handle;
|
||||
struct NtOverlapped ov = {.hEvent = h};
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fstat_metal(int fd, struct stat *st) {
|
||||
if (fd < 0) return einval();
|
||||
if (fd < 0)
|
||||
return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
|
||||
bzero(st, sizeof(*st));
|
||||
st->st_dev = g_fds.p[fd].handle;
|
||||
|
||||
@@ -97,12 +97,14 @@ textwindows int sys_fstat_nt_special(int kind, struct stat *st) {
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt(int fd, struct stat *st) {
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
switch (g_fds.p[fd].kind) {
|
||||
case kFdEmpty:
|
||||
return ebadf();
|
||||
case kFdConsole:
|
||||
case kFdDevNull:
|
||||
case kFdDevRandom:
|
||||
return sys_fstat_nt_special(g_fds.p[fd].kind, st);
|
||||
case kFdSocket:
|
||||
return sys_fstat_nt_socket(g_fds.p[fd].kind, st);
|
||||
@@ -174,7 +176,8 @@ textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path,
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (!st.st_size) {
|
||||
long size = GetSizeOfReparsePoint(handle);
|
||||
if (size == -1) return -1;
|
||||
if (size == -1)
|
||||
return -1;
|
||||
st.st_size = size;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
static int Atoi(const char *str) {
|
||||
int c;
|
||||
unsigned x = 0;
|
||||
if (!*str) return -1;
|
||||
if (!*str)
|
||||
return -1;
|
||||
while ((c = *str++)) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
x *= 10;
|
||||
@@ -58,6 +59,8 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||
return sys_fstat_nt_special(kFdConsole, st);
|
||||
} else if (!strcmp(path + 5, "null")) {
|
||||
return sys_fstat_nt_special(kFdDevNull, st);
|
||||
} else if (!strcmp(path + 5, "random") || !strcmp(path + 5, "urandom")) {
|
||||
return sys_fstat_nt_special(kFdDevRandom, st);
|
||||
} else if (!strcmp(path + 5, "stdin")) {
|
||||
return sys_fstat_nt(STDIN_FILENO, st);
|
||||
} else if (!strcmp(path + 5, "stdout")) {
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static inline const char *__strace_fstatat_flags(char buf[12], int flags) {
|
||||
if (flags == AT_SYMLINK_NOFOLLOW) return "AT_SYMLINK_NOFOLLOW";
|
||||
if (flags == AT_SYMLINK_NOFOLLOW)
|
||||
return "AT_SYMLINK_NOFOLLOW";
|
||||
FormatInt32(buf, flags);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ textwindows int sys_fstatfs_nt(int64_t handle, struct statfs *f) {
|
||||
st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs),
|
||||
kNtFileFsFullSizeInformation);
|
||||
if (!NtSuccess(st)) {
|
||||
if (st == kNtStatusDllNotFound) return enosys();
|
||||
if (st == kNtStatusDllNotFound)
|
||||
return enosys();
|
||||
return eio();
|
||||
}
|
||||
for (h = j = i = 0; FileSystemNameBuffer[i]; i++) {
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
int ftok(const char *path, int id) {
|
||||
struct stat st;
|
||||
if (stat(path, &st) == -1) return -1;
|
||||
if (stat(path, &st) == -1)
|
||||
return -1;
|
||||
return (uint32_t)id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff);
|
||||
}
|
||||
+2
-1
@@ -64,7 +64,8 @@ int getcpu(unsigned *out_opt_cpu, unsigned *out_opt_node) {
|
||||
}
|
||||
} else {
|
||||
int rc = sys_getcpu(&cpu, &node, 0);
|
||||
if (rc == -1) return -1;
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
}
|
||||
if (out_opt_cpu) {
|
||||
*out_opt_cpu = cpu;
|
||||
|
||||
@@ -51,7 +51,7 @@ static int __get_cpu_count_bsd(void) {
|
||||
} else {
|
||||
cmd[1] = HW_NCPU;
|
||||
}
|
||||
if (!sys_sysctl(cmd, 2, &c, &n, 0, 0)) {
|
||||
if (!sysctl(cmd, 2, &c, &n, 0, 0)) {
|
||||
return c;
|
||||
} else {
|
||||
return -1;
|
||||
|
||||
@@ -82,14 +82,17 @@ static dontinline textwindows int sys_getcwd_nt(char *buf, size_t size) {
|
||||
// get current directory from the system
|
||||
char16_t p16[PATH_MAX];
|
||||
uint32_t n = GetCurrentDirectory(PATH_MAX, p16);
|
||||
if (!n) return eacces(); // system call failed
|
||||
if (n >= PATH_MAX) return erange(); // not enough room?!?
|
||||
if (!n)
|
||||
return eacces(); // system call failed
|
||||
if (n >= PATH_MAX)
|
||||
return erange(); // not enough room?!?
|
||||
|
||||
// convert utf-16 to utf-8
|
||||
// we can't modify `buf` until we're certain of success
|
||||
char p8[PATH_MAX], *p = p8;
|
||||
n = tprecode16to8(p, PATH_MAX, p16).ax;
|
||||
if (n >= PATH_MAX) return erange(); // utf-8 explosion
|
||||
if (n >= PATH_MAX)
|
||||
return erange(); // utf-8 explosion
|
||||
|
||||
// turn \\?\c:\... into c:\...
|
||||
if (p[0] == '\\' && //
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
int gethostname_bsd(char *name, size_t len, int kind) {
|
||||
int cmd[2] = {CTL_KERN, kind};
|
||||
if (sys_sysctl(cmd, 2, name, &len, 0, 0) != -1) {
|
||||
if (sysctl(cmd, 2, name, &len, 0, 0) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
if (errno == ENOMEM) {
|
||||
|
||||
@@ -43,7 +43,8 @@ struct loadavg {
|
||||
int getloadavg(double *a, int n) {
|
||||
// cat /proc/loadavg
|
||||
int i, rc;
|
||||
if (n > 3) n = 3;
|
||||
if (n > 3)
|
||||
n = 3;
|
||||
if (!n) {
|
||||
rc = 0;
|
||||
} else if (n < 0) {
|
||||
@@ -63,7 +64,7 @@ int getloadavg(double *a, int n) {
|
||||
struct loadavg loadinfo;
|
||||
int mib[2] = {CTL_VM, VM_LOADAVG};
|
||||
size = sizeof(loadinfo);
|
||||
if ((rc = sys_sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) {
|
||||
if ((rc = sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) {
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i] = (double)loadinfo.ldavg[i] / loadinfo.fscale;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static int OldApeLoader(char *s) {
|
||||
(!strncmp((b = basename(s)), ".ape-", 5) && AllNumDot(b + 5));
|
||||
}
|
||||
|
||||
static char *CopyWithCwd(const char *q, char *p, char *e) {
|
||||
static int CopyWithCwd(const char *q, char *p, char *e) {
|
||||
char c;
|
||||
if (*q != '/') {
|
||||
if (q[0] == '.' && q[1] == '/') {
|
||||
@@ -109,29 +109,19 @@ static char *CopyWithCwd(const char *q, char *p, char *e) {
|
||||
if (p + 1 /* nul */ < e) {
|
||||
*p++ = c;
|
||||
} else {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
return p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if q exists then turn it into an absolute path. we also try adding
|
||||
// a .com suffix since the ape auto-appends it when resolving
|
||||
//
|
||||
// TODO(jart): is this still relevant?
|
||||
static int TryPath(const char *q, int com) {
|
||||
char *p;
|
||||
if (!(p = CopyWithCwd(q, g_prog.u.buf,
|
||||
g_prog.u.buf + sizeof(g_prog.u.buf) - com * 4))) {
|
||||
// if q exists then turn it into an absolute path.
|
||||
static int TryPath(const char *q) {
|
||||
if (!CopyWithCwd(q, g_prog.u.buf, g_prog.u.buf + sizeof(g_prog.u.buf))) {
|
||||
return 0;
|
||||
}
|
||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return 1;
|
||||
if (!com) return 0;
|
||||
p = WRITE32LE(p, READ32LE(".com"));
|
||||
*p = 0;
|
||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return 1;
|
||||
return 0;
|
||||
return !sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0);
|
||||
}
|
||||
|
||||
// if the loader passed a relative path, prepend cwd to it.
|
||||
@@ -205,7 +195,7 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
|
||||
}
|
||||
cmd[3] = -1; // current process
|
||||
if (sys_sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
||||
if (sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
||||
if (!OldApeLoader(b)) {
|
||||
goto UseBuf;
|
||||
}
|
||||
@@ -221,13 +211,13 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// don't trust argument parsing if set-id.
|
||||
// don't trust argv or envp if set-id.
|
||||
if (issetugid()) {
|
||||
goto UseEmpty;
|
||||
}
|
||||
|
||||
// try argv[0], then argv[0].com, then $_, then $_.com.
|
||||
if (TryPath(__argv[0], 1) || TryPath(__getenv(__envp, "_").s, 1)) {
|
||||
// try argv[0], then then $_.
|
||||
if (TryPath(__argv[0]) || TryPath(__getenv(__envp, "_").s)) {
|
||||
goto UseBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) {
|
||||
for (i = 0; i < n; i += j) {
|
||||
TryAgain:
|
||||
if (!impl(&x)) {
|
||||
if (f || i >= 256) break;
|
||||
if (f || i >= 256)
|
||||
break;
|
||||
goto TryAgain;
|
||||
}
|
||||
for (j = 0; j < 8 && i + j < n; ++j) {
|
||||
|
||||
@@ -60,7 +60,8 @@ static bool have_getrandom;
|
||||
|
||||
static void GetRandomEntropy(char *p, size_t n) {
|
||||
unassert(n <= 256);
|
||||
if (sys_getentropy(p, n)) notpossible;
|
||||
if (sys_getentropy(p, n))
|
||||
notpossible;
|
||||
}
|
||||
|
||||
static void GetRandomArnd(char *p, size_t n) {
|
||||
@@ -69,8 +70,10 @@ static void GetRandomArnd(char *p, size_t n) {
|
||||
cmd[0] = 1; // CTL_KERN
|
||||
cmd[1] = IsFreebsd() ? 37 : 81; // KERN_ARND
|
||||
unassert((m = n) <= 256);
|
||||
if (sys_sysctl(cmd, 2, p, &n, 0, 0) == -1) notpossible;
|
||||
if (m != n) notpossible;
|
||||
if (sysctl(cmd, 2, p, &n, 0, 0) == -1)
|
||||
notpossible;
|
||||
if (m != n)
|
||||
notpossible;
|
||||
}
|
||||
|
||||
static ssize_t GetRandomBsd(char *p, size_t n, void impl(char *, size_t)) {
|
||||
@@ -193,7 +196,8 @@ ssize_t getrandom(void *p, size_t n, unsigned f) {
|
||||
__attribute__((__constructor__(30))) static textstartup void getrandom_init(
|
||||
void) {
|
||||
int e, rc;
|
||||
if (IsWindows() || IsMetal()) return;
|
||||
if (IsWindows() || IsMetal())
|
||||
return;
|
||||
BLOCK_CANCELATION;
|
||||
e = errno;
|
||||
if (!(rc = sys_getrandom(0, 0, 0))) {
|
||||
|
||||
+10
-5
@@ -34,15 +34,20 @@ int getresgid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
|
||||
int rc, gid;
|
||||
if (IsWindows()) {
|
||||
gid = getgid();
|
||||
if (real) *real = gid;
|
||||
if (effective) *effective = gid;
|
||||
if (saved) *saved = gid;
|
||||
if (real)
|
||||
*real = gid;
|
||||
if (effective)
|
||||
*effective = gid;
|
||||
if (saved)
|
||||
*saved = gid;
|
||||
rc = 0;
|
||||
} else if (saved) {
|
||||
rc = sys_getresgid(real, effective, saved);
|
||||
} else {
|
||||
if (real) *real = sys_getgid();
|
||||
if (effective) *effective = sys_getegid();
|
||||
if (real)
|
||||
*real = sys_getgid();
|
||||
if (effective)
|
||||
*effective = sys_getegid();
|
||||
rc = 0;
|
||||
}
|
||||
STRACE("getresgid([%d], [%d], [%d]) → %d% m", real ? *real : 0,
|
||||
|
||||
+10
-5
@@ -34,15 +34,20 @@ int getresuid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
|
||||
int rc, uid;
|
||||
if (IsWindows()) {
|
||||
uid = getuid();
|
||||
if (real) *real = uid;
|
||||
if (effective) *effective = uid;
|
||||
if (saved) *saved = uid;
|
||||
if (real)
|
||||
*real = uid;
|
||||
if (effective)
|
||||
*effective = uid;
|
||||
if (saved)
|
||||
*saved = uid;
|
||||
rc = 0;
|
||||
} else if (saved) {
|
||||
rc = sys_getresuid(real, effective, saved);
|
||||
} else {
|
||||
if (real) *real = sys_getuid();
|
||||
if (effective) *effective = sys_geteuid();
|
||||
if (real)
|
||||
*real = sys_getuid();
|
||||
if (effective)
|
||||
*effective = sys_geteuid();
|
||||
rc = 0;
|
||||
}
|
||||
STRACE("getresuid([%d], [%d], [%d]) → %d% m", real ? *real : 0,
|
||||
|
||||
@@ -25,7 +25,8 @@ textwindows char *GetSystemDirectoryPath(char *buf, const char *path,
|
||||
uint32_t syslen = GetSystemDirectoryA(buf, size);
|
||||
size_t pathlen = strlen(path);
|
||||
if (syslen && syslen + pathlen + 1 < size) {
|
||||
if (buf[syslen] == '\\') --syslen;
|
||||
if (buf[syslen] == '\\')
|
||||
--syslen;
|
||||
memcpy(buf + syslen, path, pathlen + 1);
|
||||
return buf;
|
||||
} else {
|
||||
|
||||
@@ -29,7 +29,8 @@ textwindows uint32_t sys_getuid_nt(void) {
|
||||
if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) {
|
||||
GetUserName(&buf, &size);
|
||||
tmp = __fnv(buf, size >> 1) & 32767;
|
||||
if (!tmp) ++tmp;
|
||||
if (!tmp)
|
||||
++tmp;
|
||||
atomic_store_explicit(&uid, tmp, memory_order_release);
|
||||
}
|
||||
return tmp;
|
||||
|
||||
+35
-19
@@ -24,7 +24,6 @@
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
@@ -42,6 +41,7 @@
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/ifconf.h"
|
||||
#include "libc/sock/struct/ifreq.h"
|
||||
@@ -66,7 +66,7 @@ static struct HostAdapterInfoNode {
|
||||
struct sockaddr netmask;
|
||||
struct sockaddr broadcast;
|
||||
short flags;
|
||||
} *__hostInfo;
|
||||
} * __hostInfo;
|
||||
|
||||
static int ioctl_default(int fd, unsigned long request, void *arg) {
|
||||
int rc;
|
||||
@@ -107,8 +107,9 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
|
||||
*arg = MAX(0, bytes);
|
||||
return 0;
|
||||
} else if (g_fds.p[fd].kind == kFdDevNull) {
|
||||
*arg = 1;
|
||||
return 0;
|
||||
return enotty();
|
||||
} else if (g_fds.p[fd].kind == kFdDevRandom) {
|
||||
return einval();
|
||||
} else if (GetFileType(handle) == kNtFileTypePipe) {
|
||||
uint32_t avail;
|
||||
if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) {
|
||||
@@ -244,11 +245,16 @@ static textwindows struct HostAdapterInfoNode *appendHostInfo(
|
||||
* IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it
|
||||
*/
|
||||
flags = 0;
|
||||
if (aa->OperStatus == kNtIfOperStatusUp) flags |= IFF_UP | IFF_RUNNING;
|
||||
if (aa->IfType == kNtIfTypePpp) flags |= IFF_POINTOPOINT;
|
||||
if (!(aa->Flags & kNtIpAdapterNoMulticast)) flags |= IFF_MULTICAST;
|
||||
if (aa->IfType == kNtIfTypeSoftwareLoopback) flags |= IFF_LOOPBACK;
|
||||
if (aa->FirstPrefix) flags |= IFF_BROADCAST;
|
||||
if (aa->OperStatus == kNtIfOperStatusUp)
|
||||
flags |= IFF_UP | IFF_RUNNING;
|
||||
if (aa->IfType == kNtIfTypePpp)
|
||||
flags |= IFF_POINTOPOINT;
|
||||
if (!(aa->Flags & kNtIpAdapterNoMulticast))
|
||||
flags |= IFF_MULTICAST;
|
||||
if (aa->IfType == kNtIfTypeSoftwareLoopback)
|
||||
flags |= IFF_LOOPBACK;
|
||||
if (aa->FirstPrefix)
|
||||
flags |= IFF_BROADCAST;
|
||||
node->flags = flags;
|
||||
} else {
|
||||
/* Copy from previous node */
|
||||
@@ -344,13 +350,16 @@ static textwindows int createHostInfo(
|
||||
baseName[IFNAMSIZ - 2] = '\0';
|
||||
/* Replace any space with a '_' */
|
||||
for (i = 0; i < IFNAMSIZ - 2; ++i) {
|
||||
if (baseName[i] == ' ') baseName[i] = '_';
|
||||
if (!baseName[i]) break;
|
||||
if (baseName[i] == ' ')
|
||||
baseName[i] = '_';
|
||||
if (!baseName[i])
|
||||
break;
|
||||
}
|
||||
for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix;
|
||||
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
|
||||
node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
|
||||
if (!node) goto err;
|
||||
if (!node)
|
||||
goto err;
|
||||
if (!__hostInfo) {
|
||||
__hostInfo = node;
|
||||
if (_cmpxchg(&once, false, true)) {
|
||||
@@ -444,7 +453,8 @@ static textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) {
|
||||
static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
|
||||
struct HostAdapterInfoNode *node;
|
||||
node = findAdapterByName(ifr->ifr_name);
|
||||
if (!node) return ebadf();
|
||||
if (!node)
|
||||
return ebadf();
|
||||
memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr));
|
||||
return 0;
|
||||
}
|
||||
@@ -453,7 +463,8 @@ static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
|
||||
static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
|
||||
struct HostAdapterInfoNode *node;
|
||||
node = findAdapterByName(ifr->ifr_name);
|
||||
if (!node) return ebadf();
|
||||
if (!node)
|
||||
return ebadf();
|
||||
ifr->ifr_flags = node->flags;
|
||||
return 0;
|
||||
}
|
||||
@@ -462,7 +473,8 @@ static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
|
||||
static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
|
||||
struct HostAdapterInfoNode *node;
|
||||
node = findAdapterByName(ifr->ifr_name);
|
||||
if (!node) return ebadf();
|
||||
if (!node)
|
||||
return ebadf();
|
||||
memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr));
|
||||
return 0;
|
||||
}
|
||||
@@ -473,7 +485,8 @@ static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
|
||||
static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) {
|
||||
struct HostAdapterInfoNode *node;
|
||||
node = findAdapterByName(ifr->ifr_name);
|
||||
if (!node) return ebadf();
|
||||
if (!node)
|
||||
return ebadf();
|
||||
memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr));
|
||||
return 0;
|
||||
}
|
||||
@@ -513,7 +526,8 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
||||
for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e;
|
||||
p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) {
|
||||
fam = p[IsBsd() ? 17 : 16] & 255;
|
||||
if (fam != AF_INET) continue;
|
||||
if (fam != AF_INET)
|
||||
continue;
|
||||
ip = READ32BE(p + 20);
|
||||
bzero(req, sizeof(*req));
|
||||
memcpy(req->ifr_name, p, 16);
|
||||
@@ -541,8 +555,10 @@ static inline void ioctl_sockaddr2linux(void *saddr) {
|
||||
* requires adjustment between Linux and XNU
|
||||
*/
|
||||
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
|
||||
if (sys_ioctl(fd, op, ifr) == -1) return -1;
|
||||
if (IsBsd()) ioctl_sockaddr2linux(&ifr->ifr_addr);
|
||||
if (sys_ioctl(fd, op, ifr) == -1)
|
||||
return -1;
|
||||
if (IsBsd())
|
||||
ioctl_sockaddr2linux(&ifr->ifr_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ bool32 ischardev(int fd) {
|
||||
}
|
||||
} else {
|
||||
return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) ||
|
||||
__isfdkind(fd, kFdDevRandom) ||
|
||||
(__isfdkind(fd, kFdFile) &&
|
||||
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
bool isdirectory_nt(const char *path) {
|
||||
uint32_t x;
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpath(path, path16) == -1)
|
||||
return -1;
|
||||
if ((x = GetFileAttributes(path16)) != -1u) {
|
||||
return !!(x & kNtFileAttributeDirectory);
|
||||
} else {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
bool32 isexecutable(const char *path) {
|
||||
struct stat st;
|
||||
if (fstatat(AT_FDCWD, path, &st, 0)) return 0;
|
||||
if (fstatat(AT_FDCWD, path, &st, 0))
|
||||
return 0;
|
||||
return !S_ISDIR(st.st_mode) && !!(st.st_mode & 0111);
|
||||
}
|
||||
@@ -33,7 +33,8 @@ static struct {
|
||||
|
||||
static bool __is_linux_2_6_23_impl(void) {
|
||||
int rc;
|
||||
if (IsGenuineBlink()) return true;
|
||||
if (IsGenuineBlink())
|
||||
return true;
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(157), "D"(PR_GET_SECCOMP)
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
bool isregularfile_nt(const char *path) {
|
||||
uint32_t x;
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpath(path, path16) == -1)
|
||||
return -1;
|
||||
if ((x = GetFileAttributes(path16)) != -1u) {
|
||||
return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint));
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
bool issymlink_nt(const char *path) {
|
||||
uint32_t x;
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpath(path, path16) == -1)
|
||||
return -1;
|
||||
if ((x = GetFileAttributes(path16)) != -1u) {
|
||||
return !!(x & kNtFileAttributeReparsePoint);
|
||||
} else {
|
||||
|
||||
@@ -62,7 +62,7 @@ static textwindows int64_t Seek(struct Fd *f, int64_t offset, int whence) {
|
||||
}
|
||||
|
||||
textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
|
||||
if (__isfdkind(fd, kFdDevNull)) {
|
||||
if (__isfdkind(fd, kFdDevNull) || __isfdkind(fd, kFdDevRandom)) {
|
||||
return offset;
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
|
||||
+26
-13
@@ -52,31 +52,42 @@ int makedirs(const char *path, unsigned mode) {
|
||||
|
||||
e = errno;
|
||||
n = strlen(path);
|
||||
if (n >= PATH_MAX) return enametoolong();
|
||||
if (n >= PATH_MAX)
|
||||
return enametoolong();
|
||||
memcpy(buf, path, n + 1);
|
||||
i = n;
|
||||
|
||||
// descend
|
||||
while (i) {
|
||||
if (!mkdir(buf, mode)) break;
|
||||
if (!mkdir(buf, mode))
|
||||
break;
|
||||
if (errno == EEXIST) {
|
||||
if (i == n) goto CheckTop;
|
||||
if (i == n)
|
||||
goto CheckTop;
|
||||
break;
|
||||
}
|
||||
if (errno != ENOENT) return -1;
|
||||
while (i && buf[i - 1] == '/') buf[--i] = 0;
|
||||
while (i && buf[i - 1] != '/') buf[--i] = 0;
|
||||
if (errno != ENOENT)
|
||||
return -1;
|
||||
while (i && buf[i - 1] == '/')
|
||||
buf[--i] = 0;
|
||||
while (i && buf[i - 1] != '/')
|
||||
buf[--i] = 0;
|
||||
}
|
||||
|
||||
// ascend
|
||||
for (;;) {
|
||||
if (mkdir(buf, mode)) {
|
||||
if (errno != EEXIST) return -1;
|
||||
if (i == n) goto CheckTop;
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
if (i == n)
|
||||
goto CheckTop;
|
||||
}
|
||||
if (i == n) break;
|
||||
while (i < n && (c = path[i]) != '/') buf[i++] = c;
|
||||
while (i < n && (c = path[i]) == '/') buf[i++] = c;
|
||||
if (i == n)
|
||||
break;
|
||||
while (i < n && (c = path[i]) != '/')
|
||||
buf[i++] = c;
|
||||
while (i < n && (c = path[i]) == '/')
|
||||
buf[i++] = c;
|
||||
}
|
||||
|
||||
Finish:
|
||||
@@ -84,7 +95,9 @@ Finish:
|
||||
return 0;
|
||||
|
||||
CheckTop:
|
||||
if (stat(path, &st)) return -1;
|
||||
if (S_ISDIR(st.st_mode)) goto Finish;
|
||||
if (stat(path, &st))
|
||||
return -1;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
goto Finish;
|
||||
return eexist();
|
||||
}
|
||||
@@ -23,7 +23,9 @@
|
||||
|
||||
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (CreateDirectory(path16, 0)) return 0;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1)
|
||||
return -1;
|
||||
if (CreateDirectory(path16, 0))
|
||||
return 0;
|
||||
return __fix_enotdir(-1, path16);
|
||||
}
|
||||
+8
-4
@@ -42,10 +42,14 @@
|
||||
*/
|
||||
int mknod(const char *path, uint32_t mode, uint64_t dev) {
|
||||
int e, rc;
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
|
||||
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG);
|
||||
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR);
|
||||
if (mode & S_IFIFO) return enosys(); // no named pipes!
|
||||
if (IsAsan() && !__asan_is_valid_str(path))
|
||||
return efault();
|
||||
if (mode & S_IFREG)
|
||||
return creat(path, mode & ~S_IFREG);
|
||||
if (mode & S_IFDIR)
|
||||
return mkdir(path, mode & ~S_IFDIR);
|
||||
if (mode & S_IFIFO)
|
||||
return enosys(); // no named pipes!
|
||||
if (!IsWindows()) {
|
||||
// TODO(jart): Whys there code out there w/ S_xxx passed via dev?
|
||||
e = errno;
|
||||
|
||||
@@ -86,7 +86,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||
size_t i, j, k, s;
|
||||
char argbuf[PATH_MAX];
|
||||
for (k = i = 0; argv[i]; ++i) {
|
||||
if (i) APPEND(u' ');
|
||||
if (i)
|
||||
APPEND(u' ');
|
||||
if (LooksLikeCosmoDrivePath(argv[i]) &&
|
||||
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
|
||||
mungentpath(argbuf);
|
||||
@@ -112,7 +113,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!x) break;
|
||||
if (!x)
|
||||
break;
|
||||
if (x == '\\') {
|
||||
++slashes;
|
||||
} else if (x == '"') {
|
||||
@@ -125,7 +127,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||
}
|
||||
slashes = 0;
|
||||
uint32_t w = EncodeUtf16(x);
|
||||
do APPEND(w);
|
||||
do
|
||||
APPEND(w);
|
||||
while ((w >>= 16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,12 @@ static textwindows int Compare(const char *l, const char *r) {
|
||||
for (;;) {
|
||||
a = l[i] & 255;
|
||||
b = r[i] & 255;
|
||||
if (a == '=') a = 0;
|
||||
if (b == '=') b = 0;
|
||||
if (a != b || !b) break;
|
||||
if (a == '=')
|
||||
a = 0;
|
||||
if (b == '=')
|
||||
b = 0;
|
||||
if (a != b || !b)
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
return a - b;
|
||||
@@ -56,13 +59,15 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
|
||||
int c, i, cmp;
|
||||
char *var, *path = 0;
|
||||
|
||||
if (!str) return 0;
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
// copy key=val to buf
|
||||
var = env->buf + env->bufi;
|
||||
do {
|
||||
c = *str++;
|
||||
if (env->bufi + 2 > 32767) return e2big();
|
||||
if (env->bufi + 2 > 32767)
|
||||
return e2big();
|
||||
env->buf[env->bufi++] = c;
|
||||
if (c == '=' && str[0] == '/' && IsAlpha(str[1]) && str[2] == '/') {
|
||||
path = env->buf + env->bufi;
|
||||
@@ -70,7 +75,8 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
|
||||
} while (c);
|
||||
|
||||
// fixup key=/c/... → key=c:\...
|
||||
if (path) mungentpath(path);
|
||||
if (path)
|
||||
mungentpath(path);
|
||||
|
||||
// append key=val to sorted list using insertion sort technique
|
||||
for (i = env->vari;; --i) {
|
||||
@@ -143,8 +149,10 @@ textwindows int mkntenvblock(char16_t envblock[32767], char *const envp[],
|
||||
#pragma GCC pop_options
|
||||
|
||||
// load new environment into string pointer array and fix file paths
|
||||
if (InsertStrings(&env, envp) == -1) return -1;
|
||||
if (InsertStrings(&env, extravars) == -1) return -1;
|
||||
if (InsertStrings(&env, envp) == -1)
|
||||
return -1;
|
||||
if (InsertStrings(&env, extravars) == -1)
|
||||
return -1;
|
||||
if (environ) {
|
||||
// https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/
|
||||
e = __getenv(environ, "SYSTEMROOT");
|
||||
|
||||
@@ -54,8 +54,10 @@ textwindows size_t __normntpath(char16_t *p, size_t n) {
|
||||
(i + 1 < n && p[i + 1] == '.') && //
|
||||
(i + 2 == n || IsSlash(p[i + 2]))) {
|
||||
// matched "/../" or "/..$"
|
||||
while (j && p[j - 1] == '\\') --j;
|
||||
while (j && p[j - 1] != '\\') --j;
|
||||
while (j && p[j - 1] == '\\')
|
||||
--j;
|
||||
while (j && p[j - 1] != '\\')
|
||||
--j;
|
||||
} else {
|
||||
p[j++] = c;
|
||||
}
|
||||
@@ -156,7 +158,8 @@ textwindows int __mkntpath2(const char *path,
|
||||
if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
|
||||
(IsSlash(q[4]) || !q[4])) {
|
||||
m = GetTempPath(z, p);
|
||||
if (!q[4]) return m;
|
||||
if (!q[4])
|
||||
return m;
|
||||
q += 5;
|
||||
p += m;
|
||||
z -= m;
|
||||
|
||||
+10
-5
@@ -33,14 +33,19 @@ static textwindows int __mkntpathath_impl(int64_t dirhand, const char *path,
|
||||
size_t n;
|
||||
char16_t dir[PATH_MAX];
|
||||
uint32_t dirlen, filelen;
|
||||
if (!isutf8(path, -1)) return eilseq(); // thwart overlong nul in conversion
|
||||
if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1;
|
||||
if (!filelen) return enoent();
|
||||
if (!isutf8(path, -1))
|
||||
return eilseq(); // thwart overlong nul in conversion
|
||||
if ((filelen = __mkntpath2(path, file, flags)) == -1)
|
||||
return -1;
|
||||
if (!filelen)
|
||||
return enoent();
|
||||
if (file[0] != u'\\' && dirhand != AT_FDCWD) { // ProTip: \\?\C:\foo
|
||||
dirlen = GetFinalPathNameByHandle(dirhand, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (!dirlen) return __winerr();
|
||||
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
if (!dirlen)
|
||||
return __winerr();
|
||||
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir))
|
||||
return enametoolong();
|
||||
dir[dirlen] = u'\\';
|
||||
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
|
||||
memcpy(file, dir, ((n = dirlen + 1 + filelen) + 1) * sizeof(char16_t));
|
||||
|
||||
+2
-1
@@ -84,7 +84,8 @@ int mount(const char *source, const char *target, const char *type,
|
||||
if (!IsBsd()) {
|
||||
return sys_mount_linux(source, target, type, flags, data);
|
||||
} else {
|
||||
if (!strcmp(type, "iso9660")) type = "cd9660";
|
||||
if (!strcmp(type, "iso9660"))
|
||||
type = "cd9660";
|
||||
if (!strcmp(type, "vfat")) {
|
||||
if (IsOpenbsd() || IsNetbsd()) {
|
||||
type = "msdos";
|
||||
|
||||
@@ -47,7 +47,8 @@ void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
|
||||
: "=a"(res)
|
||||
: "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
if (res > -4096ul) errno = -res, res = -1;
|
||||
if (res > -4096ul)
|
||||
errno = -res, res = -1;
|
||||
} else if (IsNetbsd()) {
|
||||
if (f & MREMAP_MAYMOVE) {
|
||||
res = 0x19B;
|
||||
@@ -57,7 +58,8 @@ void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
|
||||
: CFLAG_CONSTRAINT(cf), "+a"(res), "=d"(rdx)
|
||||
: "D"(p), "S"(n), "2"(q), "r"(r10), "r"(r8)
|
||||
: "rcx", "r9", "r11", "memory", "cc");
|
||||
if (cf) errno = res, res = -1;
|
||||
if (cf)
|
||||
errno = res, res = -1;
|
||||
} else {
|
||||
res = einval();
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
|
||||
int64_t hToken, hImpersonatedToken, hFile;
|
||||
intptr_t buffer[1024 / sizeof(intptr_t)];
|
||||
BLOCK_SIGNALS;
|
||||
if (flags & X_OK) flags |= R_OK;
|
||||
if (flags & X_OK)
|
||||
flags |= R_OK;
|
||||
granted = 0;
|
||||
result = false;
|
||||
flagmask = flags;
|
||||
|
||||
@@ -157,7 +157,8 @@ textwindows int ntspawn(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sb) ntspawn_free(sb);
|
||||
if (sb)
|
||||
ntspawn_free(sb);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
+15
-2
@@ -159,6 +159,15 @@ static textwindows int sys_open_nt_special(int fd, int flags, int mode,
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_no_handle(int fd, int flags, int mode,
|
||||
int kind) {
|
||||
g_fds.p[fd].kind = kind;
|
||||
g_fds.p[fd].mode = mode;
|
||||
g_fds.p[fd].flags = flags;
|
||||
g_fds.p[fd].handle = -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
|
||||
int64_t handle;
|
||||
if (!__isfdopen(oldfd)) {
|
||||
@@ -184,7 +193,8 @@ static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
|
||||
static int Atoi(const char *str) {
|
||||
int c;
|
||||
unsigned x = 0;
|
||||
if (!*str) return -1;
|
||||
if (!*str)
|
||||
return -1;
|
||||
while ((c = *str++)) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
x *= 10;
|
||||
@@ -202,13 +212,16 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
||||
int fd, oldfd;
|
||||
BLOCK_SIGNALS;
|
||||
__fds_lock();
|
||||
if (!(flags & _O_CREAT)) mode = 0;
|
||||
if (!(flags & _O_CREAT))
|
||||
mode = 0;
|
||||
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
|
||||
if (startswith(file, "/dev/")) {
|
||||
if (!strcmp(file + 5, "tty")) {
|
||||
rc = sys_open_nt_special(fd, flags, mode, kFdConsole, u"CONIN$");
|
||||
} else if (!strcmp(file + 5, "null")) {
|
||||
rc = sys_open_nt_special(fd, flags, mode, kFdDevNull, u"NUL");
|
||||
} else if (!strcmp(file + 5, "urandom") || !strcmp(file + 5, "random")) {
|
||||
rc = sys_open_nt_no_handle(fd, flags, mode, kFdDevRandom);
|
||||
} else if (!strcmp(file + 5, "stdin")) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDIN_FILENO);
|
||||
} else if (!strcmp(file + 5, "stdout")) {
|
||||
|
||||
@@ -40,20 +40,26 @@
|
||||
int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
|
||||
int fd;
|
||||
struct MetalFile *state;
|
||||
if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME)) return enoent();
|
||||
if (flags != O_RDONLY) return eacces();
|
||||
if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size)) return eopnotsupp();
|
||||
if ((fd = __reservefd(-1)) == -1) return -1;
|
||||
if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME))
|
||||
return enoent();
|
||||
if (flags != O_RDONLY)
|
||||
return eacces();
|
||||
if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size))
|
||||
return eopnotsupp();
|
||||
if ((fd = __reservefd(-1)) == -1)
|
||||
return -1;
|
||||
if (!_weaken(calloc) || !_weaken(free)) {
|
||||
struct DirectMap dm;
|
||||
dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,
|
||||
0);
|
||||
state = dm.addr;
|
||||
if (state == (void *)-1) return -1;
|
||||
if (state == (void *)-1)
|
||||
return -1;
|
||||
} else {
|
||||
state = _weaken(calloc)(1, sizeof(struct MetalFile));
|
||||
if (!state) return -1;
|
||||
if (!state)
|
||||
return -1;
|
||||
}
|
||||
state->base = (char *)__ape_com_base;
|
||||
state->size = __ape_com_size;
|
||||
|
||||
@@ -64,12 +64,16 @@ static int openpty_impl(int *mfd, int *sfd, char *name,
|
||||
}
|
||||
*mfd = m;
|
||||
*sfd = s;
|
||||
if (name) strcpy(name, t.sname);
|
||||
if (tio) npassert(!tcsetattr(s, TCSAFLUSH, tio));
|
||||
if (wsz) npassert(!tcsetwinsize(s, wsz));
|
||||
if (name)
|
||||
strcpy(name, t.sname);
|
||||
if (tio)
|
||||
npassert(!tcsetattr(s, TCSAFLUSH, tio));
|
||||
if (wsz)
|
||||
npassert(!tcsetwinsize(s, wsz));
|
||||
return 0;
|
||||
OnError:
|
||||
if (m != -1) sys_close(m);
|
||||
if (m != -1)
|
||||
sys_close(m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -32,7 +32,8 @@
|
||||
static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
|
||||
bool restartable) {
|
||||
int sig, handler_was_called;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
|
||||
goto HandleSignal;
|
||||
}
|
||||
@@ -46,7 +47,8 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
|
||||
if (ok && _weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
|
||||
HandleSignal:
|
||||
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (!restartable || (handler_was_called & SIG_HANDLED_NO_RESTART)) {
|
||||
return eintr();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
|
||||
textwindows int sys_pause_nt(void) {
|
||||
int rc;
|
||||
while (!(rc = _park_norestart(-1u, 0))) donothing;
|
||||
while (!(rc = _park_norestart(-1u, 0)))
|
||||
donothing;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 955 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user