mirror of
https://github.com/jart/cosmopolitan.git
synced 2024-05-13 17:12:41 +00:00
Compare commits
5 commits
fbaef4af33
...
a097096270
Author | SHA1 | Date | |
---|---|---|---|
a097096270 | |||
2bfd6b37c1 | |||
69db501c68 | |||
6e6fc38935 | |||
59c7ea08c2 |
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);
|
||||
|
|
838
examples/wump.c
Normal file
838
examples/wump.c
Normal file
|
@ -0,0 +1,838 @@
|
|||
/* $NetBSD: wump.c,v 1.17 2005/02/15 12:56:20 jsm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Dave Taylor, of Intuitive Systems.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)wump.c 8.1 (Berkeley) 5/31/93";
|
||||
#else
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#define u_int uint32_t
|
||||
|
||||
/*
|
||||
* A very new version of the age old favorite Hunt-The-Wumpus game that has
|
||||
* been a part of the BSD distribution of Unix for longer than us old folk
|
||||
* would care to remember.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* some defines to spec out what our wumpus cave should look like */
|
||||
|
||||
#define MAX_ARROW_SHOT_DISTANCE 6 /* +1 for '0' stopper */
|
||||
#define MAX_LINKS_IN_ROOM 25 /* a complex cave */
|
||||
|
||||
#define MAX_ROOMS_IN_CAVE 250
|
||||
#define ROOMS_IN_CAVE 20
|
||||
#define MIN_ROOMS_IN_CAVE 10
|
||||
|
||||
#define LINKS_IN_ROOM 3
|
||||
#define NUMBER_OF_ARROWS 5
|
||||
#define PIT_COUNT 3
|
||||
#define BAT_COUNT 3
|
||||
|
||||
#define EASY 1 /* levels of play */
|
||||
#define HARD 2
|
||||
|
||||
/* some macro definitions for cleaner output */
|
||||
|
||||
#define plural(n) (n == 1 ? "" : "s")
|
||||
|
||||
/* simple cave data structure; +1 so we can index from '1' not '0' */
|
||||
struct room_record {
|
||||
int tunnel[MAX_LINKS_IN_ROOM];
|
||||
int has_a_pit, has_a_bat;
|
||||
} cave[MAX_ROOMS_IN_CAVE+1];
|
||||
|
||||
/*
|
||||
* global variables so we can keep track of where the player is, how
|
||||
* many arrows they still have, where el wumpo is, and so on...
|
||||
*/
|
||||
int player_loc = -1; /* player location */
|
||||
int wumpus_loc = -1; /* The Bad Guy location */
|
||||
int level = EASY; /* level of play */
|
||||
int arrows_left; /* arrows unshot */
|
||||
|
||||
#ifdef DEBUG
|
||||
int debug = 0;
|
||||
#endif
|
||||
|
||||
int pit_num = PIT_COUNT; /* # pits in cave */
|
||||
int bat_num = BAT_COUNT; /* # bats */
|
||||
int room_num = ROOMS_IN_CAVE; /* # rooms in cave */
|
||||
int link_num = LINKS_IN_ROOM; /* links per room */
|
||||
int arrow_num = NUMBER_OF_ARROWS; /* arrow inventory */
|
||||
|
||||
char answer[20]; /* user input */
|
||||
|
||||
int bats_nearby(void);
|
||||
void cave_init(void);
|
||||
void clear_things_in_cave(void);
|
||||
void display_room_stats(void);
|
||||
int gcd(int, int);
|
||||
int getans(const char *);
|
||||
void initialize_things_in_cave(void);
|
||||
void instructions(void);
|
||||
int int_compare(const void *, const void *);
|
||||
void jump(int);
|
||||
void kill_wump(void);
|
||||
int main(int, char **);
|
||||
int move_to(const char *);
|
||||
void move_wump(void);
|
||||
void no_arrows(void);
|
||||
void pit_kill(void);
|
||||
int pit_nearby(void);
|
||||
void pit_survive(void);
|
||||
int shoot(char *);
|
||||
void shoot_self(void);
|
||||
int take_action(void);
|
||||
void usage(void) __attribute__((__noreturn__));
|
||||
void wump_kill(void);
|
||||
int wump_nearby(void);
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
|
||||
/* Revoke setgid privileges */
|
||||
setregid(getgid(), getgid());
|
||||
|
||||
#ifdef DEBUG
|
||||
while ((c = getopt(argc, argv, "a:b:hp:r:t:d")) != -1)
|
||||
#else
|
||||
while ((c = getopt(argc, argv, "a:b:hp:r:t:")) != -1)
|
||||
#endif
|
||||
switch (c) {
|
||||
case 'a':
|
||||
arrow_num = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
bat_num = atoi(optarg);
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
level = HARD;
|
||||
break;
|
||||
case 'p':
|
||||
pit_num = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
room_num = atoi(optarg);
|
||||
if (room_num < MIN_ROOMS_IN_CAVE) {
|
||||
(void)fprintf(stderr,
|
||||
"No self-respecting wumpus would live in such a small cave!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (room_num > MAX_ROOMS_IN_CAVE) {
|
||||
(void)fprintf(stderr,
|
||||
"Even wumpii can't furnish caves that large!\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
link_num = atoi(optarg);
|
||||
if (link_num < 2) {
|
||||
(void)fprintf(stderr,
|
||||
"Wumpii like extra doors in their caves!\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
if (link_num > MAX_LINKS_IN_ROOM ||
|
||||
link_num > room_num - (room_num / 4)) {
|
||||
(void)fprintf(stderr,
|
||||
"Too many tunnels! The cave collapsed!\n(Fortunately, the wumpus escaped!)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (level == HARD) {
|
||||
bat_num += ((random() % (room_num / 2)) + 1);
|
||||
pit_num += ((random() % (room_num / 2)) + 1);
|
||||
}
|
||||
|
||||
if (bat_num > room_num / 2) {
|
||||
(void)fprintf(stderr,
|
||||
"The wumpus refused to enter the cave, claiming it was too crowded!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pit_num > room_num / 2) {
|
||||
(void)fprintf(stderr,
|
||||
"The wumpus refused to enter the cave, claiming it was too dangerous!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
instructions();
|
||||
cave_init();
|
||||
|
||||
/* and we're OFF! da dum, da dum, da dum, da dum... */
|
||||
(void)printf(
|
||||
"\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
|
||||
There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
|
||||
quiver holds %d custom super anti-evil Wumpus arrows. Good luck.\n",
|
||||
room_num, link_num, bat_num, plural(bat_num), pit_num,
|
||||
plural(pit_num), arrow_num);
|
||||
|
||||
for (;;) {
|
||||
initialize_things_in_cave();
|
||||
arrows_left = arrow_num;
|
||||
do {
|
||||
display_room_stats();
|
||||
(void)printf("Move or shoot? (m-s) ");
|
||||
(void)fflush(stdout);
|
||||
if (!fgets(answer, sizeof(answer), stdin))
|
||||
break;
|
||||
} while (!take_action());
|
||||
|
||||
if (!getans("\nCare to play another game? (y-n) "))
|
||||
exit(0);
|
||||
if (getans("In the same cave? (y-n) "))
|
||||
clear_things_in_cave();
|
||||
else
|
||||
cave_init();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
display_room_stats()
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Routine will explain what's going on with the current room, as well
|
||||
* as describe whether there are pits, bats, & wumpii nearby. It's
|
||||
* all pretty mindless, really.
|
||||
*/
|
||||
(void)printf(
|
||||
"\nYou are in room %d of the cave, and have %d arrow%s left.\n",
|
||||
player_loc, arrows_left, plural(arrows_left));
|
||||
|
||||
if (bats_nearby())
|
||||
(void)printf("*rustle* *rustle* (must be bats nearby)\n");
|
||||
if (pit_nearby())
|
||||
(void)printf("*whoosh* (I feel a draft from some pits).\n");
|
||||
if (wump_nearby())
|
||||
(void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
|
||||
|
||||
(void)printf("There are tunnels to rooms %d, ",
|
||||
cave[player_loc].tunnel[0]);
|
||||
|
||||
for (i = 1; i < link_num - 1; i++)
|
||||
if (cave[player_loc].tunnel[i] <= room_num)
|
||||
(void)printf("%d, ", cave[player_loc].tunnel[i]);
|
||||
(void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
|
||||
}
|
||||
|
||||
int
|
||||
take_action()
|
||||
{
|
||||
/*
|
||||
* Do the action specified by the player, either 'm'ove, 's'hoot
|
||||
* or something exceptionally bizarre and strange! Returns 1
|
||||
* iff the player died during this turn, otherwise returns 0.
|
||||
*/
|
||||
switch (*answer) {
|
||||
case 'M':
|
||||
case 'm': /* move */
|
||||
return(move_to(answer + 1));
|
||||
case 'S':
|
||||
case 's': /* shoot */
|
||||
return(shoot(answer + 1));
|
||||
case 'Q':
|
||||
case 'q':
|
||||
case 'x':
|
||||
exit(0);
|
||||
case '\n':
|
||||
return(0);
|
||||
}
|
||||
if (random() % 15 == 1)
|
||||
(void)printf("Que pasa?\n");
|
||||
else
|
||||
(void)printf("I don't understand!\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
move_to(room_number)
|
||||
const char *room_number;
|
||||
{
|
||||
int i, just_moved_by_bats, next_room, tunnel_available;
|
||||
|
||||
/*
|
||||
* This is responsible for moving the player into another room in the
|
||||
* cave as per their directions. If room_number is a null string,
|
||||
* then we'll prompt the user for the next room to go into. Once
|
||||
* we've moved into the room, we'll check for things like bats, pits,
|
||||
* and so on. This routine returns 1 if something occurs that kills
|
||||
* the player and 0 otherwise...
|
||||
*/
|
||||
tunnel_available = just_moved_by_bats = 0;
|
||||
next_room = atoi(room_number);
|
||||
|
||||
/* crap for magic tunnels */
|
||||
if (next_room == room_num + 1 &&
|
||||
cave[player_loc].tunnel[link_num-1] != next_room)
|
||||
++next_room;
|
||||
|
||||
while (next_room < 1 || next_room > room_num + 1) {
|
||||
if (next_room < 0 && next_room != -1)
|
||||
(void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
|
||||
if (next_room > room_num + 1)
|
||||
(void)printf("What? The cave surely isn't quite that big!\n");
|
||||
if (next_room == room_num + 1 &&
|
||||
cave[player_loc].tunnel[link_num-1] != next_room) {
|
||||
(void)printf("What? The cave isn't that big!\n");
|
||||
++next_room;
|
||||
}
|
||||
(void)printf("To which room do you wish to move? ");
|
||||
(void)fflush(stdout);
|
||||
if (!fgets(answer, sizeof(answer), stdin))
|
||||
return(1);
|
||||
next_room = atoi(answer);
|
||||
}
|
||||
|
||||
/* now let's see if we can move to that room or not */
|
||||
tunnel_available = 0;
|
||||
for (i = 0; i < link_num; i++)
|
||||
if (cave[player_loc].tunnel[i] == next_room)
|
||||
tunnel_available = 1;
|
||||
|
||||
if (!tunnel_available) {
|
||||
(void)printf("*Oof!* (You hit the wall)\n");
|
||||
if (random() % 6 == 1) {
|
||||
(void)printf("Your colorful comments awaken the wumpus!\n");
|
||||
move_wump();
|
||||
if (wumpus_loc == player_loc) {
|
||||
wump_kill();
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* now let's move into that room and check it out for dangers */
|
||||
if (next_room == room_num + 1)
|
||||
jump(next_room = (random() % room_num) + 1);
|
||||
|
||||
player_loc = next_room;
|
||||
for (;;) {
|
||||
if (next_room == wumpus_loc) { /* uh oh... */
|
||||
wump_kill();
|
||||
return(1);
|
||||
}
|
||||
if (cave[next_room].has_a_pit) {
|
||||
if (random() % 12 < 2) {
|
||||
pit_survive();
|
||||
return(0);
|
||||
} else {
|
||||
pit_kill();
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cave[next_room].has_a_bat) {
|
||||
(void)printf(
|
||||
"*flap* *flap* *flap* (humongous bats pick you up and move you%s!)\n",
|
||||
just_moved_by_bats ? " again": "");
|
||||
next_room = player_loc = (random() % room_num) + 1;
|
||||
just_moved_by_bats = 1;
|
||||
}
|
||||
|
||||
else
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
shoot(room_list)
|
||||
char *room_list;
|
||||
{
|
||||
int chance, next, roomcnt;
|
||||
int j, arrow_location, link, ok;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Implement shooting arrows. Arrows are shot by the player indicating
|
||||
* a space-separated list of rooms that the arrow should pass through;
|
||||
* if any of the rooms they specify are not accessible via tunnel from
|
||||
* the room the arrow is in, it will instead fly randomly into another
|
||||
* room. If the player hits the wumpus, this routine will indicate
|
||||
* such. If it misses, this routine will *move* the wumpus one room.
|
||||
* If it's the last arrow, the player then dies... Returns 1 if the
|
||||
* player has won or died, 0 if nothing has happened.
|
||||
*/
|
||||
arrow_location = player_loc;
|
||||
for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
|
||||
if (!(p = strtok(room_list, " \t\n"))) {
|
||||
if (roomcnt == 1) {
|
||||
(void)printf(
|
||||
"The arrow falls to the ground at your feet!\n");
|
||||
return(0);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (roomcnt > 5) {
|
||||
(void)printf(
|
||||
"The arrow wavers in its flight and and can go no further!\n");
|
||||
break;
|
||||
}
|
||||
next = atoi(p);
|
||||
for (j = 0, ok = 0; j < link_num; j++)
|
||||
if (cave[arrow_location].tunnel[j] == next)
|
||||
ok = 1;
|
||||
|
||||
if (ok) {
|
||||
if (next > room_num) {
|
||||
(void)printf(
|
||||
"A faint gleam tells you the arrow has gone through a magic tunnel!\n");
|
||||
arrow_location = (random() % room_num) + 1;
|
||||
} else
|
||||
arrow_location = next;
|
||||
} else {
|
||||
link = (random() % link_num);
|
||||
if (link == player_loc)
|
||||
(void)printf(
|
||||
"*thunk* The arrow can't find a way from %d to %d and flys back into\n\
|
||||
your room!\n",
|
||||
arrow_location, next);
|
||||
else if (cave[arrow_location].tunnel[link] > room_num)
|
||||
(void)printf(
|
||||
"*thunk* The arrow flys randomly into a magic tunnel, thence into\n\
|
||||
room %d!\n",
|
||||
cave[arrow_location].tunnel[link]);
|
||||
else
|
||||
(void)printf(
|
||||
"*thunk* The arrow can't find a way from %d to %d and flys randomly\n\
|
||||
into room %d!\n",
|
||||
arrow_location, next,
|
||||
cave[arrow_location].tunnel[link]);
|
||||
arrow_location = cave[arrow_location].tunnel[link];
|
||||
break;
|
||||
}
|
||||
chance = random() % 10;
|
||||
if (roomcnt == 3 && chance < 2) {
|
||||
(void)printf(
|
||||
"Your bowstring breaks! *twaaaaaang*\n\
|
||||
The arrow is weakly shot and can go no further!\n");
|
||||
break;
|
||||
} else if (roomcnt == 4 && chance < 6) {
|
||||
(void)printf(
|
||||
"The arrow wavers in its flight and and can go no further!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* now we've gotten into the new room let us see if El Wumpo is
|
||||
* in the same room ... if so we've a HIT and the player WON!
|
||||
*/
|
||||
if (arrow_location == wumpus_loc) {
|
||||
kill_wump();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (arrow_location == player_loc) {
|
||||
shoot_self();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (!--arrows_left) {
|
||||
no_arrows();
|
||||
return(1);
|
||||
}
|
||||
|
||||
{
|
||||
/* each time you shoot, it's more likely the wumpus moves */
|
||||
static int lastchance = 2;
|
||||
|
||||
if (((random() % level == EASY ? 12 : 9) < (lastchance += 2))) {
|
||||
move_wump();
|
||||
if (wumpus_loc == player_loc)
|
||||
wump_kill();
|
||||
lastchance = random() % 3;
|
||||
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
gcd(a, b)
|
||||
int a, b;
|
||||
{
|
||||
int r;
|
||||
|
||||
r = a % b;
|
||||
if (r == 0)
|
||||
return (b);
|
||||
return (gcd(b, r));
|
||||
}
|
||||
|
||||
void
|
||||
cave_init()
|
||||
{
|
||||
int i, j, k, link;
|
||||
int delta;
|
||||
|
||||
/*
|
||||
* This does most of the interesting work in this program actually!
|
||||
* In this routine we'll initialize the Wumpus cave to have all rooms
|
||||
* linking to all others by stepping through our data structure once,
|
||||
* recording all forward links and backwards links too. The parallel
|
||||
* "linkcount" data structure ensures that no room ends up with more
|
||||
* than three links, regardless of the quality of the random number
|
||||
* generator that we're using.
|
||||
*/
|
||||
srandom((int)time((time_t *)0));
|
||||
|
||||
/* initialize the cave first off. */
|
||||
for (i = 1; i <= room_num; ++i)
|
||||
for (j = 0; j < link_num ; ++j)
|
||||
cave[i].tunnel[j] = -1;
|
||||
|
||||
/*
|
||||
* Choose a random 'hop' delta for our guaranteed link.
|
||||
* To keep the cave connected, we need the greatest common divisor
|
||||
* of (delta + 1) and room_num to be 1.
|
||||
*/
|
||||
do {
|
||||
delta = (random() % (room_num - 1)) + 1;
|
||||
} while (gcd(room_num, delta + 1) != 1);
|
||||
|
||||
for (i = 1; i <= room_num; ++i) {
|
||||
link = ((i + delta) % room_num) + 1; /* connection */
|
||||
cave[i].tunnel[0] = link; /* forw link */
|
||||
cave[link].tunnel[1] = i; /* back link */
|
||||
}
|
||||
/* now fill in the rest of the cave with random connections */
|
||||
for (i = 1; i <= room_num; i++)
|
||||
for (j = 2; j < link_num ; j++) {
|
||||
if (cave[i].tunnel[j] != -1)
|
||||
continue;
|
||||
try_again: link = (random() % room_num) + 1;
|
||||
/* skip duplicates */
|
||||
for (k = 0; k < j; k++)
|
||||
if (cave[i].tunnel[k] == link)
|
||||
goto try_again;
|
||||
cave[i].tunnel[j] = link;
|
||||
if (random() % 2 == 1)
|
||||
continue;
|
||||
for (k = 0; k < link_num; ++k) {
|
||||
/* if duplicate, skip it */
|
||||
if (cave[link].tunnel[k] == i)
|
||||
k = link_num;
|
||||
|
||||
/* if open link, use it, force exit */
|
||||
if (cave[link].tunnel[k] == -1) {
|
||||
cave[link].tunnel[k] = i;
|
||||
k = link_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* now that we're done, sort the tunnels in each of the rooms to
|
||||
* make it easier on the intrepid adventurer.
|
||||
*/
|
||||
for (i = 1; i <= room_num; ++i)
|
||||
qsort(cave[i].tunnel, (u_int)link_num,
|
||||
sizeof(cave[i].tunnel[0]), int_compare);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debug)
|
||||
for (i = 1; i <= room_num; ++i) {
|
||||
(void)printf("<room %d has tunnels to ", i);
|
||||
for (j = 0; j < link_num; ++j)
|
||||
(void)printf("%d ", cave[i].tunnel[j]);
|
||||
(void)printf(">\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
clear_things_in_cave()
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* remove bats and pits from the current cave in preparation for us
|
||||
* adding new ones via the initialize_things_in_cave() routines.
|
||||
*/
|
||||
for (i = 1; i <= room_num; ++i)
|
||||
cave[i].has_a_bat = cave[i].has_a_pit = 0;
|
||||
}
|
||||
|
||||
void
|
||||
initialize_things_in_cave()
|
||||
{
|
||||
int i, loc;
|
||||
|
||||
/* place some bats, pits, the wumpus, and the player. */
|
||||
for (i = 0; i < bat_num; ++i) {
|
||||
do {
|
||||
loc = (random() % room_num) + 1;
|
||||
} while (cave[loc].has_a_bat);
|
||||
cave[loc].has_a_bat = 1;
|
||||
#ifdef DEBUG
|
||||
if (debug)
|
||||
(void)printf("<bat in room %d>\n", loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < pit_num; ++i) {
|
||||
do {
|
||||
loc = (random() % room_num) + 1;
|
||||
} while (cave[loc].has_a_pit && cave[loc].has_a_bat);
|
||||
cave[loc].has_a_pit = 1;
|
||||
#ifdef DEBUG
|
||||
if (debug)
|
||||
(void)printf("<pit in room %d>\n", loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
wumpus_loc = (random() % room_num) + 1;
|
||||
#ifdef DEBUG
|
||||
if (debug)
|
||||
(void)printf("<wumpus in room %d>\n", loc);
|
||||
#endif
|
||||
|
||||
do {
|
||||
player_loc = (random() % room_num) + 1;
|
||||
} while (player_loc == wumpus_loc || (level == HARD ?
|
||||
(link_num / room_num < 0.4 ? wump_nearby() : 0) : 0));
|
||||
}
|
||||
|
||||
int
|
||||
getans(prompt)
|
||||
const char *prompt;
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
/*
|
||||
* simple routine to ask the yes/no question specified until the user
|
||||
* answers yes or no, then return 1 if they said 'yes' and 0 if they
|
||||
* answered 'no'.
|
||||
*/
|
||||
for (;;) {
|
||||
(void)printf("%s", prompt);
|
||||
(void)fflush(stdout);
|
||||
if (!fgets(buf, sizeof(buf), stdin))
|
||||
return(0);
|
||||
if (*buf == 'N' || *buf == 'n')
|
||||
return(0);
|
||||
if (*buf == 'Y' || *buf == 'y')
|
||||
return(1);
|
||||
(void)printf(
|
||||
"I don't understand your answer; please enter 'y' or 'n'!\n");
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
bats_nearby()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check for bats in the immediate vicinity */
|
||||
for (i = 0; i < link_num; ++i)
|
||||
if (cave[cave[player_loc].tunnel[i]].has_a_bat)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
pit_nearby()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check for pits in the immediate vicinity */
|
||||
for (i = 0; i < link_num; ++i)
|
||||
if (cave[cave[player_loc].tunnel[i]].has_a_pit)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
wump_nearby()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* check for a wumpus within TWO caves of where we are */
|
||||
for (i = 0; i < link_num; ++i) {
|
||||
if (cave[player_loc].tunnel[i] == wumpus_loc)
|
||||
return(1);
|
||||
for (j = 0; j < link_num; ++j)
|
||||
if (cave[cave[player_loc].tunnel[i]].tunnel[j] ==
|
||||
wumpus_loc)
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
move_wump()
|
||||
{
|
||||
wumpus_loc = cave[wumpus_loc].tunnel[random() % link_num];
|
||||
}
|
||||
|
||||
int
|
||||
int_compare(a, b)
|
||||
const void *a, *b;
|
||||
{
|
||||
return(*(const int *)a < *(const int *)b ? -1 : 1);
|
||||
}
|
||||
|
||||
char* instructionsStr = "Welcome to the game of Hunt the Wumpus.\n\nThe Wumpus typically lives in a cave of twenty rooms, with each room having\nthree tunnels connecting it to other rooms in the cavern. Caves may vary,\nhowever, depending on options specified when starting the game.\n\nThe game has the following hazards for intrepid adventurers to wind their\nway through:\n\n Pits -- If you fall into one of the bottomless pits, you find yourself\n\tslung back out on the far side of the Earth and in very poor\n\tshape to continue your quest since you're dead.\n\n Bats -- As with any other cave, the Wumpus cave has bats in residence.\n\tThese are a bit more potent, however, and if you stumble into\n\tone of their rooms they will rush up and carry you elsewhere in\n\tthe cave.\n \n Wumpus -- If you happen to walk into the room the Wumpus is in you'll find\n\tthat he has quite an appetite for young adventurous humans! Not\n\trecommended.\n\nThe Wumpus, by the way, is not bothered by the hazards since he has sucker\nfeet and is too big for a bat to lift. If you try to shoot him and miss,\nthere's also a chance that he'll up and move himself into another cave,\nthough by nature the Wumpus is a sedentary creature.\n\nEach turn you may either move or shoot a crooked arrow. Moving is done\nsimply by specifying \"m\" for move and the number of the room that you'd\nlike to move down a tunnel towards. Shooting is done similarly; indicate\nthat you'd like to shoot one of your magic arrows with an \"s\" for shoot,\nthen list a set of connected room numbers through which the deadly shaft\nshould fly!\n\nIf your path for the arrow is incorrect, however, it will flail about in\nthe room it can't understand and randomly pick a tunnel to continue\nthrough. You might just end up shooting yourself in the foot if you're\nnot careful! On the other hand, if you shoot the Wumpus you've WON!\n\nGood luck.";
|
||||
|
||||
void
|
||||
instructions()
|
||||
{
|
||||
if (!getans("Instructions? (y-n) "))
|
||||
return;
|
||||
|
||||
(void)printf(instructionsStr);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: wump [-h] [-a arrows] [-b bats] [-p pits] [-r rooms] [-t tunnels]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* messages */
|
||||
|
||||
void
|
||||
wump_kill()
|
||||
{
|
||||
(void)printf(
|
||||
"*ROAR* *chomp* *snurfle* *chomp*!\n\
|
||||
Much to the delight of the Wumpus, you walked right into his mouth,\n\
|
||||
making you one of the easiest dinners he's ever had! For you, however,\n\
|
||||
it's a rather unpleasant death. The only good thing is that it's been\n\
|
||||
so long since the evil Wumpus cleaned his teeth that you immediately\n\
|
||||
passed out from the stench!\n");
|
||||
}
|
||||
|
||||
void
|
||||
kill_wump()
|
||||
{
|
||||
(void)printf(
|
||||
"*thwock!* *groan* *crash*\n\n\
|
||||
A horrible roar fills the cave, and you realize, with a smile, that you\n\
|
||||
have slain the evil Wumpus and won the game! You don't want to tarry for\n\
|
||||
long, however, because not only is the Wumpus famous, but the stench of\n\
|
||||
dead Wumpus is also quite well known, a stench plenty enough to slay the\n\
|
||||
mightiest adventurer at a single whiff!!\n");
|
||||
}
|
||||
|
||||
void
|
||||
no_arrows()
|
||||
{
|
||||
(void)printf(
|
||||
"\nYou turn and look at your quiver, and realize with a sinking feeling\n\
|
||||
that you've just shot your last arrow (figuratively, too). Sensing this\n\
|
||||
with its psychic powers, the evil Wumpus rampagees through the cave, finds\n\
|
||||
you, and with a mighty *ROAR* eats you alive!\n");
|
||||
}
|
||||
|
||||
void
|
||||
shoot_self()
|
||||
{
|
||||
(void)printf(
|
||||
"\n*Thwack!* A sudden piercing feeling informs you that the ricochet\n\
|
||||
of your wild arrow has resulted in it wedging in your side, causing\n\
|
||||
extreme agony. The evil Wumpus, with its psychic powers, realizes this\n\
|
||||
and immediately rushes to your side, not to help, alas, but to EAT YOU!\n\
|
||||
(*CHOMP*)\n");
|
||||
}
|
||||
|
||||
void
|
||||
jump(where)
|
||||
int where;
|
||||
{
|
||||
(void)printf(
|
||||
"\nWith a jaunty step you enter the magic tunnel. As you do, you\n\
|
||||
notice that the walls are shimmering and glowing. Suddenly you feel\n\
|
||||
a very curious, warm sensation and find yourself in room %d!!\n", where);
|
||||
}
|
||||
|
||||
void
|
||||
pit_kill()
|
||||
{
|
||||
(void)printf(
|
||||
"*AAAUUUUGGGGGHHHHHhhhhhhhhhh...*\n\
|
||||
The whistling sound and updraft as you walked into this room of the\n\
|
||||
cave apparently wasn't enough to clue you in to the presence of the\n\
|
||||
bottomless pit. You have a lot of time to reflect on this error as\n\
|
||||
you fall many miles to the core of the earth. Look on the bright side;\n\
|
||||
you can at least find out if Jules Verne was right...\n");
|
||||
}
|
||||
|
||||
void
|
||||
pit_survive()
|
||||
{
|
||||
(void)printf(
|
||||
"Without conscious thought you grab for the side of the cave and manage\n\
|
||||
to grasp onto a rocky outcrop. Beneath your feet stretches the limitless\n\
|
||||
depths of a bottomless pit! Rock crumbles beneath your feet!\n");
|
||||
}
|
|
@ -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 {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue