mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
130fd66f9e | ||
|
|
8a44f913ae | ||
|
|
5488f0b2ca | ||
|
|
deff138e7e | ||
|
|
b6e40a3a58 | ||
|
|
8f6bc9dabc | ||
|
|
181cd4cbe8 | ||
|
|
5c6877b02b | ||
|
|
403bc25412 | ||
|
|
3bcd40be12 | ||
|
|
fcfdd26b72 | ||
|
|
2b00ee8723 | ||
|
|
ff2b6fc0b0 | ||
|
|
0eef971494 | ||
|
|
2bfd6b37c1 | ||
|
|
69db501c68 | ||
|
|
6e6fc38935 | ||
|
|
342d0c81e5 | ||
|
|
cec4c04aa1 | ||
|
|
f8c0186221 | ||
|
|
6992d8c195 | ||
|
|
1a6b4ab627 | ||
|
|
9e848abad9 | ||
|
|
223eb358c4 | ||
|
|
ea3cc4ea0b | ||
|
|
01267ea0f5 | ||
|
|
bc6c18368f | ||
|
|
06839ab301 | ||
|
|
39dde41516 | ||
|
|
3e16e59f72 | ||
|
|
cf9a1f7f33 | ||
|
|
49a32136f8 | ||
|
|
b9d6e6e348 | ||
|
|
b431ca4449 | ||
|
|
98d06b23cc | ||
|
|
9ff65cff63 | ||
|
|
bef2cb05ff | ||
|
|
43885a76e4 | ||
|
|
74a85087de | ||
|
|
045632a743 | ||
|
|
9a10adac35 | ||
|
|
0c12c26e1d | ||
|
|
40b7da8422 | ||
|
|
640668931d | ||
|
|
1c34088ba0 | ||
|
|
bb92347158 | ||
|
|
8bfd56b59e | ||
|
|
a6baba1b07 |
No files matched your search
@@ -6,6 +6,8 @@ AlignConsecutiveMacros: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
IncludeBlocks: Merge
|
||||
|
||||
@@ -21,23 +21,23 @@
|
||||
# make -j8 -O MODE=tiny
|
||||
#
|
||||
# # build individual target
|
||||
# make -j8 -O o//examples/hello.com
|
||||
# o//examples/hello.com
|
||||
# make -j8 -O o//examples/hello
|
||||
# o//examples/hello
|
||||
#
|
||||
# # view source
|
||||
# less examples/hello.c
|
||||
#
|
||||
# # view binary
|
||||
# o//tool/viz/bing.com o//examples/hello.com |
|
||||
# o//tool/viz/fold.com
|
||||
# o//tool/viz/bing o//examples/hello |
|
||||
# o//tool/viz/fold
|
||||
#
|
||||
# # view transitive closure of legalese
|
||||
# o//tool/viz/bing.com -n o//examples/hello.com |
|
||||
# o//tool/viz/fold.com
|
||||
# o//tool/viz/bing -n o//examples/hello |
|
||||
# o//tool/viz/fold
|
||||
#
|
||||
# # basic debugging
|
||||
# make -j8 -O MODE=dbg o/dbg/examples/crashreport.com
|
||||
# o/examples/crashreport.com
|
||||
# make -j8 -O MODE=dbg o/dbg/examples/crashreport
|
||||
# o/examples/crashreport
|
||||
# less examples/crashreport.c
|
||||
#
|
||||
# # extremely tiny binaries
|
||||
@@ -51,7 +51,7 @@
|
||||
#
|
||||
# TROUBLESHOOTING
|
||||
#
|
||||
# make -j8 -O V=1 o//examples/hello.com
|
||||
# make -j8 -O V=1 o//examples/hello
|
||||
# make o//examples/life.elf -pn |& less
|
||||
# etc.
|
||||
#
|
||||
@@ -59,7 +59,7 @@
|
||||
#
|
||||
# build/config.mk
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
SHELL = build/bootstrap/cocmd
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
@@ -77,8 +77,8 @@ COMMA := ,
|
||||
PWD := $(shell pwd)
|
||||
|
||||
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
|
||||
# - user ran build/bootstrap/make.com, in which case make's working directory is in wsl
|
||||
# - user ran make, in which case cocmd.com's working directory is in wsl
|
||||
# - user ran build/bootstrap/make, in which case make's working directory is in wsl
|
||||
# - user ran make, in which case cocmd's working directory is in wsl
|
||||
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
|
||||
$(warning wsl2 interop is enabled)
|
||||
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
|
||||
@@ -89,7 +89,7 @@ UNAME_S := $(shell uname -s)
|
||||
|
||||
# apple still distributes a 17 year old version of gnu make
|
||||
ifeq ($(MAKE_VERSION), 3.81)
|
||||
$(error please use build/bootstrap/make.com)
|
||||
$(error please use build/bootstrap/make)
|
||||
endif
|
||||
|
||||
LC_ALL = C
|
||||
@@ -101,21 +101,21 @@ XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
AR = build/bootstrap/ar.com
|
||||
CP = build/bootstrap/cp.com
|
||||
RM = build/bootstrap/rm.com -f
|
||||
GZIP = build/bootstrap/gzip.com
|
||||
ECHO = build/bootstrap/echo.com
|
||||
CHMOD = build/bootstrap/chmod.com
|
||||
TOUCH = build/bootstrap/touch.com
|
||||
PKG = build/bootstrap/package.com
|
||||
MKDEPS = build/bootstrap/mkdeps.com
|
||||
ZIPOBJ = build/bootstrap/zipobj.com
|
||||
ZIPCOPY = build/bootstrap/zipcopy.com
|
||||
PECHECK = build/bootstrap/pecheck.com
|
||||
FIXUPOBJ = build/bootstrap/fixupobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 -M2048m -P8192 $(QUOTA)
|
||||
AR = build/bootstrap/ar
|
||||
CP = build/bootstrap/cp
|
||||
RM = build/bootstrap/rm -f
|
||||
GZIP = build/bootstrap/gzip
|
||||
ECHO = build/bootstrap/echo
|
||||
CHMOD = build/bootstrap/chmod
|
||||
TOUCH = build/bootstrap/touch
|
||||
PKG = build/bootstrap/package
|
||||
MKDEPS = build/bootstrap/mkdeps
|
||||
ZIPOBJ = build/bootstrap/zipobj
|
||||
ZIPCOPY = build/bootstrap/zipcopy
|
||||
PECHECK = build/bootstrap/pecheck
|
||||
FIXUPOBJ = build/bootstrap/fixupobj
|
||||
MKDIR = build/bootstrap/mkdir -p
|
||||
COMPILE = build/bootstrap/compile -V9 -M2048m -P8192 $(QUOTA)
|
||||
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
@@ -133,7 +133,7 @@ endif
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi studio freebsdarm
|
||||
HOSTS ?= pi pi5 studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
|
||||
@@ -149,9 +149,9 @@ export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.3.2
|
||||
COSMOCC = .cosmocc/3.3.3
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.2 a695012ffbeac5e26e3c4a740debc15273f47e9a8bdc55e8b76a623154d5914b)
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.3 e4d0fa63cd79cc3bfff6c2d015f1776db081409907625aea8ad40cefc1996d08)
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
@@ -187,7 +187,7 @@ o/$(MODE): \
|
||||
o/$(MODE)/: o/$(MODE)
|
||||
o/$(MODE)/.: o/$(MODE)
|
||||
|
||||
# check if we're using o//third_party/make/make.com
|
||||
# check if we're using o//third_party/make/make
|
||||
# we added sandboxing to guarantee cosmo's makefile is hermetic
|
||||
# it also shaves away 200ms of startup latency with native $(uniq)
|
||||
ifneq ($(LANDLOCKMAKE_VERSION),)
|
||||
@@ -415,17 +415,17 @@ o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: private .UNSANDBOXED = 1
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags.com
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags
|
||||
@$(RM) $@
|
||||
@o/$(MODE)/third_party/ctags/ctags.com $(TAGSFLAGS) -L $< -o $@
|
||||
@o/$(MODE)/third_party/ctags/ctags $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: private .UNSANDBOXED = 1
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags.com
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags
|
||||
@$(RM) $@
|
||||
@build/htags o/$(MODE)/third_party/ctags/ctags.com -L $< -o $@
|
||||
@build/htags o/$(MODE)/third_party/ctags/ctags -L $< -o $@
|
||||
|
||||
loc: private .UNSANDBOXED = 1
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
loc: o/$(MODE)/tool/build/summy
|
||||
find -name \*.h -or -name \*.c -or -name \*.S | \
|
||||
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
|
||||
|
||||
@@ -550,16 +550,16 @@ o/cosmopolitan.h: o/cosmopolitan.h.txt \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
|
||||
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup.com @$< >>$@
|
||||
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup @$< >>$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg \
|
||||
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
|
||||
$(filter-out %.cpp,$(filter-out %.cc,$(SRCS))) \
|
||||
$(HDRS)
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cpp,$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg -J \
|
||||
-fno-common -include libc/integral/normalize.inc -o $@ \
|
||||
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
|
||||
|
||||
@@ -582,13 +582,13 @@ TOOLCHAIN_ARTIFACTS = \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a \
|
||||
o/$(MODE)/third_party/libcxx/libcxx.a \
|
||||
o/$(MODE)/tool/build/march-native.com \
|
||||
o/$(MODE)/tool/build/ar.com \
|
||||
o/$(MODE)/tool/build/mktemper.com \
|
||||
o/$(MODE)/tool/build/fixupobj.com \
|
||||
o/$(MODE)/tool/build/zipcopy.com \
|
||||
o/$(MODE)/tool/build/apelink.com \
|
||||
o/$(MODE)/tool/build/pecheck.com
|
||||
o/$(MODE)/tool/build/march-native \
|
||||
o/$(MODE)/tool/build/ar \
|
||||
o/$(MODE)/tool/build/mktemper \
|
||||
o/$(MODE)/tool/build/fixupobj \
|
||||
o/$(MODE)/tool/build/zipcopy \
|
||||
o/$(MODE)/tool/build/apelink \
|
||||
o/$(MODE)/tool/build/pecheck
|
||||
else
|
||||
TOOLCHAIN_ARTIFACTS = \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
@@ -596,9 +596,9 @@ TOOLCHAIN_ARTIFACTS = \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/cosmopolitan.a \
|
||||
o/$(MODE)/third_party/libcxx/libcxx.a \
|
||||
o/$(MODE)/tool/build/march-native.com \
|
||||
o/$(MODE)/tool/build/fixupobj.com \
|
||||
o/$(MODE)/tool/build/zipcopy.com
|
||||
o/$(MODE)/tool/build/march-native \
|
||||
o/$(MODE)/tool/build/fixupobj \
|
||||
o/$(MODE)/tool/build/zipcopy
|
||||
endif
|
||||
|
||||
.PHONY: toolchain
|
||||
|
||||
@@ -92,8 +92,8 @@ guaranteed to be compatible and furthermore includes our extensions for
|
||||
doing build system sandboxing.
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j8
|
||||
o//examples/hello.com
|
||||
build/bootstrap/make -j8
|
||||
o//examples/hello
|
||||
```
|
||||
|
||||
Since the Cosmopolitan repository is very large, you might only want to
|
||||
@@ -103,8 +103,8 @@ depends on core LIBC packages.
|
||||
|
||||
```sh
|
||||
rm -rf o//libc o//test
|
||||
build/bootstrap/make.com o//test/posix/signal_test.com
|
||||
o//test/posix/signal_test.com
|
||||
build/bootstrap/make o//test/posix/signal_test
|
||||
o//test/posix/signal_test
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
@@ -112,21 +112,21 @@ list out each individual one. For example if you wanted to build and run
|
||||
all the unit tests in the `TEST_POSIX` package, you could say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com o//test/posix
|
||||
build/bootstrap/make o//test/posix
|
||||
```
|
||||
|
||||
Cosmopolitan provides a variety of build modes. For example, if you want
|
||||
really tiny binaries (as small as 12kb in size) then you'd say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com m=tiny
|
||||
build/bootstrap/make m=tiny
|
||||
```
|
||||
|
||||
You can furthermore cut out the bloat of other operating systems, and
|
||||
have Cosmopolitan become much more similar to Musl Libc.
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com m=tinylinux
|
||||
build/bootstrap/make m=tinylinux
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
@@ -179,11 +179,11 @@ end
|
||||
src
|
||||
```
|
||||
|
||||
You normally run the `.com.dbg` file under gdb. If you need to debug the
|
||||
`.com` file itself, then you can load the debug symbols independently as
|
||||
You normally run the `.dbg` file under gdb. If you need to debug the
|
||||
`` file itself, then you can load the debug symbols independently as
|
||||
|
||||
```sh
|
||||
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
gdb foo -ex 'add-symbol-file foo.dbg 0x401000'
|
||||
```
|
||||
|
||||
## Platform Notes
|
||||
@@ -242,16 +242,16 @@ server. You're welcome to join us! <https://discord.gg/FwAVVu7eJ4>
|
||||
|
||||
## Support Vector
|
||||
|
||||
| Platform | Min Version | Circa |
|
||||
| :--- | ---: | ---: |
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| OpenBSD | 7 | 2021 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
| Platform | Min Version | Circa |
|
||||
| :--- | ---: | ---: |
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Darwin (macOS) | 23.1.0+ | 2023 |
|
||||
| OpenBSD | 7 | 2021 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
|
||||
for a community supported version of Cosmopolitan that works on Windows
|
||||
|
||||
+2
-2
@@ -220,10 +220,10 @@ o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=8 -S -g0 $(APE_LOADER_FLAGS)
|
||||
|
||||
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy.com -f -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy -f -o $@ $<
|
||||
|
||||
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy.com -fm -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy -fm -o $@ $<
|
||||
|
||||
APE_LOADER_LDFLAGS = \
|
||||
-static \
|
||||
|
||||
+74
-28
@@ -31,6 +31,8 @@
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -39,7 +41,7 @@
|
||||
/* maximum path size that cosmo can take */
|
||||
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
|
||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||
#define SYSLIB_VERSION 9 /* sync with libc/runtime/syslib.internal.h */
|
||||
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
|
||||
|
||||
struct Syslib {
|
||||
int magic;
|
||||
@@ -106,6 +108,10 @@ struct Syslib {
|
||||
OPTIONAL (cosmo lib should check __syslib->version) */
|
||||
/* v9 (2024-01-31) */
|
||||
int (*pthread_cpu_number_np)(size_t *);
|
||||
/* v10 (2024-05-02) */
|
||||
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
|
||||
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
|
||||
long (*sysctlnametomib)(const char *, int *, size_t *);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
@@ -148,8 +154,8 @@ struct Syslib {
|
||||
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
|
||||
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
|
||||
|
||||
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
@@ -221,13 +227,15 @@ struct ApeLoader {
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
@@ -276,7 +284,8 @@ static char *Utoa(char p[21], unsigned long x) {
|
||||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
@@ -312,7 +321,8 @@ static int GetIndirectOffset(const char *arg0) {
|
||||
static void Perror(const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
|
||||
ibuf, "\n", 0l);
|
||||
}
|
||||
@@ -327,7 +337,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
|
||||
return 0;
|
||||
}
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !access(ps->path, X_OK);
|
||||
@@ -377,8 +388,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
|
||||
const char *syspath) {
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
ps->name = name;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
|
||||
return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (FindCommand(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
@@ -545,6 +558,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
|
||||
return sysret(sysctlnametomib(name, mibp, sizep));
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
long *sp, struct ElfEhdr *e,
|
||||
struct ElfPhdr *p,
|
||||
@@ -585,10 +612,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
a = p[i].p_vaddr & -pagesz;
|
||||
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
if (Max(a, c) < Min(b, d)) {
|
||||
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
|
||||
}
|
||||
}
|
||||
@@ -614,7 +642,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
if (e->e_type == ET_DYN) {
|
||||
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
@@ -630,14 +659,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
@@ -657,7 +690,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
wipe = MIN(b - a, c - a);
|
||||
wipe = Min(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
@@ -687,24 +720,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
as the default strategy which is slow but it works for both */
|
||||
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap anon");
|
||||
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
|
||||
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
|
||||
if (rc != p[i].p_filesz)
|
||||
Pexit(exe, -errno, "prog pread");
|
||||
#endif
|
||||
} else {
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap");
|
||||
}
|
||||
if (wipe) memset((void *)(dynbase + a), 0, wipe);
|
||||
if (wipe)
|
||||
memset((void *)(dynbase + a), 0, wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = sys_mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
@@ -712,7 +751,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,8 +830,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
|
||||
/* read program headers */
|
||||
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
@@ -948,6 +990,9 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.dlclose = dlclose;
|
||||
M->lib.dlerror = dlerror;
|
||||
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
|
||||
M->lib.sysctl = sys_sysctl;
|
||||
M->lib.sysctlbyname = sys_sysctlbyname;
|
||||
M->lib.sysctlnametomib = sys_sysctlnametomib;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = 0;
|
||||
@@ -970,7 +1015,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ -x build/bootstrap/make.com ]; then
|
||||
MAKE=build/bootstrap/make.com
|
||||
if [ -x build/bootstrap/make ]; then
|
||||
MAKE=build/bootstrap/make
|
||||
else
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Apple Mach-O Executable Headers
|
||||
// Fixups are applied by objbincopy.com
|
||||
// Fixups are applied by objbincopy
|
||||
// There must exist a MAC_LC_SEGMENT_64 for every PT_LOAD
|
||||
|
||||
.section .macho,"a",@progbits
|
||||
|
||||
+60
-30
@@ -228,13 +228,15 @@ extern char _end[];
|
||||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
@@ -353,7 +355,8 @@ static char *Utoa(char p[20], unsigned long x) {
|
||||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
@@ -362,7 +365,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
|
||||
long arg5, long arg6,
|
||||
long arg7, int numba,
|
||||
char os) {
|
||||
if (IsXnu()) numba |= 0x2000000;
|
||||
if (IsXnu())
|
||||
numba |= 0x2000000;
|
||||
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
|
||||
}
|
||||
|
||||
@@ -529,7 +533,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
switch ((c = *fmt++)) {
|
||||
case 's':
|
||||
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
|
||||
if (k < 512) b[k++] = *s;
|
||||
if (k < 512)
|
||||
b[k++] = *s;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
@@ -542,16 +547,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
u -= 10;
|
||||
c = 'a' + u;
|
||||
}
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (k < 512) b[k++] = c;
|
||||
if (k < 512)
|
||||
b[k++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -560,7 +568,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
|
||||
static void Perror(int os, const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(os, 2, "ape error: ", thing, ": ", reason,
|
||||
rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
|
||||
}
|
||||
@@ -572,8 +581,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
|
||||
}
|
||||
|
||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
MemMove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !Access(ps->path, X_OK, ps->os);
|
||||
@@ -600,11 +611,14 @@ static char SearchPath(struct PathSearcher *ps) {
|
||||
|
||||
static char *Commandv(struct PathSearcher *ps, int os, char *name,
|
||||
const char *syspath) {
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
|
||||
if (!(ps->namelen = StrLen((ps->name = name))))
|
||||
return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
|
||||
return name;
|
||||
ps->os = os;
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
ps->path[0] = 0;
|
||||
if (SearchPath(ps)) {
|
||||
return ps->path;
|
||||
@@ -661,7 +675,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
Pexit(os, exe, 0, "ELF segments overlap your APE loader");
|
||||
}
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
@@ -694,7 +709,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
if (e->e_type == ET_DYN) {
|
||||
rc = Mmap(0, virtmax - virtmin, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
@@ -710,14 +726,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
if (p[i].p_filesz) {
|
||||
/* load from file */
|
||||
@@ -744,17 +764,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mmap");
|
||||
if (wipe)
|
||||
Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = Mprotect(addr, size, prot2, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
@@ -762,7 +786,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap(addr, size, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(os, exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +808,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
struct ElfPhdr *p;
|
||||
|
||||
/* validate page size */
|
||||
if (!pagesz) pagesz = 4096;
|
||||
if (!pagesz)
|
||||
pagesz = 4096;
|
||||
if (pagesz & (pagesz - 1)) {
|
||||
Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
|
||||
}
|
||||
@@ -818,8 +844,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
|
||||
/* read program headers */
|
||||
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
@@ -949,7 +977,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
|
||||
/* determine ape loader program name */
|
||||
ape = argv[0];
|
||||
if (!ape) ape = "ape";
|
||||
if (!ape)
|
||||
ape = "ape";
|
||||
|
||||
/* detect openbsd */
|
||||
if (SupportsOpenbsd() && !os && !auxv[0]) {
|
||||
@@ -1021,7 +1050,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (endp - sp + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -127,6 +127,7 @@ ifeq ($(ARCH), aarch64)
|
||||
DEFAULT_COPTS += \
|
||||
-ffixed-x18 \
|
||||
-ffixed-x28 \
|
||||
-fsigned-char \
|
||||
-mno-outline-atomics
|
||||
endif
|
||||
|
||||
|
||||
+8
-8
@@ -22,14 +22,14 @@
|
||||
# - tool/build/runit.c
|
||||
# - tool/build/runitd.c
|
||||
|
||||
.PRECIOUS: o/$(MODE)/%.com.ok
|
||||
o/$(MODE)/%.com.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet dns
|
||||
o/$(MODE)/%.com.ok: private .UNVEIL += r:/etc/resolv.conf
|
||||
o/$(MODE)/%.com.ok: \
|
||||
o/$(MODE)/tool/build/runit.com \
|
||||
o/$(MODE)/tool/build/runitd.com \
|
||||
o/$(MODE)/%.com
|
||||
.PRECIOUS: o/$(MODE)/%.ok
|
||||
o/$(MODE)/%.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet dns
|
||||
o/$(MODE)/%.ok: private .UNVEIL += r:/etc/resolv.conf
|
||||
o/$(MODE)/%.ok: \
|
||||
o/$(MODE)/tool/build/runit \
|
||||
o/$(MODE)/tool/build/runitd \
|
||||
o/$(MODE)/%
|
||||
@$(COMPILE) -wATEST -tT$@ $^ $(HOSTS)
|
||||
|
||||
.PHONY:
|
||||
o/tiny/tool/build/runit.com:
|
||||
o/tiny/tool/build/runit:
|
||||
+14
-31
@@ -79,17 +79,17 @@ o/$(MODE)/%.pkg:
|
||||
$(file >$(TMPSAFE).args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
|
||||
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj
|
||||
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj $(PYFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp.com
|
||||
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp.com $(PYCFLAGS) -o $@ $<
|
||||
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp
|
||||
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp $(PYCFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac.com
|
||||
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac.com -s -o $@ $<
|
||||
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac
|
||||
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac -s -o $@ $<
|
||||
|
||||
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
|
||||
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean.com $(LUAFLAGS) -i $<
|
||||
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean
|
||||
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean $(LUAFLAGS) -i $<
|
||||
|
||||
################################################################################
|
||||
# LOCAL UNIT TESTS
|
||||
@@ -108,22 +108,22 @@ o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
|
||||
#
|
||||
# You could then run a command like:
|
||||
#
|
||||
# make -j8 o//test/libc/calls/openbsd_test.com.runs
|
||||
# make -j8 o//test/libc/calls/openbsd_test.runs
|
||||
#
|
||||
# You need PROT_EXEC permission since ftrace morphs the binary. It's
|
||||
# also worth mentioning that the pledge.com command can simulate what
|
||||
# also worth mentioning that the pledge command can simulate what
|
||||
# Landlock Make does:
|
||||
#
|
||||
# o//tool/build/pledge.com \
|
||||
# o//tool/build/pledge \
|
||||
# -v. -p 'stdio rpath wpath cpath tty prot_exec' \
|
||||
# o//test/libc/calls/openbsd_test.com \
|
||||
# o//test/libc/calls/openbsd_test \
|
||||
# ----ftrace
|
||||
#
|
||||
# This is useful in the event a test binary should run by itself, but
|
||||
# fails to run beneath Landlock Make. It's also useful sometimes to
|
||||
# override the verbosity when running tests:
|
||||
#
|
||||
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.com.runs
|
||||
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.runs
|
||||
#
|
||||
# This way, if for some reason a test should fail but calls exit(0),
|
||||
# then the stdout/stderr output, which would normally be suppressed,
|
||||
@@ -135,7 +135,7 @@ o/$(MODE)/%.runs: o/$(MODE)/%
|
||||
################################################################################
|
||||
# ELF ZIP FILES
|
||||
#
|
||||
# zipobj.com lets us do fast incremental linking of compressed data.
|
||||
# zipobj lets us do fast incremental linking of compressed data.
|
||||
# it's nice because if we link a hundred binaries that use the time zone
|
||||
# database, then that database only needs to be DEFLATE'd once.
|
||||
|
||||
@@ -183,23 +183,6 @@ o/$(MODE)/%.okk: private .UNSANDBOXED = 1
|
||||
o/$(MODE)/%.okk: %
|
||||
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
|
||||
################################################################################
|
||||
# EXECUTABLE HELPERS
|
||||
|
||||
MAKE_SYMTAB_CREATE = \
|
||||
$(COMPILE) -wASYMTAB \
|
||||
o/$(MODE)/tool/build/symtab.com \
|
||||
-o $(TMPSAFE)/.symtab \
|
||||
$<
|
||||
|
||||
MAKE_SYMTAB_ZIP = \
|
||||
$(COMPILE) -AZIP -T$@ \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
-b$(TMPDIR) \
|
||||
-9qj \
|
||||
$@ \
|
||||
$(TMPSAFE)/.symtab
|
||||
|
||||
################################################################################
|
||||
# EMACS ASSEMBLY GENERATION
|
||||
|
||||
|
||||
+24
-12
@@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
|
||||
}
|
||||
|
||||
static char *FormatInt32(char *p, int32_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(uint32_t)x;
|
||||
return FormatUint32(p, x);
|
||||
}
|
||||
|
||||
@@ -205,7 +206,8 @@ static size_t StrCat(char *dst, const char *src, size_t dsize) {
|
||||
size_t m, n = dsize;
|
||||
const char *p = dst;
|
||||
const char *q = src;
|
||||
while (n-- != 0 && *dst != '\0') dst++;
|
||||
while (n-- != 0 && *dst != '\0')
|
||||
dst++;
|
||||
m = dst - p;
|
||||
n = dsize - m;
|
||||
if (n-- == 0) {
|
||||
@@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
|
||||
for (i = 0;; ++i) {
|
||||
switch (path[i]) {
|
||||
case 0:
|
||||
if (i) return true;
|
||||
if (i)
|
||||
return true;
|
||||
// fallthrough
|
||||
case '\r':
|
||||
case '\n':
|
||||
@@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
|
||||
char hexdigest[65];
|
||||
char mode[2] = {g_mode};
|
||||
unsigned char digest[32];
|
||||
if (!IsSupportedPath(path)) return false;
|
||||
if (!GetDigest(path, f, digest)) return false;
|
||||
if (!IsSupportedPath(path))
|
||||
return false;
|
||||
if (!GetDigest(path, f, digest))
|
||||
return false;
|
||||
CopyHex(hexdigest, digest, 32);
|
||||
Write(1, hexdigest, " ", mode, path, "\n", NULL);
|
||||
return true;
|
||||
@@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
|
||||
uint8_t wantdigest[32], gotdigest[32];
|
||||
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
|
||||
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
|
||||
if (!*Chomp(buf)) continue;
|
||||
if (!*Chomp(buf))
|
||||
continue;
|
||||
for (p = buf, i = 0; i < 32; ++i) {
|
||||
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
if ((a = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1)
|
||||
goto InvalidLine;
|
||||
wantdigest[i] = a << 4 | b;
|
||||
}
|
||||
if (*p++ != ' ') goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++)) goto InvalidLine;
|
||||
if (*p++ != ' ')
|
||||
goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++))
|
||||
goto InvalidLine;
|
||||
path2 = p;
|
||||
if (!*path2) goto InvalidLine;
|
||||
if (!IsSupportedPath(path2)) continue;
|
||||
if (!*path2)
|
||||
goto InvalidLine;
|
||||
if (!IsSupportedPath(path2))
|
||||
continue;
|
||||
if ((f2 = fopen(path2, "rb"))) {
|
||||
if (GetDigest(path2, f2, gotdigest)) {
|
||||
if (!memcmp(wantdigest, gotdigest, 32)) {
|
||||
|
||||
+4
-2
@@ -27,7 +27,8 @@
|
||||
*/
|
||||
int alaw(int x) {
|
||||
int a, b, i;
|
||||
if ((a = x) < 0) a = ~a;
|
||||
if ((a = x) < 0)
|
||||
a = ~a;
|
||||
a >>= 4;
|
||||
if (a > 15) {
|
||||
if ((i = a >> 5)) {
|
||||
@@ -40,6 +41,7 @@ int alaw(int x) {
|
||||
a += 16;
|
||||
}
|
||||
}
|
||||
if (x >= 0) a |= 128;
|
||||
if (x >= 0)
|
||||
a |= 128;
|
||||
return a ^ 85;
|
||||
}
|
||||
+4
-2
@@ -28,13 +28,15 @@
|
||||
int mulaw(int x) {
|
||||
int b, i, a, s, l, h;
|
||||
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
|
||||
if (a > 8191) a = 8191;
|
||||
if (a > 8191)
|
||||
a = 8191;
|
||||
i = a >> 6;
|
||||
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
|
||||
h = 8 - s;
|
||||
l = (a >> s) & 15;
|
||||
l = 15 - l;
|
||||
b = (h << 4) | l;
|
||||
if (x >= 0) b |= 128;
|
||||
if (x >= 0)
|
||||
b |= 128;
|
||||
return b;
|
||||
}
|
||||
@@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
||||
/* TODO(jart): This isn't acceptable. */
|
||||
size_t i, j;
|
||||
if (p > 0) {
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] =
|
||||
@@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
||||
}
|
||||
} else if (p < 0) {
|
||||
p = -p;
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] = pcm[i][j] >> p;
|
||||
|
||||
+4
-2
@@ -31,8 +31,10 @@ int unalaw(int x) {
|
||||
i = (x ^ 85) & 127;
|
||||
e = i >> 4;
|
||||
m = i & 15;
|
||||
if (e > 0) m += 16;
|
||||
if (e > 0)
|
||||
m += 16;
|
||||
m = (m << 4) + 8;
|
||||
if (e > 1) m = m << (e - 1);
|
||||
if (e > 1)
|
||||
m = m << (e - 1);
|
||||
return x & 128 ? m : -m;
|
||||
}
|
||||
@@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
|
||||
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
|
||||
di = (self->mb_row * dw + self->mb_col) * BW;
|
||||
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
|
||||
if (si > max_address || di > max_address) return;
|
||||
if (si > max_address || di > max_address)
|
||||
return;
|
||||
d += di;
|
||||
s += si;
|
||||
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
|
||||
|
||||
+12
-7
@@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
|
||||
static bool IsNormalized(int n, double A[n]) {
|
||||
int i;
|
||||
double x;
|
||||
for (x = i = 0; i < n; ++i) x += A[i];
|
||||
for (x = i = 0; i < n; ++i)
|
||||
x += A[i];
|
||||
return fabs(x - 1) < 1e-4;
|
||||
}
|
||||
|
||||
@@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
||||
short *weights, *indices;
|
||||
struct SamplingSolution *res;
|
||||
long j, i, k, n, min, max, s, N[6];
|
||||
if (!dar) dar = sn, dar /= dn;
|
||||
if (!off) off = (dar - 1) / 2;
|
||||
if (!dar)
|
||||
dar = sn, dar /= dn;
|
||||
if (!off)
|
||||
off = (dar - 1) / 2;
|
||||
f = dar < 1 ? 1 / dar : dar;
|
||||
s = 3 * f + 4;
|
||||
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
|
||||
@@ -114,8 +117,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
||||
for (k = 0, j = min; j <= max; ++j) {
|
||||
fweights[k++] = ComputeWeight((j - x) / (f / par));
|
||||
}
|
||||
for (sum = k = 0; k < n; ++k) sum += fweights[k];
|
||||
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum;
|
||||
for (sum = k = 0; k < n; ++k)
|
||||
sum += fweights[k];
|
||||
for (j = 0; j < n; ++j)
|
||||
fweights[j] *= 1 / sum;
|
||||
DCHECK(IsNormalized(n, fweights));
|
||||
for (j = 0; j < n; ++j) {
|
||||
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));
|
||||
@@ -202,8 +207,8 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
|
||||
CHECK_LE(sxn, sxw);
|
||||
CHECK_LE(dyn, dyw);
|
||||
CHECK_LE(dxn, dxw);
|
||||
CHECK_LT(_bsrl(syn) + _bsrl(sxn), 32);
|
||||
CHECK_LT(_bsrl(dyn) + _bsrl(dxn), 32);
|
||||
CHECK_LT(bsrl(syn) + bsrl(sxn), 32);
|
||||
CHECK_LT(bsrl(dyn) + bsrl(dxn), 32);
|
||||
CHECK_LE(dyw, 0x7fff);
|
||||
CHECK_LE(dxw, 0x7fff);
|
||||
CHECK_LE(syw, 0x7fff);
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (__nocolor) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (__nocolor)
|
||||
return 0;
|
||||
if (visible)
|
||||
code[5] = 'h';
|
||||
if (IsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
ntcursor.bVisible = visible;
|
||||
|
||||
+8
-4
@@ -21,16 +21,20 @@
|
||||
#include "libc/limits.h"
|
||||
|
||||
static char *ansitoa(char *p, unsigned xt, unsigned base) {
|
||||
if (xt >= 8) xt -= 8, base += 60;
|
||||
if (xt >= 8)
|
||||
xt -= 8, base += 60;
|
||||
return itoa8(p, xt + base);
|
||||
}
|
||||
|
||||
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
if (bg != -1u) p = ansitoa(p, bg, 40);
|
||||
if (bg != -1u && fg != -1u) *p++ = ';';
|
||||
if (fg != -1u) p = ansitoa(p, fg, 30);
|
||||
if (bg != -1u)
|
||||
p = ansitoa(p, bg, 40);
|
||||
if (bg != -1u && fg != -1u)
|
||||
*p++ = ';';
|
||||
if (fg != -1u)
|
||||
p = ansitoa(p, fg, 30);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
+4
-2
@@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
|
||||
struct Glyph *glyph) {
|
||||
unsigned i;
|
||||
CHECK_LT(pick.bg, 4);
|
||||
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4);
|
||||
if (pick.fg != 0xff)
|
||||
CHECK_LT(pick.fg, 4);
|
||||
i = 0;
|
||||
if (pick.fg == 0xff) {
|
||||
if (!ttyeq(*bg, chunk[pick.bg])) {
|
||||
@@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
|
||||
v = CopyGlyph(v, *glyph);
|
||||
*x += 2;
|
||||
*c += 2;
|
||||
if (*x >= n) break;
|
||||
if (*x >= n)
|
||||
break;
|
||||
CopyChunk(chunk, *c, n);
|
||||
} while (ChunkEq(chunk, lastchunk));
|
||||
*x -= 2;
|
||||
|
||||
+8
-4
@@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
|
||||
}
|
||||
|
||||
static textstartup void ttyraw_hidecursor(void) {
|
||||
if (!g_ttyraw.setup) return;
|
||||
if (g_ttyraw.flags & kTtyCursor) return;
|
||||
if (!g_ttyraw.setup)
|
||||
return;
|
||||
if (g_ttyraw.flags & kTtyCursor)
|
||||
return;
|
||||
ttyhidecursor(FD);
|
||||
}
|
||||
|
||||
static textexit int ttyraw_disable(void) {
|
||||
if (!g_ttyraw.setup) return 0;
|
||||
if (!g_ttyraw.setup)
|
||||
return 0;
|
||||
ttyshowcursor(FD);
|
||||
return ttyrestore(FD, &g_ttyraw.old);
|
||||
}
|
||||
@@ -87,7 +90,8 @@ static textexit void ttyraw_onexit(void) {
|
||||
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
|
||||
struct ucontext *ctx) {
|
||||
size_t i;
|
||||
if (g_ttyraw.noreentry) _Exit(128 + sig);
|
||||
if (g_ttyraw.noreentry)
|
||||
_Exit(128 + sig);
|
||||
g_ttyraw.noreentry = true;
|
||||
if (g_ttyraw.flags != -1) {
|
||||
if (sig == SIGCONT) {
|
||||
|
||||
+103
-103
@@ -14,130 +14,130 @@ EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
||||
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
||||
EXAMPLES_MAINS_CC = $(filter %.cc,$(EXAMPLES_FILES))
|
||||
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.com)
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%)
|
||||
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
$(EXAMPLES_COMS:%=%.dbg)
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_CALLS \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_IRQ \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_VGA \
|
||||
LIBC_X \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_AWK \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_HIREDIS \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LINENOISE \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_SED \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_TR \
|
||||
THIRD_PARTY_VQSORT \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_ARGS \
|
||||
TOOL_BUILD_LIB \
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_CALLS \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_IRQ \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_VGA \
|
||||
LIBC_X \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_AWK \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_HIREDIS \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LINENOISE \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_SED \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_TR \
|
||||
THIRD_PARTY_VQSORT \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_ARGS \
|
||||
TOOL_BUILD_LIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
EXAMPLES_DEPS := \
|
||||
$(call uniq,$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/examples/unbourne.o: private \
|
||||
CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED \
|
||||
o/$(MODE)/examples/unbourne.o: private \
|
||||
CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED \
|
||||
-fpie
|
||||
|
||||
o/$(MODE)/examples/%.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
o/$(MODE)/examples/%.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/hellolua.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/hellolua.o \
|
||||
o/$(MODE)/examples/hellolua.lua.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
o/$(MODE)/examples/hellolua.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/hellolua.o \
|
||||
o/$(MODE)/examples/hellolua.lua.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
o/$(MODE)/examples/ispell.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/nesemu1.o \
|
||||
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
o/$(MODE)/examples/nesemu1.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/nesemu1.o \
|
||||
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
@@ -145,7 +145,7 @@ o/$(MODE)/examples/picol.o: private \
|
||||
CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
o/$(MODE)/examples/picol.com.dbg: \
|
||||
o/$(MODE)/examples/picol.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/picol.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
@@ -166,8 +166,8 @@ o/$(MODE)/usr/share/dict/words: \
|
||||
################################################################################
|
||||
|
||||
.PHONY: o/$(MODE)/examples
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
o/$(MODE)/examples/pylife \
|
||||
o/$(MODE)/examples/pyapp \
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
o/$(MODE)/examples/pylife \
|
||||
o/$(MODE)/examples/pyapp \
|
||||
$(EXAMPLES_BINS)
|
||||
+14
-7
@@ -104,8 +104,10 @@ void *Worker(void *id) {
|
||||
if (client == -1) {
|
||||
// accept() errors are generally ephemeral or recoverable
|
||||
// it'd potentially be a good idea to exponential backoff here
|
||||
if (errno == ECANCELED) continue; // pthread_cancel() was called
|
||||
if (errno == EMFILE) ExplainPrlimit();
|
||||
if (errno == ECANCELED)
|
||||
continue; // pthread_cancel() was called
|
||||
if (errno == EMFILE)
|
||||
ExplainPrlimit();
|
||||
LOG("accept() returned %m");
|
||||
SomethingHappened();
|
||||
continue;
|
||||
@@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
|
||||
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
|
||||
--a_workers;
|
||||
kprintf("pthread_create failed: %s\n", strerror(rc));
|
||||
if (rc == EAGAIN) ExplainPrlimit();
|
||||
if (!i) exit(1);
|
||||
if (rc == EAGAIN)
|
||||
ExplainPrlimit();
|
||||
if (!i)
|
||||
exit(1);
|
||||
threads = i;
|
||||
break;
|
||||
}
|
||||
@@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
|
||||
PrintEphemeralStatusLine();
|
||||
unassert(!pthread_cond_wait(&statuscond, &statuslock));
|
||||
// limit status line updates to sixty frames per second
|
||||
do tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
|
||||
do
|
||||
tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
|
||||
while (timespec_cmp(tick, timespec_real()) < 0);
|
||||
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0);
|
||||
}
|
||||
@@ -378,7 +383,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// on windows this is the only way accept() can be canceled
|
||||
if (IsWindows()) close(server);
|
||||
if (IsWindows())
|
||||
close(server);
|
||||
|
||||
// print status in terminal as the shutdown progresses
|
||||
unassert(!pthread_mutex_lock(&statuslock));
|
||||
@@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// close the server socket
|
||||
if (!IsWindows()) close(server);
|
||||
if (!IsWindows())
|
||||
close(server);
|
||||
|
||||
// clean up terminal line
|
||||
LOG("thank you for choosing \e[32mgreenbean\e[0m");
|
||||
|
||||
+92
-46
@@ -212,10 +212,13 @@ void editorAtExit(void) {
|
||||
int enableRawMode(int64_t fd) {
|
||||
struct termios raw;
|
||||
|
||||
if (E.rawmode) return 0; /* Already enabled. */
|
||||
if (!isatty(STDIN_FILENO)) goto fatal;
|
||||
if (E.rawmode)
|
||||
return 0; /* Already enabled. */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
goto fatal;
|
||||
atexit(editorAtExit);
|
||||
if (tcgetattr(fd, &orig_termios) == -1) goto fatal;
|
||||
if (tcgetattr(fd, &orig_termios) == -1)
|
||||
goto fatal;
|
||||
|
||||
raw = orig_termios; /* modify the original mode */
|
||||
/* input modes: no break, no CR to NL, no parity check, no strip char,
|
||||
@@ -233,7 +236,8 @@ int enableRawMode(int64_t fd) {
|
||||
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
|
||||
|
||||
/* put terminal in raw mode after flushing */
|
||||
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal;
|
||||
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
|
||||
goto fatal;
|
||||
E.rawmode = 1;
|
||||
return 0;
|
||||
|
||||
@@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
|
||||
char c, seq[3];
|
||||
do {
|
||||
nread = read(fd, &c, 1);
|
||||
if (nread == -1) exit(1);
|
||||
if (nread == -1)
|
||||
exit(1);
|
||||
} while (!nread);
|
||||
|
||||
while (1) {
|
||||
@@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
|
||||
return PAGE_DOWN;
|
||||
case '\e': /* escape sequence */
|
||||
/* If this is just an ESC, we'll timeout here. */
|
||||
if (read(fd, seq, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[0] == '[') {
|
||||
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 1, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||
/* Extended escape, read additional byte. */
|
||||
if (read(fd, seq + 2, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 2, 1) == 0)
|
||||
return CTRL('[');
|
||||
if (seq[2] == '~') {
|
||||
switch (seq[1]) {
|
||||
case '1':
|
||||
@@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
|
||||
} else if (seq[0] == 'v') {
|
||||
return PAGE_UP;
|
||||
} else if (seq[0] == 'O') {
|
||||
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
|
||||
if (read(fd, seq + 1, 1) == 0)
|
||||
return CTRL('[');
|
||||
/* ESC O sequences. */
|
||||
switch (seq[1]) {
|
||||
case 'H':
|
||||
@@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
unsigned i = 0;
|
||||
|
||||
/* Report cursor location */
|
||||
if (write(ofd, "\e[6n", 4) != 4) return -1;
|
||||
if (write(ofd, "\e[6n", 4) != 4)
|
||||
return -1;
|
||||
|
||||
/* Read the response: ESC [ rows ; cols R */
|
||||
while (i < sizeof(buf) - 1) {
|
||||
if (read(ifd, buf + i, 1) != 1) break;
|
||||
if (buf[i] == 'R') break;
|
||||
if (read(ifd, buf + i, 1) != 1)
|
||||
break;
|
||||
if (buf[i] == 'R')
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
/* Parse it. */
|
||||
if (buf[0] != CTRL('[') || buf[1] != '[') return -1;
|
||||
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1;
|
||||
if (buf[0] != CTRL('[') || buf[1] != '[')
|
||||
return -1;
|
||||
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -359,12 +373,15 @@ int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
|
||||
|
||||
/* Get the initial position so we can restore it later. */
|
||||
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
|
||||
if (retval == -1) goto failed;
|
||||
if (retval == -1)
|
||||
goto failed;
|
||||
|
||||
/* Go to right/bottom margin and get position. */
|
||||
if (write(ofd, "\e[999C\e[999B", 12) != 12) goto failed;
|
||||
if (write(ofd, "\e[999C\e[999B", 12) != 12)
|
||||
goto failed;
|
||||
retval = getCursorPosition(ifd, ofd, rows, cols);
|
||||
if (retval == -1) goto failed;
|
||||
if (retval == -1)
|
||||
goto failed;
|
||||
|
||||
/* Restore position. */
|
||||
char seq[32];
|
||||
@@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
row->hl = realloc(row->hl, row->rsize);
|
||||
memset(row->hl, HL_NORMAL, row->rsize);
|
||||
|
||||
if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */
|
||||
if (E.syntax == NULL)
|
||||
return; /* No syntax, everything is HL_NORMAL. */
|
||||
|
||||
int i, prev_sep, in_string, in_comment;
|
||||
char *p;
|
||||
@@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
prev_sep = 0;
|
||||
continue;
|
||||
}
|
||||
if (*p == in_string) in_string = 0;
|
||||
if (*p == in_string)
|
||||
in_string = 0;
|
||||
p++;
|
||||
i++;
|
||||
continue;
|
||||
@@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
|
||||
for (j = 0; keywords[j]; j++) {
|
||||
int klen = strlen(keywords[j]);
|
||||
int kw2 = keywords[j][klen - 1] == '|';
|
||||
if (kw2) klen--;
|
||||
if (kw2)
|
||||
klen--;
|
||||
|
||||
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
|
||||
/* Keyword */
|
||||
@@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
|
||||
* respecting tabs, substituting non printable characters with '?'. */
|
||||
free(row->render);
|
||||
for (j = 0; j < row->size; j++) {
|
||||
if (row->chars[j] == '\t') tabs++;
|
||||
if (row->chars[j] == '\t')
|
||||
tabs++;
|
||||
}
|
||||
|
||||
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
|
||||
@@ -626,11 +647,13 @@ void editorUpdateRow(erow *row) {
|
||||
/* Insert a row at the specified position, shifting the other rows on the bottom
|
||||
* if required. */
|
||||
void editorInsertRow(int at, char *s, size_t len) {
|
||||
if (at > E.numrows) return;
|
||||
if (at > E.numrows)
|
||||
return;
|
||||
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
|
||||
if (at != E.numrows) {
|
||||
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
|
||||
for (int j = at + 1; j <= E.numrows; j++) E.row[j].idx++;
|
||||
for (int j = at + 1; j <= E.numrows; j++)
|
||||
E.row[j].idx++;
|
||||
}
|
||||
E.row[at].size = len;
|
||||
E.row[at].chars = malloc(len + 1);
|
||||
@@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
|
||||
void editorDelRow(int at) {
|
||||
erow *row;
|
||||
|
||||
if (at >= E.numrows) return;
|
||||
if (at >= E.numrows)
|
||||
return;
|
||||
row = E.row + at;
|
||||
editorFreeRow(row);
|
||||
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
|
||||
for (int j = at; j < E.numrows - 1; j++) E.row[j].idx++;
|
||||
for (int j = at; j < E.numrows - 1; j++)
|
||||
E.row[j].idx++;
|
||||
E.numrows--;
|
||||
E.dirty++;
|
||||
}
|
||||
@@ -729,7 +754,8 @@ void editorRowAppendString(erow *row, char *s, size_t len) {
|
||||
|
||||
/* Delete the character at offset 'at' from the specified row. */
|
||||
void editorRowDelChar(erow *row, int at) {
|
||||
if (row->size <= at) return;
|
||||
if (row->size <= at)
|
||||
return;
|
||||
memmove(row->chars + at, row->chars + at + 1, row->size - at);
|
||||
editorUpdateRow(row);
|
||||
row->size--;
|
||||
@@ -745,7 +771,8 @@ void editorInsertChar(int c) {
|
||||
/* If the row where the cursor is currently located does not exist in our
|
||||
* logical representation of the file, add enough empty rows as needed. */
|
||||
if (!row) {
|
||||
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0);
|
||||
while (E.numrows <= filerow)
|
||||
editorInsertRow(E.numrows, "", 0);
|
||||
}
|
||||
row = &E.row[filerow];
|
||||
editorRowInsertChar(row, filecol, c);
|
||||
@@ -773,7 +800,8 @@ void editorInsertNewline(void) {
|
||||
}
|
||||
/* If the cursor is over the current line size, we want to conceptually
|
||||
* think it's just over the last character. */
|
||||
if (filecol >= row->size) filecol = row->size;
|
||||
if (filecol >= row->size)
|
||||
filecol = row->size;
|
||||
if (filecol == 0) {
|
||||
editorInsertRow(filerow, "", 0);
|
||||
} else {
|
||||
@@ -800,7 +828,8 @@ void editorDelChar(void) {
|
||||
int filecol = E.coloff + E.cx;
|
||||
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
|
||||
|
||||
if (!row || (filecol == 0 && filerow == 0)) return;
|
||||
if (!row || (filecol == 0 && filerow == 0))
|
||||
return;
|
||||
if (filecol == 0) {
|
||||
/* Handle the case of column 0, we need to move the current line
|
||||
* on the right of the previous one. */
|
||||
@@ -825,7 +854,8 @@ void editorDelChar(void) {
|
||||
else
|
||||
E.cx--;
|
||||
}
|
||||
if (row) editorUpdateRow(row);
|
||||
if (row)
|
||||
editorUpdateRow(row);
|
||||
E.dirty++;
|
||||
}
|
||||
|
||||
@@ -868,12 +898,15 @@ int editorSave(void) {
|
||||
int len;
|
||||
char *buf = editorRowsToString(&len);
|
||||
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644);
|
||||
if (fd == -1) goto writeerr;
|
||||
if (fd == -1)
|
||||
goto writeerr;
|
||||
|
||||
/* Use truncate + a single write(2) call in order to make saving
|
||||
* a bit safer, under the limits of what we can do in a small editor. */
|
||||
if (ftruncate(fd, len) == -1) goto writeerr;
|
||||
if (write(fd, buf, len) != len) goto writeerr;
|
||||
if (ftruncate(fd, len) == -1)
|
||||
goto writeerr;
|
||||
if (write(fd, buf, len) != len)
|
||||
goto writeerr;
|
||||
|
||||
close(fd);
|
||||
free(buf);
|
||||
@@ -883,7 +916,8 @@ int editorSave(void) {
|
||||
|
||||
writeerr:
|
||||
free(buf);
|
||||
if (fd != -1) close(fd);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
@@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
|
||||
abAppend(&ab, "~", 1);
|
||||
padding--;
|
||||
}
|
||||
while (padding--) abAppend(&ab, " ", 1);
|
||||
while (padding--)
|
||||
abAppend(&ab, " ", 1);
|
||||
abAppend(&ab, welcome, welcomelen);
|
||||
} else {
|
||||
abAppend(&ab, "~\e[0K\r\n", 7);
|
||||
@@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
|
||||
int current_color = -1;
|
||||
#endif
|
||||
if (len > 0) {
|
||||
if (len > E.screencols) len = E.screencols;
|
||||
if (len > E.screencols)
|
||||
len = E.screencols;
|
||||
char *c = r->render + E.coloff;
|
||||
#if SYNTAX
|
||||
unsigned char *hl = r->hl + E.coloff;
|
||||
@@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
|
||||
E.numrows, E.dirty ? "(modified)" : "");
|
||||
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
|
||||
E.numrows);
|
||||
if (len > E.screencols) len = E.screencols;
|
||||
if (len > E.screencols)
|
||||
len = E.screencols;
|
||||
abAppend(&ab, status, len);
|
||||
while (len < E.screencols) {
|
||||
if (E.screencols - len == rlen) {
|
||||
@@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
|
||||
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
|
||||
if (row) {
|
||||
for (j = E.coloff; j < (E.cx + E.coloff); j++) {
|
||||
if (j < row->size && row->chars[j] == CTRL('I')) cx += 7 - ((cx) % 8);
|
||||
if (j < row->size && row->chars[j] == CTRL('I'))
|
||||
cx += 7 - ((cx) % 8);
|
||||
cx++;
|
||||
}
|
||||
}
|
||||
@@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
|
||||
|
||||
int c = editorReadKey(fd);
|
||||
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
|
||||
if (qlen != 0) query[--qlen] = '\0';
|
||||
if (qlen != 0)
|
||||
query[--qlen] = '\0';
|
||||
last_match = -1;
|
||||
} else if (c == CTRL('G')) {
|
||||
break;
|
||||
@@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
|
||||
}
|
||||
|
||||
/* Search occurrence. */
|
||||
if (last_match == -1) find_next = 1;
|
||||
if (last_match == -1)
|
||||
find_next = 1;
|
||||
if (find_next) {
|
||||
char *match = NULL;
|
||||
int match_offset = 0;
|
||||
@@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
|
||||
break;
|
||||
case ARROW_UP:
|
||||
if (E.cy == 0) {
|
||||
if (E.rowoff) E.rowoff--;
|
||||
if (E.rowoff)
|
||||
E.rowoff--;
|
||||
} else {
|
||||
E.cy -= 1;
|
||||
}
|
||||
@@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
|
||||
|
||||
case CTRL('L'):
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
break;
|
||||
|
||||
case PAGE_UP:
|
||||
@@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
|
||||
E.cy = E.screenrows - 1;
|
||||
}
|
||||
times = E.screenrows;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
times = E.screenrows / 2;
|
||||
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
while (times--)
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
|
||||
break;
|
||||
|
||||
case HOME_KEY:
|
||||
case CTRL('A'):
|
||||
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT);
|
||||
while (E.cx || E.coloff)
|
||||
editorMoveCursor(ARROW_LEFT);
|
||||
break;
|
||||
case END_KEY:
|
||||
case CTRL('E'):
|
||||
|
||||
+129
-65
@@ -492,7 +492,8 @@ void TransmitVideo(void) {
|
||||
ssize_t rc;
|
||||
struct Frame* f;
|
||||
f = &vf_[frame_];
|
||||
if (!HasVideo(f)) f = FlipFrameBuffer();
|
||||
if (!HasVideo(f))
|
||||
f = FlipFrameBuffer();
|
||||
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
|
||||
f->w += rc;
|
||||
} else if (errno == EAGAIN) {
|
||||
@@ -504,9 +505,12 @@ void TransmitVideo(void) {
|
||||
|
||||
void TransmitAudio(void) {
|
||||
ssize_t rc;
|
||||
if (!playpid_) return;
|
||||
if (!audio_.i) return;
|
||||
if (playfd_ == -1) return;
|
||||
if (!playpid_)
|
||||
return;
|
||||
if (!audio_.i)
|
||||
return;
|
||||
if (playfd_ == -1)
|
||||
return;
|
||||
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
|
||||
rc /= sizeof(short);
|
||||
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
|
||||
@@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
|
||||
void PollAndSynchronize(void) {
|
||||
do {
|
||||
if (ReadKeyboard() == -1) {
|
||||
if (errno != EINTR) Exit(1);
|
||||
if (exited_) Exit(0);
|
||||
if (resized_) GetTermSize();
|
||||
if (errno != EINTR)
|
||||
Exit(1);
|
||||
if (exited_)
|
||||
Exit(0);
|
||||
if (resized_)
|
||||
GetTermSize();
|
||||
}
|
||||
} while (!timeout_);
|
||||
TransmitVideo();
|
||||
@@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF];
|
||||
if ((addr >> 13) == 3)
|
||||
return PRAM[addr & 0x1FFF];
|
||||
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
|
||||
}
|
||||
|
||||
@@ -828,7 +836,8 @@ bool offset_toggle = false;
|
||||
u8& NesMmap(int i) {
|
||||
i &= 0x3FFF;
|
||||
if (i >= 0x3F00) {
|
||||
if (i % 4 == 0) i &= 0x0F;
|
||||
if (i % 4 == 0)
|
||||
i &= 0x0F;
|
||||
return palette[i & 0x1F];
|
||||
}
|
||||
if (i < 0x2000) {
|
||||
@@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
return open_bus_decay_timer = 77777, open_bus = v;
|
||||
};
|
||||
u8 res = open_bus;
|
||||
if (write) RefreshOpenBus(v);
|
||||
if (write)
|
||||
RefreshOpenBus(v);
|
||||
switch (index) { // Which port from $200x?
|
||||
case 0:
|
||||
if (write) {
|
||||
@@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (write) break;
|
||||
if (write)
|
||||
break;
|
||||
res = reg.status | (open_bus & 0x1F);
|
||||
reg.InVBlank = false; // Reading $2002 clears the vblank flag.
|
||||
offset_toggle = false; // Also resets the toggle for address updates.
|
||||
@@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (write) reg.OAMaddr = v;
|
||||
if (write)
|
||||
reg.OAMaddr = v;
|
||||
break; // Index into Object Attribute Memory
|
||||
case 4:
|
||||
if (write) {
|
||||
@@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!write) break; // Set background scrolling offset
|
||||
if (!write)
|
||||
break; // Set background scrolling offset
|
||||
if (offset_toggle) {
|
||||
scroll.yfine = v & 7;
|
||||
scroll.ycoarse = v >> 3;
|
||||
@@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
||||
offset_toggle = !offset_toggle;
|
||||
break;
|
||||
case 6:
|
||||
if (!write) break; // Set video memory position for reads/writes
|
||||
if (!write)
|
||||
break; // Set video memory position for reads/writes
|
||||
if (offset_toggle) {
|
||||
scroll.vaddrlo = v;
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
@@ -926,17 +940,21 @@ void RenderingTick() {
|
||||
case 2: // Point to attribute table
|
||||
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
|
||||
(vaddr.xcoarse / 4);
|
||||
if (tile_decode_mode) break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
if (tile_decode_mode)
|
||||
break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
|
||||
// Reset sprite data
|
||||
if (x_ == 0) {
|
||||
sprinpos = sproutpos = 0;
|
||||
if (reg.ShowSP) reg.OAMaddr = 0;
|
||||
if (reg.ShowSP)
|
||||
reg.OAMaddr = 0;
|
||||
}
|
||||
if (!reg.ShowBG) break;
|
||||
if (!reg.ShowBG)
|
||||
break;
|
||||
// Reset scrolling (vertical once, horizontal each scanline)
|
||||
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 304 && scanline == -1)
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 256) {
|
||||
vaddr.xcoarse = (unsigned)scroll.xcoarse;
|
||||
vaddr.basenta_h = (unsigned)scroll.basenta_h;
|
||||
@@ -949,7 +967,8 @@ void RenderingTick() {
|
||||
}
|
||||
// Name table access
|
||||
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
|
||||
if (!tile_decode_mode) break;
|
||||
if (!tile_decode_mode)
|
||||
break;
|
||||
// Push the current tile into shift registers.
|
||||
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
|
||||
// 8 times.
|
||||
@@ -976,7 +995,8 @@ void RenderingTick() {
|
||||
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
|
||||
memcpy(&o, &OAM2[sprrenpos], sizeof(o));
|
||||
unsigned y = (scanline)-o.y;
|
||||
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7);
|
||||
if (o.attr & 0x80)
|
||||
y ^= (reg.SPsize ? 15 : 7);
|
||||
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
|
||||
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
|
||||
pat_addr += (y & 7) + (y & 8) * 2;
|
||||
@@ -1011,8 +1031,10 @@ void RenderingTick() {
|
||||
break;
|
||||
}
|
||||
++sprinpos; // next sprite
|
||||
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
y1 = sprtmp;
|
||||
y2 = sprtmp + (reg.SPsize ? 16 : 8);
|
||||
if (!(scanline >= y1 && scanline < y2)) {
|
||||
@@ -1020,19 +1042,23 @@ void RenderingTick() {
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].index = sprtmp;
|
||||
break;
|
||||
case 2:
|
||||
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].attr = sprtmp;
|
||||
break;
|
||||
case 3:
|
||||
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8) {
|
||||
++sproutpos;
|
||||
} else {
|
||||
reg.SPoverflow = true;
|
||||
}
|
||||
if (sprinpos == 2) reg.OAMaddr = 8;
|
||||
if (sprinpos == 2)
|
||||
reg.OAMaddr = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1060,13 +1086,17 @@ void RenderPixel() {
|
||||
auto& s = OAM3[sno];
|
||||
// Check if this sprite is horizontally in range
|
||||
unsigned xdiff = x_ - s.x_;
|
||||
if (xdiff >= 8) continue; // Also matches negative values
|
||||
if (xdiff >= 8)
|
||||
continue; // Also matches negative values
|
||||
// Determine which pixel to display; skip transparent pixels
|
||||
if (!(s.attr & 0x40)) xdiff = 7 - xdiff;
|
||||
if (!(s.attr & 0x40))
|
||||
xdiff = 7 - xdiff;
|
||||
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
|
||||
if (!spritepixel) continue;
|
||||
if (!spritepixel)
|
||||
continue;
|
||||
// Register sprite-0 hit if applicable
|
||||
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true;
|
||||
if (x_ < 255 && pixel && s.sprindex == 0)
|
||||
reg.SP0hit = true;
|
||||
// Render the pixel unless behind-background placement wanted
|
||||
if (!(s.attr & 0x20) || !pixel) {
|
||||
attr = (s.attr & 3) + 4;
|
||||
@@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
|
||||
}
|
||||
if (ctrlmask & 0x80) {
|
||||
joy_next_[0] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[0] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[0] = 0;
|
||||
}
|
||||
if (ctrlmask & 0x40) {
|
||||
joy_next_[1] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[1] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1144,18 +1176,23 @@ void Tick() {
|
||||
CPU::nmi = reg.InVBlank && reg.NMIenabled;
|
||||
break;
|
||||
}
|
||||
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0;
|
||||
if (VBlankState != 0)
|
||||
VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer)
|
||||
open_bus = 0;
|
||||
|
||||
// Graphics processing scanline?
|
||||
if (scanline < DYN) {
|
||||
/* Process graphics for this cycle */
|
||||
if (reg.ShowBGSP) RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256) RenderPixel();
|
||||
if (reg.ShowBGSP)
|
||||
RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256)
|
||||
RenderPixel();
|
||||
}
|
||||
|
||||
// Done with the cycle. Check for end of scanline.
|
||||
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++cycle_counter == 3)
|
||||
cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++x_ >= scanline_end) {
|
||||
// Begin new scanline
|
||||
FlushScanline(scanline);
|
||||
@@ -1242,30 +1279,36 @@ struct channel {
|
||||
template <unsigned c>
|
||||
int Tick() {
|
||||
channel& ch = *this;
|
||||
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8;
|
||||
if (!ChannelsEnabled[c])
|
||||
return c == 4 ? 64 : 8;
|
||||
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
|
||||
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
if (c == 3)
|
||||
wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
int volume = ch.length_counter
|
||||
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
|
||||
: 0;
|
||||
// Sample may change at wavelen intervals.
|
||||
auto& S = ch.level;
|
||||
if (!count(ch.wave_counter, wl)) return S;
|
||||
if (!count(ch.wave_counter, wl))
|
||||
return S;
|
||||
switch (c) {
|
||||
default: // Square wave. With four different 8-step binary waveforms (32
|
||||
// bits of data total).
|
||||
if (wl < 8) return S = 8;
|
||||
if (wl < 8)
|
||||
return S = 8;
|
||||
return S = (0xF33C0C04u &
|
||||
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
|
||||
? volume
|
||||
: 0;
|
||||
|
||||
case 2: // Triangle wave
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase;
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3)
|
||||
++ch.phase;
|
||||
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
|
||||
|
||||
case 3: // Noise: Linear feedback shift register
|
||||
if (!ch.hold) ch.hold = 1;
|
||||
if (!ch.hold)
|
||||
ch.hold = 1;
|
||||
ch.hold =
|
||||
(ch.hold >> 1) |
|
||||
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
|
||||
@@ -1302,7 +1345,8 @@ struct channel {
|
||||
} else {
|
||||
v -= 2;
|
||||
}
|
||||
if (v >= 0 && v <= 0x7F) ch.linear_counter = v;
|
||||
if (v >= 0 && v <= 0x7F)
|
||||
ch.linear_counter = v;
|
||||
}
|
||||
return S = ch.linear_counter;
|
||||
}
|
||||
@@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
|
||||
ch.linear_counter = ch.reg.LinearCounterInit;
|
||||
ch.env_delay = ch.reg.EnvDecayRate;
|
||||
ch.envelope = 15;
|
||||
if (index < 8) ch.phase = 0;
|
||||
if (index < 8)
|
||||
ch.phase = 0;
|
||||
break;
|
||||
case 0x10:
|
||||
ch.reg.reg3 = value;
|
||||
@@ -1384,9 +1429,11 @@ u8 Read() {
|
||||
for (c = 0; c < 5; ++c) {
|
||||
res |= channels[c].length_counter ? 1 << c : 0;
|
||||
}
|
||||
if (PeriodicIRQ) res |= 0x40;
|
||||
if (PeriodicIRQ)
|
||||
res |= 0x40;
|
||||
PeriodicIRQ = false;
|
||||
if (DMC_IRQ) res |= 0x80;
|
||||
if (DMC_IRQ)
|
||||
res |= 0x80;
|
||||
DMC_IRQ = false;
|
||||
CPU::intr = false;
|
||||
return res;
|
||||
@@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
|
||||
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
|
||||
if ((hz240counter.lo += 2) >= 14915) {
|
||||
hz240counter.lo -= 14915;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider)
|
||||
hz240counter.hi = 0;
|
||||
|
||||
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
|
||||
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
|
||||
@@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
|
||||
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
|
||||
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
|
||||
wl += d[ch.reg.SweepDecrease * 2 + c];
|
||||
if (wl < 0x800) ch.reg.WaveLength = wl;
|
||||
if (wl < 0x800)
|
||||
ch.reg.WaveLength = wl;
|
||||
}
|
||||
|
||||
// Linear tick (triangle wave only)
|
||||
@@ -1464,20 +1513,24 @@ namespace CPU {
|
||||
|
||||
void Tick() {
|
||||
// PPU clock: 3 times the CPU rate
|
||||
for (unsigned n = 0; n < 3; ++n) PPU::Tick();
|
||||
for (unsigned n = 0; n < 3; ++n)
|
||||
PPU::Tick();
|
||||
// APU clock: 1 times the CPU rate
|
||||
for (unsigned n = 0; n < 1; ++n) APU::Tick();
|
||||
for (unsigned n = 0; n < 1; ++n)
|
||||
APU::Tick();
|
||||
}
|
||||
|
||||
template <bool write>
|
||||
u8 MemAccess(u16 addr, u8 v) {
|
||||
// Memory writes are turned into reads while reset is being signalled
|
||||
if (reset && write) return MemAccess<0>(addr);
|
||||
if (reset && write)
|
||||
return MemAccess<0>(addr);
|
||||
Tick();
|
||||
// Map the memory from CPU's viewpoint.
|
||||
/**/ if (addr < 0x2000) {
|
||||
u8& r = RAM[addr & 0x7FF];
|
||||
if (!write) return r;
|
||||
if (!write)
|
||||
return r;
|
||||
r = v;
|
||||
} else if (addr < 0x4000) {
|
||||
return PPU::PpuAccess(addr & 7, v, write);
|
||||
@@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
|
||||
WB(0x2004, RB((v & 7) * 0x0100 + b));
|
||||
return 0;
|
||||
case 0x15:
|
||||
if (!write) return APU::Read();
|
||||
if (!write)
|
||||
return APU::Read();
|
||||
APU::Write(0x15, v);
|
||||
break;
|
||||
case 0x16:
|
||||
if (!write) return JoyRead(0);
|
||||
if (!write)
|
||||
return JoyRead(0);
|
||||
JoyStrobe(v);
|
||||
break;
|
||||
case 0x17:
|
||||
if (!write) return JoyRead(1); // write:passthru
|
||||
if (!write)
|
||||
return JoyRead(1); // write:passthru
|
||||
default:
|
||||
if (!write) break;
|
||||
if (!write)
|
||||
break;
|
||||
APU::Write(addr & 0x1F, v);
|
||||
}
|
||||
} else {
|
||||
@@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
|
||||
}
|
||||
void Misfire(u16 old, u16 addr) {
|
||||
u16 q = wrap(old, addr);
|
||||
if (q != addr) RB(q);
|
||||
if (q != addr)
|
||||
RB(q);
|
||||
}
|
||||
u8 Pop() {
|
||||
return RB(0x100 | u8(++S));
|
||||
@@ -1655,7 +1713,8 @@ void Op() {
|
||||
} else if (intr && !P.I) {
|
||||
op = 0x102;
|
||||
}
|
||||
if (!nmi_now) nmi_edge_detected = false;
|
||||
if (!nmi_now)
|
||||
nmi_edge_detected = false;
|
||||
|
||||
// Define function pointers for each opcode (00..FF) and each interrupt
|
||||
// (100,101,102)
|
||||
@@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
|
||||
fgetc(fp);
|
||||
fgetc(fp);
|
||||
|
||||
if (mappernum >= 0x40) mappernum &= 15;
|
||||
if (mappernum >= 0x40)
|
||||
mappernum &= 15;
|
||||
GamePak::mappernum = mappernum;
|
||||
|
||||
// Read the ROM data
|
||||
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
if (rom16count)
|
||||
GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count)
|
||||
GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
|
||||
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
|
||||
|
||||
@@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
|
||||
PPU::reg.value = 0;
|
||||
|
||||
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
|
||||
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
for (unsigned a = 0; a < 0x800; ++a)
|
||||
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
|
||||
// Run the CPU until the program is killed.
|
||||
for (;;) CPU::Op();
|
||||
for (;;)
|
||||
CPU::Op();
|
||||
}
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE* f) {
|
||||
|
||||
+62
-31
@@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
|
||||
} else if (*p->p == '[' && blevel == 0) {
|
||||
level++;
|
||||
} else if (*p->p == ']' && blevel == 0) {
|
||||
if (!--level) break;
|
||||
if (!--level)
|
||||
break;
|
||||
} else if (*p->p == '\\') {
|
||||
p->p++;
|
||||
p->len--;
|
||||
} else if (*p->p == '{') {
|
||||
blevel++;
|
||||
} else if (*p->p == '}') {
|
||||
if (blevel != 0) blevel--;
|
||||
if (blevel != 0)
|
||||
blevel--;
|
||||
}
|
||||
p->p++;
|
||||
p->len--;
|
||||
@@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
if (p->insidequote) return picolParseString(p);
|
||||
if (p->insidequote)
|
||||
return picolParseString(p);
|
||||
return picolParseSep(p);
|
||||
case '\n':
|
||||
case ';':
|
||||
if (p->insidequote) return picolParseString(p);
|
||||
if (p->insidequote)
|
||||
return picolParseString(p);
|
||||
return picolParseEol(p);
|
||||
case '[':
|
||||
return picolParseCommand(p);
|
||||
@@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
|
||||
struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
|
||||
struct picolVar *v = i->callframe->vars;
|
||||
while (v) {
|
||||
if (strcmp(v->name, name) == 0) return v;
|
||||
if (strcmp(v->name, name) == 0)
|
||||
return v;
|
||||
v = v->next;
|
||||
}
|
||||
return NULL;
|
||||
@@ -334,7 +339,8 @@ int picolSetVar(struct picolInterp *i, char *name, char *val) {
|
||||
struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) {
|
||||
struct picolCmd *c = i->commands;
|
||||
while (c) {
|
||||
if (strcmp(c->name, name) == 0) return c;
|
||||
if (strcmp(c->name, name) == 0)
|
||||
return c;
|
||||
c = c->next;
|
||||
}
|
||||
return NULL;
|
||||
@@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
int tlen;
|
||||
int prevtype = p.type;
|
||||
picolGetToken(&p);
|
||||
if (p.type == PT_EOF) break;
|
||||
if (p.type == PT_EOF)
|
||||
break;
|
||||
tlen = p.end - p.start + 1;
|
||||
if (tlen < 0) tlen = 0;
|
||||
if (tlen < 0)
|
||||
tlen = 0;
|
||||
t = malloc(tlen + 1);
|
||||
memcpy(t, p.start, tlen);
|
||||
t[tlen] = '\0';
|
||||
@@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
} else if (p.type == PT_CMD) {
|
||||
retcode = picolEval(i, t);
|
||||
free(t);
|
||||
if (retcode != PICOL_OK) goto err;
|
||||
if (retcode != PICOL_OK)
|
||||
goto err;
|
||||
t = strdup(i->result);
|
||||
} else if (p.type == PT_ESC) {
|
||||
/* XXX: escape handling missing! */
|
||||
@@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
goto err;
|
||||
}
|
||||
retcode = c->func(i, argc, argv, c->privdata);
|
||||
if (retcode != PICOL_OK) goto err;
|
||||
if (retcode != PICOL_OK)
|
||||
goto err;
|
||||
}
|
||||
/* Prepare for the next command */
|
||||
for (j = 0; j < argc; j++) free(argv[j]);
|
||||
for (j = 0; j < argc; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
argv = NULL;
|
||||
argc = 0;
|
||||
@@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
|
||||
prevtype = p.type;
|
||||
}
|
||||
err:
|
||||
for (j = 0; j < argc; j++) free(argv[j]);
|
||||
for (j = 0; j < argc; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
return retcode;
|
||||
}
|
||||
@@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
|
||||
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
char buf[64];
|
||||
int a, b, c;
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
a = atoi(argv[1]);
|
||||
b = atoi(argv[2]);
|
||||
if (argv[0][0] == '+')
|
||||
@@ -485,22 +498,26 @@ int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
}
|
||||
|
||||
int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
picolSetVar(i, argv[1], argv[2]);
|
||||
picolSetResult(i, argv[2]);
|
||||
return PICOL_OK;
|
||||
}
|
||||
|
||||
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 2) return picolArityErr(i, argv[0]);
|
||||
if (argc != 2)
|
||||
return picolArityErr(i, argv[0]);
|
||||
printf("%s\n", argv[1]);
|
||||
return PICOL_OK;
|
||||
}
|
||||
|
||||
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
int retcode;
|
||||
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]);
|
||||
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode;
|
||||
if (argc != 3 && argc != 5)
|
||||
return picolArityErr(i, argv[0]);
|
||||
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
|
||||
return retcode;
|
||||
if (atoi(i->result))
|
||||
return picolEval(i, argv[2]);
|
||||
else if (argc == 5)
|
||||
@@ -509,10 +526,12 @@ int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
}
|
||||
|
||||
int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 3) return picolArityErr(i, argv[0]);
|
||||
if (argc != 3)
|
||||
return picolArityErr(i, argv[0]);
|
||||
while (1) {
|
||||
int retcode = picolEval(i, argv[1]);
|
||||
if (retcode != PICOL_OK) return retcode;
|
||||
if (retcode != PICOL_OK)
|
||||
return retcode;
|
||||
if (atoi(i->result)) {
|
||||
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
|
||||
continue;
|
||||
@@ -530,7 +549,8 @@ int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
|
||||
int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
|
||||
void *pd) {
|
||||
if (argc != 1) return picolArityErr(i, argv[0]);
|
||||
if (argc != 1)
|
||||
return picolArityErr(i, argv[0]);
|
||||
if (strcmp(argv[0], "break") == 0)
|
||||
return PICOL_BREAK;
|
||||
else if (strcmp(argv[0], "continue") == 0)
|
||||
@@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
|
||||
tofree = p;
|
||||
while (1) {
|
||||
char *start = p;
|
||||
while (*p != ' ' && *p != '\0') p++;
|
||||
while (*p != ' ' && *p != '\0')
|
||||
p++;
|
||||
if (*p != '\0' && p == start) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (p == start) break;
|
||||
if (p == start)
|
||||
break;
|
||||
if (*p == '\0')
|
||||
done = 1;
|
||||
else
|
||||
*p = '\0';
|
||||
if (++arity > argc - 1) goto arityerr;
|
||||
if (++arity > argc - 1)
|
||||
goto arityerr;
|
||||
picolSetVar(i, start, argv[arity]);
|
||||
p++;
|
||||
if (done) break;
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
free(tofree);
|
||||
if (arity != argc - 1) goto arityerr;
|
||||
if (arity != argc - 1)
|
||||
goto arityerr;
|
||||
errcode = picolEval(i, body);
|
||||
if (errcode == PICOL_RETURN) errcode = PICOL_OK;
|
||||
if (errcode == PICOL_RETURN)
|
||||
errcode = PICOL_OK;
|
||||
picolDropCallFrame(i); /* remove the called proc callframe */
|
||||
return errcode;
|
||||
arityerr:
|
||||
@@ -594,14 +620,16 @@ arityerr:
|
||||
|
||||
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
char **procdata = malloc(sizeof(char *) * 2);
|
||||
if (argc != 4) return picolArityErr(i, argv[0]);
|
||||
if (argc != 4)
|
||||
return picolArityErr(i, argv[0]);
|
||||
procdata[0] = strdup(argv[2]); /* arguments list */
|
||||
procdata[1] = strdup(argv[3]); /* procedure body */
|
||||
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
|
||||
}
|
||||
|
||||
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) {
|
||||
if (argc != 1 && argc != 2) return picolArityErr(i, argv[0]);
|
||||
if (argc != 1 && argc != 2)
|
||||
return picolArityErr(i, argv[0]);
|
||||
picolSetResult(i, (argc == 2) ? argv[1] : "");
|
||||
return PICOL_RETURN;
|
||||
}
|
||||
@@ -631,9 +659,11 @@ int main(int argc, char **argv) {
|
||||
int retcode;
|
||||
printf("picol> ");
|
||||
fflush(stdout);
|
||||
if (fgets(clibuf, 1024, stdin) == NULL) return 0;
|
||||
if (fgets(clibuf, 1024, stdin) == NULL)
|
||||
return 0;
|
||||
retcode = picolEval(&interp, clibuf);
|
||||
if (interp.result[0] != '\0') printf("[%d] %s\n", retcode, interp.result);
|
||||
if (interp.result[0] != '\0')
|
||||
printf("[%d] %s\n", retcode, interp.result);
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
char buf[1024 * 16];
|
||||
@@ -644,7 +674,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
|
||||
fclose(fp);
|
||||
if (picolEval(&interp, buf) != PICOL_OK) printf("%s\n", interp.result);
|
||||
if (picolEval(&interp, buf) != PICOL_OK)
|
||||
printf("%s\n", interp.result);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+17
-17
@@ -14,13 +14,13 @@
|
||||
# GETTING STARTED
|
||||
#
|
||||
# # run these commands after cloning the cosmo repo on linux
|
||||
# $ make -j8 o//examples/pyapp/pyapp.com
|
||||
# $ o//examples/pyapp/pyapp.com
|
||||
# $ make -j8 o//examples/pyapp/pyapp
|
||||
# $ o//examples/pyapp/pyapp
|
||||
# cosmopolitan is cool!
|
||||
#
|
||||
# HOW IT WORKS
|
||||
#
|
||||
# $ pyobj.com -m -o pyapp.o pyapp.py
|
||||
# $ pyobj -m -o pyapp.o pyapp.py
|
||||
# $ ld -static -nostdlib -T o//ape/ape.lds ape.o crt.o \
|
||||
# pyapp.o \
|
||||
# cosmopolitan-python-stage2.a \
|
||||
@@ -29,19 +29,19 @@
|
||||
# cosmopolitan-bzip2.a \
|
||||
# cosmopolitan-python-stage1.a \
|
||||
# cosmopolitan.a
|
||||
# $ ./pyapp.com
|
||||
# $ ./pyapp
|
||||
# cosmopolitan is cool!
|
||||
#
|
||||
# NOTES
|
||||
#
|
||||
# If you enjoy this tutorial, let us know jtunney@gmail.com. If
|
||||
# If you enjoy this tutorial, let us know jtunney@gmail. If
|
||||
# you're building something cool, then we can we can add you to
|
||||
# our .gitowners file which grants you commit access so you can
|
||||
# indepnedently maintain your package, as part of the mono-repo
|
||||
|
||||
PKGS += PYAPP
|
||||
PYAPP = $(PYAPP_DEPS) o/$(MODE)/examples/pyapp/pyapp.a
|
||||
PYAPP_COMS = o/$(MODE)/examples/pyapp/pyapp.com
|
||||
PYAPP_COMS = o/$(MODE)/examples/pyapp/pyapp
|
||||
PYAPP_BINS = $(PYAPP_COMS) $(PYAPP_COMS:%=%.dbg)
|
||||
|
||||
# Specify our Cosmopolitan library dependencies
|
||||
@@ -58,7 +58,7 @@ PYAPP_DIRECTDEPS = \
|
||||
# them all out and arranges them in the correct order.
|
||||
PYAPP_DEPS := $(call uniq,$(foreach x,$(PYAPP_DIRECTDEPS),$($(x))))
|
||||
|
||||
# # Asks PYOBJ.COM to turn our Python source into an ELF object which
|
||||
# # Asks PYOBJ to turn our Python source into an ELF object which
|
||||
# # contains (a) embedded zip file artifacts of our .py file and .pyc
|
||||
# # which it it compiled; and (b) statically analyzed listings of our
|
||||
# # python namespaces and imports that GNU ld will use for tree shake
|
||||
@@ -71,18 +71,18 @@ PYAPP_DEPS := $(call uniq,$(foreach x,$(PYAPP_DIRECTDEPS),$($(x))))
|
||||
# in `.python/` (which is accessible via open() system calls, using
|
||||
# the synthetic path `"/zip/.python/"`) which means that if we want
|
||||
# to turn `pyapp/pyapp.py` into `.python/pyapp.py` so it's imported
|
||||
# using `import pyapp` then we can simply append to PYOBJ.COM flags
|
||||
# using `import pyapp` then we can simply append to PYOBJ flags
|
||||
# flags above asking it to strip one directory component and prefix
|
||||
# Lastly be sure that whenever you use this variable override trick
|
||||
# you only do it to .o files, since otherwise it'll ruin everything
|
||||
# Passing -m to PYOBJ.COM causes a C main() function to get yoinked
|
||||
# Passing -m to PYOBJ causes a C main() function to get yoinked
|
||||
# and it means our Python module can no longer be used as a library
|
||||
o/$(MODE)/examples/pyapp/pyapp.o: PYFLAGS += -m -C2 -P.python
|
||||
|
||||
# Asks PACKAGE.COM to sanity check our DIRECTDEPS and symbol graph.
|
||||
# Asks PACKAGE to sanity check our DIRECTDEPS and symbol graph.
|
||||
# This program functions as an incremental linker. It also provides
|
||||
# enhancements to the object code that GCC generated similar to LTO
|
||||
# so be certain that your .com.dbg rule depends on the .pkg output!
|
||||
# so be certain that your .dbg rule depends on the .pkg output!
|
||||
o/$(MODE)/examples/pyapp/pyapp.pkg: \
|
||||
o/$(MODE)/examples/pyapp/pyapp.o \
|
||||
$(foreach x,$(PYAPP_DIRECTDEPS),$($(x)_A).pkg)
|
||||
@@ -90,7 +90,7 @@ o/$(MODE)/examples/pyapp/pyapp.pkg: \
|
||||
# Ask GNU LD to link our APE executable within an ELF binary shell.
|
||||
# The CRT and APE dependencies are special dependencies that define
|
||||
# your _start() / WinMain() entrpoints as well as APE linker script
|
||||
o/$(MODE)/examples/pyapp/pyapp.com.dbg: \
|
||||
o/$(MODE)/examples/pyapp/pyapp.dbg: \
|
||||
$(PYAPP_DEPS) \
|
||||
o/$(MODE)/examples/pyapp/pyapp.pkg \
|
||||
o/$(MODE)/examples/pyapp/pyapp.o \
|
||||
@@ -98,10 +98,10 @@ o/$(MODE)/examples/pyapp/pyapp.com.dbg: \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(COMPILE) -ALINK.ape $(LINK) $(LINKARGS) -o $@
|
||||
|
||||
# # Unwrap the APE .COM binary, that's embedded within the linked file
|
||||
# # Unwrap the APE binary, that's embedded within the linked file
|
||||
# # NOTE: This line can be commented out, since it's in build/rules.mk
|
||||
# o/$(MODE)/examples/pyapp/pyapp.com: \
|
||||
# o/$(MODE)/examples/pyapp/pyapp.com.dbg
|
||||
# o/$(MODE)/examples/pyapp/pyapp: \
|
||||
# o/$(MODE)/examples/pyapp/pyapp.dbg
|
||||
# $(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
# Ensure that build config changes will invalidate build artifacts.
|
||||
@@ -112,5 +112,5 @@ o/$(MODE)/examples/pyapp/pyapp.o: \
|
||||
# and have it build all targets the package defines.
|
||||
.PHONY: o/$(MODE)/examples/pyapp
|
||||
o/$(MODE)/examples/pyapp: \
|
||||
o/$(MODE)/examples/pyapp/pyapp.com \
|
||||
o/$(MODE)/examples/pyapp/pyapp.com.dbg
|
||||
o/$(MODE)/examples/pyapp/pyapp \
|
||||
o/$(MODE)/examples/pyapp/pyapp.dbg
|
||||
+17
-17
@@ -14,13 +14,13 @@
|
||||
# GETTING STARTED
|
||||
#
|
||||
# # run these commands after cloning the cosmo repo on linux
|
||||
# $ make -j8 o//examples/pylife/pylife.com
|
||||
# $ o//examples/pylife/pylife.com
|
||||
# $ make -j8 o//examples/pylife/pylife
|
||||
# $ o//examples/pylife/pylife
|
||||
# cosmopolitan is cool!
|
||||
#
|
||||
# HOW IT WORKS
|
||||
#
|
||||
# $ pyobj.com -m -o pylife.o pylife.py
|
||||
# $ pyobj -m -o pylife.o pylife.py
|
||||
# $ ld -static -nostdlib -T o//ape/ape.lds ape.o crt.o \
|
||||
# pylife.o \
|
||||
# cosmopolitan-python-stage2.a \
|
||||
@@ -29,19 +29,19 @@
|
||||
# cosmopolitan-bzip2.a \
|
||||
# cosmopolitan-python-stage1.a \
|
||||
# cosmopolitan.a
|
||||
# $ ./pylife.com
|
||||
# $ ./pylife
|
||||
# cosmopolitan is cool!
|
||||
#
|
||||
# NOTES
|
||||
#
|
||||
# If you enjoy this tutorial, let us know jtunney@gmail.com. If
|
||||
# If you enjoy this tutorial, let us know jtunney@gmail. If
|
||||
# you're building something cool, then we can we can add you to
|
||||
# our .gitowners file which grants you commit access so you can
|
||||
# indepnedently maintain your package, as part of the mono-repo
|
||||
|
||||
PKGS += PYLIFE
|
||||
PYLIFE = $(PYLIFE_DEPS) o/$(MODE)/examples/pylife/pylife.a
|
||||
PYLIFE_COMS = o/$(MODE)/examples/pylife/pylife.com
|
||||
PYLIFE_COMS = o/$(MODE)/examples/pylife/pylife
|
||||
PYLIFE_BINS = $(PYLIFE_COMS) $(PYLIFE_COMS:%=%.dbg)
|
||||
|
||||
# Specify our Cosmopolitan library dependencies
|
||||
@@ -58,7 +58,7 @@ PYLIFE_DIRECTDEPS = \
|
||||
# them all out and arranges them in the correct order.
|
||||
PYLIFE_DEPS := $(call uniq,$(foreach x,$(PYLIFE_DIRECTDEPS),$($(x))))
|
||||
|
||||
# # Asks PYOBJ.COM to turn our Python source into an ELF object which
|
||||
# # Asks PYOBJ to turn our Python source into an ELF object which
|
||||
# # contains (a) embedded zip file artifacts of our .py file and .pyc
|
||||
# # which it it compiled; and (b) statically analyzed listings of our
|
||||
# # python namespaces and imports that GNU ld will use for tree shake
|
||||
@@ -71,18 +71,18 @@ PYLIFE_DEPS := $(call uniq,$(foreach x,$(PYLIFE_DIRECTDEPS),$($(x))))
|
||||
# in `.python/` (which is accessible via open() system calls, using
|
||||
# the synthetic path `"/zip/.python/"`) which means that if we want
|
||||
# to turn `pylife/pylife.py` into `.python/pylife.py` so it's imported
|
||||
# using `import pylife` then we can simply append to PYOBJ.COM flags
|
||||
# using `import pylife` then we can simply append to PYOBJ flags
|
||||
# flags above asking it to strip one directory component and prefix
|
||||
# Lastly be sure that whenever you use this variable override trick
|
||||
# you only do it to .o files, since otherwise it'll ruin everything
|
||||
# Passing -m to PYOBJ.COM causes a C main() function to get yoinked
|
||||
# Passing -m to PYOBJ causes a C main() function to get yoinked
|
||||
# and it means our Python module can no longer be used as a library
|
||||
o/$(MODE)/examples/pylife/pylife.o: PYFLAGS += -m -C2 -P.python
|
||||
|
||||
# Asks PACKAGE.COM to sanity check our DIRECTDEPS and symbol graph.
|
||||
# Asks PACKAGE to sanity check our DIRECTDEPS and symbol graph.
|
||||
# This program functions as an incremental linker. It also provides
|
||||
# enhancements to the object code that GCC generated similar to LTO
|
||||
# so be certain that your .com.dbg rule depends on the .pkg output!
|
||||
# so be certain that your .dbg rule depends on the .pkg output!
|
||||
o/$(MODE)/examples/pylife/pylife.pkg: \
|
||||
o/$(MODE)/examples/pylife/pylife.o \
|
||||
$(foreach x,$(PYLIFE_DIRECTDEPS),$($(x)_A).pkg)
|
||||
@@ -90,7 +90,7 @@ o/$(MODE)/examples/pylife/pylife.pkg: \
|
||||
# Ask GNU LD to link our APE executable within an ELF binary shell.
|
||||
# The CRT and APE dependencies are special dependencies that define
|
||||
# your _start() / WinMain() entrpoints as well as APE linker script
|
||||
o/$(MODE)/examples/pylife/pylife.com.dbg: \
|
||||
o/$(MODE)/examples/pylife/pylife.dbg: \
|
||||
$(PYLIFE_DEPS) \
|
||||
o/$(MODE)/examples/pylife/pylife.pkg \
|
||||
o/$(MODE)/examples/pylife/pylife.o \
|
||||
@@ -98,10 +98,10 @@ o/$(MODE)/examples/pylife/pylife.com.dbg: \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(COMPILE) -ALINK.ape $(LINK) $(LINKARGS) -o $@
|
||||
|
||||
# # Unwrap the APE .COM binary, that's embedded within the linked file
|
||||
# # Unwrap the APE binary, that's embedded within the linked file
|
||||
# # NOTE: This line can be commented out, since it's in build/rules.mk
|
||||
# o/$(MODE)/examples/pylife/pylife.com: \
|
||||
# o/$(MODE)/examples/pylife/pylife.com.dbg
|
||||
# o/$(MODE)/examples/pylife/pylife: \
|
||||
# o/$(MODE)/examples/pylife/pylife.dbg
|
||||
# $(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
# Ensure that build config changes will invalidate build artifacts.
|
||||
@@ -112,5 +112,5 @@ o/$(MODE)/examples/pylife/pylife.o: \
|
||||
# and have it build all targets the package defines.
|
||||
.PHONY: o/$(MODE)/examples/pylife
|
||||
o/$(MODE)/examples/pylife: \
|
||||
o/$(MODE)/examples/pylife/pylife.com \
|
||||
o/$(MODE)/examples/pylife/pylife.com.dbg
|
||||
o/$(MODE)/examples/pylife/pylife \
|
||||
o/$(MODE)/examples/pylife/pylife.dbg
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
const char *prog = argv[0];
|
||||
if (!prog) prog = "rusage";
|
||||
if (!prog)
|
||||
prog = "rusage";
|
||||
|
||||
if (argc < 2) {
|
||||
tinyprint(2, prog, ": missing command\n", NULL);
|
||||
|
||||
@@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
|
||||
} while (x);
|
||||
for (;;) {
|
||||
*p++ = m[--i];
|
||||
if (!i) break;
|
||||
if (!(i % 3)) *p++ = ',';
|
||||
if (!i)
|
||||
break;
|
||||
if (!(i % 3))
|
||||
*p++ = ',';
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
||||
@@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
|
||||
int Compare(const void *a, const void *b) {
|
||||
struct Thing *x = (struct Thing *)a;
|
||||
struct Thing *y = (struct Thing *)b;
|
||||
if (x->i < y->i) return +1;
|
||||
if (x->i > y->i) return -1;
|
||||
if (x->i < y->i)
|
||||
return +1;
|
||||
if (x->i > y->i)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
|
||||
Append((uintptr_t)__oldstack, "__oldstack");
|
||||
for (int i = 0;; ++i) {
|
||||
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i]));
|
||||
if (!argv[i]) break;
|
||||
if (!argv[i])
|
||||
break;
|
||||
Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
|
||||
}
|
||||
for (int i = 0;; ++i) {
|
||||
Append((uintptr_t)&environ[i],
|
||||
xasprintf("&environ[%d] = %`'s", i, environ[i]));
|
||||
if (!environ[i]) break;
|
||||
if (!environ[i])
|
||||
break;
|
||||
Append((uintptr_t)environ[i],
|
||||
xasprintf("environ[%d] = %`'s", i, environ[i]));
|
||||
}
|
||||
for (int i = 0;; i += 2) {
|
||||
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i]));
|
||||
if (!__auxv[i]) break;
|
||||
if (!__auxv[i])
|
||||
break;
|
||||
Append((uintptr_t)&__auxv[i + 1],
|
||||
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <fenv.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
#include "libc/calls/struct/aarch64.internal.h"
|
||||
|
||||
/*
|
||||
Do you put lots of assert(!isnan(x)) in your code??
|
||||
Your microprocessor has a feature to automate this.
|
||||
|
||||
Uncaught SIGFPE (FPE_FLTINV)
|
||||
__math_invalidf at libc/tinymath/math_errf.c:88
|
||||
logf at libc/tinymath/logf.c:100
|
||||
main at examples/trapping.c:29
|
||||
cosmo at libc/runtime/cosmo.S:105
|
||||
_start at libc/crt/crt.S:116
|
||||
|
||||
This file shows how to use floating point exception
|
||||
trapping with Cosmopolitan Libc.
|
||||
*/
|
||||
|
||||
#define TRAPS (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
|
||||
|
||||
void spring_trap(int sig, siginfo_t *si, void *arg) {
|
||||
|
||||
// print signal safely
|
||||
const char *msg;
|
||||
int sic = si->si_code;
|
||||
if (sic == FPE_INTDIV)
|
||||
msg = "FPE_INTDIV: "; // integer divide by zero
|
||||
else if (sic == FPE_INTOVF)
|
||||
msg = "FPE_INTOVF: "; // integer overflow
|
||||
else if (sic == FPE_FLTDIV)
|
||||
msg = "FPE_FLTDIV: "; // floating point divide by zero
|
||||
else if (sic == FPE_FLTOVF)
|
||||
msg = "FPE_FLTOVF: "; // floating point overflow
|
||||
else if (sic == FPE_FLTUND)
|
||||
msg = "FPE_FLTUND: "; // floating point underflow
|
||||
else if (sic == FPE_FLTRES)
|
||||
msg = "FPE_FLTRES: "; // floating point inexact
|
||||
else if (sic == FPE_FLTINV)
|
||||
msg = "FPE_FLTINV: "; // invalid floating point operation
|
||||
else if (sic == FPE_FLTSUB)
|
||||
msg = "FPE_FLTSUB: "; // subscript out of range
|
||||
else
|
||||
msg = "SIGFPE: ";
|
||||
write(1, msg, strlen(msg));
|
||||
|
||||
// recover from trap so that execution may resume
|
||||
// without this the same signal will just keep getting raised
|
||||
ucontext_t *ctx = arg;
|
||||
#ifdef __x86_64__
|
||||
if (ctx->uc_mcontext.fpregs) {
|
||||
ctx->uc_mcontext.fpregs->mxcsr |= TRAPS << 7; // disable traps
|
||||
ctx->uc_mcontext.fpregs->mxcsr &= ~TRAPS; // clear cages
|
||||
return;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
struct _aarch64_ctx *ac;
|
||||
for (ac = (struct _aarch64_ctx *)ctx->uc_mcontext.__reserved; ac->magic;
|
||||
ac = (struct _aarch64_ctx *)((char *)ac + ac->size)) {
|
||||
if (ac->magic == FPSIMD_MAGIC) {
|
||||
struct fpsimd_context *sm = (struct fpsimd_context *)ac;
|
||||
sm->fpcr &= ~(TRAPS << 8); // disable traps
|
||||
sm->fpsr &= ~TRAPS; // clear cages
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// exit if we can't recover execution
|
||||
msg = "cannot recover from signal\n";
|
||||
write(1, msg, strlen(msg));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
void setup_trap(void) {
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = spring_trap;
|
||||
sigaction(SIGFPE, &sa, 0);
|
||||
}
|
||||
|
||||
void activate_trap(void) {
|
||||
feclearexcept(TRAPS);
|
||||
if (feenableexcept(TRAPS)) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
fprintf(stderr, "warning: trapping math isn't supported on this cpu\n");
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float ident(float x) {
|
||||
return x;
|
||||
}
|
||||
float (*veil)(float) = ident;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
float x;
|
||||
setup_trap();
|
||||
|
||||
// test illegal math
|
||||
activate_trap();
|
||||
x = 0 / veil(0);
|
||||
printf("0/0 = %g\n", x);
|
||||
|
||||
// test divide by zero
|
||||
activate_trap();
|
||||
x = 1 / veil(0);
|
||||
printf("1/0 = %g\n", x);
|
||||
|
||||
// test divide by zero again
|
||||
activate_trap();
|
||||
x = -1 / veil(0);
|
||||
printf("-1/0 = %g\n", x);
|
||||
|
||||
// test domain error
|
||||
activate_trap();
|
||||
x = logf(veil(-1));
|
||||
printf("log(-1) = %g\n", x);
|
||||
|
||||
// test imaginary number
|
||||
activate_trap();
|
||||
x = sqrtf(veil(-1));
|
||||
printf("sqrt(-1) = %g\n", x);
|
||||
|
||||
// test overflow
|
||||
activate_trap();
|
||||
x = expf(veil(88.8));
|
||||
printf("expf(88.8) = %g\n", x);
|
||||
|
||||
// test underflow
|
||||
activate_trap();
|
||||
x = expf(veil(-104));
|
||||
printf("expf(-104) = %g\n", x);
|
||||
}
|
||||
+2
-1
@@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
|
||||
dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
|
||||
if (iscntrl(code[0]) && !code[1]) {
|
||||
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
|
||||
if (code[0] == CTRL('C') || code[0] == CTRL('D'))
|
||||
break;
|
||||
} else if (startswith(code, "\e[") && endswith(code, "R")) {
|
||||
yn = 1, xn = 1;
|
||||
sscanf(code, "\e[%d;%dR", &yn, &xn);
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct utsname names;
|
||||
if (uname(&names)) return 1;
|
||||
if (uname(&names))
|
||||
return 1;
|
||||
printf("%-10s %`'s\n", "sysname", names.sysname);
|
||||
printf("%-10s %`'s\n", "release", names.release);
|
||||
printf("%-10s %`'s\n", "version", names.version);
|
||||
|
||||
+973
-496
File diff suppressed because it is too large.
Load diff
+4
-2
@@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
|
||||
int main(int argc, char *argv[]) {
|
||||
int flags = 0;
|
||||
const char *dir;
|
||||
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH;
|
||||
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS;
|
||||
if (argc > 2 && strchr(argv[2], 'd') != NULL)
|
||||
flags |= FTW_DEPTH;
|
||||
if (argc > 2 && strchr(argv[2], 'p') != NULL)
|
||||
flags |= FTW_PHYS;
|
||||
dir = argc < 2 ? "." : argv[1];
|
||||
if (nftw(dir, display_info, 20, flags) == -1) {
|
||||
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);
|
||||
|
||||
+8
-4
@@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
if (isatty(0) && (s = ttyname(0)))
|
||||
appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
@@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
if (i)
|
||||
appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
@@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) continue;
|
||||
if (g_verbose) perror(pts);
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
if (g_verbose)
|
||||
perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
|
||||
@@ -242,6 +242,7 @@ libc/isystem/system_error \
|
||||
libc/isystem/termios.h \
|
||||
libc/isystem/tgmath.h \
|
||||
libc/isystem/thread \
|
||||
libc/isystem/threads.h \
|
||||
libc/isystem/time.h \
|
||||
libc/isystem/tmmintrin.h \
|
||||
libc/isystem/tuple \
|
||||
|
||||
@@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
|
||||
t.sn[5] = 0;
|
||||
|
||||
if (IsLinux()) {
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
|
||||
if (sys_ioctl(fd, TIOCGPTN, &pty))
|
||||
return -1;
|
||||
t.sn[5] = 'p';
|
||||
t.sn[6] = 't';
|
||||
t.sn[7] = 's';
|
||||
|
||||
+3
-1
@@ -237,7 +237,9 @@ int sys_munlock(const void *, size_t) libcesque;
|
||||
int sys_munlockall(void) libcesque;
|
||||
int sys_personality(uint64_t) libcesque;
|
||||
int sys_ptrace(int, ...) libcesque;
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque;
|
||||
int sysctlbyname(const char *, void *, size_t *, void *, size_t) libcesque;
|
||||
int sysctlnametomib(const char *, int *, size_t *) libcesque;
|
||||
int tmpfd(void) libcesque;
|
||||
int touch(const char *, unsigned) libcesque;
|
||||
int unveil(const char *, const char *) libcesque;
|
||||
|
||||
@@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetspeed(struct termios *t, uint32_t speed) {
|
||||
if (cfsetispeed(t, speed) == -1) return -1;
|
||||
if (cfsetospeed(t, speed) == -1) return -1;
|
||||
if (cfsetispeed(t, speed) == -1)
|
||||
return -1;
|
||||
if (cfsetospeed(t, speed) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -33,7 +33,8 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
|
||||
char16_t var[4];
|
||||
|
||||
if (len && path[len - 1] != u'\\') {
|
||||
if (len + 2 > PATH_MAX) return enametoolong();
|
||||
if (len + 2 > PATH_MAX)
|
||||
return enametoolong();
|
||||
path[len + 0] = u'\\';
|
||||
path[len + 1] = u'\0';
|
||||
}
|
||||
@@ -84,7 +85,9 @@ textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
int len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (!len) return enoent();
|
||||
if ((len = __mkntpath(path, path16)) == -1)
|
||||
return -1;
|
||||
if (!len)
|
||||
return enoent();
|
||||
return sys_chdir_nt_impl(path16, len);
|
||||
}
|
||||
@@ -24,11 +24,16 @@
|
||||
|
||||
textwindows int _check_signal(bool restartable) {
|
||||
int status;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (!_weaken(__sig_check)) return 0;
|
||||
if (!(status = _weaken(__sig_check)())) return 0;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (status == 2 && restartable) return 0;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (!_weaken(__sig_check))
|
||||
return 0;
|
||||
if (!(status = _weaken(__sig_check)()))
|
||||
return 0;
|
||||
if (_check_cancel() == -1)
|
||||
return -1;
|
||||
if (status == 2 && restartable)
|
||||
return 0;
|
||||
return eintr();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* Changes permissions on file, e.g.:
|
||||
*
|
||||
* CHECK_NE(-1, chmod("foo/bar.txt", 0644));
|
||||
* CHECK_NE(-1, chmod("o/default/program.com", 0755));
|
||||
* CHECK_NE(-1, chmod("o/default/program", 0755));
|
||||
* CHECK_NE(-1, chmod("privatefolder/", 0700));
|
||||
*
|
||||
* The esoteric bits generally available on System Five are:
|
||||
|
||||
+3
-2
@@ -53,7 +53,7 @@ static dontinline int __clk_tck_init(void) {
|
||||
cmd[0] = 1; // CTL_KERN
|
||||
cmd[1] = 12; // KERN_CLOCKRATE
|
||||
len = sizeof(clock);
|
||||
if (sys_sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
|
||||
if (sysctl(cmd, 2, &clock, &len, NULL, 0) != -1) {
|
||||
x = clock.hz;
|
||||
} else {
|
||||
x = -1;
|
||||
@@ -61,7 +61,8 @@ static dontinline int __clk_tck_init(void) {
|
||||
} else {
|
||||
x = __getauxval(AT_CLKTCK).value;
|
||||
}
|
||||
if (x < 1) x = 100;
|
||||
if (x < 1)
|
||||
x = 100;
|
||||
clk_tck = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
||||
#ifdef __x86_64__
|
||||
// intel architecture guarantees that a mapping exists between rdtsc &
|
||||
// nanoseconds only if the cpu advertises invariant timestamps support
|
||||
if (!X86_HAVE(INVTSC)) return -EINVAL;
|
||||
if (!X86_HAVE(INVTSC))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
cosmo_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
|
||||
@@ -60,14 +60,17 @@ int sys_clock_gettime_xnu(int clock, struct timespec *ts) {
|
||||
}
|
||||
return 0;
|
||||
} else if (clock == CLOCK_MONOTONIC) {
|
||||
if (!ts) return 0;
|
||||
if (!ts)
|
||||
return 0;
|
||||
return sys_clock_gettime_mono(ts);
|
||||
} else if (clock == CLOCK_BOOTTIME) {
|
||||
struct timeval x;
|
||||
size_t n = sizeof(x);
|
||||
int mib[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1;
|
||||
if (ts) *ts = timeval_totimespec(timeval_sub(timeval_real(), x));
|
||||
if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1)
|
||||
return -1;
|
||||
if (ts)
|
||||
*ts = timeval_totimespec(timeval_sub(timeval_real(), x));
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
@@ -57,7 +57,8 @@ int cosmo_clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec quantum = timespec_fromnanos(1000000000 / CLK_TCK);
|
||||
clock_gettime(time_clock, &start);
|
||||
deadline = flags & TIMER_ABSTIME ? *req : timespec_add(start, *req);
|
||||
if (timespec_cmp(start, deadline) >= 0) return 0;
|
||||
if (timespec_cmp(start, deadline) >= 0)
|
||||
return 0;
|
||||
remain = timespec_sub(deadline, start);
|
||||
if (timespec_cmp(remain, quantum) > 0) {
|
||||
waitfor = timespec_sub(remain, quantum);
|
||||
|
||||
@@ -32,10 +32,13 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
|
||||
uint32_t msdelay;
|
||||
struct timespec now;
|
||||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (sys_clock_gettime_nt(clock, &now))
|
||||
return -1;
|
||||
if (timespec_cmp(now, abs) >= 0)
|
||||
return 0;
|
||||
msdelay = timespec_tomillis(timespec_sub(abs, now));
|
||||
if (_park_norestart(msdelay, waitmask)) return -1;
|
||||
if (_park_norestart(msdelay, waitmask))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +51,8 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = *req;
|
||||
} else {
|
||||
if ((rc = sys_clock_gettime_nt(clock, &now))) goto BailOut;
|
||||
if ((rc = sys_clock_gettime_nt(clock, &now)))
|
||||
goto BailOut;
|
||||
abs = timespec_add(now, *req);
|
||||
}
|
||||
rc = sys_clock_nanosleep_nt_impl(clock, abs, m);
|
||||
|
||||
@@ -46,7 +46,8 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
||||
} else {
|
||||
int rc;
|
||||
struct timespec beg;
|
||||
if (rem) sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
|
||||
if (rem)
|
||||
sys_clock_gettime_xnu(CLOCK_REALTIME, &beg);
|
||||
struct timeval rel = timespec_totimeval(*req); // rounds up
|
||||
rc = sys_select(0, 0, 0, 0, &rel);
|
||||
if (rc == -1 && rem && errno == EINTR) {
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_close_nt(int fd, int fildes) {
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
switch (f->kind) {
|
||||
case kFdZip:
|
||||
|
||||
+4
-2
@@ -97,12 +97,14 @@ int close(int fd) {
|
||||
BLOCK_SIGNALS;
|
||||
__fds_lock();
|
||||
rc = close_impl(fd);
|
||||
if (!__vforked) __releasefd(fd);
|
||||
if (!__vforked)
|
||||
__releasefd(fd);
|
||||
__fds_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
} else {
|
||||
rc = close_impl(fd);
|
||||
if (!__vforked) __releasefd(fd);
|
||||
if (!__vforked)
|
||||
__releasefd(fd);
|
||||
}
|
||||
STRACE("close(%d) → %d% m", fd, rc);
|
||||
return rc;
|
||||
|
||||
+6
-3
@@ -37,10 +37,13 @@ ssize_t copyfd(int in, int out, size_t n) {
|
||||
ssize_t dr, dw;
|
||||
for (i = 0; i < n; i += dr) {
|
||||
dr = read(in, buf, MIN(n - i, sizeof(buf)));
|
||||
if (dr == -1) return -1;
|
||||
if (!dr) break;
|
||||
if (dr == -1)
|
||||
return -1;
|
||||
if (!dr)
|
||||
break;
|
||||
dw = write(out, buf, dr);
|
||||
if (dw == -1) return -1;
|
||||
if (dw == -1)
|
||||
return -1;
|
||||
if (dw != dr) {
|
||||
// POSIX requires atomic IO up to PIPE_BUF
|
||||
// The minimum permissible PIPE_BUF is 512
|
||||
|
||||
@@ -156,9 +156,12 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
}
|
||||
|
||||
// Not certain yet what benefit these flags offer.
|
||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||
if (flags & _O_SEQUENTIAL)
|
||||
attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM)
|
||||
attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT)
|
||||
attr |= kNtFileFlagNoBuffering;
|
||||
|
||||
// TODO(jart): Should we *always* open with write permission if the
|
||||
// kernel will give it to us? We'd then deny write access
|
||||
@@ -172,9 +175,13 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
// writing to a file across a network can occasionally return
|
||||
// kNtErrorAccessDenied." -Quoth MSDN
|
||||
|
||||
if (out_perm) *out_perm = perm;
|
||||
if (out_share) *out_share = share;
|
||||
if (out_disp) *out_disp = disp;
|
||||
if (out_attr) *out_attr = attr;
|
||||
if (out_perm)
|
||||
*out_perm = perm;
|
||||
if (out_share)
|
||||
*out_share = share;
|
||||
if (out_disp)
|
||||
*out_disp = disp;
|
||||
if (out_attr)
|
||||
*out_attr = attr;
|
||||
return 0;
|
||||
}
|
||||
@@ -42,7 +42,8 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
|
||||
char16_t *p = a;
|
||||
const char *q = "\\\\?\\pipe\\cosmo\\";
|
||||
static atomic_uint x;
|
||||
while (*q) *p++ = *q++;
|
||||
while (*q)
|
||||
*p++ = *q++;
|
||||
p = itoa16(p, __pid);
|
||||
*p++ = '-';
|
||||
p = itoa16(p, atomic_fetch_add(&x, 1));
|
||||
|
||||
+4
-2
@@ -66,12 +66,14 @@
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (_weaken(kloghandle))
|
||||
_weaken(kloghandle)();
|
||||
#ifdef __aarch64__
|
||||
if (oldfd == newfd) {
|
||||
// linux aarch64 defines dup3() but not dup2(), which wasn't such a
|
||||
// great decision, since the two syscalls don't behave the same way
|
||||
if (!(rc = read(oldfd, 0, 0))) rc = oldfd;
|
||||
if (!(rc = read(oldfd, 0, 0)))
|
||||
rc = oldfd;
|
||||
} else
|
||||
#endif
|
||||
if (!IsWindows()) {
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
int rc;
|
||||
// helps guarantee stderr log gets duplicated before user closes
|
||||
if (_weaken(kloghandle)) _weaken(kloghandle)();
|
||||
if (_weaken(kloghandle))
|
||||
_weaken(kloghandle)();
|
||||
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
|
||||
rc = einval(); // NetBSD doesn't do this
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
|
||||
uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1)
|
||||
return -1;
|
||||
return __fix_enotdir(ntaccesscheck(path16, mode), path16);
|
||||
}
|
||||
@@ -64,7 +64,8 @@ int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
rc = _weaken(__zipos_access)(&zipname, amode);
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if (!flags) goto NoFlags;
|
||||
if (!flags)
|
||||
goto NoFlags;
|
||||
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = e;
|
||||
|
||||
@@ -37,8 +37,10 @@ static textwindows int sys_fadvise_nt_impl(int fd, uint64_t offset,
|
||||
int rc, flags, mode;
|
||||
uint32_t perm, share, attr;
|
||||
|
||||
if ((int64_t)len < 0) return einval();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if ((int64_t)len < 0)
|
||||
return einval();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return ebadf();
|
||||
h1 = g_fds.p[fd].handle;
|
||||
mode = g_fds.p[fd].mode;
|
||||
flags = g_fds.p[fd].flags;
|
||||
|
||||
@@ -27,7 +27,8 @@ int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
|
||||
|
||||
textwindows int sys_fchdir_nt(int dirfd) {
|
||||
char16_t dir[PATH_MAX];
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(dirfd, kFdFile))
|
||||
return ebadf();
|
||||
return sys_chdir_nt_impl(
|
||||
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos));
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
textwindows int sys_fchmod_nt(int fd, uint32_t mode) {
|
||||
|
||||
// validate file descriptor
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (g_fds.p[fd].kind == kFdEmpty) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
if (g_fds.p[fd].kind == kFdEmpty)
|
||||
return ebadf();
|
||||
|
||||
// get current information
|
||||
struct NtFileBasicInfo fbi;
|
||||
|
||||
@@ -26,7 +26,8 @@ textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
|
||||
int flags) {
|
||||
uint32_t attr;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1)
|
||||
return -1;
|
||||
if ((attr = GetFileAttributes(path16)) != -1u) {
|
||||
if (mode & 0222) {
|
||||
attr &= ~kNtFileAttributeReadonly;
|
||||
|
||||
@@ -36,7 +36,7 @@ int sys_fchmodat2(int, const char *, unsigned, int);
|
||||
* Changes permissions on file, e.g.:
|
||||
*
|
||||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "foo/bar.txt", 0644));
|
||||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "o/default/program.com", 0755));
|
||||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "o/default/program", 0755));
|
||||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "privatefolder/", 0700));
|
||||
*
|
||||
* @param path must exist
|
||||
|
||||
+10
-5
@@ -129,7 +129,8 @@ textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
|
||||
static textwindows int64_t GetfileSize(int64_t handle) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!GetFileInformationByHandle(handle, &wst)) return __winerr();
|
||||
if (!GetFileInformationByHandle(handle, &wst))
|
||||
return __winerr();
|
||||
return (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
|
||||
}
|
||||
|
||||
@@ -156,7 +157,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
break;
|
||||
case SEEK_END: {
|
||||
int64_t size;
|
||||
if ((size = GetfileSize(f->handle)) == -1) return -1;
|
||||
if ((size = GetfileSize(f->handle)) == -1)
|
||||
return -1;
|
||||
off = size - off;
|
||||
break;
|
||||
}
|
||||
@@ -254,7 +256,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
if (cmd == F_GETLK)
|
||||
return einval();
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
@@ -318,7 +321,8 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
if (start < 0)
|
||||
return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? _O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
@@ -328,7 +332,8 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdSocket) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdDevNull)) {
|
||||
__isfdkind(fd, kFdDevNull) || //
|
||||
__isfdkind(fd, kFdDevRandom)) {
|
||||
if (cmd == F_GETFL) {
|
||||
rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT |
|
||||
_O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL);
|
||||
|
||||
@@ -27,17 +27,23 @@
|
||||
|
||||
textwindows int sys_fdatasync_nt(int fd, bool fake) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return einval();
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval();
|
||||
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst)) return __winerr();
|
||||
if (!__isfdopen(fd))
|
||||
return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return einval();
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk)
|
||||
return einval();
|
||||
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst))
|
||||
return __winerr();
|
||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
// Flushing a directory handle is possible, but it needs
|
||||
// kNtGenericWrite access, and MSDN doesn't document it.
|
||||
return 0;
|
||||
}
|
||||
if (fake) return 0;
|
||||
if (_check_signal(false) == -1) return -1;
|
||||
if (fake)
|
||||
return 0;
|
||||
if (_check_signal(false) == -1)
|
||||
return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
textwindows int sys_flock_nt(int fd, int op) {
|
||||
int64_t h;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile))
|
||||
return ebadf();
|
||||
h = g_fds.p[fd].handle;
|
||||
struct NtOverlapped ov = {.hEvent = h};
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fstat_metal(int fd, struct stat *st) {
|
||||
if (fd < 0) return einval();
|
||||
if (fd < 0)
|
||||
return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
|
||||
bzero(st, sizeof(*st));
|
||||
st->st_dev = g_fds.p[fd].handle;
|
||||
|
||||
@@ -71,7 +71,7 @@ static textwindows long GetSizeOfReparsePoint(int64_t fh) {
|
||||
}
|
||||
}
|
||||
if (x >= 0200) {
|
||||
z += _bsrl(tpenc(x)) >> 3;
|
||||
z += bsrl(tpenc(x)) >> 3;
|
||||
}
|
||||
++z;
|
||||
}
|
||||
@@ -97,12 +97,14 @@ textwindows int sys_fstat_nt_special(int kind, struct stat *st) {
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt(int fd, struct stat *st) {
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
if (fd + 0u >= g_fds.n)
|
||||
return ebadf();
|
||||
switch (g_fds.p[fd].kind) {
|
||||
case kFdEmpty:
|
||||
return ebadf();
|
||||
case kFdConsole:
|
||||
case kFdDevNull:
|
||||
case kFdDevRandom:
|
||||
return sys_fstat_nt_special(g_fds.p[fd].kind, st);
|
||||
case kFdSocket:
|
||||
return sys_fstat_nt_socket(g_fds.p[fd].kind, st);
|
||||
@@ -174,7 +176,8 @@ textwindows int sys_fstat_nt_handle(int64_t handle, const char16_t *path,
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (!st.st_size) {
|
||||
long size = GetSizeOfReparsePoint(handle);
|
||||
if (size == -1) return -1;
|
||||
if (size == -1)
|
||||
return -1;
|
||||
st.st_size = size;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
static int Atoi(const char *str) {
|
||||
int c;
|
||||
unsigned x = 0;
|
||||
if (!*str) return -1;
|
||||
if (!*str)
|
||||
return -1;
|
||||
while ((c = *str++)) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
x *= 10;
|
||||
@@ -58,6 +59,8 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||
return sys_fstat_nt_special(kFdConsole, st);
|
||||
} else if (!strcmp(path + 5, "null")) {
|
||||
return sys_fstat_nt_special(kFdDevNull, st);
|
||||
} else if (!strcmp(path + 5, "random") || !strcmp(path + 5, "urandom")) {
|
||||
return sys_fstat_nt_special(kFdDevRandom, st);
|
||||
} else if (!strcmp(path + 5, "stdin")) {
|
||||
return sys_fstat_nt(STDIN_FILENO, st);
|
||||
} else if (!strcmp(path + 5, "stdout")) {
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static inline const char *__strace_fstatat_flags(char buf[12], int flags) {
|
||||
if (flags == AT_SYMLINK_NOFOLLOW) return "AT_SYMLINK_NOFOLLOW";
|
||||
if (flags == AT_SYMLINK_NOFOLLOW)
|
||||
return "AT_SYMLINK_NOFOLLOW";
|
||||
FormatInt32(buf, flags);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ textwindows int sys_fstatfs_nt(int64_t handle, struct statfs *f) {
|
||||
st = NtQueryVolumeInformationFile(handle, &io, &fs, sizeof(fs),
|
||||
kNtFileFsFullSizeInformation);
|
||||
if (!NtSuccess(st)) {
|
||||
if (st == kNtStatusDllNotFound) return enosys();
|
||||
if (st == kNtStatusDllNotFound)
|
||||
return enosys();
|
||||
return eio();
|
||||
}
|
||||
for (h = j = i = 0; FileSystemNameBuffer[i]; i++) {
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
int ftok(const char *path, int id) {
|
||||
struct stat st;
|
||||
if (stat(path, &st) == -1) return -1;
|
||||
if (stat(path, &st) == -1)
|
||||
return -1;
|
||||
return (uint32_t)id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff);
|
||||
}
|
||||
+2
-1
@@ -64,7 +64,8 @@ int getcpu(unsigned *out_opt_cpu, unsigned *out_opt_node) {
|
||||
}
|
||||
} else {
|
||||
int rc = sys_getcpu(&cpu, &node, 0);
|
||||
if (rc == -1) return -1;
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
}
|
||||
if (out_opt_cpu) {
|
||||
*out_opt_cpu = cpu;
|
||||
|
||||
@@ -51,7 +51,7 @@ static int __get_cpu_count_bsd(void) {
|
||||
} else {
|
||||
cmd[1] = HW_NCPU;
|
||||
}
|
||||
if (!sys_sysctl(cmd, 2, &c, &n, 0, 0)) {
|
||||
if (!sysctl(cmd, 2, &c, &n, 0, 0)) {
|
||||
return c;
|
||||
} else {
|
||||
return -1;
|
||||
|
||||
@@ -82,14 +82,17 @@ static dontinline textwindows int sys_getcwd_nt(char *buf, size_t size) {
|
||||
// get current directory from the system
|
||||
char16_t p16[PATH_MAX];
|
||||
uint32_t n = GetCurrentDirectory(PATH_MAX, p16);
|
||||
if (!n) return eacces(); // system call failed
|
||||
if (n >= PATH_MAX) return erange(); // not enough room?!?
|
||||
if (!n)
|
||||
return eacces(); // system call failed
|
||||
if (n >= PATH_MAX)
|
||||
return erange(); // not enough room?!?
|
||||
|
||||
// convert utf-16 to utf-8
|
||||
// we can't modify `buf` until we're certain of success
|
||||
char p8[PATH_MAX], *p = p8;
|
||||
n = tprecode16to8(p, PATH_MAX, p16).ax;
|
||||
if (n >= PATH_MAX) return erange(); // utf-8 explosion
|
||||
if (n >= PATH_MAX)
|
||||
return erange(); // utf-8 explosion
|
||||
|
||||
// turn \\?\c:\... into c:\...
|
||||
if (p[0] == '\\' && //
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
int gethostname_bsd(char *name, size_t len, int kind) {
|
||||
int cmd[2] = {CTL_KERN, kind};
|
||||
if (sys_sysctl(cmd, 2, name, &len, 0, 0) != -1) {
|
||||
if (sysctl(cmd, 2, name, &len, 0, 0) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
if (errno == ENOMEM) {
|
||||
|
||||
@@ -43,7 +43,8 @@ struct loadavg {
|
||||
int getloadavg(double *a, int n) {
|
||||
// cat /proc/loadavg
|
||||
int i, rc;
|
||||
if (n > 3) n = 3;
|
||||
if (n > 3)
|
||||
n = 3;
|
||||
if (!n) {
|
||||
rc = 0;
|
||||
} else if (n < 0) {
|
||||
@@ -63,7 +64,7 @@ int getloadavg(double *a, int n) {
|
||||
struct loadavg loadinfo;
|
||||
int mib[2] = {CTL_VM, VM_LOADAVG};
|
||||
size = sizeof(loadinfo);
|
||||
if ((rc = sys_sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) {
|
||||
if ((rc = sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) {
|
||||
for (i = 0; i < n; i++) {
|
||||
a[i] = (double)loadinfo.ldavg[i] / loadinfo.fscale;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static int OldApeLoader(char *s) {
|
||||
(!strncmp((b = basename(s)), ".ape-", 5) && AllNumDot(b + 5));
|
||||
}
|
||||
|
||||
static char *CopyWithCwd(const char *q, char *p, char *e) {
|
||||
static int CopyWithCwd(const char *q, char *p, char *e) {
|
||||
char c;
|
||||
if (*q != '/') {
|
||||
if (q[0] == '.' && q[1] == '/') {
|
||||
@@ -109,27 +109,19 @@ static char *CopyWithCwd(const char *q, char *p, char *e) {
|
||||
if (p + 1 /* nul */ < e) {
|
||||
*p++ = c;
|
||||
} else {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
return p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if q exists then turn it into an absolute path. we also try adding
|
||||
// a .com suffix since the ape auto-appends it when resolving
|
||||
static int TryPath(const char *q, int com) {
|
||||
char *p;
|
||||
if (!(p = CopyWithCwd(q, g_prog.u.buf,
|
||||
g_prog.u.buf + sizeof(g_prog.u.buf) - com * 4))) {
|
||||
// if q exists then turn it into an absolute path.
|
||||
static int TryPath(const char *q) {
|
||||
if (!CopyWithCwd(q, g_prog.u.buf, g_prog.u.buf + sizeof(g_prog.u.buf))) {
|
||||
return 0;
|
||||
}
|
||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return 1;
|
||||
if (!com) return 0;
|
||||
p = WRITE32LE(p, READ32LE(".com"));
|
||||
*p = 0;
|
||||
if (!sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0)) return 1;
|
||||
return 0;
|
||||
return !sys_faccessat(AT_FDCWD, g_prog.u.buf, F_OK, 0);
|
||||
}
|
||||
|
||||
// if the loader passed a relative path, prepend cwd to it.
|
||||
@@ -203,7 +195,7 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
|
||||
}
|
||||
cmd[3] = -1; // current process
|
||||
if (sys_sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
||||
if (sysctl(cmd, ARRAYLEN(cmd), b, &n, 0, 0) != -1) {
|
||||
if (!OldApeLoader(b)) {
|
||||
goto UseBuf;
|
||||
}
|
||||
@@ -219,13 +211,13 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// don't trust argument parsing if set-id.
|
||||
// don't trust argv or envp if set-id.
|
||||
if (issetugid()) {
|
||||
goto UseEmpty;
|
||||
}
|
||||
|
||||
// try argv[0], then argv[0].com, then $_, then $_.com.
|
||||
if (TryPath(__argv[0], 1) || TryPath(__getenv(__envp, "_").s, 1)) {
|
||||
// try argv[0], then then $_.
|
||||
if (TryPath(__argv[0]) || TryPath(__getenv(__envp, "_").s)) {
|
||||
goto UseBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ static ssize_t GetRandomCpu(char *p, size_t n, int f, bool impl(uint64_t *)) {
|
||||
for (i = 0; i < n; i += j) {
|
||||
TryAgain:
|
||||
if (!impl(&x)) {
|
||||
if (f || i >= 256) break;
|
||||
if (f || i >= 256)
|
||||
break;
|
||||
goto TryAgain;
|
||||
}
|
||||
for (j = 0; j < 8 && i + j < n; ++j) {
|
||||
|
||||
Loaded 100 of 1184 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user