Apply clang-format update to repo (#1154)

Commit bc6c183 introduced a bunch of discrepancies between what files
look like in the repo and what clang-format says they should look like.
However, there were already a few discrepancies prior to that. Most of
these discrepancies seemed to be unintentional, but a few of them were
load-bearing (e.g., a #include that violated header ordering needing
something to have been #defined by a 'later' #include.)

I opted to take what I hope is a relatively smooth-brained approach: I
reverted the .clang-format change, ran clang-format on the whole repo,
reapplied the .clang-format change, reran clang-format again, and then
reverted the commit that contained the first run. Thus the full effect
of this PR should only be to apply the changed formatting rules to the
repo, and from skimming the results, this seems to be the case.

My work can be checked by applying the short, manual commits, and then
rerunning the command listed in the autogenerated commits (those whose
messages I have prefixed auto:) and seeing if your results agree.

It might be that the other diffs should be fixed at some point but I'm
leaving that aside for now.

fd '\.c(c|pp)?$' --print0| xargs -0 clang-format -i
This commit is contained in:
Jōshin 2024-04-25 10:38:00 -07:00 committed by GitHub
parent 342d0c81e5
commit 6e6fc38935
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
863 changed files with 9201 additions and 4627 deletions

View file

@ -221,13 +221,15 @@ struct ApeLoader {
static unsigned long StrLen(const char *s) { static unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static int StrCmp(const char *l, const char *r) { static int StrCmp(const char *l, const char *r) {
unsigned long i = 0; 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); return (l[i] & 255) - (r[i] & 255);
} }
@ -276,7 +278,8 @@ static char *Utoa(char p[21], unsigned long x) {
} }
static char *Itoa(char p[21], 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); return Utoa(p, x);
} }
@ -312,7 +315,8 @@ static int GetIndirectOffset(const char *arg0) {
static void Perror(const char *thing, long rc, const char *reason) { static void Perror(const char *thing, long rc, const char *reason) {
char ibuf[21]; char ibuf[21];
ibuf[0] = 0; ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc); if (rc)
Itoa(ibuf, -rc);
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "", Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
ibuf, "\n", 0l); ibuf, "\n", 0l);
} }
@ -327,7 +331,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) { if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
return 0; 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); memmove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0; ps->path[pathlen + ps->namelen] = 0;
return !access(ps->path, X_OK); return !access(ps->path, X_OK);
@ -377,8 +382,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) { const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin"; ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
ps->name = name; ps->name = name;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0; if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
if (ps->namelen + 1 > sizeof(ps->path)) return 0; return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
if (FindCommand(ps)) { if (FindCommand(ps)) {
return ps->path; return ps->path;
} else { } else {
@ -585,7 +592,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr & -pagesz; a = p[i].p_vaddr & -pagesz;
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz; b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
for (j = i + 1; j < e->e_phnum; ++j) { 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; c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -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)) {
@ -614,7 +622,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
if (e->e_type == ET_DYN) { if (e->e_type == ET_DYN) {
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0); -1, 0);
if (rc < 0) Pexit(exe, rc, "pie mmap"); if (rc < 0)
Pexit(exe, rc, "pie mmap");
dynbase = rc; dynbase = rc;
if (dynbase & (pagesz - 1)) { if (dynbase & (pagesz - 1)) {
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ"); Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@ -630,14 +639,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) { for (i = 0; i < e->e_phnum; ++i) {
void *addr; void *addr;
unsigned long size; unsigned long size;
if (p[i].p_type != PT_LOAD) continue; if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */ /* configure mapping */
prot = 0; prot = 0;
flags = MAP_FIXED | MAP_PRIVATE; flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ; if (p[i].p_flags & PF_R)
if (p[i].p_flags & PF_W) prot |= PROT_WRITE; prot |= PROT_READ;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC; if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
/* load from file */ /* load from file */
if (p[i].p_filesz) { if (p[i].p_filesz) {
@ -687,24 +700,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
as the default strategy which is slow but it works for both */ as the default strategy which is slow but it works for both */
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE), rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); 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); 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 #endif
} else { } else {
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz); 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) { if (prot2 != prot1) {
rc = sys_mprotect(addr, size, prot2); 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 */ /* allocate extra bss */
if (c > b) { if (c > b) {
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0); 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 { } else {
/* allocate pure bss */ /* allocate pure bss */
@ -712,7 +731,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = sys_mmap(addr, size, prot, flags, -1, 0); 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 +810,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */ /* read program headers */
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff); rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
if (rc < 0) return "failed to read ELF program headers"; if (rc < 0)
if (rc != size) return "truncated read of ELF program headers"; return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */ /* bail on recoverable program header errors */
p = &M->phdr.phdr; p = &M->phdr.phdr;
@ -970,7 +992,8 @@ int main(int argc, char **argv, char **envp) {
grows down the alloc by poking the guard pages */ grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long); n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n); sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2; if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) { for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0; ((char *)sp2)[n - 1] = 0;
} }

View file

@ -228,13 +228,15 @@ extern char _end[];
static unsigned long StrLen(const char *s) { static unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static int StrCmp(const char *l, const char *r) { static int StrCmp(const char *l, const char *r) {
unsigned long i = 0; 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); 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) { 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); return Utoa(p, x);
} }
@ -362,7 +365,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
long arg5, long arg6, long arg5, long arg6,
long arg7, int numba, long arg7, int numba,
char os) { char os) {
if (IsXnu()) numba |= 0x2000000; if (IsXnu())
numba |= 0x2000000;
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba); 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++)) { switch ((c = *fmt++)) {
case 's': case 's':
for (s = __builtin_va_arg(va, const char *); s && *s; ++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; break;
case 'd': case 'd':
@ -542,16 +547,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
u -= 10; u -= 10;
c = 'a' + u; c = 'a' + u;
} }
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
} }
break; break;
default: default:
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
break; break;
} }
break; break;
default: default:
if (k < 512) b[k++] = c; if (k < 512)
b[k++] = c;
break; 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) { static void Perror(int os, const char *thing, long rc, const char *reason) {
char ibuf[21]; char ibuf[21];
ibuf[0] = 0; ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc); if (rc)
Itoa(ibuf, -rc);
Print(os, 2, "ape error: ", thing, ": ", reason, Print(os, 2, "ape error: ", thing, ": ", reason,
rc ? " failed w/ errno " : "", ibuf, "\n", 0l); 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) { static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0; if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; return 0;
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
MemMove(ps->path + pathlen, ps->name, ps->namelen); MemMove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0; ps->path[pathlen + ps->namelen] = 0;
return !Access(ps->path, X_OK, ps->os); 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, static char *Commandv(struct PathSearcher *ps, int os, char *name,
const char *syspath) { const char *syspath) {
if (!(ps->namelen = StrLen((ps->name = name)))) return 0; if (!(ps->namelen = StrLen((ps->name = name))))
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name; return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
return name;
ps->os = os; ps->os = os;
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin"; 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; ps->path[0] = 0;
if (SearchPath(ps)) { if (SearchPath(ps)) {
return ps->path; 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"); Pexit(os, exe, 0, "ELF segments overlap your APE loader");
} }
for (j = i + 1; j < e->e_phnum; ++j) { 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; c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -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)) {
@ -694,7 +709,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
if (e->e_type == ET_DYN) { if (e->e_type == ET_DYN) {
rc = Mmap(0, virtmax - virtmin, PROT_NONE, rc = Mmap(0, virtmax - virtmin, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os); 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; dynbase = rc;
if (dynbase & (pagesz - 1)) { if (dynbase & (pagesz - 1)) {
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ"); 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) { for (i = 0; i < e->e_phnum; ++i) {
void *addr; void *addr;
unsigned long size; unsigned long size;
if (p[i].p_type != PT_LOAD) continue; if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */ /* configure mapping */
prot = 0; prot = 0;
flags = MAP_FIXED | MAP_PRIVATE; flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ; if (p[i].p_flags & PF_R)
if (p[i].p_flags & PF_W) prot |= PROT_WRITE; prot |= PROT_READ;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC; 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) { if (p[i].p_filesz) {
/* load from file */ /* 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)); addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os); rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
if (rc < 0) Pexit(os, exe, rc, "prog mmap"); if (rc < 0)
if (wipe) Bzero((void *)(dynbase + a), wipe); Pexit(os, exe, rc, "prog mmap");
if (wipe)
Bzero((void *)(dynbase + a), wipe);
if (prot2 != prot1) { if (prot2 != prot1) {
rc = Mprotect(addr, size, prot2, os); 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 */ /* allocate extra bss */
if (c > b) { if (c > b) {
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os); 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 { } else {
/* allocate pure bss */ /* 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; size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
rc = Mmap(addr, size, prot, flags, -1, 0, os); 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; struct ElfPhdr *p;
/* validate page size */ /* validate page size */
if (!pagesz) pagesz = 4096; if (!pagesz)
pagesz = 4096;
if (pagesz & (pagesz - 1)) { if (pagesz & (pagesz - 1)) {
Pexit(os, exe, 0, "AT_PAGESZ isn't two power"); 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 */ /* read program headers */
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os); rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
if (rc < 0) return "failed to read ELF program headers"; if (rc < 0)
if (rc != size) return "truncated read of ELF program headers"; return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */ /* bail on recoverable program header errors */
p = &M->phdr.phdr; p = &M->phdr.phdr;
@ -949,7 +977,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
/* determine ape loader program name */ /* determine ape loader program name */
ape = argv[0]; ape = argv[0];
if (!ape) ape = "ape"; if (!ape)
ape = "ape";
/* detect openbsd */ /* detect openbsd */
if (SupportsOpenbsd() && !os && !auxv[0]) { 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 */ grows down the alloc by poking the guard pages */
n = (endp - sp + 1) * sizeof(long); n = (endp - sp + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n); sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2; if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) { for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0; ((char *)sp2)[n - 1] = 0;
} }

View file

@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
} }
static char *FormatInt32(char *p, int32_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); 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; size_t m, n = dsize;
const char *p = dst; const char *p = dst;
const char *q = src; const char *q = src;
while (n-- != 0 && *dst != '\0') dst++; while (n-- != 0 && *dst != '\0')
dst++;
m = dst - p; m = dst - p;
n = dsize - m; n = dsize - m;
if (n-- == 0) { if (n-- == 0) {
@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
for (i = 0;; ++i) { for (i = 0;; ++i) {
switch (path[i]) { switch (path[i]) {
case 0: case 0:
if (i) return true; if (i)
return true;
// fallthrough // fallthrough
case '\r': case '\r':
case '\n': case '\n':
@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
char hexdigest[65]; char hexdigest[65];
char mode[2] = {g_mode}; char mode[2] = {g_mode};
unsigned char digest[32]; unsigned char digest[32];
if (!IsSupportedPath(path)) return false; if (!IsSupportedPath(path))
if (!GetDigest(path, f, digest)) return false; return false;
if (!GetDigest(path, f, digest))
return false;
CopyHex(hexdigest, digest, 32); CopyHex(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL); Write(1, hexdigest, " ", mode, path, "\n", NULL);
return true; return true;
@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
uint8_t wantdigest[32], gotdigest[32]; uint8_t wantdigest[32], gotdigest[32];
char buf[64 + 2 + PATH_MAX + 1 + 1], *p; char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
for (line = 0; fgets(buf, sizeof(buf), f); ++line) { 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) { for (p = buf, i = 0; i < 32; ++i) {
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine; if ((a = HexToInt(*p++ & 255)) == -1)
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine; goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
wantdigest[i] = a << 4 | b; wantdigest[i] = a << 4 | b;
} }
if (*p++ != ' ') goto InvalidLine; if (*p++ != ' ')
if (!IsModeCharacter(*p++)) goto InvalidLine; goto InvalidLine;
if (!IsModeCharacter(*p++))
goto InvalidLine;
path2 = p; path2 = p;
if (!*path2) goto InvalidLine; if (!*path2)
if (!IsSupportedPath(path2)) continue; goto InvalidLine;
if (!IsSupportedPath(path2))
continue;
if ((f2 = fopen(path2, "rb"))) { if ((f2 = fopen(path2, "rb"))) {
if (GetDigest(path2, f2, gotdigest)) { if (GetDigest(path2, f2, gotdigest)) {
if (!memcmp(wantdigest, gotdigest, 32)) { if (!memcmp(wantdigest, gotdigest, 32)) {

View file

@ -27,7 +27,8 @@
*/ */
int alaw(int x) { int alaw(int x) {
int a, b, i; int a, b, i;
if ((a = x) < 0) a = ~a; if ((a = x) < 0)
a = ~a;
a >>= 4; a >>= 4;
if (a > 15) { if (a > 15) {
if ((i = a >> 5)) { if ((i = a >> 5)) {
@ -40,6 +41,7 @@ int alaw(int x) {
a += 16; a += 16;
} }
} }
if (x >= 0) a |= 128; if (x >= 0)
a |= 128;
return a ^ 85; return a ^ 85;
} }

View file

@ -28,13 +28,15 @@
int mulaw(int x) { int mulaw(int x) {
int b, i, a, s, l, h; int b, i, a, s, l, h;
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33; a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
if (a > 8191) a = 8191; if (a > 8191)
a = 8191;
i = a >> 6; i = a >> 6;
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1; s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
h = 8 - s; h = 8 - s;
l = (a >> s) & 15; l = (a >> s) & 15;
l = 15 - l; l = 15 - l;
b = (h << 4) | l; b = (h << 4) | l;
if (x >= 0) b |= 128; if (x >= 0)
b |= 128;
return b; return b;
} }

View file

@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
/* TODO(jart): This isn't acceptable. */ /* TODO(jart): This isn't acceptable. */
size_t i, j; size_t i, j;
if (p > 0) { if (p > 0) {
if (p > 15) p = 15; if (p > 15)
p = 15;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) { for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] =
@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
} }
} else if (p < 0) { } else if (p < 0) {
p = -p; p = -p;
if (p > 15) p = 15; if (p > 15)
p = 15;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) { for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] >> p; pcm[i][j] = pcm[i][j] >> p;

View file

@ -31,8 +31,10 @@ int unalaw(int x) {
i = (x ^ 85) & 127; i = (x ^ 85) & 127;
e = i >> 4; e = i >> 4;
m = i & 15; m = i & 15;
if (e > 0) m += 16; if (e > 0)
m += 16;
m = (m << 4) + 8; m = (m << 4) + 8;
if (e > 1) m = m << (e - 1); if (e > 1)
m = m << (e - 1);
return x & 128 ? m : -m; return x & 128 ? m : -m;
} }

View file

@ -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; si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
di = (self->mb_row * dw + self->mb_col) * BW; di = (self->mb_row * dw + self->mb_col) * BW;
max_address = (dw * (self->mb_height * BW - BW + 1) - 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; d += di;
s += si; s += si;
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) { switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {

View file

@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
static bool IsNormalized(int n, double A[n]) { static bool IsNormalized(int n, double A[n]) {
int i; int i;
double x; 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; return fabs(x - 1) < 1e-4;
} }
@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
short *weights, *indices; short *weights, *indices;
struct SamplingSolution *res; struct SamplingSolution *res;
long j, i, k, n, min, max, s, N[6]; long j, i, k, n, min, max, s, N[6];
if (!dar) dar = sn, dar /= dn; if (!dar)
if (!off) off = (dar - 1) / 2; dar = sn, dar /= dn;
if (!off)
off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar; f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4; s = 3 * f + 4;
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double))); 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) { for (k = 0, j = min; j <= max; ++j) {
fweights[k++] = ComputeWeight((j - x) / (f / par)); fweights[k++] = ComputeWeight((j - x) / (f / par));
} }
for (sum = k = 0; k < n; ++k) sum += fweights[k]; for (sum = k = 0; k < n; ++k)
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum; sum += fweights[k];
for (j = 0; j < n; ++j)
fweights[j] *= 1 / sum;
DCHECK(IsNormalized(n, fweights)); DCHECK(IsNormalized(n, fweights));
for (j = 0; j < n; ++j) { for (j = 0; j < n; ++j) {
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j)); indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));

View file

@ -30,8 +30,10 @@
static int ttysetcursor(int fd, bool visible) { static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor; struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l"; char code[8] = "\e[?25l";
if (__nocolor) return 0; if (__nocolor)
if (visible) code[5] = 'h'; return 0;
if (visible)
code[5] = 'h';
if (IsWindows()) { if (IsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
ntcursor.bVisible = visible; ntcursor.bVisible = visible;

View file

@ -21,16 +21,20 @@
#include "libc/limits.h" #include "libc/limits.h"
static char *ansitoa(char *p, unsigned xt, unsigned base) { 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); return itoa8(p, xt + base);
} }
static char *setansibgfg(char *p, unsigned bg, unsigned fg) { static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
*p++ = '\e'; *p++ = '\e';
*p++ = '['; *p++ = '[';
if (bg != -1u) p = ansitoa(p, bg, 40); if (bg != -1u)
if (bg != -1u && fg != -1u) *p++ = ';'; p = ansitoa(p, bg, 40);
if (fg != -1u) p = ansitoa(p, fg, 30); if (bg != -1u && fg != -1u)
*p++ = ';';
if (fg != -1u)
p = ansitoa(p, fg, 30);
*p++ = 'm'; *p++ = 'm';
return p; return p;
} }

View file

@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Glyph *glyph) { struct Glyph *glyph) {
unsigned i; unsigned i;
CHECK_LT(pick.bg, 4); 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; i = 0;
if (pick.fg == 0xff) { if (pick.fg == 0xff) {
if (!ttyeq(*bg, chunk[pick.bg])) { if (!ttyeq(*bg, chunk[pick.bg])) {
@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
v = CopyGlyph(v, *glyph); v = CopyGlyph(v, *glyph);
*x += 2; *x += 2;
*c += 2; *c += 2;
if (*x >= n) break; if (*x >= n)
break;
CopyChunk(chunk, *c, n); CopyChunk(chunk, *c, n);
} while (ChunkEq(chunk, lastchunk)); } while (ChunkEq(chunk, lastchunk));
*x -= 2; *x -= 2;

View file

@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
} }
static textstartup void ttyraw_hidecursor(void) { static textstartup void ttyraw_hidecursor(void) {
if (!g_ttyraw.setup) return; if (!g_ttyraw.setup)
if (g_ttyraw.flags & kTtyCursor) return; return;
if (g_ttyraw.flags & kTtyCursor)
return;
ttyhidecursor(FD); ttyhidecursor(FD);
} }
static textexit int ttyraw_disable(void) { static textexit int ttyraw_disable(void) {
if (!g_ttyraw.setup) return 0; if (!g_ttyraw.setup)
return 0;
ttyshowcursor(FD); ttyshowcursor(FD);
return ttyrestore(FD, &g_ttyraw.old); 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, static relegated void ttyraw_onsig(int sig, struct siginfo *info,
struct ucontext *ctx) { struct ucontext *ctx) {
size_t i; size_t i;
if (g_ttyraw.noreentry) _Exit(128 + sig); if (g_ttyraw.noreentry)
_Exit(128 + sig);
g_ttyraw.noreentry = true; g_ttyraw.noreentry = true;
if (g_ttyraw.flags != -1) { if (g_ttyraw.flags != -1) {
if (sig == SIGCONT) { if (sig == SIGCONT) {

View file

@ -104,8 +104,10 @@ void *Worker(void *id) {
if (client == -1) { if (client == -1) {
// accept() errors are generally ephemeral or recoverable // accept() errors are generally ephemeral or recoverable
// it'd potentially be a good idea to exponential backoff here // it'd potentially be a good idea to exponential backoff here
if (errno == ECANCELED) continue; // pthread_cancel() was called if (errno == ECANCELED)
if (errno == EMFILE) ExplainPrlimit(); continue; // pthread_cancel() was called
if (errno == EMFILE)
ExplainPrlimit();
LOG("accept() returned %m"); LOG("accept() returned %m");
SomethingHappened(); SomethingHappened();
continue; continue;
@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) { if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
--a_workers; --a_workers;
kprintf("pthread_create failed: %s\n", strerror(rc)); kprintf("pthread_create failed: %s\n", strerror(rc));
if (rc == EAGAIN) ExplainPrlimit(); if (rc == EAGAIN)
if (!i) exit(1); ExplainPrlimit();
if (!i)
exit(1);
threads = i; threads = i;
break; break;
} }
@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
PrintEphemeralStatusLine(); PrintEphemeralStatusLine();
unassert(!pthread_cond_wait(&statuscond, &statuslock)); unassert(!pthread_cond_wait(&statuscond, &statuslock));
// limit status line updates to sixty frames per second // 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); while (timespec_cmp(tick, timespec_real()) < 0);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 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 // 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 // print status in terminal as the shutdown progresses
unassert(!pthread_mutex_lock(&statuslock)); unassert(!pthread_mutex_lock(&statuslock));
@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
} }
// close the server socket // close the server socket
if (!IsWindows()) close(server); if (!IsWindows())
close(server);
// clean up terminal line // clean up terminal line
LOG("thank you for choosing \e[32mgreenbean\e[0m"); LOG("thank you for choosing \e[32mgreenbean\e[0m");

View file

@ -212,10 +212,13 @@ void editorAtExit(void) {
int enableRawMode(int64_t fd) { int enableRawMode(int64_t fd) {
struct termios raw; struct termios raw;
if (E.rawmode) return 0; /* Already enabled. */ if (E.rawmode)
if (!isatty(STDIN_FILENO)) goto fatal; return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO))
goto fatal;
atexit(editorAtExit); 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 */ raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char, /* 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). */ raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */ /* 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; E.rawmode = 1;
return 0; return 0;
@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
char c, seq[3]; char c, seq[3];
do { do {
nread = read(fd, &c, 1); nread = read(fd, &c, 1);
if (nread == -1) exit(1); if (nread == -1)
exit(1);
} while (!nread); } while (!nread);
while (1) { while (1) {
@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
return PAGE_DOWN; return PAGE_DOWN;
case '\e': /* escape sequence */ case '\e': /* escape sequence */
/* If this is just an ESC, we'll timeout here. */ /* 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 (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') { if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */ /* 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] == '~') { if (seq[2] == '~') {
switch (seq[1]) { switch (seq[1]) {
case '1': case '1':
@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
} else if (seq[0] == 'v') { } else if (seq[0] == 'v') {
return PAGE_UP; return PAGE_UP;
} else if (seq[0] == 'O') { } 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. */ /* ESC O sequences. */
switch (seq[1]) { switch (seq[1]) {
case 'H': case 'H':
@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
unsigned i = 0; unsigned i = 0;
/* Report cursor location */ /* 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 */ /* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf) - 1) { while (i < sizeof(buf) - 1) {
if (read(ifd, buf + i, 1) != 1) break; if (read(ifd, buf + i, 1) != 1)
if (buf[i] == 'R') break; break;
if (buf[i] == 'R')
break;
i++; i++;
} }
buf[i] = '\0'; buf[i] = '\0';
/* Parse it. */ /* Parse it. */
if (buf[0] != CTRL('[') || buf[1] != '[') return -1; if (buf[0] != CTRL('[') || buf[1] != '[')
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1; return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
return -1;
return 0; 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. */ /* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col); 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. */ /* 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); retval = getCursorPosition(ifd, ofd, rows, cols);
if (retval == -1) goto failed; if (retval == -1)
goto failed;
/* Restore position. */ /* Restore position. */
char seq[32]; char seq[32];
@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
row->hl = realloc(row->hl, row->rsize); row->hl = realloc(row->hl, row->rsize);
memset(row->hl, HL_NORMAL, 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; int i, prev_sep, in_string, in_comment;
char *p; char *p;
@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
prev_sep = 0; prev_sep = 0;
continue; continue;
} }
if (*p == in_string) in_string = 0; if (*p == in_string)
in_string = 0;
p++; p++;
i++; i++;
continue; continue;
@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
for (j = 0; keywords[j]; j++) { for (j = 0; keywords[j]; j++) {
int klen = strlen(keywords[j]); int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen - 1] == '|'; int kw2 = keywords[j][klen - 1] == '|';
if (kw2) klen--; if (kw2)
klen--;
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) { if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
/* Keyword */ /* Keyword */
@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
* respecting tabs, substituting non printable characters with '?'. */ * respecting tabs, substituting non printable characters with '?'. */
free(row->render); free(row->render);
for (j = 0; j < row->size; j++) { 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); 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 /* Insert a row at the specified position, shifting the other rows on the bottom
* if required. */ * if required. */
void editorInsertRow(int at, char *s, size_t len) { 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)); E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
if (at != E.numrows) { if (at != E.numrows) {
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at)); 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].size = len;
E.row[at].chars = malloc(len + 1); E.row[at].chars = malloc(len + 1);
@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
void editorDelRow(int at) { void editorDelRow(int at) {
erow *row; erow *row;
if (at >= E.numrows) return; if (at >= E.numrows)
return;
row = E.row + at; row = E.row + at;
editorFreeRow(row); editorFreeRow(row);
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1)); 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.numrows--;
E.dirty++; 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. */ /* Delete the character at offset 'at' from the specified row. */
void editorRowDelChar(erow *row, int at) { 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); memmove(row->chars + at, row->chars + at + 1, row->size - at);
editorUpdateRow(row); editorUpdateRow(row);
row->size--; row->size--;
@ -745,7 +771,8 @@ void editorInsertChar(int c) {
/* If the row where the cursor is currently located does not exist in our /* 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. */ * logical representation of the file, add enough empty rows as needed. */
if (!row) { if (!row) {
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0); while (E.numrows <= filerow)
editorInsertRow(E.numrows, "", 0);
} }
row = &E.row[filerow]; row = &E.row[filerow];
editorRowInsertChar(row, filecol, c); editorRowInsertChar(row, filecol, c);
@ -773,7 +800,8 @@ void editorInsertNewline(void) {
} }
/* If the cursor is over the current line size, we want to conceptually /* If the cursor is over the current line size, we want to conceptually
* think it's just over the last character. */ * 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) { if (filecol == 0) {
editorInsertRow(filerow, "", 0); editorInsertRow(filerow, "", 0);
} else { } else {
@ -800,7 +828,8 @@ void editorDelChar(void) {
int filecol = E.coloff + E.cx; int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; 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) { if (filecol == 0) {
/* Handle the case of column 0, we need to move the current line /* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */ * on the right of the previous one. */
@ -825,7 +854,8 @@ void editorDelChar(void) {
else else
E.cx--; E.cx--;
} }
if (row) editorUpdateRow(row); if (row)
editorUpdateRow(row);
E.dirty++; E.dirty++;
} }
@ -868,12 +898,15 @@ int editorSave(void) {
int len; int len;
char *buf = editorRowsToString(&len); char *buf = editorRowsToString(&len);
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644); 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 /* 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. */ * a bit safer, under the limits of what we can do in a small editor. */
if (ftruncate(fd, len) == -1) goto writeerr; if (ftruncate(fd, len) == -1)
if (write(fd, buf, len) != len) goto writeerr; goto writeerr;
if (write(fd, buf, len) != len)
goto writeerr;
close(fd); close(fd);
free(buf); free(buf);
@ -883,7 +916,8 @@ int editorSave(void) {
writeerr: writeerr:
free(buf); free(buf);
if (fd != -1) close(fd); if (fd != -1)
close(fd);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno)); editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return 1; return 1;
} }
@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
abAppend(&ab, "~", 1); abAppend(&ab, "~", 1);
padding--; padding--;
} }
while (padding--) abAppend(&ab, " ", 1); while (padding--)
abAppend(&ab, " ", 1);
abAppend(&ab, welcome, welcomelen); abAppend(&ab, welcome, welcomelen);
} else { } else {
abAppend(&ab, "~\e[0K\r\n", 7); abAppend(&ab, "~\e[0K\r\n", 7);
@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
int current_color = -1; int current_color = -1;
#endif #endif
if (len > 0) { if (len > 0) {
if (len > E.screencols) len = E.screencols; if (len > E.screencols)
len = E.screencols;
char *c = r->render + E.coloff; char *c = r->render + E.coloff;
#if SYNTAX #if SYNTAX
unsigned char *hl = r->hl + E.coloff; unsigned char *hl = r->hl + E.coloff;
@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
E.numrows, E.dirty ? "(modified)" : ""); E.numrows, E.dirty ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1, int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
E.numrows); E.numrows);
if (len > E.screencols) len = E.screencols; if (len > E.screencols)
len = E.screencols;
abAppend(&ab, status, len); abAppend(&ab, status, len);
while (len < E.screencols) { while (len < E.screencols) {
if (E.screencols - len == rlen) { if (E.screencols - len == rlen) {
@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow]; erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (row) { if (row) {
for (j = E.coloff; j < (E.cx + E.coloff); j++) { 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++; cx++;
} }
} }
@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
int c = editorReadKey(fd); int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) { if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
if (qlen != 0) query[--qlen] = '\0'; if (qlen != 0)
query[--qlen] = '\0';
last_match = -1; last_match = -1;
} else if (c == CTRL('G')) { } else if (c == CTRL('G')) {
break; break;
@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
} }
/* Search occurrence. */ /* Search occurrence. */
if (last_match == -1) find_next = 1; if (last_match == -1)
find_next = 1;
if (find_next) { if (find_next) {
char *match = NULL; char *match = NULL;
int match_offset = 0; int match_offset = 0;
@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
break; break;
case ARROW_UP: case ARROW_UP:
if (E.cy == 0) { if (E.cy == 0) {
if (E.rowoff) E.rowoff--; if (E.rowoff)
E.rowoff--;
} else { } else {
E.cy -= 1; E.cy -= 1;
} }
@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
case CTRL('L'): case CTRL('L'):
times = E.screenrows / 2; 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; 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; break;
case PAGE_UP: case PAGE_UP:
@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
E.cy = E.screenrows - 1; E.cy = E.screenrows - 1;
} }
times = E.screenrows; 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; 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; break;
case HOME_KEY: case HOME_KEY:
case CTRL('A'): case CTRL('A'):
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT); while (E.cx || E.coloff)
editorMoveCursor(ARROW_LEFT);
break; break;
case END_KEY: case END_KEY:
case CTRL('E'): case CTRL('E'):

View file

@ -492,7 +492,8 @@ void TransmitVideo(void) {
ssize_t rc; ssize_t rc;
struct Frame* f; struct Frame* f;
f = &vf_[frame_]; 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) { if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
f->w += rc; f->w += rc;
} else if (errno == EAGAIN) { } else if (errno == EAGAIN) {
@ -504,9 +505,12 @@ void TransmitVideo(void) {
void TransmitAudio(void) { void TransmitAudio(void) {
ssize_t rc; ssize_t rc;
if (!playpid_) return; if (!playpid_)
if (!audio_.i) return; return;
if (playfd_ == -1) return; if (!audio_.i)
return;
if (playfd_ == -1)
return;
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) { if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
rc /= sizeof(short); rc /= sizeof(short);
memmove(audio_.p, audio_.p + rc, (audio_.i - 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) { void PollAndSynchronize(void) {
do { do {
if (ReadKeyboard() == -1) { if (ReadKeyboard() == -1) {
if (errno != EINTR) Exit(1); if (errno != EINTR)
if (exited_) Exit(0); Exit(1);
if (resized_) GetTermSize(); if (exited_)
Exit(0);
if (resized_)
GetTermSize();
} }
} while (!timeout_); } while (!timeout_);
TransmitVideo(); 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]; return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
} }
@ -828,7 +836,8 @@ bool offset_toggle = false;
u8& NesMmap(int i) { u8& NesMmap(int i) {
i &= 0x3FFF; i &= 0x3FFF;
if (i >= 0x3F00) { if (i >= 0x3F00) {
if (i % 4 == 0) i &= 0x0F; if (i % 4 == 0)
i &= 0x0F;
return palette[i & 0x1F]; return palette[i & 0x1F];
} }
if (i < 0x2000) { if (i < 0x2000) {
@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
return open_bus_decay_timer = 77777, open_bus = v; return open_bus_decay_timer = 77777, open_bus = v;
}; };
u8 res = open_bus; u8 res = open_bus;
if (write) RefreshOpenBus(v); if (write)
RefreshOpenBus(v);
switch (index) { // Which port from $200x? switch (index) { // Which port from $200x?
case 0: case 0:
if (write) { if (write) {
@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 2: case 2:
if (write) break; if (write)
break;
res = reg.status | (open_bus & 0x1F); res = reg.status | (open_bus & 0x1F);
reg.InVBlank = false; // Reading $2002 clears the vblank flag. reg.InVBlank = false; // Reading $2002 clears the vblank flag.
offset_toggle = false; // Also resets the toggle for address updates. offset_toggle = false; // Also resets the toggle for address updates.
@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 3: case 3:
if (write) reg.OAMaddr = v; if (write)
reg.OAMaddr = v;
break; // Index into Object Attribute Memory break; // Index into Object Attribute Memory
case 4: case 4:
if (write) { if (write) {
@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
} }
break; break;
case 5: case 5:
if (!write) break; // Set background scrolling offset if (!write)
break; // Set background scrolling offset
if (offset_toggle) { if (offset_toggle) {
scroll.yfine = v & 7; scroll.yfine = v & 7;
scroll.ycoarse = v >> 3; scroll.ycoarse = v >> 3;
@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
offset_toggle = !offset_toggle; offset_toggle = !offset_toggle;
break; break;
case 6: 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) { if (offset_toggle) {
scroll.vaddrlo = v; scroll.vaddrlo = v;
vaddr.raw = (unsigned)scroll.raw; vaddr.raw = (unsigned)scroll.raw;
@ -926,17 +940,21 @@ void RenderingTick() {
case 2: // Point to attribute table case 2: // Point to attribute table
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) + ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
(vaddr.xcoarse / 4); (vaddr.xcoarse / 4);
if (tile_decode_mode) break; // Or nametable, with sprites. if (tile_decode_mode)
case 0: // Point to nametable break; // Or nametable, with sprites.
case 0: // Point to nametable
ioaddr = 0x2000 + (vaddr.raw & 0xFFF); ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
// Reset sprite data // Reset sprite data
if (x_ == 0) { if (x_ == 0) {
sprinpos = sproutpos = 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) // 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) { if (x_ == 256) {
vaddr.xcoarse = (unsigned)scroll.xcoarse; vaddr.xcoarse = (unsigned)scroll.xcoarse;
vaddr.basenta_h = (unsigned)scroll.basenta_h; vaddr.basenta_h = (unsigned)scroll.basenta_h;
@ -949,7 +967,8 @@ void RenderingTick() {
} }
// Name table access // Name table access
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine; 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. // Push the current tile into shift registers.
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated // The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
// 8 times. // 8 times.
@ -976,7 +995,8 @@ void RenderingTick() {
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
memcpy(&o, &OAM2[sprrenpos], sizeof(o)); memcpy(&o, &OAM2[sprrenpos], sizeof(o));
unsigned y = (scanline)-o.y; 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 = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF)); pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
pat_addr += (y & 7) + (y & 8) * 2; pat_addr += (y & 7) + (y & 8) * 2;
@ -1011,8 +1031,10 @@ void RenderingTick() {
break; break;
} }
++sprinpos; // next sprite ++sprinpos; // next sprite
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp; if (sproutpos < 8)
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex; OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].sprindex = reg.OAMindex;
y1 = sprtmp; y1 = sprtmp;
y2 = sprtmp + (reg.SPsize ? 16 : 8); y2 = sprtmp + (reg.SPsize ? 16 : 8);
if (!(scanline >= y1 && scanline < y2)) { if (!(scanline >= y1 && scanline < y2)) {
@ -1020,19 +1042,23 @@ void RenderingTick() {
} }
break; break;
case 1: case 1:
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].index = sprtmp;
break; break;
case 2: case 2:
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].attr = sprtmp;
break; break;
case 3: case 3:
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp; if (sproutpos < 8)
OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8) { if (sproutpos < 8) {
++sproutpos; ++sproutpos;
} else { } else {
reg.SPoverflow = true; reg.SPoverflow = true;
} }
if (sprinpos == 2) reg.OAMaddr = 8; if (sprinpos == 2)
reg.OAMaddr = 8;
break; break;
} }
} }
@ -1060,13 +1086,17 @@ void RenderPixel() {
auto& s = OAM3[sno]; auto& s = OAM3[sno];
// Check if this sprite is horizontally in range // Check if this sprite is horizontally in range
unsigned xdiff = x_ - s.x_; 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 // 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; u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
if (!spritepixel) continue; if (!spritepixel)
continue;
// Register sprite-0 hit if applicable // 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 // Render the pixel unless behind-background placement wanted
if (!(s.attr & 0x20) || !pixel) { if (!(s.attr & 0x20) || !pixel) {
attr = (s.attr & 3) + 4; attr = (s.attr & 3) + 4;
@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
} }
if (ctrlmask & 0x80) { if (ctrlmask & 0x80) {
joy_next_[0] = fgetc(fp); joy_next_[0] = fgetc(fp);
if (feof(fp)) joy_next_[0] = 0; if (feof(fp))
joy_next_[0] = 0;
} }
if (ctrlmask & 0x40) { if (ctrlmask & 0x40) {
joy_next_[1] = fgetc(fp); 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; CPU::nmi = reg.InVBlank && reg.NMIenabled;
break; break;
} }
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1); if (VBlankState != 0)
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0; VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer)
open_bus = 0;
// Graphics processing scanline? // Graphics processing scanline?
if (scanline < DYN) { if (scanline < DYN) {
/* Process graphics for this cycle */ /* Process graphics for this cycle */
if (reg.ShowBGSP) RenderingTick(); if (reg.ShowBGSP)
if (scanline >= 0 && x_ < 256) RenderPixel(); RenderingTick();
if (scanline >= 0 && x_ < 256)
RenderPixel();
} }
// Done with the cycle. Check for end of scanline. // 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) { if (++x_ >= scanline_end) {
// Begin new scanline // Begin new scanline
FlushScanline(scanline); FlushScanline(scanline);
@ -1242,30 +1279,36 @@ struct channel {
template <unsigned c> template <unsigned c>
int Tick() { int Tick() {
channel& ch = *this; 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); 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 int volume = ch.length_counter
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope ? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
: 0; : 0;
// Sample may change at wavelen intervals. // Sample may change at wavelen intervals.
auto& S = ch.level; auto& S = ch.level;
if (!count(ch.wave_counter, wl)) return S; if (!count(ch.wave_counter, wl))
return S;
switch (c) { switch (c) {
default: // Square wave. With four different 8-step binary waveforms (32 default: // Square wave. With four different 8-step binary waveforms (32
// bits of data total). // bits of data total).
if (wl < 8) return S = 8; if (wl < 8)
return S = 8;
return S = (0xF33C0C04u & return S = (0xF33C0C04u &
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8))) (1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
? volume ? volume
: 0; : 0;
case 2: // Triangle wave 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); return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
case 3: // Noise: Linear feedback shift register case 3: // Noise: Linear feedback shift register
if (!ch.hold) ch.hold = 1; if (!ch.hold)
ch.hold = 1;
ch.hold = ch.hold =
(ch.hold >> 1) | (ch.hold >> 1) |
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14); (((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
@ -1302,7 +1345,8 @@ struct channel {
} else { } else {
v -= 2; 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; return S = ch.linear_counter;
} }
@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
ch.linear_counter = ch.reg.LinearCounterInit; ch.linear_counter = ch.reg.LinearCounterInit;
ch.env_delay = ch.reg.EnvDecayRate; ch.env_delay = ch.reg.EnvDecayRate;
ch.envelope = 15; ch.envelope = 15;
if (index < 8) ch.phase = 0; if (index < 8)
ch.phase = 0;
break; break;
case 0x10: case 0x10:
ch.reg.reg3 = value; ch.reg.reg3 = value;
@ -1384,9 +1429,11 @@ u8 Read() {
for (c = 0; c < 5; ++c) { for (c = 0; c < 5; ++c) {
res |= channels[c].length_counter ? 1 << c : 0; res |= channels[c].length_counter ? 1 << c : 0;
} }
if (PeriodicIRQ) res |= 0x40; if (PeriodicIRQ)
res |= 0x40;
PeriodicIRQ = false; PeriodicIRQ = false;
if (DMC_IRQ) res |= 0x80; if (DMC_IRQ)
res |= 0x80;
DMC_IRQ = false; DMC_IRQ = false;
CPU::intr = false; CPU::intr = false;
return res; 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. // Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
if ((hz240counter.lo += 2) >= 14915) { if ((hz240counter.lo += 2) >= 14915) {
hz240counter.lo -= 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). // 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) { 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) { if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s}; int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
wl += d[ch.reg.SweepDecrease * 2 + c]; 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) // Linear tick (triangle wave only)
@ -1464,20 +1513,24 @@ namespace CPU {
void Tick() { void Tick() {
// PPU clock: 3 times the CPU rate // 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 // 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> template <bool write>
u8 MemAccess(u16 addr, u8 v) { u8 MemAccess(u16 addr, u8 v) {
// Memory writes are turned into reads while reset is being signalled // 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(); Tick();
// Map the memory from CPU's viewpoint. // Map the memory from CPU's viewpoint.
/**/ if (addr < 0x2000) { /**/ if (addr < 0x2000) {
u8& r = RAM[addr & 0x7FF]; u8& r = RAM[addr & 0x7FF];
if (!write) return r; if (!write)
return r;
r = v; r = v;
} else if (addr < 0x4000) { } else if (addr < 0x4000) {
return PPU::PpuAccess(addr & 7, v, write); return PPU::PpuAccess(addr & 7, v, write);
@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
WB(0x2004, RB((v & 7) * 0x0100 + b)); WB(0x2004, RB((v & 7) * 0x0100 + b));
return 0; return 0;
case 0x15: case 0x15:
if (!write) return APU::Read(); if (!write)
return APU::Read();
APU::Write(0x15, v); APU::Write(0x15, v);
break; break;
case 0x16: case 0x16:
if (!write) return JoyRead(0); if (!write)
return JoyRead(0);
JoyStrobe(v); JoyStrobe(v);
break; break;
case 0x17: case 0x17:
if (!write) return JoyRead(1); // write:passthru if (!write)
return JoyRead(1); // write:passthru
default: default:
if (!write) break; if (!write)
break;
APU::Write(addr & 0x1F, v); APU::Write(addr & 0x1F, v);
} }
} else { } else {
@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
} }
void Misfire(u16 old, u16 addr) { void Misfire(u16 old, u16 addr) {
u16 q = wrap(old, addr); u16 q = wrap(old, addr);
if (q != addr) RB(q); if (q != addr)
RB(q);
} }
u8 Pop() { u8 Pop() {
return RB(0x100 | u8(++S)); return RB(0x100 | u8(++S));
@ -1655,7 +1713,8 @@ void Op() {
} else if (intr && !P.I) { } else if (intr && !P.I) {
op = 0x102; 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 // Define function pointers for each opcode (00..FF) and each interrupt
// (100,101,102) // (100,101,102)
@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
fgetc(fp); fgetc(fp);
fgetc(fp); fgetc(fp);
if (mappernum >= 0x40) mappernum &= 15; if (mappernum >= 0x40)
mappernum &= 15;
GamePak::mappernum = mappernum; GamePak::mappernum = mappernum;
// Read the ROM data // Read the ROM data
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000); if (rom16count)
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000); GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count)
GamePak::VRAM.resize(vrom8count * 0x2000);
fread(&GamePak::ROM[0], rom16count, 0x4000, fp); fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp); fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
PPU::reg.value = 0; PPU::reg.value = 0;
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync. // 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. // Run the CPU until the program is killed.
for (;;) CPU::Op(); for (;;)
CPU::Op();
} }
wontreturn void PrintUsage(int rc, FILE* f) { wontreturn void PrintUsage(int rc, FILE* f) {

View file

@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
} else if (*p->p == '[' && blevel == 0) { } else if (*p->p == '[' && blevel == 0) {
level++; level++;
} else if (*p->p == ']' && blevel == 0) { } else if (*p->p == ']' && blevel == 0) {
if (!--level) break; if (!--level)
break;
} else if (*p->p == '\\') { } else if (*p->p == '\\') {
p->p++; p->p++;
p->len--; p->len--;
} else if (*p->p == '{') { } else if (*p->p == '{') {
blevel++; blevel++;
} else if (*p->p == '}') { } else if (*p->p == '}') {
if (blevel != 0) blevel--; if (blevel != 0)
blevel--;
} }
p->p++; p->p++;
p->len--; p->len--;
@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
case ' ': case ' ':
case '\t': case '\t':
case '\r': case '\r':
if (p->insidequote) return picolParseString(p); if (p->insidequote)
return picolParseString(p);
return picolParseSep(p); return picolParseSep(p);
case '\n': case '\n':
case ';': case ';':
if (p->insidequote) return picolParseString(p); if (p->insidequote)
return picolParseString(p);
return picolParseEol(p); return picolParseEol(p);
case '[': case '[':
return picolParseCommand(p); return picolParseCommand(p);
@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
struct picolVar *picolGetVar(struct picolInterp *i, char *name) { struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
struct picolVar *v = i->callframe->vars; struct picolVar *v = i->callframe->vars;
while (v) { while (v) {
if (strcmp(v->name, name) == 0) return v; if (strcmp(v->name, name) == 0)
return v;
v = v->next; v = v->next;
} }
return NULL; 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 *picolGetCommand(struct picolInterp *i, char *name) {
struct picolCmd *c = i->commands; struct picolCmd *c = i->commands;
while (c) { while (c) {
if (strcmp(c->name, name) == 0) return c; if (strcmp(c->name, name) == 0)
return c;
c = c->next; c = c->next;
} }
return NULL; return NULL;
@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
int tlen; int tlen;
int prevtype = p.type; int prevtype = p.type;
picolGetToken(&p); picolGetToken(&p);
if (p.type == PT_EOF) break; if (p.type == PT_EOF)
break;
tlen = p.end - p.start + 1; tlen = p.end - p.start + 1;
if (tlen < 0) tlen = 0; if (tlen < 0)
tlen = 0;
t = malloc(tlen + 1); t = malloc(tlen + 1);
memcpy(t, p.start, tlen); memcpy(t, p.start, tlen);
t[tlen] = '\0'; t[tlen] = '\0';
@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
} else if (p.type == PT_CMD) { } else if (p.type == PT_CMD) {
retcode = picolEval(i, t); retcode = picolEval(i, t);
free(t); free(t);
if (retcode != PICOL_OK) goto err; if (retcode != PICOL_OK)
goto err;
t = strdup(i->result); t = strdup(i->result);
} else if (p.type == PT_ESC) { } else if (p.type == PT_ESC) {
/* XXX: escape handling missing! */ /* XXX: escape handling missing! */
@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
goto err; goto err;
} }
retcode = c->func(i, argc, argv, c->privdata); 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 */ /* 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); free(argv);
argv = NULL; argv = NULL;
argc = 0; argc = 0;
@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
prevtype = p.type; prevtype = p.type;
} }
err: err:
for (j = 0; j < argc; j++) free(argv[j]); for (j = 0; j < argc; j++)
free(argv[j]);
free(argv); free(argv);
return retcode; return retcode;
} }
@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
char buf[64]; char buf[64];
int a, b, c; int a, b, c;
if (argc != 3) return picolArityErr(i, argv[0]); if (argc != 3)
return picolArityErr(i, argv[0]);
a = atoi(argv[1]); a = atoi(argv[1]);
b = atoi(argv[2]); b = atoi(argv[2]);
if (argv[0][0] == '+') 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) { 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]); picolSetVar(i, argv[1], argv[2]);
picolSetResult(i, argv[2]); picolSetResult(i, argv[2]);
return PICOL_OK; return PICOL_OK;
} }
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) { 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]); printf("%s\n", argv[1]);
return PICOL_OK; return PICOL_OK;
} }
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
int retcode; int retcode;
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]); if (argc != 3 && argc != 5)
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode; return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
return retcode;
if (atoi(i->result)) if (atoi(i->result))
return picolEval(i, argv[2]); return picolEval(i, argv[2]);
else if (argc == 5) 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) { 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) { while (1) {
int retcode = picolEval(i, argv[1]); int retcode = picolEval(i, argv[1]);
if (retcode != PICOL_OK) return retcode; if (retcode != PICOL_OK)
return retcode;
if (atoi(i->result)) { if (atoi(i->result)) {
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE) if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
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, int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
void *pd) { void *pd) {
if (argc != 1) return picolArityErr(i, argv[0]); if (argc != 1)
return picolArityErr(i, argv[0]);
if (strcmp(argv[0], "break") == 0) if (strcmp(argv[0], "break") == 0)
return PICOL_BREAK; return PICOL_BREAK;
else if (strcmp(argv[0], "continue") == 0) else if (strcmp(argv[0], "continue") == 0)
@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
tofree = p; tofree = p;
while (1) { while (1) {
char *start = p; char *start = p;
while (*p != ' ' && *p != '\0') p++; while (*p != ' ' && *p != '\0')
p++;
if (*p != '\0' && p == start) { if (*p != '\0' && p == start) {
p++; p++;
continue; continue;
} }
if (p == start) break; if (p == start)
break;
if (*p == '\0') if (*p == '\0')
done = 1; done = 1;
else else
*p = '\0'; *p = '\0';
if (++arity > argc - 1) goto arityerr; if (++arity > argc - 1)
goto arityerr;
picolSetVar(i, start, argv[arity]); picolSetVar(i, start, argv[arity]);
p++; p++;
if (done) break; if (done)
break;
} }
free(tofree); free(tofree);
if (arity != argc - 1) goto arityerr; if (arity != argc - 1)
goto arityerr;
errcode = picolEval(i, body); 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 */ picolDropCallFrame(i); /* remove the called proc callframe */
return errcode; return errcode;
arityerr: arityerr:
@ -594,14 +620,16 @@ arityerr:
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) { int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
char **procdata = malloc(sizeof(char *) * 2); 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[0] = strdup(argv[2]); /* arguments list */
procdata[1] = strdup(argv[3]); /* procedure body */ procdata[1] = strdup(argv[3]); /* procedure body */
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata); return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
} }
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) { 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] : ""); picolSetResult(i, (argc == 2) ? argv[1] : "");
return PICOL_RETURN; return PICOL_RETURN;
} }
@ -631,9 +659,11 @@ int main(int argc, char **argv) {
int retcode; int retcode;
printf("picol> "); printf("picol> ");
fflush(stdout); fflush(stdout);
if (fgets(clibuf, 1024, stdin) == NULL) return 0; if (fgets(clibuf, 1024, stdin) == NULL)
return 0;
retcode = picolEval(&interp, clibuf); 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) { } else if (argc == 2) {
char buf[1024 * 16]; char buf[1024 * 16];
@ -644,7 +674,8 @@ int main(int argc, char **argv) {
} }
buf[fread(buf, 1, 1024 * 16, fp)] = '\0'; buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
fclose(fp); 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; return 0;
} }

View file

@ -23,7 +23,8 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *prog = argv[0]; const char *prog = argv[0];
if (!prog) prog = "rusage"; if (!prog)
prog = "rusage";
if (argc < 2) { if (argc < 2) {
tinyprint(2, prog, ": missing command\n", NULL); tinyprint(2, prog, ": missing command\n", NULL);

View file

@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
} while (x); } while (x);
for (;;) { for (;;) {
*p++ = m[--i]; *p++ = m[--i];
if (!i) break; if (!i)
if (!(i % 3)) *p++ = ','; break;
if (!(i % 3))
*p++ = ',';
} }
*p = '\0'; *p = '\0';
return p; return p;

View file

@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
int Compare(const void *a, const void *b) { int Compare(const void *a, const void *b) {
struct Thing *x = (struct Thing *)a; struct Thing *x = (struct Thing *)a;
struct Thing *y = (struct Thing *)b; struct Thing *y = (struct Thing *)b;
if (x->i < y->i) return +1; if (x->i < y->i)
if (x->i > y->i) return -1; return +1;
if (x->i > y->i)
return -1;
return 0; return 0;
} }
@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
Append((uintptr_t)__oldstack, "__oldstack"); Append((uintptr_t)__oldstack, "__oldstack");
for (int i = 0;; ++i) { for (int i = 0;; ++i) {
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[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])); Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
} }
for (int i = 0;; ++i) { for (int i = 0;; ++i) {
Append((uintptr_t)&environ[i], Append((uintptr_t)&environ[i],
xasprintf("&environ[%d] = %`'s", i, environ[i])); xasprintf("&environ[%d] = %`'s", i, environ[i]));
if (!environ[i]) break; if (!environ[i])
break;
Append((uintptr_t)environ[i], Append((uintptr_t)environ[i],
xasprintf("environ[%d] = %`'s", i, environ[i])); xasprintf("environ[%d] = %`'s", i, environ[i]));
} }
for (int i = 0;; i += 2) { for (int i = 0;; i += 2) {
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i])); 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], Append((uintptr_t)&__auxv[i + 1],
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1])); xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
} }

View file

@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
dprintf(outfd, "%`'.*s (got %d) ", n, code, n); dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
if (iscntrl(code[0]) && !code[1]) { if (iscntrl(code[0]) && !code[1]) {
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0])); 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")) { } else if (startswith(code, "\e[") && endswith(code, "R")) {
yn = 1, xn = 1; yn = 1, xn = 1;
sscanf(code, "\e[%d;%dR", &yn, &xn); sscanf(code, "\e[%d;%dR", &yn, &xn);

View file

@ -13,7 +13,8 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct utsname names; struct utsname names;
if (uname(&names)) return 1; if (uname(&names))
return 1;
printf("%-10s %`'s\n", "sysname", names.sysname); printf("%-10s %`'s\n", "sysname", names.sysname);
printf("%-10s %`'s\n", "release", names.release); printf("%-10s %`'s\n", "release", names.release);
printf("%-10s %`'s\n", "version", names.version); printf("%-10s %`'s\n", "version", names.version);

File diff suppressed because it is too large Load diff

View file

@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int flags = 0; int flags = 0;
const char *dir; const char *dir;
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH; if (argc > 2 && strchr(argv[2], 'd') != NULL)
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS; flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL)
flags |= FTW_PHYS;
dir = argc < 2 ? "." : argv[1]; dir = argc < 2 ? "." : argv[1];
if (nftw(dir, display_info, 20, flags) == -1) { if (nftw(dir, display_info, 20, flags) == -1) {
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir); fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);

View file

@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
appends(&msg, "\e[1m"); // bold text appends(&msg, "\e[1m"); // bold text
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name, appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
GetHost()); 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()); appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K"); appends(&msg, "\e[K");
@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
if (optind < argc) { if (optind < argc) {
// use cli arguments as message if they exist // use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) { for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " "); if (i)
appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) { for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') { if (*s == '\n') {
appends(&msg, "\r\n\e[K"); appends(&msg, "\r\n\e[K");
@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
char pts[32]; char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i); snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) { if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) continue; if (errno == ENOENT)
if (g_verbose) perror(pts); continue;
if (g_verbose)
perror(pts);
} }
write(fd, msg, appendz(msg).i); write(fd, msg, appendz(msg).i);
close(fd); close(fd);

View file

@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
t.sn[5] = 0; t.sn[5] = 0;
if (IsLinux()) { if (IsLinux()) {
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1; if (sys_ioctl(fd, TIOCGPTN, &pty))
return -1;
t.sn[5] = 'p'; t.sn[5] = 'p';
t.sn[6] = 't'; t.sn[6] = 't';
t.sn[7] = 's'; t.sn[7] = 's';

View file

@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int cfsetspeed(struct termios *t, uint32_t speed) { int cfsetspeed(struct termios *t, uint32_t speed) {
if (cfsetispeed(t, speed) == -1) return -1; if (cfsetispeed(t, speed) == -1)
if (cfsetospeed(t, speed) == -1) return -1; return -1;
if (cfsetospeed(t, speed) == -1)
return -1;
return 0; return 0;
} }

View file

@ -33,7 +33,8 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
char16_t var[4]; char16_t var[4];
if (len && path[len - 1] != u'\\') { 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 + 0] = u'\\';
path[len + 1] = u'\0'; 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) { textwindows int sys_chdir_nt(const char *path) {
int len; int len;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1) return -1; if ((len = __mkntpath(path, path16)) == -1)
if (!len) return enoent(); return -1;
if (!len)
return enoent();
return sys_chdir_nt_impl(path16, len); return sys_chdir_nt_impl(path16, len);
} }

View file

@ -24,11 +24,16 @@
textwindows int _check_signal(bool restartable) { textwindows int _check_signal(bool restartable) {
int status; int status;
if (_check_cancel() == -1) return -1; if (_check_cancel() == -1)
if (!_weaken(__sig_check)) return 0; return -1;
if (!(status = _weaken(__sig_check)())) return 0; if (!_weaken(__sig_check))
if (_check_cancel() == -1) return -1; return 0;
if (status == 2 && restartable) return 0; if (!(status = _weaken(__sig_check)()))
return 0;
if (_check_cancel() == -1)
return -1;
if (status == 2 && restartable)
return 0;
return eintr(); return eintr();
} }

View file

@ -61,7 +61,8 @@ static dontinline int __clk_tck_init(void) {
} else { } else {
x = __getauxval(AT_CLKTCK).value; x = __getauxval(AT_CLKTCK).value;
} }
if (x < 1) x = 100; if (x < 1)
x = 100;
clk_tck = x; clk_tck = x;
return x; return x;
} }

View file

@ -44,7 +44,8 @@ int sys_clock_gettime_mono(struct timespec *time) {
#ifdef __x86_64__ #ifdef __x86_64__
// intel architecture guarantees that a mapping exists between rdtsc & // intel architecture guarantees that a mapping exists between rdtsc &
// nanoseconds only if the cpu advertises invariant timestamps support // nanoseconds only if the cpu advertises invariant timestamps support
if (!X86_HAVE(INVTSC)) return -EINVAL; if (!X86_HAVE(INVTSC))
return -EINVAL;
#endif #endif
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init); cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick; cycles = rdtsc() - g_mono.base_tick;

View file

@ -60,14 +60,17 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
} }
return 0; return 0;
} else if (clock == CLOCK_MONOTONIC) { } else if (clock == CLOCK_MONOTONIC) {
if (!ts) return 0; if (!ts)
return 0;
return sys_clock_gettime_mono(ts); return sys_clock_gettime_mono(ts);
} else if (clock == CLOCK_BOOTTIME) { } else if (clock == CLOCK_BOOTTIME) {
struct timeval x; struct timeval x;
size_t n = sizeof(x); size_t n = sizeof(x);
int mib[] = {CTL_KERN, KERN_BOOTTIME}; int mib[] = {CTL_KERN, KERN_BOOTTIME};
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1; if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1)
if (ts) *ts = timeval_totimespec(timeval_sub(timeval_real(), x)); return -1;
if (ts)
*ts = timeval_totimespec(timeval_sub(timeval_real(), x));
return 0; return 0;
} else { } else {
return -EINVAL; return -EINVAL;

View file

@ -57,7 +57,8 @@ int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK); struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
clock_gettime(time_clock, &start); clock_gettime(time_clock, &start);
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req); 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); remain = timespec_sub(deadline, start);
if (timespec_cmp(remain, quantum) > 0) { if (timespec_cmp(remain, quantum) > 0) {
waitfor = timespec_sub(remain, quantum); waitfor = timespec_sub(remain, quantum);

View file

@ -32,10 +32,13 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
uint32_t msdelay; uint32_t msdelay;
struct timespec now; struct timespec now;
for (;;) { for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1; if (sys_clock_gettime_nt(clock, &now))
if (timespec_cmp(now, abs) >= 0) return 0; return -1;
if (timespec_cmp(now, abs) >= 0)
return 0;
msdelay = timespec_tomillis(timespec_sub(abs, now)); 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) { if (flags & TIMER_ABSTIME) {
abs = *req; abs = *req;
} else { } 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); abs = timespec_add(now, *req);
} }
rc = sys_clock_nanosleep_nt_impl(clock, abs, m); rc = sys_clock_nanosleep_nt_impl(clock, abs, m);

View file

@ -46,7 +46,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
} else { } else {
int rc; int rc;
struct timespec beg; 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 struct timeval rel = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &rel); rc = sys_select(0, 0, 0, 0, &rel);
if (rc == -1 && rem && errno == EINTR) { if (rc == -1 && rem && errno == EINTR) {

View file

@ -30,7 +30,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(int fd, int fildes) { 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; struct Fd *f = g_fds.p + fd;
switch (f->kind) { switch (f->kind) {
case kFdZip: case kFdZip:

View file

@ -97,12 +97,14 @@ int close(int fd) {
BLOCK_SIGNALS; BLOCK_SIGNALS;
__fds_lock(); __fds_lock();
rc = close_impl(fd); rc = close_impl(fd);
if (!__vforked) __releasefd(fd); if (!__vforked)
__releasefd(fd);
__fds_unlock(); __fds_unlock();
ALLOW_SIGNALS; ALLOW_SIGNALS;
} else { } else {
rc = close_impl(fd); rc = close_impl(fd);
if (!__vforked) __releasefd(fd); if (!__vforked)
__releasefd(fd);
} }
STRACE("close(%d) → %d% m", fd, rc); STRACE("close(%d) → %d% m", fd, rc);
return rc; return rc;

View file

@ -37,10 +37,13 @@ ssize_t copyfd(int in, int out, size_t n) {
ssize_t dr, dw; ssize_t dr, dw;
for (i = 0; i < n; i += dr) { for (i = 0; i < n; i += dr) {
dr = read(in, buf, MIN(n - i, sizeof(buf))); dr = read(in, buf, MIN(n - i, sizeof(buf)));
if (dr == -1) return -1; if (dr == -1)
if (!dr) break; return -1;
if (!dr)
break;
dw = write(out, buf, dr); dw = write(out, buf, dr);
if (dw == -1) return -1; if (dw == -1)
return -1;
if (dw != dr) { if (dw != dr) {
// POSIX requires atomic IO up to PIPE_BUF // POSIX requires atomic IO up to PIPE_BUF
// The minimum permissible PIPE_BUF is 512 // The minimum permissible PIPE_BUF is 512

View file

@ -156,9 +156,12 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
} }
// Not certain yet what benefit these flags offer. // Not certain yet what benefit these flags offer.
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan; if (flags & _O_SEQUENTIAL)
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess; attr |= kNtFileFlagSequentialScan;
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering; if (flags & _O_RANDOM)
attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT)
attr |= kNtFileFlagNoBuffering;
// TODO(jart): Should we *always* open with write permission if the // TODO(jart): Should we *always* open with write permission if the
// kernel will give it to us? We'd then deny write access // 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 // writing to a file across a network can occasionally return
// kNtErrorAccessDenied." -Quoth MSDN // kNtErrorAccessDenied." -Quoth MSDN
if (out_perm) *out_perm = perm; if (out_perm)
if (out_share) *out_share = share; *out_perm = perm;
if (out_disp) *out_disp = disp; if (out_share)
if (out_attr) *out_attr = attr; *out_share = share;
if (out_disp)
*out_disp = disp;
if (out_attr)
*out_attr = attr;
return 0; return 0;
} }

View file

@ -42,7 +42,8 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
char16_t *p = a; char16_t *p = a;
const char *q = "\\\\?\\pipe\\cosmo\\"; const char *q = "\\\\?\\pipe\\cosmo\\";
static atomic_uint x; static atomic_uint x;
while (*q) *p++ = *q++; while (*q)
*p++ = *q++;
p = itoa16(p, __pid); p = itoa16(p, __pid);
*p++ = '-'; *p++ = '-';
p = itoa16(p, atomic_fetch_add(&x, 1)); p = itoa16(p, atomic_fetch_add(&x, 1));

View file

@ -66,12 +66,14 @@
int dup2(int oldfd, int newfd) { int dup2(int oldfd, int newfd) {
int rc; int rc;
// helps guarantee stderr log gets duplicated before user closes // helps guarantee stderr log gets duplicated before user closes
if (_weaken(kloghandle)) _weaken(kloghandle)(); if (_weaken(kloghandle))
_weaken(kloghandle)();
#ifdef __aarch64__ #ifdef __aarch64__
if (oldfd == newfd) { if (oldfd == newfd) {
// linux aarch64 defines dup3() but not dup2(), which wasn't such a // linux aarch64 defines dup3() but not dup2(), which wasn't such a
// great decision, since the two syscalls don't behave the same way // 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 } else
#endif #endif
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -65,7 +65,8 @@
int dup3(int oldfd, int newfd, int flags) { int dup3(int oldfd, int newfd, int flags) {
int rc; int rc;
// helps guarantee stderr log gets duplicated before user closes // 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)) { if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
rc = einval(); // NetBSD doesn't do this rc = einval(); // NetBSD doesn't do this
} else if (oldfd < 0 || newfd < 0) { } else if (oldfd < 0 || newfd < 0) {

View file

@ -24,6 +24,7 @@
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode, textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
uint32_t flags) { uint32_t flags) {
char16_t path16[PATH_MAX]; 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); return __fix_enotdir(ntaccesscheck(path16, mode), path16);
} }

View file

@ -64,7 +64,8 @@ int faccessat(int dirfd, const char *path, int amode, int flags) {
rc = _weaken(__zipos_access)(&zipname, amode); rc = _weaken(__zipos_access)(&zipname, amode);
} else if (!IsWindows()) { } else if (!IsWindows()) {
e = errno; e = errno;
if (!flags) goto NoFlags; if (!flags)
goto NoFlags;
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) { if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
if (errno == ENOSYS) { if (errno == ENOSYS) {
errno = e; errno = e;

View file

@ -37,8 +37,10 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset,
int rc, flags, mode; int rc, flags, mode;
uint32_t perm, share, attr; uint32_t perm, share, attr;
if ((int64_t)len < 0) return einval(); if ((int64_t)len < 0)
if (!__isfdkind(fd, kFdFile)) return ebadf(); return einval();
if (!__isfdkind(fd, kFdFile))
return ebadf();
h1 = g_fds.p[fd].handle; h1 = g_fds.p[fd].handle;
mode = g_fds.p[fd].mode; mode = g_fds.p[fd].mode;
flags = g_fds.p[fd].flags; flags = g_fds.p[fd].flags;

View file

@ -27,7 +27,8 @@ int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
textwindows int sys_fchdir_nt(int dirfd) { textwindows int sys_fchdir_nt(int dirfd) {
char16_t dir[PATH_MAX]; char16_t dir[PATH_MAX];
if (!__isfdkind(dirfd, kFdFile)) return ebadf(); if (!__isfdkind(dirfd, kFdFile))
return ebadf();
return sys_chdir_nt_impl( return sys_chdir_nt_impl(
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir), dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos)); kNtFileNameNormalized | kNtVolumeNameDos));

View file

@ -29,8 +29,10 @@
textwindows int sys_fchmod_nt(int fd, uint32_t mode) { textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
// validate file descriptor // validate file descriptor
if (fd + 0u >= g_fds.n) return ebadf(); if (fd + 0u >= g_fds.n)
if (g_fds.p[fd].kind == kFdEmpty) return ebadf(); return ebadf();
if (g_fds.p[fd].kind == kFdEmpty)
return ebadf();
// get current information // get current information
struct NtFileBasicInfo fbi; struct NtFileBasicInfo fbi;

View file

@ -26,7 +26,8 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
int flags) { int flags) {
uint32_t attr; uint32_t attr;
uint16_t path16[PATH_MAX]; 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 ((attr = GetFileAttributes(path16)) != -1u) {
if (mode & 0222) { if (mode & 0222) {
attr &= ~kNtFileAttributeReadonly; attr &= ~kNtFileAttributeReadonly;

View file

@ -129,7 +129,8 @@ textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
static textwindows int64_t GetfileSize(int64_t handle) { static textwindows int64_t GetfileSize(int64_t handle) {
struct NtByHandleFileInformation wst; struct NtByHandleFileInformation wst;
if (!GetFileInformationByHandle(handle, &wst)) return __winerr(); if (!GetFileInformationByHandle(handle, &wst))
return __winerr();
return (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow; 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; break;
case SEEK_END: { case SEEK_END: {
int64_t size; int64_t size;
if ((size = GetfileSize(f->handle)) == -1) return -1; if ((size = GetfileSize(f->handle)) == -1)
return -1;
off = size - off; off = size - off;
break; 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 (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 // allow a big range to unlock many small ranges
for (flp = &g_locks.list, fl = *flp; fl;) { 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) { 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); return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start);
} }

View file

@ -27,17 +27,23 @@
textwindows int sys_fdatasync_nt(int fd, bool fake) { textwindows int sys_fdatasync_nt(int fd, bool fake) {
struct NtByHandleFileInformation wst; struct NtByHandleFileInformation wst;
if (!__isfdopen(fd)) return ebadf(); if (!__isfdopen(fd))
if (!__isfdkind(fd, kFdFile)) return einval(); return ebadf();
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval(); if (!__isfdkind(fd, kFdFile))
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst)) return __winerr(); 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) { if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
// Flushing a directory handle is possible, but it needs // Flushing a directory handle is possible, but it needs
// kNtGenericWrite access, and MSDN doesn't document it. // kNtGenericWrite access, and MSDN doesn't document it.
return 0; return 0;
} }
if (fake) return 0; if (fake)
if (_check_signal(false) == -1) return -1; return 0;
if (_check_signal(false) == -1)
return -1;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr(); return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
} }

View file

@ -34,7 +34,8 @@
textwindows int sys_flock_nt(int fd, int op) { textwindows int sys_flock_nt(int fd, int op) {
int64_t h; int64_t h;
struct NtByHandleFileInformation info; struct NtByHandleFileInformation info;
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (!__isfdkind(fd, kFdFile))
return ebadf();
h = g_fds.p[fd].handle; h = g_fds.p[fd].handle;
struct NtOverlapped ov = {.hEvent = h}; struct NtOverlapped ov = {.hEvent = h};

View file

@ -23,7 +23,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
int sys_fstat_metal(int fd, struct stat *st) { 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) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
bzero(st, sizeof(*st)); bzero(st, sizeof(*st));
st->st_dev = g_fds.p[fd].handle; st->st_dev = g_fds.p[fd].handle;

View file

@ -97,7 +97,8 @@ textwindows int sys_fstat_nt_special(int kind, struct stat *st) {
} }
textwindows int sys_fstat_nt(int fd, 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) { switch (g_fds.p[fd].kind) {
case kFdEmpty: case kFdEmpty:
return ebadf(); return ebadf();
@ -174,7 +175,8 @@ textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path,
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
if (!st.st_size) { if (!st.st_size) {
long size = GetSizeOfReparsePoint(handle); long size = GetSizeOfReparsePoint(handle);
if (size == -1) return -1; if (size == -1)
return -1;
st.st_size = size; st.st_size = size;
} }
} else { } else {

View file

@ -36,7 +36,8 @@
static int Atoi(const char *str) { static int Atoi(const char *str) {
int c; int c;
unsigned x = 0; unsigned x = 0;
if (!*str) return -1; if (!*str)
return -1;
while ((c = *str++)) { while ((c = *str++)) {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
x *= 10; x *= 10;

View file

@ -35,7 +35,8 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static inline const char *__strace_fstatat_flags(char buf[12], int flags) { 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); FormatInt32(buf, flags);
return buf; return buf;
} }

View file

@ -54,7 +54,8 @@ textwindows int sys_fstatfs_nt(int64_t handle, struct statfs *f) {
st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs), st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs),
kNtFileFsFullSizeInformation); kNtFileFsFullSizeInformation);
if (!NtSuccess(st)) { if (!NtSuccess(st)) {
if (st == kNtStatusDllNotFound) return enosys(); if (st == kNtStatusDllNotFound)
return enosys();
return eio(); return eio();
} }
for (h = j = i = 0; FileSystemNameBuffer[i]; i++) { for (h = j = i = 0; FileSystemNameBuffer[i]; i++) {

View file

@ -26,6 +26,7 @@
*/ */
int ftok(const char *path, int id) { int ftok(const char *path, int id) {
struct stat st; 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); return (uint32_t)id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff);
} }

View file

@ -64,7 +64,8 @@ int getcpu(unsigned *out_opt_cpu, unsigned *out_opt_node) {
} }
} else { } else {
int rc = sys_getcpu(&cpu, &node, 0); int rc = sys_getcpu(&cpu, &node, 0);
if (rc == -1) return -1; if (rc == -1)
return -1;
} }
if (out_opt_cpu) { if (out_opt_cpu) {
*out_opt_cpu = cpu; *out_opt_cpu = cpu;

View file

@ -82,14 +82,17 @@ static dontinline textwindows int sys_getcwd_nt(char *buf, size_t size) {
// get current directory from the system // get current directory from the system
char16_t p16[PATH_MAX]; char16_t p16[PATH_MAX];
uint32_t n = GetCurrentDirectory(PATH_MAX, p16); uint32_t n = GetCurrentDirectory(PATH_MAX, p16);
if (!n) return eacces(); // system call failed if (!n)
if (n >= PATH_MAX) return erange(); // not enough room?!? return eacces(); // system call failed
if (n >= PATH_MAX)
return erange(); // not enough room?!?
// convert utf-16 to utf-8 // convert utf-16 to utf-8
// we can't modify `buf` until we're certain of success // we can't modify `buf` until we're certain of success
char p8[PATH_MAX], *p = p8; char p8[PATH_MAX], *p = p8;
n = tprecode16to8(p, PATH_MAX, p16).ax; 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:\... // turn \\?\c:\... into c:\...
if (p[0] == '\\' && // if (p[0] == '\\' && //

View file

@ -43,7 +43,8 @@ struct loadavg {
int getloadavg(double *a, int n) { int getloadavg(double *a, int n) {
// cat /proc/loadavg // cat /proc/loadavg
int i, rc; int i, rc;
if (n > 3) n = 3; if (n > 3)
n = 3;
if (!n) { if (!n) {
rc = 0; rc = 0;
} else if (n < 0) { } else if (n < 0) {

View file

@ -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) { for (i = 0; i < n; i += j) {
TryAgain: TryAgain:
if (!impl(&x)) { if (!impl(&x)) {
if (f || i >= 256) break; if (f || i >= 256)
break;
goto TryAgain; goto TryAgain;
} }
for (j = 0; j < 8 && i + j < n; ++j) { for (j = 0; j < 8 && i + j < n; ++j) {

View file

@ -60,7 +60,8 @@ static bool have_getrandom;
static void GetRandomEntropy(char *p, size_t n) { static void GetRandomEntropy(char *p, size_t n) {
unassert(n <= 256); unassert(n <= 256);
if (sys_getentropy(p, n)) notpossible; if (sys_getentropy(p, n))
notpossible;
} }
static void GetRandomArnd(char *p, size_t n) { 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[0] = 1; // CTL_KERN
cmd[1] = IsFreebsd() ? 37 : 81; // KERN_ARND cmd[1] = IsFreebsd() ? 37 : 81; // KERN_ARND
unassert((m = n) <= 256); unassert((m = n) <= 256);
if (sys_sysctl(cmd, 2, p, &n, 0, 0) == -1) notpossible; if (sys_sysctl(cmd, 2, p, &n, 0, 0) == -1)
if (m != n) notpossible; notpossible;
if (m != n)
notpossible;
} }
static ssize_t GetRandomBsd(char *p, size_t n, void impl(char *, size_t)) { 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( __attribute__((__constructor__(30))) static textstartup void getrandom_init(
void) { void) {
int e, rc; int e, rc;
if (IsWindows() || IsMetal()) return; if (IsWindows() || IsMetal())
return;
BLOCK_CANCELATION; BLOCK_CANCELATION;
e = errno; e = errno;
if (!(rc = sys_getrandom(0, 0, 0))) { if (!(rc = sys_getrandom(0, 0, 0))) {

View file

@ -34,15 +34,20 @@ int getresgid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
int rc, gid; int rc, gid;
if (IsWindows()) { if (IsWindows()) {
gid = getgid(); gid = getgid();
if (real) *real = gid; if (real)
if (effective) *effective = gid; *real = gid;
if (saved) *saved = gid; if (effective)
*effective = gid;
if (saved)
*saved = gid;
rc = 0; rc = 0;
} else if (saved) { } else if (saved) {
rc = sys_getresgid(real, effective, saved); rc = sys_getresgid(real, effective, saved);
} else { } else {
if (real) *real = sys_getgid(); if (real)
if (effective) *effective = sys_getegid(); *real = sys_getgid();
if (effective)
*effective = sys_getegid();
rc = 0; rc = 0;
} }
STRACE("getresgid([%d], [%d], [%d]) → %d% m", real ? *real : 0, STRACE("getresgid([%d], [%d], [%d]) → %d% m", real ? *real : 0,

View file

@ -34,15 +34,20 @@ int getresuid(uint32_t *real, uint32_t *effective, uint32_t *saved) {
int rc, uid; int rc, uid;
if (IsWindows()) { if (IsWindows()) {
uid = getuid(); uid = getuid();
if (real) *real = uid; if (real)
if (effective) *effective = uid; *real = uid;
if (saved) *saved = uid; if (effective)
*effective = uid;
if (saved)
*saved = uid;
rc = 0; rc = 0;
} else if (saved) { } else if (saved) {
rc = sys_getresuid(real, effective, saved); rc = sys_getresuid(real, effective, saved);
} else { } else {
if (real) *real = sys_getuid(); if (real)
if (effective) *effective = sys_geteuid(); *real = sys_getuid();
if (effective)
*effective = sys_geteuid();
rc = 0; rc = 0;
} }
STRACE("getresuid([%d], [%d], [%d]) → %d% m", real ? *real : 0, STRACE("getresuid([%d], [%d], [%d]) → %d% m", real ? *real : 0,

View file

@ -25,7 +25,8 @@ textwindows char *GetSystemDirectoryPath(char *buf, const char *path,
uint32_t syslen = GetSystemDirectoryA(buf, size); uint32_t syslen = GetSystemDirectoryA(buf, size);
size_t pathlen = strlen(path); size_t pathlen = strlen(path);
if (syslen && syslen + pathlen + 1 < size) { if (syslen && syslen + pathlen + 1 < size) {
if (buf[syslen] == '\\') --syslen; if (buf[syslen] == '\\')
--syslen;
memcpy(buf + syslen, path, pathlen + 1); memcpy(buf + syslen, path, pathlen + 1);
return buf; return buf;
} else { } else {

View file

@ -29,7 +29,8 @@ textwindows uint32_t sys_getuid_nt(void) {
if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) { if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) {
GetUserName(&buf, &size); GetUserName(&buf, &size);
tmp = __fnv(buf, size >> 1) & 32767; tmp = __fnv(buf, size >> 1) & 32767;
if (!tmp) ++tmp; if (!tmp)
++tmp;
atomic_store_explicit(&uid, tmp, memory_order_release); atomic_store_explicit(&uid, tmp, memory_order_release);
} }
return tmp; return tmp;

View file

@ -244,11 +244,16 @@ static textwindows struct HostAdapterInfoNode *appendHostInfo(
* IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it * IFF_PROMISC ** NOT SUPPORTED, unknown how to retrieve it
*/ */
flags = 0; flags = 0;
if (aa->OperStatus == kNtIfOperStatusUp) flags |= IFF_UP | IFF_RUNNING; if (aa->OperStatus == kNtIfOperStatusUp)
if (aa->IfType == kNtIfTypePpp) flags |= IFF_POINTOPOINT; flags |= IFF_UP | IFF_RUNNING;
if (!(aa->Flags & kNtIpAdapterNoMulticast)) flags |= IFF_MULTICAST; if (aa->IfType == kNtIfTypePpp)
if (aa->IfType == kNtIfTypeSoftwareLoopback) flags |= IFF_LOOPBACK; flags |= IFF_POINTOPOINT;
if (aa->FirstPrefix) flags |= IFF_BROADCAST; if (!(aa->Flags & kNtIpAdapterNoMulticast))
flags |= IFF_MULTICAST;
if (aa->IfType == kNtIfTypeSoftwareLoopback)
flags |= IFF_LOOPBACK;
if (aa->FirstPrefix)
flags |= IFF_BROADCAST;
node->flags = flags; node->flags = flags;
} else { } else {
/* Copy from previous node */ /* Copy from previous node */
@ -344,13 +349,16 @@ static textwindows int createHostInfo(
baseName[IFNAMSIZ - 2] = '\0'; baseName[IFNAMSIZ - 2] = '\0';
/* Replace any space with a '_' */ /* Replace any space with a '_' */
for (i = 0; i < IFNAMSIZ - 2; ++i) { for (i = 0; i < IFNAMSIZ - 2; ++i) {
if (baseName[i] == ' ') baseName[i] = '_'; if (baseName[i] == ' ')
if (!baseName[i]) break; baseName[i] = '_';
if (!baseName[i])
break;
} }
for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix; for (count = 0, ua = aa->FirstUnicastAddress, ap = aa->FirstPrefix;
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) { (ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
node = appendHostInfo(node, baseName, aa, &ua, &ap, count); node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
if (!node) goto err; if (!node)
goto err;
if (!__hostInfo) { if (!__hostInfo) {
__hostInfo = node; __hostInfo = node;
if (_cmpxchg(&once, false, true)) { if (_cmpxchg(&once, false, true)) {
@ -444,7 +452,8 @@ static textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) {
static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr)); memcpy(&ifr->ifr_addr, &node->unicast, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -453,7 +462,8 @@ static textwindows int ioctl_siocgifaddr_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
ifr->ifr_flags = node->flags; ifr->ifr_flags = node->flags;
return 0; return 0;
} }
@ -462,7 +472,8 @@ static textwindows int ioctl_siocgifflags_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr)); memcpy(&ifr->ifr_netmask, &node->netmask, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -473,7 +484,8 @@ static textwindows int ioctl_siocgifnetmask_nt(int fd, struct ifreq *ifr) {
static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) { static textwindows int ioctl_siocgifbrdaddr_nt(int fd, struct ifreq *ifr) {
struct HostAdapterInfoNode *node; struct HostAdapterInfoNode *node;
node = findAdapterByName(ifr->ifr_name); node = findAdapterByName(ifr->ifr_name);
if (!node) return ebadf(); if (!node)
return ebadf();
memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr)); memcpy(&ifr->ifr_broadaddr, &node->broadcast, sizeof(struct sockaddr));
return 0; return 0;
} }
@ -513,7 +525,8 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e; for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e;
p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) {
fam = p[IsBsd() ? 17 : 16] & 255; fam = p[IsBsd() ? 17 : 16] & 255;
if (fam != AF_INET) continue; if (fam != AF_INET)
continue;
ip = READ32BE(p + 20); ip = READ32BE(p + 20);
bzero(req, sizeof(*req)); bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16); memcpy(req->ifr_name, p, 16);
@ -541,8 +554,10 @@ static inline void ioctl_sockaddr2linux(void *saddr) {
* requires adjustment between Linux and XNU * requires adjustment between Linux and XNU
*/ */
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) { static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
if (sys_ioctl(fd, op, ifr) == -1) return -1; if (sys_ioctl(fd, op, ifr) == -1)
if (IsBsd()) ioctl_sockaddr2linux(&ifr->ifr_addr); return -1;
if (IsBsd())
ioctl_sockaddr2linux(&ifr->ifr_addr);
return 0; return 0;
} }

View file

@ -28,7 +28,8 @@
bool isdirectory_nt(const char *path) { bool isdirectory_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !!(x & kNtFileAttributeDirectory); return !!(x & kNtFileAttributeDirectory);
} else { } else {

View file

@ -30,6 +30,7 @@
*/ */
bool32 isexecutable(const char *path) { bool32 isexecutable(const char *path) {
struct stat st; 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); return !S_ISDIR(st.st_mode) && !!(st.st_mode & 0111);
} }

View file

@ -33,7 +33,8 @@ static struct {
static bool __is_linux_2_6_23_impl(void) { static bool __is_linux_2_6_23_impl(void) {
int rc; int rc;
if (IsGenuineBlink()) return true; if (IsGenuineBlink())
return true;
asm volatile("syscall" asm volatile("syscall"
: "=a"(rc) : "=a"(rc)
: "0"(157), "D"(PR_GET_SECCOMP) : "0"(157), "D"(PR_GET_SECCOMP)

View file

@ -28,7 +28,8 @@
bool isregularfile_nt(const char *path) { bool isregularfile_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint)); return !(x & (kNtFileAttributeDirectory | kNtFileAttributeReparsePoint));
} else { } else {

View file

@ -26,7 +26,8 @@
bool issymlink_nt(const char *path) { bool issymlink_nt(const char *path) {
uint32_t x; uint32_t x;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpath(path, path16) == -1) return -1; if (__mkntpath(path, path16) == -1)
return -1;
if ((x = GetFileAttributes(path16)) != -1u) { if ((x = GetFileAttributes(path16)) != -1u) {
return !!(x & kNtFileAttributeReparsePoint); return !!(x & kNtFileAttributeReparsePoint);
} else { } else {

View file

@ -52,31 +52,42 @@ int makedirs(const char *path, unsigned mode) {
e = errno; e = errno;
n = strlen(path); n = strlen(path);
if (n >= PATH_MAX) return enametoolong(); if (n >= PATH_MAX)
return enametoolong();
memcpy(buf, path, n + 1); memcpy(buf, path, n + 1);
i = n; i = n;
// descend // descend
while (i) { while (i) {
if (!mkdir(buf, mode)) break; if (!mkdir(buf, mode))
break;
if (errno == EEXIST) { if (errno == EEXIST) {
if (i == n) goto CheckTop; if (i == n)
goto CheckTop;
break; break;
} }
if (errno != ENOENT) return -1; if (errno != ENOENT)
while (i && buf[i - 1] == '/') buf[--i] = 0; return -1;
while (i && buf[i - 1] != '/') buf[--i] = 0; while (i && buf[i - 1] == '/')
buf[--i] = 0;
while (i && buf[i - 1] != '/')
buf[--i] = 0;
} }
// ascend // ascend
for (;;) { for (;;) {
if (mkdir(buf, mode)) { if (mkdir(buf, mode)) {
if (errno != EEXIST) return -1; if (errno != EEXIST)
if (i == n) goto CheckTop; return -1;
if (i == n)
goto CheckTop;
} }
if (i == n) break; if (i == n)
while (i < n && (c = path[i]) != '/') buf[i++] = c; break;
while (i < n && (c = path[i]) == '/') buf[i++] = c; while (i < n && (c = path[i]) != '/')
buf[i++] = c;
while (i < n && (c = path[i]) == '/')
buf[i++] = c;
} }
Finish: Finish:
@ -84,7 +95,9 @@ Finish:
return 0; return 0;
CheckTop: CheckTop:
if (stat(path, &st)) return -1; if (stat(path, &st))
if (S_ISDIR(st.st_mode)) goto Finish; return -1;
if (S_ISDIR(st.st_mode))
goto Finish;
return eexist(); return eexist();
} }

View file

@ -23,7 +23,9 @@
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) { textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1; if (__mkntpathat(dirfd, path, 0, path16) == -1)
if (CreateDirectory(path16, 0)) return 0; return -1;
if (CreateDirectory(path16, 0))
return 0;
return __fix_enotdir(-1, path16); return __fix_enotdir(-1, path16);
} }

View file

@ -42,10 +42,14 @@
*/ */
int mknod(const char *path, uint32_t mode, uint64_t dev) { int mknod(const char *path, uint32_t mode, uint64_t dev) {
int e, rc; int e, rc;
if (IsAsan() && !__asan_is_valid_str(path)) return efault(); if (IsAsan() && !__asan_is_valid_str(path))
if (mode & S_IFREG) return creat(path, mode & ~S_IFREG); return efault();
if (mode & S_IFDIR) return mkdir(path, mode & ~S_IFDIR); if (mode & S_IFREG)
if (mode & S_IFIFO) return enosys(); // no named pipes! 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()) { if (!IsWindows()) {
// TODO(jart): Whys there code out there w/ S_xxx passed via dev? // TODO(jart): Whys there code out there w/ S_xxx passed via dev?
e = errno; e = errno;

View file

@ -86,7 +86,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
size_t i, j, k, s; size_t i, j, k, s;
char argbuf[PATH_MAX]; char argbuf[PATH_MAX];
for (k = i = 0; argv[i]; ++i) { for (k = i = 0; argv[i]; ++i) {
if (i) APPEND(u' '); if (i)
APPEND(u' ');
if (LooksLikeCosmoDrivePath(argv[i]) && if (LooksLikeCosmoDrivePath(argv[i]) &&
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) { strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
mungentpath(argbuf); mungentpath(argbuf);
@ -112,7 +113,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
} }
} }
} }
if (!x) break; if (!x)
break;
if (x == '\\') { if (x == '\\') {
++slashes; ++slashes;
} else if (x == '"') { } else if (x == '"') {
@ -125,7 +127,8 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
} }
slashes = 0; slashes = 0;
uint32_t w = EncodeUtf16(x); uint32_t w = EncodeUtf16(x);
do APPEND(w); do
APPEND(w);
while ((w >>= 16)); while ((w >>= 16));
} }
} }

View file

@ -44,9 +44,12 @@ static textwindows int Compare(const char *l, const char *r) {
for (;;) { for (;;) {
a = l[i] & 255; a = l[i] & 255;
b = r[i] & 255; b = r[i] & 255;
if (a == '=') a = 0; if (a == '=')
if (b == '=') b = 0; a = 0;
if (a != b || !b) break; if (b == '=')
b = 0;
if (a != b || !b)
break;
++i; ++i;
} }
return a - b; return a - b;
@ -56,13 +59,15 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
int c, i, cmp; int c, i, cmp;
char *var, *path = 0; char *var, *path = 0;
if (!str) return 0; if (!str)
return 0;
// copy key=val to buf // copy key=val to buf
var = env->buf + env->bufi; var = env->buf + env->bufi;
do { do {
c = *str++; c = *str++;
if (env->bufi + 2 > 32767) return e2big(); if (env->bufi + 2 > 32767)
return e2big();
env->buf[env->bufi++] = c; env->buf[env->bufi++] = c;
if (c == '=' && str[0] == '/' && IsAlpha(str[1]) && str[2] == '/') { if (c == '=' && str[0] == '/' && IsAlpha(str[1]) && str[2] == '/') {
path = env->buf + env->bufi; path = env->buf + env->bufi;
@ -70,7 +75,8 @@ static textwindows int InsertString(struct EnvBuilder *env, const char *str) {
} while (c); } while (c);
// fixup key=/c/... → key=c:\... // fixup key=/c/... → key=c:\...
if (path) mungentpath(path); if (path)
mungentpath(path);
// append key=val to sorted list using insertion sort technique // append key=val to sorted list using insertion sort technique
for (i = env->vari;; --i) { for (i = env->vari;; --i) {
@ -143,8 +149,10 @@ textwindows int mkntenvblock(char16_t envblock[32767], char *const envp[],
#pragma GCC pop_options #pragma GCC pop_options
// load new environment into string pointer array and fix file paths // load new environment into string pointer array and fix file paths
if (InsertStrings(&env, envp) == -1) return -1; if (InsertStrings(&env, envp) == -1)
if (InsertStrings(&env, extravars) == -1) return -1; return -1;
if (InsertStrings(&env, extravars) == -1)
return -1;
if (environ) { if (environ) {
// https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/ // https://jpassing.com/2009/12/28/the-hidden-danger-of-forgetting-to-specify-systemroot-in-a-custom-environment-block/
e = __getenv(environ, "SYSTEMROOT"); e = __getenv(environ, "SYSTEMROOT");

View file

@ -54,8 +54,10 @@ textwindows size_t __normntpath(char16_t *p, size_t n) {
(i + 1 < n && p[i + 1] == '.') && // (i + 1 < n && p[i + 1] == '.') && //
(i + 2 == n || IsSlash(p[i + 2]))) { (i + 2 == n || IsSlash(p[i + 2]))) {
// matched "/../" or "/..$" // matched "/../" or "/..$"
while (j && p[j - 1] == '\\') --j; while (j && p[j - 1] == '\\')
while (j && p[j - 1] != '\\') --j; --j;
while (j && p[j - 1] != '\\')
--j;
} else { } else {
p[j++] = c; 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' && if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
(IsSlash(q[4]) || !q[4])) { (IsSlash(q[4]) || !q[4])) {
m = GetTempPath(z, p); m = GetTempPath(z, p);
if (!q[4]) return m; if (!q[4])
return m;
q += 5; q += 5;
p += m; p += m;
z -= m; z -= m;

View file

@ -33,14 +33,19 @@ static textwindows int __mkntpathath_impl(int64_t dirhand, const char *path,
size_t n; size_t n;
char16_t dir[PATH_MAX]; char16_t dir[PATH_MAX];
uint32_t dirlen, filelen; uint32_t dirlen, filelen;
if (!isutf8(path, -1)) return eilseq(); // thwart overlong nul in conversion if (!isutf8(path, -1))
if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1; return eilseq(); // thwart overlong nul in conversion
if (!filelen) return enoent(); if ((filelen = __mkntpath2(path, file, flags)) == -1)
return -1;
if (!filelen)
return enoent();
if (file[0] != u'\\' && dirhand != AT_FDCWD) { // ProTip: \\?\C:\foo if (file[0] != u'\\' && dirhand != AT_FDCWD) { // ProTip: \\?\C:\foo
dirlen = GetFinalPathNameByHandle(dirhand, dir, ARRAYLEN(dir), dirlen = GetFinalPathNameByHandle(dirhand, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos); kNtFileNameNormalized | kNtVolumeNameDos);
if (!dirlen) return __winerr(); if (!dirlen)
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong(); return __winerr();
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir))
return enametoolong();
dir[dirlen] = u'\\'; dir[dirlen] = u'\\';
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t)); memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
memcpy(file, dir, ((n = dirlen + 1 + filelen) + 1) * sizeof(char16_t)); memcpy(file, dir, ((n = dirlen + 1 + filelen) + 1) * sizeof(char16_t));

View file

@ -84,7 +84,8 @@ int mount(const char *source, const char *target, const char *type,
if (!IsBsd()) { if (!IsBsd()) {
return sys_mount_linux(source, target, type, flags, data); return sys_mount_linux(source, target, type, flags, data);
} else { } else {
if (!strcmp(type, "iso9660")) type = "cd9660"; if (!strcmp(type, "iso9660"))
type = "cd9660";
if (!strcmp(type, "vfat")) { if (!strcmp(type, "vfat")) {
if (IsOpenbsd() || IsNetbsd()) { if (IsOpenbsd() || IsNetbsd()) {
type = "msdos"; type = "msdos";

View file

@ -47,7 +47,8 @@ void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
: "=a"(res) : "=a"(res)
: "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8) : "0"(0x019), "D"(p), "S"(n), "d"(m), "r"(r10), "r"(r8)
: "rcx", "r11", "memory", "cc"); : "rcx", "r11", "memory", "cc");
if (res > -4096ul) errno = -res, res = -1; if (res > -4096ul)
errno = -res, res = -1;
} else if (IsNetbsd()) { } else if (IsNetbsd()) {
if (f & MREMAP_MAYMOVE) { if (f & MREMAP_MAYMOVE) {
res = 0x19B; 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) : CFLAG_CONSTRAINT(cf), "+a"(res), "=d"(rdx)
: "D"(p), "S"(n), "2"(q), "r"(r10), "r"(r8) : "D"(p), "S"(n), "2"(q), "r"(r10), "r"(r8)
: "rcx", "r9", "r11", "memory", "cc"); : "rcx", "r9", "r11", "memory", "cc");
if (cf) errno = res, res = -1; if (cf)
errno = res, res = -1;
} else { } else {
res = einval(); res = einval();
} }

View file

@ -69,7 +69,8 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
int64_t hToken, hImpersonatedToken, hFile; int64_t hToken, hImpersonatedToken, hFile;
intptr_t buffer[1024 / sizeof(intptr_t)]; intptr_t buffer[1024 / sizeof(intptr_t)];
BLOCK_SIGNALS; BLOCK_SIGNALS;
if (flags & X_OK) flags |= R_OK; if (flags & X_OK)
flags |= R_OK;
granted = 0; granted = 0;
result = false; result = false;
flagmask = flags; flagmask = flags;

View file

@ -157,7 +157,8 @@ textwindows int ntspawn(
} }
} }
} }
if (sb) ntspawn_free(sb); if (sb)
ntspawn_free(sb);
ALLOW_SIGNALS; ALLOW_SIGNALS;
return rc; return rc;
} }

View file

@ -184,7 +184,8 @@ static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
static int Atoi(const char *str) { static int Atoi(const char *str) {
int c; int c;
unsigned x = 0; unsigned x = 0;
if (!*str) return -1; if (!*str)
return -1;
while ((c = *str++)) { while ((c = *str++)) {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
x *= 10; x *= 10;
@ -202,7 +203,8 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
int fd, oldfd; int fd, oldfd;
BLOCK_SIGNALS; BLOCK_SIGNALS;
__fds_lock(); __fds_lock();
if (!(flags & _O_CREAT)) mode = 0; if (!(flags & _O_CREAT))
mode = 0;
if ((rc = fd = __reservefd_unlocked(-1)) != -1) { if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
if (startswith(file, "/dev/")) { if (startswith(file, "/dev/")) {
if (!strcmp(file + 5, "tty")) { if (!strcmp(file + 5, "tty")) {

View file

@ -40,20 +40,26 @@
int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) { int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
int fd; int fd;
struct MetalFile *state; struct MetalFile *state;
if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME)) return enoent(); if (dirfd != AT_FDCWD || strcmp(file, APE_COM_NAME))
if (flags != O_RDONLY) return eacces(); return enoent();
if (!_weaken(__ape_com_base) || !_weaken(__ape_com_size)) return eopnotsupp(); if (flags != O_RDONLY)
if ((fd = __reservefd(-1)) == -1) return -1; 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)) { if (!_weaken(calloc) || !_weaken(free)) {
struct DirectMap dm; struct DirectMap dm;
dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096), dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,
0); 0);
state = dm.addr; state = dm.addr;
if (state == (void *)-1) return -1; if (state == (void *)-1)
return -1;
} else { } else {
state = _weaken(calloc)(1, sizeof(struct MetalFile)); state = _weaken(calloc)(1, sizeof(struct MetalFile));
if (!state) return -1; if (!state)
return -1;
} }
state->base = (char *)__ape_com_base; state->base = (char *)__ape_com_base;
state->size = __ape_com_size; state->size = __ape_com_size;

View file

@ -64,12 +64,16 @@ static int openpty_impl(int *mfd, int *sfd, char *name,
} }
*mfd = m; *mfd = m;
*sfd = s; *sfd = s;
if (name) strcpy(name, t.sname); if (name)
if (tio) npassert(!tcsetattr(s, TCSAFLUSH, tio)); strcpy(name, t.sname);
if (wsz) npassert(!tcsetwinsize(s, wsz)); if (tio)
npassert(!tcsetattr(s, TCSAFLUSH, tio));
if (wsz)
npassert(!tcsetwinsize(s, wsz));
return 0; return 0;
OnError: OnError:
if (m != -1) sys_close(m); if (m != -1)
sys_close(m);
return -1; return -1;
} }

View file

@ -32,7 +32,8 @@
static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask, static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) { bool restartable) {
int sig, handler_was_called; 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))) { if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
goto HandleSignal; 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))) { if (ok && _weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
HandleSignal: HandleSignal:
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask); 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)) { if (!restartable || (handler_was_called & SIG_HANDLED_NO_RESTART)) {
return eintr(); return eintr();
} }

View file

@ -22,7 +22,8 @@
textwindows int sys_pause_nt(void) { textwindows int sys_pause_nt(void) {
int rc; int rc;
while (!(rc = _park_norestart(-1u, 0))) donothing; while (!(rc = _park_norestart(-1u, 0)))
donothing;
return rc; return rc;
} }

View file

@ -26,6 +26,7 @@
*/ */
void perror(const char *thing) { void perror(const char *thing) {
const char *reason; const char *reason;
if (!(reason = _strerdoc(errno))) reason = "Unknown error"; if (!(reason = _strerdoc(errno)))
reason = "Unknown error";
tinyprint(2, thing ? thing : "", thing ? ": " : "", reason, "\n", NULL); tinyprint(2, thing ? thing : "", thing ? ": " : "", reason, "\n", NULL);
} }

View file

@ -25,7 +25,8 @@
int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) { int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) {
int e, rc; int e, rc;
if (!flags) goto OldSkool; if (!flags)
goto OldSkool;
e = errno; e = errno;
rc = __sys_pipe2(pipefd, flags); rc = __sys_pipe2(pipefd, flags);
if (rc == -1 && errno == ENOSYS) { if (rc == -1 && errno == ENOSYS) {

View file

@ -1023,18 +1023,21 @@ static const struct sock_filter kFilterIgnoreExitGroup[] = {
static privileged unsigned long StrLen(const char *s) { static privileged unsigned long StrLen(const char *s) {
unsigned long n = 0; unsigned long n = 0;
while (*s++) ++n; while (*s++)
++n;
return n; return n;
} }
static privileged void *MemCpy(void *d, const void *s, unsigned long n) { static privileged void *MemCpy(void *d, const void *s, unsigned long n) {
unsigned long i = 0; unsigned long i = 0;
for (; i < n; ++i) ((char *)d)[i] = ((char *)s)[i]; for (; i < n; ++i)
((char *)d)[i] = ((char *)s)[i];
return (char *)d + n; return (char *)d + n;
} }
static privileged char *FixCpy(char p[17], uint64_t x, int k) { static privileged char *FixCpy(char p[17], uint64_t x, int k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; while (k > 0)
*p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0'; *p = '\0';
return p; return p;
} }
@ -1305,7 +1308,8 @@ static privileged void MonitorSigSys(void) {
static privileged void AppendFilter(struct Filter *f, static privileged void AppendFilter(struct Filter *f,
const struct sock_filter *p, size_t n) { const struct sock_filter *p, size_t n) {
if (UNLIKELY(f->n + n > ARRAYLEN(f->p))) notpossible; if (UNLIKELY(f->n + n > ARRAYLEN(f->p)))
notpossible;
MemCpy(f->p + f->n, p, n * sizeof(*f->p)); MemCpy(f->p + f->n, p, n * sizeof(*f->p));
f->n += n; f->n += n;
} }
@ -2170,7 +2174,8 @@ static privileged void AppendPledge(struct Filter *f, //
if ((count = CountUnspecial(p, len))) { if ((count = CountUnspecial(p, len))) {
if (count < 256) { if (count < 256) {
for (j = i = 0; i < len; ++i) { for (j = i = 0; i < len; ++i) {
if (p[i] & SPECIAL) continue; if (p[i] & SPECIAL)
continue;
// jump to ALLOW rule below if accumulator equals ordinal // jump to ALLOW rule below if accumulator equals ordinal
struct sock_filter fragment[] = { struct sock_filter fragment[] = {
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, // instruction BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, // instruction
@ -2192,7 +2197,8 @@ static privileged void AppendPledge(struct Filter *f, //
// handle "special" ordinals which use hand-crafted bpf // handle "special" ordinals which use hand-crafted bpf
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if (!(p[i] & SPECIAL)) continue; if (!(p[i] & SPECIAL))
continue;
switch (p[i]) { switch (p[i]) {
case __NR_linux_mmap | EXEC: case __NR_linux_mmap | EXEC:
AllowMmapExec(f); AllowMmapExec(f);

View file

@ -249,12 +249,17 @@ int pledge(const char *promises, const char *execpromises) {
// may use pledge(0,0) to perform a support check, to determine if // may use pledge(0,0) to perform a support check, to determine if
// pledge() will be able to impose the restrictions it advertises // pledge() will be able to impose the restrictions it advertises
// within the host environment. // within the host environment.
if (execpromises) return einval(); if (execpromises)
if (IsGenuineBlink()) return enosys(); return einval();
if (IsOpenbsd()) return sys_pledge(0, 0); if (IsGenuineBlink())
if (!IsLinux()) return enosys(); return enosys();
if (IsOpenbsd())
return sys_pledge(0, 0);
if (!IsLinux())
return enosys();
rc = sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0); rc = sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
if (rc == 0 || rc == 2) return 0; // 2 means we're already filtered if (rc == 0 || rc == 2)
return 0; // 2 means we're already filtered
unassert(rc < 0); unassert(rc < 0);
errno = -rc; errno = -rc;
return -1; return -1;
@ -274,9 +279,11 @@ int pledge(const char *promises, const char *execpromises) {
STRACE("execpromises must be a subset of promises"); STRACE("execpromises must be a subset of promises");
rc = einval(); rc = einval();
} else { } else {
if (notsubset) iexecpromises = ipromises; if (notsubset)
iexecpromises = ipromises;
rc = sys_pledge_linux(ipromises, __pledge_mode); rc = sys_pledge_linux(ipromises, __pledge_mode);
if (rc > -4096u) errno = -rc, rc = -1; if (rc > -4096u)
errno = -rc, rc = -1;
} }
} else { } else {
e = errno; e = errno;

View file

@ -71,7 +71,8 @@ int sys_poll_metal(struct pollfd *fds, size_t nfds, unsigned timeout_ms) {
fds[i].revents = POLLNVAL; fds[i].revents = POLLNVAL;
} }
} }
if (fds[i].revents) ++rc; if (fds[i].revents)
++rc;
} }
if (rc || !blocking || unsignedsubtract(rdtsc(), start) >= timeout) { if (rc || !blocking || unsignedsubtract(rdtsc(), start) >= timeout) {
break; break;

View file

@ -81,7 +81,8 @@ static textwindows int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
// we might need to spawn threads and open pipes // we might need to spawn threads and open pipes
__fds_lock(); __fds_lock();
for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) { for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) {
if (fds[i].fd < 0) continue; if (fds[i].fd < 0)
continue;
if (__isfdopen(fds[i].fd)) { if (__isfdopen(fds[i].fd)) {
if (__isfdkind(fds[i].fd, kFdSocket)) { if (__isfdkind(fds[i].fd, kFdSocket)) {
if (sn < ARRAYLEN(sockfds)) { if (sn < ARRAYLEN(sockfds)) {

View file

@ -43,7 +43,8 @@ int posix_openpt(int flags) {
rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0); rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0);
} else if (IsFreebsd()) { } else if (IsFreebsd()) {
rc = sys_posix_openpt(flags); rc = sys_posix_openpt(flags);
if (rc == -1 && errno == ENOSPC) errno = EAGAIN; if (rc == -1 && errno == ENOSPC)
errno = EAGAIN;
} else { } else {
rc = enosys(); rc = enosys();
} }

View file

@ -87,9 +87,11 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
(timeout->tv_nsec + 999999) / 1000000)) { (timeout->tv_nsec + 999999) / 1000000)) {
ms = -1; ms = -1;
} }
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask); if (sigmask)
sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = poll(fds, nfds, ms); rc = poll(fds, nfds, ms);
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0); if (sigmask)
sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
} }
} else { } else {
uint32_t ms; uint32_t ms;

View file

@ -84,7 +84,8 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
e = errno; e = errno;
rc = sys_preadv(fd, iov, iovlen, off, off); rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc != -1 || errno != ENOSYS) return rc; if (rc != -1 || errno != ENOSYS)
return rc;
errno = e; errno = e;
for (toto = i = 0; i < iovlen; ++i) { for (toto = i = 0; i < iovlen; ++i) {

View file

@ -49,13 +49,16 @@ void __printfds(struct Fd *fds, size_t fdslen) {
int i; int i;
char buf[128]; char buf[128];
for (i = 0; i < fdslen; ++i) { for (i = 0; i < fdslen; ++i) {
if (!fds[i].kind) continue; if (!fds[i].kind)
continue;
kprintf("%3d %s", i, __fdkind2str(fds[i].kind)); kprintf("%3d %s", i, __fdkind2str(fds[i].kind));
if (fds[i].flags) { if (fds[i].flags) {
kprintf(" flags=%s", (DescribeOpenFlags)(buf, fds[i].flags)); kprintf(" flags=%s", (DescribeOpenFlags)(buf, fds[i].flags));
} }
if (fds[i].mode) kprintf(" mode=%#o", fds[i].mode); if (fds[i].mode)
if (fds[i].handle) kprintf(" handle=%ld", fds[i].handle); kprintf(" mode=%#o", fds[i].mode);
if (fds[i].handle)
kprintf(" handle=%ld", fds[i].handle);
kprintf("\n"); kprintf("\n");
} }
} }

View file

@ -24,7 +24,8 @@ char *program_invocation_short_name;
__attribute__((__constructor__(10))) static textstartup void __attribute__((__constructor__(10))) static textstartup void
program_invocation_short_name_init(void) { program_invocation_short_name_init(void) {
char *p, *r; char *p, *r;
if (!__argc) return; if (!__argc)
return;
if ((p = strrchr(__argv[0], '/'))) { if ((p = strrchr(__argv[0], '/'))) {
r = p + 1; r = p + 1;
} else { } else {

View file

@ -47,9 +47,11 @@ long ptrace(int request, ...) {
rc = einval(); /* see consts.sh */ rc = einval(); /* see consts.sh */
} else { } else {
ispeek = IsLinux() && request - 1u < 3; ispeek = IsLinux() && request - 1u < 3;
if (ispeek) data = &peek; if (ispeek)
data = &peek;
rc = __sys_ptrace(request, pid, addr, data); rc = __sys_ptrace(request, pid, addr, data);
if (rc != -1 && ispeek) rc = peek; if (rc != -1 && ispeek)
rc = peek;
} }
STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr, STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr,
data, rc); data, rc);

Some files were not shown because too many files have changed in this diff Show more