mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3093f0e467 | ||
|
|
3609f65de3 | ||
|
|
9906f299bb | ||
|
|
1d8f37a2f0 | ||
|
|
e677460d14 | ||
|
|
4937843f70 | ||
|
|
b003888696 | ||
|
|
2ca491dc56 | ||
|
|
9aa353d88b | ||
|
|
c67faf61df | ||
|
|
165c6b37e2 | ||
|
|
dcd626edf8 | ||
|
|
f032b5570b | ||
|
|
ea081b262c | ||
|
|
fae1c32267 | ||
|
|
9b6718ac99 | ||
|
|
cd672e251f | ||
|
|
500a47bc2f | ||
|
|
e4d25d68e4 | ||
|
|
f31a98d50a | ||
|
|
2816df59b2 | ||
|
|
a05ce3ad9d | ||
|
|
7c8df05042 | ||
|
|
4c77acdfcf | ||
|
|
b74b974cfd | ||
|
|
07cef612c3 | ||
|
|
deaef81463 | ||
|
|
c638eabfe0 | ||
|
|
8e68384e15 | ||
|
|
2f4ca71f26 | ||
|
|
07004ebf04 | ||
|
|
086d7006da | ||
|
|
0a51241f7a | ||
|
|
c68f6599e5 | ||
|
|
af3f62a71a | ||
|
|
6cf9b9e0fc | ||
|
|
1d4b452839 | ||
|
|
c2db3b703a | ||
|
|
edb03b89d8 | ||
|
|
7724664b13 | ||
|
|
1df4296208 | ||
|
|
ce9aeb2aed | ||
|
|
ed93fc3dd7 | ||
|
|
5f61d273e4 | ||
|
|
bf3531de81 | ||
|
|
3b0ea2db4d | ||
|
|
f029375d39 | ||
|
|
9b87dd2b87 | ||
|
|
787b04f752 | ||
|
|
0768807935 | ||
|
|
0b59f01b43 | ||
|
|
cf70a44756 | ||
|
|
a52792c59f | ||
|
|
65c9b28e99 | ||
|
|
4292348707 | ||
|
|
2ec20b6c4c | ||
|
|
47183551d6 | ||
|
|
42891e82bb | ||
|
|
624119ea38 | ||
|
|
2f3c6e7cc3 | ||
|
|
13b9ecd537 | ||
|
|
6659981457 | ||
|
|
ae2a7ac844 | ||
|
|
793393a341 | ||
|
|
952b9009e8 | ||
|
|
8f18b3ad65 | ||
|
|
56e0fd9d1d | ||
|
|
df68a6362b | ||
|
|
19c81863a3 | ||
|
|
7d31fc311a | ||
|
|
57c0b065c8 | ||
|
|
a6ecbb747d | ||
|
|
3bf95ae7ec | ||
|
|
5fd7b07fac | ||
|
|
317c8bc312 | ||
|
|
2a1f352622 | ||
|
|
06d916b449 | ||
|
|
9ea64725b6 | ||
|
|
f9fc7eb49f | ||
|
|
b0df6c1fce | ||
|
|
d5ebb1fa5b | ||
|
|
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 | ||
|
|
c8383f25b4 | ||
|
|
64a9e6fe56 | ||
|
|
0ef36489c8 | ||
|
|
7c7bf4bb90 | ||
|
|
592f6ebc20 | ||
|
|
af8f2bd19f | ||
|
|
38bceaeb8f | ||
|
|
99f0491f04 | ||
|
|
e72a88ea70 | ||
|
|
9b4701b3bc | ||
|
|
f7ff515961 | ||
|
|
3afe3a3646 | ||
|
|
b4faaa7c57 | ||
|
|
c4991e53ac | ||
|
|
ad3944a3b6 | ||
|
|
29eac8e2a2 | ||
|
|
a5a3e78fcf | ||
|
|
e9a756e78b | ||
|
|
38af54a2dd | ||
|
|
77a92f517b | ||
|
|
3eb405e0e2 | ||
|
|
68b9479f0c | ||
|
|
d9df41c4d5 | ||
|
|
fc3c536ec2 | ||
|
|
77ddf4cb07 | ||
|
|
4d018306b3 | ||
|
|
b3bb93d1d9 | ||
|
|
980af27bbf |
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
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Run this command to always ignore formatting commits in git blame
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
|
||||
# Ran clang-format
|
||||
f032b5570b4cd87c6bb4abb54c0b98e69c939955
|
||||
# Applied clang-format update to repo
|
||||
6e6fc38935054db0534d5af4fb99c6193305b946
|
||||
# revert retabbing
|
||||
2b315626f3af765cdfbc61114647412cdb798b3a
|
||||
# more modeline errata
|
||||
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
|
||||
# fix more vi modelines
|
||||
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
|
||||
# flip et/noet in modelines
|
||||
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
|
||||
# fix vi modelines
|
||||
394d998315f613a888cc6b6c051d4163bdf5cd6f
|
||||
# clang-format
|
||||
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
|
||||
# ape-m1 formatting cleanup
|
||||
da8baf2aa5ce93b958aca90a0ae69f537806324b
|
||||
# Run clang-format on most sources
|
||||
369f9740de4534c28d0e81ab2afc99decbb9a3e6
|
||||
Vendored
-108
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
|
||||
"defines": [
|
||||
"libcesque=",
|
||||
"pureconst=",
|
||||
"paramsnonnull(x)=",
|
||||
"alignas(x)",
|
||||
"alignof(x)",
|
||||
"artificial=",
|
||||
"__wur=",
|
||||
"mayalias=",
|
||||
"forceinline=",
|
||||
"forcealign(x)=",
|
||||
"scanfesque(x)=",
|
||||
"strftimeesque(x)=",
|
||||
"wontreturn=",
|
||||
"textreal=",
|
||||
"mallocesque=",
|
||||
"callocesque=",
|
||||
"vallocesque=",
|
||||
"reallocesque=",
|
||||
"strlenesque=",
|
||||
"memcpyesque=",
|
||||
"hasatleast=",
|
||||
"noinline=",
|
||||
"textexit=",
|
||||
"returnstwice=",
|
||||
"textwindows=",
|
||||
"privileged=",
|
||||
"dontinstrument=",
|
||||
"nodebuginfo=",
|
||||
"interruptfn=",
|
||||
"optimizespeed=",
|
||||
"forcealignargpointer=",
|
||||
"dontasan=",
|
||||
"dontubsan=",
|
||||
"donothing=",
|
||||
"nosideeffect=",
|
||||
"unreachable=",,
|
||||
"notpossible=",
|
||||
"thatispacked=",
|
||||
"dontthrow=",
|
||||
"dontcallback=",
|
||||
"relegated=",
|
||||
"hidden=",
|
||||
"textstartup=",
|
||||
"returnsnonnull=",
|
||||
"returnspointerwithnoaliases=",
|
||||
"printfesque(x)=",
|
||||
"attributeallocsize(x)=",
|
||||
"returnsaligned(x)=",
|
||||
"attributeallocalign(x)=",
|
||||
"nullterminated(x)="
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "gnu17",
|
||||
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
|
||||
"compilerArgs": [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-fdebug-prefix-map=${workspaceFolder}=",
|
||||
"-frecord-gcc-switches",
|
||||
"-Wa,-W",
|
||||
"-Wa,-I.",
|
||||
"-Wa,--noexecstack",
|
||||
"-Og",
|
||||
"-g",
|
||||
"-gdescribe-dies",
|
||||
"-msse3",
|
||||
"-mno-red-zone",
|
||||
"-fno-math-errno",
|
||||
"-fno-trapping-math",
|
||||
"-fno-fp-int-builtin-inexact",
|
||||
"-fno-ident",
|
||||
"-fno-common",
|
||||
"-fno-gnu-unique",
|
||||
"-fstrict-aliasing",
|
||||
"-fstrict-overflow",
|
||||
"-fno-semantic-interposition",
|
||||
"-mno-omit-leaf-frame-pointer",
|
||||
"-fno-jump-tables",
|
||||
"-nostdinc",
|
||||
"-iquote."
|
||||
],
|
||||
"forcedInclude": [
|
||||
"libc/integral/normalize.inc"
|
||||
],
|
||||
"defines": [
|
||||
"COSMO",
|
||||
"MODE="
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
#define __VSCODE_INTELLISENSE__ 1
|
||||
#include "libc/integral/normalize.inc"
|
||||
+41
-35
@@ -16,10 +16,25 @@ contributors who prefer to remain anonymous to the public.
|
||||
|
||||
The first time you send a pull request, you need to send an email to
|
||||
Justine Tunney <jtunney@gmail.com> stating that you intend to assign her
|
||||
the copyright to the changes you contribute to Cosmopolitan. This only
|
||||
applies to the code you *choose* to contribute. It only has to happen
|
||||
once. The email should be sent from an email address associated with
|
||||
your identity. Your email should link to your pull request.
|
||||
the copyright to the changes you contribute to Cosmopolitan. It only
|
||||
needs to happen once. This only applies to the code you *choose* to
|
||||
contribute. The email should be sent from an email address associated
|
||||
with your identity. Your email should link to your pull request.
|
||||
|
||||
To make things easy, here's an example of a good email you can use:
|
||||
|
||||
> **From**: YOUR NAME ([email protected])
|
||||
> **To**: Justine Tunney ([email protected])
|
||||
> **Subject**: Cosmopolitan Copyright Assignment for YOUR NAME
|
||||
>
|
||||
> Hi Justine,
|
||||
>
|
||||
> I made my first contribution to Cosmopolitan in
|
||||
> https://github.com/jart/cosmopolitan/pull/XXXX could you please take a
|
||||
> look? I intend to assign you the copyright to the changes I contribute
|
||||
> to Cosmopolitan.
|
||||
>
|
||||
> Thanks!
|
||||
|
||||
Please note that in order to give Justine the copyright, it has to be
|
||||
yours to give in the first place. If you're employed, then you should
|
||||
@@ -38,6 +53,27 @@ owners and the code should go in the `third_party/` folder. Every third
|
||||
party project should have a `README.cosmo` file that documents its
|
||||
provenance as well as any local changes you've made.
|
||||
|
||||
## Copyright Policy Exceptions
|
||||
|
||||
### Tests
|
||||
|
||||
You're encoraged to claim ownership of your test code. If you add a new
|
||||
file under the `test/` directory, then you should put your name in the
|
||||
ISC license header at the top of the file. If you add new test cases to
|
||||
an existing unit test file, then you're encouraged to append a line with
|
||||
your name to the existing copyright header of that file.
|
||||
|
||||
### Exceptional Features
|
||||
|
||||
Let's say you discovered a faster better way to implement `log10()` and
|
||||
you want to give it to Cosmopolitan. In cases like this, it really isn't
|
||||
appropriate for Justine to own your code. What you could do instead, is
|
||||
write your own new and improved `log10.c` from scratch, put your name on
|
||||
the top with the ISC license, and then add a `__notice()` directive so
|
||||
that your name will be embedded inside every executable that links the
|
||||
`log10()` function. This will help you get your name out there. Please
|
||||
note you need get approval from Justine each time you want to do this.
|
||||
|
||||
## Style Guide
|
||||
|
||||
You can use clang-format to automatically format your files:
|
||||
@@ -47,34 +83,4 @@ clang-format -i -style=file tool/net/redbean.c
|
||||
```
|
||||
|
||||
If you use Emacs this can be automated on save for Cosmopolitan using
|
||||
[tool/emacs/cosmo-format.el]([tool/emacs/cosmo-format.el]).
|
||||
|
||||
### Source Files
|
||||
|
||||
- Must use include paths relative to the root of the repository
|
||||
- Must have comment at top of file documenting copyright and license
|
||||
- Must have notice embedding if not owned by Justine (exception: tests)
|
||||
- May use language extensions that are supported by both GCC and Clang
|
||||
- Should use Google indentation (otherwise use `/* clang-format off */`)
|
||||
- Should use asm() instead of compiler APIs (exception: ctz, clz, memcpy)
|
||||
|
||||
### Header Files
|
||||
|
||||
- Must not have copyright or license comments
|
||||
- Must have once guards (otherwise change `.h` to `.inc`)
|
||||
- Must be ANSI C89 compatible to be included in the amalgamation header
|
||||
- Must include its dependencies (exception: libc/integral/normalize.inc)
|
||||
- Must not define objects (i.e. `cc -c -xc foo.h` will produce empty `.o`)
|
||||
- Should not use typedefs
|
||||
- Should not use forward declarations
|
||||
- Should not include documentation comments
|
||||
- Should not include parameter names in prototypes
|
||||
- Should not pose problems if included by C++ or Assembly sources
|
||||
- Should not declare non-ANSI code, at all, when the user requests ANSI
|
||||
|
||||
### Build Config
|
||||
|
||||
- Must not write files outside `o/`
|
||||
- Must not communicate with Internet
|
||||
- Must not depend on system libraries
|
||||
- Must not depend on system commands (exception: sh, make, gzip, zip)
|
||||
[tool/emacs/cosmo-format.el](tool/emacs/cosmo-format.el).
|
||||
@@ -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))
|
||||
|
||||
@@ -149,9 +149,9 @@ export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.3
|
||||
COSMOCC = .cosmocc/3.3.5
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3 d26ec8f4e48f6db004fc6a9677c7ff3b50c3b21e936e9393158aa2ed51b0b549)
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.5 db78fd8d3f8706e9dff4be72bf71d37a3f12062f212f407e1c33bc4af3780dd0)
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
@@ -174,6 +174,7 @@ all: o
|
||||
o: o/$(MODE)
|
||||
o/$(MODE): \
|
||||
o/$(MODE)/ape \
|
||||
o/$(MODE)/ctl \
|
||||
o/$(MODE)/dsp \
|
||||
o/$(MODE)/net \
|
||||
o/$(MODE)/libc \
|
||||
@@ -187,7 +188,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),)
|
||||
@@ -206,7 +207,7 @@ endif
|
||||
.UNVEIL += \
|
||||
libc/integral \
|
||||
libc/stdbool.h \
|
||||
rwc:/dev/shm \
|
||||
rwc:/dev/shm \
|
||||
rx:.cosmocc \
|
||||
rx:build/bootstrap \
|
||||
r:build/portcosmo.h \
|
||||
@@ -255,10 +256,11 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
|
||||
include libc/proc/BUILD.mk # │ You can now use threads
|
||||
include libc/dlopen/BUILD.mk # │ You can now use processes
|
||||
include libc/thread/BUILD.mk # │ You can finally call malloc()
|
||||
include ctl/BUILD.mk # │
|
||||
include third_party/zlib/BUILD.mk # │
|
||||
include libc/stdio/BUILD.mk # │
|
||||
include tool/hello/BUILD.mk # │
|
||||
include libc/time/BUILD.mk # │
|
||||
include third_party/tz/BUILD.mk # │
|
||||
include net/BUILD.mk # │
|
||||
include third_party/vqsort/BUILD.mk # │
|
||||
include libc/log/BUILD.mk # │
|
||||
@@ -297,7 +299,9 @@ include third_party/nsync/testing/BUILD.mk
|
||||
include libc/testlib/BUILD.mk
|
||||
include tool/viz/lib/BUILD.mk
|
||||
include tool/args/BUILD.mk
|
||||
include test/math/BUILD.mk
|
||||
include test/posix/BUILD.mk
|
||||
include test/ctl/BUILD.mk
|
||||
include test/libcxx/BUILD.mk
|
||||
include test/tool/args/BUILD.mk
|
||||
include third_party/linenoise/BUILD.mk
|
||||
@@ -361,7 +365,6 @@ include test/libc/fmt/BUILD.mk
|
||||
include test/libc/time/BUILD.mk
|
||||
include test/libc/proc/BUILD.mk
|
||||
include test/libc/stdio/BUILD.mk
|
||||
include test/libc/release/BUILD.mk
|
||||
include test/libc/BUILD.mk
|
||||
include test/net/http/BUILD.mk
|
||||
include test/net/https/BUILD.mk
|
||||
@@ -414,17 +417,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}' | $<
|
||||
|
||||
@@ -439,7 +442,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
LIBC_TIME \
|
||||
THIRD_PARTY_TZ \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
@@ -451,6 +454,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_THREAD \
|
||||
LIBC_PROC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
CTL \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_DLOPEN \
|
||||
@@ -504,7 +508,6 @@ COSMOPOLITAN_H_PKGS = \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_VGA \
|
||||
@@ -520,6 +523,7 @@ COSMOPOLITAN_H_PKGS = \
|
||||
|
||||
COSMOCC_PKGS = \
|
||||
$(COSMOPOLITAN_H_PKGS) \
|
||||
CTL \
|
||||
THIRD_PARTY_AARCH64 \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
@@ -542,23 +546,14 @@ COSMOPOLITAN_H_ROOT_HDRS = \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
|
||||
|
||||
o/cosmopolitan.h.txt: Makefile
|
||||
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
|
||||
|
||||
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 @$< >>$@
|
||||
|
||||
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 %.cc,$(SRCS)) \
|
||||
$(filter-out %.cpp,$(filter-out %.cc,$(SRCS))) \
|
||||
$(HDRS)
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cpp,$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg -J \
|
||||
-fno-common -include libc/integral/normalize.inc -o $@ \
|
||||
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
|
||||
|
||||
@@ -572,7 +567,6 @@ $(SRCS): \
|
||||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
TOOLCHAIN_ARTIFACTS = \
|
||||
o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
@@ -581,13 +575,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 \
|
||||
@@ -595,9 +589,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
|
||||
|
||||
+20
-3
@@ -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 \
|
||||
@@ -254,7 +254,24 @@ o/$(MODE)/ape: $(APE_CHECKS) \
|
||||
endif
|
||||
|
||||
# these assembly files are safe to build on aarch64
|
||||
o/$(MODE)/ape/ape.o: ape/ape.S
|
||||
o/$(MODE)/ape/ape.o: \
|
||||
ape/ape.S \
|
||||
ape/ape.h \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
ape/relocations.h \
|
||||
libc/thread/tls.h \
|
||||
ape/ape.internal.h \
|
||||
ape/macros.internal.h \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
o/$(MODE)/ape/ape.lds: \
|
||||
|
||||
+3
-4
@@ -293,7 +293,6 @@ _tdata_size = _tdata_end - _tdata_start;
|
||||
_tbss_size = _tbss_end - _tbss_start;
|
||||
_tbss_offset = _tbss_start - _tdata_start;
|
||||
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
|
||||
_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
|
||||
|
||||
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
|
||||
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
|
||||
_tdata_align = ALIGNOF(.tdata);
|
||||
_tbss_align = ALIGNOF(.tbss);
|
||||
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
|
||||
+82
-29
@@ -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
|
||||
@@ -140,6 +146,9 @@ struct Syslib {
|
||||
#define AT_RANDOM 25
|
||||
#define AT_EXECFN 31
|
||||
|
||||
#define EF_APE_MODERN 0x101ca75
|
||||
#define EF_APE_MODERN_MASK 0x1ffffff
|
||||
|
||||
#define AUXV_WORDS 31
|
||||
|
||||
/* from the xnu codebase */
|
||||
@@ -148,8 +157,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 +230,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 +287,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 +324,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 +340,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 +391,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 +561,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 +615,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 +645,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 +662,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 +693,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 +723,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 +754,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -759,7 +802,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
}
|
||||
|
||||
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
const char *exe, int fd, long *sp, long *auxv,
|
||||
char *exe, int fd, long *sp, long *auxv,
|
||||
char *execfn) {
|
||||
long i, rc;
|
||||
unsigned size;
|
||||
@@ -780,6 +823,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
if (e->e_machine != EM_AARCH64) {
|
||||
return "couldn't find ELF header with ARM64 machine type";
|
||||
}
|
||||
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
|
||||
/* change argv[0] to resolved path for older binaries */
|
||||
((char **)(sp + 1))[0] = exe;
|
||||
}
|
||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||
Pexit(exe, 0, "e_phentsize is wrong");
|
||||
}
|
||||
@@ -790,8 +837,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 +997,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 +1022,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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 nofixeol :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
@@ -196,7 +196,7 @@ ape_mz:
|
||||
.quad ape_elf_entry // 18: e_entry
|
||||
.quad ape_elf_phoff // 20: e_phoff
|
||||
.quad ape_elf_shoff // 28: e_shoff
|
||||
.long 0 // 30: e_flags
|
||||
.long 0x101ca75 // 30: ape e_flags
|
||||
.short 64 // 34: e_ehsize
|
||||
.short 56 // 36: e_phentsize
|
||||
.short ape_elf_phnum // 38: e_phnum
|
||||
@@ -669,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.shstub ape_elf_entry,8 // 18: e_entry
|
||||
.shstub ape_elf_phoff,8 // 20: e_phoff
|
||||
.shstub ape_elf_shoff,8 // 28: e_shoff
|
||||
.ascii "\\0\\0\\0\\0" // 30: e_flags
|
||||
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
|
||||
.ascii "\\100\\0" // 34: e_ehsize
|
||||
.ascii "\\070\\0" // 36: e_phentsize
|
||||
.shstub ape_elf_phnum,2 // 38: e_phnum
|
||||
@@ -1036,7 +1036,7 @@ ape_pe: .ascin "PE",4
|
||||
.quad ape_pe_base // ImageBase
|
||||
.long ape_pe_sectionalignment // SectionAlignment
|
||||
.long ape_pe_filealignment // FileAlignment
|
||||
.short v_ntversion // MajorOperatingSystemVersion
|
||||
.short 10 // MajorOperatingSystemVersion
|
||||
.short 0 // MinorOperatingSystemVersion
|
||||
.short 0 // MajorImageVersion
|
||||
.short 0 // MinorImageVersion
|
||||
|
||||
+4
-2
@@ -528,6 +528,7 @@ SECTIONS {
|
||||
*(.piro.data.sort.iat.*)
|
||||
#endif
|
||||
*(__patchable_function_entries)
|
||||
*(.note.gnu.property)
|
||||
*(__mcount_loc)
|
||||
*(.rela.dyn)
|
||||
*(.discard)
|
||||
@@ -552,7 +553,9 @@ _tdata_size = _tdata_end - _tdata_start;
|
||||
_tbss_size = _tbss_end - _tbss_start;
|
||||
_tbss_offset = _tbss_start - _tdata_start;
|
||||
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
|
||||
_tls_align = 1;
|
||||
_tdata_align = ALIGNOF(.tdata);
|
||||
_tbss_align = ALIGNOF(.tbss);
|
||||
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
|
||||
|
||||
ape_cod_offset = 0;
|
||||
ape_cod_vaddr = ADDR(.head);
|
||||
@@ -712,7 +715,6 @@ ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
|
||||
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
|
||||
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
|
||||
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
|
||||
v_ntversion = LINK_WINDOWS ? 6 : 1;
|
||||
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
|
||||
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
|
||||
v_ntsubsystem = (LINK_WINDOWS
|
||||
|
||||
+13
-6
@@ -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
|
||||
@@ -137,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
uname_r="$(uname -r)"
|
||||
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
|
||||
FLAGS=FP
|
||||
else
|
||||
FLAGS=F
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo registering APE with binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
||||
+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
|
||||
|
||||
+67
-30
@@ -152,6 +152,9 @@
|
||||
#define PR_SET_MM 35
|
||||
#define PR_SET_MM_EXE_FILE 13
|
||||
|
||||
#define EF_APE_MODERN 0x101ca75
|
||||
#define EF_APE_MODERN_MASK 0x1ffffff
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
|
||||
@@ -228,13 +231,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 +358,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 +368,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 +536,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 +550,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 +571,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 +584,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 +614,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 +678,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 +712,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 +729,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 +767,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 +789,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 +811,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");
|
||||
}
|
||||
@@ -808,6 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
return "couldn't find ELF header with x86-64 machine type";
|
||||
}
|
||||
#endif
|
||||
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
|
||||
/* change argv[0] to resolved path for older binaries */
|
||||
((char **)(sp + 1))[0] = exe;
|
||||
}
|
||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||
Pexit(os, exe, 0, "e_phentsize is wrong");
|
||||
}
|
||||
@@ -818,8 +851,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 +984,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 +1057,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;
|
||||
}
|
||||
|
||||
+15
-26
@@ -132,7 +132,7 @@
|
||||
#define SHSTUB2(SYM, X) \
|
||||
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
|
||||
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
|
||||
#define BCD_SMEAR(X) ((X) + (X) * 10000)
|
||||
#define BCD_SMEAR(X) ((X) + (X)*10000)
|
||||
#define BCD_LEFT(X) \
|
||||
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
|
||||
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
|
||||
@@ -140,23 +140,16 @@
|
||||
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
|
||||
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + \
|
||||
(X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + \
|
||||
((X) / 10) % 10 + \
|
||||
(X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + \
|
||||
((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + \
|
||||
(X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 ? 0x30303030 + \
|
||||
((X) / 1000) % 10 + \
|
||||
((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + \
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + (X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 \
|
||||
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
@@ -165,15 +158,11 @@
|
||||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
@@ -16,6 +16,8 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_start[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_end[] __attribute__((__weak__));
|
||||
extern unsigned char _tls_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tdata_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_align[] __attribute__((__weak__));
|
||||
extern unsigned char __test_start[] __attribute__((__weak__));
|
||||
extern unsigned char __ro[] __attribute__((__weak__));
|
||||
extern unsigned char __data_start[] __attribute__((__weak__));
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Executable
BIN
Binary file not shown.
Binary file not shown.
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.
+11
-11
@@ -11,20 +11,20 @@
|
||||
#
|
||||
ifeq ($(MODE),)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
ifeq ($(MODE), x86_64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
@@ -38,13 +38,13 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), zero)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-zero)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0 -fdce
|
||||
OVERRIDE_CXXFLAGS += -O0 -fdce
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
@@ -81,7 +81,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), opt)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
|
||||
TARGET_ARCH ?= -march=native
|
||||
@@ -98,7 +98,7 @@ endif
|
||||
# - Turns off support for other operating systems
|
||||
#
|
||||
ifeq ($(MODE), optlinux)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
@@ -140,7 +140,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), asan)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
@@ -160,7 +160,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
|
||||
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
|
||||
@@ -170,7 +170,7 @@ QUOTA ?= -C64 -L300
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
@@ -189,7 +189,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
|
||||
@@ -60,13 +60,10 @@ TMPSAFE = $(TMPDIR)/
|
||||
endif
|
||||
|
||||
BACKTRACES = \
|
||||
-fno-schedule-insns2 \
|
||||
-fno-optimize-sibling-calls \
|
||||
-mno-omit-leaf-frame-pointer
|
||||
|
||||
ifneq ($(ARCH), aarch64)
|
||||
BACKTRACES += -fno-schedule-insns2
|
||||
endif
|
||||
|
||||
SANITIZER = \
|
||||
-fsanitize=address
|
||||
|
||||
@@ -95,7 +92,6 @@ DEFAULT_CCFLAGS += \
|
||||
DEFAULT_COPTS ?= \
|
||||
-fno-ident \
|
||||
-fno-common \
|
||||
-fno-math-errno \
|
||||
-fno-gnu-unique \
|
||||
-fstrict-aliasing \
|
||||
-fstrict-overflow \
|
||||
@@ -128,6 +124,7 @@ ifeq ($(ARCH), aarch64)
|
||||
DEFAULT_COPTS += \
|
||||
-ffixed-x18 \
|
||||
-ffixed-x28 \
|
||||
-fsigned-char \
|
||||
-mno-outline-atomics
|
||||
endif
|
||||
|
||||
@@ -148,12 +145,14 @@ DEFAULT_CFLAGS = \
|
||||
-std=gnu2x
|
||||
|
||||
DEFAULT_CXXFLAGS = \
|
||||
-std=gnu++20 \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-fuse-cxa-atexit \
|
||||
-Wno-int-in-bool-context \
|
||||
-Wno-narrowing \
|
||||
-Wno-literal-suffix
|
||||
-Wno-literal-suffix \
|
||||
-isystem third_party/libcxx
|
||||
|
||||
DEFAULT_ASFLAGS = \
|
||||
-W \
|
||||
@@ -260,12 +259,12 @@ LD.libs = \
|
||||
$(LIBS)
|
||||
|
||||
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
|
||||
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
|
||||
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
|
||||
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
|
||||
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
|
||||
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
|
||||
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
|
||||
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
|
||||
|
||||
+8
-8
@@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
|
||||
fi
|
||||
|
||||
find_objdump() {
|
||||
if [ -x .cosmocc/3.3/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.3/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.3/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.3/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3/bin/$1-linux-musl-objdump"
|
||||
if [ -x .cosmocc/3.3.5/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.3.5/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump"
|
||||
else
|
||||
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
|
||||
exit 1
|
||||
|
||||
+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)) {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
BasedOnStyle: Mozilla
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
---
|
||||
Language: Cpp
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AlignTrailingComments: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
FixNamespaceComments: true
|
||||
---
|
||||
@@ -0,0 +1,48 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
|
||||
|
||||
PKGS += CTL
|
||||
|
||||
CTL_ARTIFACTS += CTL_A
|
||||
CTL = $(CTL_A_DEPS) $(CTL_A)
|
||||
CTL_A = o/$(MODE)/ctl/ctl.a
|
||||
CTL_A_FILES := $(wildcard ctl/*)
|
||||
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
|
||||
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
|
||||
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
CTL_A_CHECKS = \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
|
||||
|
||||
CTL_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_STR \
|
||||
|
||||
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(CTL_A): ctl/ \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_OBJS)
|
||||
|
||||
$(CTL_A).pkg: \
|
||||
$(CTL_A_OBJS) \
|
||||
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(CTL_A_OBJS): private \
|
||||
OVERRIDE_CXXFLAGS += \
|
||||
-Wframe-larger-than=4096 \
|
||||
-Walloca-larger-than=4096 \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
|
||||
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
|
||||
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
|
||||
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
|
||||
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
|
||||
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
|
||||
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
|
||||
|
||||
.PHONY: o/$(MODE)/ctl
|
||||
o/$(MODE)/ctl: $(CTL_CHECKS)
|
||||
+5015
File diff suppressed because it is too large.
Load diff
+129
@@ -0,0 +1,129 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#define COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/swap.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
class optional
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
~optional() = default;
|
||||
|
||||
optional() noexcept : present_(false)
|
||||
{
|
||||
}
|
||||
|
||||
optional(const T& value) : present_(true), value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
optional(T&& value) : present_(true), value_(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
optional(const optional& other) : present_(other.present_)
|
||||
{
|
||||
if (present_)
|
||||
new (&value_) T(other.value_);
|
||||
}
|
||||
|
||||
optional(optional&& other) noexcept : present_(other.present_)
|
||||
{
|
||||
if (present_)
|
||||
value_ = std::move(other.value_);
|
||||
}
|
||||
|
||||
optional& operator=(const optional& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
present_ = other.present_;
|
||||
if (present_)
|
||||
value_ = other.value_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=(optional&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
present_ = other.present_;
|
||||
if (present_)
|
||||
value_ = std::move(other.value_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& value() &
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return value_;
|
||||
}
|
||||
|
||||
const T& value() const&
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return value_;
|
||||
}
|
||||
|
||||
T&& value() &&
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return std::move(value_);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return present_;
|
||||
}
|
||||
|
||||
bool has_value() const noexcept
|
||||
{
|
||||
return present_;
|
||||
}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
if (present_) {
|
||||
value_.~T();
|
||||
present_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
present_ = true;
|
||||
value_ = T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void swap(optional& other) noexcept
|
||||
{
|
||||
if (present_ && other.present_) {
|
||||
std::swap(value_, other.value_);
|
||||
} else if (present_) {
|
||||
other.emplace(std::move(value_));
|
||||
reset();
|
||||
} else if (other.present_) {
|
||||
emplace(std::move(other.value_));
|
||||
other.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool present_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
@@ -0,0 +1,44 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <stdckdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
string
|
||||
strcat(const string_view lhs, const string_view rhs) noexcept
|
||||
{
|
||||
string res;
|
||||
size_t need;
|
||||
if (ckd_add(&need, lhs.n, rhs.n))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
res.reserve(need);
|
||||
if (lhs.n)
|
||||
memcpy(res.p, lhs.p, lhs.n);
|
||||
if (rhs.n)
|
||||
memcpy(res.p + lhs.n, rhs.p, rhs.n);
|
||||
res.p[res.n = lhs.n + rhs.n] = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,43 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string_view.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
int
|
||||
strcmp(const string_view lhs, const string_view rhs) noexcept
|
||||
{
|
||||
int r;
|
||||
size_t m = lhs.n;
|
||||
if ((m = rhs.n < m ? rhs.n : m)) {
|
||||
if (!m)
|
||||
return 0;
|
||||
if ((r = memcmp(lhs.p, rhs.p, m)))
|
||||
return r;
|
||||
}
|
||||
if (lhs.n == rhs.n)
|
||||
return 0;
|
||||
if (m < lhs.n)
|
||||
return +1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <__atomic/fence.h>
|
||||
#include <stdckdint.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
string::~string() noexcept
|
||||
{
|
||||
if (n) {
|
||||
if (n >= c)
|
||||
__builtin_trap();
|
||||
if (p[n])
|
||||
__builtin_trap();
|
||||
}
|
||||
if (c && !p)
|
||||
__builtin_trap();
|
||||
free(p);
|
||||
}
|
||||
|
||||
string::string(const char* s) noexcept
|
||||
{
|
||||
append(s, strlen(s));
|
||||
}
|
||||
|
||||
string::string(const string& s) noexcept
|
||||
{
|
||||
append(s.p, s.n);
|
||||
}
|
||||
|
||||
string::string(const string_view s) noexcept
|
||||
{
|
||||
append(s.p, s.n);
|
||||
}
|
||||
|
||||
string::string(size_t size, char ch) noexcept
|
||||
{
|
||||
resize(size, ch);
|
||||
}
|
||||
|
||||
string::string(const char* s, size_t size) noexcept
|
||||
{
|
||||
append(s, size);
|
||||
}
|
||||
|
||||
const char*
|
||||
string::c_str() const noexcept
|
||||
{
|
||||
if (!n)
|
||||
return "";
|
||||
if (n >= c)
|
||||
__builtin_trap();
|
||||
if (p[n])
|
||||
__builtin_trap();
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
string::reserve(size_t c2) noexcept
|
||||
{
|
||||
char* p2;
|
||||
if (c2 < n)
|
||||
c2 = n;
|
||||
if (ckd_add(&c2, c2, 15))
|
||||
__builtin_trap();
|
||||
c2 &= -16;
|
||||
if (!(p2 = (char*)realloc(p, c2)))
|
||||
__builtin_trap();
|
||||
std::atomic_signal_fence(std::memory_order_seq_cst);
|
||||
c = c2;
|
||||
p = p2;
|
||||
}
|
||||
|
||||
void
|
||||
string::resize(size_t n2, char ch) noexcept
|
||||
{
|
||||
size_t c2;
|
||||
if (ckd_add(&c2, n2, 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
if (n2 > n)
|
||||
memset(p + n, ch, n2 - n);
|
||||
p[n = n2] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::append(char ch) noexcept
|
||||
{
|
||||
if (n + 2 > c) {
|
||||
size_t c2 = c + 2;
|
||||
c2 += c2 >> 1;
|
||||
reserve(c2);
|
||||
}
|
||||
p[n++] = ch;
|
||||
p[n] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::grow(size_t size) noexcept
|
||||
{
|
||||
size_t need;
|
||||
if (ckd_add(&need, n, size))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
if (need <= c)
|
||||
return;
|
||||
size_t c2 = c;
|
||||
if (!c2) {
|
||||
c2 = need;
|
||||
} else {
|
||||
while (c2 < need)
|
||||
if (ckd_add(&c2, c2, c2 >> 1))
|
||||
__builtin_trap();
|
||||
}
|
||||
reserve(c2);
|
||||
}
|
||||
|
||||
void
|
||||
string::append(char ch, size_t size) noexcept
|
||||
{
|
||||
grow(size);
|
||||
if (size)
|
||||
memset(p + n, ch, size);
|
||||
p[n += size] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::append(const void* data, size_t size) noexcept
|
||||
{
|
||||
grow(size);
|
||||
if (size)
|
||||
memcpy(p + n, data, size);
|
||||
p[n += size] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::pop_back() noexcept
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
p[--n] = 0;
|
||||
}
|
||||
|
||||
string&
|
||||
string::operator=(string&& s) noexcept
|
||||
{
|
||||
if (p != s.p) {
|
||||
if (p) {
|
||||
clear();
|
||||
append(s.p, s.n);
|
||||
} else {
|
||||
p = s.p;
|
||||
n = s.n;
|
||||
c = s.c;
|
||||
s.p = nullptr;
|
||||
s.n = 0;
|
||||
s.c = 0;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
string::operator==(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return false;
|
||||
if (!n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::operator!=(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return true;
|
||||
if (!n)
|
||||
return false;
|
||||
return !!memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::contains(const string_view s) const noexcept
|
||||
{
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !!memmem(p, n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::ends_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p + n - s.n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::starts_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, s.n);
|
||||
}
|
||||
|
||||
size_t
|
||||
string::find(char ch, size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if ((q = (char*)memchr(p, ch, n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t
|
||||
string::find(const string_view s, size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
string
|
||||
string::substr(size_t pos, size_t count) const noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if (count > n - pos)
|
||||
count = n - pos;
|
||||
if (ckd_add(&last, pos, count))
|
||||
last = n;
|
||||
if (last > n)
|
||||
__builtin_trap();
|
||||
return string(p + pos, count);
|
||||
}
|
||||
|
||||
string&
|
||||
string::replace(size_t pos, size_t count, const string_view& s) noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (ckd_add(&last, pos, count))
|
||||
__builtin_trap();
|
||||
if (last > n)
|
||||
__builtin_trap();
|
||||
size_t need;
|
||||
if (ckd_add(&need, pos, s.n))
|
||||
__builtin_trap();
|
||||
size_t extra = n - last;
|
||||
if (ckd_add(&need, need, extra))
|
||||
__builtin_trap();
|
||||
size_t c2;
|
||||
if (ckd_add(&c2, need, 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
if (extra)
|
||||
memmove(p + pos + s.n, p + last, extra);
|
||||
memcpy(p + pos, s.p, s.n);
|
||||
p[n = need] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::insert(size_t i, const string_view s) noexcept
|
||||
{
|
||||
if (i > n)
|
||||
__builtin_trap();
|
||||
size_t extra = n - i;
|
||||
size_t need;
|
||||
if (ckd_add(&need, n, s.n))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
reserve(need);
|
||||
if (extra)
|
||||
memmove(p + i + s.n, p + i, extra);
|
||||
memcpy(p + i, s.p, s.n);
|
||||
p[n += s.n] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::erase(size_t pos, size_t count) noexcept
|
||||
{
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if (count > n - pos)
|
||||
count = n - pos;
|
||||
size_t extra = n - (pos + count);
|
||||
if (extra)
|
||||
memmove(p + pos, p + pos + count, extra);
|
||||
p[n = pos + extra] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_STRING_H_
|
||||
#define COSMOPOLITAN_CTL_STRING_H_
|
||||
#include "string_view.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string;
|
||||
|
||||
string
|
||||
strcat(const string_view, const string_view) noexcept __wur;
|
||||
|
||||
struct string
|
||||
{
|
||||
char* p = nullptr;
|
||||
size_t n = 0;
|
||||
size_t c = 0;
|
||||
|
||||
using iterator = char*;
|
||||
using const_iterator = const char*;
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
~string() noexcept;
|
||||
string() = default;
|
||||
string(const string_view) noexcept;
|
||||
string(const char*) noexcept;
|
||||
string(const string&) noexcept;
|
||||
string(const char*, size_t) noexcept;
|
||||
explicit string(size_t, char = 0) noexcept;
|
||||
string& operator=(string&&) noexcept;
|
||||
const char* c_str() const noexcept;
|
||||
|
||||
void pop_back() noexcept;
|
||||
void grow(size_t) noexcept;
|
||||
void reserve(size_t) noexcept;
|
||||
void resize(size_t, char = 0) noexcept;
|
||||
void append(char) noexcept;
|
||||
void append(char, size_t) noexcept;
|
||||
void append(unsigned long) noexcept;
|
||||
void append(const void*, size_t) noexcept;
|
||||
string& insert(size_t, const string_view) noexcept;
|
||||
string& erase(size_t = 0, size_t = npos) noexcept;
|
||||
string substr(size_t = 0, size_t = npos) const noexcept;
|
||||
string& replace(size_t, size_t, const string_view&) noexcept;
|
||||
bool operator==(const string_view) const noexcept;
|
||||
bool operator!=(const string_view) const noexcept;
|
||||
bool contains(const string_view) const noexcept;
|
||||
bool ends_with(const string_view) const noexcept;
|
||||
bool starts_with(const string_view) const noexcept;
|
||||
size_t find(char, size_t = 0) const noexcept;
|
||||
size_t find(const string_view, size_t = 0) const noexcept;
|
||||
|
||||
string(string&& s) noexcept : p(s.p), n(s.n), c(s.c)
|
||||
{
|
||||
s.p = nullptr;
|
||||
s.n = 0;
|
||||
s.c = 0;
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
n = 0;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return !n;
|
||||
}
|
||||
|
||||
char* data() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t size() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t length() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t capacity() const noexcept
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
iterator end() noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
char& front()
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
const char& front() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
char& back()
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
const char& back() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
char& operator[](size_t i) noexcept
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
const char& operator[](size_t i) const noexcept
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
void push_back(char ch) noexcept
|
||||
{
|
||||
append(ch);
|
||||
}
|
||||
|
||||
void append(const string_view s) noexcept
|
||||
{
|
||||
append(s.p, s.n);
|
||||
}
|
||||
|
||||
inline constexpr operator string_view() const noexcept
|
||||
{
|
||||
return string_view(p, n);
|
||||
}
|
||||
|
||||
string& operator=(const char* s) noexcept
|
||||
{
|
||||
clear();
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(const string_view s) noexcept
|
||||
{
|
||||
clear();
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(char x) noexcept
|
||||
{
|
||||
append(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(const string_view s) noexcept
|
||||
{
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string operator+(const string_view s) const noexcept
|
||||
{
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
int compare(const string_view s) const noexcept
|
||||
{
|
||||
return strcmp(*this, s);
|
||||
}
|
||||
|
||||
bool operator<(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) > 0;
|
||||
}
|
||||
|
||||
bool operator>=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
inline ctl::string
|
||||
operator"" s(const char* s, size_t n)
|
||||
{
|
||||
return ctl::string(s, n);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_STRING_H_
|
||||
@@ -0,0 +1,111 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string_view.h"
|
||||
|
||||
#include <stdckdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
size_t
|
||||
string_view::find(char ch, size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (n && (q = (char*)memchr(p, ch, n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t
|
||||
string_view::find(const string_view s, size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
string_view
|
||||
string_view::substr(size_t pos, size_t count) const noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if (count > n - pos)
|
||||
count = n - pos;
|
||||
if (ckd_add(&last, pos, count))
|
||||
last = n;
|
||||
if (last > n)
|
||||
__builtin_trap();
|
||||
return string_view(p + pos, count);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::operator==(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return false;
|
||||
if (!n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::operator!=(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return true;
|
||||
if (!n)
|
||||
return false;
|
||||
return !!memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::contains(const string_view s) const noexcept
|
||||
{
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !!memmem(p, n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::ends_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p + n - s.n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::starts_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, s.n);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,159 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
#define COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string_view;
|
||||
|
||||
int
|
||||
strcmp(const string_view, const string_view) noexcept;
|
||||
|
||||
struct string_view
|
||||
{
|
||||
const char* p;
|
||||
size_t n;
|
||||
|
||||
using iterator = const char*;
|
||||
using const_iterator = const char*;
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
constexpr string_view() noexcept : p(nullptr), n(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr string_view(const char* s) noexcept
|
||||
: p(s), n(s ? __builtin_strlen(s) : 0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr string_view(const char* s, size_t n) noexcept : p(s), n(n)
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr ~string_view() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const string_view) const noexcept;
|
||||
bool operator!=(const string_view) const noexcept;
|
||||
bool contains(const string_view) const noexcept;
|
||||
bool ends_with(const string_view) const noexcept;
|
||||
bool starts_with(const string_view) const noexcept;
|
||||
string_view substr(size_t = 0, size_t = npos) const noexcept;
|
||||
size_t find(char, size_t = 0) const noexcept;
|
||||
size_t find(const string_view, size_t = 0) const noexcept;
|
||||
|
||||
constexpr string_view& operator=(const string_view& s) noexcept
|
||||
{
|
||||
p = s.p;
|
||||
n = s.n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return !n;
|
||||
}
|
||||
|
||||
constexpr const char* data() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr size_t size() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr size_t length() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr const char& operator[](size_t i) const noexcept
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
constexpr void remove_prefix(size_t count)
|
||||
{
|
||||
if (count > n)
|
||||
__builtin_trap();
|
||||
p += count;
|
||||
n -= count;
|
||||
}
|
||||
|
||||
constexpr void remove_suffix(size_t count)
|
||||
{
|
||||
if (count > n)
|
||||
__builtin_trap();
|
||||
n -= count;
|
||||
}
|
||||
|
||||
constexpr const char& front() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
constexpr const char& back() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr const_iterator end() noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
int compare(const string_view s) const noexcept
|
||||
{
|
||||
return strcmp(*this, s);
|
||||
}
|
||||
|
||||
bool operator<(const string_view& s) const noexcept
|
||||
{
|
||||
return compare(s) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(const string_view& s) const noexcept
|
||||
{
|
||||
return compare(s) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(const string_view& s) const noexcept
|
||||
{
|
||||
return compare(s) > 0;
|
||||
}
|
||||
|
||||
bool operator>=(const string_view& s) const noexcept
|
||||
{
|
||||
return compare(s) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#define COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/swap.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct vector
|
||||
{
|
||||
size_t n = 0;
|
||||
size_t c = 0;
|
||||
T* p = nullptr;
|
||||
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
|
||||
vector() = default;
|
||||
|
||||
~vector()
|
||||
{
|
||||
delete[] p;
|
||||
}
|
||||
|
||||
vector(const vector& other)
|
||||
{
|
||||
n = other.n;
|
||||
c = other.c;
|
||||
p = new T[c];
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
new (&p[i]) T(other.p[i]);
|
||||
}
|
||||
|
||||
vector(vector&& other) noexcept
|
||||
{
|
||||
n = other.n;
|
||||
c = other.c;
|
||||
p = other.p;
|
||||
other.n = 0;
|
||||
other.c = 0;
|
||||
other.p = nullptr;
|
||||
}
|
||||
|
||||
explicit vector(size_t count, const T& value = T())
|
||||
{
|
||||
n = count;
|
||||
c = count;
|
||||
p = new T[c];
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
new (&p[i]) T(value);
|
||||
}
|
||||
|
||||
vector& operator=(const vector& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
T* newData = new T[other.c];
|
||||
for (size_t i = 0; i < other.n; ++i) {
|
||||
newData[i] = other.p[i];
|
||||
}
|
||||
delete[] p;
|
||||
p = newData;
|
||||
n = other.n;
|
||||
c = other.c;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector& operator=(vector&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
delete[] p;
|
||||
p = other.p;
|
||||
n = other.n;
|
||||
c = other.c;
|
||||
other.p = nullptr;
|
||||
other.n = 0;
|
||||
other.c = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return !n;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
T& operator[](size_t i)
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
const T& operator[](size_t i) const
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
T& front()
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
const T& front() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
T& back()
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
const T& back() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
p[i].~T();
|
||||
n = 0;
|
||||
}
|
||||
|
||||
void reserve(size_t c2)
|
||||
{
|
||||
if (c2 <= c)
|
||||
return;
|
||||
T* newP = new T[c2];
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
newP[i] = std::move(p[i]);
|
||||
delete[] p;
|
||||
p = newP;
|
||||
c = c2;
|
||||
}
|
||||
|
||||
void push_back(const T& e)
|
||||
{
|
||||
if (n == c) {
|
||||
size_t c2 = c + 1;
|
||||
c2 += c2 >> 1;
|
||||
reserve(c2);
|
||||
}
|
||||
new (&p[n]) T(e);
|
||||
++n;
|
||||
}
|
||||
|
||||
void push_back(T&& e)
|
||||
{
|
||||
if (n == c) {
|
||||
size_t c2 = c + 1;
|
||||
c2 += c2 >> 1;
|
||||
reserve(c2);
|
||||
}
|
||||
new (&p[n]) T(std::forward<T>(e));
|
||||
++n;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void emplace_back(Args&&... args)
|
||||
{
|
||||
if (n == c) {
|
||||
size_t c2 = c + 1;
|
||||
c2 += c2 >> 1;
|
||||
reserve(c2);
|
||||
}
|
||||
new (&p[n]) T(std::forward<Args>(args)...);
|
||||
++n;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (n > 0) {
|
||||
--n;
|
||||
p[n].~T();
|
||||
}
|
||||
}
|
||||
|
||||
void resize(size_t n2)
|
||||
{
|
||||
if (n2 > n) {
|
||||
reserve(n2);
|
||||
for (size_t i = n; i < n2; ++i)
|
||||
new (&p[i]) T();
|
||||
} else if (n2 < n) {
|
||||
for (size_t i = n2; i < n; ++i)
|
||||
p[i].~T();
|
||||
}
|
||||
n = n2;
|
||||
}
|
||||
|
||||
void swap(vector& other) noexcept
|
||||
{
|
||||
std::swap(n, other.n);
|
||||
std::swap(c, other.c);
|
||||
std::swap(p, other.p);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
+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;
|
||||
}
|
||||
+2
-2
@@ -9,8 +9,8 @@ int mulaw(int);
|
||||
int unmulaw(int);
|
||||
void *double2byte(long, const void *, double, double) vallocesque;
|
||||
void *byte2double(long, const void *, double, double) vallocesque;
|
||||
void *dct(float[restrict hasatleast 8][8], unsigned,
|
||||
float, float, float, float, float);
|
||||
void *dct(float[restrict hasatleast 8][8], unsigned, float, float, float, float,
|
||||
float);
|
||||
void *dctjpeg(float[restrict hasatleast 8][8], unsigned);
|
||||
double det3(const double[3][3]) nosideeffect;
|
||||
void *inv3(double[restrict 3][3], const double[restrict 3][3], double);
|
||||
|
||||
+2
-2
@@ -65,8 +65,8 @@
|
||||
*
|
||||
* @cost ~100ns
|
||||
*/
|
||||
void *dct(float M[restrict hasatleast 8][8], unsigned stride,
|
||||
float c0, float c1, float c2, float c3, float c4) {
|
||||
void *dct(float M[restrict hasatleast 8][8], unsigned stride, float c0,
|
||||
float c1, float c2, float c3, float c4) {
|
||||
unsigned y, x;
|
||||
for (y = 0; y < stride * 8; y += stride) {
|
||||
DCT(M[y][0], M[y][1], M[y][2], M[y][3], M[y][4], M[y][5], M[y][6], M[y][7],
|
||||
|
||||
+1
-1
@@ -16,8 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/gamma.h"
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/math.h"
|
||||
|
||||
double rgb2stdpc(double x, double g) {
|
||||
|
||||
+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;
|
||||
}
|
||||
@@ -35,7 +35,6 @@ DSP_MPEG_A_DIRECTDEPS = \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
||||
|
||||
+2
-1
@@ -64,7 +64,8 @@ forceinline bool plm_buffer_has(plm_buffer_t *b, size_t bits) {
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_read(plm_buffer_t *self, int count) {
|
||||
if (!plm_buffer_has(self, count)) return 0;
|
||||
if (!plm_buffer_has(self, count))
|
||||
return 0;
|
||||
int value = 0;
|
||||
while (count) {
|
||||
int current_byte = self->bytes[self->bit_index >> 3];
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define START_PACK 0xBA
|
||||
#define START_END 0xB9
|
||||
#define START_PACK 0xBA
|
||||
#define START_END 0xB9
|
||||
#define START_SYSTEM 0xBB
|
||||
|
||||
typedef struct plm_demux_t {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "libc/x/x.h"
|
||||
__static_yoink("pl_mpeg_notice");
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ DSP_SCALE_A_DIRECTDEPS = \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X
|
||||
|
||||
|
||||
+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);
|
||||
|
||||
@@ -38,7 +38,6 @@ DSP_TTY_A_DIRECTDEPS = \
|
||||
LIBC_SOCK \
|
||||
LIBC_SYSV \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TIME \
|
||||
LIBC_X
|
||||
|
||||
DSP_TTY_A_DEPS := \
|
||||
|
||||
+6
-2
@@ -24,9 +24,13 @@
|
||||
* The alternate buffer trick lets one restore the console exactly as it
|
||||
* was, once the program is done running.
|
||||
*/
|
||||
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
|
||||
int ttyenablealtbuf(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[?1049h");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to restore blinking box thing.
|
||||
*/
|
||||
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }
|
||||
int ttydisablealtbuf(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[?1049l");
|
||||
}
|
||||
@@ -30,8 +30,10 @@
|
||||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (__nocolor) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (__nocolor)
|
||||
return 0;
|
||||
if (visible)
|
||||
code[5] = 'h';
|
||||
if (IsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
ntcursor.bVisible = visible;
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
/**
|
||||
* Asks teletypewriter to push current position.
|
||||
*/
|
||||
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
|
||||
int ttysavecursor(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[s");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to pop previous position.
|
||||
*/
|
||||
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }
|
||||
int ttyrestorecursor(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[u");
|
||||
}
|
||||
+14
-6
@@ -21,22 +21,30 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
char *setbg16_(char *p, struct TtyRgb bg) { return setansibgfg(p, bg.xt, -1u); }
|
||||
char *setfg16_(char *p, struct TtyRgb fg) { return setansibgfg(p, -1u, fg.xt); }
|
||||
char *setbg16_(char *p, struct TtyRgb bg) {
|
||||
return setansibgfg(p, bg.xt, -1u);
|
||||
}
|
||||
char *setfg16_(char *p, struct TtyRgb fg) {
|
||||
return setansibgfg(p, -1u, fg.xt);
|
||||
}
|
||||
char *setbgfg16_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
|
||||
return setansibgfg(p, bg.xt, fg.xt);
|
||||
}
|
||||
+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;
|
||||
|
||||
+9
-5
@@ -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);
|
||||
}
|
||||
@@ -84,10 +87,11 @@ static textexit void ttyraw_onexit(void) {
|
||||
ttyraw_disable();
|
||||
}
|
||||
|
||||
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
|
||||
static relegated void ttyraw_onsig(int sig, siginfo_t *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) {
|
||||
|
||||
+106
-104
@@ -14,130 +14,131 @@ 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_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_TZ \
|
||||
THIRD_PARTY_VQSORT \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
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 +146,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 \
|
||||
@@ -154,7 +155,8 @@ o/$(MODE)/examples/picol.com.dbg: \
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/usr/share/dict/words.zip.o: private ZIPOBJ_FLAGS += -C2
|
||||
o/$(MODE)/examples/wut.o: private COPTS += -fopenmp
|
||||
|
||||
o/$(MODE)/examples/blas.o: private COPTS += -O3 -fopenmp
|
||||
|
||||
$(EXAMPLES_OBJS): examples/BUILD.mk
|
||||
|
||||
@@ -166,8 +168,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)
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
__static_yoink("__die");
|
||||
__static_yoink("GetSymbolByAddr");
|
||||
__static_yoink("malloc_inspect_all");
|
||||
|
||||
char *lol(int n) {
|
||||
return malloc(n);
|
||||
}
|
||||
|
||||
char *(*pLol)(int) = lol;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *s = pLol(4);
|
||||
s[4] = 1;
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "libc/assert.h"
|
||||
|
||||
// high performance high accuracy matrix multiplication in ansi c
|
||||
|
||||
#define MATH __target_clones("avx512f,fma")
|
||||
|
||||
namespace {
|
||||
namespace ansiBLAS {
|
||||
|
||||
static constexpr int KN = 8;
|
||||
|
||||
struct Vector {
|
||||
double v[KN];
|
||||
};
|
||||
|
||||
Vector load(const float *p) {
|
||||
Vector x;
|
||||
for (int i = 0; i < KN; ++i)
|
||||
x.v[i] = p[i];
|
||||
return x;
|
||||
}
|
||||
|
||||
Vector madd(Vector x, Vector y, Vector s) {
|
||||
for (int i = 0; i < KN; ++i)
|
||||
s.v[i] = fma(x.v[i], y.v[i], s.v[i]);
|
||||
return s;
|
||||
}
|
||||
|
||||
float hsum(Vector x) {
|
||||
double s = 0;
|
||||
for (int i = 0; i < KN; ++i)
|
||||
s += x.v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
struct ansiBLAS {
|
||||
public:
|
||||
ansiBLAS(int k, const float *A, int lda, const float *B, int ldb, float *C,
|
||||
int ldc, int ith, int nth)
|
||||
: k(k),
|
||||
A(A),
|
||||
lda(lda),
|
||||
B(B),
|
||||
ldb(ldb),
|
||||
C(C),
|
||||
ldc(ldc),
|
||||
ith(ith),
|
||||
nth(nth) {
|
||||
}
|
||||
|
||||
void matmul(int m, int n) {
|
||||
mnpack(0, m, 0, n);
|
||||
}
|
||||
|
||||
private:
|
||||
void mnpack(int m0, int m, int n0, int n) {
|
||||
int mc, nc, mp, np;
|
||||
if (m - m0 <= 0 || n - n0 <= 0)
|
||||
return;
|
||||
if (m - m0 >= 4 && n - n0 >= 3) {
|
||||
mc = 4;
|
||||
nc = 3;
|
||||
gemm<4, 3>(m0, m, n0, n);
|
||||
} else {
|
||||
mc = 1;
|
||||
nc = 1;
|
||||
gemm<1, 1>(m0, m, n0, n);
|
||||
}
|
||||
mp = m0 + (m - m0) / mc * mc;
|
||||
np = n0 + (n - n0) / nc * nc;
|
||||
mnpack(mp, m, n0, np);
|
||||
mnpack(m0, m, np, n);
|
||||
}
|
||||
|
||||
template <int RM, int RN>
|
||||
MATH void gemm(int m0, int m, int n0, int n) {
|
||||
int ytiles = (m - m0) / RM;
|
||||
int xtiles = (n - n0) / RN;
|
||||
int tiles = xtiles * ytiles;
|
||||
int duty = (tiles + nth - 1) / nth;
|
||||
int start = duty * ith;
|
||||
int end = start + duty;
|
||||
if (end > tiles)
|
||||
end = tiles;
|
||||
for (int job = start; job < end; ++job) {
|
||||
int ii = m0 + job / xtiles * RM;
|
||||
int jj = n0 + job % xtiles * RN;
|
||||
Vector Cv[RN][RM] = {};
|
||||
for (int l = 0; l < k; l += KN)
|
||||
for (int j = 0; j < RN; ++j)
|
||||
for (int i = 0; i < RM; ++i)
|
||||
Cv[j][i] = madd(load(A + lda * (ii + i) + l), //
|
||||
load(B + ldb * (jj + j) + l), //
|
||||
Cv[j][i]);
|
||||
for (int j = 0; j < RN; ++j)
|
||||
for (int i = 0; i < RM; ++i)
|
||||
C[ldc * (jj + j) + (ii + i)] = hsum(Cv[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
const int k;
|
||||
const float *const A;
|
||||
const int lda;
|
||||
const float *const B;
|
||||
const int ldb;
|
||||
float *const C;
|
||||
const int ldc;
|
||||
const int ith;
|
||||
const int nth;
|
||||
};
|
||||
|
||||
void sgemm(int m, int n, int k, //
|
||||
const float *A, int lda, //
|
||||
const float *B, int ldb, //
|
||||
float *C, int ldc) {
|
||||
int nth = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#pragma omp parallel for
|
||||
for (int ith = 0; ith < nth; ++ith) {
|
||||
ansiBLAS tb{k, A, lda, B, ldb, C, ldc, ith, nth};
|
||||
tb.matmul(m, n);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ansiBLAS
|
||||
|
||||
long micros(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
return ts.tv_sec * 1000000 + (ts.tv_nsec + 999) / 1000;
|
||||
}
|
||||
|
||||
unsigned rand32(void) {
|
||||
/* Knuth, D.E., "The Art of Computer Programming," Vol 2,
|
||||
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
|
||||
p. 106 (line 26) & p. 108 */
|
||||
static unsigned long long lcg = 1;
|
||||
lcg *= 6364136223846793005;
|
||||
lcg += 1442695040888963407;
|
||||
return lcg >> 32;
|
||||
}
|
||||
|
||||
float float01(unsigned x) { // (0,1)
|
||||
return 1.f / 8388608 * ((x >> 9) + .5f);
|
||||
}
|
||||
|
||||
float numba(void) { // (-1,1)
|
||||
return float01(rand32()) * 2 - 1;
|
||||
}
|
||||
|
||||
void fill(int m, int n, float *A, int lda) {
|
||||
for (int j = 0; j < n; ++j)
|
||||
for (int i = 0; i < m; ++i)
|
||||
A[lda * j + i] = numba();
|
||||
}
|
||||
|
||||
float *new_matrix(int m, int n, int *lda) {
|
||||
void *ptr = 0;
|
||||
int b = 64 / sizeof(float);
|
||||
*lda = (n + b - 1) & -b;
|
||||
posix_memalign(&ptr, 4096, sizeof(float) * m * *lda);
|
||||
return (float *)ptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void barrier(void) {
|
||||
}
|
||||
void (*pBarrier)(void) = barrier;
|
||||
|
||||
#define BENCH(x) \
|
||||
do { \
|
||||
x; \
|
||||
int N = 10; \
|
||||
long t1 = micros(); \
|
||||
for (long i = 0; i < N; ++i) { \
|
||||
pBarrier(); \
|
||||
x; \
|
||||
} \
|
||||
long t2 = micros(); \
|
||||
printf("%8" PRId64 " µs %s %g gigaflops\n", (t2 - t1 + N - 1) / N, #x, \
|
||||
1e6 / ((t2 - t1 + N - 1) / N) * m * n * k * 2 * 1e-9); \
|
||||
} while (0)
|
||||
|
||||
int main() {
|
||||
int m = 1024;
|
||||
int n = 1024;
|
||||
int k = 1024;
|
||||
int lda, ldb, ldc;
|
||||
float *A = new_matrix(m, k, &lda);
|
||||
float *B = new_matrix(n, k, &ldb);
|
||||
float *C = new_matrix(n, m, &ldc);
|
||||
fill(k, n, A, lda);
|
||||
fill(k, m, B, ldb);
|
||||
BENCH(ansiBLAS::sgemm(m, n, k, A, lda, B, ldb, C, ldc));
|
||||
assert(C[0] == -0x1.20902ap+4);
|
||||
assert(C[1] == -0x1.bf7726p+4);
|
||||
free(C);
|
||||
free(B);
|
||||
free(A);
|
||||
}
|
||||
+11
-8
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
@@ -26,6 +27,13 @@
|
||||
* o//examples/crashreport.com
|
||||
*/
|
||||
|
||||
int Divide(int x, int y) {
|
||||
volatile int z = 0; // force creation of stack frame
|
||||
return x / y + z;
|
||||
}
|
||||
|
||||
int (*pDivide)(int, int) = Divide;
|
||||
|
||||
dontubsan int main(int argc, char *argv[]) {
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
@@ -34,12 +42,7 @@ dontubsan int main(int argc, char *argv[]) {
|
||||
|
||||
ShowCrashReports();
|
||||
|
||||
volatile double a = 0;
|
||||
volatile double b = 23;
|
||||
volatile double c = exp(b) / a;
|
||||
(void)c;
|
||||
|
||||
volatile int x = 0;
|
||||
volatile int y = 1 / x;
|
||||
return y;
|
||||
pDivide(1, 0);
|
||||
pDivide(2, 0);
|
||||
pDivide(3, 0);
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
@@ -18,6 +19,17 @@ void crash(long x0, long x1, long x2, //
|
||||
void (*pCrash)(long, long, long, double, double, double) = crash;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// // by default we launch an addr2line subprocess to print backtraces
|
||||
// // with line numbers. you can force it to use the embedded solution
|
||||
// setenv("ADDR2LINE", "", true);
|
||||
|
||||
// // using a seccomp sandbox is another way to force embedded backtraces
|
||||
// pledge("stdio", NULL);
|
||||
|
||||
// enable the crash reporting feature
|
||||
ShowCrashReports();
|
||||
|
||||
// time to die
|
||||
pCrash(1, 2, 3, NAN, NAN, NAN);
|
||||
}
|
||||
+25
-4
@@ -9,19 +9,30 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/timezoneid.h"
|
||||
#include "libc/nt/struct/timezoneinformation.h"
|
||||
#include "libc/nt/time.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/thread/threads.h"
|
||||
#include "libc/time.h"
|
||||
|
||||
/**
|
||||
* @fileoverview High performance ISO-8601 timestamp formatter.
|
||||
*
|
||||
* The strftime() function is very slow. This goes much faster.
|
||||
* Consider using something like this instead for your loggers.
|
||||
*/
|
||||
|
||||
char *GetTimestamp(void) {
|
||||
int x;
|
||||
struct timespec ts;
|
||||
_Thread_local static long last;
|
||||
_Thread_local static char s[27];
|
||||
_Thread_local static struct tm tm;
|
||||
thread_local static long last;
|
||||
thread_local static char s[32];
|
||||
thread_local static struct tm tm;
|
||||
clock_gettime(0, &ts);
|
||||
if (ts.tv_sec != last) {
|
||||
localtime_r(&ts.tv_sec, &tm);
|
||||
@@ -61,11 +72,21 @@ char *GetTimestamp(void) {
|
||||
s[23] = '0' + x / 100000 % 10;
|
||||
s[24] = '0' + x / 10000 % 10;
|
||||
s[25] = '0' + x / 1000 % 10;
|
||||
s[26] = tm.tm_gmtoff < 0 ? '-' : '+';
|
||||
x = ABS(tm.tm_gmtoff) / 60 / 60;
|
||||
s[27] = '0' + x / 10 % 10;
|
||||
s[28] = '0' + x % 10;
|
||||
x = ABS(tm.tm_gmtoff) / 60 % 60;
|
||||
s[29] = '0' + x / 10 % 10;
|
||||
s[30] = '0' + x % 10;
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char buf[128], *p = buf;
|
||||
// setenv("TZ", "UTC", true);
|
||||
// setenv("TZ", "US/Eastern", true);
|
||||
// setenv("TZ", "Asia/Kolkata", true);
|
||||
p = stpcpy(p, GetTimestamp());
|
||||
p = stpcpy(p, "\n");
|
||||
write(1, buf, p - buf);
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
fprintf(stderr, "%s (%s)\n", argv[0], GetProgramExecutableName());
|
||||
for (char **p = environ; *p; ++p) {
|
||||
for (char** p = environ; *p; ++p) {
|
||||
printf("%s\n", *p);
|
||||
}
|
||||
return 0;
|
||||
|
||||
+15
-8
@@ -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;
|
||||
@@ -149,7 +151,7 @@ void *Worker(void *id) {
|
||||
|
||||
// check that client message wasn't fragmented into more reads
|
||||
InitHttpMessage(&msg, kHttpRequest);
|
||||
if ((inmsglen = ParseHttpMessage(&msg, buf, got)) <= 0) {
|
||||
if ((inmsglen = ParseHttpMessage(&msg, buf, got, sizeof(buf))) <= 0) {
|
||||
if (!inmsglen) {
|
||||
LOG("%6H client sent fragmented message");
|
||||
} else {
|
||||
@@ -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");
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
// clang-format off
|
||||
|
||||
|
||||
+2
-2
@@ -7,11 +7,11 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/hiredis/hiredis.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/hiredis/hiredis.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Demo of using hiredis to connect to a Redis server
|
||||
|
||||
+93
-47
@@ -71,7 +71,7 @@ Contact: [email protected]");
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
|
||||
/* Syntax highlight types */
|
||||
#define HL_NORMAL 0
|
||||
@@ -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'):
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/time.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int64_t t = 0;
|
||||
localtime(&t);
|
||||
}
|
||||
+130
-66
@@ -44,7 +44,7 @@
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/w.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "libc/zip.internal.h"
|
||||
@@ -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) {
|
||||
|
||||
@@ -42,6 +42,7 @@ EXAMPLES_PACKAGE_OBJS = \
|
||||
EXAMPLES_PACKAGE_DIRECTDEPS = \
|
||||
EXAMPLES_PACKAGE_LIB \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_STDIO \
|
||||
LIBC_TINYMATH
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ EXAMPLES_PACKAGE_LIB_A_CHECKS = \
|
||||
EXAMPLES_PACKAGE_LIB_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_MEM \
|
||||
LIBC_STDIO
|
||||
|
||||
# Evaluates variable as set of transitive package dependencies.
|
||||
|
||||
+26
-26
@@ -1,31 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
|
||||
do { \
|
||||
type val; int ret; \
|
||||
ret = sscanf(str, scan_fmt, &val); \
|
||||
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
|
||||
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
|
||||
do { \
|
||||
type val; \
|
||||
int ret; \
|
||||
ret = sscanf(str, scan_fmt, &val); \
|
||||
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
|
||||
} while (0)
|
||||
|
||||
int main()
|
||||
{
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "inF");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
|
||||
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "junk");
|
||||
return 0;
|
||||
int main() {
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "inF");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
|
||||
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "junk");
|
||||
return 0;
|
||||
}
|
||||
+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);
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "third_party/getopt/getopt.internal.h"
|
||||
// clang-format off
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
|
||||
volatile bool gotalrm;
|
||||
|
||||
|
||||
Loaded 100 of 4282 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user