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