Compare commits

...
48 Commits
Author SHA1 Message Date
Justine Tunney 130fd66f9e Release Cosmopolitan v3.3.4 2024-05-03 09:25:02 -07:00
Justine Tunney 8a44f913ae Delete flaky tests
Signals are extremely difficult to unit test reliably. This is why
functions like sigsuspend() exist. When testing something else and
portably it becomes impossible without access to kernel internals.

OpenMP flakes in QEMU on one of my workstations. I don't think the
support is production worthy, because there's been issues on MacOS
additionally. It works great for every experiment I've used it for
though. However a flaky test is worse than no test at all. So it's
removed until someone takes an interest in productionizing it.
2024-05-03 09:11:04 -07:00
Gautham 5488f0b2ca Remove zlib namespacing (#1142)
We have an optimized version of zlib from the Chromium project.
We need it for a lot of our libc services. It would be nice to export
this to user applications if we can, since projects like llamafile are
already depending on it under the private namespace, to avoid
needing to link zlib twice.
2024-05-03 08:07:25 -07:00
Gavin Hayes deff138e7e recvfrom: don't convert address if addrsize is 0 (#1153) 2024-05-03 08:03:57 -07:00
Gavin Hayes b6e40a3a58 Add /dev/(u)random on NT (#1163) 2024-05-03 07:59:51 -07:00
Cadence Ember 8f6bc9dabc Let signals interrupt fgets unless SA_RESTART set (#1152) 2024-05-03 07:49:41 -07:00
Justine Tunney 181cd4cbe8 Add sysctlbyname() for MacOS 2024-05-02 23:21:43 -07:00
Justine Tunney 5c6877b02b Introduce support for trapping math
The feenableexcept() and fedisableexcept() APIs are now provided which
let you detect when NaNs appear the moment it happens from anywhere in
your program. Tests have also been added for the mission critical math
functions expf() and erff(), whose perfect operation has been assured.
See examples/trapping.c to see how to use this powerful functionality.
2024-04-30 13:38:43 -07:00
Justine Tunney 403bc25412 Make MXCSR editable by signal handlers on Windows
It's now possible to recover from floating point exception traps.
2024-04-30 13:38:43 -07:00
Matt Colyer 3bcd40be12 Fix regression in apeinstall.sh (#1161)
This should have been a part of a6baba1.
2024-04-29 20:40:38 -07:00
Paul Kulchenko fcfdd26b72 Fix wrong parameter type in redbean documentation (#1162) 2024-04-29 20:09:25 -04:00
Justine Tunney 2b00ee8723 Fix errno.h documentation typos
Closes #1156
2024-04-28 22:57:21 -07:00
Justine Tunney ff2b6fc0b0 Add munlock() and mlock2() to pledge 2024-04-28 16:53:23 -07:00
Justine Tunney 0eef971494 Add much of C11 threads.h API 2024-04-28 07:04:08 -07:00
Gavin Hayes 2bfd6b37c1 Various paginate improvements (#1148)
* start on improving __paginate

* make __paginate more robust

* add __paginate_file

* cleanup __paginate unlinking
2024-04-26 23:12:25 -04:00
Gavin Hayes 69db501c68 Fix fork locking on win32 (#1141)
* Fix fork locking on win32

- __enable_threads / set __threaded in __proc_setup as threads are required for
  win32 subprocess management
- move mmi/fds locking out of pthread_atfork.c into fork.c so it's done anytime
  __threaded is set instead of being dependent of pthreads
- explicitly yoink _pthread_onfork_prepare, _pthread_onfork_parent, and
  _pthread_onfork_child in pthread_create.c so they are linked in in-case they
  are separated from _pthread_atfork

Big Thanks to @dfyz for help with locating the issue, testing, and devising a fix!

* fix child processes not being able to open files, initialize all necessary locks on fork
2024-04-25 23:01:27 -04:00
Jōshin 6e6fc38935 Apply clang-format update to repo (#1154)
Commit bc6c183 introduced a bunch of discrepancies between what files
look like in the repo and what clang-format says they should look like.
However, there were already a few discrepancies prior to that. Most of
these discrepancies seemed to be unintentional, but a few of them were
load-bearing (e.g., a #include that violated header ordering needing
something to have been #defined by a 'later' #include.)

I opted to take what I hope is a relatively smooth-brained approach: I
reverted the .clang-format change, ran clang-format on the whole repo,
reapplied the .clang-format change, reran clang-format again, and then
reverted the commit that contained the first run. Thus the full effect
of this PR should only be to apply the changed formatting rules to the
repo, and from skimming the results, this seems to be the case.

My work can be checked by applying the short, manual commits, and then
rerunning the command listed in the autogenerated commits (those whose
messages I have prefixed auto:) and seeing if your results agree.

It might be that the other diffs should be fixed at some point but I'm
leaving that aside for now.

fd '\.c(c|pp)?$' --print0| xargs -0 clang-format -i
2024-04-25 10:38:00 -07:00
Jōshin 342d0c81e5 vim spells the c++ filetype 'cpp' 2024-04-24 13:56:37 -07:00
Jōshin cec4c04aa1 Remove .com logic from GetProgramExecutableName (#1134)
The `com` parameter to `TryPath` was always 1, so there was no reason to
have it. This patch changes the logic to be as though `com` was 0, which
provides a possible answer to the TODO question -- the answer is no.

If we never care about appending `.com`, then `CopyWithCwd` doesn't need
to return anything beyond a boolean success value.
2024-04-23 22:07:19 -04:00
Alexey Izbyshev f8c0186221 Fix calling __dns_parse with potentially too large rlen
__res_send returns the full answer length even if it didn't fit the
buffer, but __dns_parse expects the length of the filled part of the
buffer.

Analogous to Musl commit 77327ed064bd57b0e1865cd0e0364057ff4a53b4 which
fixed the only other __dns_parse call site.
2024-04-23 09:36:07 -07:00
Quentin Rameau 6992d8c195 Remove arbitrary limit from DNS result parsing
The name resolution would abort when getting more than 63 records per
request, due to what seems to be a left-over from the original code.
This check was non-breaking but spurious prior to TCP fallback
support, since any 512-byte packet with more than 63 records was
necessarily malformed. But now, it wrongly rejects valid results.

Reported by Daniel Stefanik in Alpine Linux aports issue 15320.
2024-04-23 09:33:02 -07:00
Justine Tunney 1a6b4ab627 Import mntent bug fixes from Musl Libc
f314e133929b6379eccc632bef32eaebb66a7335
Author: Rich Felker <[email protected]>
Date:   Thu Nov 16 12:55:21 2023 -0500

    mntent: fields are delimited only by tabs or spaces, not general whitespace

    this matters because the kernel-provided mtab only escapes tabs,
    spaces, newlines, and backslashes. it leaves carriage returns, form
    feeds, and vertical tabs literal.

commit ee1d39bc1573c1ae49ee6b658938b56bbef95a6c
Author: q66 <[email protected]>
Date:   Thu Nov 9 20:48:44 2023 +0100

    mntent: unescape octal sequences

    As entries in mtab are delimited by spaces, whitespace characters
    are escaped as octal sequences. When reading them out, we have to
    unescape these sequences to get the proper string.
2024-04-23 09:29:56 -07:00
Justine Tunney 9e848abad9 Add missing Musl license headers 2024-04-23 09:29:46 -07:00
Justine Tunney 223eb358c4 Import compiler warning fix from Musl 2024-04-23 09:29:28 -07:00
Szabolcs Nagy ea3cc4ea0b math: fix fma(x,y,0) when x*y rounds to -0
if x!=0, y!=0, z==0 then

  fma(x,y,z) == x*y

in all rounding modes, while adding z can ruin the sign of 0 if x*y
rounds to -0.
2024-04-23 09:22:33 -07:00
Paul Kulchenko 01267ea0f5 Update GetRemoteAddr documentation to clarify that it may return nil. (#1149) 2024-04-22 01:55:08 -04:00
Justine Tunney bc6c18368f Update .clang-format 2024-04-19 17:11:08 -07:00
Jōshin 06839ab301 Change loop bound on uuidv4 test (#1143)
A half second (on my machine) is too long for a unit test. 1000
iterations is probably still overkill, but 0.01 seconds is fine.

Also made `y` local.
2024-04-12 12:22:34 -04:00
BONNAURE Olivier 39dde41516 [Redbean] Add UuidV4 method (#1140) 2024-04-12 11:10:27 -04:00
Jōshin 3e16e59f72 Move store after __asan_unpoison in __zipos_alloc (#1135)
Previously, the atomic store looked like it was happening while the
struct's memory was still poisoned. I was unable to observe any issues
with this, but this change seems to make the code more obviously correct
(at the cost of a redundant atomic store to zeroed space in case the map
needed to be extended.)
2024-04-10 23:04:03 -04:00
Justine Tunney cf9a1f7f33 Fix MODE=optlinux build 2024-04-06 21:02:19 -07:00
Justine Tunney 49a32136f8 Upgrade the One True Awk 2024-04-06 19:21:48 -07:00
Justine Tunney b9d6e6e348 Standardize on -fsigned-char
MaGuess on Discord pointed out the fact that cosmocc contradicts itself
on the signedness of `char`. It's up to each platform to choose one, so
the cosmo platform shall choose signed. The rationale is it makes the C
language syntax more internally similar. `char` should be `signed char`
for the same reason `int` means `signed int`. It's recommended that you
still assume `char` could go either way since that's portable thinking.
But if you want to assume we'll always have signed char, that's ok too.
2024-03-30 21:46:08 -07:00
Justine Tunney b431ca4449 Upgrade to cosmocc v3.3.3 2024-03-30 20:17:14 -07:00
Justine Tunney 98d06b23cc Release Cosmopolitan v3.3.3 2024-03-30 19:24:04 -07:00
Justine Tunney 9ff65cff63 Fix ZipOS extraction of ZIP64 assets 2024-03-30 19:00:40 -07:00
Justine Tunney bef2cb05ff Fix AVX512_BF16 2024-03-26 00:00:46 -07:00
mierenhoop 43885a76e4 Fix binary formatting for integers 2 and 3 (#1123) 2024-03-25 21:11:09 -07:00
Justine Tunney 74a85087de Support -S in cosmocross
You can now run commands like `x86_64-unknown-cosmo-c++ -S` when using
your cosmocc toolchain. Please note the S flag isn't supported for the
cosmocc command itself.
2024-03-24 15:49:55 -07:00
Justine Tunney 045632a743 Make fixupobj work on Windows
This fixes a regression with recent cosmocc toolchain releases that
causes fixupobj to fail with "ifunc ftruncate #1 failed" on Windows
2024-03-24 03:14:25 -07:00
Justine Tunney 9a10adac35 Remove .com from README 2024-03-22 19:38:38 -07:00
Justine Tunney 0c12c26e1d Update Emacs config 2024-03-22 19:27:11 -07:00
Justine Tunney 40b7da8422 Speed up fmaf() on x86 2024-03-22 19:26:56 -07:00
Justine Tunney 640668931d Clarify MacOS supported versions
We technically support versions much earlier, possibly dating back to
2018 or earlier, but they're not officially supported since I have no
way of testing them.

Closes #1129
2024-03-22 19:25:07 -07:00
Justine Tunney 1c34088ba0 Ignore -pie and -fpie in cosmocc
Fixes #1126
2024-03-22 03:55:01 -07:00
Justine Tunney bb92347158 Add deprecated stubs for _bsf / _bsr 2024-03-05 09:45:51 -08:00
Justine Tunney 8bfd56b59e Rename _bsr/_bsf to bsr/bsf
Now that these functions are behind _COSMO_SOURCE there's no reason for
having the ugly underscore anymore. To use these functions, you need to
pass -mcosmo to cosmocc.
2024-03-04 17:33:26 -08:00
Justine Tunney a6baba1b07 Stop using .com extension in monorepo
The WIN32 CreateProcess() function does not require an .exe or .com
suffix in order to spawn an executable. Now that we have Cosmo bash
we're no longer so dependent on the cmd.exe prompt.
2024-03-03 03:12:19 -08:00
1184 changed files with 18271 additions and 11993 deletions

No files matched your search

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