mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-09 10:49:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cbc2bc083 | ||
|
|
1a3d22b2fd | ||
|
|
3057315a1b | ||
|
|
6a8c21269f | ||
|
|
b3838173ec | ||
|
|
4864565198 | ||
|
|
221817e537 | ||
|
|
690be544da | ||
|
|
919b6fec10 | ||
|
|
644f290035 | ||
|
|
4577f7fe11 | ||
|
|
1b5a5719c3 | ||
|
|
b9187061a7 | ||
|
|
e56a9d0e23 | ||
|
|
2d34819779 | ||
|
|
6215c91e90 | ||
|
|
af59806a42 | ||
|
|
01e6b3ad8d | ||
|
|
daa32d27d4 | ||
|
|
84001a246c | ||
|
|
1f2288be6e | ||
|
|
fabf7f9f02 | ||
|
|
cef08d47b6 | ||
|
|
41801c9802 | ||
|
|
1966369e8e | ||
|
|
3aa8983ec1 | ||
|
|
c029e83dd8 | ||
|
|
472b95fea3 | ||
|
|
dc6d11a031 | ||
|
|
b107d2709f | ||
|
|
4effa23528 | ||
|
|
26ac6871da | ||
|
|
bf03b2e64c | ||
|
|
69c508729e | ||
|
|
7ed524ca31 | ||
|
|
052682c2c0 | ||
|
|
8a91518633 | ||
|
|
8f52c0d773 | ||
|
|
1fbfbb3192 | ||
|
|
f40f97bd07 | ||
|
|
24d79599cc | ||
|
|
da8a08fd58 | ||
|
|
59575f7e80 | ||
|
|
6c16f208b5 | ||
|
|
bb96099c65 | ||
|
|
2584a86ab4 | ||
|
|
9e98d6893d | ||
|
|
6682013d12 | ||
|
|
83abd68029 |
No files matched your search
@@ -0,0 +1,62 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
We'd love to accept your patches! Please read this guide first.
|
||||
|
||||
## Copyright Assignment
|
||||
|
||||
Please send an email to Justine Tunney <jtunney@gmail.com> stating that
|
||||
you intend to assign her the copyright to the changes you contribute to
|
||||
Cosmopolitan. Please use the same email address you use for git commits
|
||||
which should only contain original source code from you or other people
|
||||
who are also assigning copyright. Please note that, if you're employed,
|
||||
you may need to get your employer's approval beforehand. If you can not
|
||||
assign copyright due to local laws, then you may alternatively consider
|
||||
disclaiming it using the language in [Unlicense](https://unlicense.org)
|
||||
or [CC-0](http://creativecommons.org/share-your-work/public-domain/cc0)
|
||||
|
||||
This is important because we can't produce 12kb single-file executables
|
||||
that comply with license requirements if we have to embed lots of them.
|
||||
Although that's less of an issue depending on the purpose of the files.
|
||||
For example, ownership is much less of a concern in the unit test files
|
||||
so you're encouraged to put your copyright on those, provided it's ISC.
|
||||
|
||||
## Style Guide
|
||||
|
||||
You can use clang-format to automatically format your files:
|
||||
|
||||
```sh
|
||||
clang-format -i -style=file tool/net/redbean.c
|
||||
```
|
||||
|
||||
If you use Emacs this can be automated on save for Cosmopolitan using
|
||||
[tool/emacs/cosmo-format.el]([tool/emacs/cosmo-format.el]).
|
||||
|
||||
### Source Files
|
||||
|
||||
- Must use include paths relative to the root of the repository
|
||||
- Must have comment at top of file documenting copyright and license
|
||||
- Must have notice embedding if not owned by Justine (exception: tests)
|
||||
- May use language extensions that are supported by both GCC and Clang
|
||||
- Should use Google indentation (otherwise use `/* clang-format off */`)
|
||||
- Should use asm() instead of compiler APIs (exception: ctz, clz, memcpy)
|
||||
|
||||
### Header Files
|
||||
|
||||
- Must not have copyright or license comments
|
||||
- Must have once guards (otherwise change `.h` to `.inc`)
|
||||
- Must be ANSI C89 compatible to be included in the amalgamation header
|
||||
- Must include its dependencies (exception: libc/integral/normalize.inc)
|
||||
- Must not define objects (i.e. `cc -c -xc foo.h` will produce empty `.o`)
|
||||
- Should not use typedefs
|
||||
- Should not use forward declarations
|
||||
- Should not include documentation comments
|
||||
- Should not include parameter names in prototypes
|
||||
- Should not pose problems if included by C++ or Assembly sources
|
||||
- Should not declare non-ANSI code, at all, when the user requests ANSI
|
||||
|
||||
### Build Config
|
||||
|
||||
- Must not write files outside `o/`
|
||||
- Must not communicate with Internet
|
||||
- Must not depend on system libraries
|
||||
- Must not depend on system commands (exception: sh, make, gzip, zip)
|
||||
@@ -136,7 +136,8 @@ include third_party/third_party.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include third_party/lua/lua.mk
|
||||
include examples/examples.mk
|
||||
include third_party/sqlite3/sqlite3.mk
|
||||
include third_party/quickjs/quickjs.mk
|
||||
include third_party/lz4cli/lz4cli.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include third_party/chibicc/chibicc.mk
|
||||
@@ -144,6 +145,7 @@ include third_party/chibicc/test/test.mk
|
||||
include tool/build/emucrt/emucrt.mk
|
||||
include tool/build/emubin/emubin.mk
|
||||
include tool/build/build.mk
|
||||
include examples/examples.mk
|
||||
include tool/decode/lib/decodelib.mk
|
||||
include tool/decode/decode.mk
|
||||
include tool/hash/hash.mk
|
||||
@@ -188,13 +190,13 @@ include examples/package/build.mk
|
||||
#-φ-examples/package/new.sh
|
||||
include test/test.mk
|
||||
|
||||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
||||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||
SRCS := $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||
HDRS := $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
||||
|
||||
bins: $(BINS)
|
||||
check: $(CHECKS)
|
||||
@@ -205,11 +207,17 @@ tags: TAGS HTAGS
|
||||
o/$(MODE)/.x:
|
||||
@mkdir -p $(@D) && touch $@
|
||||
|
||||
ifneq ($(findstring 4.,,$(MAKE_VERSION)),$(MAKE_VERSION))
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
else
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^SRCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^HDRS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
||||
endif
|
||||
|
||||
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) $(INCS)
|
||||
@$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt
|
||||
|
||||
@@ -22,8 +22,8 @@ If you're doing your development work on Linux or BSD then you need just
|
||||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-0.3.zip
|
||||
unzip cosmopolitan-amalgamation-0.3.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-1.0.zip
|
||||
unzip cosmopolitan-amalgamation-1.0.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount \
|
||||
@@ -38,23 +38,42 @@ first run, so it can be fast and efficient for subsequent executions.
|
||||
|
||||
```sh
|
||||
./hello.com
|
||||
bash -c './hello.com' # zsh/fish workaround (we upstreamed a patch)
|
||||
bash -c './hello.com' # zsh/fish workaround (we upstreamed patches)
|
||||
```
|
||||
|
||||
So if you intend to copy the binary to Windows or Mac then please do
|
||||
that before you run it, not after.
|
||||
|
||||
If you're developing on Windows or MacOS then you need to download an
|
||||
### MacOS
|
||||
|
||||
If you're developing on MacOS you can install the GNU compiler
|
||||
collection for x86_64-elf via homebrew:
|
||||
|
||||
```sh
|
||||
brew install x86_64-elf-gcc
|
||||
```
|
||||
|
||||
Then in the above scripts just replace `gcc` and `objcopy` with
|
||||
`x86_64-elf-gcc` and `x86_64-elf-objcopy` to compile your APE binary.
|
||||
|
||||
### Windows
|
||||
|
||||
If you're developing on Windows then you need to download an
|
||||
x86_64-pc-linux-gnu toolchain beforehand. See the [Compiling on
|
||||
Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
|
||||
tutorial. It's needed because the ELF object format is what makes
|
||||
universal binaries possible.
|
||||
|
||||
Cosmopolitan can also be compiled from source on any Linux distro.
|
||||
## Source Builds
|
||||
|
||||
Cosmopolitan can be compiled from source on any Linux distro. GNU make
|
||||
needs to be installed beforehand. This is a freestanding hermetic
|
||||
repository that bootstraps using a vendored static gcc9 executable.
|
||||
No further dependencies are required.
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-0.3.tar.gz
|
||||
tar xf cosmopolitan-0.3.tar.gz # see releases page
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-1.0.tar.gz
|
||||
tar xf cosmopolitan-1.0.tar.gz # see releases page
|
||||
cd cosmopolitan
|
||||
make -j16
|
||||
o//examples/hello.com
|
||||
@@ -73,3 +92,4 @@ find o -name \*.com | xargs ls -rShal | less
|
||||
| FreeBSD | 12 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| NetBSD | 9.1 | 2020 |
|
||||
| GNU Make | 3.80 | 2010 |
|
||||
@@ -535,7 +535,37 @@ ape_disk:
|
||||
|
||||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
// Until all operating systems can be updated to support APE,
|
||||
// we have a beautiful, yet imperfect workaround, which is to
|
||||
// modify the binary to follow the local system's convention.
|
||||
// There isn't a one-size-fits-all approach for this, thus we
|
||||
// present two choices.
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
// The default behavior is: to overwrite the header in place.
|
||||
// We prefer this because it's a tiny constant one time cost.
|
||||
// We simply printf a 64-byte header and call execve() again.
|
||||
.ascii "o=\"$(command -v \"$0\")\"\n"
|
||||
#else
|
||||
// The alternative behavior is to copy to $TMPDIR and edit.
|
||||
// This imposes a variety of caveats of its own that should
|
||||
// be considered by the user beforehand, such as whether or
|
||||
// not /tmp is considered trustworthy on a given system, or
|
||||
// if the administrator chose to mount it with noexec. It's
|
||||
// up to the user to decide what's best in those situations
|
||||
// and also note that argv[0] and getauxval(AT_EXECFN) will
|
||||
// change as a result of this, and lastly note we don't try
|
||||
// to cleanup the tmp copies for the sake of efficiency. It
|
||||
// should also be noted that if $0 has directory components
|
||||
// then permission clashes can happen between system users,
|
||||
// since only root is able to set the sticky bit, which can
|
||||
// be addressed simply by overriding the TMPDIR environment
|
||||
.ascii "o=\"${TMPDIR:-/tmp}/$0\"\n"
|
||||
.ascii "if [ ! -e \"$o\" ]; then\n"
|
||||
.ascii "d=\"$o\"\n"
|
||||
.ascii "o=\"$o.$$\"\n"
|
||||
.ascii "mkdir -p \"${o%/*}\" 2>/dev/null\n"
|
||||
.ascii "cp -f \"$0\" \"$o\" || exit 120\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
#if SupportsXnu()
|
||||
.ascii "if [ -d /Applications ]; then\n"
|
||||
.ascii "dd if=\"$o\""
|
||||
@@ -547,7 +577,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
.shstub ape_macho_dd_count,2
|
||||
.ascii "\" conv=notrunc 2>/dev/null\n"
|
||||
.ascii "el"
|
||||
#endif
|
||||
#endif /* XNU */
|
||||
.ascii "if exec 7<> \"$o\"; then\n"
|
||||
.ascii "printf '"
|
||||
.ascii "\\177ELF" # 0x0: ⌂ELF
|
||||
@@ -574,19 +604,28 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
.ascii "' >&7\n"
|
||||
.ascii "exec 7<&-\n"
|
||||
.ascii "else\n"
|
||||
.ascii "exit 1\n"
|
||||
.ascii "exit 121\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$0\" \"$@\"\n" # etxtbsy tail recursion
|
||||
.ascii "R=$?\n" # architecture optimistic
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
.ascii "exec \"$0\" \"$@\"\n" # optimistic execution
|
||||
#else
|
||||
.ascii "mv -f \"$o\" \"$d\" 2>/dev/null\n"
|
||||
.ascii "o=\"$d\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$o\" \"$@\"\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "R=$?\n"
|
||||
.ascii "\n"
|
||||
.ascii "if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||||
.ascii "if Q=\"$(command -v qemu-x86_64)\"; then\n"
|
||||
.ascii "exec \"$Q\" \"$0\" \"$@\"\n"
|
||||
.ascii "exec \"$Q\" \"$o\" \"$@\"\n"
|
||||
.ascii "else\n"
|
||||
.ascii "echo error: need qemu-x86_64 >&2\n"
|
||||
.ascii "fi\n"
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
.ascii "elif [ $R -eq 127 ]; then\n" # means argv[0] was wrong
|
||||
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "fi\n"
|
||||
.ascii "exit $R\n"
|
||||
.endobj apesh
|
||||
@@ -826,48 +865,48 @@ ape_macho:
|
||||
@see "The Portable Executable File Format from Top to Bottom",
|
||||
Randy Kath, Microsoft Developer Network Technology Group. */
|
||||
|
||||
// ┌14:Uniprocessor Machine ┌─────────────────────────┐
|
||||
// │┌13:DLL │ PE File Characteristics │
|
||||
// ││┌12:System ├─────────────────────────┤
|
||||
// │││┌11:If Net Run From Swap │ r │ reserved │
|
||||
// ││││┌10:If Removable Run From Swap │ d │ deprecated │
|
||||
// │││││┌9:Debug Stripped │ D │ deprecated with │
|
||||
// ││││││┌8:32bit Machine │ │ extreme prejudice │
|
||||
// │││││││ ┌5:Large Address Aware └───┴─────────────────────┘
|
||||
// │││││││ │ ┌1:Executable
|
||||
// │││││││ │ │┌0:Relocs Stripped
|
||||
// d│││││││dr│Ddd││
|
||||
PEEXE = 0b0000001000100011
|
||||
// ┌14:Uniprocessor Machine ┌─────────────────────────┐
|
||||
// │┌13:DLL │ PE File Characteristics │
|
||||
// ││┌12:System ├─────────────────────────┤
|
||||
// │││┌11:If Net Run From Swap │ r │ reserved │
|
||||
// ││││┌10:If Removable Run From Swap │ d │ deprecated │
|
||||
// │││││┌9:Debug Stripped │ D │ deprecated with │
|
||||
// ││││││┌8:32bit Machine │ │ extreme prejudice │
|
||||
// │││││││ ┌5:Large Address Aware └───┴─────────────────────┘
|
||||
// │││││││ │ ┌1:Executable
|
||||
// │││││││ │ │┌0:Relocs Stripped
|
||||
// d│││││││dr│Ddd││
|
||||
PEEXE = 0b00000001000100011
|
||||
|
||||
// ┌15:TERMINAL_SERVER_AWARE ┌─────────────────────────┐
|
||||
// │┌14:GUARD_CF │ PE DLL Characteristics │
|
||||
// ││┌13:WDM_DRIVER ├─────────────────────────┤
|
||||
// │││┌12:APPCONTAINER │ r │ reserved │
|
||||
// ││││┌11:NO_BIND └───┴─────────────────────┘
|
||||
// │││││┌10:NO_SEH
|
||||
// ││││││┌9:NO_ISOLATION
|
||||
// │││││││┌8:NX_COMPAT
|
||||
// ││││││││┌7:FORCE_INTEGRITY
|
||||
// │││││││││┌6:DYNAMIC_BASE
|
||||
// ││││││││││┌5:HIGH_ENTROPY_VA
|
||||
// │││││││││││rrrrr
|
||||
// ┌15:TERMINAL_SERVER_AWARE ┌─────────────────────────┐
|
||||
// │┌14:GUARD_CF │ PE DLL Characteristics │
|
||||
// ││┌13:WDM_DRIVER ├─────────────────────────┤
|
||||
// │││┌12:APPCONTAINER │ r │ reserved │
|
||||
// ││││┌11:NO_BIND └───┴─────────────────────┘
|
||||
// │││││┌10:NO_SEH
|
||||
// ││││││┌9:NO_ISOLATION
|
||||
// │││││││┌8:NX_COMPAT
|
||||
// ││││││││┌7:FORCE_INTEGRITY
|
||||
// │││││││││┌6:DYNAMIC_BASE
|
||||
// ││││││││││┌5:HIGH_ENTROPY_VA
|
||||
// │││││││││││rrrrr
|
||||
DLLSTD = 0b0000000100100000
|
||||
DLLPIE = 0b0000000001100000
|
||||
DLLEXE = DLLSTD
|
||||
|
||||
// ┌31:Writeable ┌─────────────────────────┐
|
||||
// │┌30:Readable │ PE Section Flags │
|
||||
// ││┌29:Executable ├─────────────────────────┤
|
||||
// │││┌28:Shareable │ o │ for object files │
|
||||
// ││││┌27:Unpageable │ r │ reserved │
|
||||
// │││││┌26:Uncacheable └───┴─────────────────────┘
|
||||
// ││││││┌25:Discardable
|
||||
// │││││││┌24:Contains Extended Relocations
|
||||
// ││││││││ ┌15:Contains Global Pointer (GP) Relative Data
|
||||
// ││││││││ │ ┌7:Contains Uninitialized Data
|
||||
// ││││││││ │ │┌6:Contains Initialized Data
|
||||
// ││││││││ o │ ││┌5:Contains Code
|
||||
// ││││││││┌┴─┐rrrr│ ooror│││rorrr
|
||||
// ┌31:Writeable ┌─────────────────────────┐
|
||||
// │┌30:Readable │ PE Section Flags │
|
||||
// ││┌29:Executable ├─────────────────────────┤
|
||||
// │││┌28:Shareable │ o │ for object files │
|
||||
// ││││┌27:Unpageable │ r │ reserved │
|
||||
// │││││┌26:Uncacheable └───┴─────────────────────┘
|
||||
// ││││││┌25:Discardable
|
||||
// │││││││┌24:Contains Extended Relocations
|
||||
// ││││││││ ┌15:Contains Global Pointer (GP) Relative Data
|
||||
// ││││││││ │ ┌7:Contains Uninitialized Data
|
||||
// ││││││││ │ │┌6:Contains Initialized Data
|
||||
// ││││││││ o │ ││┌5:Contains Code
|
||||
// ││││││││┌┴─┐rrrr│ ooror│││rorrr
|
||||
PETEXT = 0b01110000000000000000000001100000
|
||||
PEDATA = 0b11000000000000000000000011000000
|
||||
PEIMPS = 0b11000000000000000000000001000000
|
||||
@@ -1397,19 +1436,19 @@ long: push $GDT_LONG_DATA
|
||||
jmp *%rax
|
||||
.endfn long
|
||||
|
||||
/* ▄▄▒▀▀▀▀▒▒▄░
|
||||
█████▓▓▄░░░░ ▒▒▄░
|
||||
/* ▄▄▒▀▀▀▀▒▒▄
|
||||
█████▓▓▄░░░░ ▒▒▄
|
||||
▐█▓▓█▓▄█████▓░ ▀▒▄
|
||||
▓█▓▓▓▓▓▓▓▓▓█▓ ░▀▒░
|
||||
░▀▀▓█▓▓▓▓▓▓█▓ ░▀▒▄▄▒▄▄▄▒▒▒▀▀▀▀▀▀▀▀▀▀▀▀▀▀▒▒▄▒
|
||||
░▀▓▓█▓▓▓▓▓▄ ░ ░▀▒▄▄ ▄
|
||||
░▀█▓▓▓▓▓▄░ ░▀▒░ ▄▓▌
|
||||
▀▀▓█▓▓▓▓▓▓█▓ ░▀▒▄▄▒▄▄▄▒▒▒▀▀▀▀▀▀▀▀▀▀▀▀▀▀▒▒▄▒
|
||||
▀▓▓█▓▓▓▓▓▄ ░ ░▀▒▄▄ ▄
|
||||
▀█▓▓▓▓▓▄░ ░▀▒░ ▄▓▌
|
||||
▀█▓▓▓▓▓█▓░ ░▀▄░ ░▄▓██░
|
||||
░▀█▓▓▓▓▓█▄ ░▀▒▄▄▄▄▄▄▄▄▒▀▓█▓█▓░
|
||||
░▀█▓▓▓▓█▓░ ░▄▓█▓▓█▓▄▌
|
||||
░▀█▓▓▓▓▓▄ ▄▄▄▓▓██▓▓▒▒░ ▒▒▄▓█▓▓▓▓█▓
|
||||
▀█▓▓▓▓▓█▄ ░▀▒▄▄▄▄▄▄▄▄▒▀▓█▓█▓░
|
||||
▀█▓▓▓▓█▓░ ░▄▓█▓▓█▓▄▌
|
||||
▀█▓▓▓▓▓▄ ▄▄▄▓▓██▓▓▒▒░ ▒▒▄▓█▓▓▓▓█▓
|
||||
▀█▓▓▓▓▓▓▄▄░ ░▄▄▓██▓▓▓▓▓██████████████▓▓▓▓▓▓█▀
|
||||
▐█▓▓▓▓▓▓▓██▓▓▄▄▄▄▄▄▄▄▄▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████████▓▓▀░
|
||||
▐█▓▓▓▓▓▓▓██▓▓▄▄▄▄▄▄▄▄▄▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████████▓▓▀
|
||||
▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█░ ░░░░░░
|
||||
▄░▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▌
|
||||
█▓▄▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▀▀▀▀▀▀▀▓█▓▓▓▓▓▓▓▓▓▓▓▓
|
||||
@@ -1437,7 +1476,22 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
test %rax,%rax
|
||||
jz 1f
|
||||
movb $METAL,(%rax)
|
||||
1: xor %eax,%eax
|
||||
1: push $0
|
||||
mov %rsp,%rbp
|
||||
mov .Lenv0(%rip),%rax
|
||||
mov %rax,(%rbp) # envp[0][0]
|
||||
push $0 # argv[0][0]
|
||||
push $0 # auxv[1][1]
|
||||
push $0 # auxv[1][0]
|
||||
push %rbp # auxv[0][1]
|
||||
push $31 # auxv[0][0] AT_EXECFN
|
||||
push $0 # envp[1]
|
||||
push $.Lenv0 # envp[0]
|
||||
push $0 # argv[1]
|
||||
push %rbp # argv[0]
|
||||
push $1 # argc
|
||||
xor %ebp,%ebp
|
||||
xor %eax,%eax
|
||||
xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
xor %edi,%edi
|
||||
@@ -1446,20 +1500,10 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
xor %r9d,%r9d
|
||||
xor %r10d,%r10d
|
||||
xor %r11d,%r11d
|
||||
push $0 # auxv[1][1]
|
||||
push $0 # auxv[1][0]
|
||||
push $.Larg0 # auxv[0][1]
|
||||
push $31 # auxv[0][0] AT_EXECFN
|
||||
push $0 # envp[1]
|
||||
push $.Lenv0 # envp[0]
|
||||
push $0 # argv[1]
|
||||
push $.Larg0 # argv[0]
|
||||
push $1 # argc
|
||||
jmp _start
|
||||
.endfn kernel
|
||||
|
||||
.rodata
|
||||
.Larg0: .asciz "ape.com"
|
||||
.Lenv0: .asciz "METAL=1"
|
||||
.previous
|
||||
|
||||
|
||||
+6
-1
@@ -46,5 +46,10 @@ o/ape/idata.inc: \
|
||||
$(APE_OBJS): $(BUILD_FILES) \
|
||||
ape/ape.mk
|
||||
|
||||
o/$(MODE)/ape/ape-no-modify-self.o: ape/ape.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_NO_MODIFY_SELF $<
|
||||
|
||||
.PHONY: o/$(MODE)/ape
|
||||
o/$(MODE)/ape: $(APE) $(APE_CHECKS)
|
||||
o/$(MODE)/ape: $(APE) \
|
||||
$(APE_CHECKS) \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
-1
@@ -69,6 +69,9 @@ CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
-O2
|
||||
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
|
||||
endif
|
||||
|
||||
# Debug Mode
|
||||
@@ -88,7 +91,7 @@ CONFIG_CPPFLAGS += \
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-O2
|
||||
-Og
|
||||
|
||||
CONFIG_COPTS += \
|
||||
$(SECURITY_BLANKETS) \
|
||||
|
||||
+77
-35
@@ -20,12 +20,12 @@
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ai.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/uri.h"
|
||||
#include "net/http/http.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Downloads HTTP URL to stdout.
|
||||
@@ -35,50 +35,92 @@
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int sock;
|
||||
ssize_t rc;
|
||||
unsigned long need;
|
||||
struct UriSlice path;
|
||||
size_t i, got, toto, msglen;
|
||||
char buf[1500], host[256], port[7];
|
||||
const char *url, *msg, *pathstr, *crlfcrlf, *contentlength;
|
||||
struct UriSlice us[16];
|
||||
struct Uri u = {.segs.p = us, .segs.n = ARRAYLEN(us)};
|
||||
|
||||
/*
|
||||
* Get argument.
|
||||
*/
|
||||
const char *urlarg;
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "USAGE: %s URL\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
urlarg = argv[1];
|
||||
|
||||
/*
|
||||
* Parse URL.
|
||||
*/
|
||||
struct Url url;
|
||||
char *host, *port;
|
||||
_gc(ParseUrl(urlarg, -1, &url));
|
||||
_gc(url.params.p);
|
||||
if (url.scheme.n &&
|
||||
!(url.scheme.n == 4 && !memcasecmp(url.scheme.p, "http", 4))) {
|
||||
fprintf(stderr, "ERROR: NOT AN HTTP URL: %s\n", urlarg);
|
||||
exit(1);
|
||||
}
|
||||
host = firstnonnull(_gc(strndup(url.host.p, url.host.n)), "127.0.0.1");
|
||||
port = url.port.n ? _gc(strndup(url.port.p, url.port.n)) : "80";
|
||||
port = _gc(xasprintf("%hu", atoi(port)));
|
||||
if (!IsAcceptableHost(host, -1)) {
|
||||
fprintf(stderr, "ERROR: INVALID HOST: %s\n", urlarg);
|
||||
exit(1);
|
||||
}
|
||||
url.fragment.p = 0, url.fragment.n = 0;
|
||||
url.scheme.p = 0, url.scheme.n = 0;
|
||||
url.user.p = 0, url.user.n = 0;
|
||||
url.pass.p = 0, url.pass.n = 0;
|
||||
url.host.p = 0, url.host.n = 0;
|
||||
url.port.p = 0, url.port.n = 0;
|
||||
if (!url.path.n || url.path.p[0] != '/') {
|
||||
char *p = _gc(xmalloc(1 + url.path.n));
|
||||
mempcpy(mempcpy(p, "/", 1), url.path.p, url.path.n);
|
||||
url.path.p = p;
|
||||
++url.path.n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create HTTP message.
|
||||
*/
|
||||
const char *msg;
|
||||
msg = _gc(xasprintf("GET %s HTTP/1.1\r\n"
|
||||
"Host: %s:%s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: 0\r\n"
|
||||
"Accept: text/plain; */*\r\n"
|
||||
"Accept-Encoding: identity\r\n"
|
||||
"User-Agent: github.com/jart/cosmopolitan\r\n"
|
||||
"\r\n",
|
||||
_gc(EncodeUrl(&url, 0)), host, port));
|
||||
|
||||
/*
|
||||
* Perform DNS lookup.
|
||||
*/
|
||||
struct addrinfo *addr, *addrs;
|
||||
struct addrinfo hints = {.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
.ai_flags = AI_NUMERICSERV};
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "USAGE: %s URL\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
url = argv[1];
|
||||
CHECK_NE(-1, uriparse(&u, url, strlen(url)), "BAD URL: %`'s", url);
|
||||
CHECK_EQ(kUriSchemeHttp, urischeme(u.scheme, url));
|
||||
urislice2cstr(host, sizeof(host), u.host, url, "127.0.0.1");
|
||||
urislice2cstr(port, sizeof(port), u.port, url, "80");
|
||||
path = uripath(&u);
|
||||
pathstr = path.n ? url + path.i : "/";
|
||||
msg = _gc(xstrcat("GET ", pathstr,
|
||||
" HTTP/1.1\r\n"
|
||||
"Host: ",
|
||||
host,
|
||||
"\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: 0\r\n"
|
||||
"Accept: text/plain; */*\r\n"
|
||||
"Accept-Encoding: identity\r\n"
|
||||
"User-Agent: github.com/jart/cosmopolitan\r\n"
|
||||
"\r\n"));
|
||||
msglen = strlen(msg);
|
||||
CHECK_EQ(EAI_SUCCESS, getaddrinfo(host, port, &hints, &addrs));
|
||||
for (addr = addrs; addr; addr = addr->ai_next) {
|
||||
|
||||
/*
|
||||
* Send HTTP Message.
|
||||
*/
|
||||
int sock;
|
||||
CHECK_NE(-1, (sock = socket(addr->ai_family, addr->ai_socktype,
|
||||
addr->ai_protocol)));
|
||||
CHECK_NE(-1, connect(sock, addr->ai_addr, addr->ai_addrlen));
|
||||
CHECK_EQ(msglen, write(sock, msg, msglen));
|
||||
CHECK_EQ(strlen(msg), write(sock, msg, strlen(msg)));
|
||||
shutdown(sock, SHUT_WR);
|
||||
|
||||
/*
|
||||
* Handle response.
|
||||
*/
|
||||
ssize_t rc;
|
||||
char buf[1500];
|
||||
size_t got, toto;
|
||||
unsigned long need;
|
||||
const char *msg, *crlfcrlf;
|
||||
buf[0] = '\0';
|
||||
CHECK_NE(-1, (rc = read(sock, buf, sizeof(buf))));
|
||||
got = rc;
|
||||
|
||||
@@ -74,6 +74,7 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
|
||||
+2
-1
@@ -8,9 +8,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main() {
|
||||
printf("%s \n", "hello world");
|
||||
printf("%`'s\n", "hello\1\2world→→");
|
||||
return errno;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
const struct itimerval kHertz = {
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
};
|
||||
|
||||
bool hertz;
|
||||
|
||||
void OnAlrm(void) {
|
||||
hertz = true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
CHECK_NE(-1, xsigaction(SIGALRM, OnAlrm, 0, 0, 0));
|
||||
CHECK_NE(-1, setitimer(ITIMER_REAL, &kHertz, NULL));
|
||||
for (;;) {
|
||||
CHECK_EQ(-1, pause());
|
||||
CHECK_EQ(EINTR, errno);
|
||||
if (hertz) {
|
||||
hertz = false;
|
||||
printf("ding\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* @fileoverview netcat clone
|
||||
*
|
||||
* Implemented because BusyBox's netcat doesn't detect remote close and
|
||||
* lingers in the CLOSE_WAIT wait possibly due to file descriptor leaks
|
||||
*
|
||||
* Here's an example usage:
|
||||
*
|
||||
* make -j8 o//examples/nc.com
|
||||
* printf 'GET /\r\n\r\n' | o//examples/nc.com justine.lol 80
|
||||
*
|
||||
* Once upon time we called this command "telnet"
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ssize_t rc;
|
||||
size_t i, got;
|
||||
char buf[1500];
|
||||
int err, toto, sock;
|
||||
struct addrinfo *ai = NULL;
|
||||
struct linger linger = {true, 1};
|
||||
struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}};
|
||||
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
|
||||
|
||||
if (argc != 3) exit(1);
|
||||
switch ((rc = getaddrinfo(argv[1], argv[2], &hint, &ai))) {
|
||||
case EAI_SUCCESS:
|
||||
break;
|
||||
case EAI_SYSTEM:
|
||||
perror("getaddrinfo");
|
||||
exit(1);
|
||||
default:
|
||||
fputs("EAI_", stderr);
|
||||
fputs(gai_strerror(rc), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) == -1) {
|
||||
perror("setsockopt(SO_LINGER)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
|
||||
perror("connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fds[0].fd = 0;
|
||||
fds[1].fd = sock;
|
||||
for (;;) {
|
||||
fds[0].revents = 0;
|
||||
fds[1].revents = 0;
|
||||
if (poll(fds, ARRAYLEN(fds), -1) == -1) {
|
||||
perror("poll");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fds[0].revents & (POLLIN | POLLERR | POLLHUP)) {
|
||||
if ((rc = read(0, buf, 1400)) == -1) {
|
||||
perror("read(stdin)");
|
||||
exit(1);
|
||||
}
|
||||
if (!(got = rc)) {
|
||||
shutdown(sock, SHUT_WR);
|
||||
fds[0].fd = -1;
|
||||
}
|
||||
for (i = 0; i < got; i += rc) {
|
||||
if ((rc = write(sock, buf + i, got - i)) == -1) {
|
||||
perror("write(sock)");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[1].revents & (POLLIN | POLLERR | POLLHUP)) {
|
||||
if ((rc = read(sock, buf, 1500)) == -1) {
|
||||
perror("read(sock)");
|
||||
exit(1);
|
||||
}
|
||||
if (!(got = rc)) {
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < got; i += rc) {
|
||||
if ((rc = write(1, buf + i, got - i)) == -1) {
|
||||
perror("write(stdout)");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (close(sock) == -1) {
|
||||
perror("close");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Paneling Demo.
|
||||
*
|
||||
* This is useful for creating terminal user interfaces. We take the
|
||||
* simplest approach possible. The main thing we abstract is like,
|
||||
* truncating the lines that overflow within a panel. In order to do
|
||||
* that, we abstract the ANSI parsing and the implementation is able to
|
||||
* tell how many cells wide each UNICODE character is.
|
||||
*
|
||||
* There are smarter ways for Cosmopolitan to do this. For example, it'd
|
||||
* be great to have automatic flex boxes. It'd also be nice to be able
|
||||
* to use dynamic programming for low bandwidth display updates, like
|
||||
* Emacs does, but that's less of an issue these days and can actually
|
||||
* make things slower, since for heavy workloads like printing videos,
|
||||
* having ANSI codes bouncing around the display actually goes slower.
|
||||
*
|
||||
* Beyond basic paneling, a message box widget is also provided, which
|
||||
* makes it easier to do modal dialogs.
|
||||
*/
|
||||
|
||||
struct Panels {
|
||||
union {
|
||||
struct {
|
||||
struct Panel left;
|
||||
struct Panel right;
|
||||
};
|
||||
struct Panel p[2];
|
||||
};
|
||||
} pan;
|
||||
|
||||
long tyn;
|
||||
long txn;
|
||||
char key[8];
|
||||
bool shutdown;
|
||||
bool invalidated;
|
||||
struct termios oldterm;
|
||||
|
||||
void OnShutdown(int sig) {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
void OnInvalidate(int sig) {
|
||||
invalidated = true;
|
||||
}
|
||||
|
||||
void GetTtySize(void) {
|
||||
struct winsize wsize;
|
||||
wsize.ws_row = tyn;
|
||||
wsize.ws_col = txn;
|
||||
getttysize(1, &wsize);
|
||||
tyn = wsize.ws_row;
|
||||
txn = wsize.ws_col;
|
||||
}
|
||||
|
||||
int Write(const char *s) {
|
||||
return write(1, s, strlen(s));
|
||||
}
|
||||
|
||||
void Setup(void) {
|
||||
CHECK_NE(-1, ioctl(1, TCGETS, &oldterm));
|
||||
}
|
||||
|
||||
void Enter(void) {
|
||||
struct termios term;
|
||||
memcpy(&term, &oldterm, sizeof(term));
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_cc[VTIME] = 1;
|
||||
term.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
|
||||
term.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL);
|
||||
term.c_cflag &= ~(CSIZE | PARENB);
|
||||
term.c_cflag |= CS8;
|
||||
term.c_iflag |= IUTF8;
|
||||
CHECK_NE(-1, ioctl(1, TCSETS, &term));
|
||||
Write("\e[?25l");
|
||||
}
|
||||
|
||||
void Leave(void) {
|
||||
Write(gc(xasprintf("\e[?25h\e[%d;%dH\e[S\r\n", tyn, txn)));
|
||||
ioctl(1, TCSETS, &oldterm);
|
||||
}
|
||||
|
||||
void Clear(void) {
|
||||
long i, j;
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
for (j = 0; j < pan.p[i].n; ++j) {
|
||||
free(pan.p[i].lines[j].p);
|
||||
}
|
||||
free(pan.p[i].lines);
|
||||
pan.p[i].lines = 0;
|
||||
pan.p[i].n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Layout(void) {
|
||||
long i, j;
|
||||
i = txn >> 1;
|
||||
pan.left.top = 0;
|
||||
pan.left.left = 0;
|
||||
pan.left.bottom = tyn;
|
||||
pan.left.right = i;
|
||||
pan.right.top = 0;
|
||||
pan.right.left = i + 1;
|
||||
pan.right.bottom = tyn;
|
||||
pan.right.right = txn;
|
||||
pan.left.n = pan.left.bottom - pan.left.top;
|
||||
pan.left.lines = xcalloc(pan.left.n, sizeof(*pan.left.lines));
|
||||
pan.right.n = pan.right.bottom - pan.right.top;
|
||||
pan.right.lines = xcalloc(pan.right.n, sizeof(*pan.right.lines));
|
||||
}
|
||||
|
||||
void Append(struct Panel *p, int i, const char *s) {
|
||||
if (i >= p->n) return;
|
||||
AppendStr(p->lines + i, s);
|
||||
}
|
||||
|
||||
void Draw(void) {
|
||||
Append(&pan.left, 0, gc(xasprintf("you typed %`'s", key)));
|
||||
Append(&pan.left, ((tyn + 1) >> 1) + 0, "hello left 1 𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷");
|
||||
Append(&pan.left, ((tyn + 1) >> 1) + 1, "hello left 2 (╯°□°)╯");
|
||||
Append(&pan.right, ((tyn + 1) >> 1) + 0, "hello right 1");
|
||||
Append(&pan.right, ((tyn + 1) >> 1) + 1, "hello right 2");
|
||||
PrintPanels(1, ARRAYLEN(pan.p), pan.p, tyn, txn);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sa[2] = {{.sa_handler = OnShutdown},
|
||||
{.sa_handler = OnInvalidate}};
|
||||
showcrashreports();
|
||||
Setup();
|
||||
Enter();
|
||||
GetTtySize();
|
||||
sigaction(SIGINT, &sa[0], 0);
|
||||
sigaction(SIGCONT, &sa[1], 0);
|
||||
sigaction(SIGWINCH, &sa[1], 0);
|
||||
atexit(Leave);
|
||||
do {
|
||||
Clear();
|
||||
Layout();
|
||||
Draw();
|
||||
if (invalidated) {
|
||||
Enter();
|
||||
GetTtySize();
|
||||
invalidated = false;
|
||||
} else {
|
||||
readansi(0, key, sizeof(key));
|
||||
}
|
||||
} while (!shutdown);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Directory walker example.
|
||||
* Copied from IEEE Std 1003.1-2017
|
||||
*/
|
||||
|
||||
static int display_info(const char *fpath, const struct stat *sb, int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
printf("%-3s %2d %7jd %-40s %d %s\n",
|
||||
(tflag == FTW_D) ? "d"
|
||||
: (tflag == FTW_DNR) ? "dnr"
|
||||
: (tflag == FTW_DP) ? "dp"
|
||||
: (tflag == FTW_F) ? (S_ISBLK(sb->st_mode) ? "f b"
|
||||
: S_ISCHR(sb->st_mode) ? "f c"
|
||||
: S_ISFIFO(sb->st_mode) ? "f p"
|
||||
: S_ISREG(sb->st_mode) ? "f r"
|
||||
: S_ISSOCK(sb->st_mode) ? "f s"
|
||||
: "f ?")
|
||||
: (tflag == FTW_NS) ? "ns"
|
||||
: (tflag == FTW_SL) ? "sl"
|
||||
: (tflag == FTW_SLN) ? "sln"
|
||||
: "?",
|
||||
ftwbuf->level, (intmax_t)sb->st_size, fpath, ftwbuf->base,
|
||||
fpath + ftwbuf->base);
|
||||
return 0; /* To tell nftw() to continue */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int flags = 0;
|
||||
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH;
|
||||
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS;
|
||||
if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags) == -1) {
|
||||
perror("nftw");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+17
-13
@@ -6,19 +6,23 @@ COSMOPOLITAN_C_START_
|
||||
forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
|
||||
int cmp(const void *a, const void *b, void *arg),
|
||||
void *arg) {
|
||||
int dir;
|
||||
const char *p, *pos;
|
||||
p = data;
|
||||
while (n > 0) {
|
||||
pos = p + size * (n / 2);
|
||||
dir = cmp(k, pos, arg);
|
||||
if (dir < 0) {
|
||||
n /= 2;
|
||||
} else if (dir > 0) {
|
||||
p = pos + size;
|
||||
n -= n / 2 + 1;
|
||||
} else {
|
||||
return (void *)pos;
|
||||
int c;
|
||||
const char *p;
|
||||
ssize_t m, l, r;
|
||||
if (n) {
|
||||
l = 0;
|
||||
r = n - 1;
|
||||
p = data;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
c = cmp(k, p + m * size, arg);
|
||||
if (c > 0) {
|
||||
l = m + 1;
|
||||
} else if (c < 0) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return p + m * size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
+3
-10
@@ -6,19 +6,12 @@ COSMOPOLITAN_C_START_
|
||||
void __assert_fail(const char *, const char *, int) hidden wontreturn relegated;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define __ASSERT_FAIL(EXPR, FILE, LINE)
|
||||
#define assert(EXPR) ((void)0)
|
||||
#else
|
||||
#define __ASSERT_FAIL(EXPR, FILE, LINE) __assert_fail(EXPR, FILE, LINE)
|
||||
#define assert(EXPR) \
|
||||
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
|
||||
#endif
|
||||
|
||||
#define assert(EXPR) \
|
||||
do { \
|
||||
if (!(EXPR)) { \
|
||||
__ASSERT_FAIL(#EXPR, __FILE__, __LINE__); \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define static_assert _Static_assert
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
/**
|
||||
* Reverses bits in 16-bit word.
|
||||
*/
|
||||
uint16_t(bitreverse16)(uint16_t x) {
|
||||
return kReverseBits[x & 0x00FF] << 8 | kReverseBits[(x & 0xFF00) >> 8];
|
||||
int bitreverse16(int x) {
|
||||
return BITREVERSE16(x);
|
||||
}
|
||||
@@ -22,10 +22,10 @@
|
||||
/**
|
||||
* Reverses bits in 32-bit word.
|
||||
*/
|
||||
uint32_t(bitreverse32)(uint32_t x) {
|
||||
uint32_t bitreverse32(uint32_t x) {
|
||||
x = bswap_32(x);
|
||||
x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1);
|
||||
x = ((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2);
|
||||
x = ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4);
|
||||
x = (x & 0xaaaaaaaa) >> 1 | (x & 0x55555555) << 1;
|
||||
x = (x & 0xcccccccc) >> 2 | (x & 0x33333333) << 2;
|
||||
x = (x & 0xf0f0f0f0) >> 4 | (x & 0x0f0f0f0f) << 4;
|
||||
return x;
|
||||
}
|
||||
@@ -24,8 +24,8 @@
|
||||
*/
|
||||
uint64_t bitreverse64(uint64_t x) {
|
||||
x = bswap_64(x);
|
||||
x = ((x & 0xaaaaaaaaaaaaaaaa) >> 1) | ((x & 0x5555555555555555) << 1);
|
||||
x = ((x & 0xcccccccccccccccc) >> 2) | ((x & 0x3333333333333333) << 2);
|
||||
x = ((x & 0xf0f0f0f0f0f0f0f0) >> 4) | ((x & 0x0f0f0f0f0f0f0f0f) << 4);
|
||||
x = (x & 0xaaaaaaaaaaaaaaaa) >> 1 | (x & 0x5555555555555555) << 1;
|
||||
x = (x & 0xcccccccccccccccc) >> 2 | (x & 0x3333333333333333) << 2;
|
||||
x = (x & 0xf0f0f0f0f0f0f0f0) >> 4 | (x & 0x0f0f0f0f0f0f0f0f) << 4;
|
||||
return x;
|
||||
}
|
||||
@@ -21,6 +21,6 @@
|
||||
/**
|
||||
* Reverses bits in 8-bit word.
|
||||
*/
|
||||
uint8_t(bitreverse8)(uint8_t x) {
|
||||
return kReverseBits[x];
|
||||
int bitreverse8(int x) {
|
||||
return BITREVERSE8(x);
|
||||
}
|
||||
+98
-100
@@ -13,8 +13,8 @@ extern const uint8_t kReverseBits[256];
|
||||
|
||||
uint32_t gray(uint32_t) pureconst;
|
||||
uint32_t ungray(uint32_t) pureconst;
|
||||
uint8_t bitreverse8(uint8_t) libcesque pureconst;
|
||||
uint16_t bitreverse16(uint16_t) libcesque pureconst;
|
||||
int bitreverse8(int) libcesque pureconst;
|
||||
int bitreverse16(int) libcesque pureconst;
|
||||
uint32_t bitreverse32(uint32_t) libcesque pureconst;
|
||||
uint64_t bitreverse64(uint64_t) libcesque pureconst;
|
||||
unsigned long roundup2pow(unsigned long) libcesque pureconst;
|
||||
@@ -31,106 +31,104 @@ intptr_t atomic_store(void *, intptr_t, size_t);
|
||||
│ cosmopolitan § bits » no assembly required ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define bitreverse8(X) (kReverseBits[(uint8_t)(X)])
|
||||
#define bitreverse16(X) \
|
||||
((uint16_t)kReverseBits[(uint8_t)(X)] << 010 | \
|
||||
kReverseBits[((uint16_t)(X) >> 010) & 0xff])
|
||||
#define BITREVERSE8(X) (kReverseBits[255 & (X)])
|
||||
#define BITREVERSE16(X) \
|
||||
(kReverseBits[0x00FF & (X)] << 8 | kReverseBits[(0xFF00 & (X)) >> 8])
|
||||
|
||||
#define READ16LE(S) \
|
||||
((uint16_t)((unsigned char *)(S))[1] << 010 | \
|
||||
(uint16_t)((unsigned char *)(S))[0] << 000)
|
||||
#define READ32LE(S) \
|
||||
((uint32_t)((unsigned char *)(S))[3] << 030 | \
|
||||
(uint32_t)((unsigned char *)(S))[2] << 020 | \
|
||||
(uint32_t)((unsigned char *)(S))[1] << 010 | \
|
||||
(uint32_t)((unsigned char *)(S))[0] << 000)
|
||||
#define READ64LE(S) \
|
||||
((uint64_t)((unsigned char *)(S))[7] << 070 | \
|
||||
(uint64_t)((unsigned char *)(S))[6] << 060 | \
|
||||
(uint64_t)((unsigned char *)(S))[5] << 050 | \
|
||||
(uint64_t)((unsigned char *)(S))[4] << 040 | \
|
||||
(uint64_t)((unsigned char *)(S))[3] << 030 | \
|
||||
(uint64_t)((unsigned char *)(S))[2] << 020 | \
|
||||
(uint64_t)((unsigned char *)(S))[1] << 010 | \
|
||||
(uint64_t)((unsigned char *)(S))[0] << 000)
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define READ16LE(S) ((255 & (S)[1]) << 8 | (255 & (S)[0]))
|
||||
#define READ16BE(S) ((255 & (S)[0]) << 8 | (255 & (S)[1]))
|
||||
#define READ32LE(S) \
|
||||
((uint32_t)(255 & (S)[3]) << 030 | (uint32_t)(255 & (S)[2]) << 020 | \
|
||||
(uint32_t)(255 & (S)[1]) << 010 | (uint32_t)(255 & (S)[0]) << 000)
|
||||
#define READ32BE(S) \
|
||||
((uint32_t)(255 & (S)[0]) << 030 | (uint32_t)(255 & (S)[1]) << 020 | \
|
||||
(uint32_t)(255 & (S)[2]) << 010 | (uint32_t)(255 & (S)[3]) << 000)
|
||||
#define READ64LE(S) \
|
||||
((uint64_t)(255 & (S)[7]) << 070 | (uint64_t)(255 & (S)[6]) << 060 | \
|
||||
(uint64_t)(255 & (S)[5]) << 050 | (uint64_t)(255 & (S)[4]) << 040 | \
|
||||
(uint64_t)(255 & (S)[3]) << 030 | (uint64_t)(255 & (S)[2]) << 020 | \
|
||||
(uint64_t)(255 & (S)[1]) << 010 | (uint64_t)(255 & (S)[0]) << 000)
|
||||
#define READ64BE(S) \
|
||||
((uint64_t)(255 & (S)[0]) << 070 | (uint64_t)(255 & (S)[1]) << 060 | \
|
||||
(uint64_t)(255 & (S)[2]) << 050 | (uint64_t)(255 & (S)[3]) << 040 | \
|
||||
(uint64_t)(255 & (S)[4]) << 030 | (uint64_t)(255 & (S)[5]) << 020 | \
|
||||
(uint64_t)(255 & (S)[6]) << 010 | (uint64_t)(255 & (S)[7]) << 000)
|
||||
#else /* gcc needs help knowing above are mov if s isn't a variable */
|
||||
#define READ16LE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
Ptr[1] << 8 | Ptr[0]; \
|
||||
})
|
||||
#define READ16BE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
Ptr[0] << 8 | Ptr[1]; \
|
||||
})
|
||||
#define READ32LE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
((uint32_t)Ptr[3] << 030 | (uint32_t)Ptr[2] << 020 | \
|
||||
(uint32_t)Ptr[1] << 010 | (uint32_t)Ptr[0] << 000); \
|
||||
})
|
||||
#define READ32BE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
((uint32_t)Ptr[0] << 030 | (uint32_t)Ptr[1] << 020 | \
|
||||
(uint32_t)Ptr[2] << 010 | (uint32_t)Ptr[3] << 000); \
|
||||
})
|
||||
#define READ64LE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
((uint64_t)Ptr[7] << 070 | (uint64_t)Ptr[6] << 060 | \
|
||||
(uint64_t)Ptr[5] << 050 | (uint64_t)Ptr[4] << 040 | \
|
||||
(uint64_t)Ptr[3] << 030 | (uint64_t)Ptr[2] << 020 | \
|
||||
(uint64_t)Ptr[1] << 010 | (uint64_t)Ptr[0] << 000); \
|
||||
})
|
||||
#define READ64BE(S) \
|
||||
({ \
|
||||
const uint8_t *Ptr = (const uint8_t *)(S); \
|
||||
((uint64_t)Ptr[0] << 070 | (uint64_t)Ptr[1] << 060 | \
|
||||
(uint64_t)Ptr[2] << 050 | (uint64_t)Ptr[3] << 040 | \
|
||||
(uint64_t)Ptr[4] << 030 | (uint64_t)Ptr[5] << 020 | \
|
||||
(uint64_t)Ptr[6] << 010 | (uint64_t)Ptr[7] << 000); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define READ16BE(S) \
|
||||
((uint16_t)((unsigned char *)(S))[0] << 010 | \
|
||||
(uint16_t)((unsigned char *)(S))[1] << 000)
|
||||
#define READ32BE(S) \
|
||||
((uint32_t)((unsigned char *)(S))[0] << 030 | \
|
||||
(uint32_t)((unsigned char *)(S))[1] << 020 | \
|
||||
(uint32_t)((unsigned char *)(S))[2] << 010 | \
|
||||
(uint32_t)((unsigned char *)(S))[3] << 000)
|
||||
#define READ64BE(S) \
|
||||
((uint64_t)((unsigned char *)(S))[0] << 070 | \
|
||||
(uint64_t)((unsigned char *)(S))[1] << 060 | \
|
||||
(uint64_t)((unsigned char *)(S))[2] << 050 | \
|
||||
(uint64_t)((unsigned char *)(S))[3] << 040 | \
|
||||
(uint64_t)((unsigned char *)(S))[4] << 030 | \
|
||||
(uint64_t)((unsigned char *)(S))[5] << 020 | \
|
||||
(uint64_t)((unsigned char *)(S))[6] << 010 | \
|
||||
(uint64_t)((unsigned char *)(S))[7] << 000)
|
||||
|
||||
#define WRITE16LE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint16_t Vle = (V); \
|
||||
Ple[0] = (uint8_t)(Vle >> 000); \
|
||||
Ple[1] = (uint8_t)(Vle >> 010); \
|
||||
} while (0)
|
||||
#define WRITE32LE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint32_t Vle = (V); \
|
||||
Ple[0] = (uint8_t)(Vle >> 000); \
|
||||
Ple[1] = (uint8_t)(Vle >> 010); \
|
||||
Ple[2] = (uint8_t)(Vle >> 020); \
|
||||
Ple[3] = (uint8_t)(Vle >> 030); \
|
||||
} while (0)
|
||||
#define WRITE64LE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint64_t Vle = (V); \
|
||||
Ple[0] = (uint8_t)(Vle >> 000); \
|
||||
Ple[1] = (uint8_t)(Vle >> 010); \
|
||||
Ple[2] = (uint8_t)(Vle >> 020); \
|
||||
Ple[3] = (uint8_t)(Vle >> 030); \
|
||||
Ple[4] = (uint8_t)(Vle >> 040); \
|
||||
Ple[5] = (uint8_t)(Vle >> 050); \
|
||||
Ple[6] = (uint8_t)(Vle >> 060); \
|
||||
Ple[7] = (uint8_t)(Vle >> 070); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE16BE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint16_t Vle = (V); \
|
||||
Ple[1] = (uint8_t)(Vle >> 000); \
|
||||
Ple[0] = (uint8_t)(Vle >> 010); \
|
||||
} while (0)
|
||||
#define WRITE32BE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint32_t Vle = (V); \
|
||||
Ple[3] = (uint8_t)(Vle >> 000); \
|
||||
Ple[2] = (uint8_t)(Vle >> 010); \
|
||||
Ple[1] = (uint8_t)(Vle >> 020); \
|
||||
Ple[0] = (uint8_t)(Vle >> 030); \
|
||||
} while (0)
|
||||
#define WRITE64BE(P, V) \
|
||||
do { \
|
||||
uint8_t *Ple = (uint8_t *)(P); \
|
||||
uint64_t Vle = (V); \
|
||||
Ple[7] = (uint8_t)(Vle >> 000); \
|
||||
Ple[6] = (uint8_t)(Vle >> 010); \
|
||||
Ple[5] = (uint8_t)(Vle >> 020); \
|
||||
Ple[4] = (uint8_t)(Vle >> 030); \
|
||||
Ple[3] = (uint8_t)(Vle >> 040); \
|
||||
Ple[2] = (uint8_t)(Vle >> 050); \
|
||||
Ple[1] = (uint8_t)(Vle >> 060); \
|
||||
Ple[0] = (uint8_t)(Vle >> 070); \
|
||||
} while (0)
|
||||
#define WRITE16LE(P, V) \
|
||||
((P)[0] = (0x00000000000000FF & (V)) >> 000, \
|
||||
(P)[1] = (0x000000000000FF00 & (V)) >> 010, (P) + 2)
|
||||
#define WRITE16BE(P, V) \
|
||||
((P)[0] = (0x000000000000FF00 & (V)) >> 010, \
|
||||
(P)[1] = (0x00000000000000FF & (V)) >> 000, (P) + 2)
|
||||
#define WRITE32LE(P, V) \
|
||||
((P)[0] = (0x00000000000000FF & (V)) >> 000, \
|
||||
(P)[1] = (0x000000000000FF00 & (V)) >> 010, \
|
||||
(P)[2] = (0x0000000000FF0000 & (V)) >> 020, \
|
||||
(P)[3] = (0x00000000FF000000 & (V)) >> 030, (P) + 4)
|
||||
#define WRITE32BE(P, V) \
|
||||
((P)[0] = (0x00000000FF000000 & (V)) >> 030, \
|
||||
(P)[1] = (0x0000000000FF0000 & (V)) >> 020, \
|
||||
(P)[2] = (0x000000000000FF00 & (V)) >> 010, \
|
||||
(P)[3] = (0x00000000000000FF & (V)) >> 000, (P) + 4)
|
||||
#define WRITE64LE(P, V) \
|
||||
((P)[0] = (0x00000000000000FF & (V)) >> 000, \
|
||||
(P)[1] = (0x000000000000FF00 & (V)) >> 010, \
|
||||
(P)[2] = (0x0000000000FF0000 & (V)) >> 020, \
|
||||
(P)[3] = (0x00000000FF000000 & (V)) >> 030, \
|
||||
(P)[4] = (0x000000FF00000000 & (V)) >> 040, \
|
||||
(P)[5] = (0x0000FF0000000000 & (V)) >> 050, \
|
||||
(P)[6] = (0x00FF000000000000 & (V)) >> 060, \
|
||||
(P)[7] = (0xFF00000000000000 & (V)) >> 070, (P) + 8)
|
||||
#define WRITE64BE(P, V) \
|
||||
((P)[0] = (0xFF00000000000000 & (V)) >> 070, \
|
||||
(P)[1] = (0x00FF000000000000 & (V)) >> 060, \
|
||||
(P)[2] = (0x0000FF0000000000 & (V)) >> 050, \
|
||||
(P)[3] = (0x000000FF00000000 & (V)) >> 040, \
|
||||
(P)[4] = (0x00000000FF000000 & (V)) >> 030, \
|
||||
(P)[5] = (0x0000000000FF0000 & (V)) >> 020, \
|
||||
(P)[6] = (0x000000000000FF00 & (V)) >> 010, \
|
||||
(P)[7] = (0x00000000000000FF & (V)) >> 000, (P) + 8)
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » some assembly required ─╬─│┼
|
||||
|
||||
+6
-4
@@ -5,6 +5,7 @@
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigval.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/sysinfo.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
@@ -29,7 +30,7 @@
|
||||
#define SIG_DFL ((void *)0)
|
||||
#define SIG_IGN ((void *)1)
|
||||
|
||||
#define MAP_FAILED ((void *)__SIZE_MAX__)
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
|
||||
#define ARCH_SET_GS 0x1001
|
||||
#define ARCH_SET_FS 0x1002
|
||||
@@ -120,6 +121,7 @@ int getrlimit(int, struct rlimit *);
|
||||
int getrusage(int, struct rusage *);
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int sigqueue(int, int, const union sigval);
|
||||
int link(const char *, const char *) nothrow;
|
||||
int linkat(int, const char *, int, const char *, uint32_t);
|
||||
int lstat(const char *, struct stat *);
|
||||
@@ -135,8 +137,8 @@ int mlockall(int);
|
||||
int munlock(const void *, size_t);
|
||||
int munlockall(void);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...) nodiscard;
|
||||
int openanon(char *, unsigned) nodiscard;
|
||||
int open(const char *, int, ...);
|
||||
int openanon(char *, unsigned);
|
||||
int openat(int, const char *, int, ...);
|
||||
int pause(void);
|
||||
int personality(uint64_t);
|
||||
@@ -174,7 +176,7 @@ int stat(const char *, struct stat *);
|
||||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sysinfo(struct sysinfo *) paramsnonnull();
|
||||
int sysinfo(struct sysinfo *);
|
||||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
|
||||
@@ -30,14 +30,10 @@
|
||||
* time. Among the more popular is CLOCK_MONOTONIC. This function has a
|
||||
* zero syscall implementation of that on modern x86.
|
||||
*
|
||||
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. noting
|
||||
* that on Linux CLOCK_MONOTONIC is redefined to use the monotonic
|
||||
* clock that's actually monotonic lool
|
||||
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
|
||||
* @param ts is where the result is stored
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error ENOSYS if clockid isn't available; in which case this function
|
||||
* guarantees an ordinary timestamp is still stored to ts; and
|
||||
* errno isn't restored to its original value, to detect prec. loss
|
||||
* @error EINVAL if clockid isn't supported on this system
|
||||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
@@ -46,6 +42,7 @@ int clock_gettime(int clockid, struct timespec *ts) {
|
||||
axdx_t ad;
|
||||
struct NtFileTime ft;
|
||||
if (!ts) return efault();
|
||||
if (clockid == -1) return einval();
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) {
|
||||
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
|
||||
|
||||
+81
-28
@@ -18,45 +18,98 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, unsigned arg) {
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
uint32_t flags;
|
||||
struct flock *l;
|
||||
struct NtOverlapped ov;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
l = (struct flock *)arg;
|
||||
len = l->l_len;
|
||||
off = l->l_start;
|
||||
if (!len || l->l_whence == SEEK_END) {
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) return __winerr();
|
||||
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
|
||||
} else {
|
||||
size = 0;
|
||||
}
|
||||
if (l->l_whence != SEEK_SET) {
|
||||
if (l->l_whence == SEEK_CUR) {
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) return __winerr();
|
||||
off = pos + off;
|
||||
} else if (l->l_whence == SEEK_END) {
|
||||
off = size - off;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
if (!len) len = size - off;
|
||||
if (off < 0 || len < 0) return einval();
|
||||
offset2overlap(off, &ov);
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
flags = 0;
|
||||
if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately;
|
||||
if (l->l_type == F_WRLCK) flags |= kNtLockfileExclusiveLock;
|
||||
if (LockFileEx(f->handle, flags, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else if (l->l_type == F_UNLCK) {
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
uint32_t flags;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
switch (cmd) {
|
||||
case F_GETFL:
|
||||
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
|
||||
O_NOATIME | O_NONBLOCK);
|
||||
case F_SETFL:
|
||||
/*
|
||||
* - O_APPEND doesn't appear to be tunable at cursory glance
|
||||
* - O_NONBLOCK might require we start doing all i/o in threads
|
||||
* - O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
*/
|
||||
return einval();
|
||||
case F_GETFD:
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
case F_SETFD:
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return einval();
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
|
||||
O_NOATIME | O_NONBLOCK);
|
||||
} else if (cmd == F_SETFL) {
|
||||
/*
|
||||
* - O_APPEND doesn't appear to be tunable at cursory glance
|
||||
* - O_NONBLOCK might require we start doing all i/o in threads
|
||||
* - O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
*/
|
||||
return einval();
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
} else if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
bool islock;
|
||||
islock = cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK;
|
||||
if (islock) cosmo2flock(arg);
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
if (islock) flock2cosmo(arg);
|
||||
return rc;
|
||||
}
|
||||
+8
-2
@@ -25,6 +25,12 @@
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
*
|
||||
* This function implements POSIX Advisory Locks, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK}));
|
||||
* // ...
|
||||
* CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
|
||||
*
|
||||
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
|
||||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
@@ -32,9 +38,9 @@
|
||||
*/
|
||||
int fcntl(int fd, int cmd, ...) {
|
||||
va_list va;
|
||||
unsigned arg;
|
||||
uintptr_t arg;
|
||||
va_start(va, cmd);
|
||||
arg = va_arg(va, unsigned);
|
||||
arg = va_arg(va, uintptr_t);
|
||||
va_end(va);
|
||||
if (!IsWindows()) {
|
||||
return sys_fcntl(fd, cmd, arg);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
int __fixupnewfd(int fd, int flags) {
|
||||
if (fd != -1) {
|
||||
if (flags & O_CLOEXEC) {
|
||||
sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
/**
|
||||
* Acquires lock on file.
|
||||
*
|
||||
* Please note multiple file descriptors means multiple locks.
|
||||
*
|
||||
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
|
||||
* non-blocking, and unlocking
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
|
||||
+13
-11
@@ -39,22 +39,24 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
||||
memset(st, 0, sizeof(*st));
|
||||
switch (filetype) {
|
||||
case kNtFileTypeChar:
|
||||
st->st_mode = S_IFCHR | 0600;
|
||||
st->st_mode = S_IFCHR | 0644;
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
st->st_mode = S_IFIFO | 0600;
|
||||
st->st_mode = S_IFIFO | 0644;
|
||||
break;
|
||||
case kNtFileTypeDisk:
|
||||
if (GetFileInformationByHandle(handle, &wst)) {
|
||||
st->st_mode =
|
||||
(S_IRUSR | S_IXUSR |
|
||||
(!(wst.dwFileAttributes & kNtFileAttributeReadonly) ? S_IWUSR
|
||||
: 0) |
|
||||
((wst.dwFileAttributes & kNtFileAttributeNormal) ? S_IFREG : 0) |
|
||||
((wst.dwFileAttributes & kNtFileFlagOpenReparsePoint) ? S_IFLNK
|
||||
: 0) |
|
||||
((wst.dwFileAttributes & kNtFileAttributeDirectory) ? S_IFDIR
|
||||
: 0));
|
||||
st->st_mode = 0555;
|
||||
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
||||
st->st_mode |= 0200;
|
||||
}
|
||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
st->st_mode |= S_IFDIR;
|
||||
} else if (wst.dwFileAttributes & kNtFileFlagOpenReparsePoint) {
|
||||
st->st_mode |= S_IFLNK;
|
||||
} else {
|
||||
st->st_mode |= S_IFREG;
|
||||
}
|
||||
st->st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
|
||||
st->st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
||||
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fstat(int fd, struct stat *st) {
|
||||
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
return weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
@@ -36,6 +38,7 @@
|
||||
*/
|
||||
int fstatat(int dirfd, const char *path, struct stat *st, uint32_t flags) {
|
||||
struct ZiposUri zipname;
|
||||
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
|
||||
if (weaken(__zipos_stat) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
return weaken(__zipos_stat)(&zipname, st);
|
||||
} else if (!IsWindows()) {
|
||||
|
||||
@@ -34,7 +34,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
|
||||
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if (sys_fstat(fd, &st[0]) != -1) {
|
||||
if (st[0].st_dev && st[0].st_ino) {
|
||||
if (sys_fcntl(fd, XNU_F_GETPATH, buf) != -1) {
|
||||
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
|
||||
if (sys_fstatat(AT_FDCWD, buf, &st[1], 0) != -1) {
|
||||
if (st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) {
|
||||
if (memccpy(res, buf, '\0', size)) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* Returns parent process id.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t getppid(void) {
|
||||
int getppid(void) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsNetbsd()) {
|
||||
return sys_getppid();
|
||||
|
||||
@@ -16,18 +16,20 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "net/http/http.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
unsigned ParseHttpVersion(const char *p, size_t n) {
|
||||
unsigned x;
|
||||
if (!n) return 9;
|
||||
if (n >= 8 && READ32LE(p) == ('H' | 'T' << 8 | 'T' << 16 | 'P' << 24)) {
|
||||
if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '1' << 24)) {
|
||||
return 101;
|
||||
} else if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '0' << 24)) {
|
||||
return 100;
|
||||
}
|
||||
/**
|
||||
* Returns resource usage statistics.
|
||||
*
|
||||
* @param who can be RUSAGE_{SELF,CHILDREN,THREAD}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int sys_getrusage(int who, struct rusage *usage) {
|
||||
int rc;
|
||||
if ((rc = __sys_getrusage(who, usage)) != -1) {
|
||||
__rusage2linux(usage);
|
||||
}
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
+14
-2
@@ -4,7 +4,10 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction-xnu.internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigval.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -106,11 +109,14 @@ char *sys_getcwd(char *, u64) hidden;
|
||||
char *sys_getcwd_xnu(char *, u64) hidden;
|
||||
i32 __sys_dup3(i32, i32, i32) hidden;
|
||||
i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
|
||||
i32 __sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 __sys_fstat(i32, struct stat *) hidden;
|
||||
i32 __sys_fstatat(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 __sys_getrusage(i32, struct rusage *) hidden;
|
||||
i32 __sys_openat(i32, const char *, i32, u32) hidden;
|
||||
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
|
||||
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden;
|
||||
i32 getdents(i32, char *, u32, i64 *) hidden;
|
||||
i32 sys_chdir(const char *) hidden;
|
||||
i32 sys_clock_gettime(i32, struct timespec *) hidden;
|
||||
@@ -126,7 +132,7 @@ i32 sys_fchmod(i32, u32) hidden;
|
||||
i32 sys_fchmodat(i32, const char *, u32, u32) hidden;
|
||||
i32 sys_fchown(i64, u32, u32) hidden;
|
||||
i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
|
||||
i32 sys_fcntl(i32, i32, ...) hidden;
|
||||
i32 sys_fcntl(i32, i32, u64) hidden;
|
||||
i32 sys_fdatasync(i32) hidden;
|
||||
i32 sys_flock(i32, i32) hidden;
|
||||
i32 sys_fstat(i32, struct stat *) hidden;
|
||||
@@ -170,6 +176,8 @@ i32 sys_setrlimit(i32, const struct rlimit *) hidden;
|
||||
i32 sys_setsid(void) hidden;
|
||||
i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden;
|
||||
i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
|
||||
i32 sys_sigqueue(i32, i32, const union sigval) hidden;
|
||||
i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden;
|
||||
i32 sys_sigsuspend(const sigset *, u64) hidden;
|
||||
i32 sys_symlinkat(const char *, i32, const char *) hidden;
|
||||
i32 sys_sync(void) hidden;
|
||||
@@ -220,6 +228,10 @@ int gethostname_linux(char *, size_t) hidden;
|
||||
int gethostname_bsd(char *, size_t) hidden;
|
||||
int gethostname_nt(char *, size_t) hidden;
|
||||
size_t __iovec_size(const struct iovec *, size_t) hidden;
|
||||
void __rusage2linux(struct rusage *) hidden;
|
||||
ssize_t WritevUninterruptible(int, struct iovec *, int);
|
||||
void flock2cosmo(uintptr_t);
|
||||
void cosmo2flock(uintptr_t);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||
@@ -236,7 +248,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
|
||||
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;
|
||||
int sys_fadvise_nt(int, u64, u64, int) hidden;
|
||||
int sys_fchdir_nt(int) hidden;
|
||||
int sys_fcntl_nt(int, int, unsigned) hidden;
|
||||
int sys_fcntl_nt(int, int, uintptr_t) hidden;
|
||||
int sys_fdatasync_nt(int) hidden;
|
||||
int sys_flock_nt(int, int) hidden;
|
||||
int sys_fork_nt(void) hidden;
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@
|
||||
* <-1 signals all processes in -pid process group
|
||||
* @param sig can be:
|
||||
* >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc.
|
||||
* =0 is for error checking
|
||||
* =0 checks both if pid exists and we can signal it
|
||||
* @return 0 if something was accomplished, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
|
||||
union metaflock {
|
||||
struct flock cosmo;
|
||||
struct flock_linux {
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
} linux;
|
||||
struct flock_xnu {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
} xnu;
|
||||
struct flock_freebsd {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
int32_t l_sysid;
|
||||
} freebsd;
|
||||
struct flock_openbsd {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
} openbsd;
|
||||
struct flock_netbsd {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
} netbsd;
|
||||
};
|
||||
|
||||
void flock2cosmo(uintptr_t memory) {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
int32_t l_sysid;
|
||||
union metaflock *u;
|
||||
u = (union metaflock *)memory;
|
||||
if (IsLinux()) {
|
||||
l_start = u->linux.l_start;
|
||||
l_len = u->linux.l_len;
|
||||
l_pid = u->linux.l_pid;
|
||||
l_type = u->linux.l_type;
|
||||
l_whence = u->linux.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsXnu()) {
|
||||
l_start = u->xnu.l_start;
|
||||
l_len = u->xnu.l_len;
|
||||
l_pid = u->xnu.l_pid;
|
||||
l_type = u->xnu.l_type;
|
||||
l_whence = u->xnu.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsFreebsd()) {
|
||||
l_start = u->freebsd.l_start;
|
||||
l_len = u->freebsd.l_len;
|
||||
l_pid = u->freebsd.l_pid;
|
||||
l_type = u->freebsd.l_type;
|
||||
l_whence = u->freebsd.l_whence;
|
||||
l_sysid = u->freebsd.l_sysid;
|
||||
} else if (IsOpenbsd()) {
|
||||
l_start = u->openbsd.l_start;
|
||||
l_len = u->openbsd.l_len;
|
||||
l_pid = u->openbsd.l_pid;
|
||||
l_type = u->openbsd.l_type;
|
||||
l_whence = u->openbsd.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsNetbsd()) {
|
||||
l_start = u->netbsd.l_start;
|
||||
l_len = u->netbsd.l_len;
|
||||
l_pid = u->netbsd.l_pid;
|
||||
l_type = u->netbsd.l_type;
|
||||
l_whence = u->netbsd.l_whence;
|
||||
l_sysid = 0;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
u->cosmo.l_start = l_start;
|
||||
u->cosmo.l_len = l_len;
|
||||
u->cosmo.l_pid = l_pid;
|
||||
u->cosmo.l_type = l_type;
|
||||
u->cosmo.l_whence = l_whence;
|
||||
u->cosmo.l_sysid = l_sysid;
|
||||
}
|
||||
|
||||
void cosmo2flock(uintptr_t memory) {
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int32_t l_pid;
|
||||
int16_t l_type;
|
||||
int16_t l_whence;
|
||||
int32_t l_sysid;
|
||||
union metaflock *u;
|
||||
u = (union metaflock *)memory;
|
||||
l_start = u->cosmo.l_start;
|
||||
l_len = u->cosmo.l_len;
|
||||
l_pid = u->cosmo.l_pid;
|
||||
l_type = u->cosmo.l_type;
|
||||
l_whence = u->cosmo.l_whence;
|
||||
l_sysid = u->cosmo.l_sysid;
|
||||
if (IsLinux()) {
|
||||
u->linux.l_start = l_start;
|
||||
u->linux.l_len = l_len;
|
||||
u->linux.l_pid = l_pid;
|
||||
u->linux.l_type = l_type;
|
||||
u->linux.l_whence = l_whence;
|
||||
} else if (IsXnu()) {
|
||||
u->xnu.l_start = l_start;
|
||||
u->xnu.l_len = l_len;
|
||||
u->xnu.l_pid = l_pid;
|
||||
u->xnu.l_type = l_type;
|
||||
u->xnu.l_whence = l_whence;
|
||||
} else if (IsFreebsd()) {
|
||||
u->freebsd.l_start = l_start;
|
||||
u->freebsd.l_len = l_len;
|
||||
u->freebsd.l_pid = l_pid;
|
||||
u->freebsd.l_type = l_type;
|
||||
u->freebsd.l_whence = l_whence;
|
||||
u->freebsd.l_sysid = l_sysid;
|
||||
} else if (IsOpenbsd()) {
|
||||
u->openbsd.l_start = l_start;
|
||||
u->openbsd.l_len = l_len;
|
||||
u->openbsd.l_pid = l_pid;
|
||||
u->openbsd.l_type = l_type;
|
||||
u->openbsd.l_whence = l_whence;
|
||||
} else if (IsNetbsd()) {
|
||||
u->netbsd.l_start = l_start;
|
||||
u->netbsd.l_len = l_len;
|
||||
u->netbsd.l_pid = l_pid;
|
||||
u->netbsd.l_type = l_type;
|
||||
u->netbsd.l_whence = l_whence;
|
||||
}
|
||||
}
|
||||
@@ -39,12 +39,12 @@ privileged int mprotect(void *addr, uint64_t len, int prot) {
|
||||
int64_t rc;
|
||||
uint32_t oldprot;
|
||||
if (!IsWindows()) {
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
asm volatile(CFLAG_ASM("clc\n\tsyscall")
|
||||
: CFLAG_CONSTRAINT(cf), "=a"(rc)
|
||||
: "1"(__NR_mprotect), "D"(addr), "S"(len), "d"(prot)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
if (cf) {
|
||||
rc = -rc;
|
||||
errno = rc;
|
||||
rc = -1;
|
||||
} else if (rc > -4096ul) {
|
||||
errno = -rc;
|
||||
|
||||
+3
-3
@@ -16,13 +16,13 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/prio.h"
|
||||
|
||||
static int clamp(int p) {
|
||||
return max(-NZERO, min(NZERO - 1, p));
|
||||
return MAX(-NZERO, MIN(NZERO - 1, p));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ static int clamp(int p) {
|
||||
*/
|
||||
int nice(int delta) {
|
||||
int p;
|
||||
if (abs(delta) >= NZERO * 2) {
|
||||
if (ABS(delta) >= NZERO * 2) {
|
||||
p = delta;
|
||||
} else {
|
||||
delta = clamp(delta);
|
||||
|
||||
+4
-8
@@ -56,7 +56,7 @@ static long double MeasureNanosPerCycle(void) {
|
||||
return avg;
|
||||
}
|
||||
|
||||
static void InitTime(void) {
|
||||
void RefreshTime(void) {
|
||||
struct Now now;
|
||||
now.cpn = MeasureNanosPerCycle();
|
||||
now.r0 = dtime(CLOCK_REALTIME);
|
||||
@@ -66,21 +66,17 @@ static void InitTime(void) {
|
||||
}
|
||||
|
||||
long double ConvertTicksToNanos(uint64_t ticks) {
|
||||
if (!g_now.once) InitTime();
|
||||
if (!g_now.once) RefreshTime();
|
||||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl_sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
long double nowl_art(void) {
|
||||
uint64_t ticks;
|
||||
if (!g_now.once) InitTime();
|
||||
if (!g_now.once) RefreshTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
||||
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
|
||||
}
|
||||
@@ -47,14 +47,11 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
||||
? kNtFileShareExclusive
|
||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
&kNtIsInheritable,
|
||||
(flags & O_CREAT) && (flags & O_EXCL)
|
||||
? kNtCreateNew
|
||||
: (flags & O_CREAT) && (flags & O_TRUNC)
|
||||
? kNtCreateAlways
|
||||
: (flags & O_CREAT)
|
||||
? kNtOpenAlways
|
||||
: (flags & O_TRUNC) ? kNtTruncateExisting
|
||||
: kNtOpenExisting,
|
||||
(flags & O_CREAT) && (flags & O_EXCL) ? kNtCreateNew
|
||||
: (flags & O_CREAT) && (flags & O_TRUNC) ? kNtCreateAlways
|
||||
: (flags & O_CREAT) ? kNtOpenAlways
|
||||
: (flags & O_TRUNC) ? kNtTruncateExisting
|
||||
: kNtOpenExisting,
|
||||
/* TODO(jart): Should we just always set overlapped? */
|
||||
(/* note: content indexer demolishes unix-ey i/o performance */
|
||||
kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||
|
||||
@@ -36,7 +36,7 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
|
||||
errno = err;
|
||||
fd = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode);
|
||||
if (fd != -1 && (flags & O_CLOEXEC)) {
|
||||
sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/iov.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -45,6 +46,7 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
||||
|
||||
if (fd < 0) return einval();
|
||||
if (iovlen < 0) return einval();
|
||||
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_read)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/iov.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -49,6 +50,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
|
||||
|
||||
if (fd < 0) return einval();
|
||||
if (iovlen < 0) return einval();
|
||||
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_write)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);
|
||||
|
||||
+16
-12
@@ -20,6 +20,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
@@ -31,18 +32,21 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||
if (fd < 0) return einval();
|
||||
if (iovlen < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_read)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
return sys_readv(fd, iov, iovlen);
|
||||
} else if (fd >= g_fds.n) {
|
||||
return ebadf();
|
||||
} else if (IsMetal()) {
|
||||
return sys_readv_metal(g_fds.p + fd, iov, iovlen);
|
||||
if (fd >= 0 && iovlen >= 0) {
|
||||
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_read)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
return sys_readv(fd, iov, iovlen);
|
||||
} else if (fd >= g_fds.n) {
|
||||
return ebadf();
|
||||
} else if (IsMetal()) {
|
||||
return sys_readv_metal(g_fds.p + fd, iov, iovlen);
|
||||
} else {
|
||||
return sys_readv_nt(g_fds.p + fd, iov, iovlen);
|
||||
}
|
||||
} else {
|
||||
return sys_readv_nt(g_fds.p + fd, iov, iovlen);
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,16 +16,10 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
TEST(memcpy, testBackwardsOverlap3) {
|
||||
volatile char *c;
|
||||
c = malloc(3);
|
||||
memcpy(c, "\e[C", 3);
|
||||
memcpy(c, c + 1, VEIL("r", 3) - 1);
|
||||
EXPECT_EQ('[', c[0]);
|
||||
EXPECT_EQ('C', c[1]);
|
||||
free(c);
|
||||
void __rusage2linux(struct rusage *ru) {
|
||||
if (IsXnu()) {
|
||||
ru->ru_maxrss /= 1024;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,8 @@
|
||||
*
|
||||
* Be sure to check for EINTR on your i/o calls, for best low latency.
|
||||
*
|
||||
* Timers are not inherited across fork.
|
||||
*
|
||||
* @param which can be ITIMER_REAL, ITIMER_VIRTUAL, etc.
|
||||
* @param newvalue specifies the interval ({0,0} means one-shot) and
|
||||
* duration ({0,0} means disarm) in microseconds ∈ [0,999999] and
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define SA_RESTORER 0x04000000
|
||||
|
||||
#ifndef SWITCHEROO
|
||||
#define SWITCHEROO(S1, S2, A, B, C, D) \
|
||||
do { \
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigval.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
|
||||
/* TODO(jart): XNU */
|
||||
|
||||
/**
|
||||
* Sends signal to process, with data.
|
||||
*
|
||||
* The impact of this action can be terminating the process, or
|
||||
* interrupting it to request something happen.
|
||||
*
|
||||
* @param pid can be:
|
||||
* >0 signals one process by id
|
||||
* =0 signals all processes in current process group
|
||||
* -1 signals all processes possible (except init)
|
||||
* <-1 signals all processes in -pid process group
|
||||
* @param sig can be:
|
||||
* >0 can be SIGINT, SIGTERM, SIGKILL, SIGUSR1, etc.
|
||||
* =0 checks both if pid exists and we can signal it
|
||||
* @return 0 if something was accomplished, or -1 w/ errno
|
||||
* @note this isn't supported on OpenBSD
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigqueue(int pid, int sig, const union sigval value) {
|
||||
siginfo_t info;
|
||||
if (IsFreebsd()) {
|
||||
return sys_sigqueue(pid, sig, value);
|
||||
} else {
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = SI_QUEUE;
|
||||
info.si_pid = getpid();
|
||||
info.si_uid = geteuid();
|
||||
info.si_value = value;
|
||||
return sys_sigqueueinfo(pid, &info);
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_FLOCK_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
int64_t l_start;
|
||||
int64_t l_len;
|
||||
int l_pid;
|
||||
struct flock { /* cosmopolitan abi */
|
||||
int16_t l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||
int16_t l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
int64_t l_start; /* starting offset */
|
||||
int64_t l_len; /* 0 means until end of file */
|
||||
int32_t l_pid; /* lock owner */
|
||||
int32_t l_sysid; /* remote system id or zero for local */
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct rlimit {
|
||||
int64_t rlim_cur;
|
||||
int64_t rlim_max;
|
||||
uint64_t rlim_cur; /* current (soft) limit in bytes */
|
||||
uint64_t rlim_max; /* maximum limit in bytes */
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -8,12 +8,12 @@ struct rusage {
|
||||
struct {
|
||||
struct timeval ru_utime; /* user CPU time used */
|
||||
struct timeval ru_stime; /* system CPU time used */
|
||||
int64_t ru_maxrss; /* maximum resident set size */
|
||||
int64_t ru_ixrss; /* integral shared memory size */
|
||||
int64_t ru_idrss; /* integral unshared data size */
|
||||
int64_t ru_isrss; /* integral unshared stack size */
|
||||
int64_t ru_minflt; /* page reclaims (soft page faults) */
|
||||
int64_t ru_majflt; /* page faults (hard page faults) */
|
||||
int64_t ru_maxrss; /* maximum resident set size in (kb) */
|
||||
int64_t ru_ixrss; /* shared memory size (integral kb CLK_TCK) */
|
||||
int64_t ru_idrss; /* unshared data size (integral kb CLK_TCK) */
|
||||
int64_t ru_isrss; /* unshared stack size (integral kb CLK_TCK) */
|
||||
int64_t ru_minflt; /* page reclaims */
|
||||
int64_t ru_majflt; /* page faults */
|
||||
int64_t ru_nswap; /* swaps */
|
||||
int64_t ru_inblock; /* block input operations */
|
||||
int64_t ru_oublock; /* block output operations */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
struct siginfo {
|
||||
int32_t si_signo;
|
||||
int32_t si_errno;
|
||||
int32_t si_code;
|
||||
int32_t si_code; /* {SICODE,SEGV,ILL,FPE,POLL}_xxx */
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
@@ -20,7 +20,7 @@ struct siginfo {
|
||||
};
|
||||
};
|
||||
union {
|
||||
union sigval si_value;
|
||||
union sigval si_value; /* provided by third arg of sigqueue(2) */
|
||||
struct {
|
||||
int32_t si_status;
|
||||
int64_t si_utime, si_stime;
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sysinfo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/memorystatusex.h"
|
||||
#include "libc/nt/systeminfo.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns amount of system ram, cores, etc.
|
||||
@@ -34,6 +36,11 @@
|
||||
*/
|
||||
int sysinfo(struct sysinfo *info) {
|
||||
int rc;
|
||||
if (IsAsan()) {
|
||||
if (info && !__asan_is_valid(info, sizeof(*info))) {
|
||||
return efault();
|
||||
}
|
||||
}
|
||||
memset(info, 0, sizeof(*info));
|
||||
if (!IsWindows()) {
|
||||
rc = sys_sysinfo(info);
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
/**
|
||||
@@ -30,6 +32,11 @@
|
||||
* @see stat()
|
||||
*/
|
||||
int utimes(const char *path, const struct timeval tv[2]) {
|
||||
if (IsAsan()) {
|
||||
if (tv && !__asan_is_valid(tv, sizeof(*tv) * 2)) {
|
||||
return efault();
|
||||
}
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
/*
|
||||
* we don't modernize utimes() into utimensat() because the
|
||||
|
||||
+35
-23
@@ -22,43 +22,55 @@
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct VdprintfState {
|
||||
int n;
|
||||
int fd;
|
||||
unsigned char buf[1024];
|
||||
int n, t, fd;
|
||||
char b[1024];
|
||||
};
|
||||
|
||||
static int vdprintf_flush(struct VdprintfState *df, int n) {
|
||||
int i, rc;
|
||||
for (i = 0; i < n; i += rc) {
|
||||
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
|
||||
return -1;
|
||||
static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
|
||||
struct iovec iov[2];
|
||||
if (n) {
|
||||
if (t->n + n < sizeof(t->b)) {
|
||||
memcpy(t->b + t->n, s, n);
|
||||
t->n += n;
|
||||
} else {
|
||||
iov[0].iov_base = t->b;
|
||||
iov[0].iov_len = t->n;
|
||||
iov[1].iov_base = s;
|
||||
iov[1].iov_len = n;
|
||||
if (WritevUninterruptible(t->fd, iov, 2) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t->t += t->n;
|
||||
t->n = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdprintf_putc(int c, struct VdprintfState *df) {
|
||||
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
|
||||
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
return vdprintf_flush(df, ARRAYLEN(df->buf));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string directly to system i/o device.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||
struct VdprintfState df;
|
||||
df.n = 0;
|
||||
df.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &df, fmt, va) == -1) return -1;
|
||||
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
|
||||
return df.n;
|
||||
struct iovec iov[1];
|
||||
struct VdprintfState t;
|
||||
t.n = 0;
|
||||
t.t = 0;
|
||||
t.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &t, fmt, va) == -1) return -1;
|
||||
if (t.n) {
|
||||
iov[0].iov_base = t.b;
|
||||
iov[0].iov_len = t.n;
|
||||
if (WritevUninterruptible(t.fd, iov, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t.t += t.n;
|
||||
}
|
||||
return t.t;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
int sys_wait4(int pid, int *opt_out_wstatus, int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
int rc;
|
||||
if ((rc = __sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage)) != -1) {
|
||||
if (opt_out_rusage) {
|
||||
__rusage2linux(opt_out_rusage);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/wait4.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Waits for status to change on process.
|
||||
@@ -35,6 +37,16 @@
|
||||
*/
|
||||
int wait4(int pid, int *opt_out_wstatus, int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
if (IsAsan()) {
|
||||
if (opt_out_wstatus &&
|
||||
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) {
|
||||
return efault();
|
||||
}
|
||||
if (opt_out_rusage &&
|
||||
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))) {
|
||||
return efault();
|
||||
}
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
return sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage);
|
||||
} else {
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define time_t int64_t
|
||||
#define timer_t void*
|
||||
#define uid_t uint32_t
|
||||
#define rlim_t uint64_t /* int64_t on bsd */
|
||||
|
||||
#define int_fast8_t __INT_FAST8_TYPE__
|
||||
#define uint_fast8_t __UINT_FAST8_TYPE__
|
||||
|
||||
+16
-12
@@ -19,6 +19,7 @@
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
@@ -34,18 +35,21 @@
|
||||
* @return number of bytes actually handed off, or -1 w/ errno
|
||||
*/
|
||||
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
|
||||
if (fd < 0) return einval();
|
||||
if (iovlen < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_write)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
return sys_writev(fd, iov, iovlen);
|
||||
} else if (fd >= g_fds.n) {
|
||||
return ebadf();
|
||||
} else if (IsMetal()) {
|
||||
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
|
||||
if (fd >= 0 && iovlen >= 0) {
|
||||
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
return weaken(__zipos_write)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
return sys_writev(fd, iov, iovlen);
|
||||
} else if (fd >= g_fds.n) {
|
||||
return ebadf();
|
||||
} else if (IsMetal()) {
|
||||
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
|
||||
} else {
|
||||
return sys_writev_nt(g_fds.p + fd, iov, iovlen);
|
||||
}
|
||||
} else {
|
||||
return sys_writev_nt(g_fds.p + fd, iov, iovlen);
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
||||
ssize_t WritevUninterruptible(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||
wrote = rc;
|
||||
do {
|
||||
if (wrote >= iov->iov_len) {
|
||||
wrote -= iov->iov_len;
|
||||
++iov;
|
||||
--iovlen;
|
||||
} else {
|
||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||
iov->iov_len -= wrote;
|
||||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
} while (iovlen);
|
||||
return 0;
|
||||
}
|
||||
+6
-6
@@ -45,12 +45,6 @@
|
||||
#define IsTrustworthy() 0
|
||||
#endif
|
||||
|
||||
#ifdef SECURITY_BLANKETS
|
||||
#define UseSecurityBlankets() 1
|
||||
#else
|
||||
#define UseSecurityBlankets() 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY
|
||||
#define IsTiny() 1
|
||||
#else
|
||||
@@ -63,6 +57,12 @@
|
||||
#define IsOptimized() 0
|
||||
#endif
|
||||
|
||||
#ifdef __FSANITIZE_ADDRESS__
|
||||
#define IsAsan() 1
|
||||
#else
|
||||
#define IsAsan() 0
|
||||
#endif
|
||||
|
||||
#if defined(__PIE__) || defined(__PIC__)
|
||||
#define IsPositionIndependent() 1
|
||||
#else
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
|
||||
@@ -36,12 +36,15 @@ forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
|
||||
/**
|
||||
* Compares DNS hostnames in reverse lexicographical asciibetical order.
|
||||
* @return <0, 0, or >0
|
||||
* @see test/libc/dns/dnsnamecmp_test.c (the code that matters)
|
||||
* @see test/libc/dns/comparednsnames_test.c (the code that matters)
|
||||
*/
|
||||
int dnsnamecmp(const char *A, const char *B) {
|
||||
int CompareDnsNames(const char *A, const char *B) {
|
||||
int res;
|
||||
bool first;
|
||||
size_t n, m, i, j;
|
||||
if (A == B) return 0;
|
||||
size_t n = strlen(A);
|
||||
size_t m = strlen(B);
|
||||
n = strlen(A);
|
||||
m = strlen(B);
|
||||
if (!n || !m || ((A[n - 1] == '.') ^ (B[m - 1] == '.'))) {
|
||||
if (n && m && A[n - 1] == '.' && strchr(B, '.')) {
|
||||
--m;
|
||||
@@ -51,9 +54,9 @@ int dnsnamecmp(const char *A, const char *B) {
|
||||
return A[n ? n - 1 : 0] - B[m ? m - 1 : 0];
|
||||
}
|
||||
}
|
||||
size_t i = n;
|
||||
size_t j = m;
|
||||
bool first = true;
|
||||
i = n;
|
||||
j = m;
|
||||
first = true;
|
||||
for (;;) {
|
||||
FindDnsLabel(A, &i, &n);
|
||||
FindDnsLabel(B, &j, &m);
|
||||
@@ -62,8 +65,7 @@ int dnsnamecmp(const char *A, const char *B) {
|
||||
if (!i && j) return 1;
|
||||
if (!j && i) return -1;
|
||||
}
|
||||
int res;
|
||||
if ((res = strncasecmp(&A[i], &B[j], min(n - i + 1, m - j + 1)))) {
|
||||
if ((res = strncasecmp(&A[i], &B[j], MIN(n - i + 1, m - j + 1)))) {
|
||||
return res;
|
||||
}
|
||||
if (!i || !j) {
|
||||
+12
-3
@@ -27,6 +27,15 @@
|
||||
#define EAI_INTR -104
|
||||
#define EAI_NOTCANCELED -102
|
||||
|
||||
/* AI_* conforms to NT ABI */
|
||||
#define AI_PASSIVE 1
|
||||
#define AI_CANONNAME 2
|
||||
#define AI_NUMERICHOST 4
|
||||
#define AI_NUMERICSERV 8
|
||||
#define AI_ALL 0x0100
|
||||
#define AI_ADDRCONFIG 0x0400
|
||||
#define AI_V4MAPPED 0x0800
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
@@ -48,9 +57,9 @@ int getaddrinfo(const char *, const char *, const struct addrinfo *,
|
||||
struct addrinfo **) paramsnonnull((4));
|
||||
int freeaddrinfo(struct addrinfo *);
|
||||
const char *gai_strerror(int);
|
||||
int dnsnamecmp(const char *, const char *) paramsnonnull();
|
||||
int pascalifydnsname(uint8_t *, size_t, const char *) paramsnonnull();
|
||||
int resolvedns(const struct ResolvConf *, int, const char *, struct sockaddr *,
|
||||
int CompareDnsNames(const char *, const char *) paramsnonnull();
|
||||
int PascalifyDnsName(uint8_t *, size_t, const char *) paramsnonnull();
|
||||
int ResolveDns(const struct ResolvConf *, int, const char *, struct sockaddr *,
|
||||
uint32_t) paramsnonnull();
|
||||
struct addrinfo *newaddrinfo(uint16_t);
|
||||
|
||||
|
||||
+23
-29
@@ -21,43 +21,37 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Serializes DNS message header to wire.
|
||||
* Serializes DNS message h to wire.
|
||||
*
|
||||
* @return number of bytes written (always 12) or -1 w/ errno
|
||||
* @see pascalifydnsname()
|
||||
*/
|
||||
int serializednsheader(uint8_t *buf, size_t size,
|
||||
const struct DnsHeader header) {
|
||||
if (size < 12) return enospc();
|
||||
buf[0x0] = header.id >> 010u;
|
||||
buf[0x1] = header.id >> 000u;
|
||||
buf[0x2] = header.bf1;
|
||||
buf[0x3] = header.bf2;
|
||||
buf[0x4] = header.qdcount >> 010u;
|
||||
buf[0x5] = header.qdcount >> 000u;
|
||||
buf[0x6] = header.ancount >> 010u;
|
||||
buf[0x7] = header.ancount >> 000u;
|
||||
buf[0x8] = header.nscount >> 010u;
|
||||
buf[0x9] = header.nscount >> 000u;
|
||||
buf[0xa] = header.arcount >> 010u;
|
||||
buf[0xb] = header.arcount >> 000u;
|
||||
return 12;
|
||||
void SerializeDnsHeader(uint8_t p[restrict 12], const struct DnsHeader *h) {
|
||||
p[0x0] = h->id >> 8;
|
||||
p[0x1] = h->id;
|
||||
p[0x2] = h->bf1;
|
||||
p[0x3] = h->bf2;
|
||||
p[0x4] = h->qdcount >> 8;
|
||||
p[0x5] = h->qdcount;
|
||||
p[0x6] = h->ancount >> 8;
|
||||
p[0x7] = h->ancount;
|
||||
p[0x8] = h->nscount >> 8;
|
||||
p[0x9] = h->nscount;
|
||||
p[0xa] = h->arcount >> 8;
|
||||
p[0xb] = h->arcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes DNS message header to wire.
|
||||
* Serializes DNS message h to wire.
|
||||
*
|
||||
* @return number of bytes read (always 12) or -1 w/ errno
|
||||
*/
|
||||
int deserializednsheader(struct DnsHeader *header, const uint8_t *buf,
|
||||
size_t size) {
|
||||
if (size < 12) return ebadmsg();
|
||||
header->id = READ16BE(buf + 0);
|
||||
header->bf1 = buf[2];
|
||||
header->bf2 = buf[3];
|
||||
header->qdcount = READ16BE(buf + 4);
|
||||
header->ancount = READ16BE(buf + 6);
|
||||
header->nscount = READ16BE(buf + 8);
|
||||
header->arcount = READ16BE(buf + 10);
|
||||
return 12;
|
||||
void DeserializeDnsHeader(struct DnsHeader *h, const uint8_t p[restrict 12]) {
|
||||
h->id = READ16BE(p);
|
||||
h->bf1 = p[2];
|
||||
h->bf2 = p[3];
|
||||
h->qdcount = READ16BE(p + 4);
|
||||
h->ancount = READ16BE(p + 6);
|
||||
h->nscount = READ16BE(p + 8);
|
||||
h->arcount = READ16BE(p + 10);
|
||||
}
|
||||
@@ -13,8 +13,8 @@ struct DnsHeader {
|
||||
uint16_t arcount; /* additional record count */
|
||||
};
|
||||
|
||||
int serializednsheader(uint8_t *, size_t, const struct DnsHeader);
|
||||
int deserializednsheader(struct DnsHeader *, const uint8_t *, size_t);
|
||||
void SerializeDnsHeader(uint8_t[restrict 12], const struct DnsHeader *);
|
||||
void DeserializeDnsHeader(struct DnsHeader *, const uint8_t[restrict 12]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -9,7 +9,7 @@ struct DnsQuestion {
|
||||
uint16_t qclass;
|
||||
};
|
||||
|
||||
int serializednsquestion(uint8_t *, size_t, struct DnsQuestion);
|
||||
int SerializeDnsQuestion(uint8_t *, size_t, const struct DnsQuestion *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
/**
|
||||
* Frees addresses returned by getaddrinfo().
|
||||
*/
|
||||
int freeaddrinfo(struct addrinfo *addrs) {
|
||||
int freeaddrinfo(struct addrinfo *ai) {
|
||||
struct addrinfo *next;
|
||||
while (addrs) {
|
||||
while (ai) {
|
||||
/* we assume ai_addr and ai_canonname are shoehorned */
|
||||
next = addrs->ai_next;
|
||||
free(addrs);
|
||||
addrs = next;
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -20,9 +20,9 @@
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Frees HOSTS.TXT data structure populated by parsehoststxt().
|
||||
* Frees HOSTS.TXT data structure populated by ParseHostsTxt().
|
||||
*/
|
||||
void freehoststxt(struct HostsTxt **ht) {
|
||||
void FreeHostsTxt(struct HostsTxt **ht) {
|
||||
if (*ht) {
|
||||
free_s(&(*ht)->entries.p);
|
||||
free_s(&(*ht)->strings.p);
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Frees resolv.conf data structure populated by parseresolvconf().
|
||||
* Frees resolv.conf data structure populated by ParseResolvConf().
|
||||
*/
|
||||
void freeresolvconf(struct ResolvConf **rvp) {
|
||||
void FreeResolvConf(struct ResolvConf **rvp) {
|
||||
if (*rvp) {
|
||||
free_s(&(*rvp)->nameservers.p);
|
||||
free_s(rvp);
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ai.h"
|
||||
#include "libc/sysv/consts/inaddr.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
@@ -68,13 +67,13 @@ int getaddrinfo(const char *name, const char *service,
|
||||
} else if (hints && (hints->ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST) {
|
||||
freeaddrinfo(ai);
|
||||
return EAI_NONAME;
|
||||
} else if (resolvehoststxt(gethoststxt(), AF_INET, name, ai->ai_addr,
|
||||
} else if (ResolveHostsTxt(GetHostsTxt(), AF_INET, name, ai->ai_addr,
|
||||
sizeof(ai->ai_addr4), &canon) > 0) {
|
||||
memcpy(ai->ai_canonname, canon, min(strlen(canon), DNS_NAME_MAX) + 1);
|
||||
*res = ai;
|
||||
return 0;
|
||||
} else {
|
||||
rc = resolvedns(getresolvconf(), AF_INET, name, ai->ai_addr,
|
||||
rc = ResolveDns(GetResolvConf(), AF_INET, name, ai->ai_addr,
|
||||
sizeof(ai->ai_addr4));
|
||||
if (rc > 0) {
|
||||
*res = ai;
|
||||
|
||||
@@ -53,7 +53,7 @@ static textwindows noinline char *getnthoststxtpath(char *pathbuf,
|
||||
*
|
||||
* @note yoinking realloc() ensures there's no size limits
|
||||
*/
|
||||
const struct HostsTxt *gethoststxt(void) {
|
||||
const struct HostsTxt *GetHostsTxt(void) {
|
||||
FILE *f;
|
||||
const char *path;
|
||||
char pathbuf[PATH_MAX];
|
||||
@@ -65,16 +65,16 @@ const struct HostsTxt *gethoststxt(void) {
|
||||
init->ht.entries.p = init->entries;
|
||||
init->ht.strings.n = pushpop(ARRAYLEN(init->strings));
|
||||
init->ht.strings.p = init->strings;
|
||||
__cxa_atexit(freehoststxt, &g_hoststxt, NULL);
|
||||
__cxa_atexit(FreeHostsTxt, &g_hoststxt, NULL);
|
||||
path = "/etc/hosts";
|
||||
if (IsWindows()) {
|
||||
path = firstnonnull(getnthoststxtpath(pathbuf, ARRAYLEN(pathbuf)), path);
|
||||
}
|
||||
if (!(f = fopen(path, "r")) || parsehoststxt(g_hoststxt, f) == -1) {
|
||||
if (!(f = fopen(path, "r")) || ParseHostsTxt(g_hoststxt, f) == -1) {
|
||||
/* TODO(jart): Elevate robustness. */
|
||||
}
|
||||
fclose(f);
|
||||
sorthoststxt(g_hoststxt);
|
||||
SortHostsTxt(g_hoststxt);
|
||||
}
|
||||
return g_hoststxt;
|
||||
}
|
||||
+10
-12
@@ -38,41 +38,39 @@
|
||||
* this function will append
|
||||
* @return number of nameservers appended, or -1 w/ errno
|
||||
*/
|
||||
textwindows int getntnameservers(struct ResolvConf *resolv) {
|
||||
textwindows int GetNtNameServers(struct ResolvConf *resolv) {
|
||||
int rc;
|
||||
char value8[128];
|
||||
int64_t hkInterfaces;
|
||||
struct sockaddr_in nameserver;
|
||||
char16_t value[128], ifaceuuid[64];
|
||||
uint32_t i, keycount, valuebytes, ifaceuuidlen;
|
||||
char16_t value[128], uuid[64];
|
||||
uint32_t i, keycount, valuebytes, uuidlen;
|
||||
keycount = 0;
|
||||
hkInterfaces = kNtInvalidHandleValue;
|
||||
if (!RegOpenKeyEx(
|
||||
kNtHkeyLocalMachine,
|
||||
u"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
|
||||
0, kNtKeyRead, &hkInterfaces) &&
|
||||
!RegQueryInfoKey(hkInterfaces, NULL, NULL, NULL, &keycount, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL)) {
|
||||
!RegQueryInfoKey(hkInterfaces, 0, 0, 0, &keycount, 0, 0, 0, 0, 0, 0, 0)) {
|
||||
nameserver.sin_family = AF_INET;
|
||||
nameserver.sin_port = htons(DNS_PORT);
|
||||
rc = 0;
|
||||
for (i = 0; i < keycount; ++i) {
|
||||
ifaceuuidlen = sizeof(ifaceuuid);
|
||||
if (!RegEnumKeyEx(hkInterfaces, i, ifaceuuid, &ifaceuuidlen, NULL, NULL,
|
||||
NULL, NULL) &&
|
||||
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpIpAddress",
|
||||
uuidlen = sizeof(uuid);
|
||||
if (!RegEnumKeyEx(hkInterfaces, i, uuid, &uuidlen, 0, 0, 0, 0) &&
|
||||
((!RegGetValue(hkInterfaces, uuid, u"DhcpIpAddress",
|
||||
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
|
||||
((valuebytes = sizeof(value)), &valuebytes)) &&
|
||||
valuebytes > 2 * sizeof(char16_t)) ||
|
||||
(!RegGetValue(hkInterfaces, ifaceuuid, u"IpAddress",
|
||||
(!RegGetValue(hkInterfaces, uuid, u"IpAddress",
|
||||
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
|
||||
((valuebytes = sizeof(value)), &valuebytes)) &&
|
||||
valuebytes > 2 * sizeof(char16_t))) &&
|
||||
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpNameServer",
|
||||
((!RegGetValue(hkInterfaces, uuid, u"DhcpNameServer",
|
||||
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
|
||||
((valuebytes = sizeof(value)), &valuebytes)) &&
|
||||
valuebytes > 2 * sizeof(char16_t)) ||
|
||||
(!RegGetValue(hkInterfaces, ifaceuuid, u"NameServer",
|
||||
(!RegGetValue(hkInterfaces, uuid, u"NameServer",
|
||||
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
|
||||
((valuebytes = sizeof(value)), &valuebytes)) &&
|
||||
valuebytes > 2 * sizeof(char16_t)))) {
|
||||
|
||||
@@ -34,7 +34,7 @@ static struct ResolvConfInitialStaticMemory {
|
||||
/**
|
||||
* Returns singleton with DNS server address.
|
||||
*/
|
||||
const struct ResolvConf *getresolvconf(void) {
|
||||
const struct ResolvConf *GetResolvConf(void) {
|
||||
int rc;
|
||||
FILE *f;
|
||||
struct ResolvConfInitialStaticMemory *init;
|
||||
@@ -43,16 +43,16 @@ const struct ResolvConf *getresolvconf(void) {
|
||||
g_resolvconf = &init->rv;
|
||||
pushmov(&init->rv.nameservers.n, ARRAYLEN(init->nameservers));
|
||||
init->rv.nameservers.p = init->nameservers;
|
||||
__cxa_atexit(freeresolvconf, &g_resolvconf, NULL);
|
||||
__cxa_atexit(FreeResolvConf, &g_resolvconf, NULL);
|
||||
if (!IsWindows()) {
|
||||
if ((f = fopen("/etc/resolv.conf", "r"))) {
|
||||
rc = parseresolvconf(g_resolvconf, f);
|
||||
rc = ParseResolvConf(g_resolvconf, f);
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
fclose(f);
|
||||
} else {
|
||||
rc = getntnameservers(g_resolvconf);
|
||||
rc = GetNtNameServers(g_resolvconf);
|
||||
}
|
||||
if (rc == -1 && !IsTiny()) {
|
||||
/* TODO(jart): Elevate robustness. */
|
||||
|
||||
+12
-15
@@ -1,26 +1,23 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
|
||||
#define COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct FILE;
|
||||
struct sockaddr;
|
||||
|
||||
struct HostsTxtEntry {
|
||||
unsigned char ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */
|
||||
uint32_t name; /* &ht->strings.p[he->name] */
|
||||
uint32_t canon; /* &ht->strings.p[he->canon] */
|
||||
uint8_t ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */
|
||||
uint32_t name; /* &ht->strings.p[he->name] */
|
||||
uint32_t canon; /* &ht->strings.p[he->canon] */
|
||||
};
|
||||
|
||||
struct HostsTxtEntries {
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t i, n;
|
||||
struct HostsTxtEntry *p;
|
||||
};
|
||||
|
||||
struct HostsTxtStrings {
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
@@ -29,11 +26,11 @@ struct HostsTxt {
|
||||
struct HostsTxtStrings strings;
|
||||
};
|
||||
|
||||
const struct HostsTxt *gethoststxt(void) returnsnonnull;
|
||||
void freehoststxt(struct HostsTxt **) paramsnonnull();
|
||||
int parsehoststxt(struct HostsTxt *, struct FILE *) paramsnonnull();
|
||||
void sorthoststxt(struct HostsTxt *) paramsnonnull();
|
||||
int resolvehoststxt(const struct HostsTxt *, int, const char *,
|
||||
const struct HostsTxt *GetHostsTxt(void) returnsnonnull;
|
||||
void FreeHostsTxt(struct HostsTxt **) paramsnonnull();
|
||||
int ParseHostsTxt(struct HostsTxt *, FILE *) paramsnonnull();
|
||||
void SortHostsTxt(struct HostsTxt *) paramsnonnull();
|
||||
int ResolveHostsTxt(const struct HostsTxt *, int, const char *,
|
||||
struct sockaddr *, uint32_t, const char **)
|
||||
paramsnonnull((1, 3));
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see hoststxtsort() which is the logical next step
|
||||
*/
|
||||
int parsehoststxt(struct HostsTxt *ht, FILE *f) {
|
||||
int ParseHostsTxt(struct HostsTxt *ht, FILE *f) {
|
||||
char *line;
|
||||
size_t linesize;
|
||||
struct HostsTxtEntry entry;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
* @param f is an open stream with file content
|
||||
* @return number of nameservers appended, or -1 w/ errno
|
||||
*/
|
||||
int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
|
||||
int ParseResolvConf(struct ResolvConf *resolv, struct FILE *f) {
|
||||
/* TODO(jart): options ndots:5 */
|
||||
int rc;
|
||||
char *line;
|
||||
@@ -49,7 +49,7 @@ int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
|
||||
struct sockaddr_in nameserver;
|
||||
char *directive, *value, *tok, *comment;
|
||||
rc = 0;
|
||||
line = NULL;
|
||||
line = 0;
|
||||
linesize = 0;
|
||||
nameserver.sin_family = AF_INET;
|
||||
nameserver.sin_port = htons(DNS_PORT);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* @param name is a dotted NUL-terminated hostname string
|
||||
* @return bytes written (excluding NUL) or -1 w/ errno
|
||||
*/
|
||||
int pascalifydnsname(uint8_t *buf, size_t size, const char *name) {
|
||||
int PascalifyDnsName(uint8_t *buf, size_t size, const char *name) {
|
||||
size_t i, j, k, namelen;
|
||||
if ((namelen = strlen(name)) > DNS_NAME_MAX) return enametoolong();
|
||||
i = 0;
|
||||
|
||||
@@ -14,10 +14,10 @@ struct ResolvConf {
|
||||
struct Nameservers nameservers;
|
||||
};
|
||||
|
||||
const struct ResolvConf *getresolvconf(void) returnsnonnull;
|
||||
int parseresolvconf(struct ResolvConf *, struct FILE *) paramsnonnull();
|
||||
void freeresolvconf(struct ResolvConf **) paramsnonnull();
|
||||
int getntnameservers(struct ResolvConf *) paramsnonnull();
|
||||
const struct ResolvConf *GetResolvConf(void) returnsnonnull;
|
||||
int ParseResolvConf(struct ResolvConf *, struct FILE *) paramsnonnull();
|
||||
void FreeResolvConf(struct ResolvConf **) paramsnonnull();
|
||||
int GetNtNameServers(struct ResolvConf *) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
+54
-58
@@ -38,7 +38,7 @@
|
||||
/**
|
||||
* Queries Domain Name System for address associated with name.
|
||||
*
|
||||
* @param resolvconf can be getresolvconf()
|
||||
* @param resolvconf can be GetResolvConf()
|
||||
* @param af can be AF_INET, AF_UNSPEC
|
||||
* @param name can be a local or fully-qualified hostname
|
||||
* @param addr should point to a struct sockaddr_in; if this function
|
||||
@@ -47,65 +47,62 @@
|
||||
* @return number of matches found, or -1 w/ errno
|
||||
* @error EAFNOSUPPORT. ENETDOWN, ENAMETOOLONG, EBADMSG
|
||||
*/
|
||||
int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
|
||||
int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
||||
struct sockaddr *addr, uint32_t addrsize) {
|
||||
size_t msgsize;
|
||||
int res, fd, rc, rc2;
|
||||
struct sockaddr_in *addr4;
|
||||
struct DnsQuestion question;
|
||||
int rc, fd, n;
|
||||
struct DnsQuestion q;
|
||||
struct DnsHeader h, h2;
|
||||
struct sockaddr_in *a4;
|
||||
uint8_t *p, *pe, msg[512];
|
||||
uint16_t rtype, rclass, rdlength;
|
||||
uint8_t *p, *pe, *outmsg, *inmsg;
|
||||
struct DnsHeader header, response;
|
||||
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
|
||||
if (!resolvconf->nameservers.i) return 0;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.id = rand32();
|
||||
header.bf1 = 1; /* recursion desired */
|
||||
header.qdcount = 1;
|
||||
question.qname = name;
|
||||
question.qtype = DNS_TYPE_A;
|
||||
question.qclass = DNS_CLASS_IN;
|
||||
res = -1;
|
||||
if ((outmsg = malloc(kMsgMax)) && (inmsg = malloc(kMsgMax)) &&
|
||||
(rc = serializednsheader(outmsg, kMsgMax, header)) != -1 &&
|
||||
(rc2 = serializednsquestion(outmsg + rc, kMsgMax - rc, question)) != -1) {
|
||||
msgsize = rc + rc2;
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1 &&
|
||||
sendto(fd, outmsg, msgsize, 0, (void *)&resolvconf->nameservers.p[0],
|
||||
sizeof(resolvconf->nameservers.p[0])) == msgsize) {
|
||||
if ((rc = recv(fd, inmsg, kMsgMax, 0)) != -1 &&
|
||||
(rc2 = deserializednsheader(&response, inmsg, rc)) != -1 &&
|
||||
response.id == header.id) {
|
||||
res = 0;
|
||||
if (response.ancount) {
|
||||
p = inmsg + rc2;
|
||||
pe = inmsg + rc;
|
||||
while (p < pe && response.qdcount) {
|
||||
p += strnlen((char *)p, pe - p) + 1 + 4;
|
||||
response.qdcount--;
|
||||
memset(&h, 0, sizeof(h));
|
||||
rc = ebadmsg();
|
||||
h.id = rand32();
|
||||
h.bf1 = 1; /* recursion desired */
|
||||
h.qdcount = 1;
|
||||
q.qname = name;
|
||||
q.qtype = DNS_TYPE_A;
|
||||
q.qclass = DNS_CLASS_IN;
|
||||
memset(msg, 0, sizeof(msg));
|
||||
SerializeDnsHeader(msg, &h);
|
||||
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
|
||||
if (sendto(fd, msg, 12 + n, 0, resolvconf->nameservers.p,
|
||||
sizeof(*resolvconf->nameservers.p)) == 12 + n &&
|
||||
(n = read(fd, msg, 512)) >= 12) {
|
||||
DeserializeDnsHeader(&h2, msg);
|
||||
if (h2.id == h.id) {
|
||||
rc = 0;
|
||||
if (h2.ancount) {
|
||||
p = msg + 12;
|
||||
pe = msg + n;
|
||||
while (p < pe && h2.qdcount) {
|
||||
p += strnlen((char *)p, pe - p) + 1 + 4;
|
||||
h2.qdcount--;
|
||||
}
|
||||
if (p + 1 < pe) {
|
||||
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
|
||||
p += 2;
|
||||
} else {
|
||||
p += strnlen((char *)p, pe - p) + 1;
|
||||
}
|
||||
if (p + 1 < pe) {
|
||||
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
|
||||
p += 2;
|
||||
} else {
|
||||
p += strnlen((char *)p, pe - p) + 1;
|
||||
}
|
||||
if (p + 2 + 2 + 4 + 2 < pe) {
|
||||
rtype = READ16BE(p), p += 2;
|
||||
rclass = READ16BE(p), p += 2;
|
||||
/* ttl */ p += 4;
|
||||
rdlength = READ16BE(p), p += 2;
|
||||
if (p + rdlength <= pe && rdlength == 4 &&
|
||||
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
|
||||
res = 1;
|
||||
if (addrsize) {
|
||||
if (addrsize >= kMinSockaddr4Size) {
|
||||
addr4 = (struct sockaddr_in *)addr;
|
||||
addr4->sin_family = AF_INET;
|
||||
memcpy(&addr4->sin_addr.s_addr, p, 4);
|
||||
} else {
|
||||
res = einval();
|
||||
}
|
||||
if (p + 2 + 2 + 4 + 2 < pe) {
|
||||
rtype = READ16BE(p), p += 2;
|
||||
rclass = READ16BE(p), p += 2;
|
||||
/* ttl */ p += 4;
|
||||
rdlength = READ16BE(p), p += 2;
|
||||
if (p + rdlength <= pe && rdlength == 4 &&
|
||||
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
|
||||
rc = 1;
|
||||
if (addrsize) {
|
||||
if (addrsize >= kMinSockaddr4Size) {
|
||||
a4 = (struct sockaddr_in *)addr;
|
||||
a4->sin_family = AF_INET;
|
||||
memcpy(&a4->sin_addr.s_addr, p, 4);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +110,7 @@ int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
|
||||
}
|
||||
}
|
||||
}
|
||||
res |= close(fd);
|
||||
}
|
||||
free(outmsg);
|
||||
return res;
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
@@ -27,16 +27,16 @@
|
||||
|
||||
static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
|
||||
const char *strings) {
|
||||
return dnsnamecmp(node, &strings[entry->name]);
|
||||
return CompareDnsNames(node, &strings[entry->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds address associated with name in HOSTS.TXT table.
|
||||
*
|
||||
* This function performs binary search, so sorthoststxt() must be
|
||||
* This function performs binary search, so SortHostsTxt() must be
|
||||
* called on the table beforehand.
|
||||
*
|
||||
* @param ht can be gethoststxt()
|
||||
* @param ht can be GetHostsTxt()
|
||||
* @param af can be AF_INET, AF_UNSPEC
|
||||
* @param name can be a local or fully-qualified hostname
|
||||
* @param addr should point to a struct sockaddr_in; if this function
|
||||
@@ -46,7 +46,7 @@ static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
|
||||
* @return number of matches found, or -1 w/ errno
|
||||
* @error EAFNOSUPPORT
|
||||
*/
|
||||
int resolvehoststxt(const struct HostsTxt *ht, int af, const char *name,
|
||||
int ResolveHostsTxt(const struct HostsTxt *ht, int af, const char *name,
|
||||
struct sockaddr *addr, uint32_t addrsize,
|
||||
const char **canon) {
|
||||
struct sockaddr_in *addr4;
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
* @return number of bytes written
|
||||
* @see pascalifydnsname()
|
||||
*/
|
||||
int serializednsquestion(uint8_t *buf, size_t size, struct DnsQuestion dq) {
|
||||
int SerializeDnsQuestion(uint8_t *buf, size_t size,
|
||||
const struct DnsQuestion *dq) {
|
||||
int wrote;
|
||||
if ((wrote = pascalifydnsname(buf, size, dq.qname)) == -1) return -1;
|
||||
if ((wrote = PascalifyDnsName(buf, size, dq->qname)) == -1) return -1;
|
||||
if (wrote + 1 + 4 > size) return enospc();
|
||||
buf[wrote + 1] = dq.qtype >> 010, buf[wrote + 2] = dq.qtype >> 000;
|
||||
buf[wrote + 3] = dq.qclass >> 010, buf[wrote + 4] = dq.qclass >> 000;
|
||||
buf[wrote + 1] = dq->qtype >> 8;
|
||||
buf[wrote + 2] = dq->qtype;
|
||||
buf[wrote + 3] = dq->qclass >> 8;
|
||||
buf[wrote + 4] = dq->qclass;
|
||||
return wrote + 5;
|
||||
}
|
||||
@@ -22,25 +22,26 @@
|
||||
|
||||
/**
|
||||
* Compares hostnames in HOSTS.TXT table.
|
||||
* @see dnsnamecmp(), parsehoststxt()
|
||||
* @see CompareDnsNames(), ParseHostsTxt()
|
||||
*/
|
||||
static int cmphoststxt(const struct HostsTxtEntry *e1,
|
||||
const struct HostsTxtEntry *e2, const char *strings) {
|
||||
if (e1 == e2) return 0;
|
||||
return dnsnamecmp(&strings[e1->name], &strings[e2->name]);
|
||||
return CompareDnsNames(&strings[e1->name], &strings[e2->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts entries in HOSTS.TXT table.
|
||||
*
|
||||
* This function enables resolvehoststxt() to be called so hard-coded
|
||||
* This function enables ResolveHostsTxt() to be called so hard-coded
|
||||
* hostname lookups take logarithmic time; you can blackhole all the
|
||||
* spam you want, in your /etc/hosts file.
|
||||
*
|
||||
* The sorted order, defined by dnsnamecmp(), also makes it possible to
|
||||
* efficiently search for subdomains, once the initial sort is done.
|
||||
* The sorted order, defined by CompareDnsNames(), also makes it
|
||||
* possible to efficiently search for subdomains, once the initial sort
|
||||
* is done.
|
||||
*/
|
||||
void sorthoststxt(struct HostsTxt *ht) {
|
||||
void SortHostsTxt(struct HostsTxt *ht) {
|
||||
if (ht->entries.p) {
|
||||
qsort_r(ht->entries.p, ht->entries.i, sizeof(*ht->entries.p),
|
||||
(void *)cmphoststxt, ht->strings.p);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_DOS_H_
|
||||
#define COSMOPOLITAN_LIBC_DOS_H_
|
||||
|
||||
#define DOS_DATE(YEAR, MONTH_IDX1, DAY_IDX1) \
|
||||
(((YEAR)-1980) << 9 | (MONTH_IDX1) << 5 | (DAY_IDX1))
|
||||
#define DOS_TIME(HOUR, MINUTE, SECOND) \
|
||||
((HOUR) << 11 | (MINUTE) << 5 | (SECOND) >> 1)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_DOS_H_ */
|
||||
+84
-42
@@ -23,6 +23,7 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
@@ -31,11 +32,12 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
if (out(C, arg) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
@@ -121,14 +123,18 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
char ibuf[21];
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
unsigned long lu;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
int (*out)(const char *, void *, size_t);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, i1, ui, bw, bex;
|
||||
int c, d, k, w, n, i1, ui, bw, bex;
|
||||
char *s, *q, *se, qchar, special[8];
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
|
||||
@@ -136,18 +142,64 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.prec][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
PUT(*format);
|
||||
format++;
|
||||
for (n = 1; format[n]; ++n) {
|
||||
if (format[n] == '%') break;
|
||||
}
|
||||
if (out(format, arg, n) == -1) return -1;
|
||||
format += n;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
if (!IsTiny()) {
|
||||
if (format[1] == 's') { /* FAST PATH: PLAIN STRING */
|
||||
s = va_arg(va, char *);
|
||||
if (!s) s = "(null)";
|
||||
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||
d = va_arg(va, int);
|
||||
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN LONG HEX */
|
||||
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||
if (out(ibuf, arg, uint64toarray_radix10(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||
n = va_arg(va, unsigned); /* FAST PATH: PRECISION STRING */
|
||||
s = va_arg(va, const char *);
|
||||
if (!s) s = "(null)", n = MIN(6, n);
|
||||
if (out(s, arg, n) == -1) return -1;
|
||||
format += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* GENERAL PATH */
|
||||
format++;
|
||||
sign = 0;
|
||||
flags = 0;
|
||||
getflag:
|
||||
@@ -256,7 +308,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
/* evaluate specifier */
|
||||
qchar = '"';
|
||||
log2base = 0;
|
||||
alphabet = "0123456789abcdef";
|
||||
alphabet = "0123456789abcdefpx";
|
||||
switch ((d = *format++)) {
|
||||
case 'p':
|
||||
flags |= FLAGS_HASH;
|
||||
@@ -264,7 +316,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
signbit = 63;
|
||||
goto FormatNumber;
|
||||
case 'X':
|
||||
alphabet = "0123456789ABCDEF";
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
log2base = 4;
|
||||
@@ -496,8 +548,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
} else {
|
||||
PUT('+');
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) {
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
PUT(i1 + '0');
|
||||
@@ -560,7 +611,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
if (pun.d && prec < 13) {
|
||||
pun.u[1] |= 0x100000;
|
||||
if (prec < 5) {
|
||||
ui = 1 << ((5 - prec) * 4 - 1);
|
||||
ui = 1u << ((5 - prec) * 4 - 1);
|
||||
if (pun.u[1] & ui) {
|
||||
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
|
||||
pun.u[1] += ui;
|
||||
@@ -579,7 +630,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
}
|
||||
} else {
|
||||
i1 = (13 - prec) * 4;
|
||||
ui = 1 << (i1 - 1);
|
||||
ui = 1u << (i1 - 1);
|
||||
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
|
||||
pun.u[0] += ui;
|
||||
if (!(pun.u[0] >> i1)) goto BumpIt;
|
||||
@@ -588,12 +639,13 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
}
|
||||
} else {
|
||||
if ((ui = pun.u[0])) {
|
||||
for (prec = 6; (ui = (ui << 4) & 0xffffffff); ++prec) {
|
||||
}
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
|
||||
} else if ((ui = pun.u[1] & 0xfffff)) {
|
||||
ui = __builtin_ctz(ui);
|
||||
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
|
||||
} else {
|
||||
for (prec = 0, ui = pun.u[1] & 0xfffff; ui;
|
||||
++prec, ui = (ui << 4) & 0xfffff) {
|
||||
}
|
||||
prec = 0;
|
||||
}
|
||||
}
|
||||
bw = 1;
|
||||
@@ -604,7 +656,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if ((sgn = pun.u[1] & 0x80000000)) {
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
if (pun.d || sign) sign = '-';
|
||||
}
|
||||
@@ -633,18 +685,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
PUT(alphabet[17]);
|
||||
PUT(c);
|
||||
if (prec > 0 || alt) PUT('.');
|
||||
if (prec > 0) {
|
||||
if ((i1 = prec) > 5) i1 = 5;
|
||||
prec -= i1;
|
||||
do {
|
||||
PUT(alphabet[(pun.u[1] >> 16) & 0xf]);
|
||||
pun.u[1] <<= 4;
|
||||
} while (--i1 > 0);
|
||||
while (prec > 0) {
|
||||
--prec;
|
||||
PUT(alphabet[(pun.u[0] >> 28) & 0xf]);
|
||||
pun.u[0] <<= 4;
|
||||
}
|
||||
while (prec-- > 0) {
|
||||
PUT(alphabet[(pun.q >> 48) & 0xf]);
|
||||
pun.q <<= 4;
|
||||
}
|
||||
PUT(alphabet[16]);
|
||||
if (bex < 0) {
|
||||
@@ -653,8 +696,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
} else {
|
||||
PUT('+');
|
||||
}
|
||||
for (c = 1; 10 * c <= bex; c *= 10) {
|
||||
}
|
||||
for (c = 1; 10 * c <= bex;) c *= 10;
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
PUT('0' + i1);
|
||||
@@ -662,7 +704,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
continue;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
PUT('%');
|
||||
|
||||
@@ -68,11 +68,6 @@ o/$(MODE)/libc/fmt/filetimetotimeval.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O3
|
||||
|
||||
o/$(MODE)/libc/fmt/itoa64radix10.greg.o \
|
||||
o/$(MODE)/libc/fmt/itoa128radix10.greg.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fwrapv
|
||||
|
||||
LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)))
|
||||
LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS))
|
||||
|
||||
+7
-6
@@ -6,13 +6,14 @@
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
const char *) hidden;
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
@@ -49,5 +49,5 @@ noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
|
||||
size_t int128toarray_radix10(int128_t i, char *a) {
|
||||
if (i >= 0) return uint128toarray_radix10(i, a);
|
||||
*a++ = '-';
|
||||
return 1 + uint128toarray_radix10(-i, a);
|
||||
return 1 + uint128toarray_radix10(-(uint128_t)i, a);
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ noinline size_t uint64toarray(uint64_t i, char *a, int r) {
|
||||
size_t int64toarray(int64_t i, char *a, int r) {
|
||||
if (i < 0) {
|
||||
*a++ = '-';
|
||||
i = -i;
|
||||
i = -(uint64_t)i;
|
||||
}
|
||||
return uint64toarray(i, a, r);
|
||||
}
|
||||
@@ -27,14 +27,10 @@
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
noinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
|
||||
size_t j;
|
||||
j = 0;
|
||||
size_t j = 0;
|
||||
do {
|
||||
struct {
|
||||
uint64_t q, r;
|
||||
} x = {i / 10, i % 10};
|
||||
a[j++] = x.r + '0';
|
||||
i = x.q;
|
||||
a[j++] = i % 10 + '0';
|
||||
i = i / 10;
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
reverse(a, j);
|
||||
@@ -49,5 +45,5 @@ noinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
|
||||
size_t int64toarray_radix10(int64_t i, char a[hasatleast 21]) {
|
||||
if (i >= 0) return uint64toarray_radix10(i, a);
|
||||
*a++ = '-';
|
||||
return 1 + uint64toarray_radix10(-i, a);
|
||||
return 1 + uint64toarray_radix10(-(uint64_t)i, a);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -18,44 +18,101 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Verifies buffer contains only URI characters.
|
||||
//
|
||||
// @param %rdi is data which should be 32-byte aligned
|
||||
// @param %rsi is byte length of data
|
||||
// @return number of kosher bytes
|
||||
// @cost 10x faster than fastest Ragel code
|
||||
uricspn$avx:
|
||||
.leafprologue
|
||||
.profilable
|
||||
vmovaps .Luric(%rip),%xmm0
|
||||
mov $14,%eax
|
||||
mov %rsi,%rdx
|
||||
xor %esi,%esi
|
||||
0: vmovdqu (%rdi,%rsi),%xmm1
|
||||
vmovdqu 16(%rdi,%rsi),%xmm2
|
||||
vpcmpestri $0b00010100,%xmm1,%xmm0
|
||||
jc 1f
|
||||
jo 1f
|
||||
add $16,%rsi
|
||||
sub $16,%rdx
|
||||
vpcmpestri $0b00010100,%xmm2,%xmm0
|
||||
jc 1f
|
||||
jo 1f
|
||||
add $16,%rsi
|
||||
sub $16,%rdx
|
||||
jmp 0b
|
||||
1: lea (%rsi,%rcx),%rax
|
||||
.leafepilogue
|
||||
.endfn uricspn$avx,globl,hidden
|
||||
|
||||
.rodata.cst16
|
||||
.Luric: .byte '!','!'
|
||||
.byte '$',';'
|
||||
.byte '=','='
|
||||
.byte '?','Z'
|
||||
.byte '_','_'
|
||||
.byte 'a','z'
|
||||
.byte '~','~'
|
||||
.byte 0,0
|
||||
.endobj .Luric
|
||||
.macro .e e
|
||||
.long \e - kErrorNames
|
||||
.long 1f - kErrorNames
|
||||
.rodata.str1.1
|
||||
1: .string "\e"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
kErrorNames:
|
||||
.e ENOSYS
|
||||
.e EPERM
|
||||
.e ENOENT
|
||||
.e ESRCH
|
||||
.e EINTR
|
||||
.e EIO
|
||||
.e ENXIO
|
||||
.e E2BIG
|
||||
.e ENOEXEC
|
||||
.e EBADF
|
||||
.e ECHILD
|
||||
.e EAGAIN
|
||||
.e ENOMEM
|
||||
.e EACCES
|
||||
.e EFAULT
|
||||
.e ENOTBLK
|
||||
.e EBUSY
|
||||
.e EEXIST
|
||||
.e EXDEV
|
||||
.e ENODEV
|
||||
.e ENOTDIR
|
||||
.e EISDIR
|
||||
.e EINVAL
|
||||
.e ENFILE
|
||||
.e EMFILE
|
||||
.e ENOTTY
|
||||
.e ETXTBSY
|
||||
.e EFBIG
|
||||
.e ENOSPC
|
||||
.e EDQUOT
|
||||
.e ESPIPE
|
||||
.e EROFS
|
||||
.e EMLINK
|
||||
.e EPIPE
|
||||
.e EDOM
|
||||
.e ERANGE
|
||||
.e EDEADLK
|
||||
.e ENAMETOOLONG
|
||||
.e ENOLCK
|
||||
.e ENOTEMPTY
|
||||
.e ELOOP
|
||||
.e ENOMSG
|
||||
.e EIDRM
|
||||
.e ETIME
|
||||
.e EPROTO
|
||||
.e EOVERFLOW
|
||||
.e EILSEQ
|
||||
.e EUSERS
|
||||
.e ENOTSOCK
|
||||
.e EDESTADDRREQ
|
||||
.e EMSGSIZE
|
||||
.e EPROTOTYPE
|
||||
.e ENOPROTOOPT
|
||||
.e EPROTONOSUPPORT
|
||||
.e ESOCKTNOSUPPORT
|
||||
.e ENOTSUP
|
||||
.e EOPNOTSUPP
|
||||
.e EPFNOSUPPORT
|
||||
.e EAFNOSUPPORT
|
||||
.e EADDRINUSE
|
||||
.e EADDRNOTAVAIL
|
||||
.e ENETDOWN
|
||||
.e ENETUNREACH
|
||||
.e ENETRESET
|
||||
.e ECONNABORTED
|
||||
.e ECONNRESET
|
||||
.e ENOBUFS
|
||||
.e EISCONN
|
||||
.e ENOTCONN
|
||||
.e ESHUTDOWN
|
||||
.e ETOOMANYREFS
|
||||
.e ETIMEDOUT
|
||||
.e ECONNREFUSED
|
||||
.e EHOSTDOWN
|
||||
.e EHOSTUNREACH
|
||||
.e EALREADY
|
||||
.e EINPROGRESS
|
||||
.e ESTALE
|
||||
.e EREMOTE
|
||||
.e EBADMSG
|
||||
.e ECANCELED
|
||||
.e EOWNERDEAD
|
||||
.e ENOTRECOVERABLE
|
||||
.e ENONET
|
||||
.e ERESTART
|
||||
.long 0
|
||||
.endobj kErrorNames,globl,hidden
|
||||
+13
-16
@@ -16,6 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
@@ -25,12 +26,11 @@
|
||||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
unsigned len, bool negative, unsigned log2base,
|
||||
unsigned prec, unsigned width,
|
||||
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||
char *buf, unsigned len, bool negative,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
unsigned i;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
@@ -82,24 +82,21 @@ static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
reverse(buf, len);
|
||||
if (out(buf, arg, len) == -1) return -1;
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned flags, const char *alphabet) {
|
||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned flags, const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
@@ -130,7 +127,7 @@ int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
flags);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
||||
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
|
||||
unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
|
||||
+3
-2
@@ -18,8 +18,9 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||
return rc;
|
||||
}
|
||||
+14
-14
@@ -18,20 +18,20 @@
|
||||
* format strings are constexprs that only contain directives.
|
||||
*/
|
||||
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeEgG")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
})
|
||||
|
||||
#define SFLINK(FMT) \
|
||||
|
||||
+40
-42
@@ -16,9 +16,12 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
@@ -26,56 +29,48 @@
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
typedef int (*out_f)(const char *, void *, size_t);
|
||||
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||
|
||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return f(c, a);
|
||||
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||
char buf[1] = {c};
|
||||
return out(buf, a, 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
do {
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return 0;
|
||||
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (!isascii(w)) w = tpenc(w);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return f(c, a);
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (isascii(w)) {
|
||||
w = cescapec(w);
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
w = tpenc(w);
|
||||
}
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return __fmt_stoa_word(f, a, cescapec(c));
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out('u', arg) == -1) return -1;
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
if (out(ch, arg) == -1) return -1;
|
||||
if (out(&ch, arg, 1) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -89,23 +84,25 @@ static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
*
|
||||
* @see __fmt()
|
||||
*/
|
||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
char *p, buf[1];
|
||||
unsigned w, c, pad;
|
||||
bool justdobytes, ignorenul;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
} else {
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
@@ -215,7 +212,8 @@ int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (out(qchar, arg) == -1) return -1;
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+24
-296
@@ -20,291 +20,28 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/formatmessageflags.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
STATIC_YOINK("E2BIG");
|
||||
STATIC_YOINK("EACCES");
|
||||
STATIC_YOINK("EADDRINUSE");
|
||||
STATIC_YOINK("EADDRNOTAVAIL");
|
||||
STATIC_YOINK("EADV");
|
||||
STATIC_YOINK("EAFNOSUPPORT");
|
||||
STATIC_YOINK("EAGAIN");
|
||||
STATIC_YOINK("EALREADY");
|
||||
STATIC_YOINK("EBADE");
|
||||
STATIC_YOINK("EBADF");
|
||||
STATIC_YOINK("EBADFD");
|
||||
STATIC_YOINK("EBADMSG");
|
||||
STATIC_YOINK("EBADR");
|
||||
STATIC_YOINK("EBADRQC");
|
||||
STATIC_YOINK("EBADSLT");
|
||||
STATIC_YOINK("EBFONT");
|
||||
STATIC_YOINK("EBUSY");
|
||||
STATIC_YOINK("ECANCELED");
|
||||
STATIC_YOINK("ECHILD");
|
||||
STATIC_YOINK("ECHRNG");
|
||||
STATIC_YOINK("ECOMM");
|
||||
STATIC_YOINK("ECONNABORTED");
|
||||
STATIC_YOINK("ECONNREFUSED");
|
||||
STATIC_YOINK("ECONNRESET");
|
||||
STATIC_YOINK("EDEADLK");
|
||||
STATIC_YOINK("EDESTADDRREQ");
|
||||
STATIC_YOINK("EDOM");
|
||||
STATIC_YOINK("EDOTDOT");
|
||||
STATIC_YOINK("EDQUOT");
|
||||
STATIC_YOINK("EEXIST");
|
||||
STATIC_YOINK("EFAULT");
|
||||
STATIC_YOINK("EFBIG");
|
||||
STATIC_YOINK("EHOSTDOWN");
|
||||
STATIC_YOINK("EHOSTUNREACH");
|
||||
STATIC_YOINK("EHWPOISON");
|
||||
STATIC_YOINK("EIDRM");
|
||||
STATIC_YOINK("EILSEQ");
|
||||
STATIC_YOINK("EINPROGRESS");
|
||||
STATIC_YOINK("EINTR");
|
||||
STATIC_YOINK("EINVAL");
|
||||
STATIC_YOINK("EIO");
|
||||
STATIC_YOINK("EISCONN");
|
||||
STATIC_YOINK("EISDIR");
|
||||
STATIC_YOINK("EISNAM");
|
||||
STATIC_YOINK("EKEYEXPIRED");
|
||||
STATIC_YOINK("EKEYREJECTED");
|
||||
STATIC_YOINK("EKEYREVOKED");
|
||||
STATIC_YOINK("EL2HLT");
|
||||
STATIC_YOINK("EL2NSYNC");
|
||||
STATIC_YOINK("EL3HLT");
|
||||
STATIC_YOINK("EL3RST");
|
||||
STATIC_YOINK("ELIBACC");
|
||||
STATIC_YOINK("ELIBBAD");
|
||||
STATIC_YOINK("ELIBEXEC");
|
||||
STATIC_YOINK("ELIBMAX");
|
||||
STATIC_YOINK("ELIBSCN");
|
||||
STATIC_YOINK("ELNRNG");
|
||||
STATIC_YOINK("ELOOP");
|
||||
STATIC_YOINK("EMEDIUMTYPE");
|
||||
STATIC_YOINK("EMFILE");
|
||||
STATIC_YOINK("EMLINK");
|
||||
STATIC_YOINK("EMSGSIZE");
|
||||
STATIC_YOINK("EMULTIHOP");
|
||||
STATIC_YOINK("ENAMETOOLONG");
|
||||
STATIC_YOINK("ENAVAIL");
|
||||
STATIC_YOINK("ENETDOWN");
|
||||
STATIC_YOINK("ENETRESET");
|
||||
STATIC_YOINK("ENETUNREACH");
|
||||
STATIC_YOINK("ENFILE");
|
||||
STATIC_YOINK("ENOANO");
|
||||
STATIC_YOINK("ENOBUFS");
|
||||
STATIC_YOINK("ENOCSI");
|
||||
STATIC_YOINK("ENODATA");
|
||||
STATIC_YOINK("ENODEV");
|
||||
STATIC_YOINK("ENOENT");
|
||||
STATIC_YOINK("ENOEXEC");
|
||||
STATIC_YOINK("ENOKEY");
|
||||
STATIC_YOINK("ENOLCK");
|
||||
STATIC_YOINK("ENOLINK");
|
||||
STATIC_YOINK("ENOMEDIUM");
|
||||
STATIC_YOINK("ENOMEM");
|
||||
STATIC_YOINK("ENOMSG");
|
||||
STATIC_YOINK("ENONET");
|
||||
STATIC_YOINK("ENOPKG");
|
||||
STATIC_YOINK("ENOPROTOOPT");
|
||||
STATIC_YOINK("ENOSPC");
|
||||
STATIC_YOINK("ENOSR");
|
||||
STATIC_YOINK("ENOSTR");
|
||||
STATIC_YOINK("ENOSYS");
|
||||
STATIC_YOINK("ENOTBLK");
|
||||
STATIC_YOINK("ENOTCONN");
|
||||
STATIC_YOINK("ENOTDIR");
|
||||
STATIC_YOINK("ENOTEMPTY");
|
||||
STATIC_YOINK("ENOTNAM");
|
||||
STATIC_YOINK("ENOTRECOVERABLE");
|
||||
STATIC_YOINK("ENOTSOCK");
|
||||
STATIC_YOINK("ENOTSUP");
|
||||
STATIC_YOINK("ENOTTY");
|
||||
STATIC_YOINK("ENOTUNIQ");
|
||||
STATIC_YOINK("ENXIO");
|
||||
STATIC_YOINK("EOPNOTSUPP");
|
||||
STATIC_YOINK("EOVERFLOW");
|
||||
STATIC_YOINK("EOWNERDEAD");
|
||||
STATIC_YOINK("EPERM");
|
||||
STATIC_YOINK("EPFNOSUPPORT");
|
||||
STATIC_YOINK("EPIPE");
|
||||
STATIC_YOINK("EPROTO");
|
||||
STATIC_YOINK("EPROTONOSUPPORT");
|
||||
STATIC_YOINK("EPROTOTYPE");
|
||||
STATIC_YOINK("ERANGE");
|
||||
STATIC_YOINK("EREMCHG");
|
||||
STATIC_YOINK("EREMOTE");
|
||||
STATIC_YOINK("EREMOTEIO");
|
||||
STATIC_YOINK("ERESTART");
|
||||
STATIC_YOINK("ERFKILL");
|
||||
STATIC_YOINK("EROFS");
|
||||
STATIC_YOINK("ESHUTDOWN");
|
||||
STATIC_YOINK("ESOCKTNOSUPPORT");
|
||||
STATIC_YOINK("ESPIPE");
|
||||
STATIC_YOINK("ESRCH");
|
||||
STATIC_YOINK("ESRMNT");
|
||||
STATIC_YOINK("ESTALE");
|
||||
STATIC_YOINK("ESTRPIPE");
|
||||
STATIC_YOINK("ETIME");
|
||||
STATIC_YOINK("ETIMEDOUT");
|
||||
STATIC_YOINK("ETOOMANYREFS");
|
||||
STATIC_YOINK("ETXTBSY");
|
||||
STATIC_YOINK("EUCLEAN");
|
||||
STATIC_YOINK("EUNATCH");
|
||||
STATIC_YOINK("EUSERS");
|
||||
STATIC_YOINK("EXDEV");
|
||||
STATIC_YOINK("EXFULL");
|
||||
extern const struct Error {
|
||||
int x;
|
||||
int s;
|
||||
} kErrorNames[];
|
||||
|
||||
_Alignas(char) static const char kErrnoNames[] = "\
|
||||
2BIG\000\
|
||||
ACCES\000\
|
||||
ADDRINUSE\000\
|
||||
ADDRNOTAVAIL\000\
|
||||
ADV\000\
|
||||
AFNOSUPPORT\000\
|
||||
AGAIN\000\
|
||||
ALREADY\000\
|
||||
BADE\000\
|
||||
BADF\000\
|
||||
BADFD\000\
|
||||
BADMSG\000\
|
||||
BADR\000\
|
||||
BADRQC\000\
|
||||
BADSLT\000\
|
||||
BFONT\000\
|
||||
BUSY\000\
|
||||
CANCELED\000\
|
||||
CHILD\000\
|
||||
CHRNG\000\
|
||||
COMM\000\
|
||||
CONNABORTED\000\
|
||||
CONNREFUSED\000\
|
||||
CONNRESET\000\
|
||||
DEADLK\000\
|
||||
DESTADDRREQ\000\
|
||||
DOM\000\
|
||||
DOTDOT\000\
|
||||
DQUOT\000\
|
||||
EXIST\000\
|
||||
FAULT\000\
|
||||
FBIG\000\
|
||||
HOSTDOWN\000\
|
||||
HOSTUNREACH\000\
|
||||
HWPOISON\000\
|
||||
IDRM\000\
|
||||
ILSEQ\000\
|
||||
INPROGRESS\000\
|
||||
INTR\000\
|
||||
INVAL\000\
|
||||
IO\000\
|
||||
ISCONN\000\
|
||||
ISDIR\000\
|
||||
ISNAM\000\
|
||||
KEYEXPIRED\000\
|
||||
KEYREJECTED\000\
|
||||
KEYREVOKED\000\
|
||||
L2HLT\000\
|
||||
L2NSYNC\000\
|
||||
L3HLT\000\
|
||||
L3RST\000\
|
||||
LIBACC\000\
|
||||
LIBBAD\000\
|
||||
LIBEXEC\000\
|
||||
LIBMAX\000\
|
||||
LIBSCN\000\
|
||||
LNRNG\000\
|
||||
LOOP\000\
|
||||
MEDIUMTYPE\000\
|
||||
MFILE\000\
|
||||
MLINK\000\
|
||||
MSGSIZE\000\
|
||||
MULTIHOP\000\
|
||||
NAMETOOLONG\000\
|
||||
NAVAIL\000\
|
||||
NETDOWN\000\
|
||||
NETRESET\000\
|
||||
NETUNREACH\000\
|
||||
NFILE\000\
|
||||
NOANO\000\
|
||||
NOBUFS\000\
|
||||
NOCSI\000\
|
||||
NODATA\000\
|
||||
NODEV\000\
|
||||
NOENT\000\
|
||||
NOEXEC\000\
|
||||
NOKEY\000\
|
||||
NOLCK\000\
|
||||
NOLINK\000\
|
||||
NOMEDIUM\000\
|
||||
NOMEM\000\
|
||||
NOMSG\000\
|
||||
NONET\000\
|
||||
NOPKG\000\
|
||||
NOPROTOOPT\000\
|
||||
NOSPC\000\
|
||||
NOSR\000\
|
||||
NOSTR\000\
|
||||
NOSYS\000\
|
||||
NOTBLK\000\
|
||||
NOTCONN\000\
|
||||
NOTDIR\000\
|
||||
NOTEMPTY\000\
|
||||
NOTNAM\000\
|
||||
NOTRECOVERABLE\000\
|
||||
NOTSOCK\000\
|
||||
NOTSUP\000\
|
||||
NOTTY\000\
|
||||
NOTUNIQ\000\
|
||||
NXIO\000\
|
||||
OPNOTSUPP\000\
|
||||
OVERFLOW\000\
|
||||
OWNERDEAD\000\
|
||||
PERM\000\
|
||||
PFNOSUPPORT\000\
|
||||
PIPE\000\
|
||||
PROTO\000\
|
||||
PROTONOSUPPORT\000\
|
||||
PROTOTYPE\000\
|
||||
RANGE\000\
|
||||
REMCHG\000\
|
||||
REMOTE\000\
|
||||
REMOTEIO\000\
|
||||
RESTART\000\
|
||||
RFKILL\000\
|
||||
ROFS\000\
|
||||
SHUTDOWN\000\
|
||||
SOCKTNOSUPPORT\000\
|
||||
SPIPE\000\
|
||||
SRCH\000\
|
||||
SRMNT\000\
|
||||
STALE\000\
|
||||
STRPIPE\000\
|
||||
TIME\000\
|
||||
TIMEDOUT\000\
|
||||
TOOMANYREFS\000\
|
||||
TXTBSY\000\
|
||||
UCLEAN\000\
|
||||
UNATCH\000\
|
||||
USERS\000\
|
||||
XDEV\000\
|
||||
XFULL\000\
|
||||
\000";
|
||||
|
||||
static const char *geterrname(long code) {
|
||||
const long *e;
|
||||
size_t i, n;
|
||||
e = &E2BIG;
|
||||
n = &EXFULL + 1 - e;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (code == e[i]) {
|
||||
return IndexDoubleNulString(kErrnoNames, i);
|
||||
static const char *GetErrorName(long x) {
|
||||
int i;
|
||||
if (x) {
|
||||
for (i = 0; kErrorNames[i].x; ++i) {
|
||||
if (x == *(const long *)((uintptr_t)kErrorNames + kErrorNames[i].x)) {
|
||||
return (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return "EUNKNOWN";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,28 +49,19 @@ static const char *geterrname(long code) {
|
||||
* @return 0 on success, or error code
|
||||
*/
|
||||
int strerror_r(int err, char *buf, size_t size) {
|
||||
char *p;
|
||||
const char *s;
|
||||
char16_t buf16[100];
|
||||
int winstate, sysvstate;
|
||||
if (!err || IsTiny()) {
|
||||
s = "?";
|
||||
} else {
|
||||
s = firstnonnull(geterrname(err), "?");
|
||||
err &= 0xFFFF;
|
||||
s = GetErrorName(err);
|
||||
p = buf;
|
||||
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
||||
p = stpcpy(p, s);
|
||||
*p++ = '[';
|
||||
p += uint64toarray_radix10(err, p);
|
||||
*p++ = ']';
|
||||
}
|
||||
if (!SupportsWindows()) {
|
||||
(snprintf)(buf, size, "E%s[%d]", s, err);
|
||||
} else {
|
||||
winstate = GetLastError();
|
||||
sysvstate = errno;
|
||||
if (FormatMessage(
|
||||
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, NULL,
|
||||
err, 0, buf16, ARRAYLEN(buf16) - 1, 0) > 0) {
|
||||
chomp16(buf16);
|
||||
} else {
|
||||
buf16[0] = u'\0';
|
||||
}
|
||||
(snprintf)(buf, size, "E%s/err=%d/errno:%d/GetLastError:%d%s%hs", s, err,
|
||||
sysvstate, winstate, buf16[0] ? " " : "", buf16);
|
||||
if (p - buf < size) {
|
||||
*p++ = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -16,10 +16,10 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
struct SprintfStr {
|
||||
@@ -28,10 +28,13 @@ struct SprintfStr {
|
||||
size_t n;
|
||||
};
|
||||
|
||||
static noinstrument int vsnprintfputchar(unsigned char c,
|
||||
struct SprintfStr *str) {
|
||||
if (str->i < str->n) str->p[str->i] = c;
|
||||
str->i++;
|
||||
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
|
||||
if (t->i + n <= t->n) {
|
||||
memcpy(t->p + t->i, s, n);
|
||||
} else if (t->i < t->n) {
|
||||
memcpy(t->p + t->i, s, t->n - t->i);
|
||||
}
|
||||
t->i += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -51,6 +54,6 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
||||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
@@ -584,6 +584,13 @@ typedef uint64_t uintmax_t;
|
||||
#define noasan
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
|
||||
__has_attribute(__no_sanitize_undefined__)
|
||||
#define noubsan __attribute__((__no_sanitize_undefined__))
|
||||
#else
|
||||
#define noubsan
|
||||
#endif
|
||||
|
||||
#ifndef unreachable
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define unreachable __builtin_unreachable()
|
||||
@@ -659,6 +666,7 @@ typedef uint64_t uintmax_t;
|
||||
#pragma GCC diagnostic ignored "-Wformat" /* forces only gnu pf */
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter" /* extreme prejudice */
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" /* contradicts dce! */
|
||||
#pragma GCC diagnostic ignored "-Wunused-const-variable" /* let me dce */
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable" /* belongs in tidy */
|
||||
#pragma GCC diagnostic ignored "-Wformat-extra-args" /* is also broken */
|
||||
#pragma GCC diagnostic ignored "-Wparentheses" /* annoying tidy */
|
||||
|
||||
Loaded 100 of 1183 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user