Compare commits

...
49 Commits
Author SHA1 Message Date
Justine Tunney 7cbc2bc083 Cosmopolitan 1.0 2021-05-16 20:35:10 -07:00
Justine Tunney 1a3d22b2fd Improve LLVM compatibility a little bit 2021-05-16 20:34:46 -07:00
Justine Tunney 3057315a1b Make default redbean lua module path zip:.lua/...
Fixes #157
2021-05-16 19:05:35 -07:00
Justine Tunney 6a8c21269f Make trivial code size enhancements 2021-05-16 18:22:39 -07:00
Justine Tunney b3838173ec Remove undefined behaviors 2021-05-16 11:16:28 -07:00
Justine Tunney 4864565198 Make minor improvements 2021-05-15 21:53:26 -07:00
Justine Tunney 221817e537 Further polish SQLite vendoring
- Now integrated with `make tags` for Emacs IDE features
- Delete some old deprecated broken full-text search engines
- Rename .h → .inc files that don't meet our definition of header
- Make sure every #include line is normal form so tools understand

See #162
2021-05-14 10:43:58 -07:00
Justine Tunney 690be544da Make redbean StoreAsset() work better
- Better UBSAN error messages
- POSIX Advisory Locks polyfills
- Move redbean manual to /.help.txt
- System call memory safety in ASAN mode
- Character classification now does UNICODE
2021-05-14 05:44:37 -07:00
ahgamut 919b6fec10 Get SQLite to build
* changed headers
* removed redundant declarations
* ran clang-format
* added sqlite3.mk
2021-05-14 02:40:04 -07:00
Justine Tunney 644f290035 Added sqlite-preprocessed-3350500
From https://www.sqlite.org/2021/sqlite-preprocessed-3350500.zip
2021-05-14 02:07:09 -07:00
Dan Tocchini IV 4577f7fe11 Add MacOS toolchain instructions (#163) 2021-05-07 07:52:32 -07:00
Justine Tunney 1b5a5719c3 Improve some unicode functions 2021-05-05 07:25:39 -07:00
Justine Tunney b9187061a7 Let redbean use its own ZIP EXE as NoSQL database 2021-05-03 13:07:58 -07:00
Justine Tunney e56a9d0e23 Mold the redbean binary to minimize page faults
This change brings page faults for precompressed static asset serving
down from 27 to 20 (or fewer) after fork. This is more of an art than
science. Hopefully Blinkenlights can visualize page faults soon.
2021-05-03 12:14:13 -07:00
Justine Tunney 2d34819779 Escape LaunchBrowser path
This also fix a bug where CTRL-C'ing redbean on Linux would kill the
browser process. It furthermore fixes a regression with the APE self
repair process that happened in a recent change.

See #158
2021-05-03 11:52:24 -07:00
Rowan Easter-Robinson 6215c91e90 Added Parameter to LaunchBrowser to set path (#158) 2021-05-03 10:55:21 -07:00
Justine Tunney af59806a42 Add integration test for redbean 2021-05-03 01:59:27 -07:00
Justine Tunney 01e6b3ad8d Reduce number of disk seeks in redbean 2021-05-03 01:21:50 -07:00
Justine Tunney daa32d27d4 Add live reindexing to redbean when zip changes 2021-05-02 11:50:43 -07:00
Justine Tunney 84001a246c Fix redbean date header in daemonize mode 2021-05-02 11:11:26 -07:00
Justine Tunney 1f2288be6e Improve backwards compatibility with GNU Make 2021-05-02 07:48:59 -07:00
Justine Tunney fabf7f9f02 Fix popen_test in MODE=dbg
ASAN and vfork() don't appear to play well together. Maybe in later
versions of GCC it'll be better. But vfork() is flirting with danger
after all and that probably doesn't make sense in ASAN mode anyway.
2021-05-01 17:13:48 -07:00
Justine Tunney cef08d47b6 Fix typo in redbean.c 2021-05-01 05:42:02 -07:00
Justine Tunney 41801c9802 Change default redbean log level to info
A new -s flag has been added to increase silence. This change is
intended to make it a little less weird opening the redbean binary
directly from the browser and seeing an empty terminal window.
2021-05-01 05:28:15 -07:00
Justine Tunney 1966369e8e Fix bugs and make improvements
- Fix regression with `%lu`
- Added some more headers witnessed in the wild
- Added `-M INT` option to redbean to tune max payload size
- Work around InfoZIP 256 character limit on comment line size
2021-05-01 05:11:35 -07:00
Gautham 3aa8983ec1 Add strxfrm (#160) 2021-05-01 04:53:23 -07:00
Justine Tunney c029e83dd8 Set up http://redbean.justine.lol/ demo server 2021-04-24 19:49:49 -07:00
Justine Tunney 472b95fea3 Support OnHttpRequest Lua callback
If your redbean `/.init.lua` file defines a global callable named
`OnHttpRequest` then redbean will delegate all serving control to
your function. You may then restore the default serving paths, by
calling the new `Route()`, `RouteHost()`, and `RoutePath()` APIs.

Closes #150
2021-04-24 17:27:12 -07:00
Justine Tunney dc6d11a031 Improve performance of printf functions 2021-04-24 13:58:50 -07:00
Justine Tunney b107d2709f Add /statusz page to redbean plus other enhancements
redbean improvements:

- Explicitly disable corking
- Simulate Python regex API for Lua
- Send warmup requests in main process on startup
- Add Class-A granular IPv4 network classification
- Add /statusz page so you can monitor your redbean's health
- Fix regressions on OpenBSD/NetBSD caused by recent changes
- Plug Authorization header into Lua GetUser and GetPass APIs
- Recognize X-Forwarded-{For,Host} from local reverse proxies
- Add many additional functions to redbean Lua server page API
- Report resource usage of child processes on `/` listing page
- Introduce `-a` flag for logging child process resource usage
- Introduce `-t MILLIS` flag and `ProgramTimeout(ms)` init API
- Introduce `-H "Header: value"` flag and `ProgramHeader(k,v)` API

Cosmopolitan Libc improvements:

- Make strerror() simpler
- Make inet_pton() not depend on sscanf()
- Fix OpenExecutable() which broke .data section earlier
- Fix stdio in cases where it overflows kernel tty buffer
- Fix bugs in crash reporting w/o .com.dbg binary present
- Add polyfills for SO_LINGER, SO_RCVTIMEO, and SO_SNDTIMEO
- Polyfill TCP_CORK on BSD and XNU using TCP_NOPUSH magnums

New netcat clone in examples/nc.c:

While testing some of the failure conditions for redbean, I noticed that
BusyBox's `nc` command is pretty busted, if you use it as an interactive
tool, rather than having it be part of a pipeline. Unfortunately this'll
only work on UNIX since Windows doesn't let us poll on stdio and sockets
at the same time because I don't think they want tools like this running
on their platform. So if you want forbidden fruit, it's here so enjoy it
2021-04-23 18:53:57 -07:00
Justine Tunney 4effa23528 Make more major improvements to redbean
- POSIX regular expressions for Lua
- Improved protocol parsing and encoding
- Additional APIs for ZIP storage retrieval
- Fix st_mode issue on NT for regular files
- Generalized APIs for URL and Host handling
- Worked out the kinks in resource resolution
- Allow for custom error pages like /404.html
2021-04-20 19:14:21 -07:00
Justine Tunney 26ac6871da Add TUI paneling example 2021-04-18 12:40:48 -07:00
Justine Tunney bf03b2e64c Make major improvements to redbean and libraries
The most exciting improvement is dynamic pages will soon be able to use
the executable itself as an object store. it required a heroic technique
for overcoming ETXTBSY restrictions which lets us open the executable in
read/write mode, which means (1) wa can restore the APE header, and (2)
we can potentially containerize redbean extension code so that modules
you download for your redbean online will only impact your redbean.

Here's a list of breaking changes to redbean:

- Remove /tool/net/ prefix from magic ZIP paths
- GetHeader() now returns NIL if header is absent

Here's a list of fixes and enhancements to redbean:

- Support 64-bit ZIP archives
- Record User-Agent header in logs
- Add twelve error handlers to accept()
- Display octal st_mode on listing page
- Show ZIP file comments on listing page
- Restore APE MZ header on redbean startup
- Track request count on redbean index page
- Report server uptime on redbean index page
- Don't bind server socket using SO_REUSEPORT
- Fix #151 where Lua LoadAsset() could free twice
- Report rusage accounting when workers exit w/ -vv
- Use ZIP iattr field as text/plain vs. binary hint
- Add ParseUrl() API for parsing things like a.href
- Add ParseParams() API for parsing HTTP POST bodies
- Add IsAcceptablePath() API for checking dots, etc.
- Add IsValidHttpToken() API for validating sane ASCII
- Add IsAcceptableHostPort() for validating HOST[:PORT]
- Send 400 response to HTTP/1.1 requests without a Host
- Send 403 response if ZIP or file isn't other readable
- Add virtual hosting that tries prepending Host to path
- Route requests based on Host in Request-URI if present
- Host routing will attempt to remove or add the www. prefix
- Sign-extend UNIX timestamps and don't adjust FileTime zone

Here's some of the improvements made to Cosmopolitan Libc:

- Fix ape.S indentation
- Improve consts.sh magnums
- Write pretty good URL parser
- Improve rusage accounting apis
- Bring mremap() closer to working
- Added ZIP APIs which will change
- Check for overflow in reallocarray()
- Remove overly fancy linkage in strerror()
- Fix GDB attach on crash w/ OpenBSD msyscall()
- Make sigqueue() portable to most UNIX distros
- Make integer serialization macros more elegant
- Bring back 34x tprecode8to16() performance boost
- Make malloc() more resilient to absurdly large sizes
2021-04-18 12:34:15 -07:00
Rowan Easter-Robinson 69c508729e Added LaunchBrowser API (#153)
You can now add LaunchBrowser() to .init.lua which will ask
redbean to open your website in the local desktop browser
when the server is launched.
2021-04-18 07:24:36 -07:00
Justine Tunney 7ed524ca31 Disable fesetround() tests temporarily
This isn't working as intended in the Travis CI build environment.
There's likely some kind of microarchitectural issue. This change
gets us back into the green for the time being.
2021-04-11 01:42:31 -07:00
Justine Tunney 052682c2c0 Add CONTRIBUTING.md 2021-04-11 00:55:53 -07:00
Justine Tunney 8a91518633 Fix issues revealed by ECMAScript test262
Cosmopolitan's QuickJS is now equally conformant and performant, with
the exception of Atomics, which have been disabled since Cosmopolitan
currently doesn't support pthreads.

QuickJS memory usage -- BigNum 2021-03-27 version, 64-bit, malloc limit: -1

NAME                    COUNT     SIZE
memory allocated          937   131764  (140.6 per block)
memory used               938   116103  (8 overhead, 16.7 average slack)
atoms                     513    21408  (41.7 per atom)
objects                   170    12279  (72.2 per object)
  properties              864    15531  (5.1 per object)
  shapes                   58    12995  (224.1 per shape)
bytecode functions         13     1512
  bytecode                 13      867  (66.7 per function)
C functions                99
arrays                      1
  fast arrays               1
  elements                  1       16  (1.0 per fast array)

Result: 35/74740 errors, 1279 excluded, 485 skipped, 19 new, 2 fixed

real    2m40.828s
user    2m29.764s
sys     0m10.939s
2021-04-10 17:15:35 -07:00
Justine Tunney 8f52c0d773 Get Fabrice Bellard's JavaScript engine to build
$ m=tiny
$ make -j12 MODE=$m o/$m/third_party/quickjs/qjs.com
$ o/$m/third_party/quickjs/qjs.com -e 'console.log(2 + 2)'
4
$ ls -hal o/$m/third_party/quickjs/qjs.com
631.5K

See #97
2021-04-09 01:06:57 -07:00
Justine Tunney 1fbfbb3192 Add quickjs-2021-03-27 to third_party 2021-04-08 20:55:43 -07:00
Justine Tunney f40f97bd07 Fix test failure on Windows
The send{,to,msg} and recv{,from,msg} functions have been updated to
delegate to WriteFile and ReadFile when appropriate, due to the fact
that socketpair(AF_UNIX) is implemented using kFdFile.

Thanks @fabriziobertocci for writing the test that caught this.

See #148 and #122
2021-04-07 23:36:05 -07:00
fabriziobertocci 24d79599cc Add sendmsg and recvmsg (#148) 2021-04-07 22:53:23 -07:00
Justine Tunney da8a08fd58 Provide option to have APE not modify itself
This change introduces ape-no-modify-self.o to the amalgamated release
binaries, which may be used as an alternative to ape.o to make it easier
to use APE in cases where the self-modifying behavior isn't acceptable.

Please note that this alternative copying behavior isn't necessarily
better. It introduces a whole bunch of questions of its own, which are
documented in the ape.S source comment and should be considered by both
the program author as well as the end-user of programs linked this way.

For example, build environments that use read-only file systems and
would prefer to not have a launcher wrapper (like we use in our build)
can use ape-no-modify-self.o instead of ape.o and then set the $TMPDIR
environment variable to point to a sane read-write-exec location.

Fixes #146
See #82
2021-04-07 21:01:57 -07:00
Justine Tunney 59575f7e80 Perform some minor code cleanup 2021-04-06 12:46:52 -07:00
Justine Tunney 6c16f208b5 Remove unintended log statements 2021-04-01 20:01:26 -07:00
Justine Tunney bb96099c65 Define assert as an expression
Fixes #138
2021-04-01 19:42:02 -07:00
fabriziobertocci 2584a86ab4 Added struct ip_mreq (#143) 2021-04-01 19:38:11 -07:00
dosisod 9e98d6893d Add some missing prototypes (#142) 2021-04-01 19:36:37 -07:00
fabriziobertocci 6682013d12 Implement syslog (#136) 2021-04-01 19:32:39 -07:00
Justine Tunney 83abd68029 Parse Content-Range with missing right hand side
Fixes #144
2021-04-01 18:52:54 -07:00
1183 changed files with 396005 additions and 22643 deletions

No files matched your search

+62
View File
@@ -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)
+17 -9
View File
@@ -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
+27 -7
View File
@@ -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 |
+106 -62
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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;
}
+43
View File
@@ -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
View File
@@ -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;
}
+175
View File
@@ -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);
}
+52
View File
@@ -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
View File
@@ -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
View File
@@ -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_
+2 -2
View File
@@ -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);
}
+4 -4
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+3 -6
View File
@@ -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
View File
@@ -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();
+31
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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);
+2
View File
@@ -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);
+3
View File
@@ -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()) {
+1 -1
View File
@@ -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)) {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
*/
+164
View File
@@ -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;
}
}
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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));
}
+5 -8
View File
@@ -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 |
+1 -1
View File
@@ -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);
}
}
+2
View File
@@ -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);
+2
View File
@@ -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
View File
@@ -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;
}
}
+2
View File
@@ -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
+2
View File
@@ -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 { \
+59
View File
@@ -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);
}
}
+7 -6
View File
@@ -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) */
+2 -2
View File
@@ -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) */
+6 -6
View File
@@ -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 */
+2 -2
View File
@@ -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;
+7
View File
@@ -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);
+7
View File
@@ -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
View File
@@ -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;
}
+31
View File
@@ -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;
}
+12
View File
@@ -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 {
+1
View File
@@ -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
View File
@@ -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();
}
}
+45
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+2 -2
View File
@@ -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) */
+1 -1
View File
@@ -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) */
+5 -5
View File
@@ -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;
}
+2 -2
View File
@@ -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);
+2 -2
View File
@@ -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);
+2 -3
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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)))) {
+4 -4
View File
@@ -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
View File
@@ -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));
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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;
}
+4 -4
View File
@@ -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;
+7 -4
View File
@@ -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;
}
+7 -6
View File
@@ -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);
+9
View File
@@ -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
View File
@@ -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('%');
-5
View File
@@ -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
View File
@@ -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_
+1 -1
View File
@@ -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
View File
@@ -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);
}
+4 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+9 -6
View File
@@ -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;
}
+8
View File
@@ -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