mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 08:20:28 +00:00
Merge branch 'jart:master' into master
This commit is contained in:
commit
ecb7614c9f
3950 changed files with 238159 additions and 80823 deletions
25
.git-blame-ignore-revs
Normal file
25
.git-blame-ignore-revs
Normal 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
59
.github/ISSUE_TEMPLATE/01-bug-low.yml
vendored
Normal 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
|
59
.github/ISSUE_TEMPLATE/02-bug-medium.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/02-bug-medium.yml
vendored
Normal 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
59
.github/ISSUE_TEMPLATE/03-bug-high.yml
vendored
Normal 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
|
59
.github/ISSUE_TEMPLATE/04-bug-critical.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/04-bug-critical.yml
vendored
Normal 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
|
51
.github/ISSUE_TEMPLATE/05-enhancement.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/05-enhancement.yml
vendored
Normal 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
52
.github/ISSUE_TEMPLATE/06-research.yml
vendored
Normal 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
28
.github/ISSUE_TEMPLATE/07-refactor.yml
vendored
Normal 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
15
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal 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
53
.github/labeler.yml
vendored
Normal 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
17
.github/workflows/labeler.yml
vendored
Normal 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'
|
108
.vscode/c_cpp_properties.json
vendored
108
.vscode/c_cpp_properties.json
vendored
|
@ -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
2
.vscode/vscode.h
vendored
|
@ -1,2 +0,0 @@
|
|||
#define __VSCODE_INTELLISENSE__ 1
|
||||
#include "libc/integral/normalize.inc"
|
27
Makefile
27
Makefile
|
@ -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 \
|
||||
|
|
19
ape/BUILD.mk
19
ape/BUILD.mk
|
@ -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: \
|
||||
|
|
|
@ -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)));
|
||||
|
|
111
ape/ape-m1.c
111
ape/ape-m1.c
|
@ -31,6 +31,8 @@
|
|||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
@ -39,7 +41,7 @@
|
|||
/* maximum path size that cosmo can take */
|
||||
#define PATHSIZE (PATH_MAX < 1024 ? PATH_MAX : 1024)
|
||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||
#define SYSLIB_VERSION 9 /* sync with libc/runtime/syslib.internal.h */
|
||||
#define SYSLIB_VERSION 10 /* sync with libc/runtime/syslib.internal.h */
|
||||
|
||||
struct Syslib {
|
||||
int magic;
|
||||
|
@ -106,6 +108,10 @@ struct Syslib {
|
|||
OPTIONAL (cosmo lib should check __syslib->version) */
|
||||
/* v9 (2024-01-31) */
|
||||
int (*pthread_cpu_number_np)(size_t *);
|
||||
/* v10 (2024-05-02) */
|
||||
long (*sysctl)(int *, u_int, void *, size_t *, void *, size_t);
|
||||
long (*sysctlbyname)(const char *, void *, size_t *, void *, size_t);
|
||||
long (*sysctlnametomib)(const char *, int *, size_t *);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
|
@ -140,6 +146,9 @@ struct Syslib {
|
|||
#define AT_RANDOM 25
|
||||
#define AT_EXECFN 31
|
||||
|
||||
#define EF_APE_MODERN 0x101ca75
|
||||
#define EF_APE_MODERN_MASK 0x1ffffff
|
||||
|
||||
#define AUXV_WORDS 31
|
||||
|
||||
/* from the xnu codebase */
|
||||
|
@ -148,8 +157,8 @@ struct Syslib {
|
|||
#define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110)
|
||||
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
|
||||
|
||||
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
|
@ -221,13 +230,15 @@ struct ApeLoader {
|
|||
|
||||
static unsigned long StrLen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
while (*s++)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int StrCmp(const char *l, const char *r) {
|
||||
unsigned long i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
while (l[i] == r[i] && r[i])
|
||||
++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
|
@ -276,7 +287,8 @@ static char *Utoa(char p[21], unsigned long x) {
|
|||
}
|
||||
|
||||
static char *Itoa(char p[21], long x) {
|
||||
if (x < 0) *p++ = '-', x = -(unsigned long)x;
|
||||
if (x < 0)
|
||||
*p++ = '-', x = -(unsigned long)x;
|
||||
return Utoa(p, x);
|
||||
}
|
||||
|
||||
|
@ -312,7 +324,8 @@ static int GetIndirectOffset(const char *arg0) {
|
|||
static void Perror(const char *thing, long rc, const char *reason) {
|
||||
char ibuf[21];
|
||||
ibuf[0] = 0;
|
||||
if (rc) Itoa(ibuf, -rc);
|
||||
if (rc)
|
||||
Itoa(ibuf, -rc);
|
||||
Print(2, "ape error: ", thing, ": ", reason, rc ? " failed w/ errno " : "",
|
||||
ibuf, "\n", 0l);
|
||||
}
|
||||
|
@ -327,7 +340,8 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
|||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) {
|
||||
return 0;
|
||||
}
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
if (pathlen && ps->path[pathlen - 1] != '/')
|
||||
ps->path[pathlen++] = '/';
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !access(ps->path, X_OK);
|
||||
|
@ -377,8 +391,10 @@ static char *Commandv(struct PathSearcher *ps, const char *name,
|
|||
const char *syspath) {
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
ps->name = name;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name)))
|
||||
return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path))
|
||||
return 0;
|
||||
if (FindCommand(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
|
@ -545,6 +561,20 @@ static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
|||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
static long sys_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen) {
|
||||
return sysret(sysctlbyname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
static long sys_sysctlnametomib(const char *name, int *mibp, size_t *sizep) {
|
||||
return sysret(sysctlnametomib(name, mibp, sizep));
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
long *sp, struct ElfEhdr *e,
|
||||
struct ElfPhdr *p,
|
||||
|
@ -585,10 +615,11 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
a = p[i].p_vaddr & -pagesz;
|
||||
b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD) continue;
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
c = p[j].p_vaddr & -pagesz;
|
||||
d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
if (Max(a, c) < Min(b, d)) {
|
||||
Pexit(exe, 0, "ELF segments overlap each others virtual memory");
|
||||
}
|
||||
}
|
||||
|
@ -614,7 +645,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
if (e->e_type == ET_DYN) {
|
||||
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "pie mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
Pexit(exe, 0, "OS mmap incongruent w/ AT_PAGESZ");
|
||||
|
@ -630,14 +662,18 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
flags = MAP_FIXED | MAP_PRIVATE;
|
||||
if (p[i].p_flags & PF_R) prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
if (p[i].p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (p[i].p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
|
@ -657,7 +693,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
wipe = MIN(b - a, c - a);
|
||||
wipe = Min(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
|
@ -687,24 +723,30 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
as the default strategy which is slow but it works for both */
|
||||
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap anon");
|
||||
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
|
||||
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
|
||||
if (rc != p[i].p_filesz)
|
||||
Pexit(exe, -errno, "prog pread");
|
||||
#endif
|
||||
} else {
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mmap");
|
||||
}
|
||||
if (wipe) memset((void *)(dynbase + a), 0, wipe);
|
||||
if (wipe)
|
||||
memset((void *)(dynbase + a), 0, wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = sys_mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
|
@ -712,7 +754,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = sys_mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
if (rc < 0)
|
||||
Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,7 +802,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
}
|
||||
|
||||
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
const char *exe, int fd, long *sp, long *auxv,
|
||||
char *exe, int fd, long *sp, long *auxv,
|
||||
char *execfn) {
|
||||
long i, rc;
|
||||
unsigned size;
|
||||
|
@ -780,6 +823,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
if (e->e_machine != EM_AARCH64) {
|
||||
return "couldn't find ELF header with ARM64 machine type";
|
||||
}
|
||||
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
|
||||
/* change argv[0] to resolved path for older binaries */
|
||||
((char **)(sp + 1))[0] = exe;
|
||||
}
|
||||
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
|
||||
Pexit(exe, 0, "e_phentsize is wrong");
|
||||
}
|
||||
|
@ -790,8 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
|||
|
||||
/* read program headers */
|
||||
rc = pread(fd, M->phdr.buf, size, ebuf->ehdr.e_phoff);
|
||||
if (rc < 0) return "failed to read ELF program headers";
|
||||
if (rc != size) return "truncated read of ELF program headers";
|
||||
if (rc < 0)
|
||||
return "failed to read ELF program headers";
|
||||
if (rc != size)
|
||||
return "truncated read of ELF program headers";
|
||||
|
||||
/* bail on recoverable program header errors */
|
||||
p = &M->phdr.phdr;
|
||||
|
@ -948,6 +997,9 @@ int main(int argc, char **argv, char **envp) {
|
|||
M->lib.dlclose = dlclose;
|
||||
M->lib.dlerror = dlerror;
|
||||
M->lib.pthread_cpu_number_np = pthread_cpu_number_np;
|
||||
M->lib.sysctl = sys_sysctl;
|
||||
M->lib.sysctlbyname = sys_sysctlbyname;
|
||||
M->lib.sysctlnametomib = sys_sysctlnametomib;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = 0;
|
||||
|
@ -970,7 +1022,8 @@ int main(int argc, char **argv, char **envp) {
|
|||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
if ((long)sp2 & 15)
|
||||
++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
|
||||
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 nofixeol :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
|
@ -196,7 +196,7 @@ ape_mz:
|
|||
.quad ape_elf_entry // 18: e_entry
|
||||
.quad ape_elf_phoff // 20: e_phoff
|
||||
.quad ape_elf_shoff // 28: e_shoff
|
||||
.long 0 // 30: e_flags
|
||||
.long 0x101ca75 // 30: ape e_flags
|
||||
.short 64 // 34: e_ehsize
|
||||
.short 56 // 36: e_phentsize
|
||||
.short ape_elf_phnum // 38: e_phnum
|
||||
|
@ -669,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
|||
.shstub ape_elf_entry,8 // 18: e_entry
|
||||
.shstub ape_elf_phoff,8 // 20: e_phoff
|
||||
.shstub ape_elf_shoff,8 // 28: e_shoff
|
||||
.ascii "\\0\\0\\0\\0" // 30: e_flags
|
||||
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
|
||||
.ascii "\\100\\0" // 34: e_ehsize
|
||||
.ascii "\\070\\0" // 36: e_phentsize
|
||||
.shstub ape_elf_phnum,2 // 38: e_phnum
|
||||
|
@ -1036,7 +1036,7 @@ ape_pe: .ascin "PE",4
|
|||
.quad ape_pe_base // ImageBase
|
||||
.long ape_pe_sectionalignment // SectionAlignment
|
||||
.long ape_pe_filealignment // FileAlignment
|
||||
.short v_ntversion // MajorOperatingSystemVersion
|
||||
.short 10 // MajorOperatingSystemVersion
|
||||
.short 0 // MinorOperatingSystemVersion
|
||||
.short 0 // MajorImageVersion
|
||||
.short 0 // MinorImageVersion
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
97
ape/loader.c
97
ape/loader.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
#define SHSTUB2(SYM, X) \
|
||||
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
|
||||
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
|
||||
#define BCD_SMEAR(X) ((X) + (X) * 10000)
|
||||
#define BCD_SMEAR(X) ((X) + (X)*10000)
|
||||
#define BCD_LEFT(X) \
|
||||
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
|
||||
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
|
||||
|
@ -140,23 +140,16 @@
|
|||
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
|
||||
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + \
|
||||
(X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + \
|
||||
((X) / 10) % 10 + \
|
||||
(X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + \
|
||||
((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + \
|
||||
(X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 ? 0x30303030 + \
|
||||
((X) / 1000) % 10 + \
|
||||
((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + \
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + (X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 \
|
||||
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
|
@ -165,15 +158,11 @@
|
|||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
|
|
|
@ -16,6 +16,8 @@ extern unsigned char _tdata_end[] __attribute__((__weak__));
|
|||
extern unsigned char _tbss_start[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_end[] __attribute__((__weak__));
|
||||
extern unsigned char _tls_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tdata_align[] __attribute__((__weak__));
|
||||
extern unsigned char _tbss_align[] __attribute__((__weak__));
|
||||
extern unsigned char __test_start[] __attribute__((__weak__));
|
||||
extern unsigned char __ro[] __attribute__((__weak__));
|
||||
extern unsigned char __data_start[] __attribute__((__weak__));
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -11,20 +11,20 @@
|
|||
#
|
||||
ifeq ($(MODE),)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
ifeq ($(MODE), x86_64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
|
@ -38,13 +38,13 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), zero)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-zero)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0 -fdce
|
||||
OVERRIDE_CXXFLAGS += -O0 -fdce
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
|
@ -81,7 +81,7 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), opt)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
|
||||
TARGET_ARCH ?= -march=native
|
||||
|
@ -98,7 +98,7 @@ endif
|
|||
# - Turns off support for other operating systems
|
||||
#
|
||||
ifeq ($(MODE), optlinux)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
|
@ -140,7 +140,7 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), asan)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
|
@ -160,7 +160,7 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
|
||||
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
|
||||
|
@ -170,7 +170,7 @@ QUOTA ?= -C64 -L300
|
|||
endif
|
||||
ifeq ($(MODE), aarch64-dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
|
@ -189,7 +189,7 @@ endif
|
|||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
|
|
|
@ -60,13 +60,10 @@ TMPSAFE = $(TMPDIR)/
|
|||
endif
|
||||
|
||||
BACKTRACES = \
|
||||
-fno-schedule-insns2 \
|
||||
-fno-optimize-sibling-calls \
|
||||
-mno-omit-leaf-frame-pointer
|
||||
|
||||
ifneq ($(ARCH), aarch64)
|
||||
BACKTRACES += -fno-schedule-insns2
|
||||
endif
|
||||
|
||||
SANITIZER = \
|
||||
-fsanitize=address
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
13
ctl/.clang-format
Normal 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
48
ctl/BUILD.mk
Normal 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
5015
ctl/README.md
Normal file
File diff suppressed because it is too large
Load diff
116
ctl/new.cc
Normal file
116
ctl/new.cc
Normal 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
30
ctl/new.h
Normal 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
143
ctl/optional.h
Normal 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
49
ctl/strcat.cc
Normal 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
43
ctl/strcmp.cc
Normal 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
367
ctl/string.cc
Normal 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
362
ctl/string.h
Normal 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
111
ctl/string_view.cc
Normal 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
159
ctl/string_view.h
Normal 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
247
ctl/vector.h
Normal 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_
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -28,13 +28,15 @@
|
|||
int mulaw(int x) {
|
||||
int b, i, a, s, l, h;
|
||||
a = x < 0 ? (~x >> 2) + 33 : (x >> 2) + 33;
|
||||
if (a > 8191) a = 8191;
|
||||
if (a > 8191)
|
||||
a = 8191;
|
||||
i = a >> 6;
|
||||
s = i ? (__builtin_clz(i) ^ 31) + 2 : 1;
|
||||
h = 8 - s;
|
||||
l = (a >> s) & 15;
|
||||
l = 15 - l;
|
||||
b = (h << 4) | l;
|
||||
if (x >= 0) b |= 128;
|
||||
if (x >= 0)
|
||||
b |= 128;
|
||||
return b;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
|||
/* TODO(jart): This isn't acceptable. */
|
||||
size_t i, j;
|
||||
if (p > 0) {
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] =
|
||||
|
@ -38,7 +39,8 @@ void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
|||
}
|
||||
} else if (p < 0) {
|
||||
p = -p;
|
||||
if (p > 15) p = 15;
|
||||
if (p > 15)
|
||||
p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] = pcm[i][j] >> p;
|
||||
|
|
|
@ -31,8 +31,10 @@ int unalaw(int x) {
|
|||
i = (x ^ 85) & 127;
|
||||
e = i >> 4;
|
||||
m = i & 15;
|
||||
if (e > 0) m += 16;
|
||||
if (e > 0)
|
||||
m += 16;
|
||||
m = (m << 4) + 8;
|
||||
if (e > 1) m = m << (e - 1);
|
||||
if (e > 1)
|
||||
m = m << (e - 1);
|
||||
return x & 128 ? m : -m;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ DSP_MPEG_A_DIRECTDEPS = \
|
|||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#include "dsp/mpeg/mpeg.h"
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define START_PACK 0xBA
|
||||
#define START_END 0xB9
|
||||
#define START_PACK 0xBA
|
||||
#define START_END 0xB9
|
||||
#define START_SYSTEM 0xBB
|
||||
|
||||
typedef struct plm_demux_t {
|
||||
|
|
|
@ -46,7 +46,8 @@ forceinline void plm_video_process_macroblock(plm_video_t *self,
|
|||
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
|
||||
di = (self->mb_row * dw + self->mb_col) * BW;
|
||||
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
|
||||
if (si > max_address || di > max_address) return;
|
||||
if (si > max_address || di > max_address)
|
||||
return;
|
||||
d += di;
|
||||
s += si;
|
||||
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "libc/x/x.h"
|
||||
__static_yoink("pl_mpeg_notice");
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ DSP_SCALE_A_DIRECTDEPS = \
|
|||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -38,7 +38,6 @@ DSP_TTY_A_DIRECTDEPS = \
|
|||
LIBC_SOCK \
|
||||
LIBC_SYSV \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TIME \
|
||||
LIBC_X
|
||||
|
||||
DSP_TTY_A_DEPS := \
|
||||
|
|
|
@ -24,9 +24,13 @@
|
|||
* The alternate buffer trick lets one restore the console exactly as it
|
||||
* was, once the program is done running.
|
||||
*/
|
||||
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
|
||||
int ttyenablealtbuf(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[?1049h");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to restore blinking box thing.
|
||||
*/
|
||||
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }
|
||||
int ttydisablealtbuf(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[?1049l");
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (__nocolor) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (__nocolor)
|
||||
return 0;
|
||||
if (visible)
|
||||
code[5] = 'h';
|
||||
if (IsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
ntcursor.bVisible = visible;
|
||||
|
|
|
@ -21,9 +21,13 @@
|
|||
/**
|
||||
* Asks teletypewriter to push current position.
|
||||
*/
|
||||
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
|
||||
int ttysavecursor(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[s");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to pop previous position.
|
||||
*/
|
||||
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }
|
||||
int ttyrestorecursor(int ttyfd) {
|
||||
return ttysend(ttyfd, "\e[u");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
16
examples/asantest.c
Normal 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
221
examples/blas.cc
Normal 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);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -26,6 +27,13 @@
|
|||
* o//examples/crashreport.com
|
||||
*/
|
||||
|
||||
int Divide(int x, int y) {
|
||||
volatile int z = 0; // force creation of stack frame
|
||||
return x / y + z;
|
||||
}
|
||||
|
||||
int (*pDivide)(int, int) = Divide;
|
||||
|
||||
dontubsan int main(int argc, char *argv[]) {
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
|
@ -34,12 +42,7 @@ dontubsan int main(int argc, char *argv[]) {
|
|||
|
||||
ShowCrashReports();
|
||||
|
||||
volatile double a = 0;
|
||||
volatile double b = 23;
|
||||
volatile double c = exp(b) / a;
|
||||
(void)c;
|
||||
|
||||
volatile int x = 0;
|
||||
volatile int y = 1 / x;
|
||||
return y;
|
||||
pDivide(1, 0);
|
||||
pDivide(2, 0);
|
||||
pDivide(3, 0);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
|
@ -18,6 +19,17 @@ void crash(long x0, long x1, long x2, //
|
|||
void (*pCrash)(long, long, long, double, double, double) = crash;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// // by default we launch an addr2line subprocess to print backtraces
|
||||
// // with line numbers. you can force it to use the embedded solution
|
||||
// setenv("ADDR2LINE", "", true);
|
||||
|
||||
// // using a seccomp sandbox is another way to force embedded backtraces
|
||||
// pledge("stdio", NULL);
|
||||
|
||||
// enable the crash reporting feature
|
||||
ShowCrashReports();
|
||||
|
||||
// time to die
|
||||
pCrash(1, 2, 3, NAN, NAN, NAN);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
140
examples/kilo.c
140
examples/kilo.c
|
@ -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
15
examples/localtime.c
Normal 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);
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/w.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "libc/x/xasprintf.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
@ -492,7 +492,8 @@ void TransmitVideo(void) {
|
|||
ssize_t rc;
|
||||
struct Frame* f;
|
||||
f = &vf_[frame_];
|
||||
if (!HasVideo(f)) f = FlipFrameBuffer();
|
||||
if (!HasVideo(f))
|
||||
f = FlipFrameBuffer();
|
||||
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
|
||||
f->w += rc;
|
||||
} else if (errno == EAGAIN) {
|
||||
|
@ -504,9 +505,12 @@ void TransmitVideo(void) {
|
|||
|
||||
void TransmitAudio(void) {
|
||||
ssize_t rc;
|
||||
if (!playpid_) return;
|
||||
if (!audio_.i) return;
|
||||
if (playfd_ == -1) return;
|
||||
if (!playpid_)
|
||||
return;
|
||||
if (!audio_.i)
|
||||
return;
|
||||
if (playfd_ == -1)
|
||||
return;
|
||||
if ((rc = Write(playfd_, audio_.p, audio_.i * sizeof(short))) != -1) {
|
||||
rc /= sizeof(short);
|
||||
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
|
||||
|
@ -561,9 +565,12 @@ void KeyCountdown(struct Action* a) {
|
|||
void PollAndSynchronize(void) {
|
||||
do {
|
||||
if (ReadKeyboard() == -1) {
|
||||
if (errno != EINTR) Exit(1);
|
||||
if (exited_) Exit(0);
|
||||
if (resized_) GetTermSize();
|
||||
if (errno != EINTR)
|
||||
Exit(1);
|
||||
if (exited_)
|
||||
Exit(0);
|
||||
if (resized_)
|
||||
GetTermSize();
|
||||
}
|
||||
} while (!timeout_);
|
||||
TransmitVideo();
|
||||
|
@ -734,7 +741,8 @@ u8 Access(unsigned addr, u8 value, bool write) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((addr >> 13) == 3) return PRAM[addr & 0x1FFF];
|
||||
if ((addr >> 13) == 3)
|
||||
return PRAM[addr & 0x1FFF];
|
||||
return banks[(addr / RomGranularity) % RomPages][addr % RomGranularity];
|
||||
}
|
||||
|
||||
|
@ -828,7 +836,8 @@ bool offset_toggle = false;
|
|||
u8& NesMmap(int i) {
|
||||
i &= 0x3FFF;
|
||||
if (i >= 0x3F00) {
|
||||
if (i % 4 == 0) i &= 0x0F;
|
||||
if (i % 4 == 0)
|
||||
i &= 0x0F;
|
||||
return palette[i & 0x1F];
|
||||
}
|
||||
if (i < 0x2000) {
|
||||
|
@ -844,7 +853,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
|||
return open_bus_decay_timer = 77777, open_bus = v;
|
||||
};
|
||||
u8 res = open_bus;
|
||||
if (write) RefreshOpenBus(v);
|
||||
if (write)
|
||||
RefreshOpenBus(v);
|
||||
switch (index) { // Which port from $200x?
|
||||
case 0:
|
||||
if (write) {
|
||||
|
@ -858,7 +868,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
|||
}
|
||||
break;
|
||||
case 2:
|
||||
if (write) break;
|
||||
if (write)
|
||||
break;
|
||||
res = reg.status | (open_bus & 0x1F);
|
||||
reg.InVBlank = false; // Reading $2002 clears the vblank flag.
|
||||
offset_toggle = false; // Also resets the toggle for address updates.
|
||||
|
@ -867,7 +878,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
|||
}
|
||||
break;
|
||||
case 3:
|
||||
if (write) reg.OAMaddr = v;
|
||||
if (write)
|
||||
reg.OAMaddr = v;
|
||||
break; // Index into Object Attribute Memory
|
||||
case 4:
|
||||
if (write) {
|
||||
|
@ -878,7 +890,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
|||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!write) break; // Set background scrolling offset
|
||||
if (!write)
|
||||
break; // Set background scrolling offset
|
||||
if (offset_toggle) {
|
||||
scroll.yfine = v & 7;
|
||||
scroll.ycoarse = v >> 3;
|
||||
|
@ -888,7 +901,8 @@ u8 PpuAccess(u16 index, u8 v, bool write) {
|
|||
offset_toggle = !offset_toggle;
|
||||
break;
|
||||
case 6:
|
||||
if (!write) break; // Set video memory position for reads/writes
|
||||
if (!write)
|
||||
break; // Set video memory position for reads/writes
|
||||
if (offset_toggle) {
|
||||
scroll.vaddrlo = v;
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
|
@ -926,17 +940,21 @@ void RenderingTick() {
|
|||
case 2: // Point to attribute table
|
||||
ioaddr = 0x23C0 + 0x400 * vaddr.basenta + 8 * (vaddr.ycoarse / 4) +
|
||||
(vaddr.xcoarse / 4);
|
||||
if (tile_decode_mode) break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
if (tile_decode_mode)
|
||||
break; // Or nametable, with sprites.
|
||||
case 0: // Point to nametable
|
||||
ioaddr = 0x2000 + (vaddr.raw & 0xFFF);
|
||||
// Reset sprite data
|
||||
if (x_ == 0) {
|
||||
sprinpos = sproutpos = 0;
|
||||
if (reg.ShowSP) reg.OAMaddr = 0;
|
||||
if (reg.ShowSP)
|
||||
reg.OAMaddr = 0;
|
||||
}
|
||||
if (!reg.ShowBG) break;
|
||||
if (!reg.ShowBG)
|
||||
break;
|
||||
// Reset scrolling (vertical once, horizontal each scanline)
|
||||
if (x_ == 304 && scanline == -1) vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 304 && scanline == -1)
|
||||
vaddr.raw = (unsigned)scroll.raw;
|
||||
if (x_ == 256) {
|
||||
vaddr.xcoarse = (unsigned)scroll.xcoarse;
|
||||
vaddr.basenta_h = (unsigned)scroll.basenta_h;
|
||||
|
@ -949,7 +967,8 @@ void RenderingTick() {
|
|||
}
|
||||
// Name table access
|
||||
pat_addr = 0x1000 * reg.BGaddr + 16 * NesMmap(ioaddr) + vaddr.yfine;
|
||||
if (!tile_decode_mode) break;
|
||||
if (!tile_decode_mode)
|
||||
break;
|
||||
// Push the current tile into shift registers.
|
||||
// The bitmap pattern is 16 bits, while the attribute is 2 bits, repeated
|
||||
// 8 times.
|
||||
|
@ -976,7 +995,8 @@ void RenderingTick() {
|
|||
auto& o = OAM3[sprrenpos]; // Sprite to render on next scanline
|
||||
memcpy(&o, &OAM2[sprrenpos], sizeof(o));
|
||||
unsigned y = (scanline)-o.y;
|
||||
if (o.attr & 0x80) y ^= (reg.SPsize ? 15 : 7);
|
||||
if (o.attr & 0x80)
|
||||
y ^= (reg.SPsize ? 15 : 7);
|
||||
pat_addr = 0x1000 * (reg.SPsize ? (o.index & 0x01) : reg.SPaddr);
|
||||
pat_addr += 0x10 * (reg.SPsize ? (o.index & 0xFE) : (o.index & 0xFF));
|
||||
pat_addr += (y & 7) + (y & 8) * 2;
|
||||
|
@ -1011,8 +1031,10 @@ void RenderingTick() {
|
|||
break;
|
||||
}
|
||||
++sprinpos; // next sprite
|
||||
if (sproutpos < 8) OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8) OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].y = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].sprindex = reg.OAMindex;
|
||||
y1 = sprtmp;
|
||||
y2 = sprtmp + (reg.SPsize ? 16 : 8);
|
||||
if (!(scanline >= y1 && scanline < y2)) {
|
||||
|
@ -1020,19 +1042,23 @@ void RenderingTick() {
|
|||
}
|
||||
break;
|
||||
case 1:
|
||||
if (sproutpos < 8) OAM2[sproutpos].index = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].index = sprtmp;
|
||||
break;
|
||||
case 2:
|
||||
if (sproutpos < 8) OAM2[sproutpos].attr = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].attr = sprtmp;
|
||||
break;
|
||||
case 3:
|
||||
if (sproutpos < 8) OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8)
|
||||
OAM2[sproutpos].x_ = sprtmp;
|
||||
if (sproutpos < 8) {
|
||||
++sproutpos;
|
||||
} else {
|
||||
reg.SPoverflow = true;
|
||||
}
|
||||
if (sprinpos == 2) reg.OAMaddr = 8;
|
||||
if (sprinpos == 2)
|
||||
reg.OAMaddr = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1060,13 +1086,17 @@ void RenderPixel() {
|
|||
auto& s = OAM3[sno];
|
||||
// Check if this sprite is horizontally in range
|
||||
unsigned xdiff = x_ - s.x_;
|
||||
if (xdiff >= 8) continue; // Also matches negative values
|
||||
if (xdiff >= 8)
|
||||
continue; // Also matches negative values
|
||||
// Determine which pixel to display; skip transparent pixels
|
||||
if (!(s.attr & 0x40)) xdiff = 7 - xdiff;
|
||||
if (!(s.attr & 0x40))
|
||||
xdiff = 7 - xdiff;
|
||||
u8 spritepixel = (s.pattern >> (xdiff * 2)) & 3;
|
||||
if (!spritepixel) continue;
|
||||
if (!spritepixel)
|
||||
continue;
|
||||
// Register sprite-0 hit if applicable
|
||||
if (x_ < 255 && pixel && s.sprindex == 0) reg.SP0hit = true;
|
||||
if (x_ < 255 && pixel && s.sprindex == 0)
|
||||
reg.SP0hit = true;
|
||||
// Render the pixel unless behind-background placement wanted
|
||||
if (!(s.attr & 0x20) || !pixel) {
|
||||
attr = (s.attr & 3) + 4;
|
||||
|
@ -1095,11 +1125,13 @@ void ReadToolAssistedSpeedrunRobotKeys() {
|
|||
}
|
||||
if (ctrlmask & 0x80) {
|
||||
joy_next_[0] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[0] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[0] = 0;
|
||||
}
|
||||
if (ctrlmask & 0x40) {
|
||||
joy_next_[1] = fgetc(fp);
|
||||
if (feof(fp)) joy_next_[1] = 0;
|
||||
if (feof(fp))
|
||||
joy_next_[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1144,18 +1176,23 @@ void Tick() {
|
|||
CPU::nmi = reg.InVBlank && reg.NMIenabled;
|
||||
break;
|
||||
}
|
||||
if (VBlankState != 0) VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer) open_bus = 0;
|
||||
if (VBlankState != 0)
|
||||
VBlankState += (VBlankState < 0 ? 1 : -1);
|
||||
if (open_bus_decay_timer && !--open_bus_decay_timer)
|
||||
open_bus = 0;
|
||||
|
||||
// Graphics processing scanline?
|
||||
if (scanline < DYN) {
|
||||
/* Process graphics for this cycle */
|
||||
if (reg.ShowBGSP) RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256) RenderPixel();
|
||||
if (reg.ShowBGSP)
|
||||
RenderingTick();
|
||||
if (scanline >= 0 && x_ < 256)
|
||||
RenderPixel();
|
||||
}
|
||||
|
||||
// Done with the cycle. Check for end of scanline.
|
||||
if (++cycle_counter == 3) cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++cycle_counter == 3)
|
||||
cycle_counter = 0; // For NTSC pixel shifting
|
||||
if (++x_ >= scanline_end) {
|
||||
// Begin new scanline
|
||||
FlushScanline(scanline);
|
||||
|
@ -1242,30 +1279,36 @@ struct channel {
|
|||
template <unsigned c>
|
||||
int Tick() {
|
||||
channel& ch = *this;
|
||||
if (!ChannelsEnabled[c]) return c == 4 ? 64 : 8;
|
||||
if (!ChannelsEnabled[c])
|
||||
return c == 4 ? 64 : 8;
|
||||
int wl = (ch.reg.WaveLength + 1) * (c >= 2 ? 1 : 2);
|
||||
if (c == 3) wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
if (c == 3)
|
||||
wl = NoisePeriods[ch.reg.NoiseFreq];
|
||||
int volume = ch.length_counter
|
||||
? ch.reg.EnvDecayDisable ? ch.reg.FixedVolume : ch.envelope
|
||||
: 0;
|
||||
// Sample may change at wavelen intervals.
|
||||
auto& S = ch.level;
|
||||
if (!count(ch.wave_counter, wl)) return S;
|
||||
if (!count(ch.wave_counter, wl))
|
||||
return S;
|
||||
switch (c) {
|
||||
default: // Square wave. With four different 8-step binary waveforms (32
|
||||
// bits of data total).
|
||||
if (wl < 8) return S = 8;
|
||||
if (wl < 8)
|
||||
return S = 8;
|
||||
return S = (0xF33C0C04u &
|
||||
(1u << (++ch.phase % 8 + ch.reg.DutyCycle * 8)))
|
||||
? volume
|
||||
: 0;
|
||||
|
||||
case 2: // Triangle wave
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3) ++ch.phase;
|
||||
if (ch.length_counter && ch.linear_counter && wl >= 3)
|
||||
++ch.phase;
|
||||
return S = (ch.phase & 15) ^ ((ch.phase & 16) ? 15 : 0);
|
||||
|
||||
case 3: // Noise: Linear feedback shift register
|
||||
if (!ch.hold) ch.hold = 1;
|
||||
if (!ch.hold)
|
||||
ch.hold = 1;
|
||||
ch.hold =
|
||||
(ch.hold >> 1) |
|
||||
(((ch.hold ^ (ch.hold >> (ch.reg.NoiseType ? 6 : 1))) & 1) << 14);
|
||||
|
@ -1302,7 +1345,8 @@ struct channel {
|
|||
} else {
|
||||
v -= 2;
|
||||
}
|
||||
if (v >= 0 && v <= 0x7F) ch.linear_counter = v;
|
||||
if (v >= 0 && v <= 0x7F)
|
||||
ch.linear_counter = v;
|
||||
}
|
||||
return S = ch.linear_counter;
|
||||
}
|
||||
|
@ -1338,7 +1382,8 @@ void Write(u8 index, u8 value) {
|
|||
ch.linear_counter = ch.reg.LinearCounterInit;
|
||||
ch.env_delay = ch.reg.EnvDecayRate;
|
||||
ch.envelope = 15;
|
||||
if (index < 8) ch.phase = 0;
|
||||
if (index < 8)
|
||||
ch.phase = 0;
|
||||
break;
|
||||
case 0x10:
|
||||
ch.reg.reg3 = value;
|
||||
|
@ -1384,9 +1429,11 @@ u8 Read() {
|
|||
for (c = 0; c < 5; ++c) {
|
||||
res |= channels[c].length_counter ? 1 << c : 0;
|
||||
}
|
||||
if (PeriodicIRQ) res |= 0x40;
|
||||
if (PeriodicIRQ)
|
||||
res |= 0x40;
|
||||
PeriodicIRQ = false;
|
||||
if (DMC_IRQ) res |= 0x80;
|
||||
if (DMC_IRQ)
|
||||
res |= 0x80;
|
||||
DMC_IRQ = false;
|
||||
CPU::intr = false;
|
||||
return res;
|
||||
|
@ -1396,7 +1443,8 @@ void Tick() { // Invoked at CPU's rate.
|
|||
// Divide CPU clock by 7457.5 to get a 240 Hz, which controls certain events.
|
||||
if ((hz240counter.lo += 2) >= 14915) {
|
||||
hz240counter.lo -= 14915;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider) hz240counter.hi = 0;
|
||||
if (++hz240counter.hi >= 4 + FiveCycleDivider)
|
||||
hz240counter.hi = 0;
|
||||
|
||||
// 60 Hz interval: IRQ. IRQ is not invoked in five-cycle mode (48 Hz).
|
||||
if (!IRQdisable && !FiveCycleDivider && hz240counter.hi == 0) {
|
||||
|
@ -1422,7 +1470,8 @@ void Tick() { // Invoked at CPU's rate.
|
|||
if (wl >= 8 && ch.reg.SweepEnable && ch.reg.SweepShift) {
|
||||
int s = wl >> ch.reg.SweepShift, d[4] = {s, s, ~s, -s};
|
||||
wl += d[ch.reg.SweepDecrease * 2 + c];
|
||||
if (wl < 0x800) ch.reg.WaveLength = wl;
|
||||
if (wl < 0x800)
|
||||
ch.reg.WaveLength = wl;
|
||||
}
|
||||
|
||||
// Linear tick (triangle wave only)
|
||||
|
@ -1464,20 +1513,24 @@ namespace CPU {
|
|||
|
||||
void Tick() {
|
||||
// PPU clock: 3 times the CPU rate
|
||||
for (unsigned n = 0; n < 3; ++n) PPU::Tick();
|
||||
for (unsigned n = 0; n < 3; ++n)
|
||||
PPU::Tick();
|
||||
// APU clock: 1 times the CPU rate
|
||||
for (unsigned n = 0; n < 1; ++n) APU::Tick();
|
||||
for (unsigned n = 0; n < 1; ++n)
|
||||
APU::Tick();
|
||||
}
|
||||
|
||||
template <bool write>
|
||||
u8 MemAccess(u16 addr, u8 v) {
|
||||
// Memory writes are turned into reads while reset is being signalled
|
||||
if (reset && write) return MemAccess<0>(addr);
|
||||
if (reset && write)
|
||||
return MemAccess<0>(addr);
|
||||
Tick();
|
||||
// Map the memory from CPU's viewpoint.
|
||||
/**/ if (addr < 0x2000) {
|
||||
u8& r = RAM[addr & 0x7FF];
|
||||
if (!write) return r;
|
||||
if (!write)
|
||||
return r;
|
||||
r = v;
|
||||
} else if (addr < 0x4000) {
|
||||
return PPU::PpuAccess(addr & 7, v, write);
|
||||
|
@ -1489,17 +1542,21 @@ u8 MemAccess(u16 addr, u8 v) {
|
|||
WB(0x2004, RB((v & 7) * 0x0100 + b));
|
||||
return 0;
|
||||
case 0x15:
|
||||
if (!write) return APU::Read();
|
||||
if (!write)
|
||||
return APU::Read();
|
||||
APU::Write(0x15, v);
|
||||
break;
|
||||
case 0x16:
|
||||
if (!write) return JoyRead(0);
|
||||
if (!write)
|
||||
return JoyRead(0);
|
||||
JoyStrobe(v);
|
||||
break;
|
||||
case 0x17:
|
||||
if (!write) return JoyRead(1); // write:passthru
|
||||
if (!write)
|
||||
return JoyRead(1); // write:passthru
|
||||
default:
|
||||
if (!write) break;
|
||||
if (!write)
|
||||
break;
|
||||
APU::Write(addr & 0x1F, v);
|
||||
}
|
||||
} else {
|
||||
|
@ -1527,7 +1584,8 @@ u16 wrap(u16 oldaddr, u16 newaddr) {
|
|||
}
|
||||
void Misfire(u16 old, u16 addr) {
|
||||
u16 q = wrap(old, addr);
|
||||
if (q != addr) RB(q);
|
||||
if (q != addr)
|
||||
RB(q);
|
||||
}
|
||||
u8 Pop() {
|
||||
return RB(0x100 | u8(++S));
|
||||
|
@ -1655,7 +1713,8 @@ void Op() {
|
|||
} else if (intr && !P.I) {
|
||||
op = 0x102;
|
||||
}
|
||||
if (!nmi_now) nmi_edge_detected = false;
|
||||
if (!nmi_now)
|
||||
nmi_edge_detected = false;
|
||||
|
||||
// Define function pointers for each opcode (00..FF) and each interrupt
|
||||
// (100,101,102)
|
||||
|
@ -1757,12 +1816,15 @@ Press enter to continue without sound: ",
|
|||
fgetc(fp);
|
||||
fgetc(fp);
|
||||
|
||||
if (mappernum >= 0x40) mappernum &= 15;
|
||||
if (mappernum >= 0x40)
|
||||
mappernum &= 15;
|
||||
GamePak::mappernum = mappernum;
|
||||
|
||||
// Read the ROM data
|
||||
if (rom16count) GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count) GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
if (rom16count)
|
||||
GamePak::ROM.resize(rom16count * 0x4000);
|
||||
if (vrom8count)
|
||||
GamePak::VRAM.resize(vrom8count * 0x2000);
|
||||
fread(&GamePak::ROM[0], rom16count, 0x4000, fp);
|
||||
fread(&GamePak::VRAM[0], vrom8count, 0x2000, fp);
|
||||
|
||||
|
@ -1776,10 +1838,12 @@ Press enter to continue without sound: ",
|
|||
PPU::reg.value = 0;
|
||||
|
||||
// Pre-initialize RAM the same way as FCEUX does, to improve TAS sync.
|
||||
for (unsigned a = 0; a < 0x800; ++a) CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
for (unsigned a = 0; a < 0x800; ++a)
|
||||
CPU::RAM[a] = (a & 4) ? 0xFF : 0x00;
|
||||
|
||||
// Run the CPU until the program is killed.
|
||||
for (;;) CPU::Op();
|
||||
for (;;)
|
||||
CPU::Op();
|
||||
}
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE* f) {
|
||||
|
|
|
@ -42,6 +42,7 @@ EXAMPLES_PACKAGE_OBJS = \
|
|||
EXAMPLES_PACKAGE_DIRECTDEPS = \
|
||||
EXAMPLES_PACKAGE_LIB \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_STDIO \
|
||||
LIBC_TINYMATH
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ EXAMPLES_PACKAGE_LIB_A_CHECKS = \
|
|||
EXAMPLES_PACKAGE_LIB_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_MEM \
|
||||
LIBC_STDIO
|
||||
|
||||
# Evaluates variable as set of transitive package dependencies.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
#include "third_party/getopt/getopt.internal.h"
|
||||
// clang-format off
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time.h"
|
||||
|
||||
volatile bool gotalrm;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
|
|
|
@ -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
142
examples/trapping.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
1496
examples/unbourne.c
1496
examples/unbourne.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 $<
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue