Merge branch 'jart:master' into master

This commit is contained in:
Terror 2024-06-12 19:11:37 +12:00 committed by GitHub
commit ecb7614c9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3950 changed files with 238159 additions and 80823 deletions

25
.git-blame-ignore-revs Normal file
View file

@ -0,0 +1,25 @@
# Run this command to always ignore formatting commits in git blame
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# vim c++ filetype in modelines
04c6bc478e082263d67c41bedbd033dde2d429eb
# Ran clang-format
f032b5570b4cd87c6bb4abb54c0b98e69c939955
# Applied clang-format update to repo
6e6fc38935054db0534d5af4fb99c6193305b946
# revert retabbing
2b315626f3af765cdfbc61114647412cdb798b3a
# more modeline errata
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
# fix more vi modelines
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
# flip et/noet in modelines
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
# fix vi modelines
394d998315f613a888cc6b6c051d4163bdf5cd6f
# clang-format
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
# ape-m1 formatting cleanup
da8baf2aa5ce93b958aca90a0ae69f537806324b
# Run clang-format on most sources
369f9740de4534c28d0e81ab2afc99decbb9a3e6

59
.github/ISSUE_TEMPLATE/01-bug-low.yml vendored Normal file
View file

@ -0,0 +1,59 @@
name: Low Severity Bugs
description: Used to report low severity bugs in cosmopolitan (e.g. cosmetic issues, non critical UI glitches)
title: "Bug: "
labels: ["bug", "low severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -0,0 +1,59 @@
name: Medium Severity Bug
description: Used to report medium severity bugs in cosmopolitan (e.g. Malfunctioning Features but generally still useable)
title: "Bug: "
labels: ["bug", "medium severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

59
.github/ISSUE_TEMPLATE/03-bug-high.yml vendored Normal file
View file

@ -0,0 +1,59 @@
name: High Severity Bug
description: Used to report high severity bugs in cosmopolitan (e.g. Malfunctioning features hindering important common workflow)
title: "Bug: "
labels: ["bug", "high severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -0,0 +1,59 @@
name: Critical Severity Bug
description: Used to report critical severity bugs in cosmopolitan (e.g. Crashing, Corrupted, Dataloss)
title: "Bug: "
labels: ["bug", "critical severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -0,0 +1,51 @@
name: Enhancement template
description: Used to request enhancements for cosmopolitan
title: "Feature Request: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
[Please post your idea first in Discussion if there is not yet a consensus for this enhancement request. This will help to keep this issue tracker focused on enhancements that the community has agreed needs to be implemented.](https://github.com/jart/cosmopolitan/discussions/categories/ideas)
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please confirm the following before submitting your enhancement request.
options:
- label: I am running the latest code. Mention the version if possible as well.
required: true
- label: I carefully followed the [README.md](https://github.com/jart/cosmopolitan/blob/master/README.md).
required: true
- label: I searched using keywords relevant to my issue to make sure that I am creating a new issue that is not already open (or closed).
required: true
- label: I reviewed the [Discussions](https://github.com/jart/cosmopolitan/discussions), and have a new and useful enhancement to share.
required: true
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: Please provide a detailed written description of what you were trying to do, and what you expected `cosmopolitan` to do as an enhancement.
placeholder: Detailed description of the enhancement
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation
description: Please provide a detailed written description of reasons why this feature is necessary and how it is useful to `cosmopolitan` users.
placeholder: Explanation of why this feature is needed and its benefits
validations:
required: true
- type: textarea
id: possible-implementation
attributes:
label: Possible Implementation
description: If you have an idea as to how it can be implemented, please write a detailed description. Feel free to give links to external sources or share visuals that might be helpful to understand the details better.
placeholder: Detailed description of potential implementation
validations:
required: false

52
.github/ISSUE_TEMPLATE/06-research.yml vendored Normal file
View file

@ -0,0 +1,52 @@
name: Research
description: Track new technical research area
title: "Research: "
labels: ["research"]
body:
- type: markdown
attributes:
value: |
Don't forget to check for any [duplicate research issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3A%22research+%F0%9F%94%AC%22)
- type: checkboxes
id: research-stage
attributes:
label: Research Stage
description: Track general state of this research ticket
options:
- label: Background Research (Let's try to avoid reinventing the wheel)
- label: Hypothesis Formed (How do you think this will work and it's effect?)
- label: Strategy / Implementation Forming
- label: Analysis of results
- label: Debrief / Documentation (So people in the future can learn from us)
- type: textarea
id: background
attributes:
label: Previous existing literature and research
description: Whats the current state of the art and whats the motivation for this research?
- type: textarea
id: hypothesis
attributes:
label: Hypothesis
description: How do you think this will work and it's effect?
- type: textarea
id: implementation
attributes:
label: Implementation
description: Got an approach? e.g. a PR ready to go?
- type: textarea
id: analysis
attributes:
label: Analysis
description: How does the proposed implementation behave?
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

28
.github/ISSUE_TEMPLATE/07-refactor.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: Refactor (Maintainers)
description: Used to track refactoring opportunities
title: "Refactor: "
labels: ["refactor"]
body:
- type: markdown
attributes:
value: |
Don't forget to [check for existing refactor issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3Arefactoring) in case it's already covered.
Also you may want to check [Pull request refactor label as well](https://github.com/jart/cosmopolitan/pulls?q=is%3Aopen+is%3Apr+label%3Arefactoring) for duplicates too.
- type: textarea
id: background-description
attributes:
label: Background Description
description: Please provide a detailed written description of the pain points you are trying to solve.
placeholder: Detailed description behind your motivation to request refactor
validations:
required: true
- type: textarea
id: possible-approaches
attributes:
label: Possible Refactor Approaches
description: If you have some idea of possible approaches to solve this problem. You may want to make it a todo list.
placeholder: Your idea of possible refactoring opportunity/approaches
validations:
required: false

15
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,15 @@
blank_issues_enabled: true
contact_links:
- name: FAQ
url: https://github.com/jart/cosmopolitan/wiki/FAQ
about: Is your question a common one? You may want to check here first.
- name: Got an idea?
url: https://github.com/jart/cosmopolitan/discussions/categories/ideas
about: Pop it there. It may then become an enhancement ticket.
- name: Got a question?
url: https://github.com/jart/cosmopolitan/discussions/categories/q-a
about: Ask a question there!
- name: Want to contribute?
url: https://github.com/jart/cosmopolitan/wiki/contribute
about: Head to the contribution guide page of the wiki for areas you can help with

53
.github/labeler.yml vendored Normal file
View file

@ -0,0 +1,53 @@
# https://github.com/actions/labeler
documentation:
- changed-files:
- any-glob-to-any-file:
- README.md
- LICENSE
- CONTRIBUTING.md
- libc/README.md
- tool/cosmocc/README.md
- third_party/getopt/README.txt
testing:
- changed-files:
- any-glob-to-any-file:
- test/**
build:
- changed-files:
- any-glob-to-any-file:
- build/**
- Makefile
- '*/*.mk'
examples:
- changed-files:
- any-glob-to-any-file: examples/**
devops:
- changed-files:
- any-glob-to-any-file:
- .github/**
- .clang-format
dsp:
- changed-files:
- any-glob-to-any-file:
- dsp/**
ape:
- changed-files:
- any-glob-to-any-file:
- ape/**
libc:
- changed-files:
- any-glob-to-any-file:
- libc/**
net:
- changed-files:
- any-glob-to-any-file:
- net/**
third_party:
- changed-files:
- any-glob-to-any-file:
- third_party/**
tool:
- changed-files:
- any-glob-to-any-file:
- tool/**

17
.github/workflows/labeler.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: "jart/cosmopolitan"
- uses: actions/labeler@v5
with:
configuration-path: '.github/labeler.yml'

View file

@ -1,108 +0,0 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "c11",
"cppStandard": "c++11",
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
"defines": [
"libcesque=",
"pureconst=",
"paramsnonnull(x)=",
"alignas(x)",
"alignof(x)",
"artificial=",
"__wur=",
"mayalias=",
"forceinline=",
"forcealign(x)=",
"scanfesque(x)=",
"strftimeesque(x)=",
"wontreturn=",
"textreal=",
"mallocesque=",
"callocesque=",
"vallocesque=",
"reallocesque=",
"strlenesque=",
"memcpyesque=",
"hasatleast=",
"noinline=",
"textexit=",
"returnstwice=",
"textwindows=",
"privileged=",
"dontinstrument=",
"nodebuginfo=",
"interruptfn=",
"optimizespeed=",
"forcealignargpointer=",
"dontasan=",
"dontubsan=",
"donothing=",
"nosideeffect=",
"unreachable=",,
"notpossible=",
"thatispacked=",
"dontthrow=",
"dontcallback=",
"relegated=",
"hidden=",
"textstartup=",
"returnsnonnull=",
"returnspointerwithnoaliases=",
"printfesque(x)=",
"attributeallocsize(x)=",
"returnsaligned(x)=",
"attributeallocalign(x)=",
"nullterminated(x)="
]
},
{
"name": "Linux",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "gnu17",
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
"compilerArgs": [
"-Wall",
"-Werror",
"-fdebug-prefix-map=${workspaceFolder}=",
"-frecord-gcc-switches",
"-Wa,-W",
"-Wa,-I.",
"-Wa,--noexecstack",
"-Og",
"-g",
"-gdescribe-dies",
"-msse3",
"-mno-red-zone",
"-fno-math-errno",
"-fno-trapping-math",
"-fno-fp-int-builtin-inexact",
"-fno-ident",
"-fno-common",
"-fno-gnu-unique",
"-fstrict-aliasing",
"-fstrict-overflow",
"-fno-semantic-interposition",
"-mno-omit-leaf-frame-pointer",
"-fno-jump-tables",
"-nostdinc",
"-iquote."
],
"forcedInclude": [
"libc/integral/normalize.inc"
],
"defines": [
"COSMO",
"MODE="
]
}
],
"version": 4
}

2
.vscode/vscode.h vendored
View file

@ -1,2 +0,0 @@
#define __VSCODE_INTELLISENSE__ 1
#include "libc/integral/normalize.inc"

View file

@ -133,7 +133,7 @@ endif
ifneq ($(findstring aarch64,$(MODE)),)
ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
HOSTS ?= pi studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
@ -149,9 +149,9 @@ export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
COSMOCC = .cosmocc/3.3.3
COSMOCC = .cosmocc/3.3.5
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.3 e4d0fa63cd79cc3bfff6c2d015f1776db081409907625aea8ad40cefc1996d08)
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.5 db78fd8d3f8706e9dff4be72bf71d37a3f12062f212f407e1c33bc4af3780dd0)
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
@ -174,6 +174,7 @@ all: o
o: o/$(MODE)
o/$(MODE): \
o/$(MODE)/ape \
o/$(MODE)/ctl \
o/$(MODE)/dsp \
o/$(MODE)/net \
o/$(MODE)/libc \
@ -255,10 +256,11 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include ctl/BUILD.mk # │
include third_party/zlib/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
include libc/time/BUILD.mk # │
include third_party/tz/BUILD.mk # │
include net/BUILD.mk # │
include third_party/vqsort/BUILD.mk # │
include libc/log/BUILD.mk # │
@ -299,6 +301,7 @@ include tool/viz/lib/BUILD.mk
include tool/args/BUILD.mk
include test/math/BUILD.mk
include test/posix/BUILD.mk
include test/ctl/BUILD.mk
include test/libcxx/BUILD.mk
include test/tool/args/BUILD.mk
include third_party/linenoise/BUILD.mk
@ -362,7 +365,6 @@ include test/libc/fmt/BUILD.mk
include test/libc/time/BUILD.mk
include test/libc/proc/BUILD.mk
include test/libc/stdio/BUILD.mk
include test/libc/release/BUILD.mk
include test/libc/BUILD.mk
include test/net/http/BUILD.mk
include test/net/https/BUILD.mk
@ -440,7 +442,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
LIBC_TIME \
THIRD_PARTY_TZ \
THIRD_PARTY_OPENMP \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB_GZ \
@ -452,6 +454,7 @@ COSMOPOLITAN_OBJECTS = \
LIBC_THREAD \
LIBC_PROC \
THIRD_PARTY_NSYNC_MEM \
CTL \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_DLOPEN \
@ -505,7 +508,6 @@ COSMOPOLITAN_H_PKGS = \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
LIBC_VGA \
@ -521,6 +523,7 @@ COSMOPOLITAN_H_PKGS = \
COSMOCC_PKGS = \
$(COSMOPOLITAN_H_PKGS) \
CTL \
THIRD_PARTY_AARCH64 \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
@ -543,15 +546,6 @@ COSMOPOLITAN_H_ROOT_HDRS = \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
o/cosmopolitan.h.txt: Makefile
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
o/cosmopolitan.h: o/cosmopolitan.h.txt \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup @$< >>$@
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.dbg \
@ -573,7 +567,6 @@ $(SRCS): \
ifeq ($(ARCH), x86_64)
TOOLCHAIN_ARTIFACTS = \
o/cosmopolitan.h \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/ape/ape.elf \

View file

@ -254,7 +254,24 @@ o/$(MODE)/ape: $(APE_CHECKS) \
endif
# these assembly files are safe to build on aarch64
o/$(MODE)/ape/ape.o: ape/ape.S
o/$(MODE)/ape/ape.o: \
ape/ape.S \
ape/ape.h \
libc/dce.h \
libc/elf/def.h \
ape/relocations.h \
libc/thread/tls.h \
ape/ape.internal.h \
ape/macros.internal.h \
libc/macho.internal.h \
libc/macros.internal.h \
libc/sysv/consts/prot.h \
libc/nt/pedef.internal.h \
libc/runtime/pc.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/ape/ape.lds: \

View file

@ -293,7 +293,6 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));

View file

@ -31,6 +31,8 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
@ -39,7 +41,7 @@
/* maximum path size that cosmo can take */
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
#define SYSLIB_VERSION 9 /* sync with libc/runtime/syslib.internal.h */
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
struct Syslib {
int magic;
@ -106,6 +108,10 @@ struct Syslib {
OPTIONAL (cosmo lib should check __syslib->version) */
/* v9 (2024-01-31) */
int (*pthread_cpu_number_np)(size_t *);
/* v10 (2024-05-02) */
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
long (*sysctlnametomib)(const char *, int *, size_t *);
};
#define ELFCLASS32 1
@ -140,6 +146,9 @@ struct Syslib {
#define AT_RANDOM 25
#define AT_EXECFN 31
#define EF_APE_MODERN 0x101ca75
#define EF_APE_MODERN_MASK 0x1ffffff
#define AUXV_WORDS 31
/* from the xnu codebase */
@ -148,8 +157,8 @@ struct Syslib {
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
#define READ32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
@ -221,13 +230,15 @@ struct ApeLoader {
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
while (*s++)
++n;
return n;
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255);
}
@ -276,7 +287,8 @@ static char *Utoa(char p[21], unsigned long x) {
}
static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x;
if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x);
}
@ -312,7 +324,8 @@ static int GetIndirectOffset(const char *arg0) {
static void Perror(const char *thing, long rc, const char *reason) {
char ibuf[21];
ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc);
if (rc)
Itoa(ibuf, -rc);
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
ibuf, "\n", 0l);
}
@ -327,7 +340,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
return 0;
}
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
memmove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0;
return !access(ps->path, X_OK);
@ -377,8 +391,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
ps->name = name;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
if (FindCommand(ps)) {
return ps->path;
} else {
@ -545,6 +561,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
}
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen) {
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
}
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
void *newp, size_t newlen) {
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
}
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
return sysret(sysctlnametomib(name, mibp, sizep));
}
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
long *sp, struct ElfEhdr *e,
struct ElfPhdr *p,
@ -585,10 +615,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr & -pagesz;
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue;
if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) {
if (Max(a, c) < Min(b, d)) {
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
}
}
@ -614,7 +645,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
if (e->e_type == ET_DYN) {
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (rc < 0) Pexit(exe, rc, "pie mmap");
if (rc < 0)
Pexit(exe, rc, "pie mmap");
dynbase = rc;
if (dynbase & (pagesz - 1)) {
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@ -630,14 +662,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) {
void *addr;
unsigned long size;
if (p[i].p_type != PT_LOAD) continue;
if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */
prot = 0;
flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ;
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
if (p[i].p_flags & PF_R)
prot |= PROT_READ;
if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
/* load from file */
if (p[i].p_filesz) {
@ -657,7 +693,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
wipe = MIN(b - a, c - a);
wipe = Min(b - a, c - a);
if (wipe && (~prot1 & PROT_WRITE)) {
prot1 = PROT_READ | PROT_WRITE;
}
@ -687,24 +723,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
as the default strategy which is slow but it works for both */
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
if (rc < 0)
Pexit(exe, rc, "prog mmap anon");
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
if (rc != p[i].p_filesz)
Pexit(exe, -errno, "prog pread");
#endif
} else {
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
if (rc < 0) Pexit(exe, rc, "prog mmap");
if (rc < 0)
Pexit(exe, rc, "prog mmap");
}
if (wipe) memset((void *)(dynbase + a), 0, wipe);
if (wipe)
memset((void *)(dynbase + a), 0, wipe);
if (prot2 != prot1) {
rc = sys_mprotect(addr, size, prot2);
if (rc < 0) Pexit(exe, rc, "prog mprotect");
if (rc < 0)
Pexit(exe, rc, "prog mprotect");
}
/* allocate extra bss */
if (c > b) {
flags |= MAP_ANONYMOUS;
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
if (rc < 0)
Pexit(exe, rc, "extra bss mmap");
}
} else {
/* allocate pure bss */
@ -712,7 +754,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS;
rc = sys_mmap(addr, size, prot, flags, -1, 0);
if (rc < 0) Pexit(exe, rc, "bss mmap");
if (rc < 0)
Pexit(exe, rc, "bss mmap");
}
}
@ -759,7 +802,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
}
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
const char *exe, int fd, long *sp, long *auxv,
char *exe, int fd, long *sp, long *auxv,
char *execfn) {
long i, rc;
unsigned size;
@ -780,6 +823,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
if (e->e_machine != EM_AARCH64) {
return "couldn't find ELF header with ARM64 machine type";
}
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
/* change argv[0] to resolved path for older binaries */
((char **)(sp + 1))[0] = exe;
}
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
Pexit(exe, 0, "e_phentsize is wrong");
}
@ -790,8 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
if (rc < 0) return "failed to read ELF program headers";
if (rc != size) return "truncated read of ELF program headers";
if (rc < 0)
return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */
p = &M->phdr.phdr;
@ -948,6 +997,9 @@ int main(int argc, char **argv, char **envp) {
M->lib.dlclose = dlclose;
M->lib.dlerror = dlerror;
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
M->lib.sysctl = sys_sysctl;
M->lib.sysctlbyname = sys_sysctlbyname;
M->lib.sysctlnametomib = sys_sysctlnametomib;
/* getenv("_") is close enough to at_execfn */
execfn = 0;
@ -970,7 +1022,8 @@ int main(int argc, char **argv, char **envp) {
grows down the alloc by poking the guard pages */
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 nofixeol :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -196,7 +196,7 @@ ape_mz:
.quad ape_elf_entry // 18: e_entry
.quad ape_elf_phoff // 20: e_phoff
.quad ape_elf_shoff // 28: e_shoff
.long 0 // 30: e_flags
.long 0x101ca75 // 30: ape e_flags
.short 64 // 34: e_ehsize
.short 56 // 36: e_phentsize
.short ape_elf_phnum // 38: e_phnum
@ -669,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
.shstub ape_elf_entry,8 // 18: e_entry
.shstub ape_elf_phoff,8 // 20: e_phoff
.shstub ape_elf_shoff,8 // 28: e_shoff
.ascii "\\0\\0\\0\\0" // 30: e_flags
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
.ascii "\\100\\0" // 34: e_ehsize
.ascii "\\070\\0" // 36: e_phentsize
.shstub ape_elf_phnum,2 // 38: e_phnum
@ -1036,7 +1036,7 @@ ape_pe: .ascin "PE",4
.quad ape_pe_base // ImageBase
.long ape_pe_sectionalignment // SectionAlignment
.long ape_pe_filealignment // FileAlignment
.short v_ntversion // MajorOperatingSystemVersion
.short 10 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion
.short 0 // MinorImageVersion

View file

@ -553,7 +553,9 @@ _tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tls_align = 1;
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
ape_cod_offset = 0;
ape_cod_vaddr = ADDR(.head);
@ -713,7 +715,6 @@ ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
v_ntversion = LINK_WINDOWS ? 6 : 1;
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
v_ntsubsystem = (LINK_WINDOWS

View file

@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x build/bootstrap/make.com ]; then
MAKE=build/bootstrap/make.com
if [ -x build/bootstrap/make ]; then
MAKE=build/bootstrap/make
else
MAKE=make
fi
@ -137,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
echo done >&2
fi
uname_r="$(uname -r)"
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
FLAGS=FP
else
FLAGS=F
fi
echo >&2
echo registering APE with binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then

View file

@ -152,6 +152,9 @@
#define PR_SET_MM 35
#define PR_SET_MM_EXE_FILE 13
#define EF_APE_MODERN 0x101ca75
#define EF_APE_MODERN_MASK 0x1ffffff
#define READ32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
@ -228,13 +231,15 @@ extern char _end[];
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
while (*s++)
++n;
return n;
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
while (l[i] == r[i] && r[i])
++i;
return (l[i] & 255) - (r[i] & 255);
}
@ -353,7 +358,8 @@ static char *Utoa(char p[20], unsigned long x) {
}
static char *Itoa(char p[21], long x) {
if (x < 0) *p++ = '-', x = -(unsigned long)x;
if (x < 0)
*p++ = '-', x = -(unsigned long)x;
return Utoa(p, x);
}
@ -362,7 +368,8 @@ __attribute__((__noinline__)) static long CallSystem(long arg1, long arg2,
long arg5, long arg6,
long arg7, int numba,
char os) {
if (IsXnu()) numba |= 0x2000000;
if (IsXnu())
numba |= 0x2000000;
return SystemCall(arg1, arg2, arg3, arg4, arg5, arg6, arg7, numba);
}
@ -529,7 +536,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
switch ((c = *fmt++)) {
case 's':
for (s = __builtin_va_arg(va, const char *); s && *s; ++s) {
if (k < 512) b[k++] = *s;
if (k < 512)
b[k++] = *s;
}
break;
case 'd':
@ -542,16 +550,19 @@ static long Printf(int os, int fd, const char *fmt, ...) {
u -= 10;
c = 'a' + u;
}
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
}
break;
default:
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
break;
}
break;
default:
if (k < 512) b[k++] = c;
if (k < 512)
b[k++] = c;
break;
}
}
@ -560,7 +571,8 @@ static long Printf(int os, int fd, const char *fmt, ...) {
static void Perror(int os, const char *thing, long rc, const char *reason) {
char ibuf[21];
ibuf[0] = 0;
if (rc) Itoa(ibuf, -rc);
if (rc)
Itoa(ibuf, -rc);
Print(os, 2, "ape error: ", thing, ": ", reason,
rc ? " failed w/ errno " : "", ibuf, "\n", 0l);
}
@ -572,8 +584,10 @@ __attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc,
}
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path))
return 0;
if (pathlen && ps->path[pathlen - 1] != '/')
ps->path[pathlen++] = '/';
MemMove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0;
return !Access(ps->path, X_OK, ps->os);
@ -600,11 +614,14 @@ static char SearchPath(struct PathSearcher *ps) {
static char *Commandv(struct PathSearcher *ps, int os, char *name,
const char *syspath) {
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
if (!(ps->namelen = StrLen((ps->name = name))))
return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen))
return name;
ps->os = os;
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (ps->namelen + 1 > sizeof(ps->path))
return 0;
ps->path[0] = 0;
if (SearchPath(ps)) {
return ps->path;
@ -661,7 +678,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
Pexit(os, exe, 0, "ELF segments overlap your APE loader");
}
for (j = i + 1; j < e->e_phnum; ++j) {
if (p[j].p_type != PT_LOAD) continue;
if (p[j].p_type != PT_LOAD)
continue;
c = p[j].p_vaddr & -pagesz;
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
if (MAX(a, c) < MIN(b, d)) {
@ -694,7 +712,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
if (e->e_type == ET_DYN) {
rc = Mmap(0, virtmax - virtmin, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "pie mmap");
if (rc < 0)
Pexit(os, exe, rc, "pie mmap");
dynbase = rc;
if (dynbase & (pagesz - 1)) {
Pexit(os, exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
@ -710,14 +729,18 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
for (i = 0; i < e->e_phnum; ++i) {
void *addr;
unsigned long size;
if (p[i].p_type != PT_LOAD) continue;
if (p[i].p_type != PT_LOAD)
continue;
/* configure mapping */
prot = 0;
flags = MAP_FIXED | MAP_PRIVATE;
if (p[i].p_flags & PF_R) prot |= PROT_READ;
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
if (p[i].p_flags & PF_R)
prot |= PROT_READ;
if (p[i].p_flags & PF_W)
prot |= PROT_WRITE;
if (p[i].p_flags & PF_X)
prot |= PROT_EXEC;
if (p[i].p_filesz) {
/* load from file */
@ -744,17 +767,21 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
if (wipe) Bzero((void *)(dynbase + a), wipe);
if (rc < 0)
Pexit(os, exe, rc, "prog mmap");
if (wipe)
Bzero((void *)(dynbase + a), wipe);
if (prot2 != prot1) {
rc = Mprotect(addr, size, prot2, os);
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
if (rc < 0)
Pexit(os, exe, rc, "prog mprotect");
}
/* allocate extra bss */
if (c > b) {
flags |= MAP_ANONYMOUS;
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
if (rc < 0)
Pexit(os, exe, rc, "extra bss mmap");
}
} else {
/* allocate pure bss */
@ -762,7 +789,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, char *exe, int fd,
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
flags |= MAP_ANONYMOUS;
rc = Mmap(addr, size, prot, flags, -1, 0, os);
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
if (rc < 0)
Pexit(os, exe, rc, "bss mmap");
}
}
@ -783,7 +811,8 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
struct ElfPhdr *p;
/* validate page size */
if (!pagesz) pagesz = 4096;
if (!pagesz)
pagesz = 4096;
if (pagesz & (pagesz - 1)) {
Pexit(os, exe, 0, "AT_PAGESZ isn't two power");
}
@ -808,6 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
return "couldn't find ELF header with x86-64 machine type";
}
#endif
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
/* change argv[0] to resolved path for older binaries */
((char **)(sp + 1))[0] = exe;
}
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
Pexit(os, exe, 0, "e_phentsize is wrong");
}
@ -818,8 +851,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
/* read program headers */
rc = Pread(fd, M->phdr.buf, size, e->e_phoff, os);
if (rc < 0) return "failed to read ELF program headers";
if (rc != size) return "truncated read of ELF program headers";
if (rc < 0)
return "failed to read ELF program headers";
if (rc != size)
return "truncated read of ELF program headers";
/* bail on recoverable program header errors */
p = &M->phdr.phdr;
@ -949,7 +984,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
/* determine ape loader program name */
ape = argv[0];
if (!ape) ape = "ape";
if (!ape)
ape = "ape";
/* detect openbsd */
if (SupportsOpenbsd() && !os && !auxv[0]) {
@ -1021,7 +1057,8 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
grows down the alloc by poking the guard pages */
n = (endp - sp + 1) * sizeof(long);
sp2 = (long *)__builtin_alloca(n);
if ((long)sp2 & 15) ++sp2;
if ((long)sp2 & 15)
++sp2;
for (; n > 0; n -= pagesz) {
((char *)sp2)[n - 1] = 0;
}

View file

@ -132,7 +132,7 @@
#define SHSTUB2(SYM, X) \
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
#define BCD_SMEAR(X) ((X) + (X) * 10000)
#define BCD_SMEAR(X) ((X) + (X)*10000)
#define BCD_LEFT(X) \
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
@ -140,23 +140,16 @@
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
: 0xffffffffffffffff)
#define BCD_RIGHT(X) \
(((X)) < 10000 ? 0x20202020 \
: (X) < 100000 ? 0x20202030 + \
(X) % 10 \
: (X) < 1000000 ? 0x20203030 + \
((X) / 10) % 10 + \
(X) % 10 * 0x100 \
: (X) < 10000000 ? 0x20303030 + \
((X) / 100) % 10 + \
((X) / 10) % 10 * 0x100 + \
(X) % 10 * 0x10000 \
: (X) < 100000000 ? 0x30303030 + \
((X) / 1000) % 10 + \
((X) / 100) % 10 * 0x100 + \
((X) / 10) % 10 * 0x10000 + \
(X) % 10 * 0x1000000 \
: 0xffffffffffffffff)
#define BCD_RIGHT(X) \
(((X)) < 10000 ? 0x20202020 \
: (X) < 100000 ? 0x20202030 + (X) % 10 \
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
: (X) < 100000000 \
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
: 0xffffffffffffffff)
/**
* Laying out the GDT entries for a TSS for bare metal operation.
@ -165,15 +158,11 @@
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
#define TSSDESC_ENT0(BASE, LIM) \
(((LIM) << 0 & 0x000000000000ffff) | \
((BASE) << 16 & 0x000000ffffff0000) | \
0x89 << 40 | \
((LIM) >> 16 << 48 & 0x000f000000000000) | \
0x2 << 52 | \
#define TSSDESC_ENT0(BASE, LIM) \
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
((BASE) >> 24 << 56 & 0xff00000000000000))
#define TSSDESC_ENT1(BASE) \
((BASE) >> 32 << 0 & 0x00000000ffffffff)
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
#endif /* __ASSEMBLER__ */
#endif /* APE_MACROS_H_ */

View file

@ -16,6 +16,8 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
extern unsigned char _tbss_start[] __attribute__((__weak__));
extern unsigned char _tbss_end[] __attribute__((__weak__));
extern unsigned char _tls_align[] __attribute__((__weak__));
extern unsigned char _tdata_align[] __attribute__((__weak__));
extern unsigned char _tbss_align[] __attribute__((__weak__));
extern unsigned char __test_start[] __attribute__((__weak__));
extern unsigned char __ro[] __attribute__((__weak__));
extern unsigned char __data_start[] __attribute__((__weak__));

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -11,20 +11,20 @@
#
ifeq ($(MODE),)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
TARGET_ARCH ?= -msse3
endif
ifeq ($(MODE), x86_64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
@ -38,13 +38,13 @@ endif
#
ifeq ($(MODE), zero)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64-zero)
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0 -fdce
OVERRIDE_CXXFLAGS += -O0 -fdce
CONFIG_CPPFLAGS += -DSYSDEBUG
@ -81,7 +81,7 @@ endif
#
ifeq ($(MODE), opt)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
TARGET_ARCH ?= -march=native
@ -98,7 +98,7 @@ endif
# - Turns off support for other operating systems
#
ifeq ($(MODE), optlinux)
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
@ -140,7 +140,7 @@ endif
#
ifeq ($(MODE), asan)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
CONFIG_COPTS += -fsanitize=address
@ -160,7 +160,7 @@ endif
#
ifeq ($(MODE), dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
@ -170,7 +170,7 @@ QUOTA ?= -C64 -L300
endif
ifeq ($(MODE), aarch64-dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
CONFIG_COPTS += -fsanitize=undefined
@ -189,7 +189,7 @@ endif
#
ifeq ($(MODE), sysv)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
TARGET_ARCH ?= -msse3

View file

@ -60,13 +60,10 @@ TMPSAFE = $(TMPDIR)/
endif
BACKTRACES = \
-fno-schedule-insns2 \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer
ifneq ($(ARCH), aarch64)
BACKTRACES += -fno-schedule-insns2
endif
SANITIZER = \
-fsanitize=address
@ -148,12 +145,14 @@ DEFAULT_CFLAGS = \
-std=gnu2x
DEFAULT_CXXFLAGS = \
-std=gnu++20 \
-fno-rtti \
-fno-exceptions \
-fuse-cxa-atexit \
-Wno-int-in-bool-context \
-Wno-narrowing \
-Wno-literal-suffix
-Wno-literal-suffix \
-isystem third_party/libcxx
DEFAULT_ASFLAGS = \
-W \
@ -260,12 +259,12 @@ LD.libs = \
$(LIBS)
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)

View file

@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
fi
find_objdump() {
if [ -x .cosmocc/3.3.2/bin/$1-linux-cosmo-objdump ]; then
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump
elif [ -x .cosmocc/3.3.2/bin/$1-linux-musl-objdump ]; then
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-musl-objdump
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump"
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump"
if [ -x .cosmocc/3.3.5/bin/$1-linux-cosmo-objdump ]; then
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump
elif [ -x .cosmocc/3.3.5/bin/$1-linux-musl-objdump ]; then
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-musl-objdump
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump"
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump"
else
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
exit 1

View file

@ -197,7 +197,8 @@ static char *FormatUint32(char *p, uint32_t x) {
}
static char *FormatInt32(char *p, int32_t x) {
if (x < 0) *p++ = '-', x = -(uint32_t)x;
if (x < 0)
*p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x);
}
@ -205,7 +206,8 @@ static size_t StrCat(char *dst, const char *src, size_t dsize) {
size_t m, n = dsize;
const char *p = dst;
const char *q = src;
while (n-- != 0 && *dst != '\0') dst++;
while (n-- != 0 && *dst != '\0')
dst++;
m = dst - p;
n = dsize - m;
if (n-- == 0) {
@ -277,7 +279,8 @@ static bool IsSupportedPath(const char *path) {
for (i = 0;; ++i) {
switch (path[i]) {
case 0:
if (i) return true;
if (i)
return true;
// fallthrough
case '\r':
case '\n':
@ -320,8 +323,10 @@ static bool ProduceDigest(const char *path, FILE *f) {
char hexdigest[65];
char mode[2] = {g_mode};
unsigned char digest[32];
if (!IsSupportedPath(path)) return false;
if (!GetDigest(path, f, digest)) return false;
if (!IsSupportedPath(path))
return false;
if (!GetDigest(path, f, digest))
return false;
CopyHex(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL);
return true;
@ -361,17 +366,24 @@ static bool CheckDigests(const char *path, FILE *f) {
uint8_t wantdigest[32], gotdigest[32];
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
if (!*Chomp(buf)) continue;
if (!*Chomp(buf))
continue;
for (p = buf, i = 0; i < 32; ++i) {
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
if ((a = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
wantdigest[i] = a << 4 | b;
}
if (*p++ != ' ') goto InvalidLine;
if (!IsModeCharacter(*p++)) goto InvalidLine;
if (*p++ != ' ')
goto InvalidLine;
if (!IsModeCharacter(*p++))
goto InvalidLine;
path2 = p;
if (!*path2) goto InvalidLine;
if (!IsSupportedPath(path2)) continue;
if (!*path2)
goto InvalidLine;
if (!IsSupportedPath(path2))
continue;
if ((f2 = fopen(path2, "rb"))) {
if (GetDigest(path2, f2, gotdigest)) {
if (!memcmp(wantdigest, gotdigest, 32)) {

13
ctl/.clang-format Normal file
View file

@ -0,0 +1,13 @@
---
BasedOnStyle: Mozilla
IndentWidth: 4
ColumnLimit: 80
---
Language: Cpp
AllowShortFunctionsOnASingleLine: false
AlignTrailingComments: false
AlignEscapedNewlines: DontAlign
AlwaysBreakTemplateDeclarations: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
FixNamespaceComments: true
---

48
ctl/BUILD.mk Normal file
View file

@ -0,0 +1,48 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += CTL
CTL_ARTIFACTS += CTL_A
CTL = $(CTL_A_DEPS) $(CTL_A)
CTL_A = o/$(MODE)/ctl/ctl.a
CTL_A_FILES := $(wildcard ctl/*)
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
CTL_A_CHECKS = \
$(CTL_A).pkg \
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
CTL_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STR \
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
$(CTL_A): ctl/ \
$(CTL_A).pkg \
$(CTL_A_OBJS)
$(CTL_A).pkg: \
$(CTL_A_OBJS) \
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
$(CTL_A_OBJS): private \
OVERRIDE_CXXFLAGS += \
-Wframe-larger-than=4096 \
-Walloca-larger-than=4096 \
-ffunction-sections \
-fdata-sections \
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
.PHONY: o/$(MODE)/ctl
o/$(MODE)/ctl: $(CTL_CHECKS)

5015
ctl/README.md Normal file

File diff suppressed because it is too large Load diff

116
ctl/new.cc Normal file
View file

@ -0,0 +1,116 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "new.h"
#include "libc/mem/mem.h"
using ctl::align_val_t;
namespace {
constexpr auto a1 = align_val_t(1);
} // namespace
void*
operator new(size_t n, align_val_t a)
{
void* p;
if (!(p = memalign(static_cast<size_t>(a), n))) {
__builtin_trap();
}
return p;
}
void*
operator new[](size_t n, align_val_t a)
{
return operator new(n, a);
}
void*
operator new(size_t n)
{
return operator new(n, a1);
}
void*
operator new[](size_t n)
{
return operator new(n, a1);
}
void*
operator new(size_t, void* p)
{
return p;
}
void*
operator new[](size_t, void* p)
{
return p;
}
void
operator delete(void* p) noexcept
{
free(p);
}
void
operator delete[](void* p) noexcept
{
free(p);
}
void
operator delete(void* p, align_val_t) noexcept
{
free(p);
}
void
operator delete[](void* p, align_val_t) noexcept
{
free(p);
}
void
operator delete(void* p, size_t) noexcept
{
free(p);
}
void
operator delete[](void* p, size_t) noexcept
{
free(p);
}
void
operator delete(void* p, size_t, align_val_t) noexcept
{
free(p);
}
void
operator delete[](void* p, size_t, align_val_t) noexcept
{
free(p);
}
void
operator delete(void*, void*) noexcept
{
}
void
operator delete[](void*, void*) noexcept
{
}

30
ctl/new.h Normal file
View file

@ -0,0 +1,30 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_NEW_H_
#define COSMOPOLITAN_CTL_NEW_H_
// clang-format off
namespace ctl {
enum class align_val_t : size_t {};
} // namespace ctl
void* operator new(size_t);
void* operator new[](size_t);
void* operator new(size_t, ctl::align_val_t);
void* operator new[](size_t, ctl::align_val_t);
void* operator new(size_t, void*);
void* operator new[](size_t, void*);
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;
void operator delete(void*, ctl::align_val_t) noexcept;
void operator delete[](void*, ctl::align_val_t) noexcept;
void operator delete(void*, size_t) noexcept;
void operator delete[](void*, size_t) noexcept;
void operator delete(void*, size_t, ctl::align_val_t) noexcept;
void operator delete[](void*, size_t, ctl::align_val_t) noexcept;
#endif // COSMOPOLITAN_CTL_NEW_H_

143
ctl/optional.h Normal file
View file

@ -0,0 +1,143 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
#define COSMOPOLITAN_CTL_OPTIONAL_H_
#include "new.h"
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
namespace ctl {
template<typename T>
class optional
{
public:
using value_type = T;
~optional()
{
if (present_)
value_.~T();
}
optional() noexcept : present_(false)
{
}
optional(const T& value) : present_(true)
{
new (&value_) T(value);
}
optional(T&& value) : present_(true)
{
new (&value_) T(std::move(value));
}
optional(const optional& other) : present_(other.present_)
{
if (other.present_)
new (&value_) T(other.value_);
}
optional(optional&& other) noexcept : present_(other.present_)
{
if (other.present_)
new (&value_) T(std::move(other.value_));
}
optional& operator=(const optional& other)
{
if (this != &other) {
reset();
if (other.present_)
new (&value_) T(other.value_);
present_ = other.present_;
}
return *this;
}
optional& operator=(optional&& other) noexcept
{
if (this != &other) {
reset();
if (other.present_)
new (&value_) T(std::move(other.value_));
present_ = other.present_;
}
return *this;
}
T& value() &
{
if (!present_)
__builtin_trap();
return value_;
}
const T& value() const&
{
if (!present_)
__builtin_trap();
return value_;
}
T&& value() &&
{
if (!present_)
__builtin_trap();
return std::move(value_);
}
explicit operator bool() const noexcept
{
return present_;
}
bool has_value() const noexcept
{
return present_;
}
void reset() noexcept
{
if (present_) {
value_.~T();
present_ = false;
}
}
template<typename... Args>
void emplace(Args&&... args)
{
reset();
present_ = true;
new (&value_) T(std::forward<Args>(args)...);
}
void swap(optional& other) noexcept
{
using std::swap;
if (present_ && other.present_) {
swap(value_, other.value_);
} else if (present_) {
other.emplace(std::move(value_));
reset();
} else if (other.present_) {
emplace(std::move(other.value_));
other.reset();
}
}
private:
union
{
T value_;
};
bool present_;
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_

49
ctl/strcat.cc Normal file
View file

@ -0,0 +1,49 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string.h"
#include <stdckdint.h>
#include <string.h>
namespace ctl {
string
strcat(const string_view lhs, const string_view rhs) noexcept
{
string res;
size_t need;
if (ckd_add(&need, lhs.n, rhs.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
res.reserve(need);
if (lhs.n)
memcpy(res.data(), lhs.p, lhs.n);
if (rhs.n)
memcpy(res.data() + lhs.n, rhs.p, rhs.n);
if (res.isbig()) {
res.big()->n = lhs.n + rhs.n;
} else {
res.small()->rem = __::sso_max - lhs.n - rhs.n;
}
res.data()[res.size()] = 0;
return res;
}
} // namespace ctl

43
ctl/strcmp.cc Normal file
View file

@ -0,0 +1,43 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string_view.h"
#include <string.h>
namespace ctl {
int
strcmp(const string_view lhs, const string_view rhs) noexcept
{
int r;
size_t m = lhs.n;
if ((m = rhs.n < m ? rhs.n : m)) {
if (!m)
return 0;
if ((r = memcmp(lhs.p, rhs.p, m)))
return r;
}
if (lhs.n == rhs.n)
return 0;
if (m < lhs.n)
return +1;
return -1;
}
} // namespace ctl

367
ctl/string.cc Normal file
View file

@ -0,0 +1,367 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string.h"
#include <__atomic/fence.h>
#include <stdckdint.h>
namespace ctl {
string::~string() noexcept
{
if (isbig()) {
auto* b = big();
if (b->n) {
if (b->n >= b->c)
__builtin_trap();
if (b->p[b->n])
__builtin_trap();
}
if (b->c && !b->p)
__builtin_trap();
free(b->p);
}
}
string::string(const char* s) noexcept : string()
{
append(s, strlen(s));
}
string::string(const string& s) noexcept : string()
{
append(s.data(), s.size());
}
string::string(const string_view s) noexcept : string()
{
append(s.p, s.n);
}
string::string(size_t size, char ch) noexcept : string()
{
resize(size, ch);
}
string::string(const char* s, size_t size) noexcept : string()
{
append(s, size);
}
const char*
string::c_str() const noexcept
{
if (!size())
return "";
if (size() >= capacity())
__builtin_trap();
if (data()[size()])
__builtin_trap();
return data();
}
void
string::reserve(size_t c2) noexcept
{
char* p2;
size_t n = size();
if (c2 < n + 1)
c2 = n + 1;
if (c2 <= __::string_size)
return;
if (ckd_add(&c2, c2, 15))
__builtin_trap();
c2 &= -16;
if (!isbig()) {
if (!(p2 = (char*)malloc(c2)))
__builtin_trap();
memcpy(p2, data(), size());
p2[size()] = 0;
} else {
if (!(p2 = (char*)realloc(big()->p, c2)))
__builtin_trap();
}
std::atomic_signal_fence(std::memory_order_seq_cst);
set_big_capacity(c2);
big()->n = n;
big()->p = p2;
}
void
string::resize(size_t n2, char ch) noexcept
{
size_t c2;
if (ckd_add(&c2, n2, 1))
__builtin_trap();
reserve(c2);
if (n2 > size())
memset(data() + size(), ch, n2 - size());
if (isbig()) {
big()->p[big()->n = n2] = 0;
} else {
set_small_size(n2);
data()[size()] = 0;
}
}
void
string::append(char ch) noexcept
{
size_t n2;
if (ckd_add(&n2, size(), 2))
__builtin_trap();
if (n2 > capacity()) {
size_t c2 = capacity();
if (ckd_add(&c2, c2, c2 >> 1))
__builtin_trap();
reserve(c2);
}
data()[size()] = ch;
if (isbig()) {
++big()->n;
} else {
--small()->rem;
}
data()[size()] = 0;
}
void
string::grow(size_t size) noexcept
{
size_t need;
if (ckd_add(&need, this->size(), size))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
if (need <= capacity())
return;
size_t c2 = capacity();
if (!c2)
__builtin_trap();
while (c2 < need)
if (ckd_add(&c2, c2, c2 >> 1))
__builtin_trap();
reserve(c2);
}
void
string::append(char ch, size_t size) noexcept
{
grow(size);
if (size)
memset(data() + this->size(), ch, size);
if (isbig()) {
big()->n += size;
} else {
small()->rem -= size;
}
data()[this->size()] = 0;
}
void
string::append(const void* data, size_t size) noexcept
{
grow(size);
if (size)
memcpy(this->data() + this->size(), data, size);
if (isbig()) {
big()->n += size;
} else {
small()->rem -= size;
}
this->data()[this->size()] = 0;
}
void
string::pop_back() noexcept
{
if (!size())
__builtin_trap();
if (isbig()) {
--big()->n;
} else {
++small()->rem;
}
data()[size()] = 0;
}
string&
string::operator=(string s) noexcept
{
swap(s);
return *this;
}
bool
string::operator==(const string_view s) const noexcept
{
if (size() != s.n)
return false;
if (!s.n)
return true;
return !memcmp(data(), s.p, s.n);
}
bool
string::operator!=(const string_view s) const noexcept
{
if (size() != s.n)
return true;
if (!s.n)
return false;
return !!memcmp(data(), s.p, s.n);
}
bool
string::contains(const string_view s) const noexcept
{
if (!s.n)
return true;
return !!memmem(data(), size(), s.p, s.n);
}
bool
string::ends_with(const string_view s) const noexcept
{
if (size() < s.n)
return false;
if (!s.n)
return true;
return !memcmp(data() + size() - s.n, s.p, s.n);
}
bool
string::starts_with(const string_view s) const noexcept
{
if (size() < s.n)
return false;
if (!s.n)
return true;
return !memcmp(data(), s.p, s.n);
}
size_t
string::find(char ch, size_t pos) const noexcept
{
char* q;
if ((q = (char*)memchr(data(), ch, size())))
return q - data();
return npos;
}
size_t
string::find(const string_view s, size_t pos) const noexcept
{
char* q;
if (pos > size())
__builtin_trap();
if ((q = (char*)memmem(data() + pos, size() - pos, s.p, s.n)))
return q - data();
return npos;
}
string
string::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > size())
__builtin_trap();
if (count > size() - pos)
count = size() - pos;
if (ckd_add(&last, pos, count))
last = size();
if (last > size())
__builtin_trap();
return string(data() + pos, count);
}
string&
string::replace(size_t pos, size_t count, const string_view& s) noexcept
{
size_t last;
if (ckd_add(&last, pos, count))
__builtin_trap();
if (last > size())
__builtin_trap();
size_t need;
if (ckd_add(&need, pos, s.n))
__builtin_trap();
size_t extra = size() - last;
if (ckd_add(&need, need, extra))
__builtin_trap();
size_t c2;
if (ckd_add(&c2, need, 1))
__builtin_trap();
reserve(c2);
if (extra)
memmove(data() + pos + s.n, data() + last, extra);
memcpy(data() + pos, s.p, s.n);
if (isbig()) {
big()->p[big()->n = need] = 0;
} else {
set_small_size(need);
data()[size()] = 0;
}
return *this;
}
string&
string::insert(size_t i, const string_view s) noexcept
{
if (i > size())
__builtin_trap();
size_t extra = size() - i;
size_t need;
if (ckd_add(&need, size(), s.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
reserve(need);
if (extra)
memmove(data() + i + s.n, data() + i, extra);
memcpy(data() + i, s.p, s.n);
if (isbig()) {
big()->n += s.n;
} else {
small()->rem -= s.n;
}
data()[size()] = 0;
return *this;
}
string&
string::erase(size_t pos, size_t count) noexcept
{
if (pos > size())
__builtin_trap();
if (count > size() - pos)
count = size() - pos;
size_t extra = size() - (pos + count);
if (extra)
memmove(data() + pos, data() + pos + count, extra);
if (isbig()) {
big()->n = pos + extra;
} else {
set_small_size(pos + extra);
}
data()[size()] = 0;
return *this;
}
} // namespace ctl

362
ctl/string.h Normal file
View file

@ -0,0 +1,362 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRING_H_
#define COSMOPOLITAN_CTL_STRING_H_
#include "string_view.h"
namespace ctl {
class string;
string
strcat(const string_view, const string_view) noexcept __wur;
namespace __ {
constexpr size_t string_size = 3 * sizeof(size_t);
constexpr size_t sso_max = string_size - 1;
constexpr size_t big_mask = ~(1ull << (8ull * sizeof(size_t) - 1ull));
struct small_string
{
char buf[sso_max];
// interpretation is: size == sso_max - rem
unsigned char rem;
#if 0
size_t rem : 7;
size_t big : 1 /* = 0 */;
#endif
};
struct big_string
{
char* p;
size_t n;
// interpretation is: capacity == c & big_mask
size_t c;
#if 0
size_t c : sizeof(size_t) * 8 - 1;
size_t big : 1 /* = 1 */;
#endif
};
} // namespace __
class string
{
public:
using iterator = char*;
using const_iterator = const char*;
static constexpr size_t npos = -1;
~string() /* noexcept */;
string(const string_view) noexcept;
string(const char*) noexcept;
string(const string&) noexcept;
string(const char*, size_t) noexcept;
explicit string(size_t, char = 0) noexcept;
string& operator=(string) noexcept;
const char* c_str() const noexcept;
void pop_back() noexcept;
void grow(size_t) noexcept;
void reserve(size_t) noexcept;
void resize(size_t, char = 0) noexcept;
void append(char) noexcept;
void append(char, size_t) noexcept;
void append(unsigned long) noexcept;
void append(const void*, size_t) noexcept;
string& insert(size_t, const string_view) noexcept;
string& erase(size_t = 0, size_t = npos) noexcept;
string substr(size_t = 0, size_t = npos) const noexcept;
string& replace(size_t, size_t, const string_view&) noexcept;
bool operator==(const string_view) const noexcept;
bool operator!=(const string_view) const noexcept;
bool contains(const string_view) const noexcept;
bool ends_with(const string_view) const noexcept;
bool starts_with(const string_view) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const string_view, size_t = 0) const noexcept;
string() noexcept
{
set_small_size(0);
#if 0
small()->buf[0] = 0;
#endif
}
void swap(string& s) noexcept
{
char tmp[__::string_size];
__builtin_memcpy(tmp, __builtin_launder(blob), sizeof(tmp));
__builtin_memcpy(
__builtin_launder(blob), __builtin_launder(s.blob), sizeof(tmp));
__builtin_memcpy(__builtin_launder(s.blob), tmp, sizeof(tmp));
}
string(string&& s) noexcept
{
__builtin_memcpy(blob, __builtin_launder(s.blob), sizeof(blob));
s.set_small_size(0);
#if 0
s.small()->buf[0] = 0;
#endif
}
void clear() noexcept
{
if (isbig()) {
big()->n = 0;
} else {
set_small_size(0);
}
}
bool empty() const noexcept
{
return isbig() ? !big()->n : small()->rem >= __::sso_max;
}
inline char* data() noexcept
{
return isbig() ? big()->p : small()->buf;
}
inline const char* data() const noexcept
{
return isbig() ? big()->p : small()->buf;
}
inline size_t size() const noexcept
{
#if 0
if (!isbig() && small()->rem > __::sso_max)
__builtin_trap();
#endif
return isbig() ? big()->n : __::sso_max - small()->rem;
}
size_t length() const noexcept
{
return size();
}
size_t capacity() const noexcept
{
#if 0
if (isbig() && big()->c <= __::sso_max)
__builtin_trap();
#endif
return isbig() ? __::big_mask & big()->c : __::string_size;
}
iterator begin() noexcept
{
return data();
}
iterator end() noexcept
{
return data() + size();
}
const_iterator cbegin() const noexcept
{
return data();
}
const_iterator cend() const noexcept
{
return data() + size();
}
char& front()
{
if (!size())
__builtin_trap();
return data()[0];
}
const char& front() const
{
if (!size())
__builtin_trap();
return data()[0];
}
char& back()
{
if (!size())
__builtin_trap();
return data()[size() - 1];
}
const char& back() const
{
if (!size())
__builtin_trap();
return data()[size() - 1];
}
char& operator[](size_t i) noexcept
{
if (i >= size())
__builtin_trap();
return data()[i];
}
const char& operator[](size_t i) const noexcept
{
if (i >= size())
__builtin_trap();
return data()[i];
}
void push_back(char ch) noexcept
{
append(ch);
}
void append(const string_view s) noexcept
{
append(s.p, s.n);
}
inline operator string_view() const noexcept
{
return string_view(data(), size());
}
string& operator=(const char* s) noexcept
{
clear();
append(s);
return *this;
}
string& operator=(const string_view s) noexcept
{
clear();
append(s);
return *this;
}
string& operator+=(char x) noexcept
{
append(x);
return *this;
}
string& operator+=(const string_view s) noexcept
{
append(s);
return *this;
}
string operator+(const string_view s) const noexcept
{
return strcat(*this, s);
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view s) const noexcept
{
return compare(s) >= 0;
}
private:
inline bool isbig() const noexcept
{
return *(__builtin_launder(blob) + __::sso_max) & 0x80;
}
inline void set_small_size(size_t size) noexcept
{
if (size > __::sso_max)
__builtin_trap();
*(__builtin_launder(blob) + __::sso_max) = (__::sso_max - size);
}
inline void set_big_capacity(size_t c2) noexcept
{
if (c2 > __::big_mask)
__builtin_trap();
*(__builtin_launder(blob) + __::sso_max) = 0x80;
big()->c &= ~__::big_mask;
big()->c |= c2;
}
inline __::small_string* small() noexcept
{
if (isbig())
__builtin_trap();
return __builtin_launder(reinterpret_cast<__::small_string*>(blob));
}
inline const __::small_string* small() const noexcept
{
if (isbig())
__builtin_trap();
return __builtin_launder(
reinterpret_cast<const __::small_string*>(blob));
}
inline __::big_string* big() noexcept
{
if (!isbig())
__builtin_trap();
return __builtin_launder(reinterpret_cast<__::big_string*>(blob));
}
inline const __::big_string* big() const noexcept
{
if (!isbig())
__builtin_trap();
return __builtin_launder(reinterpret_cast<const __::big_string*>(blob));
}
friend string strcat(const string_view, const string_view);
alignas(union {
__::big_string a;
__::small_string b;
}) char blob[__::string_size];
};
static_assert(sizeof(string) == __::string_size);
static_assert(sizeof(__::small_string) == __::string_size);
static_assert(sizeof(__::big_string) == __::string_size);
} // namespace ctl
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wliteral-suffix"
inline ctl::string
operator"" s(const char* s, size_t n)
{
return ctl::string(s, n);
}
#pragma GCC diagnostic pop
#endif // COSMOPOLITAN_CTL_STRING_H_

111
ctl/string_view.cc Normal file
View file

@ -0,0 +1,111 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string_view.h"
#include <stdckdint.h>
#include <string.h>
#include "string.h"
namespace ctl {
size_t
string_view::find(char ch, size_t pos) const noexcept
{
char* q;
if (n && (q = (char*)memchr(p, ch, n)))
return q - p;
return npos;
}
size_t
string_view::find(const string_view s, size_t pos) const noexcept
{
char* q;
if (pos > n)
__builtin_trap();
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
return q - p;
return npos;
}
string_view
string_view::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
if (ckd_add(&last, pos, count))
last = n;
if (last > n)
__builtin_trap();
return string_view(p + pos, count);
}
bool
string_view::operator==(const string_view s) const noexcept
{
if (n != s.n)
return false;
if (!n)
return true;
return !memcmp(p, s.p, n);
}
bool
string_view::operator!=(const string_view s) const noexcept
{
if (n != s.n)
return true;
if (!n)
return false;
return !!memcmp(p, s.p, n);
}
bool
string_view::contains(const string_view s) const noexcept
{
if (!s.n)
return true;
return !!memmem(p, n, s.p, s.n);
}
bool
string_view::ends_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p + n - s.n, s.p, s.n);
}
bool
string_view::starts_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p, s.p, s.n);
}
} // namespace ctl

159
ctl/string_view.h Normal file
View file

@ -0,0 +1,159 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRINGVIEW_H_
#define COSMOPOLITAN_CTL_STRINGVIEW_H_
namespace ctl {
struct string_view;
int
strcmp(const string_view, const string_view) noexcept;
struct string_view
{
const char* p;
size_t n;
using iterator = const char*;
using const_iterator = const char*;
static constexpr size_t npos = -1;
constexpr string_view() noexcept : p(nullptr), n(0)
{
}
constexpr string_view(const char* s) noexcept
: p(s), n(s ? __builtin_strlen(s) : 0)
{
}
constexpr string_view(const char* s, size_t n) noexcept : p(s), n(n)
{
}
inline constexpr ~string_view() noexcept
{
}
bool operator==(const string_view) const noexcept;
bool operator!=(const string_view) const noexcept;
bool contains(const string_view) const noexcept;
bool ends_with(const string_view) const noexcept;
bool starts_with(const string_view) const noexcept;
string_view substr(size_t = 0, size_t = npos) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const string_view, size_t = 0) const noexcept;
constexpr string_view& operator=(const string_view& s) noexcept
{
p = s.p;
n = s.n;
return *this;
}
constexpr bool empty() const noexcept
{
return !n;
}
constexpr const char* data() const noexcept
{
return p;
}
constexpr size_t size() const noexcept
{
return n;
}
constexpr size_t length() const noexcept
{
return n;
}
constexpr const char& operator[](size_t i) const noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
constexpr void remove_prefix(size_t count)
{
if (count > n)
__builtin_trap();
p += count;
n -= count;
}
constexpr void remove_suffix(size_t count)
{
if (count > n)
__builtin_trap();
n -= count;
}
constexpr const char& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
constexpr const char& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
constexpr const_iterator begin() noexcept
{
return p;
}
constexpr const_iterator end() noexcept
{
return p + n;
}
constexpr const_iterator cbegin() const noexcept
{
return p;
}
constexpr const_iterator cend() const noexcept
{
return p + n;
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view& s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view& s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view& s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view& s) const noexcept
{
return compare(s) >= 0;
}
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_

247
ctl/vector.h Normal file
View file

@ -0,0 +1,247 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
#define COSMOPOLITAN_CTL_OPTIONAL_H_
#include "new.h"
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
namespace ctl {
template<typename T>
struct vector
{
size_t n = 0;
size_t c = 0;
T* p = nullptr;
using iterator = T*;
using const_iterator = const T*;
vector() = default;
~vector()
{
delete[] p;
}
vector(const vector& other)
{
n = other.n;
c = other.c;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(other.p[i]);
}
vector(vector&& other) noexcept
{
n = other.n;
c = other.c;
p = other.p;
other.n = 0;
other.c = 0;
other.p = nullptr;
}
explicit vector(size_t count, const T& value = T())
{
n = count;
c = count;
p = new T[c];
for (size_t i = 0; i < n; ++i)
new (&p[i]) T(value);
}
vector& operator=(const vector& other)
{
if (this != &other) {
T* newData = new T[other.c];
for (size_t i = 0; i < other.n; ++i) {
newData[i] = other.p[i];
}
delete[] p;
p = newData;
n = other.n;
c = other.c;
}
return *this;
}
vector& operator=(vector&& other) noexcept
{
if (this != &other) {
delete[] p;
p = other.p;
n = other.n;
c = other.c;
other.p = nullptr;
other.n = 0;
other.c = 0;
}
return *this;
}
bool empty() const
{
return !n;
}
size_t size() const
{
return n;
}
size_t capacity() const
{
return c;
}
T& operator[](size_t i)
{
if (i >= n)
__builtin_trap();
return p[i];
}
const T& operator[](size_t i) const
{
if (i >= n)
__builtin_trap();
return p[i];
}
iterator begin()
{
return p;
}
iterator end()
{
return p + n;
}
const_iterator cbegin() const
{
return p;
}
const_iterator cend() const
{
return p + n;
}
T& front()
{
if (!n)
__builtin_trap();
return p[0];
}
const T& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
T& back()
{
if (!n)
__builtin_trap();
return p[n - 1];
}
const T& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
void clear()
{
for (size_t i = 0; i < n; ++i)
p[i].~T();
n = 0;
}
void reserve(size_t c2)
{
if (c2 <= c)
return;
T* newP = new T[c2];
for (size_t i = 0; i < n; ++i)
newP[i] = std::move(p[i]);
delete[] p;
p = newP;
c = c2;
}
void push_back(const T& e)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(e);
++n;
}
void push_back(T&& e)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(std::forward<T>(e));
++n;
}
template<typename... Args>
void emplace_back(Args&&... args)
{
if (n == c) {
size_t c2 = c + 1;
c2 += c2 >> 1;
reserve(c2);
}
new (&p[n]) T(std::forward<Args>(args)...);
++n;
}
void pop_back()
{
if (n > 0) {
--n;
p[n].~T();
}
}
void resize(size_t n2)
{
if (n2 > n) {
reserve(n2);
for (size_t i = n; i < n2; ++i)
new (&p[i]) T();
} else if (n2 < n) {
for (size_t i = n2; i < n; ++i)
p[i].~T();
}
n = n2;
}
void swap(vector& other) noexcept
{
std::swap(n, other.n);
std::swap(c, other.c);
std::swap(p, other.p);
}
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_

View file

@ -27,7 +27,8 @@
*/
int alaw(int x) {
int a, b, i;
if ((a = x) < 0) a = ~a;
if ((a = x) < 0)
a = ~a;
a >>= 4;
if (a > 15) {
if ((i = a >> 5)) {
@ -40,6 +41,7 @@ int alaw(int x) {
a += 16;
}
}
if (x >= 0) a |= 128;
if (x >= 0)
a |= 128;
return a ^ 85;
}

View file

@ -9,8 +9,8 @@ int mulaw(int);
int unmulaw(int);
void *double2byte(long, const void *, double, double) vallocesque;
void *byte2double(long, const void *, double, double) vallocesque;
void *dct(float[restrict hasatleast 8][8], unsigned,
float, float, float, float, float);
void *dct(float[restrict hasatleast 8][8], unsigned, float, float, float, float,
float);
void *dctjpeg(float[restrict hasatleast 8][8], unsigned);
double det3(const double[3][3]) nosideeffect;
void *inv3(double[restrict 3][3], const double[restrict 3][3], double);

View file

@ -65,8 +65,8 @@
*
* @cost ~100ns
*/
void *dct(float M[restrict hasatleast 8][8], unsigned stride,
float c0, float c1, float c2, float c3, float c4) {
void *dct(float M[restrict hasatleast 8][8], unsigned stride, float c0,
float c1, float c2, float c3, float c4) {
unsigned y, x;
for (y = 0; y < stride * 8; y += stride) {
DCT(M[y][0], M[y][1], M[y][2], M[y][3], M[y][4], M[y][5], M[y][6], M[y][7],

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsp/core/core.h"
#include "dsp/core/gamma.h"
#include "dsp/core/core.h"
#include "libc/math.h"
double rgb2stdpc(double x, double g) {

View file

@ -28,13 +28,15 @@
int mulaw(int x) {
int b, i, a, s, l, h;
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
if (a > 8191) a = 8191;
if (a > 8191)
a = 8191;
i = a >> 6;
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
h = 8 - s;
l = (a >> s) & 15;
l = 15 - l;
b = (h << 4) | l;
if (x >= 0) b |= 128;
if (x >= 0)
b |= 128;
return b;
}

View file

@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
/* TODO(jart): This isn't acceptable. */
size_t i, j;
if (p > 0) {
if (p > 15) p = 15;
if (p > 15)
p = 15;
for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) {
pcm[i][j] =
@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
}
} else if (p < 0) {
p = -p;
if (p > 15) p = 15;
if (p > 15)
p = 15;
for (i = 0; i < n; ++i) {
for (j = 0; j < 8; ++j) {
pcm[i][j] = pcm[i][j] >> p;

View file

@ -31,8 +31,10 @@ int unalaw(int x) {
i = (x ^ 85) & 127;
e = i >> 4;
m = i & 15;
if (e > 0) m += 16;
if (e > 0)
m += 16;
m = (m << 4) + 8;
if (e > 1) m = m << (e - 1);
if (e > 1)
m = m << (e - 1);
return x & 128 ? m : -m;
}

View file

@ -35,7 +35,6 @@ DSP_MPEG_A_DIRECTDEPS = \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_TIME \
LIBC_TINYMATH \
THIRD_PARTY_COMPILER_RT

View file

@ -64,7 +64,8 @@ forceinline bool plm_buffer_has(plm_buffer_t *b, size_t bits) {
}
forceinline int plm_buffer_read(plm_buffer_t *self, int count) {
if (!plm_buffer_has(self, count)) return 0;
if (!plm_buffer_has(self, count))
return 0;
int value = 0;
while (count) {
int current_byte = self->bytes[self->bit_index >> 3];

View file

@ -3,8 +3,8 @@
#include "dsp/mpeg/mpeg.h"
COSMOPOLITAN_C_START_
#define START_PACK 0xBA
#define START_END 0xB9
#define START_PACK 0xBA
#define START_END 0xB9
#define START_SYSTEM 0xBB
typedef struct plm_demux_t {

View file

@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
di = (self->mb_row * dw + self->mb_col) * BW;
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
if (si > max_address || di > max_address) return;
if (si > max_address || di > max_address)
return;
d += di;
s += si;
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {

View file

@ -39,7 +39,7 @@
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "libc/x/x.h"
__static_yoink("pl_mpeg_notice");

View file

@ -31,7 +31,6 @@ DSP_SCALE_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X

View file

@ -77,7 +77,8 @@ static struct SamplingSolution *NewSamplingSolution(long n, long s) {
static bool IsNormalized(int n, double A[n]) {
int i;
double x;
for (x = i = 0; i < n; ++i) x += A[i];
for (x = i = 0; i < n; ++i)
x += A[i];
return fabs(x - 1) < 1e-4;
}
@ -96,8 +97,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
short *weights, *indices;
struct SamplingSolution *res;
long j, i, k, n, min, max, s, N[6];
if (!dar) dar = sn, dar /= dn;
if (!off) off = (dar - 1) / 2;
if (!dar)
dar = sn, dar /= dn;
if (!off)
off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4;
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
@ -114,8 +117,10 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
for (k = 0, j = min; j <= max; ++j) {
fweights[k++] = ComputeWeight((j - x) / (f / par));
}
for (sum = k = 0; k < n; ++k) sum += fweights[k];
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum;
for (sum = k = 0; k < n; ++k)
sum += fweights[k];
for (j = 0; j < n; ++j)
fweights[j] *= 1 / sum;
DCHECK(IsNormalized(n, fweights));
for (j = 0; j < n; ++j) {
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));

View file

@ -38,7 +38,6 @@ DSP_TTY_A_DIRECTDEPS = \
LIBC_SOCK \
LIBC_SYSV \
LIBC_TINYMATH \
LIBC_TIME \
LIBC_X
DSP_TTY_A_DEPS := \

View file

@ -24,9 +24,13 @@
* The alternate buffer trick lets one restore the console exactly as it
* was, once the program is done running.
*/
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
int ttyenablealtbuf(int ttyfd) {
return ttysend(ttyfd, "\e[?1049h");
}
/**
* Asks teletypewriter to restore blinking box thing.
*/
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }
int ttydisablealtbuf(int ttyfd) {
return ttysend(ttyfd, "\e[?1049l");
}

View file

@ -30,8 +30,10 @@
static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l";
if (__nocolor) return 0;
if (visible) code[5] = 'h';
if (__nocolor)
return 0;
if (visible)
code[5] = 'h';
if (IsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
ntcursor.bVisible = visible;

View file

@ -21,9 +21,13 @@
/**
* Asks teletypewriter to push current position.
*/
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
int ttysavecursor(int ttyfd) {
return ttysend(ttyfd, "\e[s");
}
/**
* Asks teletypewriter to pop previous position.
*/
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }
int ttyrestorecursor(int ttyfd) {
return ttysend(ttyfd, "\e[u");
}

View file

@ -21,22 +21,30 @@
#include "libc/limits.h"
static char *ansitoa(char *p, unsigned xt, unsigned base) {
if (xt >= 8) xt -= 8, base += 60;
if (xt >= 8)
xt -= 8, base += 60;
return itoa8(p, xt + base);
}
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
*p++ = '\e';
*p++ = '[';
if (bg != -1u) p = ansitoa(p, bg, 40);
if (bg != -1u && fg != -1u) *p++ = ';';
if (fg != -1u) p = ansitoa(p, fg, 30);
if (bg != -1u)
p = ansitoa(p, bg, 40);
if (bg != -1u && fg != -1u)
*p++ = ';';
if (fg != -1u)
p = ansitoa(p, fg, 30);
*p++ = 'm';
return p;
}
char *setbg16_(char *p, struct TtyRgb bg) { return setansibgfg(p, bg.xt, -1u); }
char *setfg16_(char *p, struct TtyRgb fg) { return setansibgfg(p, -1u, fg.xt); }
char *setbg16_(char *p, struct TtyRgb bg) {
return setansibgfg(p, bg.xt, -1u);
}
char *setfg16_(char *p, struct TtyRgb fg) {
return setansibgfg(p, -1u, fg.xt);
}
char *setbgfg16_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
return setansibgfg(p, bg.xt, fg.xt);
}

View file

@ -666,7 +666,8 @@ static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Glyph *glyph) {
unsigned i;
CHECK_LT(pick.bg, 4);
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4);
if (pick.fg != 0xff)
CHECK_LT(pick.fg, 4);
i = 0;
if (pick.fg == 0xff) {
if (!ttyeq(*bg, chunk[pick.bg])) {
@ -744,7 +745,8 @@ static dontinline char *CopyRun(char *v, size_t n,
v = CopyGlyph(v, *glyph);
*x += 2;
*c += 2;
if (*x >= n) break;
if (*x >= n)
break;
CopyChunk(chunk, *c, n);
} while (ChunkEq(chunk, lastchunk));
*x -= 2;

View file

@ -69,13 +69,16 @@ static textstartup int ttyraw_enable(void) {
}
static textstartup void ttyraw_hidecursor(void) {
if (!g_ttyraw.setup) return;
if (g_ttyraw.flags & kTtyCursor) return;
if (!g_ttyraw.setup)
return;
if (g_ttyraw.flags & kTtyCursor)
return;
ttyhidecursor(FD);
}
static textexit int ttyraw_disable(void) {
if (!g_ttyraw.setup) return 0;
if (!g_ttyraw.setup)
return 0;
ttyshowcursor(FD);
return ttyrestore(FD, &g_ttyraw.old);
}
@ -84,10 +87,11 @@ static textexit void ttyraw_onexit(void) {
ttyraw_disable();
}
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
static relegated void ttyraw_onsig(int sig, siginfo_t *info,
struct ucontext *ctx) {
size_t i;
if (g_ttyraw.noreentry) _Exit(128 + sig);
if (g_ttyraw.noreentry)
_Exit(128 + sig);
g_ttyraw.noreentry = true;
if (g_ttyraw.flags != -1) {
if (sig == SIGCONT) {

View file

@ -65,7 +65,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_SYSV_CALLS \
LIBC_TESTLIB \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_VGA \
LIBC_X \
@ -89,8 +88,10 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_SED \
THIRD_PARTY_STB \
THIRD_PARTY_TR \
THIRD_PARTY_TZ \
THIRD_PARTY_VQSORT \
THIRD_PARTY_XED \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_ZLIB \
TOOL_ARGS \
TOOL_BUILD_LIB \
@ -154,7 +155,8 @@ o/$(MODE)/examples/picol.dbg: \
@$(APELINK)
o/$(MODE)/usr/share/dict/words.zip.o: private ZIPOBJ_FLAGS += -C2
o/$(MODE)/examples/wut.o: private COPTS += -fopenmp
o/$(MODE)/examples/blas.o: private COPTS += -O3 -fopenmp
$(EXAMPLES_OBJS): examples/BUILD.mk

16
examples/asantest.c Normal file
View file

@ -0,0 +1,16 @@
#include <stdlib.h>
__static_yoink("__die");
__static_yoink("GetSymbolByAddr");
__static_yoink("malloc_inspect_all");
char *lol(int n) {
return malloc(n);
}
char *(*pLol)(int) = lol;
int main(int argc, char *argv[]) {
char *s = pLol(4);
s[4] = 1;
}

221
examples/blas.cc Normal file
View file

@ -0,0 +1,221 @@
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <unistd.h>
#include <cinttypes>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include "libc/assert.h"
// high performance high accuracy matrix multiplication in ansi c
#define MATH __target_clones("avx512f,fma")
namespace {
namespace ansiBLAS {
static constexpr int KN = 8;
struct Vector {
double v[KN];
};
Vector load(const float *p) {
Vector x;
for (int i = 0; i < KN; ++i)
x.v[i] = p[i];
return x;
}
Vector madd(Vector x, Vector y, Vector s) {
for (int i = 0; i < KN; ++i)
s.v[i] = fma(x.v[i], y.v[i], s.v[i]);
return s;
}
float hsum(Vector x) {
double s = 0;
for (int i = 0; i < KN; ++i)
s += x.v[i];
return s;
}
struct ansiBLAS {
public:
ansiBLAS(int k, const float *A, int lda, const float *B, int ldb, float *C,
int ldc, int ith, int nth)
: k(k),
A(A),
lda(lda),
B(B),
ldb(ldb),
C(C),
ldc(ldc),
ith(ith),
nth(nth) {
}
void matmul(int m, int n) {
mnpack(0, m, 0, n);
}
private:
void mnpack(int m0, int m, int n0, int n) {
int mc, nc, mp, np;
if (m - m0 <= 0 || n - n0 <= 0)
return;
if (m - m0 >= 4 && n - n0 >= 3) {
mc = 4;
nc = 3;
gemm<4, 3>(m0, m, n0, n);
} else {
mc = 1;
nc = 1;
gemm<1, 1>(m0, m, n0, n);
}
mp = m0 + (m - m0) / mc * mc;
np = n0 + (n - n0) / nc * nc;
mnpack(mp, m, n0, np);
mnpack(m0, m, np, n);
}
template <int RM, int RN>
MATH void gemm(int m0, int m, int n0, int n) {
int ytiles = (m - m0) / RM;
int xtiles = (n - n0) / RN;
int tiles = xtiles * ytiles;
int duty = (tiles + nth - 1) / nth;
int start = duty * ith;
int end = start + duty;
if (end > tiles)
end = tiles;
for (int job = start; job < end; ++job) {
int ii = m0 + job / xtiles * RM;
int jj = n0 + job % xtiles * RN;
Vector Cv[RN][RM] = {};
for (int l = 0; l < k; l += KN)
for (int j = 0; j < RN; ++j)
for (int i = 0; i < RM; ++i)
Cv[j][i] = madd(load(A + lda * (ii + i) + l), //
load(B + ldb * (jj + j) + l), //
Cv[j][i]);
for (int j = 0; j < RN; ++j)
for (int i = 0; i < RM; ++i)
C[ldc * (jj + j) + (ii + i)] = hsum(Cv[j][i]);
}
}
const int k;
const float *const A;
const int lda;
const float *const B;
const int ldb;
float *const C;
const int ldc;
const int ith;
const int nth;
};
void sgemm(int m, int n, int k, //
const float *A, int lda, //
const float *B, int ldb, //
float *C, int ldc) {
int nth = sysconf(_SC_NPROCESSORS_ONLN);
#pragma omp parallel for
for (int ith = 0; ith < nth; ++ith) {
ansiBLAS tb{k, A, lda, B, ldb, C, ldc, ith, nth};
tb.matmul(m, n);
}
}
} // namespace ansiBLAS
long micros(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 1000000 + (ts.tv_nsec + 999) / 1000;
}
unsigned rand32(void) {
/* Knuth, D.E., "The Art of Computer Programming," Vol 2,
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
p. 106 (line 26) & p. 108 */
static unsigned long long lcg = 1;
lcg *= 6364136223846793005;
lcg += 1442695040888963407;
return lcg >> 32;
}
float float01(unsigned x) { // (0,1)
return 1.f / 8388608 * ((x >> 9) + .5f);
}
float numba(void) { // (-1,1)
return float01(rand32()) * 2 - 1;
}
void fill(int m, int n, float *A, int lda) {
for (int j = 0; j < n; ++j)
for (int i = 0; i < m; ++i)
A[lda * j + i] = numba();
}
float *new_matrix(int m, int n, int *lda) {
void *ptr = 0;
int b = 64 / sizeof(float);
*lda = (n + b - 1) & -b;
posix_memalign(&ptr, 4096, sizeof(float) * m * *lda);
return (float *)ptr;
}
} // namespace
void barrier(void) {
}
void (*pBarrier)(void) = barrier;
#define BENCH(x) \
do { \
x; \
int N = 10; \
long t1 = micros(); \
for (long i = 0; i < N; ++i) { \
pBarrier(); \
x; \
} \
long t2 = micros(); \
printf("%8" PRId64 " µs %s %g gigaflops\n", (t2 - t1 + N - 1) / N, #x, \
1e6 / ((t2 - t1 + N - 1) / N) * m * n * k * 2 * 1e-9); \
} while (0)
int main() {
int m = 1024;
int n = 1024;
int k = 1024;
int lda, ldb, ldc;
float *A = new_matrix(m, k, &lda);
float *B = new_matrix(n, k, &ldb);
float *C = new_matrix(n, m, &ldc);
fill(k, n, A, lda);
fill(k, m, B, ldb);
BENCH(ansiBLAS::sgemm(m, n, k, A, lda, B, ldb, C, ldc));
assert(C[0] == -0x1.20902ap+4);
assert(C[1] == -0x1.bf7726p+4);
free(C);
free(B);
free(A);
}

View file

@ -7,6 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
@ -26,6 +27,13 @@
* o//examples/crashreport.com
*/
int Divide(int x, int y) {
volatile int z = 0; // force creation of stack frame
return x / y + z;
}
int (*pDivide)(int, int) = Divide;
dontubsan int main(int argc, char *argv[]) {
kprintf("----------------\n");
kprintf(" THIS IS A TEST \n");
@ -34,12 +42,7 @@ dontubsan int main(int argc, char *argv[]) {
ShowCrashReports();
volatile double a = 0;
volatile double b = 23;
volatile double c = exp(b) / a;
(void)c;
volatile int x = 0;
volatile int y = 1 / x;
return y;
pDivide(1, 0);
pDivide(2, 0);
pDivide(3, 0);
}

View file

@ -7,6 +7,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
@ -18,6 +19,17 @@ void crash(long x0, long x1, long x2, //
void (*pCrash)(long, long, long, double, double, double) = crash;
int main(int argc, char *argv[]) {
// // by default we launch an addr2line subprocess to print backtraces
// // with line numbers. you can force it to use the embedded solution
// setenv("ADDR2LINE", "", true);
// // using a seccomp sandbox is another way to force embedded backtraces
// pledge("stdio", NULL);
// enable the crash reporting feature
ShowCrashReports();
// time to die
pCrash(1, 2, 3, NAN, NAN, NAN);
}

View file

@ -9,19 +9,30 @@
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/timezoneid.h"
#include "libc/nt/struct/timezoneinformation.h"
#include "libc/nt/time.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/struct/tm.h"
#include "libc/thread/threads.h"
#include "libc/time.h"
/**
* @fileoverview High performance ISO-8601 timestamp formatter.
*
* The strftime() function is very slow. This goes much faster.
* Consider using something like this instead for your loggers.
*/
char *GetTimestamp(void) {
int x;
struct timespec ts;
_Thread_local static long last;
_Thread_local static char s[27];
_Thread_local static struct tm tm;
thread_local static long last;
thread_local static char s[32];
thread_local static struct tm tm;
clock_gettime(0, &ts);
if (ts.tv_sec != last) {
localtime_r(&ts.tv_sec, &tm);
@ -61,11 +72,21 @@ char *GetTimestamp(void) {
s[23] = '0' + x / 100000 % 10;
s[24] = '0' + x / 10000 % 10;
s[25] = '0' + x / 1000 % 10;
s[26] = tm.tm_gmtoff < 0 ? '-' : '+';
x = ABS(tm.tm_gmtoff) / 60 / 60;
s[27] = '0' + x / 10 % 10;
s[28] = '0' + x % 10;
x = ABS(tm.tm_gmtoff) / 60 % 60;
s[29] = '0' + x / 10 % 10;
s[30] = '0' + x % 10;
return s;
}
int main(int argc, char *argv[]) {
char buf[128], *p = buf;
// setenv("TZ", "UTC", true);
// setenv("TZ", "US/Eastern", true);
// setenv("TZ", "Asia/Kolkata", true);
p = stpcpy(p, GetTimestamp());
p = stpcpy(p, "\n");
write(1, buf, p - buf);

View file

@ -1,9 +1,9 @@
#include "libc/stdio/stdio.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
int main(int argc, char* argv[]) {
fprintf(stderr, "%s (%s)\n", argv[0], GetProgramExecutableName());
for (char **p = environ; *p; ++p) {
for (char** p = environ; *p; ++p) {
printf("%s\n", *p);
}
return 0;

View file

@ -104,8 +104,10 @@ void *Worker(void *id) {
if (client == -1) {
// accept() errors are generally ephemeral or recoverable
// it'd potentially be a good idea to exponential backoff here
if (errno == ECANCELED) continue; // pthread_cancel() was called
if (errno == EMFILE) ExplainPrlimit();
if (errno == ECANCELED)
continue; // pthread_cancel() was called
if (errno == EMFILE)
ExplainPrlimit();
LOG("accept() returned %m");
SomethingHappened();
continue;
@ -149,7 +151,7 @@ void *Worker(void *id) {
// check that client message wasn't fragmented into more reads
InitHttpMessage(&msg, kHttpRequest);
if ((inmsglen = ParseHttpMessage(&msg, buf, got)) <= 0) {
if ((inmsglen = ParseHttpMessage(&msg, buf, got, sizeof(buf))) <= 0) {
if (!inmsglen) {
LOG("%6H client sent fragmented message");
} else {
@ -346,8 +348,10 @@ int main(int argc, char *argv[]) {
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
--a_workers;
kprintf("pthread_create failed: %s\n", strerror(rc));
if (rc == EAGAIN) ExplainPrlimit();
if (!i) exit(1);
if (rc == EAGAIN)
ExplainPrlimit();
if (!i)
exit(1);
threads = i;
break;
}
@ -364,7 +368,8 @@ int main(int argc, char *argv[]) {
PrintEphemeralStatusLine();
unassert(!pthread_cond_wait(&statuscond, &statuslock));
// limit status line updates to sixty frames per second
do tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
do
tick = timespec_add(tick, (struct timespec){0, 1e9 / 60});
while (timespec_cmp(tick, timespec_real()) < 0);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, 0);
}
@ -378,7 +383,8 @@ int main(int argc, char *argv[]) {
}
// on windows this is the only way accept() can be canceled
if (IsWindows()) close(server);
if (IsWindows())
close(server);
// print status in terminal as the shutdown progresses
unassert(!pthread_mutex_lock(&statuslock));
@ -394,7 +400,8 @@ int main(int argc, char *argv[]) {
}
// close the server socket
if (!IsWindows()) close(server);
if (!IsWindows())
close(server);
// clean up terminal line
LOG("thank you for choosing \e[32mgreenbean\e[0m");

View file

@ -42,7 +42,7 @@
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "third_party/zlib/zlib.h"
// clang-format off

View file

@ -7,11 +7,11 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/runtime/runtime.h"
#include "third_party/hiredis/hiredis.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "third_party/hiredis/hiredis.h"
/**
* @fileoverview Demo of using hiredis to connect to a Redis server

View file

@ -71,7 +71,7 @@ Contact: antirez@gmail.com");
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "libc/time.h"
/* Syntax highlight types */
#define HL_NORMAL 0
@ -212,10 +212,13 @@ void editorAtExit(void) {
int enableRawMode(int64_t fd) {
struct termios raw;
if (E.rawmode) return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO)) goto fatal;
if (E.rawmode)
return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO))
goto fatal;
atexit(editorAtExit);
if (tcgetattr(fd, &orig_termios) == -1) goto fatal;
if (tcgetattr(fd, &orig_termios) == -1)
goto fatal;
raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char,
@ -233,7 +236,8 @@ int enableRawMode(int64_t fd) {
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal;
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
goto fatal;
E.rawmode = 1;
return 0;
@ -249,7 +253,8 @@ int editorReadKey(int64_t fd) {
char c, seq[3];
do {
nread = read(fd, &c, 1);
if (nread == -1) exit(1);
if (nread == -1)
exit(1);
} while (!nread);
while (1) {
@ -260,12 +265,15 @@ int editorReadKey(int64_t fd) {
return PAGE_DOWN;
case '\e': /* escape sequence */
/* If this is just an ESC, we'll timeout here. */
if (read(fd, seq, 1) == 0) return CTRL('[');
if (read(fd, seq, 1) == 0)
return CTRL('[');
if (seq[0] == '[') {
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */
if (read(fd, seq + 2, 1) == 0) return CTRL('[');
if (read(fd, seq + 2, 1) == 0)
return CTRL('[');
if (seq[2] == '~') {
switch (seq[1]) {
case '1':
@ -308,7 +316,8 @@ int editorReadKey(int64_t fd) {
} else if (seq[0] == 'v') {
return PAGE_UP;
} else if (seq[0] == 'O') {
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
if (read(fd, seq + 1, 1) == 0)
return CTRL('[');
/* ESC O sequences. */
switch (seq[1]) {
case 'H':
@ -332,19 +341,24 @@ int getCursorPosition(int64_t ifd, int64_t ofd, int *rows, int *cols) {
unsigned i = 0;
/* Report cursor location */
if (write(ofd, "\e[6n", 4) != 4) return -1;
if (write(ofd, "\e[6n", 4) != 4)
return -1;
/* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf) - 1) {
if (read(ifd, buf + i, 1) != 1) break;
if (buf[i] == 'R') break;
if (read(ifd, buf + i, 1) != 1)
break;
if (buf[i] == 'R')
break;
i++;
}
buf[i] = '\0';
/* Parse it. */
if (buf[0] != CTRL('[') || buf[1] != '[') return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2) return -1;
if (buf[0] != CTRL('[') || buf[1] != '[')
return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
return -1;
return 0;
}
@ -359,12 +373,15 @@ int getWindowSize(int64_t ifd, int64_t ofd, int *rows, int *cols) {
/* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
if (retval == -1) goto failed;
if (retval == -1)
goto failed;
/* Go to right/bottom margin and get position. */
if (write(ofd, "\e[999C\e[999B", 12) != 12) goto failed;
if (write(ofd, "\e[999C\e[999B", 12) != 12)
goto failed;
retval = getCursorPosition(ifd, ofd, rows, cols);
if (retval == -1) goto failed;
if (retval == -1)
goto failed;
/* Restore position. */
char seq[32];
@ -406,7 +423,8 @@ void editorUpdateSyntax(erow *row) {
row->hl = realloc(row->hl, row->rsize);
memset(row->hl, HL_NORMAL, row->rsize);
if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */
if (E.syntax == NULL)
return; /* No syntax, everything is HL_NORMAL. */
int i, prev_sep, in_string, in_comment;
char *p;
@ -475,7 +493,8 @@ void editorUpdateSyntax(erow *row) {
prev_sep = 0;
continue;
}
if (*p == in_string) in_string = 0;
if (*p == in_string)
in_string = 0;
p++;
i++;
continue;
@ -515,7 +534,8 @@ void editorUpdateSyntax(erow *row) {
for (j = 0; keywords[j]; j++) {
int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen - 1] == '|';
if (kw2) klen--;
if (kw2)
klen--;
if (!memcmp(p, keywords[j], klen) && is_separator(*(p + klen))) {
/* Keyword */
@ -599,7 +619,8 @@ void editorUpdateRow(erow *row) {
* respecting tabs, substituting non printable characters with '?'. */
free(row->render);
for (j = 0; j < row->size; j++) {
if (row->chars[j] == '\t') tabs++;
if (row->chars[j] == '\t')
tabs++;
}
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
@ -626,11 +647,13 @@ void editorUpdateRow(erow *row) {
/* Insert a row at the specified position, shifting the other rows on the bottom
* if required. */
void editorInsertRow(int at, char *s, size_t len) {
if (at > E.numrows) return;
if (at > E.numrows)
return;
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
if (at != E.numrows) {
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
for (int j = at + 1; j <= E.numrows; j++) E.row[j].idx++;
for (int j = at + 1; j <= E.numrows; j++)
E.row[j].idx++;
}
E.row[at].size = len;
E.row[at].chars = malloc(len + 1);
@ -657,11 +680,13 @@ void editorFreeRow(erow *row) {
void editorDelRow(int at) {
erow *row;
if (at >= E.numrows) return;
if (at >= E.numrows)
return;
row = E.row + at;
editorFreeRow(row);
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
for (int j = at; j < E.numrows - 1; j++) E.row[j].idx++;
for (int j = at; j < E.numrows - 1; j++)
E.row[j].idx++;
E.numrows--;
E.dirty++;
}
@ -729,7 +754,8 @@ void editorRowAppendString(erow *row, char *s, size_t len) {
/* Delete the character at offset 'at' from the specified row. */
void editorRowDelChar(erow *row, int at) {
if (row->size <= at) return;
if (row->size <= at)
return;
memmove(row->chars + at, row->chars + at + 1, row->size - at);
editorUpdateRow(row);
row->size--;
@ -745,7 +771,8 @@ void editorInsertChar(int c) {
/* If the row where the cursor is currently located does not exist in our
* logical representation of the file, add enough empty rows as needed. */
if (!row) {
while (E.numrows <= filerow) editorInsertRow(E.numrows, "", 0);
while (E.numrows <= filerow)
editorInsertRow(E.numrows, "", 0);
}
row = &E.row[filerow];
editorRowInsertChar(row, filecol, c);
@ -773,7 +800,8 @@ void editorInsertNewline(void) {
}
/* If the cursor is over the current line size, we want to conceptually
* think it's just over the last character. */
if (filecol >= row->size) filecol = row->size;
if (filecol >= row->size)
filecol = row->size;
if (filecol == 0) {
editorInsertRow(filerow, "", 0);
} else {
@ -800,7 +828,8 @@ void editorDelChar(void) {
int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row || (filecol == 0 && filerow == 0)) return;
if (!row || (filecol == 0 && filerow == 0))
return;
if (filecol == 0) {
/* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */
@ -825,7 +854,8 @@ void editorDelChar(void) {
else
E.cx--;
}
if (row) editorUpdateRow(row);
if (row)
editorUpdateRow(row);
E.dirty++;
}
@ -868,12 +898,15 @@ int editorSave(void) {
int len;
char *buf = editorRowsToString(&len);
int64_t fd = open(E.filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) goto writeerr;
if (fd == -1)
goto writeerr;
/* Use truncate + a single write(2) call in order to make saving
* a bit safer, under the limits of what we can do in a small editor. */
if (ftruncate(fd, len) == -1) goto writeerr;
if (write(fd, buf, len) != len) goto writeerr;
if (ftruncate(fd, len) == -1)
goto writeerr;
if (write(fd, buf, len) != len)
goto writeerr;
close(fd);
free(buf);
@ -883,7 +916,8 @@ int editorSave(void) {
writeerr:
free(buf);
if (fd != -1) close(fd);
if (fd != -1)
close(fd);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return 1;
}
@ -924,7 +958,8 @@ void editorRefreshScreen(void) {
abAppend(&ab, "~", 1);
padding--;
}
while (padding--) abAppend(&ab, " ", 1);
while (padding--)
abAppend(&ab, " ", 1);
abAppend(&ab, welcome, welcomelen);
} else {
abAppend(&ab, "~\e[0K\r\n", 7);
@ -939,7 +974,8 @@ void editorRefreshScreen(void) {
int current_color = -1;
#endif
if (len > 0) {
if (len > E.screencols) len = E.screencols;
if (len > E.screencols)
len = E.screencols;
char *c = r->render + E.coloff;
#if SYNTAX
unsigned char *hl = r->hl + E.coloff;
@ -990,7 +1026,8 @@ void editorRefreshScreen(void) {
E.numrows, E.dirty ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d", E.rowoff + E.cy + 1,
E.numrows);
if (len > E.screencols) len = E.screencols;
if (len > E.screencols)
len = E.screencols;
abAppend(&ab, status, len);
while (len < E.screencols) {
if (E.screencols - len == rlen) {
@ -1018,7 +1055,8 @@ void editorRefreshScreen(void) {
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (row) {
for (j = E.coloff; j < (E.cx + E.coloff); j++) {
if (j < row->size && row->chars[j] == CTRL('I')) cx += 7 - ((cx) % 8);
if (j < row->size && row->chars[j] == CTRL('I'))
cx += 7 - ((cx) % 8);
cx++;
}
}
@ -1069,7 +1107,8 @@ void editorFind(int64_t fd) {
int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL('H') || c == CTRL('?')) {
if (qlen != 0) query[--qlen] = '\0';
if (qlen != 0)
query[--qlen] = '\0';
last_match = -1;
} else if (c == CTRL('G')) {
break;
@ -1096,7 +1135,8 @@ void editorFind(int64_t fd) {
}
/* Search occurrence. */
if (last_match == -1) find_next = 1;
if (last_match == -1)
find_next = 1;
if (find_next) {
char *match = NULL;
int match_offset = 0;
@ -1190,7 +1230,8 @@ void editorMoveCursor(int key) {
break;
case ARROW_UP:
if (E.cy == 0) {
if (E.rowoff) E.rowoff--;
if (E.rowoff)
E.rowoff--;
} else {
E.cy -= 1;
}
@ -1299,9 +1340,11 @@ void editorProcessKeypress(int64_t fd) {
case CTRL('L'):
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break;
case PAGE_UP:
@ -1312,14 +1355,17 @@ void editorProcessKeypress(int64_t fd) {
E.cy = E.screenrows - 1;
}
times = E.screenrows;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break;
case HOME_KEY:
case CTRL('A'):
while (E.cx || E.coloff) editorMoveCursor(ARROW_LEFT);
while (E.cx || E.coloff)
editorMoveCursor(ARROW_LEFT);
break;
case END_KEY:
case CTRL('E'):

15
examples/localtime.c Normal file
View file

@ -0,0 +1,15 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/time.h"
int main(int argc, char *argv[]) {
int64_t t = 0;
localtime(&t);
}

View file

@ -44,7 +44,7 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "libc/x/xasprintf.h"
#include "libc/x/xsigaction.h"
#include "libc/zip.internal.h"
@ -492,7 +492,8 @@ void TransmitVideo(void) {
ssize_t rc;
struct Frame* f;
f = &vf_[frame_];
if (!HasVideo(f)) f = FlipFrameBuffer();
if (!HasVideo(f))
f = FlipFrameBuffer();
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
f->w += rc;
} else if (errno == EAGAIN) {
@ -504,9 +505,12 @@ void TransmitVideo(void) {
void TransmitAudio(void) {
ssize_t rc;
if (!playpid_) return;
if (!audio_.i) return;
if (playfd_ == -1) return;
if (!playpid_)
return;
if (!audio_.i)
return;
if (playfd_ == -1)
return;
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
rc /= sizeof(short);
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
void PollAndSynchronize(void) {
do {
if (ReadKeyboard() == -1) {
if (errno != EINTR) Exit(1);
if (exited_) Exit(0);
if (resized_) GetTermSize();
if (errno != EINTR)
Exit(1);
if (exited_)
Exit(0);
if (resized_)
GetTermSize();
}
} while (!timeout_);
TransmitVideo();
@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
}
}
}
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF];
if ((addr >> 13) == 3)
return PRAM[addr & 0x1FFF];
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
}
@ -828,7 +836,8 @@ bool offset_toggle = false;
u8& NesMmap(int i) {
i &= 0x3FFF;
if (i >= 0x3F00) {
if (i % 4 == 0) i &= 0x0F;
if (i % 4 == 0)
i &= 0x0F;
return palette[i & 0x1F];
}
if (i < 0x2000) {
@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
return open_bus_decay_timer = 77777, open_bus = v;
};
u8 res = open_bus;
if (write) RefreshOpenBus(v);
if (write)
RefreshOpenBus(v);
switch (index) { // Which port from $200x?
case 0:
if (write) {
@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 2:
if (write) break;
if (write)
break;
res = reg.status | (open_bus & 0x1F);
reg.InVBlank = false; // Reading $2002 clears the vblank flag.
offset_toggle = false; // Also resets the toggle for address updates.
@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 3:
if (write) reg.OAMaddr = v;
if (write)
reg.OAMaddr = v;
break; // Index into Object Attribute Memory
case 4:
if (write) {
@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
}
break;
case 5:
if (!write) break; // Set background scrolling offset
if (!write)
break; // Set background scrolling offset
if (offset_toggle) {
scroll.yfine = v & 7;
scroll.ycoarse = v >> 3;
@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
offset_toggle = !offset_toggle;
break;
case 6:
if (!write) break; // Set video memory position for reads/writes
if (!write)
break; // Set video memory position for reads/writes
if (offset_toggle) {
scroll.vaddrlo = v;
vaddr.raw = (unsigned)scroll.raw;
@ -926,17 +940,21 @@ void RenderingTick() {
case 2: // Point to attribute table
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
(vaddr.xcoarse / 4);
if (tile_decode_mode) break; // Or nametable, with sprites.
case 0: // Point to nametable
if (tile_decode_mode)
break; // Or nametable, with sprites.
case 0: // Point to nametable
ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
// Reset sprite data
if (x_ == 0) {
sprinpos = sproutpos = 0;
if (reg.ShowSP) reg.OAMaddr = 0;
if (reg.ShowSP)
reg.OAMaddr = 0;
}
if (!reg.ShowBG) break;
if (!reg.ShowBG)
break;
// Reset scrolling (vertical once, horizontal each scanline)
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw;
if (x_ == 304 && scanline == -1)
vaddr.raw = (unsigned)scroll.raw;
if (x_ == 256) {
vaddr.xcoarse = (unsigned)scroll.xcoarse;
vaddr.basenta_h = (unsigned)scroll.basenta_h;
@ -949,7 +967,8 @@ void RenderingTick() {
}
// Name table access
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
if (!tile_decode_mode) break;
if (!tile_decode_mode)
break;
// Push the current tile into shift registers.
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
// 8 times.
@ -976,7 +995,8 @@ void RenderingTick() {
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
memcpy(&o, &OAM2[sprrenpos], sizeof(o));
unsigned y = (scanline)-o.y;
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7);
if (o.attr & 0x80)
y ^= (reg.SPsize ? 15 : 7);
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
pat_addr += (y & 7) + (y & 8) * 2;
@ -1011,8 +1031,10 @@ void RenderingTick() {
break;
}
++sprinpos; // next sprite
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex;
if (sproutpos < 8)
OAM2[sproutpos].y = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].sprindex = reg.OAMindex;
y1 = sprtmp;
y2 = sprtmp + (reg.SPsize ? 16 : 8);
if (!(scanline >= y1 && scanline < y2)) {
@ -1020,19 +1042,23 @@ void RenderingTick() {
}
break;
case 1:
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].index = sprtmp;
break;
case 2:
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].attr = sprtmp;
break;
case 3:
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8)
OAM2[sproutpos].x_ = sprtmp;
if (sproutpos < 8) {
++sproutpos;
} else {
reg.SPoverflow = true;
}
if (sprinpos == 2) reg.OAMaddr = 8;
if (sprinpos == 2)
reg.OAMaddr = 8;
break;
}
}
@ -1060,13 +1086,17 @@ void RenderPixel() {
auto& s = OAM3[sno];
// Check if this sprite is horizontally in range
unsigned xdiff = x_ - s.x_;
if (xdiff >= 8) continue; // Also matches negative values
if (xdiff >= 8)
continue; // Also matches negative values
// Determine which pixel to display; skip transparent pixels
if (!(s.attr & 0x40)) xdiff = 7 - xdiff;
if (!(s.attr & 0x40))
xdiff = 7 - xdiff;
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
if (!spritepixel) continue;
if (!spritepixel)
continue;
// Register sprite-0 hit if applicable
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true;
if (x_ < 255 && pixel && s.sprindex == 0)
reg.SP0hit = true;
// Render the pixel unless behind-background placement wanted
if (!(s.attr & 0x20) || !pixel) {
attr = (s.attr & 3) + 4;
@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
}
if (ctrlmask & 0x80) {
joy_next_[0] = fgetc(fp);
if (feof(fp)) joy_next_[0] = 0;
if (feof(fp))
joy_next_[0] = 0;
}
if (ctrlmask & 0x40) {
joy_next_[1] = fgetc(fp);
if (feof(fp)) joy_next_[1] = 0;
if (feof(fp))
joy_next_[1] = 0;
}
}
}
@ -1144,18 +1176,23 @@ void Tick() {
CPU::nmi = reg.InVBlank && reg.NMIenabled;
break;
}
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0;
if (VBlankState != 0)
VBlankState += (VBlankState < 0 ? 1 : -1);
if (open_bus_decay_timer && !--open_bus_decay_timer)
open_bus = 0;
// Graphics processing scanline?
if (scanline < DYN) {
/* Process graphics for this cycle */
if (reg.ShowBGSP) RenderingTick();
if (scanline >= 0 && x_ < 256) RenderPixel();
if (reg.ShowBGSP)
RenderingTick();
if (scanline >= 0 && x_ < 256)
RenderPixel();
}
// Done with the cycle. Check for end of scanline.
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting
if (++cycle_counter == 3)
cycle_counter = 0; // For NTSC pixel shifting
if (++x_ >= scanline_end) {
// Begin new scanline
FlushScanline(scanline);
@ -1242,30 +1279,36 @@ struct channel {
template <unsigned c>
int Tick() {
channel& ch = *this;
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8;
if (!ChannelsEnabled[c])
return c == 4 ? 64 : 8;
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq];
if (c == 3)
wl = NoisePeriods[ch.reg.NoiseFreq];
int volume = ch.length_counter
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
: 0;
// Sample may change at wavelen intervals.
auto& S = ch.level;
if (!count(ch.wave_counter, wl)) return S;
if (!count(ch.wave_counter, wl))
return S;
switch (c) {
default: // Square wave. With four different 8-step binary waveforms (32
// bits of data total).
if (wl < 8) return S = 8;
if (wl < 8)
return S = 8;
return S = (0xF33C0C04u &
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
? volume
: 0;
case 2: // Triangle wave
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase;
if (ch.length_counter && ch.linear_counter && wl >= 3)
++ch.phase;
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
case 3: // Noise: Linear feedback shift register
if (!ch.hold) ch.hold = 1;
if (!ch.hold)
ch.hold = 1;
ch.hold =
(ch.hold >> 1) |
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
@ -1302,7 +1345,8 @@ struct channel {
} else {
v -= 2;
}
if (v >= 0 && v <= 0x7F) ch.linear_counter = v;
if (v >= 0 && v <= 0x7F)
ch.linear_counter = v;
}
return S = ch.linear_counter;
}
@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
ch.linear_counter = ch.reg.LinearCounterInit;
ch.env_delay = ch.reg.EnvDecayRate;
ch.envelope = 15;
if (index < 8) ch.phase = 0;
if (index < 8)
ch.phase = 0;
break;
case 0x10:
ch.reg.reg3 = value;
@ -1384,9 +1429,11 @@ u8 Read() {
for (c = 0; c < 5; ++c) {
res |= channels[c].length_counter ? 1 << c : 0;
}
if (PeriodicIRQ) res |= 0x40;
if (PeriodicIRQ)
res |= 0x40;
PeriodicIRQ = false;
if (DMC_IRQ) res |= 0x80;
if (DMC_IRQ)
res |= 0x80;
DMC_IRQ = false;
CPU::intr = false;
return res;
@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
if ((hz240counter.lo += 2) >= 14915) {
hz240counter.lo -= 14915;
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0;
if (++hz240counter.hi >= 4 + FiveCycleDivider)
hz240counter.hi = 0;
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
wl += d[ch.reg.SweepDecrease * 2 + c];
if (wl < 0x800) ch.reg.WaveLength = wl;
if (wl < 0x800)
ch.reg.WaveLength = wl;
}
// Linear tick (triangle wave only)
@ -1464,20 +1513,24 @@ namespace CPU {
void Tick() {
// PPU clock: 3 times the CPU rate
for (unsigned n = 0; n < 3; ++n) PPU::Tick();
for (unsigned n = 0; n < 3; ++n)
PPU::Tick();
// APU clock: 1 times the CPU rate
for (unsigned n = 0; n < 1; ++n) APU::Tick();
for (unsigned n = 0; n < 1; ++n)
APU::Tick();
}
template <bool write>
u8 MemAccess(u16 addr, u8 v) {
// Memory writes are turned into reads while reset is being signalled
if (reset && write) return MemAccess<0>(addr);
if (reset && write)
return MemAccess<0>(addr);
Tick();
// Map the memory from CPU's viewpoint.
/**/ if (addr < 0x2000) {
u8& r = RAM[addr & 0x7FF];
if (!write) return r;
if (!write)
return r;
r = v;
} else if (addr < 0x4000) {
return PPU::PpuAccess(addr & 7, v, write);
@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
WB(0x2004, RB((v & 7) * 0x0100 + b));
return 0;
case 0x15:
if (!write) return APU::Read();
if (!write)
return APU::Read();
APU::Write(0x15, v);
break;
case 0x16:
if (!write) return JoyRead(0);
if (!write)
return JoyRead(0);
JoyStrobe(v);
break;
case 0x17:
if (!write) return JoyRead(1); // write:passthru
if (!write)
return JoyRead(1); // write:passthru
default:
if (!write) break;
if (!write)
break;
APU::Write(addr & 0x1F, v);
}
} else {
@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
}
void Misfire(u16 old, u16 addr) {
u16 q = wrap(old, addr);
if (q != addr) RB(q);
if (q != addr)
RB(q);
}
u8 Pop() {
return RB(0x100 | u8(++S));
@ -1655,7 +1713,8 @@ void Op() {
} else if (intr && !P.I) {
op = 0x102;
}
if (!nmi_now) nmi_edge_detected = false;
if (!nmi_now)
nmi_edge_detected = false;
// Define function pointers for each opcode (00..FF) and each interrupt
// (100,101,102)
@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
fgetc(fp);
fgetc(fp);
if (mappernum >= 0x40) mappernum &= 15;
if (mappernum >= 0x40)
mappernum &= 15;
GamePak::mappernum = mappernum;
// Read the ROM data
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000);
if (rom16count)
GamePak::ROM.resize(rom16count * 0x4000);
if (vrom8count)
GamePak::VRAM.resize(vrom8count * 0x2000);
fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
PPU::reg.value = 0;
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
for (unsigned a = 0; a < 0x800; ++a)
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
// Run the CPU until the program is killed.
for (;;) CPU::Op();
for (;;)
CPU::Op();
}
wontreturn void PrintUsage(int rc, FILE* f) {

View file

@ -42,6 +42,7 @@ EXAMPLES_PACKAGE_OBJS = \
EXAMPLES_PACKAGE_DIRECTDEPS = \
EXAMPLES_PACKAGE_LIB \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STDIO \
LIBC_TINYMATH

View file

@ -71,6 +71,7 @@ EXAMPLES_PACKAGE_LIB_A_CHECKS = \
EXAMPLES_PACKAGE_LIB_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_MEM \
LIBC_STDIO
# Evaluates variable as set of transitive package dependencies.

View file

@ -1,31 +1,31 @@
#include <stdio.h>
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
do { \
type val; int ret; \
ret = sscanf(str, scan_fmt, &val); \
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
do { \
type val; \
int ret; \
ret = sscanf(str, scan_fmt, &val); \
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
} while (0)
int main()
{
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
PARSE_AND_PRINT(float, "%f", "%f", "3715");
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
PARSE_AND_PRINT(float, "%f", "%f", "inF");
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
PARSE_AND_PRINT(float, "%f", "%f", "junk");
return 0;
int main() {
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
PARSE_AND_PRINT(float, "%f", "%f", "3715");
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
PARSE_AND_PRINT(float, "%f", "%f", "inF");
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
PARSE_AND_PRINT(float, "%f", "%f", "junk");
return 0;
}

View file

@ -123,14 +123,16 @@ int picolParseCommand(struct picolParser *p) {
} else if (*p->p == '[' && blevel == 0) {
level++;
} else if (*p->p == ']' && blevel == 0) {
if (!--level) break;
if (!--level)
break;
} else if (*p->p == '\\') {
p->p++;
p->len--;
} else if (*p->p == '{') {
blevel++;
} else if (*p->p == '}') {
if (blevel != 0) blevel--;
if (blevel != 0)
blevel--;
}
p->p++;
p->len--;
@ -270,11 +272,13 @@ int picolGetToken(struct picolParser *p) {
case ' ':
case '\t':
case '\r':
if (p->insidequote) return picolParseString(p);
if (p->insidequote)
return picolParseString(p);
return picolParseSep(p);
case '\n':
case ';':
if (p->insidequote) return picolParseString(p);
if (p->insidequote)
return picolParseString(p);
return picolParseEol(p);
case '[':
return picolParseCommand(p);
@ -310,7 +314,8 @@ void picolSetResult(struct picolInterp *i, char *s) {
struct picolVar *picolGetVar(struct picolInterp *i, char *name) {
struct picolVar *v = i->callframe->vars;
while (v) {
if (strcmp(v->name, name) == 0) return v;
if (strcmp(v->name, name) == 0)
return v;
v = v->next;
}
return NULL;
@ -334,7 +339,8 @@ int picolSetVar(struct picolInterp *i, char *name, char *val) {
struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) {
struct picolCmd *c = i->commands;
while (c) {
if (strcmp(c->name, name) == 0) return c;
if (strcmp(c->name, name) == 0)
return c;
c = c->next;
}
return NULL;
@ -372,9 +378,11 @@ int picolEval(struct picolInterp *i, char *t) {
int tlen;
int prevtype = p.type;
picolGetToken(&p);
if (p.type == PT_EOF) break;
if (p.type == PT_EOF)
break;
tlen = p.end - p.start + 1;
if (tlen < 0) tlen = 0;
if (tlen < 0)
tlen = 0;
t = malloc(tlen + 1);
memcpy(t, p.start, tlen);
t[tlen] = '\0';
@ -392,7 +400,8 @@ int picolEval(struct picolInterp *i, char *t) {
} else if (p.type == PT_CMD) {
retcode = picolEval(i, t);
free(t);
if (retcode != PICOL_OK) goto err;
if (retcode != PICOL_OK)
goto err;
t = strdup(i->result);
} else if (p.type == PT_ESC) {
/* XXX: escape handling missing! */
@ -414,10 +423,12 @@ int picolEval(struct picolInterp *i, char *t) {
goto err;
}
retcode = c->func(i, argc, argv, c->privdata);
if (retcode != PICOL_OK) goto err;
if (retcode != PICOL_OK)
goto err;
}
/* Prepare for the next command */
for (j = 0; j < argc; j++) free(argv[j]);
for (j = 0; j < argc; j++)
free(argv[j]);
free(argv);
argv = NULL;
argc = 0;
@ -438,7 +449,8 @@ int picolEval(struct picolInterp *i, char *t) {
prevtype = p.type;
}
err:
for (j = 0; j < argc; j++) free(argv[j]);
for (j = 0; j < argc; j++)
free(argv[j]);
free(argv);
return retcode;
}
@ -454,7 +466,8 @@ int picolArityErr(struct picolInterp *i, char *name) {
int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
char buf[64];
int a, b, c;
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
a = atoi(argv[1]);
b = atoi(argv[2]);
if (argv[0][0] == '+')
@ -485,22 +498,26 @@ int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) {
}
int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
picolSetVar(i, argv[1], argv[2]);
picolSetResult(i, argv[2]);
return PICOL_OK;
}
int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 2) return picolArityErr(i, argv[0]);
if (argc != 2)
return picolArityErr(i, argv[0]);
printf("%s\n", argv[1]);
return PICOL_OK;
}
int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
int retcode;
if (argc != 3 && argc != 5) return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK) return retcode;
if (argc != 3 && argc != 5)
return picolArityErr(i, argv[0]);
if ((retcode = picolEval(i, argv[1])) != PICOL_OK)
return retcode;
if (atoi(i->result))
return picolEval(i, argv[2]);
else if (argc == 5)
@ -509,10 +526,12 @@ int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) {
}
int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 3) return picolArityErr(i, argv[0]);
if (argc != 3)
return picolArityErr(i, argv[0]);
while (1) {
int retcode = picolEval(i, argv[1]);
if (retcode != PICOL_OK) return retcode;
if (retcode != PICOL_OK)
return retcode;
if (atoi(i->result)) {
if ((retcode = picolEval(i, argv[2])) == PICOL_CONTINUE)
continue;
@ -530,7 +549,8 @@ int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) {
int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv,
void *pd) {
if (argc != 1) return picolArityErr(i, argv[0]);
if (argc != 1)
return picolArityErr(i, argv[0]);
if (strcmp(argv[0], "break") == 0)
return PICOL_BREAK;
else if (strcmp(argv[0], "continue") == 0)
@ -564,25 +584,31 @@ int picolCommandCallProc(struct picolInterp *i, int argc, char **argv,
tofree = p;
while (1) {
char *start = p;
while (*p != ' ' && *p != '\0') p++;
while (*p != ' ' && *p != '\0')
p++;
if (*p != '\0' && p == start) {
p++;
continue;
}
if (p == start) break;
if (p == start)
break;
if (*p == '\0')
done = 1;
else
*p = '\0';
if (++arity > argc - 1) goto arityerr;
if (++arity > argc - 1)
goto arityerr;
picolSetVar(i, start, argv[arity]);
p++;
if (done) break;
if (done)
break;
}
free(tofree);
if (arity != argc - 1) goto arityerr;
if (arity != argc - 1)
goto arityerr;
errcode = picolEval(i, body);
if (errcode == PICOL_RETURN) errcode = PICOL_OK;
if (errcode == PICOL_RETURN)
errcode = PICOL_OK;
picolDropCallFrame(i); /* remove the called proc callframe */
return errcode;
arityerr:
@ -594,14 +620,16 @@ arityerr:
int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) {
char **procdata = malloc(sizeof(char *) * 2);
if (argc != 4) return picolArityErr(i, argv[0]);
if (argc != 4)
return picolArityErr(i, argv[0]);
procdata[0] = strdup(argv[2]); /* arguments list */
procdata[1] = strdup(argv[3]); /* procedure body */
return picolRegisterCommand(i, argv[1], picolCommandCallProc, procdata);
}
int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) {
if (argc != 1 && argc != 2) return picolArityErr(i, argv[0]);
if (argc != 1 && argc != 2)
return picolArityErr(i, argv[0]);
picolSetResult(i, (argc == 2) ? argv[1] : "");
return PICOL_RETURN;
}
@ -631,9 +659,11 @@ int main(int argc, char **argv) {
int retcode;
printf("picol> ");
fflush(stdout);
if (fgets(clibuf, 1024, stdin) == NULL) return 0;
if (fgets(clibuf, 1024, stdin) == NULL)
return 0;
retcode = picolEval(&interp, clibuf);
if (interp.result[0] != '\0') printf("[%d] %s\n", retcode, interp.result);
if (interp.result[0] != '\0')
printf("[%d] %s\n", retcode, interp.result);
}
} else if (argc == 2) {
char buf[1024 * 16];
@ -644,7 +674,8 @@ int main(int argc, char **argv) {
}
buf[fread(buf, 1, 1024 * 16, fp)] = '\0';
fclose(fp);
if (picolEval(&interp, buf) != PICOL_OK) printf("%s\n", interp.result);
if (picolEval(&interp, buf) != PICOL_OK)
printf("%s\n", interp.result);
}
return 0;
}

View file

@ -23,7 +23,8 @@
int main(int argc, char *argv[]) {
const char *prog = argv[0];
if (!prog) prog = "rusage";
if (!prog)
prog = "rusage";
if (argc < 2) {
tinyprint(2, prog, ": missing command\n", NULL);

View file

@ -50,7 +50,7 @@
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "third_party/getopt/getopt.internal.h"
// clang-format off

View file

@ -17,7 +17,7 @@
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time/time.h"
#include "libc/time.h"
volatile bool gotalrm;

View file

@ -50,8 +50,10 @@ static char *Ithoa(char p[27], unsigned long x) {
} while (x);
for (;;) {
*p++ = m[--i];
if (!i) break;
if (!(i % 3)) *p++ = ',';
if (!i)
break;
if (!(i % 3))
*p++ = ',';
}
*p = '\0';
return p;

View file

@ -36,8 +36,10 @@ void Append(intptr_t i, char *s) {
int Compare(const void *a, const void *b) {
struct Thing *x = (struct Thing *)a;
struct Thing *y = (struct Thing *)b;
if (x->i < y->i) return +1;
if (x->i > y->i) return -1;
if (x->i < y->i)
return +1;
if (x->i > y->i)
return -1;
return 0;
}
@ -46,19 +48,22 @@ int main(int argc, char *argv[]) {
Append((uintptr_t)__oldstack, "__oldstack");
for (int i = 0;; ++i) {
Append((uintptr_t)&argv[i], xasprintf("&argv[%d] = %`'s", i, argv[i]));
if (!argv[i]) break;
if (!argv[i])
break;
Append((uintptr_t)argv[i], xasprintf("argv[%d] = %`'s", i, argv[i]));
}
for (int i = 0;; ++i) {
Append((uintptr_t)&environ[i],
xasprintf("&environ[%d] = %`'s", i, environ[i]));
if (!environ[i]) break;
if (!environ[i])
break;
Append((uintptr_t)environ[i],
xasprintf("environ[%d] = %`'s", i, environ[i]));
}
for (int i = 0;; i += 2) {
Append((uintptr_t)&__auxv[i], xasprintf("&auxv[%d] = %ld", i, __auxv[i]));
if (!__auxv[i]) break;
if (!__auxv[i])
break;
Append((uintptr_t)&__auxv[i + 1],
xasprintf("&auxv[%d] = %#lx", i + 1, __auxv[i + 1]));
}

View file

@ -8,16 +8,18 @@
*/
#endif
#include "libc/calls/struct/stat.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/x/xiso8601.h"
#include "libc/time.h"
/**
* @fileoverview File metadata viewer.
@ -27,6 +29,23 @@
bool numeric;
char *xiso8601(struct timespec ts) {
struct tm tm;
if (!localtime_r(&ts.tv_sec, &tm))
return 0;
int len = 128;
char *res = malloc(len);
char *ptr = res;
char *end = res + len;
if (!res)
return 0;
ptr += strftime(ptr, end - ptr, "%Y-%m-%d %H:%M:%S", &tm);
ptr += snprintf(ptr, end - ptr, ".%09ld", ts.tv_nsec);
ptr += strftime(ptr, end - ptr, "%z %Z", &tm);
unassert(ptr + 1 <= end);
return res;
}
const char *DescribeFileType(unsigned mode) {
switch (mode & S_IFMT) {
case S_IFIFO:
@ -74,16 +93,16 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
"%-32s%s\n"
"%-32s%s\n"
"%-32s%s\n",
"bytes in file", st->st_size, "physical bytes", st->st_blocks * 512,
"device id w/ file", st->st_dev, "inode", st->st_ino,
"hard link count", st->st_nlink, "mode / permissions", st->st_mode,
DescribeFileType(st->st_mode), "owner id", st->st_uid, "group id",
st->st_gid, "flags", st->st_flags, "gen", st->st_gen,
"device id (if special)", st->st_rdev, "block size", st->st_blksize,
"access time", gc(xiso8601(&st->st_atim)), "modified time",
gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
gc(xiso8601(&st->st_ctim)), "birthtime",
gc(xiso8601(&st->st_birthtim)));
"bytes in file:", st->st_size, "physical bytes:", st->st_blocks * 512,
"device id w/ file:", st->st_dev, "inode:", st->st_ino,
"hard link count:", st->st_nlink, "mode / permissions:", st->st_mode,
DescribeFileType(st->st_mode), "owner id:", st->st_uid,
"group id:", st->st_gid, "flags:", st->st_flags, "gen:", st->st_gen,
"device id (if special):", st->st_rdev, "block size:", st->st_blksize,
"access time:", gc(xiso8601(st->st_atim)),
"modified time:", gc(xiso8601(st->st_mtim)),
"c[omplicated]time:", gc(xiso8601(st->st_ctim)),
"[birthtime]:", gc(xiso8601(st->st_birthtim)));
}
int main(int argc, char *argv[]) {

142
examples/trapping.c Normal file
View file

@ -0,0 +1,142 @@
#include <fenv.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
#include "libc/calls/struct/aarch64.internal.h"
/*
Do you put lots of assert(!isnan(x)) in your code??
Your microprocessor has a feature to automate this.
Uncaught SIGFPE (FPE_FLTINV)
__math_invalidf at libc/tinymath/math_errf.c:88
logf at libc/tinymath/logf.c:100
main at examples/trapping.c:29
cosmo at libc/runtime/cosmo.S:105
_start at libc/crt/crt.S:116
This file shows how to use floating point exception
trapping with Cosmopolitan Libc.
*/
#define TRAPS (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
void spring_trap(int sig, siginfo_t *si, void *arg) {
// print signal safely
const char *msg;
int sic = si->si_code;
if (sic == FPE_INTDIV)
msg = "FPE_INTDIV: "; // integer divide by zero
else if (sic == FPE_INTOVF)
msg = "FPE_INTOVF: "; // integer overflow
else if (sic == FPE_FLTDIV)
msg = "FPE_FLTDIV: "; // floating point divide by zero
else if (sic == FPE_FLTOVF)
msg = "FPE_FLTOVF: "; // floating point overflow
else if (sic == FPE_FLTUND)
msg = "FPE_FLTUND: "; // floating point underflow
else if (sic == FPE_FLTRES)
msg = "FPE_FLTRES: "; // floating point inexact
else if (sic == FPE_FLTINV)
msg = "FPE_FLTINV: "; // invalid floating point operation
else if (sic == FPE_FLTSUB)
msg = "FPE_FLTSUB: "; // subscript out of range
else
msg = "SIGFPE: ";
write(1, msg, strlen(msg));
// recover from trap so that execution may resume
// without this the same signal will just keep getting raised
ucontext_t *ctx = arg;
#ifdef __x86_64__
if (ctx->uc_mcontext.fpregs) {
ctx->uc_mcontext.fpregs->mxcsr |= TRAPS << 7; // disable traps
ctx->uc_mcontext.fpregs->mxcsr &= ~TRAPS; // clear cages
return;
}
#elif defined(__aarch64__)
struct _aarch64_ctx *ac;
for (ac = (struct _aarch64_ctx *)ctx->uc_mcontext.__reserved; ac->magic;
ac = (struct _aarch64_ctx *)((char *)ac + ac->size)) {
if (ac->magic == FPSIMD_MAGIC) {
struct fpsimd_context *sm = (struct fpsimd_context *)ac;
sm->fpcr &= ~(TRAPS << 8); // disable traps
sm->fpsr &= ~TRAPS; // clear cages
return;
}
}
#endif
// exit if we can't recover execution
msg = "cannot recover from signal\n";
write(1, msg, strlen(msg));
_exit(1);
}
void setup_trap(void) {
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = spring_trap;
sigaction(SIGFPE, &sa, 0);
}
void activate_trap(void) {
feclearexcept(TRAPS);
if (feenableexcept(TRAPS)) {
static bool once;
if (!once) {
fprintf(stderr, "warning: trapping math isn't supported on this cpu\n");
once = true;
}
}
}
float ident(float x) {
return x;
}
float (*veil)(float) = ident;
int main(int argc, char *argv[]) {
float x;
setup_trap();
// test illegal math
activate_trap();
x = 0 / veil(0);
printf("0/0 = %g\n", x);
// test divide by zero
activate_trap();
x = 1 / veil(0);
printf("1/0 = %g\n", x);
// test divide by zero again
activate_trap();
x = -1 / veil(0);
printf("-1/0 = %g\n", x);
// test domain error
activate_trap();
x = logf(veil(-1));
printf("log(-1) = %g\n", x);
// test imaginary number
activate_trap();
x = sqrtf(veil(-1));
printf("sqrt(-1) = %g\n", x);
// test overflow
activate_trap();
x = expf(veil(88.8));
printf("expf(88.8) = %g\n", x);
// test underflow
activate_trap();
x = expf(veil(-104));
printf("expf(-104) = %g\n", x);
}

View file

@ -198,7 +198,8 @@ int main(int argc, char *argv[]) {
dprintf(outfd, "%`'.*s (got %d) ", n, code, n);
if (iscntrl(code[0]) && !code[1]) {
dprintf(outfd, "is CTRL-%c a.k.a. ^%c\r\n", CTRL(code[0]), CTRL(code[0]));
if (code[0] == CTRL('C') || code[0] == CTRL('D')) break;
if (code[0] == CTRL('C') || code[0] == CTRL('D'))
break;
} else if (startswith(code, "\e[") && endswith(code, "R")) {
yn = 1, xn = 1;
sscanf(code, "\e[%d;%dR", &yn, &xn);

View file

@ -13,7 +13,8 @@
int main(int argc, char *argv[]) {
struct utsname names;
if (uname(&names)) return 1;
if (uname(&names))
return 1;
printf("%-10s %`'s\n", "sysname", names.sysname);
printf("%-10s %`'s\n", "release", names.release);
printf("%-10s %`'s\n", "version", names.version);

File diff suppressed because it is too large Load diff

View file

@ -9,11 +9,11 @@
#endif
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/ftw.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/s.h"
#include "libc/stdio/ftw.h"
/**
* @fileoverview Directory walker example.
@ -44,8 +44,10 @@ static int display_info(const char *fpath, const struct stat *sb, int tflag,
int main(int argc, char *argv[]) {
int flags = 0;
const char *dir;
if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS;
if (argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
if (argc > 2 && strchr(argv[2], 'p') != NULL)
flags |= FTW_PHYS;
dir = argc < 2 ? "." : argv[1];
if (nftw(dir, display_info, 20, flags) == -1) {
fprintf(stderr, "nftw() failed: %s: %s\n", strerror(errno), dir);

View file

@ -16,7 +16,7 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/struct/tm.h"
#include "libc/time.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/musl/passwd.h"
@ -96,7 +96,8 @@ int main(int argc, char *argv[]) {
appends(&msg, "\e[1m"); // bold text
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
GetHost());
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
if (isatty(0) && (s = ttyname(0)))
appendf(&msg, " (%s)", s);
appendf(&msg, " (%s):\r\n", GetTime());
appends(&msg, "\e[K");
@ -104,7 +105,8 @@ int main(int argc, char *argv[]) {
if (optind < argc) {
// use cli arguments as message if they exist
for (int i = 0; optind + i < argc; ++i) {
if (i) appends(&msg, " ");
if (i)
appends(&msg, " ");
for (s = argv[optind + i]; *s; ++s) {
if (*s == '\n') {
appends(&msg, "\r\n\e[K");
@ -135,8 +137,10 @@ int main(int argc, char *argv[]) {
char pts[32];
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
if (errno == ENOENT) continue;
if (g_verbose) perror(pts);
if (errno == ENOENT)
continue;
if (g_verbose)
perror(pts);
}
write(fd, msg, appendz(msg).i);
close(fd);

View file

@ -4,10 +4,8 @@
PKGS += LIBC
LIBC_ISYSTEM = \
libc/isystem/algorithm \
libc/isystem/alloca.h \
libc/isystem/ammintrin.h \
libc/isystem/any \
libc/isystem/ar.h \
libc/isystem/arm_acle.h \
libc/isystem/arm_bf16.h \
@ -15,51 +13,16 @@ libc/isystem/arm_fp16.h \
libc/isystem/arm_neon.h \
libc/isystem/arpa/inet.h \
libc/isystem/arpa/nameser.h \
libc/isystem/array \
libc/isystem/assert.h \
libc/isystem/atomic \
libc/isystem/bit \
libc/isystem/bitset \
libc/isystem/byteswap.h \
libc/isystem/cassert \
libc/isystem/ccomplex \
libc/isystem/cctype \
libc/isystem/cerrno \
libc/isystem/cfenv \
libc/isystem/cfloat \
libc/isystem/charconv \
libc/isystem/chrono \
libc/isystem/cinttypes \
libc/isystem/ciso646 \
libc/isystem/climits \
libc/isystem/clocale \
libc/isystem/clzerointrin.h \
libc/isystem/cmath \
libc/isystem/codecvt \
libc/isystem/compare \
libc/isystem/complex \
libc/isystem/complex.h \
libc/isystem/condition_variable \
libc/isystem/cosmo.h \
libc/isystem/cpio.h \
libc/isystem/cpuid.h \
libc/isystem/crypt.h \
libc/isystem/csetjmp \
libc/isystem/csignal \
libc/isystem/cstdarg \
libc/isystem/cstdbool \
libc/isystem/cstddef \
libc/isystem/cstdint \
libc/isystem/cstdio \
libc/isystem/cstdlib \
libc/isystem/cstring \
libc/isystem/ctgmath \
libc/isystem/ctime \
libc/isystem/ctype.h \
libc/isystem/cwchar \
libc/isystem/cwctype \
libc/isystem/cxxabi.h \
libc/isystem/deque \
libc/isystem/dirent.h \
libc/isystem/dlfcn.h \
libc/isystem/elf.h \
@ -67,57 +30,37 @@ libc/isystem/emmintrin.h \
libc/isystem/endian.h \
libc/isystem/err.h \
libc/isystem/errno.h \
libc/isystem/exception \
libc/isystem/execution \
libc/isystem/fcntl.h \
libc/isystem/features.h \
libc/isystem/fenv.h \
libc/isystem/filesystem \
libc/isystem/float.h \
libc/isystem/fnmatch.h \
libc/isystem/forward_list \
libc/isystem/fstream \
libc/isystem/ftw.h \
libc/isystem/functional \
libc/isystem/future \
libc/isystem/getopt.h \
libc/isystem/glob.h \
libc/isystem/grp.h \
libc/isystem/iconv.h \
libc/isystem/ifaddrs.h \
libc/isystem/immintrin.h \
libc/isystem/initializer_list \
libc/isystem/inttypes.h \
libc/isystem/iomanip \
libc/isystem/ios \
libc/isystem/iosfwd \
libc/isystem/iostream \
libc/isystem/iso646.h \
libc/isystem/istream \
libc/isystem/iterator \
libc/isystem/langinfo.h \
libc/isystem/libgen.h \
libc/isystem/limits \
libc/isystem/limits.h \
libc/isystem/link.h \
libc/isystem/linux/futex.h \
libc/isystem/linux/limits.h \
libc/isystem/linux/param.h \
libc/isystem/linux/types.h \
libc/isystem/list \
libc/isystem/locale \
libc/isystem/locale.h \
libc/isystem/malloc.h \
libc/isystem/map \
libc/isystem/math.h \
libc/isystem/memory \
libc/isystem/memory.h \
libc/isystem/mm3dnow.h \
libc/isystem/mm_malloc.h \
libc/isystem/mmintrin.h \
libc/isystem/mntent.h \
libc/isystem/monetary.h \
libc/isystem/mutex \
libc/isystem/mwaitxintrin.h \
libc/isystem/net/ethernet.h \
libc/isystem/net/if.h \
@ -127,7 +70,6 @@ libc/isystem/netinet/in.h \
libc/isystem/netinet/ip.h \
libc/isystem/netinet/tcp.h \
libc/isystem/netinet/udp.h \
libc/isystem/new \
libc/isystem/nl_types.h \
libc/isystem/nmmintrin.h \
libc/isystem/nsync.h \
@ -141,12 +83,9 @@ libc/isystem/nsync_note.h \
libc/isystem/nsync_once.h \
libc/isystem/nsync_time.h \
libc/isystem/nsync_waiter.h \
libc/isystem/numeric \
libc/isystem/omp-tools.h \
libc/isystem/omp.h \
libc/isystem/ompx.h \
libc/isystem/optional \
libc/isystem/ostream \
libc/isystem/paths.h \
libc/isystem/pmmintrin.h \
libc/isystem/poll.h \
@ -154,27 +93,17 @@ libc/isystem/popcntintrin.h \
libc/isystem/pthread.h \
libc/isystem/pty.h \
libc/isystem/pwd.h \
libc/isystem/queue \
libc/isystem/random \
libc/isystem/ratio \
libc/isystem/regex \
libc/isystem/regex.h \
libc/isystem/resolv.h \
libc/isystem/sched.h \
libc/isystem/scoped_allocator \
libc/isystem/search.h \
libc/isystem/semaphore.h \
libc/isystem/set \
libc/isystem/setjmp.h \
libc/isystem/sgxintrin.h \
libc/isystem/shadow.h \
libc/isystem/shared_mutex \
libc/isystem/signal.h \
libc/isystem/smmintrin.h \
libc/isystem/span \
libc/isystem/spawn.h \
libc/isystem/sstream \
libc/isystem/stack \
libc/isystem/stdalign.h \
libc/isystem/stdarg.h \
libc/isystem/stdatomic.h \
@ -182,18 +111,13 @@ libc/isystem/stdbool.h \
libc/isystem/stdc-predef.h \
libc/isystem/stdckdint.h \
libc/isystem/stddef.h \
libc/isystem/stdexcept \
libc/isystem/stdint.h \
libc/isystem/stdio.h \
libc/isystem/stdio_ext.h \
libc/isystem/stdlib.h \
libc/isystem/stdnoreturn.h \
libc/isystem/streambuf \
libc/isystem/string \
libc/isystem/string.h \
libc/isystem/string_view \
libc/isystem/strings.h \
libc/isystem/strstream \
libc/isystem/sys/auxv.h \
libc/isystem/sys/cdefs.h \
libc/isystem/sys/dir.h \
@ -238,38 +162,26 @@ libc/isystem/sys/vfs.h \
libc/isystem/sys/wait.h \
libc/isystem/sysexits.h \
libc/isystem/syslog.h \
libc/isystem/system_error \
libc/isystem/termios.h \
libc/isystem/tgmath.h \
libc/isystem/thread \
libc/isystem/threads.h \
libc/isystem/time.h \
libc/isystem/tmmintrin.h \
libc/isystem/tuple \
libc/isystem/type_traits \
libc/isystem/typeindex \
libc/isystem/typeinfo \
libc/isystem/uchar.h \
libc/isystem/ucontext.h \
libc/isystem/uio.h \
libc/isystem/unistd.h \
libc/isystem/unordered_map \
libc/isystem/unordered_set \
libc/isystem/unwind.h \
libc/isystem/utility \
libc/isystem/utime.h \
libc/isystem/utmp.h \
libc/isystem/utmpx.h \
libc/isystem/valarray \
libc/isystem/variant \
libc/isystem/vector \
libc/isystem/version \
libc/isystem/wait.h \
libc/isystem/wchar.h \
libc/isystem/wctype.h \
libc/isystem/winternl.h \
libc/isystem/wmmintrin.h \
libc/isystem/x86intrin.h \
libc/isystem/xmmintrin.h
libc/isystem/xmmintrin.h \
LIBC_HDRS = $(filter %.h,$(LIBC_FILES)) $(LIBC_ISYSTEM)
LIBC_HDRS_H = $(filter %.h,$(LIBC_HDRS))
@ -299,7 +211,6 @@ o/$(MODE)/libc: o/$(MODE)/libc/calls \
o/$(MODE)/libc/sysv \
o/$(MODE)/libc/testlib \
o/$(MODE)/libc/thread \
o/$(MODE)/libc/time \
o/$(MODE)/libc/tinymath \
o/$(MODE)/libc/vga \
o/$(MODE)/libc/x \

View file

@ -147,6 +147,13 @@ o/$(MODE)/libc/calls/pledge-linux.o: private \
-fPIC \
-ffreestanding
# we want -Os because:
# it makes a big difference
# it gets called very rarely
o/$(MODE)/libc/calls/sigcrashsig.o: private \
CFLAGS += \
-Os
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/calls/getcontext.o: libc/calls/getcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<

View file

@ -59,7 +59,8 @@ int _ptsname(int fd, char *buf, size_t size) {
t.sn[5] = 0;
if (IsLinux()) {
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
if (sys_ioctl(fd, TIOCGPTN, &pty))
return -1;
t.sn[5] = 'p';
t.sn[6] = 't';
t.sn[7] = 's';

View file

@ -237,7 +237,9 @@ int sys_munlock(const void *, size_t) libcesque;
int sys_munlockall(void) libcesque;
int sys_personality(uint64_t) libcesque;
int sys_ptrace(int, ...) libcesque;
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int sysctl(int *, unsigned, void *, size_t *, void *, size_t) libcesque;
int sysctlbyname(const char *, void *, size_t *, void *, size_t) libcesque;
int sysctlnametomib(const char *, int *, size_t *) libcesque;
int tmpfd(void) libcesque;
int touch(const char *, unsigned) libcesque;
int unveil(const char *, const char *) libcesque;

View file

@ -101,7 +101,9 @@ int cfsetispeed(struct termios *t, uint32_t speed) {
* @asyncsignalsafe
*/
int cfsetspeed(struct termios *t, uint32_t speed) {
if (cfsetispeed(t, speed) == -1) return -1;
if (cfsetospeed(t, speed) == -1) return -1;
if (cfsetispeed(t, speed) == -1)
return -1;
if (cfsetospeed(t, speed) == -1)
return -1;
return 0;
}

Some files were not shown because too many files have changed in this diff Show more