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