pax_global_header00006660000000000000000000000064146447331010014515gustar00rootroot0000000000000052 comment=66ebb53ef4fa8aea329e883ea21787a74bdcedf9 hare-0.24.2/000077500000000000000000000000001464473310100125215ustar00rootroot00000000000000hare-0.24.2/.builds/000077500000000000000000000000001464473310100140615ustar00rootroot00000000000000hare-0.24.2/.builds/alpine.yml000066400000000000000000000033761464473310100160650ustar00rootroot00000000000000image: alpine/latest oauth: pages.sr.ht/PAGES:RW packages: - scdoc sources: - git://c9x.me/qbe.git - https://git.sr.ht/~sircmpwn/harec - https://git.sr.ht/~sircmpwn/hare triggers: - action: email condition: failure to: "<~sircmpwn/hare-dev@lists.sr.ht>" tasks: - environment: | cd hare if [ "$BUILD_SUBMITTER" = "git.sr.ht" ] then if [ "$GIT_REF" != "refs/heads/master" ] then complete-build fi if [ "$(git remote get-url origin)" != "https://git.sr.ht/~sircmpwn/hare" ] then complete-build fi fi - signoff: | cd hare if [ "$BUILD_REASON" = "patchset" ] then if ! git log --format='%b' origin/master^^.. | grep 'Signed-off-by' >/dev/null then echo "Patch missing Signed-off-by" exit 1 fi fi - qbe: | cd qbe make -j2 PREFIX=/usr sudo make install PREFIX=/usr - harec: | cd harec cp configs/linux.mk config.mk make -j2 sudo make install - hare: | cd hare cp configs/linux.mk config.mk make -j2 sudo make install - check: | cd hare make -j2 check - check_with_libc: | cd hare hare test -lc - parsechk: | cd hare hare run cmd/parsechk - lint: | cd hare ./scripts/lint.sh - bootstrap: | cd hare make -j2 bootstrap if [ -n "$(git status --porcelain)" ] then echo "bootstrap makefiles out of date, run make bootstrap to regenerate" exit 1 fi - docs: | cd hare make docs/html tar -C docs/html -cvz . > docs.tar.gz if [ $BUILD_SUBMITTER != "git.sr.ht" ] then echo "Not uploading docs for non-git.sr.ht build" exit fi acurl -f https://pages.sr.ht/publish/docs.harelang.org -Fcontent=@docs.tar.gz || true hare-0.24.2/.builds/freebsd.yml000066400000000000000000000016231464473310100162200ustar00rootroot00000000000000image: freebsd/latest sources: - https://git.sr.ht/~sircmpwn/hare - https://git.sr.ht/~sircmpwn/harec - git://c9x.me/qbe.git packages: - binutils - scdoc triggers: - action: email condition: failure to: "<~sircmpwn/hare-dev@lists.sr.ht>" tasks: - environment: | cd hare if [ "$BUILD_SUBMITTER" = "git.sr.ht" ] then if [ "$GIT_REF" != "refs/heads/master" ] then complete-build fi if [ "$(git remote get-url origin)" != "https://git.sr.ht/~sircmpwn/hare" ] then complete-build fi fi - qbe: | cd qbe make -j2 PREFIX=/usr sudo make install PREFIX=/usr - harec: | cd harec cp configs/freebsd.mk config.mk make -j2 sudo make install - hare: | cd hare cp configs/freebsd.mk config.mk make -j2 sudo make install - check: | cd hare make -j2 check - check_with_libc: | cd hare hare test -lc hare-0.24.2/.builds/netbsd.yml000066400000000000000000000020301464473310100160560ustar00rootroot00000000000000image: netbsd/latest sources: - https://git.sr.ht/~sircmpwn/hare - https://git.sr.ht/~sircmpwn/harec - git://c9x.me/qbe.git packages: - binutils - scdoc - git triggers: - action: email condition: failure to: "<~sircmpwn/hare-dev@lists.sr.ht>" tasks: - environment: | cd hare if [ "$BUILD_SUBMITTER" = "git.sr.ht" ] then if [ "$GIT_REF" != "refs/heads/master" ] then complete-build fi if [ "$(git remote get-url origin)" != "https://git.sr.ht/~sircmpwn/hare" ] then complete-build fi fi - ntp-leapseconds: | ftp https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list sudo mv leap-seconds.list /usr/share/zoneinfo/leap-seconds.list - qbe: | cd qbe make -j2 PREFIX=/usr sudo make install PREFIX=/usr - harec: | cd harec cp configs/netbsd.mk config.mk make -j2 sudo make install PREFIX=/usr - hare: | cd hare cp configs/netbsd.mk config.mk make -j2 sudo make install PREFIX=/usr - check: | cd hare make -j2 check hare-0.24.2/.builds/openbsd.yml000066400000000000000000000015461464473310100162440ustar00rootroot00000000000000image: openbsd/latest sources: - https://git.sr.ht/~sircmpwn/hare - https://git.sr.ht/~sircmpwn/harec - git://c9x.me/qbe.git packages: - binutils - scdoc - git triggers: - action: email condition: failure to: "<~sircmpwn/hare-dev@lists.sr.ht>" tasks: - environment: | cd hare if [ "$BUILD_SUBMITTER" = "git.sr.ht" ] then if [ "$GIT_REF" != "refs/heads/master" ] then complete-build fi if [ "$(git remote get-url origin)" != "https://git.sr.ht/~sircmpwn/hare" ] then complete-build fi fi - qbe: | cd qbe make -j2 PREFIX=/usr doas make install PREFIX=/usr - harec: | cd harec cp configs/openbsd.mk config.mk make -j2 doas make install - hare: | cd hare cp configs/openbsd.mk config.mk make -j2 doas make install - check: | cd hare make -j2 check hare-0.24.2/.gitignore000066400000000000000000000000501464473310100145040ustar00rootroot00000000000000config.mk .cache .bin *.1 *.5 docs/html hare-0.24.2/.mailmap000066400000000000000000000000351464473310100141400ustar00rootroot00000000000000Ember Sawady hare-0.24.2/COPYING000066400000000000000000000401511464473310100135550ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. hare-0.24.2/MAINTAINERS000066400000000000000000000053321464473310100142210ustar00rootroot00000000000000Guidelines for subsystem maintainers ------------------------------------ Maintainers have write access to hare-announce, make use of it to announce notable or breaking API changes. Any changes which affect modules outside of your jurisdiction should be subject to some general review before being pushed upstream. Descriptions of section entries and preferred order --------------------------------------------------- M: *Mail* patches to: FullName R: Designated *Reviewer*: FullName These reviewers should be CCed on patches. L: *Mailing list* that is relevant to this area W: *Web-page* with status/info B: URI for where to file *bugs*. A web-page with detailed bug filing info, a direct bug tracker link, or a mailto: URI. C: URI for *chat* protocol, server and channel where developers usually hang out, for example irc://server/channel. P: Subsystem Profile document for more details submitting patches to the given subsystem. This is either an in-tree file, or a URI. T: *SCM* tree location. F: *Files* and directories wildcard patterns. A trailing slash includes all files and subdirectory files. F: drivers/net/ all files in and below drivers/net F: drivers/net/* all files in drivers/net, but not below F: */net/* all files in "any top level directory"/net One pattern per line. Multiple F: lines acceptable. X: *Excluded* files and directories that are NOT maintained, same rules as F:. Files exclusions are tested before file matches. Can be useful for excluding a specific subdirectory, for instance: F: net/ X: net/ipv6/ matches all files in and below net excluding net/ipv6/ N: Notes (free-form) Maintainers List ---------------- .. note:: When reading this list, please look for the most precise areas first. When adding to this list, please keep the entries in alphabetical order. AARCH64 SUPPORT M: Willow Barraco F: *aarch64* CRYPTOGRAPHIC LIBRARY M: Armin Preiml F: crypto/ P: crypto/conventions.txt DATE/TIME SUPPORT M: Byron Torres F: time/ DNS SUPPORT M: Conrad Hoffmann F: net/dns/ MATHEMATICAL LIBRARY M: Bor Grošelj Simić F: math/ NETBSD SUPPORT M: Mallory Adams F: *netbsd* OPENBSD SUPPORT M: Lorenz (xha) F: *openbsd* REGULAR EXPRESSIONS M: Vlad-Stefan Harbuz F: regex/ THE REST M: Drew DeVault M: Ember Sawady M: Sebastian M: Bor Grošelj Simić L: ~sircmpwn/hare-dev@lists.sr.ht T: git https://git.sr.ht/~sircmpwn/hare C: irc://irc.libera.chat/#hare-dev F: * F: */ hare-0.24.2/Makefile000066400000000000000000000065271464473310100141730ustar00rootroot00000000000000.POSIX: all: include config.mk include makefiles/$(PLATFORM).$(ARCH).mk all: $(BINOUT)/hare $(BINOUT)/haredoc docs HARE_DEFINES = \ -D PLATFORM:str='"$(PLATFORM)"' \ -D ARCH:str='"$(ARCH)"' \ -D VERSION:str="\"$(VERSION)\"" \ -D HAREPATH:str='"$(HAREPATH)"' \ -D AARCH64_AS:str='"$(AARCH64_AS)"' \ -D AARCH64_CC:str='"$(AARCH64_CC)"' \ -D AARCH64_LD:str='"$(AARCH64_LD)"' \ -D RISCV64_AS:str='"$(RISCV64_AS)"' \ -D RISCV64_CC:str='"$(RISCV64_CC)"' \ -D RISCV64_LD:str='"$(RISCV64_LD)"' \ -D X86_64_AS:str='"$(X86_64_AS)"' \ -D X86_64_CC:str='"$(X86_64_CC)"' \ -D X86_64_LD:str='"$(X86_64_LD)"' .SUFFIXES: .SUFFIXES: .ha .ssa .td .s .o .scd .ssa.td: @cmp -s '$@' '$@.tmp' 2>/dev/null || cp '$@.tmp' '$@' .ssa.s: @printf 'QBE\t%s\n' '$@' @$(QBE) $(QBEFLAGS) -o '$@' '$<' .s.o: @printf 'AS\t%s\n' '$@' @$(AS) $(ASFLAGS) -o '$@' '$<' .scd: @printf 'SCDOC\t%s\n' '$@' @$(SCDOC) < '$<' > '$@' $(BINOUT)/hare: $(OBJS) @mkdir -p -- "$(BINOUT)" @printf 'LD\t%s\n' "$@" @$(LD) $(LDLINKFLAGS) -T $(RTSCRIPT) -o $@ $(OBJS) HARE_BUILD_ENV = HAREPATH=. HAREC="$(HAREC)" QBE="$(QBE)" AS="$(AS)" \ LD="$(LD)" HAREFLAGS="$(HAREFLAGS)" HARECFLAGS="$(HARECFLAGS)" \ QBEFLAGS="$(QBEFLAGS)" ASFLAGS="$(ASFLAGS)" LDLINKFLAGS="$(LDLINKFLAGS)" $(BINOUT)/haredoc: $(BINOUT)/hare @mkdir -p $(BINOUT) @printf 'HARE\t%s\n' "$@" @env $(HARE_BUILD_ENV) \ $(BINOUT)/hare build $(HARE_DEFINES) -o $(BINOUT)/haredoc ./cmd/haredoc docs/html: $(BINOUT)/haredoc mkdir -p docs/html $(BINOUT)/haredoc -Fhtml > docs/html/index.html for d in $$(scripts/moddirs); do \ find $$d -type d | sed -E '/(\+|-)/d'; \ done \ | while read path; do \ mod=$$(echo $$path | sed -E 's@/@::@g'); \ echo $$mod; \ mkdir -p docs/html/$$path; \ $(BINOUT)/haredoc -Fhtml $$mod > docs/html/$$path/index.html; \ done docs: \ docs/hare.1 \ docs/hare-build.1 \ docs/hare-cache.1 \ docs/hare-deps.1 \ docs/haredoc.1 \ docs/hare-run.1 \ docs/hare-test.1 \ docs/haredoc.5 \ docs/hare-module.5 MAN1 = hare hare-build hare-cache hare-deps haredoc hare-run hare-test MAN5 = haredoc hare-module bootstrap: @BINOUT=$(BINOUT) ./scripts/genbootstrap clean: rm -rf -- '$(HARECACHE)' '$(BINOUT)' docs/*.1 docs/*.5 docs/html check: $(BINOUT)/hare @env HAREPATH=. HAREC='$(HAREC)' QBE='$(QBE)' AS='$(AS)' LD='$(LD)' \ HAREFLAGS='$(HAREFLAGS)' HARECFLAGS='$(HARECFLAGS)' \ QBEFLAGS='$(QBEFLAGS)' ASFLAGS='$(ASFLAGS)' \ LDLINKFLAGS='$(LDLINKFLAGS)' '$(BINOUT)/hare' test install: install-cmd install-mods install-cmd: mkdir -p -- \ '$(DESTDIR)$(BINDIR)' '$(DESTDIR)$(MANDIR)/man1' \ '$(DESTDIR)$(BINDIR)' '$(DESTDIR)$(MANDIR)/man5' install -m755 '$(BINOUT)/hare' '$(DESTDIR)$(BINDIR)/hare' install -m755 '$(BINOUT)/haredoc' '$(DESTDIR)$(BINDIR)/haredoc' for i in $(MAN1); do install -m644 docs/$$i.1 '$(DESTDIR)$(MANDIR)'/man1/$$i.1; done for i in $(MAN5); do install -m644 docs/$$i.5 '$(DESTDIR)$(MANDIR)'/man5/$$i.5; done install-mods: rm -rf -- '$(DESTDIR)$(STDLIB)' mkdir -p -- '$(DESTDIR)$(STDLIB)' cp -R -- $$(scripts/moddirs) '$(DESTDIR)$(STDLIB)' uninstall: rm -- '$(DESTDIR)$(BINDIR)/hare' rm -- '$(DESTDIR)$(BINDIR)/haredoc' for i in $(MAN1); do rm -- '$(DESTDIR)$(MANDIR)'/man1/$$i.1; done for i in $(MAN5); do rm -- '$(DESTDIR)$(MANDIR)'/man5/$$i.5; done rm -r -- '$(DESTDIR)$(STDLIB)' .PHONY: all $(BINOUT)/haredoc bootstrap clean check docs \ docs/html install start uninstall hare-0.24.2/README000066400000000000000000000007711464473310100134060ustar00rootroot00000000000000This is the Hare standard library reference documentation. For a guided introduction to the standard library, see the tutorial: https://harelang.org/tutorials/stdlib The standard library mandate states that the following services are provided: - An interface to the host operating system - Implementations of broadly useful algorithms - Implementations of broadly useful formats and protocols - Useful features to complement Hare language features - Introspective meta-features for Hare-aware programs hare-0.24.2/README.md000066400000000000000000000060771464473310100140120ustar00rootroot00000000000000# The Hare programming language Hare is a systems programming language. ## Installation For information about bootstrapping a working Hare toolchain from scratch, see [Hare Installation][5] on the website. [5]: https://harelang.org/documentation/install/ ## Contributing All contributors are required to "sign-off" their commits (using `git commit -s`) to indicate that they have agreed to the [Developer Certificate of Origin][dco], reproduced below. [dco]: https://developercertificate.org/ ``` Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` Please [send patches](https://git-send-email.io) to the [hare-dev][hare-dev] mailing list to send your changes upstream. [hare-dev]: https://lists.sr.ht/~sircmpwn/hare-dev ## Licensing We are not your lawyer, but here is a simple explanation of the intention behind the Hare licenses. The Hare standard library is available under the terms of the Mozilla Public License (MPL). You can freely link to the standard library with software distributed under any license, but if you modify the standard library, you must release your derivative works under the MPL as well. The executables - the build driver, hare, and the compiler, harec, are available under the GPL 3.0 (but *not* any later version). This permits free use and redistribution, but any changes to it require you to share the derivative work under the terms of the GPL. It is stricter than the MPL; if you link to the compiler or build driver code from a third-party program it will require you to release the third-party code as well. In short, you can write programs in Hare which use the standard library and distribute those programs under any terms you wish. However, if you modify Hare itself, you must share your changes as well. hare-0.24.2/TREES000066400000000000000000000041771464473310100133370ustar00rootroot00000000000000Incomplete list of Hare trees ----------------------------- Hare development is semi-decentralized. Anyone can stand up the infrastructure required to pursue their goals in the project, and various trees are organized and developed independently of upstream before being submitted for broader consideration. Various trees are used by specific maintainers to prepare their changes, by interest groups to maintain some detail (e.g. a specific arch), or temporary trees used to collaborate on large proposals. This document lists notable trees that may be of interest to contributors. Maintainers (see ./MAINTAINERS) are welcome to update this document without review if they want to set up a new tree. Anyone in the Hare community, regardless if they possess committer permissions, is welcome to stand up a tree on their own initiative and send a patch to the hare-dev mailing list adding it here. The format of this document is based on ./MAINTAINERS, see that document for an explanation of the syntax. HARE UPSTREAM M: See ./MAINTAINERS W: https://harelang.org T: git https://git.sr.ht/~sircmpwn/hare L: ~sircmpwn/hare-dev@lists.sr.ht L: ~sircmpwn/hare-discuss@lists.sr.ht L: ~sircmpwn/hare-users@lists.sr.ht C: irc://irc.libera.chat/#hare-dev B: https://todo.sr.ht/~sircmpwn/hare (maintainers only) B: ~sircmpwn/hare-discuss@lists.sr.ht (users) List of permanent trees ----------------------- (none yet?) List of project trees --------------------- STAGING CRYPTO T: git https://git.sr.ht/~apreiml/hare-tls L: https://lists.sr.ht/~apreiml/hare-tls List of personal trees ---------------------- ARMIN PREIML M: Armin Preiml T: git https://git.sr.ht/~apreiml/hare BOR GROŠELJ SIMIĆ M: Bor Grošelj Simić T: git https://git.sr.ht/~turminal/hare BYRON TORRES M: Byron Torres T: git https://git.sr.ht/~torresjrjr/hare EMBER SAWADY M: Ember Sawady T: git https://git.d2evs.net/~ecs/hare T: git https://git.d2evs.net/~ecs/harec B: ecs@d2evs.net N: See TODO in ~ecs/hare SEBASTIAN M: Sebastian T: git https://git.sr.ht/~sebsite/harec-plus-plus (april fools 2024) hare-0.24.2/ascii/000077500000000000000000000000001464473310100136115ustar00rootroot00000000000000hare-0.24.2/ascii/README000066400000000000000000000002461464473310100144730ustar00rootroot00000000000000The ascii module provides helper functions for working with the subset of Unicode which is defined by the American Standard Code for Information Interchange (ASCII). hare-0.24.2/ascii/ctype.ha000066400000000000000000000066541464473310100152620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def U: u8 = 0o1; def L: u8 = 0o2; def N: u8 = 0o4; def S: u8 = 0o10; def P: u8 = 0o20; def C: u8 = 0o40; def B: u8 = 0o100; def X: u8 = 0o200; // LUT of bitfields with character attributes const cclass: []u8 = [ // 0 1 2 3 4 5 6 7 C, C, C, C, C, C, C, C, // 0 C, S|C, S|C, S|C, S|C, S|C, C, C, // 10 C, C, C, C, C, C, C, C, // 20 C, C, C, C, C, C, C, C, // 30 S|B, P, P, P, P, P, P, P, // 40 P, P, P, P, P, P, P, P, // 50 N|X, N|X, N|X, N|X, N|X, N|X, N|X, N|X, // 60 N|X, N|X, P, P, P, P, P, P, // 70 P, U|X, U|X, U|X, U|X, U|X, U|X, U, // 100 U, U, U, U, U, U, U, U, // 110 U, U, U, U, U, U, U, U, // 120 U, U, U, P, P, P, P, P, // 130 P, L|X, L|X, L|X, L|X, L|X, L|X, L, // 140 L, L, L, L, L, L, L, L, // 150 L, L, L, L, L, L, L, L, // 160 L, L, L, P, P, P, P, C, // 170 ]; // Returns true if an ASCII character is a letter. export fn isalpha(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & (U | L) > 0; // Returns true if an ASCII character is uppercase. export fn isupper(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & U > 0; // Returns true if an ASCII character is lowercase. export fn islower(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & L > 0; // Returns true if an ASCII character is a digit. export fn isdigit(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & N > 0; // Returns true if an ASCII character is a hexadecimal digit. export fn isxdigit(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & X > 0; // Returns true if an ASCII character is a white-space character - // one of '\f', '\n', '\r', '\t', '\v', ' '. export fn isspace(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & S > 0; // Returns true if an ASCII character is punctuation. export fn ispunct(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & P > 0; // Returns true if an ASCII character is alphanumeric. export fn isalnum(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & (U | L | N) > 0; // Returns true if an ASCII character is printable. export fn isprint(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & (P | U | L | N | B ) > 0; // Returns true if an ASCII character is any printable character other than // space. export fn isgraph(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & (P | U | L | N) > 0; // Returns true if an ASCII character is a control character. export fn iscntrl(c: rune) bool = if (!valid(c)) false else cclass[c: u32] & C > 0; // Returns true if a rune is a space or a tab. export fn isblank(c: rune) bool = (c == ' ' || c == '\t'); // Returns the uppercase form of an ASCII character, or the original character // if it was not a lowercase letter (or was not ASCII). export fn toupper(c: rune) rune = { return if (islower(c)) { yield (c: u32 - 'a' + 'A'): rune; } else c; }; // Returns the lowercase form of an ASCII character, or the original character // if it was not an uppercase letter (or was not ASCII). export fn tolower(c: rune) rune = { return if (isupper(c)) { yield (c: u32 - 'A' + 'a'): rune; } else c; }; @test fn ctype() void = { // Just some simple tests assert(isspace(' ') && !isspace('x') && !isspace('こ')); assert(isalnum('a') && isalnum('8') && !isalnum('こ')); assert(!ispunct('\0') && iscntrl('\b')); assert(tolower('A') == 'a' && tolower('こ') == 'こ'); assert(isblank(' ') && isblank('\t') && !isblank('6')); }; hare-0.24.2/ascii/string.ha000066400000000000000000000061761464473310100154430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use sort::cmp; use strings; // Converts all ASCII uppercase characters in a string to their lowercase // representation, returning a new string. The return value must be freed by the // caller. export fn strlower(s: str) str = { let new: []u8 = alloc([], len(s)); return strlower_buf(s, new); }; // Converts all ASCII uppercase characters in a string to their lowercase // representation, returning a new string. The new string data is stored in the // supplied buffer. This function will abort if the buffer's length is too small // to fit the entire string. export fn strlower_buf(s: str, buf: []u8) str = { let it = strings::iter(s); for (let r => strings::next(&it)) { static append(buf, utf8::encoderune(tolower(r))...); }; return strings::fromutf8(buf)!; }; // Converts all ASCII lowercase characters in a string to their uppercase // representation, returning a new string. The return value must be freed by the // caller. export fn strupper(s: str) str = { let new: []u8 = alloc([], len(s)); return strupper_buf(s, new); }; // Converts all ASCII lowercase characters in a string to their uppercase // representation, returning a new string. The new string data is stored in the // supplied buffer. This function will abort if the buffer's length is too small // to fit the entire string. export fn strupper_buf(s: str, buf: []u8) str = { let it = strings::iter(s); for (let r => strings::next(&it)) { static append(buf, utf8::encoderune(toupper(r))...); }; return strings::fromutf8(buf)!; }; // Compares two strings by their sort order, treating all ASCII capital letters // as their lowercase counterpart (i.e. an ASCII-case-insensitive comparison is // performed). Zero is returned if the strings are equal, a negative value if a // is less than b, or a positive value if a is greater than b. export fn strcasecmp(a: str, b: str) int = { let abs = strings::toutf8(a); let bbs = strings::toutf8(b); for (let i = 0z; i < len(abs) && i < len(bbs); i += 1) { // you know that i am called "the Cast"... // because i *really* love to cast... // sometimes i sit and cast all day... ha ha, but // sometimes i get carried away! let cmp = tolower(abs[i]: rune): u32: int - tolower(bbs[i]: rune): u32: int; if (cmp != 0) return cmp; }; return cmp::sizes(&len(abs), &len(bbs)); }; @test fn strcasecmp() void = { let s = strupper("ABC"); defer free(s); assert(s == "ABC"); let s = strlower("ABC"); defer free(s); assert(s == "abc"); let s = strupper("abc"); defer free(s); assert(s == "ABC"); let s = strlower("abc"); defer free(s); assert(s == "abc"); let s = strupper("[[["); defer free(s); assert(s == "[[["); let s = strlower("[[["); defer free(s); assert(s == "[[["); let s = strupper("こ"); defer free(s); assert(s == "こ"); let s = strlower("こ"); defer free(s); assert(s == "こ"); assert(strcasecmp("ABC", "ABC") == 0); assert(strcasecmp("ABC", "abc") == 0); assert(strcasecmp("ABC", "aB") > 0); assert(strcasecmp("ab", "Abc") < 0); assert(strcasecmp("bcd", "ABC") > 0); assert(strcasecmp("ABC", "[[[") > 0); }; hare-0.24.2/ascii/valid.ha000066400000000000000000000012651464473310100152260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; // Returns true if a rune is a valid ASCII character. export fn valid(c: rune) bool = c: u32 <= 0o177; // Returns true if all runes in a string are valid ASCII characters. export fn validstr(s: str) bool = { const bytes = strings::toutf8(s); for (let byte .. bytes) { if (byte >= 0o200) { return false; }; }; return true; }; @test fn valid() void = { assert(valid('a') && valid('\0') && valid('\x7F')); assert(!valid('\u0080') && !valid('こ')); assert(validstr("abc\0")); assert(!validstr("š")); assert(!validstr("こんにちは")); assert(!validstr("ABCこんにちは")); }; hare-0.24.2/bufio/000077500000000000000000000000001464473310100136255ustar00rootroot00000000000000hare-0.24.2/bufio/README000066400000000000000000000014421464473310100145060ustar00rootroot00000000000000bufio provides an [[io::stream]] implementation which provides buffered I/O support, utility functions which pair well with buffered streams, and a [[scanner]] type which allocates and maintains its own read buffer. A buffered [[stream]] is used to batch read and write operations against an underlying [[io::handle]]. bufio provides several utilities for reading from handles, namely [[read_tok]] et al. These functions require small, frequent reads, or take advantage of look-ahead, and thus are most efficient when paired with a buffered [[stream]]. bufio also provides a "scanning" interface, with functions like [[scan_string]] which take in a [[scanner]]. Strings returned from scanning functions are borrowed from the scanner's read buffer, so allocated memory can be reused for future scans. hare-0.24.2/bufio/scanner.ha000066400000000000000000000215361464473310100155770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; use errors; use io; use strings; use types; def BUFSZ: size = 4096; const scanner_vtable = io::vtable { reader = &scan_read, ... }; export type scanner = struct { stream: io::stream, src: io::handle, buffer: []u8, // Index of start of pending bytes in buffer start: size, // Sub-slice with pending bytes in buffer pending: []u8, // User-confirmed maximum size of read buffer maxread: size, }; // Creates a new [[scanner]] which will allocate and maintain a read buffer for // efficient reading of a handle. The scanner will read ahead only up to maxread // bytes, which defaults to [[types::SIZE_MAX]] if no limit is required. The // user must free resources associated with the scanner using [[finish]] after // use. // // Reads from the scanner will return [[errors::overflow]] if maxread is // reached. export fn newscanner( src: io::handle, maxread: size = types::SIZE_MAX, ) scanner = { return scanner { stream = &scanner_vtable, src = src, buffer = alloc([0...], BUFSZ), maxread = maxread, start = 0, pending = [], }; }; // Creates a new [[scanner]] using a user-provided buffer. The scanner will // return [[errors::overflow]] if the buffer length is reached, but will not // perform any allocations. The user should not call [[finish]] after use unless // they wish to free the underlying buffer through bufio. export fn newscanner_static(src: io::handle, buffer: []u8) scanner = { return scanner { stream = &scanner_vtable, src = src, buffer = buffer, maxread = len(buffer), start = 0, pending = [], }; }; // Frees resources associated with a [[scanner]]. Does not close the underlying // I/O handle. export fn finish(scan: *scanner) void = { free(scan.buffer); }; fn scan_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let scan = s: *scanner; if (len(scan.pending) == 0) { match (scan_readahead(scan)?) { case io::EOF => return io::EOF; case size => void; }; }; const n = if (len(buf) > len(scan.pending)) len(scan.pending) else len(buf); buf[..n] = scan_consume(scan, n)[..]; return n; }; // Fills up the scanner buffer with data from the underlying I/O handle. If no // space remains in the read buffer, it is expanded by BUFSZ (up to maxread). // Then, one read from the underlying I/O handle is performed and scan.pending // is updated accordingly. Returns the number of bytes which had been available // prior to the call. fn scan_readahead(scan: *scanner) (size | io::EOF | io::error) = { let start = scan.start; const pending = len(scan.pending); if (start + pending == len(scan.buffer)) { if (start > 0) { // Shift buffer to the left to free space at the end scan.buffer[..len(scan.buffer) - start] = scan.buffer[start..]; scan.pending = scan.buffer[..pending]; start = 0; scan.start = 0; } else { // Buffer is full, expand it let readahead = pending + BUFSZ; if (readahead > scan.maxread) { readahead = scan.maxread; }; if (pending >= readahead) { return errors::overflow; }; append(scan.buffer, [0...], readahead); }; }; match (io::read(scan.src, scan.buffer[start + pending..])?) { case let z: size => scan.pending = scan.buffer[start..start + pending + z]; return pending; case io::EOF => return io::EOF; }; }; // Consumes N bytes from the buffer. fn scan_consume(scan: *scanner, n: size) []u8 = { assert(len(scan.pending) >= n); scan.start += n; defer scan.pending = scan.pending[n..]; return scan.pending[..n]; }; // Reads one byte from a [[scanner]]. export fn scan_byte(scan: *scanner) (u8 | io::EOF | io::error) = { if (len(scan.pending) == 0) { match (scan_readahead(scan)?) { case io::EOF => return io::EOF; case size => void; }; }; return scan_consume(scan, 1)[0]; }; // Reads the next token from a [[scanner]], delimited by delim. The delimiter is // read from the source handle but not included in the returned slice. The // return value is borrowed from the internal scanner buffer, which is // invalidated during subsequent operations which use this scanner. export fn scan_bytes( scan: *scanner, delim: (u8 | []u8), ) ([]u8 | io::EOF | io::error) = { let i = 0z; for (true) { match (bytes::index(scan.pending[i..], delim)) { case let ix: size => i += ix; break; case void => void; }; match (scan_readahead(scan)?) { case io::EOF => if (len(scan.pending) == 0) { return io::EOF; }; return scan_consume(scan, len(scan.pending)); case let prevpending: size => // No need to re-index the earlier part of the buffer i = prevpending; }; }; const ndelim = match (delim) { case u8 => yield 1z; case let u: []u8 => yield len(u); }; const nconsume = i + ndelim; return scan_consume(scan, nconsume)[..i]; }; // Reads one rune from a [[scanner]]. export fn scan_rune( scan: *scanner, ) (rune | io::EOF | io::error | utf8::invalid) = { if (len(scan.pending) < 4) { match (scan_readahead(scan)?) { case io::EOF => if (len(scan.pending) == 0) { return io::EOF; }; case size => void; }; }; const sz = utf8::utf8sz(scan.pending[0])?; if (len(scan.pending) < sz) { return utf8::invalid; }; const buf = scan_consume(scan, sz); const dec = utf8::decode(buf[..sz]); match (utf8::next(&dec)?) { case let r: rune => return r; case done => return io::EOF; case utf8::more => return utf8::invalid; }; }; // Scans a string of text from a [[scanner]] up to some delimiter. The delimiter // is read from the source handle but not included in the returned string. The // return value is borrowed from the internal scanner buffer, which is // invalidated during subsequent operations which use this scanner. export fn scan_string( scan: *scanner, delim: str, ) (const str | io::EOF | io::error | utf8::invalid) = { const token = match (scan_bytes(scan, strings::toutf8(delim))?) { case let token: []u8 => yield token; case io::EOF => return io::EOF; }; return strings::fromutf8(token)?; }; // Scans the next line of text from a [[scanner]]. The return value is borrowed // from the internal scanner buffer, which is invalidated during subsequent // operations which use this scanner. export fn scan_line( scan: *scanner, ) (const str | io::EOF | io::error | utf8::invalid) = { return scan_string(scan, "\n"); }; // Returns the internal scanner buffer, which contains all bytes read ahead by // the scanner up to this point. export fn scan_buffer(scan: *scanner) []u8 = { return scan.pending[..]; }; fn scan_unread(scan: *scanner, buf: []u8) void = { if (len(buf) == 0) { return; }; if (len(buf) <= scan.start) { const pending_end = scan.start + len(scan.pending); scan.buffer[scan.start - len(buf)..scan.start] = buf; scan.start -= len(buf); scan.pending = scan.buffer[scan.start..pending_end]; } else { assert(len(buf) <= len(scan.buffer) - len(scan.pending), "Attempted to unread more data than buffer has available"); // Shift buffer to the right to free space at the beginning scan.buffer[len(buf)..len(buf) + len(scan.pending)] = scan.buffer[scan.start..scan.start + len(scan.pending)]; scan.buffer[..len(buf)] = buf; scan.pending = scan.buffer[..len(scan.pending) + len(buf)]; scan.start = 0; }; }; // Reads a single byte from an [[io::handle]]. export fn read_byte(h: io::handle) (u8 | io::EOF | io::error) = { let buf: [1]u8 = [0...]; match (io::readall(h, buf)?) { case size => return buf[0]; case io::EOF => return io::EOF; }; }; // Reads a slice of bytes until the delimiter. Delimiter is not included but // it is read from the handle. The return value must be freed by the caller. export fn read_tok(h: io::handle, delim: u8...) ([]u8 | io::EOF | io::error) = { let buf: []u8 = []; for (true) { match (read_byte(h)?) { case let res: u8 => if (bytes::contains(delim, res)) { break; }; append(buf, res); case io::EOF => if (len(buf) == 0) { return io::EOF; }; break; }; }; return buf; }; // Reads a slice of bytes until a newline character (\n, 0x0A). Newline itself // is not included but it is read from the handle. The return value must be // freed by the caller. export fn read_line(h: io::handle) ([]u8 | io::EOF | io::error) = read_tok(h, '\n'); // Reads a rune from a UTF-8 stream. export fn read_rune( h: io::handle, ) (rune | utf8::invalid | io::EOF | io::error) = { let b: [4]u8 = [0...]; match (io::readall(h, b[..1])?) { case let n: size => void; case io::EOF => return io::EOF; }; const sz = utf8::utf8sz(b[0])?; if (sz == 1) { return b[0]: rune; }; match (io::readall(h, b[1..sz])) { case let n: size => void; case io::EOF => return io::EOF; case let err: io::error => return if (err is io::underread) utf8::invalid else err; }; let dec = utf8::decode(b[..sz]); match (utf8::next(&dec)?) { case let r: rune => return r; case done => return io::EOF; case utf8::more => return utf8::invalid; }; }; hare-0.24.2/bufio/scanner_test+test.ha000066400000000000000000000104701464473310100176040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; use io; use memio; use strings; @test fn read_byte() void = { let buf = memio::fixed([1, 3, 3, 7]); assert(read_byte(&buf) as u8 == 1); assert(read_byte(&buf) as u8 == 3); assert(read_byte(&buf) as u8 == 3); assert(read_byte(&buf) as u8 == 7); assert(read_byte(&buf) is io::EOF); }; @test fn read_tok() void = { let buf = memio::fixed([1, 3, 4, 5, 3, 7]); let tok = read_tok(&buf, 4) as []u8; defer free(tok); assert(bytes::equal(tok, [1, 3])); let tok = read_tok(&buf, 7) as []u8; defer free(tok); assert(bytes::equal(tok, [5, 3])); assert(read_tok(&buf, 1) is io::EOF); }; @test fn read_line() void = { let helloworld = strings::toutf8("hello\nworld"); let buf = memio::fixed(helloworld); let line = read_line(&buf) as []u8; defer free(line); assert(bytes::equal(line, strings::toutf8("hello"))); let line = read_line(&buf) as []u8; defer free(line); assert(bytes::equal(line, strings::toutf8("world"))); assert(read_line(&buf) is io::EOF); }; @test fn read_rune() void = { let in = memio::fixed([ 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xA1, 0xE3, 0x81, 0xAF, 0x00, ]); const expected: [_](rune | utf8::invalid | io::EOF | io::error) = [ 'こ', 'ん', 'に', 'ち', 'は', '\0', io::EOF, ]; for (let i = 0z; i < len(expected); i += 1) { let want = expected[i]; match (read_rune(&in)) { case let r: rune => assert(want is rune && want as rune == r); case io::EOF => assert(want is io::EOF); case => abort(); }; }; }; @test fn scan_rune() void = { let in = memio::fixed(strings::toutf8("hello")); let scanner = newscanner(&in, 32); defer finish(&scanner); const expected: [_](rune | utf8::invalid | io::EOF | io::error) = [ 'h', 'e', 'l', 'l', 'o', io::EOF, ]; for (let i = 0z; i < len(expected); i += 1) { let want = expected[i]; match (scan_rune(&scanner)) { case let r: rune => assert(want is rune && want as rune == r); case io::EOF => assert(want is io::EOF); case => abort(); }; }; }; @test fn scan_rune_cutoff() void = { let in = memio::fixed([ 'a', 0xE3, ]); let scanner = newscanner(&in, 32); defer finish(&scanner); const expected: [_](rune | utf8::invalid | io::EOF | io::error) = [ 'a', utf8::invalid, ]; for (let i = 0z; i < len(expected); i += 1) { let want = expected[i]; match (scan_rune(&scanner)) { case let r: rune => assert(want is rune && want as rune == r); case io::EOF => assert(want is io::EOF); case utf8::invalid => assert(want is utf8::invalid); case => abort(); }; }; }; @test fn scan_byte() void = { let in = memio::fixed([1, 2, 3]); let scanner = newscanner(&in, 3); defer finish(&scanner); assert(scan_byte(&scanner) as u8 == 1); assert(scan_byte(&scanner) as u8 == 2); assert(scan_byte(&scanner) as u8 == 3); assert(scan_byte(&scanner) is io::EOF); }; @test fn scan_read() void = { const expected: [_]u8 = [ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, ]; let in = memio::fixed(expected); let scanner = newscanner(&in, 2); defer finish(&scanner); let result = io::drain(&scanner)!; defer free(result); assert(bytes::equal(expected, result)); }; @test fn scan_unread() void = { const expected: str = " I will not repeat \nDone!\n"; let in = memio::fixed(strings::toutf8(expected)); let scanner = newscanner(&in, 32); defer finish(&scanner); let b = scan_byte(&scanner) as u8; unread(&scanner, [b]); let b = scan_rune(&scanner) as rune; unread(&scanner, utf8::encoderune(b)); let l = scan_line(&scanner)! as const str; assert(l == " I will not repeat "); unread(&scanner, strings::toutf8("\n")); unread(&scanner, strings::toutf8(l)); let l = scan_line(&scanner)! as const str; assert(l == " I will not repeat "); unread(&scanner, strings::toutf8("\n")); unread(&scanner, strings::toutf8(strings::trim(l))); let l = scan_line(&scanner)! as const str; assert(l == "I will not repeat"); unread(&scanner, strings::toutf8("See?\n")); let l = scan_line(&scanner)! as const str; assert(l == "See?"); let b = scan_rune(&scanner) as rune; unreadrune(&scanner, b); unreadrune(&scanner, ' '); unread(&scanner, strings::toutf8("I'm")); let l = scan_line(&scanner)! as const str; assert(l == "I'm Done!"); assert(scan_line(&scanner) is io::EOF); }; hare-0.24.2/bufio/stream.ha000066400000000000000000000133671464473310100154440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use errors; use io; const vtable_r: io::vtable = io::vtable { closer = &close_static, reader = &read, ... }; const vtable_w: io::vtable = io::vtable { closer = &close_static, writer = &write, ... }; const vtable_rw: io::vtable = io::vtable { closer = &close_static, reader = &read, writer = &write, ... }; export type stream = struct { stream: io::stream, source: io::handle, rbuffer: []u8, wbuffer: []u8, rpos: size, ravail: size, wavail: size, flush: []u8, }; // Creates a stream which buffers reads and writes for the underlying stream. // This is generally used to improve performance of small reads/writes for // sources where I/O operations are costly, such as if they invoke a syscall or // take place over the network. // // The caller should supply one or both of a read and write buffer as a slice of // the desired buffer, or empty slices if read or write functionality is // disabled. The same buffer may not be used for both reads and writes. // // The caller is responsible for closing the underlying stream, and freeing the // provided buffers if necessary, after the buffered stream is closed. // // let rbuf: [os::BUFSZ]u8 = [0...]; // let wbuf: [os::BUFSZ]u8 = [0...]; // let buffered = bufio::init(source, rbuf, wbuf); export fn init( src: io::handle, rbuf: []u8, wbuf: []u8, ) stream = { static let flush_default = ['\n': u8]; let st = if (len(rbuf) != 0 && len(wbuf) != 0) { assert(rbuf: *[*]u8 != wbuf: *[*]u8, "Cannot use same buffer for reads and writes"); yield &vtable_rw; } else if (len(rbuf) != 0) { yield &vtable_r; } else if (len(wbuf) != 0) { yield &vtable_w; } else { abort("Must provide at least one buffer"); }; return stream { stream = st, source = src, rbuffer = rbuf, wbuffer = wbuf, flush = flush_default, rpos = len(rbuf), // necessary for unread() before read() ... }; }; // Flushes pending writes to the underlying stream. export fn flush(s: io::handle) (void | io::error) = { let s = match (s) { case let st: *io::stream => if (st.writer != &write) { return errors::unsupported; }; yield st: *stream; case => return errors::unsupported; }; if (s.wavail == 0) { return; }; io::writeall(s.source, s.wbuffer[..s.wavail])?; s.wavail = 0; return; }; // Sets the list of bytes which will cause the stream to flush when written. By // default, the stream will flush when a newline (\n) is written. export fn setflush(s: io::handle, b: []u8) void = { let s = match (s) { case let st: *io::stream => if (st.writer != &write) { abort("Attempted to set flush bytes on unbuffered stream"); }; yield st: *stream; case => abort("Attempted to set flush bytes on unbuffered stream"); }; s.flush = b; }; // "Unreads" a slice of bytes, such that the next call to "read" will return // these bytes before reading any new data from the underlying source. The // unread data must fit into the read buffer's available space. The amount of // data which can be unread before the user makes any reads from a buffered // stream is equal to the length of the read buffer, and otherwise it is equal // to the length of the return value of the last call to [[io::read]] using this // buffered stream. Attempting to unread more data than can fit into the read // buffer will abort the program. export fn unread(s: io::handle, buf: []u8) void = { match (s) { case let st: *io::stream => switch (st.reader) { case &read => stream_unread(s: *stream, buf); case &scan_read => scan_unread(s: *scanner, buf); case => abort("Attempted unread on unbuffered stream"); }; case => abort("Attempted unread on unbuffered stream"); }; }; fn stream_unread(s: *stream, buf: []u8) void = { assert(s.rpos >= len(buf), "Attempted to unread more data than buffer has available"); s.rbuffer[s.rpos - len(buf)..s.rpos] = buf; s.rpos -= len(buf); s.ravail += len(buf); }; // Unreads a rune; see [[unread]]. export fn unreadrune(s: io::handle, rn: rune) void = { const buf = utf8::encoderune(rn); unread(s, buf); }; // Returns true if an [[io::handle]] is a [[stream]]. export fn isbuffered(in: io::handle) bool = { match (in) { case io::file => return false; case let st: *io::stream => return st.reader == &read || st.writer == &write; }; }; fn close_static(s: *io::stream) (void | io::error) = { assert(s.closer == &close_static); if (s.writer != null) { flush(s: *stream)?; }; }; fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { assert(s.reader == &read); let s = s: *stream; if (s.ravail < len(buf) && s.ravail < len(s.rbuffer)) { s.rbuffer[..s.ravail] = s.rbuffer[s.rpos..s.rpos + s.ravail]; s.rpos = 0; match (io::read(s.source, s.rbuffer[s.ravail..])) { case let err: io::error => return err; case io::EOF => if (s.ravail == 0) { return io::EOF; }; case let z: size => s.ravail += z; }; }; const n = if (len(buf) < s.ravail) len(buf) else s.ravail; buf[..n] = s.rbuffer[s.rpos..s.rpos + n]; s.rpos += n; s.ravail -= n; return n; }; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { assert(s.writer == &write); let s = s: *stream; let buf = buf; let doflush = false; if (len(s.flush) != 0) { for :search (let i = 0z; i < len(buf); i += 1) { for (let j = 0z; j < len(s.flush); j += 1) { if (buf[i] == s.flush[j]) { doflush = true; break :search; }; }; }; }; let z = 0z; for (len(buf) > 0) { let avail = len(s.wbuffer) - s.wavail; if (avail == 0) { flush(s)?; avail = len(s.wbuffer); }; const n = if (avail < len(buf)) avail else len(buf); s.wbuffer[s.wavail..s.wavail + n] = buf[..n]; buf = buf[n..]; s.wavail += n; z += n; }; if (doflush) { flush(s)?; }; return z; }; hare-0.24.2/bufio/stream_test+test.ha000066400000000000000000000063101464473310100174440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; use strings; @test fn read() void = { let sourcebuf: []u8 = [1, 3, 3, 7]; let source = memio::fixed(sourcebuf); defer io::close(&source)!; let rbuf: [1024]u8 = [0...]; let f = init(&source, rbuf, []); defer io::close(&f)!; let buf: [1024]u8 = [0...]; assert(io::read(&f, buf[..2]) as size == 2); assert(source.pos == len(source.buf), "fixed stream was not fully consumed"); assert(bytes::equal(buf[..2], [1, 3])); assert(io::read(&f, buf[2..]) as size == 2); assert(bytes::equal(buf[..4], [1, 3, 3, 7])); assert(io::read(&f, buf) is io::EOF); let sourcebuf: [32]u8 = [1, 3, 3, 7, 0...]; let source = memio::fixed(sourcebuf); let rbuf: [16]u8 = [0...]; let f = init(&source, rbuf, []); defer io::close(&f)!; let buf: [32]u8 = [0...]; assert(io::read(&f, buf) as size == 16); assert(source.pos == 16); assert(io::read(&f, buf[16..]) as size == 16); assert(bytes::equal(buf, sourcebuf)); assert(io::read(&f, buf) is io::EOF); assert(source.pos == len(source.buf)); }; @test fn write() void = { // Normal case let sink = memio::dynamic(); defer io::close(&sink)!; let wbuf: [1024]u8 = [0...]; let f = init(&sink, [], wbuf); defer io::close(&f)!; assert(io::writeall(&f, [1, 3, 3, 7]) as size == 4); assert(len(memio::buffer(&sink)) == 0); assert(io::writeall(&f, [1, 3, 3, 7]) as size == 4); assert(flush(&f) is void); assert(bytes::equal(memio::buffer(&sink), [1, 3, 3, 7, 1, 3, 3, 7])); // Test flushing via buffer exhaustion let sink = memio::dynamic(); defer io::close(&sink)!; let wbuf: [4]u8 = [0...]; let f = init(&sink, [], wbuf); assert(io::writeall(&f, [1, 3, 3, 7]) as size == 4); assert(len(memio::buffer(&sink)) == 0); assert(io::writeall(&f, [1, 3, 3, 7]) as size == 4); assert(bytes::equal(memio::buffer(&sink), [1, 3, 3, 7])); io::close(&f)!; // Should flush assert(bytes::equal(memio::buffer(&sink), [1, 3, 3, 7, 1, 3, 3, 7])); // Test flushing via flush characters let sink = memio::dynamic(); defer io::close(&sink)!; let wbuf: [1024]u8 = [0...]; let f = init(&sink, [], wbuf); assert(io::writeall(&f, strings::toutf8("hello")) as size == 5); assert(len(memio::buffer(&sink)) == 0); assert(io::writeall(&f, strings::toutf8(" world!\n")) as size == 8); assert(bytes::equal(memio::buffer(&sink), strings::toutf8("hello world!\n"))); }; @test fn unread() void = { let rbuf: [8]u8 = [0...]; let f = init(io::zero, rbuf, []); let buf: [16]u8 = [42...]; assert(io::read(&f, buf[..4]) as size == 4); assert(buf[0] == 0); assert(buf[1] == 0); assert(buf[2] == 0); assert(buf[3] == 0); unread(&f, [1, 2, 3, 4]); assert(io::read(&f, buf[..8]) as size == 8); assert(buf[0] == 1); assert(buf[1] == 2); assert(buf[2] == 3); assert(buf[3] == 4); assert(buf[4] == 0); assert(buf[5] == 0); assert(buf[6] == 0); assert(buf[7] == 0); assert(io::read(&f, buf) as size == 8); for (let i = 0z; i < 8; i += 1) { assert(buf[i] == 0); }; let input: []u8 = [1, 2, 3, 4]; let f = init(&memio::fixed(input), rbuf, []); assert(io::read(&f, buf) as size == 4); unread(&f, [1, 2, 3, 4]); assert(io::read(&f, buf) as size == 4); assert(io::read(&f, buf) is io::EOF); }; hare-0.24.2/bytes/000077500000000000000000000000001464473310100136475ustar00rootroot00000000000000hare-0.24.2/bytes/README000066400000000000000000000001251464473310100145250ustar00rootroot00000000000000The bytes module provides support functions for working with slices of bytes ([]u8). hare-0.24.2/bytes/contains.ha000066400000000000000000000025371464473310100160060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returns true if a byte slice contains a byte or a sequence of bytes. export fn contains(haystack: []u8, needles: (u8 | []u8)...) bool = { for (let i = 0z; i < len(needles); i += 1) { const matched = match (needles[i]) { case let b: u8 => yield index_byte(haystack, b) is size; case let b: []u8 => yield index_slice(haystack, b) is size; }; if (matched) { return true; }; }; return false; }; // Returns true if "in" has the given prefix, false otherwise export fn hasprefix(in: []u8, prefix: []u8) bool = { return len(in) >= len(prefix) && equal(in[..len(prefix)], prefix); }; @test fn hasprefix() void = { assert(hasprefix([], [])); assert(hasprefix([0], [])); assert(!hasprefix([], [0])); assert(hasprefix([1, 2, 3], [1, 2])); assert(!hasprefix([1, 2, 3], [1, 1])); assert(!hasprefix([1, 2, 3], [1, 2, 3, 4])); }; // Returns true if "in" has the given suffix, false otherwise export fn hassuffix(in: []u8, suffix: []u8) bool = { return len(in) >= len(suffix) && equal(in[len(in) - len(suffix)..], suffix); }; @test fn hassuffix() void = { assert(hassuffix([], [])); assert(hassuffix([0], [])); assert(!hassuffix([], [0])); assert(hassuffix([1, 2, 3], [2, 3])); assert(!hassuffix([1, 2, 3], [2, 2])); assert(hassuffix([1, 2, 3, 4], [2, 3, 4])); }; hare-0.24.2/bytes/equal.ha000066400000000000000000000013621464473310100152720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returns true if the two byte sequences are identical. // // This function should NOT be used with sensitive data such as cryptographic // hashes. In such a case, the constant-time [[crypto::compare]] should be used // instead. export fn equal(a: []u8, b: []u8) bool = { if (len(a) != len(b)) { return false; }; for (let i = 0z; i < len(a); i += 1) { if (a[i] != b[i]) { return false; }; }; return true; }; @test fn equal() void = { let a: []u8 = [1, 2, 3]; let b: []u8 = [1, 2, 3]; let c: []u8 = [1, 4, 5]; let d: []u8 = [1, 2, 3, 4]; let e: []u8 = [1, 2]; assert(equal(a, b)); assert(!equal(a, c)); assert(!equal(a, d)); assert(!equal(a, e)); }; hare-0.24.2/bytes/index.ha000066400000000000000000000150711464473310100152740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returns the offset of the first instance of "needle" in a "haystack" of // bytes, or void if it is not found. export fn index(haystack: []u8, needle: (u8 | []u8)) (size | void) = { return match (needle) { case let b: u8 => yield index_byte(haystack, b); case let b: []u8 => yield index_slice(haystack, b); }; }; fn index_byte(haystack: []u8, needle: u8) (size | void) = { for (let i = 0z; i < len(haystack); i += 1) { if (haystack[i] == needle) { return i; }; }; }; fn index_2bytes(haystack: []u8, needle: u16) (size | void) = { if (len(haystack) > 1) { let x = haystack[0]: u16; for (let i = 1z; i < len(haystack); i += 1) { x = x << 8 | haystack[i]; if (x == needle) { return i - 1; }; }; }; }; fn index_3bytes(haystack: []u8, needle: u32) (size | void) = { if (len(haystack) > 2) { let x = haystack[0]: u32 << 8 | haystack[1]; for (let i = 2z; i < len(haystack); i += 1) { x = x << 16 >> 8 | haystack[i]; if (x == needle) { return i - 2; }; }; }; }; fn index_4bytes(haystack: []u8, needle: u32) (size | void) = { if (len(haystack) > 3) { let x = haystack[0]: u32 << 16 | haystack[1]: u32 << 8 | haystack[2]; for (let i = 3z; i < len(haystack); i += 1) { x = x << 8 | haystack[i]; if (x == needle) { return i - 3; }; }; }; }; fn index_slice(haystack: []u8, b: []u8) (size | void) = { switch (len(b)) { case 0 => return 0; case 1 => return index_byte(haystack, b[0]); case 2 => return index_2bytes(haystack, b[0]: u16 << 8 | b[1]); case 3 => return index_3bytes( haystack, b[0]: u32 << 16 | b[1]: u32 << 8 | b[2], ); case 4 => return index_4bytes( haystack, b[0]: u32 << 24 | b[1]: u32 << 16 | b[2]: u32 << 8 | b[3], ); case => return index_tw(haystack, b); }; }; // Returns the offset of the last instance of "needle" in a "haystack" of // bytes, or void if it is not found. export fn rindex(haystack: []u8, needle: (u8 | []u8)) (size | void) = { match (needle) { case let b: u8 => return rindex_byte(haystack, b); case let b: []u8 => return rindex_slice(haystack, b); }; }; fn rindex_byte(haystack: []u8, needle: u8) (size | void) = { for (let i = len(haystack); i > 0; i -= 1) { if (haystack[i - 1] == needle) { return i - 1; }; }; }; fn rindex_slice(haystack: []u8, needle: []u8) (size | void) = { for (let i = 0z; i + len(needle) <= len(haystack); i += 1) { let r = len(haystack) - i; if (equal(haystack[r - len(needle)..r], needle)) { return r - len(needle); }; }; }; @test fn index() void = { // Bytes const a: [4]u8 = [1, 3, 3, 7]; assert(index(a, 7) as size == 3); assert(index(a, 42) is void); assert(index([], 42) is void); assert(rindex(a, 3) as size == 2); assert(rindex(a, 42) is void); assert(rindex([], 42) is void); // Slices const a: [4]u8 = [1, 1, 1, 2]; assert(rindex(a, [1, 1]) as size == 1); assert(rindex(a, [1, 2]) as size == 2); // len(haystack) < len(needle) assert(index([], [1, 2, 3]) is void); assert(index([1, 2, 3], [1, 2, 3, 4]) is void); // len(haystack) == len(needle) assert(index([42, 20], [42, 20]) as size == 0); assert(index([1, 1, 1, 2], [1, 1, 1, 3]) is void); assert(index([1, 42, 24], [42, 24]) as size == 1); assert(index([1, 3, 3, 7], [3, 3]) as size == 1); assert(index([1, 1, 1, 2], [1, 1, 2]) as size == 1); assert(index([1, 1, 1, 3, 2], [1, 1, 1, 2]) is void); const tests: [_](str, str) = [ ("3214567844", "0123456789"), ("3214567889012345", "0123456789012345"), ("32145678890123456789", "01234567890123456789"), ("32145678890123456789012345678901234567890211", "01234567890123456789012345678901"), ("321456788901234567890123456789012345678911", "0123456789012345678901234567890"), ("abc", "x"), ("oxoxoxoxoxoxoxoxoxoxoxox", "oy"), ("x", "a"), ("x01234567x89", "0123456789"), ("xabcqxq", "abcqq"), ("xabxc", "abc"), ("xabxcqq", "abcqq"), ("xbc", "abc"), ("xbcd", "abcd"), ("xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx"), ("xyz012345678", "0123456789"), ("xyz0123456789012345678", "01234567890123456789"), ("xyz0123456789012345678901234567890", "01234567890123456789012345678901"), ]; for (let i = 0z; i < len(tests); i += 1) { let haystack = *(&tests[i].0: *[]u8); let needle = *(&tests[i].1: *[]u8); index(haystack, needle) as void; }; const tests: [_](str, str, size) = [ ("", "", 0), ("01234567", "01234567", 0), ("0123456789", "0123456789", 0), ("0123456789012345", "0123456789012345", 0), ("01234567890123456789", "01234567890123456789", 0), ("0123456789012345678901234567890", "0123456789012345678901234567890", 0), ("01234567890123456789012345678901", "01234567890123456789012345678901", 0), ("ab", "ab", 0), ("abc", "a", 0), ("abc", "abc", 0), ("abc", "b", 1), ("abc", "c", 2), ("abcABCabc", "A", 3), ("abcd", "abcd", 0), ("abcqq", "abcqq", 0), ("barfoobarfoo", "foo", 3), ("foo", "", 0), ("foo", "foo", 0), ("foo", "o", 1), ("oofofoofooo", "f", 2), ("oofofoofooo", "foo", 4), ("oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22), ("x", "x", 0), ("x01234567", "01234567", 1), ("x0123456789", "0123456789", 1), ("x0123456789012345", "0123456789012345", 1), ("x01234567890123456789", "01234567890123456789", 1), ("x0123456789012345678901234567890", "0123456789012345678901234567890", 1), ("x01234567890123456789012345678901", "01234567890123456789012345678901", 1), ("x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33), ("x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32), ("x0123456789012345678x01234567890123456789", "01234567890123456789", 21), ("x012345678901234x0123456789012345", "0123456789012345", 17), ("x012345678x0123456789", "0123456789", 11), ("x0123456x01234567", "01234567", 9), ("xab", "ab", 1), ("xabc", "abc", 1), ("xabcd", "abcd", 1), ("xabcqq", "abcqq", 1), ("xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2), ("xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65), ("xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6), ]; for (let i = 0z; i < len(tests); i += 1) { let haystack = *(&tests[i].0: *[]u8); let needle = *(&tests[i].1: *[]u8); assert(index(haystack, needle) as size == tests[i].2); }; }; hare-0.24.2/bytes/reverse.ha000066400000000000000000000011021464473310100156260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Reverses a slice of bytes in place. export fn reverse(b: []u8) void = { for (let i = 0z; i < len(b) / 2; i += 1) { let x = b[i]; b[i] = b[len(b) - i - 1]; b[len(b) - i - 1] = x; }; }; @test fn reverse() void = { let b: [4]u8 = [1, 3, 3, 7]; reverse(b); assert(equal(b, [7, 3, 3, 1])); let b: [5]u8 = [1, 2, 3, 4, 5]; reverse(b); assert(equal(b, [5, 4, 3, 2, 1])); let b: [1]u8 = [1]; reverse(b); assert(equal(b, [1])); let b: []u8 = []; reverse(b); assert(equal(b, [])); }; hare-0.24.2/bytes/tokenize.ha000066400000000000000000000165731464473310100160250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; export type tokenizer = struct { in: []u8, // string being tokenized delim: []u8, // delimiter p: i64, // p < 0 for reverse tokenizers, 0 <= p for forward ones. }; // Tokenizes a byte slice, returning an iterator that yields tokens from the // slice delimited by one of any number of delimiter bytes. If the input slice // begins with or ends with a delimiter, an empty slice is returned respectively // as the first and last call to [[next_token]]. // // The variadic argument slice is borrowed from the caller, who should take care // to ensure that it is valid for the lifetime of the tokenizer. // // The caller must ensure that at least one delimiter is provided and that the // length of the slice is less than [[types::I64_MAX]]. export fn tokenize(in: []u8, delim: u8...) tokenizer = { assert(len(delim) > 0, "bytes::tokenize called with empty slice"); assert(len(in) < types::I64_MAX: size, "bytes::tokenize: input length exceeds I64_MAX"); if (len(in) == 0) { delim = []; }; return tokenizer { in = in, delim = delim, p = types::I64_MAX, // I64_MAX means we haven't peeked the next token yet. }; }; // Like [[tokenize]], but tokenizes the slice in reverse, such that the first // call to [[next_token]] returns the last token and the last call returns the // first token. export fn rtokenize(in: []u8, delim: u8...) tokenizer = { assert(len(delim) > 0, "bytes::rtokenize called with empty slice"); assert(len(in) < types::I64_MAX: size, "bytes::rtokenize: input length exceeds I64_MAX"); if (len(in) == 0) { delim = []; }; return tokenizer { in = in, delim = delim, // I64_MIN means we haven't peeked the next token yet. Note that // p == -1 corresponds to an index of len(s), and // p == -(1 - len(s)) corresponds to an index of 0. p = types::I64_MIN, }; }; // Returns the next token from a [[tokenizer]] and advances the cursor. export fn next_token(s: *tokenizer) ([]u8 | done) = { const b = match (peek_token(s)) { case let b: []u8 => yield b; case done => return done; }; const slen = len(s.in): i64; const reverse = s.p < 0; if (reverse) { if (slen + s.p + 1 == 0) { s.delim = s.delim[..0]; s.in = s.in[..0]; } else { const end = (slen + s.p + 1): size - 1; s.in = s.in[..end]; }; s.p = types::I64_MIN; } else { if (s.p == slen) { s.delim = s.delim[..0]; s.in = s.in[..0]; } else { s.in = s.in[s.p: size + 1..]; }; s.p = types::I64_MAX; }; return b; }; // Returns the next token from a [[tokenizer]] without advancing the cursor. export fn peek_token(s: *tokenizer) ([]u8 | done) = { if (len(s.delim) == 0) { return done; }; const reverse = s.p < 0; const ifunc = if (reverse) &rindex else &index; const known = ((reverse && s.p != types::I64_MIN) || (!reverse && s.p != types::I64_MAX)); if (!known) { let i = if (reverse) types::I64_MIN else types::I64_MAX; let dlen = 0i64; const slen = len(s.in): i64; for (let d .. s.delim) { match (ifunc(s.in, d)) { case let ix: size => if (!reverse && ix: i64 < i) { i = ix: i64; dlen = 1; } else if (reverse && ix: i64 > i) { i = ix: i64; dlen = 1; }; case void => if (!reverse && slen < i: i64) { i = slen; } else if (reverse && 0 > i: i64) { i = 0; }; }; }; if (reverse) { if (i == slen) { s.p = -(slen + 1); } else { s.p = i + dlen - slen - 1; }; } else { s.p = i; }; }; if (reverse) { return s.in[len(s.in) + s.p: size + 1..]; } else { return s.in[..s.p: size]; }; }; // Returns the remainder of the input slice from a [[tokenizer]] ahead of the // token cursor. export fn remaining_tokens(s: *tokenizer) []u8 = { return s.in; }; fn tokenize_test( func: *fn([]u8, u8...) tokenizer, testcase: str, in: []u8, delim: []u8, tokens: [][]u8, iters: size = types::SIZE_MAX, ) tokenizer = { const tok = func(in, delim...); let n = 0z; for (const want .. tokens) { if (n >= iters) { return tok; }; n += 1; const p = peek_token(&tok) as []u8; const n = next_token(&tok) as []u8; assert(equal(p, n), testcase); assert(equal(n, want), testcase); }; if (n >= iters) { return tok; }; assert(peek_token(&tok) is done, testcase); assert(next_token(&tok) is done, testcase); return tok; }; @test fn tokenize() void = { tokenize_test(&tokenize, "simple case", [1, 2, 0, 3, 4], [0], [ [1, 2], [3, 4], ]); tokenize_test(&tokenize, "multiple delimiters", [1, 2, 0, 3, 4, 42, 5, 6], [0, 42], [ [1, 2], [3, 4], [5, 6], ]); tokenize_test(&tokenize, "empty tokens", [1, 2, 0, 0, 0, 3, 4], [0], [ [1, 2], [], [], [3, 4], ]); tokenize_test(&tokenize, "leading empty tokens", [0, 1, 2, 3, 0], [0], [ [], [1, 2, 3], [], ]); const tok = tokenize_test(&tokenize, "remaining_tokens", [1, 2, 0, 3, 4], [0], [ [1, 2], ], 1); assert(equal(remaining_tokens(&tok), [3, 4])); }; @test fn rtokenize() void = { tokenize_test(&rtokenize, "simple case", [1, 2, 0, 3, 4], [0], [ [3, 4], [1, 2], ]); tokenize_test(&rtokenize, "multiple delimiters", [1, 2, 0, 3, 4, 42, 5, 6], [0, 42], [ [5, 6], [3, 4], [1, 2], ]); tokenize_test(&rtokenize, "empty tokens", [1, 2, 0, 0, 0, 3, 4], [0], [ [3, 4], [], [], [1, 2], ]); tokenize_test(&rtokenize, "leading empty tokens", [0, 1, 2, 3, 0], [0], [ [], [1, 2, 3], [], ]); const tok = tokenize_test(&rtokenize, "remaining_tokens", [1, 2, 0, 3, 4], [0], [ [3, 4], ], 1); assert(equal(remaining_tokens(&tok), [1, 2])); }; // Returns the input slice "cut" along the first instance of a delimiter, // returning everything up to the delimiter, and everything after the delimiter, // in a tuple. The contents are borrowed from the input slice. // // The caller must ensure that 'delimiter' is not an empty slice. export fn cut(in: []u8, delim: ([]u8 | u8)) ([]u8, []u8) = { let ln = if (delim is u8) { yield 1z; } else { let ln = len(delim: []u8); assert(ln > 0, "bytes::cut called with empty delimiter"); yield ln; }; match (index(in, delim)) { case let i: size => return (in[..i], in[i + ln..]); case void => return (in, []); }; }; // Returns the input slice "cut" along the last instance of a delimiter, // returning everything up to the delimiter, and everything after the delimiter, // in a tuple. The contents are borrowed from the input slice. // // The caller must ensure that 'delimiter' is not an empty slice. export fn rcut(in: []u8, delim: ([]u8 | u8)) ([]u8, []u8) = { let ln = if (delim is u8) { yield 1z; } else { let ln = len(delim: []u8); assert(ln > 0, "bytes::rcut called with empty delimiter"); yield ln; }; match (rindex(in, delim)) { case let i: size => return (in[..i], in[i + ln..]); case void => return (in, []); }; }; @test fn cut() void = { const c = cut(['a', 'b', 'c'], ['b']); assert(equal(c.0, ['a']) && equal(c.1, ['c'])); const c = cut(['a', 'b', 'c'], 'b'); assert(equal(c.0, ['a']) && equal(c.1, ['c'])); const c = cut(['a', 'b', 'c', 'b', 'a'], 'b'); assert(equal(c.0, ['a']) && equal(c.1, ['c', 'b', 'a'])); const c = cut(['a', 'b', 'c'], 'x'); assert(equal(c.0, ['a', 'b', 'c']) && equal(c.1, [])); const c = cut([], 'x'); assert(equal(c.0, []) && equal(c.1, [])); const c = rcut(['a', 'b', 'c'], ['b']); assert(equal(c.0, ['a']) && equal(c.1, ['c'])); const c = rcut(['a', 'b', 'c', 'b', 'a'], 'b'); assert(equal(c.0, ['a', 'b', 'c']) && equal(c.1, ['a'])); }; hare-0.24.2/bytes/trim.ha000066400000000000000000000021441464473310100151350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returns a slice (borrowed from given input slice) after trimming off of // the start of the input slice the bytes in the given list. export fn ltrim(in: []u8, trim: u8...) []u8 = { let i = 0z; for (i < len(in) && contains(trim, in[i]); i+= 1) void; return in[i..]; }; // Returns a slice (borrowed from given input slice) after trimming off of // the end of the input slice the bytes in the given list. export fn rtrim(in: []u8, trim: u8...) []u8 = { let i = len(in) - 1; for (i < len(in) && contains(trim, in[i]); i -= 1) void; return in[..i + 1]; }; // Returns a slice (borrowed from given input slice) after trimming off of // the both ends of the input slice the bytes in the given list. export fn trim(in: []u8, trim: u8...) []u8 = ltrim(rtrim(in, trim...), trim...); @test fn trim() void = { assert(equal(trim([0, 1, 2, 3, 5, 0], 0), [1, 2, 3, 5])); assert(equal(trim([1, 2, 3, 5], 0), [1, 2, 3, 5])); assert(equal(trim([0, 0, 0], 0), [])); assert(equal(trim([0, 5, 0], 5), [0, 5, 0])); assert(equal(trim([], 0), [])); }; hare-0.24.2/bytes/two_way.ha000066400000000000000000000033351464473310100156560ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Implements the so called Two-way string matching algorithm by Crochemore and // Perrin. It pre-processes the needle in O(len(needle)) steps and performs the // matching in O(len(haystack)) steps. It does so without any space overhead. fn index_tw(haystack: []u8, needle: []u8) (size | void) = { const n = len(haystack); const m = len(needle); if (n < m) { return void; }; if (n == m) { return if (equal(haystack, needle)) 0 else void; }; // pre-processing let tup1 = max_suf(needle, false); let i = tup1.0, p = tup1.1; let tup2 = max_suf(needle, true); let j = tup2.0, q = tup2.1; let ms = i; let per = p; if (i + 1 < j + 1) { ms = j; per = q; }; let mem0 = 0z, mem = 0z; if (equal(haystack[..ms + 1], haystack[per..per + ms + 1])) { if (ms + 1 > m - ms - 1) { per = ms + 2; } else { per = m - ms; }; mem0 = m - per; }; j = 0; for (j <= n - m) { // right half i = if (ms + 1 > mem) ms + 1 else mem; for (i < m && needle[i] == haystack[j + i]) { i += 1; }; if (i < m) { j += i - ms; mem = 0; continue; }; // left half i = ms + 1; for (i > mem && needle[i - 1] == haystack[j + i - 1]) { i -= 1; }; if (i <= mem) { return j; }; j += per; mem = mem0; }; }; fn max_suf(x: []u8, inv: bool) (size, size) = { let i = types::SIZE_MAX; let j = 0z; let k = 1z, p = 1z; let m = len(x); for (j + k < m) { let a = x[j + k]; let b = x[i + k]; if (a == b) { if (k == p) { j += p; k = 1; } else { k += 1; }; } else if (a < b ^^ inv) { j += k; k = 1; p = j - i; } else { i = j; j += 1; k = 1; p = 1; }; }; return (i, p); }; hare-0.24.2/bytes/zero.ha000066400000000000000000000004071464473310100151410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Sets all bytes in a slice to zero. This is suitable for erasing private data // from a slice. export fn zero(buf: []u8) void = { rt::memset(buf: *[*]u8, 0, len(buf)); }; hare-0.24.2/cmd/000077500000000000000000000000001464473310100132645ustar00rootroot00000000000000hare-0.24.2/cmd/COPYING000066400000000000000000001045151464473310100143250ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . hare-0.24.2/cmd/genbootstrap/000077500000000000000000000000001464473310100157735ustar00rootroot00000000000000hare-0.24.2/cmd/genbootstrap/main.ha000066400000000000000000000063221464473310100172340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0 // (c) Hare authors use fmt; use hare::module; use hare::unparse; use io; use memio; use os; use path; use strings; export fn main() void = { if (len(os::args) > 1 && os::args[1] == "-h") { fmt::errorln("usage:", os::args[0], "[...]")!; os::exit(0); }; const ctx = module::context { harepath = os::tryenv("HAREPATH", "."), harecache = os::tryenv("HARECACHE", ".cache"), tags = os::args[1..], }; let mods: []module::module = []; defer module::free_slice(mods); module::gather(&ctx, &mods, ["rt"])!; module::gather(&ctx, &mods, ["cmd", "hare"])!; let ids: [](str, str) = []; defer free(ids); defer for (let i = 0z; i < len(ids); i += 1) { free(ids[i].0); free(ids[i].1); }; let with_libc = false; for (let i = 0z; i < len(ctx.tags); i += 1) { if (ctx.tags[i] == "libc") { with_libc = true; }; }; let tds = memio::dynamic(); defer io::close(&tds)!; let objs = memio::dynamic(); defer io::close(&objs)!; for (let i = 0z; i < len(mods); i += 1) { append(ids, (strings::join("_", mods[i].ns...), unparse::identstr(mods[i].ns))); fmt::fprintf(&tds, ` HARE_TD_{}=$(HARECACHE)/{}.td`, ids[i].1, ids[i].0)!; fmt::fprintf(&objs, ` $(HARECACHE)/{}.o`, ids[i].0)!; }; let cwd = os::getcwd(); let buf = path::init(mods[0].srcs.sc[0])!; fmt::println(`# generated by cmd/genbootstrap`)!; fmt::println(`# DO NOT EDIT BY HAND. run 'make bootstrap' to update`)!; fmt::printfln(`TDENV = env{}`, memio::string(&tds)!)!; fmt::printfln(`RTSCRIPT = {}`, path::trimprefix(&buf, cwd)!)!; fmt::printfln(`OBJS ={}`, memio::string(&objs)!)!; let deps = memio::dynamic(); defer io::close(&deps)!; let sources = memio::dynamic(); defer io::close(&sources)!; for (let i = 0z; i < len(mods); i += 1) { memio::reset(&deps); for (let j = 0z; j < len(mods[i].deps); j += 1) { fmt::fprintf(&deps, ` $(HARECACHE)/{}.td`, ids[mods[i].deps[j].0].0)!; }; memio::reset(&sources); for (let j = 0z; j < len(mods[i].srcs.ha); j += 1) { path::set(&buf, mods[i].srcs.ha[j])!; fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!; }; fmt::println()!; fmt::printfln(`{}_ha ={}`, ids[i].0, memio::string(&sources)!)!; fmt::printfln(`$(HARECACHE)/{}.ssa: $({}_ha){}`, ids[i].0, ids[i].0, memio::string(&deps)!)!; fmt::println("\t" `@mkdir -p -- "$(HARECACHE)"`)!; fmt::println("\t" `@printf 'HAREC\t%s\n' "$@"`)!; fmt::printfln("\t" `@$(TDENV) $(HAREC) $(HARECFLAGS) {}-o $@ -t $(HARECACHE)/{}.td.tmp {} {} $({}_ha)`, if (i == len(mods) - 1 && with_libc) `-N "" ` else ``, ids[i].0, if (i == len(mods) - 1) `$(HARE_DEFINES)` else `-N`, if (i == len(mods) - 1) `` else ids[i].1, ids[i].0)!; if (len(mods[i].srcs.s) == 0) { continue; }; memio::reset(&sources); for (let j = 0z; j < len(mods[i].srcs.s); j += 1) { path::set(&buf, mods[i].srcs.s[j])!; fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!; }; fmt::println()!; fmt::printfln(`{}_s = $(HARECACHE)/{}.s{}`, ids[i].0, ids[i].0, memio::string(&sources)!)!; fmt::printfln(`$(HARECACHE)/{}.o: $({}_s)`, ids[i].0, ids[i].0)!; fmt::println("\t" `@printf 'AS\t%s\n' "$@"`)!; fmt::printfln("\t" `@$(AS) $(ASFLAGS) -o $@ $({}_s)`, ids[i].0)!; }; }; hare-0.24.2/cmd/genoiddb/000077500000000000000000000000001464473310100150375ustar00rootroot00000000000000hare-0.24.2/cmd/genoiddb/main.ha000066400000000000000000000070561464473310100163050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bufio; use fmt; use io; use os; use strconv; use strings; type entry = struct { name: str, val: str, idx: size, }; // Parses an oid database from stdin and writes the database as hare code to // stdout. export fn main() void = { let oids = parse_oids(); defer free_oids(oids); fmt::println("// SPDX-License-Identifier: MPL-2.0\n" "// (c) Hare authors \n" "// This is an auto generated file. Do not edit.\n" "\n" "use encoding::asn1;\n")!; fmt::println("const _db = asn1::oiddb {")!; write_db(os::stdout, oids)!; fmt::println("\tnames = [")!; for (let oid .. oids) { fmt::printfln("\t\t\"{}\",", oid.name)!; }; fmt::println("\t],")!; fmt::println("};\n")!; fmt::println("export const db = &_db;\n")!; for (let i = 0z; i < len(oids); i += 1) { fmt::print("export def ")!; write_varname(os::stdout, oids[i].name)!; fmt::printfln(": asn1::oid = {};", i)!; }; }; fn parse_oids() []entry = { let s = bufio::newscanner(os::stdin); defer bufio::finish(&s); let oids: []entry = []; for (let line => bufio::scan_line(&s)!) { if (line == "" || strings::hasprefix(line, '#')) { continue; }; const p = strings::split(line, " "); defer free(p); const name = p[0]; const val = p[len(p)-1]; append(oids, entry { name = strings::dup(name), val = strings::dup(val), ... }); }; return oids; }; fn free_oids(oids: []entry) void = { for (let oid .. oids) { free(oid.name); free(oid.val); }; free(oids); }; fn write_db(h: io::handle, oids: []entry) (void | io::error) = { fmt::print("\tlut = [")?; const maxcols = 12z; let idx = 0z; for (let e .. oids) { e.idx = idx; let der = oidtoder(e.val); assert(len(der) <= 0xff); insert(der[0], len(der): u8); defer free(der); for (let byte .. der) { fmt::print(if (idx % maxcols == 0) "\n\t\t" else " ")?; fmt::printf("0x{:.2x},", byte)?; idx += 1; }; }; fmt::println("\n\t],")?; const maxcols = 9z; fmt::print("\tindex = [")?; for (let i = 0z; i < len(oids); i += 1) { fmt::print(if (i % maxcols == 0) "\n\t\t" else " ")?; fmt::printf("0x{:.4x},", oids[i].idx)?; }; fmt::println("\n\t],")?; }; fn oidtoder(oid: str) []u8 = { let nums = oidtou64s(oid); defer free(nums); let der: []u8 = alloc([0...], 1); assert(nums[0] <= 6); assert(nums[1] < 40); der[0] = nums[0]: u8 * 40 + nums[1]: u8; let end = 1z; for (let n .. nums) { if (n == 0) { insert(der[end], 0u8); end = len(der); continue; }; let first = true; for (n > 0) { let p: u8 = n: u8 & 0x7f; n >>= 7; if (first) { first = false; } else { p |= 0x80; }; insert(der[end], p); }; end = len(der); }; return der; }; fn oidtou64s(oid: str) []u64 = { let nums = strings::tokenize(oid, "."); let intnums: []u64 = []; for (let s => strings::next_token(&nums)) { append(intnums, strconv::stou64(s)!); }; return intnums; }; fn write_varname(h: io::handle, name: str) (void | io::error) = { // assume that names are in ascii let i = strings::iter(name); let prevlow = false; for (let r => strings::next(&i)) { let r = if (r == '-') { prevlow = false; yield '_'; } else if (ascii::isdigit(r)) { prevlow = true; yield r; } else if (ascii::isupper(r)) { if (prevlow) { fmt::fprint(h, "_")?; prevlow = false; }; yield r; } else if (ascii::islower(r)) { prevlow = true; yield ascii::toupper(r); } else { fmt::fatalf("Unexpected character in oid name: {}", r); }; fmt::fprint(h, r)?; }; }; hare-0.24.2/cmd/hare/000077500000000000000000000000001464473310100142035ustar00rootroot00000000000000hare-0.24.2/cmd/hare/arch.ha000066400000000000000000000023411464473310100154320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use cmd::hare::build; // When building the bootstrap toolchain, these values will get overwritten to // equal the values in config.mk def AARCH64_AS = "as"; def AARCH64_CC = "cc"; def AARCH64_LD = "ld"; def RISCV64_AS = "as"; def RISCV64_CC = "cc"; def RISCV64_LD = "ld"; def X86_64_AS = "as"; def X86_64_CC = "cc"; def X86_64_LD = "ld"; // TODO: implement cross compiling to other kernels (e.g. linux => freebsd) // TODO: sysroots const arches: [_]build::arch = [ build::arch { name = "aarch64", qbe_name = "arm64", as_cmd = AARCH64_AS, cc_cmd = AARCH64_CC, ld_cmd = AARCH64_LD, }, build::arch { name = "riscv64", qbe_name = "rv64", as_cmd = RISCV64_AS, cc_cmd = RISCV64_CC, ld_cmd = RISCV64_LD, }, build::arch { name = "x86_64", qbe_name = "amd64_sysv", as_cmd = X86_64_AS, cc_cmd = X86_64_CC, ld_cmd = X86_64_LD, }, ]; fn set_arch_tags(tags: *[]str, a: *build::arch) void = { merge_tags(tags, "-aarch64-riscv64-x86_64")!; append(tags, a.name); }; fn get_arch(name: str) (*build::arch | unknown_arch) = { for (let arch &.. arches) { if (arch.name == name) { return arch; }; }; return name: unknown_arch; }; hare-0.24.2/cmd/hare/build.ha000066400000000000000000000134151464473310100156200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use cmd::hare::build; use errors; use fmt; use fs; use getopt; use hare::ast; use hare::lex; use hare::module; use hare::parse; use io; use memio; use os; use os::exec; use path; use strconv; use strings; use unix::tty; fn build(name: str, cmd: *getopt::command) (void | error) = { let arch = get_arch(os::arch_name(os::architecture()))!; let output = ""; let ctx = build::context { ctx = module::context { harepath = harepath(), harecache = harecache(), tags = default_tags(), }, goal = build::stage::BIN, jobs = match (os::cpucount()) { case errors::error => yield 1z; case let ncpu: size => yield ncpu; }, version = build::get_version(os::tryenv("HAREC", "harec"))?, arch = arch, platform = build::get_platform(os::sysname())?, ... }; defer build::ctx_finish(&ctx); if (name == "test") { ctx.test = true; ctx.submods = len(cmd.args) == 0; merge_tags(&ctx.ctx.tags, "+test")?; }; if (!tty::isatty(os::stderr_file)) { ctx.mode = build::output::SILENT; }; for (let opt .. cmd.opts) { switch (opt.0) { case 'a' => arch = get_arch(opt.1)?; ctx.arch = arch; case 'D' => let buf = memio::fixed(strings::toutf8(opt.1)); let sc = bufio::newscanner(&buf, len(opt.1)); defer bufio::finish(&sc); let lexer = lex::init(&sc, "<-D argument>"); append(ctx.defines, parse::define(&lexer)?); case 'F' => ctx.freestanding = true; case 'j' => match (strconv::stoz(opt.1)) { case let z: size => ctx.jobs = z; case strconv::invalid => fmt::fatal("Number of jobs must be an integer"); case strconv::overflow => if (strings::hasprefix(opt.1, '-')) { fmt::fatal("Number of jobs must be positive"); } else { fmt::fatal("Number of jobs is too large"); }; }; if (ctx.jobs == 0) { fmt::fatal("Number of jobs must be non-zero"); }; case 'L' => append(ctx.libdirs, opt.1); case 'l' => append(ctx.libs, opt.1); case 'N' => ast::ident_free(ctx.ns); ctx.ns = []; match (parse::identstr(opt.1)) { case let id: ast::ident => ctx.ns = id; case lex::syntax => return opt.1: invalid_namespace; case let e: parse::error => return e; }; case 'o' => output = opt.1; case 'q' => ctx.mode = build::output::SILENT; case 'R' => ctx.release = true; case 'T' => merge_tags(&ctx.ctx.tags, opt.1)?; case 't' => switch (opt.1) { case "td" => // intentionally undocumented ctx.goal = build::stage::TD; case "ssa" => // intentionally undocumented ctx.goal = build::stage::SSA; case "s" => ctx.goal = build::stage::S; case "o" => ctx.goal = build::stage::O; case "bin" => ctx.goal = build::stage::BIN; case => return opt.1: unknown_type; }; case 'v' => if (ctx.mode == build::output::VERBOSE) { ctx.mode = build::output::VVERBOSE; } else if (ctx.mode != build::output::VVERBOSE) { ctx.mode = build::output::VERBOSE; } else { fmt::fatal("Number of verbose levels must be <= 2"); }; case => abort(); }; }; if (name == "build" && len(cmd.args) > 1) { getopt::printusage(os::stderr, name, cmd.help)!; os::exit(os::status::FAILURE); }; set_arch_tags(&ctx.ctx.tags, arch); ctx.cmds = ["", os::tryenv("HAREC", "harec"), os::tryenv("QBE", "qbe"), os::tryenv("AS", arch.as_cmd), os::tryenv("LD", arch.ld_cmd), ]; if (!ctx.freestanding && (len(ctx.libs) > 0 || ctx.platform.need_libc)) { ctx.libc = true; merge_tags(&ctx.ctx.tags, "+libc")?; ctx.cmds[build::stage::BIN] = os::tryenv("CC", arch.cc_cmd); }; const input = if (len(cmd.args) == 0) os::getcwd() else cmd.args[0]; ctx.mods = build::gather(&ctx, os::realpath(input)?)?; append(ctx.hashes, [[void...]...], len(ctx.mods)); let built = build::execute(&ctx)?; defer free(built); if (output == "") { if (name != "build") { return run(input, built, cmd.args); }; output = get_output(ctx.goal, input)?; }; let dest = os::stdout_file; if (output != "-") { let mode: fs::mode = 0o644; if (ctx.goal == build::stage::BIN) { mode |= 0o111; }; // in the case that we are outputting to a binary that is // currently beeing executed, we need to remove it first or // otherwise os::create() will fail os::remove(output): void; dest = match (os::create(output, mode)) { case let f: io::file => yield f; case let e: fs::error => return (output, e): output_failed; }; }; defer io::close(dest)!; let src = os::open(built)?; defer io::close(src)!; io::copy(dest, src)?; }; fn run(name: str, path: str, args: []str) error = { const args: []str = if (len(args) != 0) args[1..] else []; let cmd = match(exec::cmd(path, args...)) { case exec::nocmd => fmt::fatalf("Error: Command not found: {}", path); case let e: exec::error => return e; case let c: exec::command => yield c; }; exec::setname(&cmd, name); exec::exec(&cmd); }; fn get_output(goal: build::stage, input: str) (str | error) = { static let buf = path::buffer { ... }; let stat = os::stat(input)?; path::set(&buf, os::realpath(input)?)?; if (!fs::isdir(stat.mode)) { path::pop_ext(&buf); }; // don't add the .bin extension if the goal is to create a binary if (goal != build::stage::BIN) { path::push_ext(&buf, build::stage_ext[goal])?; }; const output = match (path::peek(&buf)) { case let s: str => yield s; case void => return unknown_output; }; stat = match (os::stat(output)) { case let s: fs::filestat => yield s; case errors::noentry => return output; case fs::error => // XXX: double cast here (and below) shouldn't be necessary return output: output_exists: error; }; if (!fs::isfile(stat.mode) || fs::mode_perm(stat.mode) & fs::mode::USER_X == 0) { return output: output_exists: error; }; return output; }; hare-0.24.2/cmd/hare/build/000077500000000000000000000000001464473310100153025ustar00rootroot00000000000000hare-0.24.2/cmd/hare/build/gather.ha000066400000000000000000000033461464473310100170740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fs; use hare::ast; use hare::module; use os; use path; use strings; export fn gather(ctx: *context, input: str) ([]module::module | error) = { let mods: []module::module = []; path::set(&buf, input)!; module::gather(&ctx.ctx, &mods, ["rt"])?; if (ctx.test) { module::gather(&ctx.ctx, &mods, ["test"])?; }; if (!ctx.release) { module::gather(&ctx.ctx, &mods, ["debug"])?; }; const nsubmods = if (ctx.submods) { let id: ast::ident = []; defer ast::ident_free(id); yield gather_submodules(&ctx.ctx, &mods, &buf, &id)?; } else 0z; ctx.top = match (module::gather(&ctx.ctx, &mods, &buf)) { case let top: size => yield top; case let e: module::error => if (!(unwrap_module_error(e) is module::not_found) || nsubmods == 0) { return e; }; // running `hare test` with no args in a directory which isn't a // module // add a dummy module so the driver knows where in the cache to // put the test runner binary append(mods, module::module { path = strings::dup(input), ... }); yield len(mods) - 1; }; return mods; }; fn gather_submodules( ctx: *module::context, mods: *[]module::module, buf: *path::buffer, mod: *ast::ident, ) (size | error) = { let n = 0z; let it = os::iter(path::string(buf))?; defer fs::finish(it); for (let dir => module::next(it)?) { path::push(buf, dir.name)?; defer path::pop(buf); append(mod, dir.name); defer delete(mod[len(mod) - 1]); match (module::gather(ctx, mods, *mod)) { case size => n += 1; case let e: module::error => if (!(unwrap_module_error(e) is module::not_found)) { return e; }; }; n += gather_submodules(ctx, mods, buf, mod)?; }; return n; }; hare-0.24.2/cmd/hare/build/platform.ha000066400000000000000000000020211464473310100174330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors export type platform = struct { name: str, // Do we always need to link with libc? (and use cc instead of ld) need_libc: bool, // Additional default flags for this platform. default_flags: [NSTAGES][]str, }; const platforms: [_]platform = [ platform { name = "Linux", ... }, platform { name = "FreeBSD", ... }, platform { name = "NetBSD", ... }, platform { name = "OpenBSD", need_libc = true, default_flags = [ [], [], [], [], // IBT/BTI is a CPU feature that prevents ROP-attacks. // Since this is enforced by default on OpenBSD but not // implemented by QBE, we need to disable the // enforcement. ld.lld(1) can do this for us by // creating a custom segment. ["-z", "nobtcfi"], ], }, ]; export fn get_platform(name: str) (*platform | unknown_platform) = { for (let platform &.. platforms) { if (platform.name == name) { return platform; }; }; return name: unknown_platform; }; hare-0.24.2/cmd/hare/build/queue.ha000066400000000000000000000217121464473310100167430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use crypto::sha256; use encoding::hex; use fmt; use fs; use hare::module; use hare::unparse; use hash; use io; use memio; use os; use os::exec; use path; use shlex; use sort; use strings; use unix::tty; // a command which is currently running type job = struct { pid: exec::process, task: *task, // fd to be closed once the job has finished, in order to release the // [[io::lock]] on it lock: io::file, }; export fn execute(ctx: *context) (str | error) = { let q: []*task = []; defer free(q); defer for (let t .. q) { free_task(t); }; // stage::TD (typedef files) are generated by the SSA stage (harec) const goal = if (ctx.goal == stage::TD) stage::SSA else ctx.goal; queue(ctx, &q, goal, ctx.top); // sort by stage, harec then qbe then as then ld, and keep reverse // topo sort within each stage sort::sort(q, size(*task), &task_cmp); ctx.total = len(q); let jobs: []job = alloc([], ctx.jobs); defer free(jobs); if (len(os::tryenv("NO_COLOR", "")) == 0 && os::getenv("HAREC_COLOR") is void && tty::isatty(os::stderr_file)) { os::setenv("HAREC_COLOR", "1")!; }; for (let i = 0z; len(q) != 0; i += 1) { if (i == len(q)) { await_task(ctx, &jobs)?; i = 0; }; if (run_task(ctx, &jobs, q[i])?) { delete(q[i]); i = -1; }; }; for (await_task(ctx, &jobs) is size) void; if (ctx.mode == output::DEFAULT && ctx.total != 0) { fmt::errorln()?; }; return get_cache(ctx, ctx.top, ctx.goal)?; }; fn task_cmp(a: const *opaque, b: const *opaque) int = { let a = a: const **task, b = b: const **task; return a.kind - b.kind; }; fn queue(ctx: *context, q: *[]*task, kind: stage, idx: size) *task = { // return already existing task to avoid creating duplicates for (let t .. *q) { if (t.kind == kind && t.idx == idx) { return t; }; }; let t = alloc(task { kind = kind, idx = idx, ... }); switch (kind) { case stage::BIN => t.ndeps = len(ctx.mods); for (let i = 0z; i < len(ctx.mods); i += 1) { append(queue(ctx, q, stage::O, i).rdeps, t); }; case stage::O, stage::S => t.ndeps = 1; append(queue(ctx, q, kind - 1, idx).rdeps, t); case stage::SSA => t.ndeps = len(ctx.mods[idx].deps); for (let (dep_idx, _) .. ctx.mods[idx].deps) { append(queue(ctx, q, stage::SSA, dep_idx).rdeps, t); }; case stage::TD => abort(); }; append(q, t); return t; }; // returns true if the task was executed. returns false if the task cannot be // executed (because it is waiting for dependencies) or if the task is already // running (possibly in another instance of this build driver) fn run_task(ctx: *context, jobs: *[]job, t: *task) (bool | error) = { if (len(jobs) == ctx.jobs) { await_task(ctx, jobs)?; }; if (t.ndeps != 0) { return false; }; let mod = ctx.mods[t.idx]; let deps = get_deps(ctx, t); defer strings::freeall(deps); let flags = get_flags(ctx, t)?; defer strings::freeall(flags); ctx.hashes[t.idx][t.kind] = get_hash(ctx, deps, flags, t); os::mkdirs(module::get_cache(ctx.ctx.harecache, mod.path)?, 0o755)!; let out = get_cache(ctx, t.idx, t.kind)?; defer free(out); path::set(&buf, out)?; let lock = path::push_ext(&buf, "lock")?; let lock = os::create(lock, 0o644, fs::flag::WRONLY)?; if (!io::lock(lock, false, io::lockop::EXCLUSIVE)?) { io::close(lock)?; return false; }; path::set(&buf, out)?; let tmp = path::push_ext(&buf, "tmp")?; // TODO: use os::mkfile once that's supported on freebsd and openbsd io::close(os::create(tmp, 0o644)?)?; let args = get_args(ctx, tmp, flags, t); defer strings::freeall(args); path::set(&buf, out)?; write_args(ctx, path::push_ext(&buf, "txt")?, args, t)?; let outdated = module::outdated(out, deps, mod.srcs.mtime); let exec = t.kind != stage::SSA || len(mod.srcs.ha) != 0; if (!exec || !outdated) { if (outdated) { cleanup_task(ctx, t)?; } else if (t.kind == stage::SSA) { get_td(ctx, t.idx)?; }; io::close(lock)?; free_task(t); ctx.total -= 1; return true; }; switch (ctx.mode) { case output::DEFAULT, output::SILENT => void; case output::VERBOSE => if (tty::isatty(os::stderr_file)) { fmt::errorfln("\x1b[1m{}\x1b[0m\t{}", ctx.cmds[t.kind], mod.name)?; } else { fmt::errorfln("{}\t{}", ctx.cmds[t.kind], mod.name)?; }; case output::VVERBOSE => fmt::error(ctx.cmds[t.kind])?; for (let arg .. args) { fmt::error(" ")?; shlex::quote(os::stderr, arg)?; }; fmt::errorln()?; }; let cmd = match(exec::cmd(ctx.cmds[t.kind], args...)) { case exec::nocmd => fmt::fatalf("Error: Command not found: {}", ctx.cmds[t.kind]); case let e: exec::error => return e; case let c: exec::command => yield c; }; path::set(&buf, out)?; let output = os::create(path::push_ext(&buf, "log")?, 0o644)?; defer io::close(output)!; exec::addfile(&cmd, os::stdout_file, output); exec::addfile(&cmd, os::stderr_file, output); static append(jobs, job { pid = exec::start(&cmd)?, task = t, lock = lock, }); return true; }; fn await_task(ctx: *context, jobs: *[]job) (size | void | error) = { if (ctx.mode == output::DEFAULT && ctx.total != 0) { fmt::errorf("\x1b[G\x1b[2K{}/{} tasks completed ({}%)", ctx.completed, ctx.total, ctx.completed * 100 / ctx.total)?; }; if (len(jobs) == 0) { return; }; let (proc, status) = exec::waitany()?; let i = 0z; for (i < len(jobs) && jobs[i].pid != proc; i += 1) void; assert(i < len(jobs), "Unknown PID returned from waitany"); let j = jobs[i]; let t = j.task; static delete(jobs[i]); let out = get_cache(ctx, t.idx, t.kind)?; defer free(out); path::set(&buf, out)?; let output = os::open(path::push_ext(&buf, "log")?)?; defer io::close(output)!; let output = io::drain(output)?; defer free(output); if (len(output) > 0) { if (ctx.mode == output::DEFAULT) { fmt::errorln()?; }; io::writeall(os::stderr, output)?; }; match (exec::check(&status)) { case void => void; case let e: !exec::exit_status => if (ctx.mode == output::DEFAULT) { fmt::errorln()?; }; if (len(ctx.mods[t.idx].ns) > 0) { fmt::fatalf("{} for {} ({}) {}", ctx.cmds[t.kind], ctx.mods[t.idx].name, ctx.mods[t.idx].path, exec::exitstr(e)); } else { fmt::fatal(ctx.cmds[t.kind], "for", ctx.mods[t.idx].name, exec::exitstr(e)); }; }; cleanup_task(ctx, t)?; free_task(t); io::close(j.lock)?; ctx.completed += 1; return i; }; // update the cache after a task has been run fn cleanup_task(ctx: *context, t: *task) (void | error) = { let out = get_cache(ctx, t.idx, t.kind)?; defer free(out); if (t.kind == stage::SSA) { cleanup_ssa_task(ctx, t, out)?; }; let tmp = strings::concat(out, ".tmp"); defer free(tmp); os::move(tmp, out)?; }; fn cleanup_ssa_task(ctx: *context, t: *task, out: str) (void | error) = { // td file is hashed solely based on its contents. not worth doing this // for other types of outputs, but it gets us better caching behavior // for tds since we need to include the dependency tds in the ssa hash // see design.txt for more details let tmp = strings::concat(out, ".td.tmp"); defer free(tmp); let f = match (os::create(tmp, 0o644, fs::flag::RDWR)) { case let f: io::file => yield f; case let err: fs::error => return err; }; defer io::close(f)!; let h = sha256::sha256(); io::copy(&h, f)!; let prefix: [sha256::SZ]u8 = [0...]; hash::sum(&h, prefix); ctx.hashes[t.idx][stage::TD] = prefix; let ptr = strings::concat(out, ".td"); defer free(ptr); let ptr = os::create(ptr, 0o644)?; defer io::close(ptr)!; hex::encode(ptr, prefix)?; let td = update_env(ctx, t.idx)?; defer free(td); if (os::exists(td)) { os::remove(tmp)?; } else { os::move(tmp, td)?; }; }; // get the td for a module whose harec has been skipped fn get_td(ctx: *context, idx: size) (void | error) = { let ssa = get_cache(ctx, idx, stage::SSA)?; defer free(ssa); let ptr = strings::concat(ssa, ".td"); defer free(ptr); let ptr = match (os::open(ptr)) { case fs::error => return; case let ptr: io::file => yield ptr; }; defer io::close(ptr)!; let ptr = hex::newdecoder(ptr); let prefix: [sha256::SZ]u8 = [0...]; io::readall(&ptr, prefix)?; ctx.hashes[idx][stage::TD] = prefix; free(update_env(ctx, idx)?); }; // set $HARE_TD_, returning the path to the module's td fn update_env(ctx: *context, idx: size) (str | error) = { let path = get_cache(ctx, idx, stage::TD)?; let ns = unparse::identstr(ctx.mods[idx].ns); defer free(ns); if (ctx.mode == output::VVERBOSE) { fmt::errorfln("# HARE_TD_{}={}", ns, path)?; }; let var = strings::concat("HARE_TD_", ns); defer free(var); os::setenv(var, path)!; return path; }; fn get_cache(ctx: *context, idx: size, kind: stage) (str | error) = { let prefix = match (ctx.hashes[idx][kind]) { case void => abort("expected non-void prefix in get_cache()"); case let prefix: [sha256::SZ]u8 => yield prefix; }; let s = memio::dynamic(); memio::concat(&s, module::get_cache(ctx.ctx.harecache, ctx.mods[idx].path)?)!; memio::concat(&s, "/")!; hex::encode(&s, prefix)!; memio::concat(&s, ".", stage_ext[kind])!; return memio::string(&s)!; }; hare-0.24.2/cmd/hare/build/types.ha000066400000000000000000000042711464473310100167640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use crypto::sha256; use fs; use hare::ast; use hare::module; use io; use os::exec; use path; export type error = !(exec::error | fs::error | io::error | module::error | path::error); export type unknown_platform = !str; export type stage = enum { TD = 0, SSA, S, O, BIN, }; def NSTAGES = stage::BIN + 1; // file extensions corresponding to each [[stage]] export const stage_ext = ["td", "ssa", "s", "o", "bin"]; // a command in the queue to be run export type task = struct { // number of unfinished dependencies ndeps: size, // tasks to update (by decrementing ndeps) when this task is finished rdeps: []*task, kind: stage, idx: size, }; export fn free_task(t: *task) void = { for (let rdep &.. t.rdeps) { rdep.ndeps -= 1; }; free(t.rdeps); free(t); }; export type output = enum { DEFAULT, SILENT, VERBOSE, VVERBOSE, }; export type arch = struct { name: str, qbe_name: str, as_cmd: str, cc_cmd: str, ld_cmd: str, }; export type context = struct { ctx: module::context, arch: *arch, platform: *platform, goal: stage, defines: []ast::decl_const, libdirs: []str, libs: []str, jobs: size, ns: ast::ident, // index of the root module within the gathered module slice top: size, // output of harec -v version: []u8, // true if invoked as `hare test` test: bool, // true if building in release mode release: bool, // whether submodules of the root module should have tests enabled submods: bool, // if true, the main function won't be checked by harec freestanding: bool, // if true, we are linking with libc (using cc instead of ld) libc: bool, cmds: [NSTAGES]str, mode: output, completed: size, total: size, mods: []module::module, hashes: [][NSTAGES]([sha256::SZ]u8 | void), }; export fn ctx_finish(ctx: *context) void = { free(ctx.ctx.tags); for (let define .. ctx.defines) { ast::ident_free(define.ident); ast::type_finish(define._type); free(define._type); ast::expr_finish(define.init); free(define.init); }; free(ctx.defines); free(ctx.libdirs); free(ctx.libs); ast::ident_free(ctx.ns); free(ctx.version); module::free_slice(ctx.mods); free(ctx.hashes); }; hare-0.24.2/cmd/hare/build/util.ha000066400000000000000000000206041464473310100165730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use crypto::sha256; use fmt; use hare::ast; use hare::module; use hare::unparse; use hash; use io; use memio; use os; use os::exec; use path; use shlex; use strings; // for use as a scratch buffer let buf = path::buffer { ... }; export fn get_version(harec: str) ([]u8 | error) = { let cmd = match (exec::cmd(harec, "-v")) { case let c: exec::command => yield c; case exec::nocmd => fmt::fatalf("Error: Command not found: {}", harec); case let e: exec::error => return e; }; let pipe = exec::pipe(); exec::addfile(&cmd, os::stdout_file, pipe.1); let proc = exec::start(&cmd)?; io::close(pipe.1)?; const version = io::drain(pipe.0)?; let status = exec::wait(&proc)?; io::close(pipe.0)?; match (exec::check(&status)) { case void => return version; case let status: !exec::exit_status => fmt::fatal(harec, "-v", exec::exitstr(status)); }; }; fn get_deps(ctx: *context, t: *task) []str = { let mod = ctx.mods[t.idx]; switch (t.kind) { case stage::TD => abort(); case stage::SSA => let deps = strings::dupall(mod.srcs.ha); for (let (dep_idx, _) .. mod.deps) { append(deps, get_cache(ctx, dep_idx, stage::TD)!); }; return deps; case stage::S => return alloc([get_cache(ctx, t.idx, stage::SSA)!]...); case stage::O => let deps = strings::dupall(mod.srcs.s); append(deps, get_cache(ctx, t.idx, stage::S)!); return deps; case stage::BIN => let deps: []str = []; for (let i = 0z; i < len(ctx.mods); i += 1) { let srcs = &ctx.mods[i].srcs; for (let j = 0z; j < len(srcs.sc); j += 1) { append(deps, strings::dup(srcs.sc[j])); }; append(deps, get_cache(ctx, i, stage::O)!); for (let o .. srcs.o) { append(deps, strings::dup(o)); }; }; return deps; }; }; // returns the arguments that don't depend on the result of the hash. these will // be used to create the hash. see [[get_args]] for the arguments that depend // on the result of the hash fn get_flags(ctx: *context, t: *task) ([]str | error) = { let flags: []str = strings::dupall(ctx.platform.default_flags[t.kind]); let flags_env = switch (t.kind) { case stage::TD => abort(); case stage::SSA => yield "HARECFLAGS"; case stage::S => yield "QBEFLAGS"; case stage::O => yield "ASFLAGS"; case stage::BIN => yield if (ctx.libc) "LDFLAGS" else "LDLINKFLAGS"; }; match (shlex::split(os::tryenv(flags_env, ""))) { case let s: []str => append(flags, s...); case shlex::syntaxerr => fmt::errorfln("warning: invalid shell syntax in ${}; ignoring", flags_env)?; }; switch (t.kind) { case stage::TD => abort(); case stage::SSA => void; // below case stage::S => append(flags, strings::dup("-t")); append(flags, strings::dup(ctx.arch.qbe_name)); return flags; case stage::O => return flags; case stage::BIN => for (let libdir .. ctx.libdirs) { append(flags, strings::dup("-L")); append(flags, strings::dup(libdir)); }; if (ctx.libc) { append(flags, strings::dup("-Wl,--gc-sections")); } else { append(flags, strings::dup("--gc-sections")); append(flags, strings::dup("-z")); append(flags, strings::dup("noexecstack")); }; return flags; }; append(flags, strings::dup("-a")); append(flags, strings::dup(ctx.arch.name)); let mod = ctx.mods[t.idx]; if (len(ctx.ns) != 0 && t.idx == ctx.top) { append(flags, strings::dup("-N")); append(flags, unparse::identstr(ctx.ns)); } else if (len(mod.ns) != 0 || ctx.libc) { append(flags, strings::dup("-N")); append(flags, unparse::identstr(mod.ns)); }; if (ctx.freestanding) { append(flags, strings::dup("-m")); append(flags, ""); } else if (ctx.libc) { append(flags, strings::dup("-m.main")); }; append(flags, strings::dup("-M")); path::set(&buf, mod.path)?; for (let i = 0z; i < len(mod.ns); i += 1) { path::pop(&buf); }; append(flags, strings::concat(path::string(&buf), "/")); path::set(&buf, mod.path)?; let test = ctx.test && t.idx == ctx.top; test ||= path::trimprefix(&buf, os::getcwd()) is str && ctx.submods; if (test) { append(flags, strings::dup("-T")); }; for (let define .. ctx.defines) { let ident = define.ident; let ns = ident[..len(ident) - 1]; if (!ast::ident_eq(ns, mod.ns)) { continue; }; let buf = memio::dynamic(); memio::concat(&buf, "-D", ident[len(ident) - 1])!; match (define._type) { case null => void; case let t: *ast::_type => memio::concat(&buf, ":")!; unparse::_type(&buf, &unparse::syn_nowrap, t)!; }; memio::concat(&buf, "=")!; unparse::expr(&buf, &unparse::syn_nowrap, define.init)!; append(flags, memio::string(&buf)!); }; return flags; }; fn get_hash( ctx: *context, deps: []str, flags: []str, t: *task, ) [sha256::SZ]u8 = { let h = sha256::sha256(); hash::write(&h, strings::toutf8(ctx.cmds[t.kind])); for (let flag .. flags) { hash::write(&h, strings::toutf8(flag)); }; switch (t.kind) { case stage::TD => abort(); case stage::SSA => hash::write(&h, strings::toutf8(ctx.arch.name)); hash::write(&h, [0]); hash::write(&h, ctx.version); hash::write(&h, [0]); for (let dep .. ctx.mods[t.idx].deps) { let ns = unparse::identstr(dep.1); defer free(ns); let var = strings::concat("HARE_TD_", ns); defer free(var); let path = match (os::getenv(var)) { case void => continue; case let path: str => yield path; }; hash::write(&h, strings::toutf8(var)); hash::write(&h, strings::toutf8("=")); hash::write(&h, strings::toutf8(path)); hash::write(&h, [0]); }; case stage::S => hash::write(&h, strings::toutf8(ctx.arch.qbe_name)); hash::write(&h, [0]); case stage::O => void; case stage::BIN => for (let lib .. ctx.libs) { hash::write(&h, strings::toutf8(lib)); hash::write(&h, [0]); }; }; for (let dep .. deps) { hash::write(&h, strings::toutf8(dep)); hash::write(&h, [0]); }; let prefix: [sha256::SZ]u8 = [0...]; hash::sum(&h, prefix); return prefix; }; // returns the value of flags plus the arguments that depend on the result of // the hash. see [[get_flags]] for the arguments that don't depend on the hash fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = { let args = strings::dupall(flags); append(args, strings::dup("-o")); append(args, strings::dup(tmp)); // TODO: https://todo.sr.ht/~sircmpwn/hare/837 let srcs: []str = switch (t.kind) { case stage::TD => abort(); case stage::SSA => let td = get_cache(ctx, t.idx, stage::SSA)!; defer free(td); append(args, strings::dup("-t")); append(args, strings::concat(td, ".td.tmp")); yield ctx.mods[t.idx].srcs.ha; case stage::S => append(args, get_cache(ctx, t.idx, stage::SSA)!); yield []; case stage::O => append(args, get_cache(ctx, t.idx, stage::S)!); yield ctx.mods[t.idx].srcs.s; case stage::BIN => for (let i = 0z; i < len(ctx.mods); i += 1) { let srcs = ctx.mods[i].srcs; for (let sc .. srcs.sc) { append(args, strings::dup("-T")); append(args, strings::dup(sc)); }; append(args, get_cache(ctx, i, stage::O)!); for (let o .. srcs.o) { append(args, strings::dup(o)); }; }; // XXX: when dynamically linking on Linux, we have to disable // gc-sections again after enabling it in get_flags(); it looks // like leaving this enabled gets us SIGILL in libc (musl). this // is not broken on other platforms such as OpenBSD if (ctx.libc) { append(args, strings::dup("-Wl,--no-gc-sections")); }; for (let lib .. ctx.libs) { append(args, strings::dup("-l")); append(args, strings::dup(lib)); }; yield []; }; for (let src .. srcs) { append(args, strings::dup(src)); }; return args; }; fn write_args(ctx: *context, out: str, args: []str, t: *task) (void | error) = { let txt = os::create(out, 0o644)?; defer io::close(txt)!; if (t.kind == stage::SSA) { for (let (_, ident) .. ctx.mods[t.idx].deps) { let ns = unparse::identstr(ident); defer free(ns); let var = strings::concat("HARE_TD_", ns); defer free(var); fmt::fprintfln(txt, "# {}={}", var, os::tryenv(var, ""))?; }; }; fmt::fprint(txt, ctx.cmds[t.kind])?; for (let arg .. args) { fmt::fprint(txt, " ")?; shlex::quote(txt, arg)?; }; fmt::fprintln(txt)?; }; // XXX: somewhat questionable, related to the hare::module context hackery, can // probably only be improved with language changes fn unwrap_module_error(err: module::error) module::error = { let unwrapped = err; for (true) match (unwrapped) { case let e: module::errcontext => unwrapped = *e.1; case => break; }; return unwrapped; }; hare-0.24.2/cmd/hare/cache.ha000066400000000000000000000031171464473310100155620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fmt; use fs; use getopt; use os; use path; // TODO: flesh this out some more. we probably want to have some sort of // per-module statistics (how much space it's taking up in the cache and whether // it's up to date for each tagset) and maybe also some sort of auto-pruner // (only prune things that can no longer ever be considered up-to-date?) so that // people don't need to periodically run hare cache -c n order to avoid the // cache growing indefinitely fn cache(name: str, cmd: *getopt::command) (void | error) = { let clear = false; for (let opt .. cmd.opts) { switch (opt.0) { case 'c' => clear = true; case => abort(); }; }; if (len(cmd.args) != 0) { getopt::printusage(os::stderr, name, cmd.help)?; os::exit(os::status::FAILURE); }; let cachedir = harecache(); if (clear) { os::rmdirall(cachedir)?; fmt::println(cachedir, "(0 B)")?; return; }; os::mkdirs(cachedir, 0o755)!; let buf = path::init(cachedir)?; let sz = dirsize(&buf)?; const suffix = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; let i = 0z; for (i < len(suffix) - 1 && sz >= 1024; i += 1) { sz /= 1024; }; fmt::printfln("{} ({} {})", cachedir, sz, suffix[i])?; }; fn dirsize(buf: *path::buffer) (size | error) = { let s = 0z; let it = os::iter(path::string(buf))?; defer fs::finish(it); for (let d => fs::next(it)?) { path::push(buf, d.name)?; let stat = os::stat(path::string(buf))?; s += stat.sz; if (fs::isdir(stat.mode)) { s += dirsize(buf)?; }; path::pop(buf); }; return s; }; hare-0.24.2/cmd/hare/deps.ha000066400000000000000000000067701464473310100154620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fmt; use getopt; use hare::ast; use hare::module; use hare::parse; use os; use path; use sort; use sort::cmp; type deps_fmt = enum { DOT, TERM, }; type link = struct { depth: uint, child: size, final: bool, }; fn deps(name: str, cmd: *getopt::command) (void | error) = { let tags = default_tags(); defer free(tags); let build_dir: str = ""; let goal = deps_fmt::TERM; for (let opt .. cmd.opts) { switch (opt.0) { case 'd' => goal = deps_fmt::DOT; case 'T' => merge_tags(&tags, opt.1)?; case => abort(); }; }; if (len(cmd.args) > 1) { getopt::printusage(os::stderr, name, cmd.help)!; os::exit(os::status::FAILURE); }; const input = if (len(cmd.args) == 0) os::getcwd() else cmd.args[0]; let ctx = module::context { harepath = harepath(), harecache = harecache(), tags = tags, }; let mods: []module::module = []; let mod = match (parse::identstr(input)) { case let id: ast::ident => yield id; case parse::error => static let buf = path::buffer { ... }; path::set(&buf, os::realpath(input)?)?; yield &buf; }; module::gather(&ctx, &mods, mod)?; defer module::free_slice(mods); switch (goal) { case deps_fmt::TERM => deps_graph(&mods); case deps_fmt::DOT => fmt::println("strict digraph deps {")!; for (let mod .. mods) { for (let dep .. mod.deps) { const child = mods[dep.0]; fmt::printfln("\t\"{}\" -> \"{}\";", mod.name, child.name)!; }; }; fmt::println("}")!; }; }; fn deps_graph(mods: *[]module::module) void = { if (len(mods) == 1 && len(mods[0].deps) == 0) { fmt::println(mods[0].name, "has no dependencies")!; return; }; let links: []link = []; defer free(links); let depth: []uint = alloc([0...], len(mods)); // traverse in reverse because reverse-topo-sort for (let i = len(mods) - 1; i < len(mods); i -= 1) { // reverse-sort deps so that we know the last in the list is the // "final" child during show_deps sort::sort(mods[i].deps, size((size, ast::ident)), &revsort); for (let j = 0z; j < len(links); j += 1) { if (i < links[j].child) { continue; }; if (depth[i] <= links[j].depth) { depth[i] = links[j].depth + 1; }; }; // print in-between row for (let d = 0u; d < depth[i]; d += 1) { let passing = false; for (let j = 0z; j < len(links); j += 1) { if (i < links[j].child) { continue; }; if (d == links[j].depth) { passing = true; }; }; fmt::print(if (passing) "│ " else " ")!; }; if (i < len(mods) - 1) { fmt::println()!; }; // print row itself let on_path = false; for (let d = 0u; d < depth[i]; d += 1) { let connected = false; let passing = false; let final = false; for (let j = 0z; j < len(links); j += 1) { if (i < links[j].child) { continue; }; if (d == links[j].depth) { passing = true; if (i == links[j].child) { connected = true; on_path = true; if (links[j].final) { final = true; }; }; }; }; fmt::print( if (final) "└──" else if (connected) "├──" else if (on_path) "───" else if (passing) "│ " else " " )!; }; fmt::println(mods[i].name)!; for (let j = 0z; j < len(mods[i].deps); j += 1) { append(links, link{ depth = depth[i], child = mods[i].deps[j].0, final = len(mods[i].deps) == j + 1, }); }; }; }; // sorts in reverse fn revsort(a: const *opaque, b: const *opaque) int = -cmp::sizes(a, b); hare-0.24.2/cmd/hare/design.txt000066400000000000000000000140771464473310100162260ustar00rootroot00000000000000# caching the cached Stuff for a module is stored under $HARECACHE/path/to/module. under this path, the outputs of various commands (harec, qbe, as, and ld) are stored, in ., where is td/ssa for harec, s for qbe, o for as, and bin for ld the way the hash is computed varies slightly between extension: for everything but .td, the hash contains the full argument list for the command used to generate the file. for .ssa, the version of harec (the output of harec -v) and the various HARE_TD_* environment variables are hashed as well .td is hashed solely based on its contents, in order to get better caching behavior. this causes some trickiness which we'll get to later, so it's not worth doing for everything, but doing this for .tds allows us to only recompile a dependency of a module when its api changes, since the way that dependency rebuilds are triggered is via $HARE_TD_depended::on::module changing. this is particularly important for working on eg. rt::, since you don't actually need to recompile most things most of the time despite the fact that rt:: is in the dependency tree for most of the stdlib in order to check if the cache is already up to date, we do the following: - find the sources for the module, including the latest time at which it was modified. this gives us enough information to... - figure out what command we would run to compile it, and generate the hash at the same time - find the mtime of $XDG_CACHE_HOME/path/to/module/.. if it isn't earlier than the mtime from step 1, exit early - run the command however, there's a bit of a problem here: how do we figure out the hash for the .td if we don't end up rebuilding the module? we need it in order to set $HARE_TD_module::ident, but since it's hashed based on its contents, there's no way to figure it out without running harec. in order to get around this, we store the td hash in .ssa.td, and read it from that file whenever we skip running harec in order to avoid problems when running multiple hare builds in parallel, we take an exclusive flock on ..lock. if taking the lock fails, we defer running that command as though it had unfinished dependencies. for reasons described below, we also direct the tool's output to ..tmp then rename that to . when it's done there's also ..log (the stdout/stderr of the process, for displaying if it errors out) and ..txt (the command that was run, for debugging purposes. we might add more information here in the future) # queuing and running jobs the first step when running hare build is to gather all of the dependencies of a given module and queue up all of the commands that will need to be run in order to compile them. we keep track of each command in a task struct, which contains a module::module, the compilation stage it's running, and the command's prerequisites. the prerequisites for a harec are all of the harecs of the modules it depends on, for qbe/as it's the harec/qbe for that module, and for ld it's the ases for all of the modules that have been queued. we insert these into an array of tasks, sorted with all of the harecs first, then qbes, then ases, then ld, with a topological sort within each of these (such that each command comes before all of the commands that depend on it). in order to run a command, we scan from the start of this array until we find a job which doesn't have any unfinished prerequisites and run that the reason for this sort order is to try to improve parallelism: in order to make better use of available job slots, we want to prioritize jobs that will unblock as many other jobs as possible. running a harec will always unblock more jobs than a qbe or as, so we want to try to run them as early as possible. in my tests, this roughly halved most compilation times at -j4 # potential future improvements we only need the typedef file to be generated in order to unblock dependent harecs, not all of codegen. having harec signal to hare build that it's done with the typedefs could improve parallelism, though empirical tests that i did on 2023-08-02 didn't show a meaningful improvement. this may be worth re-investigating if we speed up the earlier parts of harec it may be possible to merge the lockfile with the output file. it clutters up $HARECACHE, so it'd be nice to do so if possible. currently, we unconditionally do an os::create in order to make sure that the lock exists before locking it. if we instead lock the output, we would need to avoid this, since it affects the mtime and would cause us to think that it's always up-to-date. note that we can't check for outdatedness separately from run_task, since the way that we avoid duplicating work between builds running in parallel is by dynamically seeing that a task is up to date after the other build driver has unlocked it # things which look like they could be good ideas but aren't actually we don't want to combine the lockfile with the tmpfile. the interactions between the renaming of the tmpfile and everything else lead to some extremely subtle race conditions we don't want to combine the output file with the tmpfile, for two reasons: - for harec, we need to ensure that if there's an up-to-date .ssa, there's always a corresponding .ssa.td. if we were to have harec output directly to the .ssa, this would mean that failing to run cleanup_task() for it would lead to cache corruption. as the code is written today this would always happen if another task errors out while the harec is in progress (though that's solvable), but it would also happen if there was a crash - if a tool were to write part of the output before erroring out, we would need to actively clear the output file in order to avoid the next build driver assuming that the partial output is complete and up-to-date all of these problems are, in theory, possible to solve in the happy case, but using a tmpfile is much more robust we don't want to use open(O_EXCL) for lockfiles. flock gives us a free unlock on program exit, so there's no way for us to eg. crash without closing the lock then have to force the user to delete the lockfile manually hare-0.24.2/cmd/hare/error.ha000066400000000000000000000011771464473310100156540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fs; use hare::module; use hare::parse; use io; use os::exec; use path; use strconv; use cmd::hare::build; type error = !( exec::error | fs::error | io::error | module::error | path::error | parse::error | strconv::error | unknown_arch | unknown_output | unknown_type | output_exists | output_failed | invalid_namespace | build::unknown_platform | ); type unknown_arch = !str; type unknown_output = !void; type unknown_type = !str; type output_exists = !str; type output_failed = !(str, fs::error); type invalid_namespace = !str; hare-0.24.2/cmd/hare/main.ha000066400000000000000000000105621464473310100154450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use cmd::hare::build; use fmt; use fs; use getopt; use hare::module; use hare::parse; use io; use os; use os::exec; use path; use strconv; def VERSION: str = "unknown"; def HAREPATH: str = "."; const help: []getopt::help = [ "compile, run, and test Hare programs", "", "args...", ("build", [ "compiles a Hare program or module", // XXX: once cross-compiling to different targets (linux, // freebsd, etc) is supported, we can probably merge -F with it ('F', "build for freestanding environment"), ('q', "build silently"), ('v', "print executed commands (specify twice to print arguments)"), ('a', "arch", "set target architecture"), ('D', "ident[:type]=value", "define a constant"), ('j', "jobs", "set parallelism for build"), ('L', "libdir", "add directory to linker library search path"), ('l', "libname", "link with a system library"), ('N', "namespace", "override namespace for module"), ('o', "path", "set output file name"), ('R', "build in release mode"), ('T', "tagset", "set/unset build tags"), ('t', "type", "build type (s/o/bin)"), "[path]" ]: []getopt::help), ("cache", [ "manages the build cache", ('c', "clears the cache"), ]: []getopt::help), ("deps", [ "prints dependency information for a Hare program", ('d', "print dot syntax for use with graphviz"), ('T', "tagset", "set/unset build tags"), "[path|module]", ]: []getopt::help), ("run", [ "compiles and runs a Hare program or module", ('q', "build silently"), ('v', "print executed commands (specify twice to print arguments)"), ('a', "arch", "set target architecture"), ('D', "ident[:type]=value", "define a constant"), ('j', "jobs", "set parallelism for build"), ('L', "libdir", "add directory to linker library search path"), ('l', "libname", "link with a system library"), ('R', "build in release mode"), ('T', "tagset", "set/unset build tags"), "[path [args...]]", ]: []getopt::help), ("test", [ "compiles and runs tests for Hare code", ('q', "build silently"), ('v', "print executed commands (specify twice to print arguments)"), ('a', "arch", "set target architecture"), ('D', "ident[:type]=value", "define a constant"), ('j', "jobs", "set parallelism for build"), ('L', "libdir", "add directory to linker library search path"), ('l', "libname", "link with a system library"), ('o', "path", "set output file name"), ('R', "build in release mode"), ('T', "tagset", "set/unset build tags"), "[path]" ]: []getopt::help), ("version", [ "provides version information for the Hare environment", ('v', "print build parameters"), ]: []getopt::help), ]; export fn main() void = { const cmd = getopt::parse(os::args, help...); defer getopt::finish(&cmd); match (cmd.subcmd) { case void => getopt::printusage(os::stderr, os::args[0], help)!; os::exit(os::status::FAILURE); case let subcmd: (str, *getopt::command) => const task = switch (subcmd.0) { case "build", "run", "test" => yield &build; case "cache" => yield &cache; case "deps" => yield &deps; case "version" => yield &version; case => abort(); }; match (task(subcmd.0, subcmd.1)) { case void => void; case let e: exec::error => fmt::fatal("Error:", exec::strerror(e)); case let e: fs::error => fmt::fatal("Error:", fs::strerror(e)); case let e: io::error => fmt::fatal("Error:", io::strerror(e)); case let e: module::error => fmt::fatal("Error:", module::strerror(e)); case let e: path::error => fmt::fatal("Error:", path::strerror(e)); case let e: parse::error => fmt::fatal("Error:", parse::strerror(e)); case let e: strconv::error => fmt::fatal("Error:", strconv::strerror(e)); case let e: unknown_arch => fmt::fatalf("Error: Unknown arch: {}", e); case let e: build::unknown_platform => fmt::fatalf("Error: Unknown platform: {}", e); case unknown_output => fmt::fatal("Error: Can't guess output in root directory"); case let e: unknown_type => fmt::fatalf("Error: Unknown build type: {}", e); case let e: output_exists => fmt::fatalf("Error: Output path '{}' already exists, but isn't an executable file", e); case let e: output_failed => fmt::fatalf("Error: Could not open output '{}': {}", e.0, fs::strerror(e.1)); case let e: invalid_namespace => fmt::fatalf("Error: Invalid namespace: {}", e); }; }; }; hare-0.24.2/cmd/hare/util.ha000066400000000000000000000022001464473310100154640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use ascii; use dirs; use hare::module; use os; use strings; fn merge_tags(current: *[]str, new: str) (void | module::error) = { let trimmed = strings::trimprefix(new, "^"); if (trimmed != new) { free(*current); *current = []; }; let newtags = module::parse_tags(trimmed)?; defer free(newtags); for :new (let newtag .. newtags) { for (let j = 0z; j < len(current); j += 1) { if (newtag.name == current[j]) { if (!newtag.include) { static delete(current[j]); }; continue :new; }; }; if (newtag.include) { append(current, newtag.name); }; }; }; fn harepath() str = os::tryenv("HAREPATH", HAREPATH); fn harecache() str = { match (os::getenv("HARECACHE")) { case let s: str => return s; case void => return dirs::cache("hare"); }; }; // contents of slice shouldn't be freed fn default_tags() []str = { let arch = os::arch_name(os::architecture()); static let platform: [7]u8 = [0...]; let platform = ascii::strlower_buf(os::sysname(), platform[..0]); let tags: []str = alloc([arch, platform]); return tags; }; hare-0.24.2/cmd/hare/version.ha000066400000000000000000000020561464473310100162050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use ascii; use fmt; use getopt; use os; use strings; fn version(name: str, cmd: *getopt::command) (void | error) = { let verbose = false; for (let opt .. cmd.opts) { switch (opt.0) { case 'v' => verbose = true; case => abort(); }; }; fmt::printfln("hare {}", VERSION)!; if (!verbose) { return; }; let build_arch = os::arch_name(os::architecture()); let build_arch = get_arch(build_arch)!; let build_platform = ascii::strlower(os::sysname()); fmt::printfln("build tags:\n\t+{}\n\t+{}\nHAREPATH{}:", build_arch.name, build_platform, if (os::getenv("HAREPATH") is str) " (from environment)" else "")?; let tok = strings::tokenize(harepath(), ":"); for (let s => strings::next_token(&tok)) { fmt::printfln("\t{}", s)?; }; fmt::println("toolchains:")?; for (let arch .. arches) { fmt::printfln(" {}:", arch.name)?; fmt::printfln("\tAS={}", arch.as_cmd)?; fmt::printfln("\tCC={}", arch.cc_cmd)?; fmt::printfln("\tLD={}", arch.ld_cmd)?; }; }; hare-0.24.2/cmd/haredoc/000077500000000000000000000000001464473310100146715ustar00rootroot00000000000000hare-0.24.2/cmd/haredoc/doc/000077500000000000000000000000001464473310100154365ustar00rootroot00000000000000hare-0.24.2/cmd/haredoc/doc/color.ha000066400000000000000000000055001464473310100170660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fmt; use hare::unparse; use os; use regex; // Colors/Renditions with defaults; SGR parameters for ANSI escape sequences. const default_colors = [ "_", // ident "1", // comment "_", // constant "_", // function "_", // global "_", // typedef "_", // import_alias "_", // secondary "94", // keyword "96", // type "33", // attribute "1", // operator "_", // punctuation "91", // rune_string "95", // number "_", // label ]; let colors: [len(default_colors)]str = [""...]; let normal_color = ""; let primary_color = ""; fn init_colors() (void | error) = { const env_colors = os::tryenv("HAREDOC_COLORS", ""); const expr = regex::compile(`([a-z_]+)=(_|[0-9;]*)`)!; defer regex::finish(&expr); const matches = regex::findall(&expr, env_colors); defer regex::result_freeall(matches); for (let m .. matches) { let (k, v) = (m[1].content, m[2].content); let idx = 0z; let out: *str = switch (k) { case "ident" => yield &colors[unparse::synkind::IDENT]; case "comment" => yield &colors[unparse::synkind::COMMENT]; case "constant" => yield &colors[unparse::synkind::CONSTANT]; case "function" => yield &colors[unparse::synkind::FUNCTION]; case "global" => yield &colors[unparse::synkind::GLOBAL]; case "typedef" => yield &colors[unparse::synkind::TYPEDEF]; case "import_alias" => yield &colors[unparse::synkind::IMPORT_ALIAS]; case "secondary" => yield &colors[unparse::synkind::SECONDARY]; case "keyword" => yield &colors[unparse::synkind::KEYWORD]; case "type" => yield &colors[unparse::synkind::TYPE]; case "attribute" => yield &colors[unparse::synkind::ATTRIBUTE]; case "operator" => yield &colors[unparse::synkind::OPERATOR]; case "punctuation" => yield &colors[unparse::synkind::PUNCTUATION]; case "rune_string" => yield &colors[unparse::synkind::RUNE_STRING]; case "number" => yield &colors[unparse::synkind::NUMBER]; case "label" => yield &colors[unparse::synkind::LABEL]; case "normal" => yield &normal_color; case "primary" => yield &primary_color; case => static let err: [64]u8 = [0...]; if (len(k) > len(err)) { return "": haredoc_colors_error; }; return fmt::bsprint(err, k): haredoc_colors_error; }; *out = if (v == "_" && k == "normal") "0" else v; }; }; fn color(kind: unparse::synkind) str = { const color = if (colors[kind] != "") colors[kind] else default_colors[kind]; if (color != "_") { return color; }; if (primary_color != "" && primary_color != "_") { switch (kind) { case unparse::synkind::CONSTANT, unparse::synkind::FUNCTION, unparse::synkind::GLOBAL, unparse::synkind::TYPEDEF => return primary_color; case => void; }; }; return if (normal_color == "") "0" else normal_color; }; hare-0.24.2/cmd/haredoc/doc/html.ha000066400000000000000000000433421464473310100167220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors // Note: ast::ident should never have to be escaped use encoding::utf8; use fmt; use hare::ast; use hare::lex; use hare::parse::doc; use hare::unparse; use io; use memio; use net::ip; use net::uri; use path; use strings; // Prints a string to an output handle, escaping any of HTML's reserved // characters. fn html_escape(out: io::handle, in: str) (size | io::error) = { let z = 0z; let iter = strings::iter(in); for (let rn => strings::next(&iter)) { z += fmt::fprint(out, switch (rn) { case '&' => yield "&"; case '<' => yield "<"; case '>' => yield ">"; case '"' => yield """; case '\'' => yield "'"; case => yield strings::fromutf8(utf8::encoderune(rn))!; })?; }; return z; }; @test fn html_escape() void = { let sink = memio::dynamic(); defer io::close(&sink)!; html_escape(&sink, "hello world!")!; assert(memio::string(&sink)! == "hello world!"); let sink = memio::dynamic(); defer io::close(&sink)!; html_escape(&sink, "\"hello world!\"")!; assert(memio::string(&sink)! == ""hello world!""); let sink = memio::dynamic(); defer io::close(&sink)!; html_escape(&sink, "")!; assert(memio::string(&sink)! == "<hello & 'world'!>"); }; // Formats output as HTML export fn emit_html(ctx: *context) (void | error) = { const decls = ctx.summary; const ident = unparse::identstr(ctx.ident); defer free(ident); if (ctx.template) { head(ctx.ident)?; }; if (len(ident) == 0) { fmt::fprintf(ctx.out, "

The Hare standard library ")?; } else { fmt::fprintf(ctx.out, "

{}", ident)?; }; for (let tag .. ctx.tags) { fmt::fprintf(ctx.out, "+{} ", tag)?; }; fmt::fprintln(ctx.out, "

")?; match (ctx.readme) { case void => void; case let f: io::file => fmt::fprintln(ctx.out, "
")?; markup_html(ctx, f, lex::location { path = "README", // XXX: this is meh line = 1, col = 1, })?; fmt::fprintln(ctx.out, "
")?; }; let identpath = strings::join("/", ctx.ident...); defer free(identpath); if (len(ctx.submods) != 0) { if (len(ctx.ident) == 0) { fmt::fprintln(ctx.out, "

Modules

")?; } else { fmt::fprintln(ctx.out, "

Submodules

")?; }; fmt::fprintln(ctx.out, "")?; }; if (len(decls.types) == 0 && len(decls.errors) == 0 && len(decls.constants) == 0 && len(decls.globals) == 0 && len(decls.funcs) == 0) { return; }; fmt::fprintln(ctx.out, "

Index

")?; tocentries(ctx.out, decls.types, "Types", "types")?; tocentries(ctx.out, decls.errors, "Errors", "Errors")?; tocentries(ctx.out, decls.constants, "Constants", "constants")?; tocentries(ctx.out, decls.globals, "Globals", "globals")?; tocentries(ctx.out, decls.funcs, "Functions", "functions")?; if (len(decls.types) != 0) { fmt::fprintln(ctx.out, "

Types

")?; for (let t &.. decls.types) { details(ctx, t)?; }; }; if (len(decls.errors) != 0) { fmt::fprintln(ctx.out, "

Errors

")?; for (let e &.. decls.errors) { details(ctx, e)?; }; }; if (len(decls.constants) != 0) { fmt::fprintln(ctx.out, "

Constants

")?; for (let c &.. decls.constants) { details(ctx, c)?; }; }; if (len(decls.globals) != 0) { fmt::fprintln(ctx.out, "

Globals

")?; for (let g &.. decls.globals) { details(ctx, g)?; }; }; if (len(decls.funcs) != 0) { fmt::fprintln(ctx.out, "

Functions

")?; for (let f &.. decls.funcs) { details(ctx, f)?; }; }; }; fn tocentries( out: io::handle, decls: []ast::decl, name: str, lname: str, ) (void | error) = { if (len(decls) == 0) { return; }; fmt::fprintfln(out, "

{}

", name)?; fmt::fprintln(out, "
")?;
	let undoc = false;
	for (let i = 0z; i < len(decls); i += 1) {
		if (!undoc && decls[i].docs == "") {
			fmt::fprintfln(
				out,
				"{}// Undocumented {}:",
				if (i == 0) "" else "\n",
				lname)?;
			undoc = true;
		};
		unparse::decl(out, &syn_centry, &decls[i])?;
		fmt::fprintln(out)?;
	};
	fmt::fprint(out, "
")?; return; }; fn details(ctx: *context, decl: *ast::decl) (void | error) = { fmt::fprintln(ctx.out, "
")?; fmt::fprint(ctx.out, "

")?; fmt::fprintf(ctx.out, "{} ", match (decl.decl) { case ast::decl_func => yield "fn"; case []ast::decl_type => yield "type"; case []ast::decl_const => yield "def"; case []ast::decl_global => yield "let"; case ast::assert_expr => abort(); })?; unparse::ident(ctx.out, decl_ident(decl))?; // TODO: Add source URL fmt::fprint(ctx.out, "[link] ")?; fmt::fprintln(ctx.out, "

")?; if (len(decl.docs) == 0) { fmt::fprintln(ctx.out, "
")?; fmt::fprintln(ctx.out, "Show undocumented member")?; }; fmt::fprintln(ctx.out, "
")?;
	unparse::decl(ctx.out, &syn_html, decl)?;
	fmt::fprintln(ctx.out, "
")?; if (len(decl.docs) != 0) { const trimmed = trim_comment(decl.docs); defer free(trimmed); const buf = strings::toutf8(trimmed); markup_html(ctx, &memio::fixed(buf), decl.start)?; } else { fmt::fprintln(ctx.out, "
")?; }; fmt::fprintln(ctx.out, "
")?; return; }; fn html_decl_ref(ctx: *context, ref: ast::ident) (void | error) = { const ik = match (resolve(ctx, ref)?) { case let ik: (ast::ident, symkind) => yield ik; case void => const ident = unparse::identstr(ref); fmt::errorfln("Warning: Unresolved reference: {}", ident)?; fmt::fprintf(ctx.out, "{}", ident)?; free(ident); return; }; // TODO: The reference is not necessarily in the stdlib const kind = ik.1, id = ik.0; const ident = unparse::identstr(id); switch (kind) { case symkind::LOCAL => fmt::fprintf(ctx.out, "{0}", ident)?; case symkind::MODULE => let ipath = strings::join("/", id...); defer free(ipath); fmt::fprintf(ctx.out, "{}::", ipath, ident)?; case symkind::SYMBOL => let ipath = strings::join("/", id[..len(id) - 1]...); defer free(ipath); fmt::fprintf(ctx.out, "{}", ipath, id[len(id) - 1], ident)?; case symkind::ENUM_LOCAL => fmt::fprintf(ctx.out, "{}", id[len(id) - 2], ident)?; case symkind::ENUM_REMOTE => let ipath = strings::join("/", id[..len(id) - 2]...); defer free(ipath); fmt::fprintf(ctx.out, "{}", ipath, id[len(id) - 2], ident)?; }; free(ident); }; fn html_mod_ref(ctx: *context, ref: ast::ident) (void | error) = { const ident = unparse::identstr(ref); defer free(ident); let ipath = strings::join("/", ref...); defer free(ipath); fmt::fprintf(ctx.out, "{}::", ipath, ident)?; }; fn html_paragraph(ctx: *context, p: doc::paragraph) (void | error) = { for (let elem .. p) { match (elem) { case let s: str => match (uri::parse(s)) { case let uri: uri::uri => defer uri::finish(&uri); if (uri.host is ip::addr || len(uri.host as str) > 0) { fmt::fprint(ctx.out, "")?; html_escape(ctx.out, s)?; fmt::fprint(ctx.out, "")?; } else { html_escape(ctx.out, s)?; }; case uri::invalid => html_escape(ctx.out, s)?; }; case let d: doc::decl_ref => html_decl_ref(ctx, d)?; case let m: doc::mod_ref => html_mod_ref(ctx, m)?; }; }; }; fn markup_html( ctx: *context, in: io::handle, loc: lex::location, ) (void | error) = { const doc = match (doc::parse(in, loc)) { case let doc: doc::doc => yield doc; case let err: lex::syntax => const err = lex::strerror(err); fmt::errorln("Warning:", err)?; fmt::fprint(ctx.out, "

Can't parse docs: ")?; html_escape(ctx.out, err)?; fmt::fprintln(ctx.out)?; return; }; defer doc::freeall(doc); for (let elem .. doc) { match (elem) { case let p: doc::paragraph => fmt::fprint(ctx.out, "

")?; html_paragraph(ctx, p)?; fmt::fprintln(ctx.out)?; case let l: doc::list => fmt::fprintln(ctx.out, "

    ")?; for (let entry .. l) { fmt::fprint(ctx.out, "
  • ")?; html_paragraph(ctx, entry)?; fmt::fprintln(ctx.out)?; }; fmt::fprintln(ctx.out, "
")?; case let c: doc::code_sample => fmt::fprint(ctx.out, "
")?;
			html_escape(ctx.out, c)?;
			fmt::fprintln(ctx.out, "
")?; }; }; }; fn syn_centry( ctx: *unparse::context, s: str, kind: unparse::synkind, ) (size | io::error) = { let z = 0z; switch (kind) { case unparse::synkind::CONSTANT, unparse::synkind::FUNCTION, unparse::synkind::GLOBAL, unparse::synkind::TYPEDEF => z += fmt::fprint(ctx.out, "")?; z += html_escape(ctx.out, s)?; z += fmt::fprint(ctx.out, "")?; ctx.linelen += len(s); return z; case => return syn_html(ctx, s, kind); }; }; fn syn_html( ctx: *unparse::context, s: str, kind: unparse::synkind, ) (size | io::error) = { let z = 0z; const span = switch (kind) { case unparse::synkind::COMMENT => const stack = ctx.stack as *unparse::stack; if (stack.cur is *ast::decl) { // doc comment is unparsed separately later return 0z; }; z += fmt::fprint(ctx.out, "")?; yield true; case unparse::synkind::KEYWORD => z += fmt::fprint(ctx.out, "")?; yield true; case unparse::synkind::TYPE => z += fmt::fprint(ctx.out, "")?; yield true; case => yield false; }; z += html_escape(ctx.out, s)?; ctx.linelen += len(s); if (span) { z += fmt::fprint(ctx.out, "")?; }; return z; }; fn breadcrumb(ident: ast::ident) str = { if (len(ident) == 0) { return ""; }; let buf = memio::dynamic(); fmt::fprintf(&buf, "stdlib » ")!; for (let i = 0z; i < len(ident) - 1; i += 1) { let ipath = strings::join("/", ident[..i+1]...); defer free(ipath); fmt::fprintf(&buf, "{}::", ipath, ident[i])!; }; fmt::fprint(&buf, ident[len(ident) - 1])!; return memio::string(&buf)!; }; const harriet_b64 = "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAABlBMVEUAAAD///+l2Z/dAAAK40lEQVRo3u3ZX2xb1R0H8O/NzWIXXGw0xILa1QE6Wk0gMspIESU3WSf2sD/wODFtpFC1Q1Ob0AJpacm5pYVUAxHENK2IUiONaQ/TBIjRFKXNvSHbijSDeaGja5vr/ovHlmIHQ66de+/57iF27Gv7um8TD/glUvzROb9z7jnnnp9/4GU++Ap8iYEeJ6EFA9k9SSlGgkFRFiizs8HgPKWQ33ZFIEgZjiYNSwsECTpxaViJQKDRSUnDSgUBKcjN0mAmEJAclAbtIOCRhiMNOkHAIVl0DRaDQJ6k5xr0gkCGpOuRbhDIkvzUWwi2IbBI8smF4TYEr5C0nzTIIGCQ5N1NgEbaPGaUZD2QgvKw0QxYzviJkSbAZXH8RPQVozSceuDROzw3ciYYFOkdPhE9YxhBwOGlwydGThtkqjHIk/98fOT06wtz3hBMnfh85HTWCAI2p6a+ME7zWCCQU3MfaUkRDBzL/mg0Sa8JcE4Mz/DY4rKui+HTY/cPz9AIBHJm6onhGVbWfS2Yn7F+uXfGYBD4wnGtGXVmLBjwsf5jTYHzpHdUvTDmBYGMw0tT6ucMBLZjfPoLpRnwjLmtvV+UNmlj8Piu3lwzQHu0N5cNBpLj+d5cfxOQH8/3FrYGgrx0lrX3Ok3BA2sVZyttJ2hVe8faFSdqB4F5/vxgu+JodnALYupfitMVDJytcgeKg8HAE3NCKTIQFN1B3tLrBc+k5261blG814OBXOFs6PX+3AREt3T0en8IBC6fvXSkpwmQ3P+1I/DeDgbyvbaP4R02AsFQsu09eIezweCvLWl41wZ2QbFR7YOL/mAwrXYoLoQVBLRzSidcPHkmCBj58Atw9WYA+hVyYksgSMzq5hXy4mNeICjqPbfKt78VAKy0dQQ9Qj59q5dvCEw9dQTKqNy7rL/h7i704d6j92FU/vpUAFASWbcdo+5Tp37VECRDzLirO+ha0tncALjZEWYkbqZNOr0NwPMik7MlHpMqKU+JepDRisxLXcuuIjnfANAaYp77jPxxkvP1XbjMWymHfzOOkqTM1gE5tDszeZKTTqpyD/ABzU7EeZI/c/OlC1Ut0Heet5hkf+nqkKkFxYnu3eQFitIrM1ULXHXEIrtZvsX9o66LUJ7kIWGUl1YtONS2m6RVvnn018XwaUgzFq4gJMl7a+fBLWzXFi8xpKx7+7vKzkTV8Pm7uqm23Or5YflaWwGmRkpt8WKRzdUAZ2+CVTEwNVcDCshmSBbKozhlCz+QLYP+N4et+UEiGr8MqAyAJHnRNmrmYeFPjo7hhkh6dqImhoWYCnSttEKymI/7QenZHBC2MCFIJ+cH7vWh0hulaOjQyHyhBnA2J0qPCUiQLERrpnrhmnsjbQGkGgFOkuQGOoSSqQcFU3guKQfpEWq+UQvqYlcLYHe0wRF0Xi63KKA69eB8QewhKc/atKAWSTkV8oHptigpzjJDsiHI2iRlnHGSUM6SHPWDUCFO0hWuQwJnSXK4QZAhFklCyZHMTtQsOS1TTkAAk+R/0z7wXKE9SroicxepK30knVkfWJfTSA5TdgvqAEk+EphnLYC5og8sbJOikAnSRIcgDbfhkpvuFjQBksd8QGrnF9bDlCDTCzF4vhbS0btJyqhkGVg1XZiCLh1mk2QOSiOgCZK0EinmECI55wOumCApGKVGuojXpdXF82nBAj/jXJykSZIc93WRSpPZImfnKhn3UX8MWZKajEoxXJVyVc3D1bl1dEnK7ZWLgC+G4lmNGdKtJLsUogpkmNNIg5PFFP0HwuKSm3U1Kcj8Sbsq/a2AwkAhcjxPSnGS5AdDlSjL4KGCUGjxrPy6IA++X3m+JZDrWtGmUmPc0wW5653Kdi+B9+QTK65ySTomKe3Buqn+GH1sd0hy4pAopWludQyzs89SJWWeE4mEb42VgwzFB6OC71BLrvEfayWQTu+IjguSorCqvIonq8Fes88qkJTiXLQExNPVIIdn4ueNcSbsd5eX/qP5DpBcy4pdz4id7LIPvVSKasVSXwybhrpyMs+u7FgpSDeyonqYE+qOyKRhc0vq/KrSeYru6mHGQvqy5zWXD2eT58pXD9+CGVCe6Sp0F+mIk/tLQLd9jxvron13k/Pisx2bSQ6Se3y7G+jsTgtSWnO59eT0JsG9ftDy6t05Usoxt0+1eCaZ5/BMFZDX5/Zft50Guf1IUknQGctyOFsNHppc3k5q5ODR0xtesmgbHPY9rLASW8LufjLjHei7K0GSz6+qbgFQVVd+YGezfCO55i2SfP4bVcDtiUVDnzCZGSuy80N1jSD53APVLehYHprUilk6o30vYns/OWreWh2Drq4N/Z351Jzd/8lhbN9iFV80Vf9ErR/RN9uJS/Lk2ZVQt1jFF+F7Lb6GNjUseNcu74WdK6EsPbmhBuiIqLGhoW27jNc6f4QYPn5Yb/G9L0yoz9y+Q5um6OgMAzjQgw5fC0/hytbIfSJJ66ftMewDwi1+cAhAGKnTjpErgxt94ICC5P1IFB0ndxuwD51hfMe3qtMK0vcpY/mxvHsH8BpiUGK+Fs6hZf/tapfdPchHASAGxHwtJDG8dvW1m4aG7uWjVwKIdaDFdwwWwti+ujU5ZU9l3CvQis4OoLoFcwB9Pwg/95KVOTPtXnFtK2JA9UxaPAdErx75zcvZ7PuFZS9CeQFQfCfMtBJbtmd4zctZeebUZh2qDiylf3cPqOqPeVf/7lOntqQBYKleHaQZ7klfhYfHh7bSeXkBRNZXgJzk7B59+bYfjouZFOc/eVAHYuH1vi7yKmLusrHBS2c4/5/vmUA7enyb92ALsFvt9C6+YnXMf9iDcASoasHFughwce+A4DtjFz42gchN1UCSbjuU48MDXXTeenyFiWtaWxTf+WBe1Qn1gz8ORBXnjjvu+FAHdGWv/5XUgfg+uTEykX+8bTSnA1AmfaO4qgdxTF1QzOOb2kZzaQAIVQNTAlAOXlInRnY/txJpAFCrQI4EoPxll/ryN9cl0ToBILykugVXjQHKd3/zoLZ07brV6AEQifsv3jrQsnlV34qlHdcsQw+A1hpgAh33bOu7xnsVoRvuaQDSQF9ywOwUb6DtBgDlFbe4HtJAZP/GyevFm0BLKwD4Uhg9WgCWHvj++o7Nb4aBlXWAhQFgyXVt2LRV+RMQ2wfAly2avx8A2te0tGzdqBLAPsRUzR/kNHD1bcAHSdhHAACqUQ3+jVbgxptiiCTx26M9PQCW1CRBLvBgayewBPvWnTYbAJq4R9GBPdBv9kwsbovF7a+aiAA9APSbb+kB4E+rcypNlD+RJX2PhDFY04UEAHQCQCT8RC68WKAozaQOFwAGVCAGbBtoDWk1LZh7dQA/ARCLoBPoqgEXoOrlGJZMdgJd9T+qL4Lw5FqgvjyR6yx9H8O7nQtJTPX7oh2YXRynuXi8+LrIl/sIm8CVhXjtPOjKCwCANvQAWBatbcEk3ygBLJ5w/nv1qy2ofKxa4CLqjFS+v7Nxqait/L268/N4I7Cp9H1L4s7F3NgHZjoA4KbtaqXM41tyiAMApgejlV+Ka/KLtLq8e9806ZlqQLFJ04xsk4IXECIzx11EgytiBUCp/OofWFMbaQ4KVRW1WpCGIuaDg6waXLYBSFdin2v0uCcqOyhqNAkSomllMK01Lx2evUxt8enLFB8roeXizae6Os2qBwXEm9U302heANUvUyEd/n9Vac3mwFW+qlZ/WcH/ADT9vVqjZ2RdAAAAAElFTkSuQmCC"; fn head(ident: ast::ident) (void | error) = { const id = unparse::identstr(ident); defer free(id); let breadcrumb = breadcrumb(ident); defer free(breadcrumb); const title = if (len(id) == 0) fmt::asprintf("Hare documentation") else fmt::asprintf("{} — Hare documentation", id); defer free(title); // TODO: Move bits to +embed? fmt::printfln(" {} ", title, harriet_b64)?; fmt::println("")?; fmt::printfln("
")?; return; }; hare-0.24.2/cmd/haredoc/doc/resolve.ha000066400000000000000000000101601464473310100174250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use fmt; use fs; use hare::ast; use hare::lex; use hare::module; use hare::parse; use io; use os; use types; type symkind = enum { LOCAL, MODULE, SYMBOL, ENUM_LOCAL, ENUM_REMOTE, }; // Resolves a reference. Given an identifier, determines if it refers to a local // symbol, a module, or a symbol in a remote module, then returns this // information combined with a corrected ident if necessary. fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void | error) = { if (is_local(ctx, what)) { return (what, symkind::LOCAL); }; if (len(what) > 1) { // Look for symbol in remote module let partial = what[..len(what) - 1]; match (module::find(ctx.mctx, partial)) { case let r: (str, module::srcset) => module::finish_srcset(&r.1); return (what, symkind::SYMBOL); case module::error => void; }; }; if (len(what) == 2) { match (lookup_local_enum(ctx, what)) { case let id: ast::ident => return (id, symkind::ENUM_LOCAL); case => void; }; }; if (len(what) > 2) { match (lookup_remote_enum(ctx, what)?) { case let id: ast::ident => return (id, symkind::ENUM_REMOTE); case => void; }; }; match (module::find(ctx.mctx, what)) { case let r: (str, module::srcset) => module::finish_srcset(&r.1); return (what, symkind::MODULE); case module::error => void; }; return; }; fn is_local(ctx: *context, what: ast::ident) bool = { if (len(what) != 1) { return false; }; const summary = ctx.summary; for (let c &.. summary.constants) { const name = decl_ident(c)[0]; if (name == what[0]) { return true; }; }; for (let e &.. summary.errors) { const name = decl_ident(e)[0]; if (name == what[0]) { return true; }; }; for (let t &.. summary.types) { const name = decl_ident(t)[0]; if (name == what[0]) { return true; }; }; for (let g &.. summary.globals) { const name = decl_ident(g)[0]; if (name == what[0]) { return true; }; }; for (let f &.. summary.funcs) { const name = decl_ident(f)[0]; if (name == what[0]) { return true; }; }; return false; }; fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = { for (let decl &.. ctx.summary.types) { const name = decl_ident(decl)[0]; if (name == what[0]) { const t = (decl.decl as []ast::decl_type)[0]; const e = match (t._type.repr) { case let e: ast::enum_type => yield e; case => return; }; for (let value .. e.values) { if (value.name == what[1]) { return what; }; }; }; }; }; fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void | error) = { // mod::decl_name::member const mod = what[..len(what) - 2]; const decl_name = what[len(what) - 2]; const member = what[len(what) - 1]; const srcs = match (module::find(ctx.mctx, mod)) { case let s: (str, module::srcset) => yield s.1; case let e: module::error => module::finish_error(e); return void; }; // This would take a lot of memory to load let decls: []ast::decl = []; defer { for (let decl .. decls) { ast::decl_finish(decl); }; free(decls); }; for (let in .. srcs.ha) { let d = scan(in)?; defer free(d); append(decls, d...); }; for (let decl .. decls) { const decls = match (decl.decl) { case let t: []ast::decl_type => yield t; case => continue; }; for (let d .. decls) { if (d.ident[0] == decl_name) { const e = match (d._type.repr) { case let e: ast::enum_type => yield e; case => abort(); }; for (let value .. e.values) { if (value.name == member) { return what; }; }; }; }; }; }; export fn scan(path: str) ([]ast::decl | parse::error) = { const input = match (os::open(path)) { case let f: io::file => yield f; case let err: fs::error => fmt::fatalf("Error reading {}: {}", path, fs::strerror(err)); }; defer io::close(input)!; let sc = bufio::newscanner(input, types::SIZE_MAX); defer bufio::finish(&sc); let lexer = lex::init(&sc, path, lex::flag::COMMENTS); let su = parse::subunit(&lexer)?; ast::imports_finish(su.imports); return su.decls; }; hare-0.24.2/cmd/haredoc/doc/sort.ha000066400000000000000000000062201464473310100167370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use hare::ast; use sort; use strings; // Sorts declarations by: // - removing unexported declarations, // - setting the "exported" field of all remaining declarations to false, so the // "export" keyword isn't unparsed, // - moving undocumented declarations to the end, // - sorting by identifier, // - removing the initializer from globals and the body from functions, // - ensuring that only one member is present in each declaration: // "let x: int, y: int;" becomes two declarations: "let x: int; let y: int;". export fn sort_decls(decls: []ast::decl) summary = { let sorted = summary { ... }; for (let decl .. decls) { if (!decl.exported) { continue; }; match (decl.decl) { case let f: ast::decl_func => append(sorted.funcs, ast::decl { exported = false, start = decl.start, end = decl.end, decl = ast::decl_func { symbol = f.symbol, ident = f.ident, prototype = f.prototype, body = null, attrs = f.attrs, }, docs = decl.docs, }); case let types: []ast::decl_type => for (let t .. types) { let bucket = &sorted.types; if (t._type.flags & ast::type_flag::ERROR == ast::type_flag::ERROR) { bucket = &sorted.errors; }; append(bucket, ast::decl { exported = false, start = decl.start, end = decl.end, decl = alloc([t]), docs = decl.docs, }); }; case let consts: []ast::decl_const => for (let c .. consts) { append(sorted.constants, ast::decl { exported = false, start = decl.start, end = decl.end, decl = alloc([c]), docs = decl.docs, }); }; case let globals: []ast::decl_global => for (let g .. globals) { append(sorted.globals, ast::decl { exported = false, start = decl.start, end = decl.end, decl = alloc([ast::decl_global { is_const = g.is_const, is_threadlocal = g.is_threadlocal, symbol = g.symbol, ident = g.ident, _type = g._type, init = null, }]), docs = decl.docs, }); }; case ast::assert_expr => void; }; }; sort::sort(sorted.constants, size(ast::decl), &decl_cmp); sort::sort(sorted.errors, size(ast::decl), &decl_cmp); sort::sort(sorted.types, size(ast::decl), &decl_cmp); sort::sort(sorted.globals, size(ast::decl), &decl_cmp); sort::sort(sorted.funcs, size(ast::decl), &decl_cmp); return sorted; }; fn decl_cmp(a: const *opaque, b: const *opaque) int = { const a = a: const *ast::decl; const b = b: const *ast::decl; if (a.docs == "" && b.docs != "") { return 1; } else if (a.docs != "" && b.docs == "") { return -1; }; const id_a = decl_ident(a), id_b = decl_ident(b); return strings::compare(id_a[len(id_a) - 1], id_b[len(id_b) - 1]); }; fn decl_ident(decl: *ast::decl) ast::ident = { match (decl.decl) { case let f: ast::decl_func => return f.ident; case let t: []ast::decl_type => assert(len(t) == 1); return t[0].ident; case let c: []ast::decl_const => assert(len(c) == 1); return c[0].ident; case let g: []ast::decl_global => assert(len(g) == 1); return g[0].ident; case ast::assert_expr => abort(); }; }; hare-0.24.2/cmd/haredoc/doc/tty.ha000066400000000000000000000105311464473310100165700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use fmt; use hare::ast; use hare::lex; use hare::unparse; use io; use os; use strings; let no_color: bool = false; // Formats output as Hare source code (prototypes) with syntax highlighting export fn emit_tty(ctx: *context) (void | error) = { if (os::tryenv("NO_COLOR", "") == "") { init_colors()?; } else { no_color = true; }; const summary = ctx.summary; if (ctx.ambiguous) { const id = unparse::identstr(ctx.ident); defer free(id); if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprint(ctx.out, "// ")?; if (!no_color) fmt::fprint(ctx.out, "\x1b[93m")?; fmt::fprint(ctx.out, "NOTE")?; if (!no_color) fmt::fprintf(ctx.out, "\x1b[m" "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprintf(ctx.out, ": {} also refers to module [[{}::]]", id, id)?; if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; fmt::fprintln(ctx.out, "\n")?; }; if (len(ctx.parse_errs) > 0) { if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprint(ctx.out, "// ")?; if (!no_color) fmt::fprint(ctx.out, "\x1b[93m")?; fmt::fprint(ctx.out, "WARNING")?; if (!no_color) fmt::fprintf(ctx.out, "\x1b[m" "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprintln(ctx.out, ": parsing errors occurred; documentation may be incomplete")?; if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; }; for (let i = 0z; i < len(ctx.parse_errs); i += 1) { fmt::fprintln(ctx.out, "//", lex::strerror(ctx.parse_errs[i]))?; }; if (len(ctx.parse_errs) > 0) { fmt::fprintln(ctx.out)?; }; match (ctx.readme) { case let readme: io::file => let rbuf: [os::BUFSZ]u8 = [0...]; let readme = bufio::init(readme, rbuf, []); let sc = bufio::newscanner(&readme); defer bufio::finish(&sc); for (let line => bufio::scan_line(&sc)?) { firstline = false; if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprint(ctx.out, "//", line)?; if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; fmt::fprintln(ctx.out)?; }; case void => void; }; emit_submodules_tty(ctx)?; // XXX: Should we emit the dependencies, too? let printed = false; for (let t &.. summary.types) { if (details_tty(ctx, t)?) { printed = true; }; }; for (let c &.. summary.constants) { if (details_tty(ctx, c)?) { printed = true; }; }; for (let e &.. summary.errors) { if (details_tty(ctx, e)?) { printed = true; }; }; for (let g &.. summary.globals) { if (details_tty(ctx, g)?) { printed = true; }; }; for (let f &.. summary.funcs) { if (details_tty(ctx, f)?) { printed = true; }; }; if (!printed) { if (!firstline) { fmt::fprintln(ctx.out)?; }; if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", color(unparse::synkind::COMMENT))?; fmt::fprint(ctx.out, "// No exported declarations")?; if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; fmt::fprintln(ctx.out)?; }; }; fn emit_submodules_tty(ctx: *context) (void | error) = { if (len(ctx.submods) != 0) { if (!firstline) { fmt::fprintln(ctx.out)?; }; firstline = false; if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m", color(unparse::synkind::COMMENT))?; if (len(ctx.ident) == 0) { fmt::fprintln(ctx.out, "// Modules")?; } else { fmt::fprintln(ctx.out, "// Submodules")?; }; for (let submodule .. ctx.submods) { let submodule = if (len(ctx.ident) != 0) { const s = unparse::identstr(ctx.ident); defer free(s); yield strings::concat(s, "::", submodule); } else { yield strings::dup(submodule); }; defer free(submodule); fmt::fprintfln(ctx.out, "// - [[{}]]", submodule)?; }; }; }; fn details_tty(ctx: *context, decl: *ast::decl) (bool | error) = { if (len(decl.docs) == 0 && !ctx.show_undocumented) { return false; }; if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?; // reset styling if (!firstline) { fmt::fprintln(ctx.out)?; }; firstline = false; unparse::decl(ctx.out, &syn_tty, decl)?; fmt::fprintln(ctx.out)?; return true; }; fn syn_tty( ctx: *unparse::context, s: str, kind: unparse::synkind, ) (size | io::error) = { let z = 0z; if (!no_color) z += fmt::fprintf(ctx.out, "\x1b[{}m", color(kind))?; z += unparse::syn_wrap(ctx, s, kind)?; if (!no_color) z += fmt::fprint(ctx.out, "\x1b[m")?; return z; }; hare-0.24.2/cmd/haredoc/doc/types.ha000066400000000000000000000040671464473310100171230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use encoding::utf8; use fmt; use fs; use hare::ast; use hare::lex; use hare::module; use hare::parse; use hare::parse::doc; use io; use os::exec; export type haredoc_colors_error = !str; export type error = !(lex::error | parse::error | doc::error | io::error | module::error | exec::error | fs::error | haredoc_colors_error | utf8::invalid); export fn strerror(err: error) str = { match (err) { case let err: lex::error => return lex::strerror(err); case let err: parse::error => return parse::strerror(err); case let err: doc::error => return doc::strerror(err); case let err: io::error => return io::strerror(err); case let err: module::error => return module::strerror(err); case let err: exec::error => return exec::strerror(err); case let err: fs::error => return fs::strerror(err); case let err: utf8::invalid => return utf8::strerror(err); case let err: haredoc_colors_error => def ERRMSG = "Error parsing HAREDOC_COLORS: invalid key"; if (len(err) == 0) { return ERRMSG; }; static let buf: [len(ERRMSG) + 64 + 3]u8 = [0...]; return fmt::bsprintf(buf, "{} '{}'", ERRMSG, err); }; }; export type context = struct { mctx: *module::context, ident: ast::ident, tags: []str, ambiguous: bool, parse_errs: []lex::syntax, srcs: module::srcset, submods: []str, summary: summary, template: bool, show_undocumented: bool, readme: (io::file | void), out: io::handle, pager: (exec::process | void), }; export type summary = struct { constants: []ast::decl, errors: []ast::decl, types: []ast::decl, globals: []ast::decl, funcs: []ast::decl, }; export fn finish_summary(s: summary) void = { for (let c .. s.constants) { free(c.decl as []ast::decl_const); }; free(s.constants); for (let e .. s.errors) { free(e.decl as []ast::decl_type); }; free(s.errors); for (let t .. s.types) { free(t.decl as []ast::decl_type); }; free(s.types); for (let g .. s.globals) { free(g.decl as []ast::decl_global); }; free(s.globals); free(s.funcs); }; hare-0.24.2/cmd/haredoc/doc/util.ha000066400000000000000000000016611464473310100167310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use fs; use hare::module; use memio; use os; use path; use sort; use sort::cmp; use strings; let firstline: bool = true; fn trim_comment(s: str) str = { let trimmed = memio::dynamic(); let tok = strings::tokenize(s, "\n"); for (let line => strings::next_token(&tok)) { memio::concat(&trimmed, strings::trimprefix(line, " "), "\n")!; }; return strings::dup(memio::string(&trimmed)!); }; export fn submodules(path: str, show_undocumented: bool) ([]str | error) = { let submodules: []str = []; let it = os::iter(path)?; defer fs::finish(it); let pathbuf = path::init(path)!; for (let d => module::next(it)?) { path::set(&pathbuf, path, d.name, "README")!; if (show_undocumented || os::exists(path::string(&pathbuf))) { append(submodules, strings::dup(d.name)); }; }; sort::sort(submodules, size(str), &cmp::strs); return submodules; }; hare-0.24.2/cmd/haredoc/error.ha000066400000000000000000000005211464473310100163320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use cmd::haredoc::doc; use fs; use hare::module; use hare::parse; use io; use os::exec; use path; use strconv; type error = !( exec::error | fs::error | io::error | module::error | path::error | parse::error | strconv::error | doc::error | ); hare-0.24.2/cmd/haredoc/main.ha000066400000000000000000000276051464473310100161410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use cmd::haredoc::doc; use fmt; use fs; use getopt; use hare::ast; use hare::lex; use hare::module; use hare::parse; use hare::unparse; use io; use memio; use os; use os::exec; use path; use strconv; use strings; const help: []getopt::help = [ "reads and formats Hare documentation", ('a', "show undocumented members (only applies to -Ftty)"), ('t', "disable HTML template (requires postprocessing)"), ('F', "format", "specify output format (tty or html)"), ('T', "tagset", "set/unset build tags"), "[identifier|path]", ]; export fn main() void = { const cmd = getopt::parse(os::args, help...); defer getopt::finish(&cmd); match (doc(os::args[0], &cmd)) { case void => void; case let e: doc::error => fmt::fatal(doc::strerror(e)); case let e: exec::error => fmt::fatal(exec::strerror(e)); case let e: fs::error => fmt::fatal(fs::strerror(e)); case let e: io::error => fmt::fatal(io::strerror(e)); case let e: module::error => fmt::fatal(module::strerror(e)); case let e: path::error => fmt::fatal(path::strerror(e)); case let e: parse::error => fmt::fatal(parse::strerror(e)); case let e: strconv::error => fmt::fatal(strconv::strerror(e)); }; }; fn doc(name: str, cmd: *getopt::command) (void | error) = { let html = false; let template = true; let show_undocumented = false; let tags: []str = default_tags(); defer free(tags); for (let (k, v) .. cmd.opts) { switch (k) { case 'F' => switch (v) { case "tty" => html = false; case "html" => html = true; case => fmt::fatal("Invalid format", v); }; case 'T' => merge_tags(&tags, v)?; case 't' => template = false; case 'a' => show_undocumented = true; case => abort(); }; }; if (show_undocumented && html) { fmt::fatal("Option -a must be used only with -Ftty"); }; if (len(cmd.args) > 1) { getopt::printusage(os::stderr, os::args[0], help)!; os::exit(os::status::FAILURE); }; let ctx = module::context { harepath = harepath(), harecache = harecache(), tags = tags, }; let declpath = ""; defer free(declpath); let declsrcs = module::srcset { ... }; defer module::finish_srcset(&declsrcs); let modpath = ""; defer free(modpath); let modsrcs = module::srcset { ... }; defer module::finish_srcset(&modsrcs); let id: ast::ident = []; defer free(id); if (len(cmd.args) == 0) { let (p, s) = module::find(&ctx, []: ast::ident)?; modpath = strings::dup(p); modsrcs = s; } else match (parseident(cmd.args[0])) { case let ident: (ast::ident, bool) => id = ident.0; const trailing = ident.1; if (!trailing) { // check if it's an ident inside a module match (module::find(&ctx, id[..len(id)-1])) { case let s: (str, module::srcset) => declpath = strings::dup(s.0); declsrcs = s.1; case let e: module::error => module::finish_error(e); }; }; // check if it's a module match (module::find(&ctx, id)) { case let s: (str, module::srcset) => modpath = strings::dup(s.0); modsrcs = s.1; case let e: module::error => module::finish_error(e); if (declpath == "") { const id = unparse::identstr(id); fmt::fatalf("Could not find {}{}", id, if (trailing) "::" else ""); }; }; case void => let buf = path::init(cmd.args[0])?; let (p, s) = module::find(&ctx, &buf)?; modpath = strings::dup(p); modsrcs = s; }; let decls: []ast::decl = []; defer { for (let decl .. decls) { ast::decl_finish(decl); }; free(decls); }; let parse_errs: []lex::syntax = []; defer { for (const err .. parse_errs) { free(err.1); }; free(parse_errs); }; if (declpath != "") { for (let ha .. declsrcs.ha) { let d = match (doc::scan(ha)) { case let d: []ast::decl => yield d; case let err: parse::error => if (html) { return err; }; match (err) { case let err: lex::syntax => const msg = strings::dup(err.1); append(parse_errs, (err.0, msg)); continue; case => return err; }; }; defer free(d); append(decls, d...); }; let matching: []ast::decl = []; let notmatching: []ast::decl = []; for (let decl .. decls) { if (has_decl(decl, id[len(id) - 1])) { append(matching, decl); } else { append(notmatching, decl); }; }; get_init_funcs(&matching, ¬matching); for (let decl .. notmatching) { ast::decl_finish(decl); }; free(notmatching); free(decls); decls = matching; if (len(matching) == 0) { if (modpath == "") { const id = unparse::identstr(id); fmt::fatalf("Could not find {}", id); }; } else { show_undocumented = true; }; }; let readme: (io::file | void) = void; defer match (readme) { case void => void; case let f: io::file => io::close(f)!; }; const ambiguous = modpath != "" && len(decls) > 0; if (len(decls) == 0) { for (let ha .. modsrcs.ha) { let d = match (doc::scan(ha)) { case let d: []ast::decl => yield d; case let err: parse::error => if (html) { return err; }; match (err) { case let err: lex::syntax => const msg = strings::dup(err.1); append(parse_errs, (err.0, msg)); continue; case => return err; }; }; defer free(d); append(decls, d...); }; const rpath = path::init(modpath, "README")!; match (os::open(path::string(&rpath))) { case let f: io::file => readme = f; case fs::error => void; }; }; const submods: []str = if (!ambiguous && modpath != "") { yield match (doc::submodules(modpath, show_undocumented)) { case let s: []str => yield s; case doc::error => yield []; }; } else []; const srcs = if (!ambiguous && modpath != "") modsrcs else declsrcs; const summary = doc::sort_decls(decls); defer doc::finish_summary(summary); const ctx = doc::context { mctx = &ctx, ident = id, tags = tags, ambiguous = ambiguous, parse_errs = parse_errs, srcs = srcs, submods = submods, summary = summary, template = template, readme = readme, show_undocumented = show_undocumented, out = os::stdout, pager = void, }; const ret = if (html) { yield doc::emit_html(&ctx); } else { ctx.out = init_tty(&ctx); yield doc::emit_tty(&ctx); }; io::close(ctx.out)!; match (ctx.pager) { case void => void; case let proc: exec::process => exec::wait(&proc)!; }; // TODO: remove ? (harec bug workaround) return ret?; }; // Nearly identical to parse::identstr, except alphanumeric lexical tokens are // converted to strings and there must be no trailing tokens that don't belong // to the ident in the string. For example, this function will parse `rt::abort` // as a valid identifier. fn parseident(in: str) ((ast::ident, bool) | void) = { let buf = memio::fixed(strings::toutf8(in)); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let success = false; let ident: ast::ident = []; defer if (!success) ast::ident_free(ident); let trailing = false; let z = 0z; for (true) { const tok = lex::lex(&lexer)!; const name = if (tok.0 == lex::ltok::NAME) { yield tok.1 as str; } else if (tok.0 < lex::ltok::LAST_KEYWORD) { yield strings::dup(lex::tokstr(tok)); } else if (tok.0 == lex::ltok::EOF && len(ident) > 0) { trailing = true; break; } else { lex::unlex(&lexer, tok); return; }; append(ident, name); z += len(name); const tok = lex::lex(&lexer)!; switch (tok.0) { case lex::ltok::EOF => break; case lex::ltok::DOUBLE_COLON => z += 1; case => lex::unlex(&lexer, tok); return; }; }; if (z > ast::IDENT_MAX) { return; }; success = true; return (ident, trailing); }; fn init_tty(ctx: *doc::context) io::handle = { const pager = match (os::getenv("PAGER")) { case let name: str => yield match (exec::cmd(name)) { case let cmd: exec::command => yield cmd; case exec::error => return os::stdout; }; case void => yield match (exec::cmd("less", "-R")) { case let cmd: exec::command => yield cmd; case exec::error => yield match (exec::cmd("more", "-R")) { case let cmd: exec::command => yield cmd; case exec::error => return os::stdout; }; }; }; const pipe = exec::pipe(); defer io::close(pipe.0)!; exec::addfile(&pager, os::stdin_file, pipe.0); // Get raw flag in if possible exec::setenv(&pager, "LESS", os::tryenv("LESS", "FRX"))!; exec::setenv(&pager, "MORE", os::tryenv("MORE", "R"))!; ctx.pager = exec::start(&pager)!; return pipe.1; }; fn has_decl(decl: ast::decl, name: str) bool = { if (!decl.exported) { return false; }; match (decl.decl) { case let consts: []ast::decl_const => for (let d .. consts) { if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; }; case let d: ast::decl_func => if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; let tok = strings::rtokenize(d.symbol, "."); match (strings::next_token(&tok)) { case done => void; case let s: str => return s == name; }; case let globals: []ast::decl_global => for (let d .. globals) { if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; let tok = strings::rtokenize(d.symbol, "."); match (strings::next_token(&tok)) { case done => void; case let s: str => return s == name; }; }; case let types: []ast::decl_type => for (let d .. types) { if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; }; case ast::assert_expr => void; }; return false; }; @test fn parseident() void = { let (ident, trailing) = parseident("hare::lex") as (ast::ident, bool); defer ast::ident_free(ident); assert(ast::ident_eq(ident, ["hare", "lex"])); assert(!trailing); let (ident, trailing) = parseident("rt::abort") as (ast::ident, bool); defer ast::ident_free(ident); assert(ast::ident_eq(ident, ["rt", "abort"])); assert(!trailing); let (ident, trailing) = parseident("foo::bar::") as (ast::ident, bool); defer ast::ident_free(ident); assert(ast::ident_eq(ident, ["foo", "bar"])); assert(trailing); assert(parseident("strings::dup*{}&@") is void); assert(parseident("") is void); assert(parseident("::") is void); }; fn get_init_funcs(matching: *[]ast::decl, notmatching: *[]ast::decl) void = { if (len(matching) != 1) { return; }; let ident = match (matching[0].decl) { case let d: []ast::decl_type => if (len(d) != 1 || len(d[0].ident) != 1) { return; }; if (d[0]._type.flags & ast::type_flag::ERROR != 0) { return; }; match (d[0]._type.repr) { case let repr: ast::builtin_type => if (repr == ast::builtin_type::VOID) { return; }; case => void; }; yield d[0].ident; case => return; }; for (let i = 0z; i < len(notmatching); i += 1) { let _type = match (notmatching[i].decl) { case let d: []ast::decl_const => yield match (d[0]._type) { case let t: *ast::_type => yield t; case null => continue; }; case let d: []ast::decl_global => yield match (d[0]._type) { case let t: *ast::_type => yield t; case null => continue; }; case let d: ast::decl_func => let _type = d.prototype.repr as ast::func_type; yield _type.result; case => continue; }; if (is_init_type(ident, _type)) { append(matching, notmatching[i]); delete(notmatching[i]); i -= 1; }; }; }; fn is_init_type(ident: ast::ident, _type: *ast::_type) bool = { let type_ident = match (_type.repr) { case let repr: ast::alias_type => yield repr.ident; case let repr: ast::list_type => if (!(repr.length is ast::len_slice)) { return false; }; yield match (repr.members.repr) { case let repr: ast::alias_type => yield repr.ident; case => return false; }; case let repr: ast::pointer_type => yield match (repr.referent.repr) { case let repr: ast::alias_type => yield repr.ident; case => return false; }; case let repr: ast::tagged_type => for (let t .. repr) { if (is_init_type(ident, t)) { return true; }; }; return false; case => return false; }; return ast::ident_eq(ident, type_ident); }; hare-0.24.2/cmd/haredoc/util.ha000066400000000000000000000022251464473310100161610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use ascii; use dirs; use hare::module; use os; use strings; def HAREPATH: str = "."; fn merge_tags(current: *[]str, new: str) (void | module::error) = { let trimmed = strings::ltrim(new, '^'); if (trimmed != new) { free(*current); *current = []; }; let newtags = module::parse_tags(trimmed)?; defer free(newtags); for :new (let newtag .. newtags) { for (let i = 0z; i < len(current); i += 1) { if (newtag.name == current[i]) { if (!newtag.include) { static delete(current[i]); }; continue :new; }; }; if (newtag.include) { append(current, newtag.name); }; }; }; fn harepath() str = os::tryenv("HAREPATH", HAREPATH); fn harecache() str = { match (os::getenv("HARECACHE")) { case let s: str => return s; case void => return dirs::cache("hare"); }; }; // contents of slice shouldn't be freed fn default_tags() []str = { let arch = os::arch_name(os::architecture()); static let platform: [7]u8 = [0...]; let platform = ascii::strlower_buf(os::sysname(), platform[..0]); let tags: []str = alloc([arch, platform]); return tags; }; hare-0.24.2/cmd/haretype/000077500000000000000000000000001464473310100151055ustar00rootroot00000000000000hare-0.24.2/cmd/haretype/main.ha000066400000000000000000000047701464473310100163530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use fmt; use getopt; use hare::ast; use hare::lex; use hare::parse; use hare::types; use hare::unparse; use io; use memio; use os; use path; use strings; fn typeinfo( store: *types::typestore, s: str, ) (void | io::error | parse::error | types::deferred | types::error) = { const hatype = if (s == "null") { fmt::println("null")?; yield types::lookup_builtin(store, ast::builtin_type::NULL); } else { let stream = memio::fixed(strings::toutf8(s)); defer io::close(&stream)!; let sc = bufio::newscanner(&stream); defer bufio::finish(&sc); let lexer = lex::init(&sc, "-"); const atype = parse::_type(&lexer)?; defer ast::type_finish(&atype); const typ = types::lookup(store, &atype)?; unparse::_type(os::stdout, &unparse::syn_nowrap, &atype)?; fmt::println()?; yield typ; }; fmt::println("\tid:", hatype.id)?; fmt::println("\tsize:", if (hatype.sz == types::SIZE_UNDEFINED) "undefined" else hatype.sz)?; fmt::println("\talign:", if (hatype._align == types::SIZE_UNDEFINED) "undefined" else hatype._align)?; }; fn str_to_arch(name: str) types::arch = { switch (name) { case "aarch64" => return types::aarch64; case "riscv64" => return types::riscv64; case "x86_64" => return types::x86_64; case => fmt::fatal("Unsupported architecture", name); }; }; export fn main() void = { let arch = os::arch_name(os::architecture()); let arch = str_to_arch(arch); const help: []getopt::help = [ "prints information about Hare types", ('m', "arch", "set target architecture (x86_64, aarch64, riscv64)"), "types...", ]; const cmd = getopt::parse(os::args, help...); defer getopt::finish(&cmd); for (let i = 0z; i < len(cmd.opts); i += 1) { const opt = cmd.opts[i]; switch (opt.0) { // TODO: tags case 'm' => arch = str_to_arch(opt.1); case => abort(); // unreachable }; }; if (len(cmd.args) == 0) { const name = path::basename(os::args[0]); getopt::printusage(os::stderr, name, help)!; os::exit(1); }; const store = types::store(arch, null, null); defer types::store_free(store); for (let i = 0z; i < len(cmd.args); i += 1) { match (typeinfo(store, cmd.args[i])) { case void => void; case let err: io::error => fmt::fatal("I/O error:", io::strerror(err)); case let err: parse::error => fmt::fatal(parse::strerror(err)); case let err: types::error => fmt::fatal(types::strerror(err)); case types::deferred => fmt::fatal("Invalid type"); }; }; }; hare-0.24.2/cmd/parsechk/000077500000000000000000000000001464473310100150645ustar00rootroot00000000000000hare-0.24.2/cmd/parsechk/main.ha000066400000000000000000000022661464473310100163300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-only // (c) Hare authors use bufio; use fmt; use fs; use hare::ast; use hare::lex; use hare::parse; use io; use os; use path; export fn main() void = { let buf = path::init()!; let status: int = os::status::SUCCESS; iter(&buf, &status); os::exit(status); }; fn iter(buf: *path::buffer, status: *int) void = { let it = os::iter(path::string(buf))!; defer fs::finish(it); for (let ent => fs::next(it)!) { path::push(buf, ent.name)!; defer path::pop(buf); const st = os::stat(path::string(buf))!; if (fs::isfile(st.mode)) { match (path::peek_ext(buf)) { case let s: str => if (s == "ha") { parse(path::string(buf), status); }; case void => void; }; } else if (fs::isdir(st.mode)) { iter(buf, status); }; }; }; fn parse(path: str, status: *int) void = { const f = os::open(path)!; defer io::close(f)!; let sc = bufio::newscanner(f); defer bufio::finish(&sc); let lexer = lex::init(&sc, path); match (parse::subunit(&lexer)) { case let su: ast::subunit => ast::subunit_finish(su); case let err: parse::error => fmt::errorln(parse::strerror(err))!; *status = os::status::FAILURE; }; }; hare-0.24.2/configs/000077500000000000000000000000001464473310100141515ustar00rootroot00000000000000hare-0.24.2/configs/freebsd.mk000066400000000000000000000014131464473310100161130ustar00rootroot00000000000000# install locations PREFIX = /usr/local BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man SRCDIR = $(PREFIX)/src STDLIB = $(SRCDIR)/hare/stdlib # variables used during build PLATFORM = freebsd ARCH = x86_64 HAREFLAGS = HARECFLAGS = QBEFLAGS = ASFLAGS = LDLINKFLAGS = --gc-sections -z noexecstack # commands used by the build script HAREC = harec QBE = qbe AS = as LD = ld SCDOC = scdoc # build locations HARECACHE = .cache BINOUT = .bin # variables that will be embedded in the binary with -D definitions HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party VERSION=$$(./scripts/version) # For cross-compilation, modify the variables below AARCH64_AS=as AARCH64_CC=cc AARCH64_LD=ld RISCV64_AS=as RISCV64_CC=cc RISCV64_LD=ld X86_64_AS=as X86_64_CC=cc X86_64_LD=ld hare-0.24.2/configs/linux.mk000066400000000000000000000014111464473310100156360ustar00rootroot00000000000000# install locations PREFIX = /usr/local BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man SRCDIR = $(PREFIX)/src STDLIB = $(SRCDIR)/hare/stdlib # variables used during build PLATFORM = linux ARCH = x86_64 HAREFLAGS = HARECFLAGS = QBEFLAGS = ASFLAGS = LDLINKFLAGS = --gc-sections -z noexecstack # commands used by the build script HAREC = harec QBE = qbe AS = as LD = ld SCDOC = scdoc # build locations HARECACHE = .cache BINOUT = .bin # variables that will be embedded in the binary with -D definitions HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party VERSION=$$(./scripts/version) # For cross-compilation, modify the variables below AARCH64_AS=as AARCH64_CC=cc AARCH64_LD=ld RISCV64_AS=as RISCV64_CC=cc RISCV64_LD=ld X86_64_AS=as X86_64_CC=cc X86_64_LD=ld hare-0.24.2/configs/netbsd.mk000066400000000000000000000014121464473310100157570ustar00rootroot00000000000000# install locations PREFIX = /usr/local BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man SRCDIR = $(PREFIX)/src STDLIB = $(SRCDIR)/hare/stdlib # variables used during build PLATFORM = netbsd ARCH = x86_64 HAREFLAGS = HARECFLAGS = QBEFLAGS = ASFLAGS = LDLINKFLAGS = --gc-sections -z noexecstack # commands used by the build script HAREC = harec QBE = qbe AS = as LD = ld SCDOC = scdoc # build locations HARECACHE = .cache BINOUT = .bin # variables that will be embedded in the binary with -D definitions HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party VERSION=$$(./scripts/version) # For cross-compilation, modify the variables below AARCH64_AS=as AARCH64_CC=cc AARCH64_LD=ld RISCV64_AS=as RISCV64_CC=cc RISCV64_LD=ld X86_64_AS=as X86_64_CC=cc X86_64_LD=ld hare-0.24.2/configs/openbsd.mk000066400000000000000000000015741464473310100161430ustar00rootroot00000000000000# install locations PREFIX = /usr/local BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/man SRCDIR = $(PREFIX)/src STDLIB = $(SRCDIR)/hare/stdlib # variables used during build PLATFORM = openbsd ARCH = x86_64 HAREFLAGS = HARECFLAGS = QBEFLAGS = ASFLAGS = LDLINKFLAGS = -z nobtcfi # commands used by the build script HAREC = harec QBE = qbe # gas is in the "binutils" package; as from the base system is too old. the "gas" # package also works on all arches except riscv64. AS = gas LD = cc SCDOC = scdoc # build locations HARECACHE = .cache BINOUT = .bin # variables that will be embedded in the binary with -D definitions HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party VERSION=$$(./scripts/version) # for cross-compilation, modify the variables below AARCH64_AS=gas AARCH64_CC=cc AARCH64_LD=cc RISCV64_AS=gas RISCV64_CC=cc RISCV64_LD=cc X86_64_AS=gas X86_64_CC=cc X86_64_LD=cc hare-0.24.2/crypto/000077500000000000000000000000001464473310100140415ustar00rootroot00000000000000hare-0.24.2/crypto/+test/000077500000000000000000000000001464473310100150735ustar00rootroot00000000000000hare-0.24.2/crypto/+test/authenc_test.ha000066400000000000000000000323251464473310100201000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use errors; type sample = struct { msg: []u8, cipher: []u8, additional: []u8, key: sessionkey, nonce: nonce, mac: mac, }; // test vector taken from the XChacha20-Poly1305-AEAD draft rfc const rfcsample: sample = sample { msg = [ 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x74, 0x2e, ], additional = [ 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ], key = [ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ], nonce = [ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, ], cipher = [ 0xbd, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b, 0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39, 0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc, 0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb, 0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44, 0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39, 0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16, 0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52, 0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45, 0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e, 0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f, 0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9, 0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9, 0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13, 0xb5, 0x2e, ], mac = [ 0xc0, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79, 0x47, 0xde, 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49, ], }; const noadsample: sample = sample { key = [ 0xdf, 0x23, 0xf4, 0xad, 0xe4, 0x6f, 0xc1, 0x41, 0x36, 0xe6, 0x63, 0x48, 0x3c, 0xcd, 0x74, 0x56, 0x44, 0x6a, 0x56, 0x56, 0xd8, 0xb4, 0x34, 0x30, 0xd4, 0xfd, 0x7b, 0xa8, 0x2c, 0x60, 0xf7, 0x62, ], msg = [ 0x9b, 0x0e, 0x38, 0x4b, 0x29, 0x09, 0x8e, 0xa3, 0xb4, 0x37, 0x7c, 0x81, 0xba, 0xc0, 0xbf, 0x7e, 0x59, 0xc2, 0xdc, 0x0f, 0x43, 0x03, 0x40, 0x1f, 0xd4, 0x1b, 0xae, 0x69, 0xfd, 0x0f, 0x0f, 0x49, 0xc8, 0xef, 0xa2, 0x30, 0x21, 0x53, 0x4a, 0xfc, 0x0c, 0xa6, 0xef, 0x3c, 0x34, 0xe9, 0x9c, 0xc7, 0x8b, 0xd7, 0xe6, 0x02, 0xcd, 0xc5, 0x28, 0x43, 0x42, 0xe3, 0xdf, 0x32, 0xf2, 0x28, 0xd9, 0x09, 0xca, 0xa4, 0x45, 0x19, 0x2a, 0x9e, 0x2d, 0x99, 0xf1, 0x40, 0x55, 0x2f, 0xb4, 0xe0, 0x04, 0xd8, 0x3b, 0x2e, 0x1e, 0xed, 0xff, 0xa6, 0x51, 0xd2, 0xe1, 0x22, ], nonce = [ 0xe2, 0x5b, 0x34, 0x1f, 0xc2, 0x8b, 0x6e, 0xc3, 0x37, 0xa0, 0x92, 0x45, 0xa8, 0xcb, 0x4b, 0x40, 0x3f, 0x24, 0x1c, 0x95, 0xff, 0x72, 0xea, 0x1d, ], cipher = [ 0x0b, 0xec, 0x57, 0xc8, 0x58, 0xf0, 0xc6, 0xb3, 0x42, 0x94, 0x86, 0xce, 0xf3, 0x3f, 0x04, 0x19, 0x41, 0xc2, 0xf7, 0xc9, 0x1f, 0x12, 0x9c, 0xbd, 0x68, 0xa8, 0xf2, 0xbe, 0xd3, 0xf3, 0x11, 0xea, 0x6e, 0xae, 0x39, 0xca, 0x93, 0x06, 0x99, 0x70, 0x67, 0xd6, 0xfa, 0xd8, 0x16, 0x4b, 0x2d, 0xf3, 0xb4, 0x73, 0x22, 0x36, 0x4b, 0x2d, 0xac, 0xd2, 0xaa, 0xab, 0x13, 0x2a, 0xd7, 0x05, 0x15, 0xbf, 0x18, 0x56, 0x20, 0xdb, 0xa4, 0xbb, 0x38, 0xa8, 0x8b, 0x0d, 0x12, 0xcc, 0x3b, 0x47, 0x4c, 0xba, 0x5f, 0x11, 0x75, 0x4e, 0x34, 0x87, 0x14, 0xe9, 0xb1, 0x23, ], mac = [ 0x07, 0x92, 0x76, 0xd8, 0x7c, 0x77, 0x71, 0x4b, 0xa4, 0xf2, 0x27, 0x66, 0x79, 0xeb, 0x38, 0xc1, ], ... }; const nomsg: sample = sample { key = [ 0x10, 0x28, 0xbe, 0x0e, 0x0e, 0x46, 0x38, 0x0f, 0x12, 0x9f, 0x56, 0x17, 0x21, 0xb8, 0x65, 0x44, 0x49, 0x0d, 0x48, 0x7a, 0x46, 0x79, 0x5b, 0x9c, 0x54, 0xfd, 0x42, 0xc4, 0x53, 0x82, 0x51, 0x14, ], nonce = [ 0x35, 0x54, 0xec, 0x93, 0x4d, 0xd5, 0xdc, 0x90, 0xa2, 0xd3, 0x72, 0xdc, 0xff, 0x0a, 0x73, 0x32, 0x5f, 0xbd, 0xcc, 0x36, 0xab, 0x3f, 0x47, 0x1c, ], additional = [ 0xbe, 0x71, 0xf2, 0x86, 0x5a, 0xb9, 0x1b, 0x3c, 0x07, 0x9b, 0xa3, 0x3a, 0x34, 0xa3, 0x5e, 0x4a, 0x51, 0x34, 0xf5, 0x02, 0x55, 0xb1, 0x97, 0x1d, 0xd8, 0xb8, 0xb0, 0x63, 0x07, 0x98, 0x11, 0x7c, 0x4e, 0x40, 0xd1, 0xfe, 0xf7, 0x8d, 0xc8, 0xbc, 0x45, 0x3c, 0x1f, 0x81, 0x2d, 0xf2, 0x98, 0x88, 0x36, 0x9d, 0x0d, 0x2f, 0x71, 0xf5, 0xdb, 0x9d, 0x05, 0x5e, 0xc5, 0x4d, 0x6d, 0xe3, 0xca, 0xbb, 0x46, 0xda, 0x99, 0x41, 0xb1, 0xcd, 0x4e, 0xdc, 0xa3, 0x82, 0xc1, 0xb7, 0xd3, 0x5b, 0xae, 0x41, 0x60, 0x6a, 0x59, 0x2e, 0xf9, 0xd3, 0xbf, 0x44, 0x95, 0xbd, ], mac = [ 0xe9, 0x50, 0xd4, 0x3f, 0x0a, 0x84, 0x69, 0x24, 0xa3, 0x9a, 0xe6, 0x06, 0x29, 0xf8, 0x16, 0xcf, ], ... }; const nothing: sample = sample { key = [ 0xbb, 0xf5, 0xf5, 0x40, 0xd7, 0x21, 0x38, 0x22, 0xe2, 0x82, 0x34, 0x0e, 0x26, 0xaa, 0x0a, 0xce, 0x94, 0x76, 0xb1, 0xac, 0x62, 0x50, 0x3f, 0x1a, 0x7c, 0x66, 0x78, 0xb3, 0x86, 0x3e, 0x4d, 0x4f, ], nonce = [ 0x54, 0xe3, 0xf0, 0xa8, 0x06, 0x86, 0x26, 0xd8, 0xd7, 0x7e, 0x26, 0x23, 0x3b, 0x95, 0xbf, 0x44, 0x30, 0x9e, 0xf6, 0xe4, 0x00, 0x65, 0xff, 0x1a, ], mac = [ 0x14, 0x23, 0x9b, 0xb3, 0xa3, 0x35, 0x9a, 0x11, 0x9c, 0x1d, 0x79, 0x65, 0x4b, 0xe2, 0x2f, 0xaf, ], ... }; const polyaligned: sample = sample { key = [ 0x8a, 0x67, 0xe3, 0x6c, 0x24, 0xbd, 0x05, 0x7f, 0x53, 0x7d, 0x3b, 0x2d, 0x25, 0x98, 0x7c, 0x21, 0xb1, 0x51, 0x90, 0xdd, 0x7a, 0x4a, 0x52, 0x49, 0x12, 0x22, 0x3e, 0x7e, 0x2e, 0x0d, 0x8a, 0x15, ], msg = [ 0xa1, 0x9c, 0x40, 0xbe, 0x6e, 0xf7, 0x43, 0x66, 0xcf, 0xe1, 0x15, 0xce, 0x0c, 0x90, 0x7c, 0x1f, 0x35, 0xfb, 0x03, 0x7f, 0x96, 0x62, 0x53, 0xa6, 0xfa, 0xf1, 0x31, 0x39, 0xae, 0x69, 0x0e, 0xf7, ], nonce = [ 0xc2, 0x16, 0x80, 0x49, 0xd1, 0x82, 0x04, 0xc5, 0x89, 0xee, 0xbc, 0x24, 0xa0, 0x37, 0x6f, 0xbb, 0x44, 0x09, 0x49, 0x8e, 0xe2, 0x73, 0x33, 0x4d, ], additional = [ 0xc1, 0xf7, 0xa5, 0xcf, 0x2f, 0xc0, 0x21, 0x55, 0x74, 0xfb, 0x75, 0xcd, 0x8b, 0x9e, 0xe2, 0x2a, ], cipher = [ 0xfe, 0xe1, 0xb9, 0xff, 0xc5, 0x03, 0x38, 0x73, 0xbb, 0x1c, 0x90, 0x7b, 0x53, 0x39, 0x65, 0xd7, 0x64, 0x12, 0xe4, 0x88, 0xa0, 0xaa, 0x8e, 0x11, 0x23, 0xd0, 0x20, 0x8a, 0x54, 0x76, 0x12, 0x75, ], mac = [ 0x7e, 0x80, 0x2c, 0x34, 0x45, 0x04, 0x5b, 0xff, 0x04, 0x58, 0x36, 0xef, 0xe2, 0x55, 0xc8, 0x45, ], }; @test fn rfc() void = { let result: []u8 = alloc(rfcsample.msg...); defer free(result); let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], rfcsample.additional[..]); assert(bytes::equal(rfcsample.cipher, b.2)); assert(bytes::equal(rfcsample.nonce, b.1)); assert(bytes::equal(rfcsample.mac, b.0)); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is []u8); assert(bytes::equal(rfcsample.msg, plain as []u8)); }; @test fn rfcmultiadditonals() void = { let result: []u8 = alloc(rfcsample.msg...); defer free(result); let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], rfcsample.additional[..4], rfcsample.additional[4..]); assert(bytes::equal(rfcsample.cipher, b.2)); assert(bytes::equal(rfcsample.nonce, b.1)); assert(bytes::equal(rfcsample.mac, b.0)); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is []u8); assert(bytes::equal(rfcsample.msg, plain as []u8)); }; @test fn noadditional() void = { let result: []u8 = alloc(noadsample.msg...); defer free(result); let b = encrypt(&noadsample.key, &noadsample.nonce, result[..]); assert(bytes::equal(noadsample.cipher, b.2)); assert(bytes::equal(noadsample.nonce, b.1)); assert(bytes::equal(noadsample.mac, b.0)); const plain = decrypt(&noadsample.key, &b); assert(plain is []u8); assert(bytes::equal(noadsample.msg, plain as []u8)); }; @test fn nomsg() void = { let result: []u8 = []; defer free(result); let b = encrypt(&nomsg.key, &nomsg.nonce, result[..], nomsg.additional); assert(bytes::equal([], b.2)); assert(bytes::equal(nomsg.nonce, b.1)); assert(bytes::equal(nomsg.mac, b.0)); const plain = decrypt(&nomsg.key, &b, nomsg.additional); assert(plain is []u8); assert(bytes::equal([], plain as []u8)); }; @test fn nothing() void = { let result: []u8 = []; defer free(result); let b = encrypt(¬hing.key, ¬hing.nonce, result[..]); assert(bytes::equal([], b.2)); assert(bytes::equal(nothing.nonce, b.1)); assert(bytes::equal(nothing.mac, b.0)); const plain = decrypt(¬hing.key, &b); assert(plain is []u8); assert(bytes::equal([], plain as []u8)); }; @test fn polyaligned() void = { let result: []u8 = alloc(polyaligned.msg...); defer free(result); let b = encrypt(&polyaligned.key, &polyaligned.nonce, result[..], polyaligned.additional[..]); assert(bytes::equal(polyaligned.cipher, b.2)); assert(bytes::equal(polyaligned.nonce, b.1)); assert(bytes::equal(polyaligned.mac, b.0)); const plain = decrypt(&polyaligned.key, &b, polyaligned.additional); assert(plain is []u8); assert(bytes::equal(polyaligned.msg, plain as []u8)); }; @test fn invalidkey() void = { const zero: [114]u8 = [0...]; let key = rfcsample.key; key[0] = 0x00; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&key, &b, rfcsample.additional); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidcipher() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); cipher[0] = 0x00; let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidcipher2() void = { let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); append(cipher, 0xff); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is errors::invalid); const zero: [115]u8 = [0...]; assert(bytes::equal(zero, cipher)); }; @test fn invalidcipher3() void = { let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); delete(cipher[len(cipher) - 1]); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is errors::invalid); const zero: [113]u8 = [0...]; assert(bytes::equal(zero, cipher)); }; @test fn invalidaddition() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let ad: []u8 = alloc(rfcsample.additional...); defer free(ad); ad[0] = 0x00; let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, ad); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidaddition2() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let ad: []u8 = alloc(rfcsample.additional...); defer free(ad); append(ad, 0xff); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, ad); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidaddition3() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let ad: []u8 = alloc(rfcsample.additional...); defer free(ad); delete(ad[len(ad) - 1]); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, ad); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidaddition4() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn invalidaddition5() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional, [0xff]); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; @test fn cipheradditionswap() void = { let additional: []u8 = alloc(rfcsample.additional...); defer free(additional); let b: box = (rfcsample.mac, rfcsample.nonce, additional); const plain = decrypt(&rfcsample.key, &b, rfcsample.cipher); assert(plain is errors::invalid); const zero: [12]u8 = [0...]; assert(bytes::equal(zero, additional)); }; @test fn invalidmac() void = { const zero: [114]u8 = [0...]; let cipher: []u8 = alloc(rfcsample.cipher...); defer free(cipher); let mac: mac = rfcsample.mac; mac[0] = 0xff; let b: box = (mac, rfcsample.nonce, cipher[..]); const plain = decrypt(&rfcsample.key, &b, rfcsample.additional); assert(plain is errors::invalid); assert(bytes::equal(zero, cipher)); }; hare-0.24.2/crypto/README000066400000000000000000000050701464473310100147230ustar00rootroot00000000000000Important notice: Hare's cryptography implementations have not been audited. You can contribute to the funding of an independent audit of our cryptography implementation on OpenCollective: https://opencollective.com/hare/projects/cryptography-audit The "crypto" module provides easy-to-use and hard-to-misuse functions for doing various high-level cryptographic operations. This is the recommended approach for most cryptographic applications. For applications which need them, direct access to supported cryptographic primitives is provided in submodules. Cryptography is a difficult, high-risk domain of programming. The life and well-being of your users may depend on your ability to implement cryptographic applications with due care. Please carefully read all of the documentation, double-check your work, and seek second opinions and independent review of your code. Our documentation and API design aims to prevent easy mistakes from being made, but it is no substitute for a good background in applied cryptography. We recommend the "Crypto 101" course as a good general introduction to cryptography: https://www.crypto101.io There are a few additional modules and functions which are of interest to users of the crypto module. Access to secure random data is provided by the [[crypto::random::]] module. The ability to securely erase sensitive data in RAM is provided by [[bytes::zero]]. Note also that [[bytes::equal]] is not suitable for constant-time comparisons; equality comparisons in a cryptographic context should utilize [[compare]] instead. TODO: Add something based on mlock to deal with storing sensitive information, and add a note here about it. We reserve the right to make breaking changes to this module in the future, which may prevent data prepared by old versions from being readable by new versions. Such changes will be accompanied with an increment of the major version of the standard library, as well as a changelog explaining what changes are required of downstream users, and a migration procedure will be prepared. The hare-announce mailing list is the appropriate way to be notified of these changes: https://lists.sr.ht/~sircmpwn/hare-announce The following features are offered in this module: - [[encrypt]] and [[decrypt]] provide authenticated encryption. - [[sign]] and [[verify]] provide public key message signing and verification. - [[exchange]] provides a secure key exchange function. - [[derivekey]] implements key derivation, which is also recommended for hashing passwords. - [[hash::]] provides a [[hash::hash]] algorithm suitable for cryptographic use. hare-0.24.2/crypto/aes/000077500000000000000000000000001464473310100146115ustar00rootroot00000000000000hare-0.24.2/crypto/aes/+test/000077500000000000000000000000001464473310100156435ustar00rootroot00000000000000hare-0.24.2/crypto/aes/+test/gcm.ha000066400000000000000000000534231464473310100167320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; use errors; use io; use memio; type gcmtestcase = struct { key: []u8, iv: []u8, plain: []u8, additional: []u8, cipher: []u8, tag: [16]u8, }; // Testcases from Appendix B of https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf const gcmtestcases: []gcmtestcase = [ gcmtestcase { key = [0...]: [16]u8, iv = [0...]: [12]u8, plain = [], cipher = [], tag = [ 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a, ], ... }, gcmtestcase { key = [0...]: [16]u8, iv = [0...]: [12]u8, plain = [0...]: [16]u8, cipher = [ 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, ], tag = [ 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, ], tag = [ 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91, ], tag = [ 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47, ], }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, ], cipher = [ 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, 0xc2, 0x3f, 0x45, 0x98, ], tag = [ 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, 0xa6, 0x37, 0xb3, 0x9b, ], cipher = [ 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, 0x4c, 0x34, 0xae, 0xe5, ], tag = [ 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50, ], }, gcmtestcase { key = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], iv = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], tag = [ 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35, ], ... }, gcmtestcase { key = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], plain = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], iv = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], cipher = [ 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00, ], tag = [ 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56, ], tag = [ 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, 0xcc, 0xda, 0x27, 0x10, ], tag = [ 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, ], cipher = [ 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, 0xa0, 0xf0, 0x62, 0xf7, ], tag = [ 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, 0xa6, 0x37, 0xb3, 0x9b, ], cipher = [ 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, 0xe9, 0xb7, 0x37, 0x3b, ], tag = [ 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9, ], ... }, gcmtestcase { key = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], iv = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], tag = [ 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b, ], ... }, gcmtestcase { key = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], plain = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], iv = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], cipher = [ 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, ], tag = [ 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad, ], tag = [ 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, ], cipher = [ 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62, ], tag = [ 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, ], cipher = [ 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, 0xf4, 0x7c, 0x9b, 0x1f, ], tag = [ 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2, ], ... }, gcmtestcase { key = [ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, ], plain = [ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, ], additional = [ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2, ], iv = [ 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, 0xa6, 0x37, 0xb3, 0x9b, ], cipher = [ 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, 0x44, 0xae, 0x7e, 0x3f, ], tag = [ 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a, ], ... }, ]; @test fn gcm_encrypt() void = { for (let i = 0z; i < len(gcmtestcases); i += 1) { const t = gcmtestcases[i]; let b = ct64(); ct64_init(&b, t.key); let result: []u8 = if (len(t.cipher) == 0) { yield []; } else { yield alloc([0...], len(t.cipher)); }; defer free(result); let resultbuf = memio::fixed(result); let gstream = cipher::gcm(); cipher::gcm_init(&gstream, &resultbuf, &b, t.iv, t.additional); defer io::close(&gstream)!; io::writeall(&gstream, t.plain)!; let tag: [cipher::GCMTAGSZ]u8 = [0...]; cipher::gcm_seal(&gstream, tag); assert(bytes::equal(t.cipher, result)); assert(bytes::equal(t.tag, tag)); }; }; @test fn gcm_decrypt() void = { for (let i = 0z; i < len(gcmtestcases); i += 1) { const t = gcmtestcases[i]; let b = ct64(); ct64_init(&b, t.key); let result: []u8 = if (len(t.cipher) == 0) { yield []; } else { yield alloc([0...], len(t.cipher)); }; defer free(result); let cipherbuf = memio::fixed(t.cipher); let gstream = cipher::gcm(); cipher::gcm_init(&gstream, &cipherbuf, &b, t.iv, t.additional); defer io::close(&gstream)!; io::readall(&gstream, result)!; assert(bytes::equal(t.plain, result)); cipher::gcm_verify(&gstream, t.tag)!; let wrongtag: [16]u8 = t.tag; wrongtag[0] += 1; match (cipher::gcm_verify(&gstream, wrongtag)) { case errors::invalid => void; case => assert(false); }; }; }; @test fn gcm_inplace() void = { for (let i = 0z; i < len(gcmtestcases); i += 1) { const t = gcmtestcases[i]; let b = ct64(); ct64_init(&b, t.key); let result: []u8 = if (len(t.plain) == 0) { yield []; } else { let r: []u8 = alloc([0...], len(t.plain)); r[..] = t.plain[..]; yield r; }; defer free(result); let resultbuf = memio::fixed(result); let gstream = cipher::gcm(); // beware: did not close the stream for sake of simplicity cipher::gcm_init(&gstream, &resultbuf, &b, t.iv, t.additional); io::writeall(&gstream, result)!; let tag: [cipher::GCMTAGSZ]u8 = [0...]; cipher::gcm_seal(&gstream, tag); assert(bytes::equal(t.cipher, result)); assert(bytes::equal(t.tag, tag)); let resultbuf = memio::fixed(result); let gstream = cipher::gcm(); cipher::gcm_init(&gstream, &resultbuf, &b, t.iv, t.additional); io::readall(&gstream, result)!; assert(bytes::equal(t.plain, result)); cipher::gcm_verify(&gstream, t.tag)!; }; }; hare-0.24.2/crypto/aes/+test/ni_test+x86_64.ha000066400000000000000000000231051464473310100205550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; use test; const zero_rk: [EXPKEYLEN256]u8 = [0...]; @test fn ni_enabled() void = { assert((hwsup && rtvtable == &x86ni_vtable && initfuncptr == &x86ni_init) || !x86ni_available()); }; // taken from fips-197.pdf Section A.1 @test fn ni_enc_key_expand_128() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c ]; const expected_rounds: [_]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa0, 0xfa, 0xfe, 0x17, 0x88, 0x54, 0x2c, 0xb1, 0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05, 0xf2, 0xc2, 0x95, 0xf2, 0x7a, 0x96, 0xb9, 0x43, 0x59, 0x35, 0x80, 0x7a, 0x73, 0x59, 0xf6, 0x7f, 0x3d, 0x80, 0x47, 0x7d, 0x47, 0x16, 0xfe, 0x3e, 0x1e, 0x23, 0x7e, 0x44, 0x6d, 0x7a, 0x88, 0x3b, 0xef, 0x44, 0xa5, 0x41, 0xa8, 0x52, 0x5b, 0x7f, 0xb6, 0x71, 0x25, 0x3b, 0xdb, 0x0b, 0xad, 0x00, 0xd4, 0xd1, 0xc6, 0xf8, 0x7c, 0x83, 0x9d, 0x87, 0xca, 0xf2, 0xb8, 0xbc, 0x11, 0xf9, 0x15, 0xbc, 0x6d, 0x88, 0xa3, 0x7a, 0x11, 0x0b, 0x3e, 0xfd, 0xdb, 0xf9, 0x86, 0x41, 0xca, 0x00, 0x93, 0xfd, 0x4e, 0x54, 0xf7, 0x0e, 0x5f, 0x5f, 0xc9, 0xf3, 0x84, 0xa6, 0x4f, 0xb2, 0x4e, 0xa6, 0xdc, 0x4f, 0xea, 0xd2, 0x73, 0x21, 0xb5, 0x8d, 0xba, 0xd2, 0x31, 0x2b, 0xf5, 0x60, 0x7f, 0x8d, 0x29, 0x2f, 0xac, 0x77, 0x66, 0xf3, 0x19, 0xfa, 0xdc, 0x21, 0x28, 0xd1, 0x29, 0x41, 0x57, 0x5c, 0x00, 0x6e, 0xd0, 0x14, 0xf9, 0xa8, 0xc9, 0xee, 0x25, 0x89, 0xe1, 0x3f, 0x0c, 0xc8, 0xb6, 0x63, 0x0c, 0xa6, ]; let block = x86ni(); x86ni_init(&block, key[..]); assert(block.rounds == 10); assert(bytes::equal(expected_rounds[..], block.expkey[..EXPKEYLEN128])); cipher::finish(&block); assert(bytes::equal(zero_rk[..], block.expkey[..EXPKEYLEN256])); }; // taken from fips-197.pdf Section A.2 @test fn ni_enc_key_expand_192() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: [24]u8 = [ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b ]; const expected_rounds: [_]u8 = [ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b, 0xfe, 0x0c, 0x91, 0xf7, 0x24, 0x02, 0xf5, 0xa5, 0xec, 0x12, 0x06, 0x8e, 0x6c, 0x82, 0x7f, 0x6b, 0x0e, 0x7a, 0x95, 0xb9, 0x5c, 0x56, 0xfe, 0xc2, 0x4d, 0xb7, 0xb4, 0xbd, 0x69, 0xb5, 0x41, 0x18, 0x85, 0xa7, 0x47, 0x96, 0xe9, 0x25, 0x38, 0xfd, 0xe7, 0x5f, 0xad, 0x44, 0xbb, 0x09, 0x53, 0x86, 0x48, 0x5a, 0xf0, 0x57, 0x21, 0xef, 0xb1, 0x4f, 0xa4, 0x48, 0xf6, 0xd9, 0x4d, 0x6d, 0xce, 0x24, 0xaa, 0x32, 0x63, 0x60, 0x11, 0x3b, 0x30, 0xe6, 0xa2, 0x5e, 0x7e, 0xd5, 0x83, 0xb1, 0xcf, 0x9a, 0x27, 0xf9, 0x39, 0x43, 0x6a, 0x94, 0xf7, 0x67, 0xc0, 0xa6, 0x94, 0x07, 0xd1, 0x9d, 0xa4, 0xe1, 0xec, 0x17, 0x86, 0xeb, 0x6f, 0xa6, 0x49, 0x71, 0x48, 0x5f, 0x70, 0x32, 0x22, 0xcb, 0x87, 0x55, 0xe2, 0x6d, 0x13, 0x52, 0x33, 0xf0, 0xb7, 0xb3, 0x40, 0xbe, 0xeb, 0x28, 0x2f, 0x18, 0xa2, 0x59, 0x67, 0x47, 0xd2, 0x6b, 0x45, 0x8c, 0x55, 0x3e, 0xa7, 0xe1, 0x46, 0x6c, 0x94, 0x11, 0xf1, 0xdf, 0x82, 0x1f, 0x75, 0x0a, 0xad, 0x07, 0xd7, 0x53, 0xca, 0x40, 0x05, 0x38, 0x8f, 0xcc, 0x50, 0x06, 0x28, 0x2d, 0x16, 0x6a, 0xbc, 0x3c, 0xe7, 0xb5, 0xe9, 0x8b, 0xa0, 0x6f, 0x44, 0x8c, 0x77, 0x3c, 0x8e, 0xcc, 0x72, 0x04, 0x01, 0x00, 0x22, 0x02, ]; let block = x86ni(); x86ni_init(&block, key[..]); assert(block.rounds == 12); assert(bytes::equal(expected_rounds[..], block.expkey[..EXPKEYLEN192])); }; // taken from fips-197.pdf Section A.3 @test fn ni_enc_key_expand_256() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: [32]u8 = [ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, ]; const expected_rounds: [_]u8 = [ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, 0x9b, 0xa3, 0x54, 0x11, 0x8e, 0x69, 0x25, 0xaf, 0xa5, 0x1a, 0x8b, 0x5f, 0x20, 0x67, 0xfc, 0xde, 0xa8, 0xb0, 0x9c, 0x1a, 0x93, 0xd1, 0x94, 0xcd, 0xbe, 0x49, 0x84, 0x6e, 0xb7, 0x5d, 0x5b, 0x9a, 0xd5, 0x9a, 0xec, 0xb8, 0x5b, 0xf3, 0xc9, 0x17, 0xfe, 0xe9, 0x42, 0x48, 0xde, 0x8e, 0xbe, 0x96, 0xb5, 0xa9, 0x32, 0x8a, 0x26, 0x78, 0xa6, 0x47, 0x98, 0x31, 0x22, 0x29, 0x2f, 0x6c, 0x79, 0xb3, 0x81, 0x2c, 0x81, 0xad, 0xda, 0xdf, 0x48, 0xba, 0x24, 0x36, 0x0a, 0xf2, 0xfa, 0xb8, 0xb4, 0x64, 0x98, 0xc5, 0xbf, 0xc9, 0xbe, 0xbd, 0x19, 0x8e, 0x26, 0x8c, 0x3b, 0xa7, 0x09, 0xe0, 0x42, 0x14, 0x68, 0x00, 0x7b, 0xac, 0xb2, 0xdf, 0x33, 0x16, 0x96, 0xe9, 0x39, 0xe4, 0x6c, 0x51, 0x8d, 0x80, 0xc8, 0x14, 0xe2, 0x04, 0x76, 0xa9, 0xfb, 0x8a, 0x50, 0x25, 0xc0, 0x2d, 0x59, 0xc5, 0x82, 0x39, 0xde, 0x13, 0x69, 0x67, 0x6c, 0xcc, 0x5a, 0x71, 0xfa, 0x25, 0x63, 0x95, 0x96, 0x74, 0xee, 0x15, 0x58, 0x86, 0xca, 0x5d, 0x2e, 0x2f, 0x31, 0xd7, 0x7e, 0x0a, 0xf1, 0xfa, 0x27, 0xcf, 0x73, 0xc3, 0x74, 0x9c, 0x47, 0xab, 0x18, 0x50, 0x1d, 0xda, 0xe2, 0x75, 0x7e, 0x4f, 0x74, 0x01, 0x90, 0x5a, 0xca, 0xfa, 0xaa, 0xe3, 0xe4, 0xd5, 0x9b, 0x34, 0x9a, 0xdf, 0x6a, 0xce, 0xbd, 0x10, 0x19, 0x0d, 0xfe, 0x48, 0x90, 0xd1, 0xe6, 0x18, 0x8d, 0x0b, 0x04, 0x6d, 0xf3, 0x44, 0x70, 0x6c, 0x63, 0x1e, ]; let block = x86ni(); x86ni_init(&block, key[..]); assert(block.rounds == 14); assert(bytes::equal(expected_rounds[..], block.expkey[..EXPKEYLEN256])); }; @test fn ni_test_encrypt_128() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; let key: [_]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; let plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let b = x86ni(); x86ni_init(&b, key[..]); cipher::encrypt(&b, result[..], plain); assert(bytes::equal(cipher, result)); }; @test fn ni_test_decrypt_128() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: [_]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let b = x86ni(); x86ni_init(&b, key[..]); cipher::decrypt(&b, result[..], cipher); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.1 @test fn ni_test_example_vector1() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: []u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; const plain: []u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: []u8 = [ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, ]; let result: [16]u8 = [0...]; let b = x86ni(); x86ni_init(&b, key[..]); cipher::encrypt(&b, result[..], plain); assert(bytes::equal(cipher, result)); cipher::decrypt(&b, result[..], cipher); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.2 @test fn ni_test_example_vector2() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: []u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ]; const plain: []u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: []u8 = [ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91, ]; let result: [16]u8 = [0...]; let b = x86ni(); x86ni_init(&b, key[..]); cipher::encrypt(&b, result[..], plain); assert(bytes::equal(cipher, result)); cipher::decrypt(&b, result[..], cipher); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.3 @test fn ni_test_example_vector3() void = { if (!x86ni_available()) { test::skip("Native x86 AES interface isn't available"); }; const key: []u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; const plain: []u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: []u8 = [ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89, ]; let result: [16]u8 = [0...]; let b = x86ni(); x86ni_init(&b, key[..]); cipher::encrypt(&b, result[..], plain); assert(bytes::equal(cipher, result)); cipher::decrypt(&b, result[..], cipher); assert(bytes::equal(plain, result)); }; hare-0.24.2/crypto/aes/+x86_64/000077500000000000000000000000001464473310100156225ustar00rootroot00000000000000hare-0.24.2/crypto/aes/+x86_64/ni.ha000066400000000000000000000044471464473310100165530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::cipher; use rt; def EXPKEYLEN128: size = 176; def EXPKEYLEN192: size = 208; def EXPKEYLEN256: size = 240; def X86NI_EXPKEYSZ: size = 480; const x86ni_vtable: cipher::blockvtable = cipher::blockvtable { blocksz = BLOCKSZ, nparallel = 1, encrypt = &x86ni_encrypt, decrypt = &x86ni_decrypt, finish = &block_finish, }; // Checks if the native AES interface is available. fn x86ni_available() bool = { return rt::cpuid_hasflags(0, rt::cpuid_ecxflag::AES | rt::cpuid_ecxflag::AVX); }; // Returns a native AES [[crypto::cipher::block]] implementation for x86_64 // CPUs supporting AES-NI. // // The caller must call [[x86ni_init]] to add a key to the cipher before using // the cipher, and must call [[crypto::cipher::finish]] when they are finished // using the cipher to securely erase any secret data stored in the cipher // state. fn x86ni() block = { return block { vtable = &x86ni_vtable, ... }; }; fn x86ni_init(b: *block, key: []u8) void = { assert(len(key) == 16 || len(key) == 24 || len(key) == 32, "Invalid aes key length"); let enc = b.expkey[..EXPKEYLEN256]; let dec = b.expkey[EXPKEYLEN256..]; const expkeylen = x86ni_keyexp(key[..], enc, dec); b.rounds = (expkeylen >> 4) - 1; }; fn x86ni_encrypt(b: *cipher::block, dest: []u8, src: []u8) void = { assert(len(dest) == len(src) && len(dest) % BLOCKSZ == 0); let b = b: *block; const expkeylen = (b.rounds + 1) << 4; let enc = b.expkey[..expkeylen]; // XXX loop could be done in assembly for (len(src) > 0) { x86ni_asencrypt(enc, dest, src); src = src[BLOCKSZ..]; dest = dest[BLOCKSZ..]; }; }; fn x86ni_decrypt(b: *cipher::block, dest: []u8, src: []u8) void = { assert(len(dest) == len(src) && len(dest) % BLOCKSZ == 0); let b = b: *block; const expkeylen = (b.rounds + 1) << 4; let dec = b.expkey[EXPKEYLEN256..]; // XXX loop could be done in assembly for (len(src) > 0) { x86ni_asdecrypt(dec[..expkeylen], dest, src); src = src[BLOCKSZ..]; dest = dest[BLOCKSZ..]; }; }; // Expands encryption and decryption key and returns the size of the round keys. fn x86ni_keyexp(key: []u8, enc_rk: []u8, dec_rk: []u8) u8; fn x86ni_asencrypt(key_exp: []u8, dest: []u8, src: []u8) void; fn x86ni_asdecrypt(key_exp: []u8, dest: []u8, src: []u8) void; hare-0.24.2/crypto/aes/+x86_64/ni.s000066400000000000000000000227471464473310100164300ustar00rootroot00000000000000.section ".text.crypto.aes.x86ni_keyexp","ax" .global crypto.aes.x86ni_keyexp .type crypto.aes.x86ni_keyexp,@function crypto.aes.x86ni_keyexp: pushq %rbp mov %rsp, %rbp pushq %rbx pushq %rcx pushq %rdx movq 0x10(%rbp), %rbx # &key movq 0x18(%rbp), %rax # keylen movq 0x28(%rbp), %rcx # &enk_rk mov $0x18, %rdx cmp %rax, %rdx je enc_key_192 jle enc_key_256 enc_key_128: movdqu (%rbx), %xmm1 movdqu %xmm1, (%rcx) aeskeygenassist $0x1, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x10(%rcx) aeskeygenassist $0x2, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x20(%rcx) aeskeygenassist $0x4, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x30(%rcx) aeskeygenassist $0x8, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x40(%rcx) aeskeygenassist $0x10, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x50(%rcx) aeskeygenassist $0x20, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x60(%rcx) aeskeygenassist $0x40, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x70(%rcx) aeskeygenassist $0x80, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x80(%rcx) aeskeygenassist $0x1b, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0x90(%rcx) aeskeygenassist $0x36, %xmm1, %xmm2 call key_expand_128 movdqu %xmm1, 0xa0(%rcx) # return rklen mov $176, %rax jmp dec_key key_expand_128: vpslldq $0x4, %xmm1, %xmm3 pxor %xmm3, %xmm1 vpslldq $0x4, %xmm1, %xmm3 pxor %xmm3, %xmm1 vpslldq $0x4, %xmm1, %xmm3 pxor %xmm3, %xmm1 pshufd $0xff, %xmm2, %xmm2 pxor %xmm2, %xmm1 ret enc_key_192: movdqu (%rbx), %xmm1 movdqu 0x10(%rbx), %xmm3 movdqu %xmm1, (%rcx) movdqu %xmm3, %xmm5 aeskeygenassist $0x1, %xmm3, %xmm2 call key_expand_192 shufpd $0, %xmm1, %xmm5 movdqu %xmm5, 0x10(%rcx) movdqu %xmm1, %xmm6 shufpd $1, %xmm3, %xmm6 movdqu %xmm6, 0x20(%rcx) aeskeygenassist $0x2, %xmm3, %xmm2 call key_expand_192 movdqu %xmm1, 0x30(%rcx) movdqu %xmm3, %xmm5 aeskeygenassist $0x4, %xmm3, %xmm2 call key_expand_192 shufpd $0, %xmm1, %xmm5 movdqu %xmm5, 0x40(%rcx) movdqu %xmm1, %xmm6 shufpd $1, %xmm3, %xmm6 movdqu %xmm6, 0x50(%rcx) aeskeygenassist $0x8, %xmm3, %xmm2 call key_expand_192 movdqu %xmm1, 0x60(%rcx) movdqu %xmm3, %xmm5 aeskeygenassist $0x10, %xmm3, %xmm2 call key_expand_192 shufpd $0, %xmm1, %xmm5 movdqu %xmm5, 0x70(%rcx) movdqu %xmm1, %xmm6 shufpd $1, %xmm3, %xmm6 movdqu %xmm6, 0x80(%rcx) aeskeygenassist $0x20, %xmm3, %xmm2 call key_expand_192 movdqu %xmm1, 0x90(%rcx) movdqu %xmm3, %xmm5 aeskeygenassist $0x40, %xmm3, %xmm2 call key_expand_192 shufpd $0, %xmm1, %xmm5 movdqu %xmm5, 0xa0(%rcx) movdqu %xmm1, %xmm6 shufpd $1, %xmm3, %xmm6 movdqu %xmm6, 0xb0(%rcx) aeskeygenassist $0x80, %xmm3, %xmm2 call key_expand_192 movdqu %xmm1, 0xc0(%rcx) movdqu %xmm3, %xmm5 # return rklen mov $208, %rax jmp dec_key key_expand_192: vpslldq $0x4, %xmm1, %xmm4 pxor %xmm4, %xmm1 vpslldq $0x4, %xmm1, %xmm4 pxor %xmm4, %xmm1 vpslldq $0x4, %xmm1, %xmm4 pxor %xmm4, %xmm1 pshufd $0x55, %xmm2, %xmm2 pxor %xmm2, %xmm1 pshufd $0xff, %xmm1, %xmm2 vpslldq $0x4, %xmm3, %xmm4 pxor %xmm4, %xmm3 pxor %xmm2, %xmm3 ret enc_key_256: movdqu (%rbx), %xmm1 movdqu 0x10(%rbx), %xmm3 movdqu %xmm1, (%rcx) movdqu %xmm3, 0x10(%rcx) aeskeygenassist $0x1, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0x20(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0x30(%rcx) aeskeygenassist $0x2, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0x40(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0x50(%rcx) aeskeygenassist $0x4, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0x60(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0x70(%rcx) aeskeygenassist $0x8, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0x80(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0x90(%rcx) aeskeygenassist $0x10, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0xa0(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0xb0(%rcx) aeskeygenassist $0x20, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0xc0(%rcx) aeskeygenassist $0x0, %xmm1, %xmm2 call key_expand_256_b movdqu %xmm3, 0xd0(%rcx) aeskeygenassist $0x40, %xmm3, %xmm2 call key_expand_256_a movdqu %xmm1, 0xe0(%rcx) # return rklen mov $240, %rax jmp dec_key key_expand_256_a: movdqa %xmm1, %xmm4 pslldq $4, %xmm4 pxor %xmm4, %xmm1 pslldq $4, %xmm4 pxor %xmm4, %xmm1 pslldq $4, %xmm4 pxor %xmm4, %xmm1 pshufd $0xff, %xmm2, %xmm2 pxor %xmm2, %xmm1 ret key_expand_256_b: movdqa %xmm3, %xmm4 pslldq $4, %xmm4 pxor %xmm4, %xmm3 pslldq $4, %xmm4 pxor %xmm4, %xmm3 pslldq $4, %xmm4 pxor %xmm4, %xmm3 pshufd $0xaa, %xmm2, %xmm2 pxor %xmm2, %xmm3 ret dec_key: movq 0x40(%rbp), %rdx # &dec_rk # store key in reverse order, therefore add offset to last rk item add %rax, %rdx sub $16, %rdx dec_key_start: movdqu 0x0(%rcx), %xmm1 movdqu %xmm1, 0x0(%rdx) movdqu 0x10(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x10(%rdx) movdqu 0x20(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x20(%rdx) movdqu 0x30(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x30(%rdx) movdqu 0x40(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x40(%rdx) movdqu 0x50(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x50(%rdx) movdqu 0x60(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x60(%rdx) movdqu 0x70(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x70(%rdx) movdqu 0x80(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x80(%rdx) movdqu 0x90(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0x90(%rdx) mov $208, %rbx cmp %rax, %rbx je dec_key_192 jle dec_key_256 movdqu 0xa0(%rcx), %xmm1 movdqu %xmm1, -0xa0(%rdx) jmp key_exp_end dec_key_192: movdqu 0xa0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xa0(%rdx) movdqu 0xb0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xb0(%rdx) movdqu 0xc0(%rcx), %xmm1 movdqu %xmm1, -0xc0(%rdx) jmp key_exp_end dec_key_256: movdqu 0xa0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xa0(%rdx) movdqu 0xb0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xb0(%rdx) movdqu 0xc0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xc0(%rdx) movdqu 0xd0(%rcx), %xmm1 aesimc %xmm1, %xmm1 movdqu %xmm1, -0xd0(%rdx) movdqu 0xe0(%rcx), %xmm1 movdqu %xmm1, -0xe0(%rdx) key_exp_end: pxor %xmm0, %xmm0 pxor %xmm1, %xmm1 pxor %xmm2, %xmm2 pxor %xmm3, %xmm3 pxor %xmm4, %xmm4 pxor %xmm5, %xmm5 pxor %xmm6, %xmm6 popq %rdx popq %rcx popq %rbx leave ret .section ".text.crypto.aes.x86ni_asencrypt","ax" .global crypto.aes.x86ni_asencrypt .type crypto.aes.x86ni_asencrypt,@function crypto.aes.x86ni_asencrypt: pushq %rbp mov %rsp, %rbp pushq %rbx pushq %rcx pushq %rdx movq 0x10(%rbp), %rbx # &rk movq 0x18(%rbp), %rax # rklen movq 0x28(%rbp), %rcx # &dest movq 0x40(%rbp), %rdx # &src movdqu (%rdx), %xmm0 movdqu (%rbx), %xmm1 pxor %xmm1, %xmm0 movdqu 0x10(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x20(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x30(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x40(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x50(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x60(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x70(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x80(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0x90(%rbx), %xmm1 aesenc %xmm1, %xmm0 mov $208, %rdx cmp %rax, %rdx jl encrypt_256 je encrypt_192 movdqu 0xa0(%rbx), %xmm1 aesenclast %xmm1, %xmm0 jmp encrypt_end encrypt_192: movdqu 0xa0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xb0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xc0(%rbx), %xmm1 aesenclast %xmm1, %xmm0 jmp encrypt_end encrypt_256: movdqu 0xa0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xb0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xc0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xd0(%rbx), %xmm1 aesenc %xmm1, %xmm0 movdqu 0xe0(%rbx), %xmm1 aesenclast %xmm1, %xmm0 jmp encrypt_end encrypt_end: movdqu %xmm0, (%rcx) pxor %xmm0, %xmm0 pxor %xmm1, %xmm1 popq %rdx popq %rcx popq %rbx leave ret .section ".text.crypto.aes.x86ni_asdescrypt","ax" .global crypto.aes.x86ni_asdecrypt .type crypto.aes.x86ni_asdecrypt,@function crypto.aes.x86ni_asdecrypt: pushq %rbp mov %rsp, %rbp pushq %rbx pushq %rcx pushq %rdx movq 0x10(%rbp), %rbx # &rk movq 0x18(%rbp), %rax # rklen movq 0x28(%rbp), %rcx # &dest movq 0x40(%rbp), %rdx # &src movdqu (%rdx), %xmm0 movdqu (%rbx), %xmm1 pxor %xmm1, %xmm0 movdqu 0x10(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x20(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x30(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x40(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x50(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x60(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x70(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x80(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0x90(%rbx), %xmm1 aesdec %xmm1, %xmm0 mov $208, %rdx cmp %rax, %rdx je decrypt_192 jl decrypt_256 movdqu 0xa0(%rbx), %xmm1 aesdeclast %xmm1, %xmm0 jmp decrypt_end decrypt_192: movdqu 0xa0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xb0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xc0(%rbx), %xmm1 aesdeclast %xmm1, %xmm0 jmp decrypt_end decrypt_256: movdqu 0xa0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xb0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xc0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xd0(%rbx), %xmm1 aesdec %xmm1, %xmm0 movdqu 0xe0(%rbx), %xmm1 aesdeclast %xmm1, %xmm0 jmp decrypt_end decrypt_end: movdqu %xmm0, (%rcx) pxor %xmm0, %xmm0 pxor %xmm1, %xmm1 popq %rdx popq %rcx popq %rbx leave ret hare-0.24.2/crypto/aes/README000066400000000000000000000016141464473310100154730ustar00rootroot00000000000000The crypto::aes module provides an implementation of the Advanced Encryption Standard per the [[crypto::cipher::block]] interface. Several implementations of AES are provided which are optimized for different scenarios. To choose the most appropriate one for your system, use [[aes]]. When combined with a block cipher mode from [[crypto::cipher::]], suitable buffer lengths for static allocation are provided as constants such as [[BLOCKSZ]], [[CTR_BUFSZ]], and [[CBC_BUFSZ]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/aes/aes+x86_64.ha000066400000000000000000000006261464473310100166310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::cipher; def MAXEXPKEYSZ: size = CT64_EXPKEYSZ; def MAXNPARALLEL: size = CT64_NPARALLEL; let rtvtable: *cipher::blockvtable = &ct64_vtable; let initfuncptr: *initfunc = &ct64_init; @init fn init() void = { if (x86ni_available()) { hwsup = true; rtvtable = &x86ni_vtable; initfuncptr = &x86ni_init; }; }; hare-0.24.2/crypto/aes/aes.ha000066400000000000000000000004261464473310100156750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::cipher; def MAXEXPKEYSZ: size = CT64_EXPKEYSZ; def MAXNPARALLEL: size = CT64_NPARALLEL; const rtvtable: *cipher::blockvtable = &ct64_vtable; const initfuncptr: *initfunc = &ct64_init; hare-0.24.2/crypto/aes/aes_ct64.ha000066400000000000000000000436461464473310100165500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Constant time aes implementation optimized for 64bit CPUs. // The code was ported from BearSSL, which contained the following notice: // // Copyright (c) 2016 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::cipher; use crypto::cipher::{blocksz,nparallel}; use crypto::math; use endian; def CT64_EXPKEYSZ: size = 960; def CT64_NPARALLEL: size = 4; // Returns an AES [[crypto::cipher::block]] cipher implementation optimized for // constant time operation on 64-bit systems. // // The caller must call [[ct64_init]] to add a key to the cipher before using // the cipher, and must call [[crypto::cipher::finish]] when they are finished // using the cipher to securely erase any secret data stored in the cipher // state. fn ct64() block = block { vtable = &ct64_vtable, ... }; const ct64_vtable: cipher::blockvtable = cipher::blockvtable { blocksz = BLOCKSZ, nparallel = CT64_NPARALLEL, encrypt = &aes_ct64_encrypt, decrypt = &aes_ct64_decrypt, finish = &block_finish, }; // Initializes the ct64 AES implementation with an encryption key. fn ct64_init(cipher: *block, key: []u8) void = { let comp_skey: [30]u64 = [0...]; cipher.rounds = br_aes_ct64_keysched(comp_skey[..], key, len(key)); br_aes_ct64_skey_expand(ct64_expkey(cipher), cipher.rounds, comp_skey[..]); }; fn ct64_expkey(b: *block) []u64 = { return (b.expkey[..]: *[*]u64)[..len(b.expkey)/size(u64)]; }; // Combines up to 4 blocks and encrypts them in one run fn aes_ct64_encrypt(b: *cipher::block, dest: []u8, src: []u8) void = { let b = b: *block; assert(len(src) % blocksz(b) == 0 && (len(src) / blocksz(b)) <= nparallel(b), "invalid block size"); let nblocks = len(src) / blocksz(b); let q: [8]u64 = [0...]; let w: [16]u32 = [0...]; br_range_dec32le(w, src); for (let i = 0z; i < nblocks; i += 1) { br_aes_ct64_interleave_in(q[i..], q[(i + 4)..], w[(i << 2)..]); }; br_aes_ct64_ortho(q); br_aes_ct64_bitslice_encrypt(b.rounds, ct64_expkey(b), q); br_aes_ct64_ortho(q); for (let i = 0z; i < nblocks; i += 1) { br_aes_ct64_interleave_out(w[(i << 2)..], q[i], q[i + 4]); }; br_range_enc32le(dest, w); }; // Combines up to 4 blocks and decrypts them in one run fn aes_ct64_decrypt(b: *cipher::block, dest: []u8, src: []u8) void = { let b = b: *block; assert(len(src) % blocksz(b) == 0 && (len(src) / blocksz(b)) <= nparallel(b), "invalid block size"); const nblocks = len(src) / blocksz(b); let q: [8]u64 = [0...]; let w: [16]u32 = [0...]; br_range_dec32le(w, src); for (let i = 0z; i < nblocks; i += 1) { br_aes_ct64_interleave_in(q[i..], q[(i + 4)..], w[(i << 2)..]); }; br_aes_ct64_ortho(q); br_aes_ct64_bitslice_decrypt(b.rounds, ct64_expkey(b), q); br_aes_ct64_ortho(q); for (let i = 0z; i < nblocks; i += 1) { br_aes_ct64_interleave_out(w[(i << 2)..], q[i], q[i + 4]); }; br_range_enc32le(dest, w); }; // see br_aes_ct64_ortho in src/inner.h of BearSSL fn br_aes_ct64_ortho(q: []u64) void = { swapn(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, &q[0], &q[1]); swapn(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, &q[2], &q[3]); swapn(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, &q[4], &q[5]); swapn(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, &q[6], &q[7]); swapn(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, &q[0], &q[2]); swapn(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, &q[1], &q[3]); swapn(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, &q[4], &q[6]); swapn(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, &q[5], &q[7]); swapn(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, &q[0], &q[4]); swapn(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, &q[1], &q[5]); swapn(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, &q[2], &q[6]); swapn(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, &q[3], &q[7]); }; // This is a macro in the C version. fn swapn(cl: u64, ch: u64, s: u32, x: *u64, y: *u64) void = { let a: u64 = *x, b: u64 = *y; *x = (a & cl) | ((b & cl) << s); *y = ((a & ch) >> s) | (b & ch); }; // see br_aes_ct64_interleave_in in src/inner.h of BearSSL fn br_aes_ct64_interleave_in(q0: []u64, q1: []u64, w: const []u32) void = { let x0 = 0u64, x1 = 0u64, x2 = 0u64, x3 = 0u64; x0 = w[0]; x1 = w[1]; x2 = w[2]; x3 = w[3]; x0 |= (x0 << 16); x1 |= (x1 << 16); x2 |= (x2 << 16); x3 |= (x3 << 16); x0 &= 0x0000FFFF0000FFFF; x1 &= 0x0000FFFF0000FFFF; x2 &= 0x0000FFFF0000FFFF; x3 &= 0x0000FFFF0000FFFF; x0 |= (x0 << 8); x1 |= (x1 << 8); x2 |= (x2 << 8); x3 |= (x3 << 8); x0 &= 0x00FF00FF00FF00FF; x1 &= 0x00FF00FF00FF00FF; x2 &= 0x00FF00FF00FF00FF; x3 &= 0x00FF00FF00FF00FF; q0[0] = x0 | (x2 << 8); q1[0] = x1 | (x3 << 8); }; // see br_aes_ct64_interleave_out in src/inner.h of BearSSL fn br_aes_ct64_interleave_out(w: []u32, q0: u64, q1: u64) void = { let x0 = 0u64, x1 = 0u64, x2 = 0u64, x3 = 0u64; x0 = q0 & 0x00FF00FF00FF00FF; x1 = q1 & 0x00FF00FF00FF00FF; x2 = (q0 >> 8) & 0x00FF00FF00FF00FF; x3 = (q1 >> 8) & 0x00FF00FF00FF00FF; x0 |= (x0 >> 8); x1 |= (x1 >> 8); x2 |= (x2 >> 8); x3 |= (x3 >> 8); x0 &= 0x0000FFFF0000FFFF; x1 &= 0x0000FFFF0000FFFF; x2 &= 0x0000FFFF0000FFFF; x3 &= 0x0000FFFF0000FFFF; w[0] = (x0 | (x0 >> 16)): u32; w[1] = (x1 | (x1 >> 16)): u32; w[2] = (x2 | (x2 >> 16)): u32; w[3] = (x3 | (x3 >> 16)): u32; }; // see br_aes_ct64_bitslice_Sbox in src/inner.h of BearSSL fn br_aes_ct64_bitslice_Sbox(q: []u64) void = { // This S-box implementation is a straightforward translation of // the circuit described by Boyar and Peralta in "A new // combinational logic minimization technique with applications // to cryptology" (https://eprint.iacr.org/2009/191.pdf). // // Note that variables x* (input) and s* (output) are numbered // in "reverse" order (x0 is the high bit, x7 is the low bit). let x0 = 0u64, x1 = 0u64, x2 = 0u64, x3 = 0u64, x4 = 0u64, x5 = 0u64, x6 = 0u64, x7 = 0u64; let y1 = 0u64, y2 = 0u64, y3 = 0u64, y4 = 0u64, y5 = 0u64, y6 = 0u64, y7 = 0u64, y8 = 0u64, y9 = 0u64, y10 = 0u64, y11 = 0u64, y12 = 0u64, y13 = 0u64, y14 = 0u64, y15 = 0u64, y16 = 0u64, y17 = 0u64, y18 = 0u64, y19 = 0u64, y20 = 0u64, y21 = 0u64; let z0 = 0u64, z1 = 0u64, z2 = 0u64, z3 = 0u64, z4 = 0u64, z5 = 0u64, z6 = 0u64, z7 = 0u64, z8 = 0u64, z9 = 0u64, z10 = 0u64, z11 = 0u64, z12 = 0u64, z13 = 0u64, z14 = 0u64, z15 = 0u64, z16 = 0u64, z17 = 0u64; let t0 = 0u64, t1 = 0u64, t2 = 0u64, t3 = 0u64, t4 = 0u64, t5 = 0u64, t6 = 0u64, t7 = 0u64, t8 = 0u64, t9 = 0u64, t10 = 0u64, t11 = 0u64, t12 = 0u64, t13 = 0u64, t14 = 0u64, t15 = 0u64, t16 = 0u64, t17 = 0u64, t18 = 0u64, t19 = 0u64, t20 = 0u64, t21 = 0u64, t22 = 0u64, t23 = 0u64, t24 = 0u64, t25 = 0u64, t26 = 0u64, t27 = 0u64, t28 = 0u64, t29 = 0u64, t30 = 0u64, t31 = 0u64, t32 = 0u64, t33 = 0u64, t34 = 0u64, t35 = 0u64, t36 = 0u64, t37 = 0u64, t38 = 0u64, t39 = 0u64, t40 = 0u64, t41 = 0u64, t42 = 0u64, t43 = 0u64, t44 = 0u64, t45 = 0u64, t46 = 0u64, t47 = 0u64, t48 = 0u64, t49 = 0u64, t50 = 0u64, t51 = 0u64, t52 = 0u64, t53 = 0u64, t54 = 0u64, t55 = 0u64, t56 = 0u64, t57 = 0u64, t58 = 0u64, t59 = 0u64, t60 = 0u64, t61 = 0u64, t62 = 0u64, t63 = 0u64, t64 = 0u64, t65 = 0u64, t66 = 0u64, t67 = 0u64; let s0 = 0u64, s1 = 0u64, s2 = 0u64, s3 = 0u64, s4 = 0u64, s5 = 0u64, s6 = 0u64, s7 = 0u64; x0 = q[7]; x1 = q[6]; x2 = q[5]; x3 = q[4]; x4 = q[3]; x5 = q[2]; x6 = q[1]; x7 = q[0]; // Top linear transformation. y14 = x3 ^ x5; y13 = x0 ^ x6; y9 = x0 ^ x3; y8 = x0 ^ x5; t0 = x1 ^ x2; y1 = t0 ^ x7; y4 = y1 ^ x3; y12 = y13 ^ y14; y2 = y1 ^ x0; y5 = y1 ^ x6; y3 = y5 ^ y8; t1 = x4 ^ y12; y15 = t1 ^ x5; y20 = t1 ^ x1; y6 = y15 ^ x7; y10 = y15 ^ t0; y11 = y20 ^ y9; y7 = x7 ^ y11; y17 = y10 ^ y11; y19 = y10 ^ y8; y16 = t0 ^ y11; y21 = y13 ^ y16; y18 = x0 ^ y16; // Non-linear section. t2 = y12 & y15; t3 = y3 & y6; t4 = t3 ^ t2; t5 = y4 & x7; t6 = t5 ^ t2; t7 = y13 & y16; t8 = y5 & y1; t9 = t8 ^ t7; t10 = y2 & y7; t11 = t10 ^ t7; t12 = y9 & y11; t13 = y14 & y17; t14 = t13 ^ t12; t15 = y8 & y10; t16 = t15 ^ t12; t17 = t4 ^ t14; t18 = t6 ^ t16; t19 = t9 ^ t14; t20 = t11 ^ t16; t21 = t17 ^ y20; t22 = t18 ^ y19; t23 = t19 ^ y21; t24 = t20 ^ y18; t25 = t21 ^ t22; t26 = t21 & t23; t27 = t24 ^ t26; t28 = t25 & t27; t29 = t28 ^ t22; t30 = t23 ^ t24; t31 = t22 ^ t26; t32 = t31 & t30; t33 = t32 ^ t24; t34 = t23 ^ t33; t35 = t27 ^ t33; t36 = t24 & t35; t37 = t36 ^ t34; t38 = t27 ^ t36; t39 = t29 & t38; t40 = t25 ^ t39; t41 = t40 ^ t37; t42 = t29 ^ t33; t43 = t29 ^ t40; t44 = t33 ^ t37; t45 = t42 ^ t41; z0 = t44 & y15; z1 = t37 & y6; z2 = t33 & x7; z3 = t43 & y16; z4 = t40 & y1; z5 = t29 & y7; z6 = t42 & y11; z7 = t45 & y17; z8 = t41 & y10; z9 = t44 & y12; z10 = t37 & y3; z11 = t33 & y4; z12 = t43 & y13; z13 = t40 & y5; z14 = t29 & y2; z15 = t42 & y9; z16 = t45 & y14; z17 = t41 & y8; // Bottom linear transformation. t46 = z15 ^ z16; t47 = z10 ^ z11; t48 = z5 ^ z13; t49 = z9 ^ z10; t50 = z2 ^ z12; t51 = z2 ^ z5; t52 = z7 ^ z8; t53 = z0 ^ z3; t54 = z6 ^ z7; t55 = z16 ^ z17; t56 = z12 ^ t48; t57 = t50 ^ t53; t58 = z4 ^ t46; t59 = z3 ^ t54; t60 = t46 ^ t57; t61 = z14 ^ t57; t62 = t52 ^ t58; t63 = t49 ^ t58; t64 = z4 ^ t59; t65 = t61 ^ t62; t66 = z1 ^ t63; s0 = t59 ^ t63; s6 = t56 ^ ~t62; s7 = t48 ^ ~t60; t67 = t64 ^ t65; s3 = t53 ^ t66; s4 = t51 ^ t66; s5 = t47 ^ t65; s1 = t64 ^ ~s3; s2 = t55 ^ ~t67; q[7] = s0; q[6] = s1; q[5] = s2; q[4] = s3; q[3] = s4; q[2] = s5; q[1] = s6; q[0] = s7; }; const rcon: []u8 = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 ]; fn sub_word(x: u32) u32 = { let q: [8]u64 = [x, 0...]; br_aes_ct64_ortho(q); br_aes_ct64_bitslice_Sbox(q); br_aes_ct64_ortho(q); return q[0]: u32; }; // see br_aes_ct64_keysched in src/inner.h of BearSSL fn br_aes_ct64_keysched( comp_skey: []u64, key: const []u8, key_len: size, ) uint = { let num_rounds: uint = 0; let nk: int = 0, nkf: int = 0; let tmp: u32 = 0; let skey: [60]u32 = [0...]; switch (key_len) { case 16 => num_rounds = 10; case 24 => num_rounds = 12; case 32 => num_rounds = 14; case => assert(false, "invalid key length"); }; nk = (key_len >> 2): int; nkf = ((num_rounds + 1) << 2): int; br_range_dec32le(skey, key); tmp = skey[(key_len >> 2) - 1]; for (let i = nk, j = 0, k = 0; i < nkf; i += 1) { if (j == 0) { tmp = (tmp << 24) | (tmp >> 8); tmp = sub_word(tmp) ^ rcon[k]; } else if (nk > 6 && j == 4) { tmp = sub_word(tmp); }; tmp ^= skey[i - nk]; skey[i] = tmp; j += 1; if (j == nk) { j = 0; k += 1; }; }; for (let i = 0, j = 0; i < nkf) { let q: [8]u64 = [0...]; br_aes_ct64_interleave_in(q[0..], q[4..], skey[i..]); q[1] = q[0]; q[2] = q[0]; q[3] = q[0]; q[5] = q[4]; q[6] = q[4]; q[7] = q[4]; br_aes_ct64_ortho(q[..]); comp_skey[j + 0] = (q[0] & 0x1111111111111111) | (q[1] & 0x2222222222222222) | (q[2] & 0x4444444444444444) | (q[3] & 0x8888888888888888); comp_skey[j + 1] = (q[4] & 0x1111111111111111) | (q[5] & 0x2222222222222222) | (q[6] & 0x4444444444444444) | (q[7] & 0x8888888888888888); i += 4; j += 2; }; return num_rounds; }; fn br_range_dec32le(v: []u32, src: []u8) void = { for (let i = 0z; len(src) > 0; i += 1) { v[i] = endian::legetu32(src); src = src[4..]; }; }; fn br_range_enc32le(dest: []u8, w: []u32) void = { for (let i = 0z; len(dest) > 0; i += 1) { endian::leputu32(dest, w[i]); dest = dest[4..]; }; }; // see br_aes_ct64_skey_expand in src/inner.h of BearSSL fn br_aes_ct64_skey_expand( skey: []u64, num_rounds: uint, comp_skey: const []u64, ) void = { let n: uint = (num_rounds + 1) << 1; for (let u = 0u, v = 0u; u < n) { let x0 = 0u64, x1 = 0u64, x2 = 0u64, x3 = 0u64; x0 = comp_skey[u]; x1 = comp_skey[u]; x2 = comp_skey[u]; x3 = comp_skey[u]; x0 &= 0x1111111111111111; x1 &= 0x2222222222222222; x2 &= 0x4444444444444444; x3 &= 0x8888888888888888; x1 >>= 1; x2 >>= 2; x3 >>= 3; skey[v + 0] = (x0 << 4) - x0; skey[v + 1] = (x1 << 4) - x1; skey[v + 2] = (x2 << 4) - x2; skey[v + 3] = (x3 << 4) - x3; u += 1; v += 4; }; }; // aes_ct64_enc.c fn add_round_key(q: []u64, sk: const []u64) void = { q[0] ^= sk[0]; q[1] ^= sk[1]; q[2] ^= sk[2]; q[3] ^= sk[3]; q[4] ^= sk[4]; q[5] ^= sk[5]; q[6] ^= sk[6]; q[7] ^= sk[7]; }; fn shift_rows(q: []u64) void = { for (let i: int = 0; i < 8; i += 1) { let x: u64 = q[i]; q[i] = (x & 0x000000000000FFFF) | ((x & 0x00000000FFF00000) >> 4) | ((x & 0x00000000000F0000) << 12) | ((x & 0x0000FF0000000000) >> 8) | ((x & 0x000000FF00000000) << 8) | ((x & 0xF000000000000000) >> 12) | ((x & 0x0FFF000000000000) << 4); }; }; fn mix_columns(q: []u64) void = { let q0 = 0u64, q1 = 0u64, q2 = 0u64, q3 = 0u64, q4 = 0u64, q5 = 0u64, q6 = 0u64, q7 = 0u64; let r0 = 0u64, r1 = 0u64, r2 = 0u64, r3 = 0u64, r4 = 0u64, r5 = 0u64, r6 = 0u64, r7 = 0u64; q0 = q[0]; q1 = q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = q[5]; q6 = q[6]; q7 = q[7]; r0 = (q0 >> 16) | (q0 << 48); r1 = (q1 >> 16) | (q1 << 48); r2 = (q2 >> 16) | (q2 << 48); r3 = (q3 >> 16) | (q3 << 48); r4 = (q4 >> 16) | (q4 << 48); r5 = (q5 >> 16) | (q5 << 48); r6 = (q6 >> 16) | (q6 << 48); r7 = (q7 >> 16) | (q7 << 48); q[0] = q7 ^ r7 ^ r0 ^ math::rotr64(q0 ^ r0, 32); q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ math::rotr64(q1 ^ r1, 32); q[2] = q1 ^ r1 ^ r2 ^ math::rotr64(q2 ^ r2, 32); q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ math::rotr64(q3 ^ r3, 32); q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ math::rotr64(q4 ^ r4, 32); q[5] = q4 ^ r4 ^ r5 ^ math::rotr64(q5 ^ r5, 32); q[6] = q5 ^ r5 ^ r6 ^ math::rotr64(q6 ^ r6, 32); q[7] = q6 ^ r6 ^ r7 ^ math::rotr64(q7 ^ r7, 32); }; // see br_aes_ct64_bitslice_encrypt in src/inner.h of BearSSL fn br_aes_ct64_bitslice_encrypt( num_rounds: uint, skey: const []u64, q: []u64, ) void = { add_round_key(q, skey); for (let u: uint = 1; u < num_rounds; u += 1) { br_aes_ct64_bitslice_Sbox(q); shift_rows(q); mix_columns(q); add_round_key(q, skey[(u << 3)..]); }; br_aes_ct64_bitslice_Sbox(q); shift_rows(q); add_round_key(q, skey[(num_rounds << 3)..]); }; // see br_aes_ct64_bitslice_invSbox in src/inner.h of BearSSL fn br_aes_ct64_bitslice_invSbox(q: []u64) void = { // See br_aes_ct_bitslice_invSbox(). This is the natural extension // to 64-bit registers. let q0 = 0u64, q1 = 0u64, q2 = 0u64, q3 = 0u64, q4 = 0u64, q5 = 0u64, q6 = 0u64, q7 = 0u64; q0 = ~q[0]; q1 = ~q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = ~q[5]; q6 = ~q[6]; q7 = q[7]; q[7] = q1 ^ q4 ^ q6; q[6] = q0 ^ q3 ^ q5; q[5] = q7 ^ q2 ^ q4; q[4] = q6 ^ q1 ^ q3; q[3] = q5 ^ q0 ^ q2; q[2] = q4 ^ q7 ^ q1; q[1] = q3 ^ q6 ^ q0; q[0] = q2 ^ q5 ^ q7; br_aes_ct64_bitslice_Sbox(q); q0 = ~q[0]; q1 = ~q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = ~q[5]; q6 = ~q[6]; q7 = q[7]; q[7] = q1 ^ q4 ^ q6; q[6] = q0 ^ q3 ^ q5; q[5] = q7 ^ q2 ^ q4; q[4] = q6 ^ q1 ^ q3; q[3] = q5 ^ q0 ^ q2; q[2] = q4 ^ q7 ^ q1; q[1] = q3 ^ q6 ^ q0; q[0] = q2 ^ q5 ^ q7; }; fn inv_shift_rows(q: []u64) void = { for (let i: int = 0; i < 8; i += 1) { let x: u64 = q[i]; q[i] = (x & 0x000000000000FFFF) | ((x & 0x000000000FFF0000) << 4) | ((x & 0x00000000F0000000) >> 12) | ((x & 0x000000FF00000000) << 8) | ((x & 0x0000FF0000000000) >> 8) | ((x & 0x000F000000000000) << 12) | ((x & 0xFFF0000000000000) >> 4); }; }; fn inv_mix_columns(q: []u64) void = { let q0 = 0u64, q1 = 0u64, q2 = 0u64, q3 = 0u64, q4 = 0u64, q5 = 0u64, q6 = 0u64, q7 = 0u64; let r0 = 0u64, r1 = 0u64, r2 = 0u64, r3 = 0u64, r4 = 0u64, r5 = 0u64, r6 = 0u64, r7 = 0u64; q0 = q[0]; q1 = q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = q[5]; q6 = q[6]; q7 = q[7]; r0 = (q0 >> 16) | (q0 << 48); r1 = (q1 >> 16) | (q1 << 48); r2 = (q2 >> 16) | (q2 << 48); r3 = (q3 >> 16) | (q3 << 48); r4 = (q4 >> 16) | (q4 << 48); r5 = (q5 >> 16) | (q5 << 48); r6 = (q6 >> 16) | (q6 << 48); r7 = (q7 >> 16) | (q7 << 48); q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ math::rotr64(q0 ^ q5 ^ q6 ^ r0 ^ r5, 32); q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ math::rotr64(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6, 32); q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ math::rotr64(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7, 32); q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ math::rotr64(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7 , 32); q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ math::rotr64(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6, 32); q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ math::rotr64(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7, 32); q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ math::rotr64(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7, 32); q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ math::rotr64(q4 ^ q5 ^ q7 ^ r4 ^ r7, 32); }; // see br_aes_ct64_bitslice_decrypt in src/inner.h of BearSSL fn br_aes_ct64_bitslice_decrypt( num_rounds: size, skey: const []u64, q: []u64, ) void = { add_round_key(q, skey[(num_rounds << 3)..]); for (let u: size = num_rounds - 1; u > 0; u -= 1) { inv_shift_rows(q); br_aes_ct64_bitslice_invSbox(q); add_round_key(q, skey[(u << 3)..]); inv_mix_columns(q); }; inv_shift_rows(q); br_aes_ct64_bitslice_invSbox(q); add_round_key(q, skey); }; hare-0.24.2/crypto/aes/block.ha000066400000000000000000000025471464473310100162250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; // The block size used by the AES algorithm. export def BLOCKSZ: size = 16; // Size of the buffer used for [[crypto::cipher::cbc_encryptor]] and // [[crypto::cipher::cbc_decryptor]]. export def CBC_BUFSZ: size = BLOCKSZ * 2; // Size of the buffer used for [[crypto::cipher::ctr]]. export def CTR_BUFSZ: size = BLOCKSZ * (MAXNPARALLEL + 1); export type block = struct { vtable: cipher::block, rounds: u32, expkey: [MAXEXPKEYSZ]u8, }; // Returns an AES [[crypto::cipher::block]] cipher implementation that has // hardware support if possible. Check [[hwsupport]] to see if it is available. // // The caller must call [[init]] to add a key to the cipher before using // the cipher, and must call [[crypto::cipher::finish]] when they are finished // using the cipher to securely erase any secret data stored in the cipher // state. export fn aes() block = block { vtable = rtvtable, ... }; let hwsup: bool = false; // Checks whether hardware AES support is available. export fn hwsupport() bool = hwsup; type initfunc = fn(b: *block, key: []u8) void; // Initializes the AES block with an encryption key. export fn init(b: *block, key: []u8) void = initfuncptr(b, key); fn block_finish(b: *cipher::block) void = { let b = b: *block; bytes::zero(b.expkey); }; hare-0.24.2/crypto/aes/cbc+test.ha000066400000000000000000000062641464473310100166350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; @test fn cbc_encrypt_decrypt() void = { const key: [_]u8 = [ 0xde, 0x05, 0x73, 0x76, 0xbf, 0x1b, 0x0c, 0xd1, 0x26, 0x66, 0xa9, 0x63, 0x30, 0xce, 0x1c, 0xde, ]; const iv: [_]u8 = [ 0x2c, 0x80, 0x9e, 0x1e, 0xc3, 0x02, 0x28, 0xae, 0x0a, 0x19, 0xea, 0xef, 0x73, 0x6c, 0x9a, 0xbb, ]; const plain: [_]u8 = [ 0x50, 0xe6, 0xd6, 0x87, 0xeb, 0xb4, 0x65, 0x9c, 0xfc, 0x70, 0x7e, 0x00, 0xe6, 0xd6, 0xef, 0x23, 0xd6, 0x11, 0xca, 0x11, 0x08, 0x2a, 0xde, 0x07, 0xf2, 0xe4, 0x09, 0x17, 0x5a, 0xac, 0xdf, 0x6c, 0x9b, 0x08, 0x82, 0x92, 0x7e, 0x2c, 0xbc, 0xb7, 0x74, 0xe0, 0xe8, 0x7b, 0xe5, 0x72, 0x86, 0x6f, 0x92, 0x37, 0x85, 0xb0, 0x5e, 0x53, 0xd0, 0xcb, 0x42, 0x70, 0x3d, 0x49, 0x6a, 0x48, 0x47, 0x36, ]; const cipher: [_]u8 = [ 0xb4, 0x6b, 0x0b, 0x36, 0xe1, 0xd7, 0x84, 0x1a, 0xf4, 0x3e, 0x74, 0x29, 0x72, 0x9c, 0x60, 0x60, 0xe1, 0x8a, 0xfc, 0x87, 0x3b, 0xe3, 0x18, 0x89, 0x8c, 0x5b, 0x5f, 0x12, 0xe6, 0x71, 0x0d, 0x7e, 0xf3, 0xfd, 0xa6, 0x82, 0x4e, 0xa8, 0x86, 0x9f, 0xaf, 0x60, 0xe9, 0x16, 0x05, 0xda, 0xe1, 0xa5, 0xaa, 0xc0, 0x57, 0x20, 0xf8, 0xbf, 0x17, 0x37, 0x74, 0x8d, 0xd5, 0x3d, 0xf8, 0x0c, 0x97, 0x05, ]; let result: [64]u8 = [0...]; let buf: [CBC_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let cbc = cipher::cbc_encryptor(&b, iv[..], buf[..]); cipher::cbc_encrypt(&cbc, result, plain); assert(bytes::equal(cipher, result)); let cbcd = cipher::cbc_decryptor(&b, iv[..], buf[..]); cipher::cbc_decrypt(&cbcd, result, cipher); assert(bytes::equal(plain, result)); }; @test fn cbc_encrypt_decrypt_in_place() void = { const key: [_]u8 = [ 0xde, 0x05, 0x73, 0x76, 0xbf, 0x1b, 0x0c, 0xd1, 0x26, 0x66, 0xa9, 0x63, 0x30, 0xce, 0x1c, 0xde, ]; const iv: [_]u8 = [ 0x2c, 0x80, 0x9e, 0x1e, 0xc3, 0x02, 0x28, 0xae, 0x0a, 0x19, 0xea, 0xef, 0x73, 0x6c, 0x9a, 0xbb, ]; const plain: [_]u8 = [ 0x50, 0xe6, 0xd6, 0x87, 0xeb, 0xb4, 0x65, 0x9c, 0xfc, 0x70, 0x7e, 0x00, 0xe6, 0xd6, 0xef, 0x23, 0xd6, 0x11, 0xca, 0x11, 0x08, 0x2a, 0xde, 0x07, 0xf2, 0xe4, 0x09, 0x17, 0x5a, 0xac, 0xdf, 0x6c, 0x9b, 0x08, 0x82, 0x92, 0x7e, 0x2c, 0xbc, 0xb7, 0x74, 0xe0, 0xe8, 0x7b, 0xe5, 0x72, 0x86, 0x6f, 0x92, 0x37, 0x85, 0xb0, 0x5e, 0x53, 0xd0, 0xcb, 0x42, 0x70, 0x3d, 0x49, 0x6a, 0x48, 0x47, 0x36, ]; const cipher: [_]u8 = [ 0xb4, 0x6b, 0x0b, 0x36, 0xe1, 0xd7, 0x84, 0x1a, 0xf4, 0x3e, 0x74, 0x29, 0x72, 0x9c, 0x60, 0x60, 0xe1, 0x8a, 0xfc, 0x87, 0x3b, 0xe3, 0x18, 0x89, 0x8c, 0x5b, 0x5f, 0x12, 0xe6, 0x71, 0x0d, 0x7e, 0xf3, 0xfd, 0xa6, 0x82, 0x4e, 0xa8, 0x86, 0x9f, 0xaf, 0x60, 0xe9, 0x16, 0x05, 0xda, 0xe1, 0xa5, 0xaa, 0xc0, 0x57, 0x20, 0xf8, 0xbf, 0x17, 0x37, 0x74, 0x8d, 0xd5, 0x3d, 0xf8, 0x0c, 0x97, 0x05, ]; let result: [64]u8 = plain; let buf: [CBC_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let cbc = cipher::cbc_encryptor(&b, iv[..], buf[..]); cipher::cbc_encrypt(&cbc, result, result); assert(bytes::equal(cipher, result)); let cbcd = cipher::cbc_decryptor(&b, iv[..], buf[..]); cipher::cbc_decrypt(&cbcd, result, result); assert(bytes::equal(plain, result)); }; hare-0.24.2/crypto/aes/ct64+test.ha000066400000000000000000000160751464473310100166670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; @test fn test_encrypt_128() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let block = ct64(); ct64_init(&block, key); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); }; @test fn test_encrypt_128_multiple_blocks() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [_]u8 = [ 0xdb, 0x3a, 0x36, 0x50, 0x85, 0x60, 0x4c, 0x65, 0xc0, 0x22, 0x5a, 0x0d, 0x68, 0x2f, 0x19, 0xc2, 0x16, 0x27, 0xdd, 0xae, 0xd7, 0x28, 0x29, 0x23, 0xfa, 0x97, 0x28, 0xb0, 0x9a, 0x90, 0xfe, 0xb3, 0xde, 0x57, 0xbc, 0x15, 0x15, 0x8d, 0xb6, 0x29, 0x61, 0x40, 0x76, 0x51, 0x32, 0xc2, 0x3d, 0x1e, 0xdf, 0x97, 0x6a, 0x5e, 0x0a, 0x6b, 0xf6, 0x40, 0xb4, 0x08, 0x7e, 0xde, 0x17, 0xa4, 0x58, 0x98 ]; const cipher: [_]u8 = [ 0xdd, 0xf4, 0x53, 0x55, 0x18, 0x7a, 0xf0, 0x65, 0x59, 0xd6, 0xdc, 0x4e, 0xc2, 0x89, 0xff, 0x7b, 0x54, 0x41, 0x6a, 0xda, 0xa0, 0xad, 0x85, 0xbd, 0x75, 0x1e, 0x59, 0x15, 0x6d, 0x30, 0xa8, 0xa8, 0xa8, 0x54, 0x6e, 0xab, 0x9c, 0x47, 0x84, 0xd, 0x6e, 0xb5, 0x5e, 0xba, 0xb0, 0xd9, 0x47, 0xfa, 0x53, 0x6b, 0xff, 0x31, 0x47, 0x86, 0xf8, 0x4c, 0x6b, 0x65, 0xaa, 0xa2, 0xd2, 0xd7, 0xc1, 0xdf ]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); // test from 1 to 4 parallel blocks for (let i = 0z; i < 4; i += 1) { let result: [64]u8 = [0...]; let sz = (i + 1) * 16; cipher::encrypt(&block, result[0..sz], plain[0..sz]); assert(bytes::equal(cipher[0..sz], result[0..sz])); }; }; @test fn test_decrypt_128_multiple_blocks() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [_]u8 = [ 0xdb, 0x3a, 0x36, 0x50, 0x85, 0x60, 0x4c, 0x65, 0xc0, 0x22, 0x5a, 0x0d, 0x68, 0x2f, 0x19, 0xc2, 0x16, 0x27, 0xdd, 0xae, 0xd7, 0x28, 0x29, 0x23, 0xfa, 0x97, 0x28, 0xb0, 0x9a, 0x90, 0xfe, 0xb3, 0xde, 0x57, 0xbc, 0x15, 0x15, 0x8d, 0xb6, 0x29, 0x61, 0x40, 0x76, 0x51, 0x32, 0xc2, 0x3d, 0x1e, 0xdf, 0x97, 0x6a, 0x5e, 0x0a, 0x6b, 0xf6, 0x40, 0xb4, 0x08, 0x7e, 0xde, 0x17, 0xa4, 0x58, 0x98 ]; const cipher: [_]u8 = [ 0xdd, 0xf4, 0x53, 0x55, 0x18, 0x7a, 0xf0, 0x65, 0x59, 0xd6, 0xdc, 0x4e, 0xc2, 0x89, 0xff, 0x7b, 0x54, 0x41, 0x6a, 0xda, 0xa0, 0xad, 0x85, 0xbd, 0x75, 0x1e, 0x59, 0x15, 0x6d, 0x30, 0xa8, 0xa8, 0xa8, 0x54, 0x6e, 0xab, 0x9c, 0x47, 0x84, 0xd, 0x6e, 0xb5, 0x5e, 0xba, 0xb0, 0xd9, 0x47, 0xfa, 0x53, 0x6b, 0xff, 0x31, 0x47, 0x86, 0xf8, 0x4c, 0x6b, 0x65, 0xaa, 0xa2, 0xd2, 0xd7, 0xc1, 0xdf ]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); // test from 1 to 4 parallel blocks for (let i = 0z; i < 4; i += 1) { let result: [64]u8 = [0...]; let sz = (i + 1) * 16; cipher::decrypt(&block, result[0..sz], cipher[0..sz]); assert(bytes::equal(plain[0..sz], result[0..sz])); }; }; @test fn test_decrypt_128() void = { const key: []u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.1 @test fn test_example_vector1() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, ]; let result: [16]u8 = [0...]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; @test fn test_example_vector1_in_place() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, ]; let result: [16]u8 = plain; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], result[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], result[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.2 @test fn test_example_vector2() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91, ]; let result: [16]u8 = [0...]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.3 @test fn test_example_vector3() void = { const key: []u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; const plain: []u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: []u8 = [ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89, ]; let result: [16]u8 = [0...]; let block = ct64(); ct64_init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; hare-0.24.2/crypto/aes/ctr+test.ha000066400000000000000000000262221464473310100166720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; use errors; use io; use memio; @test fn ctr_zero_iv() void = { const key: [_]u8 = [ 0xc3, 0x43, 0x2a, 0xf7, 0xcf, 0x56, 0x72, 0xad, 0x0f, 0x4d, 0xab, 0xee, 0xf5, 0x32, 0x0e, 0x33, ]; const iv: [_]u8 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; const plain: [_]u8 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; const cipher: [_]u8 = [ 0xda, 0xe1, 0x45, 0xd6, 0xe8, 0x6a, 0xc0, 0x4b, 0xb8, 0x68, 0xf0, 0xdb, 0xcd, 0x8a, 0x22, 0x80, ]; let result: [16]u8 = [0...]; let buf: [CTR_BUFSZ]u8 = [0...]; let resultbuf = memio::fixed(result); let b = ct64(); ct64_init(&b, key); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); const s = io::writeall(&ctr, plain)!; assert(s == len(plain)); assert(bytes::equal(cipher, result)); io::close(&ctr)!; const zero: [CTR_BUFSZ]u8 = [0...]; const bsz = cipher::blocksz(&b); assert(bytes::equal(ctr.xorbuf, zero[bsz..])); let b = ct64(); ct64_init(&b, key); result = [0...]; buf = [0...]; let cipherbuf = memio::fixed(cipher); let ctr = cipher::ctr(&cipherbuf, &b, iv[..], buf[..]); const s = io::readall(&ctr, result)!; assert(s as size == len(plain)); assert(bytes::equal(plain, result)); }; @test fn ctr_encrypt_max_iv() void = { const key: [_]u8 = [ 0xc3, 0x43, 0x2a, 0xf7, 0xcf, 0x56, 0x72, 0xad, 0x0f, 0x4d, 0xab, 0xee, 0xf5, 0x32, 0x0e, 0x33, ]; const iv: [_]u8 = [ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ]; const plain: [_]u8 = [ 0x1f, 0x03, 0x62, 0xb4, 0xb6, 0xd3, 0xc9, 0xc1, 0xfa, 0x12, 0xa1, 0x1f, 0xa5, 0x6a, 0xbe, 0x46, 0x85, 0xea, ]; const cipher: [_]u8 = [ 0x3d, 0x31, 0x42, 0x04, 0xf5, 0x1d, 0x04, 0x4c, 0x3e, 0xb1, 0xa5, 0xf8, 0x18, 0x79, 0x87, 0x41, 0x5f, 0x0b, ]; let result: [18]u8 = [0...]; let resultbuf = memio::fixed(result); let buf: [CTR_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); defer io::close(&ctr)!; io::write(&ctr, plain)!; assert(bytes::equal(cipher, result)); }; @test fn ctr_test_multiple_blocks() void = { const key: [_]u8 = [ 0xae, 0x0c, 0x47, 0x6d, 0xce, 0x69, 0xdf, 0x52, 0xf7, 0x5e, 0x1f, 0x16, 0x7e, 0xea, 0x1c, 0xf0, ]; const iv: [_]u8 = [ 0x9a, 0x11, 0xd7, 0x24, 0x43, 0x86, 0x50, 0xf0, 0xd9, 0x8c, 0x0d, 0x0d, 0x7a, 0x2e, 0x95, 0x72, ]; const plain: [_]u8 = [ 0x05, 0xc8, 0x4a, 0xf7, 0xba, 0x4b, 0xc2, 0x4f, 0xd3, 0x63, 0xf3, 0x20, 0x51, 0x2b, 0x65, 0xec, 0x4c, 0xe7, 0x7f, 0x78, 0x17, 0x45, 0x0c, 0x6e, 0xff, 0xf1, 0x73, 0x97, 0x42, 0x4d, 0x4a, 0x30, 0x5d, 0xb2, 0x79, 0x45, 0xca, 0x20, 0x10, 0x5b, 0x2c, 0x34, 0x4c, 0xed, 0x42, 0x59, 0x61, 0x3a, 0x66, 0xa3, 0x2e, 0x74, 0xa8, 0xbb, 0x9c, 0xe9, 0x4e, 0xda, 0x33, 0x97, 0x98, 0x41, 0x9a, 0xf0, 0xbb, 0x6d, 0xcb, 0x5d, 0x15, 0x60, 0x26, 0x7c, 0x6c, 0xe5, 0xa4, 0xaf, 0x52, 0x14, 0x29, 0x2f, ]; const cipher: [_]u8 = [ 0xc1, 0xe5, 0x15, 0x76, 0x5b, 0xb2, 0x3a, 0xbc, 0xc4, 0x71, 0xdf, 0xcc, 0x20, 0xe0, 0x63, 0xd6, 0xb3, 0x7d, 0x48, 0x51, 0xe0, 0xd1, 0xcb, 0x07, 0xa3, 0xc8, 0xc6, 0xb9, 0x43, 0xa9, 0x1e, 0x70, 0xb2, 0x1e, 0xbe, 0xc3, 0x11, 0x36, 0xb2, 0x64, 0x7c, 0xaf, 0x89, 0x46, 0x17, 0x60, 0x90, 0x19, 0x23, 0x53, 0xd1, 0xce, 0xc6, 0x5c, 0x50, 0x9c, 0x8c, 0x1d, 0xa8, 0xee, 0x44, 0x9c, 0xa2, 0xb2, 0x97, 0x62, 0x39, 0xcc, 0x91, 0xb0, 0xcc, 0x2c, 0x1b, 0x4c, 0xc3, 0x5d, 0xc3, 0xfa, 0xe9, 0x98, ]; let result: [80]u8 = [0...]; let resultbuf = memio::fixed(result); let buf: [CTR_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); const n = io::writeall(&ctr, plain)!; assert(n == len(cipher)); assert(bytes::equal(cipher, result)); io::close(&ctr)!; let b = ct64(); ct64_init(&b, key); let cipherbuf = memio::fixed(cipher); let ctr = cipher::ctr(&cipherbuf, &b, iv[..], buf[..]); const n = io::readall(&ctr, result)!; assert(n as size == len(plain)); assert(bytes::equal(plain, result)); io::close(&ctr)!; }; @test fn ctr_test_multiple_calls() void = { const key: [_]u8 = [ 0xae, 0x0c, 0x47, 0x6d, 0xce, 0x69, 0xdf, 0x52, 0xf7, 0x5e, 0x1f, 0x16, 0x7e, 0xea, 0x1c, 0xf0, ]; const iv: [_]u8 = [ 0x9a, 0x11, 0xd7, 0x24, 0x43, 0x86, 0x50, 0xf0, 0xd9, 0x8c, 0x0d, 0x0d, 0x7a, 0x2e, 0x95, 0x72, ]; const plain: [_]u8 = [ 0x05, 0xc8, 0x4a, 0xf7, 0xba, 0x4b, 0xc2, 0x4f, 0xd3, 0x63, 0xf3, 0x20, 0x51, 0x2b, 0x65, 0xec, 0x4c, 0xe7, 0x7f, 0x78, 0x17, 0x45, 0x0c, 0x6e, 0xff, 0xf1, 0x73, 0x97, 0x42, 0x4d, 0x4a, 0x30, 0x5d, 0xb2, 0x79, 0x45, 0xca, 0x20, 0x10, 0x5b, 0x2c, 0x34, 0x4c, 0xed, 0x42, 0x59, 0x61, 0x3a, 0x66, 0xa3, 0x2e, 0x74, 0xa8, 0xbb, 0x9c, 0xe9, 0x4e, 0xda, 0x33, 0x97, 0x98, 0x41, 0x9a, 0xf0, 0xbb, 0x6d, 0xcb, 0x5d, 0x15, 0x60, 0x26, 0x7c, 0x6c, 0xe5, 0xa4, 0xaf, 0x52, 0x14, 0x29, 0x2f, ]; const cipher: [_]u8 = [ 0xc1, 0xe5, 0x15, 0x76, 0x5b, 0xb2, 0x3a, 0xbc, 0xc4, 0x71, 0xdf, 0xcc, 0x20, 0xe0, 0x63, 0xd6, 0xb3, 0x7d, 0x48, 0x51, 0xe0, 0xd1, 0xcb, 0x07, 0xa3, 0xc8, 0xc6, 0xb9, 0x43, 0xa9, 0x1e, 0x70, 0xb2, 0x1e, 0xbe, 0xc3, 0x11, 0x36, 0xb2, 0x64, 0x7c, 0xaf, 0x89, 0x46, 0x17, 0x60, 0x90, 0x19, 0x23, 0x53, 0xd1, 0xce, 0xc6, 0x5c, 0x50, 0x9c, 0x8c, 0x1d, 0xa8, 0xee, 0x44, 0x9c, 0xa2, 0xb2, 0x97, 0x62, 0x39, 0xcc, 0x91, 0xb0, 0xcc, 0x2c, 0x1b, 0x4c, 0xc3, 0x5d, 0xc3, 0xfa, 0xe9, 0x98, ]; let result: [80]u8 = [0...]; let resultbuf = memio::fixed(result); let buf: [CTR_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); defer io::close(&ctr)!; let n = 0z; n += io::write(&ctr, plain[0..32])!; n += io::write(&ctr, plain[32..])!; // previous call only writes 32 bytes. Write remaining here. n += io::write(&ctr, plain[64..])!; assert(n == len(plain)); assert(bytes::equal(cipher, result)); let cipherbuf = memio::fixed(cipher); let ctr = cipher::ctr(&cipherbuf, &b, iv[..], buf[..]); const n = io::readall(&ctr, result)!; assert(n as size == len(plain)); assert(bytes::equal(plain, result)); }; @test fn ctr_encrypt_in_place() void = { const key: [_]u8 = [ 0x3f, 0xf8, 0x68, 0x06, 0xe4, 0xcc, 0x88, 0x11, 0xa6, 0xba, 0x14, 0xb6, 0x0b, 0x4c, 0x5a, 0xef, ]; const iv: [_]u8 = [ 0xc5, 0x4c, 0x99, 0xd2, 0xd0, 0xef, 0xf5, 0xde, 0x95, 0x38, 0x45, 0x34, 0xeb, 0xa2, 0xad, 0xa0, ]; let result: [_]u8 = [ 0x65, 0x60, 0x3b, 0x9a, 0x07, 0x56, 0xb1, 0x96, 0x3b, 0xd8, 0x8d, 0x84, 0x20, 0x29, 0xec, 0x7f, 0xa6, 0xe9, 0xf8, 0xdf, 0xa3, 0x37, 0xf3, 0x8f, ]; const cipher: [_]u8 = [ 0x14, 0xfd, 0x4b, 0x5b, 0x4a, 0x11, 0xd3, 0xdf, 0x6e, 0x02, 0x61, 0x09, 0x64, 0x1f, 0xa1, 0x86, 0xb1, 0xa6, 0xd9, 0x40, 0xaf, 0x1b, 0x02, 0xe1, ]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let buf: [CTR_BUFSZ]u8 = [0...]; let resultbuf = memio::fixed(result); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); defer io::close(&ctr)!; io::write(&ctr, result)!; assert(bytes::equal(cipher, result)); }; @test fn ctr_encrypt_smaller_buf() void = { const key: [_]u8 = [ 0x3f, 0xf8, 0x68, 0x06, 0xe4, 0xcc, 0x88, 0x11, 0xa6, 0xba, 0x14, 0xb6, 0x0b, 0x4c, 0x5a, 0xef, ]; const iv: [_]u8 = [ 0xc5, 0x4c, 0x99, 0xd2, 0xd0, 0xef, 0xf5, 0xde, 0x95, 0x38, 0x45, 0x34, 0xeb, 0xa2, 0xad, 0xa0, ]; let result: [_]u8 = [ 0x65, 0x60, 0x3b, 0x9a, 0x07, 0x56, 0xb1, 0x96, 0x3b, 0xd8, 0x8d, 0x84, 0x20, 0x29, 0xec, 0x7f, 0xa6, 0xe9, 0xf8, 0xdf, 0xa3, 0x37, 0xf3, 0x8f, ]; const cipher: [_]u8 = [ 0x14, 0xfd, 0x4b, 0x5b, 0x4a, 0x11, 0xd3, 0xdf, 0x6e, 0x02, 0x61, 0x09, 0x64, 0x1f, 0xa1, 0x86, 0xb1, 0xa6, 0xd9, 0x40, 0xaf, 0x1b, 0x02, 0xe1, ]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let buf: [64]u8 = [0...]; let resultbuf = memio::fixed(result); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); defer io::close(&ctr)!; io::write(&ctr, result)!; assert(bytes::equal(cipher, result)); }; @test fn empty_write() void = { const key: [_]u8 = [ 0x3f, 0xf8, 0x68, 0x06, 0xe4, 0xcc, 0x88, 0x11, 0xa6, 0xba, 0x14, 0xb6, 0x0b, 0x4c, 0x5a, 0xef, ]; const iv: [_]u8 = [ 0xc5, 0x4c, 0x99, 0xd2, 0xd0, 0xef, 0xf5, 0xde, 0x95, 0x38, 0x45, 0x34, 0xeb, 0xa2, 0xad, 0xa0, ]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let buf: [64]u8 = [0...]; let result: [1]u8 = [0]; let resultbuf = memio::fixed(result); let ctr = cipher::ctr(&resultbuf, &b, iv[..], buf[..]); defer io::close(&ctr)!; const n = io::write(&ctr, [])!; assert(n == 0); }; type err_stream = struct { stream: io::stream, out: io::handle, err: io::error, limit: size, }; const err_stream_vtable: io::vtable = io::vtable { writer = &err_writer, ... }; fn err_writer(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *err_stream; if (s.limit == 0) { return s.err; }; const n = if (len(buf) < s.limit) { yield len(buf); } else { return s.err; }; match(io::write(s.out, buf[..n])) { case let z: size => s.limit -= z; return n; case let e: io::error => return e; }; }; fn errwriter(out: io::handle, limit: size, err: io::error) err_stream = { return err_stream { stream = &err_stream_vtable, out = out, limit = limit, err = err, }; }; @test fn ctr_test_retry() void = { const key: [_]u8 = [ 0xae, 0x0c, 0x47, 0x6d, 0xce, 0x69, 0xdf, 0x52, 0xf7, 0x5e, 0x1f, 0x16, 0x7e, 0xea, 0x1c, 0xf0, ]; const iv: [_]u8 = [ 0x9a, 0x11, 0xd7, 0x24, 0x43, 0x86, 0x50, 0xf0, 0xd9, 0x8c, 0x0d, 0x0d, 0x7a, 0x2e, 0x95, 0x72, ]; const plain: [_]u8 = [ 0x05, 0xc8, 0x4a, 0xf7, 0xba, 0x4b, 0xc2, 0x4f, 0xd3, 0x63, 0xf3, 0x20, 0x51, 0x2b, 0x65, 0xec, 0x4c, 0xe7, 0x7f, 0x78, 0x17, 0x45, 0x0c, 0x6e, 0xff, 0xf1, 0x73, 0x97, 0x42, 0x4d, 0x4a, 0x30, 0x5d, 0xb2, 0x79, 0x45, 0xca, 0x20, 0x10, 0x5b, 0x2c, 0x34, 0x4c, 0xed, 0x42, 0x59, 0x61, 0x3a, 0x66, 0xa3, 0x2e, 0x74, 0xa8, 0xbb, 0x9c, 0xe9, 0x4e, 0xda, 0x33, 0x97, 0x98, 0x41, 0x9a, 0xf0, 0xbb, 0x6d, 0xcb, 0x5d, 0x15, 0x60, 0x26, 0x7c, 0x6c, 0xe5, 0xa4, 0xaf, 0x52, 0x14, 0x29, 0x2f, ]; const cipher: [_]u8 = [ 0xc1, 0xe5, 0x15, 0x76, 0x5b, 0xb2, 0x3a, 0xbc, 0xc4, 0x71, 0xdf, 0xcc, 0x20, 0xe0, 0x63, 0xd6, 0xb3, 0x7d, 0x48, 0x51, 0xe0, 0xd1, 0xcb, 0x07, 0xa3, 0xc8, 0xc6, 0xb9, 0x43, 0xa9, 0x1e, 0x70, 0xb2, 0x1e, 0xbe, 0xc3, 0x11, 0x36, 0xb2, 0x64, 0x7c, 0xaf, 0x89, 0x46, 0x17, 0x60, 0x90, 0x19, 0x23, 0x53, 0xd1, 0xce, 0xc6, 0x5c, 0x50, 0x9c, 0x8c, 0x1d, 0xa8, 0xee, 0x44, 0x9c, 0xa2, 0xb2, 0x97, 0x62, 0x39, 0xcc, 0x91, 0xb0, 0xcc, 0x2c, 0x1b, 0x4c, 0xc3, 0x5d, 0xc3, 0xfa, 0xe9, 0x98, ]; let result: [80]u8 = [0...]; let resultbuf = memio::fixed(result); let errw = errwriter(&resultbuf, 20, errors::again); let buf: [CTR_BUFSZ]u8 = [0...]; let b = ct64(); ct64_init(&b, key); defer cipher::finish(&b); let ctr = cipher::ctr(&errw, &b, iv[..], buf[..]); defer io::close(&ctr)!; let n = 0z; match (io::write(&ctr, plain[..64])) { case errors::again => void; case size => assert(false); }; errw.limit = 999; // try again n += io::write(&ctr, plain[..64])!; n += io::write(&ctr, plain[64..])!; assert(n == len(plain)); assert(bytes::equal(cipher, result)); }; hare-0.24.2/crypto/aes/rt+test.ha000066400000000000000000000165371464473310100165370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; @test fn rt_finish() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const zero: [CT64_EXPKEYSZ]u8 = [0...]; let block = aes(); init(&block, key); cipher::finish(&block); assert(len(block.expkey) == len(zero)); assert(bytes::equal(zero, block.expkey)); }; @test fn rt_encrypt_128() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let block = aes(); init(&block, key); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); }; @test fn rt_encrypt_128_multiple_blocks() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [_]u8 = [ 0xdb, 0x3a, 0x36, 0x50, 0x85, 0x60, 0x4c, 0x65, 0xc0, 0x22, 0x5a, 0x0d, 0x68, 0x2f, 0x19, 0xc2, 0x16, 0x27, 0xdd, 0xae, 0xd7, 0x28, 0x29, 0x23, 0xfa, 0x97, 0x28, 0xb0, 0x9a, 0x90, 0xfe, 0xb3, 0xde, 0x57, 0xbc, 0x15, 0x15, 0x8d, 0xb6, 0x29, 0x61, 0x40, 0x76, 0x51, 0x32, 0xc2, 0x3d, 0x1e, 0xdf, 0x97, 0x6a, 0x5e, 0x0a, 0x6b, 0xf6, 0x40, 0xb4, 0x08, 0x7e, 0xde, 0x17, 0xa4, 0x58, 0x98 ]; const cipher: [_]u8 = [ 0xdd, 0xf4, 0x53, 0x55, 0x18, 0x7a, 0xf0, 0x65, 0x59, 0xd6, 0xdc, 0x4e, 0xc2, 0x89, 0xff, 0x7b, 0x54, 0x41, 0x6a, 0xda, 0xa0, 0xad, 0x85, 0xbd, 0x75, 0x1e, 0x59, 0x15, 0x6d, 0x30, 0xa8, 0xa8, 0xa8, 0x54, 0x6e, 0xab, 0x9c, 0x47, 0x84, 0xd, 0x6e, 0xb5, 0x5e, 0xba, 0xb0, 0xd9, 0x47, 0xfa, 0x53, 0x6b, 0xff, 0x31, 0x47, 0x86, 0xf8, 0x4c, 0x6b, 0x65, 0xaa, 0xa2, 0xd2, 0xd7, 0xc1, 0xdf ]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); // test from 1 to 4 parallel blocks for (let i = 0z; i < 4; i += 1) { let result: [64]u8 = [0...]; let sz = (i + 1) * 16; cipher::encrypt(&block, result[0..sz], plain[0..sz]); assert(bytes::equal(cipher[0..sz], result[0..sz])); }; }; @test fn rt_decrypt_128_multiple_blocks() void = { const key: [16]u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [_]u8 = [ 0xdb, 0x3a, 0x36, 0x50, 0x85, 0x60, 0x4c, 0x65, 0xc0, 0x22, 0x5a, 0x0d, 0x68, 0x2f, 0x19, 0xc2, 0x16, 0x27, 0xdd, 0xae, 0xd7, 0x28, 0x29, 0x23, 0xfa, 0x97, 0x28, 0xb0, 0x9a, 0x90, 0xfe, 0xb3, 0xde, 0x57, 0xbc, 0x15, 0x15, 0x8d, 0xb6, 0x29, 0x61, 0x40, 0x76, 0x51, 0x32, 0xc2, 0x3d, 0x1e, 0xdf, 0x97, 0x6a, 0x5e, 0x0a, 0x6b, 0xf6, 0x40, 0xb4, 0x08, 0x7e, 0xde, 0x17, 0xa4, 0x58, 0x98 ]; const cipher: [_]u8 = [ 0xdd, 0xf4, 0x53, 0x55, 0x18, 0x7a, 0xf0, 0x65, 0x59, 0xd6, 0xdc, 0x4e, 0xc2, 0x89, 0xff, 0x7b, 0x54, 0x41, 0x6a, 0xda, 0xa0, 0xad, 0x85, 0xbd, 0x75, 0x1e, 0x59, 0x15, 0x6d, 0x30, 0xa8, 0xa8, 0xa8, 0x54, 0x6e, 0xab, 0x9c, 0x47, 0x84, 0xd, 0x6e, 0xb5, 0x5e, 0xba, 0xb0, 0xd9, 0x47, 0xfa, 0x53, 0x6b, 0xff, 0x31, 0x47, 0x86, 0xf8, 0x4c, 0x6b, 0x65, 0xaa, 0xa2, 0xd2, 0xd7, 0xc1, 0xdf ]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); // test from 1 to 4 parallel blocks for (let i = 0z; i < 4; i += 1) { let result: [64]u8 = [0...]; let sz = (i + 1) * 16; cipher::decrypt(&block, result[0..sz], cipher[0..sz]); assert(bytes::equal(plain[0..sz], result[0..sz])); }; }; @test fn rt_decrypt_128() void = { const key: []u8 = [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, ]; const plain: [16]u8 = [ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, ]; const cipher: [16]u8 = [ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, ]; let result: [16]u8 = [0...]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.1 @test fn rt_example_vector1() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, ]; let result: [16]u8 = [0...]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; @test fn rt_example_vector1_in_place() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, ]; let result: [16]u8 = plain; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], result[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], result[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.2 @test fn rt_example_vector2() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ]; const plain: [_]u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: [_]u8 = [ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91, ]; let result: [16]u8 = [0...]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; // fips-197.pdf Appendix C.3 @test fn rt_example_vector3() void = { const key: []u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; const plain: []u8 = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, ]; const cipher: []u8 = [ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89, ]; let result: [16]u8 = [0...]; let block = aes(); init(&block, key[..]); defer cipher::finish(&block); cipher::encrypt(&block, result[..], plain[..]); assert(bytes::equal(cipher, result)); cipher::decrypt(&block, result[..], cipher[..]); assert(bytes::equal(plain, result)); }; hare-0.24.2/crypto/aes/xts/000077500000000000000000000000001464473310100154275ustar00rootroot00000000000000hare-0.24.2/crypto/aes/xts/+test.ha000066400000000000000000000053251464473310100170000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; @test fn oneblock() void = { let key: [_]u8 = [ 0xfe, 0x7f, 0xec, 0x77, 0x1b, 0xa4, 0x28, 0xc7, 0xf8, 0x82, 0x62, 0x2b, 0xe7, 0x60, 0x59, 0xf5, 0x25, 0x71, 0xda, 0x8b, 0x8f, 0x72, 0x04, 0xe4, 0x38, 0xa2, 0xa5, 0x98, 0x45, 0x14, 0xff, 0xbe, 0xce, 0xf6, 0xaa, 0xcc, 0xe1, 0x86, 0xc2, 0x2b, 0x9e, 0x55, 0x86, 0x23, 0x71, 0x96, 0xa3, 0xb1, 0xa1, 0xf9, 0x11, 0x4d, 0x86, 0xf8, 0x7e, 0xd1, 0xae, 0x5a, 0x3d, 0x4a, 0x99, 0x65, 0xd0, 0xb1, ]; let sector1: [_]u8 = [ 0xe4, 0x60, 0xb0, 0x44, 0x7c, 0xc0, 0xbe, 0x63, 0xbb, 0x88, 0x62, 0xab, 0x6e, 0x49, 0xde, 0xea, ]; let crypto1: [_]u8 = [ 0x6f, 0x3c, 0x46, 0xd8, 0x36, 0x25, 0x7d, 0x70, 0x00, 0xc3, 0x94, 0x92, 0x48, 0x18, 0xa1, 0x67, ]; let result: [16]u8 = [0...]; let b = xts(); init(&b, key); encrypt(&b, result, sector1, 1); assert(bytes::equal(crypto1, result)); decrypt(&b, result, crypto1, 1); assert(bytes::equal(sector1, result)); }; @test fn multiblock() void = { const key: [_]u8 = [ 0x61, 0x7f, 0x3d, 0x06, 0xa2, 0x18, 0x4b, 0x63, 0xd7, 0xad, 0xfa, 0x07, 0xe7, 0x57, 0x6c, 0x2a, 0xb7, 0xb4, 0xce, 0x55, 0x3d, 0x90, 0xd0, 0x87, 0xdf, 0xc6, 0xf4, 0x72, 0x4c, 0x54, 0xcd, 0xda, 0x93, 0x0b, 0xb5, 0x40, 0x4b, 0xab, 0x10, 0x85, 0x6b, 0xf7, 0x45, 0xc7, 0xda, 0x5e, 0x6e, 0x69, 0xdf, 0x68, 0xdd, 0xb8, 0xdd, 0xd9, 0xc2, 0xe6, 0x85, 0x2e, 0x25, 0x7a, 0xb4, 0xfc, 0x97, 0x20, ]; const sector11: [_]u8 = [ 0xc9, 0x41, 0xae, 0x7d, 0x5c, 0x0b, 0xa5, 0xb1, 0x31, 0xee, 0x2e, 0x4b, 0xf8, 0x74, 0x29, 0xc5, 0x39, 0x9b, 0xfe, 0x2e, 0x51, 0xb8, 0xab, 0xaa, 0x72, 0x49, 0x04, 0x43, 0x2a, 0x4d, 0x50, 0xdc, ]; const crypto11: [_]u8 = [ 0x30, 0xa3, 0x8f, 0x05, 0x49, 0x1e, 0x4d, 0xda, 0x47, 0x44, 0xae, 0xff, 0x7f, 0x4d, 0x4e, 0xb5, 0xca, 0xb2, 0xfc, 0xa9, 0x70, 0x55, 0x1a, 0x05, 0xa1, 0x2a, 0xd8, 0x34, 0x6f, 0x9b, 0x02, 0xc0, ]; const sector14: [_]u8 = [ 0x2e, 0x95, 0x4d, 0xa7, 0x1f, 0xfb, 0xd3, 0xc8, 0x8e, 0x6f, 0x07, 0xab, 0x75, 0x53, 0xfc, 0x87, 0x05, 0xe8, 0xe8, 0x5a, 0x47, 0xbc, 0xc9, 0x12, 0x0c, 0xc4, 0x09, 0x30, 0x86, 0x91, 0xcc, 0xfa, ]; const crypto14: [_]u8 = [ 0xa1, 0xf8, 0xd6, 0x35, 0xcd, 0x1e, 0xbe, 0xb7, 0x64, 0xcb, 0xbe, 0x2c, 0x58, 0xb1, 0xc0, 0xd2, 0x4e, 0x8a, 0x9e, 0x09, 0x76, 0x08, 0xf7, 0x28, 0x94, 0xaf, 0xf8, 0x20, 0x1c, 0xbb, 0x02, 0x9c, ]; let result: [32]u8 = [0...]; let b = xts(); init(&b, key); encrypt(&b, result, sector11, 11); assert(bytes::equal(crypto11, result)); encrypt(&b, result, sector14, 14); assert(bytes::equal(crypto14, result)); decrypt(&b, result, crypto11, 11); assert(bytes::equal(sector11, result)); decrypt(&b, result, crypto14, 14); assert(bytes::equal(sector14, result)); }; hare-0.24.2/crypto/aes/xts/README000066400000000000000000000025351464473310100163140ustar00rootroot00000000000000xts implements the AES-XTS cipher mode as defined in the IEEE Std 1619-2007. AES-XTS is an unauthenticated transparent encryption scheme designed for use cases like disk encryption. Transparent in the sense that the output size is the same as the input size, and that blocks can be written or read in an arbitrary order. Similarly to the ECB mode, XTS operates in blocks which are a multiple of the AES block size. The security guarantees can be compared to the ECB ones, but with a different key for each block. That means following vulnerabilities exist: - Traffic analysis: An observer can see when a certain block is written back to disk with a different value. - Replay: An adversary may change a block back to an old value, if write access is available. - Changing sectors: Changing of the cipher text will result in "random" plain text. Authentication or error detection can be done before encryption, to resist such attacks. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/aes/xts/xts.ha000066400000000000000000000056501464473310100165650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::aes; use crypto::cipher; export type block = struct { b1: aes::block, b2: aes::block, x: [aes::BLOCKSZ]u8, }; // Creates a AES-XTS instance. Must be initialized with [[init]] and always be // finished using [[finish]] to erase sensitive state from memory. export fn xts() block = block { b1 = aes::aes(), b2 = aes::aes(), ... }; // Initializes the AES-XTS instance. The key length must be 64, 48, or 32 bytes // (the size of two valid AES keys). export fn init(b: *block, key: []u8) void = { assert(len(key) == 64 || len(key) == 48 || len(key) == 32, "invalid key size"); let sep: size = len(key) / 2; aes::init(&b.b1, key[..sep]); aes::init(&b.b2, key[sep..]); }; def GF_128_FDBK: u8 = 0x87; // Encrypts a block given its 'sector' number. The block must be a multiple of // [[crypto::aes::BLOCKSZ]] (16 bytes) in length. export fn encrypt(b: *block, dest: []u8, src: []u8, sector: u64) void = { assert(len(src) == len(dest) && len(src) % aes::BLOCKSZ == 0); let tweak: [aes::BLOCKSZ]u8 = [0...]; let carryin: u8 = 0; let carryout: u8 = 0; for (let j = 0z; j < len(tweak); j += 1) { tweak[j] = (sector & 0xFF): u8; sector >>= 8; }; cipher::encrypt(&b.b2, tweak, tweak); let i = 0z; for (i + aes::BLOCKSZ <= len(src); i += aes::BLOCKSZ) { for (let j = 0z; j < aes::BLOCKSZ; j += 1) { b.x[j] = src[i + j] ^ tweak[j]; }; cipher::encrypt(&b.b1, b.x, b.x); for (let j = 0z; j < aes::BLOCKSZ; j += 1) { dest[i + j] = b.x[j] ^ tweak[j]; }; // multiply primitive carryin = 0; for (let j = 0z; j < aes::BLOCKSZ; j += 1) { carryout = (tweak[j] >> 7) & 1; tweak[j] = ((tweak[j] << 1) + carryin) & 0xff; carryin = carryout; }; if (carryout != 0) { tweak[0] ^= GF_128_FDBK; }; }; }; // Decrypts a block given its 'sector' number. export fn decrypt(b: *block, dest: []u8, src: []u8, sector: u64) void = { assert(len(src) == len(dest) && len(src) % aes::BLOCKSZ == 0); let tweak: [aes::BLOCKSZ]u8 = [0...]; let carryin: u8 = 0; let carryout: u8 = 0; for (let j = 0z; j < len(tweak); j += 1) { tweak[j] = (sector & 0xFF): u8; sector >>= 8; }; cipher::encrypt(&b.b2, tweak, tweak); let i = 0z; for (i + aes::BLOCKSZ <= len(src); i += aes::BLOCKSZ) { for (let j = 0z; j < aes::BLOCKSZ; j += 1) { b.x[j] = src[i + j] ^ tweak[j]; }; cipher::decrypt(&b.b1, b.x, b.x); for (let j = 0z; j < aes::BLOCKSZ; j += 1) { dest[i + j] = b.x[j] ^ tweak[j]; }; // multiply primitive carryin = 0; for (let j = 0z; j < aes::BLOCKSZ; j += 1) { carryout = (tweak[j] >> 7) & 1; tweak[j] = ((tweak[j] << 1) + carryin) & 0xff; carryin = carryout; }; if (carryout != 0) { tweak[0] ^= GF_128_FDBK; }; }; }; // Clears the sensible data of AES-XTS instance off the memory. export fn finish(b: *block) void = { cipher::finish(&b.b1); cipher::finish(&b.b2); bytes::zero(b.x); }; hare-0.24.2/crypto/argon2/000077500000000000000000000000001464473310100152315ustar00rootroot00000000000000hare-0.24.2/crypto/argon2/+test.ha000066400000000000000000000125361464473310100166040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::hex; use strings; use test; @test fn mode_d_one_pass() void = { let pass: [32]u8 = [1...]; let salt: [16]u8 = [2...]; let secret: [8]u8 = [3...]; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; let expected: [_]u8 = [ 0xfa, 0x17, 0x75, 0xca, 0x80, 0x90, 0x64, 0x66, 0x18, 0xbe, 0x70, 0xeb, 0x0f, 0xc9, 0xde, 0x43, 0x67, 0x58, 0xed, 0x0c, 0xa5, 0x36, 0x83, 0x1a, 0xe9, 0xe1, 0x03, 0x48, 0x93, 0x81, 0xc1, 0x79, ]; let cfg = conf { secret = secret, data = data, passes = 1, parallel = 4, version = 0x13, mem = 32, ... }; argon2d(result[..], pass, salt, &cfg)!; assert(bytes::equal(result, expected)); }; @test fn rfc_d_test_vector() void = { let pass: [32]u8 = [1...]; let salt: [16]u8 = [2...]; let secret: [8]u8 = [3...]; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; let mem: []u64 = alloc([0...], 32z * BLOCKSZ); defer free(mem); let expected: [_]u8 = [ 0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97, 0x53, 0x71, 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94, 0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1, 0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, 0x4a, 0xcb, ]; let cfg = conf { secret = secret, data = data, passes = 3, parallel = 4, version = 0x13, mem = mem[..], ... }; argon2d(result[..], pass, salt, &cfg)!; assert(bytes::equal(result, expected)); }; @test fn rfc_i_test_vector() void = { let pass: [32]u8 = [1...]; let salt: [16]u8 = [2...]; let secret: [8]u8 = [3...]; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; let mem: []u64 = alloc([0...], 32z * BLOCKSZ); defer free(mem); let expected: [_]u8 = [ 0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa, 0x13, 0xf0, 0xd7, 0x7f, 0x24, 0x94, 0xbd, 0xa1, 0xc8, 0xde, 0x6b, 0x01, 0x6d, 0xd3, 0x88, 0xd2, 0x99, 0x52, 0xa4, 0xc4, 0x67, 0x2b, 0x6c, 0xe8, ]; let cfg = conf { secret = secret, data = data, passes = 3, parallel = 4, version = 0x13, mem = mem[..], ... }; argon2i(result[..], pass, salt, &cfg)!; assert(bytes::equal(result, expected)); }; @test fn rfc_id_test_vector() void = { let pass: [32]u8 = [1...]; let salt: [16]u8 = [2...]; let secret: [8]u8 = [3...]; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; let mem: []u64 = alloc([0...], 32z * BLOCKSZ); defer free(mem); let expected: [_]u8 = [ 0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c, 0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9, 0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e, 0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, 0xe6, 0x59, ]; let cfg = conf { secret = secret, data = data, passes = 3, parallel = 4, version = 0x13, mem = mem[..], ... }; argon2id(result[..], pass, salt, &cfg)!; assert(bytes::equal(result, expected)); }; type tcase = struct { c: conf, m: mode, h: str, }; @test fn samples() void = { const pass = strings::toutf8("trustno1"); const salt = strings::toutf8("abcdefgh"); const tests: [_]tcase = [ tcase { c = conf { passes = 1, parallel = 3, version = 0x13, mem = 64, ... }, m = mode::ID, h = "c7ada5ba3222fa45a3802249b509dcfb10e68a50e3faad2a6377eeca8395ab47", }, tcase { c = conf { passes = 1, parallel = 4, version = 0x13, mem = 64, ... }, m = mode::ID, h = "21543b2017ede3f865ea5cb88295628ba25eb3be53a8c4aeb0ac1a264be0110a", }, tcase { c = conf { passes = 1, parallel = 4, version = 0x13, mem = 64, ... }, m = mode::I, h = "5c3124ce5f3556e5e25f06b5108718f2cd72afee98a3249656eb85ecc0e5b314", }, tcase { c = conf { passes = 1, parallel = 4, version = 0x13, mem = 64, ... }, m = mode::D, h = "d75524ad0b899363ce77f2d1e1040763dc01cfc725db635391bba163001f08cb", }, tcase { c = conf { passes = 3, parallel = 3, version = 0x13, mem = 64, ... }, m = mode::ID, h = "226c3ca6caba42b102035d332a11b350f1e19675fccb6e24aa33ca8c31d588c1", }, tcase { c = conf { passes = 1, parallel = 8, version = 0x13, mem = 64, ... }, m = mode::ID, h = "fadf598b70708f4d91b0e98f038fd25a73950f1f85d57fb250740d817f95e9a9", }, tcase { c = conf { passes = 1, parallel = 4, version = 0x13, mem = 96, ... }, m = mode::ID, h = "c99aa41cb53cc4919d336c19d38b30d8633c71faa9475293f3fbe0aa6ccd65b2", }, ]; for (let i = 0z; i < len(tests); i += 1) { const t = tests[i]; const expected = hex::decodestr(t.h)!; defer free(expected); let dest: []u8 = alloc([0...], len(expected)); defer free(dest); argon2(dest, pass, salt, &t.c, t.m)!; assert(bytes::equal(expected, dest)); }; }; @test fn samples_slow() void = { test::require("slow"); const pass = strings::toutf8("trustno1"); const salt = strings::toutf8("abcdefgh"); const tests: [_]tcase = [ tcase { c = low_mem_conf, m = mode::ID, h = "8974537c53677aae532b319af700bb4232a0d74eee7d57296b2a3f8303a6bafe", }, tcase { c = default_conf, m = mode::ID, h = "3b282cbf435b0e022f7041549583ddc802e519109f1da8f12d2054910913d660", }, ]; for (let i = 0z; i < len(tests); i += 1) { const t = tests[i]; const expected = hex::decodestr(t.h)!; defer free(expected); let dest: []u8 = alloc([0...], len(expected)); defer free(dest); argon2(dest, pass, salt, &t.c, t.m)!; assert(bytes::equal(expected, dest)); }; }; hare-0.24.2/crypto/argon2/README000066400000000000000000000033441464473310100161150ustar00rootroot00000000000000This module provides an implementation of the argon2 key derivation function as described by RFC 9106. This is the recommended algorithm for password hashing in Hare programs, and for deriving keys for use with other cryptographic algorithms. Some thought must be given to the appropriate configuration for your use case. Some general advice is provided here; if in doubt, consult the RFC. The argon2 parameters are configured via the [[conf]] structure. To determine the appropriate configuration parameters for a particular use-case, consult section 4 of the RFC. Otherwise, sane defaults for common scenarios are provided via [[default_conf]] and [[low_mem_conf]]; consult the docs of each configuration for details. Once a suitable configuration has been selected, the user must provide a salt. This salt should be stored alongside the hash, should be unique for each password, and should be random: see [[crypto::random::]]. The salt and hash lengths are configurable, the recommended defaults are 16 and 32 bytes respectively. Equipped with the necessary parameters, the user may call the appropriate argon2 variant via [[argon2d]], [[argon2i]], or [[argon2id]]. If unsure which to use, choose [[argon2id]]. The RFC is the authoratative source on the appropriate argon2 variant and configuration parameters for your use-case. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/argon2/argon2.ha000066400000000000000000000324201464473310100167340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // (c) 2022 Alexey Yerin // (c) 2021-2022 Armin Preiml // (c) 2021-2022 Drew DeVault use bytes; use crypto::blake2b; use crypto::math; use endian; use errors::{nomem}; use hash; use io; use memio; use types; // Latest version of argon2 supported by this implementation (1.3). export def VERSION: u8 = 0x13; // Number of u64 elements of one block. export def BLOCKSZ: u32 = 128; def SLICES: size = 4; type block64 = [BLOCKSZ]u64; const zeroblock: block64 = [0...]; type mode = enum { D = 0, I = 1, ID = 2, }; // This type provides configuration options for the argon2 algorithm. Most users // will find [[default_conf]] or [[low_mem_conf]] suitable for their needs // without providing a custom configuration. If writing a custom configuration, // consult the RFC for advice on selecting suitable values for your use-case. // // 'parallel' specifies the number of parallel processes. 'pass' configures the // number of iterations. Both values must be at least one. Note: the Hare // implementation of argon2 does not process hashes in parallel, though it will // still compute the correct hash if this value is greater than one. // // 'version' specifies the version of the argon2 function. The implementation // currently only supports version 1.3. Use [[VERSION]] here. // // 'secret' and 'data' are optional byte arrays that are applied to the initial // state. Consult the RFC for details. // // The 'mem' parameter is used to configure working memory used during the // computation. The argon2 algorithm requires a large amount of memory to // compute hashes. If 'mem' set to a u32, it is interpreted as the desired // number of 1024-byte blocks the implementation shall allocate for you. If the // caller wants to manage the allocation itself, provide a []u8 instead. The // length of this slice must be at least 8 times the value of 'parallel' in // blocks, and must be a multiple of [[BLOCKSZ]]. To have the implementation // allocate 64 KiB, set 'mem' to 64. To use the same amount of caller-provided // memory, provide a slice of length 64 * [[BLOCKSZ]]. export type conf = struct { mem: (u32 | []u64), parallel: u32, passes: u32, version: u8, secret: []u8, data: []u8 }; // The default recommended configuration for most use cases. This configuration // uses 2 GiB of working memory. A 16-byte 'salt' and 32-byte 'dest' parameter // is recommended in combination with this configuration. export const default_conf: conf = conf { mem = 2 * 1024 * 1024, passes = 1, parallel = 4, version = 0x13, ... }; // The default recommended configuration for memory-constrained use cases. This // configuration uses 64 MiB of working memory. A 16-byte 'salt' and 32-byte // 'dest' parameter is recommended in combination with this configuration. export const low_mem_conf: conf = conf { mem = 64 * 1024, passes = 3, parallel = 4, version = 0x13, ... }; type context = struct { mode: mode, cols: size, rows: size, sliceblocks: size, mem: []u64, pass: u32, seedsinit: block64, seedblock: block64, }; // Computes an argon2d hash, writing the digest to 'dest'. A 'salt' length of 16 // bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 bytes // is recommended, and 4 bytes is the minimum. // // The argon2d mode uses data-dependent memory access and is suitable for // applications with no threats of side-channel timing attacks. export fn argon2d( dest: []u8, password: []u8, salt: []u8, cfg: *conf, ) (void | nomem) = { return argon2(dest, password, salt, cfg, mode::D); }; // Computes an argon2i hash, writing the digest to 'dest'. A 'salt' length of 16 // bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 bytes // is recommended, and 4 bytes is the minimum. // // The argon2i mode uses data-independent memory access and is suitable for // password hashing and key derivation. It makes more passes over memory to // protect from trade-off attacks. export fn argon2i( dest: []u8, password: []u8, salt: []u8, cfg: *conf, ) (void | nomem) = { return argon2(dest, password, salt, cfg, mode::I); }; // Computes an argon2id hash, writing the digest to 'dest'. A 'salt' length of // 16 bytes is recommended, and 8 bytes is the minimum. A 'dest' length of 32 // bytes is recommended, and 4 bytes is the minimum. // // The argon2id mode works by using argon2i for the first half of the first pass // and argon2d further on. It provides therefore protection from side-channel // attacks and brute-force cost savings due to memory trade-offs. // // If you are unsure which variant to use, argon2id is recommended. export fn argon2id( dest: []u8, password: []u8, salt: []u8, cfg: *conf, ) (void | nomem) = { return argon2(dest, password, salt, cfg, mode::ID); }; fn argon2( dest: []u8, password: []u8, salt: []u8, cfg: *conf, mode: mode, ) (void | nomem) = { assert(endian::host == &endian::little, "TODO big endian support"); assert(len(dest) >= 4 && len(dest) <= types::U32_MAX); assert(len(password) <= types::U32_MAX); assert(len(salt) >= 8 && len(salt) <= types::U32_MAX); assert(cfg.parallel >= 1); assert(cfg.passes >= 1); assert(len(cfg.secret) <= types::U32_MAX); assert(len(cfg.data) <= types::U32_MAX); let initmemsize = 0u32; let mem: []u64 = match (cfg.mem) { case let mem: []u64 => assert(len(mem) >= 8 * cfg.parallel * BLOCKSZ && len(mem) % BLOCKSZ == 0 && len(mem) / BLOCKSZ <= types::U32_MAX); initmemsize = (len(mem) / BLOCKSZ): u32; // round down memory to nearest multiple of 4 times parallel const memsize = len(mem) - len(mem) % (4 * cfg.parallel * BLOCKSZ); yield mem[..memsize]; case let memsize: u32 => assert(memsize >= 8 * cfg.parallel && memsize <= types::U32_MAX); initmemsize = memsize; const memsize = memsize - memsize % (4 * cfg.parallel); yield alloc([0...], memsize * BLOCKSZ): []u64; }; let h0: [64]u8 = [0...]; inithash(&h0, len(dest): u32, password, salt, cfg, mode, initmemsize); const memsize = (len(mem) / BLOCKSZ): u32; const cols = 4 * (memsize / (4 * cfg.parallel)); let ctx = context { rows = cfg.parallel, cols = cols, sliceblocks = cols / 4, pass = 0, mem = mem, mode = mode, seedsinit = [0...], seedblock = [0...], ... }; // hash first and second blocks of each row for (let i = 0z; i < ctx.rows; i += 1) { let src: [72]u8 = [0...]; src[..64] = h0[..]; endian::leputu32(src[64..68], 0); endian::leputu32(src[68..], i: u32); varhash(blocku8(&ctx, i, 0), src); endian::leputu32(src[64..68], 1); endian::leputu32(src[68..], i: u32); varhash(blocku8(&ctx, i, 1), src); }; // process segments for (ctx.pass < cfg.passes; ctx.pass += 1) { for (let s = 0z; s < SLICES; s += 1) { for (let i = 0z; i < ctx.rows; i += 1) { segproc(cfg, &ctx, i, s); }; }; }; // final hash let b = blocku8(&ctx, 0, ctx.cols - 1); for (let i = 1z; i < ctx.rows; i += 1) { math::xor(b, b, blocku8(&ctx, i, ctx.cols - 1)); }; varhash(dest, b); bytes::zero(h0); bytes::zero((ctx.mem: *[*]u8)[..len(ctx.mem) * size(u64)]); if (cfg.mem is u32) { // mem was allocated internally free(ctx.mem); }; }; fn block(ctx: *context, i: size, j: size) []u64 = { let index = (ctx.cols * i + j) * BLOCKSZ; return ctx.mem[index..index + BLOCKSZ]; }; fn blocku8(ctx: *context, i: size, j: size) []u8 = { return (block(ctx, i, j): *[*]u8)[..BLOCKSZ * size(u64)]; }; fn refblock(cfg: *conf, ctx: *context, seed: u64, i: size, j: size) []u64 = { const segstart = (j - (j % ctx.sliceblocks)) / ctx.sliceblocks; const index = j % ctx.sliceblocks; const l: size = if (segstart == 0 && ctx.pass == 0) { yield i; } else { yield (seed >> 32) % cfg.parallel; }; let poolstart: u64 = ((segstart + 1) % SLICES) * ctx.sliceblocks; let poolsize: u64 = 3 * ctx.sliceblocks; if (i == l) { poolsize += index; }; if (ctx.pass == 0) { poolstart = 0; poolsize = segstart * ctx.sliceblocks; if (segstart == 0 || i == l) { poolsize += index; }; }; if (index == 0 || i == l) { poolsize -= 1; }; const j1: u64 = seed & 0xffffffff; const x: u64 = (j1 * j1) >> 32; const y: u64 = (poolsize * x) >> 32; const z: u64 = (poolstart + poolsize - (y+1)) % ctx.cols: u64; return block(ctx, l: size, z: size); }; fn inithash( dest: *[64]u8, taglen: u32, password: []u8, salt: []u8, cfg: *conf, mode: mode, memsize: u32, ) void = { let u32buf: [4]u8 = [0...]; let h = blake2b::blake2b([], 64); defer hash::close(&h); hash_leputu32(&h, cfg.parallel); hash_leputu32(&h, taglen); hash_leputu32(&h, memsize); hash_leputu32(&h, cfg.passes); hash_leputu32(&h, cfg.version); hash_leputu32(&h, mode: u32); hash_leputu32(&h, len(password): u32); hash::write(&h, password); hash_leputu32(&h, len(salt): u32); hash::write(&h, salt); hash_leputu32(&h, len(cfg.secret): u32); hash::write(&h, cfg.secret); hash_leputu32(&h, len(cfg.data): u32); hash::write(&h, cfg.data); hash::sum(&h, dest[..]); }; fn hash_leputu32(h: *hash::hash, u: u32) void = { let buf: [4]u8 = [0...]; endian::leputu32(buf, u); hash::write(h, buf[..]); }; // The variable hash function H' fn varhash(dest: []u8, block: []u8) void = { let u32buf: [4]u8 = [0...]; if (len(dest) <= 64) { let h = blake2b::blake2b([], len(dest)); defer hash::close(&h); hash_leputu32(&h, len(dest): u32); hash::write(&h, block); hash::sum(&h, dest); return; }; // TODO this may be replaced with a constant time divceil in future to // avoid leaking the dest len. const r = divceil(len(dest): u32, 32) - 2; let v: [64]u8 = [0...]; let destbuf = memio::fixed(dest); let h = blake2b::blake2b([], 64); hash_leputu32(&h, len(dest): u32); hash::write(&h, block); hash::sum(&h, v[..]); hash::close(&h); io::writeall(&destbuf, v[..32])!; for (let i = 1z; i < r; i += 1) { let h = blake2b::blake2b([], 64); hash::write(&h, v[..]); hash::sum(&h, v[..]); hash::close(&h); io::writeall(&destbuf, v[..32])!; }; const remainder = len(dest) - 32 * r; let hend = blake2b::blake2b([], remainder); defer hash::close(&hend); hash::write(&hend, v[..]); hash::sum(&hend, v[..remainder]); io::writeall(&destbuf, v[..remainder])!; }; fn divceil(dividend: u32, divisor: u32) u32 = { let result = dividend / divisor; if (dividend % divisor > 0) { result += 1; }; return result; }; fn xorblock(dest: []u64, x: []u64, y: []u64) void = { for (let i = 0z; i < len(dest); i += 1) { dest[i] = x[i] ^ y[i]; }; }; fn segproc(cfg: *conf, ctx: *context, i: size, slice: size) void = { const init = switch (ctx.mode) { case mode::I => yield true; case mode::ID => yield ctx.pass == 0 && slice < 2; case mode::D => yield false; }; if (init) { ctx.seedsinit[0] = ctx.pass; ctx.seedsinit[1] = i; ctx.seedsinit[2] = slice; ctx.seedsinit[3] = len(ctx.mem) / BLOCKSZ; ctx.seedsinit[4] = cfg.passes; ctx.seedsinit[5] = ctx.mode: u64; ctx.seedsinit[6] = 0; if (ctx.pass == 0 && slice == 0) { ctx.seedsinit[6] += 1; compress(ctx.seedblock, ctx.seedsinit, zeroblock, false); compress(ctx.seedblock, ctx.seedblock, zeroblock, false); }; }; for (let b = 0z; b < ctx.sliceblocks; b += 1) { const j = slice * ctx.sliceblocks + b; if (ctx.pass == 0 && j < 2) { continue; }; const dmodeseed = switch (ctx.mode) { case mode::D => yield true; case mode::ID => yield ctx.pass > 0 || slice > 1; case mode::I => yield false; }; const pj = if (j == 0) ctx.cols - 1 else j - 1; let prev = block(ctx, i, pj); const seed: u64 = if (dmodeseed) { yield prev[0]; } else { if (b % BLOCKSZ == 0) { ctx.seedsinit[6] += 1; compress(ctx.seedblock, ctx.seedsinit, zeroblock, false); compress(ctx.seedblock, ctx.seedblock, zeroblock, false); }; yield ctx.seedblock[b % BLOCKSZ]; }; let ref = refblock(cfg, ctx, seed, i, j); compress(block(ctx, i, j), prev, ref, ctx.pass > 0); }; }; fn compress(dest: []u64, x: []u64, y: []u64, xor: bool) void = { let r: block64 = [0...]; xorblock(r, x, y); let z: block64 = [0...]; z[..] = r[..]; for (let i = 0z; i < 128; i += 16) { perm(&z[i], &z[i + 1], &z[i + 2], &z[i + 3], &z[i + 4], &z[i + 5], &z[i + 6], &z[i + 7], &z[i + 8], &z[i + 9], &z[i + 10], &z[i + 11], &z[i + 12], &z[i + 13], &z[i + 14], &z[i + 15]); }; for (let i = 0z; i < 16; i += 2) { perm(&z[i], &z[i + 1], &z[i + 16], &z[i + 17], &z[i + 32], &z[i + 33], &z[i + 48], &z[i + 49], &z[i + 64], &z[i + 65], &z[i + 80], &z[i + 81], &z[i + 96], &z[i + 97], &z[i + 112], &z[i + 113]); }; if (xor) { xorblock(r, r, dest); }; xorblock(dest, z, r); }; fn perm( x0: *u64, x1: *u64, x2: *u64, x3: *u64, x4: *u64, x5: *u64, x6: *u64, x7: *u64, x8: *u64, x9: *u64, x10: *u64, x11: *u64, x12: *u64, x13: *u64, x14: *u64, x15: *u64, ) void = { mix(x0, x4, x8, x12); mix(x1, x5, x9, x13); mix(x2, x6, x10, x14); mix(x3, x7, x11, x15); mix(x0, x5, x10, x15); mix(x1, x6, x11, x12); mix(x2, x7, x8, x13); mix(x3, x4, x9, x14); }; fn mix(a: *u64, b: *u64, c: *u64, d: *u64) void = { *a = *a + *b + 2 * (*a & 0xffffffff) * (*b & 0xffffffff); *d = math::rotr64(*d ^ *a, 32); *c = *c + *d + 2 * (*c & 0xffffffff) * (*d & 0xffffffff); *b = math::rotr64(*b ^ *c, 24); *a = *a + *b + 2 * (*a & 0xffffffff) * (*b & 0xffffffff); *d = math::rotr64(*d ^ *a, 16); *c = *c + *d + 2 * (*c & 0xffffffff) * (*d & 0xffffffff); *b = math::rotr64(*b ^ *c, 63); }; hare-0.24.2/crypto/authenc.ha000066400000000000000000000114661464473310100160120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::chachapoly; use crypto::math; use errors; use io; use memio; // A secret session key. export type sessionkey = [32]u8; // A value which is only used once. export type nonce = [24]u8; // A message authentication code. export type mac = [16]u8; // An encrypted, authenticated message. export type box = (mac, nonce, []u8); // Performs authenticated encryption on a message. The result may be // authenticated and decrypted with [[decrypt]]. // // To use this function, you must first establish a session key which is shared // with both parties. This key must be random and secret. You may derive this // key with a key exchange (such as [[exchange]] or [[dh]]), or with a key // derivation function (such as [[derivekey]]), or by sharing it in person, or // some other, similar means which preserves the traits of randomness and // secrecy. // // You must also establish a unique nonce for each message, which you must not // reuse for any future messages using the same session key. It is recommended // to generate this randomly with [[crypto::random::]]. // // The plaintext parameter provides the message to encrypt. It will be // overwritten with the ciphertext. The buffer provided in the return value is // borrowed from this parameter. // // The optional 'additional' parameters provide additional data to be // authenticated with the same MAC. This data is not encrypted, but [[decrypt]] // will fail if it has been tampered with. The order of these arguments must be // consistent between [[encrypt]] and [[decrypt]]. // // The return value contains all of the information which should be transmitted // to the other party, including the computed MAC, a copy of the nonce, and the // ciphertext. It is safe to transmit these values over an unsecured connection, // or to encode them with something like [[encoding::base64::]]. // // Any 'additional' data, if provided, is not included in the [[box]] type. The // user must provide for this data to be transmitted to the other party // themselves. // // let key: crypto::sessionkey = [0...]; // let nonce: crypto::nonce = [0...]; // random::buffer(key); // Or some other means of establishing the key // random::buffer(nonce); // // let buf: [64]u8 = [0...]; // Populate with your message // let box = crypto::encrypt(&key, &nonce, buf[..], buf[..]); // // // To decrypt this message: // let plaintext = match (crypto::decrypt(&key, &box, buf[..])) { // case let buf: []u8 => // yield buf; // case errors::invalid => // abort("Message authentication or decryption failed"); // }; // // The current implementation of this algorithm is based on RFC 8439, but uses // XChaCha20 instead of ChaCha20. export fn encrypt( key: *sessionkey, nonce: *nonce, plaintext: []u8, additional: []u8... ) box = { let s = chachapoly::chachapoly(); defer io::close(&s)!; let h = memio::fixed(plaintext); chachapoly::xinit(&s, &h, key, nonce, additional...); io::writeall(&s, plaintext)!; let m: mac = [0...]; chachapoly::seal(&s, m); return (m, *nonce, memio::buffer(&h)); }; // Authenticates and decrypts a message encrypted with [[encrypt]]. If the // decryption is successful, the plaintext slice is returned, and if not, // [[errors::invalid]] is returned. // // The 'sessionkey' parameter is the shared key. The 'box' parameter is the // output of [[encrypt]]. If additional data should be authenticated, it may be // provided in the variadic 'additional' parameters. // // Note that the data is decrypted in-place, such that the box's ciphertext // becomes overwritten with the plaintext. The return value is borrowed from // this buffer. If decryption fails, this buffer will be zeroed, causing the // ciphertext to be destroyed as well. It is advised to zero the plaintext // buffer yourself after you are done using it, see [[bytes::zero]]. // // See [[decrypt]] for the full details and a usage example. export fn decrypt( key: *sessionkey, box: *box, additional: []u8... ) ([]u8 | errors::invalid) = { let s = chachapoly::chachapoly(); defer io::close(&s)!; let ciphertext = box.2; let h = memio::fixed(ciphertext); chachapoly::xinit(&s, &h, key, box.1, additional...); let plaintext = ciphertext; io::readall(&s, plaintext)!; if (chachapoly::verify(&s, box.0) is errors::invalid) { bytes::zero(plaintext); return errors::invalid; }; return plaintext; }; // Compares two slices and returns true if they are equal. Comparison is done // in constant time, meaning that, if the slices have equal length, the time it // takes depends only on the length of the slices and not the content. export fn compare(a: []u8, b: []u8) bool = { if (len(a) != len(b)) { return false; }; return math::eqslice(a, b) == 1; }; // TODO: Add additional entry-points which provide a finer degree of control // over buffer usage. hare-0.24.2/crypto/bigint/000077500000000000000000000000001464473310100153155ustar00rootroot00000000000000hare-0.24.2/crypto/bigint/+test/000077500000000000000000000000001464473310100163475ustar00rootroot00000000000000hare-0.24.2/crypto/bigint/+test/arithm_test.ha000066400000000000000000000041511464473310100212050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; @test fn add() void = { let result: [4]u8 = [0...]; let bx = fromhex("002132a0"); defer free(bx); let by = fromhex("00ff3201"); defer free(by); let carry = add(bx, by, 0); assert(carry == 0); decode(result, bx); assert(bytes::equal([0x00, 0x21, 0x32, 0xa0], result)); let carry = add(bx, by, 1); assert(carry == 0); decode(result, bx); assert(bytes::equal([0x01, 0x20, 0x64, 0xa1], result)); }; @test fn muladd_small() void = { const mod = fromhex("0100"); defer free(mod); let x = fromhex("0100"); defer free(x); muladd_small(x, 3, mod); assert(equalshex(x, "03")); const mod = fromhex("1000000000"); defer free(mod); let x = fromhexmod("0000000001", mod); defer free(x); muladd_small(x, 27, mod); assert(equalshex(x, "8000001b")); }; @test fn mulacc() void = { let d = fromhex("0000000000000000"); defer free(d); let a = fromhex("0010"); defer free(a); let b = fromhex("0014"); defer free(b); mulacc(d, a, b); assert(equalshex(d, "0140")); mulacc(d, a, b); assert(equalshex(d, "0280")); }; @test fn rshift() void = { let x = fromhex("1020304050"); defer free(x); rshift(x, 1); assert(equalshex(x, "0810182028")); let x = fromhex("00"); defer free(x); rshift(x, 1); assert(equalshex(x, "")); }; @test fn reduce() void = { let m = fromhex("87654321"); defer free(m); let a = fromhex("1234"); defer free(a); let x = fromhex("00000000"); defer free(x); reduce(x, a, m); assert(equalshex(x, "1234")); let a = fromhex("0123456789abcdef"); defer free(a); let x = fromhex("00000000"); defer free(x); reduce(x, a, m); assert(equalshex(x, "14786ead")); }; @test fn modpow() void = { let m = fromhex("87654321"); defer free(m); let x = fromhexmod("00f03202", m); defer free(x); let e: [_]u8 = [0x00, 0x00, 0xc1, 0xf4]; const m0i = ninv31(m[1]); let tmp: [10]word = [0...]; modpow(x, e, m, m0i, tmp); assert(equalshex(x, "3de073fc")); let x = fromhexmod("00f03202", m); defer free(x); let tmp: [20]word = [0...]; modpow(x, e, m, m0i, tmp); assert(equalshex(x, "3de073fc")); }; hare-0.24.2/crypto/bigint/+test/encoding_test.ha000066400000000000000000000053241464473310100215120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; @test fn encode() void = { const decoded: [12]u8 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; let result: [12]u8 = [0...]; let buf: [5]word = [0...]; encode(buf, decoded); decode(result, buf); assert(bytes::equal(result, decoded)); }; @test fn encodebigger() void = { const decoded: [25]u8 = [ 0x8c, 0x99, 0xc4, 0x51, 0x53, 0x75, 0x86, 0x20, 0x73, 0x02, 0x2a, 0x08, 0xf6, 0x01, 0xcd, 0x8a, 0xc8, 0x39, 0xa8, 0xb3, 0x95, 0xb4, 0x27, 0xa1, 0xbb, ]; let result: [25]u8 = [0...]; let buf: []word = alloc([0...], encodelen(decoded)); defer free(buf); encode(buf, decoded); decode(result, buf); assert(bytes::equal(result, decoded)); }; @test fn decodebigger() void = { const encoded: [_]word = [ 0x32, // only 50 effective bits 0x7fffffff, 0x0007ffff, 0x7fffffff, ]; let result: [8]u8 = [0xaa...]; decode(result, encoded); assert(bytes::equal(result, [0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); }; @test fn encmoddec() void = { const input: [4]u8 = [0, 0, 0, 10]; let mod = fromhex("00190000"); defer free(mod); let resultbuf: []word = alloc([0...], encodelen(input)); defer free(resultbuf); let result: [4]u8 = [0...]; let ret = encodemod(resultbuf[..], input, mod); decode(result[..], resultbuf); assert(ret == 1); assert(bytes::equal(result, input)); const input: [4]u8 = [0, 25, 0, 0]; let ret = encodemod(resultbuf[..], input, mod); assert(ret == 0); assert(iszero(resultbuf) == 1); const input: [4]u8 = [0, 26, 0, 0]; let ret = encodemod(resultbuf[..], input, mod); assert(ret == 0); assert(iszero(resultbuf) == 1); }; @test fn encreddec() void = { const input: [4]u8 = [0, 0, 0, 0x0a]; let mod = fromhex("190000"); defer free(mod); let resultbuf: []word = alloc([0...], encodelen(input)); defer free(resultbuf); let result: [4]u8 = [0...]; encodereduce(resultbuf, input, mod); decode(result, resultbuf); assert(bytes::equal(result, input)); const input: [4]u8 = [0, 0x19, 0, 0]; let resultbuf: []word = alloc([0...], encodelen(input)); defer free(resultbuf); encodereduce(resultbuf, input, mod); decode(result, resultbuf); assert(iszero(resultbuf) == 1); const input: [4]u8 = [0x24, 0x17, 0x01, 0x05]; let resultbuf: []word = alloc([0...], encodelen(input)); defer free(resultbuf); encodereduce(resultbuf, input, mod); decode(result, resultbuf); assert(bytes::equal(result, [0x00, 0x0e, 0x01, 0x05])); }; @test fn word_countbits() void = { assert(word_countbits(0) == 0); assert(word_countbits(1) == 1); assert(word_countbits(2) == 2); assert(word_countbits(4) == 3); assert(word_countbits(7) == 3); assert(word_countbits(8) == 4); assert(word_countbits(1131) == 11); }; hare-0.24.2/crypto/bigint/+test/monty_test.ha000066400000000000000000000017221464473310100210700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn montyencode() void = { let m = fromhex("0010000061"); let x = fromhexmod("0000010064", m); defer free(x); defer free(m); const m0i = ninv31(m[1]); tomonty(x, m); frommonty(x, m, m0i); assert(equalshex(x, "010064")); }; @test fn montymul() void = { let m = fromhex("10000061"); defer free(m); let x = fromhexmod("00000123", m); defer free(x); let y = fromhexmod("000003cf", m); defer free(y); let d = fromhexmod("00000000", m); defer free(d); const m0i = ninv31(m[1]); tomonty(x, m); tomonty(y, m); montymul(d, x, y, m, m0i); frommonty(d, m, m0i); assert(equalshex(d, "04544d")); let d = fromhexmod("00000000", m); defer free(d); let x = fromhexmod("0f98b7cf", m); defer free(x); let y = fromhexmod("04216b9c", m); defer free(y); tomonty(x, m); tomonty(y, m); montymul(d, x, y, m, m0i); frommonty(d, m, m0i); assert(equalshex(d, "0d031f49")); }; hare-0.24.2/crypto/bigint/+test/utils.ha000066400000000000000000000024231464473310100200220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::hex; // The caller must free the result. export fn fromhex(h: str) []word = { let n: []u8 = hex::decodestr(h)!; defer free(n); let i: []word = alloc([0...], encodelen(n)); encode(i, n); return i; }; // 'h' must be lower than 'm' export fn fromhexmod(h: str, m: []word) []word = { let r = fromhex(h); r[0] = m[0]; return r; }; // The caller must free the result. export fn tohex(x: []word) str = { let buf: []u8 = alloc([0...], (len(x) - 1) * size(word)); defer free(buf); decode(buf, x); let i = 0z; for (i < len(buf); i += 1) { if (buf[i] != 0) { break; }; }; return hex::encodestr(buf[i..]); }; export fn equalshex(x: []word, h: str) bool = { let result = tohex(x); defer free(result); return result == h; }; @test fn iszero() void = { let x = fromhex("210032a0"); defer free(x); let y = fromhex("00000000"); defer free(y); assert(iszero(x) == 0); assert(iszero(y) == 1); }; @test fn zero() void = { let w: [4]word = [0xffffffff...]; // set effective word len to 2 words. const elen = countbits(w[1..3]); w[0] = elen; zero(w[..3], elen); // check if zero does not overwrite more or less than elen assert(w[0] == elen); assert(w[3] == 0xffffffff); }; hare-0.24.2/crypto/bigint/README000066400000000000000000000026151464473310100162010ustar00rootroot00000000000000Bigint provides constant time operations on big integers. This module is limited in scope, therefore the user must exercise caution and read the documentation carefully to avoid misuse. Restrictions apply to the compatibility of differently-sized big integers, and some functions require an uneven modulo. A big integer is an array of [[word]] and must be encoded using [[encode]], [[encodemod]] or [[encodereduce]]. See [[encodelen]] on how to calculate the required size of the array. The big integer will also store its announced bit length, i.e. the number of bits that are actually used to store its value; and the effective word length, i.e. the number of words that are actually used to store the value. The value may be decoded back to its byte format by [[decode]]. Repeated modular multiplication is supported via montgomery multiplication. See [[tomonty]] and [[frommonty]] on how to convert from and back to this format and [[montymul]] for the actual multiplication operation. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/bigint/arithm.ha000066400000000000000000000337251464473310100171250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::math::*; // Adds 'b' to 'a', if 'ctl' is 1. If 'ctl' is 0, the result will be discarded. // Returns the carry, if the addition overflows. // // 'a' and 'b' must have the same effective word length. export fn add(a: []word, b: const []word, ctl: u32) u32 = { const l = ewordlen(a); assert(equ32(l, ewordlen(b)) == 1); let carry: u32 = 0; for (let i = 1z; i <= l; i += 1) { const n: u32 = a[i] + b[i] + carry; carry = n >> WORD_BITSZ; a[i] = muxu32(ctl, n & WORD_BITMASK, a[i]): word; }; return carry; }; // Subtracts 'b' from 'a', if 'ctl' is 1. If 'ctl' is 0, the result will be // discared. Returns the carry, if the subtraction overflows. // // 'a' and 'b' must be of the same effective word length. export fn sub(a: []word, b: const []word, do: u32) u32 = { const l = ewordlen(a); assert(equ32(l, ewordlen(b)) == 1); let carry: u32 = 0; for (let i = 1z; i <= l; i += 1) { let n: u32 = a[i] - b[i] - carry; carry = n >> WORD_BITSZ; a[i] = muxu32(do, n & WORD_BITMASK, a[i]): word; }; return carry; }; // Decrements 1 from an odd integer 'x'. export fn decrodd(x: []word) void = { assert(isodd(x)); x[1] ^= 1; }; // Right-shift an integer 'x' by 'count'. The shift amount must be less than // [[WORD_BITSZ]]. export fn rshift(x: []word, count: word) void = { assert(ltu32(count, WORD_BITSZ) == 1); const l = ewordlen(x); if (l == 0) { return; }; let r = x[1] >> count; for (let i = 2z; i <= l; i += 1) { const w = x[i]; x[i - 1] = (w << (WORD_BITSZ - count) | r) & WORD_BITMASK; r = w >> count; }; x[l] = r; }; // Multiply 'x' by 2^WORD_BITSZ and then add integer 'z', modulo 'm'. This // function assumes that 'x' and 'm' have the same announced bit length, and the // announced bit length of 'm' matches its true bit length. // // 'x' and 'm' may not refer to the same array. // // This function runs in constant time for a given announced bit length of 'x' // and 'm'. fn muladd_small(x: []word, z: word, m: const []word) void = { assert(&x[0] != &m[0], "'x' and 'm' may not refer to the same array"); let hi: u32 = 0; // We can test on the modulus bit length since we accept to leak that // length. const m_bitlen = m[0]; if (m_bitlen == 0) { return; }; if (m_bitlen <= WORD_BITSZ) { hi = x[1] >> 1; const lo = (x[1] << WORD_BITSZ) | z; x[1] = divu32(hi, lo, m[1]).1: word; return; }; let mlen = ewordlen(m); let mblr = m_bitlen & WORD_BITSZ: word; // Principle: we estimate the quotient (x*2^31+z)/m by // doing a 64/32 division with the high words. // // Let: // w = 2^31 // a = (w*a0 + a1) * w^N + a2 // b = b0 * w^N + b2 // such that: // 0 <= a0 < w // 0 <= a1 < w // 0 <= a2 < w^N // w/2 <= b0 < w // 0 <= b2 < w^N // a < w*b // I.e. the two top words of a are a0:a1, the top word of b is // b0, we ensured that b0 is "full" (high bit set), and a is // such that the quotient q = a/b fits on one word (0 <= q < w). // // If a = b*q + r (with 0 <= r < q), we can estimate q by // doing an Euclidean division on the top words: // a0*w+a1 = b0*u + v (with 0 <= v < b0) // Then the following holds: // 0 <= u <= w // u-2 <= q <= u let a0: u32 = 0, a1: u32 = 0, b0: u32 = 0; hi = x[mlen]; if (mblr == 0) { a0 = x[mlen]; x[2..mlen+1] = x[1..mlen]; x[1] = z; a1 = x[mlen]; b0 = m[mlen]; } else { a0 = ((x[mlen] << (WORD_BITSZ: word - mblr)) | (x[mlen - 1] >> mblr)) & WORD_BITMASK; x[2..mlen+1] = x[1..mlen]; x[1] = z; a1 = ((x[mlen] << (WORD_BITSZ: word - mblr)) | (x[mlen - 1] >> mblr)) & WORD_BITMASK; b0 = ((m[mlen] << (WORD_BITSZ: word - mblr)) | (m[mlen - 1] >> mblr)) & WORD_BITMASK; }; // We estimate a divisor q. If the quotient returned by br_div() // is g: // -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF. // -- Otherwise: // -- if g == 0 then we set q = 0; // -- otherwise, we set q = g - 1. // The properties described above then ensure that the true // quotient is q-1, q or q+1. // // Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We // must adjust the parameters to br_div() accordingly. // const (g, _) = divu32(a0 >> 1, a1 | (a0 << 31), b0); const q = muxu32(equ32(a0, b0), WORD_BITMASK, muxu32(equ32(g, 0), 0, g - 1)); // We subtract q*m from x (with the extra high word of value 'hi'). // Since q may be off by 1 (in either direction), we may have to // add or subtract m afterwards. // // The 'tb' flag will be true (1) at the end of the loop if the // result is greater than or equal to the modulus (not counting // 'hi' or the carry). let cc: u32 = 0; let tb: u32 = 1; for (let u = 1z; u <= mlen; u += 1) { const mw = m[u]; const zl = mul31(mw, q) + cc; cc = (zl >> WORD_BITSZ): word; const zw = zl: word & WORD_BITMASK; const xw = x[u]; let nxw = xw - zw; cc += nxw >> WORD_BITSZ; nxw &= WORD_BITMASK; x[u] = nxw; tb = muxu32(equ32(nxw, mw), tb, gtu32(nxw, mw)); }; // If we underestimated q, then either cc < hi (one extra bit // beyond the top array word), or cc == hi and tb is true (no // extra bit, but the result is not lower than the modulus). In // these cases we must subtract m once. // // Otherwise, we may have overestimated, which will show as // cc > hi (thus a negative result). Correction is adding m once. const over = gtu32(cc, hi); const under = ~over & (tb | ltu32(cc, hi)); add(x, m, over); sub(x, m, under); }; // Multiply two 31-bit integers, with a 62-bit result. This default // implementation assumes that the basic multiplication operator // yields constant-time code. fn mul31(x: u32, y: u32) u64 = x: u64 * y: u64; fn mul31_lo(x: u32, y: u32) u32 = (x: u32 * y: u32) & 0x7FFFFFFF; // Calculate "m0i" which is equal to -(1/m0) mod 2^WORD_BITSZ, where m0 is the // least significant value word of m: []word. fn ninv31(m0: u32) u32 = { let y: u32 = 2 - m0; y *= 2 - y * m0; y *= 2 - y * m0; y *= 2 - y * m0; y *= 2 - y * m0; return muxu32(m0 & 1, -y, 0) & 0x7FFFFFFF; }; // Calculates "m0i" which is equal to -(1/'m0') mod 2^WORD_BITSZ. 'm0' is the // the first significant word of a big integer, which is the word at index 1. export fn ninv(m0: word) word = ninv31(m0); // Compute 'd' + 'a' * 'b', result in 'd'. The initial announced bit length of // 'd' MUST match that of 'a'. The 'd' array MUST be large enough to accommodate // the full result, plus (possibly) an extra word. The resulting announced bit // length of 'd' will be the sum of the announced bit lengths of 'a' and 'b' // (therefore, it may be larger than the actual bit length of the numerical // result). // // 'a' and 'b' may be the same array. 'd' must be disjoint from both 'a' and // 'b'. export fn mulacc(d: []word, a: const []word, b: const []word) void = { assert(&a[0] != &d[0] && &b[0] != &d[0]); const alen = ewordlen(a); const blen = ewordlen(b); // We want to add the two bit lengths, but these are encoded, // which requires some extra care. const dl: u32 = (a[0] & WORD_BITSZ) + (b[0] & WORD_BITSZ); const dh: u32 = (a[0] >> WORD_SHIFT) + (b[0] >> WORD_SHIFT); d[0] = (dh << WORD_SHIFT) + dl + (~(dl - WORD_BITSZ): u32 >> 31); for (let u = 0z; u < blen; u += 1) { // Carry always fits on 31 bits; we want to keep it in a // 32-bit register on 32-bit architectures (on a 64-bit // architecture, cast down from 64 to 32 bits means // clearing the high bits, which is not free; on a 32-bit // architecture, the same operation really means ignoring // the top register, which has negative or zero cost). const f: u32 = b[1 + u]; let cc: u64 = 0; // TODO #if BR_64 u32 for (let v = 0z; v < alen; v += 1) { let z: u64 = d[1 + u + v]: u64 + mul31(f, a[1 + v]) + cc; cc = z >> WORD_BITSZ; d[1 + u + v] = z: word & WORD_BITMASK; }; d[1 + u + alen] = cc: word; }; }; // Reduce an integer 'a' modulo another 'm'. The result is written in 'x' and // its announced bit length is set to be equal to that of 'm'. // // 'x' must be distinct from 'a' and 'm'. // // This function runs in constant time for given announced bit lengths of 'a' // and 'm'. export fn reduce(x: []word, a: const []word, m: const []word) void = { assert(&x[0] != &a[0] && &x[0] != &m[0]); const m_bitlen = m[0]; const mlen = ewordlen(m); x[0] = m_bitlen; if (m_bitlen == 0) { return; }; // If the source is shorter, then simply copy all words from a[] // and zero out the upper words. const a_bitlen = a[0]; const alen = ewordlen(a); if (a_bitlen < m_bitlen) { x[1..1 + alen] = a[1..1 + alen]; for (let u = alen; u < mlen; u += 1) { x[u + 1] = 0; }; return; }; // The source length is at least equal to that of the modulus. // We must thus copy N-1 words, and input the remaining words // one by one. x[1..mlen] = a[2 + (alen - mlen).. 1 + mlen]; x[mlen] = 0; for (let u = 1 + alen - mlen; u > 0; u -= 1) { muladd_small(x, a[u], m); }; }; // Copies 'src' to 'dest' if ctl is 1. The length of 'src' must match the length // of 'dest'. fn ccopyword(ctl: u32, dest: []word, src: const []word) void = { for (let i = 0z; i < len(dest); i += 1) { const x = src[i]; const y = dest[i]; dest[i] = muxu32(ctl, x, y); }; }; // Compute a modular exponentiation. 'x' must be an integer modulo 'm' (same // announced bit length, lower value). 'm' must be odd. The exponent is in // big-endian unsigned notation, over len(e) bytes. The 'm0i' parameter is equal // to -(1/m0) mod 2^31, where m0 is the least significant value word of 'm' // (this works only if 'm' is an odd integer). See [[ninv]] on how to get this // value. The 'tmp' array is used for temporaries and MUST be large enough to // accommodate at least two temporary values with the same size as 'm' // (including the leading 'bit length' word). If there is room for more // temporaries, then this function may use the extra room for window-based // optimisation, resulting in faster computations. // // Returned value is 1 on success, 0 on error. An error is reported if the // provided 'tmp' array is too short. export fn modpow( x: []word, e: const []u8, m: const []word, m0i: u32, tmp: []word, ) u32 = { assert(m[1] & 1 == 1, "'m' must be odd"); assert(equ32(x[0], m[0]) == 1); // Get modulus size. let mwlen = ewordlen(m) + 1; const tmplen = (mwlen & 1) + mwlen; let t1 = tmp[..tmplen]; let t2 = tmp[tmplen..]; const twlen = len(tmp); if (twlen < (mwlen << 1)) { return 0; }; // Compute possible window size, with a maximum of 5 bits. // When the window has size 1 bit, we use a specific code // that requires only two temporaries. Otherwise, for a // window of k bits, we need 2^k+1 temporaries. let win_len: word = 5; for (win_len > 1; win_len -= 1) { if (((1u32 << win_len: u32) + 1) * mwlen <= twlen) { break; }; }; // Everything is done in Montgomery representation. tomonty(x, m); // Compute window contents. If the window has size one bit only, // then t2 is set to x; otherwise, t2[0] is left untouched, and // t2[k] is set to x^k (for k >= 1). if (win_len == 1) { t2[..mwlen] = x[..mwlen]; } else { let base = t2[mwlen..]; base[..mwlen] = x[..mwlen]; for (let u = 2z; u < (1u << win_len: uint); u += 1) { montymul(base[mwlen..2 * mwlen], base[..mwlen], x, m, m0i); base = base[mwlen..]; }; }; // We need to set x to 1, in Montgomery representation. This can // be done efficiently by setting the high word to 1, then doing // one word-sized shift. zero(x, m[0]); x[ewordlen(m)] = 1; muladd_small(x, 0, m); let elen = len(e); let e = e[..]; // We process bits from most to least significant. At each // loop iteration, we have acc_len bits in acc. let acc: word = 0; let acc_len = 0i; for (acc_len > 0 || elen > 0) { // Get the next bits. let k = win_len; if (acc_len: u32 < win_len) { if (elen > 0) { acc = (acc << 8) | e[0]; e = e[1..]; elen -= 1; acc_len += 8; } else { k = acc_len: u32; }; }; let bits: u32 = (acc >> (acc_len: u32 - k: u32)) & ((1u32 << k: u32) - 1u32); acc_len -= k: int; // We could get exactly k bits. Compute k squarings. for (let i = 0z; i < k: size; i += 1) { montymul(t1, x, x, m, m0i); // memcpy(x, t1, mlen); x[..mwlen] = t1[..mwlen]; }; // Window lookup: we want to set t2 to the window // lookup value, assuming the bits are non-zero. If // the window length is 1 bit only, then t2 is // already set; otherwise, we do a constant-time lookup. if (win_len > 1) { zero(t2, m[0]); let base = t2[mwlen..]; for (let u = 1u32; u < (1 << k): size; u += 1) { let mask: u32 = -equ32(u, bits); for (let v = 1z; v < mwlen; v += 1) { t2[v] |= mask & base[v]; }; base = base[mwlen..]; }; }; // Multiply with the looked-up value. We keep the // product only if the exponent bits are not all-zero. montymul(t1, x, t2, m, m0i); ccopyword(nequ32(bits, 0), x[..mwlen], t1[..mwlen]); }; // Convert back from Montgomery representation, and exit. frommonty(x, m, m0i); return 1; }; hare-0.24.2/crypto/bigint/encoding.ha000066400000000000000000000213451464473310100174220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::math::*; // Minimal required words to encode 'x' into an []word. To statically allocate // resources, following expression may be used: // // ((number_of_bits + WORD_BITSZ - 1) / WORD_BITSZ) + 1 export fn encodelen(x: []u8) size = { return (((len(x) * 8) + WORD_BITSZ - 1) / WORD_BITSZ) + 1; }; // Encode 'src' from its big-endian unsigned encoding into the internal // representation. The caller must make sure that 'dest' has enough space to // store 'src'. See [[encodelen]] for how to calculate the required size. // // This function runs in constant time for given 'src' length. export fn encode(dest: []word, src: const []u8) void = { let acc: u32 = 0; let accbits: u32 = 0; let didx: size = 1; for (let i = len(src) - 1; i < len(src); i -= 1) { acc |= (src[i] << accbits); accbits += 8; if (accbits >= WORD_BITSZ) { dest[didx] = (acc & WORD_BITMASK): word; accbits -= WORD_BITSZ; acc = src[i] >> (8 - accbits); didx += 1; }; }; dest[didx] = acc: word; dest[0] = countbits(dest[1..didx + 1]): word; }; // Get the announced bit length of 'n' in encoded form. fn countbits(n: const []word) u32 = { let tw: u32 = 0; let twk: u32 = 0; for (let i = len(n) - 1; i < len(n); i -= 1) { const c = equ32(tw, 0); const w = n[i]; tw = muxu32(c, w, tw); twk = muxu32(c, i: u32, twk); }; return (twk << WORD_SHIFT) + word_countbits(tw); }; // Counts the number of bits until including the highest bit set to 1. fn word_countbits(x: u32) u32 = { let k: u32 = nequ32(x, 0); let c: u32 = 0; c = gtu32(x, 0xffff); x = muxu32(c, x >> 16, x); k += c << 4; c = gtu32(x, 0x00ff); x = muxu32(c, x >> 8, x); k += c << 3; c = gtu32(x, 0x000f); x = muxu32(c, x >> 4, x); k += c << 2; c = gtu32(x, 0x0003); x = muxu32(c, x >> 2, x); k += c << 1; k += gtu32(x, 0x0001); return k; }; // Get the encoded bit length of a word. fn ebitlen(x: const []word) u32 = { return x[0]; }; // Get the effective word lenght of 'x'. The effective wordlen is the number of // words that are used to represent the actual value. Eg. the number 7 will have // an effective word length of 1, no matter of len(x). The first element // containing the encoded word len is not added to the result. export fn ewordlen(x: const []word) u32 = { return (x[0] + WORD_BITSZ) >> WORD_SHIFT; }; // Decode 'src' into a big-endian unsigned byte array. The caller must ensure // that 'dest' has enough space to store the decoded value. See [[decodelen]] on // how to determine the required length. export fn decode(dest: []u8, src: const []word) void = { let acc: u64 = 0; let accbits: u64 = 0; let sidx: size = 1; let sz = ewordlen(src); for (let i = len(dest) - 1; i < len(dest); i -= 1) { if (accbits < 8) { if (sidx <= sz) { acc |= ((src[sidx]: u64) << accbits: u64): u64; sidx += 1; }; accbits += WORD_BITSZ; }; dest[i] = acc: u8; acc >>= 8; accbits -= 8; }; }; // Returns the number of bytes required to store a big integer given by 'src'. // // For static allocation following expression may be used: // // ((len(src) - 1) * WORD_BITSZ + 7) / 8 export fn decodelen(src: const []word) size = { return ((len(src) - 1) * WORD_BITSZ + 7) / 8; }; // Encodes an integer from its big-endian unsigned encoding. 'src' must be lower // than 'm'. If not 'dest' will be set to 0. 'dest' will have the announced bit // length of 'm' after decoding. // // The return value is 1 if the decoded value fits within 'm' or 0 otherwise. // // This function runs in constant time for a given 'src' length and announced // bit length of m, independent of whether the value fits within 'm' or not. export fn encodemod(dest: []word, src: const []u8, m: const []word) u32 = { // Two-pass algorithm: in the first pass, we determine whether the // value fits; in the second pass, we do the actual write. // // During the first pass, 'r' contains the comparison result so // far: // 0x00000000 value is equal to the modulus // 0x00000001 value is greater than the modulus // 0xFFFFFFFF value is lower than the modulus // // Since we iterate starting with the least significant bytes (at // the end of src[]), each new comparison overrides the previous // except when the comparison yields 0 (equal). // // During the second pass, 'r' is either 0xFFFFFFFF (value fits) // or 0x00000000 (value does not fit). // // We must iterate over all bytes of the source, _and_ possibly // some extra virtual bytes (with value 0) so as to cover the // complete modulus as well. We also add 4 such extra bytes beyond // the modulus length because it then guarantees that no accumulated // partial word remains to be processed. let mlen = 0z, tlen = 0z; mlen = ewordlen(m); tlen = mlen << (WORD_SHIFT - 3); // mlen in bytes if (tlen < len(src)) { tlen = len(src); }; tlen += 4; let r: u32 = 0; for (let pass = 0z; pass < 2; pass += 1) { let v: size = 1; let acc: u32 = 0, acc_len: u32 = 0; for (let u = 0z; u < tlen; u += 1) { // inner loop is similar to encode until the mlen check let b: u32 = 0; if (u < len(src)) { b = src[len(src) - 1 - u]; }; acc |= (b << acc_len); acc_len += 8; if (acc_len >= WORD_BITSZ) { const xw: u32 = acc & WORD_BITMASK; acc_len -= WORD_BITSZ; acc = b >> (8 - acc_len); if (v <= mlen) { if (pass == 1) { dest[v] = (r & xw): word; } else { let cc = cmpu32(xw, m[v]: u32): u32; r = muxu32(equ32(cc, 0), r, cc); }; } else { if (pass == 0) { r = muxu32(equ32(xw, 0), r, 1); }; }; v += 1; }; }; // When we reach this point at the end of the first pass: // r is either 0, 1 or -1; we want to set r to 0 if it // is equal to 0 or 1, and leave it to -1 otherwise. // // When we reach this point at the end of the second pass: // r is either 0 or -1; we want to leave that value // untouched. This is a subcase of the previous. r >>= 1; r |= (r << 1); }; dest[0] = m[0]; return r & 1; }; // Encode an integer from its big-endian unsigned representation, and reduce it // modulo the provided modulus 'm'. The announced bit length of the result is // set to be equal to that of the modulus. // // 'dest' must be distinct from 'm'. export fn encodereduce(dest: []word, src: const []u8, m: const []word) void = { assert(&dest[0] != &m[0], "'dest' and 'm' must be distinct"); // Get the encoded bit length. const m_ebitlen = m[0]; // Special case for an invalid (null) modulus. if (m_ebitlen == 0) { dest[0] = 0; return; }; zero(dest, m_ebitlen); // First decode directly as many bytes as possible. This requires // computing the actual bit length. let m_rbitlen = m_ebitlen >> WORD_SHIFT; m_rbitlen = (m_ebitlen & WORD_BITSZ) + (m_rbitlen << WORD_SHIFT) - m_rbitlen; const mblen: size = (m_rbitlen + 7) >> 3; let k: size = mblen - 1; if (k >= len(src)) { encode(dest, src); dest[0] = m_ebitlen; return; }; encode(dest, src[..k]); dest[0] = m_ebitlen; // Input remaining bytes, using 31-bit words. let acc: word = 0; let acc_len: word = 0; for (k < len(src)) { const v = src[k]; k += 1; if (acc_len >= 23) { acc_len -= 23; acc <<= (8 - acc_len); acc |= v >> acc_len; muladd_small(dest, acc, m); acc = v & (0xFF >> (8 - acc_len)); } else { acc = (acc << 8) | v; acc_len += 8; }; }; // We may have some bits accumulated. We then perform a shift to // be able to inject these bits as a full 31-bit word. if (acc_len != 0) { acc = (acc | (dest[1] << acc_len)) & WORD_BITMASK; rshift(dest, WORD_BITSZ - acc_len); muladd_small(dest, acc, m); }; }; hare-0.24.2/crypto/bigint/monty.ha000066400000000000000000000130571464473310100170030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::math::*; // Convert a modular integer to Montgomery representation. The integer 'x' must // be lower than 'm', but with the same announced bit length. export fn tomonty(x: []word, m: const []word) void = { assert(equ32(x[0], m[0]) == 1); for (let k: u32 = ewordlen(m); k > 0; k -= 1) { muladd_small(x, 0, m); }; }; // Convert a modular integer back from Montgomery representation. The integer // 'x' must be less than 'm', but with the same announced bit length. The 'm0i' // parameter is equal to -(1/m0) mod 2^32, where m0 is the least significant // value word of 'm' (this works only if 'm' is an odd integer). See [[ninv]] // for how to get this value. export fn frommonty(x: []word, m: const []word, m0i: word) void = { assert(equ32(x[0], m[0]) == 1); const mlen = ewordlen(m); for (let u = 0z; u < mlen; u += 1) { const f: u32 = mul31_lo(x[1], m0i); let cc: u64 = 0; for (let v = 0z; v < mlen; v += 1) { const z: u64 = x[v + 1]: u64 + mul31(f, m[v + 1]) + cc; cc = z >> 31; if (v != 0) { x[v] = z: word & WORD_BITMASK; }; }; x[mlen] = cc: u32; }; // We may have to do an extra subtraction, but only if the // value in x[] is indeed greater than or equal to that of m[], // which is why we must do two calls (first call computes the // carry, second call performs the subtraction only if the carry // is 0). sub(x, m, notu32(sub(x, m, 0))); }; // Compute a modular Montgomery multiplication. 'd' is filled with the value of // 'x'*'y'/R modulo 'm' (where R is the Montgomery factor). The array 'd' must // be distinct from 'x', 'y' and 'm'. 'x' and 'y' must be numerically lower than // 'm'. 'x' and 'y' may be the same array. The 'm0i' parameter is equal to // -(1/m0) mod 2^32, where m0 is the least significant value word of 'm' (this // works only if 'm' is an odd integer). See [[ninv]] for how to get this value. export fn montymul( d: []word, x: const []word, y: const []word, m: const []word, m0i: u32 ) void = { // Each outer loop iteration computes: // d <- (d + xu*y + f*m) / 2^31 // We have xu <= 2^31-1 and f <= 2^31-1. // Thus, if d <= 2*m-1 on input, then: // 2*m-1 + 2*(2^31-1)*m <= (2^32)*m-1 // and the new d value is less than 2*m. // // We represent d over 31-bit words, with an extra word 'dh' // which can thus be only 0 or 1. let v: size = 0; const mlen = ewordlen(m); const len4 = mlen & ~3: size; zero(d, m[0]); let dh: u32 = 0; for (let u = 0z; u < mlen; u += 1) { // The carry for each operation fits on 32 bits: // d[v+1] <= 2^31-1 // xu*y[v+1] <= (2^31-1)*(2^31-1) // f*m[v+1] <= (2^31-1)*(2^31-1) // r <= 2^32-1 // (2^31-1) + 2*(2^31-1)*(2^31-1) + (2^32-1) = 2^63 - 2^31 // After division by 2^31, the new r is then at most 2^32-1 // // Using a 32-bit carry has performance benefits on 32-bit // systems; however, on 64-bit architectures, we prefer to // keep the carry (r) in a 64-bit register, thus avoiding some // "clear high bits" operations. const xu: u32 = x[u + 1]; const f: u32 = mul31_lo((d[1] + mul31_lo(x[u + 1], y[1])), m0i); let r: u64 = 0; // TODO if !BR_64 u32 v = 0; for (v < len4; v += 4) { let z: u64 = d[v + 1]: u64 + mul31(xu, y[v + 1]) + mul31(f, m[v + 1]) + r; r = z >> 31; d[v + 0] = z: u32 & 0x7FFFFFFF; z = d[v + 2]: u64 + mul31(xu, y[v + 2]) + mul31(f, m[v + 2]) + r; r = z >> 31; d[v + 1] = z: u32 & 0x7FFFFFFF; z = d[v + 3]: u64 + mul31(xu, y[v + 3]) + mul31(f, m[v + 3]) + r; r = z >> 31; d[v + 2] = z: u32 & 0x7FFFFFFF; z = d[v + 4]: u64 + mul31(xu, y[v + 4]) + mul31(f, m[v + 4]) + r; r = z >> 31; d[v + 3] = z: u32 & 0x7FFFFFFF; }; for (v < mlen; v += 1) { const z: u64 = d[v + 1]: u64 + mul31(xu, y[v + 1]) + mul31(f, m[v + 1]) + r; r = z >> 31; d[v] = z: u32 & 0x7FFFFFFF; }; // Since the new dh can only be 0 or 1, the addition of // the old dh with the carry MUST fit on 32 bits, and // thus can be done into dh itself. dh += r: u32; d[mlen] = dh & 0x7FFFFFFF; dh >>= 31; }; // We must write back the bit length because it was overwritten in // the loop (not overwriting it would require a test in the loop, // which would yield bigger and slower code). d[0] = m[0]; // d[] may still be greater than m[] at that point; notably, the // 'dh' word may be non-zero. sub(d, m, nequ32(dh, 0) | notu32(sub(d, m, 0))); }; hare-0.24.2/crypto/bigint/types.ha000066400000000000000000000012371464473310100167760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A big integer is stored in an array of words. The first word holds // information about the effective size of the big integer. The subsequend // words encode the value in little-endian order. The [[WORD_BITMASK]] masks the // bits that are actually used to store the value in each word. export type word = u32; // Number of bits that are used for storing the value in a word. export def WORD_BITSZ: u32 = 31; // Bitmask for bits that are used for storing the value in a word. export def WORD_BITMASK: word = 0x7fffffff; // full_bitlen(word) == 1 << WORD_SHIFT def WORD_SHIFT: u32 = 5; hare-0.24.2/crypto/bigint/util.ha000066400000000000000000000034521464473310100166100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use bytes; // Sets encoded bitlen of 'x' to 'ebitlen' and then zeroes its effective words. export fn zero(x: []word, ebitlen: word) void = { x[0] = ebitlen; const ewordlen = ewordlen(x); bytes::zero((x: *[*]u8)[size(word)..(1 + ewordlen) * size(word)]); }; // Checks whether the effective words of 'x' are zero. Returns 1 if so, or 0 // otherwise. export fn iszero(x: []word) u32 = { let z: u32 = 0; for (let i = ewordlen(x); i > 0; i -= 1) { z |= x[i]; }; return ~(z | -(z: i32): u32) >> 31; }; fn isodd(x: []word) bool = { return x[1] & 1 == 1; }; hare-0.24.2/crypto/blake2b/000077500000000000000000000000001464473310100153435ustar00rootroot00000000000000hare-0.24.2/crypto/blake2b/+test.ha000066400000000000000000000101171464473310100167070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::hex; use fmt; use hash; use io; use memio; use strings; @test fn blake2b() void = { for (let i = 0z; i < len(vectors); i += 1) { let key = hex::decodestr(vectors[i].key)!; defer free(key); let out = hex::decodestr(vectors[i].out)!; defer free(out); let in = hex::decodestr(vectors[i].in)!; defer free(in); let blake = blake2b(key, len(out)); defer hash::close(&blake); hash::write(&blake, in); let sum: []u8 = alloc([], len(out)); defer free(sum); for (let i = 0z; i < len(out); i += 1) { append(sum, 0); }; hash::sum(&blake, sum); let out = memio::dynamic(); defer io::close(&out)!; let enc = hex::newencoder(&out); io::write(&enc, sum)!; assert(memio::string(&out)! == vectors[i].out); }; const vectors = [ ("", "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"), ("abc", "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"), ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "7285ff3e8bd768d69be62b3bf18765a325917fa9744ac2f582a20850bc2b1141ed1b3e4528595acc90772bdf2d37dc8a47130b44f33a02e8730e5ad8e166e888"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "ce741ac5930fe346811175c5227bb7bfcd47f42612fae46c0809514f9e0e3a11ee1773287147cdeaeedff50709aa716341fe65240f4ad6777d6bfaf9726e5e52"), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", "ecd6fbbe1c86782edf2a00d008787f8ef3afb5fd6e9f93a1c9ec121feb3aca3935c64f57b75e73e2b3754c10d4cc5638e32a3dfc55cf259a7e57ad3222ff70f3"), ("'Life is too short to run proprietary software' - Bdale Garbee", "62d6301236854494d2303c4cf35e56a26b00eedeb603cc975bbcb8208cfb8ca5b13ffe5ff7d38beffe2a75aad5386eac1b3f3896fe4ba4bee70abbc4523f1808"), ("'The central enemy of reliability is complexity.' - Geer et al", "855016890590a1e470d01154fcd4acd23ba4a64699a1ef0375c2b6227c6a928768589788316e8eb6008811027ffde1f6ce16bd6ad7f002888fbf45461a2e1a12"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; let blake = blake2b([], 64); defer hash::close(&blake); hash::write(&blake, strings::toutf8(vector.0)); static let sum: [64]u8 = [0...]; assert(len(sum) >= hash::sz(&blake)); hash::sum(&blake, sum); let hex = memio::dynamic(); defer io::close(&hex)!; for (let j = 0z; j < len(sum); j += 1) { fmt::fprintf(&hex, "{:.2x}", sum[j])!; }; if (memio::string(&hex)! != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, memio::string(&hex)!, vector.1)!; abort(); }; }; }; @test fn blake2b_multiple_writes() void = { let in: [_]u8 = [ 0x20, 0x00, 0x00, 0x00, 0x75, 0x96, 0xf8, 0xa3, 0x2f, 0xb7, 0xcf, 0x12, 0x83, 0x05, 0x0f, 0xbd, 0x4b, 0x48, 0x97, 0x70, 0xe1, 0x67, 0x90, 0x1d, 0xc2, 0x02, 0x63, 0x31, 0x48, 0x2c, 0xda, 0xdc, 0xf4, 0x37, 0x3b, 0xa1, 0x33, 0x10, 0xb8, 0xb9, 0x91, 0x1e, 0xc5, 0xc8, 0xb7, 0x45, 0xcc, 0x3c, 0x45, 0x26, 0xf4, 0x95, 0xf1, 0x79, 0x1b, 0x0b, 0xe4, 0x5f, 0xed, 0xdf, 0x5e, 0xbf, 0x61, 0xef, 0xa6, 0x21, 0x12, 0x4b, 0x8a, 0x81, 0x65, 0xe8, 0x92, 0x3d, 0xe4, 0x99, 0x66, 0x76, 0x4e, 0x68, 0x46, 0xfe, 0x22, 0x5b, 0xce, 0xce, 0x80, 0x86, 0x72, 0xa5, 0x0d, 0x23, 0x45, 0xd3, 0x27, 0x42, 0x4b, 0xf7, 0x34, 0x31, 0xd5, 0x17, 0x8d, 0x48, 0x87, 0x6a, 0x1b, 0x52, 0x32, 0xc8, 0x86, 0x7b, 0x42, 0x57, 0xc7, 0xd0, 0xe1, 0x27, 0x79, 0x53, 0xd6, 0xf6, 0xb1, 0xcb, 0x3f, 0x9b, 0xed, 0x28, 0xb4, ]; let expected: [_]u8 = [ 0xf8, 0x9a, 0x3a, 0x42, 0x54, 0x89, 0x3a, 0xe7, 0x48, 0xa7, 0x76, 0xb8, 0x45, 0x1e, 0x15, 0x5c, 0x13, 0x56, 0x33, 0xac, 0x23, 0x30, 0xb6, 0xb7, 0x74, 0xe7, 0x93, 0x7e, 0x29, 0xfa, 0xcd, 0x3e, ]; let result: [32]u8 = [0...]; let h = blake2b([], len(result)); defer hash::close(&h); hash::write(&h, in[..4]); hash::write(&h, in[4..]); hash::sum(&h, result[..]); assert(bytes::equal(expected, result)); }; hare-0.24.2/crypto/blake2b/README000066400000000000000000000012021464473310100162160ustar00rootroot00000000000000This module implements the blake2b password hashing algorithm, bug-for-bug compatible with the classic OpenBSD implementation. It is not recommended except in cases of backwards-compatibility with legacy systems. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/blake2b/blake2b.ha000066400000000000000000000107071464473310100171640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math; use endian; use hash; use io; def R1: int = 32; def R2: int = 24; def R3: int = 16; def R4: int = 63; def r: u64 = 12; def BSZ: size = 128; const iv: [8]u64 = [ 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179, ]; const sigma: [12][16]u8 = [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], ]; export type digest = struct { hash::hash, h: [8]u64, tlow: u64, thigh: u64, block: [BSZ]u8, blocklen: size, }; const blake2b_vtable: io::vtable = io::vtable { writer = &write, closer = &close, ... }; // Creates a [[hash::hash]] which computes a BLAKE2b hash with a given key and a // given hash size. The size must be between 1 and 64, inclusive. If this // function is used to hash sensitive information, the caller should call // [[hash::close]] to erase sensitive data from memory after use; if not, the // use of [[hash::close]] is optional. This function does not provide reset // functionality and calling [[hash::reset]] on it will terminate execution. export fn blake2b(key: []u8, sz: size) digest = { assert(1 <= sz); assert(sz <= 64); assert(len(key) <= 64); let h = iv; h[0] ^= 0x01010000 ^ (len(key) << 8) ^ sz; let keyblock: [BSZ]u8 = [0...]; keyblock[..len(key)] = key; return digest { stream = &blake2b_vtable, sum = &sum, sz = sz, h = h, tlow = 0, thigh = 0, block = keyblock, blocklen = if (len(key) > 0) BSZ else 0, ... }; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { if (len(buf) == 0) return 0z; let h = st: *digest; let length = len(buf); let buf = buf[..]; for (h.blocklen + len(buf) > BSZ) { const n = BSZ - h.blocklen; h.block[h.blocklen..h.blocklen + n] = buf[..n]; buf = buf[n..]; h.tlow += BSZ; if (h.tlow < n: u64) h.thigh += 1; compress(&h.h, &h.block, h.tlow, h.thigh, false); h.blocklen = 0; }; h.block[h.blocklen..h.blocklen + len(buf)] = buf; h.blocklen += len(buf); return length; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *digest; let copy = *h; let h = © defer hash::close(h); h.tlow += h.blocklen; if (h.tlow < h.blocklen: u64) h.thigh += 1; // Padding let tmp: [BSZ]u8 = [0...]; h.block[h.blocklen..BSZ] = tmp[..BSZ - h.blocklen]; h.blocklen = BSZ; compress(&h.h, &h.block, h.tlow, h.thigh, true); for (let i = 0z; i < h.sz / 8; i += 1) { endian::leputu64(buf[i * 8..i * 8 + 8], h.h[i]); }; }; // Compression function F fn compress(h: *[8]u64, b: *[BSZ]u8, tlow: u64, thigh: u64, f: bool) void = { let v: [16]u64 = [0...]; v[..8] = h[..]; v[8..] = iv; v[12] ^= tlow; v[13] ^= thigh; if (f) v[14] = ~v[14]; let m: [16]u64 = [0...]; for (let i = 0z; i < len(m); i += 1) { m[i] = endian::legetu64(b[i * 8..i * 8 + 8]); }; for (let i = 0u64; i < r; i += 1) { const s = &sigma[i]; mix(&v, 0, 4, 8, 12, m[s[0]], m[s[1]]); mix(&v, 1, 5, 9, 13, m[s[2]], m[s[3]]); mix(&v, 2, 6, 10, 14, m[s[4]], m[s[5]]); mix(&v, 3, 7, 11, 15, m[s[6]], m[s[7]]); mix(&v, 0, 5, 10, 15, m[s[8]], m[s[9]]); mix(&v, 1, 6, 11, 12, m[s[10]], m[s[11]]); mix(&v, 2, 7, 8, 13, m[s[12]], m[s[13]]); mix(&v, 3, 4, 9, 14, m[s[14]], m[s[15]]); }; for (let i = 0; i < 8; i += 1) { h[i] ^= v[i] ^ v[i + 8]; }; }; // Mixing function G fn mix(v: *[16]u64, a: size, b: size, c: size, d: size, x: u64, y: u64) void = { v[a] = v[a] + v[b] + x; v[d] = math::rotr64(v[d] ^ v[a], R1); v[c] = v[c] + v[d]; v[b] = math::rotr64(v[b] ^ v[c], R2); v[a] = v[a] + v[b] + y; v[d] = math::rotr64(v[d] ^ v[a], R3); v[c] = v[c] + v[d]; v[b] = math::rotr64(v[b] ^ v[c], R4); }; fn close(stream: *io::stream) (void | io::error) = { let s = stream: *digest; bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); bytes::zero(s.block); }; hare-0.24.2/crypto/blake2b/vectors+test.ha000066400000000000000000007604061464473310100203320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors type vector = struct { in: str, key: str, out: str, }; // From https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2-kat.json const vectors: [_]vector = [ vector { in = "", key = "", out = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", }, vector { in = "00", key = "", out = "2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b", }, vector { in = "0001", key = "", out = "1c08798dc641aba9dee435e22519a4729a09b2bfe0ff00ef2dcd8ed6f8a07d15eaf4aee52bbf18ab5608a6190f70b90486c8a7d4873710b1115d3debbb4327b5", }, vector { in = "000102", key = "", out = "40a374727302d9a4769c17b5f409ff32f58aa24ff122d7603e4fda1509e919d4107a52c57570a6d94e50967aea573b11f86f473f537565c66f7039830a85d186", }, vector { in = "00010203", key = "", out = "77ddf4b14425eb3d053c1e84e3469d92c4cd910ed20f92035e0c99d8a7a86cecaf69f9663c20a7aa230bc82f60d22fb4a00b09d3eb8fc65ef547fe63c8d3ddce", }, vector { in = "0001020304", key = "", out = "cbaa0ba7d482b1f301109ae41051991a3289bc1198005af226c5e4f103b66579f461361044c8ba3439ff12c515fb29c52161b7eb9c2837b76a5dc33f7cb2e2e8", }, vector { in = "000102030405", key = "", out = "f95d45cf69af5c2023bdb505821e62e85d7caedf7beda12c0248775b0c88205eeb35af3a90816f6608ce7dd44ec28db1140614e1ddebf3aa9cd1843e0fad2c36", }, vector { in = "00010203040506", key = "", out = "8f945ba700f2530e5c2a7df7d5dce0f83f9efc78c073fe71ae1f88204a4fd1cf70a073f5d1f942ed623aa16e90a871246c90c45b621b3401a5ddbd9df6264165", }, vector { in = "0001020304050607", key = "", out = "e998e0dc03ec30eb99bb6bfaaf6618acc620320d7220b3af2b23d112d8e9cb1262f3c0d60d183b1ee7f096d12dae42c958418600214d04f5ed6f5e718be35566", }, vector { in = "000102030405060708", key = "", out = "6a9a090c61b3410aede7ec9138146ceb2c69662f460c3da53c6515c1eb31f41ca3d280e567882f95cf664a94147d78f42cfc714a40d22ef19470e053493508a2", }, vector { in = "00010203040506070809", key = "", out = "29102511d749db3cc9b4e335fa1f5e8faca8421d558f6a3f3321d50d044a248ba595cfc3efd3d2adc97334da732413f5cbf4751c362ba1d53862ac1e8dabeee8", }, vector { in = "000102030405060708090a", key = "", out = "c97a4779d47e6f77729b5917d0138abb35980ab641bd73a8859eb1ac98c05362ed7d608f2e9587d6ba9e271d343125d40d933a8ed04ec1fe75ec407c7a53c34e", }, vector { in = "000102030405060708090a0b", key = "", out = "10f0dc91b9f845fb95fad6860e6ce1adfa002c7fc327116d44d047cd7d5870d772bb12b5fac00e02b08ac2a0174d0446c36ab35f14ca31894cd61c78c849b48a", }, vector { in = "000102030405060708090a0b0c", key = "", out = "dea9101cac62b8f6a3c650f90eea5bfae2653a4eafd63a6d1f0f132db9e4f2b1b662432ec85b17bcac41e775637881f6aab38dd66dcbd080f0990a7a6e9854fe", }, vector { in = "000102030405060708090a0b0c0d", key = "", out = "441ffaa08cd79dff4afc9b9e5b5620eec086730c25f661b1d6fbfbd1cec3148dd72258c65641f2fca5eb155fadbcabb13c6e21dc11faf72c2a281b7d56145f19", }, vector { in = "000102030405060708090a0b0c0d0e", key = "", out = "444b240fe3ed86d0e2ef4ce7d851edde22155582aa0914797b726cd058b6f45932e0e129516876527b1dd88fc66d7119f4ab3bed93a61a0e2d2d2aeac336d958", }, vector { in = "000102030405060708090a0b0c0d0e0f", key = "", out = "bfbabbef45554ccfa0dc83752a19cc35d5920956b301d558d772282bc867009168e9e98606bb5ba73a385de5749228c925a85019b71f72fe29b3cd37ca52efe6", }, vector { in = "000102030405060708090a0b0c0d0e0f10", key = "", out = "9c4d0c3e1cdbbf485bec86f41cec7c98373f0e09f392849aaa229ebfbf397b22085529cb7ef39f9c7c2222a514182b1effaa178cc3687b1b2b6cbcb6fdeb96f8", }, vector { in = "000102030405060708090a0b0c0d0e0f1011", key = "", out = "477176b3bfcbadd7657c23c24625e4d0d674d1868f006006398af97aa41877c8e70d3d14c3bbc9bbcdcea801bd0e1599af1f3eec67405170f4e26c964a57a8b7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112", key = "", out = "a78c490eda3173bb3f10dee52f110fb1c08e0302230b85ddd7c11257d92de148785ef00c039c0bb8eb9808a35b2d8c080f572859714c9d4069c5bcaf090e898e", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213", key = "", out = "58d023397beb5b4145cb2255b07d74290b36d9fd1e594afbd8eea47c205b2efbfe6f46190faf95af504ab072e36f6c85d767a321bfd7f22687a4abbf494a689c", }, vector { in = "000102030405060708090a0b0c0d0e0f1011121314", key = "", out = "4001ec74d5a46fd29c2c3cdbe5d1b9f20e51a941be98d2a4e1e2fbf866a672121db6f81a514cfd10e7358d571bdba48e4ce708b9d124894bc0b5ed554935f73a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415", key = "", out = "ccd1b22dab6511225d2401ea2d8625d206a12473cc732b615e5640cefff0a4adf971b0e827a619e0a80f5db9ccd0962329010d07e34a2064e731c520817b2183", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213141516", key = "", out = "b4a0a9e3574edb9e1e72aa31e39cc5f30dbf943f8cabc408449654a39131e66d718a18819143e3ea96b4a1895988a1c0056cf2b6e04f9ac19d657383c2910c44", }, vector { in = "000102030405060708090a0b0c0d0e0f1011121314151617", key = "", out = "447becab16630608d39f4f058b16f7af95b85a76aa0fa7cea2b80755fb76e9c804f2ca78f02643c915fbf2fce5e19de86000de03b18861815a83126071f8a37b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718", key = "", out = "54e6dab9977380a5665822db93374eda528d9beb626f9b94027071cb26675e112b4a7fec941ee60a81e4d2ea3ff7bc52cfc45dfbfe735a1c646b2cf6d6a49b62", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213141516171819", key = "", out = "3ea62625949e3646704d7e3c906f82f6c028f540f5f72a794b0c57bf97b7649bfeb90b01d3ca3e829de21b3826e6f87014d3c77350cb5a15ff5d468a81bec160", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a", key = "", out = "213cfe145c54a33691569980e5938c8883a46d84d149c8ff1a67cd287b4d49c6da69d3a035443db085983d0efe63706bd5b6f15a7da459e8d50a19093db55e80", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b", key = "", out = "5716c4a38f38db104e494a0a27cbe89a26a6bb6f499ec01c8c01aa7cb88497e75148cd6eee12a7168b6f78ab74e4be749251a1a74c38c86d6129177e2889e0b6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c", key = "", out = "030460a98bdf9ff17cd96404f28fc304f2b7c04eaade53677fd28f788ca22186b8bc80dd21d17f8549c711aff0e514e19d4e15f5990252a03e082f28dc2052f6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d", key = "", out = "19e7f1ccee88a10672333e390cf22013a8c734c6cb9eab41f17c3c8032a2e4aca0569ea36f0860c7a1af28fa476840d66011168859334a9e4ef9cc2e61a0e29e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e", key = "", out = "29f8b8c78c80f2fcb4bdf7825ed90a70d625ff785d262677e250c04f3720c888d03f8045e4edf3f5285bd39d928a10a7d0a5df00b8484ac2868142a1e8bea351", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", key = "", out = "5c52920a7263e39d57920ca0cb752ac6d79a04fef8a7a216a1ecb7115ce06d89fd7d735bd6f4272555dba22c2d1c96e6352322c62c5630fde0f4777a76c3de2c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", key = "", out = "83b098f262251bf660064a9d3511ce7687a09e6dfbb878299c30e93dfb43a9314db9a600337db26ebeedaf2256a96dabe9b29e7573ad11c3523d874dde5be7ed", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021", key = "", out = "9447d98aa5c9331352f43d3e56d0a9a9f9581865998e2885cc56dd0a0bd5a7b50595bd10f7529bcd31f37dc16a1465d594079667da2a3fcb70401498837cedeb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", key = "", out = "867732f2feeb23893097561ac710a4bff453be9cfbedba8ba324f9d312a82d732e1b83b829fdcd177b882ca0c1bf544b223be529924a246a63cf059bfdc50a1b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223", key = "", out = "f15ab26d4cdfcf56e196bb6ba170a8fccc414de9285afd98a3d3cf2fb88fcbc0f19832ac433a5b2cc2392a4ce34332987d8d2c2bef6c3466138db0c6e42fa47b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324", key = "", out = "2813516d68ed4a08b39d648aa6aacd81e9d655ecd5f0c13556c60fdf0d333ea38464b36c02baccd746e9575e96c63014f074ae34a0a25b320f0fbedd6acf7665", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425", key = "", out = "d3259afca8a48962fa892e145acf547f26923ae8d4924c8a531581526b04b44c7af83c643ef5a0bc282d36f3fb04c84e28b351f40c74b69dc7840bc717b6f15f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526", key = "", out = "f14b061ae359fa31b989e30332bfe8de8cc8cdb568e14be214a2223b84caab7419549ecfcc96ce2acec119485d87d157d3a8734fc426597d64f36570ceaf224d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", key = "", out = "55e70b01d1fbf8b23b57fb62e26c2ce54f13f8fa2464e6eb98d16a6117026d8b90819012496d4071ebe2e59557ece3519a7aa45802f9615374877332b73490b3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728", key = "", out = "25261eb296971d6e4a71b2928e64839c67d422872bf9f3c31993615222de9f8f0b2c4be8548559b4b354e736416e3218d4e8a1e219a4a6d43e1a9a521d0e75fc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", key = "", out = "08307f347c41294e34bb54cb42b1522d22f824f7b6e5db50fda096798e181a8f026fa27b4ae45d52a62caf9d5198e24a4913c6671775b2d723c1239bfbf016d7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a", key = "", out = "1e5c62e7e9bfa1b118747a2de08b3ca10112af96a46e4b22c3fc06f9bfee4eb5c49e057a4a4886234324572576bb9b5ecfde0d99b0de4f98ec16e4d1b85fa947", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b", key = "", out = "c74a77395fb8bc126447454838e561e962853dc7eb49a1e3cb67c3d0851f3e39517be8c350ac910903d49cd2bfdf545c99316d0346170b739f0add5d533c2cfc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c", key = "", out = "0dd57b423cc01eb2861391eb886a0d17079b933fc76eb3fc08a19f8a74952cb68f6bcdc644f77370966e4d13e80560bcf082ef0479d48fbbab4df03b53a4e178", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d", key = "", out = "4d8dc3923edccdfce70072398b8a3da5c31fcb3ee3b645c85f717cbaeb4b673a19394425a585bfb464d92f1597d0b754d163f97ced343b25db5a70ef48ebb34f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e", key = "", out = "f0a50553e4dfb0c4e3e3d3ba82034857e3b1e50918f5b8a7d698e10d242b0fb544af6c92d0c3aaf9932220416117b4e78ecb8a8f430e13b82a5915290a5819c5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", key = "", out = "b15543f3f736086627cc5365e7e8988c2ef155c0fd4f428961b00d1526f04d6d6a658b4b8ed32c5d8621e7f4f8e8a933d9ecc9dd1b8333cbe28cfc37d9719e1c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", key = "", out = "7b4fa158e415fef023247264cbbe15d16d91a44424a8db707eb1e2033c30e9e1e7c8c0864595d2cb8c580eb47e9d16abbd7e44e824f7cedb7def57130e52cfe9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031", key = "", out = "60424ff23234c34dc9687ad502869372cc31a59380186bc2361c835d972f49666eb1ac69629de646f03f9b4db9e2ace093fbfdf8f20ab5f98541978be8ef549f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132", key = "", out = "7406018ce704d84f5eb9c79fea97da345699468a350ee0b2d0f3a4bf2070304ea862d72a51c57d3064947286f531e0eaf7563702262e6c724abf5ed8c8398d17", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233", key = "", out = "14ef5c6d647b3bd1e6e32006c231199810de5c4dc88e70240273b0ea18e651a3eb4f5ca3114b8a56716969c7cda27e0c8db832ad5e89a2dc6cb0adbe7d93abd1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334", key = "", out = "38cf6c24e3e08bcf1f6cf3d1b1f65b905239a3118033249e448113ec632ea6dc346feeb2571c38bd9a7398b2221280328002b23e1a45adaffe66d93f6564eaa2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435", key = "", out = "6cd7208a4bc7e7e56201bbba02a0f489cd384abe40afd4222f158b3d986ee72a54c50fb64fd4ed2530eda2c8af2928a0da6d4f830ae1c9db469dfd970f12a56f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536", key = "", out = "659858f0b5c9edab5b94fd732f6e6b17c51cc096104f09beb3afc3aa467c2ecf885c4c6541effa9023d3b5738ae5a14d867e15db06fe1f9d1127b77e1aabb516", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", key = "", out = "26cca0126f5d1a813c62e5c71001c046f9c92095704550be5873a495a999ad010a4f79491f24f286500adce1a137bc2084e4949f5b7294cefe51ecaff8e95cba", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738", key = "", out = "4147c1f55172788c5567c561feef876f621fff1ce87786b8467637e70dfbcd0dbdb6415cb600954ab9c04c0e457e625b407222c0fe1ae21b2143688ada94dc58", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839", key = "", out = "5b1bf154c62a8af6e93d35f18f7f90abb16a6ef0e8d1aecd118bf70167bab2af08935c6fdc0663ce74482d17a8e54b546d1c296631c65f3b522a515839d43d71", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a", key = "", out = "9f600419a4e8f4fb834c24b0f7fc13bf4e279d98e8a3c765ee934917403e3a66097182ea21453cb63ebbe8b73a9c2167596446438c57627f330badd4f569f7d6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b", key = "", out = "457ef6466a8924fd8011a34471a5a1ac8ccd9bd0d07a97414ac943021ce4b9e4b9c8db0a28f016ed43b1542481990022147b313e194671131e708dd43a3ed7dc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c", key = "", out = "9997b2194d9af6dfcb9143f41c0ed83d3a3f4388361103d38c2a49b280a581212715fd908d41c651f5c715ca38c0ce2830a37e00e508ced1bcdc320e5e4d1e2e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d", key = "", out = "5c6bbf16baa180f986bd40a1287ed4c549770e7284858fc47bc21ab95ebbf3374b4ee3fd9f2af60f3395221b2acc76f2d34c132954049f8a3a996f1e32ec84e5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e", key = "", out = "d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", key = "", out = "2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40", key = "", out = "fcbe8be7dcb49a32dbdf239459e26308b84dff1ea480df8d104eeff34b46fae98627b450c2267d48c0946a697c5b59531452ac0484f1c84e3a33d0c339bb2e28", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041", key = "", out = "a19093a6e3bcf5952f850f2030f69b9606f147f90b8baee3362da71d9f35b44ef9d8f0a7712ba1877fddcd2d8ea8f1e5a773d0b745d4725605983a2de901f803", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142", key = "", out = "3c2006423f73e268fa59d2920377eb29a4f9a8b462be15983ee3b85ae8a78e992633581a9099893b63db30241c34f643027dc878279af5850d7e2d4a2653073a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243", key = "", out = "d0f2f2e3787653f77cce2fa24835785bbd0c433fc779465a115149905a9dd1cb827a628506d457fcf124a0c2aef9ce2d2a0a0f63545570d8667ff9e2eba07334", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344", key = "", out = "78a9fc048e25c6dcb5de45667de8ffdd3a93711141d594e9fa62a959475da6075ea8f0916e84e45ad911b75467077ee52d2c9aebf4d58f20ce4a3a00458b05d4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445", key = "", out = "45813f441769ab6ed37d349ff6e72267d76ae6bb3e3c612ec05c6e02a12af5a37c918b52bf74267c3f6a3f183a8064ff84c07b193d08066789a01accdb6f9340", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546", key = "", out = "956da1c68d83a7b881e01b9a966c3c0bf27f68606a8b71d457bd016d4c41dd8a380c709a296cb4c6544792920fd788835771a07d4a16fb52ed48050331dc4c8b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454647", key = "", out = "df186c2dc09caa48e14e942f75de5ac1b7a21e4f9f072a5b371e09e07345b0740c76177b01278808fec025eded9822c122afd1c63e6f0ce2e32631041063145c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748", key = "", out = "87475640966a9fdcd6d3a3b5a2cca5c08f0d882b10243c0ec1bf3c6b1c37f2cd3212f19a057864477d5eaf8faed73f2937c768a0af415e84bbce6bd7de23b660", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849", key = "", out = "c3b573bbe10949a0fbd4ff884c446f2229b76902f9dfdbb8a0353da5c83ca14e8151bbaac82fd1576a009adc6f1935cf26edd4f1fb8da483e6c5cd9d8923adc3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a", key = "", out = "b09d8d0bba8a7286e43568f7907550e42036d674e3c8fc34d8ca46f771d6466b70fb605875f6a863c877d12f07063fdc2e90ccd459b1910dcd52d8f10b2b0a15", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b", key = "", out = "af3a22bf75b21abfb0acd54422ba1b7300a952eff02ebeb65b5c234471a98df32f4f9643ce1904108a168767924280bd76c83f8c82d9a79d9259b195362a2a04", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c", key = "", out = "bf4ff2221b7e6957a724cd964aa3d5d0d9941f540413752f4699d8101b3e537508bf09f8508b317736ffd265f2847aa7d84bd2d97569c49d632aed9945e5fa5e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", key = "", out = "9c6b6b78199b1bdacb4300e31479fa622a6b5bc80d4678a6078f88a8268cd7206a2799e8d4621a464ef6b43dd8adffe97caf221b22b6b8778b149a822aefbb09", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e", key = "", out = "890656f09c99d280b5ecb381f56427b813751bc652c7828078b23a4af83b4e3a61fdbac61f89bee84ea6bee760c047f25c6b0a201c69a38fd6fd971af18588bb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", key = "", out = "31a046f7882ffe6f83ce472e9a0701832ec7b3f76fbcfd1df60fe3ea48fde1651254247c3fd95e100f9172731e17fd5297c11f4bb328363ca361624a81af797c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50", key = "", out = "27a60b2d00e7a671d47d0aec2a686a0ac04b52f40ab6629028eb7d13f4baa99ac0fe46ee6c814944f2f4b4d20e9378e4847ea44c13178091e277b87ea7a55711", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051", key = "", out = "8b5ccef194162c1f19d68f91e0b0928f289ec5283720840c2f73d253111238dcfe94af2b59c2c1ca2591901a7bc060e7459b6c47df0f71701a35cc0aa831b5b6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152", key = "", out = "57ab6c4b2229aeb3b70476d803cd63812f107ce6da17fed9b17875e8f86c724f49e024cbf3a1b8b119c50357652b81879d2ade2d588b9e4f7cedba0e4644c9ee", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253", key = "", out = "0190a8dac320a739f322e15731aa140ddaf5bed294d5c82e54fef29f214e18aafaa84f8be99af62950266b8f901f15dd4c5d35516fc35b4cab2e96e4695bbe1c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354", key = "", out = "d14d7c4c415eeb0e10b159224bea127ebd84f9591c702a330f5bb7bb7aa44ea39de6ed01f18da7adf40cfb97c5d152c27528824b21e239526af8f36b214e0cfb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455", key = "", out = "be28c4be706970488fac7d29c3bd5c4e986085c4c3332f1f3fd30973db614164ba2f31a78875ffdc150325c88327a9443ed04fdfe5be93876d1628560c764a80", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556", key = "", out = "031da1069e3a2e9c3382e436ffd79df74b1ca6a8adb2deabe676ab45994cbc054f037d2f0eace858d32c14e2d1c8b46077308e3bdc2c1b53172ecf7a8c14e349", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354555657", key = "", out = "4665cef8ba4db4d0acb118f2987f0bb09f8f86aa445aa3d5fc9a8b346864787489e8fcecc125d17e9b56e12988eac5ecc7286883db0661b8ff05da2afff30fe4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758", key = "", out = "63b7032e5f930cc9939517f9e986816cfbec2be59b9568b13f2ead05bae7777cab620c6659404f7409e4199a3be5f7865aa7cbdf8c4253f7e8219b1bd5f46fea", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556575859", key = "", out = "9f09bf093a2b0ff8c2634b49e37f1b2135b447aa9144c9787dbfd92129316c99e88aab8a21fdef2372d1189aec500f95775f1f92bfb45545e4259fb9b7b02d14", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a", key = "", out = "f9f8493c68088807df7f6a2693d64ea59f03e9e05a223e68524ca32195a4734b654fcea4d2734c866cf95c889fb10c49159be2f5043dc98bb55e02ef7bdcb082", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b", key = "", out = "3c9a7359ab4febce07b20ac447b06a240b7fe1dae5439c49b60b5819f7812e4c172406c1aac316713cf0dded1038077258e2eff5b33913d9d95caeb4e6c6b970", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c", key = "", out = "ad6aab8084510e822cfce8625d62cf4de655f4763884c71e80bab9ac9d5318dba4a6033ed29084e65216c031606ca17615dcfe3ba11d26851ae0999ca6e232cf", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d", key = "", out = "156e9e6261374c9dc884f36e70f0fe1ab9297997b836fa7d170a9c9ebf575b881e7bcea44d6c0248d35597907154828955be19135852f9228815eca024a8adfb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e", key = "", out = "4215407633f4cca9b6788be93e6aa3d963c7d6ce4b147247099f46a3acb500a30038cb3e788c3d29f132ad844e80e9e99251f6db96acd8a091cfc770af53847b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f", key = "", out = "1c077e279de6548523502b6df800ffdab5e2c3e9442eb838f58c295f3b147cef9d701c41c321283f00c71affa0619310399126295b78dd4d1a74572ef9ed5135", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60", key = "", out = "f07a555f49fe481cf4cd0a87b71b82e4a95064d06677fdd90a0eb598877ba1c83d4677b393c3a3b6661c421f5b12cb99d20376ba7275c2f3a8f5a9b7821720da", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061", key = "", out = "b5911b380d20c7b04323e4026b38e200f534259233b581e02c1e3e2d8438d6c66d5a4eb201d5a8b75072c4ec29106334da70bc79521b0ced2cfd533f5ff84f95", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162", key = "", out = "01f070a09bae911296361f91aa0e8e0d09a7725478536d9d48c5fe1e5e7c3c5b9b9d6eb07796f6da57ae562a7d70e882e37adfde83f0c433c2cd363536bb22c8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263", key = "", out = "6f793eb4374a48b0775acaf9adcf8e45e54270c9475f004ad8d5973e2aca52747ff4ed04ae967275b9f9eb0e1ff75fb4f794fa8be9add7a41304868d103fab10", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364", key = "", out = "965f20f139765fcc4ce4ba3794675863cac24db472cd2b799d035bce3dbea502da7b524865f6b811d8c5828d3a889646fe64a380da1aa7c7044e9f245dced128", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465", key = "", out = "ec295b5783601244c30e4641e3b45be222c4dce77a58700f53bc8ec52a941690b4d0b087fb6fcb3f39832b9de8f75ec20bd43079811749cdc907edb94157d180", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566", key = "", out = "61c72f8ccc91dbb54ca6750bc489672de09faedb8fdd4f94ff2320909a303f5d5a98481c0bc1a625419fb4debfbf7f8a53bb07ec3d985e8ea11e72d559940780", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364656667", key = "", out = "afd8145b259eefc8d12620c3c5b03e1ed8fd2ccefe0365078c80fd42c1770e28b44948f27e65a1886690110db814397b68e43d80d1ba16dfa358e739c898cfa3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768", key = "", out = "552fc7893cf1ce933ada35c0da98844e41545e244c3157a1428d7b4c21f9cd7e4071aed77b7ca9f1c38fba32237412ef21a342742ec8324378f21e507fafdd88", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566676869", key = "", out = "467a33fbadf5ebc52596ef86aaaefc6faba8ee651b1ce04de368a03a5a9040ef2835e00adb09abb3fbd2bce818a2413d0b0253b5bda4fc5b2f6f85f3fd5b55f2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a", key = "", out = "22eff8e6dd5236f5f57d94ede874d6c9428e8f5d566f17cd6d1848cd752fe13c655cb10fbaaff76872f2bf2da99e15dc624075e1ec2f58a3f64072121838569e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b", key = "", out = "9cec6bbf62c4bce4138abae1cbec8dad31950444e90321b1347196834c114b864af3f3cc3508f83751ffb4eda7c84d140734bb4263c3625c00f04f4c8068981b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c", key = "", out = "a8b60fa4fc2442f6f1514ad7402626920cc7c2c9f72124b8cba8ee2cb7c4586f658a4410cffcc0ab88343955e094c6af0d20d0c714fb0a988f543f300f58d389", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d", key = "", out = "8271cc45dfa5e4170e847e8630b952cf9c2aa777d06f26a7585b8381f188dacc7337391cfcc94b053dc4ec29cc17f077870428f1ac23fddda165ef5a3f155f39", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e", key = "", out = "bf23c0c25c8060e4f6995f1623a3bebecaa96e308680000a8aa3cd56bb1a6da099e10d9231b37f4519b2efd2c24de72f31a5f19535241b4a59fa3c03ceb790e7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f", key = "", out = "877fd652c05281009c0a5250e7a3a671f8b18c108817fe4a874de22da8e45db11958a600c5f62e67d36cbf84474cf244a9c2b03a9fb9dc711cd1a2cab6f3fae0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70", key = "", out = "29df4d87ea444baf5bcdf5f4e41579e28a67de84149f06c03f110ea84f572a9f676addd04c4878f49c5c00accda441b1a387caceb2e993bb7a10cd8c2d6717e1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071", key = "", out = "710dacb166844639cd7b637c274209424e2449dc35d790bbfa4f76177054a36b3b76fac0ca6e61df1e687000678ac0746df75d0a3954897681fd393a155a1bb4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172", key = "", out = "c1d5f93b8dea1f2571babccbc01764541a0cda87e444d673c50966ca559c33354b3acb26e5d5781ffb28847a4b4754d77008c62a835835f500dea7c3b58bdae2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273", key = "", out = "a41e41271cdab8af4d72b104bfb2ad041ac4df14677da671d85640c4b187f50c2b66513c4619fbd5d5dc4fe65dd37b9042e9848dda556a504caa2b1c6afe4730", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374", key = "", out = "e7bcbacdc379c43d81ebadcb37781552fc1d753e8cf310d968392d06c91f1d64cc9e90ce1d22c32d277fc6cda433a4d442c762e9eacf2c259f32d64cf9da3a22", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475", key = "", out = "51755b4ac5456b13218a19c5b9242f57c4a981e4d4ecdce09a3193362b808a579345d4881c2607a56534dd7f21956aff72c2f4173a6e7b6cc2212ba0e3daee1f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576", key = "", out = "dcc2c4beb9c1f2607b786c20c631972347034c1cc02fcc7d02ff01099cfe1c6989840ac213923629113aa8bad713ccf0fe4ce13264fb32b8b0fe372da382544a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374757677", key = "", out = "3d55176acea4a7e3a65ffa9fb10a7a1767199cf077cee9f71532d67cd7c73c9f93cfc37ccdcc1fdef50aad46a504a650d298d597a3a9fa95c6c40cb71fa5e725", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778", key = "", out = "d07713c005de96dd21d2eb8bbeca66746ea51a31ae922a3e74864889540a48db27d7e4c90311638b224bf0201b501891754848113c266108d0adb13db71909c7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576777879", key = "", out = "58983c21433d950caa23e4bc18543b8e601c204318532152daf5e159a0cd1480183d29285c05f129cb0cc3164687928086ffe380158df1d394c6ac0d4288bca8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a", key = "", out = "8100a8dc528d2b682ab4250801ba33f02a3e94c54dac0ae1482aa21f51ef3a82f3807e6facb0aeb05947bf7aa2adcb034356f90fa4560ede02201a37e411ec1a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b", key = "", out = "07025f1bb6c784f3fe49de5c14b936a5acacacaab33f6ac4d0e00ab6a12483d6bec00b4fe67c7ca5cc508c2a53efb5bfa5398769d843ff0d9e8b14d36a01a77f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c", key = "", out = "ba6aefd972b6186e027a76273a4a723321a3f580cfa894da5a9ce8e721c828552c64dacee3a7fd2d743b5c35ad0c8efa71f8ce99bf96334710e2c2346e8f3c52", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d", key = "", out = "e0721e02517aedfa4e7e9ba503e025fd46e714566dc889a84cbfe56a55dfbe2fc4938ac4120588335deac8ef3fa229adc9647f54ad2e3472234f9b34efc46543", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e", key = "", out = "b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f", key = "", out = "2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80", key = "", out = "f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081", key = "", out = "df0a9d0c212843a6a934e3902b2dd30d17fba5f969d2030b12a546d8a6a45e80cf5635f071f0452e9c919275da99bed51eb1173c1af0518726b75b0ec3bae2b5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182", key = "", out = "a3eb6e6c7bf2fb8b28bfe8b15e15bb500f781ecc86f778c3a4e655fc5869bf2846a245d4e33b7b14436a17e63be79b36655c226a50ffbc7124207b0202342db5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283", key = "", out = "56d4cbcd070563426a017069425c2cd2ae540668287a5fb9dac432eb8ab1a353a30f2fe1f40d83333afe696a267795408a92fe7da07a0c1814cf77f36e105ee8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384", key = "", out = "e59b9987d428b3eda37d80abdb16cd2b0aef674c2b1dda4432ea91ee6c935c684b48b4428a8cc740e579a30deff35a803013820dd23f14ae1d8413b5c8672aec", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485", key = "", out = "cd9fcc99f99d4cc16d031900b2a736e1508db4b586814e6345857f354a70ccecb1df3b50a19adaf43c278efa423ff4bb6c523ec7fd7859b97b168a7ebff8467c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586", key = "", out = "0602185d8c3a78738b99164b8bc6ffb21c7debebbf806372e0da44d121545597b9c662a255dc31542cf995ecbe6a50fb5e6e0ee4ef240fe557eded1188087e86", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384858687", key = "", out = "c08afa5b927bf08097afc5fff9ca4e7800125c1f52f2af3553fa2b89e1e3015c4f87d5e0a48956ad31450b083dad147ffb5ec03434a26830cf37d103ab50c5da", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788", key = "", out = "36f1e1c11d6ef6bc3b536d505d544a871522c5c2a253067ec9933b6ec25464daf985525f5b9560a16d890259ac1bb5cc67c0c469cde133def000ea1d686f4f5d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586878889", key = "", out = "bf2ab2e2470f5438c3b689e66e7686fffa0cb1e1798ad3a86ff99075bf6138e33d9c0ce59afb24ac67a02af34428191a9a0a6041c07471b7c3b1a752d6fc0b8b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a", key = "", out = "d400601f9728ccc4c92342d9787d8d28ab323af375ca5624b4bb91d17271fbae862e413be73f1f68e615b8c5c391be0dbd9144746eb339ad541547ba9c468a17", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b", key = "", out = "79fe2fe157eb85a038abb8ebbc647731d2c83f51b0ac6ee14aa284cb6a3549a4dcceb300740a825f52f5fb30b03b8c4d8b0f4aa67a63f4a94e3303c4eda4c02b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c", key = "", out = "75351313b52a8529298d8c186b1768666dcca8595317d7a4816eb88c062020c0c8efc554bb341b64688db5ccafc35f3c3cd09d6564b36d7b04a248e146980d4b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d", key = "", out = "e3128b1d311d02179d7f25f97a5a8bee2cc8c86303644fcd664e157d1fef00f23e46f9a5e8e5c890ce565bb6abd4302ce06469d52a5bd53e1c5a54d04649dc03", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e", key = "", out = "c2382a72d2d3ace9d5933d00b60827ed380cda08d0ba5f6dd41e29ee6dbe8ecb9235f06be95d83b6816a2fb7a5ad47035e8a4b69a4884b99e4bece58cab25d44", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f", key = "", out = "6b1c69460bbd50ac2ed6f32e6e887cfed407d47dcf0aaa60387fe320d780bd03eab6d7baeb2a07d10cd552a300341354ea9a5f03183a623f92a2d4d9f00926af", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90", key = "", out = "6cda206c80cdc9c44ba990e0328c314f819b142d00630404c48c05dc76d1b00ce4d72fc6a48e1469ddef609412c364820854214b4869af090f00d3c1ba443e1b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091", key = "", out = "7ffc8c26fbd6a0f7a609e6e1939f6a9edf1b0b066641fb76c4f9602ed748d11602496b35355b1aa255850a509d2f8ee18c8f3e1d7dcbc37a136598f56a59ed17", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192", key = "", out = "70de1f08dd4e09d5fc151f17fc991a23abfc05104290d50468882efaf582b6ec2f14f577c0d68c3ad06626916e3c86e6daab6c53e5163e82b6bd0ce49fc0d8df", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293", key = "", out = "4f81935756ed35ee2058ee0c6a6110d6fac5cb6a4f46aa9411603f99965823b6da4838276c5c06bc7880e376d92758369ee7305bcec8d3cfd28ccabb7b4f0579", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394", key = "", out = "abcb61cb3683d18f27ad527908ed2d32a0426cb7bb4bf18061903a7dc42e7e76f982382304d18af8c80d91dd58dd47af76f8e2c36e28af2476b4bccf82e89fdf", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495", key = "", out = "02d261ad56a526331b643dd2186de9a82e72a58223cd1e723686c53d869b83b94632b7b647ab2afc0d522e29da3a5615b741d82852e0df41b66007dbcba90543", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596", key = "", out = "c5832741fa30c5436823015383d297ff4c4a5d7276c3f902122066e04be5431b1a85faf73b918434f9300963d1dea9e8ac3924ef490226edeea5f743e410669f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394959697", key = "", out = "cfaeab268cd075a5a6aed515023a032d54f2f2ff733ce0cbc78db51db4504d675923f82746d6594606ad5d67734b11a67cc6a468c2032e43ca1a94c6273a985e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798", key = "", out = "860850f92eb268272b67d133609bd64e34f61bf03f4c1738645c17fec818465d7ecd2be2907641130025fda79470ab731646e7f69440e8367ea76ac4cee8a1df", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596979899", key = "", out = "84b154ed29bbedefa648286839046f4b5aa34430e2d67f7496e4c39f2c7ea78995f69e1292200016f16ac3b37700e6c7e7861afc396b64a59a1dbf47a55c4bbc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a", key = "", out = "aeeec260a5d8eff5ccab8b95da435a63ed7a21ea7fc7559413fd617e33609f8c290e64bbacc528f6c080262288b0f0a3219be223c991bee92e72349593e67638", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b", key = "", out = "8ad78a9f26601d127e8d2f2f976e63d19a054a17dcf59e0f013ab54a6887bbdffde7aaae117e0fbf3271016595b9d9c712c01b2c53e9655a382bc4522e616645", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c", key = "", out = "8934159dade1ac74147dfa282c75954fcef443ef25f80dfe9fb6ea633b8545111d08b34ef43fff17026c7964f5deac6d2b3c29dacf2747f022df5967dfdc1a0a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d", key = "", out = "cd36dd0b240614cf2fa2b9e959679dcdd72ec0cd58a43da3790a92f6cdeb9e1e795e478a0a47d371100d340c5cedcdbbc9e68b3f460818e5bdff7b4cda4c2744", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e", key = "", out = "00df4e099b807137a85990f49d3a94315e5a5f7f7a6076b303e96b056fb93800111f479628e2f8db59aeb6ac70c3b61f51f9b46e80ffdeae25ebddb4af6cb4ee", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", key = "", out = "2b9c955e6caed4b7c9e246b86f9a1726e810c59d126cee66ed71bf015b83558a4b6d84d18dc3ff4620c2ffb722359fdef85ba0d4e2d22ecbe0ed784f99afe587", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0", key = "", out = "181df0a261a2f7d29ea5a15772715105d450a4b6c236f699f462d60ca76487feedfc9f5eb92df838e8fb5dc3694e84c5e0f4a10b761f506762be052c745a6ee8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1", key = "", out = "21fb203458bf3a7e9a80439f9a902899cd5de0139dfd56f7110c9dec8437b26bda63de2f565926d85edb1d6c6825669743dd9992653d13979544d5dc8228bfaa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2", key = "", out = "ef021f29c5ffb830e64b9aa9058dd660fd2fcb81c497a7e698bcfbf59de5ad4a86ff93c10a4b9d1ae5774725f9072dcde9e1f199bab91f8bff921864aa502eee", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", key = "", out = "b3cfda40526b7f1d37569bdfcdf911e5a6efe6b2ec90a0454c47b2c046bf130fc3b352b34df4813d48d33ab8e269b69b075676cb6d00a8dcf9e1f967ec191b2c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4", key = "", out = "b4c6c3b267071eefb9c8c72e0e2b941293641f8673cb70c1cc26ad1e73cf141755860ad19b34c2f34ed35bb52ec4507cc1fe59047743a5f0c6febde625e26091", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5", key = "", out = "57a34f2bcca60d4b85103b830c9d7952a416be5263ae429c9e5e53fe8590a8f78ec65a51109ea85dcdf7b6223f9f2b340539fad81923dbf8edabf95129e4dff6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6", key = "", out = "9cf46662fcd61a232277b685663b8b5da832dfd9a3b8ccfeec993ec6ac415ad07e048adfe414df272770dba867da5c1224c6fd0aa0c2187d426ac647e9887361", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7", key = "", out = "5ce1042ab4d542c2f9ee9d17262af8164098935bef173d0e18489b04841746cd2f2df866bd7da6e5ef9024c648023ec723ab9c62fd80285739d84f15d2ab515a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8", key = "", out = "8488396bd4a8729b7a473178f232dadf3f0f8e22678ba5a43e041e72da1e2cf82194c307207a54cb8156293339eaec693ff66bfcd5efc65e95e4ecaf54530abd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9", key = "", out = "f598da901c3835bca560779037dfde9f0c51dc61c0b760fc1522d7b470ee63f5bdc6498476e86049ad86e4e21af2854a984cc905427d2f17f66b1f41c3da6f61", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aa", key = "", out = "5f93269798cf02132107337660a8d7a177354c0212eb93e555e7c37a08aef3d8dce01217011cd965c04dd2c105f2e2b6cae5e4e6bcaf09dfbee3e0a6a6357c37", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaab", key = "", out = "0ecf581d47bac9230986faabd70c2f5b80e91066f0ec55a842937882286d2ca007bb4e973b0b091d52167ff7c4009c7ab4ad38fff1dceacdb7be81ef4a452952", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabac", key = "", out = "5aeca8abe1528582b2a307b4009585498a3d467ca6101cb0c5126f9976056e9ffc123cc20c302b2a737f492c75d21f01512c90ca0541dfa56e950a321dcb28d8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacad", key = "", out = "732fbf8f1cb2b8329263ede27858fe46f8d3354d376bcda0548e7ce1fa9dd11f85eb661fe950b543aa635ca4d3f04ede5b32d6b656e5ce1c44d35c4a6c56cff8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadae", key = "", out = "d5e938735d63788c80100aefd18648d18cf272f69f20ff24cfe2895c088ad08b0104da1672a4eb26fc52545cc7d7a01b266cf546c403c45bd129eb41bdd9200b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", key = "", out = "65a245b49352ee297d91af8c8be00528ac6e046dd83ac7bd465a98816dd68f3e00e1ae8f895327a7e9a8c9326598379a29c9fc91ec0c6eef08f3e2b216c11008", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0", key = "", out = "c95654b63019130ab45dd0fb4941b98aeb3af2a123913eca2ce99b3e97410a7bf8661cc7fbaa2bc1cf2b13113b1ed40a0118b88e5fffc3542759ea007ed4c58d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1", key = "", out = "1eb262f38fa494431f017dad44c0dfb69324ac032f04b657fc91a88647bb74760f24e7c956514f0cf002990b182c1642b9b2426e96a61187e4e012f00e217d84", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2", key = "", out = "3b955aeebfa5151ac1ab8e3f5cc1e3767084c842a575d36269836e97353d41622b731dddcd5f269550a3a5b87be1e90326340b6e0e62555815d9600597ac6ef9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3", key = "", out = "68289f6605473ba0e4f241baf7477a9885426a858f19ef2a18b0d40ef8e41282ed5526b519799e270f13881327918278755711071d8511fe963e3b5606aa3716", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4", key = "", out = "80a33787542612c38f6bcd7cd86cab460227509b1cbad5ec408a91413d51155a0476dadbf3a2518e4a6e77cc346622e347a469bf8baa5f04eb2d98705355d063", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5", key = "", out = "34629bc6d831391c4cdf8af1b4b7b6b8e8ee17cf98c70e5dd586cd99f14b11df945166236a9571e6d591bb83ee4d164d46f6b9d8ef86ff865a81bfb91b00424b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6", key = "", out = "8b7cc339163863bb4383e542b0ef0e7cf36b84ad932cdf5a80419ec9ad692e7a7e784d2c7cb3796a18b8f800035f3aa06c824100611120a7bdeb35618ccb81b7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7", key = "", out = "4f084e4939dd5a7f5a658fad58a18a15c25c32ec1c7fd5c5c6c3e892b3971aeaac308304ef17b1c47239ea4bb398b3fd6d4528d8de8e768ae0f1a5a5c6b5c297", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8", key = "", out = "48f407a1af5b8009b2051742e8cf5cd5656669e7d722ee8e7bd202060849442168d8facc117c012bfb7bf449d99befff6a34aea203f1d8d352722be5014ec818", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9", key = "", out = "a6aa82cd1e426f9a73bfa39a29037876114655b8c22d6d3ff8b638ae7dea6b17843e09e52eb66fa1e475e4a8a3de429b7d0f4a776fcb8bdc9b9fede7d52e815f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9ba", key = "", out = "5817027d6bdd00c5dd10ac593cd560372270775a18526d7e6f13872a2e20eab664625be7168ac4bd7c9e0ce7fc4099e0f48442e2c767191c6e1284e9b2ccea8c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babb", key = "", out = "08e41028340a45c74e4052b3a8d6389e22e043a1adab5e28d97619450d723469b620caa519b81c14523854f619fd3027e3847bd03276e60604a80ddb4de876d6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbc", key = "", out = "130b8420537eb07d72abda07c85acbd8b9a44f16321dd0422145f809673d30f2b5321326e2bff317ef3fef983c51c4f8ab24a325d298e34afce569a82555774c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbd", key = "", out = "ac49b844afaa012e31c474ca263648844fd2f6307992c2f752aca02c3828965175794deee2d2ee95c61cd284f6b5a2d75e2ef2b29ee8149e77fb81447b2fd04b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", key = "", out = "b9d7ca81cc60bb9578e44024e5a0a0be80f27336a6a9f4e53df3999cb191280b090e2ac2d29c5baad9d71415bdc129e69aa2667af6a7fd5e189fccdcee817340", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf", key = "", out = "a755e113386572c75ced61d719706070b9146048e42a9f8cd35667a088b42f08808abdf77e618abd959afc757379ca2c00bcc1a48390fa2bff618b1e0078a613", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0", key = "", out = "a73c7debed326f1c0db0795ee7d6e3946894b826b1f8101c56c823ba17168312e7f53fc7dbe52c3e11e69852c40485e2ef182477862ea6a34ec136e2dfeea6f4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1", key = "", out = "6cb8f9d52c56d82cac28f39ea1593e8bb2506293ac0d68376a1709b62a46df14a4ae64b2d8fab76733a1ced2d548e3f3c6fcb49d40c3d5808e449cd83d1c2aa2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2", key = "", out = "683fa2b2369a10162c1c1c7b24bc970ee67da220564f32203f625696c0352a0b9ad96624362d952d84463c1106a2dba7a092599884b35a0b89c8f1b6a9b5a61e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3", key = "", out = "aad9ad44610118b77d508aeb1bbcd1c1b7d0171397fb510a401bbc0ec34623670d86a2dc3c8f3ab5a2044df730256727545f0860ce21a1eac717dfc48f5d228e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4", key = "", out = "c42578de23b4c987d5e1ac4d689ed5de4b0417f9704bc6bce969fa13471585d62c2cb1212a944f397fc9ca2c3747c3beb694ec4c5be68828dda53ef43faec6c0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5", key = "", out = "470f00841ee8244e63ed2c7ea30e2e419897c197462ecccecf713b42a5065fff5914bc9b79affe8f6b657875e789ae213bd914cd35bd174d46e9d18bd843773d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6", key = "", out = "34fc4213730f47a5e9a3580f643e12945cfcb31bf206f6ad450ce528da3fa432e005d6b0ecce10dca7c5995f6aacc5150e1b009e19751e8309f8859531844374", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7", key = "", out = "fb3c1f0f56a56f8e316fdf5d853c8c872c39635d083634c3904fc3ac07d1b578e85ff0e480e92d44ade33b62e893ee32343e79ddf6ef292e89b582d312502314", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8", key = "", out = "c7c97fc65dd2b9e3d3d607d31598d3f84261e9919251e9c8e57bb5f829377d5f73eabbed55c6c381180f29ad02e5be797ffec7e57bdecbc50ad3d062f0993ab0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9", key = "", out = "a57a49cdbe67ae7d9f797bb5cc7efc2df07f4e1b15955f85dae74b76e2ecb85afb6cd9eeed8888d5ca3ec5ab65d27a7b19e578475760a045ac3c92e13a938e77", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9ca", key = "", out = "c7143fce9614a17fd653aeb140726dc9c3dbb1de6cc581b2726897ec24b7a50359ad492243be66d9edd8c933b5b80e0b91bb61ea98056006516976fae8d99a35", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacb", key = "", out = "65bb58d07f937e2d3c7e65385f9c54730b704105ccdb691f6e146d4ee8f6c086f49511035110a9ad6031fdceb943e0f9613bcb276dd40f0624ef0f924f809783", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcc", key = "", out = "e540277f683b1186dd3b5b3f61433396581a35feb12002be8c6a6231fc40ffa70f08081bc58b2d94f7649543614a435faa2d62110e13dabc7b86629b63af9c24", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd", key = "", out = "418500878c5fbcb584c432f4285e05e49f2e3e075399a0dbfcf874ebf8c03d02bf16bc6989d161c77ca0786b05053c6c709433712319192128835cf0b660595b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdce", key = "", out = "889090dbb1944bdc9433ee5ef1010c7a4a24a8e71ecea8e12a31318ce49dcab0aca5c3802334aab2cc84b14c6b9321fe586bf3f876f19cd406eb1127fb944801", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf", key = "", out = "53b6a28910aa92e27e536fb549cf9b9918791060898e0b9fe183577ff43b5e9c7689c745b32e412269837c31b89e6cc12bf76e13cad366b74ece48bb85fd09e9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0", key = "", out = "7c092080c6a80d672409d081d3d177106bcd63567785140719490950ae07ae8fcaabbaaab330cfbcf7374482c220af2eadeeb73dcbb35ed823344e144e7d4899", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1", key = "", out = "9ccde566d2400509181111f32dde4cd63209fe59a30c114546ad2776d889a41bad8fa1bb468cb2f9d42ca9928a7770fef8e8ba4d0c812d9a1e75c3d8d2ccd75a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2", key = "", out = "6e293bf5d03fe43977cfe3f57ccdb3ae282a85455dca33f37f4b74f8398cc612433d755cbec412f8f82a3bd3bc4a278f7ecd0dfa9bbdc40be7a787c8f159b2df", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3", key = "", out = "c56546fb2178456f336164c18b90deffc83ae2b5a3aca77b6884d36d2c1db39501b3e65e36c758c66e3188451fdb3515ee162c001f06c3e8cb573adf30f7a101", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4", key = "", out = "6f82f89f299ebca2fe014b59bffe1aa84e88b1915fe256afb646fd8448af2b8891a7fab37a4ea6f9a50e6c317039d8cf878f4c8e1a0dd464f0b4d6ff1c7ea853", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5", key = "", out = "2b8599ff9c3d6198637ad51e57d1998b0d75313fe2dd61a533c964a6dd9607c6f723e9452ce46e014b1c1d6de77ba5b88c914d1c597bf1eae13474b4290e89b2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6", key = "", out = "08bf346d38e1df06c8260edb1da75579275948d5c0a0aa9ed2886f8856de5417a156998758f5b17e52f101ca957a71137473dfd18d7d209c4c10d9233c93691d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7", key = "", out = "6df2156d773114d310b63db9ee5350d77e6bcf25b05fcd910f9b31bc42bb13fe8225ebcb2a23a62280777b6bf74e2cd0917c7640b43defe468cd1e18c943c66a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8", key = "", out = "7c7038bc13a91151828a5ba82b4a96040f258a4dfb1b1373f0d359168afb0517a20b28a12d3644046be66b8d08d8ae7f6a923ea1c00187c6d11dc502bac71305", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9", key = "", out = "bcd1b30d808fb739b987cbf154bea00da9d40380b861d4c1d6377122dadd61c0e59018b71941cfb62e00dcd70aeb9abf0473e80f0a7eca6b6dea246ab229dd2b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9da", key = "", out = "7ed4468d968530fe7ab2c33540b26d8c3bd3ed44b34fbe8c2a9d7f805b5ada0ea252eeade4fce97f89728ad85bc8bb2430b1bef2cddd32c8446e59b8e8ba3c67", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb", key = "", out = "6d30b7c6ce8a3236c0ca2f8d728b1088ca06983a8043e621d5dcf0c537d13b08791edeb01a3cf0943ec1c890ab6e29b146a236cd46bcb9d93bf516fb67c63fe5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc", key = "", out = "97fe03cef31438508911bded975980a66029305dc5e3fa8ad1b4fb22fcdf5a19a733320327d8f71ccf496cb3a44a77af56e3dde73d3a5f176896cc57c9a5ad99", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd", key = "", out = "785a9d0fbd21136dbce8fa7eafd63c9dad220052978416b31d9753eaa149097847ed9b30a65c70507eff01879149ed5cf0471d37798edc05abd56ad4a2cccb1d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcddde", key = "", out = "ad408d2abddfd37b3bf34794c1a3371d928ed7fc8d966225333584c5665817832a37c07f0dc7cb5aa874cd7d20fe8fab8eabcb9b33d2e0841f6e200960899d95", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf", key = "", out = "97668f745b6032fc815d9579322769dccd9501a5080029b8ae826befb6742331bd9f76efeb3e2b8e81a9786b282f5068a3a2424697a77c41876b7e753f4c7767", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0", key = "", out = "26bb985f47e7fee0cfd252d4ef96bed42b9c370c1c6a3e8c9eb04ef7f7818b833a0d1f043ebafb911dc779e02740a02a44d3a1ea45ed4ad55e686c927cafe97e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1", key = "", out = "5bfe2b1dcf7fe9b95088acedb575c19016c743b2e763bf5851ac407c9eda43715edfa48b4825492c5179593fff21351b76e8b7e034e4c53c79f61f29c479bd08", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2", key = "", out = "c76509ef72f4a6f9c9c40618ed52b2084f83502232e0ac8bdaf3264368e4d0180f6854c4abf4f6509c79caafc44cf3194afc57bd077bd7b3c9bda3d4b8775816", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3", key = "", out = "d66f2beab990e354ccb910e4e9c7ac618c7b63ef292a96b552341de78dc46d3ec8cfabc699b50af41fda39cf1b0173660923510ad67faedef5207cffe8641d20", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4", key = "", out = "7d8f0672992b79be3a364d8e5904f4ab713bbc8ab01b4f309ad8ccf223ce1034a860dcb0b00550612cc2fa17f2969e18f22e1427d254b4a82b3a03a3eb394adf", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5", key = "", out = "a56d6725bfb3de47c1414adf25fc8f0fc9846f6987722bc06366d5ca4e89722925ebbc881418844075397a0ca89842c7b9e9e07e1d9d183ebeb39e120b483bf7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6", key = "", out = "af5e03d7fe60c67e10313344434e79485a03a758d6dce985574745763c1c5c77d4fb3e6fb12230368370993bf90feed0c5d1607524562d7c09c0c210ed393d7c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7", key = "", out = "7a20540cc07bf72b582421fc342e82f52134b69841ec28ed189e2ea6a29dd2f82a640352d222b52f2911dc72a7dab31caadd80c6118f13c56b2a1e4373be0ea3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8", key = "", out = "486f02c63e5467ea1fdde7e82bfacc2c1ba5d636d9f3d08b210da3f372f706ec218cc17ff60aef703bbe0c15c38ae55d286a684f864c78211ccab4178c92adba", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9", key = "", out = "1c7a5c1dedcd04a921788f7eb23361ca1953b04b9c7aec35d65ea3e4996db26f281278ea4ae666ad81027d98af57262cdbfa4c085f4210568c7e15eec7805114", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9ea", key = "", out = "9ce3fa9a860bdbd5378fd6d7b8b671c6cb7692910ce8f9b6cb4122cbcbe6ac06ca0422cef1225935053b7d193a81b9e972eb85a1d3074f14cbb5ec9f0573892d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb", key = "", out = "a91187be5c371c4265c174fd4653b8ab708551f83d1fee1cc1479581bc006d6fb78fcc9a5dee1db3666f508f9780a37593ebcccf5fbed39667dc6361e921f779", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebec", key = "", out = "4625767d7b1d3d3ed2fbc674af14e0244152f2a4021fcf3311505d89bd81e2f9f9a500c3b199914db49500b3c98d03ea93286751a686a3b875daab0ccd63b44f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebeced", key = "", out = "43dfdfe1b014fed3a2acabb7f3e9a182f2aa18019d27e3e6cdcf31a15b428e91e7b08cf5e5c376fce2d8a28ff85ab0a0a1656edb4a0a91532620096d9a5a652d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedee", key = "", out = "279e3202be3989ba3112772585177487e4fe3ee3eab49c2f7fa7fe87cfe7b80d3e0355edff6d031e6c96c795db1c6f041880ec3824defacf9263820a8e7327de", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef", key = "", out = "ea2d066ac229d4d4b616a8bedec734325224e4b4e58f1ae6dad7e40c2da29196c3b1ea9571dacc81e87328caa0211e09027b0524aa3f4a849917b3586747ebbb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0", key = "", out = "49f014f5c61822c899ab5cae51be4044a4495e777deb7da9b6d8490efbb87530adf293daf079f94c33b7044ef62e2e5bb3eb11e17304f8453ee6ce24f033ddb0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1", key = "", out = "9233490344e5b0dc5912671b7ae54cee7730dbe1f4c7d92a4d3e3aab50571708db51dcf9c2944591db651db32d22935b86944969be77d5b5feae6c3840a8db26", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2", key = "", out = "b6e75e6f4c7f453b7465d25b5ac8c7196902eaa953875228c8634e16e2ae1f38bc3275304335f5989eccc1e34167d4e68d7719968fba8e2fe67947c35c48e806", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3", key = "", out = "cc14ca665af1483efbc3af80080e650d5046a3932f4f51f3fe90a0705ec25104adf07839265dc51d43401411246e474f0d5e5637af94767283d53e0617e981f4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4", key = "", out = "230a1c857cb2e7852e41b647e90e4585d2d881e1734dc38955356e8dd7bff39053092c6b38e236e1899525647073dddf6895d64206325e7647f275567b255909", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5", key = "", out = "cbb65321ac436e2ffdab2936359ce49023f7dee7614ef28d173c3d27c5d1bffa51553d433f8ee3c9e49c05a2b883cce954c9a8093b80612a0cdd4732e041f995", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6", key = "", out = "3e7e570074337275efb51315588034c3cf0dddca20b4612e0bd5b881e7e5476d319ce4fe9f19186e4c0826f44f131eb048e65be242b1172c63badb123ab0cbe8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7", key = "", out = "d32e9ec02d38d4e1b8249df8dcb00c5b9c68eb8922672e3505393b6a210ba56f9496e5ee0490ef387c3cdec061f06bc0382d9304cafbb8e0cd33d57029e62df2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8", key = "", out = "8c1512466089f05b3775c262b62d22b83854a83218130b4ec91b3ccbd293d2a54302cecaab9b100c68d1e6ddc8f07cddbdfe6fdaaaf099cc09d6b725879c6369", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9", key = "", out = "91a7f61c97c2911e4c812ef71d780ad8fa788794561d08303fd1c1cb608a46a12563086ec5b39d471aed94fb0f6c678a43b8792932f9028d772a22768ea23a9b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fa", key = "", out = "4f6bb222a395e8b18f6ba155477aed3f0729ac9e83e16d31a2a8bc655422b837c891c6199e6f0d75799e3b691525c581953517f252c4b9e3a27a28fbaf49644c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafb", key = "", out = "5d06c07e7a646c413a501c3f4bb2fc38127de7509b7077c4d9b5613201c1aa02fd5f79d2745915dd57fbcb4ce08695f6efc0cb3d2d330e19b4b0e6004ea6471e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfc", key = "", out = "b96756e57909968f14b796a5d30f4c9d671472cf82c8cfb2caca7ac7a44ca0a14c9842d00c82e337502c94d5960aca4c492ea7b0df919ddf1aada2a275bb10d4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd", key = "", out = "ff0a015e98db9c99f03977710aac3e658c0d896f6d71d618ba79dc6cf72ac75b7c038eb6862dede4543e145413a6368d69f5722c827ba3ef25b6ae6440d39276", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", key = "", out = "5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928", }, vector { in = "", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", }, vector { in = "00", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", }, vector { in = "0001", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", }, vector { in = "000102", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", }, vector { in = "00010203", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", }, vector { in = "0001020304", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", }, vector { in = "000102030405", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", }, vector { in = "00010203040506", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", }, vector { in = "0001020304050607", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", }, vector { in = "000102030405060708", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", }, vector { in = "00010203040506070809", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", }, vector { in = "000102030405060708090a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", }, vector { in = "000102030405060708090a0b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", }, vector { in = "000102030405060708090a0b0c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", }, vector { in = "000102030405060708090a0b0c0d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", }, vector { in = "000102030405060708090a0b0c0d0e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", }, vector { in = "000102030405060708090a0b0c0d0e0f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", }, vector { in = "000102030405060708090a0b0c0d0e0f10", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", }, vector { in = "000102030405060708090a0b0c0d0e0f1011", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", }, vector { in = "000102030405060708090a0b0c0d0e0f101112", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", }, vector { in = "000102030405060708090a0b0c0d0e0f1011121314", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213141516", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", }, vector { in = "000102030405060708090a0b0c0d0e0f1011121314151617", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", }, vector { in = "000102030405060708090a0b0c0d0e0f10111213141516171819", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454647", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354555657", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556575859", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364656667", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263646566676869", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374757677", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576777879", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384858687", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586878889", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394959697", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596979899", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aa", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaab", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabac", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacad", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadae", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9ba", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babb", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbc", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbd", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9ca", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacb", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcc", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdce", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9da", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcddde", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9ea", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebec", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebeced", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedee", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fa", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafb", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfc", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", }, vector { in = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", out = "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", }, ]; hare-0.24.2/crypto/blowfish/000077500000000000000000000000001464473310100156565ustar00rootroot00000000000000hare-0.24.2/crypto/blowfish/+test.ha000066400000000000000000000200111464473310100172140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; const key_vectors: [_][8]u8 = [ [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], [0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], [0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57], [0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E], [0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86], [0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E], [0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6], [0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE], [0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6], [0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE], [0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16], [0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F], [0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46], [0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E], [0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76], [0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07], [0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F], [0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7], [0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF], [0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6], [0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF], [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], [0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E], [0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10], ]; const clear_vectors: [_][8]u8 = [ [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], [0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42], [0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA], [0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72], [0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A], [0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2], [0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A], [0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2], [0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A], [0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02], [0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A], [0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32], [0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA], [0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62], [0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2], [0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA], [0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92], [0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A], [0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2], [0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], ]; const cipher_vectors: [_][8]u8 = [ [0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78], [0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A], [0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2], [0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D], [0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96], [0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7], [0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78], [0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D], [0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B], [0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0], [0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4], [0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB], [0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A], [0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18], [0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98], [0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5], [0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79], [0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3], [0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69], [0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B], [0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E], [0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD], [0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19], [0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3], [0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5], [0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78], [0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01], [0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2], [0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE], [0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D], [0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4], [0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC], [0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A], [0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A], ]; @test fn encrypt() void = { for (let i = 0z; i < len(key_vectors); i += 1) { const key = key_vectors[i]; const clear = clear_vectors[i]; const cipher = cipher_vectors[i]; const bf = new(); defer cipher::finish(&bf); init(&bf, key); let buf: [8]u8 = [0...]; cipher::encrypt(&bf, buf, clear); assert(bytes::equal(cipher, buf)); }; }; @test fn decrypt() void = { for (let i = 0z; i < len(key_vectors); i += 1) { const key = key_vectors[i]; const clear = clear_vectors[i]; const cipher = cipher_vectors[i]; const bf = new(); defer cipher::finish(&bf); init(&bf, key); let buf: [8]u8 = [0...]; cipher::decrypt(&bf, buf, cipher); assert(bytes::equal(clear, buf)); }; }; const salted_vectors: [_][8]u8 = [ [0x0c, 0x82, 0x3b, 0x7b, 0x8d, 0x01, 0x4b, 0x7e], [0xd1, 0xe1, 0x93, 0xf0, 0x70, 0xa6, 0xdb, 0x12], [0xfc, 0x5e, 0xba, 0xde, 0xcb, 0xf8, 0x59, 0xad], [0x8a, 0x0c, 0x76, 0xe7, 0xdd, 0x2c, 0xd3, 0xa8], [0x2c, 0xcb, 0x7b, 0xee, 0xac, 0x7b, 0x7f, 0xf8], [0xbb, 0xf6, 0x30, 0x6f, 0xe1, 0x5d, 0x62, 0xbf], [0x97, 0x1e, 0xc1, 0x3d, 0x3d, 0xe0, 0x11, 0xe9], [0x06, 0xd7, 0x4d, 0xb1, 0x80, 0xa3, 0xb1, 0x38], [0x67, 0xa1, 0xa9, 0x75, 0x0e, 0x5b, 0xc6, 0xb4], [0x51, 0x0f, 0x33, 0x0e, 0x4f, 0x67, 0xd2, 0x0c], [0xf1, 0x73, 0x7e, 0xd8, 0x44, 0xea, 0xdb, 0xe5], [0x14, 0x0e, 0x16, 0xce, 0x7f, 0x4a, 0x9c, 0x7b], [0x4b, 0xfe, 0x43, 0xfd, 0xbf, 0x36, 0x04, 0x47], [0xb1, 0xeb, 0x3e, 0x15, 0x36, 0xa7, 0xbb, 0xe2], [0x6d, 0x0b, 0x41, 0xdd, 0x00, 0x98, 0x0b, 0x19], [0xd3, 0xce, 0x45, 0xce, 0x1d, 0x56, 0xb7, 0xfc], [0xd9, 0xf0, 0xfd, 0xda, 0xc0, 0x23, 0xb7, 0x93], [0x4c, 0x6f, 0xa1, 0xe4, 0x0c, 0xa8, 0xca, 0x57], [0xe6, 0x2f, 0x28, 0xa7, 0x0c, 0x94, 0x0d, 0x08], [0x8f, 0xe3, 0xf0, 0xb6, 0x29, 0xe3, 0x44, 0x03], [0xff, 0x98, 0xdd, 0x04, 0x45, 0xb4, 0x6d, 0x1f], [0x9e, 0x45, 0x4d, 0x18, 0x40, 0x53, 0xdb, 0xef], [0xb7, 0x3b, 0xef, 0x29, 0xbe, 0xa8, 0x13, 0x71], [0x02, 0x54, 0x55, 0x41, 0x8e, 0x04, 0xfc, 0xad], [0x6a, 0x0a, 0xee, 0x7c, 0x10, 0xd9, 0x19, 0xfe], [0x0a, 0x22, 0xd9, 0x41, 0xcc, 0x23, 0x87, 0x13], [0x6e, 0xff, 0x1f, 0xff, 0x36, 0x17, 0x9c, 0xbe], [0x79, 0xad, 0xb7, 0x40, 0xf4, 0x9f, 0x51, 0xa6], [0x97, 0x81, 0x99, 0xa4, 0xde, 0x9e, 0x9f, 0xb6], [0x12, 0x19, 0x7a, 0x28, 0xd0, 0xdc, 0xcc, 0x92], [0x81, 0xda, 0x60, 0x1e, 0x0e, 0xdd, 0x65, 0x56], [0x7d, 0x76, 0x20, 0xb2, 0x73, 0xc9, 0x9e, 0xee], ]; @test fn salted() void = { let key: [32]u8 = [0...]; let salt: [32]u8 = [0...]; for (let i = 0z; i < len(key); i += 1) { key[i] = i: u8; salt[i] = i: u8 + 32; }; for (let i = 0z; i < len(salted_vectors); i += 1) { let bf = new(); init_salt(&bf, key, salt[..i]); let buf: [8]u8 = [0...]; cipher::encrypt(&bf, buf, buf); assert(bytes::equal(buf, salted_vectors[i])); }; }; hare-0.24.2/crypto/blowfish/README000066400000000000000000000015241464473310100165400ustar00rootroot00000000000000The crypto::blowfish module provides an implementation of Bruce Schneier's Blowfish encryption standard via the [[crypto::cipher::block]] interface. The use of this algorithm is not recommended except for legacy use-cases; prefer [[crypto::aes::]] when possible. When combined with a block cipher mode from [[crypto::cipher::]], suitable buffer lengths for static allocation are provided as constants such as [[BLOCKSZ]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/blowfish/blowfish.ha000066400000000000000000000166011464473310100200110ustar00rootroot00000000000000// SPDX-License-Identifier: MIT // (c) Hare authors // (c) 2010 The Go Authors. All rights reserved. use bytes; use crypto::cipher; // The block size of the Blowfish cipher in bytes. export def BLOCKSZ: size = 8; export type state = struct { block: cipher::block, p: [18]u32, s0: [256]u32, s1: [256]u32, s2: [256]u32, s3: [256]u32, }; const vtable: cipher::blockvtable = cipher::blockvtable { blocksz = BLOCKSZ, nparallel = 1, encrypt = &block_encrypt, decrypt = &block_decrypt, finish = &block_finish, }; // Initializes a new Blowfish cipher. The user should must call [[init]] or // [[init_salt]] prior to use, then may use [[crypto::cipher::encrypt]] et al. // The user must call [[finish]] when they are done using the stream to securely // erase secret information stored in the stream state. export fn new() state = { return state { block = &vtable, p = p, s0 = s0, s1 = s1, s2 = s2, s3 = s3, }; }; // Performs key expansion for a Blowfish cipher. export fn init(c: *state, key: []u8) void = { let j = 0z; for (let i = 0z; i < len(c.p); i += 1) { c.p[i] ^= getword(key, &j); }; let l = 0u32, r = 0u32; init_vector(c, &l, &r, c.p); init_vector(c, &l, &r, c.s0); init_vector(c, &l, &r, c.s1); init_vector(c, &l, &r, c.s2); init_vector(c, &l, &r, c.s3); }; fn init_vector(c: *state, l: *u32, r: *u32, vec: []u32) void = { for (let i = 0z; i < len(vec); i += 2) { const (v0, v1) = encrypt(c, *l, *r); *l = v0; *r = v1; vec[i] = *l; vec[i+1] = *r; }; }; // Performs salted key expansion for a Blowfish cipher. export fn init_salt(c: *state, key: []u8, salt: []u8) void = { if (len(salt) == 0) { init(c, key); return; }; assert(len(key) >= 1, "Invalid blowfish key size"); let j = 0z; for (let i = 0z; i < 18; i += 1) { c.p[i] ^= getword(key, &j); }; j = 0; let l = 0u32, r = 0u32; init_vector_salt(c, &l, &r, c.p, salt, &j); init_vector_salt(c, &l, &r, c.s0, salt, &j); init_vector_salt(c, &l, &r, c.s1, salt, &j); init_vector_salt(c, &l, &r, c.s2, salt, &j); init_vector_salt(c, &l, &r, c.s3, salt, &j); }; fn init_vector_salt( c: *state, l: *u32, r: *u32, vec: []u32, salt: []u8, j: *size, ) void = { for (let i = 0z; i < len(vec); i += 2) { *l ^= getword(salt, j); *r ^= getword(salt, j); const (v0, v1) = encrypt(c, *l, *r); *l = v0; *r = v1; vec[i] = *l; vec[i+1] = *r; }; }; fn block_encrypt(c: *cipher::block, dest: []u8, src: []u8) void = { const c = c: *state; assert(c.block.encrypt == &block_encrypt); let l = src[0]<<24u32 | src[1]<<16u32 | src[2]<<8u32 | src[3]: u32; let r = src[4]<<24u32 | src[5]<<16u32 | src[6]<<8u32 | src[7]: u32; const (l, r) = encrypt(c, l, r); dest[0] = (l>>24): u8; dest[1] = (l>>16): u8; dest[2] = (l>>8): u8; dest[3] = l: u8; dest[4] = (r>>24): u8; dest[5] = (r>>16): u8; dest[6] = (r>>8): u8; dest[7] = r: u8; }; fn block_decrypt(c: *cipher::block, dest: []u8, src: []u8) void = { const c = c: *state; assert(c.block.decrypt == &block_decrypt); let l = src[0]<<24u32 | src[1]<<16u32 | src[2]<<8u32 | src[3]: u32; let r = src[4]<<24u32 | src[5]<<16u32 | src[6]<<8u32 | src[7]: u32; const v = decrypt(c, l, r); l = v.0; r = v.1; dest[0] = (l>>24): u8; dest[1] = (l>>16): u8; dest[2] = (l>>8): u8; dest[3] = l: u8; dest[4] = (r>>24): u8; dest[5] = (r>>16): u8; dest[6] = (r>>8): u8; dest[7] = r: u8; }; fn block_finish(cipher: *cipher::block) void = { const cipher = cipher: *state; assert(cipher.block.finish == &block_finish); bytes::zero((&cipher.p: *[*]u8)[..len(cipher.p) * size(u32)]); bytes::zero((&cipher.s0: *[*]u8)[..len(cipher.s0) * size(u32)]); bytes::zero((&cipher.s1: *[*]u8)[..len(cipher.s1) * size(u32)]); bytes::zero((&cipher.s2: *[*]u8)[..len(cipher.s2) * size(u32)]); bytes::zero((&cipher.s3: *[*]u8)[..len(cipher.s3) * size(u32)]); }; fn encrypt(c: *state, l: u32, r: u32) (u32, u32) = { let xl = l, xr = r; xl ^= c.p[0]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[1]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[2]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[3]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[4]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[5]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[6]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[7]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[8]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[9]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[10]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[11]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[12]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[13]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[14]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[15]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[16]; xr ^= c.p[17]; return (xr, xl); }; fn decrypt(c: *state, l: u32, r: u32) (u32, u32) = { let xl = l, xr = r; xl ^= c.p[17]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[16]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[15]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[14]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[13]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[12]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[11]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[10]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[9]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[8]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[7]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[6]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[5]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[4]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[3]; xr ^= ((c.s0[(xl>>24): u8] + c.s1[(xl>>16): u8]) ^ c.s2[(xl>>8): u8]) + c.s3[(xl): u8] ^ c.p[2]; xl ^= ((c.s0[(xr>>24): u8] + c.s1[(xr>>16): u8]) ^ c.s2[(xr>>8): u8]) + c.s3[(xr): u8] ^ c.p[1]; xr ^= c.p[0]; return (xr, xl); }; // Gets the next word from b and updates the index, looping around in a circular // buffer. fn getword(b: []u8, i: *size) u32 = { let j = *i; let w = 0u32; for (let i = 0; i < 4; i += 1) { w = w<<8 | b[j]: u32; j += 1; if (j >= len(b)) { j = 0; }; }; *i = j; return w; }; hare-0.24.2/crypto/blowfish/const.ha000066400000000000000000000312101464473310100173130ustar00rootroot00000000000000// SPDX-License-Identifier: MIT // (c) Hare authors // (c) 2010 The Go Authors. All rights reserved. const s0: [256]u32 = [ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, ]; const s1: [256]u32 = [ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, ]; const s2: [256]u32 = [ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, ]; const s3: [256]u32 = [ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, ]; const p: [18]u32 = [ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, ]; hare-0.24.2/crypto/chacha/000077500000000000000000000000001464473310100152505ustar00rootroot00000000000000hare-0.24.2/crypto/chacha/+test.ha000066400000000000000000000202441464473310100166160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; // test vector taken from rfc8439 @test fn chacha20() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; const nonce: [_]u8 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00 ]; const msg: [_]u8 = [ 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x74, 0x2e, ]; const cipher: [_]u8 = [ 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, 0x87, 0x4d, ]; let result: [114]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = chacha20(); defer io::close(&c)!; chacha20_init(&c, &cipherbuf, key, nonce); setctr(&c, 1); const n = io::writeall(&c, msg)!; assert(n == len(msg)); assert(bytes::equal(cipher, result)); result = [0...]; cipherbuf = memio::fixed(result); chacha20_init(&c, &cipherbuf, key, nonce); setctr(&c, 1); io::write(&c, msg[..10])!; io::write(&c, msg[10..63])!; io::writeall(&c, msg[63..])!; assert(bytes::equal(cipher, result)); }; // test vector taken from xchacha20 rfc const xkey: [_]u8 = [ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ]; const xnonce: [_]u8 = [ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58, ]; const xmsg: [_]u8 = [ 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e, ]; const xcipher: [_]u8 = [ 0x7d, 0x0a, 0x2e, 0x6b, 0x7f, 0x7c, 0x65, 0xa2, 0x36, 0x54, 0x26, 0x30, 0x29, 0x4e, 0x06, 0x3b, 0x7a, 0xb9, 0xb5, 0x55, 0xa5, 0xd5, 0x14, 0x9a, 0xa2, 0x1e, 0x4a, 0xe1, 0xe4, 0xfb, 0xce, 0x87, 0xec, 0xc8, 0xe0, 0x8a, 0x8b, 0x5e, 0x35, 0x0a, 0xbe, 0x62, 0x2b, 0x2f, 0xfa, 0x61, 0x7b, 0x20, 0x2c, 0xfa, 0xd7, 0x20, 0x32, 0xa3, 0x03, 0x7e, 0x76, 0xff, 0xdc, 0xdc, 0x43, 0x76, 0xee, 0x05, 0x3a, 0x19, 0x0d, 0x7e, 0x46, 0xca, 0x1d, 0xe0, 0x41, 0x44, 0x85, 0x03, 0x81, 0xb9, 0xcb, 0x29, 0xf0, 0x51, 0x91, 0x53, 0x86, 0xb8, 0xa7, 0x10, 0xb8, 0xac, 0x4d, 0x02, 0x7b, 0x8b, 0x05, 0x0f, 0x7c, 0xba, 0x58, 0x54, 0xe0, 0x28, 0xd5, 0x64, 0xe4, 0x53, 0xb8, 0xa9, 0x68, 0x82, 0x41, 0x73, 0xfc, 0x16, 0x48, 0x8b, 0x89, 0x70, 0xca, 0xc8, 0x28, 0xf1, 0x1a, 0xe5, 0x3c, 0xab, 0xd2, 0x01, 0x12, 0xf8, 0x71, 0x07, 0xdf, 0x24, 0xee, 0x61, 0x83, 0xd2, 0x27, 0x4f, 0xe4, 0xc8, 0xb1, 0x48, 0x55, 0x34, 0xef, 0x2c, 0x5f, 0xbc, 0x1e, 0xc2, 0x4b, 0xfc, 0x36, 0x63, 0xef, 0xaa, 0x08, 0xbc, 0x04, 0x7d, 0x29, 0xd2, 0x50, 0x43, 0x53, 0x2d, 0xb8, 0x39, 0x1a, 0x8a, 0x3d, 0x77, 0x6b, 0xf4, 0x37, 0x2a, 0x69, 0x55, 0x82, 0x7c, 0xcb, 0x0c, 0xdd, 0x4a, 0xf4, 0x03, 0xa7, 0xce, 0x4c, 0x63, 0xd5, 0x95, 0xc7, 0x5a, 0x43, 0xe0, 0x45, 0xf0, 0xcc, 0xe1, 0xf2, 0x9c, 0x8b, 0x93, 0xbd, 0x65, 0xaf, 0xc5, 0x97, 0x49, 0x22, 0xf2, 0x14, 0xa4, 0x0b, 0x7c, 0x40, 0x2c, 0xdb, 0x91, 0xae, 0x73, 0xc0, 0xb6, 0x36, 0x15, 0xcd, 0xad, 0x04, 0x80, 0x68, 0x0f, 0x16, 0x51, 0x5a, 0x7a, 0xce, 0x9d, 0x39, 0x23, 0x64, 0x64, 0x32, 0x8a, 0x37, 0x74, 0x3f, 0xfc, 0x28, 0xf4, 0xdd, 0xb3, 0x24, 0xf4, 0xd0, 0xf5, 0xbb, 0xdc, 0x27, 0x0c, 0x65, 0xb1, 0x74, 0x9a, 0x6e, 0xff, 0xf1, 0xfb, 0xaa, 0x09, 0x53, 0x61, 0x75, 0xcc, 0xd2, 0x9f, 0xb9, 0xe6, 0x05, 0x7b, 0x30, 0x73, 0x20, 0xd3, 0x16, 0x83, 0x8a, 0x9c, 0x71, 0xf7, 0x0b, 0x5b, 0x59, 0x07, 0xa6, 0x6f, 0x7e, 0xa4, 0x9a, 0xad, 0xc4, 0x09, ]; @test fn xchacha20() void = { let result: [304]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = chacha20(); defer io::close(&c)!; xchacha20_init(&c, &cipherbuf, xkey, xnonce); setctr(&c, 1); io::writeall(&c, xmsg)!; assert(bytes::equal(xcipher, result)); }; @test fn skipblocks() void = { let result: [18]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = chacha20(); defer io::close(&c)!; xchacha20_init(&c, &cipherbuf, xkey, xnonce); // just encrypt a few bytes of each block, to check if setctr works setctr(&c, 1); io::writeall(&c, xmsg[..5])!; setctr(&c, 2); io::writeall(&c, xmsg[64..70])!; setctr(&c, 3); io::writeall(&c, xmsg[128..135])!; assert(bytes::equal(result[..5], xcipher[..5])); assert(bytes::equal(result[5..11], xcipher[64..70])); assert(bytes::equal(result[11..], xcipher[128..135])); }; // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03#section-2.2.1 @test fn hchacha20() void = { const key: [_]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; const nonce: [_]u8 = [ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27, ]; const expected: [_]u8 = [ 0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, 0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73, 0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53, 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc, ]; let out: [32]u8 = [0...]; hchacha20(&out, key, nonce); assert(bytes::equal(out, expected)); }; hare-0.24.2/crypto/chacha/README000066400000000000000000000021371464473310100161330ustar00rootroot00000000000000crypto::chacha provides an implementation of the Chacha20 and XChacha20 stream ciphers. Use [[chacha20]] to create a [[crypto::cipher::xorstream]] and either [[chacha20_init]] or [[xchacha20_init]] to set the handle, key and nonce of the appropriate size, [[NONCESZ]] for chacha20 or [[XNONCESZ]] for XChacha20. After calling the appropriate init function, [[io::write]] may be used to encrypt blocks to the handle or [[io::read]] to decrypt blocks from the handle. The stream must be closed with [[io::close]] to wipe sensitive data from memory. Writing blocks of length [[BLOCKSZ]] is not required. However, seeking the key stream with [[setctr]] only operates in units of [[BLOCKSZ]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/chacha/chacha20.ha000066400000000000000000000126731464473310100171440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; use crypto::math::{rotl32, xor}; use endian; use io; // Size of a Chacha key, in bytes. export def KEYSZ: size = 32; // Size of the XChacha20 nonce, in bytes. export def XNONCESZ: size = 24; // Size of the Chacha20 nonce, in bytes. export def NONCESZ: size = 12; // The block size of the Chacha cipher in bytes. export def BLOCKSZ: size = 64; def ROUNDS: size = 20; const magic: [4]u32 = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]; // A ChaCha20 or XChaCha20 [[crypto::cipher::xorstream]] depending on // intialisation. export type stream = struct { cipher::xorstream, state: [16]u32, xorbuf: [BLOCKSZ]u8, xorused: size, rounds: size, }; // Creates a ChaCha20 or XChaCha20 stream cipher. Must be initialized with // [[chacha20_init]] or [[xchacha20_init]] prior to use, and must be closed // with [[io::close]] after use to wipe sensitive data from memory. export fn chacha20() stream = { return stream { stream = &cipher::xorstream_vtable, h = 0, keybuf = &keybuf, advance = &advance, finish = &finish, xorused = BLOCKSZ, rounds = ROUNDS, ... }; }; // Initialize a Chacha20 stream. export fn chacha20_init( s: *stream, h: io::handle, key: []u8, nonce: []u8 ) void = { assert(len(key) == KEYSZ); assert(len(nonce) == NONCESZ); s.h = h; s.state[0] = magic[0]; s.state[1] = magic[1]; s.state[2] = magic[2]; s.state[3] = magic[3]; s.state[4] = endian::legetu32(key[0..4]); s.state[5] = endian::legetu32(key[4..8]); s.state[6] = endian::legetu32(key[8..12]); s.state[7] = endian::legetu32(key[12..16]); s.state[8] = endian::legetu32(key[16..20]); s.state[9] = endian::legetu32(key[20..24]); s.state[10] = endian::legetu32(key[24..28]); s.state[11] = endian::legetu32(key[28..32]); s.state[13] = endian::legetu32(nonce[0..4]); s.state[14] = endian::legetu32(nonce[4..8]); s.state[15] = endian::legetu32(nonce[8..12]); }; // Initialise a XChacha20 stream. export fn xchacha20_init( s: *stream, h: io::handle, key: []u8, nonce: []u8 ) void = { assert(len(key) == KEYSZ); assert(len(nonce) == XNONCESZ); let dkey: [32]u8 = [0...]; hchacha20(&dkey, key, nonce[..16]); let dnonce: [NONCESZ]u8 = [0...]; dnonce[4..] = nonce[16..]; chacha20_init(s, h, &dkey, dnonce); bytes::zero(dkey); bytes::zero(dnonce); }; // Derives a new key from 'key' and 'nonce' as used during XChaCha20 // initialization. This function may only be used for specific purposes // such as X25519 key derivation. Do not use if in doubt. export fn hchacha20(out: []u8, key: []u8, nonce: []u8) void = { assert(len(out) == KEYSZ); assert(len(key) == KEYSZ); assert(len(nonce) == 16); let state: [16]u32 = [0...]; defer bytes::zero((state: []u8: *[*]u8)[..BLOCKSZ]); state[0] = magic[0]; state[1] = magic[1]; state[2] = magic[2]; state[3] = magic[3]; state[4] = endian::legetu32(key[0..4]); state[5] = endian::legetu32(key[4..8]); state[6] = endian::legetu32(key[8..12]); state[7] = endian::legetu32(key[12..16]); state[8] = endian::legetu32(key[16..20]); state[9] = endian::legetu32(key[20..24]); state[10] = endian::legetu32(key[24..28]); state[11] = endian::legetu32(key[28..32]); state[12] = endian::legetu32(nonce[0..4]); state[13] = endian::legetu32(nonce[4..8]); state[14] = endian::legetu32(nonce[8..12]); state[15] = endian::legetu32(nonce[12..16]); hblock(state[..], &state, 20); endian::leputu32(out[0..4], state[0]); endian::leputu32(out[4..8], state[1]); endian::leputu32(out[8..12], state[2]); endian::leputu32(out[12..16], state[3]); endian::leputu32(out[16..20], state[12]); endian::leputu32(out[20..24], state[13]); endian::leputu32(out[24..28], state[14]); endian::leputu32(out[28..32], state[15]); }; // Advances the key stream to "seek" to a future state by 'counter' times // [[BLOCKSZ]]. export fn setctr(s: *stream, counter: u32) void = { s.state[12] = counter; // enforce block generation s.xorused = BLOCKSZ; }; fn keybuf(s: *cipher::xorstream) []u8 = { let s = s: *stream; if (s.xorused >= BLOCKSZ) { block((s.xorbuf: []u8: *[*]u32)[..16], &s.state, s.rounds); // TODO on big endian systems s.xorbuf values need to // be converted from little endian. s.state[12] += 1; s.xorused = 0; }; return s.xorbuf[s.xorused..]; }; fn advance(s: *cipher::xorstream, n: size) void = { let s = s: *stream; assert(n <= len(s.xorbuf)); s.xorused += n; }; fn block(dest: []u32, state: *[16]u32, rounds: size) void = { hblock(dest, state, rounds); for (let i = 0z; i < 16; i += 1) { dest[i] += state[i]; }; }; fn hblock(dest: []u32, state: *[16]u32, rounds: size) void = { for (let i = 0z; i < 16; i += 1) { dest[i] = state[i]; }; for (let i = 0z; i < rounds; i += 2) { qr(&dest[0], &dest[4], &dest[8], &dest[12]); qr(&dest[1], &dest[5], &dest[9], &dest[13]); qr(&dest[2], &dest[6], &dest[10], &dest[14]); qr(&dest[3], &dest[7], &dest[11], &dest[15]); qr(&dest[0], &dest[5], &dest[10], &dest[15]); qr(&dest[1], &dest[6], &dest[11], &dest[12]); qr(&dest[2], &dest[7], &dest[8], &dest[13]); qr(&dest[3], &dest[4], &dest[9], &dest[14]); }; }; fn qr(a: *u32, b: *u32, c: *u32, d: *u32) void = { *a += *b; *d ^= *a; *d = rotl32(*d, 16); *c += *d; *b ^= *c; *b = rotl32(*b, 12); *a += *b; *d ^= *a; *d = rotl32(*d, 8); *c += *d; *b ^= *c; *b = rotl32(*b, 7); }; fn finish(c: *cipher::xorstream) void = { let s = c: *stream; bytes::zero((s.state[..]: *[*]u8)[..BLOCKSZ]); bytes::zero(s.xorbuf); }; hare-0.24.2/crypto/chachapoly/000077500000000000000000000000001464473310100161545ustar00rootroot00000000000000hare-0.24.2/crypto/chachapoly/README000066400000000000000000000020011464473310100170250ustar00rootroot00000000000000This module provides Chacha20-Poly1305 and XChacha20-Poly1305 stream implementations as described in RFC 8439. A stream is created with [[chachapoly]]. [[init]] initializes a stream as a Chacha20-Poly1305 one where [[xinit]] will initialize it as a XChacha20-Poly1305 stream. After initializiation data can be encrypted by writing to or decrypted by reading from the stream. The user must call [[seal]] when encryption is done to create the authentication tag and [[verify]] in case of decryption to check if the dercypted data is valid. If the data is invalid it must not be processed further. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/chachapoly/chachapoly.ha000066400000000000000000000102001464473310100205720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::chacha; use crypto::mac; use crypto::math; use crypto::poly1305; use endian; use errors; use io; use memio; use types; // Nonce size as required by [[init]]. export def NONCESZ: size = chacha::NONCESZ; // Nonce size as required by [[xinit]]. export def XNONCESZ: size = chacha::XNONCESZ; // Key size export def KEYSZ: size = chacha::KEYSZ; // Tag size export def TAGSZ: size = poly1305::SZ; export type stream = struct { stream: io::stream, h: io::teestream, c: chacha::stream, p: poly1305::state, adsz: size, msgsz: size, }; // Create a stream that must be initialised by [[init]] or [[xinit]]. The user // must call [[io::close]] when they are done using the stream to securly erase // secret information stored in the stream state. export fn chachapoly() stream = { return stream { stream = &vtable, c = chacha::chacha20(), p = poly1305::poly1305(), h = io::tee(io::empty, io::empty), ... }; }; const vtable: io::vtable = io::vtable { writer = &writer, reader = &reader, closer = &closer, ... }; type initfunc = fn (s: *chacha::stream, h: io::handle, k: []u8, n: []u8) void; // Initialises the stream as Chacha20-Poly1305. Encrypts to or decrypts from // 'h'. 'nonce' must be a random value that will only be used once. Additional // data can be passed as 'ad'. export fn init( s: *stream, h: io::handle, key: const []u8, nonce: const []u8, ad: const []u8... ) void = geninit(s, &chacha::chacha20_init, h, key, nonce, ad...); // Initialise the stream as XChacha20-Poly1305. Encrypts to or decrypts from // 'h'. 'nonce' must be a random value that will only be used once. Additional // data can be passed as 'ad'. export fn xinit( s: *stream, h: io::handle, key: const []u8, nonce: const []u8, ad: const []u8... ) void = geninit(s, &chacha::xchacha20_init, h, key, nonce, ad...); fn geninit( s: *stream, finit: *initfunc, h: io::handle, key: const []u8, nonce: const []u8, ad: const []u8... ) void = { assert(len(ad) <= types::U32_MAX); let otk: poly1305::key = [0...]; defer bytes::zero(otk); let otkbuf = memio::fixed(otk); finit(&s.c, &otkbuf, key, nonce); io::writeall(&s.c, otk[..])!; poly1305::init(&s.p, &otk); s.adsz = 0z; for (let i = 0z; i < len(ad); i += 1) { s.adsz += len(ad[i]); mac::write(&s.p, ad[i]); }; polypad(&s.p, s.adsz); s.h = io::tee(h, &s.p); finit(&s.c, &s.h, key, nonce); chacha::setctr(&s.c, 1); s.msgsz = 0; }; fn polypad(p: *poly1305::state, n: size) void = { if (n % poly1305::BLOCKSZ == 0) { return; }; const pad: [poly1305::BLOCKSZ]u8 = [0...]; const padlen = poly1305::BLOCKSZ - (n % poly1305::BLOCKSZ); mac::write(p, pad[..padlen]); }; // Finishes encryption and writes the authentication code to 'tag'. After // calling seal, the user must not write any more data to the stream. export fn seal(s: *stream, tag: []u8) void = writemac(s, tag); fn writemac(s: *stream, tag: []u8) void = { assert(len(tag) == TAGSZ); assert(s.msgsz <= types::U32_MAX); polypad(&s.p, s.msgsz); let nbuf: [8]u8 = [0...]; endian::leputu64(nbuf, s.adsz: u32); mac::write(&s.p, nbuf); endian::leputu64(nbuf, s.msgsz: u32); mac::write(&s.p, nbuf); mac::sum(&s.p, tag[..]); }; // Verifies the authentication tag against the decrypted data. Must be called // after reading all data from the stream to ensure that the data was not // modified. If the data was modified, [[errors::invalid]] will be returned and // the data must not be trusted. export fn verify(s: *stream, tag: []u8) (void | errors::invalid) = { let ntag: [TAGSZ]u8 = [0...]; writemac(s, ntag); if (math::eqslice(ntag, tag) == 0) { return errors::invalid; }; }; fn writer(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *stream; const n = io::write(&s.c, buf)?; s.msgsz += n; return n; }; fn reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let s = s: *stream; match (io::read(&s.c, buf)?) { case io::EOF => return io::EOF; case let n: size => s.msgsz += n; return n; }; }; fn closer(s: *io::stream) (void | io::error) = { let s = s: *stream; io::close(&s.c)!; mac::finish(&s.p); }; hare-0.24.2/crypto/chachapoly/encryption+test.ha000066400000000000000000000130521464473310100216340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; @test fn encrypt() void = { let plain: [_]u8 = [ 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x74, 0x2e ]; let ad: [_]u8 = [ 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ]; let key: [_]u8 = [ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ]; let nonce: [_]u8 = [ 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, ]; let cipher: [_]u8 = [ 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, ]; let tag: [_]u8 = [ 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91, ]; let out = memio::dynamic(); defer io::close(&out)!; let s = chachapoly(); init(&s, &out, key, nonce, ad); io::writeall(&s, plain)!; let outtag: [TAGSZ]u8 = [0...]; seal(&s, outtag); let outbuf = memio::buffer(&out); assert(bytes::equal(outbuf, cipher)); assert(bytes::equal(outtag, tag)); let out = memio::dynamic(); defer io::close(&out)!; let in = memio::fixed(cipher); let s = chachapoly(); init(&s, &in, key, nonce, ad); io::copy(&out, &s)!; verify(&s, tag)!; let outbuf = memio::buffer(&out); assert(bytes::equal(outbuf, plain)); io::close(&s)!; }; type sample = struct { msg: []u8, cipher: []u8, additional: []u8, key: []u8, nonce: []u8, mac: []u8, }; // test vector taken from the XChacha20-Poly1305-AEAD draft rfc const rfcsample: sample = sample { msg = [ 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x74, 0x2e, ], additional = [ 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ], key = [ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ], nonce = [ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, ], cipher = [ 0xbd, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b, 0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39, 0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc, 0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb, 0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44, 0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39, 0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16, 0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52, 0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45, 0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e, 0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f, 0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9, 0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9, 0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13, 0xb5, 0x2e, ], mac = [ 0xc0, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79, 0x47, 0xde, 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49, ], }; @test fn xencrypt() void = { let tc = rfcsample; let out = memio::dynamic(); defer io::close(&out)!; let s = chachapoly(); xinit(&s, &out, tc.key, tc.nonce, tc.additional); io::writeall(&s, tc.msg)!; let outtag: [TAGSZ]u8 = [0...]; seal(&s, outtag); let outbuf = memio::buffer(&out); assert(bytes::equal(outbuf, tc.cipher)); assert(bytes::equal(outtag, tc.mac)); let out = memio::dynamic(); defer io::close(&out)!; let in = memio::fixed(tc.cipher); let s = chachapoly(); xinit(&s, &in, tc.key, tc.nonce, tc.additional); io::copy(&out, &s)!; verify(&s, tc.mac)!; let outbuf = memio::buffer(&out); assert(bytes::equal(outbuf, tc.msg)); io::close(&s)!; }; hare-0.24.2/crypto/cipher/000077500000000000000000000000001464473310100153135ustar00rootroot00000000000000hare-0.24.2/crypto/cipher/README000066400000000000000000000016101464473310100161710ustar00rootroot00000000000000The crypto::cipher module provides block cipher encryption modes. The [[block]] type provides an abstraction over a block cipher algorithm, and functions like [[cbc_decryptor]] create encryptors or decryptors for specific block encryption modes. Block ciphers in Hare rely upon caller-provided buffer allocations, and do not allocate memory at runtime. Consult the documentation for the underlying algorithm, e.g. [[crypto::aes::]], for the appropriate buffer sizes to use. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/cipher/block.ha000066400000000000000000000016621464473310100167240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An abstract interface for implementing block ciphers. export type blockvtable = struct { blocksz: size, nparallel: size, encrypt: *fn(b: *block, dest: []u8, src: []u8) void, decrypt: *fn(b: *block, dest: []u8, src: []u8) void, finish: *fn(b: *block) void, }; export type block = *blockvtable; // Returns the block size in bytes for a [[block]] cipher. export fn blocksz(b: *block) size = b.blocksz; // Returns the number of blocks that can be processed at once for a [[block]] // cipher. export fn nparallel(b: *block) size = b.nparallel; // Encrypt up to [[nparallel]] blocks from 'src' and writes to 'dest'. export fn encrypt(b: *block, dest: []u8, src: []u8) void = b.encrypt(b, dest, src); // Decrypt up to [[nparallel]] blocks from 'src' and writes to 'dest'. export fn decrypt(b: *block, dest: []u8, src: []u8) void = b.decrypt(b, dest, src); hare-0.24.2/crypto/cipher/cbc.ha000066400000000000000000000057721464473310100163670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::math; export type cbc_mode = struct { b: *block, encrypt: bool, carry: []u8, carrybuf: []u8, }; // Creates a cipher block chaining (CBC) mode encryptor. // // The user must supply an initialization vector (IV) equal in length to the // block size of the underlying [[block]] cipher, and a temporary state buffer // whose size is equal to the block size times two. The module providing the // underlying block cipher usually provides constants which define the lengths // of these buffers for static allocation. export fn cbc_encryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = { assert(len(iv) == blocksz(b), "len(iv) must be the same as the block size"); assert(len(buf) == blocksz(b) * 2, "buffer needs to be two times of the block size"); const bsz = blocksz(b); let carry = buf[0..bsz]; carry[..] = iv[..]; return cbc_mode { b = b, encrypt = true, carry = carry, carrybuf = buf[bsz..], }; }; // Creates a cipher block chaining (CBC) mode decryptor. // // The user must supply an initialization vector (IV) equal in length to the // block size of the underlying [[block]] cipher, and a temporary state buffer // whose size is equal to the block size times two. The module providing the // underlying block cipher usually provides constants which define the lengths // of these buffers for static allocation. export fn cbc_decryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = { assert(len(iv) == blocksz(b), "len(iv) must be the same as block length sz"); assert(len(buf) == blocksz(b) * 2, "buffer needs to be two times of the block size"); const bsz = blocksz(b); let carry = buf[0..bsz]; carry[..] = iv[..]; return cbc_mode { b = b, encrypt = false, carry = carry, carrybuf = buf[bsz..], }; }; // Encrypts given blocks with a length that is a multiple of the block size. // In place encryption only works if dest and src point exactly at the // same range. export fn cbc_encrypt(c: *cbc_mode, dest: []u8, src: []u8) void = { const sz = blocksz(c.b); assert(c.encrypt); assert(len(dest) % sz == 0 && len(src) == len(dest), "size of dest and src needs to match and be a multiple of block size"); for (let i = 0z; i < len(dest); i += sz) { let eb = i + sz; math::xor(dest[i..eb], src[i..eb], c.carry); encrypt(c.b, dest[i..eb], dest[i..eb]); c.carry[..] = dest[i..eb]; }; }; // Decrypts given blocks with a length that is a multiple of the block size. // In place decryption only works if dest and src point exactly at the // same range. export fn cbc_decrypt(c: *cbc_mode, dest: []u8, src: []u8) void = { const sz = blocksz(c.b); assert(!c.encrypt); assert(len(dest) % sz == 0 && len(src) == len(dest), "size of dest and src needs to match and be a multiple of block size"); for (let i = 0z; i < len(dest); i += sz) { let eb = i + sz; c.carrybuf[..] = c.carry[..]; c.carry[..] = src[i..eb]; decrypt(c.b, dest[i..eb], src[i..eb]); math::xor(dest[i..eb], dest[i..eb], c.carrybuf); }; }; hare-0.24.2/crypto/cipher/cipher.ha000066400000000000000000000003771464473310100171060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Discards any state associated with a block or a stream cipher algorithm, // securely erasing secret data from memory. export fn finish(a: *block) void = { a.finish(a); }; hare-0.24.2/crypto/cipher/ctr.ha000066400000000000000000000061311464473310100164160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math::{xor}; use io; // A counter mode (CTR) stream. export type ctr_stream = struct { xorstream, b: *block, counter: []u8, xorbuf: []u8, xorused: size, }; // Creates a counter mode (CTR) cipher stream which can be used for encryption // (by encrypting writes to the underlying handle) or decryption (or by // decrypting reads from the underlying handle), but not both. // // The user must supply an initialization vector (IV) equal in length to the // block size of the underlying [[block]] cipher, and a temporary state buffer // whose size is equal to the block size times two. The module providing the // underlying block cipher usually provides constants which define the lengths // of these buffers for static allocation. // // The user must call [[io::close]] when they are done using the stream to // securely erase secret information stored in the stream state. This will also // finish the underlying [[block]] cipher. export fn ctr(h: io::handle, b: *block, iv: []u8, buf: []u8) ctr_stream = { assert(len(iv) == blocksz(b), "iv is of invalid block size"); assert(len(buf) >= blocksz(b) * 2, "buf must be at least 2 * blocksize"); const bsz = blocksz(b); // one buf block is used for the counter let counter = buf[0..bsz]; // the remaining space is used to store the key stream. It needs // to be at least the size of one block and ideally the size of // nparallel(b) times the block size. A bigger buffer than the latter // option is of no use. let xorbuf = buf[bsz..]; counter[..] = iv[..]; // cap the buffer to a multiple of bsz. let maxxorbufsz = blocksz(b) * nparallel(b); const xorbufsz = if (len(xorbuf) < maxxorbufsz) { yield len(xorbuf) - len(xorbuf) % blocksz(b); } else { yield maxxorbufsz; }; let s = ctr_stream { stream = &xorstream_vtable, h = h, keybuf = &ctr_keybuf, advance = &ctr_advance, finish = &ctr_finish, b = b, counter = counter, xorbuf = xorbuf[..xorbufsz], // mark all as used to force fill xorbuf xorused = xorbufsz, ... }; return s; }; fn fill_xorbuf(ctr: *ctr_stream) void = { const bsz = blocksz(ctr.b); // Write and increment the counter to each available block for (let i = 0z; i < len(ctr.xorbuf) / bsz; i += 1) { ctr.xorbuf[i * bsz..(i * bsz + bsz)] = ctr.counter[0..bsz]; for (let j = len(ctr.counter); j > 0; j -= 1) { ctr.counter[j - 1] += 1; if (ctr.counter[j - 1] != 0) { break; }; }; }; encrypt(ctr.b, ctr.xorbuf, ctr.xorbuf); ctr.xorused = 0; }; fn ctr_keybuf(s: *xorstream) []u8 = { let ctr = s: *ctr_stream; if (ctr.xorused >= len(ctr.xorbuf)) { fill_xorbuf(ctr); }; return ctr.xorbuf[ctr.xorused..]; }; fn ctr_advance(s: *xorstream, n: size) void = { let ctr = s: *ctr_stream; // fill_xorbuf could be smarter, to skip multiple blocks at once. // It's of no use, since xorstream doesn't support skipping an arbritary // number of blocks. assert(n <= len(ctr.xorbuf)); ctr.xorused += n; }; fn ctr_finish(s: *xorstream) void = { let ctr = s: *ctr_stream; bytes::zero(ctr.xorbuf); finish(ctr.b); }; hare-0.24.2/crypto/cipher/gcm.ha000066400000000000000000000143331464473310100163770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math::{xor,eqslice}; use endian::{beputu64, beputu32, begetu32}; use errors; use io; use types; def GCMBLOCKSZ: size = 16; export def GCMTAGSZ: size = 16; export type gcmstream = struct { stream: io::stream, block: nullable *block, handle: io::handle, tagbuf: [GCMBLOCKSZ]u8, xorbuf: [GCMBLOCKSZ]u8, cipherbuf: [GCMBLOCKSZ]u8, y0: [GCMBLOCKSZ]u8, h: [GCMBLOCKSZ]u8, y: u32, xorbufpos: size, adlen: u64, clen: u64, }; const gcm_vtable: io::vtable = io::vtable { writer = &gcm_writer, reader = &gcm_reader, closer = &gcm_closer, ... }; // Creates a Galois Counter Mode (GCM) io::stream which can be used for // encryption (by encrypting writes to the underlying handle) or decryption (or // by decrypting reads from the underlying handle), but not both. [[gcm_init]] // must be called to initialize the stream, before reading or writing. To // authenticate the encrypted data an authentication tag must be created using // [[gcm_seal]] after the encryption step. The authentication tag must be passed // to [[gcm_verify]] after decryption to make sure that the encrypted and // additional data were not modified. In case of a verification fail the // decrypted data must not be trusted and hence discarded. // // A maximum of 2**36-32 bytes may be encrypted. // // The user must call [[io::close]] when they are done using the stream to // securely erase secret information stored in the stream state. Close will // also finish the 'block' provided by [[gcm_init]]. export fn gcm() gcmstream = { return gcmstream { stream = &gcm_vtable, handle = 0, ... }; }; // Initialises the gcmstream. The data will be encrypted to or encrypted from // the given 'handle' The implementation only supports a block cipher 'b' with a // block size of 16 bytes. The initialization vector (nonce) 'iv' may have any // size up to 2**61 bytes. 12 bytes is the recommended size, if efficiency is // critical. The additional data 'ad' will be authenticated but not encrypted // and may have a maximum length of 2**61 - 1 bytes. 'ad' will not be written to // the underlying handle. export fn gcm_init( s: *gcmstream, handle: io::handle, b: *block, iv: const []u8, ad: const []u8 ) void = { assert(blocksz(b) == GCMBLOCKSZ); assert(len(iv): u64 <= (types::U64_MAX >> 3)); s.handle = handle; s.block = b; s.adlen = len(ad); s.xorbufpos = GCMBLOCKSZ; // to force fill xorbuf at start encrypt(b, s.h, s.h); if (len(iv) == 12) { s.y0[..12] = iv[..]; s.y0[15] |= 1; } else { let ivlen = s.tagbuf; beputu64(ivlen[8..], len(iv) << 3); ghash_ctmul64(s.y0, s.h, iv); ghash_ctmul64(s.y0, s.h, ivlen); bytes::zero(ivlen); }; s.y = begetu32(s.y0[12..]) + 1; let ad = ad[..]; for (len(ad) > 0) { const max = if (len(ad) >= GCMBLOCKSZ) { yield GCMBLOCKSZ; } else { yield len(ad); }; ghash_ctmul64(s.tagbuf, s.h, ad[..max]); ad = ad[max..]; }; }; fn gcm_writer(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *gcmstream; if (len(buf) == 0) { return 0z; }; if (s.xorbufpos == GCMBLOCKSZ) { // current key block is depleted, prepare the next one fillxorbuf(s); }; let buf = buf[..]; let n: size = 0; const max = if (s.xorbufpos + len(buf) > len(s.cipherbuf)) { yield len(s.cipherbuf) - s.xorbufpos; } else { yield len(buf); }; let cipher = s.cipherbuf[s.xorbufpos..s.xorbufpos + max]; let key = s.xorbuf[s.xorbufpos..s.xorbufpos + max]; xor(cipher, key, buf[..max]); const n = io::write(s.handle, cipher)?; s.xorbufpos += n; s.clen += n; if (s.xorbufpos == GCMBLOCKSZ) { ghash_ctmul64(s.tagbuf, s.h, s.cipherbuf); }; return n; }; fn fillxorbuf(s: *gcmstream) void = { let y: [GCMBLOCKSZ]u8 = [0...]; s.xorbuf[..] = s.y0[..]; beputu32(s.xorbuf[12..], s.y); encrypt(s.block as *block, s.xorbuf, s.xorbuf); s.y += 1; s.xorbufpos = 0; }; fn gcm_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let s = s: *gcmstream; const n = match (io::read(s.handle, buf)?) { case io::EOF => return io::EOF; case let s: size => yield s; }; for (let i = n; i > 0) { if (s.xorbufpos == GCMBLOCKSZ) { fillxorbuf(s); }; const max = if (s.xorbufpos + i > GCMBLOCKSZ) { yield len(s.cipherbuf) - s.xorbufpos; } else { yield i; }; let cipher = s.cipherbuf[s.xorbufpos..s.xorbufpos + max]; let key = s.xorbuf[s.xorbufpos..s.xorbufpos + max]; cipher[..] = buf[..max]; xor(buf[..max], buf[..max], key); buf = buf[max..]; i -= max; s.xorbufpos += max; s.clen += max; if (s.xorbufpos == len(s.cipherbuf)) { ghash_ctmul64(s.tagbuf, s.h, s.cipherbuf); }; }; return n; }; // Finishes encryption and returns the authentication tag. After calling seal, // the user must not write any more data to the stream. export fn gcm_seal(s: *gcmstream, tag: []u8) void = { assert(len(tag) == GCMTAGSZ); if (s.xorbufpos > 0 && s.xorbufpos < GCMBLOCKSZ) { // last block was is not full, therefore the content was not // hashed yet. ghash_ctmul64(s.tagbuf, s.h, s.cipherbuf[..s.xorbufpos]); }; beputu64(tag, s.adlen << 3); beputu64(tag[8..], s.clen << 3); ghash_ctmul64(s.tagbuf, s.h, tag); // use tmp to store the resulting tag encrypt(s.block as *block, tag, s.y0); xor(tag, tag, s.tagbuf); }; // Verifies the authentication tag against the decrypted data. Must be called // after reading all data from the stream to ensure that the data was not // modified. If the data was modified, [[errors::invalid]] will be returned and // the data must not be trusted. export fn gcm_verify(s: *gcmstream, tag: []u8) (void | errors::invalid) = { assert(len(tag) == GCMTAGSZ); if (s.xorbufpos > 0 && s.xorbufpos < GCMBLOCKSZ) { ghash_ctmul64(s.tagbuf, s.h, s.cipherbuf[..s.xorbufpos]); }; let tmp: [16]u8 = [0...]; beputu64(tmp, s.adlen << 3); beputu64(tmp[8..], s.clen << 3); ghash_ctmul64(s.tagbuf, s.h, tmp); encrypt(s.block as *block, tmp, s.y0); xor(tmp, tmp, s.tagbuf); if (eqslice(tag, tmp) == 0) { return errors::invalid; }; }; fn gcm_closer(s: *io::stream) (void | io::error) = { let s = s: *gcmstream; bytes::zero(s.tagbuf); bytes::zero(s.xorbuf); bytes::zero(s.cipherbuf); bytes::zero(s.y0); bytes::zero(s.h); if (s.block is *block) { finish(s.block as *block); }; }; hare-0.24.2/crypto/cipher/ghash.ha000066400000000000000000000075261464473310100167310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2016 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use bytes; use endian::{begetu64,beputu64}; fn bmul64(x: u64, y: u64) u64 = { const x0 = x & 0x1111111111111111; const x1 = x & 0x2222222222222222; const x2 = x & 0x4444444444444444; const x3 = x & 0x8888888888888888; const y0 = y & 0x1111111111111111; const y1 = y & 0x2222222222222222; const y2 = y & 0x4444444444444444; const y3 = y & 0x8888888888888888; let z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1); let z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2); let z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3); let z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0); z0 &= 0x1111111111111111; z1 &= 0x2222222222222222; z2 &= 0x4444444444444444; z3 &= 0x8888888888888888; return z0 | z1 | z2 | z3; }; fn rev64(x: u64) u64 = { x = ((x & 0x5555555555555555) << 1) | ((x >> 1) & 0x5555555555555555); x = ((x & 0x3333333333333333) << 2) | ((x >> 2) & 0x3333333333333333); x = ((x & 0x0F0F0F0F0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F0F0F0F0F); x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF00FF00FF); x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF); return (x << 32) | (x >> 32); }; // GHASH implementation that relies on constant time 64bit multiplication fn ghash_ctmul64(y: []u8, h: const []u8, data: const []u8) void = { let buf = data[..]; let tmp: [16]u8 = [0...]; let y1 = begetu64(y); let y0 = begetu64(y[8..]); const h1 = begetu64(h); const h0 = begetu64(h[8..]); const h0r = rev64(h0); const h1r = rev64(h1); const h2 = h0 ^ h1; const h2r = h0r ^ h1r; for (len(buf) > 0) { let src: []u8 = []; if (len(buf) >= 16) { src = buf[..16]; buf = buf[16..]; } else { tmp[..len(buf)] = buf[..]; bytes::zero(tmp[len(buf)..len(tmp)]); src = tmp; buf = []; }; y1 ^= begetu64(src); y0 ^= begetu64(src[8..]); const y0r = rev64(y0); const y1r = rev64(y1); const y2 = y0 ^ y1; const y2r = y0r ^ y1r; const z0 = bmul64(y0, h0); const z1 = bmul64(y1, h1); let z2 = bmul64(y2, h2); let z0h = bmul64(y0r, h0r); let z1h = bmul64(y1r, h1r); let z2h = bmul64(y2r, h2r); z2 ^= z0 ^ z1; z2h ^= z0h ^ z1h; z0h = rev64(z0h) >> 1; z1h = rev64(z1h) >> 1; z2h = rev64(z2h) >> 1; let v0 = z0; let v1 = z0h ^ z2; let v2 = z1 ^ z2h; let v3 = z1h; v3 = (v3 << 1) | (v2 >> 63); v2 = (v2 << 1) | (v1 >> 63); v1 = (v1 << 1) | (v0 >> 63); v0 = (v0 << 1); v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7); v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57); v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); y0 = v2; y1 = v3; }; beputu64(y, y1); beputu64(y[8..], y0); }; hare-0.24.2/crypto/cipher/stream.ha000066400000000000000000000046411464473310100171250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::math::{xor}; use io; // An abstract interface for implementing streams that encrypt or decrypt by // producing a key stream that is xored with the data. The stream field should // be set to &[[xorstream_vtable]]. // // After initializing the xorstream can be written to with [[io::write]] to // encrypt data and write it to the handle 'h'. For decrpytion 'h' will provide // the ciphertext and the plaintext can be read from the xorstream with // [[io::read]]. export type xorstream = struct { stream: io::stream, h: io::handle, // Returns usable part of the current key buffer. The buffer must be // modifiable by the callee. keybuf: *fn(s: *xorstream) []u8, // Advances the start index of the keybuffer by 'n' bytes. advance: *fn(s: *xorstream, n: size) void, // Erases all sensitive data from memory. finish: *fn(s: *xorstream) void, }; export const xorstream_vtable: io::vtable = io::vtable { writer = &xor_writer, reader = &xor_reader, closer = &xor_closer, ... }; fn xor_writer(s: *io::stream, in: const []u8) (size | io::error) = { let s = s: *xorstream; let keybuf = s.keybuf(s); const max = if (len(in) > len(keybuf)) { yield len(keybuf); } else { yield len(in); }; if (max == 0) { return 0z; }; keybuf = keybuf[..max]; // Modify the keybuf to store the cipher for writing, so that we won't // need additional space. xor(keybuf, keybuf, in[..max]); match (io::write(s.h, keybuf)) { case let n: size => if (n < max) { // revert the unused part of the keybuf to allow retry xor(keybuf[n..], keybuf[n..], in[n..max]); }; s.advance(s, n); return n; case let e: io::error => // revert the keybuf to allow retry xor(keybuf, keybuf, in[..max]); return e; }; }; fn xor_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let s = s: *xorstream; if (len(buf) == 0) { return 0z; }; match (io::read(s.h, buf)) { case io::EOF => return io::EOF; case let e: io::error => return e; case let n: size => for (let z = 0z; z < n) { let keybuf = s.keybuf(s); const max = if (n - z > len(keybuf)) { yield len(keybuf); } else { yield n - z; }; xor(buf[..max], buf[..max], keybuf[..max]); buf = buf[max..]; s.advance(s, max); z += max; }; return n; }; }; fn xor_closer(s: *io::stream) (void | io::error) = { let s = s: *xorstream; s.finish(s); }; hare-0.24.2/crypto/conventions.txt000066400000000000000000000014701464473310100171510ustar00rootroot00000000000000This is a WIP document offering some advice on how to implement cryptographic algorithms securely for Hare. All cryptographic algorithms must be constant time, such that an attacker cannot learn any secret information by analysis of the time required to complete a cryptographic operation. Not all of the math performed by cryptographic algorithms in Hare needs to be constant-time: just math whose inputs include secret information. It is important to know that secret data has been securely erased from memory when it is no longer required. A few items to note about Hare: - Return-by-value will leave garbage on the stack which is copied into the caller's stack frame and abandoned. You cannot return-by-value any objects which contain secret information. - To securely erase an array's contents, use bytes::zero. hare-0.24.2/crypto/curve25519/000077500000000000000000000000001464473310100155735ustar00rootroot00000000000000hare-0.24.2/crypto/curve25519/+test.ha000066400000000000000000000317651464473310100171530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::random; use encoding::hex; use fmt; use io; @test fn unpack25519() void = { let in: [SCALARSZ]u8 = [1u8...]; let fe = unpack25519(&in); let expected: elem = [257...]; for (let i = 0z; i < FIELDSZ; i += 1) { assert(fe[i] == expected[i]); }; }; @test fn subfe() void = { let in: [SCALARSZ]u8 = [1u8...]; let in2: [SCALARSZ]u8 = [3u8...]; let fe = unpack25519(&in); let fe2 = unpack25519(&in2); let out: elem = [0...]; subfe(&out, &fe2, &fe); let e2: elem = [514...]; for (let i = 0z; i < FIELDSZ; i += 1) { assert(out[i] == e2[i]); }; }; @test fn swap25519() void = { let pin: [SCALARSZ]u8 = [1u8...]; let qin: [SCALARSZ]u8 = [3u8...]; let p = unpack25519(&pin); let q = unpack25519(&qin); swap25519(&p, &q, 1); let expected = unpack25519(&qin); for (let i = 0z; i < FIELDSZ; i += 1) { assert(p[i] == expected[i]); }; expected = unpack25519(&pin); for (let i = 0z; i < FIELDSZ; i += 1) { assert(q[i] == expected[i]); }; swap25519(&p, &q, 0); // nop let expected = unpack25519(&qin); for (let i = 0z; i < FIELDSZ; i += 1) { assert(p[i] == expected[i]); }; expected = unpack25519(&pin); for (let i = 0z; i < FIELDSZ; i += 1) { assert(q[i] == expected[i]); }; }; @test fn unpackpack() void = { let in: [SCALARSZ]u8 = [1u8...]; let fe = unpack25519(&in); let expected: elem = [257...]; for (let i = 0z; i < FIELDSZ; i += 1) { assert(fe[i] == expected[i]); }; let out: [SCALARSZ]u8 = [0u8...]; pack25519(&out, &fe); for (let i = 0z; i < FIELDSZ; i += 1) { assert(in[i] == out[i]); }; }; @test fn x25519basepoint() void = { let x: [SCALARSZ]u8 = [1, 0...]; let out: [SCALARSZ]u8 = [0...]; for (let i = 0z; i < 200; i += 1) { clamp(&x); x25519(&out, &x, &BASEPOINT); x[..] = out[..]; }; let hex = hex::encodestr(out[..]); defer free(hex); const expectedhex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"; if (hex != expectedhex) { fmt::errorfln("\ngot {}, want {}", hex, expectedhex)!; abort(); }; }; @test fn vectors() void = { const vectors = [( [0x66u8, 0x8f, 0xb9, 0xf7, 0x6a, 0xd9, 0x71, 0xc8, 0x1a, 0xc9, 0x0, 0x7, 0x1a, 0x15, 0x60, 0xbc, 0xe2, 0xca, 0x0, 0xca, 0xc7, 0xe6, 0x7a, 0xf9, 0x93, 0x48, 0x91, 0x37, 0x61, 0x43, 0x40, 0x14], // in [0xdbu8, 0x5f, 0x32, 0xb7, 0xf8, 0x41, 0xe7, 0xa1, 0xa0, 0x9, 0x68, 0xef, 0xfd, 0xed, 0x12, 0x73, 0x5f, 0xc4, 0x7a, 0x3e, 0xb1, 0x3b, 0x57, 0x9a, 0xac, 0xad, 0xea, 0xe8, 0x9, 0x39, 0xa7, 0xdd], // base [0x9u8, 0xd, 0x85, 0xe5, 0x99, 0xea, 0x8e, 0x2b, 0xee, 0xb6, 0x13, 0x4, 0xd3, 0x7b, 0xe1, 0xe, 0xc5, 0xc9, 0x5, 0xf9, 0x92, 0x7d, 0x32, 0xf4, 0x2a, 0x9a, 0xa, 0xfb, 0x3e, 0xb, 0x40, 0x74], // expect ), ( [0x63, 0x66, 0x95, 0xe3, 0x4f, 0x75, 0xb9, 0xa2, 0x79, 0xc8, 0x70, 0x6f, 0xad, 0x12, 0x89, 0xf2, 0xc0, 0xb1, 0xe2, 0x2e, 0x16, 0xf8, 0xb8, 0x86, 0x17, 0x29, 0xc1, 0xa, 0x58, 0x29, 0x58, 0xaf], [0x9, 0xd, 0x7, 0x1, 0xf8, 0xfd, 0xe2, 0x8f, 0x70, 0x4, 0x3b, 0x83, 0xf2, 0x34, 0x62, 0x25, 0x41, 0x9b, 0x18, 0xa7, 0xf2, 0x7e, 0x9e, 0x3d, 0x2b, 0xfd, 0x4, 0xe1, 0xf, 0x3d, 0x21, 0x3e], [0xbf, 0x26, 0xec, 0x7e, 0xc4, 0x13, 0x6, 0x17, 0x33, 0xd4, 0x40, 0x70, 0xea, 0x67, 0xca, 0xb0, 0x2a, 0x85, 0xdc, 0x1b, 0xe8, 0xcf, 0xe1, 0xff, 0x73, 0xd5, 0x41, 0xcc, 0x8, 0x32, 0x55, 0x6], ), ( [0x73, 0x41, 0x81, 0xcd, 0x1a, 0x94, 0x6, 0x52, 0x2a, 0x56, 0xfe, 0x25, 0xe4, 0x3e, 0xcb, 0xf0, 0x29, 0x5d, 0xb5, 0xdd, 0xd0, 0x60, 0x9b, 0x3c, 0x2b, 0x4e, 0x79, 0xc0, 0x6f, 0x8b, 0xd4, 0x6d], [0xf8, 0xa8, 0x42, 0x1c, 0x7d, 0x21, 0xa9, 0x2d, 0xb3, 0xed, 0xe9, 0x79, 0xe1, 0xfa, 0x6a, 0xcb, 0x6, 0x2b, 0x56, 0xb1, 0x88, 0x5c, 0x71, 0xc5, 0x11, 0x53, 0xcc, 0xb8, 0x80, 0xac, 0x73, 0x15], [0x11, 0x76, 0xd0, 0x16, 0x81, 0xf2, 0xcf, 0x92, 0x9d, 0xa2, 0xc7, 0xa3, 0xdf, 0x66, 0xb5, 0xd7, 0x72, 0x9f, 0xd4, 0x22, 0x22, 0x6f, 0xd6, 0x37, 0x42, 0x16, 0xbf, 0x7e, 0x2, 0xfd, 0xf, 0x62], ), ( [0x1f, 0x70, 0x39, 0x1f, 0x6b, 0xa8, 0x58, 0x12, 0x94, 0x13, 0xbd, 0x80, 0x1b, 0x12, 0xac, 0xbf, 0x66, 0x23, 0x62, 0x82, 0x5c, 0xa2, 0x50, 0x9c, 0x81, 0x87, 0x59, 0xa, 0x2b, 0xe, 0x61, 0x72], [0xd3, 0xea, 0xd0, 0x7a, 0x0, 0x8, 0xf4, 0x45, 0x2, 0xd5, 0x80, 0x8b, 0xff, 0xc8, 0x97, 0x9f, 0x25, 0xa8, 0x59, 0xd5, 0xad, 0xf4, 0x31, 0x2e, 0xa4, 0x87, 0x48, 0x9c, 0x30, 0xe0, 0x1b, 0x3b], [0xf8, 0x48, 0x2f, 0x2e, 0x9e, 0x58, 0xbb, 0x6, 0x7e, 0x86, 0xb2, 0x87, 0x24, 0xb3, 0xc0, 0xa3, 0xbb, 0xb5, 0x7, 0x3e, 0x4c, 0x6a, 0xcd, 0x93, 0xdf, 0x54, 0x5e, 0xff, 0xdb, 0xba, 0x50, 0x5f], ), ( [0x3a, 0x7a, 0xe6, 0xcf, 0x8b, 0x88, 0x9d, 0x2b, 0x7a, 0x60, 0xa4, 0x70, 0xad, 0x6a, 0xd9, 0x99, 0x20, 0x6b, 0xf5, 0x7d, 0x90, 0x30, 0xdd, 0xf7, 0xf8, 0x68, 0xc, 0x8b, 0x1a, 0x64, 0x5d, 0xaa], [0x4d, 0x25, 0x4c, 0x80, 0x83, 0xd8, 0x7f, 0x1a, 0x9b, 0x3e, 0xa7, 0x31, 0xef, 0xcf, 0xf8, 0xa6, 0xf2, 0x31, 0x2d, 0x6f, 0xed, 0x68, 0xe, 0xf8, 0x29, 0x18, 0x51, 0x61, 0xc8, 0xfc, 0x50, 0x60], [0x47, 0xb3, 0x56, 0xd5, 0x81, 0x8d, 0xe8, 0xef, 0xac, 0x77, 0x4b, 0x71, 0x4c, 0x42, 0xc4, 0x4b, 0xe6, 0x85, 0x23, 0xdd, 0x57, 0xdb, 0xd7, 0x39, 0x62, 0xd5, 0xa5, 0x26, 0x31, 0x87, 0x62, 0x37], ), ( [0x20, 0x31, 0x61, 0xc3, 0x15, 0x9a, 0x87, 0x6a, 0x2b, 0xea, 0xec, 0x29, 0xd2, 0x42, 0x7f, 0xb0, 0xc7, 0xc3, 0xd, 0x38, 0x2c, 0xd0, 0x13, 0xd2, 0x7c, 0xc3, 0xd3, 0x93, 0xdb, 0xd, 0xaf, 0x6f], [0x6a, 0xb9, 0x5d, 0x1a, 0xbe, 0x68, 0xc0, 0x9b, 0x0, 0x5c, 0x3d, 0xb9, 0x4, 0x2c, 0xc9, 0x1a, 0xc8, 0x49, 0xf7, 0xe9, 0x4a, 0x2a, 0x4a, 0x9b, 0x89, 0x36, 0x78, 0x97, 0xb, 0x7b, 0x95, 0xbf], [0x11, 0xed, 0xae, 0xdc, 0x95, 0xff, 0x78, 0xf5, 0x63, 0xa1, 0xc8, 0xf1, 0x55, 0x91, 0xc0, 0x71, 0xde, 0xa0, 0x92, 0xb4, 0xd7, 0xec, 0xaa, 0xc8, 0xe0, 0x38, 0x7b, 0x5a, 0x16, 0xc, 0x4e, 0x5d], ), ( [0x13, 0xd6, 0x54, 0x91, 0xfe, 0x75, 0xf2, 0x3, 0xa0, 0x8, 0xb4, 0x41, 0x5a, 0xbc, 0x60, 0xd5, 0x32, 0xe6, 0x95, 0xdb, 0xd2, 0xf1, 0xe8, 0x3, 0xac, 0xcb, 0x34, 0xb2, 0xb7, 0x2c, 0x3d, 0x70], [0x2e, 0x78, 0x4e, 0x4, 0xca, 0x0, 0x73, 0x33, 0x62, 0x56, 0xa8, 0x39, 0x25, 0x5e, 0xd2, 0xf7, 0xd4, 0x79, 0x6a, 0x64, 0xcd, 0xc3, 0x7f, 0x1e, 0xb0, 0xe5, 0xc4, 0xc8, 0xd1, 0xd1, 0xe0, 0xf5], [0x56, 0x3e, 0x8c, 0x9a, 0xda, 0xa7, 0xd7, 0x31, 0x1, 0xb0, 0xf2, 0xea, 0xd3, 0xca, 0xe1, 0xea, 0x5d, 0x8f, 0xcd, 0x5c, 0xd3, 0x60, 0x80, 0xbb, 0x8e, 0x6e, 0xc0, 0x3d, 0x61, 0x45, 0x9, 0x17], ), ( [0x68, 0x6f, 0x7d, 0xa9, 0x3b, 0xf2, 0x68, 0xe5, 0x88, 0x6, 0x98, 0x31, 0xf0, 0x47, 0x16, 0x3f, 0x33, 0x58, 0x99, 0x89, 0xd0, 0x82, 0x6e, 0x98, 0x8, 0xfb, 0x67, 0x8e, 0xd5, 0x7e, 0x67, 0x49], [0x8b, 0x54, 0x9b, 0x2d, 0xf6, 0x42, 0xd3, 0xb2, 0x5f, 0xe8, 0x38, 0xf, 0x8c, 0xc4, 0x37, 0x5f, 0x99, 0xb7, 0xbb, 0x4d, 0x27, 0x5f, 0x77, 0x9f, 0x3b, 0x7c, 0x81, 0xb8, 0xa2, 0xbb, 0xc1, 0x29], [0x1, 0x47, 0x69, 0x65, 0x42, 0x6b, 0x61, 0x71, 0x74, 0x9a, 0x8a, 0xdd, 0x92, 0x35, 0x2, 0x5c, 0xe5, 0xf5, 0x57, 0xfe, 0x40, 0x9, 0xf7, 0x39, 0x30, 0x44, 0xeb, 0xbb, 0x8a, 0xe9, 0x52, 0x79], ), ( [0x82, 0xd6, 0x1c, 0xce, 0xdc, 0x80, 0x6a, 0x60, 0x60, 0xa3, 0x34, 0x9a, 0x5e, 0x87, 0xcb, 0xc7, 0xac, 0x11, 0x5e, 0x4f, 0x87, 0x77, 0x62, 0x50, 0xae, 0x25, 0x60, 0x98, 0xa7, 0xc4, 0x49, 0x59], [0x8b, 0x6b, 0x9d, 0x8, 0xf6, 0x1f, 0xc9, 0x1f, 0xe8, 0xb3, 0x29, 0x53, 0xc4, 0x23, 0x40, 0xf0, 0x7, 0xb5, 0x71, 0xdc, 0xb0, 0xa5, 0x6d, 0x10, 0x72, 0x4e, 0xce, 0xf9, 0x95, 0xc, 0xfb, 0x25], [0x9c, 0x49, 0x94, 0x1f, 0x9c, 0x4f, 0x18, 0x71, 0xfa, 0x40, 0x91, 0xfe, 0xd7, 0x16, 0xd3, 0x49, 0x99, 0xc9, 0x52, 0x34, 0xed, 0xf2, 0xfd, 0xfb, 0xa6, 0xd1, 0x4a, 0x5a, 0xfe, 0x9e, 0x5, 0x58], ), ( [0x7d, 0xc7, 0x64, 0x4, 0x83, 0x13, 0x97, 0xd5, 0x88, 0x4f, 0xdf, 0x6f, 0x97, 0xe1, 0x74, 0x4c, 0x9e, 0xb1, 0x18, 0xa3, 0x1a, 0x7b, 0x23, 0xf8, 0xd7, 0x9f, 0x48, 0xce, 0x9c, 0xad, 0x15, 0x4b], [0x1a, 0xcd, 0x29, 0x27, 0x84, 0xf4, 0x79, 0x19, 0xd4, 0x55, 0xf8, 0x87, 0x44, 0x83, 0x58, 0x61, 0xb, 0xb9, 0x45, 0x96, 0x70, 0xeb, 0x99, 0xde, 0xe4, 0x60, 0x5, 0xf6, 0x89, 0xca, 0x5f, 0xb6], [0x0, 0xf4, 0x3c, 0x2, 0x2e, 0x94, 0xea, 0x38, 0x19, 0xb0, 0x36, 0xae, 0x2b, 0x36, 0xb2, 0xa7, 0x61, 0x36, 0xaf, 0x62, 0x8a, 0x75, 0x1f, 0xe5, 0xd0, 0x1e, 0x3, 0xd, 0x44, 0x25, 0x88, 0x59], ), ( [0xfb, 0xc4, 0x51, 0x1d, 0x23, 0xa6, 0x82, 0xae, 0x4e, 0xfd, 0x8, 0xc8, 0x17, 0x9c, 0x1c, 0x6, 0x7f, 0x9c, 0x8b, 0xe7, 0x9b, 0xbc, 0x4e, 0xff, 0x5c, 0xe2, 0x96, 0xc6, 0xbc, 0x1f, 0xf4, 0x45], [0x55, 0xca, 0xff, 0x21, 0x81, 0xf2, 0x13, 0x6b, 0xe, 0xd0, 0xe1, 0xe2, 0x99, 0x44, 0x48, 0xe1, 0x6c, 0xc9, 0x70, 0x64, 0x6a, 0x98, 0x3d, 0x14, 0xd, 0xc4, 0xea, 0xb3, 0xd9, 0x4c, 0x28, 0x4e], [0xae, 0x39, 0xd8, 0x16, 0x53, 0x23, 0x45, 0x79, 0x4d, 0x26, 0x91, 0xe0, 0x80, 0x1c, 0xaa, 0x52, 0x5f, 0xc3, 0x63, 0x4d, 0x40, 0x2c, 0xe9, 0x58, 0xb, 0x33, 0x38, 0xb4, 0x6f, 0x8b, 0xb9, 0x72], ), ( [0x4e, 0x6, 0xc, 0xe1, 0xc, 0xeb, 0xf0, 0x95, 0x9, 0x87, 0x16, 0xc8, 0x66, 0x19, 0xeb, 0x9f, 0x7d, 0xf6, 0x65, 0x24, 0x69, 0x8b, 0xa7, 0x98, 0x8c, 0x3b, 0x90, 0x95, 0xd9, 0xf5, 0x1, 0x34], [0x57, 0x73, 0x3f, 0x2d, 0x86, 0x96, 0x90, 0xd0, 0xd2, 0xed, 0xae, 0xc9, 0x52, 0x3d, 0xaa, 0x2d, 0xa9, 0x54, 0x45, 0xf4, 0x4f, 0x57, 0x83, 0xc1, 0xfa, 0xec, 0x6c, 0x3a, 0x98, 0x28, 0x18, 0xf3], [0xa6, 0x1e, 0x74, 0x55, 0x2c, 0xce, 0x75, 0xf5, 0xe9, 0x72, 0xe4, 0x24, 0xf2, 0xcc, 0xb0, 0x9c, 0x83, 0xbc, 0x1b, 0x67, 0x1, 0x47, 0x48, 0xf0, 0x2c, 0x37, 0x1a, 0x20, 0x9e, 0xf2, 0xfb, 0x2c], ), ( [0x5c, 0x49, 0x2c, 0xba, 0x2c, 0xc8, 0x92, 0x48, 0x8a, 0x9c, 0xeb, 0x91, 0x86, 0xc2, 0xaa, 0xc2, 0x2f, 0x1, 0x5b, 0xf3, 0xef, 0x8d, 0x3e, 0xcc, 0x9c, 0x41, 0x76, 0x97, 0x62, 0x61, 0xaa, 0xb1], [0x67, 0x97, 0xc2, 0xe7, 0xdc, 0x92, 0xcc, 0xbe, 0x7c, 0x5, 0x6b, 0xec, 0x35, 0xa, 0xb6, 0xd3, 0xbd, 0x2a, 0x2c, 0x6b, 0xc5, 0xa8, 0x7, 0xbb, 0xca, 0xe1, 0xf6, 0xc2, 0xaf, 0x80, 0x36, 0x44], [0xfc, 0xf3, 0x7, 0xdf, 0xbc, 0x19, 0x2, 0xb, 0x28, 0xa6, 0x61, 0x8c, 0x6c, 0x62, 0x2f, 0x31, 0x7e, 0x45, 0x96, 0x7d, 0xac, 0xf4, 0xae, 0x4a, 0xa, 0x69, 0x9a, 0x10, 0x76, 0x9f, 0xde, 0x14], ), ( [0xea, 0x33, 0x34, 0x92, 0x96, 0x5, 0x5a, 0x4e, 0x8b, 0x19, 0x2e, 0x3c, 0x23, 0xc5, 0xf4, 0xc8, 0x44, 0x28, 0x2a, 0x3b, 0xfc, 0x19, 0xec, 0xc9, 0xdc, 0x64, 0x6a, 0x42, 0xc3, 0x8d, 0xc2, 0x48], [0x2c, 0x75, 0xd8, 0x51, 0x42, 0xec, 0xad, 0x3e, 0x69, 0x44, 0x70, 0x4, 0x54, 0xc, 0x1c, 0x23, 0x54, 0x8f, 0xc8, 0xf4, 0x86, 0x25, 0x1b, 0x8a, 0x19, 0x46, 0x3f, 0x3d, 0xf6, 0xf8, 0xac, 0x61], [0x5d, 0xca, 0xb6, 0x89, 0x73, 0xf9, 0x5b, 0xd3, 0xae, 0x4b, 0x34, 0xfa, 0xb9, 0x49, 0xfb, 0x7f, 0xb1, 0x5a, 0xf1, 0xd8, 0xca, 0xe2, 0x8c, 0xd6, 0x99, 0xf9, 0xc1, 0xaa, 0x33, 0x37, 0x34, 0x2f], ), ( [0x4f, 0x29, 0x79, 0xb1, 0xec, 0x86, 0x19, 0xe4, 0x5c, 0xa, 0xb, 0x2b, 0x52, 0x9, 0x34, 0x54, 0x1a, 0xb9, 0x44, 0x7, 0xb6, 0x4d, 0x19, 0xa, 0x76, 0xf3, 0x23, 0x14, 0xef, 0xe1, 0x84, 0xe7], [0xf7, 0xca, 0xe1, 0x8d, 0x8d, 0x36, 0xa7, 0xf5, 0x61, 0x17, 0xb8, 0xb7, 0xe, 0x25, 0x52, 0x27, 0x7f, 0xfc, 0x99, 0xdf, 0x87, 0x56, 0xb5, 0xe1, 0x38, 0xbf, 0x63, 0x68, 0xbc, 0x87, 0xf7, 0x4c], [0xe4, 0xe6, 0x34, 0xeb, 0xb4, 0xfb, 0x66, 0x4f, 0xe8, 0xb2, 0xcf, 0xa1, 0x61, 0x5f, 0x0, 0xe6, 0x46, 0x6f, 0xff, 0x73, 0x2c, 0xe1, 0xf8, 0xa0, 0xc8, 0xd2, 0x72, 0x74, 0x31, 0xd1, 0x6f, 0x14], ), ( [0xf5, 0xd8, 0xa9, 0x27, 0x90, 0x1d, 0x4f, 0xa4, 0x24, 0x90, 0x86, 0xb7, 0xff, 0xec, 0x24, 0xf5, 0x29, 0x7d, 0x80, 0x11, 0x8e, 0x4a, 0xc9, 0xd3, 0xfc, 0x9a, 0x82, 0x37, 0x95, 0x1e, 0x3b, 0x7f], [0x3c, 0x23, 0x5e, 0xdc, 0x2, 0xf9, 0x11, 0x56, 0x41, 0xdb, 0xf5, 0x16, 0xd5, 0xde, 0x8a, 0x73, 0x5d, 0x6e, 0x53, 0xe2, 0x2a, 0xa2, 0xac, 0x14, 0x36, 0x56, 0x4, 0x5f, 0xf2, 0xe9, 0x52, 0x49], [0xab, 0x95, 0x15, 0xab, 0x14, 0xaf, 0x9d, 0x27, 0xe, 0x1d, 0xae, 0xc, 0x56, 0x80, 0xcb, 0xc8, 0x88, 0xb, 0xd8, 0xa8, 0xe7, 0xeb, 0x67, 0xb4, 0xda, 0x42, 0xa6, 0x61, 0x96, 0x1e, 0xfc, 0xb], ), ( [0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4], [0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c], [0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52], )]; for (let i = 0z; i < len(vectors); i += 1) { let got: [SCALARSZ]u8 = [0...]; let scalar = vectors[i].0; clamp(&scalar); scalarmult(&got, &scalar, &vectors[i].1); if (!bytes::equal(got[..], vectors[i].2[..])) { fmt::errorfln("Case i={} failed", i)!; printvector("in", &vectors[i].0); printvector("base", &vectors[i].1); printvector("got", &got); printvector("expect", &vectors[i].2); abort(); }; }; }; @test fn highbitignored() void = { let s: [SCALARSZ]u8 = [0...]; let u: [POINTSZ]u8 = [0...]; io::readall(random::stream, s[..])!; io::readall(random::stream, u[..])!; let hi0: [32]u8 = [0...]; let hi1: [32]u8 = [0...]; u[31] &= 0x7f; scalarmult(&hi0, &s, &u); u[31] |= 0x80; scalarmult(&hi1, &s, &u); if (!bytes::equal(hi0[..], hi1[..])) { fmt::errorfln("high bit of group point should not affect result")!; abort(); }; }; fn printvector(name: str, vec: const *[SCALARSZ]u8) void = { fmt::errorf("{:6} = [", name)!; for (let i = 0z; i < 31; i += 1) { fmt::errorf("{:.2x}, ", vec[i])!; }; fmt::errorfln("{:.2x}]", vec[31])!; }; hare-0.24.2/crypto/curve25519/README000066400000000000000000000013131464473310100164510ustar00rootroot00000000000000The curve25519 module implements the x25519 function which performs scalar multiplication on the elliptic curve known as Curve25519. See RFC 7748. The implementation is based on the paper "Implementing Curve25519/X25519: A Tutorial on Elliptic Curve Cryptography" by Martin Kleppmann. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/curve25519/curve25519.ha000066400000000000000000000123721464473310100176440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; // Implements the curve25519 elliptic curve // Implementations used for reference // // Kleppmann: https://martin.kleppmann.com/papers/curve25519.pdf // OpenSSL: https://github.com/openssl/openssl/blob/master/crypto/ec/curve25519.c // Go: https://github.com/golang/crypto/blob/master/curve25519/curve25519.go // TweetNaCl: https://tweetnacl.cr.yp.to/ // The size of the scalar input to X25519. export def SCALARSZ: size = 32; // The size of the point input to X25519. export def POINTSZ: size = 32; // The canonical Curve25519 generator export const BASEPOINT: [POINTSZ]u8 = [9, 0...]; // An internal representation used for arithmetic operations. def FIELDSZ: size = 16; type elem = [FIELDSZ]i64; // Constant used in scalar multiplication. const _121665: elem = [0xdb41, 1, 0...]; // Compute the result of the scalar multiplication (scalar * point) and put the // result in out. export fn x25519( out: []u8, scalar: const []u8, point: const []u8, ) void = { assert(len(out) == SCALARSZ); assert(len(scalar) == SCALARSZ); assert(len(point) == POINTSZ); scalarmult(out, scalar, point); }; // Compute the result of the scalar multiplication (scalar * point) where point // is BASEPOINT. export fn scalarmult_base( out: []u8, scalar: const []u8 ) void = { assert(len(out) == SCALARSZ); assert(len(scalar) == SCALARSZ); scalarmult(out, scalar, &BASEPOINT); }; // Prepares the scalar to avoid particular attacks. See the "clamping" section // in Kleppmann's paper. export fn clamp(scalar: []u8) void = { assert(len(scalar) == SCALARSZ); scalar[0] &= 0xf8; scalar[31] = (scalar[31] & 0x7f) | 0x40; }; // Set out to the product (scalar * point) export fn scalarmult( out: []u8, scalar: const []u8, point: const []u8 ) void = { assert(len(out) == SCALARSZ); assert(len(scalar) == SCALARSZ); assert(len(point) == POINTSZ); let clamped: [SCALARSZ]u8 = [0...]; clamped[..] = scalar[..]; defer bytes::zero(clamped); clamp(&clamped); let x = unpack25519(point); let a: elem = [1, 0...]; let b: elem = x; let c: elem = [0...]; let d: elem = [1, 0...]; let e: elem = [0...]; let f: elem = [0...]; for (let i = 254i; i >= 0; i -= 1) { let iz = i : size; let bit = ((clamped[iz >> 3] >> (iz & 7)) & 1) : i64; swap25519(&a, &b, bit); swap25519(&c, &d, bit); addfe(&e, &a, &c); subfe(&a, &a, &c); addfe(&c, &b, &d); subfe(&b, &b, &d); mulfe(&d, &e, &e); mulfe(&f, &a, &a); mulfe(&a, &c, &a); mulfe(&c, &b, &e); addfe(&e, &a, &c); subfe(&a, &a, &c); mulfe(&b, &a, &a); subfe(&c, &d, &f); mulfe(&a, &c, &_121665); addfe(&a, &a, &d); mulfe(&c, &c, &a); mulfe(&a, &d, &f); mulfe(&d, &b, &x); mulfe(&b, &e, &e); swap25519(&a, &b, bit); swap25519(&c, &d, bit); }; invfe(&c, &c); mulfe(&a, &a, &c); pack25519(out, &a); }; fn unpack25519(in: []u8) elem = { let fe: elem = [0...]; for (let i = 0z; i < FIELDSZ; i += 1) { fe[i] = in[2 * i]: i64 + ((in[2 * i + 1]: i64) << 8); }; fe[15] &= 0x7fff; return fe; }; fn carry25519(fe: *elem) void = { let carry = 0i64; for (let i = 0z; i < FIELDSZ; i += 1) { carry = fe[i] >> 16; fe[i] -= (carry << 16); if (i < 15) { fe[i + 1] += carry; } else { fe[0] += (38 * carry); }; }; }; // Set out = a + b fn addfe(out: *elem, a: const *elem, b: const *elem) void = { for (let i = 0z; i < FIELDSZ; i += 1) { out[i] = a[i] + b[i]; }; }; // Set out = a - b fn subfe(out: *elem, a: const *elem, b: const *elem) void = { for (let i = 0z; i < FIELDSZ; i += 1) { out[i] = a[i] - b[i]; }; }; // Set out = a * b fn mulfe(out: *elem, a: const *elem, b: const *elem) void = { let product: [31]i64 = [0...]; for (let i = 0z; i < FIELDSZ; i += 1) { for (let j = 0z; j < FIELDSZ; j += 1) { product[i + j] += a[i] * b[j]; }; }; for (let i = 0z; i < 15; i += 1) { product[i] += (38 * product[i + 16]); }; out[0..FIELDSZ] = product[0..FIELDSZ]; carry25519(out); carry25519(out); }; // Compute the multiplicative inverse fn invfe(out: *elem, a: const *elem) void = { let c: elem = *a; for (let i = 253i; i >= 0; i -= 1) { mulfe(&c, &c, &c); if (i != 2 && i != 4) { mulfe(&c, &c, a); }; }; out[..] = c[..]; }; // Swap inputs p and q, if bit is 1, do nothing if bit is 0. // // If bit is 1, this function swaps the content of parameters p and q (both in // elem representation), and it does nothing if bit is 0. As bit may be // part of a secret value, this function cannot use a simple if statement, // because that would not be constant-time fn swap25519(p: *elem, q: *elem, bit: i64) void = { let c = ~(bit : u64 - 1) : i64; for (let i = 0z; i < FIELDSZ; i += 1) { let t = c & (p[i] ^ q[i]); p[i] ^= t; q[i] ^= t; }; }; fn pack25519(out: []u8, a: const *elem) void = { let m: elem = [0...]; let t: elem = *a; carry25519(&t); carry25519(&t); carry25519(&t); for (let _i = 0z; _i < 2; _i += 1) { m[0] = t[0] - 0xffed; for (let i = 1z; i < 15; i += 1) { m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); m[i - 1] &= 0xffff; }; m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); let carry = (m[15] >> 16) & 1; m[14] &= 0xffff; swap25519(&t, &m, 1 - carry); }; for (let i = 0z; i < FIELDSZ; i += 1) { out[2 * i] = (t[i] & 0xff) : u8; out[2 * i + 1] = (t[i] >> 8) : u8; }; }; hare-0.24.2/crypto/ec/000077500000000000000000000000001464473310100144305ustar00rootroot00000000000000hare-0.24.2/crypto/ec/README000066400000000000000000000010251464473310100153060ustar00rootroot00000000000000The crypto::ec module provides implementations for a selection of elliptic curves and their operations. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/ec/curves+test.ha000066400000000000000000001167101464473310100172320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; // Testcases have been generated with help of pycryptdome. type multc = struct { a: []u8, b: []u8, x: []u8, y: []u8, result: u32, expected: []u8, }; fn tmuladd(c: *curve, tcs: []multc) void = { for (let i = 0z; i < len(tcs); i += 1) { let t = tcs[i]; assert(c.muladd(t.a, t.b, t.x, t.y) == t.result); if (t.result == 1) { assert(bytes::equal(t.a, t.expected)); }; }; }; @test fn p256_mulgen() void = { const c = p256; // multiply by 1 let m1: [P256_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; let g = alloc(P256_G); defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P256_G)); assert(c.mulgen(g, m1) == 65); assert(bytes::equal(g, P256_G)); // multiply by order - 1 let o = alloc(P256_N); defer free(o); o[len(o) - 1] -= 1; const expected: [_]u8 = [ 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0xb0, 0x1c, 0xbd, 0x1c, 0x01, 0xe5, 0x80, 0x65, 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a, ]; assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); let g = alloc(P256_G); defer free(g); assert(c.mulgen(g, o) == 65); assert(bytes::equal(g, expected)); let priv: [_]u8 = [ 0xde, 0x5c, 0x88, 0x05, 0x42, 0xa0, 0x71, 0xe2, 0xf6, 0xfe, 0xd0, 0xdc, 0x80, 0x07, 0x37, 0xc4, 0x35, 0xa6, 0x29, 0x48, 0x85, 0x70, 0x4f, 0x54, 0x1c, 0x41, 0x89, 0xaf, 0xf6, 0xbc, 0xb5, 0x19, ]; const expected: [_]u8 = [ 0x04, 0x8a, 0x0d, 0x13, 0x84, 0x8e, 0x4f, 0xdb, 0x05, 0x83, 0x8e, 0x76, 0x24, 0xf9, 0x8a, 0xb2, 0x83, 0x5a, 0x79, 0xb0, 0x65, 0x63, 0x9b, 0x4c, 0x30, 0xcf, 0x69, 0x31, 0x46, 0xf7, 0x10, 0x49, 0x13, 0x46, 0x0b, 0xb0, 0x4e, 0x3e, 0x44, 0x7f, 0xad, 0x96, 0xfa, 0xfb, 0xc5, 0x78, 0xc0, 0xee, 0xc6, 0xc4, 0x88, 0xa3, 0xe5, 0xc3, 0x10, 0x3c, 0x63, 0x24, 0xc1, 0x48, 0x43, 0x37, 0x13, 0xdf, 0xc9, ]; let g = alloc(P256_G); defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); let r: [65]u8 = [0...]; assert(c.mulgen(r, priv) == 65); assert(bytes::equal(r, expected)); }; @test fn p256_muladd() void = { let c = p256; let tcs: [_]multc = [ multc { a = [ 0x04, 0xee, 0x19, 0x71, 0x69, 0xae, 0xbd, 0x94, 0xc7, 0x8d, 0x4e, 0x7f, 0x05, 0x06, 0xb4, 0xdf, 0x60, 0x43, 0x22, 0x2c, 0x50, 0x8d, 0x33, 0x8a, 0x5a, 0xd0, 0x02, 0x60, 0x95, 0x5e, 0xda, 0x31, 0x64, 0x4c, 0x7e, 0x63, 0xa9, 0xa0, 0xaf, 0x56, 0xbb, 0x7c, 0x03, 0x84, 0x8a, 0x44, 0x30, 0xfd, 0x39, 0x1d, 0xc0, 0x0f, 0x5c, 0x50, 0xcf, 0xda, 0xf1, 0x99, 0x69, 0x8e, 0x77, 0x62, 0x56, 0x34, 0xce, ], b = [], x = [ 0xef, 0xcb, 0x7a, 0x72, 0x9c, 0xb4, 0x6a, 0xe6, 0xb4, 0x66, 0xa6, 0x8c, 0x1a, 0x18, 0x64, 0x5c, 0xd8, 0xdc, 0x9d, 0xa2, 0x5b, 0x48, 0x45, 0xcd, 0x68, 0x0c, 0x5f, 0x93, 0x1b, 0x74, 0x42, 0x0b, ], y = [ 0x7b, 0x6b, 0x8f, 0x14, 0x8b, 0x7a, 0x5d, 0xbe, 0xa5, 0xd0, 0x6b, 0x7a, 0x3c, 0xaa, 0x6f, 0x4b, 0x2a, 0xeb, 0x52, 0x7e, 0x80, 0xdb, 0xc5, 0x95, 0x73, 0x91, 0xab, 0x3d, 0x29, 0xbc, 0xbd, 0x74, ], result = 1, expected = [ 0x04, 0x85, 0x93, 0xaf, 0x32, 0x68, 0x1c, 0xa8, 0xba, 0xf8, 0x64, 0x4e, 0xd3, 0xd8, 0xf3, 0x52, 0x88, 0xdf, 0x3b, 0x92, 0x5b, 0xb4, 0xbb, 0xf6, 0xd4, 0x2c, 0xce, 0x42, 0x8c, 0xa5, 0x9b, 0xd4, 0xb0, 0x87, 0xac, 0xfe, 0x83, 0xcc, 0x11, 0xd1, 0x98, 0x3e, 0x63, 0xc8, 0xba, 0xc1, 0x8e, 0x7e, 0xf2, 0xd1, 0xa7, 0x78, 0x93, 0xa8, 0x71, 0x9e, 0xee, 0xd2, 0xf9, 0xe3, 0xf3, 0x0a, 0xda, 0xf6, 0x26, ], }, multc { a = [ 0x04, 0xee, 0x19, 0x71, 0x69, 0xae, 0xbd, 0x94, 0xc7, 0x8d, 0x4e, 0x7f, 0x05, 0x06, 0xb4, 0xdf, 0x60, 0x43, 0x22, 0x2c, 0x50, 0x8d, 0x33, 0x8a, 0x5a, 0xd0, 0x02, 0x60, 0x95, 0x5e, 0xda, 0x31, 0x64, 0x4c, 0x7e, 0x63, 0xa9, 0xa0, 0xaf, 0x56, 0xbb, 0x7c, 0x03, 0x84, 0x8a, 0x44, 0x30, 0xfd, 0x39, 0x1d, 0xc0, 0x0f, 0x5c, 0x50, 0xcf, 0xda, 0xf1, 0x99, 0x69, 0x8e, 0x77, 0x62, 0x56, 0x34, 0xce, ], b = [ 0x04, 0xbd, 0x52, 0x07, 0x83, 0x40, 0x88, 0x6a, 0xa5, 0x24, 0xd8, 0x22, 0x13, 0x4f, 0xc3, 0xf3, 0x03, 0xca, 0xe1, 0xd3, 0x5e, 0x01, 0x95, 0x82, 0x5f, 0xa9, 0x95, 0x9f, 0xc3, 0xc4, 0x92, 0x8f, 0xd2, 0x30, 0x18, 0x56, 0x29, 0x93, 0x74, 0x50, 0xbd, 0xa6, 0x8d, 0x88, 0xf6, 0x03, 0xd6, 0x16, 0xd9, 0x9d, 0x01, 0x82, 0xbe, 0x08, 0x13, 0xec, 0x9f, 0xb4, 0xb1, 0x18, 0xbc, 0x14, 0x09, 0x31, 0xad, ], x = [ 0xef, 0xcb, 0x7a, 0x72, 0x9c, 0xb4, 0x6a, 0xe6, 0xb4, 0x66, 0xa6, 0x8c, 0x1a, 0x18, 0x64, 0x5c, 0xd8, 0xdc, 0x9d, 0xa2, 0x5b, 0x48, 0x45, 0xcd, 0x68, 0x0c, 0x5f, 0x93, 0x1b, 0x74, 0x42, 0x0b, ], y = [ 0x7b, 0x6b, 0x8f, 0x14, 0x8b, 0x7a, 0x5d, 0xbe, 0xa5, 0xd0, 0x6b, 0x7a, 0x3c, 0xaa, 0x6f, 0x4b, 0x2a, 0xeb, 0x52, 0x7e, 0x80, 0xdb, 0xc5, 0x95, 0x73, 0x91, 0xab, 0x3d, 0x29, 0xbc, 0xbd, 0x74, ], result = 1, expected = [ 0x04, 0x7f, 0x66, 0x4b, 0x8c, 0x3e, 0x64, 0x5b, 0xc1, 0x97, 0x60, 0xac, 0xa6, 0xc3, 0x0c, 0x17, 0x80, 0xff, 0xd0, 0x95, 0xcd, 0x4d, 0x5b, 0xf1, 0x35, 0x25, 0x53, 0x5a, 0xec, 0xff, 0xb1, 0xd9, 0xdb, 0xdd, 0x96, 0xe3, 0xfb, 0x84, 0x68, 0x2b, 0x53, 0x04, 0x4b, 0xcd, 0x7c, 0x4e, 0x10, 0xfa, 0x87, 0x4c, 0x14, 0x43, 0xf0, 0x1b, 0x57, 0x39, 0x02, 0x35, 0x44, 0xef, 0xa0, 0x38, 0xb5, 0x70, 0xb8, ], }, // invalid a multc { a = [ 0x04, 0xee, 0x19, 0x71, 0x69, 0xae, 0xbd, 0x94, 0xc7, 0x8d, 0x4e, 0x0f, 0x05, 0x06, 0xb4, 0xdf, 0x60, 0x43, 0x22, 0x0c, 0x50, 0x8d, 0x33, 0x8a, 0x5a, 0xd0, 0x02, 0x00, 0x95, 0x5e, 0xda, 0x31, 0x64, 0x4c, 0x7e, 0x03, 0xa9, 0xa0, 0xaf, 0x56, 0xbb, 0x7c, 0x03, 0x04, 0x8a, 0x44, 0x30, 0xfd, 0x39, 0x1d, 0xc0, 0x0f, 0x5c, 0x50, 0xcf, 0xda, 0xf1, 0x99, 0x69, 0x0e, 0x77, 0x62, 0x56, 0x34, 0xce, ], b = [ 0x04, 0xbd, 0x52, 0x07, 0x83, 0x40, 0x88, 0x6a, 0xa5, 0x24, 0xd8, 0x22, 0x13, 0x4f, 0xc3, 0xf3, 0x03, 0xca, 0xe1, 0xd3, 0x5e, 0x01, 0x95, 0x82, 0x5f, 0xa9, 0x95, 0x9f, 0xc3, 0xc4, 0x92, 0x8f, 0xd2, 0x30, 0x18, 0x56, 0x29, 0x93, 0x74, 0x50, 0xbd, 0xa6, 0x8d, 0x88, 0xf6, 0x03, 0xd6, 0x16, 0xd9, 0x9d, 0x01, 0x82, 0xbe, 0x08, 0x13, 0xec, 0x9f, 0xb4, 0xb1, 0x18, 0xbc, 0x14, 0x09, 0x31, 0xad, ], x = [ 0xef, 0xcb, 0x7a, 0x72, 0x9c, 0xb4, 0x6a, 0xe6, 0xb4, 0x66, 0xa6, 0x8c, 0x1a, 0x18, 0x64, 0x5c, 0xd8, 0xdc, 0x9d, 0xa2, 0x5b, 0x48, 0x45, 0xcd, 0x68, 0x0c, 0x5f, 0x93, 0x1b, 0x74, 0x42, 0x0b, ], y = [ 0x7b, 0x6b, 0x8f, 0x14, 0x8b, 0x7a, 0x5d, 0xbe, 0xa5, 0xd0, 0x6b, 0x7a, 0x3c, 0xaa, 0x6f, 0x4b, 0x2a, 0xeb, 0x52, 0x7e, 0x80, 0xdb, 0xc5, 0x95, 0x73, 0x91, 0xab, 0x3d, 0x29, 0xbc, 0xbd, 0x74, ], result = 0, expected = [], }, // invalid b multc { a = [ 0x04, 0xee, 0x19, 0x71, 0x69, 0xae, 0xbd, 0x94, 0xc7, 0x8d, 0x4e, 0x7f, 0x05, 0x06, 0xb4, 0xdf, 0x60, 0x43, 0x22, 0x2c, 0x50, 0x8d, 0x33, 0x8a, 0x5a, 0xd0, 0x02, 0x60, 0x95, 0x5e, 0xda, 0x31, 0x64, 0x4c, 0x7e, 0x63, 0xa9, 0xa0, 0xaf, 0x56, 0xbb, 0x7c, 0x03, 0x84, 0x8a, 0x44, 0x30, 0xfd, 0x39, 0x1d, 0xc0, 0x0f, 0x5c, 0x50, 0xcf, 0xda, 0xf1, 0x99, 0x69, 0x8e, 0x77, 0x62, 0x56, 0x34, 0xce, ], b = [ 0x04, 0xbd, 0x52, 0x07, 0x83, 0x40, 0x88, 0x6a, 0xf5, 0x24, 0xd8, 0x22, 0x13, 0x4f, 0xc3, 0xf3, 0xf3, 0xca, 0xe1, 0xd3, 0x5e, 0x01, 0x95, 0x82, 0x3f, 0xa9, 0x95, 0x9f, 0xc3, 0xc4, 0x92, 0x8f, 0x52, 0x30, 0x18, 0x56, 0x29, 0x93, 0x74, 0x50, 0x1d, 0xa6, 0x8d, 0x88, 0xf6, 0x03, 0xd6, 0x16, 0xd9, 0x9d, 0x01, 0x82, 0xbe, 0x08, 0x13, 0xec, 0x9f, 0xb4, 0xb1, 0x18, 0xbc, 0x14, 0x09, 0x31, 0xad, ], x = [ 0xef, 0xcb, 0x7a, 0x72, 0x9c, 0xb4, 0x6a, 0xe6, 0xb4, 0x66, 0xa6, 0x8c, 0x1a, 0x18, 0x64, 0x5c, 0xd8, 0xdc, 0x9d, 0xa2, 0x5b, 0x48, 0x45, 0xcd, 0x68, 0x0c, 0x5f, 0x93, 0x1b, 0x74, 0x42, 0x0b, ], y = [ 0x7b, 0x6b, 0x8f, 0x14, 0x8b, 0x7a, 0x5d, 0xbe, 0xa5, 0xd0, 0x6b, 0x7a, 0x3c, 0xaa, 0x6f, 0x4b, 0x2a, 0xeb, 0x52, 0x7e, 0x80, 0xdb, 0xc5, 0x95, 0x73, 0x91, 0xab, 0x3d, 0x29, 0xbc, 0xbd, 0x74, ], result = 0, expected = [], }, // invalid a and b multc { a = [ 0x04, 0xee, 0x19, 0x71, 0x69, 0xae, 0xbd, 0x94, 0xc7, 0x8d, 0x4e, 0x0f, 0x05, 0x06, 0xb4, 0xdf, 0x60, 0x43, 0x22, 0x0c, 0x50, 0x8d, 0x33, 0x8a, 0x5a, 0xd0, 0x02, 0x00, 0x95, 0x5e, 0xda, 0x31, 0x64, 0x4c, 0x7e, 0x03, 0xa9, 0xa0, 0xaf, 0x56, 0xbb, 0x7c, 0x03, 0x04, 0x8a, 0x44, 0x30, 0xfd, 0x39, 0x1d, 0xc0, 0x0f, 0x5c, 0x50, 0xcf, 0xda, 0xf1, 0x99, 0x69, 0x0e, 0x77, 0x62, 0x56, 0x34, 0xce, ], b = [ 0x04, 0xbd, 0x52, 0x07, 0x83, 0xf0, 0x88, 0x6a, 0xa5, 0x24, 0xd8, 0x22, 0x13, 0xff, 0xc3, 0xf3, 0x03, 0xca, 0xe1, 0xd3, 0x5e, 0xf1, 0x95, 0x82, 0x5f, 0xa9, 0x95, 0x9f, 0xc3, 0xf4, 0x92, 0x8f, 0xd2, 0x30, 0x18, 0x56, 0x29, 0xf3, 0x74, 0x50, 0xbd, 0xa6, 0x8d, 0x88, 0xf6, 0xf3, 0xd6, 0x16, 0xd9, 0x9d, 0x01, 0x82, 0xbe, 0xf8, 0x13, 0xec, 0x9f, 0xb4, 0xb1, 0x18, 0xbc, 0x14, 0x09, 0x31, 0xad, ], x = [ 0xef, 0xcb, 0x7a, 0x72, 0x9c, 0xb4, 0x6a, 0xe6, 0xb4, 0x66, 0xa6, 0x8c, 0x1a, 0x18, 0x64, 0x5c, 0xd8, 0xdc, 0x9d, 0xa2, 0x5b, 0x48, 0x45, 0xcd, 0x68, 0x0c, 0x5f, 0x93, 0x1b, 0x74, 0x42, 0x0b, ], y = [ 0x7b, 0x6b, 0x8f, 0x14, 0x8b, 0x7a, 0x5d, 0xbe, 0xa5, 0xd0, 0x6b, 0x7a, 0x3c, 0xaa, 0x6f, 0x4b, 0x2a, 0xeb, 0x52, 0x7e, 0x80, 0xdb, 0xc5, 0x95, 0x73, 0x91, 0xab, 0x3d, 0x29, 0xbc, 0xbd, 0x74, ], result = 0, expected = [], } ]; tmuladd(p256, tcs); }; @test fn p384_mulgen() void = { let c = p384; // multiply by 1 let m1: [P384_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; let g = alloc(P384_G); defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P384_G)); assert(c.mulgen(g, m1) == 97); assert(bytes::equal(g, P384_G)); // multiply by order - 1 let o = alloc(P384_N); defer free(o); o[len(o) - 1] -= 1; const expected: [_]u8 = [ 0x04, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, 0xc9, 0xe8, 0x21, 0xb5, 0x69, 0xd9, 0xd3, 0x90, 0xa2, 0x61, 0x67, 0x40, 0x6d, 0x6d, 0x23, 0xd6, 0x07, 0x0b, 0xe2, 0x42, 0xd7, 0x65, 0xeb, 0x83, 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0, ]; assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); let g = alloc(P384_G); defer free(g); assert(c.mulgen(g, o) == 97); assert(bytes::equal(g, expected)); // random example let priv: [_]u8 = [ 0xde, 0x5c, 0x88, 0x05, 0x42, 0xa0, 0x71, 0xe2, 0xf6, 0xfe, 0xd0, 0xdc, 0x80, 0x07, 0x37, 0xc4, 0x35, 0xa6, 0x29, 0x48, 0x85, 0x70, 0x4f, 0x54, 0x1c, 0x41, 0x89, 0xaf, 0xf6, 0xbc, 0xb5, 0x19, 0x85, 0x70, 0x4f, 0x54, 0x1c, 0x41, 0x89, 0xaf, 0xf6, 0xbc, 0xb5, 0x19, 0xb5, 0x19, 0xb5, 0x19, ]; const expected: [_]u8 = [ 0x04, 0xb6, 0xb4, 0x77, 0x6e, 0x08, 0x86, 0x64, 0x55, 0x3a, 0x64, 0xe0, 0xa3, 0xb0, 0x56, 0x39, 0x18, 0x4c, 0x5b, 0x15, 0x3b, 0x19, 0xd0, 0x99, 0xc5, 0xd2, 0x7a, 0x4a, 0x23, 0xb9, 0xf7, 0x37, 0x95, 0x4b, 0xe0, 0x97, 0x4c, 0x72, 0x16, 0x34, 0x76, 0xf6, 0xce, 0x9e, 0xb7, 0x52, 0xc9, 0x33, 0xed, 0x26, 0x5b, 0x7c, 0xb0, 0xd8, 0xe8, 0x8f, 0xc1, 0xb2, 0xd4, 0xbe, 0xe3, 0x20, 0xc7, 0x82, 0xc7, 0x71, 0x3d, 0xaf, 0xad, 0xdb, 0xe8, 0x56, 0xba, 0xad, 0x29, 0x76, 0x4c, 0x12, 0x24, 0xe9, 0x59, 0xca, 0xef, 0x09, 0x48, 0x0d, 0x40, 0xb1, 0xce, 0x5f, 0xcf, 0x6b, 0x62, 0xfd, 0xe5, 0x4b, 0xcc, ]; let g = alloc(P384_G); defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); let r: [97]u8 = [0...]; assert(c.mulgen(r, priv) == 97); assert(bytes::equal(r, expected)); }; @test fn p384_muladd() void = { let tcs = [ multc { a = [ 0x04, 0xe4, 0x4f, 0x26, 0xd9, 0xce, 0xa7, 0xf0, 0x69, 0xed, 0xa6, 0x1f, 0x01, 0xcb, 0xef, 0x53, 0xe8, 0x2b, 0xf8, 0xdc, 0x16, 0x56, 0x05, 0x64, 0x8a, 0x46, 0xf8, 0x54, 0x25, 0x8e, 0x3e, 0x6c, 0xe8, 0xc3, 0x88, 0x0b, 0x30, 0xba, 0x9c, 0x8b, 0xf7, 0xf8, 0x17, 0xbb, 0x34, 0x08, 0x4b, 0xc5, 0xa7, 0xa3, 0x1d, 0x46, 0x64, 0x4d, 0xd1, 0xe5, 0x68, 0x23, 0x49, 0x11, 0xbd, 0x4f, 0x21, 0x6f, 0xcd, 0x88, 0x4d, 0xeb, 0x22, 0xad, 0x36, 0x57, 0xf3, 0x94, 0x5b, 0x13, 0x3c, 0xf3, 0xf6, 0xc6, 0xc6, 0x3c, 0xa1, 0x8e, 0xb6, 0x8c, 0x39, 0x85, 0x01, 0x85, 0x22, 0x16, 0xe7, 0xba, 0x9a, 0xa1, 0xd1, ], b = [], x = [ 0xda, 0x9c, 0x84, 0xcf, 0x2d, 0x77, 0x4c, 0xfa, 0xe5, 0xdc, 0x52, 0xc3, 0xb3, 0xda, 0x1c, 0xa0, 0x26, 0xb0, 0x53, 0x16, 0x66, 0x46, 0x5f, 0x60, 0xa6, 0xbe, 0x6e, 0xd1, 0x0a, 0x5f, 0x01, 0x50, 0x63, 0xe1, 0x47, 0x62, 0x68, 0xcf, 0x40, 0x3a, 0x2b, 0xf0, 0x96, 0x6c, 0x1e, 0x71, 0x24, 0x79, ], y = [ 0xd9, 0xa7, 0x84, 0xd0, 0x77, 0x9e, 0x07, 0x4d, 0x78, 0x09, 0x84, 0xef, 0x5b, 0x7d, 0x94, 0xd7, 0xd8, 0x1f, 0x94, 0x1e, 0xfc, 0x3d, 0x76, 0x6c, 0x0d, 0x4c, 0x87, 0x76, 0xdf, 0x52, 0xfc, 0xe0, 0x02, 0x17, 0x2c, 0x95, 0x5e, 0x4b, 0xb7, 0x1f, 0x84, 0xce, 0x2e, 0x54, 0xf2, 0x08, 0xf7, 0x6a, ], result = 1, expected = [ 0x04, 0x69, 0xf9, 0xbb, 0x7a, 0x32, 0x63, 0xef, 0xf2, 0xce, 0x3f, 0x4f, 0xf2, 0x48, 0x86, 0xd8, 0xe4, 0xa1, 0x68, 0x1f, 0x7b, 0x6c, 0x24, 0xcf, 0xa2, 0x60, 0x03, 0x0c, 0x8b, 0x10, 0x24, 0x4c, 0xea, 0x6f, 0x47, 0xc3, 0x75, 0xb0, 0x04, 0x07, 0xe0, 0xd1, 0x32, 0x8d, 0x02, 0x42, 0x75, 0x8c, 0x67, 0x90, 0x19, 0x12, 0x26, 0xd3, 0xaf, 0x57, 0x67, 0xc9, 0x20, 0x17, 0xd5, 0x2e, 0x57, 0xbb, 0x78, 0x98, 0xe4, 0xb5, 0xd5, 0x65, 0x53, 0x78, 0x20, 0x99, 0x2b, 0x43, 0x17, 0x1d, 0x2f, 0xdb, 0x2c, 0xd5, 0xe5, 0x61, 0x22, 0x1f, 0xae, 0x22, 0xae, 0x71, 0x03, 0x25, 0x9a, 0x47, 0x28, 0x4a, 0x0f, ], }, multc { a = [ 0x04, 0xe4, 0x4f, 0x26, 0xd9, 0xce, 0xa7, 0xf0, 0x69, 0xed, 0xa6, 0x1f, 0x01, 0xcb, 0xef, 0x53, 0xe8, 0x2b, 0xf8, 0xdc, 0x16, 0x56, 0x05, 0x64, 0x8a, 0x46, 0xf8, 0x54, 0x25, 0x8e, 0x3e, 0x6c, 0xe8, 0xc3, 0x88, 0x0b, 0x30, 0xba, 0x9c, 0x8b, 0xf7, 0xf8, 0x17, 0xbb, 0x34, 0x08, 0x4b, 0xc5, 0xa7, 0xa3, 0x1d, 0x46, 0x64, 0x4d, 0xd1, 0xe5, 0x68, 0x23, 0x49, 0x11, 0xbd, 0x4f, 0x21, 0x6f, 0xcd, 0x88, 0x4d, 0xeb, 0x22, 0xad, 0x36, 0x57, 0xf3, 0x94, 0x5b, 0x13, 0x3c, 0xf3, 0xf6, 0xc6, 0xc6, 0x3c, 0xa1, 0x8e, 0xb6, 0x8c, 0x39, 0x85, 0x01, 0x85, 0x22, 0x16, 0xe7, 0xba, 0x9a, 0xa1, 0xd1, ], b = [ 0x04, 0xe0, 0xb0, 0x1d, 0x37, 0xe0, 0x12, 0xba, 0x21, 0xcd, 0xc5, 0xc4, 0x18, 0xfd, 0x85, 0x0a, 0x21, 0x11, 0x32, 0x69, 0x73, 0xc0, 0xd4, 0x55, 0xf3, 0x2e, 0x9d, 0x25, 0x0c, 0x4a, 0xc8, 0x89, 0x4d, 0x7c, 0xbf, 0xca, 0x2d, 0x28, 0x6d, 0x20, 0x5b, 0xbf, 0x0d, 0x1b, 0x6e, 0x92, 0x97, 0xd6, 0xbb, 0xe2, 0x1b, 0x17, 0xac, 0xce, 0xd9, 0x7c, 0x7e, 0x54, 0xca, 0xfb, 0xaf, 0x53, 0xa8, 0xde, 0xba, 0x4c, 0x0a, 0x0f, 0x67, 0x03, 0xe7, 0x23, 0xcf, 0x19, 0x07, 0x31, 0x71, 0x9a, 0x49, 0x51, 0x7f, 0xbd, 0x5b, 0xa0, 0x34, 0x5f, 0x79, 0xba, 0x48, 0xf1, 0x41, 0x9d, 0xcc, 0x2d, 0xef, 0x80, 0xbb, ], x = [ 0xda, 0x9c, 0x84, 0xcf, 0x2d, 0x77, 0x4c, 0xfa, 0xe5, 0xdc, 0x52, 0xc3, 0xb3, 0xda, 0x1c, 0xa0, 0x26, 0xb0, 0x53, 0x16, 0x66, 0x46, 0x5f, 0x60, 0xa6, 0xbe, 0x6e, 0xd1, 0x0a, 0x5f, 0x01, 0x50, 0x63, 0xe1, 0x47, 0x62, 0x68, 0xcf, 0x40, 0x3a, 0x2b, 0xf0, 0x96, 0x6c, 0x1e, 0x71, 0x24, 0x79, ], y = [ 0xd9, 0xa7, 0x84, 0xd0, 0x77, 0x9e, 0x07, 0x4d, 0x78, 0x09, 0x84, 0xef, 0x5b, 0x7d, 0x94, 0xd7, 0xd8, 0x1f, 0x94, 0x1e, 0xfc, 0x3d, 0x76, 0x6c, 0x0d, 0x4c, 0x87, 0x76, 0xdf, 0x52, 0xfc, 0xe0, 0x02, 0x17, 0x2c, 0x95, 0x5e, 0x4b, 0xb7, 0x1f, 0x84, 0xce, 0x2e, 0x54, 0xf2, 0x08, 0xf7, 0x6a, ], result = 1, expected = [ 0x04, 0xdc, 0x38, 0x1d, 0x38, 0x27, 0x1a, 0x83, 0x03, 0x46, 0x18, 0xa6, 0xa7, 0xa7, 0x3e, 0xeb, 0xa3, 0x3b, 0x9b, 0x05, 0x00, 0xe8, 0x09, 0xac, 0x1a, 0x77, 0x5f, 0x21, 0xec, 0x5d, 0xe4, 0x70, 0x3d, 0x18, 0x1f, 0x38, 0x5b, 0x5d, 0xaf, 0xed, 0xc3, 0xff, 0xe4, 0x8a, 0xdb, 0x4b, 0x35, 0xfd, 0x34, 0x2b, 0xfa, 0x29, 0x04, 0xe8, 0x55, 0x73, 0xcf, 0xce, 0x1e, 0x2c, 0x34, 0x24, 0x08, 0xca, 0x21, 0x71, 0xe1, 0xb4, 0x90, 0xd6, 0xe0, 0x60, 0xff, 0x3b, 0x40, 0x70, 0xcd, 0x47, 0x26, 0xd1, 0x5b, 0xc6, 0xbf, 0x30, 0x94, 0x40, 0x6f, 0x88, 0x09, 0x12, 0xe7, 0x3e, 0x22, 0x88, 0x7e, 0x6e, 0xc1, ], }, // invalid a multc { a = [ 0x04, 0xe4, 0x4f, 0x26, 0xd9, 0xce, 0xa7, 0xf0, 0x69, 0xed, 0xa6, 0x1f, 0x01, 0xcb, 0xef, 0x53, 0xe8, 0x2b, 0x08, 0xdc, 0x16, 0x56, 0x05, 0x64, 0x8a, 0x46, 0x08, 0x54, 0x25, 0x8e, 0x3e, 0x6c, 0xe8, 0xc3, 0xf8, 0x0b, 0x30, 0xba, 0x9c, 0x8b, 0xf7, 0xf8, 0xf7, 0xbb, 0x34, 0x08, 0x4b, 0xc5, 0xa7, 0xa3, 0xfd, 0x46, 0x64, 0x4d, 0xd1, 0xe5, 0x68, 0x23, 0x49, 0x11, 0xbd, 0x4f, 0x21, 0x6f, 0xcd, 0x88, 0x4d, 0xeb, 0x22, 0xad, 0x36, 0x57, 0xf3, 0x94, 0x00, 0x13, 0x3c, 0xf3, 0xf6, 0xc6, 0xc6, 0x3c, 0x00, 0x8e, 0xb6, 0x8c, 0x39, 0x85, 0x01, 0x85, 0x00, 0x16, 0xe7, 0xba, 0x9a, 0xa1, 0xd1, ], b = [ 0x04, 0xe0, 0xb0, 0x1d, 0x37, 0xe0, 0x12, 0xba, 0x21, 0xcd, 0xc5, 0xc4, 0x18, 0xfd, 0x85, 0x0a, 0x21, 0x11, 0x32, 0x69, 0x73, 0xc0, 0xd4, 0x55, 0xf3, 0x2e, 0x9d, 0x25, 0x0c, 0x4a, 0xc8, 0x89, 0x4d, 0x7c, 0xbf, 0xca, 0x2d, 0x28, 0x6d, 0x20, 0x5b, 0xbf, 0x0d, 0x1b, 0x6e, 0x92, 0x97, 0xd6, 0xbb, 0xe2, 0x1b, 0x17, 0xac, 0xce, 0xd9, 0x7c, 0x7e, 0x54, 0xca, 0xfb, 0xaf, 0x53, 0xa8, 0xde, 0xba, 0x4c, 0x0a, 0x0f, 0x67, 0x03, 0xe7, 0x23, 0xcf, 0x19, 0x07, 0x31, 0x71, 0x9a, 0x49, 0x51, 0x7f, 0xbd, 0x5b, 0xa0, 0x34, 0x5f, 0x79, 0xba, 0x48, 0xf1, 0x41, 0x9d, 0xcc, 0x2d, 0xef, 0x80, 0xbb, ], x = [ 0xda, 0x9c, 0x84, 0xcf, 0x2d, 0x77, 0x4c, 0xfa, 0xe5, 0xdc, 0x52, 0xc3, 0xb3, 0xda, 0x1c, 0xa0, 0x26, 0xb0, 0x53, 0x16, 0x66, 0x46, 0x5f, 0x60, 0xa6, 0xbe, 0x6e, 0xd1, 0x0a, 0x5f, 0x01, 0x50, 0x63, 0xe1, 0x47, 0x62, 0x68, 0xcf, 0x40, 0x3a, 0x2b, 0xf0, 0x96, 0x6c, 0x1e, 0x71, 0x24, 0x79, ], y = [ 0xd9, 0xa7, 0x84, 0xd0, 0x77, 0x9e, 0x07, 0x4d, 0x78, 0x09, 0x84, 0xef, 0x5b, 0x7d, 0x94, 0xd7, 0xd8, 0x1f, 0x94, 0x1e, 0xfc, 0x3d, 0x76, 0x6c, 0x0d, 0x4c, 0x87, 0x76, 0xdf, 0x52, 0xfc, 0xe0, 0x02, 0x17, 0x2c, 0x95, 0x5e, 0x4b, 0xb7, 0x1f, 0x84, 0xce, 0x2e, 0x54, 0xf2, 0x08, 0xf7, 0x6a, ], result = 0, expected = [], }, // invalid b multc { a = [ 0x04, 0xe4, 0x4f, 0x26, 0xd9, 0xce, 0xa7, 0xf0, 0x69, 0xed, 0xa6, 0x1f, 0x01, 0xcb, 0xef, 0x53, 0xe8, 0x2b, 0xf8, 0xdc, 0x16, 0x56, 0x05, 0x64, 0x8a, 0x46, 0xf8, 0x54, 0x25, 0x8e, 0x3e, 0x6c, 0xe8, 0xc3, 0x88, 0x0b, 0x30, 0xba, 0x9c, 0x8b, 0xf7, 0xf8, 0x17, 0xbb, 0x34, 0x08, 0x4b, 0xc5, 0xa7, 0xa3, 0x1d, 0x46, 0x64, 0x4d, 0xd1, 0xe5, 0x68, 0x23, 0x49, 0x11, 0xbd, 0x4f, 0x21, 0x6f, 0xcd, 0x88, 0x4d, 0xeb, 0x22, 0xad, 0x36, 0x57, 0xf3, 0x94, 0x5b, 0x13, 0x3c, 0xf3, 0xf6, 0xc6, 0xc6, 0x3c, 0xa1, 0x8e, 0xb6, 0x8c, 0x39, 0x85, 0x01, 0x85, 0x22, 0x16, 0xe7, 0xba, 0x9a, 0xa1, 0xd1, ], b = [ 0x04, 0xe0, 0xb0, 0x1d, 0x37, 0xe0, 0x12, 0xba, 0x21, 0xcd, 0xc5, 0xc4, 0x18, 0xfd, 0x85, 0x0a, 0x21, 0x11, 0x32, 0x69, 0x73, 0xc0, 0xd4, 0x55, 0xf3, 0x2e, 0x9d, 0x25, 0x0c, 0x4a, 0xc8, 0x89, 0x4d, 0x7c, 0xbf, 0xca, 0x2d, 0x28, 0x6d, 0x20, 0x5b, 0x0f, 0x0d, 0x1b, 0x6e, 0x92, 0x97, 0xd6, 0xbb, 0x0f, 0x1b, 0x17, 0xac, 0xce, 0xd9, 0x7c, 0x7e, 0x0f, 0xca, 0xfb, 0xaf, 0x53, 0xa8, 0xde, 0xba, 0x0f, 0x0a, 0x0f, 0x67, 0x03, 0xe7, 0x23, 0xcf, 0x0f, 0x07, 0x31, 0x71, 0x9a, 0x49, 0x51, 0x7f, 0x0f, 0x5b, 0xa0, 0x34, 0x5f, 0x79, 0xba, 0x48, 0xff, 0x41, 0x9d, 0xcc, 0x2d, 0xef, 0x80, 0xbb, ], x = [ 0xda, 0x9c, 0x84, 0xcf, 0x2d, 0x77, 0x4c, 0xfa, 0xe5, 0xdc, 0x52, 0xc3, 0xb3, 0xda, 0x1c, 0xa0, 0x26, 0xb0, 0x53, 0x16, 0x66, 0x46, 0x5f, 0x60, 0xa6, 0xbe, 0x6e, 0xd1, 0x0a, 0x5f, 0x01, 0x50, 0x63, 0xe1, 0x47, 0x62, 0x68, 0xcf, 0x40, 0x3a, 0x2b, 0xf0, 0x96, 0x6c, 0x1e, 0x71, 0x24, 0x79, ], y = [ 0xd9, 0xa7, 0x84, 0xd0, 0x77, 0x9e, 0x07, 0x4d, 0x78, 0x09, 0x84, 0xef, 0x5b, 0x7d, 0x94, 0xd7, 0xd8, 0x1f, 0x94, 0x1e, 0xfc, 0x3d, 0x76, 0x6c, 0x0d, 0x4c, 0x87, 0x76, 0xdf, 0x52, 0xfc, 0xe0, 0x02, 0x17, 0x2c, 0x95, 0x5e, 0x4b, 0xb7, 0x1f, 0x84, 0xce, 0x2e, 0x54, 0xf2, 0x08, 0xf7, 0x6a, ], result = 0, expected = [], }, // invalid a and b multc { a = [ 0x04, 0xe4, 0x4f, 0x26, 0xd9, 0xce, 0xa7, 0xf0, 0x69, 0xed, 0xf6, 0x1f, 0x01, 0xcb, 0xef, 0x53, 0xe8, 0x2b, 0xf8, 0xdc, 0x16, 0x56, 0x05, 0x64, 0x8a, 0x46, 0xf8, 0x54, 0x25, 0x8e, 0x3e, 0x6c, 0xe8, 0xc3, 0xf8, 0x0b, 0x30, 0xba, 0x9c, 0x8b, 0xf7, 0xf8, 0xf7, 0xbb, 0x34, 0x08, 0x4b, 0xc5, 0xa7, 0xa3, 0xfd, 0x46, 0x64, 0x4d, 0xd1, 0xe5, 0x68, 0x23, 0xf9, 0x11, 0xbd, 0x4f, 0x21, 0x6f, 0xcd, 0x88, 0xfd, 0xeb, 0x22, 0xad, 0x36, 0x57, 0xf3, 0x94, 0xfb, 0x13, 0x3c, 0xf3, 0xf6, 0xc6, 0xc6, 0x3c, 0xf1, 0x8e, 0xb6, 0x8c, 0x39, 0x85, 0x01, 0x85, 0xf2, 0x16, 0xe7, 0xba, 0x9a, 0xa1, 0xd1, ], b = [ 0x04, 0xe0, 0xb0, 0x1d, 0x37, 0xe0, 0x12, 0xba, 0x21, 0xcd, 0xc5, 0xc4, 0x18, 0xfd, 0x85, 0x0a, 0x21, 0x11, 0x32, 0x60, 0x73, 0xc0, 0xd4, 0x55, 0xf3, 0x2e, 0x9d, 0x20, 0x0c, 0x4a, 0xc8, 0x89, 0x4d, 0x7c, 0xbf, 0xc0, 0x2d, 0x28, 0x6d, 0x20, 0x5b, 0xbf, 0x0d, 0x10, 0x6e, 0x92, 0x97, 0xd6, 0xbb, 0xe2, 0x1b, 0x10, 0xac, 0xce, 0xd9, 0x7c, 0x7e, 0x54, 0xca, 0xf0, 0xaf, 0x53, 0xa8, 0xde, 0xba, 0x4c, 0x0a, 0x00, 0x67, 0x03, 0xe7, 0x23, 0xcf, 0x19, 0x07, 0x30, 0x71, 0x9a, 0x49, 0x51, 0x7f, 0xbd, 0x5b, 0xa0, 0x34, 0x5f, 0x79, 0xba, 0x48, 0xf1, 0x41, 0x90, 0xcc, 0x2d, 0xef, 0x80, 0xbb, ], x = [ 0xda, 0x9c, 0x84, 0xcf, 0x2d, 0x77, 0x4c, 0xfa, 0xe5, 0xdc, 0x52, 0xc3, 0xb3, 0xda, 0x1c, 0xa0, 0x26, 0xb0, 0x53, 0x16, 0x66, 0x46, 0x5f, 0x60, 0xa6, 0xbe, 0x6e, 0xd1, 0x0a, 0x5f, 0x01, 0x50, 0x63, 0xe1, 0x47, 0x62, 0x68, 0xcf, 0x40, 0x3a, 0x2b, 0xf0, 0x96, 0x6c, 0x1e, 0x71, 0x24, 0x79, ], y = [ 0xd9, 0xa7, 0x84, 0xd0, 0x77, 0x9e, 0x07, 0x4d, 0x78, 0x09, 0x84, 0xef, 0x5b, 0x7d, 0x94, 0xd7, 0xd8, 0x1f, 0x94, 0x1e, 0xfc, 0x3d, 0x76, 0x6c, 0x0d, 0x4c, 0x87, 0x76, 0xdf, 0x52, 0xfc, 0xe0, 0x02, 0x17, 0x2c, 0x95, 0x5e, 0x4b, 0xb7, 0x1f, 0x84, 0xce, 0x2e, 0x54, 0xf2, 0x08, 0xf7, 0x6a, ], result = 0, expected = [], }, ]; tmuladd(p384, tcs); }; @test fn p521_mulgen() void = { let c = p521; // multiply by 1 let m1: [P521_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; let g = alloc(P521_G); defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P521_G)); assert(c.mulgen(g, m1) == 133); assert(bytes::equal(g, P521_G)); // multiply by order - 1 let o = alloc(P521_N); defer free(o); o[len(o) - 1] -= 1; const expected: [_]u8 = [ 0x04, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66, 0x00, 0xe7, 0xc6, 0xd6, 0x95, 0x87, 0x65, 0xc4, 0x3f, 0xfb, 0xa3, 0x75, 0xa0, 0x4b, 0xd3, 0x82, 0xe4, 0x26, 0x67, 0x0a, 0xbb, 0xb6, 0xa8, 0x64, 0xbb, 0x97, 0xe8, 0x50, 0x42, 0xe8, 0xd8, 0xc1, 0x99, 0xd3, 0x68, 0x11, 0x8d, 0x66, 0xa1, 0x0b, 0xd9, 0xbf, 0x3a, 0xaf, 0x46, 0xfe, 0xc0, 0x52, 0xf8, 0x9e, 0xca, 0xc3, 0x8f, 0x79, 0x5d, 0x8d, 0x3d, 0xbf, 0x77, 0x41, 0x6b, 0x89, 0x60, 0x2e, 0x99, 0xaf, ]; assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); let g = alloc(P521_G); defer free(g); assert(c.mulgen(g, o) == 133); assert(bytes::equal(g, expected)); // random example let priv: [_]u8 = [ 0x01, 0x1f, 0xd5, 0x29, 0xff, 0x28, 0x24, 0x93, 0x43, 0x23, 0x3c, 0x0f, 0xe4, 0x15, 0x6a, 0xea, 0x1c, 0x95, 0xe6, 0xf1, 0x5e, 0x19, 0x30, 0xfe, 0xb4, 0xea, 0x0d, 0x24, 0xb3, 0x67, 0xa0, 0xeb, 0xcf, 0xed, 0x5c, 0xcf, 0xcf, 0x9f, 0x9d, 0x48, 0x04, 0x8b, 0xb1, 0x56, 0x53, 0xba, 0xa4, 0x86, 0x01, 0x29, 0x61, 0x21, 0xca, 0xd7, 0x63, 0x84, 0x35, 0x45, 0xc3, 0x9b, 0x55, 0xff, 0x9a, 0x4f, 0x27, 0x03, ]; const expected: [_]u8 = [ 0x04, 0x00, 0x9f, 0x72, 0x15, 0x21, 0x0c, 0xdd, 0x22, 0x24, 0x16, 0xbb, 0x18, 0xa6, 0x46, 0x21, 0xee, 0x4f, 0x73, 0x1e, 0x9e, 0x03, 0xaf, 0x79, 0xc7, 0x1f, 0xf0, 0x33, 0x1c, 0xa6, 0xa1, 0x13, 0x98, 0x95, 0x6e, 0x88, 0x44, 0x6b, 0xa4, 0xbd, 0x4d, 0x49, 0x9e, 0xcb, 0x96, 0x0e, 0xdf, 0x67, 0x89, 0xca, 0xd5, 0xc3, 0x9e, 0x99, 0xa8, 0xc9, 0x00, 0x4b, 0x2c, 0x49, 0x57, 0xd7, 0xee, 0xf4, 0x6e, 0x07, 0xbb, 0x01, 0x35, 0xe2, 0xa4, 0xd6, 0x60, 0x99, 0x2c, 0x62, 0xad, 0xab, 0x89, 0xb5, 0xe7, 0xb6, 0x4b, 0x44, 0x89, 0xcf, 0xb0, 0x19, 0x29, 0xf8, 0x54, 0x76, 0x07, 0x40, 0x3a, 0xee, 0x41, 0x0c, 0x64, 0xeb, 0xda, 0x1e, 0x22, 0x4a, 0xee, 0xdb, 0x16, 0xa0, 0x5d, 0xe1, 0x95, 0x2f, 0xe3, 0xbc, 0x53, 0xd3, 0xf4, 0x36, 0x76, 0x03, 0x1f, 0xd8, 0xc6, 0xf4, 0x23, 0x4f, 0x45, 0x4e, 0x11, 0xeb, 0xb2, 0xb1, 0x62, ]; let g = alloc(P521_G); defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); let r: [133]u8 = [0...]; assert(c.mulgen(r, priv) == 133); assert(bytes::equal(r, expected)); }; @test fn p521_muladd() void = { let tcs = [ multc { a = [ 0x04, 0x01, 0xb1, 0x0a, 0x39, 0x7f, 0x94, 0xe9, 0x0b, 0x4f, 0x8f, 0xf1, 0xe8, 0x31, 0xca, 0x0a, 0xda, 0x8f, 0x1c, 0x80, 0x1e, 0x1a, 0x95, 0x65, 0xdb, 0x0f, 0x52, 0x7f, 0xaa, 0x14, 0x65, 0x6d, 0xe9, 0xe6, 0x5c, 0xa2, 0x34, 0xc8, 0xea, 0x11, 0x67, 0x4a, 0xc3, 0x5f, 0xce, 0x8b, 0xa8, 0xe8, 0xe4, 0x8b, 0x6c, 0x9e, 0x5c, 0x0d, 0x37, 0xf0, 0x4e, 0x33, 0xb8, 0xd1, 0x5f, 0xce, 0x90, 0x92, 0xa7, 0x14, 0x07, 0x01, 0x1e, 0xde, 0x56, 0x92, 0xcc, 0x39, 0xb6, 0xe9, 0xcf, 0xbe, 0xe0, 0xeb, 0x35, 0x30, 0xfc, 0xf2, 0x2b, 0xc6, 0xe4, 0xfa, 0x71, 0x2e, 0x2f, 0x87, 0x54, 0x83, 0xb1, 0x9c, 0x96, 0xe2, 0xbb, 0x72, 0xca, 0x51, 0xf2, 0x58, 0x25, 0x80, 0xf4, 0x47, 0xa3, 0xb6, 0x29, 0x45, 0x3c, 0x28, 0xa7, 0x65, 0x85, 0x40, 0xb7, 0x2b, 0x75, 0x38, 0x4a, 0x3e, 0x25, 0x0a, 0xb6, 0x58, 0xe3, 0x9a, 0x7c, 0xde, 0xd5, ], b = [], x = [ 0x01, 0x74, 0xe2, 0x0e, 0x0c, 0xa6, 0xd0, 0x12, 0xb0, 0xc3, 0x86, 0xbc, 0xfc, 0x9a, 0xcb, 0x09, 0x7a, 0xf9, 0xca, 0xb7, 0xc8, 0x79, 0x39, 0x3e, 0xb6, 0x8e, 0x3e, 0x2f, 0x02, 0x6a, 0xfd, 0x07, 0x65, 0xe9, 0x97, 0xe1, 0xf5, 0xf0, 0x16, 0x9a, 0xa2, 0xe6, 0x03, 0x75, 0x1f, 0xa2, 0xf4, 0xe5, 0xcd, 0x54, 0x94, 0x60, 0xb2, 0xfd, 0xe7, 0x97, 0xea, 0x72, 0x02, 0xb9, 0x96, 0x48, 0xd3, 0x45, 0xc2, 0x26, ], y = [ 0x01, 0xae, 0xa0, 0x8f, 0x5b, 0x13, 0xe1, 0x85, 0x4f, 0xfe, 0xcf, 0x73, 0x6a, 0x18, 0xc3, 0xfa, 0xb7, 0xe6, 0xfc, 0xe5, 0xa9, 0x09, 0x8a, 0x68, 0x4f, 0x49, 0x93, 0x59, 0xeb, 0xfd, 0x91, 0xf9, 0x45, 0x1d, 0xcf, 0x51, 0x61, 0x39, 0x5c, 0x87, 0x6c, 0x70, 0x9d, 0xfa, 0x7a, 0x86, 0x30, 0x64, 0x3a, 0x4f, 0x48, 0x78, 0x3a, 0x2f, 0x9f, 0x84, 0x07, 0xc1, 0x94, 0x5a, 0xc7, 0x1a, 0xe2, 0x5d, 0x73, 0xb3, ], result = 1, expected = [ 0x04, 0x00, 0x27, 0xd3, 0x90, 0xf4, 0xf7, 0xdc, 0x2a, 0x67, 0xa0, 0x2b, 0x8c, 0x31, 0x3b, 0xe3, 0x37, 0xb9, 0xf9, 0x08, 0x49, 0x46, 0x56, 0xa6, 0xa4, 0x3d, 0x7c, 0x0a, 0x74, 0x98, 0x72, 0x20, 0xbe, 0xa7, 0xf8, 0x67, 0x95, 0x7d, 0x1f, 0x6a, 0x38, 0x03, 0xc9, 0xf3, 0xac, 0x55, 0xb9, 0x5b, 0x5d, 0xeb, 0x01, 0xe0, 0xaf, 0xf1, 0x66, 0xcf, 0x90, 0xe3, 0x43, 0x5c, 0x25, 0xfb, 0xcd, 0x48, 0xd4, 0xf5, 0xbd, 0x01, 0xb5, 0xa5, 0xd4, 0xa1, 0xe4, 0x4f, 0xab, 0x94, 0x96, 0xdd, 0x32, 0x7f, 0x9e, 0x40, 0x1c, 0x25, 0x7d, 0xcb, 0xed, 0xa5, 0x53, 0xac, 0x4f, 0xa3, 0x72, 0x75, 0x56, 0xd8, 0x32, 0x2c, 0x76, 0xed, 0x0d, 0xe7, 0x5c, 0xbd, 0xbd, 0xe8, 0x09, 0x35, 0x0e, 0x57, 0xd4, 0x20, 0xe1, 0x46, 0x6c, 0x49, 0xe1, 0x49, 0xc6, 0x04, 0x6e, 0xf9, 0xc9, 0x87, 0x76, 0x0a, 0x9a, 0x3b, 0x2b, 0xa6, 0x43, 0xc2, 0x24, ], }, multc { a = [ 0x04, 0x01, 0xb1, 0x0a, 0x39, 0x7f, 0x94, 0xe9, 0x0b, 0x4f, 0x8f, 0xf1, 0xe8, 0x31, 0xca, 0x0a, 0xda, 0x8f, 0x1c, 0x80, 0x1e, 0x1a, 0x95, 0x65, 0xdb, 0x0f, 0x52, 0x7f, 0xaa, 0x14, 0x65, 0x6d, 0xe9, 0xe6, 0x5c, 0xa2, 0x34, 0xc8, 0xea, 0x11, 0x67, 0x4a, 0xc3, 0x5f, 0xce, 0x8b, 0xa8, 0xe8, 0xe4, 0x8b, 0x6c, 0x9e, 0x5c, 0x0d, 0x37, 0xf0, 0x4e, 0x33, 0xb8, 0xd1, 0x5f, 0xce, 0x90, 0x92, 0xa7, 0x14, 0x07, 0x01, 0x1e, 0xde, 0x56, 0x92, 0xcc, 0x39, 0xb6, 0xe9, 0xcf, 0xbe, 0xe0, 0xeb, 0x35, 0x30, 0xfc, 0xf2, 0x2b, 0xc6, 0xe4, 0xfa, 0x71, 0x2e, 0x2f, 0x87, 0x54, 0x83, 0xb1, 0x9c, 0x96, 0xe2, 0xbb, 0x72, 0xca, 0x51, 0xf2, 0x58, 0x25, 0x80, 0xf4, 0x47, 0xa3, 0xb6, 0x29, 0x45, 0x3c, 0x28, 0xa7, 0x65, 0x85, 0x40, 0xb7, 0x2b, 0x75, 0x38, 0x4a, 0x3e, 0x25, 0x0a, 0xb6, 0x58, 0xe3, 0x9a, 0x7c, 0xde, 0xd5, ], b = [ 0x04, 0x01, 0x01, 0xbf, 0xd2, 0xa7, 0xed, 0xe7, 0x68, 0x5a, 0x86, 0x4b, 0xc8, 0x40, 0x42, 0x9d, 0xea, 0x5c, 0xe5, 0x3e, 0x3d, 0x3d, 0x48, 0xc6, 0x38, 0xb0, 0x7f, 0xd4, 0x35, 0x67, 0x67, 0xb2, 0x12, 0xa7, 0xba, 0xd4, 0xc3, 0x22, 0x3f, 0x7d, 0xff, 0xe2, 0x23, 0x8e, 0x72, 0x71, 0x2c, 0x24, 0xd5, 0x91, 0xdc, 0x9c, 0xb2, 0xc7, 0x2d, 0x5c, 0xe1, 0xf7, 0x17, 0x49, 0x09, 0xeb, 0xe4, 0x26, 0xab, 0xe6, 0x6d, 0x01, 0x26, 0xb1, 0x8e, 0x19, 0xb3, 0xe3, 0x72, 0xe9, 0xf4, 0x15, 0xe3, 0x52, 0x2a, 0xb3, 0xcb, 0xac, 0xf8, 0xe7, 0xc0, 0x14, 0x60, 0x97, 0x71, 0xa0, 0x54, 0x2b, 0x94, 0x4c, 0x13, 0x6e, 0xfb, 0x98, 0x11, 0x72, 0x60, 0x6a, 0x0e, 0xd5, 0xb4, 0xe8, 0x17, 0x6c, 0x09, 0x2a, 0xff, 0x89, 0xac, 0x88, 0xcd, 0x56, 0xe4, 0xcc, 0x66, 0x79, 0x8c, 0xb7, 0xd2, 0x44, 0x44, 0x60, 0xd8, 0x04, 0xa2, 0x50, 0x0f, ], x = [ 0x01, 0x74, 0xe2, 0x0e, 0x0c, 0xa6, 0xd0, 0x12, 0xb0, 0xc3, 0x86, 0xbc, 0xfc, 0x9a, 0xcb, 0x09, 0x7a, 0xf9, 0xca, 0xb7, 0xc8, 0x79, 0x39, 0x3e, 0xb6, 0x8e, 0x3e, 0x2f, 0x02, 0x6a, 0xfd, 0x07, 0x65, 0xe9, 0x97, 0xe1, 0xf5, 0xf0, 0x16, 0x9a, 0xa2, 0xe6, 0x03, 0x75, 0x1f, 0xa2, 0xf4, 0xe5, 0xcd, 0x54, 0x94, 0x60, 0xb2, 0xfd, 0xe7, 0x97, 0xea, 0x72, 0x02, 0xb9, 0x96, 0x48, 0xd3, 0x45, 0xc2, 0x26, ], y = [ 0x01, 0xae, 0xa0, 0x8f, 0x5b, 0x13, 0xe1, 0x85, 0x4f, 0xfe, 0xcf, 0x73, 0x6a, 0x18, 0xc3, 0xfa, 0xb7, 0xe6, 0xfc, 0xe5, 0xa9, 0x09, 0x8a, 0x68, 0x4f, 0x49, 0x93, 0x59, 0xeb, 0xfd, 0x91, 0xf9, 0x45, 0x1d, 0xcf, 0x51, 0x61, 0x39, 0x5c, 0x87, 0x6c, 0x70, 0x9d, 0xfa, 0x7a, 0x86, 0x30, 0x64, 0x3a, 0x4f, 0x48, 0x78, 0x3a, 0x2f, 0x9f, 0x84, 0x07, 0xc1, 0x94, 0x5a, 0xc7, 0x1a, 0xe2, 0x5d, 0x73, 0xb3, ], result = 1, expected = [ 0x04, 0x01, 0x4b, 0x18, 0x4d, 0x28, 0xd0, 0x8f, 0x23, 0xfc, 0x27, 0x13, 0x7e, 0xc9, 0x9d, 0xb2, 0x39, 0xb5, 0x5b, 0x7a, 0x30, 0xcb, 0x35, 0x47, 0x1b, 0x04, 0x63, 0x8a, 0x50, 0x15, 0xb2, 0x79, 0x9d, 0x74, 0xf5, 0xbc, 0x21, 0x14, 0x5e, 0x9f, 0x3f, 0x88, 0xfe, 0x46, 0x9d, 0x7c, 0xb8, 0x1a, 0x1c, 0x5c, 0x86, 0x60, 0xf2, 0xbb, 0x04, 0xdc, 0x81, 0x9d, 0xf3, 0x35, 0x75, 0x5e, 0xa9, 0x58, 0x36, 0x17, 0x33, 0x01, 0x86, 0xd9, 0x16, 0xdb, 0x10, 0xae, 0x45, 0x0a, 0xb6, 0x75, 0x6d, 0x90, 0x85, 0x92, 0xde, 0x4c, 0x96, 0x3b, 0xfd, 0x31, 0xe6, 0x99, 0x7f, 0xe2, 0xb6, 0xfd, 0xbb, 0x76, 0xe4, 0x62, 0x8f, 0xb8, 0xba, 0x8c, 0x9d, 0xc9, 0xc4, 0x2f, 0x3e, 0x67, 0xd5, 0xaf, 0xbc, 0xf0, 0x60, 0x8c, 0xca, 0xec, 0xa9, 0x21, 0xd1, 0x8e, 0x29, 0xc9, 0x81, 0x76, 0xdb, 0x17, 0x17, 0xd8, 0x6b, 0x97, 0x58, 0x88, 0x78, ], }, // invalid a multc { a = [ 0x04, 0x01, 0xb1, 0x0a, 0x39, 0x7f, 0x94, 0xe9, 0x0b, 0x4f, 0x8f, 0xf1, 0xe8, 0x31, 0xca, 0x0a, 0xda, 0x8f, 0x1c, 0x80, 0x1e, 0x1a, 0x95, 0x65, 0xdb, 0x0f, 0x52, 0x7f, 0xaa, 0x14, 0x65, 0x6d, 0xe9, 0xef, 0x5c, 0xa2, 0x34, 0xc8, 0xea, 0x11, 0x67, 0x4f, 0xc3, 0x5f, 0xce, 0x8b, 0xa8, 0xe8, 0xe4, 0x8f, 0x6c, 0x9e, 0x5c, 0x0d, 0x37, 0xf0, 0x4e, 0x3f, 0xb8, 0xd1, 0x5f, 0xce, 0x90, 0x92, 0xa7, 0x1f, 0x07, 0x01, 0x1e, 0xde, 0x56, 0x92, 0xcc, 0x3f, 0xb6, 0xe9, 0xcf, 0xbe, 0xe0, 0xeb, 0x35, 0x3f, 0xfc, 0xf2, 0x2b, 0xc6, 0xe4, 0xfa, 0x71, 0x2f, 0x2f, 0x87, 0x54, 0x83, 0xb1, 0x9c, 0x96, 0xef, 0xbb, 0x72, 0xca, 0x51, 0xf2, 0x58, 0x25, 0x8f, 0xf4, 0x47, 0xa3, 0xb6, 0x29, 0x45, 0x3c, 0x2f, 0xa7, 0x65, 0x85, 0x40, 0xb7, 0x2b, 0x75, 0x38, 0x4a, 0x3e, 0x25, 0x0a, 0xb6, 0x58, 0xe3, 0x9a, 0x7c, 0xde, 0xd5, ], b = [ 0x04, 0x01, 0x01, 0xbf, 0xd2, 0xa7, 0xed, 0xe7, 0x68, 0x5a, 0x86, 0x4b, 0xc8, 0x40, 0x42, 0x9d, 0xea, 0x5c, 0xe5, 0x3e, 0x3d, 0x3d, 0x48, 0xc6, 0x38, 0xb0, 0x7f, 0xd4, 0x35, 0x67, 0x67, 0xb2, 0x12, 0xa7, 0xba, 0xd4, 0xc3, 0x22, 0x3f, 0x7d, 0xff, 0xe2, 0x23, 0x8e, 0x72, 0x71, 0x2c, 0x24, 0xd5, 0x91, 0xdc, 0x9c, 0xb2, 0xc7, 0x2d, 0x5c, 0xe1, 0xf7, 0x17, 0x49, 0x09, 0xeb, 0xe4, 0x26, 0xab, 0xe6, 0x6d, 0x01, 0x26, 0xb1, 0x8e, 0x19, 0xb3, 0xe3, 0x72, 0xe9, 0xf4, 0x15, 0xe3, 0x52, 0x2a, 0xb3, 0xcb, 0xac, 0xf8, 0xe7, 0xc0, 0x14, 0x60, 0x97, 0x71, 0xa0, 0x54, 0x2b, 0x94, 0x4c, 0x13, 0x6e, 0xfb, 0x98, 0x11, 0x72, 0x60, 0x6a, 0x0e, 0xd5, 0xb4, 0xe8, 0x17, 0x6c, 0x09, 0x2a, 0xff, 0x89, 0xac, 0x88, 0xcd, 0x56, 0xe4, 0xcc, 0x66, 0x79, 0x8c, 0xb7, 0xd2, 0x44, 0x44, 0x60, 0xd8, 0x04, 0xa2, 0x50, 0x0f, ], x = [ 0x01, 0x74, 0xe2, 0x0e, 0x0c, 0xa6, 0xd0, 0x12, 0xb0, 0xc3, 0x86, 0xbc, 0xfc, 0x9a, 0xcb, 0x09, 0x7a, 0xf9, 0xca, 0xb7, 0xc8, 0x79, 0x39, 0x3e, 0xb6, 0x8e, 0x3e, 0x2f, 0x02, 0x6a, 0xfd, 0x07, 0x65, 0xe9, 0x97, 0xe1, 0xf5, 0xf0, 0x16, 0x9a, 0xa2, 0xe6, 0x03, 0x75, 0x1f, 0xa2, 0xf4, 0xe5, 0xcd, 0x54, 0x94, 0x60, 0xb2, 0xfd, 0xe7, 0x97, 0xea, 0x72, 0x02, 0xb9, 0x96, 0x48, 0xd3, 0x45, 0xc2, 0x26, ], y = [ 0x01, 0xae, 0xa0, 0x8f, 0x5b, 0x13, 0xe1, 0x85, 0x4f, 0xfe, 0xcf, 0x73, 0x6a, 0x18, 0xc3, 0xfa, 0xb7, 0xe6, 0xfc, 0xe5, 0xa9, 0x09, 0x8a, 0x68, 0x4f, 0x49, 0x93, 0x59, 0xeb, 0xfd, 0x91, 0xf9, 0x45, 0x1d, 0xcf, 0x51, 0x61, 0x39, 0x5c, 0x87, 0x6c, 0x70, 0x9d, 0xfa, 0x7a, 0x86, 0x30, 0x64, 0x3a, 0x4f, 0x48, 0x78, 0x3a, 0x2f, 0x9f, 0x84, 0x07, 0xc1, 0x94, 0x5a, 0xc7, 0x1a, 0xe2, 0x5d, 0x73, 0xb3, ], result = 0, expected = [], }, // invalid b multc { a = [ 0x04, 0x01, 0xb1, 0x0a, 0x39, 0x7f, 0x94, 0xe9, 0x0b, 0x4f, 0x8f, 0xf1, 0xe8, 0x31, 0xca, 0x0a, 0xda, 0x8f, 0x1c, 0x80, 0x1e, 0x1a, 0x95, 0x65, 0xdb, 0x0f, 0x52, 0x7f, 0xaa, 0x14, 0x65, 0x6d, 0xe9, 0xe6, 0x5c, 0xa2, 0x34, 0xc8, 0xea, 0x11, 0x67, 0x4a, 0xc3, 0x5f, 0xce, 0x8b, 0xa8, 0xe8, 0xe4, 0x8b, 0x6c, 0x9e, 0x5c, 0x0d, 0x37, 0xf0, 0x4e, 0x33, 0xb8, 0xd1, 0x5f, 0xce, 0x90, 0x92, 0xa7, 0x14, 0x07, 0x01, 0x1e, 0xde, 0x56, 0x92, 0xcc, 0x39, 0xb6, 0xe9, 0xcf, 0xbe, 0xe0, 0xeb, 0x35, 0x30, 0xfc, 0xf2, 0x2b, 0xc6, 0xe4, 0xfa, 0x71, 0x2e, 0x2f, 0x87, 0x54, 0x83, 0xb1, 0x9c, 0x96, 0xe2, 0xbb, 0x72, 0xca, 0x51, 0xf2, 0x58, 0x25, 0x80, 0xf4, 0x47, 0xa3, 0xb6, 0x29, 0x45, 0x3c, 0x28, 0xa7, 0x65, 0x85, 0x40, 0xb7, 0x2b, 0x75, 0x38, 0x4a, 0x3e, 0x25, 0x0a, 0xb6, 0x58, 0xe3, 0x9a, 0x7c, 0xde, 0xd5, ], b = [ 0x04, 0x01, 0x01, 0xbf, 0xd2, 0xa7, 0xed, 0xe7, 0x68, 0x5a, 0x86, 0x4b, 0xc8, 0x40, 0x42, 0x9d, 0xea, 0x5c, 0xe5, 0x5e, 0x3d, 0x3d, 0x48, 0xc6, 0x38, 0xb0, 0x7f, 0x54, 0x35, 0x67, 0x67, 0xb2, 0x12, 0xa7, 0xba, 0x54, 0xc3, 0x22, 0x3f, 0x7d, 0xff, 0xe2, 0x23, 0x5e, 0x72, 0x71, 0x2c, 0x24, 0xd5, 0x91, 0xdc, 0x5c, 0xb2, 0xc7, 0x2d, 0x5c, 0xe1, 0xf7, 0x17, 0x59, 0x09, 0xeb, 0xe4, 0x26, 0xab, 0xe6, 0x6d, 0x51, 0x26, 0xb1, 0x8e, 0x19, 0xb3, 0xe3, 0x72, 0x59, 0xf4, 0x15, 0xe3, 0x52, 0x2a, 0xb3, 0xcb, 0x5c, 0xf8, 0xe7, 0xc0, 0x14, 0x60, 0x97, 0x71, 0x50, 0x54, 0x2b, 0x94, 0x4c, 0x13, 0x6e, 0xfb, 0x58, 0x11, 0x72, 0x60, 0x6a, 0x0e, 0xd5, 0xb4, 0x58, 0x17, 0x6c, 0x09, 0x2a, 0xff, 0x89, 0xac, 0x58, 0xcd, 0x56, 0xe4, 0xcc, 0x66, 0x79, 0x8c, 0xb7, 0xd2, 0x44, 0x44, 0x60, 0xd8, 0x04, 0xa2, 0x50, 0x0f, ], x = [ 0x01, 0x74, 0xe2, 0x0e, 0x0c, 0xa6, 0xd0, 0x12, 0xb0, 0xc3, 0x86, 0xbc, 0xfc, 0x9a, 0xcb, 0x09, 0x7a, 0xf9, 0xca, 0xb7, 0xc8, 0x79, 0x39, 0x3e, 0xb6, 0x8e, 0x3e, 0x2f, 0x02, 0x6a, 0xfd, 0x07, 0x65, 0xe9, 0x97, 0xe1, 0xf5, 0xf0, 0x16, 0x9a, 0xa2, 0xe6, 0x03, 0x75, 0x1f, 0xa2, 0xf4, 0xe5, 0xcd, 0x54, 0x94, 0x60, 0xb2, 0xfd, 0xe7, 0x97, 0xea, 0x72, 0x02, 0xb9, 0x96, 0x48, 0xd3, 0x45, 0xc2, 0x26, ], y = [ 0x01, 0xae, 0xa0, 0x8f, 0x5b, 0x13, 0xe1, 0x85, 0x4f, 0xfe, 0xcf, 0x73, 0x6a, 0x18, 0xc3, 0xfa, 0xb7, 0xe6, 0xfc, 0xe5, 0xa9, 0x09, 0x8a, 0x68, 0x4f, 0x49, 0x93, 0x59, 0xeb, 0xfd, 0x91, 0xf9, 0x45, 0x1d, 0xcf, 0x51, 0x61, 0x39, 0x5c, 0x87, 0x6c, 0x70, 0x9d, 0xfa, 0x7a, 0x86, 0x30, 0x64, 0x3a, 0x4f, 0x48, 0x78, 0x3a, 0x2f, 0x9f, 0x84, 0x07, 0xc1, 0x94, 0x5a, 0xc7, 0x1a, 0xe2, 0x5d, 0x73, 0xb3, ], result = 0, expected = [], }, // invalid a and b multc { a = [ 0x04, 0x01, 0xb1, 0x0a, 0x39, 0x7f, 0x94, 0xe9, 0x0b, 0x4f, 0x8f, 0xf1, 0xe8, 0x31, 0xca, 0x0a, 0xda, 0x8f, 0xfc, 0x80, 0x1e, 0x1a, 0x95, 0x65, 0xdb, 0x0f, 0xf2, 0x7f, 0xaa, 0x14, 0x65, 0x6d, 0xe9, 0xe6, 0xfc, 0xa2, 0x34, 0xc8, 0xea, 0x11, 0x67, 0x4a, 0xf3, 0x5f, 0xce, 0x8b, 0xa8, 0xe8, 0xe4, 0x8b, 0xfc, 0x9e, 0x5c, 0x0d, 0x37, 0xf0, 0x4e, 0x33, 0xf8, 0xd1, 0x5f, 0xce, 0x90, 0x92, 0xa7, 0x14, 0xf7, 0x01, 0x1e, 0xde, 0x56, 0x92, 0xcc, 0x39, 0xf6, 0xe9, 0xcf, 0xbe, 0xe0, 0xeb, 0x35, 0x30, 0xfc, 0xf2, 0x2b, 0xc6, 0xe4, 0xfa, 0x71, 0x2e, 0xff, 0x87, 0x54, 0x83, 0xb1, 0x9c, 0x96, 0xe2, 0xfb, 0x72, 0xca, 0x51, 0xf2, 0x58, 0x25, 0x80, 0xf4, 0x47, 0xa3, 0xb6, 0x29, 0x45, 0x3c, 0x28, 0xf7, 0x65, 0x85, 0x40, 0xb7, 0x2b, 0x75, 0x38, 0x4a, 0x3e, 0x25, 0x0a, 0xb6, 0x58, 0xe3, 0x9a, 0x7c, 0xde, 0xd5, ], b = [ 0x04, 0x01, 0x01, 0xbf, 0xd2, 0xa7, 0xed, 0xe7, 0x68, 0x5a, 0x06, 0x4b, 0xc8, 0x40, 0x42, 0x9d, 0xea, 0x5c, 0x05, 0x3e, 0x3d, 0x3d, 0x48, 0xc6, 0x38, 0xb0, 0x0f, 0xd4, 0x35, 0x67, 0x67, 0xb2, 0x12, 0xa7, 0x0a, 0xd4, 0xc3, 0x22, 0x3f, 0x7d, 0xff, 0xe2, 0x03, 0x8e, 0x72, 0x71, 0x2c, 0x24, 0xd5, 0x91, 0x0c, 0x9c, 0xb2, 0xc7, 0x2d, 0x5c, 0xe1, 0xf7, 0x07, 0x49, 0x09, 0xeb, 0xe4, 0x26, 0xab, 0xe6, 0x0d, 0x01, 0x26, 0xb1, 0x8e, 0x19, 0xb3, 0xe3, 0x72, 0xe9, 0xf4, 0x15, 0xe3, 0x52, 0x2a, 0xb3, 0xcb, 0xac, 0xf8, 0xe7, 0xc0, 0x14, 0x60, 0x97, 0x71, 0xa0, 0x54, 0x2b, 0x94, 0x4c, 0x13, 0x6e, 0xfb, 0x98, 0x11, 0x72, 0x60, 0x6a, 0x0e, 0xd5, 0xb4, 0xe8, 0x17, 0x6c, 0x09, 0x2a, 0xff, 0x89, 0xac, 0x88, 0xcd, 0x56, 0xe4, 0xcc, 0x66, 0x79, 0x8c, 0xb7, 0xd2, 0x44, 0x44, 0x60, 0xd8, 0x04, 0xa2, 0x50, 0x0f, ], x = [ 0x01, 0x74, 0xe2, 0x0e, 0x0c, 0xa6, 0xd0, 0x12, 0xb0, 0xc3, 0x86, 0xbc, 0xfc, 0x9a, 0xcb, 0x09, 0x7a, 0xf9, 0xca, 0xb7, 0xc8, 0x79, 0x39, 0x3e, 0xb6, 0x8e, 0x3e, 0x2f, 0x02, 0x6a, 0xfd, 0x07, 0x65, 0xe9, 0x97, 0xe1, 0xf5, 0xf0, 0x16, 0x9a, 0xa2, 0xe6, 0x03, 0x75, 0x1f, 0xa2, 0xf4, 0xe5, 0xcd, 0x54, 0x94, 0x60, 0xb2, 0xfd, 0xe7, 0x97, 0xea, 0x72, 0x02, 0xb9, 0x96, 0x48, 0xd3, 0x45, 0xc2, 0x26, ], y = [ 0x01, 0xae, 0xa0, 0x8f, 0x5b, 0x13, 0xe1, 0x85, 0x4f, 0xfe, 0xcf, 0x73, 0x6a, 0x18, 0xc3, 0xfa, 0xb7, 0xe6, 0xfc, 0xe5, 0xa9, 0x09, 0x8a, 0x68, 0x4f, 0x49, 0x93, 0x59, 0xeb, 0xfd, 0x91, 0xf9, 0x45, 0x1d, 0xcf, 0x51, 0x61, 0x39, 0x5c, 0x87, 0x6c, 0x70, 0x9d, 0xfa, 0x7a, 0x86, 0x30, 0x64, 0x3a, 0x4f, 0x48, 0x78, 0x3a, 0x2f, 0x9f, 0x84, 0x07, 0xc1, 0x94, 0x5a, 0xc7, 0x1a, 0xe2, 0x5d, 0x73, 0xb3, ], result = 0, expected = [], }, ]; tmuladd(p521, tcs); }; hare-0.24.2/crypto/ec/genkeys+test.ha000066400000000000000000000015351464473310100173660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; @test fn keygen_p256() void = edgecases(p256); @test fn keygen_p384() void = edgecases(p384); @test fn keygen_p521() void = edgecases(p521); fn edgecases(c: *curve) void = { const scalarsz = len(c.order()); let priv: [MAX_SCALARSZ]u8 = [0...]; let priv = priv[..scalarsz]; let zero: [MAX_SCALARSZ]u8 = [0...]; let zero = zero[..scalarsz]; let rnd = memio::fixed(zero); assert(keygen(c, priv, &rnd) is io::error); let rnd = memio::fixed(c.order()); assert(keygen(c, priv, &rnd) is io::error); let sub1: [MAX_SCALARSZ]u8 = [0...]; let sub1 = sub1[..scalarsz]; sub1[..] = c.order()[..]; sub1[len(sub1) - 1] -= 1; let rnd = memio::fixed(sub1); assert(keygen(c, priv, &rnd): size == scalarsz); assert(bytes::equal(sub1, priv)); }; hare-0.24.2/crypto/ec/keygen.ha000066400000000000000000000020251464473310100162230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; // Generates a random private key scalar suitable for given curve 'c'. // 'rand' must be cryptographic random stream like the one provided by // [[crypto::random::stream]]. export fn keygen(c: *curve, priv: []u8, rand: io::handle) (size | io::error) = c.keygen(c, priv, rand); // A keygen that generates random keys until one is found that fits within // the order of curve 'c'. fn mask_keygen( c: *curve, priv: []u8, rand: io::handle ) (size | io::error) = { const order = c.order(); assert(len(priv) == len(order)); assert(order[0] != 0); // mask all bits until including the highest value one. let mask = order[0]; mask |= (mask >> 1); mask |= (mask >> 2); mask |= (mask >> 4); for (true) { match (io::readall(rand, priv)?) { case let s: size => assert(s == len(priv)); case io::EOF => return (0: io::underread): io::error; }; priv[0] &= mask; if (validate_scalar(c, priv) is void) { return len(priv); }; }; }; hare-0.24.2/crypto/ec/p256.ha000066400000000000000000001063471464473310100154510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Ported from BearSSL // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use bytes; use crypto::math::*; // Note from the BearSSL documentation: // // The ec_p256_m31 implementation supports P-256 with specialised code, // including modular reduction routines that leverage the special format of the // field modulus, and internal split of data as sequences of 30-bit words, which // helps with carry propagation. ec_p256_m31 also includes fixed point // optimisations, for the common case of multiplying the conventional generator // point. These implementations are faster than the generic "i31" code, but with // a larger code footprint. // // Convert an integer from unsigned big-endian encoding to a sequence of 30-bit // words in little-endian order. The final "partial" word is returned. fn be8tole30(dest: []u32, src: []u8) u32 = { let acc: u32 = 0; let acclen: u32 = 0; let destpos = 0; for (let i = len(src); i > 0; i -= 1) { let b = src[i - 1]: u32; if (acclen < 22) { acc |= b << acclen; acclen += 8; } else { dest[destpos] = (acc | (b << acclen)) & 0x3FFFFFFF; destpos += 1; acc = b >> (30 - acclen); acclen -= 22; }; }; return acc; }; // Convert an integer (30-bit words, little-endian) to unsigned // big-endian encoding. The total encoding length is provided; all // the destination bytes will be filled. fn le30tobe8(dest: []u8, src: []u32) void = { let acc: u32 = 0; let acclen: u32 = 0; let srcpos: size = 0; for (let i = len(dest); i > 0; i -= 1) { if (acclen < 8) { let w = src[srcpos]; srcpos += 1; dest[i - 1] = (acc | (w << acclen)): u8; acc = w >> (8 - acclen); acclen += 22; } else { dest[i - 1] = acc: u8; acc >>= 8; acclen -= 8; }; }; }; @test fn be8tole30() void = { let be8: [6]u8 = [0x11, 0x22, 0xF3, 0x44, 0x55, 0x66]; let le30result: [2]u32 = [0...]; let be8result: [6]u8 = [0...]; le30result[1] = be8tole30(le30result, be8); le30tobe8(be8result, le30result); assert(bytes::equal(be8, be8result)); }; fn arsh(x: u32, n: u32) u32 = (x: i32 >> n: i32): u32; fn arshw(x: u64, n: u32) u64 = (x: i64 >> n: i32): u64; @test fn arsh() void = assert(arsh(0x80000000u32, 2) == 0xe0000000); // Multiply two integers. Source integers are represented as arrays of // nine 30-bit words, for values up to 2^270-1. Result is encoded over // 18 words of 30 bits each. fn mul9(d: []u32, a: []u32, b: []u32) void = { // Maximum intermediate result is no more than // 10376293531797946367, which fits in 64 bits. Reason: // // 10376293531797946367 = 9 * (2^30-1)^2 + 9663676406 // 10376293531797946367 < 9663676407 * 2^30 // // Thus, adding together 9 products of 30-bit integers, with // a carry of at most 9663676406, yields an integer that fits // on 64 bits and generates a carry of at most 9663676406. let t: [17]u64 = [0...]; t[0] = mulu32(a[0], b[0]); t[1] = mulu32(a[0], b[1]) + mulu32(a[1], b[0]); t[2] = mulu32(a[0], b[2]) + mulu32(a[1], b[1]) + mulu32(a[2], b[0]); t[3] = mulu32(a[0], b[3]) + mulu32(a[1], b[2]) + mulu32(a[2], b[1]) + mulu32(a[3], b[0]); t[4] = mulu32(a[0], b[4]) + mulu32(a[1], b[3]) + mulu32(a[2], b[2]) + mulu32(a[3], b[1]) + mulu32(a[4], b[0]); t[5] = mulu32(a[0], b[5]) + mulu32(a[1], b[4]) + mulu32(a[2], b[3]) + mulu32(a[3], b[2]) + mulu32(a[4], b[1]) + mulu32(a[5], b[0]); t[6] = mulu32(a[0], b[6]) + mulu32(a[1], b[5]) + mulu32(a[2], b[4]) + mulu32(a[3], b[3]) + mulu32(a[4], b[2]) + mulu32(a[5], b[1]) + mulu32(a[6], b[0]); t[7] = mulu32(a[0], b[7]) + mulu32(a[1], b[6]) + mulu32(a[2], b[5]) + mulu32(a[3], b[4]) + mulu32(a[4], b[3]) + mulu32(a[5], b[2]) + mulu32(a[6], b[1]) + mulu32(a[7], b[0]); t[8] = mulu32(a[0], b[8]) + mulu32(a[1], b[7]) + mulu32(a[2], b[6]) + mulu32(a[3], b[5]) + mulu32(a[4], b[4]) + mulu32(a[5], b[3]) + mulu32(a[6], b[2]) + mulu32(a[7], b[1]) + mulu32(a[8], b[0]); t[9] = mulu32(a[1], b[8]) + mulu32(a[2], b[7]) + mulu32(a[3], b[6]) + mulu32(a[4], b[5]) + mulu32(a[5], b[4]) + mulu32(a[6], b[3]) + mulu32(a[7], b[2]) + mulu32(a[8], b[1]); t[10] = mulu32(a[2], b[8]) + mulu32(a[3], b[7]) + mulu32(a[4], b[6]) + mulu32(a[5], b[5]) + mulu32(a[6], b[4]) + mulu32(a[7], b[3]) + mulu32(a[8], b[2]); t[11] = mulu32(a[3], b[8]) + mulu32(a[4], b[7]) + mulu32(a[5], b[6]) + mulu32(a[6], b[5]) + mulu32(a[7], b[4]) + mulu32(a[8], b[3]); t[12] = mulu32(a[4], b[8]) + mulu32(a[5], b[7]) + mulu32(a[6], b[6]) + mulu32(a[7], b[5]) + mulu32(a[8], b[4]); t[13] = mulu32(a[5], b[8]) + mulu32(a[6], b[7]) + mulu32(a[7], b[6]) + mulu32(a[8], b[5]); t[14] = mulu32(a[6], b[8]) + mulu32(a[7], b[7]) + mulu32(a[8], b[6]); t[15] = mulu32(a[7], b[8]) + mulu32(a[8], b[7]); t[16] = mulu32(a[8], b[8]); // Propagate carries. let cc: u64 = 0; for (let i = 0z; i < 17; i += 1) { let w = t[i] + cc; d[i] = w: u32 & 0x3FFFFFFF; cc = w >> 30; }; d[17] = cc: u32; }; // Square a 270-bit integer, represented as an array of nine 30-bit words. // Result uses 18 words of 30 bits each. fn square9(d: []u32, a: []u32) void = { let t: [17]u64 = [0...]; t[0] = mulu32(a[0], a[0]); t[1] = ((mulu32(a[0], a[1])) << 1); t[2] = mulu32(a[1], a[1]) + ((mulu32(a[0], a[2])) << 1); t[3] = ((mulu32(a[0], a[3]) + mulu32(a[1], a[2])) << 1); t[4] = mulu32(a[2], a[2]) + ((mulu32(a[0], a[4]) + mulu32(a[1], a[3])) << 1); t[5] = ((mulu32(a[0], a[5]) + mulu32(a[1], a[4]) + mulu32(a[2], a[3])) << 1); t[6] = mulu32(a[3], a[3]) + ((mulu32(a[0], a[6]) + mulu32(a[1], a[5]) + mulu32(a[2], a[4])) << 1); t[7] = ((mulu32(a[0], a[7]) + mulu32(a[1], a[6]) + mulu32(a[2], a[5]) + mulu32(a[3], a[4])) << 1); t[8] = mulu32(a[4], a[4]) + ((mulu32(a[0], a[8]) + mulu32(a[1], a[7]) + mulu32(a[2], a[6]) + mulu32(a[3], a[5])) << 1); t[9] = ((mulu32(a[1], a[8]) + mulu32(a[2], a[7]) + mulu32(a[3], a[6]) + mulu32(a[4], a[5])) << 1); t[10] = mulu32(a[5], a[5]) + ((mulu32(a[2], a[8]) + mulu32(a[3], a[7]) + mulu32(a[4], a[6])) << 1); t[11] = ((mulu32(a[3], a[8]) + mulu32(a[4], a[7]) + mulu32(a[5], a[6])) << 1); t[12] = mulu32(a[6], a[6]) + ((mulu32(a[4], a[8]) + mulu32(a[5], a[7])) << 1); t[13] = ((mulu32(a[5], a[8]) + mulu32(a[6], a[7])) << 1); t[14] = mulu32(a[7], a[7]) + ((mulu32(a[6], a[8])) << 1); t[15] = ((mulu32(a[7], a[8])) << 1); t[16] = mulu32(a[8], a[8]); // Propagate carries. let cc: u64 = 0; for (let i = 0z; i < 17; i += 1) { let w = t[i] + cc; d[i] = w: u32 & 0x3FFFFFFF; cc = w >> 30; }; d[17] = cc: u32; }; // Base field modulus for P-256. const F256: [_]u32 = [ 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x0000003F, 0x00000000, 0x00000000, 0x00001000, 0x3FFFC000, 0x0000FFFF ]; // The 'b' curve equation coefficient for P-256. const P256_B: [_]u32 = [ 0x27D2604B, 0x2F38F0F8, 0x053B0F63, 0x0741AC33, 0x1886BC65, 0x2EF555DA, 0x293E7B3E, 0x0D762A8E, 0x00005AC6 ]; // Addition in the field. Source operands shall fit on 257 bits; output // will be lower than twice the modulus. fn add_f256(d: []u32, a: []u32, b: []u32) void = { let w: u32 = 0; let cc: u32 = 0; for (let i = 0z; i < 9; i += 1) { w = a[i] + b[i] + cc; d[i] = w & 0x3FFFFFFF; cc = w >> 30; }; w >>= 16; d[8] &= 0xFFFF; d[3] -= w << 6; d[6] -= w << 12; d[7] += w << 14; cc = w; for (let i = 0z; i < 9; i += 1) { w = d[i] + cc; d[i] = w & 0x3FFFFFFF; cc = arsh(w, 30); }; }; // Subtraction in the field. Source operands shall be smaller than twice // the modulus; the result will fulfil the same property. fn sub_f256(d: []u32, a: []u32, b: []u32) void = { let w: u32 = 0; let cc: u32 = 0; // We really compute a - b + 2*p to make sure that the result is // positive. w = a[0] - b[0] - 0x00002; d[0] = w & 0x3FFFFFFF; w = a[1] - b[1] + arsh(w, 30); d[1] = w & 0x3FFFFFFF; w = a[2] - b[2] + arsh(w, 30); d[2] = w & 0x3FFFFFFF; w = a[3] - b[3] + arsh(w, 30) + 0x00080; d[3] = w & 0x3FFFFFFF; w = a[4] - b[4] + arsh(w, 30); d[4] = w & 0x3FFFFFFF; w = a[5] - b[5] + arsh(w, 30); d[5] = w & 0x3FFFFFFF; w = a[6] - b[6] + arsh(w, 30) + 0x02000; d[6] = w & 0x3FFFFFFF; w = a[7] - b[7] + arsh(w, 30) - 0x08000; d[7] = w & 0x3FFFFFFF; w = a[8] - b[8] + arsh(w, 30) + 0x20000; d[8] = w & 0xFFFF; w >>= 16; d[8] &= 0xFFFF; d[3] -= w << 6; d[6] -= w << 12; d[7] += w << 14; cc = w; for (let i = 0z; i < 9; i += 1) { w = d[i] + cc; d[i] = w & 0x3FFFFFFF; cc = arsh(w, 30); }; }; // Compute a multiplication in F256. Source operands shall be less than // twice the modulus. fn mul_f256(d: []u32, a: []u32, b: []u32) void = { let t: [18]u32 = [0...]; let s: [18]u64 = [0...]; let x: u64 = 0; mul9(t, a, b); // Modular reduction: each high word in added/subtracted where // necessary. // // The modulus is: // p = 2^256 - 2^224 + 2^192 + 2^96 - 1 // Therefore: // 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p // // For a word x at bit offset n (n >= 256), we have: // x*2^n = x*2^(n-32) - x*2^(n-64) // - x*2^(n - 160) + x*2^(n-256) mod p // // Thus, we can nullify the high word if we reinject it at some // proper emplacements. // // We use 64-bit intermediate words to allow for carries to // accumulate easily, before performing the final propagation. for (let i = 0; i < 18; i += 1) { s[i] = t[i]; }; for (let i = 17; i >= 9; i -= 1) { let y = s[i]; s[i - 1] += arshw(y, 2); s[i - 2] += (y << 28) & 0x3FFFFFFF; s[i - 2] -= arshw(y, 4); s[i - 3] -= (y << 26) & 0x3FFFFFFF; s[i - 5] -= arshw(y, 10); s[i - 6] -= (y << 20) & 0x3FFFFFFF; s[i - 8] += arshw(y, 16); s[i - 9] += (y << 14) & 0x3FFFFFFF; }; // Carry propagation must be signed. Moreover, we may have overdone // it a bit, and obtain a negative result. // // The loop above ran 9 times; each time, each word was augmented // by at most one extra word (in absolute value). Thus, the top // word must in fine fit in 39 bits, so the carry below will fit // on 9 bits. let cc: u64 = 0; for (let i = 0z; i < 9; i += 1) { x = s[i] + cc; d[i] = x: u32 & 0x3FFFFFFF; cc = arshw(x, 30); }; // All nine words fit on 30 bits, but there may be an extra // carry for a few bits (at most 9), and that carry may be // negative. Moreover, we want the result to fit on 257 bits. // The two lines below ensure that the word in d[] has length // 256 bits, and the (signed) carry (beyond 2^256) is in cc. The // significant length of cc is less than 24 bits, so we will be // able to switch to 32-bit operations. cc = arshw(x, 16); d[8] &= 0xFFFF; // One extra round of reduction, for cc*2^256, which means // adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative) // value. If cc is negative, then it may happen (rarely, but // not neglectibly so) that the result would be negative. In // order to avoid that, if cc is negative, then we add the // modulus once. Note that if cc is negative, then propagating // that carry must yield a value lower than the modulus, so // adding the modulus once will keep the final result under // twice the modulus. let z = cc: u32; d[3] -= z << 6; d[6] -= (z << 12) & 0x3FFFFFFF; d[7] -= arsh(z, 18); d[7] += (z << 14) & 0x3FFFFFFF; d[8] += arsh(z, 16); let c = z >> 31; d[0] -= c; d[3] += c << 6; d[6] += c << 12; d[7] -= c << 14; d[8] += c << 16; for (let i = 0z; i < 9; i += 1) { let w = d[i] + z; d[i] = w & 0x3FFFFFFF; z = arsh(w, 30); }; }; // Compute a square in F256. Source operand shall be less than // twice the modulus. fn square_f256(d: []u32, a: []u32) void = { let t: [18]u32 = [0...]; let s: [18]u64 = [0...]; square9(t, a); // Modular reduction: each high word in added/subtracted where // necessary. // // The modulus is: // p = 2^256 - 2^224 + 2^192 + 2^96 - 1 // Therefore: // 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p // // For a word x at bit offset n (n >= 256), we have: // x*2^n = x*2^(n-32) - x*2^(n-64) // - x*2^(n - 160) + x*2^(n-256) mod p // // Thus, we can nullify the high word if we reinject it at some // proper emplacements. // // We use 64-bit intermediate words to allow for carries to // accumulate easily, before performing the final propagation. for (let i = 0; i < 18; i += 1) { s[i] = t[i]; }; for (let i = 17; i >= 9; i -= 1) { let y = s[i]; s[i - 1] += arshw(y, 2); s[i - 2] += (y << 28) & 0x3FFFFFFF; s[i - 2] -= arshw(y, 4); s[i - 3] -= (y << 26) & 0x3FFFFFFF; s[i - 5] -= arshw(y, 10); s[i - 6] -= (y << 20) & 0x3FFFFFFF; s[i - 8] += arshw(y, 16); s[i - 9] += (y << 14) & 0x3FFFFFFF; }; // Carry propagation must be signed. Moreover, we may have overdone // it a bit, and obtain a negative result. // // The loop above ran 9 times; each time, each word was augmented // by at most one extra word (in absolute value). Thus, the top // word must in fine fit in 39 bits, so the carry below will fit // on 9 bits. let cc: u64 = 0; let x: u64 = 0; for (let i = 0; i < 9; i += 1) { x = s[i] + cc; d[i] = x: u32 & 0x3FFFFFFF; cc = arshw(x, 30); }; // All nine words fit on 30 bits, but there may be an extra // carry for a few bits (at most 9), and that carry may be // negative. Moreover, we want the result to fit on 257 bits. // The two lines below ensure that the word in d[] has length // 256 bits, and the (signed) carry (beyond 2^256) is in cc. The // significant length of cc is less than 24 bits, so we will be // able to switch to 32-bit operations. cc = arshw(x, 16); d[8] &= 0xFFFF; // One extra round of reduction, for cc*2^256, which means // adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative) // value. If cc is negative, then it may happen (rarely, but // not neglectibly so) that the result would be negative. In // order to avoid that, if cc is negative, then we add the // modulus once. Note that if cc is negative, then propagating // that carry must yield a value lower than the modulus, so // adding the modulus once will keep the final result under // twice the modulus. let z = cc: u32; d[3] -= z << 6; d[6] -= (z << 12) & 0x3FFFFFFF; d[7] -= arsh(z, 18); d[7] += (z << 14) & 0x3FFFFFFF; d[8] += arsh(z, 16); let c = z >> 31; d[0] -= c; d[3] += c << 6; d[6] += c << 12; d[7] -= c << 14; d[8] += c << 16; for (let i = 0z; i < 9; i += 1) { let w = d[i] + z; d[i] = w & 0x3FFFFFFF; z = arsh(w, 30); }; }; // Perform a "final reduction" in field F256 (field for curve P-256). // The source value must be less than twice the modulus. If the value // is not lower than the modulus, then the modulus is subtracted and // this function returns 1; otherwise, it leaves it untouched and it // returns 0. fn reduce_final_f256(d: []u32) u32 = { let t: [9]u32 = [0...]; let cc: u32 = 0; for (let i = 0; i < 9; i += 1) { let w = d[i] - F256[i] - cc; cc = w >> 31; t[i] = w & 0x3FFFFFFF; }; cc ^= 1; ccopyu32(cc, d, t); return cc; }; // Jacobian coordinates for a point in P-256: affine coordinates (X,Y) // are such that: // X = x / z^2 // Y = y / z^3 // For the point at infinity, z = 0. // Each point thus admits many possible representations. // // Coordinates are represented in arrays of 32-bit integers, each holding // 30 bits of data. Values may also be slightly greater than the modulus, // but they will always be lower than twice the modulus. type p256_jacobian = struct { x: [9]u32, y: [9]u32, z: [9]u32, }; // Convert a point to affine coordinates: // - If the point is the point at infinity, then all three coordinates // are set to 0. // - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y' // coordinates are the 'X' and 'Y' affine coordinates. // The coordinates are guaranteed to be lower than the modulus. fn p256_to_affine(p: *p256_jacobian) void = { let t1: [9]u32 = [0...]; let t2: [9]u32 = [0...]; // Invert z with a modular exponentiation: the modulus is // p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is // p-2. Exponent bit pattern (from high to low) is: // - 32 bits of value 1 // - 31 bits of value 0 // - 1 bit of value 1 // - 96 bits of value 0 // - 94 bits of value 1 // - 1 bit of value 0 // - 1 bit of value 1 // Thus, we precompute z^(2^31-1) to speed things up. // // If z = 0 (point at infinity) then the modular exponentiation // will yield 0, which leads to the expected result (all three // coordinates set to 0). // A simple square-and-multiply for z^(2^31-1). We could save about // two dozen multiplications here with an addition chain, but // this would require a bit more code, and extra stack buffers. t1[..] = p.z[..]; for (let i = 0; i < 30; i += 1) { square_f256(t1, t1); mul_f256(t1, t1, p.z); }; // Square-and-multiply. Apart from the squarings, we have a few // multiplications to set bits to 1; we multiply by the original z // for setting 1 bit, and by t1 for setting 31 bits. t2[..] = p.z[..]; for (let i = 1; i < 256; i += 1) { square_f256(t2, t2); switch (i) { case 31, 190, 221, 252 => mul_f256(t2, t2, t1); case 63, 253, 255 => mul_f256(t2, t2, p.z); case => void; }; }; // Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3. mul_f256(t1, t2, t2); mul_f256(p.x, t1, p.x); mul_f256(t1, t1, t2); mul_f256(p.y, t1, p.y); reduce_final_f256(p.x); reduce_final_f256(p.y); // Multiply z by 1/z. If z = 0, then this will yield 0, otherwise // this will set z to 1. mul_f256(p.z, p.z, t2); reduce_final_f256(p.z); }; // Double a point in P-256. This function works for all valid points, // including the point at infinity. fn p256_double(q: *p256_jacobian) void = { // Doubling formulas are: // // s = 4*x*y^2 // m = 3*(x + z^2)*(x - z^2) // x' = m^2 - 2*s // y' = m*(s - x') - 8*y^4 // z' = 2*y*z // // These formulas work for all points, including points of order 2 // and points at infinity: // - If y = 0 then z' = 0. But there is no such point in P-256 // anyway. // - If z = 0 then z' = 0. let t1: [9]u32 = [0...]; let t2: [9]u32 = [0...]; let t3: [9]u32 = [0...]; let t4: [9]u32 = [0...]; // Compute z^2 in t1. square_f256(t1, q.z); // Compute x-z^2 in t2 and x+z^2 in t1. add_f256(t2, q.x, t1); sub_f256(t1, q.x, t1); // Compute 3*(x+z^2)*(x-z^2) in t1. mul_f256(t3, t1, t2); add_f256(t1, t3, t3); add_f256(t1, t3, t1); // Compute 4*x*y^2 (in t2) and 2*y^2 (in t3). square_f256(t3, q.y); add_f256(t3, t3, t3); mul_f256(t2, q.x, t3); add_f256(t2, t2, t2); // Compute x' = m^2 - 2*s. square_f256(q.x, t1); sub_f256(q.x, q.x, t2); sub_f256(q.x, q.x, t2); // Compute z' = 2*y*z. mul_f256(t4, q.y, q.z); add_f256(q.z, t4, t4); // Compute y' = m*(s - x') - 8*y^4. Note that we already have // 2*y^2 in t3. sub_f256(t2, t2, q.x); mul_f256(q.y, t1, t2); square_f256(t4, t3); add_f256(t4, t4, t4); sub_f256(q.y, q.y, t4); }; // Add point P2 to point P1. // // This function computes the wrong result in the following cases: // // - If P1 == 0 but P2 != 0 // - If P1 != 0 but P2 == 0 // - If P1 == P2 // // In all three cases, P1 is set to the point at infinity. // // Returned value is 0 if one of the following occurs: // // - P1 and P2 have the same Y coordinate // - P1 == 0 and P2 == 0 // - The Y coordinate of one of the points is 0 and the other point is // the point at infinity. // // The third case cannot actually happen with valid points, since a point // with Y == 0 is a point of order 2, and there is no point of order 2 on // curve P-256. // // Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller // can apply the following: // // - If the result is not the point at infinity, then it is correct. // - Otherwise, if the returned value is 1, then this is a case of // P1+P2 == 0, so the result is indeed the point at infinity. // - Otherwise, P1 == P2, so a "double" operation should have been // performed. fn p256_add(p1: *p256_jacobian, p2: *p256_jacobian) u32 = { // Addtions formulas are: // // u1 = x1 * z2^2 // u2 = x2 * z1^2 // s1 = y1 * z2^3 // s2 = y2 * z1^3 // h = u2 - u1 // r = s2 - s1 // x3 = r^2 - h^3 - 2 * u1 * h^2 // y3 = r * (u1 * h^2 - x3) - s1 * h^3 // z3 = h * z1 * z2 let t1: [9]u32 = [0...]; let t2: [9]u32 = [0...]; let t3: [9]u32 = [0...]; let t4: [9]u32 = [0...]; let t5: [9]u32 = [0...]; let t6: [9]u32 = [0...]; let t7: [9]u32 = [0...]; let ret: u32 = 0; // Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). square_f256(t3, p2.z); mul_f256(t1, p1.x, t3); mul_f256(t4, p2.z, t3); mul_f256(t3, p1.y, t4); // Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). square_f256(t4, p1.z); mul_f256(t2, p2.x, t4); mul_f256(t5, p1.z, t4); mul_f256(t4, p2.y, t5); // Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). // We need to test whether r is zero, so we will do some extra // reduce. sub_f256(t2, t2, t1); sub_f256(t4, t4, t3); reduce_final_f256(t4); ret = 0; for (let i = 0; i < 9; i += 1) { ret |= t4[i]; }; ret = (ret | -ret) >> 31; // Compute u1*h^2 (in t6) and h^3 (in t5); square_f256(t7, t2); mul_f256(t6, t1, t7); mul_f256(t5, t7, t2); // Compute x3 = r^2 - h^3 - 2*u1*h^2. square_f256(p1.x, t4); sub_f256(p1.x, p1.x, t5); sub_f256(p1.x, p1.x, t6); sub_f256(p1.x, p1.x, t6); // Compute y3 = r*(u1*h^2 - x3) - s1*h^3. sub_f256(t6, t6, p1.x); mul_f256(p1.y, t4, t6); mul_f256(t1, t5, t3); sub_f256(p1.y, p1.y, t1); // Compute z3 = h*z1*z2. mul_f256(t1, p1.z, p2.z); mul_f256(p1.z, t1, t2); return ret; }; // Add point P2 to point P1. This is a specialised function for the // case when P2 is a non-zero point in affine coordinate. // // This function computes the wrong result in the following cases: // // - If P1 == 0 // - If P1 == P2 // // In both cases, P1 is set to the point at infinity. // // Returned value is 0 if one of the following occurs: // // - P1 and P2 have the same Y coordinate // - The Y coordinate of P2 is 0 and P1 is the point at infinity. // // The second case cannot actually happen with valid points, since a point // with Y == 0 is a point of order 2, and there is no point of order 2 on // curve P-256. // // Therefore, assuming that P1 != 0 on input, then the caller // can apply the following: // // - If the result is not the point at infinity, then it is correct. // - Otherwise, if the returned value is 1, then this is a case of // P1+P2 == 0, so the result is indeed the point at infinity. // - Otherwise, P1 == P2, so a "double" operation should have been // performed. fn p256_add_mixed(p1: *p256_jacobian, p2: *p256_jacobian) u32 = { // Addtions formulas are: // // u1 = x1 // u2 = x2 * z1^2 // s1 = y1 // s2 = y2 * z1^3 // h = u2 - u1 // r = s2 - s1 // x3 = r^2 - h^3 - 2 * u1 * h^2 // y3 = r * (u1 * h^2 - x3) - s1 * h^3 // z3 = h * z1 let t1: [9]u32 = [0...]; let t2: [9]u32 = [0...]; let t3: [9]u32 = [0...]; let t4: [9]u32 = [0...]; let t5: [9]u32 = [0...]; let t6: [9]u32 = [0...]; let t7: [9]u32 = [0...]; let ret: u32 = 0; // Compute u1 = x1 (in t1) and s1 = y1 (in t3). t1[..] = p1.x[..]; t3[..] = p1.y[..]; // Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). square_f256(t4, p1.z); mul_f256(t2, p2.x, t4); mul_f256(t5, p1.z, t4); mul_f256(t4, p2.y, t5); // Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4). // We need to test whether r is zero, so we will do some extra // reduce. sub_f256(t2, t2, t1); sub_f256(t4, t4, t3); reduce_final_f256(t4); ret = 0; for (let i = 0; i < 9; i += 1) { ret |= t4[i]; }; ret = (ret | -ret) >> 31; // Compute u1*h^2 (in t6) and h^3 (in t5); square_f256(t7, t2); mul_f256(t6, t1, t7); mul_f256(t5, t7, t2); // Compute x3 = r^2 - h^3 - 2*u1*h^2. square_f256(p1.x, t4); sub_f256(p1.x, p1.x, t5); sub_f256(p1.x, p1.x, t6); sub_f256(p1.x, p1.x, t6); // Compute y3 = r*(u1*h^2 - x3) - s1*h^3. sub_f256(t6, t6, p1.x); mul_f256(p1.y, t4, t6); mul_f256(t1, t5, t3); sub_f256(p1.y, p1.y, t1); // Compute z3 = h*z1*z2. mul_f256(p1.z, p1.z, t2); return ret; }; // Decode a P-256 point. This function does not support the point at // infinity. Returned value is 0 if the point is invalid, 1 otherwise. fn p256_decode(p: *p256_jacobian, src: const []u8) u32 = { let tx: [9]u32 = [0...]; let ty: [9]u32 = [0...]; let t1: [9]u32 = [0...]; let t2: [9]u32 = [0...]; let bad: u32 = 0; if (len(src) != 65) { return 0; }; let buf = src; // First byte must be 0x04 (uncompressed format). We could support // "hybrid format" (first byte is 0x06 or 0x07, and encodes the // least significant bit of the Y coordinate), but it is explicitly // forbidden by RFC 5480 (section 2.2). bad = nequ32(buf[0], 0x04); // Decode the coordinates, and check that they are both lower // than the modulus. tx[8] = be8tole30(tx, buf[1..33]); ty[8] = be8tole30(ty, buf[33..]); bad |= reduce_final_f256(tx); bad |= reduce_final_f256(ty); // Check curve equation. square_f256(t1, tx); mul_f256(t1, tx, t1); square_f256(t2, ty); sub_f256(t1, t1, tx); sub_f256(t1, t1, tx); sub_f256(t1, t1, tx); add_f256(t1, t1, P256_B); sub_f256(t1, t1, t2); reduce_final_f256(t1); for (let i = 0; i < 9; i += 1) { bad |= t1[i]; }; // Copy coordinates to the point structure. p.x[..] = tx[..]; p.y[..] = ty[..]; p.z[..] = [0...]; p.z[0] = 1; return equ32(bad, 0); }; // Encode a point into a buffer. This function assumes that the point is // valid, in affine coordinates, and not the point at infinity. fn p256_encode(dest: []u8, p: *p256_jacobian) void = { dest[0] = 0x04; le30tobe8(dest[1..33], p.x); le30tobe8(dest[33..], p.y); }; // Multiply a curve point by an integer. The integer is assumed to be // lower than the curve order, and the base point must not be the point // at infinity. fn p256_mul(p: *p256_jacobian, x: []u8) void = { // qz is a flag that is initially 1, and remains equal to 1 // as long as the point is the point at infinity. // // We use a 2-bit window to handle multiplier bits by pairs. // The precomputed window really is the points P2 and P3. let qz: u32 = 1; let p2 = p256_jacobian { ... }; let p3 = p256_jacobian { ... }; let q = p256_jacobian { ... }; let t = p256_jacobian { ... }; let u = p256_jacobian { ... }; let xpos: size = 0; // Compute window values. p2 = *p; p256_double(&p2); p3 = *p; p256_add(&p3, &p2); // We start with Q = 0. We process multiplier bits 2 by 2. for (let i = len(x); i > 0; i -= 1) { for (let k = 6i8; k >= 0; k -= 2) { let bits: u32 = 0; let bnz: u32 = 0; p256_double(&q); p256_double(&q); t = *p; u = q; bits = (x[xpos] >> k: u8) & 3u32; bnz = nequ32(bits, 0); jaccopy(equ32(bits, 2), &t, &p2); jaccopy(equ32(bits, 3), &t, &p3); p256_add(&u, &t); jaccopy(bnz & qz, &q, &t); jaccopy(bnz & ~qz, &q, &u); qz &= ~bnz; }; xpos += 1; }; *p = q; }; fn jaccopy(ctl: u32, dest: *p256_jacobian, src: *p256_jacobian) void = { ccopyu32(ctl, dest.x, src.x); ccopyu32(ctl, dest.y, src.y); ccopyu32(ctl, dest.z, src.z); }; // Precomputed window: k*G points, where G is the curve generator, and k // is an integer from 1 to 15 (inclusive). The X and Y coordinates of // the point are encoded as 9 words of 30 bits each (little-endian // order). const gwin: [15][18]u32 = [ [ 0x1898c296, 0x1284e517, 0x1eb33a0f, 0x00df604b, 0x2440f277, 0x339b958e, 0x04247f8b, 0x347cb84b, 0x00006b17, 0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0x0f9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x00004fe3, ], [ 0x07669978, 0x182d23f1, 0x3f21b35a, 0x225a789d, 0x351ac3c0, 0x08e00c12, 0x34f7e8a5, 0x1ec62340, 0x00007cf2, 0x227873d1, 0x3812de74, 0x0e982299, 0x1f6b798f, 0x3430dbba, 0x366b1a7d, 0x2d040293, 0x154436e3, 0x00000777, ], [ 0x06e7fd6c, 0x2d05986f, 0x3ada985f, 0x31adc87b, 0x0bf165e6, 0x1fbe5475, 0x30a44c8f, 0x3934698c, 0x00005ecb, 0x227d5032, 0x29e6c49e, 0x04fb83d9, 0x0aac0d8e, 0x24a2ecd8, 0x2c1b3869, 0x0ff7e374, 0x19031266, 0x00008734, ], [ 0x2b030852, 0x024c0911, 0x05596ef5, 0x07f8b6de, 0x262bd003, 0x3779967b, 0x08fbba02, 0x128d4cb4, 0x0000e253, 0x184ed8c6, 0x310b08fc, 0x30ee0055, 0x3f25b0fc, 0x062d764e, 0x3fb97f6a, 0x33cc719d, 0x15d69318, 0x0000e0f1, ], [ 0x03d033ed, 0x05552837, 0x35be5242, 0x2320bf47, 0x268fdfef, 0x13215821, 0x140d2d78, 0x02de9454, 0x00005159, 0x3da16da4, 0x0742ed13, 0x0d80888d, 0x004bc035, 0x0a79260d, 0x06fcdafe, 0x2727d8ae, 0x1f6a2412, 0x0000e0c1, ], [ 0x3c2291a9, 0x1ac2aba4, 0x3b215b4c, 0x131d037a, 0x17dde302, 0x0c90b2e2, 0x0602c92d, 0x05ca9da9, 0x0000b01a, 0x0fc77fe2, 0x35f1214e, 0x07e16bdf, 0x003ddc07, 0x2703791c, 0x3038b7ee, 0x3dad56fe, 0x041d0c8d, 0x0000e85c, ], [ 0x3187b2a3, 0x0018a1c0, 0x00fef5b3, 0x3e7e2e2a, 0x01fb607e, 0x2cc199f0, 0x37b4625b, 0x0edbe82f, 0x00008e53, 0x01f400b4, 0x15786a1b, 0x3041b21c, 0x31cd8cf2, 0x35900053, 0x1a7e0e9b, 0x318366d0, 0x076f780c, 0x000073eb, ], [ 0x1b6fb393, 0x13767707, 0x3ce97dbb, 0x348e2603, 0x354cadc1, 0x09d0b4ea, 0x1b053404, 0x1de76fba, 0x000062d9, 0x0f09957e, 0x295029a8, 0x3e76a78d, 0x3b547dae, 0x27cee0a2, 0x0575dc45, 0x1d8244ff, 0x332f647a, 0x0000ad5a, ], [ 0x10949ee0, 0x1e7a292e, 0x06df8b3d, 0x02b2e30b, 0x31f8729e, 0x24e35475, 0x30b71878, 0x35edbfb7, 0x0000ea68, 0x0dd048fa, 0x21688929, 0x0de823fe, 0x1c53faa9, 0x0ea0c84d, 0x052a592a, 0x1fce7870, 0x11325cb2, 0x00002a27, ], [ 0x04c5723f, 0x30d81a50, 0x048306e4, 0x329b11c7, 0x223fb545, 0x085347a8, 0x2993e591, 0x1b5aca8e, 0x0000cef6, 0x04af0773, 0x28d2eea9, 0x2751eeec, 0x037b4a7f, 0x3b4c1059, 0x08f37674, 0x2ae906e1, 0x18a88a6a, 0x00008786, ], [ 0x34bc21d1, 0x0cce474d, 0x15048bf4, 0x1d0bb409, 0x021cda16, 0x20de76c3, 0x34c59063, 0x04ede20e, 0x00003ed1, 0x282a3740, 0x0be3bbf3, 0x29889dae, 0x03413697, 0x34c68a09, 0x210ebe93, 0x0c8a224c, 0x0826b331, 0x00009099, ], [ 0x0624e3c4, 0x140317ba, 0x2f82c99d, 0x260c0a2c, 0x25d55179, 0x194dcc83, 0x3d95e462, 0x356f6a05, 0x0000741d, 0x0d4481d3, 0x2657fc8b, 0x1ba5ca71, 0x3ae44b0d, 0x07b1548e, 0x0e0d5522, 0x05fdc567, 0x2d1aa70e, 0x00000770, ], [ 0x06072c01, 0x23857675, 0x1ead58a9, 0x0b8a12d9, 0x1ee2fc79, 0x0177cb61, 0x0495a618, 0x20deb82b, 0x0000177c, 0x2fc7bfd8, 0x310eef8b, 0x1fb4df39, 0x3b8530e8, 0x0f4e7226, 0x0246b6d0, 0x2a558a24, 0x163353af, 0x000063bb, ], [ 0x24d2920b, 0x1c249dcc, 0x2069c5e5, 0x09ab2f9e, 0x36df3cf1, 0x1991fd0c, 0x062b97a7, 0x1e80070e, 0x000054e7, 0x20d0b375, 0x2e9f20bd, 0x35090081, 0x1c7a9ddc, 0x22e7c371, 0x087e3016, 0x03175421, 0x3c6eca7d, 0x0000f599, ], [ 0x259b9d5f, 0x0d9a318f, 0x23a0ef16, 0x00ebe4b7, 0x088265ae, 0x2cde2666, 0x2bae7adf, 0x1371a5c6, 0x0000f045, 0x0d034f36, 0x1f967378, 0x1b5fa3f4, 0x0ec8739d, 0x1643e62a, 0x1653947e, 0x22d1f4e6, 0x0fb8d64b, 0x0000b5b9, ], ]; // Lookup one of the Gwin[] values, by index. This is constant-time. fn lookup_gwin(t: *p256_jacobian, idx: u32) void = { let xy: [18]u32 = [0...]; let k: u32 = 0; let u: size = 0; for (let k = 0u32; k < 15; k += 1) { let m = -equ32(idx, k + 1); for (let u = 0z; u < 18; u += 1) { xy[u] |= m & gwin[k][u]; }; }; t.x[..] = xy[..9]; t.y[..] = xy[9..]; t.z[..] = [0...]; t.z[0] = 1; }; // Multiply the generator by an integer. The integer is assumed non-zero // and lower than the curve order. fn p256_mulgen(p :*p256_jacobian, x: []u8) void = { // qz is a flag that is initially 1, and remains equal to 1 // as long as the point is the point at infinity. // // We use a 4-bit window to handle multiplier bits by groups // of 4. The precomputed window is constant static data, with // points in affine coordinates; we use a constant-time lookup. let q = p256_jacobian { ... }; let qz: u32 = 1; let xpos: size = 0; for (let i = len(x); i > 0; i -= 1) { let bx = x[xpos]: u32; xpos += 1; for (let k = 0z; k < 2; k += 1) { let bits: u32 = 0; let bnz: u32 = 0; let t = p256_jacobian { ... }; let u = p256_jacobian { ... }; p256_double(&q); p256_double(&q); p256_double(&q); p256_double(&q); bits = (bx >> 4) & 0x0f; bnz = nequ32(bits, 0); lookup_gwin(&t, bits); u = q; p256_add_mixed(&u, &t); jaccopy(bnz & qz, &q, &t); jaccopy(bnz & ~qz, &q, &u); qz &= ~bnz; bx <<= 4; }; }; *p = q; }; const P256_G: [_]u8 = [ 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 ]; const P256_N: [_]u8 = [ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51 ]; fn api256_mul(g: []u8, x: []u8) u32 = { if (len(g) != 65) { return 0; }; let p = p256_jacobian { ... }; let r = p256_decode(&p, g); p256_mul(&p, x); p256_to_affine(&p); p256_encode(g, &p); return r; }; fn api256_mulgen(r: []u8, x: []u8) size = { let p = p256_jacobian { ... }; p256_mulgen(&p, x); p256_to_affine(&p); p256_encode(r[..65], &p); return 65; }; fn api256_muladd(a: []u8, b: []u8, x: []u8, y: []u8) u32 ={ let p = p256_jacobian { ... }; let q = p256_jacobian { ... }; if (len(a) != 65) { return 0; }; let r = p256_decode(&p, a); p256_mul(&p, x); if (len(b) == 0) { p256_mulgen(&q, y); } else { r &= p256_decode(&q, b); p256_mul(&q, y); }; // The final addition may fail in case both points are equal. let t = p256_add(&p, &q); reduce_final_f256(p.z); let z: u32 = 0; for (let i = 0z; i < 9; i += 1) { z |= p.z[i]; }; z = equ32(z, 0); p256_double(&q); // If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we // have the following: // // z = 0, t = 0 return P (normal addition) // z = 0, t = 1 return P (normal addition) // z = 1, t = 0 return Q (a 'double' case) // z = 1, t = 1 report an error (P+Q = 0) jaccopy(z & ~t, &p, &q); p256_to_affine(&p); p256_encode(a, &p); r &= ~(z & t); return r; }; fn api256_order() const []u8 = P256_N; fn api256_generator() const []u8 = P256_G; const _p256: curve = curve { pointsz = P256_POINTSZ, order = &api256_order, generator = &api256_generator, mul = &api256_mul, mulgen = &api256_mulgen, muladd = &api256_muladd, keygen = &mask_keygen, }; // Size of a [[p256]] point in bytes. export def P256_POINTSZ = 65; // Size of a [[p256]] scalar in bytes. export def P256_SCALARSZ = 32; // A [[curve]] implementation of P-256, also known as secp256r1 or prime256v1. // // The point size is defined by [[P256_POINTSZ]] and the scalar size is defined // by [[P256_SCALARSZ]. See the documentation of [[curve]] on how to encode // such values. export const p256: *curve = &_p256; hare-0.24.2/crypto/ec/prime.ha000066400000000000000000000560561464473310100160720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Ported from BearSSL // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::math::*; use crypto::bigint::*; type curveparams = struct { p: []word, b: []word, r2: []word, p0i: word, pointlen: size, g: []u8, }; // Parameters for supported curves (field modulus, and 'b' equation // parameter; both values use the 'i31' format, and 'b' is in Montgomery // representation). const p384params = curveparams { p = [ 0x0000018C, 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8, 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000FFF ], b = [ 0x0000018C, 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C, 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B, 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE, 0x000008A5 ], r2 = [ 0x0000018C, 0x00000000, 0x00000080, 0x7FFFFE00, 0x000001FF, 0x00000800, 0x00000000, 0x7FFFE000, 0x00001FFF, 0x00008000, 0x00008000, 0x00000000, 0x00000000, 0x00000000 ], p0i = 0x00000001, pointlen = 97, g = [ // XXX: use P384_G, when possible 0x04, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, ], }; const p521params = curveparams { p = [ 0x00000219, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x01FFFFFF ], b = [ 0x00000219, 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A, 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F, 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366, 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393, 0x00654FAE ], r2 = [ 0x00000219, 0x00001000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 ], p0i = 0x00000001, pointlen = 133, g = [ // XXX: use P384_G, when possible 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1, 0x66, 0x50, ], }; @test fn bigint_support() void = { // This is a port of the i31 variant from BearSSL. Word must be an u32 // in order for this code to work. static assert(size(word) == 4); }; def MAX_COORDSZ = (MAX_COORDBITSZ + 61) / 31; type prime_jacobian = struct { // TODO things would be a lot easier if this is a flat array c: [3][MAX_COORDSZ]word, }; type reg = []word; // XXX: BearSSL is using memcpy. Can I do this here also? fn jcpy(d: *prime_jacobian, a: *prime_jacobian) void = { for (let i = 0z; i < len(d.c); i += 1) { d.c[i][..] = a.c[i][..]; // XXX: is this copy ct? }; }; fn jccpy(ctl: u32, d: *prime_jacobian, a: *prime_jacobian) void = { for (let i = 0z; i < len(d.c); i += 1) { ccopyu32(ctl, d.c[i]: []u32, a.c[i][..]: []u32); }; }; fn mset(d: reg, a: reg) void = { for (let i = 0z; i < len(d); i += 1) { d[i] = a[i]; }; }; fn madd(d: reg, a: reg, cc: *curveparams) void = { let ctl = add(d, a, 1); ctl |= notu32(sub(d, cc.p, 0)); sub(d, cc.p, ctl); }; fn msub(d: reg, a: reg, cc: *curveparams) void = { add(d, cc.p, sub(d, a, 1)); }; fn mmul(d: reg, a: reg, b: reg, cc: *curveparams) void = { montymul(d, a, b, cc.p, cc.p0i); }; fn minv(d: reg, a: reg, b: reg, cc: *curveparams) void = { let tp: [MAX_POINTSZ / 2]u8 = [0...]; let plen = (cc.p[0] - (cc.p[0] >> 5) + 7) >> 3; decode(tp[..plen], cc.p); tp[plen - 1] -= 2; // XXX: change modpow to use two bigints as buf, like it was intended let buf: [2 * MAX_COORDSZ]word = [0...]; modpow(d, tp[..plen], cc.p, cc.p0i, buf); }; fn prime_zero(p: *prime_jacobian, cc: *curveparams) void = { for (let i = 0z; i < len(p.c); i += 1) { for (let j = 0z; j < len(p.c[i]); j += 1) { p.c[i][j] = 0; }; }; p.c[0][0] = cc.p[0]; p.c[1][0] = cc.p[0]; p.c[2][0] = cc.p[0]; }; // Doubling formulas are: // // s = 4*x*y^2 // m = 3*(x + z^2)*(x - z^2) // x' = m^2 - 2*s // y' = m*(s - x') - 8*y^4 // z' = 2*y*z // // If y = 0 (P has order 2) then this yields infinity (z' = 0), as it // should. This case should not happen anyway, because our curves have // prime order, and thus do not contain any point of order 2. // // If P is infinity (z = 0), then again the formulas yield infinity, // which is correct. Thus, this code works for all points. // // Cost: 8 multiplications fn point_double(p: *prime_jacobian, cc: *curveparams) void = { let px: [MAX_COORDSZ]word = p.c[0]; let py: [MAX_COORDSZ]word = p.c[1]; let pz: [MAX_COORDSZ]word = p.c[2]; let t1: [MAX_COORDSZ]word = [0...]; let t2: [MAX_COORDSZ]word = [0...]; let t3: [MAX_COORDSZ]word = [0...]; let t4: [MAX_COORDSZ]word = [0...]; // Compute z^2 (in t1). mmul(t1, pz, pz, cc); // Compute x-z^2 (in t2) and then x+z^2 (in t1). mset(t2, px); msub(t2, t1, cc); madd(t1, px, cc); // Compute m = 3*(x+z^2)*(x-z^2) (in t1). mmul(t3, t1, t2, cc); mset(t1, t3); madd(t1, t3, cc); madd(t1, t3, cc); // Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3). mmul(t3, py, py, cc); madd(t3, t3, cc); mmul(t2, px, t3, cc); madd(t2, t2, cc); // Compute x' = m^2 - 2*s. mmul(px, t1, t1, cc); msub(px, t2, cc); msub(px, t2, cc); // Compute z' = 2*y*z. mmul(t4, py, pz, cc); mset(pz, t4); madd(pz, t4, cc); // Compute y' = m*(s - x') - 8*y^4. Note that we already have // 2*y^2 in t3. msub(t2, px, cc); mmul(py, t1, t2, cc); mmul(t4, t3, t3, cc); msub(py, t4, cc); msub(py, t4, cc); // copy back result p.c[0][..] = px[..]; p.c[1][..] = py[..]; p.c[2][..] = pz[..]; }; // Addtions formulas are: // // u1 = x1 * z2^2 // u2 = x2 * z1^2 // s1 = y1 * z2^3 // s2 = y2 * z1^3 // h = u2 - u1 // r = s2 - s1 // x3 = r^2 - h^3 - 2 * u1 * h^2 // y3 = r * (u1 * h^2 - x3) - s1 * h^3 // z3 = h * z1 * z2 // // If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that // z3 == 0, so the result is correct. // If either of P1 or P2 is infinity, but not both, then z3 == 0, which is // not correct. // h == 0 only if u1 == u2; this happens in two cases: // -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2 // -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity) // // Thus, the following situations are not handled correctly: // -- P1 = 0 and P2 != 0 // -- P1 != 0 and P2 = 0 // -- P1 = P2 // All other cases are properly computed. However, even in "incorrect" // situations, the three coordinates still are properly formed field // elements. // // The returned flag is cleared if r == 0. This happens in the following // cases: // -- Both points are on the same horizontal line (same Y coordinate). // -- Both points are infinity. // -- One point is infinity and the other is on line Y = 0. // The third case cannot happen with our curves (there is no valid point // on line Y = 0 since that would be a point of order 2). If the two // source points are non-infinity, then remains only the case where the // two points are on the same horizontal line. // // This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and // P2 != 0: // -- If the returned value is not the point at infinity, then it was properly // computed. // -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result // is indeed the point at infinity. // -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should // use the 'double' code. // // Cost: 16 multiplications fn point_add(p1: *prime_jacobian, p2: *prime_jacobian, cc: *curveparams) u32 = { let p1x: [MAX_COORDSZ]word = p1.c[0]; let p1y: [MAX_COORDSZ]word = p1.c[1]; let p1z: [MAX_COORDSZ]word = p1.c[2]; let p2x: [MAX_COORDSZ]word = p2.c[0]; let p2y: [MAX_COORDSZ]word = p2.c[1]; let p2z: [MAX_COORDSZ]word = p2.c[2]; let t1: [MAX_COORDSZ]word = [0...]; let t2: [MAX_COORDSZ]word = [0...]; let t3: [MAX_COORDSZ]word = [0...]; let t4: [MAX_COORDSZ]word = [0...]; let t5: [MAX_COORDSZ]word = [0...]; let t6: [MAX_COORDSZ]word = [0...]; let t7: [MAX_COORDSZ]word = [0...]; let r: u32 = 1; // Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3). mmul(t3, p2z, p2z, cc); mmul(t1, p1x, t3, cc); mmul(t4, p2z, t3, cc); mmul(t3, p1y, t4, cc); // Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4). mmul(t4, p1z, p1z, cc); mmul(t2, p2x, t4, cc); mmul(t5, p1z, t4, cc); mmul(t4, p2y, t5, cc); // Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4). msub(t2, t1, cc); msub(t4, t3, cc); // Report cases where r = 0 through the returned flag. r &= ~iszero(t4); // Compute u1*h^2 (in t6) and h^3 (in t5). mmul(t7, t2, t2, cc); mmul(t6, t1, t7, cc); mmul(t5, t7, t2, cc); // Compute x3 = r^2 - h^3 - 2*u1*h^2. // t1 and t7 can be used as scratch registers. mmul(p1x, t4, t4, cc); msub(p1x, t5, cc); msub(p1x, t6, cc); msub(p1x, t6, cc); // Compute y3 = r*(u1*h^2 - x3) - s1*h^3. msub(t6, p1x, cc); mmul(p1y, t4, t6, cc); mmul(t1, t5, t3, cc); msub(p1y, t1, cc); // Compute z3 = h*z1*z2. mmul(t1, p1z, p2z, cc); mmul(p1z, t1, t2, cc); // copy back result p1.c[0][..] = p1x[..]; p1.c[1][..] = p1y[..]; p1.c[2][..] = p1z[..]; return r; }; // Check that the point is on the curve. This code snippet assumes the // following conventions: // -- Coordinates x and y have been freshly decoded in P1 (but not // converted to Montgomery coordinates yet). // -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1. fn prime_check(p1: *prime_jacobian, p2: *prime_jacobian, cc: *curveparams) u32 = { let p1x: [MAX_COORDSZ]word = p1.c[0]; let p1y: [MAX_COORDSZ]word = p1.c[1]; let p1z: [MAX_COORDSZ]word = p1.c[2]; let p2x: [MAX_COORDSZ]word = p2.c[0]; let p2y: [MAX_COORDSZ]word = p2.c[1]; let p2z: [MAX_COORDSZ]word = p2.c[2]; let t1: [MAX_COORDSZ]word = [0...]; let t2: [MAX_COORDSZ]word = [0...]; let r: u32 = 1; // Convert x and y to Montgomery representation. mmul(t1, p1x, p2x, cc); mmul(t2, p1y, p2x, cc); mset(p1x, t1); mset(p1y, t2); // Compute x^3 in t1. */ mmul(t2, p1x, p1x, cc); mmul(t1, p1x, t2, cc); // Subtract 3*x from t1. */ msub(t1, p1x, cc); msub(t1, p1x, cc); msub(t1, p1x, cc); // Add b. */ madd(t1, p2y, cc); // Compute y^2 in t2. */ mmul(t2, p1y, p1y, cc); // Compare y^2 with x^3 - 3*x + b; they must match. */ msub(t1, t2, cc); r &= ~iszero(t1); // Set z to 1 (in Montgomery representation). */ mmul(p1z, p2x, p2z, cc); // copy back result p1.c[0][..] = p1x[..]; p1.c[1][..] = p1y[..]; p1.c[2][..] = p1z[..]; return r; }; // Conversion back to affine coordinates. This code snippet assumes that // the z coordinate of P2 is set to 1 (not in Montgomery representation). fn prime_affine(p1: *prime_jacobian, p2: *prime_jacobian, cc: *curveparams) void = { let p1x: [MAX_COORDSZ]word = p1.c[0]; let p1y: [MAX_COORDSZ]word = p1.c[1]; let p1z: [MAX_COORDSZ]word = p1.c[2]; let p2x: [MAX_COORDSZ]word = p2.c[0]; let p2y: [MAX_COORDSZ]word = p2.c[1]; let p2z: [MAX_COORDSZ]word = p2.c[2]; let t1: [MAX_COORDSZ]word = [0...]; let t2: [MAX_COORDSZ]word = [0...]; let t3: [MAX_COORDSZ]word = [0...]; let t4: [MAX_COORDSZ]word = [0...]; let t5: [MAX_COORDSZ]word = [0...]; let t6: [MAX_COORDSZ]word = [0...]; let t7: [MAX_COORDSZ]word = [0...]; let r: u32 = 1; // Save z*R in t1. */ mset(t1, p1z); // Compute z^3 in t2. */ mmul(t2, p1z, p1z, cc); mmul(t3, p1z, t2, cc); mmul(t2, t3, p2z, cc); // Invert to (1/z^3) in t2. */ minv(t2, t3, t4, cc); // Compute y. */ mset(t3, p1y); mmul(p1y, t2, t3, cc); // Compute (1/z^2) in t3. */ mmul(t3, t2, t1, cc); // Compute x. */ mset(t2, p1x); mmul(p1x, t2, t3, cc); // copy back result p1.c[0][..] = p1x[..]; p1.c[1][..] = p1y[..]; p1.c[2][..] = p1z[..]; }; fn prime_setone(x: []word, p: []word) void = { for (let i = 0z; i < len(x); i += 1) { x[i] = 0; }; x[0] = p[0]; x[1] = 1; }; fn prime_pointzero(p: *prime_jacobian) void = { // XXX: bytes::zero? for (let i = 0z; i < len(p.c); i += 1) { for (let j = 0z; j < len(p.c[i]); j += 1) { p.c[i][j] = 0; }; }; }; fn point_mul(p: *prime_jacobian, x: []u8, cc: *curveparams) void = { // We do a simple double-and-add ladder with a 2-bit window // to make only one add every two doublings. We thus first // precompute 2P and 3P in some local buffers. // // We always perform two doublings and one addition; the // addition is with P, 2P and 3P and is done in a temporary // array. // // The addition code cannot handle cases where one of the // operands is infinity, which is the case at the start of the // ladder. We therefore need to maintain a flag that controls // this situation. let p2 = prime_jacobian { ... }; let p3 = prime_jacobian { ... }; let q = prime_jacobian { ... }; let t = prime_jacobian { ... }; let u = prime_jacobian { ... }; jcpy(&p2, p); point_double(&p2, cc); jcpy(&p3, p); point_add(&p3, &p2, cc); prime_zero(&q, cc); let qz: u32 = 1; for (let i = 0z; i < len(x); i += 1) { for (let k: i32 = 6; k >= 0; k -= 2) { point_double(&q, cc); point_double(&q, cc); jcpy(&t, p); jcpy(&u, &q); let bits: u32 = (x[i]: u32 >> k: u32) & 3; let bnz: u32 = nequ32(bits, 0); jccpy(equ32(bits, 2), &t, &p2); jccpy(equ32(bits, 3), &t, &p3); point_add(&u, &t, cc); jccpy(bnz & qz, &q, &t); jccpy(bnz & ~qz, &q, &u); qz &= ~bnz; }; }; jcpy(p, &q); }; // Decode point into Jacobian coordinates. This function does not support // the point at infinity. If the point is invalid then this returns 0, but // the coordinates are still set to properly formed field elements. fn point_decode(p: *prime_jacobian, src: []u8, cc: *curveparams) u32 = { // Points must use uncompressed format: // -- first byte is 0x04; // -- coordinates X and Y use unsigned big-endian, with the same // length as the field modulus. // // We don't support hybrid format (uncompressed, but first byte // has value 0x06 or 0x07, depending on the least significant bit // of Y) because it is rather useless, and explicitly forbidden // by PKIX (RFC 5480, section 2.2). // // We don't support compressed format either, because it is not // much used in practice (there are or were patent-related // concerns about point compression, which explains the lack of // generalised support). Also, point compression support would // need a bit more code. let q = prime_jacobian { ... }; let buf = src; prime_pointzero(p); let plen: size = (cc.p[0] - (cc.p[0] >> 5) + 7) >> 3; if (len(src) != 1 + (plen << 1)) { return 0; }; let r: u32 = encodemod(p.c[0], buf[1..1 + plen], cc.p); r &= encodemod(p.c[1], buf[1 + plen..1 + 2*plen], cc.p); // Check first byte. r &= equ32(buf[0], 0x04); // Convert coordinates and check that the point is valid. let zlen: size = ((cc.p[0] + 63) >> 5); q.c[0][..zlen] = cc.r2[..zlen]; q.c[1][..zlen] = cc.b[..zlen]; prime_setone(q.c[2], cc.p); r &= ~prime_check(p, &q, cc); return r; }; // Encode a point. This method assumes that the point is correct and is // not the point at infinity. Encoded size is always 1+2*plen, where // plen is the field modulus length, in bytes. fn point_encode(dest: []u8, p: *prime_jacobian, cc: *curveparams) void = { let q = prime_jacobian { ... }; let t = prime_jacobian { ... }; let xbl: u32 = cc.p[0]; xbl -= (xbl >> 5); let plen: size = (xbl + 7) >> 3; dest[0] = 0x04; jcpy(&q, p); prime_setone(t.c[2], cc.p); prime_affine(&q, &t, cc); decode(dest[1..1+plen], q.c[0]); decode(dest[1+plen..1+2*plen], q.c[1]); }; fn prime_mul(g: []u8, x: []u8, cc: *curveparams) u32 = { if (len(g) != cc.pointlen) { return 0; }; let p = prime_jacobian { ... }; let r = point_decode(&p, g, cc); point_mul(&p, x, cc); point_encode(g, &p, cc); return r; }; const P384_G: [_]u8 = [ 0x04, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, ]; fn p384_generator() const []u8 = P384_G; const P384_N: [_]u8 = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73, ]; fn p384_order() const []u8 = P384_N; fn p384_mul(p: []u8, x: []u8) u32 = { return prime_mul(p, x, &p384params); }; fn p384_mulgen(r: []u8, x: []u8) size = { const g = P384_G[..]; r[..len(g)] = P384_G[..]; p384_mul(r[..len(g)], x); return len(g); }; fn prime_muladd(cc: *curveparams, a: []u8, b: []u8, x: []u8, y: []u8) u32 = { let p = prime_jacobian { ... }; let q = prime_jacobian { ... }; // TODO: see about merging the two ladders. Right now, we do // two independent point multiplications, which is a bit // wasteful of CPU resources (but yields short code). if (len(a) != cc.pointlen) { return 0; }; let r = point_decode(&p, a, cc); if (len(b) == 0) { b = cc.g[..]; }; r &= point_decode(&q, b, cc); point_mul(&p, x, cc); point_mul(&q, y, cc); // We want to compute P+Q. Since the base points A and B are distinct // from infinity, and the multipliers are non-zero and lower than the // curve order, then we know that P and Q are non-infinity. This // leaves two special situations to test for: // -- If P = Q then we must use point_double(). // -- If P+Q = 0 then we must report an error. let t = point_add(&p, &q, cc); point_double(&q, cc); let z = iszero(p.c[2]); // If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we // have the following: // // z = 0, t = 0 return P (normal addition) // z = 0, t = 1 return P (normal addition) // z = 1, t = 0 return Q (a 'double' case) // z = 1, t = 1 report an error (P+Q = 0) jccpy(z & ~t, &p, &q); point_encode(a, &p, cc); r &= ~(z & t); return r; }; fn p384_muladd(a: []u8, b: []u8, x: []u8, y: []u8) u32 = prime_muladd(&p384params, a, b, x, y); const _p384: curve = curve { pointsz = P384_POINTSZ, order = &p384_order, generator = &p384_generator, mul = &p384_mul, mulgen = &p384_mulgen, muladd = &p384_muladd, keygen = &mask_keygen, }; // Size of a [[p384]] point in bytes. export def P384_POINTSZ = 97; // Size of a [[p384]] scalar in bytes. export def P384_SCALARSZ = 48; // A [[curve]] implementation of P-384, also known as secp384r1; // // The point size is defined by [[P384_POINTSZ]] and the scalar size is defined // by [[P384_SCALARSZ]. See the documentation of [[curve]] on how to encode // such values. export const p384: *curve = &_p384; const P521_N: [_]u8 = [ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09, ]; fn p521_order() const []u8 = P521_N; const P521_G: [_]u8 = [ 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1, 0x66, 0x50 ]; fn p521_generator() const []u8 = P521_G; fn p521_mul(p: []u8, x: []u8) u32 = { return prime_mul(p, x, &p521params); }; fn p521_mulgen(r: []u8, x: []u8) size = { const g = P521_G[..]; r[..len(g)] = P521_G[..]; p521_mul(r[..len(g)], x); return len(g); }; fn p521_muladd(a: []u8, b: []u8, x: []u8, y: []u8) u32 = prime_muladd(&p521params, a, b, x, y); const _p521: curve = curve { pointsz = P521_POINTSZ, order = &p521_order, generator = &p521_generator, mul = &p521_mul, mulgen = &p521_mulgen, muladd = &p521_muladd, keygen = &mask_keygen, }; // Size of a [[p521]] point in bytes. export def P521_POINTSZ = 133; // Size of a [[p521]] scalar in bytes. export def P521_SCALARSZ = 66; // A [[curve]] implementation of P-521, also known as secp521r1; // // The point size is defined by [[P521_POINTSZ]] and the scalar size is defined // by [[P521_SCALARSZ]. See the documentation of [[curve]] on how to encode // such values. export const p521: *curve = &_p521; hare-0.24.2/crypto/ec/types.ha000066400000000000000000000061651464473310100161160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; // Maxium coordinate size of the modules curves in bits. export def MAX_COORDBITSZ = 528z; // Maximum size of a point of the modules curves in bytes. export def MAX_POINTSZ = P521_POINTSZ; // Maximum size of a scalar of the modules curves in bytes. export def MAX_SCALARSZ = P521_SCALARSZ; // Interface for common operations over a specific curve. // // The encoding of points (e.g. public keys for dsa and dh) depends on the curve. // For the NIST curves ([[p256]], [[p384]] and [[p521]]) the point is required // to be stored according to the uncompressed format defined in RFC 8422 Chapter // 5.4.1. That means with a leading byte of value 0x04 that indicates the // format. Followed by the x and y coordinates, which must be of length // [[pointsz]] / 2, left padded by 0. // // Scalar values (e.g. private keys for dsa and dh) must be provided in // big-endian encoding and left-padded to fill the indicated space. They MUST be // non-zero and less than the curve order, otherwise result values will be // indeterminate and an error code is not guaranteed. The function [[scalarsz]] // will return the encoded scalar size of any curve implemented by this module. export type curve = struct { // Size in bytes of an encoded point. pointsz: size, // Returns the order of the subgroup generated by the conventional // generator. Unsigned big-endian encoding is used. order: *fn () const []u8, // XXX: change to const []u8, when possible // Get the conventional generator as an encoded curve point. generator: *fn () const []u8, // XXX: change to const []u8, when possible // Multiply curve point 'p' by scalar 'x'. The result is stored in 'r'. // Returns 1 on success. // // Point 'p' must be a valid point on the curve subgroup. If this is // not the case the function fails with 0 as result. // // On error the results in 'p' are indeterminate. mul: *fn (p: []u8, x: []u8) u32, // Multiply the generator by the scalar 'x' and write the result to 'r'. // // Returns the encoded point length in bytes. mulgen: *fn (r: []u8, x: []u8) size, // Multiply two curve points ('a' and 'b') by two integers ('x' and 'y') // and stores the sum in 'a' ('a' = 'a' * 'x' + 'b' * 'y'). // // If an empty slice is given as 'b', the curve generator is used // instead of 'b'. // // Returns 0 in case of failure. Validates that the provided points are // part of the relevant curve subgroup. // // Returns 1 on success. muladd: *fn (a: []u8, b: []u8, x: []u8, y: []u8) u32, // Generate a private key from given random seed 'rand'. The function // may read repeatedly from 'rand' until a suitable key is found. // // Returns the size of bytes read into 'priv' on success or // [[io::error]], if reading from 'rand' failed. keygen: *fn (c: *curve, priv: []u8, rand: io::handle) (size | io::error), }; // Returns the encoded size of any point of curve 'c'. export fn pointsz(c: *curve) size = c.pointsz; // Returns the encoded size of any scalar of curve 'c'. export fn scalarsz(c: *curve) size = len(c.order()); // Invalid curve parameter. export type invalid = !void; hare-0.24.2/crypto/ec/validate.ha000066400000000000000000000025221464473310100165340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Checks whether the point is encoded in the curves point format. Does NOT // check if it is a valid point on the curve. For such point validation use // [[validate_point]]. export fn validate_pointformat(c: *curve, p: []u8) (void | invalid) = { if (len(p) != c.pointsz || p[0] != 0x04) { return invalid; }; }; // Checks if given point is properly encoded and a valid point on given curve // 'c'. This operation is quite expensive. Note that in any case point // validation will be done on every mul and muladd operation. export fn validate_point(c: *curve, p: []u8) (void | invalid) = { validate_pointformat(c, p)?; static let scalarbuf: [MAX_POINTSZ]u8 = [0...]; let scalarbuf = scalarbuf[..len(c.order())]; scalarbuf[len(scalarbuf) - 1] = 1; if (c.mul(p, scalarbuf) == 0) { return invalid; }; }; // Validates if given scalar is less than the curve order and greater then zero. export fn validate_scalar(c: *curve, n: []u8) (void | invalid) = { const order = c.order(); let cc: u16 = 0; let zz: u8 = 0; for (let i = len(n); i > 0; i -= 1) { // subtraction with carry cc = ((n[i - 1]: u16 - order[i - 1] - cc) >> 8) & 1; zz |= n[i - 1]; }; // cc == 0 means the carry is not set because order < priv if (cc == 0 || zz == 0) { return invalid; }; }; hare-0.24.2/crypto/ecdh/000077500000000000000000000000001464473310100147445ustar00rootroot00000000000000hare-0.24.2/crypto/ecdh/README000066400000000000000000000010511464473310100156210ustar00rootroot00000000000000The crypto::ecdh module implements elliptic-curve diffie hellman key generation for curves implemented in [[crypto::ec::]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/ecdh/basic+test.ha000066400000000000000000000140221464473310100173110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::ec; use bytes; @test fn p256_invalidpoint() void = { let priv = p256(); priv.x[..] = [ 0x7d, 0x7d, 0xc5, 0xf7, 0x1e, 0xb2, 0x9d, 0xda, 0xf8, 0x0d, 0x62, 0x14, 0x63, 0x2e, 0xea, 0xe0, 0x3d, 0x90, 0x58, 0xaf, 0x1f, 0xb6, 0xd2, 0x2e, 0xd8, 0x0b, 0xad, 0xb6, 0x2b, 0xc1, 0xa5, 0x34, ]; const pub: [_]u8 = [ 0x04, 0xea, 0xd2, 0x18, 0x59, 0x01, 0x19, 0xe8, 0x87, 0x6b, 0x29, 0x14, 0x6f, 0xf8, 0x9c, 0xa6, 0x17, 0x70, 0xc4, 0xed, 0xbb, 0xf9, 0x7d, 0x38, 0xce, 0x38, 0x5e, 0xd2, 0x81, 0xd8, 0xa6, 0xb2, 0x30, 0x28, 0xaf, 0x61, 0x28, 0x1f, 0xd3, 0x5e, 0x2f, 0xa7, 0x00, 0x25, 0x23, 0xac, 0xc8, 0x5a, 0x42, 0x9c, 0xb0, 0x6e, 0xe6, 0x64, 0x83, 0x25, 0x38, 0x9f, 0x59, 0xed, 0xfc, 0xe1, 0x40, 0x51, 0x41, ]; const otherpub: [_]u8 = [ 0x04, 0x70, 0x0c, 0x48, 0xf7, 0x7f, 0x56, 0x58, 0x4c, 0x5c, 0xc6, 0x32, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x1b, 0x6b, 0xac, 0xce, 0x3a, 0x4d, 0xf6, 0xb4, 0x2c, 0xe7, 0xcc, 0x83, 0x88, 0x33, 0xd2, 0x00, 0xdb, 0x71, 0xe5, 0x09, 0xe3, 0xfd, 0x9b, 0x06, 0x0d, 0xdb, 0x20, 0xba, 0x5c, 0x51, 0xdc, 0xc5, 0x94, 0x8d, 0x46, 0xfb, 0xf6, 0x40, 0xdf, 0xe0, 0x44, 0x17, 0x82, 0xca, 0xb8, 0x5f, 0xa4, 0xac, ]; const shared: [_]u8 = [ 0x46, 0xfc, 0x62, 0x10, 0x64, 0x20, 0xff, 0x01, 0x2e, 0x54, 0xa4, 0x34, 0xfb, 0xdd, 0x2d, 0x25, 0xcc, 0xc5, 0x85, 0x20, 0x60, 0x56, 0x1e, 0x68, 0x04, 0x0d, 0xd7, 0x77, 0x89, 0x97, 0xbd, 0x7b, ]; let dpub: [ec::P256_POINTSZ]u8 = [0...]; pubkey(dpub, &priv); assert(bytes::equal(dpub, pub)); let dshared: [P256_SHAREDSZ]u8 = [0...]; let zero: [P256_SHAREDSZ]u8 = [0...]; assert(derive(dshared, &priv, otherpub) is invalidkey); assert(bytes::equal(dshared, zero)); }; @test fn p384_invalidpoint() void = { let priv = p384(); priv.x[..] = [ 0x3c, 0xc3, 0x12, 0x2a, 0x68, 0xf0, 0xd9, 0x50, 0x27, 0xad, 0x38, 0xc0, 0x67, 0x91, 0x6b, 0xa0, 0xeb, 0x8c, 0x38, 0x89, 0x4d, 0x22, 0xe1, 0xb1, 0x56, 0x18, 0xb6, 0x81, 0x8a, 0x66, 0x17, 0x74, 0xad, 0x46, 0x3b, 0x20, 0x5d, 0xa8, 0x8c, 0xf6, 0x99, 0xab, 0x4d, 0x43, 0xc9, 0xcf, 0x98, 0xa1, ]; const pub: [_]u8 = [ 0x04, 0x98, 0x03, 0x80, 0x7f, 0x2f, 0x6d, 0x2f, 0xd9, 0x66, 0xcd, 0xd0, 0x29, 0x0b, 0xd4, 0x10, 0xc0, 0x19, 0x03, 0x52, 0xfb, 0xec, 0x7f, 0xf6, 0x24, 0x7d, 0xe1, 0x30, 0x2d, 0xf8, 0x6f, 0x25, 0xd3, 0x4f, 0xe4, 0xa9, 0x7b, 0xef, 0x60, 0xcf, 0xf5, 0x48, 0x35, 0x5c, 0x01, 0x5d, 0xbb, 0x3e, 0x5f, 0xba, 0x26, 0xca, 0x69, 0xec, 0x2f, 0x5b, 0x5d, 0x9d, 0xad, 0x20, 0xcc, 0x9d, 0xa7, 0x11, 0x38, 0x3a, 0x9d, 0xbe, 0x34, 0xea, 0x3f, 0xa5, 0xa2, 0xaf, 0x75, 0xb4, 0x65, 0x02, 0x62, 0x9a, 0xd5, 0x4d, 0xd8, 0xb7, 0xd7, 0x3a, 0x8a, 0xbb, 0x06, 0xa3, 0xa3, 0xbe, 0x47, 0xd6, 0x50, 0xcc, 0x99, ]; const otherpub: [_]u8 = [ 0x04, 0xa7, 0xc7, 0x6b, 0x97, 0x0c, 0x3b, 0x5f, 0xe8, 0xb0, 0x5d, 0x28, 0x38, 0xae, 0x04, 0xab, 0x47, 0x69, 0x7b, 0x9e, 0xaf, 0x52, 0xe7, 0x64, 0x59, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x51, 0x32, 0x72, 0x73, 0x44, 0x66, 0xb4, 0x00, 0x09, 0x1a, 0xdb, 0xf2, 0xd6, 0x8c, 0x58, 0xe0, 0xc5, 0x00, 0x66, 0xac, 0x68, 0xf1, 0x9f, 0x2e, 0x1c, 0xb8, 0x79, 0xae, 0xd4, 0x3a, 0x99, 0x69, 0xb9, 0x1a, 0x08, 0x39, 0xc4, 0xc3, 0x8a, 0x49, 0x74, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x24, 0x34, 0x51, 0x91, 0x5e, 0xd0, 0x90, 0x5a, 0x32, 0xb0, 0x60, 0x99, 0x2b, 0x46, 0x8c, 0x64, 0x76, 0x6f, 0xc8, 0x43, 0x7a, ]; let dpub: [ec::P384_POINTSZ]u8 = [0...]; pubkey(dpub, &priv); assert(bytes::equal(dpub, pub)); let dshared: [P384_SHAREDSZ]u8 = [0...]; let zero: [P384_SHAREDSZ]u8 = [0...]; assert(derive(dshared, &priv, otherpub) is invalidkey); assert(bytes::equal(dshared, zero)); }; @test fn p521_invalidpoint() void = { let priv = p521(); priv.x[..] = [ 0x01, 0x7e, 0xec, 0xc0, 0x7a, 0xb4, 0xb3, 0x29, 0x06, 0x8f, 0xba, 0x65, 0xe5, 0x6a, 0x1f, 0x88, 0x90, 0xaa, 0x93, 0x5e, 0x57, 0x13, 0x4a, 0xe0, 0xff, 0xcc, 0xe8, 0x02, 0x73, 0x51, 0x51, 0xf4, 0xea, 0xc6, 0x56, 0x4f, 0x6e, 0xe9, 0x97, 0x4c, 0x5e, 0x68, 0x87, 0xa1, 0xfe, 0xfe, 0xe5, 0x74, 0x3a, 0xe2, 0x24, 0x1b, 0xfe, 0xb9, 0x5d, 0x5c, 0xe3, 0x1d, 0xdc, 0xb6, 0xf9, 0xed, 0xb4, 0xd6, 0xfc, 0x47, ]; const pub: [_]u8 = [ 0x04, 0x00, 0x60, 0x2f, 0x9d, 0x0c, 0xf9, 0xe5, 0x26, 0xb2, 0x9e, 0x22, 0x38, 0x1c, 0x20, 0x3c, 0x48, 0xa8, 0x86, 0xc2, 0xb0, 0x67, 0x30, 0x33, 0x36, 0x63, 0x14, 0xf1, 0xff, 0xbc, 0xba, 0x24, 0x0b, 0xa4, 0x2f, 0x4e, 0xf3, 0x8a, 0x76, 0x17, 0x46, 0x35, 0xf9, 0x1e, 0x6b, 0x4e, 0xd3, 0x42, 0x75, 0xeb, 0x01, 0xc8, 0x46, 0x7d, 0x05, 0xca, 0x80, 0x31, 0x5b, 0xf1, 0xa7, 0xbb, 0xd9, 0x45, 0xf5, 0x50, 0xa5, 0x01, 0xb7, 0xc8, 0x5f, 0x26, 0xf5, 0xd4, 0xb2, 0xd7, 0x35, 0x5c, 0xf6, 0xb0, 0x21, 0x17, 0x65, 0x99, 0x43, 0x76, 0x2b, 0x6d, 0x1d, 0xb5, 0xab, 0x4f, 0x1d, 0xbc, 0x44, 0xce, 0x7b, 0x29, 0x46, 0xeb, 0x6c, 0x7d, 0xe3, 0x42, 0x96, 0x28, 0x93, 0xfd, 0x38, 0x7d, 0x1b, 0x73, 0xd7, 0xa8, 0x67, 0x2d, 0x1f, 0x23, 0x69, 0x61, 0x17, 0x0b, 0x7e, 0xb3, 0x57, 0x99, 0x53, 0xee, 0x5c, 0xdc, 0x88, 0xcd, 0x2d, ]; const otherpub: [_]u8 = [ 0x04, 0x00, 0x68, 0x5a, 0x48, 0xe8, 0x6c, 0x79, 0xf0, 0xf0, 0x87, 0x5f, 0x7b, 0xc1, 0x8d, 0x25, 0xeb, 0x5f, 0xc8, 0xc0, 0xb0, 0x7e, 0x5d, 0xa4, 0xf4, 0x37, 0x0f, 0x3a, 0x94, 0x90, 0x34, 0x08, 0x54, 0x33, 0x4b, 0x1e, 0x1b, 0x87, 0xfa, 0x39, 0x54, 0x64, 0xc6, 0x06, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd0, 0xf7, 0x85, 0x60, 0x1d, 0x37, 0xc0, 0x98, 0x70, 0xeb, 0xf1, 0x76, 0x66, 0x68, 0x77, 0xa2, 0x04, 0x6d, 0x01, 0xba, 0x52, 0xc5, 0x6f, 0xc8, 0x77, 0x6d, 0x9e, 0x8f, 0x5d, 0xb4, 0xf0, 0xcc, 0x27, 0x63, 0x6d, 0x0b, 0x74, 0x1b, 0xbe, 0x05, 0x40, 0x06, 0x97, 0x94, 0x2e, 0x80, 0xb7, 0x39, 0x88, 0x4a, 0x83, 0xbd, 0xe9, 0x9e, 0x0f, 0x67, 0x16, 0x93, 0x9e, 0x63, 0x2b, 0xc8, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xd4, 0x43, 0xa3, 0x48, 0xb6, 0xc3, 0xe5, 0x22, 0x49, 0x79, 0x55, 0xa4, 0xf3, 0xc3, 0x02, 0xf6, 0x76, ]; let dpub: [ec::P521_POINTSZ]u8 = [0...]; pubkey(dpub, &priv); assert(bytes::equal(dpub, pub)); let dshared: [P521_SHAREDSZ]u8 = [0...]; let zero: [P521_SHAREDSZ]u8 = [0...]; assert(derive(dshared, &priv, otherpub) is invalidkey); assert(bytes::equal(dshared, zero)); }; hare-0.24.2/crypto/ecdh/ecdh.ha000066400000000000000000000054671464473310100161750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::ec; use io; // Size of the shared secret in bytes when using p256 curves. export def P256_SHAREDSZ = ec::P256_POINTSZ / 2; // Size of the shared secret in bytes when using p384 curves. export def P384_SHAREDSZ = ec::P384_POINTSZ / 2; // Size of the shared secret in bytes when using p521 curves. export def P521_SHAREDSZ = ec::P521_POINTSZ / 2; // Key is either not of expected size or is not a valid point on given curve. export type invalidkey = !void; export type privkey = struct { curve: *ec::curve, get_x: *fn (priv: *privkey) []u8, }; fn p256_get_x(priv: *privkey) []u8 = (priv: *p256key).x; fn p384_get_x(priv: *privkey) []u8 = (priv: *p384key).x; fn p521_get_x(priv: *privkey) []u8 = (priv: *p521key).x; export type p256key = struct { priv: privkey, x: [ec::P256_SCALARSZ]u8, }; export type p384key = struct { priv: privkey, x: [ec::P384_SCALARSZ]u8, }; export type p521key = struct { priv: privkey, x: [ec::P521_SCALARSZ]u8, }; // Creates an unitialized p256 key. The curve is also known as secp256r1 or // prime256. The key must be initialized using [[newkey]]. export fn p256() p256key = p256key { priv = privkey { curve = ec::p256, get_x = &p256_get_x, }, ... }; // Creates an unitialized p384 key. The curve is also known as secp384r1. The // key must be initialized using [[newkey]]. export fn p384() p384key = p384key { priv = privkey { curve = ec::p384, get_x = &p384_get_x, }, ... }; // Creates an unitialized p521 key. The curve is also known as secp521r1. The // key must be initialized using [[newkey]]. export fn p521() p521key = p521key { priv = privkey { curve = ec::p521, get_x = &p521_get_x, }, ... }; // Generates a key seeding from the 'rand' stream and stores it in 'priv'. // 'rand' must be a cryptographic random generator like // [[crypto::random::stream]]. export fn newkey(priv: *privkey, rand: io::handle) (void | io::error) = ec::keygen(priv.curve, priv.get_x(priv), rand)?; // Derives the public key from given 'priv' and stores it into 'pub'. Returns // the number of key bytes written to 'pub'. export fn pubkey(pub: []u8, priv: *privkey) size = priv.curve.mulgen(pub, priv.get_x(priv)); // Derives a shared secret with the private key 'priv' and the peer's public // key 'pub' and stores it in 'shared'. export fn derive( shared: []u8, priv: *privkey, pub: []u8 ) (size | invalidkey) = { match (ec::validate_pointformat(priv.curve, pub)) { case ec::invalid => return invalidkey; case void => void; }; let buf: [ec::MAX_POINTSZ]u8 = [0...]; let buf = buf[..len(pub)]; buf[..] = pub[..]; if (priv.curve.mul(buf, priv.get_x(priv)) == 0) { return invalidkey; }; const csz = priv.curve.pointsz / 2; shared[..] = buf[1..csz + 1]; bytes::zero(buf); return csz; }; hare-0.24.2/crypto/ecdh/nist+test.ha000066400000000000000000004430651464473310100172220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::ec; use test; type testcase = struct { otherpub: []u8, priv: []u8, pub: []u8, shared: []u8, }; // https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Component-Testing @test fn nist_p256() void = run(p256cases[..1], &p256()); @test fn nist_p384() void = run(p384cases[..1], &p384()); @test fn nist_p521() void = run(p521cases[..1], &p521()); @test fn nist_p256_full() void = { test::require("slow"); run(p256cases[1..], &p256()); }; @test fn nist_p384_full() void = { test::require("slow"); run(p384cases[1..], &p384()); }; @test fn nist_p521_full() void = { test::require("slow"); run(p521cases[1..], &p521()); }; fn run(cases: []testcase, priv: *privkey) void = { let pubbuf: [ec::MAX_POINTSZ]u8 = [0...]; let pub = pubbuf[..priv.curve.pointsz]; let sharedbuf: [ec::MAX_POINTSZ / 2]u8 = [0...]; let shared = sharedbuf[..priv.curve.pointsz / 2]; for (let i = 0z; i < len(cases); i += 1) { const c = cases[i]; priv.get_x(priv)[..] = c.priv; pubkey(pub, priv); assert(bytes::equal(pub, c.pub)); derive(shared, priv, c.otherpub)!; assert(bytes::equal(shared, c.shared)); }; }; const p256cases: [_]testcase = [ //COUNT = 0 testcase { otherpub = [ 0x04, 0x70, 0x0c, 0x48, 0xf7, 0x7f, 0x56, 0x58, 0x4c, 0x5c, 0xc6, 0x32, 0xca, 0x65, 0x64, 0x0d, 0xb9, 0x1b, 0x6b, 0xac, 0xce, 0x3a, 0x4d, 0xf6, 0xb4, 0x2c, 0xe7, 0xcc, 0x83, 0x88, 0x33, 0xd2, 0x87, 0xdb, 0x71, 0xe5, 0x09, 0xe3, 0xfd, 0x9b, 0x06, 0x0d, 0xdb, 0x20, 0xba, 0x5c, 0x51, 0xdc, 0xc5, 0x94, 0x8d, 0x46, 0xfb, 0xf6, 0x40, 0xdf, 0xe0, 0x44, 0x17, 0x82, 0xca, 0xb8, 0x5f, 0xa4, 0xac, ], priv = [ 0x7d, 0x7d, 0xc5, 0xf7, 0x1e, 0xb2, 0x9d, 0xda, 0xf8, 0x0d, 0x62, 0x14, 0x63, 0x2e, 0xea, 0xe0, 0x3d, 0x90, 0x58, 0xaf, 0x1f, 0xb6, 0xd2, 0x2e, 0xd8, 0x0b, 0xad, 0xb6, 0x2b, 0xc1, 0xa5, 0x34, ], pub = [ 0x04, 0xea, 0xd2, 0x18, 0x59, 0x01, 0x19, 0xe8, 0x87, 0x6b, 0x29, 0x14, 0x6f, 0xf8, 0x9c, 0xa6, 0x17, 0x70, 0xc4, 0xed, 0xbb, 0xf9, 0x7d, 0x38, 0xce, 0x38, 0x5e, 0xd2, 0x81, 0xd8, 0xa6, 0xb2, 0x30, 0x28, 0xaf, 0x61, 0x28, 0x1f, 0xd3, 0x5e, 0x2f, 0xa7, 0x00, 0x25, 0x23, 0xac, 0xc8, 0x5a, 0x42, 0x9c, 0xb0, 0x6e, 0xe6, 0x64, 0x83, 0x25, 0x38, 0x9f, 0x59, 0xed, 0xfc, 0xe1, 0x40, 0x51, 0x41, ], shared = [ 0x46, 0xfc, 0x62, 0x10, 0x64, 0x20, 0xff, 0x01, 0x2e, 0x54, 0xa4, 0x34, 0xfb, 0xdd, 0x2d, 0x25, 0xcc, 0xc5, 0x85, 0x20, 0x60, 0x56, 0x1e, 0x68, 0x04, 0x0d, 0xd7, 0x77, 0x89, 0x97, 0xbd, 0x7b, ], }, //COUNT = 1 testcase { otherpub = [ 0x04, 0x80, 0x9f, 0x04, 0x28, 0x9c, 0x64, 0x34, 0x8c, 0x01, 0x51, 0x5e, 0xb0, 0x3d, 0x5c, 0xe7, 0xac, 0x1a, 0x8c, 0xb9, 0x49, 0x8f, 0x5c, 0xaa, 0x50, 0x19, 0x7e, 0x58, 0xd4, 0x3a, 0x86, 0xa7, 0xae, 0xb2, 0x9d, 0x84, 0xe8, 0x11, 0x19, 0x7f, 0x25, 0xeb, 0xa8, 0xf5, 0x19, 0x40, 0x92, 0xcb, 0x6f, 0xf4, 0x40, 0xe2, 0x6d, 0x44, 0x21, 0x01, 0x13, 0x72, 0x46, 0x1f, 0x57, 0x92, 0x71, 0xcd, 0xa3, ], priv = [ 0x38, 0xf6, 0x5d, 0x6d, 0xce, 0x47, 0x67, 0x60, 0x44, 0xd5, 0x8c, 0xe5, 0x13, 0x95, 0x82, 0xd5, 0x68, 0xf6, 0x4b, 0xb1, 0x60, 0x98, 0xd1, 0x79, 0xdb, 0xab, 0x07, 0x74, 0x1d, 0xd5, 0xca, 0xf5, ], pub = [ 0x04, 0x11, 0x9f, 0x2f, 0x04, 0x79, 0x02, 0x78, 0x2a, 0xb0, 0xc9, 0xe2, 0x7a, 0x54, 0xaf, 0xf5, 0xeb, 0x9b, 0x96, 0x48, 0x29, 0xca, 0x99, 0xc0, 0x6b, 0x02, 0xdd, 0xba, 0x95, 0xb0, 0xa3, 0xf6, 0xd0, 0x8f, 0x52, 0xb7, 0x26, 0x66, 0x4c, 0xac, 0x36, 0x6f, 0xc9, 0x8a, 0xc7, 0xa0, 0x12, 0xb2, 0x68, 0x2c, 0xbd, 0x96, 0x2e, 0x5a, 0xcb, 0x54, 0x46, 0x71, 0xd4, 0x1b, 0x94, 0x45, 0x70, 0x4d, 0x1d, ], shared = [ 0x05, 0x7d, 0x63, 0x60, 0x96, 0xcb, 0x80, 0xb6, 0x7a, 0x8c, 0x03, 0x8c, 0x89, 0x0e, 0x88, 0x7d, 0x1a, 0xdf, 0xa4, 0x19, 0x5e, 0x9b, 0x3c, 0xe2, 0x41, 0xc8, 0xa7, 0x78, 0xc5, 0x9c, 0xda, 0x67, ], }, //COUNT = 2 testcase { otherpub = [ 0x04, 0xa2, 0x33, 0x9c, 0x12, 0xd4, 0xa0, 0x3c, 0x33, 0x54, 0x6d, 0xe5, 0x33, 0x26, 0x8b, 0x4a, 0xd6, 0x67, 0xde, 0xbf, 0x45, 0x8b, 0x46, 0x4d, 0x77, 0x44, 0x36, 0x36, 0x44, 0x0e, 0xe7, 0xfe, 0xc3, 0xef, 0x48, 0xa3, 0xab, 0x26, 0xe2, 0x02, 0x20, 0xbc, 0xda, 0x2c, 0x18, 0x51, 0x07, 0x68, 0x39, 0xda, 0xe8, 0x8e, 0xae, 0x96, 0x28, 0x69, 0xa4, 0x97, 0xbf, 0x73, 0xcb, 0x66, 0xfa, 0xf5, 0x36, ], priv = [ 0x1a, 0xcc, 0xfa, 0xf1, 0xb9, 0x77, 0x12, 0xb8, 0x5a, 0x6f, 0x54, 0xb1, 0x48, 0x98, 0x5a, 0x1b, 0xdc, 0x4c, 0x9b, 0xec, 0x0b, 0xd2, 0x58, 0xca, 0xd4, 0xb3, 0xd6, 0x03, 0xf4, 0x9f, 0x32, 0xc8, ], pub = [ 0x04, 0xd9, 0xf2, 0xb7, 0x9c, 0x17, 0x28, 0x45, 0xbf, 0xdb, 0x56, 0x0b, 0xbb, 0x01, 0x44, 0x7c, 0xa5, 0xec, 0xc0, 0x47, 0x0a, 0x09, 0x51, 0x3b, 0x61, 0x26, 0x90, 0x2c, 0x6b, 0x4f, 0x8d, 0x10, 0x51, 0xf8, 0x15, 0xef, 0x5e, 0xc3, 0x21, 0x28, 0xd3, 0x48, 0x78, 0x34, 0x76, 0x46, 0x78, 0x70, 0x2e, 0x64, 0xe1, 0x64, 0xff, 0x73, 0x15, 0x18, 0x5e, 0x23, 0xaf, 0xf5, 0xfa, 0xcd, 0x96, 0xd7, 0xbc, ], shared = [ 0x2d, 0x45, 0x7b, 0x78, 0xb4, 0x61, 0x41, 0x32, 0x47, 0x76, 0x18, 0xa5, 0xb0, 0x77, 0x96, 0x5e, 0xc9, 0x07, 0x30, 0xa8, 0xc8, 0x1a, 0x1c, 0x75, 0xd6, 0xd4, 0xec, 0x68, 0x00, 0x5d, 0x67, 0xec, ], }, //COUNT = 3 testcase { otherpub = [ 0x04, 0xdf, 0x39, 0x89, 0xb9, 0xfa, 0x55, 0x49, 0x57, 0x19, 0xb3, 0xcf, 0x46, 0xdc, 0xcd, 0x28, 0xb5, 0x15, 0x3f, 0x78, 0x08, 0x19, 0x1d, 0xd5, 0x18, 0xef, 0xf0, 0xc3, 0xcf, 0xf2, 0xb7, 0x05, 0xed, 0x42, 0x22, 0x94, 0xff, 0x46, 0x00, 0x34, 0x29, 0xd7, 0x39, 0xa3, 0x32, 0x06, 0xc8, 0x75, 0x25, 0x52, 0xc8, 0xba, 0x54, 0xa2, 0x70, 0xde, 0xfc, 0x06, 0xe2, 0x21, 0xe0, 0xfe, 0xaf, 0x6a, 0xc4, ], priv = [ 0x20, 0x7c, 0x43, 0xa7, 0x9b, 0xfe, 0xe0, 0x3d, 0xb6, 0xf4, 0xb9, 0x44, 0xf5, 0x3d, 0x2f, 0xb7, 0x6c, 0xc4, 0x9e, 0xf1, 0xc9, 0xc4, 0xd3, 0x4d, 0x51, 0xb6, 0xc6, 0x5c, 0x4d, 0xb6, 0x93, 0x2d, ], pub = [ 0x04, 0x24, 0x27, 0x7c, 0x33, 0xf4, 0x50, 0x46, 0x2d, 0xcb, 0x3d, 0x48, 0x01, 0xd5, 0x7b, 0x9c, 0xed, 0x05, 0x18, 0x8f, 0x16, 0xc2, 0x8e, 0xda, 0x87, 0x32, 0x58, 0x04, 0x8c, 0xd1, 0x60, 0x7e, 0x0d, 0xc4, 0x78, 0x97, 0x53, 0xe2, 0xb1, 0xf6, 0x3b, 0x32, 0xff, 0x01, 0x4e, 0xc4, 0x2c, 0xd6, 0xa6, 0x9f, 0xac, 0x81, 0xdf, 0xe6, 0xd0, 0xd6, 0xfd, 0x4a, 0xf3, 0x72, 0xae, 0x27, 0xc4, 0x6f, 0x88, ], shared = [ 0x96, 0x44, 0x12, 0x59, 0x53, 0x4b, 0x80, 0xf6, 0xae, 0xe3, 0xd2, 0x87, 0xa6, 0xbb, 0x17, 0xb5, 0x09, 0x4d, 0xd4, 0x27, 0x7d, 0x9e, 0x29, 0x4f, 0x8f, 0xe7, 0x3e, 0x48, 0xbf, 0x2a, 0x00, 0x24, ], }, //COUNT = 4 testcase { otherpub = [ 0x04, 0x41, 0x19, 0x2d, 0x28, 0x13, 0xe7, 0x95, 0x61, 0xe6, 0xa1, 0xd6, 0xf5, 0x3c, 0x8b, 0xc1, 0xa4, 0x33, 0xa1, 0x99, 0xc8, 0x35, 0xe1, 0x41, 0xb0, 0x5a, 0x74, 0xa9, 0x7b, 0x0f, 0xae, 0xb9, 0x22, 0x1a, 0xf9, 0x8c, 0xc4, 0x5e, 0x98, 0xa7, 0xe0, 0x41, 0xb0, 0x1c, 0xf3, 0x5f, 0x46, 0x2b, 0x75, 0x62, 0x28, 0x13, 0x51, 0xc8, 0xeb, 0xf3, 0xff, 0xa0, 0x2e, 0x33, 0xa0, 0x72, 0x2a, 0x13, 0x28, ], priv = [ 0x59, 0x13, 0x7e, 0x38, 0x15, 0x23, 0x50, 0xb1, 0x95, 0xc9, 0x71, 0x8d, 0x39, 0x67, 0x3d, 0x51, 0x98, 0x38, 0x05, 0x5a, 0xd9, 0x08, 0xdd, 0x47, 0x57, 0x15, 0x2f, 0xd8, 0x25, 0x5c, 0x09, 0xbf, ], pub = [ 0x04, 0xa8, 0xc5, 0xfd, 0xce, 0x8b, 0x62, 0xc5, 0xad, 0xa5, 0x98, 0xf1, 0x41, 0xad, 0xb3, 0xb2, 0x6c, 0xf2, 0x54, 0xc2, 0x80, 0xb2, 0x85, 0x7a, 0x63, 0xd2, 0xad, 0x78, 0x3a, 0x73, 0x11, 0x5f, 0x6b, 0x80, 0x6e, 0x1a, 0xaf, 0xec, 0x4a, 0xf8, 0x0a, 0x0d, 0x78, 0x6b, 0x3d, 0xe4, 0x53, 0x75, 0xb5, 0x17, 0xa7, 0xe5, 0xb5, 0x1f, 0xfb, 0x2c, 0x35, 0x65, 0x37, 0xc9, 0xe6, 0xef, 0x22, 0x7d, 0x4a, ], shared = [ 0x19, 0xd4, 0x4c, 0x8d, 0x63, 0xe8, 0xe8, 0xdd, 0x12, 0xc2, 0x2a, 0x87, 0xb8, 0xcd, 0x4e, 0xce, 0x27, 0xac, 0xdd, 0xe0, 0x4d, 0xbf, 0x47, 0xf7, 0xf2, 0x75, 0x37, 0xa6, 0x99, 0x9a, 0x8e, 0x62, ], }, //COUNT = 5 testcase { otherpub = [ 0x04, 0x33, 0xe8, 0x20, 0x92, 0xa0, 0xf1, 0xfb, 0x38, 0xf5, 0x64, 0x9d, 0x58, 0x67, 0xfb, 0xa2, 0x8b, 0x50, 0x31, 0x72, 0xb7, 0x03, 0x55, 0x74, 0xbf, 0x8e, 0x5b, 0x71, 0x00, 0xa3, 0x05, 0x27, 0x92, 0xf2, 0xcf, 0x6b, 0x60, 0x1e, 0x0a, 0x05, 0x94, 0x5e, 0x33, 0x55, 0x50, 0xbf, 0x64, 0x8d, 0x78, 0x2f, 0x46, 0x18, 0x6c, 0x77, 0x2c, 0x0f, 0x20, 0xd3, 0xcd, 0x0d, 0x6b, 0x8c, 0xa1, 0x4b, 0x2f, ], priv = [ 0xf5, 0xf8, 0xe0, 0x17, 0x46, 0x10, 0xa6, 0x61, 0x27, 0x79, 0x79, 0xb5, 0x8c, 0xe5, 0xc9, 0x0f, 0xee, 0x6c, 0x9b, 0x3b, 0xb3, 0x46, 0xa9, 0x0a, 0x71, 0x96, 0x25, 0x5e, 0x40, 0xb1, 0x32, 0xef, ], pub = [ 0x04, 0x7b, 0x86, 0x1d, 0xcd, 0x28, 0x44, 0xa5, 0xa8, 0x36, 0x3f, 0x6b, 0x8e, 0xf8, 0xd4, 0x93, 0x64, 0x0f, 0x55, 0x87, 0x92, 0x17, 0x18, 0x9d, 0x80, 0x32, 0x6a, 0xad, 0x94, 0x80, 0xdf, 0xc1, 0x49, 0xc4, 0x67, 0x5b, 0x45, 0xee, 0xb3, 0x06, 0x40, 0x5f, 0x6c, 0x33, 0xc3, 0x8b, 0xc6, 0x9e, 0xb2, 0xbd, 0xec, 0x9b, 0x75, 0xad, 0x5a, 0xf4, 0x70, 0x6a, 0xab, 0x84, 0x54, 0x3b, 0x9c, 0xc6, 0x3a, ], shared = [ 0x66, 0x4e, 0x45, 0xd5, 0xbb, 0xa4, 0xac, 0x93, 0x1c, 0xd6, 0x5d, 0x52, 0x01, 0x7e, 0x4b, 0xe9, 0xb1, 0x9a, 0x51, 0x5f, 0x66, 0x9b, 0xea, 0x47, 0x03, 0x54, 0x2a, 0x2c, 0x52, 0x5c, 0xd3, 0xd3, ], }, //COUNT = 6 testcase { otherpub = [ 0x04, 0x6a, 0x9e, 0x0c, 0x3f, 0x91, 0x6e, 0x4e, 0x31, 0x5c, 0x91, 0x14, 0x7b, 0xe5, 0x71, 0x68, 0x6d, 0x90, 0x46, 0x4e, 0x8b, 0xf9, 0x81, 0xd3, 0x4a, 0x90, 0xb6, 0x35, 0x3b, 0xca, 0x6e, 0xeb, 0xa7, 0x40, 0xf9, 0xbe, 0xad, 0x39, 0xc2, 0xf2, 0xbc, 0xc2, 0x60, 0x2f, 0x75, 0xb8, 0xa7, 0x3e, 0xc7, 0xbd, 0xff, 0xcb, 0xce, 0xad, 0x15, 0x9d, 0x01, 0x74, 0xc6, 0xc4, 0xd3, 0xc5, 0x35, 0x7f, 0x05, ], priv = [ 0x3b, 0x58, 0x9a, 0xf7, 0xdb, 0x03, 0x45, 0x9c, 0x23, 0x06, 0x8b, 0x64, 0xf6, 0x3f, 0x28, 0xd3, 0xc3, 0xc6, 0xbc, 0x25, 0xb5, 0xbf, 0x76, 0xac, 0x05, 0xf3, 0x54, 0x82, 0x88, 0x8b, 0x51, 0x90, ], pub = [ 0x04, 0x9f, 0xb3, 0x8e, 0x2d, 0x58, 0xea, 0x1b, 0xaf, 0x76, 0x22, 0xe9, 0x67, 0x20, 0x10, 0x1c, 0xae, 0x3c, 0xde, 0x4b, 0xa6, 0xc1, 0xe9, 0xfa, 0x26, 0xd9, 0xb1, 0xde, 0x08, 0x99, 0x10, 0x28, 0x63, 0xd5, 0x56, 0x1b, 0x90, 0x04, 0x06, 0xed, 0xf5, 0x08, 0x02, 0xdd, 0x7d, 0x73, 0xe8, 0x93, 0x95, 0xf8, 0xae, 0xd7, 0x2f, 0xba, 0x0e, 0x1d, 0x1b, 0x61, 0xfe, 0x1d, 0x22, 0x30, 0x22, 0x60, 0xf0, ], shared = [ 0xca, 0x34, 0x2d, 0xaa, 0x50, 0xdc, 0x09, 0xd6, 0x1b, 0xe7, 0xc1, 0x96, 0xc8, 0x5e, 0x60, 0xa8, 0x0c, 0x5c, 0xb0, 0x49, 0x31, 0x74, 0x68, 0x20, 0xbe, 0x54, 0x8c, 0xdd, 0xe0, 0x55, 0x67, 0x9d, ], }, //COUNT = 7 testcase { otherpub = [ 0x04, 0xa9, 0xc0, 0xac, 0xad, 0xe5, 0x5c, 0x2a, 0x73, 0xea, 0xd1, 0xa8, 0x6f, 0xb0, 0xa9, 0x71, 0x32, 0x23, 0xc8, 0x24, 0x75, 0x79, 0x1c, 0xd0, 0xe2, 0x10, 0xb0, 0x46, 0x41, 0x2c, 0xe2, 0x24, 0xbb, 0xf6, 0xde, 0x0a, 0xfa, 0x20, 0xe9, 0x3e, 0x07, 0x84, 0x67, 0xc0, 0x53, 0xd2, 0x41, 0x90, 0x3e, 0xda, 0xd7, 0x34, 0xc6, 0xb4, 0x03, 0xba, 0x75, 0x8c, 0x2b, 0x5f, 0xf0, 0x4c, 0x9d, 0x42, 0x29, ], priv = [ 0xd8, 0xbf, 0x92, 0x9a, 0x20, 0xea, 0x74, 0x36, 0xb2, 0x46, 0x1b, 0x54, 0x1a, 0x11, 0xc8, 0x0e, 0x61, 0xd8, 0x26, 0xc0, 0xa4, 0xc9, 0xd3, 0x22, 0xb3, 0x1d, 0xd5, 0x4e, 0x7f, 0x58, 0xb9, 0xc8, ], pub = [ 0x04, 0x20, 0xf0, 0x76, 0x31, 0xe4, 0xa6, 0x51, 0x2a, 0x89, 0xad, 0x48, 0x7c, 0x4e, 0x9d, 0x63, 0x03, 0x9e, 0x57, 0x9c, 0xb0, 0xd7, 0xa5, 0x56, 0xcb, 0x9e, 0x66, 0x1c, 0xd5, 0x9c, 0x1e, 0x7f, 0xa4, 0x6d, 0xe9, 0x18, 0x46, 0xb3, 0xee, 0xe8, 0xa5, 0xec, 0x09, 0xc2, 0xab, 0x1f, 0x41, 0xe2, 0x1b, 0xd8, 0x36, 0x20, 0xcc, 0xdd, 0x1b, 0xdc, 0xe3, 0xab, 0x7e, 0xa6, 0xe0, 0x2d, 0xd2, 0x74, 0xf5, ], shared = [ 0x35, 0xaa, 0x9b, 0x52, 0x53, 0x6a, 0x46, 0x1b, 0xfd, 0xe4, 0xe8, 0x5f, 0xc7, 0x56, 0xbe, 0x92, 0x8c, 0x7d, 0xe9, 0x79, 0x23, 0xf0, 0x41, 0x6c, 0x7a, 0x3a, 0xc8, 0xf8, 0x8b, 0x3d, 0x44, 0x89, ], }, //COUNT = 8 testcase { otherpub = [ 0x04, 0x94, 0xe9, 0x4f, 0x16, 0xa9, 0x82, 0x55, 0xff, 0xf2, 0xb9, 0xac, 0x0c, 0x95, 0x98, 0xaa, 0xc3, 0x54, 0x87, 0xb3, 0x23, 0x2d, 0x32, 0x31, 0xbd, 0x93, 0xb7, 0xdb, 0x7d, 0xf3, 0x6f, 0x9e, 0xb9, 0xd8, 0x04, 0x9a, 0x43, 0x57, 0x9c, 0xfa, 0x90, 0xb8, 0x09, 0x3a, 0x94, 0x41, 0x6c, 0xbe, 0xfb, 0xf9, 0x33, 0x86, 0xf1, 0x5b, 0x3f, 0x6e, 0x19, 0x0b, 0x6e, 0x34, 0x55, 0xfe, 0xdf, 0xe6, 0x9a, ], priv = [ 0x0f, 0x98, 0x83, 0xba, 0x0e, 0xf3, 0x2e, 0xe7, 0x5d, 0xed, 0x0d, 0x8b, 0xda, 0x39, 0xa5, 0x14, 0x6a, 0x29, 0xf1, 0xf2, 0x50, 0x7b, 0x3b, 0xd4, 0x58, 0xdb, 0xea, 0x0b, 0x2b, 0xb0, 0x5b, 0x4d, ], pub = [ 0x04, 0xab, 0xb6, 0x1b, 0x42, 0x3b, 0xe5, 0xd6, 0xc2, 0x6e, 0x21, 0xc6, 0x05, 0x83, 0x2c, 0x91, 0x42, 0xdc, 0x1d, 0xfe, 0x5a, 0x5f, 0xff, 0x28, 0x72, 0x67, 0x37, 0x93, 0x6e, 0x6f, 0xbf, 0x51, 0x6d, 0x73, 0x3d, 0x25, 0x13, 0xef, 0x58, 0xbe, 0xab, 0x20, 0x20, 0x90, 0x58, 0x6f, 0xac, 0x91, 0xbf, 0x0f, 0xee, 0x31, 0xe8, 0x0a, 0xb3, 0x34, 0x73, 0xab, 0x23, 0xa2, 0xd8, 0x9e, 0x58, 0xfa, 0xd6, ], shared = [ 0x60, 0x5c, 0x16, 0x17, 0x8a, 0x9b, 0xc8, 0x75, 0xdc, 0xbf, 0xf5, 0x4d, 0x63, 0xfe, 0x00, 0xdf, 0x69, 0x9c, 0x03, 0xe8, 0xa8, 0x88, 0xe9, 0xe9, 0x4d, 0xfb, 0xab, 0x90, 0xb2, 0x5f, 0x39, 0xb4, ], }, //COUNT = 9 testcase { otherpub = [ 0x04, 0xe0, 0x99, 0xbf, 0x2a, 0x4d, 0x55, 0x74, 0x60, 0xb5, 0x54, 0x44, 0x30, 0xbb, 0xf6, 0xda, 0x11, 0x00, 0x4d, 0x12, 0x7c, 0xb5, 0xd6, 0x7f, 0x64, 0xab, 0x07, 0xc9, 0x4f, 0xcd, 0xf5, 0x27, 0x4f, 0xd9, 0xc5, 0x0d, 0xbe, 0x70, 0xd7, 0x14, 0xed, 0xb5, 0xe2, 0x21, 0xf4, 0xe0, 0x20, 0x61, 0x0e, 0xeb, 0x62, 0x70, 0x51, 0x7e, 0x68, 0x8c, 0xa6, 0x4f, 0xb0, 0xe9, 0x8c, 0x7e, 0xf8, 0xc1, 0xc5, ], priv = [ 0x2b, 0xee, 0xdb, 0x04, 0xb0, 0x5c, 0x69, 0x88, 0xf6, 0xa6, 0x75, 0x00, 0xbb, 0x81, 0x3f, 0xaf, 0x2c, 0xae, 0x0d, 0x58, 0x0c, 0x92, 0x53, 0xb6, 0x33, 0x9e, 0x4a, 0x33, 0x37, 0xbb, 0x6c, 0x08, ], pub = [ 0x04, 0x3d, 0x63, 0xe4, 0x29, 0xcb, 0x5f, 0xa8, 0x95, 0xa9, 0x24, 0x71, 0x29, 0xbf, 0x4e, 0x48, 0xe8, 0x9f, 0x35, 0xd7, 0xb1, 0x1d, 0xe8, 0x15, 0x8e, 0xfe, 0xb3, 0xe1, 0x06, 0xa2, 0xa8, 0x73, 0x95, 0x0c, 0xae, 0x9e, 0x47, 0x7e, 0xf4, 0x1e, 0x7c, 0x8c, 0x10, 0x64, 0x37, 0x9b, 0xb7, 0xb5, 0x54, 0xdd, 0xcb, 0xca, 0xe7, 0x9f, 0x98, 0x14, 0x28, 0x1f, 0x1e, 0x50, 0xf0, 0x40, 0x3c, 0x61, 0xf3, ], shared = [ 0xf9, 0x6e, 0x40, 0xa1, 0xb7, 0x28, 0x40, 0x85, 0x4b, 0xb6, 0x2b, 0xc1, 0x3c, 0x40, 0xcc, 0x27, 0x95, 0xe3, 0x73, 0xd4, 0xe7, 0x15, 0x98, 0x0b, 0x26, 0x14, 0x76, 0x83, 0x5a, 0x09, 0x2e, 0x0b, ], }, //COUNT = 10 testcase { otherpub = [ 0x04, 0xf7, 0x5a, 0x5f, 0xe5, 0x6b, 0xda, 0x34, 0xf3, 0xc1, 0x39, 0x62, 0x96, 0x62, 0x6e, 0xf0, 0x12, 0xdc, 0x07, 0xe4, 0x82, 0x58, 0x38, 0x77, 0x8a, 0x64, 0x5c, 0x82, 0x48, 0xcf, 0xf0, 0x16, 0x58, 0x33, 0xbb, 0xdf, 0x1b, 0x17, 0x72, 0xd8, 0x05, 0x9d, 0xf5, 0x68, 0xb0, 0x61, 0xf3, 0xf1, 0x12, 0x2f, 0x28, 0xa8, 0xd8, 0x19, 0x16, 0x7c, 0x97, 0xbe, 0x44, 0x8e, 0x3d, 0xc3, 0xfb, 0x0c, 0x3c, ], priv = [ 0x77, 0xc1, 0x5d, 0xcf, 0x44, 0x61, 0x0e, 0x41, 0x69, 0x6b, 0xab, 0x75, 0x89, 0x43, 0xef, 0xf1, 0x40, 0x93, 0x33, 0xe4, 0xd5, 0xa1, 0x1b, 0xbe, 0x72, 0xc8, 0xf6, 0xc3, 0x95, 0xe9, 0xf8, 0x48, ], pub = [ 0x04, 0xad, 0x5d, 0x13, 0xc3, 0xdb, 0x50, 0x8d, 0xdc, 0xd3, 0x84, 0x57, 0xe5, 0x99, 0x14, 0x34, 0xa2, 0x51, 0xbe, 0xd4, 0x9c, 0xf5, 0xdd, 0xcb, 0x59, 0xcd, 0xee, 0x73, 0x86, 0x5f, 0x13, 0x8c, 0x9f, 0x62, 0xce, 0xc1, 0xe7, 0x05, 0x88, 0xaa, 0x4f, 0xdf, 0xc7, 0xb9, 0xa0, 0x9d, 0xaa, 0x67, 0x80, 0x81, 0xc0, 0x4e, 0x12, 0x08, 0xb9, 0xd6, 0x62, 0xb8, 0xa2, 0x21, 0x4b, 0xf8, 0xe8, 0x1a, 0x21, ], shared = [ 0x83, 0x88, 0xfa, 0x79, 0xc4, 0xba, 0xbd, 0xca, 0x02, 0xa8, 0xe8, 0xa3, 0x4f, 0x9e, 0x43, 0x55, 0x49, 0x76, 0xe4, 0x20, 0xa4, 0xad, 0x27, 0x3c, 0x81, 0xb2, 0x6e, 0x42, 0x28, 0xe9, 0xd3, 0xa3, ], }, //COUNT = 11 testcase { otherpub = [ 0x04, 0x2d, 0xb4, 0x54, 0x0d, 0x50, 0x23, 0x07, 0x56, 0x15, 0x8a, 0xbf, 0x61, 0xd9, 0x83, 0x57, 0x12, 0xb6, 0x48, 0x6c, 0x74, 0x31, 0x21, 0x83, 0xcc, 0xef, 0xca, 0xef, 0x27, 0x97, 0xb7, 0x67, 0x4d, 0x62, 0xf5, 0x7f, 0x31, 0x4e, 0x3f, 0x34, 0x95, 0xdc, 0x4e, 0x09, 0x90, 0x12, 0xf5, 0xe0, 0xba, 0x71, 0x77, 0x0f, 0x96, 0x60, 0xa1, 0xea, 0xda, 0x54, 0x10, 0x4c, 0xdf, 0xde, 0x77, 0x24, 0x3e, ], priv = [ 0x42, 0xa8, 0x3b, 0x98, 0x50, 0x11, 0xd1, 0x23, 0x03, 0xdb, 0x1a, 0x80, 0x0f, 0x26, 0x10, 0xf7, 0x4a, 0xa7, 0x1c, 0xdf, 0x19, 0xc6, 0x7d, 0x54, 0xce, 0x6c, 0x9e, 0xd9, 0x51, 0xe9, 0x09, 0x3e, ], pub = [ 0x04, 0xab, 0x48, 0xca, 0xa6, 0x1e, 0xa3, 0x5f, 0x13, 0xf8, 0xed, 0x07, 0xff, 0xa6, 0xa1, 0x3e, 0x8d, 0xb2, 0x24, 0xdf, 0xec, 0xfa, 0xe1, 0xa7, 0xdf, 0x8b, 0x1b, 0xb6, 0xeb, 0xaf, 0x0c, 0xb9, 0x7d, 0x12, 0x74, 0x53, 0x0c, 0xa2, 0xc3, 0x85, 0xa3, 0x21, 0x8b, 0xdd, 0xfb, 0xcb, 0xf0, 0xb4, 0x02, 0x4c, 0x9b, 0xad, 0xd5, 0x24, 0x3b, 0xff, 0x83, 0x4e, 0xbf, 0xf2, 0x4a, 0x86, 0x18, 0xdc, 0xcb, ], shared = [ 0x72, 0x87, 0x7c, 0xea, 0x33, 0xcc, 0xc4, 0x71, 0x50, 0x38, 0xd4, 0xbc, 0xbd, 0xfe, 0x0e, 0x43, 0xf4, 0x2a, 0x9e, 0x2c, 0x0c, 0x3b, 0x01, 0x7f, 0xc2, 0x37, 0x0f, 0x4b, 0x9a, 0xcb, 0xda, 0x4a, ], }, //COUNT = 12 testcase { otherpub = [ 0x04, 0xcd, 0x94, 0xfc, 0x94, 0x97, 0xe8, 0x99, 0x07, 0x50, 0x30, 0x9e, 0x9a, 0x85, 0x34, 0xfd, 0x11, 0x4b, 0x0a, 0x6e, 0x54, 0xda, 0x89, 0xc4, 0x79, 0x61, 0x01, 0x89, 0x70, 0x41, 0xd1, 0x4e, 0xcb, 0xc3, 0xde, 0xf4, 0xb5, 0xfe, 0x04, 0xfa, 0xee, 0x0a, 0x11, 0x93, 0x22, 0x29, 0xff, 0xf5, 0x63, 0x63, 0x7b, 0xfd, 0xee, 0x0e, 0x79, 0xc6, 0xde, 0xea, 0xf4, 0x49, 0xf8, 0x54, 0x01, 0xc5, 0xc4, ], priv = [ 0xce, 0xed, 0x35, 0x50, 0x7b, 0x5c, 0x93, 0xea, 0xd5, 0x98, 0x91, 0x19, 0xb9, 0xba, 0x34, 0x2c, 0xfe, 0x38, 0xe6, 0xe6, 0x38, 0xba, 0x6e, 0xea, 0x34, 0x3a, 0x55, 0x47, 0x5d, 0xe2, 0x80, 0x0b, ], pub = [ 0x04, 0x9a, 0x8c, 0xd9, 0xbd, 0x72, 0xe7, 0x17, 0x52, 0xdf, 0x91, 0x44, 0x0f, 0x77, 0xc5, 0x47, 0x50, 0x9a, 0x84, 0xdf, 0x98, 0x11, 0x4e, 0x7d, 0xe4, 0xf2, 0x6c, 0xdb, 0x39, 0x23, 0x4a, 0x62, 0x5d, 0xd0, 0x7c, 0xfc, 0x84, 0xc8, 0xe1, 0x44, 0xfa, 0xb2, 0x83, 0x9f, 0x51, 0x89, 0xbb, 0x1d, 0x7c, 0x88, 0x63, 0x1d, 0x57, 0x9b, 0xbc, 0x58, 0x01, 0x2e, 0xd9, 0xa2, 0x32, 0x7d, 0xa5, 0x2f, 0x62, ], shared = [ 0xe4, 0xe7, 0x40, 0x8d, 0x85, 0xff, 0x0e, 0x0e, 0x9c, 0x83, 0x80, 0x03, 0xf2, 0x8c, 0xdb, 0xd5, 0x24, 0x7c, 0xdc, 0xe3, 0x1f, 0x32, 0xf6, 0x24, 0x94, 0xb7, 0x0e, 0x5f, 0x1b, 0xc3, 0x63, 0x07, ], }, //COUNT = 13 testcase { otherpub = [ 0x04, 0x15, 0xb9, 0xe4, 0x67, 0xaf, 0x4d, 0x29, 0x0c, 0x41, 0x74, 0x02, 0xe0, 0x40, 0x42, 0x6f, 0xe4, 0xcf, 0x23, 0x6b, 0xae, 0x72, 0xba, 0xa3, 0x92, 0xed, 0x89, 0x78, 0x0d, 0xfc, 0xcd, 0xb4, 0x71, 0xcd, 0xf4, 0xe9, 0x17, 0x0f, 0xb9, 0x04, 0x30, 0x2b, 0x8f, 0xd9, 0x3a, 0x82, 0x0b, 0xa8, 0xcc, 0x7e, 0xd4, 0xef, 0xd3, 0xa6, 0xf2, 0xd6, 0xb0, 0x5b, 0x80, 0xb2, 0xff, 0x2a, 0xee, 0x4e, 0x77, ], priv = [ 0x43, 0xe0, 0xe9, 0xd9, 0x5a, 0xf4, 0xdc, 0x36, 0x48, 0x3c, 0xdd, 0x19, 0x68, 0xd2, 0xb7, 0xee, 0xb8, 0x61, 0x1f, 0xcc, 0xe7, 0x7f, 0x3a, 0x4e, 0x7d, 0x05, 0x9a, 0xe4, 0x3e, 0x50, 0x96, 0x04, ], pub = [ 0x04, 0xf9, 0x89, 0xcf, 0x8e, 0xe9, 0x56, 0xa8, 0x2e, 0x7e, 0xbd, 0x98, 0x81, 0xcd, 0xbf, 0xb2, 0xfd, 0x94, 0x61, 0x89, 0xb0, 0x8d, 0xb5, 0x35, 0x59, 0xbc, 0x8c, 0xfd, 0xd4, 0x80, 0x71, 0xeb, 0x14, 0x5e, 0xff, 0x28, 0xf1, 0xa1, 0x8a, 0x61, 0x6b, 0x04, 0xb7, 0xd3, 0x37, 0x86, 0x86, 0x79, 0xf6, 0xdd, 0x84, 0xf9, 0xa7, 0xb3, 0xd7, 0xb6, 0xf8, 0xaf, 0x27, 0x6c, 0x19, 0x61, 0x1a, 0x54, 0x1d, ], shared = [ 0xed, 0x56, 0xbc, 0xf6, 0x95, 0xb7, 0x34, 0x14, 0x2c, 0x24, 0xec, 0xb1, 0xfc, 0x1b, 0xb6, 0x4d, 0x08, 0xf1, 0x75, 0xeb, 0x24, 0x3a, 0x31, 0xf3, 0x7b, 0x3d, 0x9b, 0xb4, 0x40, 0x7f, 0x3b, 0x96, ], }, //COUNT = 14 testcase { otherpub = [ 0x04, 0x49, 0xc5, 0x03, 0xba, 0x6c, 0x4f, 0xa6, 0x05, 0x18, 0x2e, 0x18, 0x6b, 0x5e, 0x81, 0x11, 0x3f, 0x07, 0x5b, 0xc1, 0x1d, 0xcf, 0xd5, 0x1c, 0x93, 0x2f, 0xb2, 0x1e, 0x95, 0x1e, 0xee, 0x2f, 0xa1, 0x8a, 0xf7, 0x06, 0xff, 0x09, 0x22, 0xd8, 0x7b, 0x3f, 0x0c, 0x5e, 0x4e, 0x31, 0xd8, 0xb2, 0x59, 0xae, 0xb2, 0x60, 0xa9, 0x26, 0x96, 0x43, 0xed, 0x52, 0x0a, 0x13, 0xbb, 0x25, 0xda, 0x59, 0x24, ], priv = [ 0xb2, 0xf3, 0x60, 0x0d, 0xf3, 0x36, 0x8e, 0xf8, 0xa0, 0xbb, 0x85, 0xab, 0x22, 0xf4, 0x1f, 0xc0, 0xe5, 0xf4, 0xfd, 0xd5, 0x4b, 0xe8, 0x16, 0x7a, 0x5c, 0x3c, 0xd4, 0xb0, 0x8d, 0xb0, 0x49, 0x03, ], pub = [ 0x04, 0x69, 0xc6, 0x27, 0x62, 0x5b, 0x36, 0xa4, 0x29, 0xc3, 0x98, 0xb4, 0x5c, 0x38, 0x67, 0x7c, 0xb3, 0x5d, 0x8b, 0xeb, 0x1c, 0xf7, 0x8a, 0x57, 0x1e, 0x40, 0xe9, 0x9f, 0xe4, 0xea, 0xc1, 0xcd, 0x4e, 0x81, 0x69, 0x01, 0x12, 0xb0, 0xa8, 0x8f, 0x20, 0xf7, 0x13, 0x6b, 0x28, 0xd7, 0xd4, 0x7e, 0x5f, 0xbc, 0x2a, 0xda, 0x3c, 0x8e, 0xdd, 0x87, 0x58, 0x9b, 0xc1, 0x9e, 0xc9, 0x59, 0x06, 0x37, 0xbd, ], shared = [ 0xbc, 0x5c, 0x70, 0x55, 0x08, 0x9f, 0xc9, 0xd6, 0xc8, 0x9f, 0x83, 0xc1, 0xea, 0x1a, 0xda, 0x87, 0x9d, 0x99, 0x34, 0xb2, 0xea, 0x28, 0xfc, 0xf4, 0xe4, 0xa7, 0xe9, 0x84, 0xb2, 0x8a, 0xd2, 0xcf, ], }, //COUNT = 15 testcase { otherpub = [ 0x04, 0x19, 0xb3, 0x8d, 0xe3, 0x9f, 0xdd, 0x2f, 0x70, 0xf7, 0x09, 0x16, 0x31, 0xa4, 0xf7, 0x5d, 0x19, 0x93, 0x74, 0x0b, 0xa9, 0x42, 0x91, 0x62, 0xc2, 0xa4, 0x53, 0x12, 0x40, 0x16, 0x36, 0xb2, 0x9c, 0x09, 0xae, 0xd7, 0x23, 0x2b, 0x28, 0xe0, 0x60, 0x94, 0x17, 0x41, 0xb6, 0x82, 0x8b, 0xcd, 0xfa, 0x2b, 0xc4, 0x9c, 0xc8, 0x44, 0xf3, 0x77, 0x36, 0x11, 0x50, 0x4f, 0x82, 0xa3, 0x90, 0xa5, 0xae, ], priv = [ 0x40, 0x02, 0x53, 0x43, 0x07, 0xf8, 0xb6, 0x2a, 0x9b, 0xf6, 0x7f, 0xf6, 0x41, 0xdd, 0xc6, 0x0f, 0xef, 0x59, 0x3b, 0x17, 0xc3, 0x34, 0x12, 0x39, 0xe9, 0x5b, 0xdb, 0x3e, 0x57, 0x9b, 0xfd, 0xc8, ], pub = [ 0x04, 0x5f, 0xe9, 0x64, 0x67, 0x13, 0x15, 0xa1, 0x8a, 0xa6, 0x8a, 0x2a, 0x6e, 0x3d, 0xd1, 0xfd, 0xe7, 0xe2, 0x3b, 0x8c, 0xe7, 0x18, 0x14, 0x71, 0xcf, 0xac, 0x43, 0xc9, 0x9e, 0x1a, 0xe8, 0x02, 0x62, 0xd5, 0x82, 0x7b, 0xe2, 0x82, 0xe6, 0x2c, 0x84, 0xde, 0x53, 0x1b, 0x96, 0x38, 0x84, 0xba, 0x83, 0x2d, 0xb5, 0xd6, 0xb2, 0xc3, 0xa2, 0x56, 0xf0, 0xe6, 0x04, 0xfe, 0x7e, 0x6b, 0x8a, 0x7f, 0x72, ], shared = [ 0x9a, 0x4e, 0x8e, 0x65, 0x7f, 0x6b, 0x0e, 0x09, 0x7f, 0x47, 0x95, 0x4a, 0x63, 0xc7, 0x5d, 0x74, 0xfc, 0xba, 0x71, 0xa3, 0x0d, 0x83, 0x65, 0x1e, 0x3e, 0x5a, 0x91, 0xaa, 0x7c, 0xcd, 0x83, 0x43, ], }, //COUNT = 16 testcase { otherpub = [ 0x04, 0x2c, 0x91, 0xc6, 0x1f, 0x33, 0xad, 0xfe, 0x93, 0x11, 0xc9, 0x42, 0xfd, 0xbf, 0xf6, 0xba, 0x47, 0x02, 0x0f, 0xef, 0xf4, 0x16, 0xb7, 0xbb, 0x63, 0xce, 0xc1, 0x3f, 0xaf, 0x9b, 0x09, 0x99, 0x54, 0x6c, 0xab, 0x31, 0xb0, 0x64, 0x19, 0xe5, 0x22, 0x1f, 0xca, 0x01, 0x4f, 0xb8, 0x4e, 0xc8, 0x70, 0x62, 0x2a, 0x1b, 0x12, 0xba, 0xb5, 0xae, 0x43, 0x68, 0x2a, 0xa7, 0xea, 0x73, 0xea, 0x08, 0xd0, ], priv = [ 0x4d, 0xfa, 0x12, 0xde, 0xfc, 0x60, 0x31, 0x90, 0x21, 0xb6, 0x81, 0xb3, 0xff, 0x84, 0xa1, 0x0a, 0x51, 0x19, 0x58, 0xc8, 0x50, 0x93, 0x9e, 0xd4, 0x56, 0x35, 0x93, 0x4b, 0xa4, 0x97, 0x91, 0x47, ], pub = [ 0x04, 0xc9, 0xb2, 0xb8, 0x49, 0x6f, 0x14, 0x40, 0xbd, 0x4a, 0x2d, 0x1e, 0x52, 0x75, 0x2f, 0xd3, 0x72, 0x83, 0x5b, 0x36, 0x48, 0x85, 0xe1, 0x54, 0xa7, 0xda, 0xc4, 0x92, 0x95, 0xf2, 0x81, 0xec, 0x7c, 0xfb, 0xe6, 0xb9, 0x26, 0xa8, 0xa4, 0xde, 0x26, 0xcc, 0xc8, 0x3b, 0x80, 0x2b, 0x12, 0x12, 0x40, 0x07, 0x54, 0xbe, 0x25, 0xd9, 0xf3, 0xee, 0xaf, 0x00, 0x8b, 0x09, 0x87, 0x0a, 0xe7, 0x63, 0x21, ], shared = [ 0x3c, 0xa1, 0xfc, 0x7a, 0xd8, 0x58, 0xfb, 0x1a, 0x6a, 0xba, 0x23, 0x25, 0x42, 0xf3, 0xe2, 0xa7, 0x49, 0xff, 0xc7, 0x20, 0x3a, 0x23, 0x74, 0xa3, 0xf3, 0xd3, 0x26, 0x7f, 0x1f, 0xc9, 0x7b, 0x78, ], }, //COUNT = 17 testcase { otherpub = [ 0x04, 0xa2, 0x8a, 0x2e, 0xdf, 0x58, 0x02, 0x56, 0x68, 0xf7, 0x24, 0xaa, 0xf8, 0x3a, 0x50, 0x95, 0x6b, 0x7a, 0xc1, 0xcf, 0xbb, 0xff, 0x79, 0xb0, 0x8c, 0x3b, 0xf8, 0x7d, 0xfd, 0x28, 0x28, 0xd7, 0x67, 0xdf, 0xa7, 0xbf, 0xff, 0xd4, 0xc7, 0x66, 0xb8, 0x6a, 0xbe, 0xaf, 0x5c, 0x99, 0xb6, 0xe5, 0x0c, 0xb9, 0xcc, 0xc9, 0xd9, 0xd0, 0x0b, 0x7f, 0xfc, 0x78, 0x04, 0xb0, 0x49, 0x1b, 0x67, 0xbc, 0x03, ], priv = [ 0x13, 0x31, 0xf6, 0xd8, 0x74, 0xa4, 0xed, 0x3b, 0xc4, 0xa2, 0xc6, 0xe9, 0xc7, 0x43, 0x31, 0xd3, 0x03, 0x97, 0x96, 0x31, 0x4b, 0xee, 0xe3, 0xb7, 0x15, 0x2f, 0xcd, 0xba, 0x55, 0x56, 0x30, 0x4e, ], pub = [ 0x04, 0x59, 0xe1, 0xe1, 0x01, 0x52, 0x10, 0x46, 0xad, 0x9c, 0xf1, 0xd0, 0x82, 0xe9, 0xd2, 0xec, 0x7d, 0xd2, 0x25, 0x30, 0xcc, 0xe0, 0x64, 0x99, 0x1f, 0x1e, 0x55, 0xc5, 0xbc, 0xf5, 0xfc, 0xb5, 0x91, 0x48, 0x2f, 0x4f, 0x67, 0x31, 0x76, 0xc8, 0xfd, 0xaa, 0x0b, 0xb6, 0xe5, 0x9b, 0x15, 0xa3, 0xe4, 0x74, 0x54, 0xe3, 0xa0, 0x42, 0x97, 0xd3, 0x86, 0x3c, 0x93, 0x38, 0xd9, 0x8a, 0xdd, 0x1f, 0x37, ], shared = [ 0x1a, 0xaa, 0xbe, 0x7e, 0xe6, 0xe4, 0xa6, 0xfa, 0x73, 0x22, 0x91, 0x20, 0x24, 0x33, 0xa2, 0x37, 0xdf, 0x1b, 0x49, 0xbc, 0x53, 0x86, 0x6b, 0xfb, 0xe0, 0x0d, 0xb9, 0x6a, 0x0f, 0x58, 0x22, 0x4f, ], }, //COUNT = 18 testcase { otherpub = [ 0x04, 0xa2, 0xef, 0x85, 0x7a, 0x08, 0x1f, 0x9d, 0x6e, 0xb2, 0x06, 0xa8, 0x1c, 0x4c, 0xf7, 0x8a, 0x80, 0x2b, 0xdf, 0x59, 0x8a, 0xe3, 0x80, 0xc8, 0x88, 0x6e, 0xcd, 0x85, 0xfd, 0xc1, 0xed, 0x76, 0x44, 0x56, 0x3c, 0x4c, 0x20, 0x41, 0x9f, 0x07, 0xbc, 0x17, 0xd0, 0x53, 0x9f, 0xad, 0xe1, 0x85, 0x5e, 0x34, 0x83, 0x95, 0x15, 0xb8, 0x92, 0xc0, 0xf5, 0xd2, 0x65, 0x61, 0xf9, 0x7f, 0xa0, 0x4d, 0x1a, ], priv = [ 0xdd, 0x5e, 0x9f, 0x70, 0xae, 0x74, 0x00, 0x73, 0xca, 0x02, 0x04, 0xdf, 0x60, 0x76, 0x3f, 0xb6, 0x03, 0x6c, 0x45, 0x70, 0x9b, 0xf4, 0xa7, 0xbb, 0x4e, 0x67, 0x14, 0x12, 0xfa, 0xd6, 0x5d, 0xa3, ], pub = [ 0x04, 0x30, 0xb9, 0xdb, 0x2e, 0x2e, 0x97, 0x7b, 0xcd, 0xc9, 0x8c, 0xb8, 0x7d, 0xd7, 0x36, 0xcb, 0xd8, 0xe7, 0x85, 0x52, 0x12, 0x19, 0x25, 0xcf, 0x16, 0xe1, 0x93, 0x36, 0x57, 0xc2, 0xfb, 0x23, 0x14, 0x6a, 0x45, 0x02, 0x88, 0x00, 0xb8, 0x12, 0x91, 0xbc, 0xe5, 0xc2, 0xe1, 0xfe, 0xd7, 0xde, 0xd6, 0x50, 0x62, 0x0e, 0xbb, 0xe6, 0x05, 0x0c, 0x6f, 0x3a, 0x7f, 0x0d, 0xfb, 0x46, 0x73, 0xab, 0x5c, ], shared = [ 0x43, 0x0e, 0x6a, 0x4f, 0xba, 0x44, 0x49, 0xd7, 0x00, 0xd2, 0x73, 0x3e, 0x55, 0x7f, 0x66, 0xa3, 0xbf, 0x3d, 0x50, 0x51, 0x7c, 0x12, 0x71, 0xb1, 0xdd, 0xae, 0x11, 0x61, 0xb7, 0xac, 0x79, 0x8c, ], }, //COUNT = 19 testcase { otherpub = [ 0x04, 0xcc, 0xd8, 0xa2, 0xd8, 0x6b, 0xc9, 0x2f, 0x2e, 0x01, 0xbc, 0xe4, 0xd6, 0x92, 0x2c, 0xf7, 0xfe, 0x16, 0x26, 0xae, 0xd0, 0x44, 0x68, 0x5e, 0x95, 0xe2, 0xee, 0xbd, 0x46, 0x45, 0x05, 0xf0, 0x1f, 0xe9, 0xdd, 0xd5, 0x83, 0xa9, 0x63, 0x5a, 0x66, 0x77, 0x77, 0xd5, 0xb8, 0xa8, 0xf3, 0x1b, 0x0f, 0x79, 0xeb, 0xa1, 0x2c, 0x75, 0x02, 0x34, 0x10, 0xb5, 0x4b, 0x85, 0x67, 0xdd, 0xdc, 0x0f, 0x38, ], priv = [ 0x5a, 0xe0, 0x26, 0xcf, 0xc0, 0x60, 0xd5, 0x56, 0x00, 0x71, 0x7e, 0x55, 0xb8, 0xa1, 0x2e, 0x11, 0x6d, 0x1d, 0x0d, 0xf3, 0x4a, 0xf8, 0x31, 0x97, 0x90, 0x57, 0x60, 0x7c, 0x2d, 0x9c, 0x2f, 0x76, ], pub = [ 0x04, 0x46, 0xc9, 0xeb, 0xd1, 0xa4, 0xa3, 0xc8, 0xc0, 0xb6, 0xd5, 0x72, 0xb5, 0xdc, 0xfb, 0xa1, 0x24, 0x67, 0x60, 0x32, 0x08, 0xa9, 0xcb, 0x5d, 0x2a, 0xcf, 0xbb, 0x73, 0x3c, 0x40, 0xcf, 0x63, 0x91, 0x46, 0xc9, 0x13, 0xa2, 0x7d, 0x04, 0x41, 0x85, 0xd3, 0x8b, 0x46, 0x7a, 0xce, 0x01, 0x1e, 0x04, 0xd4, 0xd9, 0xbb, 0xbb, 0x8c, 0xb9, 0xae, 0x25, 0xfa, 0x92, 0xaa, 0xf1, 0x5a, 0x59, 0x5e, 0x86, ], shared = [ 0x1c, 0xe9, 0xe6, 0x74, 0x05, 0x29, 0x49, 0x9f, 0x98, 0xd1, 0xf1, 0xd7, 0x13, 0x29, 0x14, 0x7a, 0x33, 0xdf, 0x1d, 0x05, 0xe4, 0x76, 0x5b, 0x53, 0x9b, 0x11, 0xcf, 0x61, 0x5d, 0x69, 0x74, 0xd3, ], }, //COUNT = 20 testcase { otherpub = [ 0x04, 0xc1, 0x88, 0xff, 0xc8, 0x94, 0x7f, 0x73, 0x01, 0xfb, 0x7b, 0x53, 0xe3, 0x67, 0x46, 0x09, 0x7c, 0x21, 0x34, 0xbf, 0x9c, 0xc9, 0x81, 0xba, 0x74, 0xb4, 0xe9, 0xc4, 0x36, 0x1f, 0x59, 0x5e, 0x4e, 0xbf, 0x7d, 0x2f, 0x20, 0x56, 0xe7, 0x24, 0x21, 0xef, 0x39, 0x3f, 0x0c, 0x0f, 0x2b, 0x0e, 0x00, 0x13, 0x0e, 0x3c, 0xac, 0x4a, 0xbb, 0xcc, 0x00, 0x28, 0x61, 0x68, 0xe8, 0x5e, 0xc5, 0x50, 0x51, ], priv = [ 0xb6, 0x01, 0xac, 0x42, 0x5d, 0x5d, 0xbf, 0x9e, 0x17, 0x35, 0xc5, 0xe2, 0xd5, 0xbd, 0xb7, 0x9c, 0xa9, 0x8b, 0x3d, 0x5b, 0xe4, 0xa2, 0xcf, 0xd6, 0xf2, 0x27, 0x3f, 0x15, 0x0e, 0x06, 0x4d, 0x9d, ], pub = [ 0x04, 0x7c, 0x9e, 0x95, 0x08, 0x41, 0xd2, 0x6c, 0x8d, 0xde, 0x89, 0x94, 0x39, 0x8b, 0x8f, 0x5d, 0x47, 0x5a, 0x02, 0x2b, 0xc6, 0x3d, 0xe7, 0x77, 0x3f, 0xcf, 0x8d, 0x55, 0x2e, 0x01, 0xf1, 0xba, 0x0a, 0xcc, 0x42, 0xb9, 0x88, 0x5c, 0x9b, 0x3b, 0xee, 0x0f, 0x8d, 0x8c, 0x57, 0xd3, 0xa8, 0xf6, 0x35, 0x50, 0x16, 0xc0, 0x19, 0xc4, 0x06, 0x2f, 0xa2, 0x2c, 0xff, 0x2f, 0x20, 0x9b, 0x5c, 0xc2, 0xe1, ], shared = [ 0x46, 0x90, 0xe3, 0x74, 0x3c, 0x07, 0xd6, 0x43, 0xf1, 0xbc, 0x18, 0x36, 0x36, 0xab, 0x2a, 0x9c, 0xb9, 0x36, 0xa6, 0x0a, 0x80, 0x21, 0x13, 0xc4, 0x9b, 0xb1, 0xb3, 0xf2, 0xd0, 0x66, 0x16, 0x60, ], }, //COUNT = 21 testcase { otherpub = [ 0x04, 0x31, 0x7e, 0x10, 0x20, 0xff, 0x53, 0xfc, 0xce, 0xf1, 0x8b, 0xf4, 0x7b, 0xb7, 0xf2, 0xdd, 0x77, 0x07, 0xfb, 0x7b, 0x7a, 0x75, 0x78, 0xe0, 0x4f, 0x35, 0xb3, 0xbe, 0xed, 0x22, 0x2a, 0x0e, 0xb6, 0x09, 0x42, 0x0c, 0xe5, 0xa1, 0x9d, 0x77, 0xc6, 0xfe, 0x1e, 0xe5, 0x87, 0xe6, 0xa4, 0x9f, 0xba, 0xf8, 0xf2, 0x80, 0xe8, 0xdf, 0x03, 0x3d, 0x75, 0x40, 0x33, 0x02, 0xe5, 0xa2, 0x7d, 0xb2, 0xae, ], priv = [ 0xfe, 0xfb, 0x1d, 0xda, 0x18, 0x45, 0x31, 0x2b, 0x5f, 0xce, 0x6b, 0x81, 0xb2, 0xbe, 0x20, 0x5a, 0xf2, 0xf3, 0xa2, 0x74, 0xf5, 0xa2, 0x12, 0xf6, 0x6c, 0x0d, 0x9f, 0xc3, 0x3d, 0x7a, 0xe5, 0x35, ], pub = [ 0x04, 0x38, 0xb5, 0x4d, 0xb8, 0x55, 0x00, 0xcb, 0x20, 0xc6, 0x10, 0x56, 0xed, 0xd3, 0xd8, 0x8b, 0x6a, 0x9d, 0xc2, 0x67, 0x80, 0xa0, 0x47, 0xf2, 0x13, 0xa6, 0xe1, 0xb9, 0x00, 0xf7, 0x65, 0x96, 0xeb, 0x63, 0x87, 0xe4, 0xe5, 0x78, 0x15, 0x71, 0xe4, 0xeb, 0x8a, 0xe6, 0x29, 0x91, 0xa3, 0x3b, 0x5d, 0xc3, 0x33, 0x01, 0xc5, 0xbc, 0x7e, 0x12, 0x5d, 0x53, 0x79, 0x4a, 0x39, 0x16, 0x0d, 0x8f, 0xd0, ], shared = [ 0x30, 0xc2, 0x26, 0x1b, 0xd0, 0x00, 0x4e, 0x61, 0xfe, 0xda, 0x2c, 0x16, 0xaa, 0x5e, 0x21, 0xff, 0xa8, 0xd7, 0xe7, 0xf7, 0xdb, 0xf6, 0xec, 0x37, 0x9a, 0x43, 0xb4, 0x8e, 0x4b, 0x36, 0xae, 0xb0, ], }, //COUNT = 22 testcase { otherpub = [ 0x04, 0x45, 0xfb, 0x02, 0xb2, 0xce, 0xb9, 0xd7, 0xc7, 0x9d, 0x9c, 0x2f, 0xa9, 0x3e, 0x9c, 0x79, 0x67, 0xc2, 0xfa, 0x4d, 0xf5, 0x78, 0x9f, 0x96, 0x40, 0xb2, 0x42, 0x64, 0xb1, 0xe5, 0x24, 0xfc, 0xb1, 0x5c, 0x6e, 0x8e, 0xcf, 0x1f, 0x7d, 0x30, 0x23, 0x89, 0x3b, 0x7b, 0x1c, 0xa1, 0xe4, 0xd1, 0x78, 0x97, 0x2e, 0xe2, 0xa2, 0x30, 0x75, 0x7d, 0xdc, 0x56, 0x4f, 0xfe, 0x37, 0xf5, 0xc5, 0xa3, 0x21, ], priv = [ 0x33, 0x4a, 0xe0, 0xc4, 0x69, 0x3d, 0x23, 0x93, 0x5a, 0x7e, 0x8e, 0x04, 0x3e, 0xbb, 0xde, 0x21, 0xe1, 0x68, 0xa7, 0xcb, 0xa3, 0xfa, 0x50, 0x7c, 0x9b, 0xe4, 0x1d, 0x76, 0x81, 0xe0, 0x49, 0xce, ], pub = [ 0x04, 0x3f, 0x2b, 0xf1, 0x58, 0x9a, 0xbf, 0x30, 0x47, 0xbf, 0x3e, 0x54, 0xac, 0x9a, 0x95, 0x37, 0x9b, 0xff, 0x95, 0xf8, 0xf5, 0x54, 0x05, 0xf6, 0x4e, 0xca, 0x36, 0xa7, 0xee, 0xbe, 0x8f, 0xfc, 0xa7, 0x52, 0x12, 0xa9, 0x4e, 0x66, 0xc5, 0xae, 0x9a, 0x89, 0x91, 0x87, 0x2f, 0x66, 0xa7, 0x27, 0x23, 0xd8, 0x0e, 0xc5, 0xb2, 0xe9, 0x25, 0x74, 0x5c, 0x45, 0x6f, 0x53, 0x71, 0x94, 0x3b, 0x3a, 0x06, ], shared = [ 0x2a, 0xda, 0xe4, 0xa1, 0x38, 0xa2, 0x39, 0xdc, 0xd9, 0x3c, 0x24, 0x3a, 0x38, 0x03, 0xc3, 0xe4, 0xcf, 0x96, 0xe3, 0x7f, 0xe1, 0x4e, 0x6a, 0x9b, 0x71, 0x7b, 0xe9, 0x59, 0x99, 0x59, 0xb1, 0x1c, ], }, //COUNT = 23 testcase { otherpub = [ 0x04, 0xa1, 0x9e, 0xf7, 0xbf, 0xf9, 0x8a, 0xda, 0x78, 0x18, 0x42, 0xfb, 0xfc, 0x51, 0xa4, 0x7a, 0xff, 0x39, 0xb5, 0x93, 0x5a, 0x1c, 0x7d, 0x96, 0x25, 0xc8, 0xd3, 0x23, 0xd5, 0x11, 0xc9, 0x2d, 0xe6, 0xe9, 0xc1, 0x84, 0xdf, 0x75, 0xc9, 0x55, 0xe0, 0x2e, 0x02, 0xe4, 0x00, 0xff, 0xe4, 0x5f, 0x78, 0xf3, 0x39, 0xe1, 0xaf, 0xe6, 0xd0, 0x56, 0xfb, 0x32, 0x45, 0xf4, 0x70, 0x0c, 0xe6, 0x06, 0xef, ], priv = [ 0x2c, 0x4b, 0xde, 0x40, 0x21, 0x4f, 0xcc, 0x3b, 0xfc, 0x47, 0xd4, 0xcf, 0x43, 0x4b, 0x62, 0x9a, 0xcb, 0xe9, 0x15, 0x7f, 0x8f, 0xd0, 0x28, 0x25, 0x40, 0x33, 0x1d, 0xe7, 0x94, 0x2c, 0xf0, 0x9d, ], pub = [ 0x04, 0x29, 0xc0, 0x80, 0x7f, 0x10, 0xcb, 0xc4, 0x2f, 0xb4, 0x5c, 0x99, 0x89, 0xda, 0x50, 0x68, 0x1e, 0xea, 0xd7, 0x16, 0xda, 0xa7, 0xb9, 0xe9, 0x1f, 0xd3, 0x2e, 0x06, 0x2f, 0x5e, 0xb9, 0x2c, 0xa0, 0xff, 0x1d, 0x6d, 0x19, 0x55, 0xd7, 0x37, 0x6b, 0x2d, 0xa2, 0x4f, 0xe1, 0x16, 0x3a, 0x27, 0x16, 0x59, 0x13, 0x63, 0x41, 0xbc, 0x2e, 0xb1, 0x19, 0x5f, 0xc7, 0x06, 0xdc, 0x62, 0xe7, 0xf3, 0x4d, ], shared = [ 0x2e, 0x27, 0x7e, 0xc3, 0x0f, 0x5e, 0xa0, 0x7d, 0x6c, 0xe5, 0x13, 0x14, 0x9b, 0x94, 0x79, 0xb9, 0x6e, 0x07, 0xf4, 0xb6, 0x91, 0x3b, 0x1b, 0x5c, 0x11, 0x30, 0x5c, 0x14, 0x44, 0xa1, 0xbc, 0x0b, ], }, //COUNT = 24 testcase { otherpub = [ 0x04, 0x35, 0x6c, 0x5a, 0x44, 0x4c, 0x04, 0x9a, 0x52, 0xfe, 0xe0, 0xad, 0xeb, 0x7e, 0x5d, 0x82, 0xae, 0x5a, 0xa8, 0x30, 0x30, 0xbf, 0xff, 0x31, 0xbb, 0xf8, 0xce, 0x20, 0x96, 0xcf, 0x16, 0x1c, 0x4b, 0x57, 0xd1, 0x28, 0xde, 0x8b, 0x2a, 0x57, 0xa0, 0x94, 0xd1, 0xa0, 0x01, 0xe5, 0x72, 0x17, 0x3f, 0x96, 0xe8, 0x86, 0x6a, 0xe3, 0x52, 0xbf, 0x29, 0xcd, 0xda, 0xf9, 0x2f, 0xc8, 0x5b, 0x2f, 0x92, ], priv = [ 0x85, 0xa2, 0x68, 0xf9, 0xd7, 0x77, 0x2f, 0x99, 0x0c, 0x36, 0xb4, 0x2b, 0x0a, 0x33, 0x1a, 0xdc, 0x92, 0xb5, 0x94, 0x1d, 0xe0, 0xb8, 0x62, 0xd5, 0xd8, 0x9a, 0x34, 0x7c, 0xbf, 0x8f, 0xaa, 0xb0, ], pub = [ 0x04, 0x9c, 0xf4, 0xb9, 0x85, 0x81, 0xca, 0x17, 0x79, 0x45, 0x3c, 0xc8, 0x16, 0xff, 0x28, 0xb4, 0x10, 0x0a, 0xf5, 0x6c, 0xf1, 0xbf, 0x2e, 0x5b, 0xc3, 0x12, 0xd8, 0x3b, 0x6b, 0x1b, 0x21, 0xd3, 0x33, 0x7a, 0x55, 0x04, 0xfc, 0xac, 0x52, 0x31, 0xa0, 0xd1, 0x2d, 0x65, 0x82, 0x18, 0x28, 0x48, 0x68, 0x22, 0x9c, 0x84, 0x4a, 0x04, 0xa3, 0x45, 0x0d, 0x6c, 0x73, 0x81, 0xab, 0xe0, 0x80, 0xbf, 0x3b, ], shared = [ 0x1e, 0x51, 0x37, 0x3b, 0xd2, 0xc6, 0x04, 0x4c, 0x12, 0x9c, 0x43, 0x6e, 0x74, 0x2a, 0x55, 0xbe, 0x2a, 0x66, 0x8a, 0x85, 0xae, 0x08, 0x44, 0x1b, 0x67, 0x56, 0x44, 0x5d, 0xf5, 0x49, 0x38, 0x57, ], }, ]; const p384cases = [ //COUNT = 0 testcase { otherpub = [ 0x04, 0xa7, 0xc7, 0x6b, 0x97, 0x0c, 0x3b, 0x5f, 0xe8, 0xb0, 0x5d, 0x28, 0x38, 0xae, 0x04, 0xab, 0x47, 0x69, 0x7b, 0x9e, 0xaf, 0x52, 0xe7, 0x64, 0x59, 0x2e, 0xfd, 0xa2, 0x7f, 0xe7, 0x51, 0x32, 0x72, 0x73, 0x44, 0x66, 0xb4, 0x00, 0x09, 0x1a, 0xdb, 0xf2, 0xd6, 0x8c, 0x58, 0xe0, 0xc5, 0x00, 0x66, 0xac, 0x68, 0xf1, 0x9f, 0x2e, 0x1c, 0xb8, 0x79, 0xae, 0xd4, 0x3a, 0x99, 0x69, 0xb9, 0x1a, 0x08, 0x39, 0xc4, 0xc3, 0x8a, 0x49, 0x74, 0x9b, 0x66, 0x1e, 0xfe, 0xdf, 0x24, 0x34, 0x51, 0x91, 0x5e, 0xd0, 0x90, 0x5a, 0x32, 0xb0, 0x60, 0x99, 0x2b, 0x46, 0x8c, 0x64, 0x76, 0x6f, 0xc8, 0x43, 0x7a, ], priv = [ 0x3c, 0xc3, 0x12, 0x2a, 0x68, 0xf0, 0xd9, 0x50, 0x27, 0xad, 0x38, 0xc0, 0x67, 0x91, 0x6b, 0xa0, 0xeb, 0x8c, 0x38, 0x89, 0x4d, 0x22, 0xe1, 0xb1, 0x56, 0x18, 0xb6, 0x81, 0x8a, 0x66, 0x17, 0x74, 0xad, 0x46, 0x3b, 0x20, 0x5d, 0xa8, 0x8c, 0xf6, 0x99, 0xab, 0x4d, 0x43, 0xc9, 0xcf, 0x98, 0xa1, ], pub = [ 0x04, 0x98, 0x03, 0x80, 0x7f, 0x2f, 0x6d, 0x2f, 0xd9, 0x66, 0xcd, 0xd0, 0x29, 0x0b, 0xd4, 0x10, 0xc0, 0x19, 0x03, 0x52, 0xfb, 0xec, 0x7f, 0xf6, 0x24, 0x7d, 0xe1, 0x30, 0x2d, 0xf8, 0x6f, 0x25, 0xd3, 0x4f, 0xe4, 0xa9, 0x7b, 0xef, 0x60, 0xcf, 0xf5, 0x48, 0x35, 0x5c, 0x01, 0x5d, 0xbb, 0x3e, 0x5f, 0xba, 0x26, 0xca, 0x69, 0xec, 0x2f, 0x5b, 0x5d, 0x9d, 0xad, 0x20, 0xcc, 0x9d, 0xa7, 0x11, 0x38, 0x3a, 0x9d, 0xbe, 0x34, 0xea, 0x3f, 0xa5, 0xa2, 0xaf, 0x75, 0xb4, 0x65, 0x02, 0x62, 0x9a, 0xd5, 0x4d, 0xd8, 0xb7, 0xd7, 0x3a, 0x8a, 0xbb, 0x06, 0xa3, 0xa3, 0xbe, 0x47, 0xd6, 0x50, 0xcc, 0x99, ], shared = [ 0x5f, 0x9d, 0x29, 0xdc, 0x5e, 0x31, 0xa1, 0x63, 0x06, 0x03, 0x56, 0x21, 0x36, 0x69, 0xc8, 0xce, 0x13, 0x2e, 0x22, 0xf5, 0x7c, 0x9a, 0x04, 0xf4, 0x0b, 0xa7, 0xfc, 0xea, 0xd4, 0x93, 0xb4, 0x57, 0xe5, 0x62, 0x1e, 0x76, 0x6c, 0x40, 0xa2, 0xe3, 0xd4, 0xd6, 0xa0, 0x4b, 0x25, 0xe5, 0x33, 0xf1, ], }, //COUNT = 1 testcase { otherpub = [ 0x04, 0x30, 0xf4, 0x3f, 0xcf, 0x2b, 0x6b, 0x00, 0xde, 0x53, 0xf6, 0x24, 0xf1, 0x54, 0x30, 0x90, 0x68, 0x18, 0x39, 0x71, 0x7d, 0x53, 0xc7, 0xc9, 0x55, 0xd1, 0xd6, 0x9e, 0xfa, 0xf0, 0x34, 0x9b, 0x73, 0x63, 0xac, 0xb4, 0x47, 0x24, 0x01, 0x01, 0xcb, 0xb3, 0xaf, 0x66, 0x41, 0xce, 0x4b, 0x88, 0xe0, 0x25, 0xe4, 0x6c, 0x0c, 0x54, 0xf0, 0x16, 0x2a, 0x77, 0xef, 0xcc, 0x27, 0xb6, 0xea, 0x79, 0x20, 0x02, 0xae, 0x2b, 0xa8, 0x27, 0x14, 0x29, 0x9c, 0x86, 0x08, 0x57, 0xa6, 0x81, 0x53, 0xab, 0x62, 0xe5, 0x25, 0xec, 0x05, 0x30, 0xd8, 0x1b, 0x5a, 0xa1, 0x58, 0x97, 0x98, 0x1e, 0x85, 0x87, 0x57, ], priv = [ 0x92, 0x86, 0x0c, 0x21, 0xbd, 0xe0, 0x61, 0x65, 0xf8, 0xe9, 0x00, 0xc6, 0x87, 0xf8, 0xef, 0x0a, 0x05, 0xd1, 0x4f, 0x29, 0x0b, 0x3f, 0x07, 0xd8, 0xb3, 0xa8, 0xcc, 0x64, 0x04, 0x36, 0x6e, 0x5d, 0x51, 0x19, 0xcd, 0x6d, 0x03, 0xfb, 0x12, 0xdc, 0x58, 0xe8, 0x9f, 0x13, 0xdf, 0x9c, 0xd7, 0x83, ], pub = [ 0x04, 0xea, 0x40, 0x18, 0xf5, 0xa3, 0x07, 0xc3, 0x79, 0x18, 0x0b, 0xf6, 0xa6, 0x2f, 0xd2, 0xce, 0xce, 0xeb, 0xee, 0xb7, 0xd4, 0xdf, 0x06, 0x3a, 0x66, 0xfb, 0x83, 0x8a, 0xa3, 0x52, 0x43, 0x41, 0x97, 0x91, 0xf7, 0xe2, 0xc9, 0xd4, 0x80, 0x3c, 0x93, 0x19, 0xaa, 0x0e, 0xb0, 0x3c, 0x41, 0x6b, 0x66, 0x68, 0x83, 0x5a, 0x91, 0x48, 0x4f, 0x05, 0xef, 0x02, 0x82, 0x84, 0xdf, 0x64, 0x36, 0xfb, 0x88, 0xff, 0xeb, 0xab, 0xcd, 0xd6, 0x9a, 0xb0, 0x13, 0x3e, 0x67, 0x35, 0xa1, 0xbc, 0xfb, 0x37, 0x20, 0x3d, 0x10, 0xd3, 0x40, 0xa8, 0x32, 0x8a, 0x7b, 0x68, 0x77, 0x0c, 0xa7, 0x58, 0x78, 0xa1, 0xa6, ], shared = [ 0xa2, 0x37, 0x42, 0xa2, 0xc2, 0x67, 0xd7, 0x42, 0x5f, 0xda, 0x94, 0xb9, 0x3f, 0x93, 0xbb, 0xcc, 0x24, 0x79, 0x1a, 0xc5, 0x1c, 0xd8, 0xfd, 0x50, 0x1a, 0x23, 0x8d, 0x40, 0x81, 0x2f, 0x4c, 0xbf, 0xc5, 0x9a, 0xac, 0x95, 0x20, 0xd7, 0x58, 0xcf, 0x78, 0x9c, 0x76, 0x30, 0x0c, 0x69, 0xd2, 0xff, ], }, //COUNT = 2 testcase { otherpub = [ 0x04, 0x1a, 0xef, 0xbf, 0xa2, 0xc6, 0xc8, 0xc8, 0x55, 0xa1, 0xa2, 0x16, 0x77, 0x45, 0x50, 0xb7, 0x9a, 0x24, 0xcd, 0xa3, 0x76, 0x07, 0xbb, 0x1f, 0x7c, 0xc9, 0x06, 0x65, 0x0e, 0xe4, 0xb3, 0x81, 0x6d, 0x68, 0xf6, 0xa9, 0xc7, 0x5d, 0xa6, 0xe4, 0x24, 0x2c, 0xeb, 0xfb, 0x66, 0x52, 0xf6, 0x51, 0x80, 0x41, 0x9d, 0x28, 0xb7, 0x23, 0xeb, 0xad, 0xb7, 0x65, 0x8f, 0xce, 0xbb, 0x9a, 0xd9, 0xb7, 0xad, 0xea, 0x67, 0x4f, 0x1d, 0xa3, 0xdc, 0x6b, 0x63, 0x97, 0xb5, 0x5d, 0xa0, 0xf6, 0x1a, 0x3e, 0xdd, 0xac, 0xb4, 0xac, 0xdb, 0x14, 0x44, 0x1c, 0xb2, 0x14, 0xb0, 0x4a, 0x08, 0x44, 0xc0, 0x2f, 0xa3, ], priv = [ 0x12, 0xcf, 0x6a, 0x22, 0x3a, 0x72, 0x35, 0x25, 0x43, 0x83, 0x0f, 0x3f, 0x18, 0x53, 0x0d, 0x5c, 0xb3, 0x7f, 0x26, 0x88, 0x0a, 0x0b, 0x29, 0x44, 0x82, 0xc8, 0xa8, 0xef, 0x8a, 0xfa, 0xd0, 0x9a, 0xa7, 0x8b, 0x7d, 0xc2, 0xf2, 0x78, 0x9a, 0x78, 0xc6, 0x6a, 0xf5, 0xd1, 0xcc, 0x55, 0x38, 0x53, ], pub = [ 0x04, 0xfc, 0xfc, 0xea, 0x08, 0x5e, 0x8c, 0xf7, 0x4d, 0x0d, 0xce, 0xd1, 0x62, 0x0b, 0xa8, 0x42, 0x36, 0x94, 0xf9, 0x03, 0xa2, 0x19, 0xbb, 0xf9, 0x01, 0xb0, 0xb5, 0x9d, 0x6a, 0xc8, 0x1b, 0xaa, 0xd3, 0x16, 0xa2, 0x42, 0xba, 0x32, 0xbd, 0xe8, 0x5c, 0xb2, 0x48, 0x11, 0x9b, 0x85, 0x2f, 0xab, 0x66, 0x97, 0x2e, 0x3c, 0x68, 0xc7, 0xab, 0x40, 0x2c, 0x58, 0x36, 0xf2, 0xa1, 0x6e, 0xd4, 0x51, 0xa3, 0x31, 0x20, 0xa7, 0x75, 0x0a, 0x60, 0x39, 0xf3, 0xff, 0x15, 0x38, 0x8e, 0xe6, 0x22, 0xb7, 0x06, 0x5f, 0x71, 0x22, 0xbf, 0x6d, 0x51, 0xae, 0xfb, 0xc2, 0x9b, 0x37, 0xb0, 0x34, 0x04, 0x58, 0x1b, ], shared = [ 0x3d, 0x2e, 0x64, 0x0f, 0x35, 0x08, 0x05, 0xee, 0xd1, 0xff, 0x43, 0xb4, 0x0a, 0x72, 0xb2, 0xab, 0xed, 0x0a, 0x51, 0x8b, 0xce, 0xbe, 0x8f, 0x2d, 0x15, 0xb1, 0x11, 0xb6, 0x77, 0x32, 0x23, 0xda, 0x3c, 0x34, 0x89, 0x12, 0x1d, 0xb1, 0x73, 0xd4, 0x14, 0xb5, 0xbd, 0x5a, 0xd7, 0x15, 0x34, 0x35, ], }, //COUNT = 3 testcase { otherpub = [ 0x04, 0x8b, 0xc0, 0x89, 0x32, 0x6e, 0xc5, 0x5b, 0x9c, 0xf5, 0x9b, 0x34, 0xf0, 0xeb, 0x75, 0x4d, 0x93, 0x59, 0x6c, 0xa2, 0x90, 0xfc, 0xb3, 0x44, 0x4c, 0x83, 0xd4, 0xde, 0x3a, 0x56, 0x07, 0x03, 0x7e, 0xc3, 0x97, 0x68, 0x3f, 0x8c, 0xef, 0x07, 0xea, 0xb2, 0xfe, 0x35, 0x7e, 0xae, 0x36, 0xc4, 0x49, 0xd9, 0xd1, 0x6c, 0xe8, 0xac, 0x85, 0xb3, 0xf1, 0xe9, 0x45, 0x68, 0x52, 0x1a, 0xae, 0x53, 0x4e, 0x67, 0x13, 0x9e, 0x31, 0x0e, 0xc7, 0x26, 0x93, 0x52, 0x6a, 0xa2, 0xe9, 0x27, 0xb5, 0xb3, 0x22, 0xc9, 0x5a, 0x1a, 0x03, 0x3c, 0x22, 0x9c, 0xb6, 0x77, 0x0c, 0x95, 0x7c, 0xd3, 0x14, 0x8d, 0xd7, ], priv = [ 0x8d, 0xd4, 0x80, 0x63, 0xa3, 0xa0, 0x58, 0xc3, 0x34, 0xb5, 0xcc, 0x7a, 0x4c, 0xe0, 0x7d, 0x02, 0xe5, 0xee, 0x6d, 0x8f, 0x1f, 0x3c, 0x51, 0xa1, 0x60, 0x09, 0x62, 0xcb, 0xab, 0x46, 0x26, 0x90, 0xae, 0x3c, 0xd9, 0x74, 0xfb, 0x39, 0xe4, 0x0b, 0x0e, 0x84, 0x3d, 0xaa, 0x0f, 0xd3, 0x2d, 0xe1, ], pub = [ 0x04, 0xe3, 0x8c, 0x98, 0x46, 0x24, 0x81, 0x23, 0xc3, 0x42, 0x18, 0x61, 0xea, 0x4d, 0x32, 0x66, 0x9a, 0x7b, 0x5c, 0x3c, 0x08, 0x37, 0x6a, 0xd2, 0x81, 0x04, 0x39, 0x94, 0x94, 0xc8, 0x4f, 0xf5, 0xef, 0xa3, 0x89, 0x4a, 0xdb, 0x2c, 0x6c, 0xbe, 0x8c, 0x3c, 0x91, 0x3e, 0xf2, 0xee, 0xc5, 0xbd, 0x3c, 0x9f, 0xa8, 0x40, 0x24, 0xa1, 0x02, 0x87, 0x96, 0xdf, 0x84, 0x02, 0x1f, 0x7b, 0x6c, 0x9d, 0x02, 0xf0, 0xf4, 0xbd, 0x1a, 0x61, 0x2a, 0x03, 0xcb, 0xf7, 0x5a, 0x0b, 0xee, 0xa4, 0x3f, 0xef, 0x8a, 0xe8, 0x4b, 0x48, 0xc6, 0x01, 0x72, 0xaa, 0xdf, 0x09, 0xc1, 0xad, 0x01, 0x6d, 0x0b, 0xf3, 0xce, ], shared = [ 0x6a, 0x42, 0xcf, 0xc3, 0x92, 0xab, 0xa0, 0xbf, 0xd3, 0xd1, 0x7b, 0x7c, 0xcf, 0x06, 0x2b, 0x91, 0xfc, 0x09, 0xbb, 0xf3, 0x41, 0x76, 0x12, 0xd0, 0x2a, 0x90, 0xbd, 0xde, 0x62, 0xae, 0x40, 0xc5, 0x4b, 0xb2, 0xe5, 0x6e, 0x16, 0x7d, 0x6b, 0x70, 0xdb, 0x67, 0x00, 0x97, 0xeb, 0x8d, 0xb8, 0x54, ], }, //COUNT = 4 testcase { otherpub = [ 0x04, 0xeb, 0x95, 0x2e, 0x2d, 0x9a, 0xc0, 0xc2, 0x0c, 0x6c, 0xc4, 0x8f, 0xb2, 0x25, 0xc2, 0xad, 0x15, 0x4f, 0x53, 0xc8, 0x75, 0x0b, 0x00, 0x3f, 0xd3, 0xb4, 0xed, 0x8e, 0xd1, 0xdc, 0x0d, 0xef, 0xac, 0x61, 0xbc, 0xdd, 0xe0, 0x2a, 0x2b, 0xcf, 0xee, 0x70, 0x67, 0xd7, 0x5d, 0x34, 0x2e, 0xd2, 0xb0, 0xf1, 0x82, 0x82, 0x05, 0xba, 0xec, 0xe8, 0x2d, 0x1b, 0x26, 0x7d, 0x0d, 0x7f, 0xf2, 0xf9, 0xc9, 0xe1, 0x5b, 0x69, 0xa7, 0x2d, 0xf4, 0x70, 0x58, 0xa9, 0x7f, 0x38, 0x91, 0x00, 0x5d, 0x1f, 0xb3, 0x88, 0x58, 0xf5, 0x60, 0x3d, 0xe8, 0x40, 0xe5, 0x91, 0xdf, 0xa4, 0xf6, 0xe7, 0xd4, 0x89, 0xe1, ], priv = [ 0x84, 0xec, 0xe6, 0xcc, 0x34, 0x29, 0x30, 0x9b, 0xd5, 0xb2, 0x3e, 0x95, 0x97, 0x93, 0xed, 0x2b, 0x11, 0x1e, 0xc5, 0xcb, 0x43, 0xb6, 0xc1, 0x80, 0x85, 0xfc, 0xae, 0xa9, 0xef, 0xa0, 0x68, 0x5d, 0x98, 0xa6, 0x26, 0x2e, 0xe0, 0xd3, 0x30, 0xee, 0x25, 0x0b, 0xc8, 0xa6, 0x7d, 0x0e, 0x73, 0x3f, ], pub = [ 0x04, 0x32, 0x22, 0x06, 0x3a, 0x29, 0x97, 0xb3, 0x02, 0xee, 0x60, 0xee, 0x19, 0x61, 0x10, 0x8f, 0xf4, 0xc7, 0xac, 0xf1, 0xc0, 0xef, 0x1d, 0x5f, 0xb0, 0xd1, 0x64, 0xb8, 0x4b, 0xce, 0x71, 0xc4, 0x31, 0x70, 0x5c, 0xb9, 0xae, 0xa9, 0xa4, 0x5f, 0x5d, 0x73, 0x80, 0x66, 0x55, 0xa0, 0x58, 0xbe, 0xe3, 0xe6, 0x1f, 0xa9, 0xe7, 0xfb, 0xe7, 0xcd, 0x43, 0xab, 0xf9, 0x95, 0x96, 0xa3, 0xd3, 0xa0, 0x39, 0xe9, 0x9f, 0xa9, 0xdc, 0x93, 0xb0, 0xbd, 0xd9, 0xca, 0xd8, 0x19, 0x66, 0xd1, 0x7e, 0xea, 0xf5, 0x57, 0x06, 0x8a, 0xfa, 0x7c, 0x78, 0x46, 0x6b, 0xb5, 0xb2, 0x20, 0x32, 0xd1, 0x10, 0x0f, 0xa6, ], shared = [ 0xce, 0x7b, 0xa4, 0x54, 0xd4, 0x41, 0x27, 0x29, 0xa3, 0x2b, 0xb8, 0x33, 0xa2, 0xd1, 0xfd, 0x2a, 0xe6, 0x12, 0xd4, 0x66, 0x7c, 0x3a, 0x90, 0x0e, 0x06, 0x92, 0x14, 0x81, 0x86, 0x13, 0x44, 0x7d, 0xf8, 0xc6, 0x11, 0xde, 0x66, 0xda, 0x20, 0x0d, 0xb7, 0xc3, 0x75, 0xcf, 0x91, 0x3e, 0x44, 0x05, ], }, //COUNT = 5 testcase { otherpub = [ 0x04, 0x44, 0x1d, 0x02, 0x9e, 0x24, 0x4e, 0xb7, 0x16, 0x8d, 0x64, 0x7d, 0x4d, 0xf5, 0x0d, 0xb5, 0xf4, 0xe4, 0x97, 0x4a, 0xb3, 0xfd, 0xaf, 0x02, 0x2a, 0xff, 0x05, 0x8b, 0x36, 0x95, 0xd0, 0xb8, 0xc8, 0x14, 0xcc, 0x88, 0xda, 0x62, 0x85, 0xdc, 0x6d, 0xf1, 0xac, 0x55, 0xc5, 0x53, 0x88, 0x50, 0x03, 0xe8, 0x02, 0x5a, 0xc2, 0x3a, 0x41, 0xd4, 0xb1, 0xea, 0x2a, 0xa4, 0x6c, 0x50, 0xc6, 0xe4, 0x79, 0x94, 0x6b, 0x59, 0xb6, 0xd7, 0x64, 0x97, 0xcd, 0x92, 0x49, 0x97, 0x7e, 0x0b, 0xfe, 0x4a, 0x62, 0x62, 0x62, 0x2f, 0x13, 0xd4, 0x2a, 0x3c, 0x43, 0xd6, 0x6b, 0xdb, 0xb3, 0x04, 0x03, 0xc3, 0x45, ], priv = [ 0x68, 0xfc, 0xe2, 0x12, 0x1d, 0xc3, 0xa1, 0xe3, 0x7b, 0x10, 0xf1, 0xdd, 0xe3, 0x09, 0xf9, 0xe2, 0xe1, 0x8f, 0xac, 0x47, 0xcd, 0x17, 0x70, 0x95, 0x14, 0x51, 0xc3, 0x48, 0x4c, 0xdb, 0x77, 0xcb, 0x13, 0x6d, 0x00, 0xe7, 0x31, 0x26, 0x05, 0x97, 0xcc, 0x28, 0x59, 0x60, 0x1c, 0x01, 0xa2, 0x5b, ], pub = [ 0x04, 0x86, 0x8b, 0xe0, 0xe6, 0x94, 0x84, 0x18, 0x30, 0xe4, 0x24, 0xd9, 0x13, 0xd8, 0xe7, 0xd8, 0x6b, 0x84, 0xee, 0x10, 0x21, 0xd8, 0x2b, 0x0e, 0xcf, 0x52, 0x3f, 0x09, 0xfe, 0x89, 0xa7, 0x6c, 0x0c, 0x95, 0xc4, 0x9f, 0x2d, 0xfb, 0xcf, 0x82, 0x9c, 0x1e, 0x39, 0x70, 0x9d, 0x55, 0xef, 0xbb, 0x3b, 0x91, 0x95, 0xeb, 0x18, 0x36, 0x75, 0xb4, 0x0f, 0xd9, 0x2f, 0x51, 0xf3, 0x77, 0x13, 0x31, 0x7e, 0x4a, 0x9b, 0x4f, 0x71, 0x5c, 0x8a, 0xb2, 0x2e, 0x07, 0x73, 0xb1, 0xbc, 0x71, 0xd3, 0xa2, 0x19, 0xf0, 0x5b, 0x81, 0x16, 0x07, 0x46, 0x58, 0xee, 0x86, 0xb5, 0x2e, 0x36, 0xf3, 0x89, 0x71, 0x16, ], shared = [ 0xba, 0x69, 0xf0, 0xac, 0xdf, 0x3e, 0x1c, 0xa9, 0x5c, 0xaa, 0xac, 0x4e, 0xca, 0xf4, 0x75, 0xbb, 0xe5, 0x1b, 0x54, 0x77, 0x7e, 0xfc, 0xe0, 0x1c, 0xa3, 0x81, 0xf4, 0x53, 0x70, 0xe4, 0x86, 0xfe, 0x87, 0xf9, 0xf4, 0x19, 0xb1, 0x50, 0xc6, 0x1e, 0x32, 0x9a, 0x28, 0x6d, 0x1a, 0xa2, 0x65, 0xec, ], }, //COUNT = 6 testcase { otherpub = [ 0x04, 0x3d, 0x4e, 0x6b, 0xf0, 0x8a, 0x73, 0x40, 0x4a, 0xcc, 0xc1, 0x62, 0x98, 0x73, 0x46, 0x8e, 0x42, 0x69, 0xe8, 0x2d, 0x90, 0xd8, 0x32, 0xe5, 0x8a, 0xd7, 0x21, 0x42, 0x63, 0x9b, 0x5a, 0x05, 0x6a, 0xd8, 0xd3, 0x5c, 0x66, 0xc6, 0x0e, 0x81, 0x49, 0xfa, 0xc0, 0xc7, 0x97, 0xbc, 0xeb, 0x7c, 0x2f, 0x9b, 0x03, 0x08, 0xdc, 0x7f, 0x0e, 0x6d, 0x29, 0xf8, 0xc2, 0x77, 0xac, 0xbc, 0x65, 0xa2, 0x1e, 0x5a, 0xdb, 0x83, 0xd1, 0x1e, 0x68, 0x73, 0xbc, 0x0a, 0x07, 0xfd, 0xa0, 0x99, 0x7f, 0x48, 0x25, 0x04, 0x60, 0x2f, 0x59, 0xe1, 0x0b, 0xc5, 0xcb, 0x47, 0x6b, 0x83, 0xd0, 0xa4, 0xf7, 0x5e, 0x71, ], priv = [ 0xb1, 0x76, 0x4c, 0x54, 0x89, 0x7e, 0x7a, 0xae, 0x6d, 0xe9, 0xe7, 0x75, 0x1f, 0x2f, 0x37, 0xde, 0x84, 0x92, 0x91, 0xf8, 0x8f, 0x0f, 0x91, 0x09, 0x31, 0x55, 0xb8, 0x58, 0xd1, 0xcc, 0x32, 0xa3, 0xa8, 0x79, 0x80, 0xf7, 0x06, 0xb8, 0x6c, 0xc8, 0x3f, 0x92, 0x7b, 0xdf, 0xdb, 0xea, 0xe0, 0xbd, ], pub = [ 0x04, 0xc3, 0x71, 0x22, 0x2f, 0xea, 0xa6, 0x77, 0x0c, 0x6f, 0x3e, 0xa3, 0xe0, 0xda, 0xc9, 0x74, 0x0d, 0xef, 0x4f, 0xcf, 0x82, 0x13, 0x78, 0xb7, 0xf9, 0x1f, 0xf9, 0x37, 0xc2, 0x1e, 0x04, 0x70, 0xf7, 0x0f, 0x3a, 0x31, 0xd5, 0xc6, 0xb2, 0x91, 0x21, 0x95, 0xf1, 0x09, 0x26, 0x94, 0x2b, 0x48, 0xae, 0x04, 0x7d, 0x6b, 0x4d, 0x76, 0x51, 0x23, 0x56, 0x3f, 0x81, 0x11, 0x6b, 0xc6, 0x65, 0xb7, 0xb8, 0xcc, 0x62, 0x07, 0x83, 0x0d, 0x80, 0x5f, 0xd8, 0x4d, 0xa7, 0xcb, 0x80, 0x5a, 0x65, 0xba, 0xa7, 0xc1, 0x2f, 0xd5, 0x92, 0xd1, 0xb5, 0xb5, 0xe3, 0xe6, 0x5d, 0x96, 0x72, 0xa9, 0xef, 0x76, 0x62, ], shared = [ 0x1a, 0x66, 0x88, 0xee, 0x1d, 0x6e, 0x59, 0x86, 0x5d, 0x8e, 0x3a, 0xda, 0x37, 0x78, 0x1d, 0x36, 0xbb, 0x0c, 0x27, 0x17, 0xee, 0xf9, 0x2e, 0x61, 0x96, 0x4d, 0x39, 0x27, 0xcb, 0x76, 0x5c, 0x29, 0x65, 0xea, 0x80, 0xf7, 0xf6, 0x3e, 0x58, 0xc3, 0x22, 0xba, 0x03, 0x97, 0xfa, 0xea, 0xf6, 0x2b, ], }, //COUNT = 7 testcase { otherpub = [ 0x04, 0xf5, 0xf6, 0xbe, 0xf1, 0xd1, 0x10, 0xda, 0x03, 0xbe, 0x00, 0x17, 0xea, 0xc7, 0x60, 0xcc, 0x34, 0xb2, 0x4d, 0x09, 0x2f, 0x73, 0x6f, 0x23, 0x7b, 0xc7, 0x05, 0x4b, 0x38, 0x65, 0x31, 0x2a, 0x81, 0x3b, 0xcb, 0x62, 0xd2, 0x97, 0xfb, 0x10, 0xa4, 0xf7, 0xab, 0xf5, 0x47, 0x08, 0xfe, 0x2d, 0x3d, 0x06, 0xfd, 0xf8, 0xd7, 0xdc, 0x03, 0x2f, 0x4e, 0x10, 0x01, 0x0b, 0xf1, 0x9c, 0xbf, 0x61, 0x59, 0x32, 0x12, 0x52, 0xff, 0x41, 0x5f, 0xb9, 0x19, 0x20, 0xd4, 0x38, 0xf2, 0x4e, 0x67, 0xe6, 0x0c, 0x2e, 0xb0, 0x46, 0x32, 0x04, 0x67, 0x9f, 0xa3, 0x56, 0xaf, 0x44, 0xce, 0xa9, 0xc9, 0xeb, 0xf5, ], priv = [ 0xf0, 0xf7, 0xa9, 0x6e, 0x70, 0xd9, 0x8f, 0xd5, 0xa3, 0x0a, 0xd6, 0x40, 0x6c, 0xf5, 0x6e, 0xb5, 0xb7, 0x2a, 0x51, 0x0e, 0x9f, 0x19, 0x2f, 0x50, 0xe1, 0xf8, 0x45, 0x24, 0xdb, 0xf3, 0xd2, 0x43, 0x9f, 0x72, 0x87, 0xbb, 0x36, 0xf5, 0xaa, 0x91, 0x2a, 0x79, 0xde, 0xaa, 0xb4, 0xad, 0xea, 0x82, ], pub = [ 0x04, 0x99, 0xc8, 0xc4, 0x1c, 0xb1, 0xab, 0x5e, 0x08, 0x54, 0xa3, 0x46, 0xe4, 0xb0, 0x8a, 0x53, 0x7c, 0x17, 0x06, 0xa6, 0x15, 0x53, 0x38, 0x7c, 0x8d, 0x94, 0x94, 0x3a, 0xb1, 0x51, 0x96, 0xd4, 0x0d, 0xba, 0xa5, 0x5b, 0x82, 0x10, 0xa7, 0x7a, 0x5d, 0x00, 0x91, 0x5f, 0x2c, 0x4e, 0xa6, 0x9e, 0xab, 0x55, 0x31, 0x06, 0x5b, 0xdc, 0xf1, 0x7b, 0xfb, 0x3c, 0xb5, 0x5a, 0x02, 0xe4, 0x1a, 0x57, 0xc7, 0xf6, 0x94, 0xc3, 0x83, 0xad, 0x28, 0x9f, 0x90, 0x0f, 0xbd, 0x65, 0x6c, 0x22, 0x33, 0xa9, 0x3c, 0x92, 0xe9, 0x33, 0xe7, 0xa2, 0x6f, 0x54, 0xcb, 0xb5, 0x6f, 0x0a, 0xd8, 0x75, 0xc5, 0x1b, 0xb0, ], shared = [ 0xd0, 0x6a, 0x56, 0x8b, 0xf2, 0x33, 0x6b, 0x90, 0xcb, 0xac, 0x32, 0x51, 0x61, 0xbe, 0x76, 0x95, 0xea, 0xcb, 0x22, 0x95, 0xf5, 0x99, 0x50, 0x0d, 0x78, 0x7f, 0x07, 0x26, 0x12, 0xac, 0xa3, 0x13, 0xee, 0x5d, 0x87, 0x4f, 0x80, 0x7d, 0xde, 0xf6, 0xc1, 0xf0, 0x23, 0xfe, 0x2b, 0x6e, 0x7c, 0xd0, ], }, //COUNT = 8 testcase { otherpub = [ 0x04, 0x7c, 0xde, 0xc7, 0x7e, 0x07, 0x37, 0xea, 0x37, 0xc6, 0x7b, 0x89, 0xb7, 0x13, 0x7f, 0xe3, 0x88, 0x18, 0x01, 0x0f, 0x44, 0x64, 0x43, 0x8e, 0xe4, 0xd1, 0xd3, 0x5a, 0x0c, 0x48, 0x8c, 0xad, 0x3f, 0xde, 0x2f, 0x37, 0xd0, 0x08, 0x85, 0xd3, 0x6d, 0x3b, 0x79, 0x5b, 0x9f, 0x93, 0xd2, 0x3a, 0x67, 0x28, 0xc4, 0x2e, 0xe8, 0xd6, 0x02, 0x7c, 0x56, 0xcf, 0x97, 0x9b, 0xa4, 0xc2, 0x29, 0xfd, 0xb0, 0x1d, 0x23, 0x49, 0x44, 0xf8, 0xac, 0x43, 0x36, 0x50, 0x11, 0x2c, 0x3c, 0xf0, 0xf0, 0x28, 0x44, 0xe8, 0x88, 0xa3, 0x56, 0x9d, 0xfe, 0xf7, 0x82, 0x8a, 0x8a, 0x88, 0x45, 0x89, 0xaa, 0x05, 0x5e, ], priv = [ 0x9e, 0xfb, 0x87, 0xdd, 0xc6, 0x1d, 0x43, 0xc4, 0x82, 0xba, 0x66, 0xe1, 0xb1, 0x43, 0xae, 0xf6, 0x78, 0xfb, 0xd0, 0xd1, 0xbe, 0xbc, 0x20, 0x00, 0x94, 0x1f, 0xab, 0xe6, 0x77, 0xfe, 0x5b, 0x70, 0x6b, 0xf7, 0x8f, 0xce, 0x36, 0xd1, 0x00, 0xb1, 0x7c, 0xc7, 0x87, 0xea, 0xd7, 0x4b, 0xbc, 0xa2, ], pub = [ 0x04, 0x4c, 0x34, 0xef, 0xee, 0x8f, 0x0c, 0x95, 0x56, 0x5d, 0x20, 0x65, 0xd1, 0xbb, 0xac, 0x2a, 0x2d, 0xd2, 0x5a, 0xe9, 0x64, 0x32, 0x0e, 0xb6, 0xbc, 0xce, 0xdc, 0x5f, 0x3a, 0x9b, 0x42, 0xa8, 0x81, 0xa1, 0xaf, 0xca, 0x1b, 0xb6, 0xb8, 0x80, 0x58, 0x4f, 0xa2, 0x7b, 0x01, 0xc1, 0x93, 0xcd, 0x92, 0xd8, 0xfb, 0x01, 0xdb, 0xf7, 0xcd, 0x0a, 0x38, 0x68, 0xc2, 0x6b, 0x95, 0x1f, 0x39, 0x3c, 0x3c, 0x56, 0xc2, 0x85, 0x8c, 0xee, 0x90, 0x1f, 0x77, 0x93, 0xff, 0x5d, 0x27, 0x19, 0x25, 0xd1, 0x3a, 0x41, 0xf8, 0xe5, 0x24, 0x09, 0xf4, 0xeb, 0xa1, 0x99, 0x0f, 0x33, 0xac, 0xb0, 0xba, 0xc6, 0x69, ], shared = [ 0xbb, 0x3b, 0x1e, 0xda, 0x9c, 0x65, 0x60, 0xd8, 0x2f, 0xf5, 0xbe, 0xe4, 0x03, 0x33, 0x9f, 0x1e, 0x80, 0x34, 0x23, 0x38, 0xa9, 0x91, 0x34, 0x48, 0x53, 0xb5, 0x6b, 0x24, 0xf1, 0x09, 0xa4, 0xd9, 0x4b, 0x92, 0xf6, 0x54, 0xf0, 0x42, 0x5e, 0xdd, 0x4c, 0x20, 0x59, 0x03, 0xd7, 0x58, 0x61, 0x04, ], }, //COUNT = 9 testcase { otherpub = [ 0x04, 0x8e, 0xee, 0xa3, 0xa3, 0x19, 0xc8, 0xdf, 0x99, 0xfb, 0xc2, 0x9c, 0xb5, 0x5f, 0x24, 0x3a, 0x72, 0x0d, 0x95, 0x50, 0x95, 0x15, 0xee, 0x5c, 0xc5, 0x87, 0xa5, 0xc5, 0xae, 0x22, 0xfb, 0xbd, 0x00, 0x9e, 0x62, 0x6d, 0xb3, 0xe9, 0x11, 0xde, 0xf0, 0xb9, 0x9a, 0x4f, 0x7a, 0xe3, 0x04, 0xb1, 0xba, 0x73, 0x87, 0x7d, 0xc9, 0x4d, 0xb9, 0xad, 0xdd, 0xc0, 0xd9, 0xa4, 0xb2, 0x4e, 0x89, 0x76, 0xc2, 0x2d, 0x73, 0xc8, 0x44, 0x37, 0x0e, 0x1e, 0xe8, 0x57, 0xf8, 0xd1, 0xb1, 0x29, 0xa3, 0xbd, 0x5f, 0x63, 0xf4, 0x0c, 0xaf, 0x3b, 0xd0, 0x53, 0x3e, 0x38, 0xa5, 0xf5, 0x77, 0x70, 0x74, 0xff, 0x9e, ], priv = [ 0xd7, 0x87, 0xa5, 0x7f, 0xde, 0x22, 0xec, 0x65, 0x6a, 0x0a, 0x52, 0x5c, 0xf3, 0xc7, 0x38, 0xb3, 0x0d, 0x73, 0xaf, 0x61, 0xe7, 0x43, 0xea, 0x90, 0x89, 0x3e, 0xcb, 0x2d, 0x7b, 0x62, 0x2a, 0xdd, 0x2f, 0x94, 0xee, 0x25, 0xc2, 0x17, 0x14, 0x67, 0xaf, 0xb0, 0x93, 0xf3, 0xf8, 0x4d, 0x00, 0x18, ], pub = [ 0x04, 0x17, 0x15, 0x46, 0x92, 0x3b, 0x87, 0xb2, 0xcb, 0xba, 0xd6, 0x64, 0xf0, 0x1c, 0xe9, 0x32, 0xbf, 0x09, 0xd6, 0xa6, 0x11, 0x81, 0x68, 0x67, 0x84, 0x46, 0xbf, 0xa9, 0xf0, 0x93, 0x86, 0x08, 0xcb, 0x46, 0x67, 0xa9, 0x8f, 0x4e, 0xc8, 0xac, 0x14, 0x62, 0x28, 0x5c, 0x25, 0x08, 0xf7, 0x48, 0x62, 0xfa, 0x41, 0xcb, 0x4d, 0xb6, 0x8a, 0xe7, 0x1f, 0x1f, 0x8a, 0x3e, 0x89, 0x39, 0xdc, 0x52, 0xc2, 0xde, 0xc6, 0x1a, 0x83, 0xc9, 0x83, 0xbe, 0xb2, 0xa0, 0x2b, 0xaf, 0x29, 0xec, 0x49, 0x27, 0x80, 0x88, 0x88, 0x2e, 0xd0, 0xcf, 0x56, 0xc7, 0x4b, 0x5c, 0x17, 0x3b, 0x55, 0x2c, 0xcf, 0x63, 0xcf, ], shared = [ 0x1e, 0x97, 0xb6, 0x0a, 0xdd, 0x7c, 0xb3, 0x5c, 0x74, 0x03, 0xdd, 0x88, 0x4c, 0x0a, 0x75, 0x79, 0x5b, 0x76, 0x83, 0xff, 0xf8, 0xb4, 0x9f, 0x9d, 0x86, 0x72, 0xa8, 0x20, 0x6b, 0xfd, 0xcf, 0x0a, 0x10, 0x6b, 0x87, 0x68, 0xf9, 0x83, 0x25, 0x8c, 0x74, 0x16, 0x74, 0x22, 0xe4, 0x4e, 0x4d, 0x14, ], }, //COUNT = 10 testcase { otherpub = [ 0x04, 0xa7, 0x21, 0xf6, 0xa2, 0xd4, 0x52, 0x74, 0x11, 0x83, 0x4b, 0x13, 0xd4, 0xd3, 0xa3, 0x3c, 0x29, 0xbe, 0xb8, 0x3a, 0xb7, 0x68, 0x24, 0x65, 0xc6, 0xcb, 0xaf, 0x66, 0x24, 0xac, 0xa6, 0xea, 0x58, 0xc3, 0x0e, 0xb0, 0xf2, 0x9d, 0xd8, 0x42, 0x88, 0x66, 0x95, 0x40, 0x0d, 0x72, 0x54, 0xf2, 0x0f, 0x14, 0xba, 0x6e, 0x26, 0x35, 0x51, 0x09, 0xad, 0x35, 0x12, 0x93, 0x66, 0xd5, 0xe3, 0xa6, 0x40, 0xae, 0x79, 0x85, 0x05, 0xa7, 0xfa, 0x55, 0xa9, 0x6a, 0x36, 0xb5, 0xda, 0xd3, 0x3d, 0xe0, 0x04, 0x74, 0xf6, 0x67, 0x0f, 0x52, 0x22, 0x14, 0xdd, 0x79, 0x52, 0x14, 0x0a, 0xb0, 0xa7, 0xeb, 0x68, ], priv = [ 0x83, 0xd7, 0x0f, 0x7b, 0x16, 0x4d, 0x9f, 0x4c, 0x22, 0x7c, 0x76, 0x70, 0x46, 0xb2, 0x0e, 0xb3, 0x4d, 0xfc, 0x77, 0x8f, 0x53, 0x87, 0xe3, 0x2e, 0x83, 0x4b, 0x1e, 0x6d, 0xae, 0xc2, 0x0e, 0xdb, 0x8c, 0xa5, 0xbb, 0x41, 0x92, 0x09, 0x3f, 0x54, 0x3b, 0x68, 0xe6, 0xae, 0xb7, 0xce, 0x78, 0x8b, ], pub = [ 0x04, 0x57, 0xcd, 0x77, 0x0f, 0x3b, 0xbc, 0xbe, 0x0c, 0x78, 0xc7, 0x70, 0xea, 0xb0, 0xb1, 0x69, 0xbc, 0x45, 0xe1, 0x39, 0xf8, 0x63, 0x78, 0xff, 0xae, 0x1c, 0x2b, 0x16, 0x96, 0x67, 0x27, 0xc2, 0xf2, 0xeb, 0x72, 0x45, 0x72, 0xb8, 0xf3, 0xeb, 0x22, 0x8d, 0x13, 0x0d, 0xb4, 0xff, 0x86, 0x2c, 0x63, 0x7e, 0xc5, 0xc8, 0x81, 0x3b, 0x68, 0x55, 0x58, 0xd8, 0x3e, 0x92, 0x4f, 0x14, 0xbc, 0x71, 0x9f, 0x6e, 0xb7, 0xae, 0x0c, 0xbb, 0x2c, 0x47, 0x42, 0x27, 0xc5, 0xbd, 0xa8, 0x86, 0x37, 0xa4, 0xf2, 0x6c, 0x64, 0x81, 0x79, 0x29, 0xaf, 0x99, 0x95, 0x92, 0xda, 0x6f, 0x78, 0x74, 0x90, 0x33, 0x2f, ], shared = [ 0x10, 0x23, 0x47, 0x88, 0x40, 0xe5, 0x47, 0x75, 0xbf, 0xc6, 0x92, 0x93, 0xa3, 0xcf, 0x97, 0xf5, 0xbc, 0x91, 0x47, 0x26, 0x45, 0x5c, 0x66, 0x53, 0x8e, 0xb5, 0x62, 0x3e, 0x21, 0x8f, 0xee, 0xf7, 0xdf, 0x4b, 0xef, 0xa2, 0x3e, 0x09, 0xd7, 0x71, 0x45, 0xad, 0x57, 0x7d, 0xb3, 0x2b, 0x41, 0xf9, ], }, //COUNT = 11 testcase { otherpub = [ 0x04, 0xd8, 0x82, 0xa8, 0x50, 0x5c, 0x2d, 0x5c, 0xb9, 0xb8, 0x85, 0x1f, 0xc6, 0x76, 0x67, 0x7b, 0xb0, 0x08, 0x76, 0x81, 0xad, 0x53, 0xfa, 0xce, 0xba, 0x17, 0x38, 0x28, 0x6b, 0x45, 0x82, 0x75, 0x61, 0xe7, 0xda, 0x37, 0xb8, 0x80, 0x27, 0x6c, 0x65, 0x6c, 0xfc, 0x38, 0xb3, 0x2a, 0xde, 0x84, 0x7e, 0x34, 0xb3, 0x14, 0xbd, 0xc1, 0x34, 0x57, 0x56, 0x54, 0x57, 0x3c, 0xff, 0xaf, 0x40, 0x44, 0x5d, 0xa2, 0xe6, 0xaa, 0xf9, 0x87, 0xf7, 0xe9, 0x13, 0xcd, 0x4c, 0x30, 0x91, 0x52, 0x30, 0x58, 0x98, 0x4a, 0x25, 0xd8, 0xf2, 0x1d, 0xa8, 0x32, 0x61, 0x92, 0x45, 0x6c, 0x6a, 0x0f, 0xa5, 0xf6, 0x0c, ], priv = [ 0x8f, 0x55, 0x8e, 0x05, 0x81, 0x8b, 0x88, 0xed, 0x38, 0x3d, 0x5f, 0xca, 0x96, 0x2e, 0x53, 0x41, 0x3d, 0xb1, 0xa0, 0xe4, 0x63, 0x7e, 0xda, 0x19, 0x4f, 0x76, 0x19, 0x44, 0xcb, 0xea, 0x11, 0x4a, 0xb9, 0xd5, 0xda, 0x17, 0x5a, 0x7d, 0x57, 0x88, 0x25, 0x50, 0xb0, 0xe4, 0x32, 0xf3, 0x95, 0xa9, ], pub = [ 0x04, 0x9a, 0x2f, 0x57, 0xf4, 0x86, 0x7c, 0xe7, 0x53, 0xd7, 0x2b, 0x0d, 0x95, 0x19, 0x5d, 0xf6, 0xf9, 0x6c, 0x1f, 0xae, 0x93, 0x4f, 0x60, 0x2e, 0xfd, 0x7b, 0x6a, 0x54, 0x58, 0x2f, 0x55, 0x6c, 0xfa, 0x53, 0x9d, 0x89, 0x00, 0x5c, 0xa2, 0xed, 0xac, 0x08, 0xad, 0x9b, 0x72, 0xdd, 0x1f, 0x60, 0xba, 0xd9, 0xb9, 0x4e, 0xe8, 0x2d, 0xa9, 0xcc, 0x60, 0x1f, 0x34, 0x60, 0x44, 0x99, 0x8b, 0xa3, 0x87, 0xae, 0xe5, 0x64, 0x04, 0xdc, 0x6e, 0xcc, 0x8a, 0xb2, 0xb5, 0x90, 0x44, 0x33, 0x19, 0xd0, 0xb2, 0xb6, 0x17, 0x6f, 0x9d, 0x0e, 0xac, 0x2d, 0x44, 0x67, 0x8e, 0xd5, 0x61, 0x60, 0x7d, 0x09, 0xa9, ], shared = [ 0x6a, 0xd6, 0xb9, 0xdc, 0x8a, 0x6c, 0xf0, 0xd3, 0x69, 0x1c, 0x50, 0x1c, 0xbb, 0x96, 0x78, 0x67, 0xf6, 0xe4, 0xbb, 0xb7, 0x64, 0xb6, 0x0d, 0xbf, 0xf8, 0xfc, 0xff, 0x3e, 0xd4, 0x2d, 0xbb, 0xa3, 0x9d, 0x63, 0xcf, 0x32, 0x5b, 0x4b, 0x40, 0x78, 0x85, 0x84, 0x95, 0xdd, 0xee, 0x75, 0xf9, 0x54, ], }, //COUNT = 12 testcase { otherpub = [ 0x04, 0x81, 0x5c, 0x9d, 0x77, 0x3d, 0xbf, 0x5f, 0xb6, 0xa1, 0xb8, 0x67, 0x99, 0x96, 0x62, 0x47, 0xf4, 0x00, 0x6a, 0x23, 0xc9, 0x2e, 0x68, 0xc5, 0x5e, 0x9e, 0xaa, 0x99, 0x8b, 0x17, 0xd8, 0x83, 0x2d, 0xd4, 0xd8, 0x4d, 0x92, 0x7d, 0x83, 0x1d, 0x4f, 0x68, 0xda, 0xc6, 0x7c, 0x64, 0x88, 0x21, 0x9f, 0xe7, 0x92, 0x69, 0x94, 0x8b, 0x26, 0x11, 0x48, 0x45, 0x60, 0xfd, 0x49, 0x0f, 0xee, 0xc8, 0x87, 0xcb, 0x55, 0xef, 0x99, 0xa4, 0xb5, 0x24, 0x88, 0x0f, 0xa7, 0x49, 0x9d, 0x6a, 0x07, 0x28, 0x3a, 0xae, 0x2a, 0xfa, 0x33, 0xfe, 0xab, 0x97, 0xde, 0xca, 0x40, 0xbc, 0x60, 0x6c, 0x4d, 0x87, 0x64, ], priv = [ 0x0f, 0x5d, 0xee, 0x0a, 0xff, 0xa7, 0xbb, 0xf2, 0x39, 0xd5, 0xdf, 0xf3, 0x29, 0x87, 0xeb, 0xb7, 0xcf, 0x84, 0xfc, 0xce, 0xed, 0x64, 0x3e, 0x1d, 0x3c, 0x62, 0xd0, 0xb3, 0x35, 0x2a, 0xec, 0x23, 0xb6, 0xe5, 0xac, 0x7f, 0xa4, 0x10, 0x5c, 0x8c, 0xb2, 0x61, 0x26, 0xad, 0x2d, 0x18, 0x92, 0xcb, ], pub = [ 0x04, 0x23, 0x34, 0x6b, 0xdf, 0xbc, 0x9d, 0x7c, 0x7c, 0x73, 0x6e, 0x02, 0xbd, 0xf6, 0x07, 0x67, 0x1f, 0xf6, 0x08, 0x2f, 0xdd, 0x27, 0x33, 0x4a, 0x8b, 0xc7, 0x5f, 0x3b, 0x23, 0x68, 0x1e, 0xbe, 0x61, 0x4d, 0x05, 0x97, 0xdd, 0x61, 0x4f, 0xae, 0x58, 0x67, 0x7c, 0x83, 0x5a, 0x9f, 0x0b, 0x27, 0x3b, 0x82, 0xba, 0x36, 0x29, 0x0d, 0x2f, 0x94, 0xdb, 0x41, 0x47, 0x9e, 0xb4, 0x5a, 0xb4, 0xea, 0xf6, 0x79, 0x28, 0xa2, 0x31, 0x51, 0x38, 0xd5, 0x9e, 0xec, 0xc9, 0xb5, 0x28, 0x5d, 0xfd, 0xdd, 0x67, 0x14, 0xf7, 0x75, 0x57, 0x21, 0x6e, 0xa4, 0x4c, 0xc6, 0xfc, 0x11, 0x9d, 0x82, 0x43, 0xef, 0xaf, ], shared = [ 0xcc, 0x9e, 0x06, 0x35, 0x66, 0xd4, 0x6b, 0x35, 0x7b, 0x3f, 0xca, 0xe2, 0x18, 0x27, 0x37, 0x73, 0x31, 0xe5, 0xe2, 0x90, 0xa3, 0x6e, 0x60, 0xcd, 0x7c, 0x39, 0x10, 0x2b, 0x82, 0x8a, 0xe0, 0xb9, 0x18, 0xdc, 0x5a, 0x02, 0x21, 0x6b, 0x07, 0xfe, 0x6f, 0x19, 0x58, 0xd8, 0x34, 0xe4, 0x24, 0x37, ], }, //COUNT = 13 testcase { otherpub = [ 0x04, 0x1c, 0x0e, 0xed, 0xa7, 0xa2, 0xbe, 0x00, 0x0c, 0x5b, 0xdc, 0xda, 0x04, 0x78, 0xae, 0xd4, 0xdb, 0x73, 0x3d, 0x2a, 0x9e, 0x34, 0x12, 0x24, 0x37, 0x91, 0x23, 0xad, 0x84, 0x70, 0x30, 0xf2, 0x9e, 0x3b, 0x16, 0x8f, 0xa1, 0x8e, 0x89, 0xa3, 0xc0, 0xfb, 0xa2, 0xa6, 0xce, 0x1c, 0x28, 0xfc, 0x3b, 0xec, 0x8c, 0x1c, 0x83, 0xc1, 0x18, 0xc4, 0xdb, 0xea, 0x94, 0x27, 0x18, 0x69, 0xf2, 0xd8, 0x68, 0xeb, 0x65, 0xe8, 0xb4, 0x4e, 0x21, 0xe6, 0xf1, 0x4b, 0x0f, 0x4d, 0x9b, 0x38, 0xc0, 0x68, 0xda, 0xef, 0xa2, 0x71, 0x14, 0x25, 0x5b, 0x9a, 0x41, 0xd0, 0x84, 0xcc, 0x4a, 0x1a, 0xd8, 0x54, 0x56, ], priv = [ 0x03, 0x7b, 0x63, 0x3b, 0x5b, 0x8b, 0xa8, 0x57, 0xc0, 0xfc, 0x85, 0x65, 0x68, 0x68, 0x23, 0x2e, 0x2f, 0xeb, 0xf5, 0x95, 0x78, 0x71, 0x83, 0x91, 0xb8, 0x1d, 0xa8, 0x54, 0x1a, 0x00, 0xbf, 0xe5, 0x3c, 0x30, 0xae, 0x04, 0x15, 0x18, 0x47, 0xf2, 0x74, 0x99, 0xf8, 0xd7, 0xab, 0xad, 0x8c, 0xf4, ], pub = [ 0x04, 0x88, 0x78, 0xac, 0x8a, 0x94, 0x7f, 0x7d, 0x5c, 0xb2, 0xb4, 0x7a, 0xad, 0x24, 0xfb, 0xb8, 0x21, 0x0d, 0x86, 0x12, 0x65, 0x85, 0x39, 0x9a, 0x28, 0x71, 0xf8, 0x4a, 0xa9, 0xc5, 0xfd, 0xe3, 0x07, 0x4a, 0xe5, 0x40, 0xc6, 0xbf, 0x82, 0x27, 0x5c, 0xa8, 0x22, 0xd0, 0xfe, 0xb8, 0x62, 0xbc, 0x74, 0x63, 0x2f, 0x5c, 0xd2, 0xf9, 0x00, 0xc2, 0x71, 0x1c, 0x32, 0xf8, 0x93, 0x07, 0x28, 0xeb, 0x64, 0x7d, 0x31, 0xed, 0xd8, 0xd6, 0x50, 0xf9, 0x65, 0x4e, 0x7d, 0x33, 0xe5, 0xed, 0x1b, 0x47, 0x54, 0x89, 0xd0, 0x8d, 0xaa, 0x30, 0xd8, 0xcb, 0xcb, 0xa6, 0xbf, 0xc3, 0xb6, 0x0d, 0x9b, 0x5a, 0x37, ], shared = [ 0xde, 0xff, 0x7f, 0x03, 0xbd, 0x09, 0x86, 0x5b, 0xaf, 0x94, 0x5e, 0x73, 0xed, 0xff, 0x6d, 0x51, 0x22, 0xc0, 0x3f, 0xb5, 0x61, 0xdb, 0x87, 0xde, 0xc8, 0x66, 0x2e, 0x09, 0xbe, 0xd4, 0x34, 0x0b, 0x28, 0xa9, 0xef, 0xe1, 0x18, 0x33, 0x7b, 0xb7, 0xd3, 0xd4, 0xf7, 0xf5, 0x68, 0x63, 0x5f, 0xf9, ], }, //COUNT = 14 testcase { otherpub = [ 0x04, 0xc9, 0x5c, 0x18, 0x5e, 0x25, 0x6b, 0xf9, 0x97, 0xf3, 0x0b, 0x31, 0x15, 0x48, 0xae, 0x7f, 0x76, 0x8a, 0x38, 0xde, 0xe4, 0x3e, 0xee, 0xef, 0x43, 0x08, 0x3f, 0x30, 0x77, 0xbe, 0x70, 0xe2, 0xbf, 0x39, 0xac, 0x1d, 0x4d, 0xaf, 0x36, 0x0c, 0x51, 0x4c, 0x8c, 0x6b, 0xe6, 0x23, 0x44, 0x3d, 0x1a, 0x3e, 0x63, 0xa6, 0x63, 0xea, 0xf7, 0x5d, 0x8a, 0x76, 0x5a, 0xb2, 0xb9, 0xa3, 0x55, 0x13, 0xd7, 0x93, 0x3f, 0xa5, 0xe2, 0x64, 0x20, 0xa5, 0x24, 0x45, 0x50, 0xec, 0x6c, 0x3b, 0x6f, 0x03, 0x3b, 0x96, 0xdb, 0x2a, 0xca, 0x3d, 0x6a, 0xc6, 0xaa, 0xb0, 0x52, 0xce, 0x92, 0x95, 0x95, 0xae, 0xa5, ], priv = [ 0xe3, 0xd0, 0x71, 0x06, 0xbe, 0xdc, 0xc0, 0x96, 0xe7, 0xd9, 0x16, 0x30, 0xff, 0xd3, 0x09, 0x4d, 0xf2, 0xc7, 0x85, 0x9d, 0xb8, 0xd7, 0xed, 0xbb, 0x2e, 0x37, 0xb4, 0xac, 0x47, 0xf4, 0x29, 0xa6, 0x37, 0xd0, 0x6a, 0x67, 0xd2, 0xfb, 0xa3, 0x38, 0x38, 0x76, 0x4e, 0xf2, 0x03, 0x46, 0x49, 0x91, ], pub = [ 0x04, 0xe7, 0x4a, 0x1a, 0x2b, 0x85, 0xf1, 0xcb, 0xf8, 0xdb, 0xbd, 0xf0, 0x50, 0xcf, 0x1a, 0xff, 0x8a, 0xcb, 0x02, 0xfd, 0xa2, 0xfb, 0x65, 0x91, 0xf9, 0xd3, 0xcf, 0xe4, 0xe7, 0x9d, 0x0a, 0xe9, 0x38, 0xa9, 0xc1, 0x48, 0x3e, 0x7b, 0x75, 0xf8, 0xdb, 0x24, 0x50, 0x5d, 0x65, 0x06, 0x5c, 0xdb, 0x18, 0x17, 0x73, 0xee, 0x59, 0x18, 0x22, 0xf7, 0xab, 0xaa, 0x85, 0x6a, 0x1a, 0x60, 0xbc, 0x0a, 0x52, 0x03, 0x54, 0x8d, 0xbd, 0x1c, 0xb5, 0x02, 0x54, 0x66, 0xef, 0xf8, 0x48, 0x1b, 0xd0, 0x76, 0x14, 0xea, 0xa0, 0x4a, 0x16, 0xc3, 0xdb, 0x76, 0x90, 0x59, 0x13, 0xe9, 0x72, 0xa5, 0xb6, 0xb5, 0x9d, ], shared = [ 0xc8, 0xb1, 0x03, 0x8f, 0x73, 0x5a, 0xd3, 0xbb, 0x3e, 0x46, 0x37, 0xc3, 0xe4, 0x7e, 0xab, 0x48, 0x76, 0x37, 0x91, 0x1a, 0x6b, 0x79, 0x50, 0xa4, 0xe4, 0x61, 0x94, 0x83, 0x29, 0xd3, 0x92, 0x3b, 0x96, 0x9e, 0x5d, 0xb6, 0x63, 0x67, 0x56, 0x23, 0x61, 0x1a, 0x45, 0x7f, 0xcd, 0xa3, 0x5a, 0x71, ], }, //COUNT = 15 testcase { otherpub = [ 0x04, 0x34, 0x97, 0x23, 0x8a, 0x7e, 0x6a, 0xd1, 0x66, 0xdf, 0x2d, 0xac, 0x03, 0x9a, 0xa4, 0xda, 0xc8, 0xd1, 0x7a, 0xa9, 0x25, 0xe7, 0xc7, 0x63, 0x1e, 0xb3, 0xb5, 0x6e, 0x3a, 0xaa, 0x1c, 0x54, 0x5f, 0xcd, 0x54, 0xd2, 0xe5, 0x98, 0x58, 0x07, 0x91, 0x0f, 0xb2, 0x02, 0xb1, 0xfc, 0x19, 0x1d, 0x2a, 0xa4, 0x9e, 0x5c, 0x48, 0x7d, 0xcc, 0x7a, 0xa4, 0x0a, 0x8f, 0x23, 0x4c, 0x97, 0x94, 0x46, 0x04, 0x0d, 0x91, 0x74, 0xe3, 0xad, 0x35, 0x7d, 0x40, 0x4d, 0x77, 0x65, 0x18, 0x31, 0x95, 0xae, 0xd3, 0xf9, 0x13, 0x64, 0x1b, 0x90, 0xc8, 0x1a, 0x30, 0x6e, 0xbf, 0x0d, 0x89, 0x13, 0x86, 0x13, 0x16, ], priv = [ 0xf3, 0xf9, 0xb0, 0xc6, 0x5a, 0x49, 0xa5, 0x06, 0x63, 0x2c, 0x8a, 0x45, 0xb1, 0x0f, 0x66, 0xb5, 0x31, 0x6f, 0x9e, 0xeb, 0x06, 0xfa, 0xe2, 0x18, 0xf2, 0xda, 0x62, 0x33, 0x3f, 0x99, 0x90, 0x51, 0x17, 0xb1, 0x41, 0xc7, 0x60, 0xe8, 0x97, 0x4e, 0xfc, 0x4a, 0xf1, 0x05, 0x70, 0x63, 0x57, 0x91, ], pub = [ 0x04, 0xa4, 0xad, 0x77, 0xaa, 0x7d, 0x86, 0xe5, 0x36, 0x11, 0x18, 0xa6, 0xb9, 0x21, 0x71, 0x0c, 0x82, 0x07, 0x21, 0x21, 0x07, 0x12, 0xf4, 0xc3, 0x47, 0x98, 0x5f, 0xde, 0xe5, 0x8a, 0xa4, 0xef, 0xfa, 0x1e, 0x28, 0xbe, 0x80, 0xa1, 0x7b, 0x12, 0x0b, 0x13, 0x9f, 0x96, 0x30, 0x0f, 0x89, 0xb4, 0x9b, 0x1d, 0xdf, 0x22, 0xe0, 0x7e, 0x03, 0xf1, 0x56, 0x0d, 0x8f, 0x45, 0xa4, 0x80, 0x09, 0x45, 0x60, 0xdb, 0xa9, 0xfa, 0xe7, 0xf9, 0x53, 0x11, 0x30, 0xc1, 0xb5, 0x7e, 0xbb, 0x95, 0x98, 0x24, 0x96, 0x52, 0x4f, 0x31, 0xd3, 0x79, 0x77, 0x93, 0x39, 0x6f, 0xa8, 0x23, 0xf2, 0x2b, 0xdb, 0x43, 0x28, ], shared = [ 0xd3, 0x37, 0xea, 0xa3, 0x2b, 0x9f, 0x71, 0x6b, 0x87, 0x47, 0xb0, 0x05, 0xb9, 0x7a, 0x55, 0x3c, 0x59, 0xda, 0xb0, 0xc5, 0x1d, 0xf4, 0x1a, 0x2d, 0x49, 0x03, 0x9c, 0xda, 0xe7, 0x05, 0xaa, 0x75, 0xc7, 0xb9, 0xe7, 0xbc, 0x0b, 0x6a, 0x0e, 0x8c, 0x57, 0x8c, 0x90, 0x2b, 0xc4, 0xff, 0xf2, 0x3e, ], }, //COUNT = 16 testcase { otherpub = [ 0x04, 0x90, 0xa3, 0x47, 0x37, 0xd4, 0x5b, 0x1a, 0xa6, 0x5f, 0x74, 0xe0, 0xbd, 0x06, 0x59, 0xbc, 0x11, 0x8f, 0x8e, 0x4b, 0x77, 0x4b, 0x76, 0x19, 0x44, 0xff, 0xa6, 0x57, 0x3c, 0x6d, 0xf4, 0xf4, 0x1d, 0xec, 0x0d, 0x11, 0xb6, 0x97, 0xab, 0xd9, 0x34, 0xd3, 0x90, 0x87, 0x1d, 0x4b, 0x45, 0x32, 0x40, 0x9b, 0x59, 0x07, 0x19, 0xbb, 0x33, 0x07, 0xc1, 0x49, 0xa7, 0x81, 0x7b, 0xe3, 0x55, 0xd6, 0x84, 0x89, 0x3a, 0x30, 0x77, 0x64, 0xb5, 0x12, 0xee, 0xff, 0xe0, 0x7c, 0xb6, 0x99, 0xed, 0xb5, 0xa6, 0xff, 0xbf, 0x8d, 0x60, 0x32, 0xe6, 0xc7, 0x9d, 0x5e, 0x93, 0xe9, 0x42, 0x12, 0xc2, 0xaa, 0x4e, ], priv = [ 0x59, 0xfc, 0xe7, 0xfa, 0xd7, 0xde, 0x28, 0xba, 0xc0, 0x23, 0x06, 0x90, 0xc9, 0x57, 0x10, 0xc7, 0x20, 0xe5, 0x28, 0xf9, 0xa4, 0xe5, 0x4d, 0x3a, 0x6a, 0x8c, 0xd5, 0xfc, 0x5c, 0x5f, 0x21, 0x63, 0x70, 0x31, 0xce, 0x1c, 0x5b, 0x4e, 0x3d, 0x39, 0x64, 0x7d, 0x8d, 0xcb, 0x9b, 0x79, 0x46, 0x64, ], pub = [ 0x04, 0x9c, 0x43, 0xbf, 0x97, 0x1e, 0xdf, 0x09, 0x40, 0x28, 0x76, 0xee, 0x74, 0x20, 0x95, 0x38, 0x1f, 0x78, 0xb1, 0xbd, 0x3a, 0xa3, 0x9b, 0x51, 0x32, 0xaf, 0x75, 0xdb, 0xfe, 0x7e, 0x98, 0xbd, 0x78, 0xbd, 0xe1, 0x0f, 0xe2, 0xe9, 0x03, 0xc2, 0xb6, 0x37, 0x9e, 0x1d, 0xee, 0xe1, 0x75, 0xa1, 0xb0, 0xa6, 0xc5, 0x8e, 0xce, 0xa5, 0xa4, 0x77, 0xbb, 0x01, 0xbd, 0x54, 0x3b, 0x33, 0x9f, 0x1c, 0xc4, 0x9f, 0x13, 0x71, 0xa2, 0xcd, 0xa4, 0xd4, 0x6e, 0xb4, 0xe5, 0x3e, 0x25, 0x05, 0x97, 0x94, 0x23, 0x51, 0xa9, 0x96, 0x65, 0xa1, 0x22, 0xff, 0xea, 0x9b, 0xde, 0x06, 0x36, 0xc3, 0x75, 0xda, 0xf2, ], shared = [ 0x32, 0xd2, 0x92, 0xb6, 0x95, 0xa4, 0x48, 0x8e, 0x42, 0xa7, 0xb7, 0x92, 0x2e, 0x1a, 0xe5, 0x37, 0xd7, 0x6a, 0x3d, 0x21, 0xa0, 0xb2, 0xe3, 0x68, 0x75, 0xf6, 0x0e, 0x9f, 0x6d, 0x3e, 0x87, 0x79, 0xc2, 0xaf, 0xb3, 0xa4, 0x13, 0xb9, 0xdd, 0x79, 0xae, 0x18, 0xe7, 0x0b, 0x47, 0xd3, 0x37, 0xc1, ], }, //COUNT = 17 testcase { otherpub = [ 0x04, 0xdd, 0xa5, 0x46, 0xac, 0xfc, 0x8f, 0x90, 0x3d, 0x11, 0xe2, 0xe3, 0x92, 0x06, 0x69, 0x63, 0x6d, 0x44, 0xb2, 0x06, 0x8a, 0xeb, 0x66, 0xff, 0x07, 0xaa, 0x26, 0x6f, 0x00, 0x30, 0xe1, 0x53, 0x5b, 0x0e, 0xd0, 0x20, 0x3c, 0xb8, 0xa4, 0x60, 0xac, 0x99, 0x0f, 0x13, 0x94, 0xfa, 0xf2, 0x2f, 0x1d, 0x15, 0xbb, 0xb2, 0x59, 0x79, 0x13, 0x03, 0x5f, 0xaa, 0xdf, 0x41, 0x34, 0x76, 0xf4, 0xc7, 0x0f, 0x72, 0x79, 0x76, 0x9a, 0x40, 0xc9, 0x86, 0xf4, 0x70, 0xc4, 0x27, 0xb4, 0xee, 0x49, 0x62, 0xab, 0xdf, 0x81, 0x73, 0xbb, 0xad, 0x81, 0x87, 0x47, 0x72, 0x92, 0x5f, 0xd3, 0x2f, 0x0b, 0x15, 0x9f, ], priv = [ 0x3e, 0x49, 0xfb, 0xf9, 0x50, 0xa4, 0x24, 0xc5, 0xd8, 0x02, 0x28, 0xdc, 0x4b, 0xc3, 0x5e, 0x9f, 0x6c, 0x6c, 0x0c, 0x1d, 0x04, 0x44, 0x09, 0x98, 0xda, 0x0a, 0x60, 0x9a, 0x87, 0x75, 0x75, 0xdb, 0xe4, 0x37, 0xd6, 0xa5, 0xce, 0xda, 0xa2, 0xdd, 0xd2, 0xa1, 0xa1, 0x7f, 0xd1, 0x12, 0xad, 0xed, ], pub = [ 0x04, 0x5a, 0x94, 0x95, 0x94, 0x22, 0x8b, 0x1a, 0x3d, 0x6f, 0x59, 0x9e, 0xb3, 0xdb, 0x0d, 0x06, 0x07, 0x0f, 0xbc, 0x55, 0x1c, 0x65, 0x7b, 0x58, 0x23, 0x4b, 0xa1, 0x64, 0xce, 0x3f, 0xe4, 0x15, 0xfa, 0x5f, 0x3e, 0xb8, 0x23, 0xc0, 0x8d, 0xc2, 0x9b, 0x8c, 0x34, 0x12, 0x19, 0xc7, 0x7b, 0x6b, 0x3d, 0x2b, 0xaa, 0xd4, 0x47, 0xc8, 0xc2, 0x90, 0xcf, 0xed, 0x25, 0xed, 0xd9, 0x03, 0x1c, 0x41, 0xd0, 0xb7, 0x69, 0x21, 0x45, 0x73, 0x27, 0xf4, 0x2d, 0xb3, 0x11, 0x22, 0xb8, 0x1f, 0x33, 0x7b, 0xbf, 0x0b, 0x10, 0x39, 0xec, 0x83, 0x0c, 0xe9, 0x06, 0x1a, 0x37, 0x61, 0x95, 0x3c, 0x75, 0xe4, 0xa8, ], shared = [ 0x12, 0x20, 0xe7, 0xe6, 0xca, 0xd7, 0xb2, 0x5d, 0xf9, 0x8e, 0x5b, 0xbd, 0xcc, 0x6c, 0x0b, 0x65, 0xca, 0x6c, 0x2a, 0x50, 0xc5, 0xff, 0x6c, 0x41, 0xdc, 0xa7, 0x1e, 0x47, 0x56, 0x46, 0xfd, 0x48, 0x96, 0x15, 0x97, 0x9c, 0xa9, 0x2f, 0xb4, 0x38, 0x9a, 0xea, 0xde, 0xfd, 0xe7, 0x9a, 0x24, 0xf1, ], }, //COUNT = 18 testcase { otherpub = [ 0x04, 0x78, 0x8b, 0xe2, 0x33, 0x6c, 0x52, 0xf4, 0x45, 0x4d, 0x63, 0xee, 0x94, 0x4b, 0x1e, 0x49, 0xbf, 0xb6, 0x19, 0xa0, 0x83, 0x71, 0x04, 0x8e, 0x6d, 0xa9, 0x2e, 0x58, 0x4e, 0xae, 0x70, 0xbd, 0xe1, 0xf1, 0x71, 0xc4, 0xdf, 0x37, 0x8b, 0xd1, 0xf3, 0xc0, 0xab, 0x03, 0x04, 0x8a, 0x23, 0x78, 0x02, 0x46, 0x73, 0xeb, 0xd8, 0xdb, 0x60, 0x4e, 0xaf, 0x41, 0x71, 0x17, 0x48, 0xba, 0xb2, 0x96, 0x8a, 0x23, 0xca, 0x44, 0x76, 0xce, 0x14, 0x4e, 0x72, 0x82, 0x47, 0xf0, 0x8a, 0xf7, 0x52, 0x92, 0x91, 0x57, 0xb5, 0x83, 0x0f, 0x1e, 0x26, 0x06, 0x74, 0x66, 0xbd, 0xfa, 0x8b, 0x65, 0x14, 0x5a, 0x33, ], priv = [ 0x50, 0xcc, 0xc1, 0xf7, 0x07, 0x6e, 0x92, 0xf4, 0x63, 0x8e, 0x85, 0xf2, 0xdb, 0x98, 0xe0, 0xb4, 0x83, 0xe6, 0xe2, 0x20, 0x4c, 0x92, 0xbd, 0xd4, 0x40, 0xa6, 0xde, 0xea, 0x04, 0xe3, 0x7a, 0x07, 0xc6, 0xe7, 0x27, 0x91, 0xc1, 0x90, 0xad, 0x4e, 0x4e, 0x86, 0xe0, 0x1e, 0xfb, 0xa8, 0x42, 0x69, ], pub = [ 0x04, 0x75, 0x6c, 0x07, 0xdf, 0x0c, 0xe3, 0x2c, 0x83, 0x9d, 0xac, 0x9f, 0xb4, 0x73, 0x3c, 0x9c, 0x28, 0xb7, 0x01, 0x13, 0xa6, 0x76, 0xa7, 0x05, 0x7c, 0x38, 0xd2, 0x23, 0xf2, 0x2a, 0x3a, 0x90, 0x95, 0xa8, 0xd5, 0x64, 0x65, 0x3a, 0xf5, 0x28, 0xe0, 0x4c, 0x7e, 0x18, 0x24, 0xbe, 0x4a, 0x65, 0x12, 0x17, 0xc2, 0xce, 0x69, 0x62, 0xcb, 0xd2, 0xa2, 0xe0, 0x66, 0x29, 0x7b, 0x39, 0xd5, 0x7d, 0xd9, 0xbb, 0x46, 0x80, 0xf0, 0x19, 0x1d, 0x39, 0x0f, 0x70, 0xb4, 0xe4, 0x61, 0x41, 0x9b, 0x29, 0x72, 0xce, 0x68, 0xad, 0x46, 0x12, 0x7f, 0xdd, 0xa6, 0xc3, 0x91, 0x95, 0x77, 0x4e, 0xa8, 0x6d, 0xf3, ], shared = [ 0x79, 0x3b, 0xb9, 0xcd, 0x22, 0xa9, 0x3c, 0xf4, 0x68, 0xfa, 0xf8, 0x04, 0xa3, 0x8d, 0x12, 0xb7, 0x8c, 0xb1, 0x21, 0x89, 0xec, 0x67, 0x9d, 0xdd, 0x2e, 0x9a, 0xa2, 0x1f, 0xa9, 0xa5, 0xa0, 0xb0, 0x49, 0xab, 0x16, 0xa2, 0x35, 0x74, 0xfe, 0x04, 0xc1, 0xc3, 0xc0, 0x23, 0x43, 0xb9, 0x1b, 0xeb, ], }, //COUNT = 19 testcase { otherpub = [ 0x04, 0xd0, 0x9b, 0xb8, 0x22, 0xeb, 0x99, 0xe3, 0x80, 0x60, 0x95, 0x47, 0x47, 0xc8, 0x2b, 0xb3, 0x27, 0x8c, 0xf9, 0x6b, 0xbf, 0x36, 0xfe, 0xce, 0x34, 0x00, 0xf4, 0xc8, 0x73, 0x83, 0x8a, 0x40, 0xc1, 0x35, 0xeb, 0x3b, 0xab, 0xb9, 0x29, 0x3b, 0xd1, 0x00, 0x1b, 0xf3, 0xec, 0xde, 0xe7, 0xbf, 0x26, 0xd4, 0x16, 0xdb, 0x6e, 0x1b, 0x87, 0xbb, 0xb7, 0x42, 0x77, 0x88, 0xa3, 0xb6, 0xc7, 0xa7, 0xab, 0x2c, 0x16, 0x5b, 0x1e, 0x36, 0x6f, 0x96, 0x08, 0xdf, 0x51, 0x20, 0x37, 0x58, 0x4f, 0x21, 0x3a, 0x64, 0x8d, 0x47, 0xf1, 0x6a, 0xc3, 0x26, 0xe1, 0x9a, 0xae, 0x97, 0x2f, 0x63, 0xfd, 0x76, 0xc9, ], priv = [ 0x06, 0xf1, 0x32, 0xb7, 0x1f, 0x74, 0xd8, 0x7b, 0xf9, 0x98, 0x57, 0xe1, 0xe4, 0x35, 0x0a, 0x59, 0x4e, 0x5f, 0xe3, 0x55, 0x33, 0xb8, 0x88, 0x55, 0x2c, 0xec, 0xcb, 0xc0, 0xd8, 0x92, 0x3c, 0x90, 0x2e, 0x36, 0x14, 0x1d, 0x76, 0x91, 0xe2, 0x86, 0x31, 0xb8, 0xbc, 0x9b, 0xaf, 0xe5, 0xe0, 0x64, ], pub = [ 0x04, 0x2a, 0x3c, 0xc6, 0xb8, 0xff, 0x5c, 0xde, 0x92, 0x6e, 0x7e, 0x3a, 0x18, 0x9a, 0x1b, 0xd0, 0x29, 0xc9, 0xb5, 0x86, 0x35, 0x1a, 0xf8, 0x83, 0x8f, 0x4f, 0x20, 0x1c, 0xb8, 0xf4, 0xb7, 0x0e, 0xf3, 0xb0, 0xda, 0x06, 0xd3, 0x52, 0xc8, 0x0f, 0xc2, 0x6b, 0xaf, 0x8f, 0x42, 0xb7, 0x84, 0x45, 0x9e, 0xbf, 0x99, 0x85, 0x96, 0x01, 0x76, 0xda, 0x6d, 0x23, 0xc7, 0x45, 0x2a, 0x29, 0x54, 0xff, 0xcb, 0xbc, 0xb2, 0x42, 0x49, 0xb4, 0x30, 0x19, 0xa2, 0xa0, 0x23, 0xe0, 0xb3, 0xda, 0xbd, 0x46, 0x1f, 0x19, 0xad, 0x3e, 0x77, 0x5c, 0x36, 0x4f, 0x3f, 0x11, 0xad, 0x49, 0xf3, 0x09, 0x94, 0x00, 0xd3, ], shared = [ 0x01, 0x2d, 0x19, 0x1c, 0xf7, 0x40, 0x4a, 0x52, 0x36, 0x78, 0xc6, 0xfc, 0x07, 0x5d, 0xe8, 0x28, 0x5b, 0x24, 0x37, 0x20, 0xa9, 0x03, 0x04, 0x77, 0x08, 0xbb, 0x33, 0xe5, 0x01, 0xe0, 0xdb, 0xee, 0x5b, 0xcc, 0x40, 0xd7, 0xc3, 0xef, 0x6c, 0x6d, 0xa3, 0x9e, 0xa2, 0x4d, 0x83, 0x0d, 0xa1, 0xe8, ], }, //COUNT = 20 testcase { otherpub = [ 0x04, 0x13, 0x74, 0x12, 0x62, 0xed, 0xe5, 0x86, 0x1d, 0xad, 0x71, 0x06, 0x3d, 0xfd, 0x20, 0x4b, 0x91, 0xea, 0x1d, 0x3b, 0x7c, 0x63, 0x1d, 0xf6, 0x8e, 0xb9, 0x49, 0x96, 0x95, 0x27, 0xd7, 0x9a, 0x1d, 0xc5, 0x92, 0x95, 0xef, 0x7d, 0x2b, 0xca, 0x67, 0x43, 0xe8, 0xcd, 0x77, 0xb0, 0x4d, 0x1b, 0x58, 0x0b, 0xaa, 0xea, 0xdc, 0x7e, 0x19, 0xd7, 0x4a, 0x8a, 0x04, 0x45, 0x1a, 0x13, 0x5f, 0x1b, 0xe1, 0xb0, 0x2f, 0xe2, 0x99, 0xf9, 0xdc, 0x00, 0xbf, 0xdf, 0x20, 0x1e, 0x83, 0xd9, 0x95, 0xc6, 0x95, 0x0b, 0xcc, 0x1c, 0xb8, 0x9d, 0x6f, 0x7b, 0x30, 0xbf, 0x54, 0x65, 0x6b, 0x9a, 0x4d, 0xa5, 0x86, ], priv = [ 0x12, 0x04, 0x8e, 0xbb, 0x43, 0x31, 0xec, 0x19, 0xa1, 0xe2, 0x3f, 0x1a, 0x2c, 0x77, 0x3b, 0x66, 0x4c, 0xcf, 0xe9, 0x0a, 0x28, 0xbf, 0xb8, 0x46, 0xfc, 0x12, 0xf8, 0x1d, 0xff, 0x44, 0xb7, 0x44, 0x3c, 0x77, 0x64, 0x71, 0x64, 0xbf, 0x1e, 0x9e, 0x67, 0xfd, 0x2c, 0x07, 0xa6, 0x76, 0x62, 0x41, ], pub = [ 0x04, 0xbc, 0x18, 0x83, 0x6b, 0xc7, 0xa9, 0xfd, 0xf5, 0x4b, 0x53, 0x52, 0xf3, 0x7d, 0x75, 0x28, 0xab, 0x8f, 0xa8, 0xec, 0x54, 0x4a, 0x8c, 0x61, 0x80, 0x51, 0x1c, 0xbf, 0xdd, 0x49, 0xcc, 0xe3, 0x77, 0xc3, 0x9e, 0x34, 0xc0, 0x31, 0xb5, 0x24, 0x0d, 0xc9, 0x98, 0x05, 0x03, 0xed, 0x2f, 0x26, 0x2c, 0x80, 0x86, 0xcb, 0xe3, 0x38, 0x19, 0x10, 0x80, 0xf0, 0xb7, 0xa1, 0x6c, 0x7a, 0xfc, 0x4c, 0x7b, 0x03, 0x26, 0xf9, 0xac, 0x66, 0xf5, 0x85, 0x52, 0xef, 0x4b, 0xb9, 0xd2, 0x4d, 0xe3, 0x42, 0x9e, 0xd5, 0xd3, 0x27, 0x7e, 0xd5, 0x8f, 0xcf, 0x48, 0xf2, 0xb5, 0xf6, 0x13, 0x26, 0xbe, 0xc6, 0xc6, ], shared = [ 0xad, 0x0f, 0xd3, 0xdd, 0xff, 0xe8, 0x88, 0x4b, 0x92, 0x63, 0xf3, 0xc1, 0x5f, 0xe1, 0xf0, 0x7f, 0x2a, 0x5a, 0x22, 0xff, 0xdc, 0x7e, 0x96, 0x70, 0x85, 0xee, 0xa4, 0x5f, 0x0c, 0xd9, 0x59, 0xf2, 0x0f, 0x18, 0xf5, 0x22, 0x76, 0x3e, 0x28, 0xbc, 0xc9, 0x25, 0xe4, 0x96, 0xa5, 0x2d, 0xda, 0x98, ], }, //COUNT = 21 testcase { otherpub = [ 0x04, 0x9e, 0x22, 0xcb, 0xc1, 0x86, 0x57, 0xf5, 0x16, 0xa8, 0x64, 0xb3, 0x7b, 0x78, 0x33, 0x48, 0xb6, 0x6f, 0x1a, 0xa9, 0x62, 0x6c, 0xd6, 0x31, 0xf4, 0xfa, 0x1b, 0xd3, 0x2a, 0xd8, 0x8c, 0xf1, 0x1d, 0xb5, 0x20, 0x57, 0xc6, 0x60, 0x86, 0x0d, 0x39, 0xd1, 0x1f, 0xbf, 0x02, 0x4f, 0xab, 0xd4, 0x44, 0x6b, 0x0d, 0x53, 0xc7, 0x96, 0x81, 0xc2, 0x81, 0x16, 0xdf, 0x71, 0xe9, 0xce, 0xe7, 0x4f, 0xd5, 0x6c, 0x8b, 0x7f, 0x04, 0xb3, 0x9f, 0x11, 0x98, 0xcc, 0x72, 0x28, 0x4e, 0x98, 0xbe, 0x95, 0x62, 0xe3, 0x59, 0x26, 0xfb, 0x4f, 0x48, 0xa9, 0xfb, 0xec, 0xaf, 0xe7, 0x29, 0x30, 0x9e, 0x8b, 0x6f, ], priv = [ 0x34, 0xd6, 0x1a, 0x69, 0x9c, 0xa5, 0x76, 0x16, 0x9f, 0xcd, 0xc0, 0xcc, 0x7e, 0x44, 0xe4, 0xe1, 0x22, 0x1d, 0xb0, 0xfe, 0x63, 0xd1, 0x68, 0x50, 0xc8, 0x10, 0x40, 0x29, 0xf7, 0xd4, 0x84, 0x49, 0x71, 0x4b, 0x98, 0x84, 0x32, 0x8c, 0xae, 0x18, 0x99, 0x78, 0x75, 0x4a, 0xb4, 0x60, 0xb4, 0x86, ], pub = [ 0x04, 0x86, 0x7f, 0x81, 0x10, 0x4c, 0xcd, 0x6b, 0x16, 0x3a, 0x79, 0x02, 0xb6, 0x70, 0xef, 0x40, 0x60, 0x42, 0xcb, 0x0c, 0xce, 0x7d, 0xcd, 0xc6, 0x3d, 0x1d, 0xfc, 0x91, 0xb2, 0xc4, 0x0e, 0x3c, 0xdf, 0x75, 0x95, 0x83, 0x4b, 0xf9, 0xec, 0xeb, 0x79, 0x84, 0x9f, 0x16, 0x36, 0xfc, 0x84, 0x62, 0xfc, 0x9d, 0x4b, 0xde, 0x8e, 0x87, 0x5e, 0xc4, 0x96, 0x97, 0xd2, 0x58, 0xd1, 0xd5, 0x94, 0x65, 0xf8, 0x43, 0x1c, 0x6f, 0x55, 0x31, 0xe1, 0xc5, 0x9e, 0x9f, 0x9e, 0xbe, 0x3c, 0xf1, 0x64, 0xa8, 0xd9, 0xce, 0x10, 0xa1, 0x2f, 0x19, 0x79, 0x28, 0x3a, 0x95, 0x9b, 0xad, 0x24, 0x4d, 0xd8, 0x38, 0x63, ], shared = [ 0xdc, 0x4c, 0xa3, 0x92, 0xdc, 0x15, 0xe2, 0x01, 0x85, 0xf2, 0xc6, 0xa8, 0xea, 0x5e, 0xc3, 0x1d, 0xfc, 0x96, 0xf5, 0x61, 0x53, 0xa4, 0x73, 0x94, 0xb3, 0x07, 0x2b, 0x13, 0xd0, 0x01, 0x5f, 0x5d, 0x4a, 0xe1, 0x3b, 0xeb, 0x3b, 0xed, 0x54, 0xd6, 0x58, 0x48, 0xf9, 0xb8, 0x38, 0x3e, 0x6c, 0x95, ], }, //COUNT = 22 testcase { otherpub = [ 0x04, 0x2d, 0xb5, 0xda, 0x5f, 0x94, 0x0e, 0xaa, 0x88, 0x4f, 0x4d, 0xb5, 0xec, 0x21, 0x39, 0xb0, 0x46, 0x9f, 0x38, 0xe4, 0xe6, 0xfb, 0xbc, 0xc5, 0x2d, 0xf1, 0x5c, 0x0f, 0x7c, 0xf7, 0xfc, 0xb1, 0x80, 0x8c, 0x74, 0x97, 0x64, 0xb6, 0xbe, 0x85, 0xd2, 0xfd, 0xc5, 0xb1, 0x6f, 0x58, 0xad, 0x5d, 0xc0, 0x22, 0xe8, 0xb0, 0x2d, 0xcf, 0x33, 0xe1, 0xb5, 0xa0, 0x83, 0x84, 0x95, 0x45, 0xf8, 0x4a, 0xd5, 0xe4, 0x3f, 0x77, 0xcb, 0x71, 0x54, 0x6d, 0xbb, 0xac, 0x0d, 0x11, 0xbd, 0xb2, 0xee, 0x20, 0x2e, 0x9d, 0x38, 0x72, 0xe8, 0xd0, 0x28, 0xc0, 0x89, 0x90, 0x74, 0x6c, 0x5e, 0x1d, 0xde, 0x99, 0x89, ], priv = [ 0xdc, 0x60, 0xfa, 0x87, 0x36, 0xd7, 0x02, 0x13, 0x5f, 0xf1, 0x6a, 0xab, 0x99, 0x2b, 0xb8, 0x8e, 0xac, 0x39, 0x7f, 0x59, 0x72, 0x45, 0x6c, 0x72, 0xec, 0x44, 0x73, 0x74, 0xd0, 0xd8, 0xce, 0x61, 0x15, 0x38, 0x31, 0xbf, 0xc8, 0x6a, 0xd5, 0xa6, 0xeb, 0x5b, 0x60, 0xbf, 0xb9, 0x6a, 0x86, 0x2c, ], pub = [ 0x04, 0xb6, 0x9b, 0xee, 0xde, 0x85, 0xd0, 0xf8, 0x29, 0xfe, 0xc1, 0xb8, 0x93, 0xcc, 0xb9, 0xc3, 0xe0, 0x52, 0xff, 0x69, 0x2e, 0x13, 0xb9, 0x74, 0x53, 0x7b, 0xc5, 0xb0, 0xf9, 0xfe, 0xaf, 0x7b, 0x22, 0xe8, 0x4f, 0x03, 0x23, 0x16, 0x29, 0xb2, 0x48, 0x66, 0xbd, 0xb4, 0xb8, 0xcf, 0x90, 0x89, 0x14, 0x66, 0xf8, 0x5e, 0x2b, 0xfc, 0xab, 0xa2, 0x84, 0x32, 0x85, 0xb0, 0xe1, 0x4e, 0xbc, 0x07, 0xef, 0x7d, 0xaf, 0xff, 0x8b, 0x42, 0x44, 0x16, 0xfe, 0xe6, 0x47, 0xb5, 0x98, 0x97, 0xb6, 0x19, 0xf2, 0x0e, 0xed, 0x95, 0xa6, 0x32, 0xe6, 0xa4, 0x20, 0x6b, 0xf7, 0xda, 0x42, 0x9c, 0x04, 0xc5, 0x60, ], shared = [ 0xd7, 0x65, 0xb2, 0x08, 0x11, 0x2d, 0x2b, 0x9e, 0xd5, 0xad, 0x10, 0xc4, 0x04, 0x6e, 0x2e, 0x3b, 0x0d, 0xbf, 0x57, 0xc4, 0x69, 0x32, 0x95, 0x19, 0xe2, 0x39, 0xac, 0x28, 0xb2, 0x5c, 0x7d, 0x85, 0x2b, 0xf7, 0x57, 0xd5, 0xde, 0x0e, 0xe2, 0x71, 0xca, 0xdd, 0x02, 0x1d, 0x86, 0xcf, 0xd3, 0x47, ], }, //COUNT = 23 testcase { otherpub = [ 0x04, 0x32, 0x96, 0x47, 0xba, 0xa3, 0x54, 0x22, 0x4e, 0xb4, 0x41, 0x48, 0x29, 0xc5, 0x36, 0x8c, 0x82, 0xd7, 0x89, 0x3b, 0x39, 0x80, 0x4e, 0x08, 0xcb, 0xb2, 0x18, 0x0f, 0x45, 0x9b, 0xef, 0xc4, 0xb3, 0x47, 0xa3, 0x89, 0xa7, 0x0c, 0x91, 0xa2, 0x3b, 0xd9, 0xd3, 0x0c, 0x83, 0xbe, 0x52, 0x95, 0xd3, 0xcc, 0x8f, 0x61, 0x92, 0x3f, 0xad, 0x2a, 0xa8, 0xe5, 0x05, 0xd6, 0xcf, 0xa1, 0x26, 0xb9, 0xfa, 0xbd, 0x5a, 0xf9, 0xdc, 0xe2, 0x90, 0xb7, 0x56, 0x60, 0xef, 0x06, 0xd1, 0xca, 0xa7, 0x36, 0x81, 0xd0, 0x60, 0x89, 0xc3, 0x3b, 0xc4, 0x24, 0x6b, 0x3a, 0xa3, 0x0d, 0xbc, 0xd2, 0x43, 0x5b, 0x12, ], priv = [ 0x6f, 0xa6, 0xa1, 0xc7, 0x04, 0x73, 0x09, 0x87, 0xaa, 0x63, 0x4b, 0x05, 0x16, 0xa8, 0x26, 0xab, 0xa8, 0xc6, 0xd6, 0x41, 0x1d, 0x3a, 0x4c, 0x89, 0x77, 0x2d, 0x7a, 0x62, 0x61, 0x02, 0x56, 0xa2, 0xe2, 0xf2, 0x89, 0xf5, 0xc3, 0x44, 0x0b, 0x0e, 0xc1, 0xe7, 0x0f, 0xa3, 0x39, 0xe2, 0x51, 0xce, ], pub = [ 0x04, 0x53, 0xde, 0x1f, 0xc1, 0x32, 0x8e, 0x8d, 0xe1, 0x4a, 0xec, 0xab, 0x29, 0xad, 0x8a, 0x40, 0xd6, 0xb1, 0x37, 0x68, 0xf8, 0x6f, 0x7d, 0x29, 0x84, 0x33, 0xd2, 0x0f, 0xec, 0x79, 0x1f, 0x86, 0xf8, 0xbc, 0x73, 0xf3, 0x58, 0x09, 0x8b, 0x25, 0x6a, 0x29, 0x8b, 0xb4, 0x88, 0xde, 0x25, 0x7b, 0xf4, 0xac, 0x28, 0x94, 0x4f, 0xd2, 0x7f, 0x17, 0xb8, 0x29, 0x46, 0xc0, 0x4c, 0x66, 0xc4, 0x1f, 0x00, 0x53, 0xd3, 0x69, 0x2f, 0x27, 0x5d, 0xa5, 0x5c, 0xd8, 0x73, 0x9a, 0x95, 0xbd, 0x8c, 0xd3, 0xaf, 0x2f, 0x96, 0xe4, 0xde, 0x95, 0x9e, 0xa8, 0x34, 0x4d, 0x89, 0x45, 0x37, 0x59, 0x05, 0x85, 0x8b, ], shared = [ 0xd3, 0x77, 0x88, 0x50, 0xae, 0xb5, 0x88, 0x04, 0xfb, 0xe9, 0xdf, 0xe6, 0xf3, 0x8b, 0x9f, 0xa8, 0xe2, 0x0c, 0x2c, 0xa4, 0xe0, 0xde, 0xc3, 0x35, 0xaa, 0xfc, 0xec, 0xa0, 0x33, 0x3e, 0x3f, 0x24, 0x90, 0xb5, 0x3c, 0x0c, 0x1a, 0x14, 0xa8, 0x31, 0xba, 0x37, 0xc4, 0xb9, 0xd7, 0x4b, 0xe0, 0xf2, ], }, //COUNT = 24 testcase { otherpub = [ 0x04, 0x29, 0xd8, 0xa3, 0x6d, 0x22, 0x20, 0x0a, 0x75, 0xb7, 0xae, 0xa1, 0xbb, 0x47, 0xcd, 0xfc, 0xb1, 0xb7, 0xfd, 0x66, 0xde, 0x96, 0x70, 0x41, 0x43, 0x47, 0x28, 0xab, 0x5d, 0x53, 0x3a, 0x06, 0x0d, 0xf7, 0x32, 0x13, 0x06, 0x00, 0xfe, 0x6f, 0x75, 0x85, 0x2a, 0x87, 0x1f, 0xb2, 0x93, 0x8e, 0x39, 0xe1, 0x9b, 0x53, 0xdb, 0x52, 0x83, 0x95, 0xde, 0x89, 0x7a, 0x45, 0x10, 0x89, 0x67, 0x71, 0x5e, 0xb8, 0xcb, 0x55, 0xc3, 0xfc, 0xbf, 0x23, 0x37, 0x93, 0x72, 0xc0, 0x87, 0x3a, 0x05, 0x8d, 0x57, 0x54, 0x4b, 0x10, 0x2e, 0xcc, 0xe7, 0x22, 0xb2, 0xcc, 0xab, 0xb1, 0xa6, 0x03, 0x77, 0x4f, 0xd5, ], priv = [ 0x74, 0xad, 0x83, 0x86, 0xc1, 0xcb, 0x2c, 0xa0, 0xfc, 0xde, 0xb3, 0x1e, 0x08, 0x69, 0xbb, 0x3f, 0x48, 0xc0, 0x36, 0xaf, 0xe2, 0xef, 0x11, 0x0c, 0xa3, 0x02, 0xbc, 0x8b, 0x91, 0x0f, 0x62, 0x1c, 0x9f, 0xcc, 0x54, 0xce, 0xc3, 0x2b, 0xb8, 0x9e, 0xc7, 0xca, 0xa8, 0x4c, 0x7b, 0x8e, 0x54, 0xa8, ], pub = [ 0x04, 0x27, 0xa3, 0xe8, 0x3c, 0xfb, 0x9d, 0x51, 0x22, 0xe7, 0x31, 0x29, 0xd8, 0x01, 0x61, 0x58, 0x57, 0xda, 0x7c, 0xc0, 0x89, 0xcc, 0xcc, 0x9c, 0x54, 0xab, 0x30, 0x32, 0xa1, 0x9e, 0x0a, 0x0a, 0x9f, 0x67, 0x73, 0x46, 0xe3, 0x7f, 0x08, 0xa0, 0xb3, 0xed, 0x8d, 0xa6, 0xe5, 0xdd, 0x69, 0x10, 0x63, 0x8d, 0x60, 0xe4, 0x4a, 0xa5, 0xe0, 0xfd, 0x30, 0xc9, 0x18, 0x45, 0x67, 0x96, 0xaf, 0x37, 0xf0, 0xe4, 0x19, 0x57, 0x90, 0x16, 0x45, 0xe5, 0xc5, 0x96, 0xc6, 0xd9, 0x89, 0xf5, 0x85, 0x9b, 0x03, 0xa0, 0xbd, 0x7d, 0x1f, 0x4e, 0x77, 0x93, 0x6f, 0xff, 0x3c, 0x74, 0xd2, 0x04, 0xe5, 0x38, 0x8e, ], shared = [ 0x81, 0xe1, 0xe7, 0x15, 0x75, 0xbb, 0x45, 0x05, 0x49, 0x8d, 0xe0, 0x97, 0x35, 0x01, 0x86, 0x43, 0x0a, 0x62, 0x42, 0xfa, 0x6c, 0x57, 0xb8, 0x5a, 0x5f, 0x98, 0x4a, 0x23, 0x37, 0x11, 0x23, 0xd2, 0xd1, 0x42, 0x4e, 0xef, 0xbf, 0x80, 0x42, 0x58, 0x39, 0x2b, 0xc7, 0x23, 0xe4, 0xef, 0x1e, 0x35, ], }, ]; const p521cases = [ //COUNT = 0 testcase { otherpub = [ 0x04, 0x00, 0x68, 0x5a, 0x48, 0xe8, 0x6c, 0x79, 0xf0, 0xf0, 0x87, 0x5f, 0x7b, 0xc1, 0x8d, 0x25, 0xeb, 0x5f, 0xc8, 0xc0, 0xb0, 0x7e, 0x5d, 0xa4, 0xf4, 0x37, 0x0f, 0x3a, 0x94, 0x90, 0x34, 0x08, 0x54, 0x33, 0x4b, 0x1e, 0x1b, 0x87, 0xfa, 0x39, 0x54, 0x64, 0xc6, 0x06, 0x26, 0x12, 0x4a, 0x4e, 0x70, 0xd0, 0xf7, 0x85, 0x60, 0x1d, 0x37, 0xc0, 0x98, 0x70, 0xeb, 0xf1, 0x76, 0x66, 0x68, 0x77, 0xa2, 0x04, 0x6d, 0x01, 0xba, 0x52, 0xc5, 0x6f, 0xc8, 0x77, 0x6d, 0x9e, 0x8f, 0x5d, 0xb4, 0xf0, 0xcc, 0x27, 0x63, 0x6d, 0x0b, 0x74, 0x1b, 0xbe, 0x05, 0x40, 0x06, 0x97, 0x94, 0x2e, 0x80, 0xb7, 0x39, 0x88, 0x4a, 0x83, 0xbd, 0xe9, 0x9e, 0x0f, 0x67, 0x16, 0x93, 0x9e, 0x63, 0x2b, 0xc8, 0x98, 0x6f, 0xa1, 0x8d, 0xcc, 0xd4, 0x43, 0xa3, 0x48, 0xb6, 0xc3, 0xe5, 0x22, 0x49, 0x79, 0x55, 0xa4, 0xf3, 0xc3, 0x02, 0xf6, 0x76, ], priv = [ 0x01, 0x7e, 0xec, 0xc0, 0x7a, 0xb4, 0xb3, 0x29, 0x06, 0x8f, 0xba, 0x65, 0xe5, 0x6a, 0x1f, 0x88, 0x90, 0xaa, 0x93, 0x5e, 0x57, 0x13, 0x4a, 0xe0, 0xff, 0xcc, 0xe8, 0x02, 0x73, 0x51, 0x51, 0xf4, 0xea, 0xc6, 0x56, 0x4f, 0x6e, 0xe9, 0x97, 0x4c, 0x5e, 0x68, 0x87, 0xa1, 0xfe, 0xfe, 0xe5, 0x74, 0x3a, 0xe2, 0x24, 0x1b, 0xfe, 0xb9, 0x5d, 0x5c, 0xe3, 0x1d, 0xdc, 0xb6, 0xf9, 0xed, 0xb4, 0xd6, 0xfc, 0x47, ], pub = [ 0x04, 0x00, 0x60, 0x2f, 0x9d, 0x0c, 0xf9, 0xe5, 0x26, 0xb2, 0x9e, 0x22, 0x38, 0x1c, 0x20, 0x3c, 0x48, 0xa8, 0x86, 0xc2, 0xb0, 0x67, 0x30, 0x33, 0x36, 0x63, 0x14, 0xf1, 0xff, 0xbc, 0xba, 0x24, 0x0b, 0xa4, 0x2f, 0x4e, 0xf3, 0x8a, 0x76, 0x17, 0x46, 0x35, 0xf9, 0x1e, 0x6b, 0x4e, 0xd3, 0x42, 0x75, 0xeb, 0x01, 0xc8, 0x46, 0x7d, 0x05, 0xca, 0x80, 0x31, 0x5b, 0xf1, 0xa7, 0xbb, 0xd9, 0x45, 0xf5, 0x50, 0xa5, 0x01, 0xb7, 0xc8, 0x5f, 0x26, 0xf5, 0xd4, 0xb2, 0xd7, 0x35, 0x5c, 0xf6, 0xb0, 0x21, 0x17, 0x65, 0x99, 0x43, 0x76, 0x2b, 0x6d, 0x1d, 0xb5, 0xab, 0x4f, 0x1d, 0xbc, 0x44, 0xce, 0x7b, 0x29, 0x46, 0xeb, 0x6c, 0x7d, 0xe3, 0x42, 0x96, 0x28, 0x93, 0xfd, 0x38, 0x7d, 0x1b, 0x73, 0xd7, 0xa8, 0x67, 0x2d, 0x1f, 0x23, 0x69, 0x61, 0x17, 0x0b, 0x7e, 0xb3, 0x57, 0x99, 0x53, 0xee, 0x5c, 0xdc, 0x88, 0xcd, 0x2d, ], shared = [ 0x00, 0x5f, 0xc7, 0x04, 0x77, 0xc3, 0xe6, 0x3b, 0xc3, 0x95, 0x4b, 0xd0, 0xdf, 0x3e, 0xa0, 0xd1, 0xf4, 0x1e, 0xe2, 0x17, 0x46, 0xed, 0x95, 0xfc, 0x5e, 0x1f, 0xdf, 0x90, 0x93, 0x0d, 0x5e, 0x13, 0x66, 0x72, 0xd7, 0x2c, 0xc7, 0x70, 0x74, 0x2d, 0x17, 0x11, 0xc3, 0xc3, 0xa4, 0xc3, 0x34, 0xa0, 0xad, 0x97, 0x59, 0x43, 0x6a, 0x4d, 0x3c, 0x5b, 0xf6, 0xe7, 0x4b, 0x95, 0x78, 0xfa, 0xc1, 0x48, 0xc8, 0x31, ], }, //COUNT = 1 testcase { otherpub = [ 0x04, 0x01, 0xdf, 0x27, 0x7c, 0x15, 0x21, 0x08, 0x34, 0x9b, 0xc3, 0x4d, 0x53, 0x9e, 0xe0, 0xcf, 0x06, 0xb2, 0x4f, 0x5d, 0x35, 0x00, 0x67, 0x7b, 0x44, 0x45, 0x45, 0x3c, 0xcc, 0x21, 0x40, 0x94, 0x53, 0xaa, 0xfb, 0x8a, 0x72, 0xa0, 0xbe, 0x9e, 0xbe, 0x54, 0xd1, 0x22, 0x70, 0xaa, 0x51, 0xb3, 0xab, 0x7f, 0x31, 0x6a, 0xa5, 0xe7, 0x4a, 0x95, 0x1c, 0x5e, 0x53, 0xf7, 0x4c, 0xd9, 0x5f, 0xc2, 0x9a, 0xee, 0x7a, 0x01, 0x3d, 0x52, 0xf3, 0x3a, 0x9f, 0x3c, 0x14, 0x38, 0x4d, 0x15, 0x87, 0xfa, 0x8a, 0xbe, 0x7a, 0xed, 0x74, 0xbc, 0x33, 0x74, 0x9a, 0xd9, 0xc5, 0x70, 0xb4, 0x71, 0x77, 0x64, 0x22, 0xc7, 0xd4, 0x50, 0x5d, 0x9b, 0x0a, 0x96, 0xb3, 0xbf, 0xac, 0x04, 0x1e, 0x4c, 0x6a, 0x69, 0x90, 0xae, 0x7f, 0x70, 0x0e, 0x5b, 0x4a, 0x66, 0x40, 0x22, 0x91, 0x12, 0xde, 0xaf, 0xa0, 0xcd, 0x8b, 0xb0, 0xd0, 0x89, 0xb0, ], priv = [ 0x00, 0x81, 0x6f, 0x19, 0xc1, 0xfb, 0x10, 0xef, 0x94, 0xd4, 0xa1, 0xd8, 0x1c, 0x15, 0x6e, 0xc3, 0xd1, 0xde, 0x08, 0xb6, 0x67, 0x61, 0xf0, 0x3f, 0x06, 0xee, 0x4b, 0xb9, 0xdc, 0xeb, 0xbb, 0xfe, 0x1e, 0xaa, 0x1e, 0xd4, 0x9a, 0x6a, 0x99, 0x08, 0x38, 0xd8, 0xed, 0x31, 0x8c, 0x14, 0xd7, 0x4c, 0xc8, 0x72, 0xf9, 0x5d, 0x05, 0xd0, 0x7a, 0xd5, 0x0f, 0x62, 0x1c, 0xeb, 0x62, 0x0c, 0xd9, 0x05, 0xcf, 0xb8, ], pub = [ 0x04, 0x00, 0xd4, 0x56, 0x15, 0xed, 0x5d, 0x37, 0xfd, 0xe6, 0x99, 0x61, 0x0a, 0x62, 0xcd, 0x43, 0xba, 0x76, 0xbe, 0xdd, 0x8f, 0x85, 0xed, 0x31, 0x00, 0x5f, 0xe0, 0x0d, 0x64, 0x50, 0xfb, 0xbd, 0x10, 0x12, 0x91, 0xab, 0xd9, 0x6d, 0x49, 0x45, 0xa8, 0xb5, 0x7b, 0xc7, 0x3b, 0x3f, 0xe9, 0xf4, 0x67, 0x11, 0x05, 0x30, 0x9e, 0xc9, 0xb6, 0x87, 0x9d, 0x05, 0x51, 0xd9, 0x30, 0xda, 0xc8, 0xba, 0x45, 0xd2, 0x55, 0x01, 0x42, 0x53, 0x32, 0x84, 0x4e, 0x59, 0x2b, 0x44, 0x0c, 0x00, 0x27, 0x97, 0x2a, 0xd1, 0x52, 0x64, 0x31, 0xc0, 0x67, 0x32, 0xdf, 0x19, 0xcd, 0x46, 0xa2, 0x42, 0x17, 0x2d, 0x4d, 0xd6, 0x7c, 0x2c, 0x8c, 0x99, 0xdf, 0xc2, 0x2e, 0x49, 0x94, 0x9a, 0x56, 0xcf, 0x90, 0xc6, 0x47, 0x36, 0x35, 0xce, 0x82, 0xf2, 0x5b, 0x33, 0x68, 0x2f, 0xb1, 0x9b, 0xc3, 0x3b, 0xd9, 0x10, 0xed, 0x8c, 0xe3, 0xa7, 0xfa, ], shared = [ 0x00, 0x0b, 0x39, 0x20, 0xac, 0x83, 0x0a, 0xde, 0x81, 0x2c, 0x8f, 0x96, 0x80, 0x5d, 0xa2, 0x23, 0x6e, 0x00, 0x2a, 0xcb, 0xbf, 0x13, 0x59, 0x6a, 0x9a, 0xb2, 0x54, 0xd4, 0x4d, 0x0e, 0x91, 0xb6, 0x25, 0x5e, 0xbf, 0x12, 0x29, 0xf3, 0x66, 0xfb, 0x5a, 0x05, 0xc5, 0x88, 0x4e, 0xf4, 0x60, 0x32, 0xc2, 0x6d, 0x42, 0x18, 0x92, 0x73, 0xca, 0x4e, 0xfa, 0x4c, 0x3d, 0xb6, 0xbd, 0x12, 0xa6, 0x85, 0x37, 0x59, ], }, //COUNT = 2 testcase { otherpub = [ 0x04, 0x00, 0x92, 0xdb, 0x31, 0x42, 0x56, 0x4d, 0x27, 0xa5, 0xf0, 0x00, 0x6f, 0x81, 0x99, 0x08, 0xfb, 0xa1, 0xb8, 0x50, 0x38, 0xa5, 0xbc, 0x25, 0x09, 0x90, 0x6a, 0x49, 0x7d, 0xaa, 0xc6, 0x7f, 0xd7, 0xae, 0xe0, 0xfc, 0x2d, 0xab, 0xa4, 0xe4, 0x33, 0x4e, 0xea, 0xef, 0x0e, 0x00, 0x19, 0x20, 0x4b, 0x47, 0x1c, 0xd8, 0x80, 0x24, 0xf8, 0x21, 0x15, 0xd8, 0x14, 0x9c, 0xc0, 0xcf, 0x4f, 0x7c, 0xe1, 0xa4, 0xd5, 0x01, 0x6b, 0xad, 0x06, 0x23, 0xf5, 0x17, 0xb1, 0x58, 0xd9, 0x88, 0x18, 0x41, 0xd2, 0x57, 0x1e, 0xfb, 0xad, 0x63, 0xf8, 0x5c, 0xbe, 0x2e, 0x58, 0x19, 0x60, 0xc5, 0xd6, 0x70, 0x60, 0x1a, 0x67, 0x60, 0x27, 0x26, 0x75, 0xa5, 0x48, 0x99, 0x62, 0x17, 0xe4, 0xab, 0x2b, 0x8e, 0xbc, 0xe3, 0x1d, 0x71, 0xfc, 0xa6, 0x3f, 0xcc, 0x3c, 0x08, 0xe9, 0x1c, 0x1d, 0x8e, 0xdd, 0x91, 0xcf, 0x6f, 0xe8, 0x45, 0xf8, ], priv = [ 0x01, 0x2f, 0x2e, 0x0c, 0x6d, 0x9e, 0x9d, 0x11, 0x7c, 0xeb, 0x97, 0x23, 0xbc, 0xed, 0x02, 0xeb, 0x3d, 0x4e, 0xeb, 0xf5, 0xfe, 0xea, 0xf8, 0xee, 0x01, 0x13, 0xcc, 0xd8, 0x05, 0x7b, 0x13, 0xdd, 0xd4, 0x16, 0xe0, 0xb7, 0x42, 0x80, 0xc2, 0xd0, 0xba, 0x8e, 0xd2, 0x91, 0xc4, 0x43, 0xbc, 0x1b, 0x14, 0x1c, 0xaf, 0x8a, 0xfb, 0x3a, 0x71, 0xf9, 0x7f, 0x57, 0xc2, 0x25, 0xc0, 0x3e, 0x1e, 0x4d, 0x42, 0xb0, ], pub = [ 0x04, 0x00, 0x71, 0x7f, 0xcb, 0x3d, 0x4a, 0x40, 0xd1, 0x03, 0x87, 0x1e, 0xde, 0x04, 0x4d, 0xc8, 0x03, 0xdb, 0x50, 0x8a, 0xaa, 0x4a, 0xe7, 0x4b, 0x70, 0xb9, 0xfb, 0x8d, 0x8d, 0xfd, 0x84, 0xbf, 0xec, 0xfa, 0xd1, 0x78, 0x71, 0x87, 0x96, 0x98, 0xc2, 0x92, 0xd2, 0xfd, 0x5e, 0x17, 0xb4, 0xf9, 0x34, 0x36, 0x36, 0xc5, 0x31, 0xa4, 0xfa, 0xc6, 0x8a, 0x35, 0xa9, 0x36, 0x65, 0x54, 0x6b, 0x9a, 0x87, 0x86, 0x79, 0x00, 0xf3, 0xd9, 0x6a, 0x86, 0x37, 0x03, 0x69, 0x93, 0xab, 0x5d, 0x24, 0x45, 0x00, 0xff, 0xf9, 0xd2, 0x77, 0x21, 0x12, 0x82, 0x6f, 0x64, 0x36, 0x60, 0x3d, 0x3e, 0xb2, 0x34, 0xa4, 0x4d, 0x5c, 0x4e, 0x5c, 0x57, 0x72, 0x34, 0x67, 0x9c, 0x4f, 0x9d, 0xf7, 0x25, 0xee, 0x5b, 0x91, 0x18, 0xf2, 0x3d, 0x8a, 0x58, 0xd0, 0xcc, 0x01, 0x09, 0x6d, 0xaf, 0x70, 0xe8, 0xdf, 0xec, 0x01, 0x28, 0xbd, 0xc2, 0xe8, ], shared = [ 0x00, 0x6b, 0x38, 0x0a, 0x6e, 0x95, 0x67, 0x92, 0x77, 0xcf, 0xee, 0x4e, 0x83, 0x53, 0xbf, 0x96, 0xef, 0x2a, 0x1e, 0xbd, 0xd0, 0x60, 0x74, 0x9f, 0x2f, 0x04, 0x6f, 0xe5, 0x71, 0x05, 0x37, 0x40, 0xbb, 0xcc, 0x9a, 0x0b, 0x55, 0x79, 0x0b, 0xc9, 0xab, 0x56, 0xc3, 0x20, 0x8a, 0xa0, 0x5d, 0xdf, 0x74, 0x6a, 0x10, 0xa3, 0xad, 0x69, 0x4d, 0xaa, 0xe0, 0x0d, 0x98, 0x0d, 0x94, 0x4a, 0xab, 0xc6, 0xa0, 0x8f, ], }, //COUNT = 3 testcase { otherpub = [ 0x04, 0x00, 0xfd, 0xd4, 0x0d, 0x9e, 0x9d, 0x97, 0x40, 0x27, 0xcb, 0x3b, 0xae, 0x68, 0x21, 0x62, 0xea, 0xc1, 0x32, 0x8a, 0xd6, 0x1b, 0xc4, 0x35, 0x3c, 0x45, 0xbf, 0x5a, 0xfe, 0x76, 0xbf, 0x60, 0x7d, 0x28, 0x94, 0xc8, 0xcc, 0xe2, 0x36, 0x95, 0xd9, 0x20, 0xf2, 0x46, 0x4f, 0xda, 0x47, 0x73, 0xd4, 0x69, 0x3b, 0xe4, 0xb3, 0x77, 0x35, 0x84, 0x69, 0x1b, 0xdb, 0x03, 0x29, 0xb7, 0xf4, 0xc8, 0x6c, 0xc2, 0x99, 0x00, 0x34, 0xce, 0xac, 0x6a, 0x3f, 0xef, 0x1c, 0x3e, 0x1c, 0x49, 0x4b, 0xfe, 0x8d, 0x87, 0x2b, 0x18, 0x38, 0x32, 0x21, 0x9a, 0x7e, 0x14, 0xda, 0x41, 0x4d, 0x4e, 0x34, 0x74, 0x57, 0x36, 0x71, 0xec, 0x19, 0xb0, 0x33, 0xbe, 0x83, 0x1b, 0x91, 0x54, 0x35, 0x90, 0x59, 0x25, 0xb4, 0x49, 0x47, 0xc5, 0x92, 0x95, 0x99, 0x45, 0xb4, 0xeb, 0x7c, 0x95, 0x1c, 0x3b, 0x9c, 0x8c, 0xf5, 0x25, 0x30, 0xba, 0x23, ], priv = [ 0x00, 0xe5, 0x48, 0xa7, 0x9d, 0x8b, 0x05, 0xf9, 0x23, 0xb9, 0x82, 0x5d, 0x11, 0xb6, 0x56, 0xf2, 0x22, 0xe8, 0xcb, 0x98, 0xb0, 0xf8, 0x9d, 0xe1, 0xd3, 0x17, 0x18, 0x4d, 0xc5, 0xa6, 0x98, 0xf7, 0xc7, 0x11, 0x61, 0xee, 0x7d, 0xc1, 0x1c, 0xd3, 0x1f, 0x4f, 0x4f, 0x8a, 0xe3, 0xa9, 0x81, 0xe1, 0xa3, 0xe7, 0x8b, 0xde, 0xbb, 0x97, 0xd7, 0xc2, 0x04, 0xb9, 0x26, 0x1b, 0x4e, 0xf9, 0x2e, 0x09, 0x18, 0xe0, ], pub = [ 0x04, 0x00, 0x0c, 0xe8, 0x00, 0x21, 0x7e, 0xd2, 0x43, 0xdd, 0x10, 0xa7, 0x9a, 0xd7, 0x3d, 0xf5, 0x78, 0xaa, 0x8a, 0x3f, 0x91, 0x94, 0xaf, 0x52, 0x8c, 0xd1, 0x09, 0x4b, 0xbf, 0xee, 0x27, 0xa3, 0xb5, 0x48, 0x1a, 0xd5, 0x86, 0x2c, 0x88, 0x76, 0xc0, 0xc3, 0xf9, 0x12, 0x94, 0xc0, 0xab, 0x3a, 0xa8, 0x06, 0xd9, 0x02, 0x0c, 0xba, 0xa2, 0xed, 0x72, 0xb7, 0xfe, 0xcd, 0xc5, 0xa0, 0x9a, 0x6d, 0xad, 0x6f, 0x32, 0x01, 0x54, 0x3c, 0x9a, 0xb4, 0x5b, 0x12, 0x46, 0x92, 0x32, 0x91, 0x8e, 0x21, 0xd5, 0xa3, 0x51, 0xf9, 0xa4, 0xb9, 0xcb, 0xf9, 0xef, 0xb2, 0xaf, 0xcc, 0x40, 0x2f, 0xa9, 0xb3, 0x16, 0x50, 0xbe, 0xc2, 0xd6, 0x41, 0xa0, 0x5c, 0x44, 0x0d, 0x35, 0x33, 0x1c, 0x08, 0x93, 0xd1, 0x1f, 0xb1, 0x31, 0x51, 0x33, 0x59, 0x88, 0xb3, 0x03, 0x34, 0x13, 0x01, 0xa7, 0x3d, 0xc5, 0xf6, 0x1d, 0x57, 0x4e, 0x67, 0xd9, ], shared = [ 0x00, 0xfb, 0xbc, 0xd0, 0xb8, 0xd0, 0x53, 0x31, 0xfe, 0xf6, 0x08, 0x6f, 0x22, 0xa6, 0xcc, 0xe4, 0xd3, 0x57, 0x24, 0xab, 0x7a, 0x2f, 0x49, 0xdd, 0x84, 0x58, 0xd0, 0xbf, 0xd5, 0x7a, 0x0b, 0x8b, 0x70, 0xf2, 0x46, 0xc1, 0x7c, 0x44, 0x68, 0xc0, 0x76, 0x87, 0x4b, 0x0d, 0xff, 0x7a, 0x03, 0x36, 0x82, 0x3b, 0x19, 0xe9, 0x8b, 0xf1, 0xce, 0xc0, 0x5e, 0x4b, 0xef, 0xfb, 0x05, 0x91, 0xf9, 0x77, 0x13, 0xc6, ], }, //COUNT = 4 testcase { otherpub = [ 0x04, 0x00, 0x98, 0xd9, 0x9d, 0xee, 0x08, 0x16, 0x55, 0x0e, 0x84, 0xdb, 0xfc, 0xed, 0x7e, 0x88, 0x13, 0x7f, 0xdd, 0xcf, 0x58, 0x1a, 0x72, 0x5a, 0x45, 0x50, 0x21, 0x11, 0x5f, 0xe4, 0x9f, 0x8d, 0xc3, 0xcf, 0x23, 0x3c, 0xd9, 0xea, 0x0e, 0x6f, 0x03, 0x9d, 0xc7, 0x91, 0x9d, 0xa9, 0x73, 0xcd, 0xce, 0xac, 0xa2, 0x05, 0xda, 0x39, 0xe0, 0xbd, 0x98, 0xc8, 0x06, 0x25, 0x36, 0xc4, 0x7f, 0x25, 0x8f, 0x44, 0xb5, 0x00, 0xcd, 0x22, 0x5c, 0x87, 0x97, 0x37, 0x1b, 0xe0, 0xc4, 0x29, 0x7d, 0x2b, 0x45, 0x77, 0x40, 0x10, 0x0c, 0x77, 0x41, 0x41, 0xd8, 0xf2, 0x14, 0xc2, 0x3b, 0x61, 0xaa, 0x2b, 0x6c, 0xd4, 0x80, 0x6b, 0x9b, 0x70, 0x72, 0x2a, 0xa4, 0x96, 0x5f, 0xb6, 0x22, 0xf4, 0x2b, 0x73, 0x91, 0xe2, 0x7e, 0x5e, 0xc2, 0x1c, 0x56, 0x79, 0xc5, 0xb0, 0x6b, 0x59, 0x12, 0x73, 0x72, 0x99, 0x7d, 0x42, 0x1a, 0xdc, 0x1e, ], priv = [ 0x01, 0xc8, 0xaa, 0xe9, 0x4b, 0xb1, 0x0b, 0x8c, 0xa4, 0xf7, 0xbe, 0x57, 0x7b, 0x4f, 0xb3, 0x2b, 0xb2, 0x38, 0x10, 0x32, 0xc4, 0x94, 0x2c, 0x24, 0xfc, 0x2d, 0x75, 0x3e, 0x7c, 0xc5, 0xe4, 0x7b, 0x48, 0x33, 0x89, 0xd9, 0xf3, 0xb9, 0x56, 0xd2, 0x0e, 0xe9, 0x00, 0x1b, 0x1e, 0xef, 0x9f, 0x23, 0x54, 0x5f, 0x72, 0xc5, 0x60, 0x21, 0x40, 0x04, 0x68, 0x39, 0xe9, 0x63, 0x31, 0x3c, 0x3d, 0xec, 0xc8, 0x64, ], pub = [ 0x04, 0x01, 0x06, 0xa1, 0x4e, 0x2e, 0xe8, 0xff, 0x97, 0x0a, 0xa8, 0xab, 0x0c, 0x79, 0xb9, 0x7a, 0x33, 0xbb, 0xa2, 0x95, 0x8e, 0x07, 0x0b, 0x75, 0xb9, 0x47, 0x36, 0xb7, 0x7b, 0xbe, 0x3f, 0x77, 0x73, 0x24, 0xfa, 0x52, 0x87, 0x27, 0x71, 0xaa, 0x88, 0xa6, 0x3a, 0x9e, 0x84, 0x90, 0xc3, 0x37, 0x8d, 0xf4, 0xdc, 0x76, 0x0c, 0xd1, 0x4d, 0x62, 0xbe, 0x70, 0x07, 0x79, 0xdd, 0x1a, 0x43, 0x77, 0x94, 0x36, 0x56, 0x00, 0x23, 0x66, 0xce, 0x39, 0x41, 0xe0, 0xb2, 0x84, 0xb1, 0xaa, 0x81, 0x21, 0x5d, 0x0d, 0x3b, 0x97, 0x78, 0xfc, 0xe2, 0x3c, 0x8c, 0xd1, 0xe4, 0xed, 0x6f, 0xa0, 0xab, 0xf6, 0x21, 0x56, 0xc9, 0x1d, 0x4b, 0x3e, 0xb5, 0x59, 0x99, 0xc3, 0x47, 0x1b, 0xed, 0x27, 0x5e, 0x9e, 0x60, 0xe5, 0xaa, 0x9d, 0x69, 0x0d, 0x31, 0x0b, 0xfb, 0x15, 0xc9, 0xc5, 0xbb, 0xd6, 0xf5, 0xe9, 0xeb, 0x39, 0x68, 0x2b, 0x74, ], shared = [ 0x01, 0x45, 0xcf, 0xa3, 0x8f, 0x25, 0x94, 0x35, 0x16, 0xc9, 0x6a, 0x5f, 0xd4, 0xbf, 0xeb, 0xb2, 0xf6, 0x45, 0xd1, 0x05, 0x20, 0x11, 0x7a, 0xa5, 0x19, 0x71, 0xef, 0xf4, 0x42, 0x80, 0x8a, 0x23, 0xb4, 0xe2, 0x3c, 0x18, 0x7e, 0x63, 0x9f, 0xf9, 0x28, 0xc3, 0x72, 0x5f, 0xbd, 0x1c, 0x0c, 0x2a, 0xd0, 0xd4, 0xae, 0xb2, 0x07, 0xbc, 0x1a, 0x6f, 0xb6, 0xcb, 0x6d, 0x46, 0x78, 0x88, 0xdc, 0x04, 0x4b, 0x3c, ], }, //COUNT = 5 testcase { otherpub = [ 0x04, 0x00, 0x7a, 0xe1, 0x15, 0xad, 0xaa, 0xf0, 0x41, 0x69, 0x1a, 0xb6, 0xb7, 0xfb, 0x8c, 0x92, 0x1f, 0x99, 0xd8, 0xed, 0x32, 0xd2, 0x83, 0xd6, 0x70, 0x84, 0xe8, 0x0b, 0x9a, 0xd9, 0xc4, 0x0c, 0x56, 0xcd, 0x98, 0x38, 0x9f, 0xb0, 0xa8, 0x49, 0xd9, 0xec, 0xf7, 0x26, 0x8c, 0x29, 0x7b, 0x6f, 0x93, 0x40, 0x61, 0x19, 0xf4, 0x0e, 0x32, 0xb5, 0x77, 0x3e, 0xd2, 0x5a, 0x28, 0xa9, 0xa8, 0x5c, 0x4a, 0x75, 0x88, 0x01, 0xa2, 0x8e, 0x00, 0x4e, 0x37, 0xee, 0xae, 0xfe, 0x1f, 0x4d, 0xbb, 0x71, 0xf1, 0x87, 0x86, 0x96, 0x14, 0x1a, 0xf3, 0xa1, 0x0a, 0x96, 0x91, 0xc4, 0xed, 0x93, 0x48, 0x72, 0x14, 0x64, 0x3b, 0x76, 0x1f, 0xa4, 0xb0, 0xfb, 0xee, 0xb2, 0x47, 0xcf, 0x6d, 0x3f, 0xba, 0x7a, 0x60, 0x69, 0x75, 0x36, 0xad, 0x03, 0xf4, 0x9b, 0x80, 0xa9, 0xd1, 0xcb, 0x07, 0x96, 0x73, 0x65, 0x49, 0x77, 0xc5, 0xfa, 0x94, ], priv = [ 0x00, 0x9b, 0x0a, 0xf1, 0x37, 0xc9, 0x69, 0x6c, 0x75, 0xb7, 0xe6, 0xdf, 0x7b, 0x73, 0x15, 0x6b, 0xb2, 0xd4, 0x5f, 0x48, 0x2e, 0x5a, 0x42, 0x17, 0x32, 0x4f, 0x47, 0x8b, 0x10, 0xce, 0xb7, 0x6a, 0xf0, 0x97, 0x24, 0xcf, 0x86, 0xaf, 0xa3, 0x16, 0xe7, 0xf8, 0x99, 0x18, 0xd3, 0x1d, 0x54, 0x82, 0x4a, 0x5c, 0x33, 0x10, 0x7a, 0x48, 0x3c, 0x15, 0xc1, 0x5b, 0x96, 0xed, 0xc6, 0x61, 0x34, 0x0b, 0x1c, 0x0e, ], pub = [ 0x04, 0x00, 0x74, 0x8c, 0xdb, 0xb8, 0x75, 0xd3, 0x5f, 0x4b, 0xcc, 0xb6, 0x2a, 0xbe, 0x20, 0xe8, 0x2d, 0x32, 0xe4, 0xc1, 0x4d, 0xc2, 0xfe, 0xb5, 0xb8, 0x7d, 0xa2, 0xd0, 0xcc, 0xb1, 0x1c, 0x9b, 0x6d, 0x4b, 0x77, 0x37, 0xb6, 0xc4, 0x6f, 0x0d, 0xfb, 0x4d, 0x89, 0x6e, 0x2d, 0xb9, 0x2f, 0xcf, 0x53, 0xcd, 0xbb, 0xae, 0x2a, 0x40, 0x4c, 0x0b, 0xab, 0xd5, 0x64, 0xad, 0x7a, 0xde, 0xac, 0x62, 0x73, 0xef, 0xa3, 0x01, 0x98, 0x4a, 0xca, 0xb8, 0xd8, 0xf1, 0x73, 0x32, 0x3d, 0xe0, 0xbb, 0x60, 0x27, 0x4b, 0x22, 0x88, 0x71, 0x60, 0x93, 0x73, 0xbb, 0x22, 0xa1, 0x72, 0x87, 0xe9, 0xde, 0xc7, 0x49, 0x58, 0x73, 0xab, 0xc0, 0x9a, 0x89, 0x15, 0xb5, 0x4c, 0x84, 0x55, 0xc8, 0xe0, 0x2f, 0x65, 0x4f, 0x60, 0x2e, 0x23, 0xa2, 0xbb, 0xd7, 0xa9, 0xeb, 0xb7, 0x4f, 0x30, 0x09, 0xbd, 0x65, 0xec, 0xc6, 0x50, 0x81, 0x4c, 0xc0, ], shared = [ 0x00, 0x5c, 0x57, 0x21, 0xe9, 0x6c, 0x27, 0x33, 0x19, 0xfd, 0x60, 0xec, 0xc4, 0x6b, 0x59, 0x62, 0xf6, 0x98, 0xe9, 0x74, 0xb4, 0x29, 0xf2, 0x8f, 0xe6, 0x96, 0x2f, 0x4a, 0xc6, 0x56, 0xbe, 0x2e, 0xb8, 0x67, 0x4c, 0x4a, 0xaf, 0xc0, 0x37, 0xea, 0xb4, 0x8e, 0xce, 0x61, 0x29, 0x53, 0xb1, 0xe8, 0xd8, 0x61, 0x01, 0x6b, 0x6a, 0xd0, 0xc7, 0x98, 0x05, 0x78, 0x4c, 0x67, 0xf7, 0x3a, 0xda, 0x96, 0xf3, 0x51, ], }, //COUNT = 6 testcase { otherpub = [ 0x04, 0x01, 0x25, 0x88, 0x11, 0x5e, 0x6f, 0x7f, 0x7b, 0xdc, 0xfd, 0xf5, 0x7f, 0x03, 0xb1, 0x69, 0xb4, 0x79, 0x75, 0x8b, 0xaa, 0xfd, 0xaf, 0x56, 0x9d, 0x04, 0x13, 0x59, 0x87, 0xb2, 0xce, 0x61, 0x64, 0xc0, 0x2a, 0x57, 0x68, 0x5e, 0xb5, 0x27, 0x6b, 0x5d, 0xae, 0x62, 0x95, 0xd3, 0xfe, 0x90, 0x62, 0x0f, 0x38, 0xb5, 0x53, 0x5c, 0x6d, 0x22, 0x60, 0xc1, 0x73, 0xe6, 0x1e, 0xb8, 0x88, 0xca, 0x92, 0x02, 0x03, 0x01, 0x54, 0x2c, 0x16, 0x9c, 0xf9, 0x7c, 0x25, 0x96, 0xfe, 0x2d, 0xdd, 0x84, 0x8a, 0x22, 0x2e, 0x36, 0x7c, 0x5f, 0x7e, 0x62, 0x67, 0xeb, 0xc1, 0xbc, 0xd9, 0xab, 0x5d, 0xcf, 0x49, 0x15, 0x8f, 0x1a, 0x48, 0xe4, 0xaf, 0x29, 0xa8, 0x97, 0xb7, 0xe6, 0xa8, 0x20, 0x91, 0xc2, 0xdb, 0x87, 0x4d, 0x8e, 0x7a, 0xbf, 0x0f, 0x58, 0x06, 0x46, 0x91, 0x34, 0x41, 0x54, 0xf3, 0x96, 0xdb, 0xae, 0xd1, 0x88, 0xb6, ], priv = [ 0x01, 0xe4, 0x8f, 0xaa, 0xce, 0xe6, 0xde, 0xc8, 0x3f, 0xfc, 0xde, 0x94, 0x4c, 0xf6, 0xbd, 0xf4, 0xce, 0x4b, 0xae, 0x72, 0x74, 0x78, 0x88, 0xeb, 0xaf, 0xee, 0x45, 0x5b, 0x1e, 0x91, 0x58, 0x49, 0x71, 0xef, 0xb4, 0x91, 0x27, 0x97, 0x6a, 0x52, 0xf4, 0x14, 0x29, 0x52, 0xf7, 0xc2, 0x07, 0xec, 0x02, 0x65, 0xf2, 0xb7, 0x18, 0xcf, 0x3e, 0xad, 0x96, 0xea, 0x4f, 0x62, 0xc7, 0x52, 0xe4, 0xf7, 0xac, 0xd3, ], pub = [ 0x04, 0x01, 0x0e, 0xb1, 0xb4, 0xd9, 0x17, 0x2b, 0xcc, 0x23, 0xf4, 0xf2, 0x0c, 0xc9, 0x56, 0x0f, 0xc5, 0x49, 0x28, 0xc3, 0xf3, 0x4e, 0xa6, 0x1c, 0x00, 0x39, 0x1d, 0xc7, 0x66, 0xc7, 0x6e, 0xd9, 0xfa, 0x60, 0x84, 0x49, 0x37, 0x7d, 0x1e, 0x4f, 0xad, 0xd1, 0x23, 0x60, 0x25, 0x41, 0x73, 0x30, 0xb4, 0xb9, 0x10, 0x86, 0x70, 0x4a, 0xce, 0x3e, 0x4e, 0x64, 0x84, 0xc6, 0x06, 0xe2, 0xa9, 0x43, 0x47, 0x8c, 0x86, 0x01, 0x49, 0x41, 0x38, 0x64, 0x06, 0x98, 0x25, 0xee, 0x1d, 0x08, 0x28, 0xda, 0x9f, 0x4a, 0x97, 0x71, 0x30, 0x05, 0xe9, 0xbd, 0x1a, 0xdb, 0xc3, 0xb3, 0x8c, 0x5b, 0x94, 0x69, 0x00, 0x72, 0x1a, 0x96, 0x0f, 0xe9, 0x6a, 0xd2, 0xc1, 0xb3, 0xa4, 0x4f, 0xe3, 0xde, 0x91, 0x56, 0x13, 0x6d, 0x44, 0xcb, 0x17, 0xcb, 0xc2, 0x41, 0x57, 0x29, 0xbb, 0x78, 0x2e, 0x16, 0xbf, 0xe2, 0xde, 0xb3, 0x06, 0x9e, 0x43, ], shared = [ 0x01, 0x73, 0x6d, 0x97, 0x17, 0x42, 0x9b, 0x4f, 0x41, 0x2e, 0x90, 0x3f, 0xeb, 0xe2, 0xf9, 0xe0, 0xff, 0xfd, 0x81, 0x35, 0x5d, 0x6c, 0xe2, 0xc0, 0x6f, 0xf3, 0xf6, 0x6a, 0x3b, 0xe1, 0x5c, 0xee, 0xc6, 0xe6, 0x5e, 0x30, 0x83, 0x47, 0x59, 0x3f, 0x00, 0xd7, 0xf3, 0x35, 0x91, 0xda, 0x40, 0x43, 0xc3, 0x07, 0x63, 0xd7, 0x27, 0x49, 0xf7, 0x2c, 0xdc, 0xee, 0xbe, 0x82, 0x5e, 0x4b, 0x34, 0xec, 0xd5, 0x70, ], }, //COUNT = 7 testcase { otherpub = [ 0x04, 0x01, 0x69, 0x49, 0x1d, 0x55, 0xbd, 0x09, 0x04, 0x9f, 0xdf, 0x4c, 0x2a, 0x53, 0xa6, 0x60, 0x48, 0x0f, 0xee, 0x4c, 0x03, 0xa0, 0x53, 0x86, 0x75, 0xd1, 0xcd, 0x09, 0xb5, 0xbb, 0xa7, 0x8d, 0xac, 0x48, 0x54, 0x3e, 0xf1, 0x18, 0xa1, 0x17, 0x3b, 0x3f, 0xbf, 0x8b, 0x20, 0xe3, 0x9c, 0xe0, 0xe6, 0xb8, 0x90, 0xa1, 0x63, 0xc5, 0x0f, 0x96, 0x45, 0xb3, 0xd2, 0x1d, 0x1c, 0xbb, 0x3b, 0x60, 0xa6, 0xff, 0xf4, 0x00, 0x83, 0x49, 0x4b, 0x2e, 0xba, 0x76, 0x91, 0x0f, 0xed, 0x33, 0xc7, 0x61, 0x80, 0x45, 0x15, 0x01, 0x1f, 0xab, 0x50, 0xe3, 0xb3, 0x77, 0xab, 0xd8, 0xa8, 0xa0, 0x45, 0xd8, 0x86, 0xd2, 0x23, 0x8d, 0x2c, 0x26, 0x8a, 0xc1, 0xb6, 0xec, 0x88, 0xbd, 0x71, 0xb7, 0xba, 0x78, 0xe2, 0xc3, 0x3c, 0x15, 0x2e, 0x4b, 0xf7, 0xda, 0x5d, 0x56, 0x5e, 0x4a, 0xcb, 0xec, 0xf5, 0xe9, 0x2c, 0x7a, 0xd6, 0x62, 0xbb, ], priv = [ 0x00, 0xc2, 0x9a, 0xa2, 0x23, 0xea, 0x8d, 0x64, 0xb4, 0xa1, 0xed, 0xa2, 0x7f, 0x39, 0xd3, 0xbc, 0x98, 0xea, 0x01, 0x48, 0xdd, 0x98, 0xc1, 0xcb, 0xe5, 0x95, 0xf8, 0xfd, 0x2b, 0xfb, 0xde, 0x11, 0x9c, 0x9e, 0x01, 0x7a, 0x50, 0xf5, 0xd1, 0xfc, 0x12, 0x1c, 0x08, 0xc1, 0xce, 0xf3, 0x1b, 0x75, 0x88, 0x59, 0x55, 0x6e, 0xb3, 0xe0, 0xe0, 0x42, 0xd8, 0xdd, 0x6a, 0xaa, 0xc5, 0x7a, 0x05, 0xca, 0x61, 0xe3, ], pub = [ 0x04, 0x00, 0x15, 0x11, 0xc8, 0x48, 0xef, 0x60, 0xd5, 0x41, 0x9a, 0x98, 0xd1, 0x02, 0x04, 0xdb, 0x0f, 0xe5, 0x82, 0x24, 0x12, 0x43, 0x70, 0x06, 0x1b, 0xcf, 0xa4, 0xe9, 0x24, 0x9d, 0x50, 0x61, 0x8c, 0x56, 0xbf, 0x37, 0x22, 0x47, 0x1b, 0x25, 0x9f, 0x38, 0x26, 0x3b, 0xb7, 0xb2, 0x80, 0xd2, 0x3c, 0xaf, 0x2a, 0x1e, 0xe8, 0x73, 0x7f, 0x93, 0x71, 0xcd, 0xb2, 0x73, 0x2c, 0xdc, 0x95, 0x83, 0x69, 0x93, 0x0c, 0x01, 0xd4, 0x61, 0x68, 0x1a, 0xe6, 0xd8, 0xc4, 0x9b, 0x4c, 0x5f, 0x4d, 0x60, 0x16, 0x14, 0x3f, 0xb1, 0xbd, 0x74, 0x91, 0x57, 0x3e, 0x3e, 0xd0, 0xe6, 0xc4, 0x8b, 0x82, 0xe8, 0x21, 0x64, 0x4f, 0x87, 0xf8, 0x2f, 0x0e, 0x5f, 0x08, 0xfd, 0x16, 0xf1, 0xf9, 0x8f, 0xa1, 0x75, 0x86, 0x20, 0x0a, 0xb0, 0x2e, 0xd8, 0xc6, 0x27, 0xb3, 0x5c, 0x3f, 0x27, 0x61, 0x7e, 0xc5, 0xfd, 0x92, 0xf4, 0x56, 0x20, 0x3f, ], shared = [ 0x01, 0x8f, 0x2a, 0xe9, 0x47, 0x6c, 0x77, 0x17, 0x26, 0xa7, 0x77, 0x80, 0x20, 0x8d, 0xed, 0xfe, 0xfa, 0x20, 0x54, 0x88, 0x99, 0x6b, 0x18, 0xfe, 0xcc, 0x50, 0xbf, 0xd4, 0xc1, 0x32, 0x75, 0x3f, 0x57, 0x66, 0xb2, 0xcd, 0x74, 0x4a, 0xfa, 0x99, 0x18, 0x60, 0x6d, 0xe2, 0xe0, 0x16, 0xef, 0xfc, 0x63, 0x62, 0x2e, 0x90, 0x29, 0xe7, 0x6d, 0xc6, 0xe3, 0xf0, 0xc6, 0x9f, 0x7a, 0xec, 0xed, 0x56, 0x5c, 0x2c, ], }, //COUNT = 8 testcase { otherpub = [ 0x04, 0x00, 0x84, 0x15, 0xf5, 0xbb, 0xd0, 0xee, 0xe3, 0x87, 0xd6, 0xc0, 0x9d, 0x0e, 0xf8, 0xac, 0xaf, 0x29, 0xc6, 0x6d, 0xb4, 0x5d, 0x6b, 0xa1, 0x01, 0x86, 0x0a, 0xe4, 0x5d, 0x3c, 0x60, 0xe1, 0xe0, 0xe3, 0xf7, 0x24, 0x7a, 0x46, 0x26, 0xa6, 0x0f, 0xdd, 0x40, 0x49, 0x65, 0xc3, 0x56, 0x6c, 0x79, 0xf6, 0x44, 0x9e, 0x85, 0x6c, 0xe0, 0xbf, 0x94, 0x61, 0x9f, 0x97, 0xda, 0x8d, 0xa2, 0x4b, 0xd2, 0xcf, 0xb6, 0x00, 0xfd, 0xd7, 0xc5, 0x9c, 0x58, 0xc3, 0x61, 0xbc, 0x50, 0xa7, 0xa5, 0xd0, 0xd3, 0x6f, 0x72, 0x3b, 0x17, 0xc4, 0xf2, 0xad, 0x2b, 0x03, 0xc2, 0x4d, 0x42, 0xdc, 0x50, 0xf7, 0x4a, 0x8c, 0x46, 0x5a, 0x0a, 0xfc, 0x46, 0x83, 0xf1, 0x0f, 0xab, 0x84, 0x65, 0x2d, 0xfe, 0x9e, 0x92, 0x8c, 0x26, 0x26, 0xb5, 0x45, 0x64, 0x53, 0xe1, 0x57, 0x3f, 0xf6, 0x0b, 0xe1, 0x50, 0x74, 0x67, 0xd4, 0x31, 0xfb, 0xb2, ], priv = [ 0x00, 0x28, 0x69, 0x2b, 0xe2, 0xbf, 0x5c, 0x4b, 0x48, 0x93, 0x98, 0x46, 0xfb, 0x3d, 0x5b, 0xce, 0x74, 0x65, 0x4b, 0xb2, 0x64, 0x6e, 0x15, 0xf8, 0x38, 0x9e, 0x23, 0x70, 0x8a, 0x1a, 0xfa, 0xdf, 0x56, 0x15, 0x11, 0xea, 0x0d, 0x99, 0x57, 0xd0, 0xb5, 0x34, 0x53, 0x81, 0x9d, 0x60, 0xfb, 0xa8, 0xf6, 0x5a, 0x18, 0xf7, 0xb2, 0x9d, 0xf0, 0x21, 0xb1, 0xbb, 0x01, 0xcd, 0x16, 0x32, 0x93, 0xac, 0xc3, 0xcc, ], pub = [ 0x04, 0x01, 0xcf, 0xdc, 0x10, 0xc7, 0x99, 0xf5, 0xc7, 0x9c, 0xb6, 0x93, 0x0a, 0x65, 0xfb, 0xa3, 0x51, 0x74, 0x8e, 0x07, 0x56, 0x79, 0x93, 0xe5, 0xe4, 0x10, 0xef, 0x4c, 0xac, 0xc4, 0xcd, 0x8a, 0x25, 0x78, 0x49, 0x91, 0xeb, 0x46, 0x74, 0xe4, 0x10, 0x50, 0xf9, 0x30, 0xc7, 0x19, 0x0a, 0xc8, 0x12, 0xb9, 0x24, 0x5f, 0x48, 0xa7, 0x97, 0x3b, 0x65, 0x8d, 0xaf, 0x40, 0x88, 0x22, 0xfe, 0x5b, 0x85, 0xf6, 0x68, 0x01, 0x80, 0xd9, 0xdd, 0xfc, 0x9a, 0xf7, 0x7b, 0x9c, 0x4a, 0x6f, 0x02, 0xa8, 0x34, 0xdb, 0x15, 0xe5, 0x35, 0xe0, 0xb3, 0x84, 0x5b, 0x2c, 0xce, 0x30, 0x38, 0x83, 0x01, 0xb5, 0x1c, 0xec, 0xbe, 0x32, 0x76, 0x30, 0x7e, 0xf4, 0x39, 0xb5, 0xc9, 0xe6, 0xa7, 0x2d, 0xc2, 0xd9, 0x4d, 0x87, 0x9b, 0xc3, 0x95, 0x05, 0x2d, 0xbb, 0x4a, 0x57, 0x87, 0xd0, 0x6e, 0xfb, 0x28, 0x02, 0x10, 0xfb, 0x8b, 0xe0, 0x37, ], shared = [ 0x01, 0x05, 0xa3, 0x46, 0x98, 0x8b, 0x92, 0xed, 0x8c, 0x7a, 0x25, 0xce, 0x4d, 0x79, 0xd2, 0x1b, 0xc8, 0x6c, 0xfc, 0xc7, 0xf9, 0x9c, 0x6c, 0xd1, 0x9d, 0xbb, 0x4a, 0x39, 0xf4, 0x8a, 0xb9, 0x43, 0xb7, 0x9e, 0x4f, 0x06, 0x47, 0x34, 0x8d, 0xa0, 0xb8, 0x0b, 0xd8, 0x64, 0xb8, 0x5c, 0x6b, 0x8d, 0x92, 0x53, 0x6d, 0x6a, 0xa5, 0x44, 0xdc, 0x75, 0x37, 0xa0, 0x0c, 0x85, 0x8f, 0x8b, 0x66, 0x31, 0x9e, 0x25, ], }, //COUNT = 9 testcase { otherpub = [ 0x04, 0x01, 0xc7, 0x21, 0xee, 0xa8, 0x05, 0xa5, 0xcb, 0xa2, 0x9f, 0x34, 0xba, 0x57, 0x58, 0x77, 0x5b, 0xe0, 0xcf, 0x61, 0x60, 0xe6, 0xc0, 0x87, 0x23, 0xf5, 0xab, 0x17, 0xbf, 0x96, 0xa1, 0xff, 0x2b, 0xd9, 0x42, 0x79, 0x61, 0xa4, 0xf3, 0x4b, 0x07, 0xfc, 0x0b, 0x14, 0xca, 0x4b, 0x2b, 0xf6, 0x84, 0x5d, 0xeb, 0xd5, 0xa8, 0x69, 0xf1, 0x24, 0xeb, 0xfa, 0x7a, 0xa7, 0x2f, 0xe5, 0x65, 0x05, 0x0b, 0x7f, 0x18, 0x00, 0xb6, 0xe8, 0x9e, 0xb0, 0xe1, 0xdc, 0xf1, 0x81, 0x23, 0x6f, 0x7c, 0x54, 0x8f, 0xd1, 0xa8, 0xc1, 0x6b, 0x25, 0x8b, 0x52, 0xc1, 0xa9, 0xbf, 0xd3, 0xfe, 0x8f, 0x22, 0x84, 0x1b, 0x26, 0x76, 0x32, 0x65, 0xf0, 0x74, 0xc4, 0xcc, 0xf2, 0xd6, 0x34, 0xae, 0x97, 0xb7, 0x01, 0x95, 0x6f, 0x67, 0xa1, 0x10, 0x06, 0xc5, 0x2d, 0x97, 0x19, 0x7d, 0x92, 0xf5, 0x85, 0xf5, 0x74, 0x8b, 0xc2, 0x67, 0x2e, 0xeb, ], priv = [ 0x01, 0x19, 0x4d, 0x1e, 0xe6, 0x13, 0xf5, 0x36, 0x6c, 0xbc, 0x44, 0xb5, 0x04, 0xd2, 0x1a, 0x0c, 0xf6, 0x71, 0x5e, 0x20, 0x9c, 0xd3, 0x58, 0xf2, 0xdd, 0x5f, 0x3e, 0x71, 0xcc, 0x0d, 0x67, 0xd0, 0xe9, 0x64, 0x16, 0x8c, 0x42, 0xa0, 0x84, 0xeb, 0xda, 0x74, 0x6f, 0x98, 0x63, 0xa8, 0x6b, 0xac, 0xff, 0xc8, 0x19, 0xf1, 0xed, 0xf1, 0xb8, 0xc7, 0x27, 0xcc, 0xfb, 0x30, 0x47, 0x24, 0x0a, 0x57, 0xc4, 0x35, ], pub = [ 0x04, 0x01, 0x6b, 0xd1, 0x5c, 0x8a, 0x58, 0xd3, 0x66, 0xf7, 0xf2, 0xb2, 0xf2, 0x98, 0xcc, 0x87, 0xb7, 0x48, 0x5e, 0x9e, 0xe7, 0x0d, 0x11, 0xd1, 0x24, 0x48, 0xb8, 0x37, 0x7c, 0x0a, 0x82, 0xc7, 0x62, 0x6f, 0x67, 0xaf, 0xf7, 0xf9, 0x7b, 0xe7, 0xa3, 0x54, 0x6b, 0xf4, 0x17, 0xee, 0xed, 0xdf, 0x75, 0xa9, 0x3c, 0x13, 0x01, 0x91, 0xc8, 0x41, 0x08, 0x04, 0x2e, 0xa2, 0xfc, 0xa1, 0x7f, 0xd3, 0xf8, 0x0d, 0x14, 0x01, 0x56, 0x05, 0x02, 0xd0, 0x4b, 0x74, 0xfc, 0xe1, 0x74, 0x3a, 0xab, 0x47, 0x7a, 0x9d, 0x1e, 0xac, 0x93, 0xe5, 0x22, 0x69, 0x81, 0xfd, 0xb9, 0x7a, 0x74, 0x78, 0xce, 0x4c, 0xe5, 0x66, 0xff, 0x72, 0x43, 0x93, 0x12, 0x84, 0xfa, 0xd8, 0x50, 0xb0, 0xc2, 0xbc, 0xae, 0x0d, 0xdd, 0x2d, 0x97, 0x79, 0x01, 0x60, 0xc1, 0xa2, 0xe7, 0x7c, 0x3e, 0xd6, 0xc9, 0x5e, 0xcc, 0x44, 0xb8, 0x9e, 0x26, 0x37, 0xfc, ], shared = [ 0x00, 0x45, 0x31, 0xb3, 0xd2, 0xc6, 0xcd, 0x12, 0xf2, 0x16, 0x04, 0xc8, 0x61, 0x0e, 0x67, 0x23, 0xdb, 0xf4, 0xda, 0xf8, 0x0b, 0x5a, 0x45, 0x9d, 0x6b, 0xa5, 0x81, 0x43, 0x97, 0xd1, 0xc1, 0xf7, 0xa2, 0x1d, 0x7c, 0x11, 0x4b, 0xe9, 0x64, 0xe2, 0x73, 0x76, 0xaa, 0xeb, 0xe3, 0xa7, 0xbc, 0x3d, 0x6a, 0xf7, 0xa7, 0xf8, 0xc7, 0xbe, 0xfb, 0x61, 0x1a, 0xfe, 0x48, 0x7f, 0xf0, 0x32, 0x92, 0x1f, 0x75, 0x0f, ], }, //COUNT = 10 testcase { otherpub = [ 0x04, 0x01, 0xc3, 0x58, 0x23, 0xe4, 0x40, 0xa9, 0x36, 0x3a, 0xb9, 0x8d, 0x9f, 0xc7, 0xa7, 0xbc, 0x0c, 0x05, 0x32, 0xdc, 0x79, 0x77, 0xa7, 0x91, 0x65, 0x59, 0x9b, 0xf1, 0xa9, 0xcc, 0x64, 0xc0, 0x0f, 0xb3, 0x87, 0xb4, 0x2c, 0xca, 0x36, 0x52, 0x86, 0xe8, 0x43, 0x03, 0x60, 0xbf, 0xad, 0x36, 0x43, 0xbc, 0x31, 0x35, 0x4e, 0xda, 0x50, 0xdc, 0x93, 0x6c, 0x32, 0x9e, 0xcd, 0xb6, 0x09, 0x05, 0xc4, 0x0f, 0xcb, 0x00, 0xd9, 0xe7, 0xf4, 0x33, 0x53, 0x1e, 0x44, 0xdf, 0x4f, 0x6d, 0x51, 0x42, 0x01, 0xcb, 0xaa, 0xbb, 0x06, 0xba, 0xdd, 0x67, 0x83, 0xe0, 0x11, 0x11, 0x72, 0x6d, 0x81, 0x55, 0x31, 0xd2, 0x33, 0xc5, 0xcd, 0xb7, 0x22, 0x89, 0x3f, 0xfb, 0xb2, 0x02, 0x72, 0x59, 0xd5, 0x94, 0xde, 0x77, 0x43, 0x88, 0x09, 0x73, 0x81, 0x20, 0xc6, 0xf7, 0x83, 0x93, 0x4f, 0x92, 0x6c, 0x3f, 0xb6, 0x9b, 0x40, 0xc4, 0x09, ], priv = [ 0x01, 0xfd, 0x90, 0xe3, 0xe4, 0x16, 0xe9, 0x8a, 0xa3, 0xf2, 0xb6, 0xaf, 0xa7, 0xf3, 0xbf, 0x36, 0x8e, 0x45, 0x1a, 0xd9, 0xca, 0x5b, 0xd5, 0x4b, 0x5b, 0x14, 0xae, 0xe2, 0xed, 0x67, 0x23, 0xdd, 0xe5, 0x18, 0x1f, 0x50, 0x85, 0xb6, 0x81, 0x69, 0xb0, 0x9f, 0xbe, 0xc7, 0x21, 0x37, 0x2c, 0xcf, 0x6b, 0x28, 0x47, 0x13, 0xf9, 0xa6, 0x35, 0x6b, 0x8d, 0x56, 0x0a, 0x8f, 0xf7, 0x8c, 0xa3, 0x73, 0x7c, 0x88, ], pub = [ 0x04, 0x01, 0xeb, 0xea, 0x1b, 0x10, 0xd3, 0xe3, 0xb9, 0x71, 0xb7, 0xef, 0xb6, 0x9f, 0xc8, 0x78, 0xde, 0x11, 0xc7, 0xf4, 0x72, 0xe4, 0xe4, 0xd3, 0x84, 0xc3, 0x1b, 0x8d, 0x62, 0x88, 0xd8, 0x07, 0x15, 0x17, 0xac, 0xad, 0xe9, 0xb3, 0x97, 0x96, 0xc7, 0xaf, 0x51, 0x63, 0xbc, 0xf7, 0x1a, 0xed, 0xa7, 0x77, 0x53, 0x3f, 0x38, 0x2c, 0x6c, 0xf0, 0xa4, 0xd9, 0xbb, 0xb9, 0x38, 0xc8, 0x5f, 0x44, 0xb7, 0x80, 0x37, 0x01, 0x6b, 0x0e, 0x3e, 0x19, 0xc2, 0x99, 0x6b, 0x2c, 0xbd, 0x1f, 0xf6, 0x47, 0x30, 0xe7, 0xca, 0x90, 0xed, 0xca, 0x19, 0x84, 0xf9, 0xb2, 0x95, 0x13, 0x33, 0x53, 0x5e, 0x57, 0x48, 0xba, 0xa3, 0x4a, 0x99, 0xf6, 0x1f, 0xf4, 0xd5, 0xf8, 0x12, 0x07, 0x9e, 0x0f, 0x01, 0xe8, 0x77, 0x89, 0xf3, 0x4e, 0xfd, 0xad, 0x80, 0x98, 0x01, 0x5e, 0xe7, 0x4a, 0x4f, 0x84, 0x6d, 0xd1, 0x90, 0xd1, 0x6d, 0xc6, 0xe1, ], shared = [ 0x01, 0x00, 0xc8, 0x93, 0x59, 0x69, 0x07, 0x7b, 0xae, 0x0b, 0xa8, 0x9e, 0xf0, 0xdf, 0x81, 0x61, 0xd9, 0x75, 0xec, 0x58, 0x70, 0xac, 0x81, 0x1a, 0xe7, 0xe6, 0x5c, 0xa5, 0x39, 0x4e, 0xfb, 0xa4, 0xf0, 0x63, 0x3d, 0x41, 0xbf, 0x79, 0xea, 0x5e, 0x5b, 0x94, 0x96, 0xbb, 0xd7, 0xaa, 0xe0, 0x00, 0xb0, 0x59, 0x4b, 0xaa, 0x82, 0xef, 0x8f, 0x24, 0x4e, 0x69, 0x84, 0xae, 0x87, 0xae, 0x1e, 0xd1, 0x24, 0xb7, ], }, //COUNT = 11 testcase { otherpub = [ 0x04, 0x00, 0x09, 0x30, 0x57, 0xfb, 0x86, 0x2f, 0x2a, 0xd2, 0xe8, 0x2e, 0x58, 0x1b, 0xae, 0xb3, 0x32, 0x4e, 0x7b, 0x32, 0x94, 0x6f, 0x2b, 0xa8, 0x45, 0xa9, 0xbe, 0xee, 0xd8, 0x7d, 0x69, 0x95, 0xf5, 0x49, 0x18, 0xec, 0x66, 0x19, 0xb9, 0x93, 0x19, 0x55, 0xd5, 0xa8, 0x9d, 0x4d, 0x74, 0xad, 0xf1, 0x04, 0x6b, 0xb3, 0x62, 0x19, 0x2f, 0x2e, 0xf6, 0xbd, 0x3e, 0x3d, 0x2d, 0x04, 0xdd, 0x1f, 0x87, 0x05, 0x4a, 0x00, 0xaa, 0x3f, 0xb2, 0x44, 0x83, 0x35, 0xf6, 0x94, 0xe3, 0xcd, 0xa4, 0xae, 0x0c, 0xc7, 0x1b, 0x1b, 0x2f, 0x2a, 0x20, 0x6f, 0xa8, 0x02, 0xd7, 0x26, 0x2f, 0x19, 0x98, 0x3c, 0x44, 0x67, 0x4f, 0xe1, 0x53, 0x27, 0xac, 0xaa, 0xc1, 0xfa, 0x40, 0x42, 0x4c, 0x39, 0x5a, 0x65, 0x56, 0xcb, 0x81, 0x67, 0x31, 0x25, 0x27, 0xfa, 0xe5, 0x86, 0x5e, 0xcf, 0xfc, 0x14, 0xbb, 0xdc, 0x17, 0xda, 0x78, 0xcd, 0xcf, ], priv = [ 0x00, 0x90, 0x12, 0xec, 0xfd, 0xad, 0xc8, 0x5c, 0xed, 0x63, 0x0a, 0xfe, 0xa5, 0x34, 0xcd, 0xc8, 0xe9, 0xd1, 0xab, 0x8b, 0xe5, 0xf3, 0x75, 0x3d, 0xcf, 0x5f, 0x2b, 0x09, 0xb4, 0x0e, 0xda, 0x66, 0xfc, 0x68, 0x58, 0x54, 0x9b, 0xc3, 0x6e, 0x6f, 0x8d, 0xf5, 0x59, 0x98, 0xcf, 0xa9, 0xa0, 0x70, 0x3a, 0xec, 0xf6, 0xc4, 0x27, 0x99, 0xc2, 0x45, 0x01, 0x10, 0x64, 0xf5, 0x30, 0xc0, 0x9d, 0xb9, 0x83, 0x69, ], pub = [ 0x04, 0x00, 0x23, 0x4e, 0x32, 0xbe, 0x0a, 0x90, 0x71, 0x31, 0xd2, 0xd1, 0x28, 0xa6, 0x47, 0x7e, 0x0c, 0xac, 0xeb, 0x86, 0xf0, 0x24, 0x79, 0x74, 0x5e, 0x0f, 0xe2, 0x45, 0xcb, 0x33, 0x2d, 0xe6, 0x31, 0xc0, 0x78, 0x87, 0x11, 0x60, 0x48, 0x2e, 0xee, 0xf5, 0x84, 0xe2, 0x74, 0xdf, 0x7f, 0xa4, 0x12, 0xce, 0xa3, 0xe1, 0xe9, 0x1f, 0x71, 0xec, 0xba, 0x87, 0x81, 0xd9, 0x20, 0x5d, 0x48, 0x38, 0x63, 0x41, 0xad, 0x01, 0xcf, 0x86, 0x45, 0x5b, 0x09, 0xb1, 0xc0, 0x05, 0xcf, 0xfb, 0xa8, 0xd7, 0x62, 0x89, 0xa3, 0x75, 0x96, 0x28, 0xc8, 0x74, 0xbe, 0xea, 0x46, 0x2f, 0x51, 0xf3, 0x0b, 0xd5, 0x81, 0xe3, 0x80, 0x31, 0x34, 0x30, 0x7d, 0xed, 0xbb, 0x77, 0x1b, 0x33, 0x34, 0xee, 0x15, 0xbe, 0x2e, 0x24, 0x2c, 0xd7, 0x9c, 0x34, 0x07, 0xd2, 0xf5, 0x89, 0x35, 0x45, 0x6c, 0x69, 0x41, 0xdd, 0x9b, 0x6d, 0x15, 0x5a, 0x46, ], shared = [ 0x01, 0x7f, 0x36, 0xaf, 0x19, 0x30, 0x38, 0x41, 0xd1, 0x3a, 0x38, 0x9d, 0x95, 0xec, 0x0b, 0x80, 0x1c, 0x7f, 0x9a, 0x67, 0x9a, 0x82, 0x31, 0x46, 0xc7, 0x5c, 0x17, 0xbc, 0x44, 0x25, 0x6e, 0x9a, 0xd4, 0x22, 0xa4, 0xf8, 0xb3, 0x1f, 0x14, 0x64, 0x7b, 0x2c, 0x7d, 0x31, 0x7b, 0x93, 0x3f, 0x7c, 0x29, 0x46, 0xc4, 0xb8, 0xab, 0xd1, 0xd5, 0x6d, 0x62, 0x0f, 0xab, 0x1b, 0x5f, 0xf1, 0xa3, 0xad, 0xc7, 0x1f, ], }, //COUNT = 12 testcase { otherpub = [ 0x04, 0x00, 0x83, 0x19, 0x2e, 0xd0, 0xb1, 0xcb, 0x31, 0xf7, 0x58, 0x17, 0x79, 0x49, 0x37, 0xf6, 0x6a, 0xd9, 0x1c, 0xf7, 0x45, 0x52, 0xcd, 0x51, 0x0c, 0xed, 0xb9, 0xfd, 0x64, 0x13, 0x10, 0x42, 0x2a, 0xf5, 0xd0, 0x9f, 0x22, 0x1c, 0xad, 0x24, 0x9e, 0xe8, 0x14, 0xd1, 0x6d, 0xd7, 0xac, 0x84, 0xde, 0xd9, 0xea, 0xcd, 0xc2, 0x83, 0x40, 0xfc, 0xfc, 0x9c, 0x0c, 0x06, 0xab, 0xe3, 0x0a, 0x2f, 0xc2, 0x8c, 0xd8, 0x00, 0x22, 0x12, 0xed, 0x86, 0x8c, 0x9b, 0xa0, 0xfb, 0x2c, 0x91, 0xe2, 0xc3, 0x9b, 0xa9, 0x39, 0x96, 0xa3, 0xe4, 0xeb, 0xf4, 0x5f, 0x28, 0x52, 0xd0, 0x92, 0x8c, 0x48, 0x93, 0x0e, 0x87, 0x5c, 0xc7, 0xb4, 0x28, 0xd0, 0xe7, 0xf3, 0xf4, 0xd5, 0x03, 0xe5, 0xd6, 0x0c, 0x68, 0xcb, 0x49, 0xb1, 0x3c, 0x24, 0x80, 0xcd, 0x48, 0x6b, 0xed, 0x92, 0x00, 0xca, 0xdd, 0xad, 0xdf, 0xe4, 0xff, 0x8e, 0x35, 0x62, ], priv = [ 0x01, 0xb5, 0xff, 0x84, 0x7f, 0x8e, 0xff, 0x20, 0xb8, 0x8c, 0xfa, 0xd4, 0x2c, 0x06, 0xe5, 0x8c, 0x37, 0x42, 0xf2, 0xf8, 0xf1, 0xfd, 0xfd, 0x64, 0xb5, 0x39, 0xba, 0x48, 0xc2, 0x59, 0x26, 0x92, 0x6b, 0xd5, 0xe3, 0x32, 0xb4, 0x56, 0x49, 0xc0, 0xb1, 0x84, 0xf7, 0x72, 0x55, 0xe9, 0xd5, 0x8f, 0xe8, 0xaf, 0xa1, 0xa6, 0xd9, 0x68, 0xe2, 0xcb, 0x1d, 0x46, 0x37, 0x77, 0x71, 0x20, 0xc7, 0x65, 0xc1, 0x28, ], pub = [ 0x04, 0x01, 0xde, 0x3d, 0xc9, 0x26, 0x3b, 0xc8, 0xc4, 0x96, 0x9d, 0xc6, 0x84, 0xbe, 0x0e, 0xec, 0x54, 0xbe, 0xfd, 0x9a, 0x9f, 0x3d, 0xba, 0x19, 0x4d, 0x86, 0x58, 0xa7, 0x89, 0x34, 0x1b, 0xf0, 0xd7, 0x8d, 0x84, 0xda, 0x67, 0x35, 0x22, 0x7c, 0xaf, 0xaf, 0x09, 0x35, 0x19, 0x51, 0x69, 0x11, 0x97, 0x57, 0x3c, 0x8c, 0x36, 0x0a, 0x11, 0xe5, 0x28, 0x57, 0x12, 0xb8, 0xbb, 0xdf, 0x5a, 0xc9, 0x1b, 0x97, 0x7c, 0x00, 0x81, 0x2d, 0xe5, 0x8c, 0xd0, 0x95, 0xec, 0x2e, 0x5a, 0x9b, 0x24, 0x7e, 0xb3, 0xed, 0x41, 0xd8, 0xbe, 0xf6, 0xae, 0xac, 0xe1, 0x94, 0xa7, 0xa0, 0x5b, 0x65, 0xaa, 0x5d, 0x28, 0x9f, 0xbc, 0x9b, 0x17, 0x70, 0xec, 0x84, 0xbb, 0x6b, 0xe0, 0xc2, 0xc6, 0x4c, 0xc3, 0x7c, 0x1d, 0x54, 0xa7, 0xf5, 0xd7, 0x13, 0x77, 0xa9, 0xad, 0xbe, 0x20, 0xf2, 0x6f, 0x6f, 0x2b, 0x54, 0x4a, 0x82, 0x1e, 0xa8, 0x31, ], shared = [ 0x00, 0x06, 0x2f, 0x9f, 0xc2, 0x9a, 0xe1, 0xa6, 0x8b, 0x2e, 0xe0, 0xdc, 0xf9, 0x56, 0xcb, 0xd3, 0x8c, 0x88, 0xae, 0x5f, 0x64, 0x5e, 0xaa, 0x54, 0x6b, 0x00, 0xeb, 0xe8, 0x7a, 0x72, 0x60, 0xbf, 0x72, 0x4b, 0xe2, 0x0d, 0x34, 0xb9, 0xd0, 0x20, 0x76, 0x65, 0x5c, 0x93, 0x3d, 0x05, 0x6b, 0x21, 0xe3, 0x04, 0xc2, 0x4d, 0xdb, 0x1d, 0xed, 0xf1, 0xdd, 0x76, 0xde, 0x61, 0x1f, 0xc4, 0xa2, 0x34, 0x03, 0x36, ], }, //COUNT = 13 testcase { otherpub = [ 0x04, 0x01, 0xa8, 0x9b, 0x63, 0x6a, 0x93, 0xe5, 0xd2, 0xba, 0x6c, 0x22, 0x92, 0xbf, 0x23, 0x03, 0x3a, 0x84, 0xf0, 0x6a, 0x3a, 0xc1, 0x22, 0x0e, 0xa7, 0x1e, 0x80, 0x6a, 0xfb, 0xe0, 0x97, 0xa8, 0x04, 0xcc, 0x67, 0xe9, 0xba, 0xa5, 0x14, 0xcf, 0xb6, 0xc1, 0x2c, 0x91, 0x94, 0xbe, 0x30, 0x21, 0x2b, 0xf7, 0xaa, 0xe7, 0xfd, 0xf6, 0xd3, 0x76, 0xc2, 0x12, 0xf0, 0x55, 0x4e, 0x65, 0x64, 0x63, 0xff, 0xab, 0x7e, 0x01, 0x82, 0xef, 0xca, 0xf7, 0x0f, 0xc4, 0x12, 0xd3, 0x36, 0x60, 0x2e, 0x01, 0x4d, 0xa4, 0x72, 0x56, 0xa0, 0xb6, 0x06, 0xf2, 0xad, 0xdc, 0xce, 0x80, 0x53, 0xbf, 0x81, 0x7a, 0xc8, 0x65, 0x6b, 0xb4, 0xe4, 0x2f, 0x14, 0xc8, 0xcb, 0xf2, 0xa6, 0x8f, 0x48, 0x8a, 0xb3, 0x5d, 0xcd, 0xf6, 0x40, 0x56, 0x27, 0x1d, 0xee, 0x1f, 0x60, 0x6a, 0x44, 0x0b, 0xa4, 0xbd, 0x4e, 0x5a, 0x11, 0xb8, 0xb8, 0xe5, 0x4f, ], priv = [ 0x01, 0x1a, 0x63, 0x47, 0xd4, 0xe8, 0x01, 0xc9, 0x19, 0x23, 0x48, 0x83, 0x54, 0xcc, 0x53, 0x3e, 0x7e, 0x35, 0xfd, 0xdf, 0x81, 0xff, 0x0f, 0xb7, 0xf5, 0x6b, 0xb0, 0x72, 0x6e, 0x0c, 0x29, 0xee, 0x5d, 0xcd, 0xc5, 0xf3, 0x94, 0xba, 0x54, 0xcf, 0x57, 0x26, 0x90, 0x48, 0xaa, 0xb6, 0xe0, 0x55, 0x89, 0x5c, 0x8d, 0xa2, 0x4b, 0x8b, 0x06, 0x39, 0xa7, 0x42, 0x31, 0x43, 0x90, 0xcc, 0x04, 0x19, 0x0e, 0xd6, ], pub = [ 0x04, 0x00, 0xfe, 0x30, 0x26, 0x7f, 0x33, 0xba, 0x5c, 0xde, 0xfc, 0x25, 0xcb, 0xb3, 0xc9, 0x32, 0x0d, 0xad, 0x9c, 0xcb, 0x1d, 0x7d, 0x37, 0x66, 0x44, 0x62, 0x0c, 0xa4, 0xfa, 0xde, 0xe5, 0x62, 0x6a, 0x3c, 0xed, 0xe2, 0x5a, 0xd2, 0x54, 0x62, 0x4d, 0xef, 0x72, 0x7a, 0x70, 0x48, 0xf7, 0x14, 0x5f, 0x76, 0x16, 0x2a, 0xa9, 0x80, 0x42, 0xf9, 0xb1, 0x23, 0xb2, 0x07, 0x6f, 0x8e, 0x8c, 0xf5, 0x9b, 0x3f, 0xdf, 0x00, 0x11, 0x45, 0xdc, 0x66, 0x31, 0x95, 0x3b, 0x6e, 0x29, 0x45, 0xe9, 0x43, 0x01, 0xd6, 0xcb, 0xb0, 0x98, 0xfe, 0x4b, 0x04, 0xf7, 0xee, 0x9b, 0x09, 0x41, 0x1d, 0xf1, 0x04, 0xdc, 0x82, 0xd7, 0xd7, 0x9e, 0xc4, 0x6a, 0x01, 0xed, 0x0f, 0x2d, 0x3e, 0x7d, 0xb6, 0xeb, 0x68, 0x06, 0x94, 0xbd, 0xeb, 0x10, 0x7c, 0x10, 0x78, 0xae, 0xc6, 0xca, 0xbd, 0x9e, 0xbe, 0xe3, 0xd3, 0x42, 0xfe, 0x7e, 0x54, 0xdf, ], shared = [ 0x01, 0x28, 0xab, 0x09, 0xbf, 0xec, 0x54, 0x06, 0x79, 0x9e, 0x61, 0x0f, 0x77, 0x2b, 0xa1, 0x7e, 0x89, 0x22, 0x49, 0xfa, 0x8e, 0x0e, 0x7b, 0x18, 0xa0, 0x4b, 0x91, 0x97, 0x03, 0x4b, 0x25, 0x0b, 0x48, 0x29, 0x4f, 0x18, 0x67, 0xfb, 0x96, 0x41, 0x51, 0x8f, 0x92, 0x76, 0x60, 0x66, 0xa0, 0x7a, 0x8b, 0x91, 0x7b, 0x0e, 0x76, 0x87, 0x9e, 0x10, 0x11, 0xe5, 0x1c, 0xcb, 0xd9, 0xf5, 0x40, 0xc5, 0x4d, 0x4f, ], }, //COUNT = 14 testcase { otherpub = [ 0x04, 0x01, 0x72, 0x00, 0xb3, 0xf1, 0x6a, 0x68, 0xcb, 0xae, 0xd2, 0xbf, 0x78, 0xba, 0x8c, 0xdd, 0xfb, 0x6c, 0xff, 0xac, 0x26, 0x2b, 0xba, 0x00, 0xfb, 0xc2, 0x5f, 0x9d, 0xc7, 0x2a, 0x07, 0xce, 0x59, 0x37, 0x29, 0x04, 0x89, 0x9f, 0x36, 0x4c, 0x44, 0xcb, 0x26, 0x4c, 0x09, 0x7b, 0x64, 0x7d, 0x44, 0x12, 0xbe, 0xe3, 0xe5, 0x19, 0x89, 0x2d, 0x53, 0x4d, 0x91, 0x29, 0xf8, 0xa2, 0x8f, 0x75, 0x00, 0xfe, 0xe7, 0x00, 0xba, 0xba, 0x8d, 0x67, 0x2a, 0x4f, 0x4a, 0x3b, 0x63, 0xde, 0x48, 0xb9, 0x6f, 0x56, 0xe1, 0x8d, 0xf5, 0xd6, 0x8f, 0x7d, 0x70, 0xd5, 0x10, 0x98, 0x33, 0xf4, 0x37, 0x70, 0xd6, 0x73, 0x2e, 0x06, 0xb3, 0x9a, 0xd6, 0x0d, 0x93, 0xe5, 0xb4, 0x3d, 0xb8, 0x78, 0x9f, 0x1e, 0xc0, 0xab, 0xa4, 0x72, 0x86, 0xa3, 0x9e, 0xa5, 0x84, 0x23, 0x5a, 0xce, 0xa7, 0x57, 0xdb, 0xf1, 0x3d, 0x53, 0xb5, 0x83, 0x64, ], priv = [ 0x00, 0x22, 0xb6, 0xd2, 0xa2, 0x2d, 0x71, 0xdf, 0xaa, 0x81, 0x1d, 0x2d, 0x9f, 0x9f, 0x31, 0xfb, 0xed, 0x27, 0xf2, 0xe1, 0xf3, 0xd2, 0x39, 0x53, 0x8d, 0xdf, 0x3e, 0x4c, 0xc8, 0xc3, 0x9a, 0x33, 0x02, 0x66, 0xdb, 0x25, 0xb7, 0xbc, 0x0a, 0x97, 0x04, 0xf1, 0x7b, 0xde, 0x7f, 0x35, 0x92, 0xbf, 0x5f, 0x1f, 0x2d, 0x4b, 0x56, 0x01, 0x3a, 0xac, 0xc3, 0xd8, 0xd1, 0xbc, 0x02, 0xf0, 0x0d, 0x31, 0x46, 0xcc, ], pub = [ 0x04, 0x00, 0xba, 0x38, 0xcf, 0xbf, 0x9f, 0xd2, 0x51, 0x8a, 0x3f, 0x61, 0xd4, 0x35, 0x49, 0xe7, 0xa6, 0xa6, 0xd2, 0x8b, 0x2b, 0xe5, 0x7f, 0xfd, 0x3e, 0x0f, 0xac, 0xeb, 0x63, 0x6b, 0x34, 0xed, 0x17, 0xe0, 0x44, 0xa9, 0xf2, 0x49, 0xda, 0xe8, 0xfc, 0x13, 0x2e, 0x93, 0x7e, 0x2d, 0x93, 0x49, 0xcd, 0x2e, 0xd7, 0x7b, 0xb1, 0x04, 0x9c, 0xeb, 0x69, 0x2a, 0x2e, 0xc5, 0xb1, 0x7a, 0xd6, 0x15, 0x02, 0xa6, 0x4c, 0x00, 0x1e, 0xc9, 0x1d, 0x30, 0x58, 0x57, 0x3f, 0xa6, 0xc0, 0x56, 0x4a, 0x02, 0xa1, 0xa0, 0x10, 0x16, 0x0c, 0x31, 0x3b, 0xc7, 0xc7, 0x35, 0x10, 0xdc, 0x98, 0x3e, 0x54, 0x61, 0x68, 0x2b, 0x5b, 0xe0, 0x0d, 0xbc, 0xe7, 0xe2, 0xc6, 0x82, 0xad, 0x73, 0xf2, 0x9c, 0xa8, 0x22, 0xcd, 0xc1, 0x11, 0xf6, 0x8f, 0xab, 0xe3, 0x3a, 0x7b, 0x38, 0x4a, 0x64, 0x83, 0x42, 0xc3, 0xcd, 0xb9, 0xf0, 0x50, 0xbc, 0xdb, ], shared = [ 0x01, 0x01, 0xe4, 0x62, 0xe9, 0xd9, 0x15, 0x99, 0x68, 0xf6, 0x44, 0x0e, 0x95, 0x6f, 0x11, 0xdc, 0xf2, 0x22, 0x7a, 0xe4, 0xae, 0xa8, 0x16, 0x67, 0x12, 0x2b, 0x6a, 0xf9, 0x23, 0x9a, 0x29, 0x1e, 0xb5, 0xd6, 0xcf, 0x5a, 0x40, 0x87, 0xf3, 0x58, 0x52, 0x5f, 0xca, 0xcf, 0xa4, 0x6b, 0xb2, 0xdb, 0x01, 0xa7, 0x5a, 0xf1, 0xba, 0x51, 0x9b, 0x2d, 0x31, 0xda, 0x33, 0xed, 0xa8, 0x7a, 0x9d, 0x56, 0x57, 0x48, ], }, //COUNT = 15 testcase { otherpub = [ 0x04, 0x00, 0x4e, 0xfd, 0x5d, 0xbd, 0x2f, 0x97, 0x9e, 0x38, 0x31, 0xce, 0x98, 0xf8, 0x23, 0x55, 0xd6, 0xca, 0x14, 0xa5, 0x75, 0x78, 0x42, 0x87, 0x58, 0x82, 0x99, 0x0a, 0xb8, 0x5a, 0xb9, 0xb7, 0x35, 0x2d, 0xd6, 0xb9, 0xb2, 0xf4, 0xea, 0x9a, 0x1e, 0x95, 0xc3, 0x88, 0x0d, 0x65, 0xd1, 0xf3, 0x60, 0x2f, 0x9c, 0xa6, 0x53, 0xdc, 0x34, 0x6f, 0xac, 0x85, 0x86, 0x58, 0xd7, 0x56, 0x26, 0xf4, 0xd4, 0xfb, 0x08, 0x00, 0x61, 0xcf, 0x15, 0xdb, 0xda, 0xa7, 0xf3, 0x15, 0x89, 0xc9, 0x84, 0x00, 0x37, 0x3d, 0xa2, 0x84, 0x50, 0x6d, 0x70, 0xc8, 0x9f, 0x07, 0x4e, 0xd2, 0x62, 0xa9, 0xe2, 0x81, 0x40, 0x79, 0x6b, 0x72, 0x36, 0xc2, 0xee, 0xf9, 0x90, 0x16, 0x08, 0x5e, 0x71, 0x55, 0x2f, 0xf4, 0x88, 0xc7, 0x2b, 0x73, 0x39, 0xfe, 0xfb, 0x79, 0x15, 0xc3, 0x84, 0x59, 0xcb, 0x20, 0xab, 0x85, 0xae, 0xc4, 0xe4, 0x50, 0x52, ], priv = [ 0x00, 0x5b, 0xac, 0xff, 0xf2, 0x68, 0xac, 0xf6, 0x55, 0x3c, 0x3c, 0x58, 0x3b, 0x46, 0x4e, 0xa3, 0x6a, 0x1d, 0x35, 0xe2, 0xb2, 0x57, 0xa5, 0xd4, 0x9e, 0xb3, 0x41, 0x9d, 0x5a, 0x09, 0x50, 0x87, 0xc2, 0xfb, 0x4d, 0x15, 0xcf, 0x5b, 0xf5, 0xaf, 0x81, 0x6d, 0x0f, 0x3f, 0xf7, 0x58, 0x64, 0x90, 0xcc, 0xd3, 0xdd, 0xc1, 0xa9, 0x8b, 0x39, 0xce, 0x63, 0x74, 0x9c, 0x62, 0x88, 0xce, 0x0d, 0xbd, 0xac, 0x7d, ], pub = [ 0x04, 0x00, 0x36, 0xe4, 0x88, 0xda, 0x75, 0x81, 0x47, 0x2a, 0x9d, 0x8e, 0x62, 0x8c, 0x58, 0xd6, 0xad, 0x72, 0x73, 0x11, 0xb7, 0xe6, 0xa3, 0xf6, 0xae, 0x33, 0xa8, 0x54, 0x4f, 0x34, 0xb0, 0x92, 0x80, 0x24, 0x90, 0x20, 0xbe, 0x71, 0x96, 0x91, 0x6f, 0xaf, 0xd9, 0x0e, 0x2e, 0xc5, 0x4b, 0x66, 0xb5, 0x46, 0x8d, 0x23, 0x61, 0xb9, 0x9b, 0x56, 0xfa, 0x00, 0xd7, 0xac, 0x37, 0xab, 0xb8, 0xc6, 0xf1, 0x66, 0x53, 0x01, 0x1e, 0xdb, 0x9f, 0xb8, 0xad, 0xb6, 0xa4, 0x3f, 0x4f, 0x5f, 0x5f, 0xdc, 0x14, 0x21, 0xc9, 0xfe, 0x04, 0xfc, 0x8b, 0xa4, 0x6c, 0x9b, 0x66, 0x33, 0x4e, 0x3a, 0xf9, 0x27, 0xc8, 0xbe, 0xfb, 0x43, 0x07, 0x10, 0x4f, 0x29, 0x9a, 0xce, 0xc4, 0xe3, 0x0f, 0x81, 0x2d, 0x93, 0x45, 0xc9, 0x72, 0x0d, 0x19, 0x86, 0x9d, 0xbf, 0xff, 0xd4, 0xca, 0x3e, 0x7d, 0x27, 0x13, 0xeb, 0x5f, 0xc3, 0xf4, 0x26, 0x15, ], shared = [ 0x01, 0x41, 0xd6, 0xa4, 0xb7, 0x19, 0xab, 0x67, 0xea, 0xf0, 0x4a, 0x92, 0xc0, 0xa4, 0x1e, 0x2d, 0xda, 0x78, 0xf4, 0x35, 0x4f, 0xb9, 0x0b, 0xdc, 0x35, 0x20, 0x2c, 0xc7, 0x69, 0x9b, 0x9b, 0x04, 0xd4, 0x96, 0x16, 0xf8, 0x22, 0x55, 0xde, 0xbf, 0x7b, 0xbe, 0xc0, 0x45, 0xae, 0x58, 0xf9, 0x82, 0xa6, 0x69, 0x05, 0xfc, 0xfa, 0xe6, 0x9d, 0x68, 0x97, 0x85, 0xe3, 0x8c, 0x86, 0x8e, 0xb4, 0xa2, 0x7e, 0x7b, ], }, //COUNT = 16 testcase { otherpub = [ 0x04, 0x01, 0x29, 0x89, 0x1d, 0xe0, 0xcf, 0x3c, 0xf8, 0x2e, 0x8c, 0x2c, 0xf1, 0xbf, 0x90, 0xbb, 0x29, 0x6f, 0xe0, 0x0a, 0xb0, 0x8c, 0xa4, 0x5b, 0xb7, 0x89, 0x2e, 0x0e, 0x22, 0x7a, 0x50, 0x4f, 0xdd, 0x05, 0xd2, 0x38, 0x1a, 0x44, 0x48, 0xb6, 0x8a, 0xdf, 0xf9, 0xc4, 0x15, 0x3c, 0x87, 0xea, 0xcb, 0x78, 0x33, 0x0d, 0x8b, 0xd5, 0x25, 0x15, 0xf9, 0xf9, 0xa0, 0xb5, 0x8e, 0x85, 0xf4, 0x46, 0xbb, 0x4e, 0x10, 0x00, 0x9e, 0xdd, 0x67, 0x96, 0x96, 0xd3, 0xd1, 0xd0, 0xef, 0x32, 0x7f, 0x20, 0x03, 0x83, 0x25, 0x3f, 0x64, 0x13, 0x68, 0x3d, 0x9e, 0x4f, 0xcc, 0x87, 0xbb, 0x35, 0xf1, 0x12, 0xc2, 0xf1, 0x10, 0x09, 0x8d, 0x15, 0xe5, 0x70, 0x1d, 0x7c, 0xee, 0xe4, 0x16, 0x29, 0x1f, 0xf5, 0xfe, 0xd8, 0x5e, 0x68, 0x7f, 0x72, 0x73, 0x88, 0xb9, 0xaf, 0xe2, 0x6a, 0x4f, 0x6f, 0xee, 0xd5, 0x60, 0xb2, 0x18, 0xe6, 0xbb, ], priv = [ 0x00, 0x8e, 0x2c, 0x93, 0xc5, 0x42, 0x38, 0x76, 0x22, 0x3a, 0x63, 0x7c, 0xad, 0x36, 0x7c, 0x85, 0x89, 0xda, 0x69, 0xa2, 0xd0, 0xfc, 0x68, 0x61, 0x2f, 0x31, 0x92, 0x3a, 0xe5, 0x02, 0x19, 0xdf, 0x24, 0x52, 0xe7, 0xcc, 0x92, 0x61, 0x5b, 0x67, 0xf1, 0x7b, 0x57, 0xff, 0xd2, 0xf5, 0x2b, 0x19, 0x15, 0x4b, 0xb4, 0x0d, 0x77, 0x15, 0x33, 0x64, 0x20, 0xfd, 0xe2, 0xe8, 0x9f, 0xee, 0x24, 0x4f, 0x59, 0xdc, ], pub = [ 0x04, 0x00, 0xfa, 0x3b, 0x35, 0x11, 0x8d, 0x6c, 0x42, 0x25, 0x70, 0xf7, 0x24, 0xa2, 0x6f, 0x90, 0xb2, 0x83, 0x3b, 0x19, 0x23, 0x91, 0x74, 0xce, 0xa0, 0x81, 0xc5, 0x31, 0x33, 0xf6, 0x4d, 0xb6, 0x0d, 0x69, 0x40, 0xea, 0x12, 0x61, 0x29, 0x9c, 0x04, 0xc1, 0xf4, 0x58, 0x7c, 0xdb, 0x0c, 0x4c, 0x39, 0x61, 0x64, 0x79, 0xc1, 0xbb, 0x0c, 0x14, 0x67, 0x99, 0xa1, 0x18, 0x03, 0x2d, 0xcf, 0x98, 0xf8, 0x99, 0xc0, 0x00, 0x69, 0xf0, 0x40, 0x22, 0x90, 0x06, 0x15, 0x1f, 0xa3, 0x2b, 0x51, 0xf6, 0x79, 0xc8, 0x81, 0x6f, 0x7c, 0x17, 0x50, 0x6b, 0x40, 0x38, 0x09, 0xdc, 0x77, 0xcd, 0x58, 0xa2, 0xae, 0xc4, 0x30, 0xd9, 0x4d, 0x13, 0xb6, 0xc9, 0x16, 0xde, 0x99, 0xf3, 0x55, 0xaa, 0x45, 0xfc, 0xfb, 0xc6, 0x85, 0x3d, 0x68, 0x6c, 0x71, 0xbe, 0x49, 0x6a, 0x06, 0x7d, 0x24, 0xbf, 0xae, 0xa4, 0x81, 0x8f, 0xc5, 0x1f, 0x75, ], shared = [ 0x00, 0x34, 0x5e, 0x26, 0xe0, 0xab, 0xb1, 0xaa, 0xc1, 0x2b, 0x75, 0xf3, 0xa9, 0xcf, 0x41, 0xef, 0xe1, 0xc3, 0x36, 0x39, 0x6d, 0xff, 0xa4, 0xa0, 0x67, 0xa4, 0xc2, 0xcf, 0xeb, 0x87, 0x8c, 0x68, 0xb2, 0xb0, 0x45, 0xfa, 0xa4, 0xe5, 0xb4, 0xe6, 0xfa, 0x46, 0x78, 0xf5, 0xb6, 0x03, 0xc3, 0x51, 0x90, 0x3b, 0x14, 0xbf, 0x9a, 0x6a, 0x70, 0xc4, 0x39, 0x25, 0x71, 0x99, 0xa6, 0x40, 0x89, 0x0b, 0x61, 0xd1, ], }, //COUNT = 17 testcase { otherpub = [ 0x04, 0x01, 0xa3, 0xc2, 0x02, 0x40, 0xe5, 0x9f, 0x5b, 0x7a, 0x3e, 0x17, 0xc2, 0x75, 0xd2, 0x31, 0x4b, 0xa1, 0x74, 0x12, 0x10, 0xad, 0x58, 0xb7, 0x10, 0x36, 0xf8, 0xc8, 0x3c, 0xc1, 0xf6, 0xb0, 0xf4, 0x09, 0xdf, 0xdd, 0x91, 0x13, 0xe9, 0x4b, 0x67, 0xec, 0x39, 0xc3, 0x29, 0x14, 0x26, 0xc2, 0x3f, 0xfc, 0xc4, 0x47, 0x05, 0x46, 0x70, 0xd2, 0x90, 0x8f, 0xf8, 0xfe, 0x67, 0xdc, 0x23, 0x06, 0x03, 0x4c, 0x5c, 0x01, 0xd2, 0x82, 0x5b, 0xfd, 0x3a, 0xf8, 0xb1, 0xe1, 0x32, 0x05, 0x78, 0x0c, 0x13, 0x7f, 0xe9, 0x38, 0xf8, 0x4f, 0xde, 0x40, 0x18, 0x8e, 0x61, 0xea, 0x02, 0xce, 0xad, 0x81, 0xba, 0xdf, 0xdb, 0x42, 0x5c, 0x29, 0xf7, 0xd7, 0xfb, 0x03, 0x24, 0xde, 0xba, 0xdc, 0x10, 0xbb, 0xb9, 0x3d, 0xe6, 0x8f, 0x62, 0xc3, 0x50, 0x69, 0x26, 0x82, 0x83, 0xf5, 0x26, 0x58, 0x65, 0xdb, 0x57, 0xa7, 0x9f, 0x7b, 0xf7, ], priv = [ 0x00, 0x04, 0xd4, 0x9d, 0x39, 0xd4, 0x0d, 0x81, 0x11, 0xbf, 0x16, 0xd2, 0x8c, 0x59, 0x36, 0x55, 0x43, 0x26, 0xb1, 0x97, 0x35, 0x3e, 0xeb, 0xbc, 0xf4, 0x75, 0x45, 0x39, 0x3b, 0xc8, 0xd3, 0xaa, 0xf9, 0x8f, 0x14, 0xf5, 0xbe, 0x70, 0x74, 0xbf, 0xb3, 0x8e, 0x6c, 0xc9, 0x7b, 0x98, 0x97, 0x54, 0x07, 0x4d, 0xad, 0xdb, 0x30, 0x45, 0xf4, 0xe4, 0xce, 0x74, 0x56, 0x69, 0xfd, 0xb3, 0xec, 0x0d, 0x5f, 0xa8, ], pub = [ 0x04, 0x01, 0x2e, 0xc2, 0x26, 0xd0, 0x50, 0xce, 0x07, 0xc7, 0x9b, 0x3d, 0xf4, 0xd0, 0xf0, 0x89, 0x1f, 0x9f, 0x7a, 0xdf, 0x46, 0x2e, 0x8c, 0x98, 0xdb, 0xc1, 0xa2, 0xa1, 0x4f, 0x5e, 0x53, 0xa3, 0xf5, 0xad, 0x89, 0x44, 0x33, 0x58, 0x7c, 0xc4, 0x29, 0xa8, 0xbe, 0x9e, 0xa1, 0xd8, 0x4f, 0xa3, 0x3b, 0x18, 0x03, 0x69, 0x0d, 0xae, 0x04, 0xda, 0x72, 0x18, 0xd3, 0x00, 0x26, 0x15, 0x7f, 0xc9, 0x95, 0xcf, 0x52, 0x00, 0x48, 0x37, 0xdf, 0xbf, 0x34, 0x26, 0xf5, 0x7b, 0x5c, 0x79, 0x32, 0x69, 0x13, 0x0a, 0xbb, 0x9a, 0x38, 0xf6, 0x18, 0x53, 0x22, 0x11, 0x93, 0x11, 0x54, 0xdb, 0x4e, 0xeb, 0x9a, 0xed, 0xe8, 0x8e, 0x57, 0x29, 0x0f, 0x84, 0x2e, 0xa0, 0xf2, 0xea, 0x9a, 0x5f, 0x74, 0xc6, 0x20, 0x3a, 0x39, 0x20, 0xfe, 0x4e, 0x30, 0x5f, 0x61, 0x18, 0xf6, 0x76, 0xb1, 0x54, 0xe1, 0xd7, 0x5b, 0x9c, 0xb5, 0xeb, 0x88, ], shared = [ 0x00, 0x6f, 0xe9, 0xde, 0x6f, 0xb8, 0xe6, 0x72, 0xe7, 0xfd, 0x15, 0x0f, 0xdc, 0x5e, 0x61, 0x7f, 0xab, 0xb0, 0xd4, 0x39, 0x06, 0x35, 0x4c, 0xcf, 0xd2, 0x24, 0x75, 0x7c, 0x72, 0x76, 0xf7, 0xa1, 0x01, 0x00, 0x91, 0xb1, 0x7e, 0xd0, 0x72, 0x07, 0x4f, 0x8d, 0x10, 0xa5, 0xec, 0x97, 0x1e, 0xb3, 0x5a, 0x5c, 0xb7, 0x07, 0x66, 0x03, 0xb7, 0xbc, 0x38, 0xd4, 0x32, 0xcb, 0xc0, 0x59, 0xf8, 0x0f, 0x94, 0x88, ], }, //COUNT = 18 testcase { otherpub = [ 0x04, 0x00, 0x7e, 0x2d, 0x13, 0x8f, 0x28, 0x32, 0xe3, 0x45, 0xae, 0x8f, 0xf6, 0x59, 0x57, 0xe4, 0x0e, 0x5e, 0xc7, 0x16, 0x3f, 0x01, 0x6b, 0xdf, 0x6d, 0x24, 0xa2, 0x24, 0x3d, 0xaa, 0x63, 0x1d, 0x87, 0x8a, 0x4a, 0x16, 0x78, 0x39, 0x90, 0xc7, 0x22, 0x38, 0x21, 0x30, 0xf9, 0xe5, 0x1f, 0x0c, 0x1b, 0xd6, 0xff, 0x5a, 0xc9, 0x67, 0x80, 0xe4, 0x8b, 0x68, 0xf5, 0xde, 0xc9, 0x5f, 0x42, 0xe6, 0x14, 0x4b, 0xb5, 0x00, 0xb0, 0xde, 0x5c, 0x89, 0x67, 0x91, 0xf5, 0x28, 0x86, 0xb0, 0xf0, 0x99, 0x13, 0xe2, 0x6e, 0x78, 0xdd, 0x0b, 0x69, 0x79, 0x8f, 0xc4, 0xdf, 0x6d, 0x95, 0xe3, 0xca, 0x70, 0x8e, 0xcb, 0xcb, 0xcc, 0xe1, 0xc1, 0x89, 0x5f, 0x55, 0x61, 0xbb, 0xab, 0xaa, 0xe3, 0x72, 0xe9, 0xe6, 0x7e, 0x6e, 0x1a, 0x3b, 0xe6, 0x0e, 0x19, 0xb4, 0x70, 0xcd, 0xf6, 0x73, 0xec, 0x1f, 0xc3, 0x93, 0xd3, 0x42, 0x6e, 0x20, ], priv = [ 0x01, 0x1a, 0x5d, 0x1c, 0xc7, 0x9c, 0xd2, 0xbf, 0x73, 0xea, 0x10, 0x6f, 0x0e, 0x60, 0xa5, 0xac, 0xe2, 0x20, 0x81, 0x3b, 0x53, 0xe2, 0x7b, 0x73, 0x98, 0x64, 0x33, 0x4a, 0x07, 0xc0, 0x33, 0x67, 0xef, 0xda, 0x7a, 0x46, 0x19, 0xfa, 0x6e, 0xef, 0x3a, 0x97, 0x46, 0x49, 0x22, 0x83, 0xb3, 0xc4, 0x45, 0x61, 0x0a, 0x02, 0x3a, 0x9c, 0xc4, 0x9b, 0xf4, 0x59, 0x11, 0x40, 0x38, 0x4f, 0xca, 0x5c, 0x8b, 0xb5, ], pub = [ 0x04, 0x00, 0xeb, 0x07, 0xc7, 0x33, 0x2e, 0xed, 0xb7, 0xd3, 0x03, 0x60, 0x59, 0xd3, 0x5f, 0x7d, 0x22, 0x88, 0xd4, 0x37, 0x7d, 0x5f, 0x42, 0x33, 0x7a, 0xd3, 0x96, 0x40, 0x79, 0xfb, 0x12, 0x0c, 0xcd, 0x4c, 0x8b, 0xd3, 0x84, 0xb5, 0x85, 0x62, 0x10, 0x55, 0x21, 0x70, 0x23, 0xac, 0xd9, 0xa9, 0x4f, 0xcb, 0x3b, 0x96, 0x5b, 0xfb, 0x39, 0x46, 0x75, 0xe7, 0x88, 0xad, 0xe4, 0x1a, 0x1d, 0xe7, 0x3e, 0x62, 0x0c, 0x00, 0x49, 0x1a, 0x83, 0x5d, 0xe2, 0xe6, 0xe7, 0xde, 0xb7, 0xe0, 0x90, 0xf4, 0xa1, 0x1f, 0x2c, 0x46, 0x0c, 0x0b, 0x1f, 0x3d, 0x5e, 0x94, 0xee, 0x8d, 0x75, 0x10, 0x14, 0xdc, 0x72, 0x07, 0x84, 0xfd, 0x3b, 0x54, 0x50, 0x0c, 0x86, 0xeb, 0xae, 0xf1, 0x84, 0x29, 0xf0, 0x9e, 0x8e, 0x87, 0x6d, 0x5d, 0x15, 0x38, 0x96, 0x8a, 0x03, 0x0d, 0x77, 0x15, 0xdd, 0xe9, 0x9f, 0x0d, 0x8f, 0x06, 0xe2, 0x9d, 0x59, ], shared = [ 0x01, 0xe4, 0xe7, 0x59, 0xec, 0xed, 0xce, 0x10, 0x13, 0xba, 0xf7, 0x3e, 0x6f, 0xcc, 0x0b, 0x92, 0x45, 0x1d, 0x03, 0xbd, 0xd5, 0x04, 0x89, 0xb7, 0x88, 0x71, 0xc3, 0x33, 0x11, 0x49, 0x90, 0xc9, 0xba, 0x6a, 0x9b, 0x2f, 0xc7, 0xb1, 0xa2, 0xd9, 0xa1, 0x79, 0x4c, 0x1b, 0x60, 0xd9, 0x27, 0x9a, 0xf6, 0xf1, 0x46, 0xf0, 0xbb, 0xfb, 0x06, 0x83, 0x14, 0x04, 0x03, 0xbf, 0xa4, 0xcc, 0xdb, 0x52, 0x4a, 0x29, ], }, //COUNT = 19 testcase { otherpub = [ 0x04, 0x00, 0x11, 0x8c, 0x36, 0x02, 0x22, 0x09, 0xb1, 0xaf, 0x8e, 0xba, 0xd1, 0xa1, 0x2b, 0x56, 0x6f, 0xc4, 0x87, 0x44, 0x57, 0x6e, 0x11, 0x99, 0xfe, 0x80, 0xde, 0x1c, 0xdf, 0x85, 0x1c, 0xdf, 0x03, 0xe5, 0xb9, 0x09, 0x1a, 0x8f, 0x7e, 0x07, 0x9e, 0x83, 0xb7, 0xf8, 0x27, 0x25, 0x9b, 0x69, 0x1d, 0x0c, 0x22, 0xee, 0x29, 0xd6, 0xbd, 0xf7, 0x3e, 0xc7, 0xbb, 0xfd, 0x74, 0x6f, 0x2c, 0xd9, 0x7a, 0x35, 0x7d, 0x00, 0xda, 0x5f, 0xf4, 0x90, 0x45, 0x48, 0xa3, 0x42, 0xe2, 0xe7, 0xba, 0x6a, 0x1f, 0x4e, 0xe5, 0xf8, 0x40, 0x41, 0x1a, 0x96, 0xcf, 0x63, 0xe6, 0xfe, 0x62, 0x2f, 0x22, 0xc1, 0x3e, 0x61, 0x4e, 0x0a, 0x84, 0x7c, 0x11, 0xa1, 0xab, 0x3f, 0x1d, 0x12, 0xcc, 0x85, 0x0c, 0x32, 0xe0, 0x95, 0x61, 0x4c, 0xa8, 0xf7, 0xe2, 0x72, 0x14, 0x77, 0xb4, 0x86, 0xe9, 0xff, 0x40, 0x37, 0x29, 0x77, 0xc3, 0xf6, 0x5c, ], priv = [ 0x01, 0x0c, 0x90, 0x8c, 0xaf, 0x1b, 0xe7, 0x4c, 0x61, 0x6b, 0x62, 0x5f, 0xc8, 0xc1, 0xf5, 0x14, 0x44, 0x6a, 0x6a, 0xec, 0x83, 0xb5, 0x93, 0x71, 0x41, 0xd6, 0xaf, 0xbb, 0x0a, 0x8c, 0x76, 0x66, 0xa7, 0x74, 0x6f, 0xa1, 0xf7, 0xa6, 0x66, 0x4a, 0x21, 0x23, 0xe8, 0xcd, 0xf6, 0xcd, 0x8b, 0xf8, 0x36, 0xc5, 0x6d, 0x3c, 0x0e, 0xbd, 0xcc, 0x98, 0x0e, 0x43, 0xa1, 0x86, 0xf9, 0x38, 0xf3, 0xa7, 0x8a, 0xe7, ], pub = [ 0x04, 0x00, 0x31, 0x89, 0x0f, 0x4c, 0x7a, 0xbe, 0xc3, 0xf7, 0x23, 0x36, 0x22, 0x85, 0xd7, 0x7d, 0x26, 0x36, 0xf8, 0x76, 0x81, 0x7d, 0xb3, 0xbb, 0xc8, 0x8b, 0x01, 0xe7, 0x73, 0x59, 0x7b, 0x96, 0x9f, 0xf6, 0xf0, 0x13, 0xea, 0x47, 0x0c, 0x85, 0x4a, 0xb4, 0xa7, 0x73, 0x90, 0x04, 0xeb, 0x8c, 0xbe, 0xa6, 0x9b, 0x82, 0xdd, 0xf3, 0x6a, 0xca, 0xdd, 0x40, 0x68, 0x71, 0x79, 0x8e, 0xcb, 0x2a, 0xc3, 0xaa, 0x7f, 0x00, 0xd8, 0xb4, 0x29, 0xae, 0x32, 0x50, 0x26, 0x6b, 0x96, 0x43, 0xc0, 0xc7, 0x65, 0xa6, 0x0d, 0xc1, 0x01, 0x55, 0xbc, 0x25, 0x31, 0xcf, 0x86, 0x27, 0x29, 0x6f, 0x49, 0x78, 0xb6, 0x64, 0x0a, 0x9e, 0x60, 0x0e, 0x19, 0xd0, 0x03, 0x7d, 0x58, 0x50, 0x3f, 0xa8, 0x07, 0x99, 0x54, 0x6a, 0x81, 0x4d, 0x74, 0x78, 0xa5, 0x50, 0xaa, 0x90, 0xe5, 0xeb, 0xeb, 0x05, 0x25, 0x27, 0xfa, 0xae, 0xae, 0x5d, 0x08, ], shared = [ 0x01, 0x63, 0xc9, 0x19, 0x1d, 0x65, 0x10, 0x39, 0xa5, 0xfe, 0x98, 0x5a, 0x0e, 0xea, 0x1e, 0xba, 0x01, 0x8a, 0x40, 0xab, 0x19, 0x37, 0xfc, 0xd2, 0xb6, 0x12, 0x20, 0x82, 0x0e, 0xe8, 0xf2, 0x30, 0x2e, 0x97, 0x99, 0xf6, 0xed, 0xfc, 0x3f, 0x51, 0x74, 0xf3, 0x69, 0xd6, 0x72, 0xd3, 0x77, 0xea, 0x89, 0x54, 0xa8, 0xd0, 0xc8, 0xb8, 0x51, 0xe8, 0x1a, 0x56, 0xfd, 0xa9, 0x52, 0x12, 0xa6, 0x57, 0x8f, 0x0e, ], }, //COUNT = 20 testcase { otherpub = [ 0x04, 0x01, 0x78, 0x0e, 0xdf, 0xf1, 0xca, 0x1c, 0x03, 0xcf, 0xbe, 0x59, 0x3e, 0xdc, 0x6c, 0x04, 0x9b, 0xcb, 0x28, 0x60, 0x29, 0x4a, 0x92, 0xc3, 0x55, 0x48, 0x9d, 0x9a, 0xfb, 0x2e, 0x70, 0x20, 0x75, 0xad, 0xe1, 0xc9, 0x53, 0x89, 0x5a, 0x45, 0x62, 0x30, 0xa0, 0xcd, 0xe9, 0x05, 0xde, 0x4a, 0x3f, 0x38, 0x57, 0x3d, 0xbf, 0xcc, 0xcd, 0x67, 0xad, 0x6e, 0x7e, 0x93, 0xf0, 0xb5, 0x58, 0x1e, 0x92, 0x6a, 0x5d, 0x00, 0xa5, 0x48, 0x19, 0x62, 0xc9, 0x16, 0x29, 0x62, 0xe7, 0xf0, 0xeb, 0xde, 0xc9, 0x36, 0x93, 0x5d, 0x0e, 0xaa, 0x81, 0x3e, 0x82, 0x26, 0xd4, 0x0d, 0x7f, 0x61, 0x19, 0xbf, 0xd9, 0x40, 0x60, 0x23, 0x80, 0xc8, 0x67, 0x21, 0xe6, 0x1d, 0xb1, 0x83, 0x0f, 0x51, 0xe1, 0x39, 0xf2, 0x10, 0x00, 0x0b, 0xce, 0xc0, 0xd8, 0xed, 0xd3, 0x9e, 0x54, 0xd7, 0x3a, 0x9a, 0x12, 0x9f, 0x95, 0xcd, 0x5f, 0xa9, 0x79, ], priv = [ 0x01, 0xb3, 0x7d, 0x6b, 0x72, 0x88, 0xde, 0x67, 0x13, 0x60, 0x42, 0x5d, 0x3e, 0x5a, 0xc1, 0xcc, 0xb2, 0x18, 0x15, 0x07, 0x9d, 0x8d, 0x73, 0x43, 0x1e, 0x9b, 0x74, 0xa6, 0xf0, 0xe7, 0xae, 0x00, 0x4a, 0x35, 0x75, 0x75, 0xb1, 0x1a, 0xd6, 0x66, 0x42, 0xce, 0x8b, 0x77, 0x55, 0x93, 0xeb, 0xa9, 0xd9, 0x8b, 0xf2, 0x5c, 0x75, 0xef, 0x0b, 0x4d, 0x3a, 0x20, 0x98, 0xbb, 0xc6, 0x41, 0xf5, 0x9a, 0x2b, 0x77, ], pub = [ 0x04, 0x00, 0x18, 0x9a, 0x5e, 0xe3, 0x4d, 0xe7, 0xe3, 0x5a, 0xef, 0xea, 0xee, 0xf9, 0x22, 0x0c, 0x18, 0x07, 0x1b, 0x4c, 0x29, 0xa4, 0xc3, 0xbd, 0x9d, 0x95, 0x44, 0x58, 0xbd, 0x3e, 0x82, 0xa7, 0xa3, 0x4d, 0xa3, 0x4c, 0xff, 0x55, 0x79, 0xb8, 0x10, 0x1c, 0x06, 0x5b, 0x1f, 0x2f, 0x52, 0x7c, 0xf4, 0x58, 0x15, 0x01, 0xe2, 0x8e, 0xf5, 0x67, 0x18, 0x73, 0xe6, 0x52, 0x67, 0x73, 0x3d, 0x00, 0x35, 0x20, 0xaf, 0x01, 0xeb, 0x4b, 0xc5, 0x0a, 0x7b, 0x4d, 0x45, 0x99, 0xd7, 0xe3, 0xfa, 0x77, 0x3d, 0xdb, 0x9e, 0xb2, 0x52, 0xc9, 0xb3, 0x42, 0x28, 0x72, 0xe5, 0x44, 0xbd, 0xf7, 0x5c, 0x7b, 0xf6, 0x0f, 0x51, 0x66, 0xdd, 0xc1, 0x1e, 0xb0, 0x8f, 0xa7, 0xc3, 0x08, 0x22, 0xda, 0xba, 0xee, 0x37, 0x3a, 0xb4, 0x68, 0xeb, 0x2d, 0x92, 0x2e, 0x48, 0x4e, 0x2a, 0x52, 0x7f, 0xff, 0x2e, 0xbb, 0x80, 0x4b, 0x7d, 0x9a, 0x37, ], shared = [ 0x01, 0x5d, 0x61, 0x3e, 0x26, 0x7a, 0x36, 0x34, 0x2e, 0x0d, 0x12, 0x5c, 0xda, 0xd6, 0x43, 0xd8, 0x0d, 0x97, 0xed, 0x06, 0x00, 0xaf, 0xb9, 0xe6, 0xb9, 0x54, 0x5c, 0x9e, 0x64, 0xa9, 0x8c, 0xc6, 0xda, 0x7c, 0x5a, 0xaa, 0x3a, 0x8d, 0xa0, 0xbd, 0xd9, 0xdd, 0x3b, 0x97, 0xe9, 0x78, 0x82, 0x18, 0xa8, 0x0a, 0xba, 0xfc, 0x10, 0x6e, 0xf0, 0x65, 0xc8, 0xf1, 0xc4, 0xe1, 0x11, 0x9e, 0xf5, 0x8d, 0x29, 0x8b, ], }, //COUNT = 21 testcase { otherpub = [ 0x04, 0x01, 0x6d, 0xac, 0xff, 0xa1, 0x83, 0xe5, 0x30, 0x30, 0x83, 0xa3, 0x34, 0xf7, 0x65, 0xde, 0x72, 0x4e, 0xc5, 0xec, 0x94, 0x02, 0x02, 0x6d, 0x47, 0x97, 0x88, 0x4a, 0x98, 0x28, 0xa0, 0xd3, 0x21, 0xa8, 0xcf, 0xac, 0x74, 0xab, 0x73, 0x7f, 0xe2, 0x0a, 0x7d, 0x6b, 0xef, 0xcf, 0xc7, 0x3b, 0x6a, 0x35, 0xc1, 0xc7, 0xb0, 0x1d, 0x37, 0x3e, 0x31, 0xab, 0xc1, 0x92, 0xd4, 0x8a, 0x42, 0x41, 0xa3, 0x58, 0x03, 0x01, 0x1e, 0x53, 0x27, 0xca, 0xc2, 0x2d, 0x30, 0x5e, 0x71, 0x56, 0xe5, 0x59, 0x17, 0x6e, 0x19, 0xbe, 0xe7, 0xe4, 0xf2, 0xf5, 0x9e, 0x86, 0xf1, 0xa9, 0xd0, 0xb6, 0x60, 0x3b, 0x6a, 0x7d, 0xf1, 0x06, 0x9b, 0xde, 0x63, 0x87, 0xfe, 0xb7, 0x15, 0x87, 0xb8, 0xff, 0xce, 0x5b, 0x26, 0x6e, 0x1b, 0xae, 0x86, 0xde, 0x29, 0x37, 0x8a, 0x34, 0xe5, 0xc7, 0x4b, 0x67, 0x24, 0xc4, 0xd4, 0x0a, 0x71, 0x99, 0x23, ], priv = [ 0x00, 0xf2, 0x66, 0x1a, 0xc7, 0x62, 0xf6, 0x0c, 0x5f, 0xff, 0x23, 0xbe, 0x5d, 0x96, 0x9c, 0xcd, 0x4e, 0xc6, 0xf9, 0x8e, 0x4e, 0x72, 0x61, 0x8d, 0x12, 0xbd, 0xcd, 0xb9, 0xb4, 0x10, 0x21, 0x62, 0x33, 0x37, 0x88, 0xc0, 0xba, 0xe5, 0x9f, 0x91, 0xcd, 0xfc, 0x17, 0x2c, 0x7a, 0x16, 0x81, 0xee, 0x44, 0xd9, 0x6a, 0xb2, 0x13, 0x5a, 0x6e, 0x5f, 0x34, 0x15, 0xeb, 0xbc, 0xd5, 0x51, 0x65, 0xb1, 0xaf, 0xb0, ], pub = [ 0x04, 0x00, 0xa8, 0xe2, 0x5a, 0x69, 0x02, 0xd6, 0x87, 0xb4, 0x78, 0x7c, 0xdc, 0x94, 0xc3, 0x64, 0xac, 0x7c, 0xec, 0xc5, 0xc4, 0x95, 0x48, 0x3e, 0xd3, 0x63, 0xdc, 0x0a, 0xa9, 0x5e, 0xe2, 0xbd, 0x73, 0x9c, 0x4c, 0x4d, 0x46, 0xb1, 0x70, 0x06, 0xc7, 0x28, 0xb0, 0x76, 0x35, 0x0d, 0x7d, 0x7e, 0x54, 0xc6, 0x82, 0x2f, 0x52, 0xf4, 0x71, 0x62, 0xa2, 0x51, 0x09, 0xaa, 0xab, 0xa6, 0x90, 0xca, 0xb6, 0x96, 0xec, 0x01, 0x68, 0xd2, 0xf0, 0x8f, 0xe1, 0x9e, 0x4d, 0xc9, 0xee, 0x7a, 0x19, 0x5b, 0x03, 0xc9, 0xf7, 0xfe, 0x66, 0x76, 0xf9, 0xf5, 0x20, 0xb6, 0x27, 0x05, 0x57, 0x50, 0x4e, 0x72, 0xca, 0x43, 0x94, 0xa2, 0xc6, 0x91, 0x86, 0x25, 0xe1, 0x5a, 0xc0, 0xc5, 0x1b, 0x8f, 0x95, 0xcd, 0x56, 0x01, 0x23, 0x65, 0x3f, 0xb8, 0xe8, 0xee, 0x6d, 0xb9, 0x61, 0xe2, 0xc4, 0xc6, 0x2c, 0xc5, 0x4e, 0x92, 0xe2, 0xa2, 0xa9, ], shared = [ 0x01, 0x4d, 0x60, 0x82, 0xa3, 0xb5, 0xce, 0xd1, 0xab, 0x8c, 0xa2, 0x65, 0xa8, 0x10, 0x6f, 0x30, 0x21, 0x46, 0xc4, 0xac, 0xb8, 0xc3, 0x0b, 0xb1, 0x4a, 0x4c, 0x99, 0x1e, 0x3c, 0x82, 0xa9, 0x73, 0x12, 0x88, 0xbd, 0xb9, 0x1e, 0x0e, 0x85, 0xbd, 0xa3, 0x13, 0x91, 0x2d, 0x06, 0x38, 0x4f, 0xc4, 0x4f, 0x21, 0x53, 0xfb, 0x13, 0x50, 0x6f, 0xa9, 0xcf, 0x43, 0xc9, 0xaa, 0xb5, 0x75, 0x09, 0x88, 0xc9, 0x43, ], }, //COUNT = 22 testcase { otherpub = [ 0x04, 0x00, 0xa0, 0x91, 0x42, 0x1d, 0x37, 0x03, 0xe3, 0xb3, 0x41, 0xe9, 0xf1, 0xe7, 0xd5, 0x8f, 0x8c, 0xf7, 0xbd, 0xbd, 0x17, 0x98, 0xd0, 0x01, 0x96, 0x7b, 0x80, 0x1d, 0x1c, 0xec, 0x27, 0xe6, 0x05, 0xc5, 0x80, 0xb2, 0x38, 0x7c, 0x1c, 0xb4, 0x64, 0xf5, 0x5c, 0xe7, 0xac, 0x80, 0x33, 0x41, 0x02, 0xab, 0x03, 0xcf, 0xb8, 0x6d, 0x88, 0xaf, 0x76, 0xc9, 0xf4, 0x12, 0x9c, 0x01, 0xbe, 0xdd, 0x3b, 0xbf, 0xc4, 0x00, 0x8c, 0x9c, 0x57, 0x7a, 0x8e, 0x6f, 0xc4, 0x46, 0x81, 0x5e, 0x9d, 0x40, 0xba, 0xa6, 0x60, 0x25, 0xf1, 0x5d, 0xae, 0x28, 0x5f, 0x19, 0xeb, 0x66, 0x8e, 0xe6, 0x0a, 0xe9, 0xc9, 0x8e, 0x7e, 0xcd, 0xbf, 0x2b, 0x2a, 0x68, 0xe2, 0x29, 0x28, 0x05, 0x9f, 0x67, 0xdb, 0x18, 0x80, 0x07, 0x16, 0x1d, 0x3e, 0xcf, 0x39, 0x7e, 0x08, 0x83, 0xf0, 0xc4, 0xeb, 0x7e, 0xaf, 0x78, 0x27, 0xa6, 0x22, 0x05, 0xcc, ], priv = [ 0x00, 0xf4, 0x30, 0xca, 0x12, 0x61, 0xf0, 0x96, 0x81, 0xa9, 0x28, 0x2e, 0x9e, 0x97, 0x0a, 0x92, 0x34, 0x22, 0x7b, 0x1d, 0x5e, 0x58, 0xd5, 0x58, 0xc3, 0xcc, 0x6e, 0xff, 0x44, 0xd1, 0xbd, 0xf5, 0x3d, 0xe1, 0x6a, 0xd5, 0xee, 0x2b, 0x18, 0xb9, 0x2d, 0x62, 0xfc, 0x79, 0x58, 0x61, 0x16, 0xb0, 0xef, 0xc1, 0x5f, 0x79, 0x34, 0x0f, 0xb7, 0xea, 0xf5, 0xce, 0x6c, 0x44, 0x34, 0x1d, 0xcf, 0x8d, 0xde, 0x27, ], pub = [ 0x04, 0x00, 0x6c, 0x1d, 0x9b, 0x5e, 0xca, 0x87, 0xde, 0x1f, 0xb8, 0x71, 0xa0, 0xa3, 0x2f, 0x80, 0x7c, 0x72, 0x5a, 0xdc, 0xcd, 0xe9, 0xb3, 0x96, 0x74, 0x53, 0xa7, 0x13, 0x47, 0xd6, 0x08, 0xf0, 0xc0, 0x30, 0xcd, 0x09, 0xe3, 0x38, 0xcd, 0xec, 0xbf, 0x4a, 0x02, 0x01, 0x5b, 0xc8, 0xa6, 0xe8, 0xd3, 0xe2, 0x59, 0x5f, 0xe7, 0x73, 0xff, 0xc2, 0xfc, 0x4e, 0x4a, 0x55, 0xd0, 0xb1, 0xa2, 0xcc, 0x00, 0x32, 0x3b, 0x01, 0x14, 0x1b, 0x21, 0x09, 0xe7, 0xf4, 0x98, 0x1c, 0x95, 0x2a, 0xa8, 0x18, 0xa2, 0xb9, 0xf6, 0xf5, 0xc4, 0x1f, 0xec, 0xcd, 0xb7, 0xa7, 0xa4, 0x5b, 0x9b, 0x4b, 0x67, 0x29, 0x37, 0x77, 0x1b, 0x00, 0x8c, 0xae, 0x5f, 0x93, 0x4d, 0xfe, 0x3f, 0xed, 0x10, 0xd3, 0x83, 0xab, 0x1f, 0x38, 0x76, 0x9c, 0x92, 0xce, 0x88, 0xd9, 0xbe, 0x54, 0x14, 0x81, 0x7e, 0xcb, 0x07, 0x3a, 0x31, 0xab, 0x36, 0x8c, 0xcb, ], shared = [ 0x00, 0x20, 0xc0, 0x07, 0x47, 0xcb, 0x8d, 0x49, 0x2f, 0xd4, 0x97, 0xe0, 0xfe, 0xc5, 0x46, 0x44, 0xbf, 0x02, 0x7d, 0x41, 0x8a, 0xb6, 0x86, 0x38, 0x1f, 0x10, 0x97, 0x12, 0xa9, 0x9c, 0xab, 0xe3, 0x28, 0xb9, 0x74, 0x3d, 0x22, 0x25, 0x83, 0x6f, 0x9a, 0xd6, 0x6e, 0x5d, 0x7f, 0xed, 0x1d, 0xe2, 0x47, 0xe0, 0xda, 0x92, 0xf6, 0x0d, 0x5b, 0x31, 0xf9, 0xe4, 0x76, 0x72, 0xe5, 0x7f, 0x71, 0x05, 0x98, 0xf4, ], }, //COUNT = 23 testcase { otherpub = [ 0x04, 0x00, 0x4f, 0x38, 0x81, 0x66, 0x81, 0x77, 0x12, 0x89, 0xce, 0x0c, 0xb8, 0x3a, 0x5e, 0x29, 0xa1, 0xab, 0x06, 0xfc, 0x91, 0xf7, 0x86, 0x99, 0x4b, 0x23, 0x70, 0x8f, 0xf0, 0x8a, 0x08, 0xa0, 0xf6, 0x75, 0xb8, 0x09, 0xae, 0x99, 0xe9, 0xf9, 0x96, 0x7e, 0xb1, 0xa4, 0x9f, 0x19, 0x60, 0x57, 0xd6, 0x9e, 0x50, 0xd6, 0xde, 0xdb, 0x4d, 0xd2, 0xd9, 0xa8, 0x1c, 0x02, 0xbd, 0xcc, 0x8f, 0x7f, 0x51, 0x84, 0x60, 0x00, 0x9e, 0xfb, 0x24, 0x4c, 0x8b, 0x91, 0x08, 0x7d, 0xe1, 0xee, 0xd7, 0x66, 0x50, 0x0f, 0x0e, 0x81, 0x53, 0x07, 0x52, 0xd4, 0x69, 0x25, 0x6e, 0xf7, 0x9f, 0x6b, 0x96, 0x5d, 0x8a, 0x22, 0x32, 0xa0, 0xc2, 0xdb, 0xc4, 0xe8, 0xe1, 0xd0, 0x92, 0x14, 0xba, 0xb3, 0x84, 0x85, 0xbe, 0x6e, 0x35, 0x7c, 0x42, 0x00, 0xd0, 0x73, 0xb5, 0x2f, 0x04, 0xe4, 0xa1, 0x6f, 0xc6, 0xf5, 0x24, 0x71, 0x87, 0xae, 0xcb, ], priv = [ 0x00, 0x5d, 0xc3, 0x3a, 0xed, 0xa0, 0x3c, 0x2e, 0xb2, 0x33, 0x01, 0x4e, 0xe4, 0x68, 0xdf, 0xf7, 0x53, 0xb7, 0x2f, 0x73, 0xb0, 0x09, 0x91, 0x04, 0x3e, 0xa3, 0x53, 0x82, 0x8a, 0xe6, 0x9d, 0x4c, 0xd0, 0xfa, 0xde, 0xda, 0x7b, 0xb2, 0x78, 0xb5, 0x35, 0xd7, 0xc5, 0x74, 0x06, 0xff, 0x2e, 0x6e, 0x47, 0x3a, 0x5a, 0x4f, 0xf9, 0x8e, 0x90, 0xf9, 0x0d, 0x6d, 0xad, 0xd2, 0x51, 0x00, 0xe8, 0xd8, 0x56, 0x66, ], pub = [ 0x04, 0x00, 0xc8, 0x25, 0xba, 0x30, 0x73, 0x73, 0xce, 0xc8, 0xdd, 0x24, 0x98, 0xee, 0xf8, 0x2e, 0x21, 0xfd, 0x98, 0x62, 0x16, 0x8d, 0xbf, 0xeb, 0x83, 0x59, 0x39, 0x80, 0xca, 0x9f, 0x82, 0x87, 0x53, 0x33, 0x89, 0x9f, 0xe9, 0x4f, 0x13, 0x7d, 0xaf, 0x1c, 0x41, 0x89, 0xeb, 0x50, 0x29, 0x37, 0xc3, 0xa3, 0x67, 0xea, 0x79, 0x51, 0xed, 0x8b, 0x0f, 0x33, 0x77, 0xfc, 0xdf, 0x29, 0x22, 0x02, 0x1d, 0x46, 0xa5, 0x01, 0x6b, 0x8a, 0x25, 0x40, 0xd5, 0xe6, 0x54, 0x93, 0x88, 0x8b, 0xc3, 0x37, 0x24, 0x9e, 0x67, 0xc0, 0xa6, 0x87, 0x74, 0xf3, 0xe8, 0xd8, 0x1e, 0x3b, 0x45, 0x74, 0xa0, 0x12, 0x51, 0x65, 0xf0, 0xbd, 0x58, 0xb8, 0xaf, 0x9d, 0xe7, 0x4b, 0x35, 0x83, 0x25, 0x39, 0xf9, 0x5c, 0x3c, 0xd9, 0xf1, 0xb7, 0x59, 0x40, 0x85, 0x60, 0xaa, 0x68, 0x51, 0xae, 0x3a, 0xc7, 0x55, 0x53, 0x47, 0xb0, 0xd3, 0xb1, 0x3b, ], shared = [ 0x00, 0xc2, 0xbf, 0xaf, 0xcd, 0x7f, 0xbd, 0x3e, 0x2f, 0xd1, 0xc7, 0x50, 0xfd, 0xea, 0x61, 0xe7, 0x0b, 0xd4, 0x78, 0x7a, 0x7e, 0x68, 0x46, 0x8c, 0x57, 0x4e, 0xe9, 0x9e, 0xbc, 0x47, 0xee, 0xde, 0xf0, 0x64, 0xe8, 0x94, 0x4a, 0x73, 0xbc, 0xb7, 0x91, 0x3d, 0xba, 0xb5, 0xd9, 0x3d, 0xca, 0x66, 0x0d, 0x21, 0x6c, 0x55, 0x36, 0x22, 0x36, 0x27, 0x94, 0xf7, 0xa2, 0xac, 0xc7, 0x10, 0x22, 0xbd, 0xb1, 0x6f, ], }, //COUNT = 24 testcase { otherpub = [ 0x04, 0x01, 0xa3, 0x20, 0x99, 0xb0, 0x2c, 0x0b, 0xd8, 0x53, 0x71, 0xf6, 0x0b, 0x0d, 0xd2, 0x08, 0x90, 0xe6, 0xc7, 0xaf, 0x04, 0x8c, 0x81, 0x79, 0x89, 0x0f, 0xda, 0x30, 0x8b, 0x35, 0x9d, 0xbb, 0xc2, 0xb7, 0xa8, 0x32, 0xbb, 0x8c, 0x65, 0x26, 0xc4, 0xaf, 0x99, 0xa7, 0xea, 0x3f, 0x0b, 0x3c, 0xb9, 0x6a, 0xe1, 0xeb, 0x76, 0x84, 0x13, 0x27, 0x95, 0xc4, 0x78, 0xad, 0x6f, 0x96, 0x2e, 0x4a, 0x6f, 0x44, 0x6d, 0x01, 0x76, 0x27, 0x35, 0x7b, 0x39, 0xe9, 0xd7, 0x63, 0x2a, 0x13, 0x70, 0xb3, 0xe9, 0x3c, 0x1a, 0xfb, 0x5c, 0x85, 0x1b, 0x91, 0x0e, 0xb4, 0xea, 0xd0, 0xc9, 0xd3, 0x87, 0xdf, 0x67, 0xcd, 0xe8, 0x50, 0x03, 0xe0, 0xe4, 0x27, 0x55, 0x2f, 0x1c, 0xd0, 0x90, 0x59, 0xaa, 0xd0, 0x26, 0x2e, 0x23, 0x5c, 0xce, 0x5f, 0xba, 0x8c, 0xed, 0xc4, 0xfd, 0xc1, 0x46, 0x3d, 0xa7, 0x6d, 0xcd, 0x4b, 0x6d, 0x1a, 0x46, ], priv = [ 0x00, 0xdf, 0x14, 0xb1, 0xf1, 0x43, 0x2a, 0x7b, 0x0f, 0xb0, 0x53, 0x96, 0x5f, 0xd8, 0x64, 0x3a, 0xfe, 0xe2, 0x6b, 0x24, 0x51, 0xec, 0xb6, 0xa8, 0xa5, 0x3a, 0x65, 0x5d, 0x5f, 0xbe, 0x16, 0xe4, 0xc6, 0x4c, 0xe8, 0x64, 0x72, 0x25, 0xeb, 0x11, 0xe7, 0xfd, 0xcb, 0x23, 0x62, 0x74, 0x71, 0xdf, 0xfc, 0x5c, 0x25, 0x23, 0xbd, 0x2a, 0xe8, 0x99, 0x57, 0xcb, 0xa3, 0xa5, 0x7a, 0x23, 0x93, 0x3e, 0x5a, 0x78, ], pub = [ 0x04, 0x00, 0x4e, 0x85, 0x83, 0xbb, 0xbb, 0x2e, 0xcd, 0x93, 0xf0, 0x71, 0x4c, 0x33, 0x2d, 0xff, 0x5a, 0xb3, 0xbc, 0x63, 0x96, 0xe6, 0x2f, 0x3c, 0x56, 0x02, 0x29, 0x66, 0x43, 0x29, 0xba, 0xa5, 0x13, 0x8c, 0x3b, 0xb1, 0xc3, 0x64, 0x28, 0xab, 0xd4, 0xe2, 0x3d, 0x17, 0xfc, 0xb7, 0xa2, 0xcf, 0xcc, 0x22, 0x4b, 0x2e, 0x73, 0x4c, 0x89, 0x41, 0xf6, 0xf1, 0x21, 0x72, 0x2d, 0x7b, 0x6b, 0x94, 0x15, 0x45, 0x76, 0x01, 0xcf, 0x08, 0x74, 0xf2, 0x04, 0xb0, 0x36, 0x3f, 0x02, 0x08, 0x64, 0x67, 0x2f, 0xad, 0xbf, 0x87, 0xc8, 0x81, 0x1e, 0xb1, 0x47, 0x75, 0x8b, 0x25, 0x4b, 0x74, 0xb1, 0x4f, 0xae, 0x74, 0x21, 0x59, 0xf0, 0xf6, 0x71, 0xa0, 0x18, 0x21, 0x2b, 0xbf, 0x25, 0xb8, 0x51, 0x9e, 0x12, 0x6d, 0x4c, 0xad, 0x77, 0x8c, 0xff, 0xf5, 0x0d, 0x28, 0x8f, 0xd3, 0x9c, 0xeb, 0x0c, 0xac, 0x63, 0x5b, 0x17, 0x5e, 0xc0, ], shared = [ 0x01, 0xaa, 0xf2, 0x4e, 0x5d, 0x47, 0xe4, 0x08, 0x0c, 0x18, 0xc5, 0x5e, 0xa3, 0x55, 0x81, 0xcd, 0x8d, 0xa3, 0x0f, 0x1a, 0x07, 0x95, 0x65, 0x04, 0x5d, 0x20, 0x08, 0xd5, 0x1b, 0x12, 0xd0, 0xab, 0xb4, 0x41, 0x1c, 0xda, 0x7a, 0x07, 0x85, 0xb1, 0x5d, 0x14, 0x9e, 0xd3, 0x01, 0xa3, 0x69, 0x70, 0x62, 0xf4, 0x2d, 0xa2, 0x37, 0xaa, 0x7f, 0x07, 0xe0, 0xaf, 0x3f, 0xd0, 0x0e, 0xb1, 0x80, 0x0d, 0x9c, 0x41, ], }, ]; hare-0.24.2/crypto/ecdsa/000077500000000000000000000000001464473310100151205ustar00rootroot00000000000000hare-0.24.2/crypto/ecdsa/README000066400000000000000000000010521464473310100157760ustar00rootroot00000000000000This module implements the elliptic curve digital signature algorithm for a selection of curves supported by [[crypto::ec]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/ecdsa/ecdsa.ha000066400000000000000000000243571464473310100165240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Ported from BearSSL // // Copyright (c) 2016 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use crypto::ec; use crypto::bigint; use hash; use crypto::bigint::{word}; def POINTSZ = 1 + ((ec::MAX_COORDBITSZ + bigint::WORD_BITSZ - 1) / bigint::WORD_BITSZ); // Maximum signature size of curves supported by [[crypto::ec]]. export def MAX_SIGSZ = ec::MAX_POINTSZ - 1; // Returns the size of a signature created/verifiable with given key. It is // [[crypto::ec::pointsz]] - 1 for the NIST curves. export fn sigsz(key: (*pubkey | *privkey)) size = { let c = match (key) { case let k: *pubkey => yield k.curve; case let k: *privkey => yield k.curve; }; return c.pointsz - 1; }; // Size of signature created with a P256 key. export def P256_SIGSZ = 64; // Size of signature created with a P384 key. export def P384_SIGSZ = 96; // Size of signature created with a P521 key. export def P521_SIGSZ = 132; // Verifies the signature 'sig' with message 'hash' using the public key 'pub'. // Returns [[invalidkey]] or [[invalidsig]] in case of error. An invalid key may // not be detected and causes an [[invalidsig]] in this case. Verification is // done in constant time, but may return earlier if the signature format is not // valid. export fn verify(pub: *pubkey, hash: []u8, sig: []u8) (void | error) = { // IMPORTANT: this code is fit only for curves with a prime // order. This is needed so that modular reduction of the X // coordinate of a point can be done with a simple subtraction. assert(pub.curve == ec::p256 || pub.curve == ec::p384 || pub.curve == ec::p521); let n: [POINTSZ]bigint::word = [0...]; let r: [POINTSZ]bigint::word = [0...]; let s: [POINTSZ]bigint::word = [0...]; let t: [POINTSZ*2]bigint::word = [0...]; let t1 = t[..POINTSZ]; let t2 = t[POINTSZ..]; let tx: [(ec::MAX_COORDBITSZ + 7) >> 3]u8 = [0...]; let ty: [(ec::MAX_COORDBITSZ + 7) >> 3]u8 = [0...]; let eu: [ec::MAX_POINTSZ]u8 = [0...]; let q = pub.get_q(pub); // Signature length must be even. if (len(sig) & 1 == 1) { return invalidsig; }; let rlen = len(sig) >> 1; let generator = pub.curve.generator(); // Public key point must have the proper size for this curve. if (len(q) != len(generator)) { return invalidkey; }; // Get modulus; then decode the r and s values. They must be // lower than the modulus, and s must not be null. let order = pub.curve.order(); const nlen = len(order); bigint::encode(n, order); let n0i = bigint::ninv(n[1]); if (bigint::encodemod(r, sig[..rlen], n) == 0) { return invalidsig; }; if (bigint::encodemod(s, sig[rlen..2 * rlen], n) == 0) { return invalidsig; }; if (bigint::iszero(s) == 1) { return invalidsig; }; // Invert s. We do that with a modular exponentiation; we use // the fact that for all the curves we support, the least // significant byte is not 0 or 1, so we can subtract 2 without // any carry to process. // We also want 1/s in Montgomery representation, which can be // done by converting _from_ Montgomery representation before // the inversion (because (1/s)*R = 1/(s/R)). bigint::frommonty(s, n, n0i); tx[..nlen] = order[..]; tx[nlen - 1] -= 2; bigint::modpow(s, tx[..nlen], n, n0i, t); t1[..] = [0...]; // Truncate the hash to the modulus length (in bits) and reduce // it modulo the curve order. The modular reduction can be done // with a subtraction since the truncation already reduced the // value to the modulus bit length. bits2int(t1, hash, n[0]); bigint::sub(t1, n, bigint::sub(t1, n, 0) ^ 1); // Multiply the (truncated, reduced) hash value with 1/s, result in // t2, encoded in ty. bigint::montymul(t2, t1, s, n, n0i); bigint::decode(ty[..nlen], t2); // Multiply r with 1/s, result in t1, encoded in tx. bigint::montymul(t1, r, s, n, n0i); bigint::decode(tx[..nlen], t1); // Compute the point x*Q + y*G. let ulen = len(generator); eu[..ulen] = q[..ulen]; let res = pub.curve.muladd(eu[..ulen], [], tx[..nlen], ty[..nlen]); // Get the X coordinate, reduce modulo the curve order, and // compare with the 'r' value. // // The modular reduction can be done with subtractions because // we work with curves of prime order, so the curve order is // close to the field order (Hasse's theorem). bigint::zero(t1, n[0]); bigint::encode(t1, eu[1..(ulen >> 1) + 1]); t1[0] = n[0]; bigint::sub(t1, n, bigint::sub(t1, n, 0) ^ 1); res &= ~bigint::sub(t1, r, 1); res &= bigint::iszero(t1); if (res != 1) { return invalidsig; }; }; def ORDER_LEN = (ec::MAX_COORDBITSZ + 7) >> 3; // Signs hashed message 'hash' with the private key and stores it into 'sig'. // Returns the number of bytes written to sig on success or [[invalidkey]] // otherwise. // // The signature is done in a deterministic way according to RFC 6979, hence // 'hashfn' and 'hashbuf' are required. 'hashfn' can be the same as the one that // created 'hash', though it might not be. The overall security will be limited // by the weaker of the two hash functions, according to the RFC. 'hashbuf' must // be of size [[hash::sz]] of 'hashfn' * 2 + [[hash::bsz]] of 'hashfn'. // // For the size requirenment of 'sig' see [[sigsz]]. export fn sign( priv: *privkey, hash: []u8, hashfn: *hash::hash, hashbuf: []u8, sig: []u8 ) (u32 | invalidkey) = { // IMPORTANT: this code is fit only for curves with a prime // order. This is needed so that modular reduction of the X // coordinate of a point can be done with a simple subtraction. // We also rely on the last byte of the curve order to be distinct // from 0 and 1. assert(priv.curve == ec::p256 || priv.curve == ec::p384 || priv.curve == ec::p521); let n: [POINTSZ]bigint::word = [0...]; let r: [POINTSZ]bigint::word = [0...]; let s: [POINTSZ]bigint::word = [0...]; let x: [POINTSZ]bigint::word = [0...]; let m: [POINTSZ]bigint::word = [0...]; let k: [POINTSZ]bigint::word = [0...]; let tmp: [POINTSZ * 2]bigint::word = [0...]; let tt: [ORDER_LEN << 1]u8 = [0...]; let eu: [ec::MAX_POINTSZ]u8 = [0...]; // Get modulus. let order = priv.curve.order(); const nlen = len(order); bigint::encode(n, order); const n0i = bigint::ninv(n[1]); // Get private key as an i31 integer. This also checks that the // private key is well-defined (not zero, and less than the // curve order). if (bigint::encodemod(x, priv.get_x(priv), n) == 0) { return invalidkey; }; if (bigint::iszero(x) == 1) { return invalidkey; }; // Truncate and reduce the hash value modulo the curve order. bits2int(m, hash, n[0]); bigint::sub(m, n, bigint::sub(m, n, 0) ^ 1); bigint::decode(tt[..nlen], x); bigint::decode(tt[nlen..nlen * 2], m); // RFC 6979 generation of the "k" value. // // The process uses HMAC_DRBG (with the hash function used to // process the message that is to be signed). The seed is the // concatenation of the encodings of the private key and // the hash value (after truncation and modular reduction). hash::reset(hashfn); let drbg = hmac_drbg(hashfn, tt[..nlen*2], hashbuf); for (true) { hmac_drbg_generate(&drbg, eu[..nlen]); bits2int(k, eu[..nlen], n[0]); if (bigint::iszero(k) == 1) continue; if (bigint::sub(k, n, 0) > 0) { break; }; }; // Compute k*G and extract the X coordinate, then reduce it // modulo the curve order. Since we support only curves with // prime order, that reduction is only a matter of computing // a subtraction. bigint::decode(tt[..nlen], k[..]); let ulen = priv.curve.mulgen(eu, tt[..nlen]); bigint::zero(r, n[0]); bigint::encode(r, eu[1..(ulen >> 1) + 1]); r[0] = n[0]; bigint::sub(r, n, bigint::sub(r, n, 0) ^ 1); // Compute 1/k in double-Montgomery representation. We do so by // first converting _from_ Montgomery representation (twice), // then using a modular exponentiation. bigint::frommonty(k, n, n0i); bigint::frommonty(k, n, n0i); tt[..nlen] = order[..nlen]; tt[nlen - 1] -= 2; bigint::modpow(k, tt[..nlen], n, n0i, tmp); // Compute s = (m+xr)/k (mod n). // The k[] array contains R^2/k (double-Montgomery representation); // we thus can use direct Montgomery multiplications and conversions // from Montgomery, avoiding any call to br_i31_to_monty() (which // is slower). let t1 = tmp[..POINTSZ]; let t2 = tmp[POINTSZ..]; bigint::frommonty(m, n, n0i); bigint::montymul(t1, x, r, n, n0i); let ctl = bigint::add(t1, m, 1); ctl |= bigint::sub(t1, n, 0) ^ 1; bigint::sub(t1, n, ctl); bigint::montymul(s, t1, k, n, n0i); // Encode r and s in the signature. bigint::decode(sig[..nlen], r); bigint::decode(sig[nlen..nlen*2], s); return (nlen << 1): u32; }; // Decode some bytes as an i31 integer, with truncation (corresponding // to the 'bits2int' operation in RFC 6979). The target ENCODED bit // length is provided as last parameter. The resulting value will have // this declared bit length, and consists the big-endian unsigned decoding // of exactly that many bits in the source (capped at the source length). fn bits2int(x: []bigint::word, src: []u8, ebitlen: bigint::word) void = { let sc: i32 = 0; let l: size = len(src); let bitlen: u32 = ebitlen - (ebitlen >> 5); let hbitlen = len(src): u32 << 3; if (hbitlen > bitlen) { l = (bitlen + 7) >> 3; sc = ((hbitlen - bitlen) & 7): i32; }; bigint::zero(x, ebitlen); bigint::encode(x, src[..l]); bigint::rshift(x, sc: bigint::word); x[0] = ebitlen; }; hare-0.24.2/crypto/ecdsa/error.ha000066400000000000000000000006731464473310100165710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Invalid key. export type invalidkey = !void; // Invalid signature. export type invalidsig = !void; // Possible ecdsa errors. export type error = !(invalidkey | invalidsig); // String representation of error 'e'. export fn strerror(e: error) str = { match (e) { case invalidkey => return "Invalid key"; case invalidsig => return "Invalid sig"; }; }; hare-0.24.2/crypto/ecdsa/hmac_drbg.ha000066400000000000000000000047361464473310100173520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::hmac; use crypto::mac; use crypto::sha1; use hash; // Partial HMAC_DRBG implementation as describe in RFC6979 Section 3.1.1 type drbg = struct { h: *hash::hash, k: []u8, v: []u8, initgen: bool, buf: []u8, }; // 'buf' must be at least 2 * hash::sz(h) + hash::bsz(h) fn hmac_drbg(h: *hash::hash, seed: const []u8, buf: []u8) drbg = { const hlen = hash::sz(h); assert(len(buf) >= 2 * hlen + hash::bsz(h)); let s = drbg { h = h, k = buf[..hlen], v = buf[hlen..2*hlen], initgen = true, buf = buf[2*hlen..], }; s.k[..] = [0...]; s.v[..] = [1...]; hash::reset(h); let hm = hmac::hmac(h, s.k, s.buf); mac::write(&hm, s.v); mac::write(&hm, [0x00]); mac::write(&hm, seed); mac::sum(&hm, s.k); hmac_drbg_update(&s); hash::reset(h); let hm = hmac::hmac(h, s.k, s.buf); mac::write(&hm, s.v); mac::write(&hm, [0x01]); mac::write(&hm, seed); mac::sum(&hm, s.k); hmac_drbg_update(&s); return s; }; fn hmac_drbg_update(s: *drbg) void = { hash::reset(s.h); let hm = hmac::hmac(s.h, s.k, s.buf); mac::write(&hm, s.v); mac::sum(&hm, s.v); }; fn hmac_drbg_generate(s: *drbg, dest: []u8) void = { if (!s.initgen) { hash::reset(s.h); let hm = hmac::hmac(s.h, s.k, s.buf); mac::write(&hm, s.v); mac::write(&hm, [0x00]); mac::sum(&hm, s.k); hmac_drbg_update(s); }; s.initgen = false; let n = 0z; for (n < len(dest)) { hmac_drbg_update(s); const remain = len(dest) - n; let max = if (remain > len(s.v)) len(s.v) else remain; dest[n..n+max] = s.v[..max]; n += max; }; }; @test fn hmac_drbg() void = { const seed: [_]u8 = [ 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66, 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8, ]; let h = sha1::sha1(); let buf: [sha1::SZ * 2 + sha1::BLOCKSZ]u8 = [0...]; let s = hmac_drbg(&h, seed, buf); let dest: [30]u8 = [0...]; hmac_drbg_generate(&s, dest); const expect: [_]u8 = [ 0x4e, 0xea, 0xad, 0x22, 0xb1, 0xbc, 0x51, 0x9e, 0xe6, 0xaa, 0x5a, 0x56, 0xd7, 0xab, 0x29, 0xc3, 0x39, 0xc4, 0xea, 0x10, 0x11, 0x2e, 0xe5, 0x4e, 0x2a, 0x6f, 0x81, 0xcd, 0x19, 0x7a, ]; assert(bytes::equal(expect, dest)); const expect: [_]u8 = [ 0xe2, 0x1f, 0x3a, 0x90, 0x38, 0xc4, 0xc6, 0xe1, 0xa5, 0x0c, 0x72, 0x6c, 0x04, 0x90, 0xe0, 0x6a, 0xa3, 0xcb, 0x8c, 0xce, 0xd2, 0x89, 0x1d, 0x01, 0xf3, ]; hmac_drbg_generate(&s, dest); assert(bytes::equal(expect, dest[..25])); }; hare-0.24.2/crypto/ecdsa/key.ha000066400000000000000000000122651464473310100162300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::ec; use io; export type pubkey = struct { curve: *ec::curve, get_q: *fn (pub: *pubkey) []u8, }; export type privkey = struct { curve: *ec::curve, get_x: *fn (priv: *privkey) []u8, }; export type p256privkey = struct { priv: privkey, x: [ec::P256_SCALARSZ]u8, }; export type p384privkey = struct { priv: privkey, x: [ec::P384_SCALARSZ]u8, }; export type p521privkey = struct { priv: privkey, x: [ec::P521_SCALARSZ]u8, }; fn p256_get_x(priv: *privkey) []u8 = (priv: *p256privkey).x; fn p384_get_x(priv: *privkey) []u8 = (priv: *p384privkey).x; fn p521_get_x(priv: *privkey) []u8 = (priv: *p521privkey).x; // Creates an unitialized p256 [[privkey]]. The curve is also known as secp256r1 // or prime256. The key must be initialized using [[newkey]]. The key must be // finished with [[privkey_finish]] to wipe it from memory. export fn p256priv() p256privkey = p256privkey { priv = privkey { curve = ec::p256, get_x = &p256_get_x, }, ... }; // Creates an unitialized p384 [[privkey]]. The curve is also known as // secp384r1. The key must be initialized using [[newkey]]. The key must be // finished with [[privkey_finish]] to wipe it from memory. export fn p384priv() p384privkey = p384privkey { priv = privkey { curve = ec::p384, get_x = &p384_get_x, }, ... }; // Creates an unitialized p521 [[privkey]]. The curve is also known as // secp521r1. The key must be initialized using [[newkey]]. The key must be // finished with [[privkey_finish]] to wipe it from memory. export fn p521priv() p521privkey = p521privkey { priv = privkey { curve = ec::p521, get_x = &p521_get_x, }, ... }; fn p256_get_q(pub: *pubkey) []u8 = (pub: *p256pubkey).q; fn p384_get_q(pub: *pubkey) []u8 = (pub: *p384pubkey).q; fn p521_get_q(pub: *pubkey) []u8 = (pub: *p521pubkey).q; // Generates a key seeding from the 'rand' stream and stores it in 'priv'. // 'rand' must be a cryptographic random generator like // [[crypto::random::stream]]. export fn newkey(priv: *privkey, rand: io::handle) (void | io::error) = { ec::keygen(priv.curve, priv.get_x(priv), rand)?; }; // Returns the buffer to the encoded key. See [[crypto::ec::curve]] on how the // scalar must be encoded. The key must be valid, otherwise undefined behaviour // may result. The function [[privkey_validate]] checks if the scalar is valid // for given curve. export fn privkey_buf(priv: *privkey) []u8 = priv.get_x(priv); // Checks whether 'priv' is a valid private key. export fn privkey_validate(priv: *privkey) (void | invalidkey) = { match (ec::validate_scalar(priv.curve, priv.get_x(priv))) { case void => void; case ec::invalid => return invalidkey; }; }; // Wipes private key data from memory. export fn privkey_finish(priv: *privkey) void = { bytes::zero(priv.get_x(priv)); }; export type p256pubkey = struct { pub: pubkey, q: [ec::P256_POINTSZ]u8, }; export type p384pubkey = struct { pub: pubkey, q: [ec::P384_POINTSZ]u8, }; export type p521pubkey = struct { pub: pubkey, q: [ec::P521_POINTSZ]u8, }; // Creates an unitialized p256 [[pubkey]]. The curve is also known as secp256r1 // or prime256. export fn p256pub() p256pubkey = p256pubkey { pub = pubkey { curve = ec::p256, get_q = &p256_get_q, }, ... }; export fn p384pub() p384pubkey = p384pubkey { pub = pubkey { curve = ec::p384, get_q = &p384_get_q, }, ... }; export fn p521pub() p521pubkey = p521pubkey { pub = pubkey { curve = ec::p521, get_q = &p521_get_q, }, ... }; // Initializes the pubkey 'pub' from the coordinates 'x' and 'y' of a public // point. // // Does not validate if the point is on curve. [[verify]] will fail, if such is // the case. export fn pubkey_init(pub: *pubkey, x: []u8, y: []u8) (void | invalidkey) = { const csz = pub.curve.pointsz / 2; if (len(x) > csz || len(y) > csz) { return invalidkey; }; let q = pub.get_q(pub); q[..] = [0x04, 0x00...]; const xoff = 1 + (csz - len(x)); const yoff = 1 + xoff + (csz - len(y)); q[xoff..xoff + len(x)] = x[..]; q[yoff..] = y[..]; }; // Derives the public key from given 'priv' and stores it into 'pub'. export fn pubkey_derive(pub: *pubkey, priv: *privkey) void = { assert(pub.curve == priv.curve); priv.curve.mulgen(pub.get_q(pub), priv.get_x(priv)); }; // Returns the buffer to the point stored in 'pub' to be able to store or read // the point in encoded form. See [[crypto::ec::curve]] for how the point is // and must be encoded. export fn pubkey_buf(pub: *pubkey) []u8 = pub.get_q(pub); // Validates if the pubkey is encoded properly. Does not check if the point is // on curve. [[verify]] will fail, if the point is not on the curve. export fn pubkey_validate_format(pub: *pubkey) (void | invalidkey) = { match (ec::validate_pointformat(pub.curve, pub.get_q(pub))) { case void => void; case ec::invalid => return invalidkey; }; }; // Validates the key of 'pub' and checks whether the point is on the curve. // This operation is expensive and is not strictly necessary, since this is // done during [[verify]] also. export fn pubkey_validate(pub: *pubkey) (void | invalidkey) = { match (ec::validate_point(pub.curve, pub.get_q(pub))) { case void => void; case ec::invalid => return invalidkey; }; }; hare-0.24.2/crypto/ecdsa/rfc6979+test.ha000066400000000000000000000364011464473310100175220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::sha1; use crypto::sha256; use crypto::sha512; use encoding::hex; use hash; use io; use strings; use test; const p256q: [_]u8 = [ 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99 ]; const p256x: [_]u8 = [ 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21 ]; const p384q: [_]u8 = [ 0x04, 0xec, 0x3a, 0x4e, 0x41, 0x5b, 0x4e, 0x19, 0xa4, 0x56, 0x86, 0x18, 0x02, 0x9f, 0x42, 0x7f, 0xa5, 0xda, 0x9a, 0x8b, 0xc4, 0xae, 0x92, 0xe0, 0x2e, 0x06, 0xaa, 0xe5, 0x28, 0x6b, 0x30, 0x0c, 0x64, 0xde, 0xf8, 0xf0, 0xea, 0x90, 0x55, 0x86, 0x60, 0x64, 0xa2, 0x54, 0x51, 0x54, 0x80, 0xbc, 0x13, 0x80, 0x15, 0xd9, 0xb7, 0x2d, 0x7d, 0x57, 0x24, 0x4e, 0xa8, 0xef, 0x9a, 0xc0, 0xc6, 0x21, 0x89, 0x67, 0x08, 0xa5, 0x93, 0x67, 0xf9, 0xdf, 0xb9, 0xf5, 0x4c, 0xa8, 0x4b, 0x3f, 0x1c, 0x9d, 0xb1, 0x28, 0x8b, 0x23, 0x1c, 0x3a, 0xe0, 0xd4, 0xfe, 0x73, 0x44, 0xfd, 0x25, 0x33, 0x26, 0x47, 0x20 ]; const p384x: [_]u8 = [ 0x6b, 0x9d, 0x3d, 0xad, 0x2e, 0x1b, 0x8c, 0x1c, 0x05, 0xb1, 0x98, 0x75, 0xb6, 0x65, 0x9f, 0x4d, 0xe2, 0x3c, 0x3b, 0x66, 0x7b, 0xf2, 0x97, 0xba, 0x9a, 0xa4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xd8, 0x96, 0xd5, 0x72, 0x4e, 0x4c, 0x70, 0xa8, 0x25, 0xf8, 0x72, 0xc9, 0xea, 0x60, 0xd2, 0xed, 0xf5 ]; const p521q: [_]u8 = [ 0x04, 0x01, 0x89, 0x45, 0x50, 0xd0, 0x78, 0x59, 0x32, 0xe0, 0x0e, 0xaa, 0x23, 0xb6, 0x94, 0xf2, 0x13, 0xf8, 0xc3, 0x12, 0x1f, 0x86, 0xdc, 0x97, 0xa0, 0x4e, 0x5a, 0x71, 0x67, 0xdb, 0x4e, 0x5b, 0xcd, 0x37, 0x11, 0x23, 0xd4, 0x6e, 0x45, 0xdb, 0x6b, 0x5d, 0x53, 0x70, 0xa7, 0xf2, 0x0f, 0xb6, 0x33, 0x15, 0x5d, 0x38, 0xff, 0xa1, 0x6d, 0x2b, 0xd7, 0x61, 0xdc, 0xac, 0x47, 0x4b, 0x9a, 0x2f, 0x50, 0x23, 0xa4, 0x00, 0x49, 0x31, 0x01, 0xc9, 0x62, 0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, 0x41, 0x39, 0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, 0x63, 0x0f, 0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, 0xa8, 0x28, 0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, 0xd4, 0xd3, 0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, 0xfc, 0xf5 ]; const p521x: [_]u8 = [ 0x00, 0xfa, 0xd0, 0x6d, 0xaa, 0x62, 0xba, 0x3b, 0x25, 0xd2, 0xfb, 0x40, 0x13, 0x3d, 0xa7, 0x57, 0x20, 0x5d, 0xe6, 0x7f, 0x5b, 0xb0, 0x01, 0x8f, 0xee, 0x8c, 0x86, 0xe1, 0xb6, 0x8c, 0x7e, 0x75, 0xca, 0xa8, 0x96, 0xeb, 0x32, 0xf1, 0xf4, 0x7c, 0x70, 0x85, 0x58, 0x36, 0xa6, 0xd1, 0x6f, 0xcc, 0x14, 0x66, 0xf6, 0xd8, 0xfb, 0xec, 0x67, 0xdb, 0x89, 0xec, 0x0c, 0x08, 0xb0, 0xe9, 0x96, 0xb8, 0x35, 0x38 ]; type hashf = enum { SHA1, SHA224, SHA256, SHA384, SHA512, }; type tcurveid = enum { P256, P384, P521, }; type testcase = struct { curve: tcurveid, qpoint: []u8, x: []u8, hashf: hashf, msg: str, k: str, sig: str, }; // XXX: alloc is used to circumvent not initialisable during compiletime error. fn rfc6979_cases() []testcase = alloc([ // Test vectors for P-256, from RFC 6979 testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA1, msg = "sample", k = "882905f1227fd620fbf2abf21244f0ba83d0dc3a9103dbbee43a1fb858109db4", sig = "61340c88c3aaebeb4f6d667f672ca9759a6ccaa9fa8811313039ee4a35471d32" "6d7f147dac089441bb2e2fe8f7a3fa264b9c475098fdcf6e00d7c996e1b8b7eb", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA256, msg = "sample", k = "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60", sig = "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA256, msg = "sample", k = "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60", sig = "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA384, msg = "sample", k = "09f634b188cefd98e7ec88b1aa9852d734d0bc272f7d2a47decc6ebeb375aad4", sig = "0eafea039b20e9b42309fb1d89e213057cbf973dc0cfc8f129edddc800ef77194861f0491e6998b9455193e34e7b0d284ddd7149a74b95b9261f13abde940954", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA512, msg = "sample", k = "5fa81c63109badb88c1f367b47da606da28cad69aa22c4fe6ad7df73a7173aa5", sig = "8496a60b5e9b47c825488827e0495b0e3fa109ec4568fd3f8d1097678eb97f002362ab1adbe2b8adf9cb9edab740ea6049c028114f2460f96554f61fae3302fe", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA1, msg = "test", k = "8c9520267c55d6b980df741e56b4adee114d84fbfa2e62137954164028632a2e", sig = "0cbcc86fd6abd1d99e703e1ec50069ee5c0b4ba4b9ac60e409e8ec5910d81a8901b9d7b73dfaa60d5651ec4591a0136f87653e0fd780c3b1bc872ffdeae479b1", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA256, msg = "test", k = "d16b6ae827f17175e040871a1c7ec3500192c4c92677336ec2537acaee0008e0", sig = "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA384, msg = "test", k = "16aeffa357260b04b1dd199693960740066c1a8f3e8edd79070aa914d361b3b8", sig = "83910e8b48bb0c74244ebdf7f07a1c5413d61472bd941ef3920e623fbccebeb68ddbec54cf8cd5874883841d712142a56a8d0f218f5003cb0296b6b509619f2c", }, testcase { curve = tcurveid::P256, qpoint = p256q, x = p256x, hashf = hashf::SHA512, msg = "test", k = "6915d11632aca3c40d5d51c08daf9c555933819548784480e93499000d9f0b7f", sig = "461d93f31b6540894788fd206c07cfa0cc35f46fa3c91816fff1040ad1581a0439af9f15de0db8d97e72719c74820d304ce5226e32dedae67519e840d1194e55", }, // Test vectors for P-384, from RFC 6979. testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA1, msg = "sample", k = "4471ef7518bb2c7c20f62eae1c387ad0c5e8e470995db4acf694466e6ab096630f29e5938d25106c3c340045a2db01a7", sig = "ec748d839243d6fbef4fc5c4859a7dffd7f3abddf72014540c16d73309834fa37b9ba002899f6fda3a4a9386790d4eb2a3bcfa947beef4732bf247ac17f71676cb31a847b9ff0cbc9c9ed4c1a5b3facf26f49ca031d4857570ccb5ca4424a443", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA256, msg = "sample", k = "180ae9f9aec5438a44bc159a1fcb277c7be54fa20e7cf404b490650a8acc414e375572342863c899f9f2edf9747a9b60", sig = "21b13d1e013c7fa1392d03c5f99af8b30c570c6f98d4ea8e354b63a21d3daa33bde1e888e63355d92fa2b3c36d8fb2cdf3aa443fb107745bf4bd77cb3891674632068a10ca67e3d45db2266fa7d1feebefdc63eccd1ac42ec0cb8668a4fa0ab0", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA384, msg = "sample", k = "94ed910d1a099dad3254e9242ae85abde4ba15168eaf0ca87a555fd56d10fbca2907e3e83ba95368623b8c4686915cf9", sig = "94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d64c4ea95ad133c81a648152e44acf96e36dd1e80fabe4699ef4aeb15f178cea1fe40db2603138f130e740a19624526203b6351d0a3a94fa329c145786e679e7b82c71a38628ac8", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA512, msg = "sample", k = "92fc3c7183a883e24216d1141f1a8976c5b0dd797dfa597e3d7b32198bd35331a4e966532593a52980d0e3aaa5e10ec3", sig = "ed0959d5880ab2d869ae7f6c2915c6d60f96507f9cb3e047c0046861da4a799cfe30f35cc900056d7c99cd7882433709512c8cceee3890a84058ce1e22dbc2198f42323ce8aca9135329f03c068e5112dc7cc3ef3446defceb01a45c2667fdd5", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA1, msg = "test", k = "66cc2c8f4d303fc962e5ff6a27bd79f84ec812ddae58cf5243b64a4ad8094d47ec3727f3a3c186c15054492e30698497", sig = "4bc35d3a50ef4e30576f58cd96ce6bf638025ee624004a1f7789a8b8e43d0678acd9d29876daf46638645f7f404b11c7d5a6326c494ed3ff614703878961c0fde7b2c278f9a65fd8c4b7186201a2991695ba1c84541327e966fa7b50f7382282", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA256, msg = "test", k = "0cfac37587532347dc3389fdc98286bba8c73807285b184c83e62e26c401c0faa48dd070ba79921a3457abff2d630ad7", sig = "6d6defac9ab64dabafe36c6bf510352a4cc27001263638e5b16d9bb51d451559f918eedaf2293be5b475cc8f0188636b2d46f3becbcc523d5f1a1256bf0c9b024d879ba9e838144c8ba6baeb4b53b47d51ab373f9845c0514eefb14024787265", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA384, msg = "test", k = "015ee46a5bf88773ed9123a5ab0807962d193719503c527b031b4c2d225092ada71f4a459bc0da98adb95837db8312ea", sig = "8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36ab775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023dbddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13173923e06a739f040649a667bf3b828246baa5a5", }, testcase { curve = tcurveid::P384, qpoint = p384q, x = p384x, hashf = hashf::SHA512, msg = "test", k = "3780c4f67cb15518b6acae34c9f83568d2e12e47deab6c50a4e4ee5319d1e8ce0e2cc8a136036dc4b9c00e6888f66b6c", sig = "a0d5d090c9980faf3c2ce57b7ae951d31977dd11c775d314af55f76c676447d06fb6495cd21b4b6e340fc236584fb277976984e59b4c77b0e8e4460dca3d9f20e07b9bb1f63beefaf576f6b2e8b224634a2092cd3792e0159ad9cee37659c736", }, // Test vectors for P-521, from RFC 6979. */ testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA1, msg = "sample", k = "0089c071b419e1c2820962321787258469511958e80582e95d8378e0c2ccdb3cb42bede42f50e3fa3c71f5a76724281d31d9c89f0f91fc1be4918db1c03a5838d0f9", sig = "00343b6ec45728975ea5cba6659bbb6062a5ff89eea58be3c80b619f322c87910fe092f7d45bb0f8eee01ed3f20babec079d202ae677b243ab40b5431d497c55d75d00e7b0e675a9b24413d448b8cc119d2bf7b2d2df032741c096634d6d65d0dbe3d5694625fb9e8104d3b842c1b0e2d0b98bea19341e8676aef66ae4eba3d5475d5d16", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA256, msg = "sample", k = "00edf38afcaaecab4383358b34d67c9f2216c8382aaea44a3dad5fdc9c32575761793fef24eb0fc276dfc4f6e3ec476752f043cf01415387470bcbd8678ed2c7e1a0", sig = "01511bb4d675114fe266fc4372b87682baecc01d3cc62cf2303c92b3526012659d16876e25c7c1e57648f23b73564d67f61c6f14d527d54972810421e7d87589e1a7004a171143a83163d6df460aaf61522695f207a58b95c0644d87e52aa1a347916e4f7a72930b1bc06dbe22ce3f58264afd23704cbb63b29b931f7de6c9d949a7ecfc", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA384, msg = "sample", k = "01546a108bc23a15d6f21872f7ded661fa8431ddbd922d0dcdb77cc878c8553ffad064c95a920a750ac9137e527390d2d92f153e66196966ea554d9adfcb109c4211", sig = "01ea842a0e17d2de4f92c15315c63ddf72685c18195c2bb95e572b9c5136ca4b4b576ad712a52be9730627d16054ba40cc0b8d3ff035b12ae75168397f5d50c6745101f21a3cee066e1961025fb048bd5fe2b7924d0cd797babe0a83b66f1e35eeaf5fde143fa85dc394a7dee766523393784484bdf3e00114a1c857cde1aa203db65d61", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA512, msg = "sample", k = "01dae2ea071f8110dc26882d4d5eae0621a3256fc8847fb9022e2b7d28e6f10198b1574fdd03a9053c08a1854a168aa5a57470ec97dd5ce090124ef52a2f7ecbffd3", sig = "00c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f174e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e377fa00617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af282623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4a67a", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA1, msg = "test", k = "00bb9f2bf4fe1038ccf4dabd7139a56f6fd8bb1386561bd3c6a4fc818b20df5ddba80795a947107a1ab9d12daa615b1ade4f7a9dc05e8e6311150f47f5c57ce8b222", sig = "013bad9f29abe20de37ebeb823c252ca0f63361284015a3bf430a46aaa80b87b0693f0694bd88afe4e661fc33b094cd3b7963bed5a727ed8bd6a3a202abe009d036701e9bb81ff7944ca409ad138dbbee228e1afcc0c890fc78ec8604639cb0dbdc90f717a99ead9d272855d00162ee9527567dd6a92cbd629805c0445282bbc916797ff", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA256, msg = "test", k = "001de74955efaabc4c4f17f8e84d881d1310b5392d7700275f82f145c61e843841af09035bf7a6210f5a431a6a9e81c9323354a9e69135d44ebd2fcaa7731b909258", sig = "000e871c4a14f993c6c7369501900c4bc1e9c7b0b4ba44e04868b30b41d8071042eb28c4c250411d0ce08cd197e4188ea4876f279f90b3d8d74a3c76e6f1e4656aa800cd52dbaa33b063c3a6cd8058a1fb0a46a4754b034fcc644766ca14da8ca5ca9fde00e88c1ad60ccba759025299079d7a427ec3cc5b619bfbc828e7769bcd694e86", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA384, msg = "test", k = "01f1fc4a349a7da9a9e116bfdd055dc08e78252ff8e23ac276ac88b1770ae0b5dceb1ed14a4916b769a523ce1e90ba22846af11df8b300c38818f713dadd85de0c88", sig = "014bee21a18b6d8b3c93fab08d43e739707953244fdbe924fa926d76669e7ac8c89df62ed8975c2d8397a65a49dcc09f6b0ac62272741924d479354d74ff6075578c0133330865c067a0eaf72362a65e2d7bc4e461e8c8995c3b6226a21bd1aa78f0ed94fe536a0dca35534f0cd1510c41525d163fe9d74d134881e35141ed5e8e95b979", }, testcase { curve = tcurveid::P521, qpoint = p521q, x = p521x, hashf = hashf::SHA512, msg = "test", k = "016200813020ec986863bedfc1b121f605c1215645018aea1a7b215a564de9eb1b38a67aa1128b80ce391c4fb71187654aaa3431027bfc7f395766ca988c964dc56d", sig = "013e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d08725f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945babd47ee6d01fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b155e2de4dce3", }, ]); @test fn ecdsa_rfc6979() void = { test::require("slow"); let sigbuf: [MAX_SIGSZ]u8 = [0...]; let sumbuf: [sha512::SZ]u8 = [0...]; let hashbuf: [sha512::SZ * 2 + sha512::BLOCKSZ]u8 = [0...]; let cases = rfc6979_cases(); defer free(cases); for (let tc &.. cases) { let h: *hash::hash = switch (tc.hashf) { case hashf::SHA1 => yield &sha1::sha1(); case hashf::SHA224 => abort("not implemented"); case hashf::SHA256 => yield &sha256::sha256(); case hashf::SHA384 => yield &sha512::sha384(); case hashf::SHA512 => yield &sha512::sha512(); case => abort(); }; let pub: *pubkey = switch (tc.curve) { case tcurveid::P256 => yield &p256pub(); case tcurveid::P384 => yield &p384pub(); case tcurveid::P521 => yield &p521pub(); case => abort(); }; pubkey_buf(pub)[..] = tc.qpoint[..]; let sum = sumbuf[..hash::sz(h)]; io::writeall(h, strings::toutf8(tc.msg))!; hash::sum(h, sum); let sig = hex::decodestr(tc.sig)!; defer free(sig); sigbuf[..len(sig)] = sig[..]; verify(pub, sum, sigbuf[..len(sig)])!; let priv: *privkey = switch (tc.curve) { case tcurveid::P256 => yield &p256priv(); case tcurveid::P384 => yield &p384priv(); case tcurveid::P521 => yield &p521priv(); case => abort(); }; privkey_buf(priv)[..] = tc.x[..]; const n = sign(priv, sum, h, hashbuf, sigbuf)!; assert(n == sigsz(pub)); assert(bytes::equal(sigbuf[..n], sig)); }; }; hare-0.24.2/crypto/ecdsa/validate+test.ha000066400000000000000000000031261464473310100202000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::ec; use crypto::sha256; use hash; use memio; const randbuf: [_]u8 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x4e, 0x6c, 0xf9, 0x0f, 0xbc, 0xd7, 0xfa, 0x68, 0x33, 0x0d, 0x62, 0x04, 0xdd, 0x61, 0x1c, 0x00, 0xd9, 0x69, 0xfb, 0xa5, 0xcd, 0xb7, 0xa9, 0x9d, 0xca, 0x94, 0xfb, 0x50, 0x20, 0x5a, 0x6b, ]; @test fn validate() void = { let rnd = memio::fixed(randbuf); let k = p256priv(); newkey(&k, &rnd)!; assert(bytes::equal(randbuf[ec::P256_SCALARSZ * 2..], privkey_buf(&k))); privkey_validate(&k)!; let p = p256pub(); pubkey_derive(&p, &k); pubkey_validate_format(&p)!; pubkey_validate(&p)!; let hashfn = sha256::sha256(); let hashbuf: [sha256::SZ * 2 + sha256::BLOCKSZ]u8 = [0...]; let msghash: [sha256::SZ]u8 = [0...]; hash::write(&hashfn, [0, 1, 2, 3]); hash::sum(&hashfn, msghash); let sig: [P256_SIGSZ]u8 = [0...]; assert(sign(&k, msghash, &hashfn, hashbuf, sig)! == len(sig)); verify(&p, msghash, sig)!; const save = sig[4]; sig[4] = 0xff; assert(verify(&p, msghash, sig) is invalidsig); sig[4] = save; pubkey_buf(&p)[1] = 0xff; assert(verify(&p, msghash, sig) is invalidsig); assert(pubkey_validate(&p) is invalidkey); }; hare-0.24.2/crypto/ed25519/000077500000000000000000000000001464473310100150375ustar00rootroot00000000000000hare-0.24.2/crypto/ed25519/+test.ha000066400000000000000000000044631464473310100164120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::hex; use strings; @test fn roundtrip() void = { let seed: seed = [1...]; let priv_key: privkey = [0...]; privkey_init(&priv_key, &seed); let pub_key = privkey_getpubkey(&priv_key); const msg = strings::toutf8("hello, world!"); let sig = sign(&priv_key, msg); assert(verify(&pub_key, msg, &sig)); let bad_pub_key = pub_key; bad_pub_key[0] ^= 1; const bad_msg = strings::toutf8("HELLO, WORLD!"); let bad_sig = sig; bad_sig[0] ^= 1; assert(!verify(&bad_pub_key, msg, &sig)); assert(!verify(&pub_key, bad_msg, &sig)); assert(!verify(&pub_key, msg, &bad_sig)); }; @test fn golden() void = { let priv_key = hex::decodestr("8ed7a797b9cea8a8370d419136bcdf683b759d2e3c6947f17e13e2485aa9d420b49f3a78b1c6a7fca8f3466f33bc0e929f01fba04306c2a7465f46c3759316d9")!; defer free(priv_key); const pub_key = privkey_getpubkey(priv_key); let msg = hex::decodestr("a750c232933dc14b1184d86d8b4ce72e16d69744ba69818b6ac33b1d823bb2c3")!; defer free(msg); let good_sig = hex::decodestr("04266c033b91c1322ceb3446c901ffcf3cc40c4034e887c9597ca1893ba7330becbbd8b48142ef35c012c6ba51a66df9308cb6268ad6b1e4b03e70102495790b")!; defer free(good_sig); const sig = sign(priv_key, msg); assert(bytes::equal(sig, good_sig)); assert(verify(pub_key, msg, sig)); }; @test fn issue716() void = { // See https://todo.sr.ht/~sircmpwn/hare/716 let pubkey: [_]u8 = [ 0x51, 0xe2, 0xf3, 0x79, 0xb1, 0x52, 0x37, 0x59, 0x19, 0x0e, 0x08, 0xc8, 0xcb, 0xd3, 0xab, 0xb6, 0xbd, 0x2d, 0xf7, 0x71, 0x22, 0x87, 0x95, 0xa7, 0x52, 0x5a, 0x1b, 0x67, 0xb1, 0x7f, 0x2d, 0x26, ]; let signature: [_]u8 = [ 0xae, 0x81, 0x01, 0x87, 0x46, 0xba, 0x6d, 0xcb, 0x5e, 0x40, 0xda, 0x4d, 0x5a, 0x9b, 0xaa, 0x15, 0xc3, 0x9c, 0x84, 0xd7, 0x3d, 0x98, 0xf2, 0x85, 0x0a, 0x82, 0x5e, 0x37, 0xc5, 0x92, 0xa6, 0x4d, 0x2b, 0x93, 0x64, 0x80, 0xe8, 0xde, 0x2e, 0x3b, 0x4b, 0x69, 0x50, 0x3b, 0xda, 0xa2, 0x4d, 0xcd, 0x7f, 0x73, 0xbe, 0x92, 0x2d, 0x7c, 0x90, 0xc4, 0x85, 0x27, 0xff, 0x68, 0xfc, 0x6a, 0x53, 0x0b, ]; let msg: []u8 = [ 0xaa, 0xaf, 0x0a, 0xa9, 0x77, 0xf1, 0x29, 0x40, 0x28, 0xed, 0xef, 0xa9, 0x7c, 0x22, 0x80, 0x60, 0x84, 0x96, 0x53, 0xef, 0x54, 0x42, 0x29, 0x9b, 0x07, 0xf8, 0x88, 0xaa, 0xb1, 0x04, 0xe2, 0x4d, ]; assert(verify(&pubkey, msg, &signature)); }; hare-0.24.2/crypto/ed25519/README000066400000000000000000000012131464473310100157140ustar00rootroot00000000000000This module implements the ed25519 signature algorithm, as defined by RFC 8032. Do not use the same secret key for both key exchanges and signatures. The public keys are different and revealing both may leak information. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/ed25519/ed25519.ha000066400000000000000000000070671464473310100163610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Implements the Ed25519 signature scheme. // // This implementation is a straightforward port of TweetNaCl, // with the API of crypto/ed25519 from the Go standard library. use bytes; use crypto::sha512; use hash; // The size of an Ed25519 seed. export def SEEDSZ: size = 32; // The size of an Ed25519 public key. export def PUBKEYSZ: size = 32; // The size of an Ed25519 private key. export def PRIVKEYSZ: size = 64; // The size of an Ed25519 signature. export def SIGNATURESZ: size = 64; export type privkey = [PRIVKEYSZ]u8; export type pubkey = [PUBKEYSZ]u8; export type seed = [SEEDSZ]u8; // Derives a new Ed25519 private key from a given seed. The seed must be // initialized to cryptographically random data; [[crypto::random::]] is // recommended for this purpose. export fn privkey_init(priv: []u8, seed: []u8) void = { assert(len(priv) == PRIVKEYSZ); assert(len(seed) == SEEDSZ); let h: [64]u8 = [0...]; let sha = sha512::sha512(); hash::write(&sha, seed[..]); hash::sum(&sha, h[..]); hash::close(&sha); let s: scalar = [0...]; s[..] = h[..SCALARSZ]; scalar_clamp(&s); let A = point { ... }; scalarmult_base(&A, &s); let A_bytes: [POINTSZ]u8 = [0...]; point_encode(&A_bytes, &A); priv[0..SEEDSZ] = seed[..]; priv[SEEDSZ..PRIVKEYSZ] = A_bytes[..]; }; // Derive the public key for a given private key. ' export fn privkey_getpubkey(priv: []u8) pubkey = { assert(len(priv) == PRIVKEYSZ); let pk: pubkey = [0...]; pk[0..] = priv[SEEDSZ..]; return pk; }; // Signs a message with a private key, returning the signature. export fn sign(priv: []u8, msg: []u8) [SIGNATURESZ]u8 = { assert(len(priv) == PRIVKEYSZ); let h: [64]u8 = [0...]; let sha = sha512::sha512(); hash::write(&sha, priv[0..SEEDSZ]); hash::sum(&sha, h); let esk: scalar = [0...]; esk[..] = h[0..32]; scalar_clamp(&esk); hash::reset(&sha); hash::write(&sha, h[32..64]); hash::write(&sha, msg); let msg_digest: [64]u8 = [0...]; hash::sum(&sha, msg_digest); let msg_reduced: scalar = [0...]; scalar_reduce(&msg_reduced, &msg_digest); let R = point {...}; scalarmult_base(&R, &msg_reduced); let R_bytes: [POINTSZ]u8 = [0...]; point_encode(&R_bytes, &R); hash::reset(&sha); hash::write(&sha, R_bytes[..]); hash::write(&sha, priv[32..64]); hash::write(&sha, msg); let hram: [64]u8 = [0...]; hash::sum(&sha, hram); hash::close(&sha); let hram_reduced: scalar = [0...]; scalar_reduce(&hram_reduced, &hram); let s: scalar = [0...]; scalar_multiply_add(&s, &hram_reduced, &esk, &msg_reduced); let sig: [SIGNATURESZ]u8 =[0...]; sig[0..32] = R_bytes[..]; sig[32..64] = s[..]; return sig; }; // Given a public key, verifies a signature produced with the // corresponding private key for a given message, returning true if the // signature is valid and false otherwise. export fn verify(pub: []u8, msg: []u8, sig: []u8) bool = { assert(len(pub) == PUBKEYSZ); assert(len(sig) == SIGNATURESZ); let A = point { ... }; if (!point_decode(&A, pub)) { return false; }; let sha = sha512::sha512(); hash::write(&sha, sig[0..32]); hash::write(&sha, pub[..]); hash::write(&sha, msg); let hram: [64]u8 = [0...]; hash::sum(&sha, hram); hash::close(&sha); let hram_reduced: scalar = [0...]; scalar_reduce(&hram_reduced, &hram); let check_R = point { ... }; scalarmult(&check_R, &A, &hram_reduced); let s: scalar = [0...]; s[..] = sig[32..64]; scalarmult_base(&A, &s); point_add(&check_R, &check_R, &A); let R_bytes: [POINTSZ]u8 = [0...]; point_encode(&R_bytes, &check_R); return bytes::equal(R_bytes, sig[0..32]); }; hare-0.24.2/crypto/ed25519/edwards25519.ha000066400000000000000000000200221464473310100174040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def FIELDSZ: size = 16; type elem = [FIELDSZ]i64; const feZero: elem = [0...]; const feOne: elem = [1, 0...]; const D: elem = [0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]; const D2: elem = [0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]; const X: elem = [0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]; const Y: elem = [0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]; const I: elem = [0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]; fn fe_reduce(fe: *elem) void = { let carry: i64 = 0; for (let i = 0z; i < FIELDSZ; i += 1) { carry = fe[i] >> 16; fe[i] -= (carry << 16); if (i+1 < FIELDSZ) { fe[i + 1] += carry; } else { fe[0] += (38 * carry); }; }; }; fn fe_add(out: *elem, a: const *elem, b: const *elem) *elem = { for (let i = 0z; i < FIELDSZ; i += 1) { out[i] = a[i] + b[i]; }; return out; }; fn fe_sub(out: *elem, a: const *elem, b: const *elem) *elem = { for (let i = 0z; i < FIELDSZ; i += 1) { out[i] = a[i] - b[i]; }; return out; }; fn fe_negate(out: *elem, a: const *elem) *elem = { return fe_sub(out, &feZero, a); }; fn fe_mul(out: *elem, a: const *elem, b: const *elem) *elem = { let prod: [31]i64 = [0...]; for (let i = 0z; i < FIELDSZ; i += 1) { for (let j = 0z; j < FIELDSZ; j += 1) { prod[i + j] += a[i] * b[j]; }; }; for (let i = 0; i < 15; i += 1) { prod[i] += (38 * prod[i + 16]); }; out[0..FIELDSZ] = prod[0..FIELDSZ]; fe_reduce(out); fe_reduce(out); return out; }; fn fe_square(out: *elem, a: const *elem) *elem = { return fe_mul(out, a, a); }; // out = i ** (2**252 - 3) fn fe_pow2523(out: *elem, a: *elem) *elem = { let c: elem = [0...]; c[..] = a[..]; for (let i = 250i; i >= 0; i -= 1) { fe_square(&c, &c); if (i != 1) { fe_mul(&c, &c, a); }; }; out[..] = c[..]; return out; }; fn fe_inv(out: *elem, a: const *elem) *elem = { let c: elem = [0...]; c[..] = a[..]; for (let i = 253i; i >= 0; i -= 1) { fe_square(&c, &c); if (i != 2 && i != 4) { fe_mul(&c, &c, a); }; }; out[..] = c[..]; return out; }; fn fe_parity(a: const *elem) u8 = { let d: scalar = [0...]; fe_encode(&d, a); return d[0]&1; }; // a == b -> 0 // a != b -> 1 fn fe_cmp(a: const *elem, b: const *elem) u8 = { let x: scalar = [0...]; fe_encode(&x, a); let y: scalar = [0...]; fe_encode(&y, b); // constant-time compare let d: u32 = 0; for (let i = 0z; i < SCALARSZ; i += 1) { d |= x[i] ^ y[i]; }; return (1 & ((d - 1) >> 8): u8) - 1; }; // swap p and q if bit is 1, otherwise noop fn fe_swap(p: *elem, q: *elem, bit: u8) void = { let c = ~(bit: u64 - 1): i64; for (let i = 0z; i < FIELDSZ; i += 1) { let t = c & (p[i] ^ q[i]); p[i] ^= t; q[i] ^= t; }; }; fn fe_encode(out: *scalar, a: const *elem) void = { let m: elem = [0...]; let t: elem = *a; fe_reduce(&t); fe_reduce(&t); fe_reduce(&t); for (let _i = 0; _i < 2; _i += 1) { m[0] = t[0] - 0xffed; for (let i = 1z; i < 15; i += 1) { m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); m[i - 1] &= 0xffff; }; m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); let b = ((m[15] >> 16): u8) & 1; m[14] &= 0xffff; fe_swap(&t, &m, 1-b); }; for (let i = 0z; i < FIELDSZ; i += 1) { out[2*i+0] = (t[i] & 0xff) : u8; out[2*i+1] = (t[i] >> 8) : u8; }; }; // len(in) must be SCALARSZ fn fe_decode(fe: *elem, in: []u8) *elem = { for (let i = 0z; i < FIELDSZ; i += 1) { fe[i] = in[2 * i] : i64 + ((in[2 * i + 1] : i64) << 8); }; fe[15] &= 0x7fff; return fe; }; def SCALARSZ: size = 32; type scalar = [SCALARSZ]u8; const L: scalar = [ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ]; fn scalar_clamp(s: *scalar) void = { s[0] &= 248; s[31] &= 127; s[31] |= 64; }; // r = x % -1 fn scalar_mod_L(r: *scalar, x: *[64]i64) void = { for (let i: i64 = 63; i >= 32; i -= 1) { let carry: i64 = 0; let j = i - 32; for (j < i - 12; j += 1) { x[j] += carry - 16 * x[i] * (L[j - (i - 32)]: i64); carry = (x[j] + 128) >> 8; x[j] -= carry << 8; }; x[j] += carry; x[i] = 0; }; let carry: i64 = 0; for (let j = 0; j < 32; j += 1) { x[j] += carry - (x[31] >> 4) * (L[j]: i64); carry = x[j] >> 8; x[j] &= 255; }; for (let j = 0; j < 32; j += 1) { x[j] -= carry * (L[j]: i64); }; for (let i = 0; i < 32; i += 1) { x[i+1] += x[i] >> 8; r[i] = (x[i]&255): u8; }; }; fn scalar_reduce(r: *scalar, h: *[64]u8) void = { let x: [64]i64 = [0...]; for (let i = 0; i < 64; i += 1) { x[i] = h[i]: i64; }; scalar_mod_L(r, &x); }; // s = a*b + c fn scalar_multiply_add(s: *scalar, a: *scalar, b: *scalar, c: *scalar) void = { let x: [64]i64 = [0...]; for (let i = 0; i < 32; i += 1) { for (let j = 0; j < 32; j += 1) { x[i+j] += (a[i]: i64) * (b[j]: i64); }; }; for (let i = 0; i < 32; i += 1) { x[i] += (c[i]: i64); }; scalar_mod_L(s, &x); }; def POINTSZ: size = 32; type point = struct { x: elem, y: elem, z: elem, t: elem, }; // out = p += q fn point_add(out: *point, p: *point, q: *point) *point = { let a: elem = [0...]; let b: elem = [0...]; let c: elem = [0...]; let d: elem = [0...]; let t: elem = [0...]; let e: elem = [0...]; let f: elem = [0...]; let g: elem = [0...]; let h: elem = [0...]; fe_sub(&a, &p.y, &p.x); fe_sub(&t, &q.y, &q.x); fe_mul(&a, &a, &t); fe_add(&b, &p.x, &p.y); fe_add(&t, &q.x, &q.y); fe_mul(&b, &b, &t); fe_mul(&c, &p.t, &q.t); fe_mul(&c, &c, &D2); fe_mul(&d, &p.z, &q.z); fe_add(&d, &d, &d); fe_sub(&e, &b, &a); fe_sub(&f, &d, &c); fe_add(&g, &d, &c); fe_add(&h, &b, &a); fe_mul(&out.x, &e, &f); fe_mul(&out.y, &h, &g); fe_mul(&out.z, &g, &f); fe_mul(&out.t, &e, &h); return out; }; // swap p and q if bit is 1, otherwise noop fn point_swap(p: *point, q: *point, bit: u8) void = { fe_swap(&p.x, &q.x, bit); fe_swap(&p.y, &q.y, bit); fe_swap(&p.z, &q.z, bit); fe_swap(&p.t, &q.t, bit); }; // p = q * s fn scalarmult(p: *point, q: *point, s: const *scalar) *point = { p.x[..] = feZero[..]; p.y[..] = feOne[..]; p.z[..] = feOne[..]; p.t[..] = feZero[..]; for (let i = 255; i >= 0; i -= 1) { let b: u8 = (s[i/8]>>((i: u8)&7))&1; point_swap(p, q, b); point_add(q, q, p); point_add(p, p, p); point_swap(p, q, b); }; return p; }; // p = B * s fn scalarmult_base(p: *point, s: const *scalar) *point = { let B = point {...}; B.x[..] = X[..]; B.y[..] = Y[..]; B.z[..] = feOne[..]; fe_mul(&B.t, &X, &Y); return scalarmult(p, &B, s); }; fn point_encode(out: *scalar, p: *point) void = { let tx: elem = [0...]; let ty: elem = [0...]; let zi: elem = [0...]; fe_inv(&zi, &p.z); fe_mul(&tx, &p.x, &zi); fe_mul(&ty, &p.y, &zi); fe_encode(out, &ty); out[31] ^= fe_parity(&tx) << 7; }; // len(in) must be POINTSZ fn point_decode(p: *point, in: []u8) bool = { let t: elem = [0...]; let chk: elem = [0...]; let num: elem = [0...]; let den: elem = [0...]; let den2: elem = [0...]; let den4: elem = [0...]; let den6: elem = [0...]; p.z[..] = feOne[..]; fe_decode(&p.y, in); fe_square(&num, &p.y); fe_mul(&den, &num, &D); fe_sub(&num, &num, &p.z); fe_add(&den, &p.z, &den); fe_square(&den2, &den); fe_square(&den4, &den2); fe_mul(&den6, &den4, &den2); fe_mul(&t, &den6, &num); fe_mul(&t, &t, &den); fe_pow2523(&t, &t); fe_mul(&t, &t, &num); fe_mul(&t, &t, &den); fe_mul(&t, &t, &den); fe_mul(&p.x, &t, &den); fe_square(&chk, &p.x); fe_mul(&chk, &chk, &den); if (fe_cmp(&chk, &num) != 0) { fe_mul(&p.x, &p.x, &I); }; fe_square(&chk, &p.x); fe_mul(&chk, &chk, &den); if (fe_cmp(&chk, &num) != 0) { return false; }; if (fe_parity(&p.x) == (in[31]>>7)) { fe_negate(&p.x, &p.x); }; fe_mul(&p.t, &p.x, &p.y); return true; }; hare-0.24.2/crypto/hkdf/000077500000000000000000000000001464473310100147555ustar00rootroot00000000000000hare-0.24.2/crypto/hkdf/+test.ha000066400000000000000000000165661464473310100163370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::sha1; use crypto::sha256; // test taken from RFC 5869 @test fn rfc1() void = { let h = sha256::sha256(); let dest: [42]u8 = [0...]; const key: [22]u8 = [0x0b...]; const salt: [13]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, ]; const info: [10]u8 = [ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, ]; const expected: [42]u8 = [ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65, ]; let buf: [sha256::SZ + sha256::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, info, salt, buf); assert(bytes::equal(expected, dest)); }; // test taken from RFC 5869 @test fn rfc2() void = { let h = sha256::sha256(); let dest: [82]u8 = [0...]; const key: [80]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ]; const salt: [80]u8 = [ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, ]; const info: [80]u8 = [ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; const expected: [82]u8 = [ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87, ]; let buf: [sha256::SZ + sha256::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, info, salt, buf); assert(bytes::equal(expected, dest)); }; // test taken from RFC 5869 @test fn rfc3() void = { let h = sha256::sha256(); let dest: [42]u8 = [0...]; const key: [22]u8 = [0x0b...]; const expected: [42]u8 = [ 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8, ]; let buf: [sha256::SZ + sha256::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, [], [], buf); assert(bytes::equal(expected, dest)); }; // test taken from RFC 5869 @test fn rfc4() void = { let h = sha1::sha1(); let dest: [42]u8 = [0...]; const key: [11]u8 = [0x0b...]; const salt: [13]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, ]; const info: [10]u8 = [ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, ]; const expected: [42]u8 = [ 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96, ]; let buf: [sha1::SZ + sha1::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, info, salt, buf); assert(bytes::equal(expected, dest)); }; // test taken from RFC 5869 @test fn rfc5() void = { let h = sha1::sha1(); let dest: [82]u8 = [0...]; const key: [80]u8 = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ]; const salt: [80]u8 = [ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, ]; const info: [80]u8 = [ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; const expected: [82]u8 = [ 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4, ]; let buf: [sha1::SZ + sha1::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, info, salt, buf); assert(bytes::equal(expected, dest)); }; // test taken from RFC 5869 @test fn rfc6() void = { let h = sha1::sha1(); let dest: [42]u8 = [0...]; const key: [22]u8 = [0x0c...]; const expected: [42]u8 = [ 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48, ]; let buf: [sha1::SZ + sha1::BLOCKSZ]u8 = [0...]; hkdf(&h, dest[..], key, [], void, buf); assert(bytes::equal(expected, dest)); }; hare-0.24.2/crypto/hkdf/README000066400000000000000000000005061464473310100156360ustar00rootroot00000000000000This module provides a HKDF implementation according to RFC 5869. A pesudorandom key is created using [[extract]], which in turn is used to derive keys using [[expand]]. [[hkdf]] combines both [[extract]] and [[expand]] for deriving a single key. See the RFC 5869 for detailed usage guidance on how to choose the parameters. hare-0.24.2/crypto/hkdf/hkdf.ha000066400000000000000000000101051464473310100162000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::hmac; use crypto::mac; use hash; // Calls [[extract]] and [[expand]] to derive a single key from specified 'key' // material using HMAC with 'h' as underlying hash function and writes it to // 'dest'. The resulting key size is of the size of 'dest'. // // 'info' binds the resulting key to the context in where it is being used and // therefore prevents the derivation of the same key for different contexts. It // should be independent of the input key. 'salt' does not need to be secret and // it's recommended to use a random or pseudo random value, ideally of the hash // size of the given hash function. The 'salt' must be a fixed value or void // between many different contexts. // // 'buf' must be of the size [[hash::bsz]] + [[hash::sz]] of given hash 'h'. export fn hkdf( h: *hash::hash, dest: []u8, key: []u8, info: []u8, salt: ([]u8 | void), buf: []u8, ) void = { const hashsz = hash::sz(h); assert(len(buf) >= (hash::sz(h) + hash::bsz(h)), "len(buf) must be at least `hash::sz(h) + hash::bsz(h)`"); let prk = buf[..hashsz]; let buf = buf[hashsz..]; extract(h, prk, key, salt, buf); // use prk as buffer for the last block operation since it's not // required for future expanding. iexpand(h, dest, prk, info, buf, prk); // buf is zeroed in expand }; // Extracts a pseudo random key (prk) from given 'key' and 'salt' and writes it // to 'prk' using HMAC of given hash function 'h'. 'prk' must be the size of // [[hash::sz]] of given hash. The resulting 'prk' can be used to derive keys // using the [[expand]] function. // // 'salt' does not need to be secret and it's recommended to use a random or // pseudo random value, ideally of the hash size of the given hash function. // 'buf' must be of the size [[hash::bsz]] of given hash. export fn extract( h: *hash::hash, prk: []u8, key: []u8, salt: ([]u8 | void), buf: []u8 ) void = { const hashsz = hash::sz(h); assert(len(buf) >= hash::bsz(h), "len(buf) must be at least `hash::bsz(h)`"); assert(len(prk) == hash::sz(h), "prk must be of hash::sz(h)"); let prkkey = match(salt) { case let s: []u8 => yield s; case void => bytes::zero(prk); yield prk; }; let hm = hmac::hmac(h, prkkey, buf); mac::write(&hm, key); mac::sum(&hm, prk); mac::finish(&hm); // buf is zeroed in mac::finish }; // Derives a new key form 'prk' using HMAC of given hash function 'h' and stores // it into 'dest'. 'prk' must be created using [[extract]]. 'info' binds the // resulting key to the context in where it is being used and therefore prevents // the derivation of the same key for different contexts. 'buf' must be at least // of the size [[hash::sz]] + [[hash::bsz]] of given hash function 'h'. The same // hash function that was used at the [[extract]] step must also be used in // [[expand]]. export fn expand( h: *hash::hash, dest: []u8, prk: []u8, info: []u8, buf: []u8, ) void = { assert(len(buf) >= (hash::bsz(h) + hash::sz(h)), "len(buf) must be at least `hash::bsz(h)`"); const hashsz = hash::sz(h); iexpand(h, dest, prk, info, buf[hashsz..], buf[..hashsz]); }; // Internal [[expand]] function that allows to specify separately 'hashbuf', // the buffer for the last block operation. fn iexpand( h: *hash::hash, dest: []u8, prk: []u8, info: []u8, buf: []u8, hashbuf: []u8, ) void = { const hashsz = hash::sz(h); // to avoid ctr overflows assert((len(dest) + hashsz - 1) / hashsz < 255, "'dest' exceeds maximum allowed size"); let ctr: [1]u8 = [0]; let preblock: []u8 = []; defer bytes::zero(hashbuf); // buf is zeroed during mac::finish for (let i = 0u8; len(dest) > 0; i += 1) { hash::reset(h); let hm = hmac::hmac(h, prk, buf); defer mac::finish(&hm); if (i > 0) { mac::write(&hm, preblock); }; mac::write(&hm, info); ctr[0] = i + 1; mac::write(&hm, ctr); const n = if (len(dest) >= hashsz) { mac::sum(&hm, dest[..hashsz]); preblock = dest[..hashsz]; yield hashsz; } else { mac::sum(&hm, hashbuf); dest[..] = hashbuf[..len(dest)]; yield len(dest); }; dest = dest[n..]; }; }; hare-0.24.2/crypto/hmac/000077500000000000000000000000001464473310100147515ustar00rootroot00000000000000hare-0.24.2/crypto/hmac/+test.ha000066400000000000000000000064251464473310100163240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::mac; use crypto::sha1; use crypto::sha256; use hash; use strings; fn assert_hmac_sha1(keystr: str, vectors: [](str, [20]u8)) void = { let key = strings::toutf8(keystr); let h = sha1::sha1(); let buf: [sha1::BLOCKSZ]u8 = [0x1...]; for (let i = 0z; i < len(vectors); i += 1) { hash::reset(&h); let hmac = hmac(&h, key, buf); defer mac::finish(&hmac); const vector = vectors[i]; mac::write(&hmac, strings::toutf8(vector.0)); let sum: [sha1::SZ]u8 = [0...]; mac::sum(&hmac, sum); assert(bytes::equal(vector.1, sum)); }; }; @test fn hmac_sha1_empty_key() void = { const vectors: [_](str, [20]u8) = [ ( "", [ 0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08, 0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63, 0x70, 0x69, 0x0e, 0x1d, ] ), ( "abc", [ 0x9b, 0x4a, 0x91, 0x8f, 0x39, 0x8d, 0x74, 0xd3, 0xe3, 0x67, 0x97, 0x0a, 0xba, 0x3c, 0xbe, 0x54, 0xe4, 0xd2, 0xb5, 0xd9, ] ), ( "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijkl" "mnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopq" "rstu", [ 0xf4, 0x50, 0x13, 0xac, 0xc6, 0xa6, 0xa5, 0x3a, 0x49, 0xbf, 0xc0, 0x7b, 0x1e, 0xd8, 0xf5, 0x39, 0x5b, 0xf3, 0x9d, 0x96, ] ), ]; assert_hmac_sha1("", vectors); }; @test fn hmac_sha1() void = { const vectors: [_](str, [20]u8) = [ ( "", [ 0xc5, 0x89, 0xa2, 0x7a, 0xb0, 0xaf, 0x9f, 0xe7, 0xe0, 0x38, 0x68, 0x24, 0x73, 0x5d, 0x22, 0x0d, 0x04, 0x1b, 0x70, 0xf0, ] ), ( "abc", [ 0x85, 0x2d, 0x02, 0xc6, 0xfd, 0x3b, 0x51, 0xdf, 0x64, 0x4a, 0xfb, 0x13, 0x81, 0x76, 0xb3, 0x07, 0x61, 0xca, 0x95, 0x27, ] ), ( "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijkl" "mnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopq" "rstu", [ 0x41, 0x29, 0x43, 0xf0, 0x84, 0x0d, 0xc1, 0xa1, 0x33, 0x8a, 0x16, 0xec, 0x3d, 0x73, 0x0b, 0x76, 0x25, 0xac, 0xf0, 0xaa, ] ), ]; assert_hmac_sha1("trustno1", vectors); }; @test fn hmac_sha1_large_key() void = { const vectors: [_](str, [20]u8) = [ ( "", [ 0x24, 0xe4, 0x38, 0xcb, 0x07, 0x54, 0xef, 0x48, 0x97, 0x20, 0x05, 0x65, 0xd5, 0xf2, 0x7f, 0x6e, 0x62, 0x77, 0xfc, 0x95 ], ), ( "abc", [ 0xe3, 0x1a, 0x77, 0xff, 0xf1, 0x4b, 0xbf, 0xba, 0x5d, 0x2f, 0x8b, 0x44, 0xa6, 0x33, 0xd4, 0xc9, 0xfc, 0x8a, 0xd0, 0xe9, ] ), ( "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijkl" "mnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopq" "rstu", [ 0x5a, 0x64, 0x69, 0x18, 0xa0, 0xe3, 0xaf, 0xe9, 0xab, 0x45, 0x1d, 0xf3, 0xcd, 0xdd, 0x1e, 0x7e, 0xb9, 0x19, 0xa7, 0x4b ] ), ]; let key = "xxabcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhi" "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; assert_hmac_sha1(key, vectors); }; @test fn sha256() void = { const expected: [_]u8 = [ 0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec, 0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5, 0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53, 0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad, ]; let hmac = sha256([]); defer mac::finish(&hmac); let sum: [sha256::SZ]u8 = [0...]; mac::sum(&hmac, sum); assert(bytes::equal(expected, sum)); }; hare-0.24.2/crypto/hmac/README000066400000000000000000000010121464473310100156230ustar00rootroot00000000000000The hmac module computes the HMAC message authentication code algorithm defined by RFC 2104. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/hmac/hmac.ha000066400000000000000000000042121464473310100161720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::mac; use hash; use io; export type state = struct { mac::mac, h: *hash::hash, keypad: []u8, }; const hmac_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[crypto::mac::mac]] that computes an HMAC using the provided hash // function 'h' with given 'key'. The caller must provide a 'buf' of // [[hash::bsz]] bytes. Use the BLOCKSZ constant of the given hash function to // allocate the memory statically. // // The caller must take extra care to call [[crypto::mac::finish]] when they are // finished using the MAC function, which, in addition to freeing state // associated with the MAC, will securely erase state which contains secret // information. export fn hmac(h: *hash::hash, key: const []u8, buf: []u8) state = { const bsz = hash::bsz(h); assert(len(buf) >= bsz, "buf must be at least the size of one " "block of the given hash function"); let keypad = buf[..bsz]; init(h, key, keypad); return state { h = h, stream = &hmac_vtable, sz = hash::sz(h), bsz = bsz, sum = &gensum, finish = &finish, keypad = keypad, ... }; }; fn init(h: *hash::hash, key: []u8, keypad: []u8) void = { const bsz = hash::bsz(h); keypad[..] = [0...]; if (len(key) > bsz) { hash::write(h, key); hash::sum(h, keypad); hash::reset(h); } else { keypad[..len(key)] = key[..]; }; for (let i = 0z; i < bsz; i += 1) { keypad[i] = 0x36 ^ keypad[i]; }; hash::write(h, keypad); for (let i = 0z; i < bsz; i += 1) { // keypad for the outer hash is xored with 0x5c instead of 0x36 keypad[i] = keypad[i] ^ 0x36 ^ 0x5c; }; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { let hm = st: *state; return hash::write(hm.h, buf); }; fn sum(h: *hash::hash, keypad: []u8, dest: []u8) void = { hash::sum(h, dest); hash::reset(h); hash::write(h, keypad); hash::write(h, dest); hash::sum(h, dest); }; fn gensum(mac: *mac::mac, dest: []u8) void = { let hm = mac: *state; sum(hm.h, hm.keypad, dest); }; fn finish(mac: *mac::mac) void = { let hm = mac: *state; bytes::zero(hm.keypad); io::close(hm.h)!; }; hare-0.24.2/crypto/hmac/sha1.ha000066400000000000000000000023741464473310100161250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::mac; use crypto::sha1; use hash; use io; export type sha1state = struct { mac::mac, h: sha1::state, keypad: [sha1::BLOCKSZ]u8, }; const sha1_vtable: io::vtable = io::vtable { writer = &sha1write, ... }; // Creates a [[crypto::mac::mac]] that computes an HMAC with given 'key' using // SHA1 as underlying hash function. // // The caller must take extra care to call [[crypto::mac::finish]] when they are // finished using the MAC function, which, in addition to freeing state // associated with the MAC, will securely erase state which contains secret // information. export fn sha1(key: []u8) sha1state = { let s = sha1state { h = sha1::sha1(), stream = &sha1_vtable, sz = sha1::SZ, bsz = sha1::BLOCKSZ, sum = &sha1sum, finish = &sha1finish, ... }; init(&s.h, key, s.keypad); return s; }; fn sha1write(st: *io::stream, buf: const []u8) (size | io::error) = { let hm = st: *sha1state; return hash::write(&hm.h, buf); }; fn sha1sum(mac: *mac::mac, dest: []u8) void = { let hm = mac: *sha1state; sum(&hm.h, hm.keypad, dest); }; fn sha1finish(mac: *mac::mac) void = { let hm = mac: *sha1state; bytes::zero(hm.keypad); io::close(&hm.h)!; }; hare-0.24.2/crypto/hmac/sha256.ha000066400000000000000000000024521464473310100162760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::mac; use crypto::sha256; use hash; use io; export type sha256state = struct { mac::mac, h: sha256::state, keypad: [sha256::BLOCKSZ]u8, }; const sha256_vtable: io::vtable = io::vtable { writer = &sha256write, ... }; // Creates a [[crypto::mac::mac]] that computes an HMAC with given 'key' using // SHA256 as underlying hash function. // // The caller must take extra care to call [[crypto::mac::finish]] when they are // finished using the MAC function, which, in addition to freeing state // associated with the MAC, will securely erase state which contains secret // information. export fn sha256(key: []u8) sha256state = { let s = sha256state { stream = &sha256_vtable, h = sha256::sha256(), sz = sha256::SZ, bsz = sha256::BLOCKSZ, sum = &sha256sum, finish = &sha256finish, ... }; init(&s.h, key, s.keypad); return s; }; fn sha256write(st: *io::stream, buf: const []u8) (size | io::error) = { let hm = st: *sha256state; return hash::write(&hm.h, buf); }; fn sha256sum(mac: *mac::mac, dest: []u8) void = { let hm = mac: *sha256state; sum(&hm.h, hm.keypad, dest); }; fn sha256finish(mac: *mac::mac) void = { let hm = mac: *sha256state; bytes::zero(hm.keypad); io::close(&hm.h)!; }; hare-0.24.2/crypto/keyderiv.ha000066400000000000000000000041641464473310100162020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::argon2; use errors; // Given a password, derive a key. Given the same password, salt, memory, and // passes, this function will always produce the same key. This function is // designed to derive cryptographic keys from user-provided passwords, or to // verify a password for user logins. // // The user provides a buffer for the key to be written to via the 'dest' // parameter. The minimum supported length for this buffer is 4 bytes, and the // recommended length is 32 bytes. // // The salt parameter should be randomly generated, stored alongside the key, // and used in subsequent calls to produce the same key. It must be at least 8 // bytes, but 16 bytes is recommended. Use [[crypto::random::]] to generate a // different salt for each key. // // The 'mem' and 'passes' functions are provided to tune the behavior of this // algorithm. It is designed to be computationally expensive, and you must // adjust these figures to suit your hardware and use-case. If you provide a u32 // for 'mem', the algorithm will dynamically allocate that many kilobytes of // working memory. To allocate this memory yourself, provide a []u64 instead. // The number of passes controls the amount of time spent generating the key, // higher numbers take longer. // // To identify ideal values for these parameters, start with 100000 for 'mem' // (100 MiB) and 0 for 'passes'. If it takes too long, reduce the amount of // memory, and if it does not take long enough, increase the amount of memory. // If you have reached the maximum amount of memory you are able to use, // increase passes. // // The current implementation of this function uses argon2id version 1.3 with the // provided number of memory blocks, passes equal to passes + 3, and parallelism // set to one. export fn derivekey( dest: []u8, salt: []u8, password: []u8, mem: (u32 | []u64), passes: u32, ) (void | errors::nomem) = { const config = argon2::conf { mem = mem, parallel = 1, passes = passes + 3, version = argon2::VERSION, ... }; return argon2::argon2id(dest, password, salt, &config); }; hare-0.24.2/crypto/keystore/000077500000000000000000000000001464473310100157065ustar00rootroot00000000000000hare-0.24.2/crypto/keystore/README000066400000000000000000000020071464473310100165650ustar00rootroot00000000000000The keystore module provides a means of securely storing private information, ideally through the assistance of operating system key storage facilities. The purpose of this feature is to store private data without keeping it in the process's address space, so that bugs which can lead to reading process memory cannot recover the key while it's not actively in use. On platforms without a suitable feature, a fallback implementation stores the secrets in the process heap, providing no security. This is an opportunistic API which allows your program to take advantage of these features if available. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/keystore/impl+linux.ha000066400000000000000000000015401464473310100203140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use linux::keyctl; export type key = keyctl::serial; // Creates a new secure key. The caller should clear the secret buffer with // [[bytes::zero]] after initialization. export fn newkey(buf: []u8, name: str) (key | errors::error) = { match (keyctl::add_key("user", name, buf, keyctl::PROCESS_KEYRING)) { case keyctl::nokey => abort(); case let err: errors::error => return err; case let key: keyctl::serial => return key; }; }; // Destroys a secure key. export fn destroy(key: key) void = { keyctl::revoke(key)!; }; // Reads secret data from a secure key. When the caller is done using the secret // buffer, they should use [[bytes::zero]] to securely wipe the buffer memory. export fn read(key: key, buf: []u8) size = { return keyctl::read(key, buf)!; }; hare-0.24.2/crypto/keystore/impl.ha000066400000000000000000000014521464473310100171630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: At least use mlock or something use bytes; use errors; export type key = []u8; // Creates a new secure key. The caller should clear the secret buffer with // [[bytes::zero]] after initialization. export fn newkey(buf: []u8, name: str) (key | errors::error) = { return alloc(buf...): []u8: key; }; // Destroys a secure key. export fn destroy(key: key) void = { bytes::zero(key[..]); free(key); }; // Reads secret data from a secure key. When the caller is done using the secret // buffer, they should use [[bytes::zero]] to securely wipe the buffer memory. export fn read(key: key, buf: []u8) size = { let amt = len(buf); if (len(key) < len(buf)) { amt = len(key); }; buf[..amt] = key[..amt]; return amt; }; hare-0.24.2/crypto/mac/000077500000000000000000000000001464473310100146015ustar00rootroot00000000000000hare-0.24.2/crypto/mac/README000066400000000000000000000001331464473310100154560ustar00rootroot00000000000000mac provides a generic interface for use with message authentication code (MAC) functions. hare-0.24.2/crypto/mac/mac.ha000066400000000000000000000037711464473310100156630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; // TODO: Use a vtable-based approach like io::stream // The general purpose interface for a MAC function. export type mac = struct { // A stream which only supports writes and never returns errors. stream: io::stream, // Writes the resulting MAC to 'buf'. Must only be called once, and must // be followed by calling [[finish]]. sum: nullable *fn(mac: *mac, buf: []u8) void, // Finalizes the MAC function, securely discards all state and frees // all resources used by the MAC. finish: *fn(mac: *mac) void, // Size of the MAC in bytes. sz: size, // Internal block size of the MAC in bytes. bsz: size, }; // Writes an input to the MAC function. export fn write(m: *mac, buf: const []u8) size = io::write(m, buf) as size; // Computes the final MAC and writes it to 'buf', which must be at least [[sz]] // bytes. Generally, each MAC implementation provides a constant which is equal // to the length, so you may not have to dynamically allocate this buffer. // // This function may only be called once for any given [[mac]] object; calling // it more than once will cause a runtime assertion to fail. // // After calling [[sum]], you must call [[finish]] to securely erase sensitive // information stored in the MAC function state. export fn sum(m: *mac, buf: []u8) void = { assert(len(buf) >= m.sz, "mac::finish buffer does not meet minimum required size"); match(m.sum) { case let f: *fn(mac: *mac, buf: []u8) void => f(m, buf); m.sum = null; case null => abort("MAC is already finished or sum has already been called"); }; }; // Finalizes the MAC function, securely discarding any sensitive state, and // freeing any associated resources. export fn finish(m: *mac) void = { m.finish(m); m.sum = null; }; // Returns the size of the MAC in bytes. This is consistent regardless // of the MAC state. export fn sz(m: *mac) size = m.sz; // Returns the block size of the MAC in bytes. export fn bsz(m: *mac) size = m.bsz; hare-0.24.2/crypto/math/000077500000000000000000000000001464473310100147725ustar00rootroot00000000000000hare-0.24.2/crypto/math/README000066400000000000000000000010161464473310100156500ustar00rootroot00000000000000crypto::math provides constant-time mathematical operations useful for cryptographic algorithms. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/math/arithm.ha000066400000000000000000000043171464473310100165750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2017 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // Returns the quotient and remainder of (hi, lo) divided by y: // quo = (hi, lo) / y, rem = (hi, lo) % y with the dividend bits' upper // half in parameter hi and the lower half in parameter lo. // Panics for y == 0 (division by zero) or y <= hi (quotient overflow). export fn divu32(hi: u32, lo: u32, y: u32) (u32, u32) = { assert(y != 0); assert(y > hi); let q: u32 = 0; const ch: u32 = equ32(hi, y); hi = muxu32(ch, 0, hi); for (let k: u32 = 31; k > 0; k -= 1) { const j = (32 - k); const w = (hi << j) | (lo >> k); const ctl = geu32(w, y) | (hi >> k); const hi2 = (w - y) >> j; const lo2 = lo - (y << k); hi = muxu32(ctl, hi2, hi); lo = muxu32(ctl, lo2, lo); q |= ctl << k; }; let cf = geu32(lo, y) | hi; q |= cf; const r = muxu32(cf, lo - y, lo); return (q, r); }; @test fn divu32() void = { const r = divu32(1, 4294967295, 9); assert(r.0 == 954437176); assert(r.1 == 7); const r = divu32(0, 485, 13); assert(r.0 == 37); assert(r.1 == 4); }; hare-0.24.2/crypto/math/bits.ha000066400000000000000000000123041464473310100162450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Rotates a 32-bit unsigned integer left by k bits. k may be negative to rotate // right instead, or see [[rotr32]]. export fn rotl32(x: u32, k: int) u32 = { const n = 32u32; const s = k: u32 & (n - 1); return x << s | x >> (n - s); }; // Rotates a 32-bit unsigned integer right by k bits. k may be negative to // rotate left instead, or see [[rotl32]]. export fn rotr32(x: u32, k: int) u32 = rotl32(x, -k); @test fn lrot32() void = { let a = 0b11110000111100001111000011110000u32; assert(rotl32(a, 2) == 0b11000011110000111100001111000011u32); assert(rotl32(a, -2) == 0b00111100001111000011110000111100u32); assert(rotl32(a, 32) == 0b11110000111100001111000011110000u32); assert(rotl32(a, 64) == 0b11110000111100001111000011110000u32); }; // Rotates a 64-bit unsigned integer left by k bits. k may be negative to rotate // right instead, or see [[rotr64]]. export fn rotl64(x: u64, k: int) u64 = { const n = 64u64; const s = k: u64 & (n - 1); return x << s | x >> (n - s); }; // Rotates a 64-bit unsigned integer right by k bits. k may be negative to rotate // left instead, or see [[rotl64]]. export fn rotr64(x: u64, k: int) u64 = rotl64(x, -k); @test fn lrot64() void = { let a = 1u64; assert(rotl64(a, 1) == 0b10); assert(rotl64(a, -1) == 0b1000000000000000000000000000000000000000000000000000000000000000); assert(rotl64(a, 39) == (1u64 << 39)); let a = 0b1111000011110000111100001111000011110000111100001111000011110000u64; assert(rotl64(a, 64) == a); assert(rotl64(a, 0) == a); assert(rotl64(a, 2) == 0b1100001111000011110000111100001111000011110000111100001111000011u64); assert(rotl64(a, -2) == 0b0011110000111100001111000011110000111100001111000011110000111100u64); }; // Stores the xor of 'a' and 'b' into 'dest'. All parameters must have the same // length. 'dest' may be the same slice as 'a' and/or 'b'. export fn xor(dest: []u8, a: []u8, b: []u8) void = { assert(len(dest) == len(a) && len(dest) == len(b), "dest, a and b must have the same length"); for (let i = 0z; i < len(dest); i += 1) { dest[i] = a[i] ^ b[i]; }; }; // Compare two byte slices in constant time. // // Returns 1 if the two slices have the same contents, 0 otherwise. export fn eqslice(x: []u8, y: []u8) int = { assert(len(x) == len(y), "slices must have the same length"); let v: u8 = 0; for (let i = 0z; i < len(x); i += 1) { v |= x[i] ^ y[i]; }; return equ8(v, 0); }; @test fn eqslice() void = { assert(eqslice([], []) == 1); assert(eqslice([0], [0]) == 1); assert(eqslice([1], [0]) == 0); assert(eqslice([1, 0], [0, 0]) == 0); assert(eqslice([0, 0], [0, 0]) == 1); assert(eqslice([0x12, 0xAB], [0x12, 0xAB]) == 1); assert(eqslice([0x12, 0xAB], [0x12, 0xAC]) == 0); assert(eqslice([0x12, 0xAB], [0x11, 0xAB]) == 0); }; // Compare two bytes in constant time. Returns 1 if the bytes are the same // value, 0 otherwise. export fn equ8(x: u8, y: u8) int = ((((x ^ y) : u32) - 1) >> 31) : int; // Returns x if ctl == 1 and y if ctl == 0. export fn muxu32(ctl: u32, x: u32, y: u32) u32 = y ^ ((-(ctl: i32)): u32 & (x ^ y)); @test fn muxu32() void = { assert(muxu32(1, 0x4, 0xff) == 0x4); assert(muxu32(0, 0x4, 0xff) == 0xff); }; // Negates first bit. export fn notu32(x: u32) u32 = x ^ 1; // Compares 'x' and 'y'. Returns 1 if they are equal or 0 otherwise. export fn equ32(x: u32, y: u32) u32 = { let q = x ^ y; return ((q | -(q: i32): u32) >> 31) ^ 1; }; @test fn equ32() void = { assert(equ32(0x4f, 0x4f) == 1); assert(equ32(0x4f, 0x0) == 0); assert(equ32(0x2, 0x6) == 0); }; // Returns 1 if 'x' is zero or 0 if not. export fn eq0u32(x: u32) u32 = { return ~(x | -x) >> 31; }; @test fn eq0u32() void = { assert(eq0u32(0) == 1); assert(eq0u32(1) == 0); assert(eq0u32(0x1234) == 0); assert(eq0u32(types::U32_MAX) == 0); }; // Returns 1 if x != y and 0 otherwise. export fn nequ32(x: u32, y: u32) u32 = { let q = x ^ y; return (q | -(q: i32): u32) >> 31; }; // Returns 1 if x > y and 0 otherwise. export fn gtu32(x: u32, y: u32) u32 = { let z: u32 = y - x; return (z ^ ((x ^ y) & (x ^ z))) >> 31; }; @test fn gtu32() void = { assert(gtu32(1, 0) == 1); assert(gtu32(0, 1) == 0); assert(gtu32(0, 0) == 0); assert(gtu32(0xf3, 0xf2) == 1); assert(gtu32(0x20, 0xff) == 0); assert(gtu32(0x23, 0x23) == 0); }; // Returns 1 if x >= y and 0 otherwise. export fn geu32(x: u32, y: u32) u32 = notu32(gtu32(y, x)); // Returns 1 if x < y and 0 otherwise. export fn ltu32(x: u32, y: u32) u32 = gtu32(y, x); // Returns 1 if x <= y and 0 otherwise. export fn leu32(x: u32, y: u32) u32 = notu32(gtu32(x, y)); // Compares 'x' with 'y'. Returns -1 if x < y, 0 if x == y and 1 if x > x. export fn cmpu32(x: u32, y: u32) i32 = gtu32(x, y): i32 | -(gtu32(y, x): i32); @test fn cmpu32() void = { assert(cmpu32(0, 0) == 0); assert(cmpu32(0x34, 0x34) == 0); assert(cmpu32(0x12, 0x34) == -1); assert(cmpu32(0x87, 0x34) == 1); }; // Multiplies two u32 and returns result as u64. export fn mulu32(x: u32, y: u32) u64 = x: u64 * y: u64; // Copies 'src' to 'dest' if 'ctl' == 1 export fn ccopyu32(ctl: u32, dest: []u32, src: const []u32) void = { for (let i = 0z; i < len(dest); i += 1) { const x = src[i]; const y = dest[i]; dest[i] = muxu32(ctl, x, y); }; }; hare-0.24.2/crypto/poly1305/000077500000000000000000000000001464473310100153355ustar00rootroot00000000000000hare-0.24.2/crypto/poly1305/+test.ha000066400000000000000000000112771464473310100167110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::mac; // example taken from the Poly1305-AES paper from D. J. Bernstein @test fn example1() void = { const message: [_]u8 = [0xf3, 0xf6]; const key: [32]u8 = [ 0x85, 0x1f, 0xc4, 0x0c, 0x34, 0x67, 0xac, 0x0b, 0xe0, 0x5c, 0xc2, 0x04, 0x04, 0xf3, 0xf7, 0x00, 0x58, 0x0b, 0x3b, 0x0f, 0x94, 0x47, 0xbb, 0x1e, 0x69, 0xd0, 0x95, 0xb5, 0x92, 0x8b, 0x6d, 0xbc, ]; const expected: [_]u8 = [ 0xf4, 0xc6, 0x33, 0xc3, 0x04, 0x4f, 0xc1, 0x45, 0xf8, 0x4f, 0x33, 0x5c, 0xb8, 0x19, 0x53, 0xde, ]; let result: [16]u8 = [0...]; let p = poly1305(); init(&p, &key); mac::write(&p, message); mac::sum(&p, result); mac::finish(&p); assert(bytes::equal(expected, result)); }; // example taken from the Poly1305-AES paper from D. J. Bernstein @test fn example2() void = { const key: [_]u8 = [ 0xa0, 0xf3, 0x08, 0x00, 0x00, 0xf4, 0x64, 0x00, 0xd0, 0xc7, 0xe9, 0x07, 0x6c, 0x83, 0x44, 0x03, 0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7, 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7, ]; const expected: [_]u8 = [ 0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7, 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7, ]; let result: [16]u8 = [0...]; let p = poly1305(); init(&p, &key); mac::sum(&p, result); mac::finish(&p); assert(bytes::equal(expected, result)); }; // example taken from the Poly1305-AES paper from D. J. Bernstein @test fn example3() void = { const message: [_]u8 = [ 0x66, 0x3c, 0xea, 0x19, 0x0f, 0xfb, 0x83, 0xd8, 0x95, 0x93, 0xf3, 0xf4, 0x76, 0xb6, 0xbc, 0x24, 0xd7, 0xe6, 0x79, 0x10, 0x7e, 0xa2, 0x6a, 0xdb, 0x8c, 0xaf, 0x66, 0x52, 0xd0, 0x65, 0x61, 0x36, ]; const expected: [_]u8 = [ 0x0e, 0xe1, 0xc1, 0x6b, 0xb7, 0x3f, 0x0f, 0x4f, 0xd1, 0x98, 0x81, 0x75, 0x3c, 0x01, 0xcd, 0xbe, ]; const key: [32]u8 = [ 0x48, 0x44, 0x3d, 0x0b, 0xb0, 0xd2, 0x11, 0x09, 0xc8, 0x9a, 0x10, 0x0b, 0x5c, 0xe2, 0xc2, 0x08, 0x83, 0x14, 0x9c, 0x69, 0xb5, 0x61, 0xdd, 0x88, 0x29, 0x8a, 0x17, 0x98, 0xb1, 0x07, 0x16, 0xef, ]; let result: [16]u8 = [0...]; let p = poly1305(); init(&p, &key); mac::write(&p, message); mac::sum(&p, result); mac::finish(&p); assert(bytes::equal(expected, result)); }; // example taken from the Poly1305-AES paper from D. J. Bernstein @test fn example4() void = { const message: [_]u8 = [ 0xab, 0x08, 0x12, 0x72, 0x4a, 0x7f, 0x1e, 0x34, 0x27, 0x42, 0xcb, 0xed, 0x37, 0x4d, 0x94, 0xd1, 0x36, 0xc6, 0xb8, 0x79, 0x5d, 0x45, 0xb3, 0x81, 0x98, 0x30, 0xf2, 0xc0, 0x44, 0x91, 0xfa, 0xf0, 0x99, 0x0c, 0x62, 0xe4, 0x8b, 0x80, 0x18, 0xb2, 0xc3, 0xe4, 0xa0, 0xfa, 0x31, 0x34, 0xcb, 0x67, 0xfa, 0x83, 0xe1, 0x58, 0xc9, 0x94, 0xd9, 0x61, 0xc4, 0xcb, 0x21, 0x09, 0x5c, 0x1b, 0xf9, ]; const expected: [_]u8 = [ 0x51, 0x54, 0xad, 0x0d, 0x2c, 0xb2, 0x6e, 0x01, 0x27, 0x4f, 0xc5, 0x11, 0x48, 0x49, 0x1f, 0x1b, ]; const key: [32]u8 = [ 0x12, 0x97, 0x6a, 0x08, 0xc4, 0x42, 0x6d, 0x0c, 0xe8, 0xa8, 0x24, 0x07, 0xc4, 0xf4, 0x82, 0x07, 0x80, 0xf8, 0xc2, 0x0a, 0xa7, 0x12, 0x02, 0xd1, 0xe2, 0x91, 0x79, 0xcb, 0xcb, 0x55, 0x5a, 0x57, ]; let result: [16]u8 = [0...]; let p = poly1305(); init(&p, &key); mac::write(&p, message); mac::sum(&p, result); mac::finish(&p); assert(bytes::equal(expected, result)); }; @test fn writepatterns() void = { const message: [_]u8 = [ 0xab, 0x08, 0x12, 0x72, 0x4a, 0x7f, 0x1e, 0x34, 0x27, 0x42, 0xcb, 0xed, 0x37, 0x4d, 0x94, 0xd1, 0x36, 0xc6, 0xb8, 0x79, 0x5d, 0x45, 0xb3, 0x81, 0x98, 0x30, 0xf2, 0xc0, 0x44, 0x91, 0xfa, 0xf0, 0x99, 0x0c, 0x62, 0xe4, 0x8b, 0x80, 0x18, 0xb2, 0xc3, 0xe4, 0xa0, 0xfa, 0x31, 0x34, 0xcb, 0x67, 0xfa, 0x83, 0xe1, 0x58, 0xc9, 0x94, 0xd9, 0x61, 0xc4, 0xcb, 0x21, 0x09, 0x5c, 0x1b, 0xf9, ]; const expected: [_]u8 = [ 0x51, 0x54, 0xad, 0x0d, 0x2c, 0xb2, 0x6e, 0x01, 0x27, 0x4f, 0xc5, 0x11, 0x48, 0x49, 0x1f, 0x1b, ]; const key: [32]u8 = [ 0x12, 0x97, 0x6a, 0x08, 0xc4, 0x42, 0x6d, 0x0c, 0xe8, 0xa8, 0x24, 0x07, 0xc4, 0xf4, 0x82, 0x07, 0x80, 0xf8, 0xc2, 0x0a, 0xa7, 0x12, 0x02, 0xd1, 0xe2, 0x91, 0x79, 0xcb, 0xcb, 0x55, 0x5a, 0x57, ]; patternwrite(&key, message[..], expected[..], [5, 20, 38]); patternwrite(&key, message[..], expected[..], [1, 2, 8, 10]); patternwrite(&key, message[..], expected[..], [16, 16]); patternwrite(&key, message[..], expected[..], [12, 4, 14, 2, 8, 8]); }; fn patternwrite(key: *key, msg: []u8, expected: []u8, pattern: []uint) void = { let p = poly1305(); init(&p, key); for (let i = 0z; i < len(pattern); i += 1) { let n = pattern[i]; mac::write(&p, msg[..n]); msg = msg[n..]; }; if (len(msg) > 0) { mac::write(&p, msg); }; let result: [16]u8 = [0...]; mac::sum(&p, result); mac::finish(&p); assert(bytes::equal(expected, result)); }; hare-0.24.2/crypto/poly1305/README000066400000000000000000000007531464473310100162220ustar00rootroot00000000000000This module provides the poly1305 MAC as defined in RFC 8439. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/poly1305/poly1305.ha000066400000000000000000000077671464473310100171640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // This implementation was ported from Loup Vaillant's monocypher project. use bytes; use crypto::mac; use endian; use io; // Internal block size in bytes. export def BLOCKSZ: size = 16; // Length of the resulting MAC in bytes. export def SZ: size = 16; // Poly1305 key. export type key = [32]u8; export type state = struct { mac::mac, r: [4]u32, h: [5]u32, c: [16]u8, pad: [4]u32, cidx: size, }; const poly1305_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[crypto::mac::mac]] that computes the poly1305 MAC. It needs to // be initialised using [[init]]. Like the other MACs it needs to be finished // using [[crypto::mac::finish]] after use. export fn poly1305() state = { return state { stream = &poly1305_vtable, sum = &sum, finish = &finish, sz = SZ, bsz = BLOCKSZ, ... }; }; // Initialises the MAC with given one time key. export fn init(p: *state, key: *key) void = { leputu32slice(p.r, key); leputu32slice(p.pad, key[16..]); p.r[0] &= 0x0fffffff; for (let i = 1z; i < 4; i += 1) { p.r[i] &= 0x0ffffffc; }; p.cidx = 0; }; fn leputu32slice(dest: []u32, src: []u8) void = { for (let i = 0z; i < len(dest); i += 1) { dest[i] = endian::legetu32(src[i * 4..(i + 1) * 4]); }; }; fn write(st: *io::stream, bbuf: const []u8) (size | io::error) = { let p = st: *state; let buf: []u8 = bbuf; const written = len(buf); for (len(buf) > 0) { const n = if (len(buf) <= BLOCKSZ - p.cidx) { yield len(buf); } else { yield BLOCKSZ - p.cidx; }; p.c[p.cidx..p.cidx + n] = buf[..n]; p.cidx += n; buf = buf[n..]; if (p.cidx >= BLOCKSZ) { block(p, p.c, 1); p.cidx = 0; }; }; return written; }; fn block(p: *state, buf: []u8, end: u32) void = { let s: [4]u32 = [0...]; leputu32slice(s, buf); // s = h + c, without carry propagation const s0: u64 = p.h[0]: u64 + s[0]; const s1: u64 = p.h[1]: u64 + s[1]; const s2: u64 = p.h[2]: u64 + s[2]; const s3: u64 = p.h[3]: u64 + s[3]; const s4: u32 = p.h[4] + end; // Local all the things! const r0: u32 = p.r[0]; const r1: u32 = p.r[1]; const r2: u32 = p.r[2]; const r3: u32 = p.r[3]; const rr0: u32 = (r0 >> 2) * 5; const rr1: u32 = (r1 >> 2) + r1; const rr2: u32 = (r2 >> 2) + r2; const rr3: u32 = (r3 >> 2) + r3; // (h + c) * r, without carry propagation const x0: u64 = s0 * r0 + s1 * rr3 + s2 * rr2 + s3 * rr1 + s4 * rr0; const x1: u64 = s0 * r1 + s1 * r0 + s2 * rr3 + s3 * rr2 + s4 * rr1; const x2: u64 = s0 * r2 + s1 * r1 + s2 * r0 + s3 * rr3 + s4 * rr2; const x3: u64 = s0 * r3 + s1 * r2 + s2 * r1 + s3 * r0 + s4 * rr3; const x4: u32 = s4 * (r0 & 3); // partial reduction modulo 2^130 - 5 const u5: u32 = x4 + (x3 >> 32): u32; const u0: u64 = (u5 >> 2) * 5 + (x0 & 0xffffffff); const u1: u64 = (u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32); const u2: u64 = (u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32); const u3: u64 = (u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32); const u4: u64 = (u3 >> 32) + (u5 & 3); // Update the hash p.h[0] = u0: u32; p.h[1] = u1: u32; p.h[2] = u2: u32; p.h[3] = u3: u32; p.h[4] = u4: u32; }; fn sum(m: *mac::mac, buf: []u8) void = { let p = m: *state; if (p.cidx > 0) { // update last block p.c[p.cidx] = 1; bytes::zero(p.c[p.cidx + 1..]); block(p, p.c, 0); }; // check if we should subtract 2^130-5 by performing the // corresponding carry propagation. let c: u64 = 5; for (let i = 0z; i < 4; i += 1) { c += p.h[i]; c >>= 32; }; c += p.h[4]; c = (c >> 2) * 5; // shift the carry back to the beginning // c now indicates how many times we should subtract 2^130-5 (0 or 1) for (let i = 0z; i < 4; i += 1) { c += p.h[i]: u64 + p.pad[i]: u64; endian::leputu32(buf[i * 4..(i + 1) * 4], c: u32); c = c >> 32; }; }; fn finish(m: *mac::mac) void = { let p = m: *state; bytes::zero((p.r[..]: *[*]u8)[..len(p.r) * size(u32)]); bytes::zero((p.h[..]: *[*]u8)[..len(p.h) * size(u32)]); bytes::zero(p.c[..]); bytes::zero((p.pad[..]: *[*]u8)[..len(p.pad) * size(u32)]); }; hare-0.24.2/crypto/random/000077500000000000000000000000001464473310100153215ustar00rootroot00000000000000hare-0.24.2/crypto/random/+freebsd.ha000066400000000000000000000016201464473310100173170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Fills the given buffer with cryptographically random data. If the system is // unable to provide random data, abort. If you need to handle errors or want to // use whatever random data the system can provide, even if less than the // requested amount, use [[stream]] instead. export fn buffer(buf: []u8) void = { let n = 0z; for (n < len(buf)) { match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) { case let err: rt::errno => switch (err) { case rt::EINTR => void; case => abort(); }; case let z: size => n += z; }; }; }; fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { assert(s == stream); match (rt::getrandom(buf: *[*]u8, len(buf), 0)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/crypto/random/+linux.ha000066400000000000000000000016201464473310100170440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Fills the given buffer with cryptographically random data. If the system is // unable to provide random data, abort. If you need to handle errors or want to // use whatever random data the system can provide, even if less than the // requested amount, use [[stream]] instead. export fn buffer(buf: []u8) void = { let n = 0z; for (n < len(buf)) { match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) { case let err: rt::errno => switch (err) { case rt::EINTR => void; case => abort(); }; case let z: size => n += z; }; }; }; fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { assert(s == stream); match (rt::getrandom(buf: *[*]u8, len(buf), 0)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/crypto/random/+netbsd.ha000066400000000000000000000016201464473310100171640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Fills the given buffer with cryptographically random data. If the system is // unable to provide random data, abort. If you need to handle errors or want to // use whatever random data the system can provide, even if less than the // requested amount, use [[stream]] instead. export fn buffer(buf: []u8) void = { let n = 0z; for (n < len(buf)) { match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) { case let err: rt::errno => switch (err) { case rt::EINTR => void; case => abort(); }; case let z: size => n += z; }; }; }; fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { assert(s == stream); match (rt::getrandom(buf: *[*]u8, len(buf), 0)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/crypto/random/+openbsd.ha000066400000000000000000000011401464473310100173340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; use io; // Fills the given buffer with cryptographically random data. If the system is // unable to provide random data, abort. If you need to handle errors or want to // use whatever random data the system can provide, even if less than the // requested amount, use [[stream]] instead. export fn buffer(buf: []u8) void = { rt::arc4random_buf(buf: *[*]u8: *const opaque, len(buf)); }; fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { assert(s == stream); buffer(buf); return len(buf); }; hare-0.24.2/crypto/random/README000066400000000000000000000004161464473310100162020ustar00rootroot00000000000000crypto::random provides a cryptographically secure random number generator, which yields a nondeterministic sequence of random numbers. If true randomness isn't required for your use case, you may be better off using [[math::random::]]'s pseudorandom number generator. hare-0.24.2/crypto/random/random.ha000066400000000000000000000017141464473310100171160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; let _stream_vt: io::vtable = io::vtable { reader = &rand_reader, ... }; const _stream: io::stream = &_stream_vt; // An [[io::handle]] which returns cryptographically random data on reads. Be // aware, it may return less than you asked for! export let stream: *io::stream = &_stream; @test fn buffer() void = { let buf: [4096]u8 = [0...]; buffer(buf[..]); let sum = 0z; for (let i = 0z; i < len(buf); i += 1) { sum += buf[i]; }; let avg = sum / len(buf); assert(avg < 0xA0 && avg > 0x60); }; @test fn reader() void = { let buf: [4096]u8 = [0...]; let test: []u8 = []; match (io::readall(stream, buf[..])) { case (io::error | io::EOF) => abort(); case let n: size => test = buf[..n]; }; assert(len(test) > 0); let sum = 0z; for (let i = 0z; i < len(test); i += 1) { sum += test[i]; }; let avg = sum / len(test); assert(avg < 0xA0 && avg > 0x60); }; hare-0.24.2/crypto/rsa/000077500000000000000000000000001464473310100146265ustar00rootroot00000000000000hare-0.24.2/crypto/rsa/+test/000077500000000000000000000000001464473310100156605ustar00rootroot00000000000000hare-0.24.2/crypto/rsa/+test/core_test.ha000066400000000000000000000146311464473310100201660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::bigint::*; let pubbuf: [PUBEXP_BUFSZ]u8 = [0...]; let privbuf: [PRIVEXP_BUFSZ]u8 = [0...]; let pkcs1_verifybuf: [PKCS1_VERIFYBUFSZ]u8 = [0...]; let pkcs1_signbuf: [PKCS1_SIGNBUFSZ]u8 = [0...]; @test fn tiny() void = { let pub = pubparams { e = [0x01, 0x00, 0x01], n = [0x1, 0x87], ... }; let msg: []u8 = [0x00, 0xc]; pubexp(&pub, msg, pubbuf)!; assert(bytes::equal(msg, [0x01, 0x2d])); }; @test fn smallprivexp() void = { let priv = privparams { nbitlen = 200, p = [ 0x0a, 0xd2, 0xbe, 0xc0, 0xbf, 0x9a, 0xfa, 0x3b, 0x64, 0x7a, 0x27, 0x33, 0x59, ], q = [ 0x0c, 0xfd, 0x9a, 0xec, 0x42, 0xcd, 0xce, 0xc0, 0xc5, 0x43, 0x31, 0xbf, 0x33, ], dp = [ 0x03, 0x3c, 0x37, 0xb4, 0xda, 0x11, 0x73, 0x57, 0x29, 0x93, 0xb2, 0x00, 0x11, ], dq = [ 0x01, 0xde, 0xde, 0xd9, 0x18, 0x81, 0x84, 0x3d, 0x13, 0xea, 0xaa, 0x16, 0x2b, ], iq = [ 0x08, 0x24, 0xbc, 0x1a, 0xea, 0xcc, 0xdf, 0xe1, 0x5a, 0x0a, 0x6f, 0x32, 0xa8, ], ... }; let x: [_]u8 = [ 0x0c, 0x5b, 0xea, 0x82, 0x38, 0xc2, 0xfc, 0x7a, 0x2c, 0xe3, 0xc1, 0x39, 0x44, 0x5b, 0x21, 0xc2, 0xa4, 0x6e, 0xb1, 0x7b, 0xeb, 0xbb, 0xd4, 0xea, 0xfc, ]; const expected: [_]u8 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x07, 0xc9, ]; privexp(&priv, x, privbuf)!; assert(bytes::equal(expected, x)); }; @test fn pubprivexp() void = { const x: [_]u8 = [ 0x6e, 0xb5, 0x5f, 0xbd, 0x48, 0x09, 0x08, 0x7c, 0x01, 0xb3, 0x74, 0x26, 0x73, 0x9d, 0x3e, 0xd5, 0x08, 0x7d, 0xe8, 0x11, 0x01, 0x21, 0x31, 0x11, 0x91, 0x34, 0x5b, 0xe5, 0x6c, 0x37, 0x79, 0x7b, 0xdb, 0x75, 0x16, 0x62, 0x0e, 0x7d, 0x1d, 0xd1, 0x04, 0x45, 0xbc, 0xa9, 0x79, 0xd0, 0xb1, 0x1d, 0x1e, 0x20, 0x65, 0x37, 0x92, 0x90, 0xa8, 0xd3, 0x5f, 0x07, 0x24, 0x54, 0x53, 0x97, 0x69, 0x84, 0xe2, 0xbb, 0xc0, 0xb5, 0x82, 0x4f, 0x29, 0xac, 0xc9, 0x07, 0xa7, 0x75, 0x08, 0x1c, 0x0c, 0x72, 0x9f, 0x35, 0x1b, 0x75, 0xb2, 0x79, 0x3f, 0x41, 0xa5, 0xcb, 0x9d, 0x69, 0x02, 0xa8, 0x08, 0xfe, 0x11, 0x19, 0x2f, 0xc2, 0xdb, 0x0e, 0xa6, 0xe0, 0xc4, 0x44, 0x33, 0xd6, 0xad, 0x59, 0x11, 0xa7, 0x38, 0xc0, 0xe7, 0x37, 0x21, 0xa8, 0x13, 0x96, 0xe9, 0x63, 0x25, 0xd9, 0x2e, 0xbf, 0x10, 0x59, 0x49, 0xdd, 0xc0, 0x55, 0xeb, 0x6d, 0xbe, 0x0a, 0x1e, 0xe2, 0x62, 0xce, 0x53, 0x2e, 0xaa, 0xed, 0xe5, 0x7e, 0xf7, 0x1b, 0xbb, 0x09, 0x75, 0x5e, 0x5f, 0xf9, 0x78, 0x12, 0x51, 0xa4, 0x63, 0x52, 0xa4, 0xba, 0x45, 0xbc, 0x48, 0x89, 0xb2, 0x73, 0xb4, 0xa5, 0x25, 0xd3, 0x1a, 0xd5, 0x9d, 0xff, 0x4e, 0xba, 0xd0, 0xb0, 0xb5, 0x21, 0x11, 0x25, 0x4d, 0x84, 0x90, 0x6e, 0xcd, 0x68, 0xd6, 0xd7, 0x39, 0xf7, 0x03, 0xb5, 0x7e, 0x78, 0x7e, 0x33, 0x2c, 0x7f, 0x34, 0x8f, 0x6f, 0xb2, 0x24, 0xe0, 0x5f, 0xd6, 0x18, 0x42, 0x4d, 0xb4, 0x5b, 0xe5, 0xc6, 0x92, 0xde, 0x54, 0x37, 0x69, 0x36, 0x7d, 0xe0, 0x0b, 0xa2, 0x6a, 0xb7, 0x41, 0xf4, 0x23, 0x09, 0x7f, 0x26, 0x64, 0xff, 0x10, 0x8a, 0x28, 0x34, 0xca, 0x08, 0x81, 0xf5, 0x38, 0x58, 0x46, 0xd2, 0xc0, 0x1c, 0x35, 0x31, 0x69, 0xcc, 0x4a, 0xed, 0x04, 0x22, 0x06, 0xbf, 0x79, 0x62, 0x0e, 0x43, 0x5e, 0x90, 0xf3, 0x95, 0x6b, 0x6e, 0xc3, 0x80, 0x9c, 0x63, 0xd1, 0xf7, 0xf2, 0x9f, 0x83, 0xb2, 0x09, 0x08, 0xcf, 0xb3, 0x87, 0x79, 0xc6, 0x24, 0xe6, 0x98, 0x58, 0xda, 0xdc, 0x0c, 0x67, 0x4c, 0x1f, 0xe7, 0xc3, 0x26, 0xec, 0xdd, 0x7e, 0x91, 0xb0, 0x31, 0x99, 0x5c, 0x93, 0x52, 0x17, 0xa2, 0x0f, 0xb1, 0xfb, 0x09, 0xd2, 0xa9, 0xe5, 0xdf, 0x1e, 0x5c, 0xa8, 0xf5, 0x0c, 0x20, 0xc3, 0xe3, 0x07, 0x32, 0x1b, 0x42, 0xc1, 0x58, 0xb2, 0x1c, 0x52, 0x7d, 0x56, 0xf8, 0x0c, 0xad, 0x03, 0xf5, 0x40, 0x07, 0x9c, 0xf4, 0x41, 0xf5, 0x54, 0xed, 0x66, 0x11, 0xd6, 0x98, 0xa4, 0x32, 0xd2, 0x94, 0x02, 0x74, 0xa9, 0xe1, 0x3a, 0x61, 0x18, 0x37, 0x54, 0xce, 0x03, 0x17, 0xc9, 0xc9, 0x99, 0x22, 0xd7, 0x3f, 0x71, 0x7f, 0xf5, 0x8d, 0xa3, ]; const result: [_]u8 = [ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40, 0xcd, 0xcc, 0x9b, 0x65, 0xfe, 0xa7, 0xb2, 0x4d, 0xb6, 0xae, 0xb7, 0xfb, 0xcb, 0x78, 0xb6, 0x10, 0x64, 0xcd, 0x9a, 0xdb, 0x81, 0x4f, 0xc0, 0x8a, 0x17, 0xd3, 0xc0, 0x6b, 0xa2, 0xdd, 0xbc, 0x61, 0xeb, 0xbf, 0xe2, 0x8e, 0x91, 0xf2, 0xd6, 0x75, 0xa2, 0x5b, 0x0e, 0x61, 0x85, 0x74, 0xda, 0xcc, 0x94, 0x59, 0xc4, 0x4b, 0x95, 0x0f, 0x80, 0xf6, 0x5e, 0xd4, 0x68, 0x09, 0x65, 0x5f, 0x28, 0x85, ]; let xc = alloc(x); defer free(xc); pubexp(&sign3072.pub, xc, pubbuf)!; assert(bytes::equal(result, xc)); privexp(&sign3072.priv, xc, privbuf)!; assert(bytes::equal(x, xc)); }; hare-0.24.2/crypto/rsa/+test/keys_test.ha000066400000000000000000000572601464473310100202160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; type keypair = struct { pub: pubparams, priv: privparams, d: []u8, }; let sign3072: keypair = keypair { pub = pubparams { n = [ 0xe1, 0x83, 0x1c, 0x9d, 0xa1, 0x19, 0xe5, 0x74, 0x86, 0x07, 0x85, 0x50, 0x96, 0x21, 0x62, 0x11, 0xdd, 0x80, 0xca, 0xe2, 0x2b, 0xf0, 0x22, 0x11, 0x83, 0xf0, 0x35, 0x65, 0xc6, 0x1c, 0x54, 0x18, 0xc6, 0x58, 0xd8, 0x2e, 0x32, 0xed, 0xa0, 0x84, 0x65, 0x24, 0xe5, 0x96, 0x79, 0xda, 0x05, 0x43, 0x65, 0x83, 0x56, 0xe7, 0x5c, 0xed, 0x2f, 0x82, 0x56, 0x04, 0x2f, 0x47, 0x4b, 0xdf, 0x7d, 0x7c, 0xd5, 0xf2, 0x07, 0xbb, 0x44, 0x43, 0x78, 0x18, 0x14, 0xc1, 0x00, 0x44, 0x16, 0xca, 0x6c, 0x08, 0x53, 0x1c, 0x19, 0x76, 0x51, 0xcf, 0x4a, 0x25, 0x33, 0xca, 0x1e, 0xf3, 0x0d, 0x31, 0x2a, 0x6a, 0x6f, 0x77, 0x1f, 0xe4, 0x55, 0xe9, 0x01, 0xea, 0x7c, 0x1d, 0x41, 0x70, 0xb7, 0x39, 0x2e, 0xb9, 0x05, 0x79, 0x47, 0xe9, 0xae, 0x14, 0xeb, 0x38, 0xfe, 0xc8, 0x57, 0x8d, 0xfe, 0x1b, 0x68, 0x66, 0x34, 0xb1, 0x80, 0xf6, 0xf8, 0x8a, 0x82, 0xe8, 0x60, 0x1b, 0x3a, 0xf7, 0xcc, 0x51, 0xdf, 0xd3, 0xb4, 0x67, 0xbf, 0xae, 0xb2, 0x6d, 0xa0, 0x7f, 0xdf, 0x08, 0xdf, 0xc4, 0x1d, 0xf9, 0x15, 0xad, 0x68, 0xe8, 0x71, 0xce, 0xf2, 0x5a, 0x0d, 0x1d, 0x92, 0x87, 0x77, 0x88, 0x05, 0x9c, 0xb6, 0x7d, 0x08, 0x33, 0x7a, 0x94, 0xcf, 0x53, 0x80, 0x04, 0x16, 0xe6, 0x03, 0x14, 0x54, 0x53, 0x7d, 0xb2, 0xe5, 0x8c, 0x80, 0x64, 0xe7, 0x14, 0xdf, 0xbd, 0xf9, 0x07, 0xbe, 0xa6, 0xb1, 0x1e, 0x4d, 0x65, 0xfa, 0x0a, 0x18, 0x10, 0x45, 0x83, 0x39, 0x0e, 0x9b, 0xa0, 0x86, 0xa7, 0x0b, 0xb7, 0x58, 0x58, 0x82, 0x52, 0x17, 0x53, 0x7c, 0xfe, 0xcf, 0x55, 0x0e, 0x61, 0xd8, 0xd4, 0xbc, 0xe9, 0x87, 0x21, 0x65, 0x74, 0xe8, 0x0a, 0xab, 0x43, 0x98, 0x3a, 0x83, 0x72, 0xaf, 0xd0, 0x7f, 0x93, 0xd4, 0x39, 0xa6, 0x09, 0xc8, 0x1d, 0xf1, 0x06, 0x25, 0x95, 0x9e, 0x13, 0x55, 0x06, 0x28, 0x03, 0xb2, 0x3c, 0xf2, 0x3a, 0xb0, 0x8c, 0xba, 0x4e, 0x05, 0x19, 0xbb, 0x98, 0x02, 0xca, 0x8d, 0x4d, 0xd2, 0xff, 0x8a, 0xa5, 0x34, 0x8a, 0x06, 0x15, 0xc0, 0xc3, 0xf6, 0x1b, 0xb8, 0x5e, 0xd7, 0xb9, 0x28, 0x39, 0x8c, 0x96, 0xdb, 0x85, 0x56, 0x21, 0xba, 0xff, 0x7b, 0x5f, 0x25, 0x47, 0xb5, 0x2e, 0x6c, 0x70, 0x73, 0xab, 0x13, 0x4d, 0x24, 0xa8, 0xb3, 0x73, 0xd7, 0x7f, 0xd8, 0xb3, 0xe4, 0xdf, 0x94, 0x9c, 0x48, 0xd6, 0x80, 0x0b, 0x8b, 0xd1, 0xd4, 0x29, 0xb9, 0xa2, 0xef, 0xab, 0x1e, 0x8d, 0xa7, 0x74, 0xa2, 0xc7, 0xe3, 0x89, 0xb5, 0x01, 0xcf, 0xf0, 0xc2, 0x28, 0x4d, 0x8e, 0x60, 0x42, 0x37, 0xbe, 0x18, 0x61, 0x29, 0x8d, 0x01, 0xe6, 0xf9, 0xb5, 0xa7, 0xc5, 0xb7, 0xce, 0xa8, 0x85, 0x61, 0x1b, ], e = [0x01, 0x00, 0x01], ... }, priv = privparams { nbitlen = 3072, p = [ 0x00, 0xff, 0xce, 0xa3, 0x93, 0x98, 0xe2, 0x7b, 0x85, 0xab, 0xfe, 0x6d, 0x3b, 0xb3, 0xfb, 0xa4, 0xca, 0xbe, 0x21, 0x7f, 0xa9, 0x09, 0x40, 0xe1, 0xf0, 0x10, 0xcf, 0xee, 0x9b, 0x23, 0xea, 0xff, 0xe7, 0x52, 0x28, 0x38, 0x51, 0x3b, 0xd4, 0x5b, 0xb7, 0xef, 0x4b, 0x7a, 0x23, 0xa8, 0xff, 0xa3, 0x41, 0xd9, 0xc1, 0x7b, 0xf4, 0x7d, 0x7a, 0xa6, 0x4f, 0x28, 0x66, 0x25, 0x6b, 0xda, 0x96, 0x97, 0x75, 0x8a, 0xd9, 0x3b, 0xb2, 0x48, 0x5a, 0xe7, 0x06, 0x37, 0x18, 0x0f, 0xb0, 0x3f, 0x0f, 0x1c, 0x38, 0x63, 0xe3, 0x16, 0x5c, 0xa0, 0xfe, 0xea, 0xc0, 0x08, 0x4d, 0xfc, 0x34, 0x28, 0x18, 0xd1, 0xa1, 0x51, 0x8c, 0xb1, 0x58, 0xb2, 0xbc, 0xad, 0xc0, 0xa8, 0x6b, 0x7f, 0xf2, 0xf9, 0xbc, 0xb5, 0xc7, 0x3f, 0x1f, 0x1a, 0x44, 0x75, 0xfe, 0x9f, 0xd1, 0x96, 0x8b, 0x7f, 0x03, 0xe7, 0x0a, 0x58, 0x67, 0xb1, 0xf4, 0x0d, 0x77, 0xc9, 0x31, 0xde, 0xda, 0xf2, 0x16, 0x1e, 0x02, 0xb7, 0xfc, 0x17, 0x93, 0xd7, 0x6d, 0x08, 0x73, 0xda, 0x92, 0x12, 0x49, 0xf2, 0x86, 0x93, 0xcd, 0x60, 0xb8, 0x00, 0xe2, 0xbc, 0xf7, 0x7e, 0x2c, 0xb1, 0x1c, 0x3f, 0x74, 0xf0, 0x01, 0x53, 0x25, 0x11, 0x47, 0x89, 0xe7, 0x4d, 0x6f, 0x06, 0x9b, 0x43, 0x9e, 0xab, 0x47, 0x9f, 0x83, 0x45, 0x40, 0x95, 0x3f, 0x83, 0xff, ], q = [ 0x00, 0xe1, 0xae, 0xa0, 0x84, 0xac, 0xc1, 0xa4, 0xba, 0xf9, 0x4b, 0x00, 0x65, 0xa7, 0x89, 0xf0, 0x92, 0x34, 0x62, 0x58, 0x5a, 0x1c, 0xcf, 0x4b, 0xb2, 0xda, 0x5f, 0xab, 0x11, 0x6e, 0x78, 0x91, 0x56, 0x9d, 0x8b, 0xb1, 0xdb, 0x5a, 0x68, 0xb7, 0x5d, 0x39, 0x76, 0xac, 0x77, 0xd7, 0x2c, 0xea, 0xd8, 0xac, 0xa1, 0xc6, 0xbe, 0x87, 0xe4, 0xca, 0xa8, 0x00, 0x85, 0x2b, 0x8a, 0x9c, 0x53, 0x89, 0x3f, 0xdf, 0x84, 0x6a, 0x8e, 0x6e, 0xb2, 0xc0, 0x2a, 0x56, 0xd9, 0x43, 0xee, 0xca, 0x43, 0x6a, 0x4d, 0x04, 0x59, 0xe1, 0xd4, 0x5b, 0x11, 0x3d, 0xea, 0x5b, 0xe1, 0x11, 0xa2, 0xfc, 0xca, 0x77, 0xd7, 0x3a, 0xbc, 0x43, 0xbf, 0xf3, 0xae, 0x9c, 0x98, 0x2a, 0x6c, 0x2e, 0x34, 0x27, 0x5c, 0x4b, 0xd7, 0x5a, 0x74, 0xf4, 0xf4, 0x4e, 0x63, 0x83, 0xef, 0x2d, 0xc5, 0x15, 0x2a, 0xd0, 0x7b, 0x3c, 0xf9, 0x2e, 0xcb, 0x0f, 0x8f, 0x48, 0x29, 0x1f, 0xe3, 0xc4, 0xac, 0x65, 0xbd, 0xcb, 0xbb, 0xb1, 0xf0, 0x45, 0x6e, 0x6c, 0x38, 0xbf, 0x5d, 0x50, 0xef, 0xb2, 0xd9, 0x62, 0x13, 0x92, 0x6f, 0xa7, 0x4a, 0x24, 0x83, 0x1e, 0x25, 0x40, 0x4a, 0x4e, 0x1c, 0x90, 0xf2, 0x5f, 0x6c, 0x8a, 0xe0, 0x4f, 0xdc, 0xc1, 0x2d, 0x8d, 0x15, 0x95, 0xdf, 0x0f, 0x1b, 0xce, 0x28, 0xce, 0x2f, 0xcf, 0x13, 0xb2, 0xe5, ], dp = [ 0x02, 0x49, 0x8c, 0xb8, 0xe3, 0x23, 0x13, 0x4b, 0xac, 0xb0, 0x07, 0xb6, 0x02, 0xf3, 0xfb, 0x13, 0x3d, 0x03, 0xfb, 0xaa, 0x3d, 0x44, 0xf1, 0x40, 0x3e, 0x46, 0x3d, 0xb1, 0xf1, 0x6e, 0x46, 0x7f, 0x81, 0x02, 0x8f, 0x0e, 0x5a, 0xe4, 0x99, 0x35, 0x59, 0xd4, 0x68, 0xf1, 0x2c, 0xaf, 0xac, 0x7c, 0x08, 0x40, 0x6c, 0xa5, 0x51, 0x01, 0xe9, 0xbe, 0xc7, 0x73, 0xb2, 0x5d, 0xf6, 0x84, 0x66, 0x32, 0x4c, 0xdd, 0x88, 0x65, 0x1d, 0xb4, 0x82, 0x60, 0x51, 0xd9, 0xcb, 0x3a, 0x1e, 0x36, 0x3a, 0x60, 0x5e, 0xb4, 0x47, 0x1c, 0xe8, 0xeb, 0x9e, 0x99, 0xbc, 0xf9, 0x45, 0x8a, 0x09, 0xd9, 0xbe, 0xf6, 0x1c, 0x4e, 0x8f, 0xbf, 0x65, 0x49, 0xbe, 0x9b, 0xfc, 0x65, 0x89, 0xad, 0x58, 0x82, 0x51, 0x75, 0xc8, 0xa0, 0xb4, 0x91, 0x6c, 0x24, 0xac, 0xb5, 0x29, 0x0d, 0x72, 0x43, 0x4c, 0xab, 0x91, 0x02, 0xcc, 0x5a, 0x8c, 0x4c, 0x47, 0xe6, 0x44, 0x41, 0xdc, 0xec, 0x49, 0xb4, 0x68, 0x84, 0xbe, 0x89, 0x39, 0xe1, 0xe5, 0xb3, 0x73, 0x7e, 0xde, 0xde, 0xfe, 0x66, 0x29, 0xa8, 0x2a, 0x77, 0x3a, 0xba, 0xcc, 0x49, 0xc2, 0x3d, 0x10, 0x10, 0x5a, 0x98, 0xe7, 0x14, 0x7b, 0xf3, 0xd6, 0xe5, 0xb6, 0xdb, 0xf4, 0x9b, 0x4b, 0x89, 0xd3, 0xde, 0xf5, 0x55, 0x1c, 0x9e, 0x05, 0xde, 0x7f, 0xf7, 0x23, 0x6d, ], dq = [ 0x2d, 0x13, 0x96, 0x18, 0x29, 0xf1, 0x5b, 0x97, 0xc4, 0xe7, 0x48, 0x23, 0x05, 0xbd, 0xb5, 0x81, 0x5e, 0x59, 0x2e, 0x50, 0x81, 0x64, 0x9e, 0x38, 0x11, 0x09, 0xfe, 0xbf, 0x32, 0x93, 0x7e, 0x64, 0x10, 0x7f, 0xb0, 0x7c, 0xa1, 0xa8, 0x3c, 0xc7, 0xb0, 0x0c, 0x96, 0x12, 0x31, 0xb6, 0x55, 0x0a, 0x06, 0x21, 0x21, 0xf3, 0x38, 0x6d, 0x68, 0x54, 0xfa, 0x15, 0x9f, 0x46, 0xc6, 0x46, 0xa1, 0x29, 0x52, 0xd9, 0xbd, 0xf6, 0xc9, 0x01, 0x87, 0x04, 0x6d, 0xe8, 0x63, 0x7b, 0x34, 0x87, 0x16, 0x9a, 0x5f, 0x7e, 0x1c, 0x6f, 0x2f, 0xe9, 0x57, 0xb6, 0x91, 0xb7, 0x78, 0xb0, 0x57, 0x51, 0x91, 0x72, 0x39, 0xd7, 0x14, 0xa9, 0x28, 0x60, 0xfe, 0x02, 0x1e, 0xa7, 0x10, 0xeb, 0x75, 0xd9, 0x27, 0x84, 0xd2, 0x1a, 0x7e, 0x3a, 0xb5, 0xd5, 0x86, 0xaa, 0xa5, 0x37, 0xb2, 0x2c, 0xa5, 0x0b, 0x98, 0x78, 0x24, 0xf2, 0x86, 0x1f, 0x16, 0x48, 0xb0, 0x87, 0xeb, 0xe6, 0x8b, 0x43, 0xc7, 0x87, 0xab, 0xd8, 0xd3, 0xe5, 0x64, 0x54, 0x49, 0x54, 0xb8, 0x2f, 0xc8, 0x47, 0x47, 0x21, 0xa5, 0xa4, 0x0b, 0x83, 0xf1, 0x9b, 0x06, 0xd0, 0x65, 0xf0, 0xf1, 0x7d, 0x1f, 0x2e, 0x6a, 0x04, 0xe2, 0x10, 0x3f, 0xa3, 0x56, 0x2a, 0x64, 0xfd, 0xa4, 0xbb, 0xb2, 0xe6, 0xd8, 0xdc, 0xa9, 0xa2, 0x3e, 0xf8, 0x2e, 0x49, ], iq = [ 0x66, 0x80, 0xb0, 0x0c, 0xd2, 0x08, 0xc1, 0x5f, 0x8c, 0x33, 0xb9, 0xa0, 0x1b, 0x0d, 0xb4, 0xd3, 0x00, 0x3d, 0xda, 0xd7, 0x46, 0xb4, 0xab, 0xc8, 0xa7, 0x8a, 0xe1, 0x06, 0x07, 0x5e, 0x34, 0xb2, 0xb3, 0x88, 0x6f, 0xb9, 0x3d, 0x51, 0x0d, 0x23, 0x9f, 0xa0, 0x65, 0x87, 0x41, 0x5e, 0x7d, 0xb0, 0x4c, 0xbf, 0xc5, 0xfc, 0x18, 0xbc, 0x22, 0xd6, 0xae, 0x95, 0xee, 0xad, 0x14, 0xe0, 0x75, 0xcc, 0x6e, 0xfa, 0xa0, 0xe6, 0x21, 0xd3, 0x1d, 0x1b, 0x8c, 0xda, 0x4d, 0x24, 0xcc, 0x1e, 0xd9, 0x94, 0x72, 0xb6, 0x2e, 0xe0, 0x5c, 0xc4, 0x4e, 0x84, 0xfe, 0xe9, 0xe2, 0x8c, 0xf0, 0x98, 0x07, 0xc3, 0x82, 0x2c, 0xfc, 0xbe, 0x9e, 0xb5, 0x77, 0xdb, 0x94, 0xf9, 0xc6, 0x84, 0xdf, 0x36, 0x6f, 0xfe, 0x62, 0x91, 0xda, 0x5b, 0xe2, 0x6e, 0x73, 0x4d, 0x3b, 0x7a, 0x84, 0xc6, 0x69, 0xb7, 0x04, 0x6d, 0x1e, 0xa1, 0x7d, 0x5b, 0x50, 0xd9, 0x1b, 0xda, 0xb4, 0x67, 0xb7, 0x9c, 0x15, 0x49, 0x8b, 0x53, 0xd2, 0x11, 0xe8, 0x8d, 0x96, 0x96, 0x8f, 0x0b, 0xe2, 0x4b, 0x7d, 0xca, 0x4a, 0x1e, 0x7f, 0xb2, 0x1c, 0x42, 0x10, 0x1f, 0x68, 0x1d, 0x7c, 0x47, 0xe3, 0xd6, 0x11, 0x4a, 0x2d, 0x81, 0xfe, 0xf0, 0x1d, 0xd6, 0x8c, 0xd5, 0xb0, 0x42, 0x0b, 0x65, 0x4b, 0x18, 0xd9, 0x12, 0x22, 0xbd, 0x0f, 0x88, ], ... }, ... }; let enc4096: keypair = keypair { pub = pubparams { n = [ 0x00, 0xaf, 0xa5, 0xc5, 0xc6, 0x39, 0x74, 0xc1, 0x5b, 0x85, 0xba, 0xc9, 0x66, 0x2e, 0x44, 0x9f, 0xd8, 0x75, 0xbc, 0x14, 0x4e, 0x8b, 0x93, 0x09, 0xa9, 0x32, 0x32, 0x06, 0xcc, 0x33, 0x40, 0x5f, 0xd1, 0x68, 0xc6, 0x00, 0x6f, 0xa4, 0xe4, 0xe0, 0x3d, 0xde, 0x7e, 0xed, 0x87, 0xeb, 0x7e, 0x42, 0xd4, 0xe1, 0xa6, 0xab, 0xfc, 0xf4, 0xf3, 0x47, 0x46, 0x7d, 0x1c, 0x05, 0x62, 0xaa, 0x6e, 0x5f, 0x61, 0xe7, 0xca, 0x48, 0xf6, 0xb9, 0x70, 0x23, 0x9d, 0x50, 0xe3, 0x7d, 0x00, 0x19, 0x78, 0x32, 0xb2, 0x05, 0x4b, 0xe1, 0x99, 0x6f, 0x1f, 0x57, 0x98, 0x2a, 0x58, 0x53, 0x45, 0xc8, 0x44, 0x59, 0x68, 0xf2, 0x22, 0xc4, 0x4e, 0x0e, 0xff, 0xcd, 0x2b, 0x9a, 0x1a, 0x39, 0xd0, 0x77, 0xff, 0x7c, 0x62, 0x04, 0xc9, 0xb3, 0xfc, 0xff, 0x66, 0x38, 0x6e, 0x54, 0xc4, 0xa7, 0x56, 0xa2, 0xf0, 0xab, 0xdf, 0x18, 0x98, 0xd9, 0x6a, 0x12, 0x64, 0xa0, 0xff, 0x96, 0x89, 0x52, 0x4d, 0xc0, 0x3a, 0x33, 0x07, 0x73, 0x83, 0x42, 0xd3, 0x30, 0x86, 0xba, 0x29, 0x69, 0x6b, 0x65, 0x14, 0x93, 0xf5, 0x61, 0xea, 0x40, 0x28, 0xa2, 0xcb, 0xa2, 0x0c, 0xa4, 0x47, 0x52, 0x40, 0x05, 0x95, 0xc4, 0x4a, 0x1d, 0x2c, 0x93, 0x5a, 0x67, 0x31, 0xac, 0x95, 0x42, 0x2e, 0x9c, 0x07, 0x22, 0x6a, 0xaa, 0x60, 0x38, 0x8e, 0xab, 0x97, 0x09, 0x0a, 0x63, 0x43, 0x57, 0x0b, 0x58, 0x02, 0x55, 0x3d, 0x78, 0xba, 0xcb, 0x80, 0x29, 0x84, 0xc3, 0xd2, 0x08, 0x8a, 0xce, 0xc5, 0x41, 0x04, 0x85, 0x6d, 0xad, 0xbb, 0x30, 0x09, 0x32, 0x8b, 0x32, 0x95, 0xcb, 0xd6, 0x9c, 0x2a, 0xfc, 0x52, 0x5e, 0xf8, 0xbc, 0x7b, 0x1f, 0x97, 0x09, 0xbc, 0x84, 0x67, 0xf3, 0xf4, 0x2d, 0x5c, 0xc5, 0x5b, 0x30, 0xcd, 0x85, 0xee, 0xbc, 0x44, 0xd1, 0x45, 0x09, 0x9f, 0xa2, 0x62, 0xf6, 0x2b, 0xe9, 0xe1, 0x4e, 0x08, 0x3d, 0xf7, 0x78, 0xd8, 0x4e, 0x6e, 0xec, 0x87, 0x0a, 0x9d, 0x6d, 0x17, 0x33, 0xa2, 0x9a, 0x28, 0x10, 0x42, 0xfc, 0x34, 0xd7, 0x86, 0x4c, 0x21, 0x97, 0x9e, 0xae, 0xe4, 0x36, 0x6e, 0xd2, 0xdf, 0x4f, 0xe8, 0xd6, 0xcc, 0xd7, 0x82, 0xb9, 0xb0, 0x6e, 0x8c, 0x19, 0x08, 0xa5, 0xca, 0x44, 0x47, 0x52, 0x83, 0x26, 0x66, 0xe8, 0x54, 0x18, 0x80, 0x11, 0x69, 0x11, 0x4e, 0x00, 0x59, 0xf2, 0x62, 0x9b, 0x57, 0x87, 0xb3, 0x87, 0xd3, 0x17, 0xaf, 0x87, 0x20, 0xeb, 0x90, 0x7f, 0x19, 0xd9, 0x3f, 0xee, 0x98, 0xe6, 0xcf, 0x26, 0x1f, 0x20, 0xef, 0xf6, 0x77, 0x5b, 0xc7, 0x01, 0x89, 0x8b, 0x77, 0xf9, 0x13, 0x89, 0xfb, 0x9d, 0xb8, 0x3f, 0x82, 0x05, 0x66, 0xa9, 0xd9, 0x72, 0x66, 0x2c, 0xda, 0x19, 0x56, 0x18, 0x1e, 0xf8, 0x12, 0x1f, 0x61, 0x8b, 0xa9, 0x6e, 0x75, 0x0e, 0x40, 0x33, 0xfd, 0xde, 0x70, 0x62, 0xc2, 0x0a, 0x30, 0x0c, 0x46, 0x8f, 0x22, 0xc9, 0x15, 0x31, 0x6c, 0xc8, 0xfd, 0xdd, 0xc5, 0x9e, 0x6b, 0x41, 0x46, 0x9f, 0x32, 0xac, 0x3d, 0xc4, 0xd6, 0x61, 0x80, 0x8e, 0x12, 0x3b, 0x7c, 0xb2, 0xda, 0x07, 0x80, 0xd8, 0xf5, 0x07, 0xcd, 0xe6, 0x74, 0x9d, 0x4f, 0x09, 0x54, 0x24, 0x3d, 0x02, 0xf8, 0x96, 0x10, 0x58, 0x4f, 0x78, 0x30, 0xbc, 0x98, 0x01, 0xf6, 0xa3, 0x80, 0x58, 0x64, 0x07, 0x50, 0x5d, 0x06, 0x1e, 0xe9, 0x77, 0xf5, 0x65, 0xe5, 0x90, 0xf9, 0x63, 0x73, 0x9f, 0xd3, 0x9d, 0xc7, 0xba, 0xc1, 0x79, 0x28, 0x7f, 0xfd, 0xce, 0x28, 0x84, 0xb8, 0x49, 0x78, 0x9b, 0xb4, 0x6e, 0x7b, 0xe5, 0xeb, 0x1d, 0x9f, 0xc8, 0x63, 0xd5, 0x99, 0x05, 0x2d, 0x73, 0x8e, 0xe1, 0x32, 0xaa, 0x2d, ], e = [0x10, 0x00, 0x01], ... }, priv = privparams { nbitlen = 4096, p = [ 0x00, 0xd9, 0x34, 0x08, 0x8a, 0x7c, 0x2f, 0xe7, 0x38, 0x7d, 0x7e, 0xc9, 0x30, 0xb5, 0x05, 0x2b, 0x5f, 0x93, 0xd3, 0xf8, 0xee, 0x13, 0x2a, 0x81, 0xec, 0x6d, 0x69, 0x35, 0x8b, 0x7c, 0x92, 0x0b, 0xae, 0x5b, 0x8d, 0x4c, 0x8d, 0x0c, 0x08, 0x77, 0x39, 0xf0, 0xde, 0x2b, 0x9e, 0x48, 0x87, 0xc4, 0x2f, 0x15, 0x80, 0x30, 0x94, 0x18, 0xfe, 0x72, 0x5e, 0x3d, 0x6b, 0x82, 0x29, 0xca, 0xd6, 0xe7, 0xa5, 0x7e, 0x8b, 0x26, 0x23, 0xee, 0x2e, 0x6d, 0xe8, 0x00, 0x53, 0x1a, 0xaa, 0x9c, 0x2f, 0xc7, 0xfb, 0xab, 0x10, 0x3d, 0xb9, 0x84, 0x15, 0x73, 0xbb, 0x18, 0xfe, 0x45, 0xa7, 0x70, 0x74, 0xdc, 0x9e, 0x39, 0xe6, 0x61, 0xa9, 0x6a, 0x06, 0xb3, 0xa5, 0x35, 0x57, 0x3b, 0x7b, 0xa9, 0xb7, 0xe1, 0xd7, 0x56, 0x00, 0xa9, 0x03, 0xd8, 0x33, 0xe4, 0x5a, 0x76, 0x4f, 0x8f, 0x14, 0xcc, 0xe2, 0xf2, 0xf7, 0xf0, 0x10, 0x3f, 0xd4, 0x5d, 0x02, 0x49, 0xb7, 0xf8, 0x47, 0x32, 0x4c, 0x13, 0x6c, 0xfb, 0xf5, 0xf5, 0x8a, 0x43, 0xcb, 0xa7, 0xb4, 0x8d, 0xd5, 0x11, 0x39, 0x99, 0x1b, 0xe1, 0x81, 0x0b, 0x1b, 0x4e, 0x1f, 0x15, 0xf9, 0x60, 0x98, 0x5c, 0x0a, 0x89, 0x72, 0x2b, 0x25, 0xfb, 0x11, 0xfb, 0x8f, 0x4f, 0x21, 0x3c, 0x3a, 0xe9, 0xd1, 0xca, 0x36, 0x64, 0xaf, 0xbf, 0xac, 0x5e, 0xee, 0x92, 0x98, 0xa6, 0xd0, 0x4d, 0x74, 0x1d, 0x68, 0xfe, 0x84, 0xd4, 0x8d, 0xa8, 0x44, 0xac, 0x63, 0xf7, 0xbb, 0x9c, 0xaa, 0x65, 0x3a, 0xe9, 0x4b, 0x12, 0xb8, 0x28, 0xbf, 0xf1, 0x58, 0x44, 0x32, 0xe6, 0x59, 0x10, 0xb5, 0x5d, 0xd0, 0x03, 0xf7, 0x8d, 0x42, 0xcc, 0x61, 0x24, 0xe1, 0xf1, 0x2f, 0x7a, 0x4b, 0xf6, 0x97, 0x1e, 0x75, 0xa1, 0xec, 0xd9, 0x0b, 0x64, 0x46, 0xae, 0x67, 0x5b, 0x7d, 0xc5, 0x63, ], q = [ 0x00, 0xcf, 0x05, 0x89, 0xb9, 0x51, 0x83, 0xd3, 0xab, 0xed, 0xe4, 0x61, 0x35, 0x3c, 0x48, 0xbe, 0xb6, 0x15, 0x87, 0x4e, 0xab, 0x18, 0xef, 0x23, 0x6d, 0x37, 0xcf, 0x39, 0xe7, 0x64, 0x4e, 0x58, 0xaa, 0xe9, 0x3a, 0xb5, 0x23, 0x45, 0xc9, 0xe5, 0x4f, 0xad, 0xa9, 0x10, 0x30, 0xdf, 0x5d, 0x06, 0x20, 0x16, 0xc6, 0x5e, 0x2a, 0x49, 0xbd, 0x2d, 0x14, 0xe3, 0x32, 0x96, 0xfa, 0x50, 0x5d, 0xfc, 0x9b, 0x44, 0x60, 0xa7, 0x36, 0x59, 0x62, 0xe9, 0xba, 0x8e, 0x15, 0x5b, 0x52, 0xd3, 0x6d, 0x84, 0x02, 0x90, 0x0d, 0xee, 0xb8, 0x60, 0x7b, 0x68, 0x80, 0x1f, 0xf2, 0xe2, 0x2a, 0xe3, 0x9a, 0xfb, 0x0d, 0x97, 0xae, 0x34, 0x65, 0x32, 0xfd, 0x13, 0xf2, 0x77, 0xfd, 0x21, 0x79, 0x48, 0x39, 0xb3, 0xd4, 0x19, 0x29, 0x0c, 0x42, 0xcb, 0xd5, 0x6a, 0x6c, 0xed, 0x48, 0xfa, 0x54, 0x83, 0x16, 0x04, 0x73, 0xd6, 0xbc, 0xb2, 0xc9, 0xb2, 0xd4, 0x6b, 0xbb, 0x5f, 0xb1, 0x69, 0xd3, 0x51, 0x3c, 0x29, 0x77, 0xba, 0xcf, 0x83, 0xc4, 0xe7, 0x84, 0xf6, 0x0c, 0xdc, 0xfa, 0x55, 0x1b, 0xa3, 0xb4, 0xa1, 0xc0, 0x8a, 0x61, 0xfa, 0x79, 0x1b, 0x82, 0xb3, 0xb0, 0xaa, 0xc0, 0xed, 0xe2, 0xf9, 0x69, 0x1c, 0x8a, 0x17, 0x56, 0xa9, 0xc1, 0xbb, 0x86, 0xe7, 0xff, 0xfe, 0x71, 0xcc, 0xa2, 0xea, 0xe4, 0x92, 0x8b, 0xed, 0xcc, 0x3e, 0x10, 0xd6, 0x4a, 0x53, 0xea, 0xdf, 0x53, 0xf5, 0x0c, 0x2b, 0x7d, 0x84, 0x54, 0x6e, 0xac, 0xb8, 0x57, 0x1e, 0xd3, 0x8c, 0xc4, 0x92, 0xae, 0x6a, 0x1d, 0x6f, 0x1d, 0x44, 0xfe, 0xc8, 0x61, 0xf8, 0x4e, 0xd9, 0xc6, 0x61, 0xef, 0xc9, 0x5d, 0xc1, 0xc6, 0x64, 0xfa, 0x42, 0xf5, 0x46, 0x39, 0x6e, 0xa0, 0x7a, 0x70, 0xb2, 0x20, 0xbc, 0x1e, 0xf8, 0xb4, 0x91, 0x1c, 0xef, 0x2f, ], dp = [ 0x4f, 0xcd, 0x85, 0x61, 0xd4, 0x55, 0x09, 0x60, 0x41, 0x03, 0xa7, 0x4a, 0x05, 0x08, 0x7c, 0x32, 0x26, 0xaf, 0x58, 0x23, 0xa8, 0xd9, 0x12, 0x59, 0x5a, 0xad, 0xb0, 0x25, 0xaa, 0xc4, 0x42, 0x14, 0x72, 0xc0, 0xcc, 0xa2, 0x7a, 0x0c, 0x56, 0x39, 0xec, 0x9c, 0xc4, 0x6b, 0xe8, 0x7c, 0x31, 0x81, 0x97, 0x25, 0xbd, 0x33, 0x7c, 0xa7, 0x68, 0x3f, 0xe5, 0xd3, 0x2d, 0x44, 0xcb, 0xa8, 0xff, 0xfd, 0x57, 0x2c, 0x2a, 0xfc, 0x42, 0x93, 0xbe, 0x7f, 0xe2, 0x36, 0xa6, 0x72, 0x8e, 0xe6, 0x23, 0x54, 0xfd, 0x39, 0xff, 0x63, 0xbc, 0xfa, 0xe0, 0xc5, 0x9a, 0x5e, 0x3a, 0x1b, 0x55, 0xff, 0x29, 0xdb, 0xdc, 0xac, 0x1f, 0xaf, 0xce, 0x2b, 0xde, 0x2f, 0x52, 0x14, 0xd5, 0xdf, 0x0e, 0xb1, 0x68, 0x01, 0xe5, 0x30, 0x62, 0xe8, 0xed, 0xb3, 0xcb, 0x2f, 0xcd, 0x8e, 0x57, 0xa4, 0xad, 0xce, 0xa8, 0xb4, 0x9d, 0xf8, 0x6a, 0x6b, 0x4d, 0x2c, 0xfd, 0x06, 0xe1, 0xea, 0xce, 0xb9, 0x12, 0xde, 0x15, 0x08, 0xfe, 0x89, 0x29, 0x75, 0x97, 0x0d, 0x88, 0x9b, 0x03, 0x34, 0x25, 0x64, 0x10, 0x0b, 0x88, 0x98, 0x24, 0xb0, 0xd9, 0x33, 0x01, 0xe1, 0x98, 0xd7, 0xaa, 0x3e, 0x4f, 0x4a, 0x2a, 0x20, 0x26, 0x4c, 0x36, 0x27, 0xa0, 0xe8, 0x88, 0x66, 0x33, 0x24, 0x9f, 0x03, 0xcf, 0xa9, 0xb6, 0x4b, 0x73, 0x83, 0x30, 0xaf, 0x11, 0xf6, 0x1a, 0xa4, 0x2b, 0xf7, 0x83, 0xdc, 0xf4, 0x39, 0x1f, 0x19, 0xaf, 0xb8, 0xb7, 0xcc, 0x07, 0x5b, 0x88, 0xc1, 0xb3, 0x84, 0x04, 0x3c, 0xd9, 0xa0, 0xb3, 0x95, 0xfb, 0xfa, 0x37, 0x60, 0x5b, 0xb2, 0x84, 0xf2, 0x9c, 0x6d, 0x31, 0x88, 0x73, 0xb3, 0xac, 0x18, 0xe4, 0x97, 0x2a, 0x67, 0xc5, 0xa2, 0x34, 0xb7, 0x3f, 0xdb, 0xa6, 0xa1, 0x2d, 0x8c, 0xfe, 0x19, 0x8c, 0xbf, ], dq = [ 0x00, 0xcb, 0x6c, 0x77, 0xae, 0xa0, 0x08, 0xd7, 0xa0, 0x23, 0xfc, 0xbc, 0x00, 0x61, 0xa2, 0x61, 0xb3, 0xee, 0x67, 0xac, 0xc7, 0xb7, 0x92, 0x94, 0xcf, 0x27, 0x7d, 0xfb, 0x3a, 0x02, 0x78, 0x71, 0xec, 0x4f, 0x8d, 0x9e, 0x9c, 0x70, 0x61, 0x39, 0x71, 0x18, 0x05, 0xfe, 0xa0, 0xe7, 0x7b, 0x33, 0x1f, 0xa9, 0x01, 0x77, 0x5a, 0x3a, 0x67, 0x27, 0xbb, 0x54, 0x9d, 0x4b, 0x79, 0xe0, 0x2a, 0xda, 0xa3, 0x7f, 0x87, 0x32, 0x07, 0xd7, 0xc1, 0xb8, 0x45, 0xd6, 0x83, 0xe9, 0xde, 0xf3, 0x5e, 0xb3, 0xcf, 0x08, 0xda, 0x87, 0xee, 0xa8, 0xef, 0xda, 0xf9, 0xbb, 0x6b, 0x21, 0x0e, 0x5f, 0xe4, 0xd4, 0x38, 0xc1, 0x09, 0x2e, 0xf7, 0x1a, 0x29, 0x50, 0xc6, 0x7b, 0x5d, 0x42, 0xdd, 0x38, 0x39, 0x6b, 0x19, 0x49, 0x37, 0xea, 0x92, 0x60, 0x54, 0xef, 0x64, 0xe5, 0xad, 0x46, 0x3e, 0x71, 0x28, 0xdb, 0x6b, 0x30, 0x60, 0xef, 0x95, 0xfe, 0xa1, 0x78, 0xd2, 0xff, 0xef, 0x07, 0x3b, 0xdc, 0xa1, 0x2f, 0x66, 0x35, 0x2c, 0xe0, 0x20, 0x46, 0x17, 0x82, 0xe7, 0x94, 0xe4, 0x6f, 0x68, 0xdf, 0x6e, 0x09, 0x5b, 0x77, 0x1f, 0x5b, 0xce, 0x51, 0x58, 0x17, 0x55, 0xcc, 0x14, 0x14, 0x2d, 0x6a, 0x42, 0xfd, 0x06, 0x3c, 0x74, 0xae, 0x0e, 0x6e, 0x44, 0xdc, 0x07, 0xd2, 0x70, 0xe4, 0x52, 0x5a, 0x5a, 0x0c, 0x1e, 0x6f, 0xa6, 0xb8, 0x7e, 0x36, 0xf3, 0x86, 0x8e, 0x4e, 0xb0, 0xe3, 0x23, 0xf8, 0x40, 0x38, 0x1d, 0xf7, 0x3a, 0xc5, 0x50, 0xe6, 0x3b, 0x9e, 0x21, 0x32, 0xb9, 0x2c, 0x10, 0x8c, 0x34, 0xc8, 0xad, 0x4b, 0x1d, 0xe9, 0xaf, 0x21, 0x93, 0x2c, 0x7d, 0x40, 0xf3, 0x5e, 0x0b, 0xa3, 0x01, 0xbf, 0x75, 0xe0, 0x71, 0x62, 0xe1, 0x52, 0x2f, 0x16, 0xf9, 0xcf, 0xa0, 0xe7, 0x66, 0x17, 0x09, 0xc5, 0x85, ], iq = [ 0x00, 0xcc, 0x1c, 0x14, 0x9c, 0x4f, 0x16, 0xa4, 0x5c, 0x14, 0x37, 0x53, 0xde, 0xf7, 0xf4, 0x74, 0x76, 0xc8, 0xb1, 0x62, 0x49, 0x42, 0xcf, 0xbf, 0x65, 0xe5, 0x8f, 0x4c, 0xb6, 0x7d, 0x59, 0x41, 0x87, 0x32, 0x8c, 0x9b, 0x9f, 0x96, 0x9e, 0xb1, 0xf0, 0x2e, 0x4b, 0xa2, 0xc2, 0xab, 0x01, 0x19, 0x19, 0x6c, 0x79, 0x01, 0xc8, 0x52, 0xff, 0xd4, 0xbd, 0xd8, 0xba, 0xeb, 0xc1, 0x70, 0xea, 0xfb, 0x37, 0x31, 0x79, 0x16, 0xe0, 0x78, 0x79, 0xaf, 0x41, 0x37, 0xaa, 0x4e, 0x2c, 0xdc, 0x1d, 0x1b, 0xdc, 0x44, 0x1e, 0x03, 0x2e, 0xd0, 0x17, 0x25, 0x23, 0x67, 0xd2, 0x7b, 0xea, 0xc2, 0x91, 0xb7, 0x9a, 0x31, 0xa5, 0xff, 0xbd, 0x36, 0x07, 0xae, 0xd7, 0xec, 0x05, 0xb9, 0x05, 0x31, 0x16, 0xc4, 0x29, 0xf9, 0x23, 0x0c, 0x6d, 0x2e, 0xc3, 0x0b, 0x6a, 0xc9, 0xe2, 0xab, 0x8b, 0x05, 0x8b, 0xb4, 0xc2, 0x4d, 0xbf, 0xa7, 0x6b, 0xa4, 0x00, 0x23, 0x82, 0xb4, 0xfa, 0x8d, 0xcf, 0x0d, 0x31, 0x8e, 0xd6, 0xbc, 0xc2, 0x15, 0xae, 0x8c, 0xa7, 0x0f, 0xd0, 0xf4, 0x5b, 0x87, 0x6a, 0xd0, 0x9f, 0xa5, 0xb4, 0x5c, 0xd7, 0xbf, 0xca, 0x40, 0x82, 0x44, 0x00, 0xf9, 0xda, 0x06, 0x4e, 0x8c, 0x48, 0x8f, 0x11, 0xf3, 0x64, 0x05, 0x55, 0x8d, 0xfb, 0x39, 0xf8, 0x91, 0x8a, 0x83, 0xd6, 0x73, 0x05, 0x1f, 0x4c, 0xed, 0x47, 0x96, 0xf5, 0x73, 0xe8, 0xf9, 0xb3, 0xeb, 0x91, 0xe4, 0xea, 0x0e, 0xb8, 0xd5, 0xa8, 0xf2, 0x60, 0xcc, 0x05, 0x5b, 0x1d, 0x9b, 0xe5, 0xe4, 0xe5, 0x36, 0x0b, 0x2b, 0xc0, 0xd2, 0x1c, 0x55, 0xd6, 0x68, 0xb6, 0xd8, 0x56, 0x83, 0x80, 0x22, 0x44, 0x34, 0x9b, 0x2b, 0x71, 0xc1, 0x4b, 0xca, 0x36, 0x41, 0x2a, 0x2e, 0xff, 0x23, 0x8b, 0x0a, 0x16, 0x76, 0x56, 0xb6, 0x8e, 0x3b, 0x69, ], ... }, d = [ 0x54, 0x76, 0xd8, 0x0b, 0x41, 0x77, 0xe6, 0xbf, 0x77, 0x28, 0x62, 0x4e, 0xf3, 0xb2, 0xe6, 0x56, 0xf6, 0x0e, 0xd2, 0x89, 0x0e, 0xcf, 0x4f, 0x57, 0x00, 0x9f, 0x53, 0xeb, 0x80, 0x3d, 0xd5, 0x95, 0xe2, 0xd7, 0x4c, 0x40, 0x63, 0xbf, 0xf8, 0x21, 0x68, 0x4c, 0x0b, 0x37, 0x50, 0x44, 0x30, 0x29, 0x24, 0xb5, 0xbc, 0x80, 0xf0, 0xdd, 0xc8, 0x09, 0x9a, 0x82, 0x0e, 0x08, 0xeb, 0x42, 0x16, 0x36, 0x03, 0x7b, 0x9f, 0xe8, 0x9d, 0x35, 0xd2, 0xba, 0x84, 0xba, 0x50, 0x52, 0xea, 0xec, 0x85, 0x1c, 0x5c, 0x35, 0xa8, 0x2f, 0xdb, 0x62, 0xec, 0x01, 0x6d, 0x63, 0x79, 0xef, 0xd5, 0xa5, 0x20, 0x85, 0xb9, 0xe2, 0x84, 0x19, 0xb1, 0x56, 0xcb, 0x37, 0xcb, 0x6c, 0x0f, 0x1f, 0x33, 0x85, 0x35, 0x30, 0x01, 0x73, 0x69, 0x4d, 0x21, 0x17, 0xeb, 0xcd, 0x0a, 0x90, 0x62, 0x93, 0xe3, 0xd8, 0xee, 0x1d, 0x63, 0x3b, 0xa5, 0x59, 0x3f, 0xad, 0x0a, 0x4a, 0xbd, 0xfe, 0x1d, 0x08, 0xec, 0x86, 0x50, 0x21, 0xa6, 0x27, 0x99, 0xcb, 0xea, 0xca, 0xee, 0xdc, 0x99, 0x28, 0x1e, 0xbc, 0x6d, 0x86, 0x13, 0x66, 0xcd, 0x21, 0x7d, 0x5f, 0x84, 0xf6, 0xa5, 0x4c, 0xf2, 0xbd, 0x7c, 0xb2, 0x0f, 0x69, 0x40, 0x6c, 0x3e, 0x13, 0xbc, 0x0a, 0x04, 0x1e, 0xe6, 0x6b, 0x79, 0x76, 0x68, 0xd3, 0x78, 0x48, 0xbb, 0x09, 0xc8, 0x73, 0xe1, 0xd2, 0x0f, 0xf7, 0xc2, 0xf4, 0xde, 0x86, 0x88, 0xac, 0xfd, 0xd0, 0x7d, 0xa9, 0x8c, 0xcd, 0x9e, 0x48, 0xf2, 0xf8, 0xa5, 0x03, 0xf0, 0x07, 0x17, 0x8e, 0xad, 0x7b, 0x95, 0x56, 0xe6, 0xea, 0x4f, 0x11, 0xff, 0xaa, 0x9d, 0x00, 0x82, 0xc3, 0xad, 0x8d, 0xd9, 0x3d, 0x2f, 0xec, 0xb6, 0xae, 0xe3, 0xd1, 0x05, 0x5c, 0x07, 0x30, 0x54, 0x6b, 0x4c, 0xa5, 0x98, 0x61, 0x3c, 0x40, 0xe3, 0x8c, 0xf3, 0x01, 0xc2, 0xdd, 0xdd, 0x18, 0xbd, 0x38, 0x35, 0x34, 0x87, 0xbf, 0x05, 0xba, 0x8e, 0x1d, 0x4b, 0x33, 0x63, 0xcc, 0x65, 0x11, 0xbf, 0x59, 0x48, 0x5e, 0x46, 0x82, 0x17, 0xda, 0x6b, 0xcf, 0x7c, 0x06, 0xca, 0x74, 0xbd, 0xa9, 0x78, 0xe0, 0xd2, 0x20, 0xdf, 0xcd, 0x4a, 0xa0, 0x67, 0xe6, 0x90, 0x14, 0x43, 0x20, 0x26, 0x47, 0x83, 0x79, 0xc0, 0xe8, 0xb7, 0x60, 0xb7, 0xa8, 0x96, 0x56, 0x77, 0xc4, 0x9d, 0x32, 0x52, 0xc3, 0xa2, 0x10, 0x69, 0x2c, 0x51, 0x81, 0xc5, 0xd2, 0xa2, 0x27, 0x61, 0xf4, 0x0a, 0xa7, 0x51, 0xe8, 0x44, 0xcb, 0xae, 0xbe, 0xb1, 0x10, 0x75, 0xaa, 0x1c, 0xae, 0x5e, 0xa8, 0x8d, 0x16, 0x6a, 0x4c, 0xf4, 0x26, 0x7a, 0xce, 0x61, 0x70, 0xaf, 0x86, 0x9b, 0x4c, 0xca, 0x26, 0x51, 0xe4, 0xcd, 0xb5, 0x7a, 0x4e, 0xe2, 0xe8, 0x8a, 0xbc, 0x70, 0xcc, 0x1a, 0xc6, 0x54, 0x07, 0x51, 0x14, 0xfd, 0x08, 0x58, 0xba, 0x46, 0xca, 0xa2, 0x2e, 0xf0, 0x4c, 0x0e, 0xc3, 0x5d, 0xd9, 0x53, 0x4d, 0xbe, 0x8c, 0x2f, 0x28, 0x38, 0xf4, 0x26, 0x84, 0x59, 0xba, 0x07, 0xbc, 0xf0, 0xaf, 0x74, 0xb6, 0x4b, 0xf6, 0xdc, 0xab, 0x21, 0xbb, 0xab, 0x5c, 0x97, 0x29, 0x48, 0x87, 0x00, 0x27, 0xf7, 0x58, 0xbb, 0x1d, 0xad, 0x66, 0x50, 0x77, 0x33, 0xfc, 0xb2, 0xc2, 0x8f, 0x4c, 0x3b, 0x4f, 0xab, 0xb4, 0x8f, 0x87, 0x00, 0x3d, 0x55, 0xf3, 0x23, 0xce, 0x22, 0xde, 0x74, 0x29, 0x3e, 0xf0, 0xe8, 0x04, 0x14, 0xf7, 0x36, 0xb1, 0x1b, 0xcf, 0xbc, 0x9b, 0x5d, 0x3d, 0x75, 0xfc, 0x15, 0xcb, 0x3d, 0x2d, 0x8f, 0xaf, 0x1e, 0x12, 0xe8, 0xb4, 0x94, 0xac, 0x64, 0x1b, 0x7c, 0x54, 0x1c, 0xeb, 0x47, 0x40, 0xe3, 0x2b, 0x48, 0x3c, 0xd8, 0x10, 0xf3, 0x93, 0xdb, 0x75, ], }; @test fn initd() void = { let params = privparams { p = enc4096.priv.p, q = enc4096.priv.q, iq = enc4096.priv.iq, ... }; let priv: [PRIVKEYSZ]u8 = [0...]; privkey_initd(priv, params, enc4096.d, enc4096.pub.n)!; const newparams = privkey_params(priv); assert(enc4096.priv.nbitlen == newparams.nbitlen); assert(enc4096.priv.nbitlen == privkey_nbitlen(priv)); assert(bytes::equal(ltrim(enc4096.priv.dp), ltrim(newparams.dp))); assert(bytes::equal(ltrim(enc4096.priv.dq), ltrim(newparams.dq))); }; hare-0.24.2/crypto/rsa/+test/pkcs1_test.ha000066400000000000000000000406011464473310100202530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::sha1; use crypto::sha256; use crypto::sha512; use hash; use io; const msg: [_]u8 = [ 0x53, 0x53, 0x48, 0x53, 0x49, 0x47, 0x00, 0x00, 0x00, 0x03, 0x6a, 0x6f, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x00, 0x00, 0x00, 0x40, 0xce, 0x25, 0x8d, 0xf2, 0x3a, 0x14, 0xf2, 0x80, 0xeb, 0xea, 0x9b, 0xd4, 0xd7, 0xb8, 0x94, 0xce, 0x23, 0x98, 0xa8, 0x27, 0x30, 0x42, 0x61, 0x6a, 0xd2, 0x15, 0x59, 0x97, 0xc2, 0xb4, 0x79, 0x8b, 0x16, 0xdc, 0x49, 0xb5, 0x26, 0x51, 0x77, 0xe3, 0x27, 0x5c, 0xdf, 0xc0, 0xa5, 0x46, 0x97, 0xdb, 0x7b, 0x2c, 0x3b, 0x9b, 0x97, 0x3e, 0xc9, 0xca, 0xea, 0x9a, 0xcd, 0xbd, 0x2c, 0xaa, 0xcc, 0x77, ]; const sig1: [_] u8 = [ 0x3a, 0x29, 0x89, 0x83, 0xf5, 0xb6, 0x25, 0x0c, 0x00, 0xd4, 0x44, 0x4a, 0x16, 0xa9, 0xcf, 0xb6, 0x14, 0x3d, 0xc1, 0xa9, 0x45, 0x24, 0xb1, 0x54, 0x53, 0x2b, 0x59, 0x81, 0xf8, 0x7c, 0xdb, 0x4c, 0x16, 0xd1, 0x0e, 0x68, 0xb8, 0x1a, 0x48, 0x02, 0x3d, 0x34, 0x08, 0x14, 0xb7, 0xc1, 0x90, 0x1f, 0x4d, 0x7f, 0xbc, 0xa1, 0xef, 0x8c, 0xf0, 0x71, 0x24, 0x11, 0x27, 0xa7, 0x1c, 0xc9, 0x44, 0x11, 0x65, 0x1e, 0xca, 0xa0, 0x4b, 0xb5, 0x27, 0x67, 0xe3, 0x80, 0x4d, 0x79, 0xbf, 0x28, 0xb9, 0x85, 0xe8, 0x27, 0xad, 0x7d, 0xca, 0x2e, 0x0d, 0xb2, 0xe6, 0x42, 0x29, 0x37, 0x8b, 0xb2, 0xc3, 0x0c, 0x49, 0x9f, 0x78, 0x2c, 0x03, 0xe4, 0x2e, 0x83, 0x79, 0xb0, 0x6c, 0x09, 0xf4, 0x3c, 0xc7, 0x14, 0xfa, 0x73, 0x41, 0x28, 0x39, 0x1f, 0x8a, 0x23, 0x7b, 0x71, 0x5d, 0x15, 0x23, 0x69, 0x95, 0x1c, 0x8d, 0x50, 0x6c, 0x4e, 0x6e, 0x7d, 0xab, 0xcf, 0xab, 0xbd, 0xa2, 0xf1, 0x18, 0x2d, 0xb3, 0x70, 0x5d, 0x62, 0x45, 0xad, 0xa9, 0x1b, 0x40, 0x1f, 0xe8, 0xe1, 0x25, 0x19, 0x78, 0xfd, 0x73, 0x49, 0x45, 0x09, 0x21, 0x5c, 0x25, 0xff, 0x86, 0x1d, 0x6c, 0x63, 0xc6, 0xc1, 0xc0, 0x56, 0xe9, 0x84, 0x6d, 0x15, 0xc6, 0xcf, 0xeb, 0x33, 0xc5, 0x80, 0xda, 0x34, 0x30, 0x04, 0x92, 0x91, 0x04, 0xeb, 0x8f, 0xcb, 0x42, 0xd4, 0x41, 0x9a, 0x03, 0x86, 0x35, 0xed, 0x78, 0xa6, 0x1e, 0x95, 0x5f, 0x5e, 0x9e, 0xc0, 0x23, 0x3a, 0xd1, 0x72, 0xc3, 0x9a, 0x16, 0x6b, 0xa5, 0xc3, 0x90, 0x40, 0x1b, 0x56, 0xe3, 0xc2, 0xd5, 0x66, 0xb0, 0x86, 0xfe, 0x54, 0xb7, 0xa4, 0x51, 0xba, 0x41, 0xae, 0xb0, 0xd5, 0xad, 0x76, 0x13, 0x7b, 0xa6, 0x4d, 0x3e, 0x77, 0x59, 0x27, 0xcd, 0x31, 0x4a, 0xfb, 0xbd, 0x79, 0x9a, 0xc6, 0x9e, 0x0d, 0x45, 0x56, 0xc0, 0xcc, 0x3f, 0xdd, 0xbd, 0x2e, 0x0c, 0x11, 0xb6, 0x81, 0x14, 0xdb, 0x67, 0x78, 0x68, 0x7b, 0x0b, 0x3b, 0xf6, 0xb7, 0x00, 0x99, 0x5f, 0xda, 0xf9, 0x47, 0x97, 0xf7, 0x04, 0x8f, 0xda, 0x37, 0xbf, 0x9c, 0xbf, 0xa8, 0xe5, 0x57, 0x45, 0x7c, 0xc7, 0xf3, 0x51, 0x81, 0x95, 0xd4, 0x1b, 0xf1, 0x51, 0xfb, 0x7e, 0xad, 0xc3, 0x60, 0x78, 0x2e, 0x11, 0xe1, 0x6f, 0x10, 0x1c, 0x99, 0xe0, 0x43, 0x41, 0x58, 0x24, 0x5b, 0x0d, 0xd5, 0xae, 0x3e, 0x8b, 0x43, 0xf4, 0x1f, 0x11, 0x48, 0x16, 0xcf, 0x3b, 0x33, 0x05, 0x03, 0xdd, 0x03, 0x14, 0xe9, 0x22, 0x8b, 0xab, 0x2e, 0xe6, 0xd3, 0xaf, 0x9e, 0xf4, 0x16, 0xdf, 0xc8, 0x81, 0x21, 0xc4, 0x9e, 0x3e, 0xbd, 0x06, 0xb1, 0x7a, 0xd8, 0x3a, 0xb9, 0xd1, 0x74, 0x07, 0x2b, 0x99, 0xe6, 0x77, 0xe1, 0x99, 0x81, ]; const sig256: [_]u8 = [ 0x46, 0x31, 0xbd, 0xdb, 0xc9, 0x1a, 0xc4, 0x96, 0x05, 0x35, 0x8c, 0xba, 0xf0, 0xc0, 0x82, 0x84, 0xdc, 0x00, 0x5d, 0x43, 0xe2, 0x24, 0x43, 0x82, 0xee, 0xeb, 0x10, 0x69, 0xb8, 0x83, 0x07, 0xe8, 0xf9, 0x4a, 0x24, 0xbe, 0x8a, 0xb1, 0x19, 0xe3, 0x98, 0x72, 0x2f, 0x08, 0x29, 0x06, 0x6a, 0xbc, 0x9b, 0x0f, 0xa3, 0x83, 0x22, 0xe4, 0xf1, 0x8b, 0xcf, 0x56, 0xc5, 0x4e, 0x1f, 0x6e, 0xdf, 0xdd, 0x9e, 0xb3, 0x14, 0xe2, 0x59, 0xe8, 0x04, 0xd8, 0x4b, 0xd6, 0xed, 0x32, 0xfc, 0x3a, 0x07, 0xbb, 0xe1, 0xe4, 0xee, 0x6d, 0xb3, 0x23, 0x63, 0xa8, 0x8e, 0xc5, 0x97, 0xb9, 0xb2, 0x89, 0x68, 0x6a, 0x75, 0x13, 0x1e, 0xca, 0x8d, 0x62, 0x6d, 0x4c, 0xf1, 0x8f, 0x93, 0xd2, 0xac, 0x96, 0xf7, 0xd6, 0xde, 0xf7, 0xb2, 0x2c, 0xf8, 0x7d, 0x54, 0x31, 0x34, 0xe3, 0x50, 0xd5, 0x55, 0xc8, 0xa8, 0xce, 0x45, 0x78, 0xf4, 0xfc, 0xf4, 0x1d, 0x7d, 0xde, 0x9f, 0xb7, 0x7d, 0xc3, 0x1b, 0xfd, 0xb4, 0x5a, 0x1f, 0x7d, 0x69, 0x55, 0x5c, 0x76, 0x75, 0xd0, 0x14, 0x42, 0x28, 0xf9, 0x6b, 0xd0, 0x35, 0x9b, 0xe3, 0x9c, 0x64, 0xd0, 0x0d, 0x16, 0x5f, 0x66, 0x41, 0xe9, 0x84, 0x27, 0x60, 0xe6, 0x9e, 0x24, 0x7e, 0x89, 0xc5, 0x99, 0x4e, 0x3e, 0xfd, 0x6b, 0xcc, 0xa9, 0x99, 0xbe, 0x04, 0x9f, 0xd0, 0x8a, 0x97, 0x05, 0x36, 0x82, 0xc9, 0x00, 0x85, 0x1a, 0x1e, 0x6b, 0x02, 0x8e, 0xab, 0x5b, 0xfd, 0x52, 0x65, 0x7c, 0x95, 0x57, 0x35, 0xcc, 0x05, 0xe8, 0x82, 0x80, 0x42, 0x65, 0x1d, 0x04, 0xdc, 0x1c, 0x45, 0xf0, 0x91, 0x3a, 0x8c, 0x87, 0x44, 0xa3, 0x7b, 0x15, 0xe8, 0xfd, 0xb4, 0xb6, 0x56, 0x53, 0xaa, 0x5f, 0xdb, 0x3f, 0x46, 0x86, 0xb4, 0x97, 0xfb, 0x12, 0x73, 0xe0, 0xfc, 0x92, 0x0c, 0xcf, 0x80, 0x9f, 0x3b, 0x8b, 0x8a, 0xd0, 0x0e, 0x93, 0xd7, 0xcf, 0x87, 0xb7, 0xe2, 0x85, 0x83, 0x22, 0x18, 0x36, 0x31, 0xed, 0x5a, 0x75, 0xc0, 0xe3, 0x54, 0xcd, 0xf4, 0x55, 0xbd, 0xdc, 0xdc, 0x63, 0x9b, 0x48, 0x62, 0x6c, 0x59, 0x6d, 0xff, 0xe1, 0x23, 0xa1, 0x1f, 0xd2, 0xbd, 0x54, 0x90, 0xda, 0x3f, 0x1a, 0x02, 0xdd, 0xbd, 0x63, 0x46, 0x86, 0x7e, 0xda, 0x6c, 0x5e, 0xed, 0x18, 0x8f, 0x55, 0x70, 0xce, 0xba, 0x8f, 0xab, 0x25, 0xb4, 0x3a, 0xa2, 0x9d, 0xca, 0x6e, 0xd2, 0xb6, 0xb3, 0x8b, 0xb2, 0xcf, 0x4e, 0xa2, 0x84, 0x7e, 0xdf, 0xf0, 0x46, 0x28, 0x23, 0x90, 0x88, 0x0d, 0x12, 0x85, 0x39, 0xbc, 0xfc, 0x1d, 0x51, 0xee, 0x96, 0xca, 0x8b, 0x60, 0x99, 0xba, 0xa0, 0x77, 0x63, 0x05, 0xd7, 0xa4, 0xc6, 0x03, 0xc0, 0x1d, 0x6f, 0x69, 0xbe, 0x4b, 0x4a, 0xaf, 0xeb, 0x2b, 0xc8, 0xc6, ]; const sig384: [_]u8 = [ 0x0b, 0xed, 0x44, 0xc2, 0xb6, 0x97, 0xe0, 0xe2, 0x02, 0xb3, 0x66, 0x4f, 0x5b, 0x8d, 0xf0, 0xb8, 0x82, 0x0f, 0x4f, 0x28, 0x6d, 0xd4, 0x81, 0xb6, 0x24, 0x1f, 0x66, 0x1a, 0xa9, 0xa1, 0x8c, 0x4d, 0xc0, 0x11, 0x36, 0x03, 0xf9, 0x2d, 0x35, 0x6e, 0xc8, 0xeb, 0x95, 0x77, 0x86, 0xcf, 0xae, 0x4d, 0x40, 0xf5, 0xed, 0xef, 0x9b, 0x9c, 0x24, 0x2b, 0x89, 0x04, 0x89, 0x46, 0x2c, 0xbd, 0xea, 0x0a, 0xa9, 0xba, 0x50, 0x89, 0xc8, 0x52, 0x33, 0x63, 0xe4, 0xbf, 0x26, 0x4a, 0x57, 0x82, 0xc7, 0xc8, 0x5b, 0x9e, 0x64, 0x94, 0x1e, 0xe5, 0x26, 0x8a, 0xde, 0x6b, 0x63, 0xe1, 0x3f, 0xd8, 0x18, 0xf9, 0xcc, 0xe5, 0x33, 0x0d, 0x98, 0x41, 0xc3, 0xb5, 0x9a, 0x9c, 0x90, 0xb7, 0xe8, 0xc4, 0x68, 0xa0, 0xb8, 0x8d, 0x22, 0x5f, 0x5a, 0xe4, 0x53, 0xbf, 0x82, 0x08, 0x6e, 0x5f, 0xe1, 0xa5, 0xeb, 0x23, 0x8a, 0xc9, 0xe3, 0xeb, 0x6b, 0xd1, 0x6d, 0x95, 0x64, 0xc0, 0x25, 0x37, 0xc9, 0xb4, 0x14, 0x85, 0xa9, 0x7e, 0x44, 0xbc, 0x15, 0x56, 0xdb, 0x03, 0xac, 0x4d, 0x19, 0x61, 0x24, 0x5a, 0xc3, 0x48, 0x34, 0x72, 0xff, 0xc6, 0x97, 0xee, 0xf8, 0xf7, 0xdb, 0x07, 0xce, 0x47, 0x61, 0x53, 0x40, 0xe7, 0xf4, 0x2b, 0xca, 0xa0, 0xcc, 0xd6, 0xd8, 0x46, 0x5b, 0x88, 0xd9, 0xf0, 0xd9, 0x01, 0x87, 0x85, 0x33, 0x6b, 0x34, 0xb8, 0x34, 0xc8, 0x50, 0x86, 0x1f, 0xbe, 0xf9, 0xca, 0x07, 0x13, 0x2b, 0x31, 0x20, 0x92, 0xb2, 0xec, 0x31, 0xf0, 0xd1, 0x45, 0xab, 0x8c, 0xaa, 0x19, 0xb6, 0x81, 0x98, 0x31, 0x74, 0xd2, 0x96, 0x4e, 0x6a, 0xac, 0x90, 0xbe, 0xfe, 0xb7, 0xbb, 0x56, 0x3b, 0x72, 0x68, 0x0e, 0xc4, 0xef, 0x63, 0xc9, 0xfe, 0xe8, 0xa2, 0xf6, 0x92, 0x82, 0x05, 0x24, 0xf2, 0x52, 0xb0, 0x5a, 0x90, 0xdf, 0x04, 0xff, 0x6c, 0xb0, 0x79, 0x80, 0x28, 0xb0, 0x64, 0x08, 0x14, 0x93, 0x12, 0x02, 0x13, 0xd3, 0x6d, 0x8c, 0x9c, 0xfe, 0x42, 0x89, 0xcd, 0xc5, 0x94, 0x9f, 0x46, 0x72, 0xda, 0x49, 0x4d, 0xd9, 0xa6, 0x97, 0x21, 0x80, 0xa2, 0xfa, 0x57, 0x79, 0xd0, 0xc6, 0x83, 0x30, 0x29, 0x26, 0x09, 0x81, 0xba, 0x17, 0x60, 0x06, 0x31, 0x21, 0x6f, 0xfc, 0xf6, 0x53, 0x93, 0xe9, 0x7f, 0xe2, 0x64, 0x56, 0xd5, 0xf5, 0x11, 0x4f, 0x8b, 0xe1, 0xce, 0x3f, 0x41, 0x54, 0xf4, 0x5f, 0x08, 0xbc, 0xfd, 0x13, 0x21, 0x62, 0x99, 0x4a, 0x4e, 0x8c, 0x14, 0xd2, 0x80, 0xf0, 0x18, 0x9c, 0xbf, 0x3a, 0xb4, 0x80, 0x5b, 0x3d, 0x28, 0xa5, 0xbc, 0x12, 0x96, 0x9d, 0xa9, 0x92, 0x01, 0xbe, 0x62, 0xbb, 0xf6, 0x1f, 0x24, 0x37, 0xfa, 0xa2, 0xe4, 0x73, 0x65, 0x27, 0x0b, 0xc6, 0x95, 0x86, 0x2e, 0x46, ]; const sig512: [_]u8 = [ 0x6e, 0xb5, 0x5f, 0xbd, 0x48, 0x09, 0x08, 0x7c, 0x01, 0xb3, 0x74, 0x26, 0x73, 0x9d, 0x3e, 0xd5, 0x08, 0x7d, 0xe8, 0x11, 0x01, 0x21, 0x31, 0x11, 0x91, 0x34, 0x5b, 0xe5, 0x6c, 0x37, 0x79, 0x7b, 0xdb, 0x75, 0x16, 0x62, 0x0e, 0x7d, 0x1d, 0xd1, 0x04, 0x45, 0xbc, 0xa9, 0x79, 0xd0, 0xb1, 0x1d, 0x1e, 0x20, 0x65, 0x37, 0x92, 0x90, 0xa8, 0xd3, 0x5f, 0x07, 0x24, 0x54, 0x53, 0x97, 0x69, 0x84, 0xe2, 0xbb, 0xc0, 0xb5, 0x82, 0x4f, 0x29, 0xac, 0xc9, 0x07, 0xa7, 0x75, 0x08, 0x1c, 0x0c, 0x72, 0x9f, 0x35, 0x1b, 0x75, 0xb2, 0x79, 0x3f, 0x41, 0xa5, 0xcb, 0x9d, 0x69, 0x02, 0xa8, 0x08, 0xfe, 0x11, 0x19, 0x2f, 0xc2, 0xdb, 0x0e, 0xa6, 0xe0, 0xc4, 0x44, 0x33, 0xd6, 0xad, 0x59, 0x11, 0xa7, 0x38, 0xc0, 0xe7, 0x37, 0x21, 0xa8, 0x13, 0x96, 0xe9, 0x63, 0x25, 0xd9, 0x2e, 0xbf, 0x10, 0x59, 0x49, 0xdd, 0xc0, 0x55, 0xeb, 0x6d, 0xbe, 0x0a, 0x1e, 0xe2, 0x62, 0xce, 0x53, 0x2e, 0xaa, 0xed, 0xe5, 0x7e, 0xf7, 0x1b, 0xbb, 0x09, 0x75, 0x5e, 0x5f, 0xf9, 0x78, 0x12, 0x51, 0xa4, 0x63, 0x52, 0xa4, 0xba, 0x45, 0xbc, 0x48, 0x89, 0xb2, 0x73, 0xb4, 0xa5, 0x25, 0xd3, 0x1a, 0xd5, 0x9d, 0xff, 0x4e, 0xba, 0xd0, 0xb0, 0xb5, 0x21, 0x11, 0x25, 0x4d, 0x84, 0x90, 0x6e, 0xcd, 0x68, 0xd6, 0xd7, 0x39, 0xf7, 0x03, 0xb5, 0x7e, 0x78, 0x7e, 0x33, 0x2c, 0x7f, 0x34, 0x8f, 0x6f, 0xb2, 0x24, 0xe0, 0x5f, 0xd6, 0x18, 0x42, 0x4d, 0xb4, 0x5b, 0xe5, 0xc6, 0x92, 0xde, 0x54, 0x37, 0x69, 0x36, 0x7d, 0xe0, 0x0b, 0xa2, 0x6a, 0xb7, 0x41, 0xf4, 0x23, 0x09, 0x7f, 0x26, 0x64, 0xff, 0x10, 0x8a, 0x28, 0x34, 0xca, 0x08, 0x81, 0xf5, 0x38, 0x58, 0x46, 0xd2, 0xc0, 0x1c, 0x35, 0x31, 0x69, 0xcc, 0x4a, 0xed, 0x04, 0x22, 0x06, 0xbf, 0x79, 0x62, 0x0e, 0x43, 0x5e, 0x90, 0xf3, 0x95, 0x6b, 0x6e, 0xc3, 0x80, 0x9c, 0x63, 0xd1, 0xf7, 0xf2, 0x9f, 0x83, 0xb2, 0x09, 0x08, 0xcf, 0xb3, 0x87, 0x79, 0xc6, 0x24, 0xe6, 0x98, 0x58, 0xda, 0xdc, 0x0c, 0x67, 0x4c, 0x1f, 0xe7, 0xc3, 0x26, 0xec, 0xdd, 0x7e, 0x91, 0xb0, 0x31, 0x99, 0x5c, 0x93, 0x52, 0x17, 0xa2, 0x0f, 0xb1, 0xfb, 0x09, 0xd2, 0xa9, 0xe5, 0xdf, 0x1e, 0x5c, 0xa8, 0xf5, 0x0c, 0x20, 0xc3, 0xe3, 0x07, 0x32, 0x1b, 0x42, 0xc1, 0x58, 0xb2, 0x1c, 0x52, 0x7d, 0x56, 0xf8, 0x0c, 0xad, 0x03, 0xf5, 0x40, 0x07, 0x9c, 0xf4, 0x41, 0xf5, 0x54, 0xed, 0x66, 0x11, 0xd6, 0x98, 0xa4, 0x32, 0xd2, 0x94, 0x02, 0x74, 0xa9, 0xe1, 0x3a, 0x61, 0x18, 0x37, 0x54, 0xce, 0x03, 0x17, 0xc9, 0xc9, 0x99, 0x22, 0xd7, 0x3f, 0x71, 0x7f, 0xf5, 0x8d, 0xa3, ]; const sig512_224: [_]u8 = [ 0x65, 0xda, 0xf7, 0x42, 0x16, 0xe9, 0xcb, 0xc0, 0xed, 0x1e, 0xb7, 0xf1, 0x18, 0xab, 0x30, 0xf4, 0xe9, 0xf3, 0x4c, 0x1f, 0x8f, 0x94, 0x61, 0x79, 0xe1, 0x89, 0x89, 0xbb, 0x6d, 0x26, 0xcb, 0xfc, 0xaf, 0x99, 0xdc, 0x6b, 0x16, 0x4c, 0x51, 0x4f, 0x49, 0xb0, 0xd8, 0x98, 0x89, 0x95, 0x10, 0x6f, 0xa2, 0x50, 0x6e, 0x04, 0xaa, 0x98, 0xd7, 0x63, 0x91, 0x21, 0x8f, 0x5a, 0xd5, 0xd1, 0x9c, 0x31, 0xe2, 0x0c, 0xd1, 0xb1, 0xf8, 0xf5, 0x06, 0x75, 0x50, 0x33, 0x31, 0x49, 0xa4, 0xac, 0x87, 0x75, 0x1b, 0x03, 0x12, 0x27, 0x23, 0xbf, 0xe5, 0xe5, 0xcf, 0xa6, 0x33, 0xeb, 0xa3, 0x20, 0xbd, 0xc7, 0x21, 0x89, 0x4a, 0x66, 0x8a, 0x0d, 0xe4, 0x29, 0x7f, 0x39, 0xe1, 0x21, 0x7e, 0x2d, 0x23, 0x26, 0xe0, 0xae, 0xc9, 0xb7, 0xb6, 0xce, 0x85, 0x2d, 0x9e, 0x98, 0xc0, 0x02, 0x6c, 0x4e, 0x81, 0xcf, 0x4f, 0xea, 0x85, 0x66, 0xae, 0x4a, 0xca, 0xf9, 0x48, 0x35, 0x0c, 0xb4, 0x33, 0x30, 0xb9, 0x60, 0xc3, 0x9b, 0xb7, 0x02, 0x81, 0x02, 0xb2, 0x85, 0xcf, 0x64, 0x41, 0xa9, 0xc9, 0xf1, 0x71, 0x04, 0xef, 0xe1, 0x27, 0xbd, 0x8d, 0xd6, 0x16, 0xb3, 0xfc, 0x2e, 0xf3, 0x5b, 0xfa, 0xb1, 0xa3, 0xfd, 0x22, 0x58, 0xda, 0xaf, 0x0c, 0x3b, 0xf4, 0x9c, 0xa9, 0x53, 0x0c, 0x96, 0x2f, 0x73, 0x9f, 0x74, 0xb3, 0x03, 0xf6, 0xb6, 0x4e, 0xcb, 0x40, 0xed, 0xb3, 0x1b, 0x1c, 0x53, 0x19, 0xf7, 0x78, 0xb0, 0x59, 0x05, 0xd5, 0x1b, 0x5e, 0xb9, 0xaf, 0x23, 0xdd, 0xa9, 0xc4, 0x2d, 0x6f, 0x09, 0x67, 0xcb, 0x5d, 0x9e, 0x03, 0xfb, 0xe6, 0x70, 0x72, 0xef, 0x62, 0xb8, 0x50, 0xad, 0x70, 0xb1, 0x34, 0xfd, 0x92, 0x0f, 0xb1, 0xfd, 0x8a, 0x37, 0x63, 0x93, 0xa2, 0x9b, 0x2c, 0x9b, 0x62, 0xe6, 0x95, 0x3a, 0xfb, 0x44, 0x4c, 0xf5, 0x96, 0x2b, 0x9f, 0x7a, 0x6f, 0xae, 0xc4, 0xa5, 0xe4, 0x23, 0x3b, 0x06, 0xf5, 0x95, 0x89, 0xa6, 0x15, 0xb1, 0xd5, 0xa3, 0xdd, 0x2c, 0x17, 0xf5, 0x60, 0x5d, 0x09, 0x69, 0x42, 0x88, 0xe7, 0x21, 0x60, 0x79, 0xe9, 0x69, 0x9d, 0x12, 0x2e, 0x6a, 0xdf, 0x51, 0x45, 0x54, 0x91, 0x54, 0x17, 0xe7, 0x6c, 0x8c, 0xbf, 0xe3, 0x69, 0xc2, 0xfa, 0xb4, 0x7b, 0x72, 0xda, 0x48, 0xe4, 0xd1, 0xce, 0x86, 0x8f, 0x17, 0x5d, 0x18, 0x21, 0x72, 0x28, 0x8a, 0x78, 0xca, 0xa1, 0x90, 0x6b, 0x6d, 0xc0, 0x39, 0xb3, 0xe9, 0x71, 0x65, 0xe8, 0xbb, 0x19, 0xf4, 0x8b, 0x59, 0xc2, 0x9e, 0x7b, 0xa3, 0xf2, 0xcb, 0x0d, 0xa0, 0xb4, 0x32, 0xe2, 0xdb, 0x72, 0x5c, 0x7f, 0xe2, 0x32, 0x77, 0x62, 0xf1, 0xb9, 0x34, 0xe9, 0x95, 0x8d, 0x76, 0xa4, 0xf2, 0xd2, 0x31, 0x46, 0xc1, 0xf9, 0xdb, ]; const sig512_256: [_]u8 = [ 0xb9, 0x33, 0xe4, 0x78, 0x0f, 0x91, 0xa3, 0xe4, 0x2c, 0x34, 0x9a, 0xfc, 0x00, 0xba, 0x37, 0x8e, 0x1f, 0x94, 0xe4, 0xf2, 0xae, 0x75, 0x96, 0x9f, 0xe1, 0x9c, 0xef, 0xf9, 0x72, 0x50, 0x21, 0x3b, 0xe6, 0xef, 0xa5, 0x3e, 0x04, 0x9e, 0x75, 0x25, 0x1a, 0x2c, 0xa1, 0x74, 0x26, 0x74, 0x20, 0x57, 0x2c, 0xda, 0x83, 0x1f, 0x21, 0xb0, 0x07, 0x0a, 0x88, 0xd3, 0x1d, 0x0c, 0x59, 0xef, 0x93, 0x1d, 0x38, 0xe6, 0xe8, 0x77, 0x3a, 0x70, 0xad, 0xb2, 0xcd, 0x9e, 0x3b, 0xf0, 0x48, 0xfd, 0x49, 0xe7, 0x06, 0x8e, 0x6d, 0x16, 0x01, 0x44, 0x8f, 0xbd, 0x74, 0x96, 0xae, 0xc6, 0x6f, 0x03, 0x7f, 0xc2, 0xb1, 0x0c, 0x00, 0x45, 0xbe, 0x14, 0x1a, 0xdc, 0xa2, 0xe8, 0x61, 0xaf, 0x03, 0x39, 0x5a, 0xa9, 0x6c, 0xf2, 0xa7, 0x31, 0x95, 0x91, 0x4f, 0xf2, 0xff, 0x93, 0x03, 0xac, 0x8e, 0xe7, 0x1c, 0xd7, 0xae, 0x71, 0x9a, 0x5d, 0x0e, 0xb6, 0xed, 0x99, 0x24, 0x8c, 0xec, 0x95, 0x9e, 0x98, 0xf6, 0x04, 0xb8, 0xa9, 0x36, 0x64, 0xbe, 0xdd, 0x3d, 0x9f, 0x59, 0xed, 0x7d, 0x51, 0x5b, 0x1a, 0xb5, 0x68, 0x00, 0xa1, 0x5f, 0x0e, 0xdb, 0xb1, 0xd5, 0x43, 0x4f, 0xd7, 0x2e, 0xc7, 0x61, 0x86, 0xdb, 0x21, 0xaf, 0xa7, 0xd3, 0x0f, 0xb6, 0xa2, 0x59, 0x34, 0x86, 0xeb, 0xe6, 0x2e, 0x44, 0xb3, 0x2c, 0xea, 0x1c, 0x47, 0x7c, 0x81, 0x54, 0xba, 0x4a, 0x3a, 0x89, 0x63, 0x1e, 0x2f, 0x10, 0x2b, 0x96, 0xd2, 0x54, 0x76, 0xa3, 0xd8, 0x2c, 0x41, 0xb8, 0xaa, 0xd0, 0x35, 0xf0, 0x00, 0xf6, 0xba, 0x82, 0x4d, 0xe4, 0xe7, 0x5a, 0xfc, 0x2e, 0xc6, 0x03, 0x2e, 0x9e, 0x90, 0x0c, 0x37, 0xa8, 0xff, 0x87, 0xa7, 0x78, 0x2f, 0x68, 0xd2, 0x85, 0xa8, 0xf2, 0x93, 0x88, 0x2a, 0x90, 0x03, 0xe1, 0x4a, 0x2e, 0x58, 0x63, 0x92, 0x21, 0xf2, 0x8c, 0x3d, 0xdd, 0x49, 0xc1, 0x0e, 0x15, 0x1b, 0xcf, 0x21, 0xd5, 0x0d, 0x24, 0xba, 0xd6, 0x29, 0xdb, 0xb3, 0x53, 0xfc, 0x56, 0xa9, 0x55, 0xb6, 0x1e, 0x8d, 0xd5, 0xd7, 0x16, 0x0c, 0x65, 0x53, 0xc7, 0xda, 0xc7, 0x8b, 0x35, 0x99, 0x38, 0x80, 0xa8, 0xe7, 0x5e, 0x57, 0x60, 0xad, 0x24, 0xe6, 0x0c, 0x4c, 0xa3, 0xbf, 0xe5, 0x79, 0x9c, 0x1b, 0xa2, 0x1f, 0x6c, 0xf4, 0x4b, 0x50, 0x36, 0x15, 0xf7, 0x9b, 0xab, 0x17, 0x8f, 0x15, 0x1f, 0x5b, 0x93, 0x67, 0x56, 0x70, 0x5c, 0x5b, 0x59, 0xef, 0x1b, 0x41, 0xf9, 0x36, 0xc5, 0x6f, 0x49, 0x1e, 0x2f, 0x99, 0xdd, 0x13, 0xb6, 0xd1, 0x2b, 0xb9, 0x68, 0x36, 0xbf, 0x02, 0xd6, 0x27, 0x6f, 0xeb, 0x83, 0x8a, 0x77, 0x12, 0xf7, 0x07, 0xd8, 0x3f, 0x60, 0x57, 0x5b, 0x24, 0x73, 0x64, 0x85, 0x90, 0xf0, 0xbd, 0x76, 0xcd, ]; @test fn pkcs1() void = { let pk = sign3072.priv; let priv: [PRIVKEYSZ]u8 = [0...]; privkey_init(priv, sign3072.priv)!; let pub: [PUBKEYSZ]u8 = [0...]; pubkey_init(pub, sign3072.pub)!; assertpkcs1(priv, pub, msg, sig1, pkcs1_hashalgo::SHA1); assertpkcs1(priv, pub, msg, sig256, pkcs1_hashalgo::SHA256); assertpkcs1(priv, pub, msg, sig384, pkcs1_hashalgo::SHA384); assertpkcs1(priv, pub, msg, sig512, pkcs1_hashalgo::SHA512); assertpkcs1(priv, pub, msg, sig512_224, pkcs1_hashalgo::SHA512_224); assertpkcs1(priv, pub, msg, sig512_256, pkcs1_hashalgo::SHA512_256); }; fn assertpkcs1( priv: []u8, pub: []u8, msg: []u8, sig: []u8, algo: pkcs1_hashalgo ) void = { let nsig: []u8 = alloc([0...], len(sig)); defer free(nsig); let msghash = pkcs1_hash(msg, algo); defer free(msghash); pkcs1_sign(priv, msghash, nsig, algo, pkcs1_signbuf)!; assert(bytes::equal(nsig, sig)); pkcs1_verify(pub, msghash, sig, algo, pkcs1_verifybuf)!; const tmp = msghash[0]; msghash[0] += 1; assert(pkcs1_verify(pub, msghash, sig, algo, pkcs1_verifybuf) is error); msghash[0] = tmp; nsig[0] += 1; assert(pkcs1_verify(pub, msghash, nsig, algo, pkcs1_verifybuf) is error); }; fn pkcs1_hash(msg: []u8, algo: pkcs1_hashalgo) []u8 = { let h: *hash::hash = switch (algo) { case pkcs1_hashalgo::SHA1 => yield &sha1::sha1(); case pkcs1_hashalgo::SHA256 => yield &sha256::sha256(); case pkcs1_hashalgo::SHA384 => yield &sha512::sha384(); case pkcs1_hashalgo::SHA512 => yield &sha512::sha512(); case pkcs1_hashalgo::SHA512_224 => yield &sha512::sha512_224(); case pkcs1_hashalgo::SHA512_256 => yield &sha512::sha512_256(); case => abort("unreachable"); }; defer hash::close(h); let out: []u8 = alloc([0...], hash::sz(h)); io::writeall(h, msg)!; hash::sum(h, out); return out; }; hare-0.24.2/crypto/rsa/README000066400000000000000000000020461464473310100155100ustar00rootroot00000000000000This module provides RSA signature and encryption schemes defined in PKCS #1. The implementation only supports RSA keys with two prime factors. Most of the RSA operations in this module require buffers to perform. Buffer sizes are provided for keys of a default maximum size of 4096-bits. [[BITSZ]] may be changed with compiler flags to support bigger keys. [[MINBITSZ]] defines the minimum size accordingly. Public and private keys are stored in byte slices. [[pubkey_init]] is used to initialize a public key. [[privkey_init]] or [[privkey_initd]] is used to initialize a private key, depending on which parameters are available. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/rsa/core.ha000066400000000000000000000170301464473310100160710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The following code was initially ported from BearSSL. // // Copyright (c) 2016 Thomas Pornin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use bytes; use crypto::bigint::*; use crypto::math::{divu32}; use errors; use types; // Maximum factor size of a key of [[BITSZ]]. def MAXFACTOR: size = ((BITSZ + 64) >> 1); // Required buf size for the [[pubexp]] operation. def PUBEXP_BUFSZ: size = size(word) * (1 + (4 * (2 + ((BITSZ + WORD_BITSZ - 1) / WORD_BITSZ)))); // Requried buf size for the [[privexp]] operation. def PRIVEXP_BUFSZ: size = size(word) * (1 + (8 * (2 + ((MAXFACTOR + WORD_BITSZ - 1) / WORD_BITSZ)))); // Performs the modular exponentiation of 'x' with the public exponent of 'pub'. // 'x' is modified in place. 'x' must be the same length as the actual length // of 'pub.n'. // // For the size of 'buf' see [[PUBEXP_BUFSZ]]. If the buffer is not large // enough, [[errors::overflow]] will be returned. In case of 'x' being not of // required length or if 'x' is not modulo 'pub.n' [[errors::invalid]] is // returned and 'x' will be zeroed. fn pubexp(pub: *pubparams, x: []u8, buf: []u8) (void | error) = { // supported key length leaks. But that is not a problem. const wbuflen = len(buf) / size(word); let wbuf: []word = (buf: *[*]word)[..wbuflen]; let n = pub.n; // get the maximal allowed key size for given buffer. Reverse of the // [[PUBEXP_BUFSZ]] equation. const maxkeybits = (((wbuflen - 1) / 4) - 2) * WORD_BITSZ; if (len(n) == 0 || len(n) > (maxkeybits >> 3)) { return errors::overflow; }; if (len(x) != len(n)) { bytes::zero(x); return errors::invalid; }; // add word size - 1 to ceil required words in the division that follows const maxnbitlen = (len(n) << 3) + WORD_BITSZ: size - 1; assert(maxnbitlen <= types::U32_MAX); let bwordlen = 1 + divu32(0, maxnbitlen: u32, WORD_BITSZ).0; // make it even bwordlen += bwordlen & 1; let nenc = wbuf[..bwordlen]; let xenc = wbuf[bwordlen..2 * bwordlen]; let t = wbuf[2 * bwordlen..]; // From now on, buf will be indirectly used via slices borrowed from // wbuf. Therefore make sure it gets cleared in the end. defer bytes::zero(buf); encode(nenc, n); const n0i = ninv(nenc[1]); // if m is odd, n0i is also. let result: word = n0i & 1; result &= encodemod(xenc, x, nenc); modpow(xenc, pub.e, nenc, n0i, t); decode(x, xenc); if (result == 0: word) { bytes::zero(x); return errors::invalid; }; }; // Performs modular exponentiation of 'x' with the private exponent of 'priv'. // 'x' is modified in place. 'x' must be the same length as the actual length // of the modulus n (see [[privkey_nsize]]). // // For size of 'buf' see [[PRIVEXP_BUFSZ]]. If the buffer is not large enough // [[errors::overflow]] will be returned. In case of an invalid size of 'x' or // an invalid key, [[errors::invalid]] will be returned and 'x' will be zeroed. fn privexp(priv: *privparams, x: []u8, buf: []u8) (void | error) = { // supported key length leaks. But that is not a problem. const wbuflen = len(buf) / size(word); let wbuf: []word = (buf: *[*]word)[..wbuflen]; let p = priv.p; let q = priv.q; const maxflen = if (len(p) > len(q)) len(p) else len(q); // add word size - 1 to ceil required words in the division that follows const maxfbitlen = (maxflen << 3) + WORD_BITSZ: size - 1; assert(maxfbitlen <= types::U32_MAX); let bwordlen = 1 + divu32(0, maxfbitlen: u32, WORD_BITSZ).0; // make it even bwordlen += bwordlen & 1; // We need at least 6 big integers for the following calculations if (6 * bwordlen > len(wbuf)) { return errors::overflow; }; // From now on, buf will be indirectly used via wbuf. Therefore make // sure it gets cleared in the end. defer bytes::zero(buf); let mq = wbuf[..bwordlen]; encode(mq, q); let t1 = wbuf[bwordlen..2 * bwordlen]; encode(t1, p); // compute modulus n let t2 = wbuf[2 * bwordlen..4 * bwordlen]; zero(t2, mq[0]); mulacc(t2, mq, t1); // ceiled modulus length in bytes const nlen = (priv.nbitlen + 7) >> 3; if(len(x) != nlen) { bytes::zero(x); return errors::invalid; }; let t3 = wbuf[4 * bwordlen..6 * bwordlen]; let t3 = (t3: *[*]u8)[..nlen]; decode(t3, t2); let r: u32 = 0; // Check if x is mod n. // // We encode the modulus into bytes, to perform the comparison with // bytes. We know that the product length, in bytes, is exactly nlen. // // The comparison actually computes the carry when subtracting the // modulus from the source value; that carry must be 1 for a value in // the correct range. We keep it in r, which is our accumulator for the // error code. for (let u = nlen; u > 0) { u -= 1; r = ((x[u] - (t3[u] + r)) >> 8) & 1; }; // Move the decoded p to another temporary buffer. let mp = wbuf[2 * bwordlen..3 * bwordlen]; mp[..] = t1[..]; // Compute s2 = x^dq mod q. const q0i = ninv(mq[1]); let s2 = wbuf[bwordlen..bwordlen * 3]; encodereduce(s2, x, mq); r &= modpow(s2, priv.dq, mq, q0i, wbuf[3 * bwordlen..]); // Compute s1 = x^dp mod p. const p0i = ninv(mp[1]); let s1 = wbuf[bwordlen * 3..]; encodereduce(s1, x, mp); r &= modpow(s1, priv.dp, mp, p0i, wbuf[4 * bwordlen..]); // Compute: // h = (s1 - s2)*(1/q) mod p // s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is // unclear about whether p may be lower than q (some existing, // widely deployed implementations of RSA don't tolerate p < q), // but we want to support that occurrence, so we need to use the // reduction function. // // Since we use br_i31_decode_reduce() for iq (purportedly, the // inverse of q modulo p), we also tolerate improperly large // values for this parameter. let t1 = wbuf[4 * bwordlen..5 * bwordlen]; let t2 = wbuf[5 * bwordlen..]; reduce(t2, s2, mp); add(s1, mp, sub(s1, t2, 1)); tomonty(s1, mp); encodereduce(t1, priv.iq, mp); montymul(t2, s1, t1, mp, p0i); // h is now in t2. We compute the final result: // s = s2 + q*h // All these operations are non-modular. // // We need mq, s2 and t2. We use the t3 buffer as destination. // The buffers mp, s1 and t1 are no longer needed, so we can // reuse them for t3. Moreover, the first step of the computation // is to copy s2 into t3, after which s2 is not needed. Right // now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5. // Therefore, we have ample room for t3 by simply using s2. let t3 = s2; mulacc(t3, mq, t2); // Encode the result. Since we already checked the value of xlen, // we can just use it right away. decode(x, t3); if ((p0i & q0i & r) != 1) { bytes::zero(x); return errors::invalid; }; }; hare-0.24.2/crypto/rsa/errors.ha000066400000000000000000000011471464473310100164570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // Signature verification failed. export type badsig = !void; // A tagged union of all RSA error types. export type error = !( badsig | errors::overflow | errors::invalid ); // Converts an [[error]] into a human-friendly string representation. export fn strerror(err: error) str = { match (err) { case badsig => return "Signature verification failed"; case errors::overflow => return "Key or key operation exceeds given buffer size"; case errors::invalid => return errors::strerror(errors::invalid); }; }; hare-0.24.2/crypto/rsa/keys.ha000066400000000000000000000215241464473310100161170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::bigint; use crypto::math::*; use endian; use errors; use io; use memio; use types; // The default bit size of RSA keys is 4096-bit. Used as base for buffer sizes. export def BITSZ: size = 4096; // The minimum bit size of RSA keys used only for validation during key init. // The default value is 1024-bit. export def MINBITSZ: size = 1024; // RSA key parameters for initializing public keys with [[pubkey_init]]. export type pubparams = struct { // Modulus in big-endian order n: []u8, // Public exponent in big-endian order e: []u8, }; // RSA key parameters for initializing private keys with [[privkey_init]]. If // the private exponent d is available, [[privkey_initd]] may be used, which // derives 'dp' and 'dq'. All big integer values are in big-endian order. export type privparams = struct { // Bit length of the modulus n. If unknown, the modulus can be provided // to the init function, which derivces the length. nbitlen: size, // First prime factor. p: []u8, // Second prime factor q: []u8, // First exponent. dp = d mod (p - 1) where d is the private exponent. // May be omitted on [[privkey_initd]]. dp: []u8, // Second exponent. dq = d mod (q - 1) where d is the private exponent. // May be omitted on [[privkey_initd]]. dq: []u8, // Coefficient. iq = q^-1 mod p. iq: []u8, }; // Size required to store a public key of [[BITSZ]] length. export def PUBKEYSZ: size = 5 + 2 * (BITSZ >> 3); // Initializes a public key from given [[pubparams]] 'x'. The data format // of 'pubkey' is subject to change and must not be used to serialize the key. // [[PUBKEYSZ]] defines the required size to store a key of [[BITSZ]]. // // If given key does not fit into 'pubkey' or is too small, [[errors::overflow]] // is returned. Returns [[errors::invalid]], if given key parameters are // invalid. Returns the number of bytes written to 'pubkey' on success. export fn pubkey_init(pubkey: []u8, x: pubparams) (size | error) = { let e = ltrim(x.e); let n = ltrim(x.n); if (len(pubkey) < pubkey_len(n, e) || len(n) > types::U16_MAX || len(e) > types::U16_MAX) { return errors::overflow; }; // Very basic key checks that only catch obvious errors. if ((len(e) == 1 && e[0] == 1) || len(e) > len(n)) { return errors::invalid; }; if (bitlen(n) < MINBITSZ) { return errors::invalid; }; let w = memio::fixed(pubkey); let s = 0z; s += writeslice(&w, e)!; s += writeslice(&w, n)!; return s; }; // Returns the length of the modulus 'n' of given public key. export fn pubkey_nbitlen(pubkey: []u8) size = { let p = pubkey_params(pubkey); return bitlen(p.n); }; // Returns the length the public key would require in its encoded form. fn pubkey_len(n: []u8, e: []u8) size = 1z + 2 + len(n) + 2 + len(e); // Returns the slice without preceeding zeroes. fn ltrim(s: []u8) []u8 = { for (len(s) > 0 && s[0] == 0) { s = s[1..]; }; return s; }; fn writeslice(dest: io::handle, a: []u8) (size | io::error) = { let lenbuf: [2]u8 = [0...]; endian::beputu16(lenbuf, len(a): u16); let s = io::write(dest, lenbuf)?; s += io::write(dest, a)?; return s; }; // Counts the bits for given slice 'n'. fn bitlen(s: []u8) size = { for (s[0] == 0) { s = s[1..]; }; return countbits(s[0]) + 8 * (len(s) - 1); }; fn countbits(x: u8) size = { let k: u32 = nequ32(x, 0); let c: u32 = 0; c = gtu32(x, 0x0f); x = muxu32(c, x >> 4, x): u8; k += c << 2; c = gtu32(x, 0x03); x = muxu32(c, x >> 2, x): u8; k += c << 1; k += gtu32(x, 0x01); return k; }; @test fn countbits() void = { assert(countbits(0xf0) == 8); assert(countbits(0x70) == 7); assert(countbits(0x30) == 6); assert(countbits(0x10) == 5); assert(countbits(0x08) == 4); assert(countbits(0x04) == 3); assert(countbits(0x03) == 2); assert(countbits(0x01) == 1); assert(countbits(0x00) == 0); }; // Returns the public key parameters, borrowed from given 'pubkey'. export fn pubkey_params(pubkey: []u8) pubparams = { let keybuf = pubkey; return pubparams { e = nextslice(&keybuf), n = nextslice(&keybuf), }; }; fn nextslice(key: *[]u8) []u8 = { const l = endian::begetu16(key[..2]); let s = key[2..2 + l]; *key = key[2 + l..]; return s; }; // Size required to store a private key of [[BITSZ]] length. export def PRIVKEYSZ: size = 13 + (MAXFACTOR >> 3) * 5; fn privkey_len(x: *privparams) size = 13z + len(x.p) + len(x.q) + len(x.dp) + len(x.dq) + len(x.iq); // Initializes the private key 'privkey' using the values from 'x'. 'nbitlen' of // 'x' may be omitted, if the modulus 'n' is passed. All other values of 'x' // must be present. If 'x' is missing 'dp' and 'dq' use [[privkey_initd]]. // // In case of invalid parameters or if the key is too small, [[errors::invalid]] // is returned. If the key does not fit 'privkey', [[errors::overflow]] is // returned. On success the number of bytes written to 'privkey' is returned. export fn privkey_init(privkey: []u8, x: privparams, n: []u8...) (size | error) = { privkey_normalize(privkey, &x)?; if (len(x.dp) == 0 || len(x.dq) == 0) { return errors::invalid; }; let s = privkey_writehead(privkey, &x, n...)?; let w = memio::fixed(privkey[s..]); s += writeslice(&w, x.dp)!; s += writeslice(&w, x.dq)!; s += writeslice(&w, x.iq)!; s += writeslice(&w, x.p)!; s += writeslice(&w, x.q)!; return s; }; // Trims key parameters and also does basic key checks. fn privkey_normalize(privkey: []u8, x: *privparams) (void | error) = { x.p = ltrim(x.p); x.q = ltrim(x.q); x.dp = ltrim(x.dp); x.dq = ltrim(x.dq); x.iq = ltrim(x.iq); if (len(privkey) < privkey_len(x) || len(x.p) > types::U16_MAX || len(x.q) > types::U16_MAX || len(x.dp) > types::U16_MAX || len(x.dq) > types::U16_MAX || len(x.iq) > types::U16_MAX) { return errors::overflow; }; if (len(x.p) == 0 || len(x.q) == 0 || len(x.iq) == 0 || !isodd(x.p) || !isodd(x.q)) { return errors::invalid; }; }; fn isodd(x: []u8) bool = { assert(len(x) > 0); return x[len(x)-1] & 1 == 1; }; fn privkey_writehead( privkey: []u8, p: *privparams, n: []u8... ) (size | error) = { assert(len(n) <= 1); const nbitlen = if (len(n) == 1) bitlen(n[0]) else p.nbitlen; if (nbitlen > types::U16_MAX) { return errors::overflow; }; if (nbitlen < MINBITSZ) { return errors::invalid; }; let w = memio::fixed(privkey); let lenbuf: [2]u8 = [0...]; endian::beputu16(lenbuf, nbitlen: u16); return io::write(&w, lenbuf)!; }; // Initializes the private key 'privkey' using the values from 'x' and the // secret exponent 'd'. 'dp' and 'dq' will be derived from 'p' and 'q' of 'x'. // 'nbitlen' of 'x' may be omitted, if the modulus 'n' is passed. 'x' must // provide 'iq'. // // In case of invalid parameters or if the key is too small, [[errors::invalid]] // is returned. If the key does not fit 'privkey', [[errors::overflow]] is // returned. On success the number of bytes written to 'privkey' is returend. export fn privkey_initd( privkey: []u8, x: privparams, d: []u8, n: []u8... ) (size | error) = { privkey_normalize(privkey, &x)?; let s = privkey_writehead(privkey, &x, n...)?; // the order is important. The dmod operation uses the space for the // remaining factors as buffer. s += privkey_dmod(privkey[s..], d, x.p); s += privkey_dmod(privkey[s..], d, x.q); let w = memio::fixed(privkey[s..]); s += writeslice(&w, x.iq)!; s += writeslice(&w, x.p)!; s += writeslice(&w, x.q)!; // zero out tail in case the privkey_dmod operation left buffered values bytes::zero(privkey[s..]); return s; }; // Calculates 'x' = 'd' mod 'y' - 1 and stores 'x' into 'out' preceeding a // u16 len. 'out' will also be used as a calculation buffer. 'y' must be odd. fn privkey_dmod(out: []u8, d: []u8, y: []u8) size = { const encwordlen = bigint::encodelen(y); const enclen = encwordlen * size(bigint::word); const xlen = len(y); assert(len(out) >= 2 + xlen + 2 * enclen); assert(isodd(y)); let buf = out[2 + xlen..]; // XXX: this may be only done once for both dp and dq let by = (buf[..enclen]: *[*]bigint::word)[..encwordlen]; bigint::encode(by, y); bigint::decrodd(by); let bx = (buf[enclen..2 * enclen]: *[*]bigint::word)[..encwordlen]; bigint::encodereduce(bx, d, by); out[0] = (xlen >> 8): u8; out[1] = xlen: u8; bigint::decode(out[2..2 + xlen], bx); return 2 + xlen; }; // Returns the private key parameters borrowed from 'privkey'. export fn privkey_params(privkey: []u8) privparams = { let keybuf = privkey[2..]; return privparams { nbitlen = privkey_nbitlen(privkey), dp = nextslice(&keybuf), dq = nextslice(&keybuf), iq = nextslice(&keybuf), p = nextslice(&keybuf), q = nextslice(&keybuf), ... }; }; // Returns the length of the modulus 'n'. export fn privkey_nbitlen(privkey: []u8) size = { return endian::begetu16(privkey[0..2]); }; // Returns the number of bytes that are required to store a value modulo 'n'. export fn privkey_nsize(privkey: []u8) size = { return (privkey_nbitlen(privkey) + 7) / 8; }; hare-0.24.2/crypto/rsa/pkcs1.ha000066400000000000000000000102711464473310100161620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::math; use crypto::sha1; use crypto::sha256; use crypto::sha512; use errors; // Supported hash algorithms for [[pkcs1_sign]] and [[pkcs1_verify]]. export type pkcs1_hashalgo = enum { SHA1, // SHA224, We don't have this one yet SHA256, SHA384, SHA512, SHA512_224, SHA512_256, }; const OID_SHA1: [_]u8 = [ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, ]; const OID_SHA224: [_]u8 = [ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c, ]; const OID_SHA256: [_]u8 = [ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, ]; const OID_SHA384: [_]u8 = [ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30, ]; const OID_SHA512: [_]u8 = [ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40, ]; const OID_SHA512_224: [_]u8 = [ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05, 0x00, 0x04, 0x1c, ]; const OID_SHA512_256: [_]u8 = [ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20, ]; // Required buffer size for [[pkcs1_verify]]. export def PKCS1_VERIFYBUFSZ: size = PUBEXP_BUFSZ + (BITSZ / 8); // Verifies a PKCS#1 v1.5 signature given a public key 'pubkey', the message // hash 'msghash', the signature 'sig' and the hash algorithm 'algo'. 'algo' // must reflect the hash algorithm 'sig' was created with. // // A temporary buffer 'buf' of size [[PKCS1_VERIFYBUFSZ]] must be provided. export fn pkcs1_verify( pubkey: []u8, msghash: []u8, sig: []u8, algo: pkcs1_hashalgo, buf: []u8 ) (void | error) = { let pub = pubkey_params(pubkey); let actualsig = buf[..len(sig)]; let pubbuf = buf[len(sig)..]; actualsig[..] = sig[..]; match (pubexp(&pub, actualsig, pubbuf)) { case let e: error => return e; case void => void; }; let expectedsig = pubbuf[..len(sig)]; pkcs1_sig_encode(expectedsig, msghash, algo)?; if (math::eqslice(expectedsig, actualsig) == 0) { return badsig; }; }; // Required buffer size for [[pkcs1_sign]]. export def PKCS1_SIGNBUFSZ: size = PRIVEXP_BUFSZ; // Signs a message hash 'msghash' using the PKCS#1 V1.5 signature scheme. The // signature will be written to 'sig' which must be in the the size of the // modulus n (see [[privkey_nsize]]). 'algo' defines the hash algorithm // 'msghash' was created with. // // A temporary buffer 'buf' of size [[PKCS1_SIGNBUFSZ]] must be provided. export fn pkcs1_sign( priv: []u8, msghash: []u8, sig: []u8, algo: pkcs1_hashalgo, buf: []u8 ) (void | error) = { let priv = privkey_params(priv); pkcs1_sig_encode(sig, msghash, algo)?; privexp(&priv, sig, buf)?; }; // Returns hash id and hash size for given 'algo'. fn pkcs1_hashinfo(algo: pkcs1_hashalgo) (const []u8, size) = { switch (algo) { case pkcs1_hashalgo::SHA1 => return (OID_SHA1, sha1::SZ); case pkcs1_hashalgo::SHA256 => return (OID_SHA256, sha256::SZ); case pkcs1_hashalgo::SHA384 => return (OID_SHA384, sha512::SZ384); case pkcs1_hashalgo::SHA512 => return (OID_SHA512, sha512::SZ); case pkcs1_hashalgo::SHA512_224 => return (OID_SHA512_224, sha512::SZ224); case pkcs1_hashalgo::SHA512_256 => return (OID_SHA512_256, sha512::SZ256); case => abort("unreachable"); }; }; // Creates an unauthenticated signature of 'msg' and writes it into 'sig' using // given hash algorithm 'algo'. fn pkcs1_sig_encode( sig: []u8, msghash: []u8, algo: pkcs1_hashalgo ) (void | error) = { let (hid, hsz) = pkcs1_hashinfo(algo); if (len(msghash) != hsz) { return errors::invalid; }; let tlen = len(hid) + hsz; if (len(sig) < tlen + 11) { return badsig; }; const hsep = len(sig) - tlen - 1; sig[..2] = [0x00, 0x01]; for (let i = 2z; i < hsep; i += 1) { sig[i] = 0xff; }; sig[hsep] = 0x00; sig[hsep + 1..len(sig) - hsz] = hid[..]; sig[len(sig) - hsz..] = msghash[..]; }; hare-0.24.2/crypto/salsa/000077500000000000000000000000001464473310100151445ustar00rootroot00000000000000hare-0.24.2/crypto/salsa/+test.ha000066400000000000000000000170121464473310100165110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; use types; @test fn qr() void = { let s: [4]u32 = [0xe7e8c006, 0xc4f9417d, 0x6479b4b2, 0x68c67137]; qr(&s[0], &s[1], &s[2], &s[3]); assert(s[0] == 0xe876d72b); assert(s[1] == 0x9361dfd5); assert(s[2] == 0xf1460244); assert(s[3] == 0x948541a3); }; @test fn xsalsa20() void = { let key: [KEYSZ]u8 = [ 0x47, 0x85, 0x1a, 0xb8, 0xa0, 0xd4, 0x41, 0x20, 0xb7, 0x7b, 0xf6, 0x16, 0x0d, 0xcb, 0xbf, 0xa6, 0x9f, 0xa9, 0xc5, 0xdd, 0x2a, 0x0c, 0xb9, 0x8c, 0xeb, 0x72, 0xe7, 0x96, 0x57, 0x01, 0xb5, 0x5a, ]; let nonce: [XNONCESZ]u8 = [ 0x1b, 0xcb, 0x13, 0xb8, 0xf5, 0x27, 0x53, 0x34, 0xa0, 0xb4, 0x8e, 0xd2, 0xeb, 0x5b, 0xbc, 0x15, 0x44, 0x5b, 0x05, 0x09, 0x56, 0xa8, 0x86, 0xa7, ]; let msg: [_]u8 = [ 0xb4, 0x6d, 0x7c, 0xfd, 0x74, 0xe3, 0x91, 0xfa, 0x9a, 0xa2, 0x14, 0x52, 0x53, 0xe1, 0xfb, 0x5c, 0xf3, 0x4a, 0x60, 0x17, 0x2f, 0x46, 0x80, 0x07, 0x43, 0x43, 0xa1, 0x6c, 0x15, 0xf3, 0xad, 0x9e, 0x83, 0x1e, 0x63, 0x0b, 0x10, 0x57, 0xf9, 0x19, 0x3e, 0x0d, 0xc4, 0x14, 0xd0, 0x1c, 0xef, 0x46, 0x62, 0x94, 0xdc, 0x43, 0xdd, 0xfa, 0x96, 0xa9, 0xa2, 0xd7, 0xc8, 0x53, 0xea, 0xf8, 0x52, 0x1b, 0xce, 0xd0, 0x65, 0x5d, 0x63, 0xfa, 0x23, 0x88, 0x86, 0x95, 0x11, 0x12, 0x00, 0xec, 0xa2, 0x52, 0x1e, 0xac, 0x80, 0xd7, 0x07, 0xb4, 0x76, 0x38, 0x67, 0xcf, 0xca, 0x67, 0x81, 0xca, 0xb6, 0xb2, 0x5a, 0xb8, 0x7d, 0xe7, 0x6e, 0xed, 0x08, 0x82, 0x1f, 0x12, 0x94, 0x84, 0x08, 0xe4, 0x94, 0x8f, 0xa7, 0x72, 0x09, 0x82, ]; let cipher: [_]u8 = [ 0x17, 0x14, 0xa7, 0x77, 0xf1, 0xe0, 0xf7, 0xd7, 0x9a, 0x8f, 0xe7, 0x16, 0xe7, 0x75, 0x13, 0x9c, 0xb8, 0x15, 0xb2, 0xcc, 0x07, 0x97, 0x50, 0x66, 0xa4, 0xc2, 0xcd, 0x1c, 0x1b, 0x6e, 0xea, 0x90, 0x59, 0xa9, 0x31, 0xb7, 0x24, 0x68, 0x4a, 0x64, 0xf4, 0xc0, 0x00, 0xd0, 0xa5, 0x66, 0x55, 0x77, 0x2c, 0xbf, 0x27, 0x0b, 0xc2, 0xab, 0xf6, 0x5f, 0x43, 0xe7, 0xf3, 0x49, 0xb8, 0x7d, 0x34, 0xd5, 0x05, 0x65, 0xc8, 0x4b, 0x97, 0x90, 0x56, 0xcb, 0xfa, 0x85, 0x17, 0x25, 0x8e, 0x6b, 0xc6, 0x32, 0x88, 0xab, 0x85, 0x1a, 0x35, 0x12, 0xec, 0xdd, 0xb6, 0x7d, 0x28, 0x33, 0xdb, 0xbd, 0x89, 0x9d, 0x89, 0xf0, 0x19, 0xcf, 0xd5, 0x47, 0x8f, 0xcc, 0x66, 0x37, 0x7d, 0x59, 0xa4, 0x4b, 0x2a, 0x61, 0x1f, 0x5b, 0x52, 0xf5, ]; let result: [116]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = salsa20(); defer io::close(&c)!; xsalsa20_init(&c, &cipherbuf, key, nonce); io::writeall(&c, msg)!; assert(bytes::equal(cipher, result)); }; @test fn xsalsa20_ctr_overflow_u32() void = { let key: [KEYSZ]u8 = [ 0x7f, 0xa3, 0x4d, 0x21, 0x7c, 0xc3, 0x91, 0x99, 0x47, 0xef, 0xa1, 0xde, 0x4b, 0xaa, 0x8d, 0xcb, 0x38, 0x4e, 0x7f, 0xf7, 0xbe, 0xd6, 0xaf, 0x4c, 0x11, 0x97, 0x68, 0x39, 0xf1, 0xd9, 0x0f, 0x92, ]; let nonce: [XNONCESZ]u8 = [ 0x42, 0x4a, 0xff, 0xdb, 0x30, 0xde, 0x7f, 0xaf, 0xe9, 0xd4, 0xd5, 0xe5, 0x64, 0xfc, 0x3a, 0x87, 0xe1, 0x74, 0x9d, 0x3b, 0xd5, 0x5f, 0x01, 0xec, ]; let msg: [_]u8 = [ 0x64, 0xf8, 0xd2, 0x0d, 0xc5, 0x54, 0x27, 0x5d, 0xae, 0x74, 0x23, 0xf8, 0xae, 0x43, 0xfb, 0xed, 0x35, 0xbf, 0xda, 0x89, 0x4f, 0xb1, 0x0c, 0xcc, 0x06, 0x7b, 0xb9, 0x75, 0xcf, 0x3b, 0x8e, 0x02, 0x3f, 0xc4, 0x96, 0xf2, 0xfd, 0xef, 0x68, 0xae, 0x28, 0x30, 0x3a, 0x61, 0x1c, 0xcc, 0x3f, 0xa8, 0x9c, 0xec, 0x3a, 0x10, 0x84, 0x6a, 0xae, 0x47, 0xf4, 0x35, 0xa3, 0x42, 0xeb, 0x21, 0xb8, 0x30, 0x4c, 0x24, 0xf1, 0x00, 0x08, 0x9b, 0x0b, 0x86, 0x9e, 0x42, 0x97, 0x29, 0x5e, 0x9d, 0x7c, 0xdb, 0x7c, 0x16, 0x29, 0xac, 0x7c, 0xf8, 0xf5, 0xd8, 0xb3, 0xa8, 0x0d, 0x5a, 0xdb, 0x46, 0x21, 0x52, 0x42, 0x85, 0xdf, 0x42, 0xc9, 0x01, 0x66, 0xe3, 0x7b, 0x2a, 0xa5, 0xec, 0xee, 0x8c, 0x3a, 0xa9, 0xac, 0xd6, 0x6a, 0xa4, ]; let cipher: [_]u8 = [ 0xcc, 0x10, 0x8d, 0x36, 0xfd, 0x0c, 0x27, 0x88, 0x2f, 0x40, 0xc8, 0x94, 0xf6, 0x8e, 0xda, 0x54, 0x66, 0x6b, 0x57, 0x54, 0xd9, 0x2a, 0x2a, 0x77, 0xa5, 0x0e, 0x13, 0xdd, 0x37, 0x36, 0xd7, 0x6d, 0x32, 0xf0, 0xe0, 0xcc, 0x1e, 0x96, 0x94, 0x0a, 0xab, 0x96, 0x99, 0x70, 0x2b, 0xa5, 0x9b, 0xf1, 0x5a, 0x80, 0x88, 0x51, 0x37, 0x1d, 0xa5, 0x46, 0x63, 0x43, 0x34, 0xd9, 0x23, 0x36, 0x55, 0x5c, 0x3e, 0xcd, 0xf5, 0x18, 0xbe, 0x20, 0x4b, 0x7f, 0x7f, 0xad, 0xe9, 0xc1, 0x73, 0xf9, 0x9a, 0x75, 0xd3, 0x70, 0xbc, 0x92, 0x30, 0xf2, 0x03, 0x5a, 0x4e, 0x38, 0x8a, 0xab, 0x0c, 0x8a, 0x07, 0x14, 0xe7, 0x3f, 0x92, 0x90, 0xdd, 0x79, 0x7c, 0xa3, 0xa2, 0x3d, 0xda, 0xd5, 0x0f, 0xdf, 0x85, 0x7b, 0xcb, 0x7c, 0x7b, 0x2f, ]; let result: [116]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = salsa20(); defer io::close(&c)!; xsalsa20_init(&c, &cipherbuf, key, nonce); setctr(&c, types::U32_MAX); io::writeall(&c, msg)!; assert(bytes::equal(cipher, result)); }; @test fn xsalsa20_ctr_overflow_u64() void = { let key: [KEYSZ]u8 = [ 0xe3, 0xe0, 0xa8, 0x09, 0x09, 0xd2, 0x8c, 0xb4, 0x13, 0xa6, 0x8a, 0x33, 0xdf, 0x9c, 0xa2, 0x7f, 0x46, 0xd1, 0x9e, 0x32, 0x14, 0x53, 0x66, 0x23, 0x36, 0x45, 0x58, 0xff, 0x68, 0x36, 0x78, 0x69, ]; let nonce: [XNONCESZ]u8 = [ 0x8d, 0xe8, 0x84, 0xa0, 0x91, 0x0a, 0x26, 0xa3, 0xb4, 0x8a, 0x05, 0x22, 0x41, 0x77, 0xd1, 0x14, 0xbd, 0x09, 0x35, 0x0e, 0xbd, 0x73, 0xe5, 0xae, ]; let msg: [_]u8 = [ 0xa8, 0xd2, 0x9f, 0x40, 0x9e, 0xe5, 0xc9, 0xd4, 0x3e, 0x5c, 0x36, 0x1e, 0x9b, 0x75, 0x61, 0xf1, 0xe2, 0xfc, 0x57, 0xf6, 0x54, 0x06, 0x69, 0x1f, 0xb4, 0xba, 0xf3, 0xa9, 0xcf, 0xff, 0x02, 0x64, 0x06, 0x78, 0x2a, 0xce, 0x64, 0x38, 0xf5, 0x96, 0x5d, 0xfa, 0x2f, 0xe0, 0x5a, 0x61, 0x10, 0xf3, 0x97, 0x17, 0x68, 0xcc, 0xc2, 0x30, 0x02, 0x87, 0xc1, 0x58, 0xff, 0x9e, 0xc7, 0x9f, 0x95, 0xe8, 0xe6, 0x87, 0xbe, 0xa6, 0xc1, 0x14, 0x2a, 0x59, 0x44, 0x91, 0x95, 0x2d, 0x2f, 0xf7, 0xc3, 0xf7, 0x8a, 0x45, 0x28, 0xb0, 0x97, 0x72, 0xa6, 0x1d, 0x7b, 0x74, 0x71, 0x68, 0x2f, 0xe9, 0xbd, 0x5d, 0xf3, 0xd7, 0xd1, 0x4e, 0x73, 0x1b, 0xbf, 0x29, 0xad, 0xa7, 0x08, 0xe8, 0x70, 0x5f, 0x2b, 0x4d, 0x60, 0x3f, 0xf1, 0x09, ]; let cipher: [_]u8 = [ 0x6b, 0x01, 0x72, 0xc3, 0x54, 0x65, 0x85, 0xd6, 0x63, 0xef, 0x4b, 0x55, 0xbe, 0xd6, 0x32, 0x7c, 0x3a, 0x2e, 0x35, 0xac, 0x1a, 0xa9, 0x73, 0x57, 0xb1, 0xe7, 0x97, 0x1d, 0x5c, 0xd3, 0x9c, 0x9e, 0xee, 0x3d, 0x8e, 0xd7, 0x44, 0x4b, 0xee, 0xce, 0x6e, 0x5d, 0x81, 0x7e, 0x9a, 0x8a, 0x58, 0x65, 0x53, 0x1d, 0x8a, 0x7c, 0x6c, 0x4d, 0x18, 0x77, 0x8f, 0x65, 0x22, 0xd9, 0x47, 0xb4, 0x80, 0x16, 0x07, 0x22, 0x88, 0x92, 0x8e, 0x66, 0x5d, 0xac, 0xf4, 0x15, 0xf2, 0xd9, 0xe5, 0xc9, 0xdc, 0xeb, 0x01, 0xc1, 0x94, 0x9a, 0xdd, 0x74, 0x70, 0xfd, 0xe1, 0x40, 0x48, 0x72, 0xab, 0xbc, 0xe6, 0xec, 0x12, 0xdc, 0xf2, 0x57, 0xc6, 0xcf, 0xd5, 0x2f, 0x12, 0x56, 0xed, 0xe2, 0x3c, 0x93, 0x5a, 0xf6, 0x17, 0x63, 0xea, 0x41, ]; let result: [116]u8 = [0...]; let cipherbuf = memio::fixed(result); let c = salsa20(); defer io::close(&c)!; xsalsa20_init(&c, &cipherbuf, key, nonce); setctr(&c, types::U64_MAX); io::writeall(&c, msg)!; assert(bytes::equal(cipher, result)); }; // taken from naclcrypto-20090310.pdf @test fn hsalsa20() void = { const key: [_]u8 = [ 0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2, 0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89, ]; const nonce: [_]u8 = [ 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6, ]; const expected: [_]u8 = [ 0xdc, 0x90, 0x8d, 0xda, 0x0b, 0x93, 0x44, 0xa9, 0x53, 0x62, 0x9b, 0x73, 0x38, 0x20, 0x77, 0x88, 0x80, 0xf3, 0xce, 0xb4, 0x21, 0xbb, 0x61, 0xb9, 0x1c, 0xbd, 0x4c, 0x3e, 0x66, 0x25, 0x6c, 0xe4, ]; let out: [32]u8 = [0...]; hsalsa20(&out, &key, &nonce); assert(bytes::equal(out, expected)); }; hare-0.24.2/crypto/salsa/README000066400000000000000000000021601464473310100160230ustar00rootroot00000000000000crypto::salsa provides an implementation of the Salsa20 and XSalsa20 stream ciphers, per "Salsa20 specification" by Daniel J. Bernstein. Use [[salsa20]] to create a stream and either [[xsalsa20_init]] or [[salsa20_init]] to set handle, key and nonce of the appropriate size, [[NONCESZ]] for salsa20 or [[XNONCESZ]] for XSalsa20. After calling the appropriate init function, [[io::write]] may be used to encrypt blocks to the handle or [[io::read]] to decrypt blocks from the handle. The stream must be closed with [[io::close]] to wipe sensitive data from memory. Writing blocks of length [[BLOCKSZ]] is not required. However, seeking the key stream with [[setctr]] only operates in units of [[BLOCKSZ]]. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/salsa/salsa20.ha000066400000000000000000000115631464473310100167310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::cipher; use crypto::math::{rotl32, xor}; use endian; use io; // Size of a Salsa key, in bytes. export def KEYSZ: size = 32; // Size of the XSalsa20 nonce, in bytes. export def XNONCESZ: size = 24; // Size of the Salsa20 nonce, in bytes. export def NONCESZ: size = 8; def ROUNDS: size = 20; // The block size of the Salsa cipher. export def BLOCKSZ: size = 64; const magic: [4]u32 = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]; export type stream = struct { cipher::xorstream, state: [16]u32, xorbuf: [BLOCKSZ]u8, xorused: size, rounds: size, }; // Create a Salsa20 or XSalsa20 stream. Must be initialized with either // [[salsa20_init]] or [[xsalsa20_init]], and must be closed with [[io::close]] // after use to wipe sensitive data from memory. export fn salsa20() stream = { return stream { stream = &cipher::xorstream_vtable, h = 0, keybuf = &keybuf, advance = &advance, finish = &finish, xorused = BLOCKSZ, rounds = ROUNDS, ... }; }; fn init( state: *[16]u32, key: []u8, nonce: []u8, ctr: []u8 ) void = { state[0] = magic[0]; state[1] = endian::legetu32(key[0..4]); state[2] = endian::legetu32(key[4..8]); state[3] = endian::legetu32(key[8..12]); state[4] = endian::legetu32(key[12..16]); state[5] = magic[1]; state[6] = endian::legetu32(nonce[0..4]); state[7] = endian::legetu32(nonce[4..8]); state[8] = endian::legetu32(ctr[0..4]); state[9] = endian::legetu32(ctr[4..8]); state[10] = magic[2]; state[11] = endian::legetu32(key[16..20]); state[12] = endian::legetu32(key[20..24]); state[13] = endian::legetu32(key[24..28]); state[14] = endian::legetu32(key[28..32]); state[15] = magic[3]; }; // Initialize a Salsa20 stream. export fn salsa20_init( s: *stream, h: io::handle, key: []u8, nonce: []u8, ) void = { assert(len(key) == KEYSZ); assert(len(nonce) == NONCESZ); let counter: [8]u8 = [0...]; init(&s.state, key, nonce, &counter); s.h = h; }; // Initialize an XSalsa20 stream. XSalsa20 differs from Salsa20 via the use of a // larger nonce parameter. export fn xsalsa20_init( s: *stream, h: io::handle, key: []u8, nonce: []u8 ) void = { assert(len(key) == KEYSZ); assert(len(nonce) == XNONCESZ); let dkey: [32]u8 = [0...]; defer bytes::zero(dkey); hsalsa20(&dkey, key, nonce[..16]); salsa20_init(s, h, &dkey, nonce[16..]: *[NONCESZ]u8); }; // Derives a new key from 'key' and 'nonce' as used during XSalsa20 // initialization. This function may only be used for specific purposes // such as X25519 key derivation. Do not use if in doubt. export fn hsalsa20(out: []u8, key: []u8, nonce: []u8) void = { assert(len(out) == KEYSZ); assert(len(key) == KEYSZ); assert(len(nonce) == 16); let state: [16]u32 = [0...]; defer bytes::zero((state: []u8: *[*]u8)[..BLOCKSZ]); init(&state, key, nonce[0..8]: *[8]u8, nonce[8..16]: *[8]u8); hblock(state[..], &state, 20); endian::leputu32(out[0..4], state[0]); endian::leputu32(out[4..8], state[5]); endian::leputu32(out[8..12], state[10]); endian::leputu32(out[12..16], state[15]); endian::leputu32(out[16..20], state[6]); endian::leputu32(out[20..24], state[7]); endian::leputu32(out[24..28], state[8]); endian::leputu32(out[28..32], state[9]); }; // Advances the key stream to "seek" to a future state by 'counter' times // [[BLOCKSZ]]. export fn setctr(s: *stream, counter: u64) void = { s.state[8] = (counter & 0xFFFFFFFF): u32; s.state[9] = (counter >> 32): u32; s.xorused = BLOCKSZ; }; fn keybuf(s: *cipher::xorstream) []u8 = { let s = s: *stream; if (s.xorused >= BLOCKSZ) { block((s.xorbuf[..]: *[*]u32)[..16], &s.state, s.rounds); s.state[8] += 1; if (s.state[8] == 0) { s.state[9] += 1; }; s.xorused = 0; }; return s.xorbuf[s.xorused..]; }; fn advance(s: *cipher::xorstream, n: size) void = { let s = s: *stream; assert(n <= len(s.xorbuf)); s.xorused += n; }; fn block(dest: []u32, state: *[16]u32, rounds: size) void = { hblock(dest, state, rounds); for (let i = 0z; i < 16; i += 1) { dest[i] += state[i]; }; }; fn hblock(dest: []u32, state: *[16]u32, rounds: size) void = { for (let i = 0z; i < 16; i += 1) { dest[i] = state[i]; }; for (let i = 0z; i < rounds; i += 2) { qr(&dest[0], &dest[4], &dest[8], &dest[12]); qr(&dest[5], &dest[9], &dest[13], &dest[1]); qr(&dest[10], &dest[14], &dest[2], &dest[6]); qr(&dest[15], &dest[3], &dest[7], &dest[11]); qr(&dest[0], &dest[1], &dest[2], &dest[3]); qr(&dest[5], &dest[6], &dest[7], &dest[4]); qr(&dest[10], &dest[11], &dest[8], &dest[9]); qr(&dest[15], &dest[12], &dest[13], &dest[14]); }; }; fn qr(a: *u32, b: *u32, c: *u32, d: *u32) void = { *b ^= rotl32(*a + *d, 7); *c ^= rotl32(*b + *a, 9); *d ^= rotl32(*c + *b, 13); *a ^= rotl32(*d + *c, 18); }; fn finish(s: *cipher::xorstream) void = { let s = s: *stream; bytes::zero((s.state[..]: *[*]u8)[..len(s.state) * size(u32)]); bytes::zero(s.xorbuf); }; hare-0.24.2/crypto/sha1/000077500000000000000000000000001464473310100146755ustar00rootroot00000000000000hare-0.24.2/crypto/sha1/+test.ha000066400000000000000000000043311464473310100162420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::hex; use fmt; use hash; use strings; use test; @test fn sha1() void = { let sha = sha1(); const vectors = [ ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"), ("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"), ("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"), ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "a49b2446a02c645bf419f995b67091253a04a259"), // From Pro Git Chapter 10.2 // https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_object_storage // output of: echo -n 'what is up, doc?' | git hash-object --stdin ("blob 16\0what is up, doc?", "bd9dbf5aae1a3862dd1526723246b20206e5fc37"), ("Hare is a cool language", "947feae3d0d65cc083c8f3e87858206e36aae908"), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", "05c8dd2605161bdd0b5d70f1f225f4dd69a01e3b"), ("'Life is too short to run proprietary software' - Bdale Garbee", "91ad4bdc2fbe2b731cbe8bf2958099391c7af3b8"), ("'The central enemy of reliability is complexity.' - Geer et al", "4b6eb2aa55ef59cc59be6d181c64141e7c1e5eab"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; @test fn sha1_1gb() void = { test::require("slow"); const input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; const expected = "7789f0c9ef7bfc40d93311143dfbe69e2017f592"; let sha = sha1(); for (let i = 0z; i < 16777216; i += 1) hash::write(&sha, strings::toutf8(input)); let sum: [SZ]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); if (shahex != expected) { fmt::errorfln("1GB vector: {} != {}", shahex, expected)!; abort(); }; }; hare-0.24.2/crypto/sha1/sha1.ha000066400000000000000000000117021464473310100160440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math; use endian; use hash; use io; // The size, in bytes, of a SHA-1 digest. export def SZ: size = 20; // The internal block size. export def BLOCKSZ: size = 64; def chunk: size = 64; def init0: u32 = 0x67452301; def init1: u32 = 0xEFCDAB89; def init2: u32 = 0x98BADCFE; def init3: u32 = 0x10325476; def init4: u32 = 0xC3D2E1F0; export type state = struct { hash::hash, h: [5]u32, x: [chunk]u8, nx: size, ln: size, }; const sha1_vtable: io::vtable = io::vtable { writer = &write, closer = &close, ... }; // Creates a [[hash::hash]] which computes a SHA-1 hash. Note that this // algorithm is no longer considered secure. Where possible, applications are // encouraged to use [[crypto::sha256::]] or [[crypto::sha512::]] instead. If // this function is used to hash sensitive information, the caller should call // [[hash::close]] to erase sensitive data from memory after use; if not, the // use of [[hash::close]] is optional. export fn sha1() state = { let sha = state { stream = &sha1_vtable, sum = &sum, reset = &reset, sz = SZ, bsz = BLOCKSZ, ... }; hash::reset(&sha); return sha; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { let h = st: *state; let b: []u8 = buf; let nn = len(buf); h.ln += nn; if (h.nx > 0) { // Compute how many bytes can be copied into h.x let r = len(h.x) - h.nx; let n = if (nn > r) r else nn; h.x[h.nx..h.nx + n] = b[..n]; h.nx += n; if (h.nx == chunk) { block(h, h.x[..]); h.nx = 0; }; b = b[n..]; }; if (len(b) >= chunk) { let n = len(b) & ~(chunk - 1); block(h, b[..n]); b = b[n..]; }; if (len(b) > 0) { let n = len(b); h.x[..n] = b[..n]; h.nx = n; }; return nn; }; fn reset(h: *hash::hash) void = { let h = h: *state; h.h[0] = init0; h.h[1] = init1; h.h[2] = init2; h.h[3] = init3; h.h[4] = init4; h.nx = 0; h.ln = 0; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; let copy = *h; let h = © defer hash::close(h); // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. let ln = h.ln; let tmp: [64]u8 = [0x80, 0...]; const pad = if ((ln % 64z) < 56z) 56z - ln % 64z else 64 + 56z - ln % 64z; write(h, tmp[..pad])!; // Length in bits. ln <<= 3; endian::beputu64(tmp, ln: u64); write(h, tmp[..8])!; assert(h.nx == 0); // Where we write the digest endian::beputu32(buf[0..], h.h[0]); endian::beputu32(buf[4..], h.h[1]); endian::beputu32(buf[8..], h.h[2]); endian::beputu32(buf[12..], h.h[3]); endian::beputu32(buf[16..], h.h[4]); }; def K0: u32 = 0x5A827999; def K1: u32 = 0x6ED9EBA1; def K2: u32 = 0x8F1BBCDC; def K3: u32 = 0xCA62C1D6; // A generic, pure Hare version of the SHA-1 block step fn block(h: *state, p: []u8) void = { let w: [16]u32 = [0...]; let h0 = h.h[0]; let h1 = h.h[1]; let h2 = h.h[2]; let h3 = h.h[3]; let h4 = h.h[4]; for (len(p) >= chunk) { for (let i = 0z; i < 16; i += 1) { let j = i * 4; w[i] = p[j]: u32 << 24 | p[j+1]: u32 << 16 | p[j+2]: u32 << 8 | p[j+3]: u32; }; let a = h0; let b = h1; let c = h2; let d = h3; let e = h4; // Each of the four 20-iteration rounds differs only in the // computation of f and the choice of Ki for i=0..5 let i = 0z; for (i < 16; i += 1) { let f = (b & c) | (~b & d); let t = math::rotl32(a, 5) + f + e + w[i & 0xf] + K0; // The order matters here! e = d; d = c; c = math::rotl32(b, 30); b = a; a = t; }; for (i < 20; i += 1) { let tmp = w[(i - 3) & 0xf] ^ w[(i - 8) & 0xf] ^ w[(i - 14) & 0xf] ^ w[i & 0xf]; w[i & 0xf] = tmp << 1 | tmp >> 31; let f = (b & c) | (~b & d); let t = math::rotl32(a, 5) + f + e + w[i & 0xf] + K0; e = d; d = c; c = math::rotl32(b, 30); b = a; a = t; }; for (i < 40; i += 1) { let tmp = w[(i - 3) & 0xf] ^ w[(i - 8) & 0xf] ^ w[(i - 14) & 0xf] ^ w[i & 0xf]; w[i & 0xf] = tmp << 1 | tmp >> 31; let f = b ^ c ^ d; let t = math::rotl32(a, 5) + f + e + w[i & 0xf] + K1; e = d; d = c; c = math::rotl32(b, 30); b = a; a = t; }; for (i < 60; i += 1) { let tmp = w[(i - 3) & 0xf] ^ w[(i - 8) & 0xf] ^ w[(i - 14) & 0xf] ^ w[i & 0xf]; w[i & 0xf] = tmp << 1 | tmp >> 31; let f = ((b | c) & d) | (b & c); let t = math::rotl32(a, 5) + f + e + w[i & 0xf] + K2; e = d; d = c; c = math::rotl32(b, 30); b = a; a = t; }; for (i < 80; i += 1) { let tmp = w[(i - 3) & 0xf] ^ w[(i - 8) & 0xf] ^ w[(i - 14) & 0xf] ^ w[i & 0xf]; w[i & 0xf] = tmp << 1 | tmp >> 31; let f = b ^ c ^ d; let t = math::rotl32(a, 5) + f + e + w[i & 0xf] + K3; e = d; d = c; c = math::rotl32(b, 30); b = a; a = t; }; h0 += a; h1 += b; h2 += c; h3 += d; h4 += e; p = p[chunk..]; }; h.h[0] = h0; h.h[1] = h1; h.h[2] = h2; h.h[3] = h3; h.h[4] = h4; }; fn close(stream: *io::stream) (void | io::error) = { let s = stream: *state; bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); bytes::zero(s.x); }; hare-0.24.2/crypto/sha256/000077500000000000000000000000001464473310100150515ustar00rootroot00000000000000hare-0.24.2/crypto/sha256/+test.ha000066400000000000000000000046461464473310100164270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::hex; use fmt; use hash; use strings; use test; @test fn sha256() void = { let sha = sha256(); const vectors = [ ("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), ("abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"), ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"), ("hello world", "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"), ("Hare is a cool language", "3f6fe31611580448e33af475ce0e66c7d55a156c6ec43c794225cc3084e04635"), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", "5cfa9eccaafa0a7d9d965e36b0a54cc1dd97dd1dff7e11d5e631bdea7f2ef328"), ("'Life is too short to run proprietary software' - Bdale Garbee", "79ecc26605c1fa5156821c5da9ebc959d8a46050ee49f47da57bf9391a558ceb"), ("'The central enemy of reliability is complexity.' - Geer et al", "80b2fd9ae9e9c2ccd801c923f5e3684d56c6b05edc2eb480634b0af10f9c810b"), ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", "10ebb04c1ddd55528d0c8db05a1f5fad6c04ebc20cfc4a53308f9a05a90cc438"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; @test fn sha256_1gb() void = { test::require("slow"); let sha = sha256(); const input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; const expected = "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e"; hash::reset(&sha); for (let i = 0z; i < 16777216; i += 1) { hash::write(&sha, strings::toutf8(input)); }; let sum: [SZ]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); if (shahex != expected) { fmt::errorfln("Biggo vector: {} != {}", shahex, expected)!; abort(); }; }; hare-0.24.2/crypto/sha256/sha256.ha000066400000000000000000000116041464473310100163750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math; use endian; use hash; use io; // The size, in bytes, of a SHA-256 digest. export def SZ: size = 32; // The internal block size. export def BLOCKSZ: size = 64; // This is loosely based on the Go implementation def init0: u32 = 0x6A09E667; def init1: u32 = 0xBB67AE85; def init2: u32 = 0x3C6EF372; def init3: u32 = 0xA54FF53A; def init4: u32 = 0x510E527F; def init5: u32 = 0x9B05688C; def init6: u32 = 0x1F83D9AB; def init7: u32 = 0x5BE0CD19; const k: [_]u32 = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; export type state = struct { hash::hash, h: [8]u32, x: [BLOCKSZ]u8, nx: size, ln: size, }; const sha256_vtable: io::vtable = io::vtable { writer = &write, closer = &close, ... }; // Creates a [[hash::hash]] which computes a SHA-256 hash. If this function is // used to hash sensitive information, the caller should call [[hash::close]] to // erase sensitive data from memory after use; if not, the use of // [[hash::close]] is optional. export fn sha256() state = { let sha = state { stream = &sha256_vtable, sum = &sum, reset = &reset, sz = SZ, bsz = BLOCKSZ, ... }; hash::reset(&sha); return sha; }; fn reset(h: *hash::hash) void = { let h = h: *state; h.h[0] = init0; h.h[1] = init1; h.h[2] = init2; h.h[3] = init3; h.h[4] = init4; h.h[5] = init5; h.h[6] = init6; h.h[7] = init7; h.nx = 0; h.ln = 0; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { let h = st: *state; let b: []u8 = buf; let n = len(b); h.ln += n; if (h.nx > 0) { let n = if (len(b) > len(h.x) - h.nx) { yield len(h.x) - h.nx; } else len(b); h.x[h.nx..h.nx + n] = b[..n]; h.nx += n; if (h.nx == BLOCKSZ) { block(h, h.x[..]); h.nx = 0; }; b = b[n..]; }; if (len(b) >= BLOCKSZ) { let n = len(b) & ~(BLOCKSZ - 1); block(h, b[..n]); b = b[n..]; }; if (len(b) > 0) { let n = len(b); h.x[..n] = b[..n]; h.nx = n; }; return n; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; let copy = *h; let h = © defer hash::close(h); // Add padding let ln = h.ln; let tmp: [64]u8 = [0...]; tmp[0] = 0x80; const n = if ((ln % 64z) < 56z) 56z - ln % 64z else 64z + 56z - ln % 64z; write(h, tmp[..n])!; ln <<= 3; endian::beputu64(tmp, ln: u64); write(h, tmp[..8])!; assert(h.nx == 0); endian::beputu32(buf[0..], h.h[0]); endian::beputu32(buf[4..], h.h[1]); endian::beputu32(buf[8..], h.h[2]); endian::beputu32(buf[12..], h.h[3]); endian::beputu32(buf[16..], h.h[4]); endian::beputu32(buf[20..], h.h[5]); endian::beputu32(buf[24..], h.h[6]); endian::beputu32(buf[28..], h.h[7]); }; // TODO: Rewrite me in assembly fn block(h: *state, buf: []u8) void = { let w: [64]u32 = [0...]; let h0 = h.h[0], h1 = h.h[1], h2 = h.h[2], h3 = h.h[3], h4 = h.h[4], h5 = h.h[5], h6 = h.h[6], h7 = h.h[7]; for (len(buf) >= BLOCKSZ) { for (let i = 0; i < 16; i += 1) { let j = i * 4; w[i] = buf[j]: u32 << 24 | buf[j+1]: u32 << 16 | buf[j+2]: u32 << 8 | buf[j+3]: u32; }; for (let i = 16; i < 64; i += 1) { let v1 = w[i - 2]; let t1 = (math::rotr32(v1, 17)) ^ (math::rotr32(v1, 19)) ^ (v1 >> 10); let v2 = w[i - 15]; let t2 = (math::rotr32(v2, 7)) ^ (math::rotr32(v2, 18)) ^ (v2 >> 3); w[i] = t1 + w[i - 7] + t2 + w[i - 16]; }; let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7; for (let i = 0; i < 64; i += 1) { let t1 = h + ((math::rotr32(e, 6)) ^ (math::rotr32(e, 11)) ^ (math::rotr32(e, 25))) + ((e & f) ^ (~e & g)) + k[i] + w[i]; let t2 = ((math::rotr32(a, 2)) ^ (math::rotr32(a, 13)) ^ (math::rotr32(a, 22))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; }; h0 += a; h1 += b; h2 += c; h3 += d; h4 += e; h5 += f; h6 += g; h7 += h; buf = buf[BLOCKSZ..]; }; h.h[0] = h0; h.h[1] = h1; h.h[2] = h2; h.h[3] = h3; h.h[4] = h4; h.h[5] = h5; h.h[6] = h6; h.h[7] = h7; }; fn close(stream: *io::stream) (void | io::error) = { let s = stream: *state; bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); bytes::zero(s.x); }; hare-0.24.2/crypto/sha512/000077500000000000000000000000001464473310100150445ustar00rootroot00000000000000hare-0.24.2/crypto/sha512/+test.ha000066400000000000000000000105341464473310100164130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::hex; use fmt; use hash; use strings; @test fn sha512() void = { let sha = sha512(); const vectors = [ ("abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"), ("", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"), ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", "f3d99b807bd734bcec25d64109ff5d78405d5b76a34332270c7062a4c9e6d1711ee6ed230e688fef257cf19e94e0163671c99f4c785d50e8adddef9f37060023"), ("'Life is too short to run proprietary software' - Bdale Garbee", "b1eeae774232d4ba74410e7d951fc3e7de165dbc9498babb243e4a87983595a79f5970ed67ebf2e275059928b4f0309926f85dad45126875530e8d2350a93a2b"), ("'The central enemy of reliability is complexity.' - Geer et al", "7eee0bc24a069679eb272aeb698136f8e3bca79b4220c70bf091607b78358fe4b3621a9e28295d73157806a20470a17cc21b9a3eefa7408c6cf1f288d1403a0d"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; @test fn sha512_224() void = { let sha = sha512_224(); const vectors = [ ("", "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"), ("abc", "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9") ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ224]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; @test fn sha512_256() void = { let sha = sha512_256(); const vectors = [ ("", "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"), ("abc", "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ256]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; @test fn sha384() void = { let sha = sha384(); const vectors = [ ("", "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"), ("abc", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; hash::reset(&sha); hash::write(&sha, strings::toutf8(vector.0)); let sum: [SZ384]u8 = [0...]; hash::sum(&sha, sum); let shahex = hex::encodestr(sum); defer free(shahex); if (shahex != vector.1) { fmt::errorfln("Vector {}: {} != {}", i, shahex, vector.1)!; abort(); }; }; }; hare-0.24.2/crypto/sha512/README000066400000000000000000000001721464473310100157240ustar00rootroot00000000000000The sha512 module implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 hash algorithms as defined in FIPS 180-4. hare-0.24.2/crypto/sha512/sha512.ha000066400000000000000000000223721464473310100163670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::math; use endian; use hash; use io; export type variant = enum { SHA384, SHA512, SHA512_224, SHA512_256, }; // The size, in bytes, of a SHA-512 checksum. export def SZ: size = 64; // The size, in bytes, of a SHA-512/224 checksum. export def SZ224: size = 28; // The size, in bytes, of a SHA-512/256 checksum. export def SZ256: size = 32; // The size, in bytes, of a SHA-384 checksum. export def SZ384: size = 48; // The internal block size. export def BLOCKSZ: size = 128; def chunk: size = BLOCKSZ; def init0: u64 = 0x6a09e667f3bcc908; def init1: u64 = 0xbb67ae8584caa73b; def init2: u64 = 0x3c6ef372fe94f82b; def init3: u64 = 0xa54ff53a5f1d36f1; def init4: u64 = 0x510e527fade682d1; def init5: u64 = 0x9b05688c2b3e6c1f; def init6: u64 = 0x1f83d9abfb41bd6b; def init7: u64 = 0x5be0cd19137e2179; def init0_224: u64 = 0x8c3d37c819544da2; def init1_224: u64 = 0x73e1996689dcd4d6; def init2_224: u64 = 0x1dfab7ae32ff9c82; def init3_224: u64 = 0x679dd514582f9fcf; def init4_224: u64 = 0x0f6d2b697bd44da8; def init5_224: u64 = 0x77e36f7304c48942; def init6_224: u64 = 0x3f9d85a86a1d36c8; def init7_224: u64 = 0x1112e6ad91d692a1; def init0_256: u64 = 0x22312194fc2bf72c; def init1_256: u64 = 0x9f555fa3c84c64c2; def init2_256: u64 = 0x2393b86b6f53b151; def init3_256: u64 = 0x963877195940eabd; def init4_256: u64 = 0x96283ee2a88effe3; def init5_256: u64 = 0xbe5e1e2553863992; def init6_256: u64 = 0x2b0199fc2c85b8aa; def init7_256: u64 = 0x0eb72ddc81c52ca2; def init0_384: u64 = 0xcbbb9d5dc1059ed8; def init1_384: u64 = 0x629a292a367cd507; def init2_384: u64 = 0x9159015a3070dd17; def init3_384: u64 = 0x152fecd8f70e5939; def init4_384: u64 = 0x67332667ffc00b31; def init5_384: u64 = 0x8eb44a8768581511; def init6_384: u64 = 0xdb0c2e0d64f98fa7; def init7_384: u64 = 0x47b5481dbefa4fa4; export type digest = struct { hash::hash, h: [8]u64, x: [chunk]u8, nx: size, ln: size, var: variant, }; // Creates a [[hash::hash]] which computes a SHA-512 hash. If this function is // used to hash sensitive information, the caller should call [[hash::close]] to // erase sensitive data from memory after use; if not, the use of // [[hash::close]] is optional. export fn sha512() digest = init(variant::SHA512, SZ); // Creates a [[hash::hash]] which computes a SHA-512/224 hash. If this function // is used to hash sensitive information, the caller should call [[hash::close]] // to erase sensitive data from memory after use; if not, the use of // [[hash::close]] is optional. export fn sha512_224() digest = init(variant::SHA512_224, SZ224); // Creates a [[hash::hash]] which computes a SHA-512/256 hash. If this function // is used to hash sensitive information, the caller should call [[hash::close]] // to erase sensitive data from memory after use; if not, the use of // [[hash::close]] is optional. export fn sha512_256() digest = init(variant::SHA512_256, SZ256); // Creates a [[hash::hash]] which computes a SHA-384 hash. If this function is // used to hash sensitive information, the caller should call [[hash::close]] to // erase sensitive data from memory after use; if not, the use of // [[hash::close]] is optional. export fn sha384() digest = init(variant::SHA384, SZ384); const sha512_vtable: io::vtable = io::vtable { writer = &write, closer = &close, ... }; // Internal initialization function fn init(var: variant, sz: size) digest = { let sha = digest { stream = &sha512_vtable, sum = &sum, reset = &reset, sz = sz, bsz = chunk, var = var, ... }; hash::reset(&sha); return sha; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { let h = st: *digest; let b: []u8 = buf; let nn = len(buf); h.ln += nn; if (h.nx > 0) { // Compute how many bytes can be copied into h.x let r = len(h.x) - h.nx; let n = if (nn > r) r else nn; h.x[h.nx..h.nx + n] = b[..n]; h.nx += n; if (h.nx == chunk) { block(h, h.x[..]); h.nx = 0; }; b = b[n..]; }; if (len(b) >= chunk) { let n = len(b) & ~(chunk - 1); block(h, b[..n]); b = b[n..]; }; if (len(b) > 0) { let n = len(b); h.x[..n] = b[..]; h.nx = n; }; return nn; }; fn sum(h: *hash::hash, buf: []u8) void = { let d = h: *digest; let copy = *d; let d = © defer hash::close(d); // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128 let ln = d.ln; let tmp: [chunk]u8 = [0x80, 0...]; if ((ln % 128) < 112) { const n = 112 - (ln % 128); write(d, tmp[..n])!; } else { const n = 128 + 112 - (ln % 128); write(d, tmp[..n])!; }; // Length in bits ln <<= 3; endian::beputu64(tmp, 0u64); // upper 64 bits are always zero endian::beputu64(tmp[8..], ln : u64); write(d, tmp[..16])!; assert(d.nx == 0); let dig: [SZ]u8 = [0...]; endian::beputu64(dig[0..], d.h[0]); endian::beputu64(dig[8..], d.h[1]); endian::beputu64(dig[16..], d.h[2]); endian::beputu64(dig[24..], d.h[3]); endian::beputu64(dig[32..], d.h[4]); endian::beputu64(dig[40..], d.h[5]); if (d.var != variant::SHA384) { endian::beputu64(dig[48..], d.h[6]); endian::beputu64(dig[56..], d.h[7]); }; // We only copy the necessary bytes from fixed-size array into the // returned slice. The size is already found in the inner hash struct. buf[..d.sz] = dig[..d.sz]; }; fn reset(h: *hash::hash) void = { let d = h: *digest; switch (d.var) { case variant::SHA384 => d.h[0] = init0_384; d.h[1] = init1_384; d.h[2] = init2_384; d.h[3] = init3_384; d.h[4] = init4_384; d.h[5] = init5_384; d.h[6] = init6_384; d.h[7] = init7_384; case variant::SHA512_224 => d.h[0] = init0_224; d.h[1] = init1_224; d.h[2] = init2_224; d.h[3] = init3_224; d.h[4] = init4_224; d.h[5] = init5_224; d.h[6] = init6_224; d.h[7] = init7_224; case variant::SHA512_256 => d.h[0] = init0_256; d.h[1] = init1_256; d.h[2] = init2_256; d.h[3] = init3_256; d.h[4] = init4_256; d.h[5] = init5_256; d.h[6] = init6_256; d.h[7] = init7_256; case => d.h[0] = init0; d.h[1] = init1; d.h[2] = init2; d.h[3] = init3; d.h[4] = init4; d.h[5] = init5; d.h[6] = init6; d.h[7] = init7; }; d.nx = 0; d.ln = 0; }; const k: [_]u64 = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, ]; fn block(h: *digest, p: []u8) void = { let w: [80]u64 = [0...]; let h0 = h.h[0]; let h1 = h.h[1]; let h2 = h.h[2]; let h3 = h.h[3]; let h4 = h.h[4]; let h5 = h.h[5]; let h6 = h.h[6]; let h7 = h.h[7]; for (len(p) >= chunk; p = p[chunk..]) { for (let i = 0z; i < 16; i += 1) { let j = i * 8; w[i] = p[j]: u64 << 56 | p[j+1]: u64 << 48 | p[j+2]: u64 << 40 | p[j+3]: u64 << 32 | p[j+4]: u64 << 24 | p[j+5]: u64 << 16 | p[j+6]: u64 << 8 | p[j+7]: u64; }; for (let i = 16z; i < 80; i += 1) { let v1 = w[i - 2]; let t1 = math::rotr64(v1, 19) ^ math::rotr64(v1, 61) ^ (v1 >> 6); let v2 = w[i - 15]; let t2 = math::rotr64(v2, 1) ^ math::rotr64(v2, 8) ^ (v2 >> 7); w[i] = t1 + w[i - 7] + t2 + w[i - 16]; }; let a = h0; let b = h1; let c = h2; let d = h3; let e = h4; let f = h5; let g = h6; let h = h7; for (let i = 0z; i < 80; i += 1) { let t1 = h + (math::rotr64(e, 14) ^ math::rotr64(e, 18) ^ math::rotr64(e, 41)) + ((e & f) ^ (~e & g)) + k[i] + w[i]; let t2 = (math::rotr64(a, 28) ^ math::rotr64(a, 34) ^ math::rotr64(a, 39)) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; }; h0 += a; h1 += b; h2 += c; h3 += d; h4 += e; h5 += f; h6 += g; h7 += h; }; h.h[0] = h0; h.h[1] = h1; h.h[2] = h2; h.h[3] = h3; h.h[4] = h4; h.h[5] = h5; h.h[6] = h6; h.h[7] = h7; }; fn close(stream: *io::stream) (void | io::error) = { let s = stream: *digest; bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]); bytes::zero(s.x); }; hare-0.24.2/crypto/x25519/000077500000000000000000000000001464473310100147165ustar00rootroot00000000000000hare-0.24.2/crypto/x25519/+test.ha000066400000000000000000000030771464473310100162710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::random; @test fn sample() void = { let seed: [32]u8 = [0xff...]; let priv: key = [0...]; priv[31] = 0xbf; newkey(&priv, &seed); let pub: key = [0...]; pubkey(&pub, &priv); const pexpected: key = [ 0x84, 0x7c, 0x0d, 0x2c, 0x37, 0x52, 0x34, 0xf3, 0x65, 0xe6, 0x60, 0x95, 0x51, 0x87, 0xa3, 0x73, 0x5a, 0x0f, 0x76, 0x13, 0xd1, 0x60, 0x9d, 0x3a, 0x6a, 0x4d, 0x8c, 0x53, 0xae, 0xaa, 0x5a, 0x22, ]; assert(bytes::equal(pexpected, pub)); const otherpub: key = [ 0x28, 0x18, 0x84, 0xe0, 0x0f, 0xae, 0x8a, 0x33, 0x75, 0x05, 0xbf, 0x38, 0x15, 0x2a, 0x97, 0xc0, 0x20, 0x4a, 0x8c, 0x1d, 0x4c, 0xfa, 0x2d, 0x2b, 0x12, 0x99, 0x80, 0xed, 0xe7, 0x32, 0xaf, 0x0d, ]; const expected: key = [ 0x07, 0x4a, 0xaf, 0x3c, 0xa3, 0x87, 0xd5, 0xa3, 0x71, 0x25, 0x9f, 0x50, 0xb3, 0xf0, 0xa1, 0xe9, 0x63, 0x6b, 0x18, 0x1d, 0x5e, 0x4e, 0x6e, 0xb3, 0x1a, 0xe9, 0xda, 0x01, 0x05, 0x4a, 0x8c, 0x3b, ]; let shared: key = [0...]; derive(&shared, &priv, &otherpub); assert(bytes::equal(expected, shared)); }; @test fn random() void = { let seed: [32]u8 = [0...]; let priv1: key = [0...]; let priv2: key = [0...]; let pub1: key = [0...]; let pub2: key = [0...]; let shared1: key = [0...]; let shared2: key = [0...]; random::buffer(seed); newkey(&priv1, &seed); random::buffer(seed); newkey(&priv2, &seed); pubkey(&pub1, &priv1); pubkey(&pub2, &priv2); derive(&shared1, &priv1, &pub2); derive(&shared2, &priv2, &pub1); assert(bytes::equal(&shared1, &shared2)); }; hare-0.24.2/crypto/x25519/README000066400000000000000000000015321464473310100155770ustar00rootroot00000000000000The crypto::x25519 module provides functions to generate key pairs and to derive shared keys between them, based on curve25519. A key pair is created by generating a private key with [[newkey]] and deriving the public key with [[pubkey]]. A shared key can be found by using [[derive]]. Do not use the same secret key for both key exchanges and signatures. The public keys are different and revealing both may leak information. This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level [[crypto::]] module. Be advised that Hare's cryptography implementations have not been audited. hare-0.24.2/crypto/x25519/x25519.ha000066400000000000000000000025561464473310100161150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::curve25519; // Type for private, public or shared keys. export type key = [KEYSZ]u8; // The size of a x25519 key. export def KEYSZ: size = 32; // The size of a x25519 key seed. export def SEEDSZ: size = 32; // Initializes a new x25519 private key from the provided 32-byte seed, // which should be generated with [[crypto::random::]]. export fn newkey(priv: []u8, seed: []u8) void = { assert(len(priv) == KEYSZ); assert(len(seed) == SEEDSZ); priv[..] = seed[..]; curve25519::clamp(priv); }; // Derives the public key from a private key prepared with [[newkey]], // writing it to the 'pub' parameter. export fn pubkey(pub: []u8, priv: const []u8) void = { assert(len(priv) == KEYSZ); assert(len(pub) == KEYSZ); curve25519::scalarmult_base(pub, priv); }; // Derives a 32-byte shared key from the private key of one key-pair and // the public key of a second key-pair. export fn derive(shared: []u8, priv: []u8, pub: []u8) void = { assert(len(shared) == KEYSZ); assert(len(priv) == KEYSZ); assert(len(pub) == KEYSZ); curve25519::x25519(shared, priv, pub); // TODO figure out if checking for low order points is required // https://github.com/jedisct1/libsodium/blob/cec56d867f741e66f78b9fde37d9081643599a2a/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L90 }; hare-0.24.2/debug/000077500000000000000000000000001464473310100136075ustar00rootroot00000000000000hare-0.24.2/debug/+aarch64/000077500000000000000000000000001464473310100151125ustar00rootroot00000000000000hare-0.24.2/debug/+aarch64/getfp.s000066400000000000000000000003011464473310100163750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors .section ".text.debug.getfp","ax" .global debug.getfp .type debug.getfp,@function debug.getfp: mov x0, x29 ret hare-0.24.2/debug/+aarch64/walk.ha000066400000000000000000000017061464473310100163660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn getfp() *stackframe; // Details for a stack frame. Contents are architecture-specific. export type stackframe = struct { fp: nullable *stackframe, lr: uintptr, }; // Returns the caller's stack frame. Call [[next]] to walk the stack. export fn walk() stackframe = *getfp(); // Returns the next stack frame walking the stack. export fn next(frame: stackframe) (stackframe | done) = { match (frame.fp) { case null => return done; case let next: *stackframe => if (!isaddrmapped(next)) { return done; }; if (next.fp == null) { return done; }; return *next; }; }; // Return the program counter address for the given stack frame. export fn frame_pc(frame: stackframe) uintptr = frame.lr; // Implementation detail, constructs a synthetic stack frame. fn mkframe(next: *stackframe, ip: uintptr) stackframe = { return stackframe { fp = next, lr = ip, }; }; hare-0.24.2/debug/+freebsd/000077500000000000000000000000001464473310100152745ustar00rootroot00000000000000hare-0.24.2/debug/+freebsd/+aarch64/000077500000000000000000000000001464473310100165775ustar00rootroot00000000000000hare-0.24.2/debug/+freebsd/+aarch64/ucontext.ha000066400000000000000000000013701464473310100207630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; def AARCH64_FP: uint = 29; // fp is an alias of r29 def AARCH64_LR: uint = 30; // lr is an alias of r30 // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_gpregs.gp_sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_gpregs.gp_elr: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.mc_gpregs.gp_x[AARCH64_FP]: uintptr: *stackframe); }; hare-0.24.2/debug/+freebsd/+riscv64/000077500000000000000000000000001464473310100166475ustar00rootroot00000000000000hare-0.24.2/debug/+freebsd/+riscv64/ucontext.ha000066400000000000000000000012071464473310100210320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_gpregs.gp_sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_gpregs.gp_sepc: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.mc_gpregs.gp_s[0]: uintptr: *stackframe); }; hare-0.24.2/debug/+freebsd/+x86_64/000077500000000000000000000000001464473310100163055ustar00rootroot00000000000000hare-0.24.2/debug/+freebsd/+x86_64/ucontext.ha000066400000000000000000000011501464473310100204650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_rsp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_rip: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.mc_rbp: uintptr: *stackframe); }; hare-0.24.2/debug/+freebsd/translate.ha000066400000000000000000000004441464473310100176050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Tries to translate a pointer into an ELF address of the currently running // binary. export fn translate(ptr: uintptr) (uintptr | void) = { // TODO FreeBSD (will break when enabling PIE code) return ptr; }; hare-0.24.2/debug/+linux/000077500000000000000000000000001464473310100150215ustar00rootroot00000000000000hare-0.24.2/debug/+linux/+aarch64/000077500000000000000000000000001464473310100163245ustar00rootroot00000000000000hare-0.24.2/debug/+linux/+aarch64/ucontext.ha000066400000000000000000000013231464473310100205060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; def AARCH64_FP: uint = 29; // fp is an alias of r29 def AARCH64_LR: uint = 30; // lr is an alias of r30 // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.pc: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.regs[AARCH64_FP]: uintptr: *stackframe); }; hare-0.24.2/debug/+linux/+riscv64/000077500000000000000000000000001464473310100163745ustar00rootroot00000000000000hare-0.24.2/debug/+linux/+riscv64/ucontext.ha000066400000000000000000000011641464473310100205610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.sc_regs.sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.sc_regs.pc: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.sc_regs.s0: uintptr: *stackframe); }; hare-0.24.2/debug/+linux/+x86_64/000077500000000000000000000000001464473310100160325ustar00rootroot00000000000000hare-0.24.2/debug/+linux/+x86_64/ucontext.ha000066400000000000000000000011341464473310100202140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.ip: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.bp: uintptr: *stackframe); }; hare-0.24.2/debug/+linux/translate.ha000066400000000000000000000004421464473310100173300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Tries to translate a pointer into an ELF address of the currently running // binary. export fn translate(ptr: uintptr) (uintptr | void) = { // TODO Linux (will break when enabling PIE code) return ptr; }; hare-0.24.2/debug/+netbsd/000077500000000000000000000000001464473310100151415ustar00rootroot00000000000000hare-0.24.2/debug/+netbsd/+x86_64/000077500000000000000000000000001464473310100161525ustar00rootroot00000000000000hare-0.24.2/debug/+netbsd/+x86_64/ucontext.ha000066400000000000000000000011501464473310100203320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_rsp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.uc_mcontext.mc_rip: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.uc_mcontext.mc_rbp: uintptr: *stackframe); }; hare-0.24.2/debug/+netbsd/translate.ha000066400000000000000000000004431464473310100174510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Tries to translate a pointer into an ELF address of the currently running // binary. export fn translate(ptr: uintptr) (uintptr | void) = { // TODO NetBSD (will break when enabling PIE code) return ptr; }; hare-0.24.2/debug/+openbsd/000077500000000000000000000000001464473310100153145ustar00rootroot00000000000000hare-0.24.2/debug/+openbsd/+aarch64/000077500000000000000000000000001464473310100166175ustar00rootroot00000000000000hare-0.24.2/debug/+openbsd/+aarch64/ucontext.ha000066400000000000000000000012661464473310100210070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; def AARCH64_FP: uint = 29; // fp is an alias of r29 def AARCH64_LR: uint = 30; // lr is an alias of r30 // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_elr: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.sc_x[AARCH64_FP]: uintptr: *stackframe); }; hare-0.24.2/debug/+openbsd/+riscv64/000077500000000000000000000000001464473310100166675ustar00rootroot00000000000000hare-0.24.2/debug/+openbsd/+riscv64/ucontext.ha000066400000000000000000000011051464473310100210470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_sp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_sepc: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.sc_s[0]: uintptr: *stackframe); }; hare-0.24.2/debug/+openbsd/+x86_64/000077500000000000000000000000001464473310100163255ustar00rootroot00000000000000hare-0.24.2/debug/+openbsd/+x86_64/ucontext.ha000066400000000000000000000011041464473310100205040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Returns the stack pointer from a ucontext. fn uctx_sp(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_rsp: uintptr; }; // Returns the instruction pointer from a ucontext. fn uctx_ip(uctx: *opaque) uintptr = { const uctx = uctx: *rt::ucontext; return uctx.sc_rip: uintptr; }; // Returns the current call frame from a ucontext. fn uctx_frame(uctx: *opaque) stackframe = { const uctx = uctx: *rt::ucontext; return *(uctx.sc_rbp: uintptr: *stackframe); }; hare-0.24.2/debug/+openbsd/translate.ha000066400000000000000000000015271464473310100176300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Tries to translate a pointer into an ELF address of the currently running // binary. export fn translate(ptr: uintptr) (uintptr | void) = { let dl_info = rt::dl_info { ... }; // In order to avoid translating symbols in shared libaries and // producing invalid results, use the current function (which should be // in the main binary) to get the base image address. // // Theoretically, it should be possible to get symbol names from shared // libaries. You would have to load the ELF shared libary at the path // [[dl_info.fname]] as an ELF image and resolve the symbol name // from there. Then you could do "s/&translate/ptr" below. const ret = rt::dladdr(&translate: *opaque, &dl_info); if (ret != 0) { return ptr - dl_info.fbase: uintptr; }; }; hare-0.24.2/debug/+riscv64/000077500000000000000000000000001464473310100151625ustar00rootroot00000000000000hare-0.24.2/debug/+riscv64/getfp.s000066400000000000000000000002751464473310100164570ustar00rootroot00000000000000# SPDX-License-Identifier: MPL-2.0 # (c) Hare authors .section ".text.debug.getfp","ax" .global debug.getfp .type debug.getfp,@function debug.getfp: mv a0, fp ret hare-0.24.2/debug/+riscv64/walk.ha000066400000000000000000000017061464473310100164360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn getfp() *stackframe; // Details for a stack frame. Contents are architecture-specific. export type stackframe = struct { fp: nullable *stackframe, ra: uintptr, }; // Returns the caller's stack frame. Call [[next]] to walk the stack. export fn walk() stackframe = *getfp(); // Returns the next stack frame walking the stack. export fn next(frame: stackframe) (stackframe | done) = { match (frame.fp) { case null => return done; case let next: *stackframe => if (!isaddrmapped(next)) { return done; }; if (next.fp == null) { return done; }; return *next; }; }; // Return the program counter address for the given stack frame. export fn frame_pc(frame: stackframe) uintptr = frame.ra; // Implementation detail, constructs a synthetic stack frame. fn mkframe(next: *stackframe, ip: uintptr) stackframe = { return stackframe { fp = next, ra = ip, }; }; hare-0.24.2/debug/+x86_64/000077500000000000000000000000001464473310100146205ustar00rootroot00000000000000hare-0.24.2/debug/+x86_64/getfp.s000066400000000000000000000003151464473310100161100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors .section ".text.debug.getfp","ax" .global debug.getfp .type debug.getfp,@function debug.getfp: endbr64 movq %rbp,%rax ret hare-0.24.2/debug/+x86_64/walk.ha000066400000000000000000000017061464473310100160740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn getfp() *stackframe; // Details for a stack frame. Contents are architecture-specific. export type stackframe = struct { fp: nullable *stackframe, ip: uintptr, }; // Returns the caller's stack frame. Call [[next]] to walk the stack. export fn walk() stackframe = *getfp(); // Returns the next stack frame walking the stack. export fn next(frame: stackframe) (stackframe | done) = { match (frame.fp) { case null => return done; case let next: *stackframe => if (!isaddrmapped(next)) { return done; }; if (next.fp == null) { return done; }; return *next; }; }; // Return the program counter address for the given stack frame. export fn frame_pc(frame: stackframe) uintptr = frame.ip; // Implementation detail, constructs a synthetic stack frame. fn mkframe(next: *stackframe, ip: uintptr) stackframe = { return stackframe { fp = next, ip = ip, }; }; hare-0.24.2/debug/README000066400000000000000000000016101464473310100144650ustar00rootroot00000000000000The debug module implements various runtime debugging services. It is enabled by default when you build programs in debug mode (you can disable this by building in release mode with the -R flag to hare(1)). It provides detailed backtraces in various error conditions, including: - Assertion failures - Built-in assertions (e.g. for the "as" operator) - Segmentation faults - Arithmetic exceptions (e.g. divide by zero) - Bus errors - Stack overflows In order to accomplish this, the debug module does some logic on @init which rigs up [[rt::]] with debugging hooks and installs the relevant signal handlers globally. If you set your own signal handlers for terminating signals (e.g. SIGFPE) that the debug module handles, they will override the debug hooks. This module may also be used explicitly to inspect details of the running program -- for instance, you can trace the call stack with [[walk]]. hare-0.24.2/debug/abort.ha000066400000000000000000000015411464473310100152310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use fmt; use rt; @init fn init_abort() void = { rt::onabort(&debug_abort); }; // Note: take care not to get into an abort loop when working on this code fn debug_abort( path: *str, line: u64, col: u64, msg: str, ) never = { fmt::errorfln("Abort: {}:{}:{}: {}", *path, line, col, msg): void; const self = match (image::self()) { case let img: image::image => yield img; case => halt(); }; defer image::close(&self); let frame = walk(); // Skip rt::abort and debug::debug_abort for (let skip = 2; skip > 0; skip -= 1) { match (next(frame)) { case let next: stackframe => frame = next; case done => halt(); }; }; backtrace(&self, frame); halt(); }; fn halt() never = { rt::kill(rt::getpid(), rt::SIGABRT): void; for (true) void; }; hare-0.24.2/debug/altstack.s000066400000000000000000000001051464473310100155750ustar00rootroot00000000000000.bss .globl debug.altstack .balign 16 debug.altstack: .balign 16384 hare-0.24.2/debug/backtrace.ha000066400000000000000000000074241464473310100160470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use debug::dwarf; use debug::image; use fmt; use format::elf; use fs; use io; use os; use time; def MAX_FRAMES_TOP: size = 16z; def MAX_FRAMES_BOTTOM: size = 16z; def MAX_FRAMES: size = MAX_FRAMES_TOP + MAX_FRAMES_BOTTOM; fn backtrace(self: *image::image, frame: stackframe) void = { let orig = frame; let nframe = 1z; for (true; nframe += 1) { match (next(frame)) { case let next: stackframe => frame = next; case done => break; }; }; frame = orig; const st = match (os::fstat(self.fd)) { case let st: fs::filestat => yield st; case fs::error => yield fs::filestat { mask = 0, ... }; }; static let seen: [MAX_FRAMES]uintptr = [0: uintptr...]; let seen = seen[..0]; for (let i = 0z; i < nframe; i += 1) { if (i < MAX_FRAMES_TOP || i > nframe - MAX_FRAMES_BOTTOM) { printframe(self, &seen, &st, frame); }; if (i == MAX_FRAMES_TOP && nframe > MAX_FRAMES) { fmt::errorfln("\t({} additional frames omitted)", nframe - MAX_FRAMES): void; }; match (next(frame)) { case let next: stackframe => frame = next; case done => break; }; }; }; fn printframe( self: *image::image, seen: *[]uintptr, imgstat: *fs::filestat, frame: stackframe, ) void = { const pc = frame_pc(frame); // Try to translate the address match (translate(pc: uintptr)) { case let ptr: uintptr => pc = ptr; case => void; }; const sym = match (symbol_byaddr(self, pc)) { case let sym: elf::sym64 => yield sym; case => fmt::errorfln("(unknown) [0x{:x}]", pc): void; return; }; const name = match (symbol_name(self, &sym)) { case let name: const str => yield name; case => fmt::errorfln("(unknown) [0x{:x}]", pc): void; return; }; // Look for DWARF line numbers, if possible const (path, line, col) = match (dwarf::addr_to_line(self, pc)) { case (void | io::error) => // No line number available, print what we've got fmt::errorfln("{}+0x{:x} [0x{:x}]", symname_to_ident(name), pc - sym.st_value: uintptr, pc): void; return; case let tuple: (const str, uint, uint) => yield tuple; }; const file = match (os::open(path)) { case fs::error => printframe_with_symbol(&sym, name, path, (line, col), pc); return; case let file: io::file => yield file; }; defer io::close(file): void; static let linebuf: [1024]u8 = [0...]; const scan = bufio::newscanner_static(file, linebuf); let context = ""; for (let i = 0u; i < line; i += 1) { match (bufio::scan_line(&scan)) { case let s: const str => context = s; case => printframe_with_symbol(&sym, name, path, (line, col), pc); return; }; }; fmt::errorf("{}:{}:{} {}+0x{:x} [0x{:x}]", path, line, col, symname_to_ident(name), pc - sym.st_value: uintptr, pc): void; // Skip context on frames we've already printed for (let i = 0z; i < len(seen); i += 1) { if (seen[i] == pc) { fmt::errorfln(" (already shown)"): void; return; }; }; static append(seen, pc); fmt::errorln(): void; if (imgstat.mask & fs::stat_mask::MTIME != 0) { match (os::fstat(file)) { case let st: fs::filestat => if (st.mask & fs::stat_mask::MTIME == 0) yield; if (time::compare(st.mtime, imgstat.mtime) == 1) { fmt::errorln("* Warning: file was modified after executable was built"): void; }; case => void; }; }; fmt::errorfln("| {}", context): void; if (col != 0) { fmt::errorf(" "): void; for (let i = 1u; i < col - 1; i += 1) { fmt::errorf(" "): void; }; fmt::errorf("^"): void; }; fmt::errorln(): void; }; fn printframe_with_symbol( sym: *elf::sym64, name: str, path: str, loc: (uint, uint), pc: uintptr, ) void = { fmt::errorfln("{}:{}:{} {}+0x{:x} [0x{:x}]", path, loc.0, loc.1, symname_to_ident(name), pc - sym.st_value: uintptr, pc): void; fmt::errorln(): void; }; hare-0.24.2/debug/constants.ha000066400000000000000000000003441464473310100161360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Maximum length of a symbol name, including nul terminator, with the // statically allocated debug data structures. def MAX_SYMNAME: size = 1024; hare-0.24.2/debug/dwarf/000077500000000000000000000000001464473310100147125ustar00rootroot00000000000000hare-0.24.2/debug/dwarf/README000066400000000000000000000004401464473310100155700ustar00rootroot00000000000000debug::dwarf includes an implementation of the DWARF Debugging Information Format. The implementation is incomplete and, while it may be useful to third-parties, is mainly designed to support the needs of [[debug::]]'s runtime debugging features. This module implements DWARF version 4. hare-0.24.2/debug/dwarf/abbrev.ha000066400000000000000000000047071464473310100164750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use errors; use format::elf; use io; export type abbrev_table = struct { items: []abbrev, }; // A single abbreviated tag from a .debug_abbrev section. export type abbrev = struct { code: u64, tag: u32, has_children: bool, fields: []afield, }; // A field in a .debug_abbrev section export type afield = struct { attr: u32, form: u32, }; // Loads an abbreviation table from the .debug_abbrev section, loading the table // at the provided offset from the start of the ELF section. // // Pass the result to [[abbrev_table_finish]] to free resources associated with // the table when you're done with it. export fn load_abbrevs( image: *image::image, offs: u64, ) (abbrev_table | void | errors::invalid) = { const sec = match (image::section_byname(image, ".debug_abbrev")) { case let sec: *elf::section64 => yield sec; case null => return; }; const rd = image::section_reader(image, sec); io::seek(&rd, offs: io::off, io::whence::SET)!; const rd = new_table_reader(&rd, false)! as table_reader; let abbrevs: []abbrev = []; for (true) { match (read_abbrev(&rd)) { case io::EOF => break; case io::error => return errors::invalid; case let ab: abbrev => append(abbrevs, ab); }; }; return abbrev_table { items = abbrevs, }; }; // Reads an entry from an abbreviation table. fn read_abbrev( rd: *table_reader, ) (abbrev | io::EOF | io::error) = { const code = read_uleb128(rd)?; if (code == 0) { return io::EOF; }; const tag = read_uleb128(rd)?; const children = read_ubyte(rd)? != 0; let fields: []afield = []; for (true) { const name = read_uleb128(rd)?; const form = read_uleb128(rd)?; if (name == 0 && form == 0) { break; }; append(fields, afield { attr = name: u32, form = form: u32, }); }; return abbrev { code = code, tag = tag: u32, has_children = children, fields = fields, }; }; // Frees resources associated with an [[abbrev_table]]. export fn abbrev_table_finish(table: *abbrev_table) void = { for (let i = 0z; i < len(table.items); i += 1) { free(table.items[i].fields); }; free(table.items); }; // Retrieves an abbreviation from an [[abbrev_table]] by its abbreviation code. export fn get_abbrev(table: *abbrev_table, code: u64) const nullable *abbrev = { // TODO: Sort the list and do this faster for (let item &.. table.items) { if (item.code == code) { return item; }; }; return null; }; hare-0.24.2/debug/dwarf/addr_to_line.ha000066400000000000000000000043431464473310100176530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use io; use path; // Determines the file path, line number, and column number of a given address // in the program image. Returns void if unknown. The return value is statically // allocated. export fn addr_to_line( image: *image::image, addr: uintptr, ) ((const str, uint, uint) | void | io::error) = { const dinfo_offs = match (arange_lookup(image, addr)) { case let offs: u64 => yield offs; case => return; // XXX: We could walk .debug_info I guess }; const dinfo = match (read_debug_info(image, dinfo_offs)?) { case let rd: debug_info_reader => yield rd; case => return; }; defer debug_info_finish(&dinfo); let comp_dir = ""; let stmt_list = 0u64, found = false; for (!found) { const entry = match (debug_info_next(&dinfo)) { case io::EOF => return; case let ent: entry => yield ent; }; defer entry_finish(&entry); if (entry.tag != DW_TAG_compile_unit) { continue; }; for (const field &.. entry.fields) { switch (field.attr) { case DW_AT_stmt_list => stmt_list = field.constant; found = true; case DW_AT_comp_dir => comp_dir = field.string; case => void; }; }; }; const prog = match (exec_line_program(image, stmt_list)) { case let prog: line_program => yield prog; case => return; }; defer line_program_finish(&prog); let last = line_state { ... }; for (const state => line_next(&prog)?) { defer last = state; if (state.file == 1) { continue; }; if (state.addr < addr) { continue; }; // If this is the first state we've seen, use it if (last.vm_loc != 0) { state = last; }; if (state.file == 0) { return; }; const file = &prog.head.files[state.file - 1]; static let path = path::buffer { ... }; path::set(&path)!; if (!path::abs(file.name)) { let dir = ""; if (file.dir != 0) { dir = prog.head.dirs[file.dir - 1]; if (!path::abs(dir) && comp_dir != "") { path::set(&path, comp_dir, dir)!; } else { path::set(&path, dir)!; }; } else if (comp_dir != "") { path::set(&path, comp_dir)!; }; }; path::push(&path, file.name)!; return (path::string(&path), state.line, state.column); }; }; hare-0.24.2/debug/dwarf/aranges.ha000066400000000000000000000032311464473310100166430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use errors; use format::elf; use io; // Supported version of .debug_aranges decoder def ARANGES_VERSION: u16 = 2; // Returns the debug_info offset for the DIE that corresponds to this address, // if known, or void if unknown. export fn arange_lookup( image: *image::image, addr: uintptr, ) (u64 | void | errors::invalid) = { const aranges = match (image::section_byname(image, ".debug_aranges")) { case let sec: *elf::section64 => yield sec; case null => return; }; // Read all arange tables in this section const rd = image::section_reader(image, aranges); for (const rd => new_table_reader(&rd, true)!) { match (arange_match(&rd, addr)) { case void => void; case let u: u64 => return u; case io::error => return errors::invalid; }; }; }; fn arange_match(rd: *table_reader, addr: uintptr) (u64 | void | io::error) = { const ver = read_uhalf(rd)?; const info_offset = read_secword(rd)?; const asize = read_ubyte(rd)?; const ssize = read_ubyte(rd)?; assert(ver == ARANGES_VERSION, "debug::dwarf: unsupported .debug_ranges version"); assert(ssize == 0, "debug::dwarf: unsupported segmented target for .debug_aranges"); assert(asize == 8, "debug::dwarf: unsupported address size for .debug_aranges"); read_align(rd, asize * 2)?; const au64 = addr: u64; for (!read_iseof(rd)) { const min = read_ulong(rd)?; const length = read_ulong(rd)?; if (min == 0 && length == 0) { if (!read_iseof(rd)) { return errors::invalid; }; break; }; const max = min + length; if (min <= au64 && max > au64) { return info_offset; }; }; }; hare-0.24.2/debug/dwarf/constant.ha000066400000000000000000000575531464473310100170740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // DWARF constant definitions // Updated as of DWARF 5 export def DW_TAG_array_type: u32 = 0x01; export def DW_TAG_class_type: u32 = 0x02; export def DW_TAG_entry_point: u32 = 0x03; export def DW_TAG_enumeration_type: u32 = 0x04; export def DW_TAG_formal_parameter: u32 = 0x05; // 0x06, 0x07: reserved export def DW_TAG_imported_declaration: u32 = 0x08A; // 0x09: reserved export def DW_TAG_label: u32 = 0x0a; export def DW_TAG_lexical_block: u32 = 0x0b; // 0x0c: reserved export def DW_TAG_member: u32 = 0x0d; // 0x0e: reserved export def DW_TAG_pointer_type: u32 = 0x0f; export def DW_TAG_reference_type: u32 = 0x10; export def DW_TAG_compile_unit: u32 = 0x11; export def DW_TAG_string_type: u32 = 0x12; export def DW_TAG_structure_type: u32 = 0x13; // 0x14: reserved export def DW_TAG_subroutine_type: u32 = 0x15; export def DW_TAG_typedef: u32 = 0x16; export def DW_TAG_union_type: u32 = 0x17; export def DW_TAG_unspecified_paramters: u32 = 0x18; export def DW_TAG_variant: u32 = 0x19; export def DW_TAG_common_block: u32 = 0x1a; export def DW_TAG_common_inclusion: u32 = 0x1b; export def DW_TAG_inheritance: u32 = 0x1c; export def DW_TAG_inlined_subroutine: u32 = 0x1d; export def DW_TAG_module: u32 = 0x1e; export def DW_TAG_ptr_to_member_type: u32 = 0x1f; export def DW_TAG_set_type: u32 = 0x20; export def DW_TAG_subrange_type: u32 = 0x21; export def DW_TAG_with_stmt: u32 = 0x22; export def DW_TAG_access_declaration: u32 = 0x23; export def DW_TAG_base_type: u32 = 0x24; export def DW_TAG_catch_block: u32 = 0x25; export def DW_TAG_const_type: u32 = 0x26; export def DW_TAG_constant: u32 = 0x27; export def DW_TAG_enumerator: u32 = 0x28; export def DW_TAG_file_type: u32 = 0x29; export def DW_TAG_friend: u32 = 0x2a; export def DW_TAG_namelist: u32 = 0x2b; export def DW_TAG_namelist_item: u32 = 0x2c; export def DW_TAG_packed_type: u32 = 0x2d; export def DW_TAG_subprogram: u32 = 0x2e; export def DW_TAG_template_type_parameter: u32 = 0x2f; export def DW_TAG_template_value_parameter: u32 = 0x30; export def DW_TAG_thrown_type: u32 = 0x31; export def DW_TAG_try_block: u32 = 0x32; export def DW_TAG_variant_part: u32 = 0x33; export def DW_TAG_variable: u32 = 0x34; export def DW_TAG_volatile_type: u32 = 0x35; export def DW_TAG_dwarf_procedure: u32 = 0x36; export def DW_TAG_restrict_type: u32 = 0x37; export def DW_TAG_interface_type: u32 = 0x38; export def DW_TAG_namespace: u32 = 0x39; export def DW_TAG_imported_module: u32 = 0x3a; export def DW_TAG_unspecified_type: u32 = 0x3b; export def DW_TAG_partial_unit: u32 = 0x3c; export def DW_TAG_imported_unit: u32 = 0x3d; // 0x3e: reserved export def DW_TAG_condition: u32 = 0x3f; export def DW_TAG_shared_type: u32 = 0x40; export def DW_TAG_type_unit: u32 = 0x41; export def DW_TAG_rvalue_reference_type: u32 = 0x42; export def DW_TAG_template_alias: u32 = 0x43; export def DW_TAG_coarray_type: u32 = 0x44; export def DW_TAG_generic_subrange: u32 = 0x45; export def DW_TAG_dynamic_type: u32 = 0x46; export def DW_TAG_atomic_type: u32 = 0x47; export def DW_TAG_call_site: u32 = 0x48; export def DW_TAG_call_site_parameter: u32 = 0x49; export def DW_TAG_skeleton_unit: u32 = 0x4a; export def DW_TAG_immutable_type: u32 = 0x4b; export def DW_TAG_lo_user: u32 = 0x4080; export def DW_TAG_hi_user: u32 = 0xffff; export def DW_CHILDREN_no: uint = 0x00; export def DW_CHILDREN_yes: uint = 0x01; export def DW_AT_sibling: u32 = 0x01; export def DW_AT_location: u32 = 0x02; export def DW_AT_name: u32 = 0x03; // 0x04-0x08: reserved export def DW_AT_ordering: u32 = 0x09; // 0x0a: reserved export def DW_AT_byte_size: u32 = 0x0b; // 0x0c: reserved export def DW_AT_bit_size: u32 = 0x0d; // 0x0e, 0x0f: reserved export def DW_AT_stmt_list: u32 = 0x10; export def DW_AT_low_pc: u32 = 0x11; export def DW_AT_high_pc: u32 = 0x12; export def DW_AT_language: u32 = 0x13; // 0x14: reserved export def DW_AT_discr: u32 = 0x15; export def DW_AT_discr_value: u32 = 0x16; export def DW_AT_visibility: u32 = 0x17; export def DW_AT_import: u32 = 0x18; export def DW_AT_string_length: u32 = 0x19; export def DW_AT_common_reference: u32 = 0x1a; export def DW_AT_comp_dir: u32 = 0x1b; export def DW_AT_const_value: u32 = 0x1c; export def DW_AT_containing_type: u32 = 0x1d; export def DW_AT_default_value: u32 = 0x1e; // 0x1f: reserved export def DW_AT_inline: u32 = 0x20; export def DW_AT_is_optional: u32 = 0x21; export def DW_AT_is_lower_bound: u32 = 0x22; // 0x23, 0x24: reserved export def DW_AT_producer: u32 = 0x25; // 0x26: reserved export def DW_AT_prototyped: u32 = 0x27; // 0x28, 0x29: reserved export def DW_AT_return_addr: u32 = 0x2a; // 0x2b: reserved export def DW_AT_start_scope: u32 = 0x2c; // 0x2d: reserved export def DW_AT_bit_stride: u32 = 0x2e; export def DW_AT_upper_bound: u32 = 0x2f; // 0x30: reserved export def DW_AT_abstract_origin: u32 = 0x31; export def DW_AT_accessibility: u32 = 0x32; export def DW_AT_address_class: u32 = 0x33; export def DW_AT_artificial: u32 = 0x34; export def DW_AT_base_types: u32 = 0x35; export def DW_AT_calling_convention: u32 = 0x36; export def DW_AT_count: u32 = 0x37; export def DW_AT_data_member_location: u32 = 0x38; export def DW_AT_decl_column: u32 = 0x39; export def DW_AT_decl_file: u32 = 0x3a; export def DW_AT_decl_line: u32 = 0x3b; export def DW_AT_declaration: u32 = 0x3c; export def DW_AT_discr_list: u32 = 0x3d; export def DW_AT_encoding: u32 = 0x3e; export def DW_AT_external: u32 = 0x3f; export def DW_AT_frame_base: u32 = 0x40; export def DW_AT_friend: u32 = 0x41; export def DW_AT_identifier_case: u32 = 0x42; // 0x43: reserved export def DW_AT_namelist_item: u32 = 0x44; export def DW_AT_priority: u32 = 0x45; export def DW_AT_segment: u32 = 0x46; export def DW_AT_specification: u32 = 0x47; export def DW_AT_static_link: u32 = 0x48; export def DW_AT_type: u32 = 0x49; export def DW_AT_use_location: u32 = 0x4a; export def DW_AT_variable_parameter: u32 = 0x4b; export def DW_AT_virtuality: u32 = 0x4c; export def DW_AT_vtable_elem_location: u32 = 0x4d; export def DW_AT_allocated: u32 = 0x4e; export def DW_AT_associated: u32 = 0x4f; export def DW_AT_data_location: u32 = 0x50; export def DW_AT_byte_stride: u32 = 0x51; export def DW_AT_entry_pc: u32 = 0x52; export def DW_AT_use_UTF8: u32 = 0x53; export def DW_AT_extension: u32 = 0x54; export def DW_AT_ranges: u32 = 0x55; export def DW_AT_trampoline: u32 = 0x56; export def DW_AT_call_column: u32 = 0x57; export def DW_AT_call_file: u32 = 0x58; export def DW_AT_call_line: u32 = 0x59; export def DW_AT_description: u32 = 0x5a; export def DW_AT_binary_scale: u32 = 0x5b; export def DW_AT_decimal_scale: u32 = 0x5c; export def DW_AT_small: u32 = 0x5d; export def DW_AT_decimal_sign: u32 = 0x5e; export def DW_AT_digit_count: u32 = 0x5f; export def DW_AT_picture_string: u32 = 0x60; export def DW_AT_mutable: u32 = 0x61; export def DW_AT_threads_scaled: u32 = 0x62; export def DW_AT_explicit: u32 = 0x63; export def DW_AT_object_pointer: u32 = 0x64; export def DW_AT_endianity: u32 = 0x65; export def DW_AT_elemental: u32 = 0x66; export def DW_AT_pure: u32 = 0x67; export def DW_AT_recursive: u32 = 0x68; export def DW_AT_signature: u32 = 0x69; export def DW_AT_main_subprogram: u32 = 0x6a; export def DW_AT_data_bit_offset: u32 = 0x6b; export def DW_AT_const_expr: u32 = 0x6c; export def DW_AT_enum_class: u32 = 0x6d; export def DW_AT_linkage_name: u32 = 0x6e; export def DW_AT_string_length_bit_size: u32 = 0x6f; export def DW_AT_string_length_byte_size: u32 = 0x70; export def DW_AT_rank: u32 = 0x71; export def DW_AT_str_offsets_base: u32 = 0x72; export def DW_AT_addr_base: u32 = 0x73; export def DW_AT_rnglists_base: u32 = 0x74; // 0x75: reserved export def DW_AT_dwo_name: u32 = 0x76; export def DW_AT_reference: u32 = 0x77; export def DW_AT_rvalue_reference: u32 = 0x78; export def DW_AT_macros: u32 = 0x79; export def DW_AT_call_all_calls: u32 = 0x7a; export def DW_AT_call_all_source_calls: u32 = 0x7b; export def DW_AT_call_all_tail_calls: u32 = 0x7c; export def DW_AT_call_return_pc: u32 = 0x7d; export def DW_AT_call_value: u32 = 0x7e; export def DW_AT_call_origin: u32 = 0x7f; export def DW_AT_call_parameter: u32 = 0x80; export def DW_AT_call_pc: u32 = 0x81; export def DW_AT_call_tail_call: u32 = 0x82; export def DW_AT_call_target: u32 = 0x83; export def DW_AT_call_target_clobbered: u32 = 0x84; export def DW_AT_call_data_location: u32 = 0x85; export def DW_AT_call_data_value: u32 = 0x86; export def DW_AT_noreturn: u32 = 0x87; export def DW_AT_alignment: u32 = 0x88; export def DW_AT_export_symbols: u32 = 0x89; export def DW_AT_deleted: u32 = 0x8a; export def DW_AT_defaulted: u32 = 0x8b; export def DW_AT_loclists_base: u32 = 0x8c; export def DW_AT_lo_user: u32 = 0x2000; export def DW_AT_hi_user: u32 = 0x3fff; export def DW_FORM_addr: u32 = 0x01; // 0x02: reserved export def DW_FORM_block2: u32 = 0x03; export def DW_FORM_block4: u32 = 0x04; export def DW_FORM_data2: u32 = 0x05; export def DW_FORM_data4: u32 = 0x06; export def DW_FORM_data8: u32 = 0x07; export def DW_FORM_string: u32 = 0x08; export def DW_FORM_block: u32 = 0x09; export def DW_FORM_block1: u32 = 0x0a; export def DW_FORM_data1: u32 = 0x0b; export def DW_FORM_flag: u32 = 0x0c; export def DW_FORM_sdata: u32 = 0x0d; export def DW_FORM_strp: u32 = 0x0e; export def DW_FORM_udata: u32 = 0x0f; export def DW_FORM_ref_addr: u32 = 0x10; export def DW_FORM_ref1: u32 = 0x11; export def DW_FORM_ref2: u32 = 0x12; export def DW_FORM_ref4: u32 = 0x13; export def DW_FORM_ref8: u32 = 0x14; export def DW_FORM_ref_udata: u32 = 0x15; export def DW_FORM_indirect: u32 = 0x16; export def DW_FORM_sec_offset: u32 = 0x17; export def DW_FORM_exprloc: u32 = 0x18; export def DW_FORM_flag_present: u32 = 0x19; export def DW_FORM_strx: u32 = 0x1a; export def DW_FORM_addrx: u32 = 0x1b; export def DW_FORM_ref_sup4: u32 = 0x1c; export def DW_FORM_strp_sup: u32 = 0x1d; export def DW_FORM_data16: u32 = 0x1e; export def DW_FORM_line_strp: u32 = 0x1f; export def DW_FORM_ref_sig8: u32 = 0x20; export def DW_FORM_implicit_const: u32 = 0x21; export def DW_FORM_loclistx: u32 = 0x22; export def DW_FORM_rnglistx: u32 = 0x23; export def DW_FORM_ref_sup8: u32 = 0x24; export def DW_FORM_strx1: u32 = 0x25; export def DW_FORM_strx2: u32 = 0x26; export def DW_FORM_strx3: u32 = 0x27; export def DW_FORM_strx4: u32 = 0x28; export def DW_FORM_addrx1: u32 = 0x29; export def DW_FORM_addrx2: u32 = 0x2a; export def DW_FORM_addrx3: u32 = 0x2b; export def DW_FORM_addrx4: u32 = 0x2c; // 0x01, 0x02: reserved export def DW_OP_addr: u8 = 0x03; // 0x04, 0x05: reserved export def DW_OP_deref: u8 = 0x06; // 0x07: reserved export def DW_OP_const1u: u8 = 0x08; export def DW_OP_const1s: u8 = 0x09; export def DW_OP_const2u: u8 = 0x0a; export def DW_OP_const2s: u8 = 0x0b; export def DW_OP_const4u: u8 = 0x0c; export def DW_OP_const4s: u8 = 0x0d; export def DW_OP_const8u: u8 = 0x0e; export def DW_OP_const8s: u8 = 0x0f; export def DW_OP_constu: u8 = 0x10; export def DW_OP_consts: u8 = 0x11; export def DW_OP_dup: u8 = 0x12; export def DW_OP_drop: u8 = 0x13; export def DW_OP_over: u8 = 0x14; export def DW_OP_pick: u8 = 0x15; export def DW_OP_swap: u8 = 0x16; export def DW_OP_rot: u8 = 0x17; export def DW_OP_xdref: u8 = 0x18; export def DW_OP_abs: u8 = 0x19; export def DW_OP_and: u8 = 0x1a; export def DW_OP_div: u8 = 0x1b; export def DW_OP_minus: u8 = 0x1c; export def DW_OP_mod: u8 = 0x1d; export def DW_OP_mul: u8 = 0x1e; export def DW_OP_neg: u8 = 0x1f; export def DW_OP_not: u8 = 0x20; export def DW_OP_or: u8 = 0x21; export def DW_OP_plus: u8 = 0x22; export def DW_OP_plus_uconst: u8 = 0x23; export def DW_OP_shl: u8 = 0x24; export def DW_OP_shr: u8 = 0x25; export def DW_OP_shra: u8 = 0x26; export def DW_OP_xor: u8 = 0x27; export def DW_OP_bra: u8 = 0x28; export def DW_OP_eq: u8 = 0x29; export def DW_OP_ge: u8 = 0x2a; export def DW_OP_gt: u8 = 0x2b; export def DW_OP_le: u8 = 0x2c; export def DW_OP_lt: u8 = 0x2d; export def DW_OP_ne: u8 = 0x2e; export def DW_OP_skip: u8 = 0x2f; export def DW_OP_lit0: u8 = 0x30; export def DW_OP_lit1: u8 = 0x31; export def DW_OP_lit2: u8 = 0x32; export def DW_OP_lit3: u8 = 0x33; export def DW_OP_lit4: u8 = 0x34; export def DW_OP_lit5: u8 = 0x35; export def DW_OP_lit6: u8 = 0x36; export def DW_OP_lit7: u8 = 0x37; export def DW_OP_lit8: u8 = 0x38; export def DW_OP_lit9: u8 = 0x39; export def DW_OP_lit10: u8 = 0x3a; export def DW_OP_lit11: u8 = 0x3b; export def DW_OP_lit12: u8 = 0x3c; export def DW_OP_lit13: u8 = 0x3d; export def DW_OP_lit14: u8 = 0x3e; export def DW_OP_lit15: u8 = 0x3f; export def DW_OP_lit16: u8 = 0x40; export def DW_OP_lit17: u8 = 0x41; export def DW_OP_lit18: u8 = 0x42; export def DW_OP_lit19: u8 = 0x43; export def DW_OP_lit20: u8 = 0x44; export def DW_OP_lit21: u8 = 0x45; export def DW_OP_lit22: u8 = 0x46; export def DW_OP_lit23: u8 = 0x47; export def DW_OP_lit24: u8 = 0x48; export def DW_OP_lit25: u8 = 0x49; export def DW_OP_lit26: u8 = 0x4a; export def DW_OP_lit27: u8 = 0x4b; export def DW_OP_lit28: u8 = 0x4c; export def DW_OP_lit29: u8 = 0x4d; export def DW_OP_lit30: u8 = 0x4e; export def DW_OP_lit31: u8 = 0x4f; export def DW_OP_reg0: u8 = 0x50; export def DW_OP_reg1: u8 = 0x51; export def DW_OP_reg2: u8 = 0x52; export def DW_OP_reg3: u8 = 0x53; export def DW_OP_reg4: u8 = 0x54; export def DW_OP_reg5: u8 = 0x55; export def DW_OP_reg6: u8 = 0x56; export def DW_OP_reg7: u8 = 0x57; export def DW_OP_reg8: u8 = 0x58; export def DW_OP_reg9: u8 = 0x59; export def DW_OP_reg10: u8 = 0x5a; export def DW_OP_reg11: u8 = 0x5b; export def DW_OP_reg12: u8 = 0x5c; export def DW_OP_reg13: u8 = 0x5d; export def DW_OP_reg14: u8 = 0x5e; export def DW_OP_reg15: u8 = 0x5f; export def DW_OP_reg16: u8 = 0x60; export def DW_OP_reg17: u8 = 0x61; export def DW_OP_reg18: u8 = 0x62; export def DW_OP_reg19: u8 = 0x63; export def DW_OP_reg20: u8 = 0x64; export def DW_OP_reg21: u8 = 0x65; export def DW_OP_reg22: u8 = 0x66; export def DW_OP_reg23: u8 = 0x67; export def DW_OP_reg24: u8 = 0x68; export def DW_OP_reg25: u8 = 0x69; export def DW_OP_reg26: u8 = 0x6a; export def DW_OP_reg27: u8 = 0x6b; export def DW_OP_reg28: u8 = 0x6c; export def DW_OP_reg29: u8 = 0x6d; export def DW_OP_reg30: u8 = 0x6e; export def DW_OP_reg31: u8 = 0x6f; export def DW_OP_breg0: u8 = 0x70; export def DW_OP_breg1: u8 = 0x71; export def DW_OP_breg2: u8 = 0x72; export def DW_OP_breg3: u8 = 0x73; export def DW_OP_breg4: u8 = 0x74; export def DW_OP_breg5: u8 = 0x75; export def DW_OP_breg6: u8 = 0x76; export def DW_OP_breg7: u8 = 0x77; export def DW_OP_breg8: u8 = 0x78; export def DW_OP_breg9: u8 = 0x79; export def DW_OP_breg10: u8 = 0x7a; export def DW_OP_breg11: u8 = 0x7b; export def DW_OP_breg12: u8 = 0x7c; export def DW_OP_breg13: u8 = 0x7d; export def DW_OP_breg14: u8 = 0x7e; export def DW_OP_breg15: u8 = 0x7f; export def DW_OP_breg16: u8 = 0x80; export def DW_OP_breg17: u8 = 0x81; export def DW_OP_breg18: u8 = 0x82; export def DW_OP_breg19: u8 = 0x83; export def DW_OP_breg20: u8 = 0x84; export def DW_OP_breg21: u8 = 0x85; export def DW_OP_breg22: u8 = 0x86; export def DW_OP_breg23: u8 = 0x87; export def DW_OP_breg24: u8 = 0x88; export def DW_OP_breg25: u8 = 0x89; export def DW_OP_breg26: u8 = 0x8a; export def DW_OP_breg27: u8 = 0x8b; export def DW_OP_breg28: u8 = 0x8c; export def DW_OP_breg29: u8 = 0x8d; export def DW_OP_breg30: u8 = 0x8e; export def DW_OP_breg31: u8 = 0x8f; export def DW_OP_regx: u8 = 0x90; export def DW_OP_fbreg: u8 = 0x91; export def DW_OP_bregx: u8 = 0x92; export def DW_OP_piece: u8 = 0x93; export def DW_OP_dref_size: u8 = 0x94; export def DW_OP_xdref_size: u8 = 0x95; export def DW_OP_nop: u8 = 0x96; export def DW_OP_push_object_address: u8 = 0x97; export def DW_OP_call2: u8 = 0x98; export def DW_OP_call4: u8 = 0x99; export def DW_OP_call_ref: u8 = 0x9a; export def DW_OP_form_tls_address: u8 = 0x9b; export def DW_OP_call_frame_cfa: u8 = 0x9c; export def DW_OP_bit_piece: u8 = 0x9d; export def DW_OP_implicit_value: u8 = 0x9e; export def DW_OP_stack_value: u8 = 0x9f; export def DW_OP_implicit_pointer: u8 = 0xa0; export def DW_OP_addrx: u8 = 0xa1; export def DW_OP_constx: u8 = 0xa2; export def DW_OP_entry_value: u8 = 0xa3; export def DW_OP_const_type: u8 = 0xa4; export def DW_OP_regval_type: u8 = 0xa5; export def DW_OP_deref_type: u8 = 0xa6; export def DW_OP_xdref_type: u8 = 0xa7; export def DW_OP_convert: u8 = 0xa8; export def DW_OP_reinterpret: u8 = 0xa9; export def DW_OP_lo_user: u8 = 0xe0; export def DW_OP_hi_user: u8 = 0xff; export def DW_LLE_end_of_list: u8 = 0x00; export def DW_LLE_base_addressx: u8 = 0x01; export def DW_LLE_startx_endx: u8 = 0x02; export def DW_LLE_startx_length: u8 = 0x03; export def DW_LLE_offset_pair: u8 = 0x04; export def DW_LLE_default_location: u8 = 0x05; export def DW_LLE_base_address: u8 = 0x06; export def DW_LLE_start_end: u8 = 0x07; export def DW_LLE_start_length: u8 = 0x08; export def DW_ATE_address: u8 = 0x01; export def DW_ATE_boolean: u8 = 0x02; export def DW_ATE_complex_float: u8 = 0x03; export def DW_ATE_float: u8 = 0x04; export def DW_ATE_signed: u8 = 0x05; export def DW_ATE_signed_char: u8 = 0x06; export def DW_ATE_unsigned: u8 = 0x07; export def DW_ATE_unsigned_char: u8 = 0x08; export def DW_ATE_imaginary_float: u8 = 0x09; export def DW_ATE_packed_decimal: u8 = 0x0a; export def DW_ATE_numeric_string: u8 = 0x0b; export def DW_ATE_edited: u8 = 0x0c; export def DW_ATE_signed_fixed: u8 = 0x0d; export def DW_ATE_unsigned_fixed: u8 = 0x0e; export def DW_ATE_decimal_float: u8 = 0x0f; export def DW_ATE_UTF: u8 = 0x10; export def DW_ATE_UCS: u8 = 0x11; export def DW_ATE_ASCII: u8 = 0x12; export def DW_ATE_lo_user: u8 = 0x80; export def DW_ATE_hi_user: u8 = 0xff; export def DW_DS_unsigned: u8 = 0x01; export def DW_DS_leading_overpunch: u8 = 0x02; export def DW_DS_trailing_overpunch: u8 = 0x03; export def DW_DS_leading_separate: u8 = 0x04; export def DW_DS_trailing_separate: u8 = 0x05; export def DW_END_default: u8 = 0x00; export def DW_END_big: u8 = 0x01; export def DW_END_little: u8 = 0x02; export def DW_END_lo_user: u8 = 0x40; export def DW_END_hi_user: u8 = 0xff; export def DW_ACCESS_public: u8 = 0x01; export def DW_ACCESS_protected: u8 = 0x02; export def DW_ACCESS_private: u8 = 0x03; export def DW_VIS_local: u8 = 0x01; export def DW_VIS_exported: u8 = 0x02; export def DW_VIS_qualified: u8 = 0x03; export def DW_VIRTUALITY_none: u8 = 0x00; export def DW_VIRTUALITY_virtual: u8 = 0x01; export def DW_VIRTUALITY_pure_virtual: u8 = 0x02; export def DW_LANG_C89: u16 = 0x0001; export def DW_LANG_C: u16 = 0x0002; export def DW_LANG_Ada83: u16 = 0x0003; export def DW_LANG_C_plus_plus: u16 = 0x0004; export def DW_LANG_Cobol74: u16 = 0x0005; export def DW_LANG_Cobol85: u16 = 0x0006; export def DW_LANG_Fortran77: u16 = 0x0007; export def DW_LANG_Fortran90: u16 = 0x0008; export def DW_LANG_Pascal83: u16 = 0x0009; export def DW_LANG_Modula2: u16 = 0x000a; export def DW_LANG_Java: u16 = 0x000b; export def DW_LANG_C99: u16 = 0x000c; export def DW_LANG_Ada95: u16 = 0x000d; export def DW_LANG_Fortran95: u16 = 0x000e; export def DW_LANG_PLI: u16 = 0x000f; export def DW_LANG_ObjC: u16 = 0x0010; export def DW_LANG_ObjC_plus_plus: u16 = 0x0011; export def DW_LANG_UPC: u16 = 0x0012; export def DW_LANG_D: u16 = 0x0013; export def DW_LANG_Python: u16 = 0x0014; export def DW_LANG_OpenCL: u16 = 0x0015; export def DW_LANG_Go: u16 = 0x0016; export def DW_LANG_Modula3: u16 = 0x0017; export def DW_LANG_Haskell: u16 = 0x0018; export def DW_LANG_C_plus_plus_03: u16 = 0x0019; export def DW_LANG_C_plus_plus_11: u16 = 0x001a; export def DW_LANG_OCaml: u16 = 0x001b; export def DW_LANG_Rust: u16 = 0x001c; export def DW_LANG_c11: u16 = 0x001d; export def DW_LANG_Swift: u16 = 0x001e; export def DW_LANG_Julia: u16 = 0x001f; export def DW_LANG_Dylan: u16 = 0x0020; export def DW_LANG_C_plus_plus_14: u16 = 0x0021; export def DW_LANG_Fortran03: u16 = 0x0022; export def DW_LANG_Fortran08: u16 = 0x0023; export def DW_LANG_RenderScript: u16 = 0x0024; export def DW_LANG_BLISS: u16 = 0x0025; export def DW_LANG_lo_user: u16 = 0x8000; export def DW_LANG_hi_user: u16 = 0xffff; export def DW_ADDR_none: uint = 0; export def DW_ID_case_sensitive: u8 = 0x00; export def DW_ID_up_case: u8 = 0x01; export def DW_ID_down_case: u8 = 0x02; export def DW_ID_case_insensitive: u8 = 0x03; export def DW_CC_normal: u8 = 0x01; export def DW_CC_program: u8 = 0x02; export def DW_CC_nocall: u8 = 0x03; export def DW_CC_pass_by_reference: u8 = 0x04; export def DW_CC_pass_by_value: u8 = 0x05; export def DW_CC_lo_user: u8 = 0x40; export def DW_CC_hi_user: u8 = 0xff; export def DW_INL_not_inlined: u8 = 0x00; export def DW_INL_inlined: u8 = 0x01; export def DW_INL_declared_not_inlined: u8 = 0x02; export def DW_INL_declared_inlined: u8 = 0x03; export def DW_ORD_row_major: u8 = 0x00; export def DW_ORD_col_major: u8 = 0x01; export def DW_DSC_label: u8 = 0x00; export def DW_DSC_range: u8 = 0x01; export def DW_IDX_compile_unit: u16 = 0x01; export def DW_IDX_type_unit: u16 = 0x02; export def DW_IDX_die_offset: u16 = 0x03; export def DW_IDX_parent: u16 = 0x04; export def DW_IDX_type_hash: u16 = 0x05; export def DW_IDX_lo_user: u16 = 0x2000; export def DW_IDX_hi_user: u16 = 0x3fff; export def DW_DEFAULTED_no: u8 = 0x00; export def DW_DEFAULTED_in_class: u8 = 0x01; export def DW_DEFAULTED_out_of_class: u8 = 0x02; export def DW_LNS_copy: u8 = 0x01; export def DW_LNS_advance_pc: u8 = 0x02; export def DW_LNS_advance_line: u8 = 0x03; export def DW_LNS_set_file: u8 = 0x04; export def DW_LNS_set_column: u8 = 0x05; export def DW_LNS_negate_stmt: u8 = 0x06; export def DW_LNS_set_basic_block: u8 = 0x07; export def DW_LNS_const_add_pc: u8 = 0x08; export def DW_LNS_fixed_advance_pc: u8 = 0x09; export def DW_LNS_set_prologue_end: u8 = 0x0a; export def DW_LNS_set_epilogue_begin: u8 = 0x0b; export def DW_LNS_isa: u8 = 0x0c; export def DW_LNE_end_sequence: u8 = 0x01; export def DW_LNE_set_address: u8 = 0x02; export def DW_LNE_define_file: u8 = 0x03; export def DW_LNE_set_discriminator: u8 = 0x04; export def DW_LNE_lo_user: u8 = 0x80; export def DW_LNE_hi_user: u8 = 0xff; export def DW_LNCT_path: u16 = 0x01; export def DW_LNCT_directory_index: u16 = 0x02; export def DW_LNCT_timestamp: u16 = 0x03; export def DW_LNCT_size: u16 = 0x04; export def DW_LNCT_MD5: u16 = 0x05; export def DW_LNCT_lo_user: u16 = 0x2000; export def DW_LNCT_hi_user: u16 = 0x3ff; export def DW_MACRO_define: u8 = 0x01; export def DW_MACRO_undef: u8 = 0x02; export def DW_MACRO_start_file: u8 = 0x03; export def DW_MACRO_end_file: u8 = 0x04; export def DW_MACRO_define_strp: u8 = 0x05; export def DW_MACRO_undef_strp: u8 = 0x06; export def DW_MACRO_import: u8 = 0x07; export def DW_MACRO_define_sup: u8 = 0x08; export def DW_MACRO_undef_sup: u8 = 0x09; export def DW_MACRO_import_sup: u8 = 0x0a; export def DW_MACRO_define_strx: u8 = 0x0b; export def DW_MACRO_undef_strx: u8 = 0x0c; export def DW_MACRO_lo_user: u8 = 0xe0; export def DW_MACRO_hi_user: u8 = 0xff; // The following instructions are omitted: // DW_CFA_advance_loc // DW_CFA_offset // DW_CFA_restore export def DW_CFA_nop: u8 = 0x00; export def DW_CFA_set_loc: u8 = 0x01; export def DW_CFA_advance_loc1: u8 = 0x02; export def DW_CFA_advance_loc2: u8 = 0x03; export def DW_CFA_advance_loc3: u8 = 0x04; export def DW_CFA_offset_extended: u8 = 0x05; export def DW_CFA_restore_extended: u8 = 0x06; export def DW_CFA_undefined: u8 = 0x07; export def DW_CFA_same_value: u8 = 0x08; export def DW_CFA_register: u8 = 0x09; export def DW_CFA_remember_state: u8 = 0x0a; export def DW_CFA_restore_state: u8 = 0x0b; export def DW_CFA_def_cfa: u8 = 0x0c; export def DW_CFA_def_cfa_register: u8 = 0x0d; export def DW_CFA_def_cfa_offset: u8 = 0x0e; export def DW_CFA_def_cfa_expression: u8 = 0x0f; export def DW_CFA_expression: u8 = 0x10; export def DW_CFA_offset_extended_sf: u8 = 0x11; export def DW_CFA_def_cfa_sf: u8 = 0x12; export def DW_CFA_def_cfa_offset_sf: u8 = 0x13; export def DW_CFA_val_offset: u8 = 0x14; export def DW_CFA_val_offset_sf: u8 = 0x15; export def DW_CFA_val_expression: u8 = 0x16; export def DW_CFA_lo_user: u8 = 0x1c; export def DW_CFA_hi_user: u8 = 0x3f; export def DW_RLE_end_of_list: u8 = 0x00; export def DW_RLE_base_addressx: u8 = 0x01; export def DW_RLE_startx_endx: u8 = 0x02; export def DW_RLE_startx_length: u8 = 0x03; export def DW_RLE_offset_pair: u8 = 0x04; export def DW_RLE_base_address: u8 = 0x05; export def DW_RLE_start_end: u8 = 0x06; export def DW_RLE_start_length: u8 = 0x07; hare-0.24.2/debug/dwarf/info.ha000066400000000000000000000117541464473310100161670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use debug::image; use format::elf; use io; use memio; def INFO_VERSION: u16 = 4; export type debug_info_reader = struct { image: *image::image, abbrev: abbrev_table, strings: (string_table | void), mem: *memio::stream, rd: *table_reader, }; // Reads the debug info from a DWARF image. Returns a [[debug_info_reader]], // call [[debug_info_next]] to retrieve the next DIE. // // Pass the return value to [[debug_info_finish]] after you're done with it. export fn read_debug_info( image: *image::image, offs: u64, ) (debug_info_reader | void | io::error) = { const sec = match (image::section_byname(image, ".debug_info")) { case let sec: *elf::section64 => yield sec; case null => return; }; const memrd = alloc(image::section_reader(image, sec)); io::seek(memrd, offs: io::off, io::whence::SET)?; const rd = match (new_table_reader(memrd, true)?) { case let rd: table_reader => yield alloc(rd); case io::EOF => return; }; const ver = read_uhalf(rd)!; const abbrev_offs = read_secword(rd)!; const asize = read_ubyte(rd)!; assert(ver <= INFO_VERSION, "debug::dwarf: unsupported .debug_info version"); assert(asize == 8, "debug::dwarf: unsupported address size in .debug_info"); const abbrevs = match (load_abbrevs(image, abbrev_offs)?) { case void => return; case let tab: abbrev_table => yield tab; }; return debug_info_reader { image = image, abbrev = abbrevs, strings = load_strings(image)?, mem = memrd, rd = rd, }; }; // Returns the next debug info [[entry]] (DIE) from a [[debug_info_reader]]. // Pass the return value to [[entry_finish]] when done. export fn debug_info_next(di: *debug_info_reader) (entry | io::EOF) = { if (read_iseof(di.rd)) { return io::EOF; }; let code = read_uleb128(di.rd)!; for (code == 0) { if (read_iseof(di.rd)) { return io::EOF; }; code = read_uleb128(di.rd)!; }; const ref = get_abbrev(&di.abbrev, code); assert(ref != null, "debug::dwarf: unknown abbreviated tag"); return read_die(di, di.rd, ref as *abbrev)!; }; // Frees resources associated with a [[debug_info_reader]]. export fn debug_info_finish(di: *debug_info_reader) void = { free(di.mem); free(di.rd); }; // A debug entry. export type entry = struct { tag: u32, children: bool, fields: []field, }; // Frees resources associated with an [[entry]]. export fn entry_finish(ent: *entry) void = { free(ent.fields); }; // A debug [[entry]] field. export type field = struct { attr: u32, form: u32, union { address: uintptr, block: []u8, constant: u64, string: const str, flag: bool, reference: u64, exprloc: []u8, ptr: u64, }, }; fn read_die( ir: *debug_info_reader, rd: *table_reader, abbrev: *abbrev, ) (entry | io::error) = { let fields: []field = []; for (const abf &.. abbrev.fields) { let field = field { attr = abf.attr, form = abf.form, ... }; let form = abf.form; for (form == DW_FORM_indirect) { form = read_uleb128(rd)?: u32; }; // NOTE: Only supports up to DWARF 4 forms for now switch (form) { case DW_FORM_addr => field.address = read_ulong(rd)?: uintptr; case DW_FORM_block => field.block = read_slice(rd, read_uleb128(rd)?)?; case DW_FORM_block1 => field.block = read_slice(rd, read_ubyte(rd)?)?; case DW_FORM_block2 => field.block = read_slice(rd, read_uhalf(rd)?)?; case DW_FORM_block4 => field.block = read_slice(rd, read_uword(rd)?)?; case DW_FORM_data1 => field.constant = read_ubyte(rd)?; case DW_FORM_data2 => field.constant = read_uhalf(rd)?; case DW_FORM_data4 => field.constant = read_uword(rd)?; case DW_FORM_data8 => field.constant = read_ulong(rd)?; case DW_FORM_udata => field.constant = read_uleb128(rd)?; case DW_FORM_sdata => field.constant = read_sleb128(rd)?: u64; case DW_FORM_string => field.string = read_string(rd)?; case DW_FORM_strp => // TODO: Look up in .debug_strings const offs = read_secword(rd)?; match (ir.strings) { case let tab: string_table => field.string = get_strp(&tab, offs); case void => field.string = "(unknown)"; }; case DW_FORM_flag => field.flag = read_ubyte(rd)? != 0; case DW_FORM_flag_present => field.flag = true; case DW_FORM_ref_addr => field.reference = read_secword(rd)?; case DW_FORM_ref1 => field.reference = read_ubyte(rd)?; case DW_FORM_ref2 => field.reference = read_uhalf(rd)?; case DW_FORM_ref4 => field.reference = read_uword(rd)?; case DW_FORM_ref8 => field.reference = read_ulong(rd)?; case DW_FORM_ref_udata => field.reference = read_uleb128(rd)?; case DW_FORM_ref_sig8 => field.reference = read_ulong(rd)?; case DW_FORM_sec_offset => field.reference = read_secword(rd)?; case DW_FORM_exprloc => field.exprloc = read_slice(rd, read_uleb128(rd)?)?; case DW_FORM_indirect => abort(); case => return errors::unsupported; }; append(fields, field); }; return entry { tag = abbrev.tag, children = abbrev.has_children, fields = fields, }; }; hare-0.24.2/debug/dwarf/line.ha000066400000000000000000000156151464473310100161630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use format::elf; use io; use memio; def MIN_LINE_VERSION: u16 = 2; def MAX_LINE_VERSION: u16 = 3; // Boolean flags for the line number state machine export type line_flag = enum uint { NONE = 0, IS_STMT = 1 << 0, BASIC_BLOCK = 1 << 1, END_SEQUENCE = 1 << 2, PROLOGUE_END = 1 << 3, EPILOGUE_BEGIN = 1 << 4, }; // Line number program state export type line_state = struct { vm_loc: u64, addr: uintptr, op_index: uint, file: uint, line: uint, column: uint, flags: line_flag, isa: uint, discriminator: uint, }; // A file with associated line numbers. export type line_file = struct { name: str, dir: u64, mtime: u64, length: u64, }; // Header information for a .debug_line program. export type line_header = struct { min_instr_length: u8, max_ops_per_instr: u8, default_isstmt: bool, line_base: i8, line_range: u8, opcode_base: u8, opcode_lengths: []u8, dirs: []str, files: []line_file, }; // Line number program export type line_program = struct { mem: *memio::stream, rd: *table_reader, state: line_state, head: line_header, }; // Initializes a new line number state machine to run the line number program at // the specified offset in .debug_line. // // Use [[line_step]] to step the state machine, and pass the result to // [[line_program_finish]] to free resources associated with the state machine // when done using it. export fn exec_line_program( image: *image::image, offs: u64, ) (line_program | void | io::error) = { const sec = match (image::section_byname(image, ".debug_line")) { case let sec: *elf::section64 => yield sec; case null => return; }; const memrd = alloc(image::section_reader(image, sec)); io::seek(memrd, offs: io::off, io::whence::SET)?; const rd = alloc(new_table_reader(memrd, true)? as table_reader); // Read program header const ver = read_uhalf(rd)!; assert(ver >= MIN_LINE_VERSION && ver <= MAX_LINE_VERSION, "debug::dwarf: unsupported .debug_line version"); let head = line_header { ... }; const head_len = read_secword(rd)?; head.min_instr_length = read_ubyte(rd)?; head.max_ops_per_instr = 1; // Non-VLIW architectures only head.default_isstmt = read_ubyte(rd)? != 0; head.line_base = read_sbyte(rd)?; head.line_range = read_ubyte(rd)?; head.opcode_base = read_ubyte(rd)?; // Opcode lengths for (let i = 0u8; i < head.opcode_base - 1; i += 1) { const op = read_ubyte(rd)?; append(head.opcode_lengths, op); }; // Directories for (true) { const dir = read_string(rd)?; if (len(dir) == 0) { break; }; append(head.dirs, dir); }; // Files for (true) { const name = read_string(rd)?; if (len(name) == 0) { break; }; const dir = read_uleb128(rd)?; const mtime = read_uleb128(rd)?; const length = read_uleb128(rd)?; append(head.files, line_file { name = name, dir = dir, mtime = mtime, length = length, }); }; let prog = line_program { mem = memrd, rd = rd, state = line_state { ... }, head = head, }; line_prog_reset(&prog); return prog; }; fn line_prog_reset(prog: *line_program) void = { const head = &prog.head; prog.state = line_state { vm_loc = 0, addr = 0, op_index = 0, file = 1, line = 1, column = 0, flags = if (head.default_isstmt) line_flag::IS_STMT else 0, isa = 0, discriminator = 0, }; }; // Frees resources associated with a [[line_program]]. export fn line_program_finish(prog: *line_program) void = { free(prog.mem); free(prog.rd); free(prog.head.opcode_lengths); free(prog.head.dirs); free(prog.head.files); }; // Runs the line number state machine until the next COPY instruction. export fn line_next(prog: *line_program) (line_state | io::EOF | io::error) = { for (true) { match (line_step(prog)?) { case let state: line_state => return state; case io::EOF => return io::EOF; case void => continue; }; }; }; // Step the line number state machine. Returns the current line_state on a copy // or end-of-sequence instruction, [[io::EOF]] at the end of the file, or void // otherwise. export fn line_step( prog: *line_program, ) (line_state | void | io::EOF | io::error) = { let state = &prog.state; if (read_iseof(prog.rd)) { return io::EOF; }; state.vm_loc = read_tell(prog.rd); const opcode = read_ubyte(prog.rd)?; if (opcode == 0) { // Extended opcode const length = read_uleb128(prog.rd)?; const opcode = read_ubyte(prog.rd)?; switch (opcode) { case DW_LNE_end_sequence => let copy = *state; line_prog_reset(prog); return copy; case DW_LNE_set_address => state.addr = read_ulong(prog.rd)?: uintptr; case DW_LNE_define_file => const name = read_string(prog.rd)?; const dir = read_uleb128(prog.rd)?; const mtime = read_uleb128(prog.rd)?; const length = read_uleb128(prog.rd)?; append(prog.head.files, line_file { name = name, dir = dir, mtime = mtime, length = length, }); state.file = len(prog.head.files): uint; case DW_LNE_set_discriminator => state.discriminator = read_uleb128(prog.rd)?: uint; case => // Unknown opcode, skip read_slice(prog.rd, length - 1)?; }; } else if (opcode < prog.head.opcode_base) { // Special opcode switch (opcode) { case DW_LNS_copy => let copy = *state; state.discriminator = 0; state.flags &= ~( line_flag::BASIC_BLOCK | line_flag::PROLOGUE_END | line_flag::EPILOGUE_BEGIN); return copy; case DW_LNS_advance_pc => const op_adv = read_uleb128(prog.rd)?; state.addr += (prog.head.min_instr_length * op_adv): uintptr; case DW_LNS_advance_line => const line = state.line: i64; const offs = read_sleb128(prog.rd)?; line += offs; state.line = line: uint; case DW_LNS_set_file => state.file = read_uleb128(prog.rd)?: uint; case DW_LNS_set_column => state.column = read_uleb128(prog.rd)?: uint; case DW_LNS_negate_stmt => state.flags ^= line_flag::IS_STMT; case DW_LNS_set_basic_block => state.flags |= line_flag::BASIC_BLOCK; case DW_LNS_const_add_pc => const opcode = 255 - prog.head.opcode_base; const op_adv = opcode / prog.head.line_range; state.addr += (prog.head.min_instr_length * op_adv): uintptr; case DW_LNS_fixed_advance_pc => state.addr += read_uhalf(prog.rd)?: uintptr; state.op_index = 0; case DW_LNS_set_prologue_end => state.flags |= line_flag::PROLOGUE_END; case DW_LNS_set_epilogue_begin => state.flags |= line_flag::EPILOGUE_BEGIN; case DW_LNS_isa => state.isa = read_uleb128(prog.rd)?: uint; case => // Unknown opcode, skip const length = prog.head.opcode_lengths[opcode - 1]; for (length != 0; length -= 1) { read_uleb128(prog.rd)?; }; }; } else { const opcode = opcode - prog.head.opcode_base; const op_adv = opcode / prog.head.line_range; state.addr += (prog.head.min_instr_length * op_adv): uintptr; let line = state.line: int; line += prog.head.line_base: int + opcode: int % prog.head.line_range: int; state.line = line: uint; }; }; hare-0.24.2/debug/dwarf/reader.ha000066400000000000000000000120171464473310100164670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use endian; use errors; use io; use memio; use strings; use types; export type table_reader = struct { src: *memio::stream, orig_length: size, length: size, is64: bool, }; // Creates a new DWARF table reader. // // If "read_length" is true, this function will read the length from the start // of the table. Returns [[io::EOF]] immediately if there is insufficient data // available in the provided I/O handle. // // The reader will return [[io::underread]] if the DWARF table is truncated. fn new_table_reader( in: *memio::stream, read_length: bool, ) (table_reader | io::EOF | io::error) = { let rd = table_reader { src = in, orig_length = types::SIZE_MAX, length = types::SIZE_MAX, is64 = false, }; if (read_length) { const word = match (read_uword(&rd)) { case let uw: u32 => yield uw; case io::underread => return io::EOF; case let err: io::error => return err; }; if (word == 0xffffffff) { rd.is64 = true; const long = match (read_ulong(&rd)) { case let ul: u64 => yield ul; case let err: io::error => if (err is io::underread) { return io::EOF; }; return err; }; rd.length = long: size; } else if (word >= 0xfffffff0) { // Reserved value return errors::invalid; } else { rd.length = word: size; }; }; rd.orig_length = rd.length; return rd; }; fn read_iseof(rd: *table_reader) bool = rd.length == 0; fn read_advance(rd: *table_reader, nbyte: size) (void | io::error) = { if (rd.length < nbyte) { return 0: io::underread; }; rd.length -= nbyte; }; // Aligns the reader on a given alignment. This function is needed because both // binutils and LLVM inexplicably add padding to .debug_aranges to align the // first tuple on the address size * 2, despite the fact that this is mentioned // nowhere in the DWARF specification and in fact section 7.25 specifically // states that DWARF data is not aligned. It took me 6 hours to figure this out. fn read_align(rd: *table_reader, alignment: size) (void | io::error) = { let cur = rd.orig_length - rd.length + size(u32); if (rd.is64) { cur += size(u64); }; const offs = alignment - (cur % alignment); if (offs == 0) { return; }; let buf: [128]u8 = [0...]; io::readall(rd.src, buf[..offs])?; rd.length -= offs; }; // Returns the current location of the reader from the start of the section. fn read_tell(rd: *table_reader) size = { const offs = rd.orig_length - rd.length; if (rd.is64) { return offs + size(u32) + size(u64); } else { return offs + size(u32); }; }; fn read_sbyte(rd: *table_reader) (i8 | io::error) = { read_advance(rd, size(i8))?; match (bufio::read_byte(rd.src)?) { case let byte: u8 => return byte: i8; case io::EOF => return 0: io::underread; }; }; fn read_ubyte(rd: *table_reader) (u8 | io::error) = { read_advance(rd, size(u8))?; match (bufio::read_byte(rd.src)?) { case let byte: u8 => return byte; case io::EOF => return 0: io::underread; }; }; fn read_uhalf(rd: *table_reader) (u16 | io::error) = { read_advance(rd, size(u16))?; let buf: [size(u16)]u8 = [0...]; match (io::readall(rd.src, buf)?) { case io::EOF => return 0: io::underread; case size => return endian::host.getu16(buf); }; }; fn read_uword(rd: *table_reader) (u32 | io::error) = { read_advance(rd, size(u32))?; let buf: [size(u32)]u8 = [0...]; match (io::readall(rd.src, buf)?) { case io::EOF => return 0: io::underread; case size => return endian::host.getu32(buf); }; }; fn read_ulong(rd: *table_reader) (u64 | io::error) = { read_advance(rd, size(u64))?; let buf: [size(u64)]u8 = [0...]; match (io::readall(rd.src, buf)?) { case io::EOF => return 0u64: io::underread: io::error; case size => return endian::host.getu64(buf); }; }; fn read_secword(rd: *table_reader) (u64 | io::error) = { if (rd.is64) { return read_ulong(rd)?; } else { return read_uword(rd)?: u64; }; }; fn read_uleb128(rd: *table_reader) (u64 | io::error) = { let bits = 0u64, val = 0u64; for (true) { const x = read_ubyte(rd)?; val |= (x & ~0x80) << bits; if (x & 0x80 == 0) break; bits += 7; }; return val; }; fn read_sleb128(rd: *table_reader) (i64 | io::error) = { let bits = 0u64, uval = 0u64; for (true) { const x = read_ubyte(rd)?; uval |= (x & ~0x80) << bits; bits += 7; if (x & 0x80 == 0) break; }; let val = uval: i64; let bits = bits: i64; if (val & (1 << (bits-1)) != 0) { val |= -1 << bits; }; return val; }; // Borrowed from underlying source fn read_slice(rd: *table_reader, amt: size) ([]u8 | io::error) = { match (memio::borrowedread(rd.src, amt)) { case let sl: []u8 => rd.length -= len(sl); return sl; case io::EOF => return 0: io::underread; }; }; // Borrowed from underlying source fn read_string(rd: *table_reader) (const str | io::error) = { // XXX: Leaks, should probably borrow from memio match (bufio::read_tok(rd.src, 0)?) { case let data: []u8 => rd.length -= len(data) + 1; return strings::fromutf8(data)!; case io::EOF => return 0: io::underread; }; }; hare-0.24.2/debug/dwarf/strings.ha000066400000000000000000000013311464473310100167130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use format::elf; use io; use types::c; export type string_table = struct { data: []u8, }; // Loads a DWARF string table from .debug_str. export fn load_strings( image: *image::image, ) (string_table | void | io::error) = { const sec = match (image::section_byname(image, ".debug_str")) { case let sec: *elf::section64 => yield sec; case null => return; }; return string_table { data = image::section_data(image, sec), }; }; // Returns a string from the string table. export fn get_strp(table: *string_table, offs: u64) const str = { const string = &table.data[offs]: *const c::char; return c::tostr(string)!; }; hare-0.24.2/debug/fault.ha000066400000000000000000000070361464473310100152420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use debug::image; use rt; use unix::signal; use unix::signal::{sig}; use fmt; // altstack.s let altstack: [ALTSTACK_SIZE]uintptr; // 16 KiB, sync with altstack.s def ALTSTACK_SIZE: size = 16384; @init fn init_overflow() void = { rt::sigaltstack(&rt::stack_t { ss_sp = rt::malloc(ALTSTACK_SIZE): *opaque, ss_flags = 0, ss_size = ALTSTACK_SIZE, }, null)!; signal::handle(sig::SEGV, &signal_handler, signal::flag::ONSTACK); signal::handle(sig::FPE, &signal_handler, signal::flag::ONSTACK); signal::handle(sig::BUS, &signal_handler, signal::flag::ONSTACK); signal::handle(sig::ILL, &signal_handler, signal::flag::ONSTACK); }; fn signal_handler(sig: sig, info: *signal::siginfo, uctx: *opaque) void = { signal::resetall(); const ip = uctx_ip(uctx); const sp = uctx_sp(uctx); const addr = info.addr: uintptr; let frame = uctx_frame(uctx); switch (sig) { case sig::SEGV => const is_overflow = addr & ~0xFFFF == sp & ~0xFFFF; fmt::errorfln("{} ({}) at address 0x{:x}", if (is_overflow) "Stack overflow" else "Illegal pointer access", errcode_str(sig, info.code), addr): void; case sig::BUS => fmt::errorfln("Bus error ({}) at address 0x{:x}", errcode_str(sig, info.code), addr): void; case sig::FPE => // addr is the location of the faulting instruction, construct // an additional synethetic stack frame let copy = frame; frame = mkframe(©, addr); fmt::errorfln("Arithmetic exception ({})", errcode_str(sig, info.code)): void; case => void; }; const self = match (image::self()) { case let img: image::image => yield img; case => halt(); }; defer image::close(&self); fmt::errorln("Backtrace:"): void; backtrace(&self, frame); halt(); }; fn errcode_str(sig: sig, code: signal::code) const str = { // Note: this only handles a few cases by design // It also is limited only to error codes defined by POSIX switch (sig) { case sig::ILL => switch (code) { case signal::code::ILLOPC => return "illegal opcode"; case signal::code::ILLOPN => return "illegal operand"; case signal::code::ILLADR => return "illegal addressing mode"; case signal::code::ILLTRP => return "illegal trap"; case signal::code::PRVOPC => return "privileged opcode"; case signal::code::PRVREG => return "privileged register"; case signal::code::COPROC => return "coprocessor error"; case signal::code::BADSTK => return "internal stack error"; case => void; }; case sig::FPE => switch (code) { case signal::code::INTDIV => return "integer divide by zero"; case signal::code::INTOVF => return "integer overflow"; case signal::code::FLTDIV => return "floating-point divide by zero"; case signal::code::FLTOVF => return "floating-point overflow"; case signal::code::FLTUND => return "floating-point underflow"; case signal::code::FLTRES => return "floating-point inexact result"; case signal::code::FLTINV => return "invalid floating-point operation"; case signal::code::FLTSUB => return "subscript out of range"; case => void; }; case sig::SEGV => switch (code) { case signal::code::MAPERR => return "address not mapped to object"; case signal::code::ACCERR => return "invalid permissions for mapped object"; case => void; }; case sig::BUS => switch (code) { case signal::code::ADRALN => return "invalid address alignment"; case signal::code::ADRERR => return "nonexistent physical address"; case signal::code::OBJERR => return "object-specific hardware error"; case => void; }; case => void; }; return "unknown reason"; }; hare-0.24.2/debug/ident.ha000066400000000000000000000011231464473310100152210ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use strings; // Converts a symbol name to a Hare identifier. The return value is statically // allocated. export fn symname_to_ident(name: str) const str = { static let buf: [MAX_SYMNAME * 2]u8 = [0...]; let slice = buf[..0]; const iter = strings::iter(name); for (const rn => strings::next(&iter)) { if (rn == '.') { static append(slice, ':'); static append(slice, ':'); } else { static append(slice, utf8::encoderune(rn)...); }; }; return strings::fromutf8(slice)!; }; hare-0.24.2/debug/image/000077500000000000000000000000001464473310100146715ustar00rootroot00000000000000hare-0.24.2/debug/image/README000066400000000000000000000004711464473310100155530ustar00rootroot00000000000000This module implements functionality for examining executable files. It provides some support code for working with memory-mapped ELF executables. That this module does not make compatibility guarantees and is subject to change in the future should Hare be ported to a target with a different executable format. hare-0.24.2/debug/image/open.ha000066400000000000000000000026011464473310100161430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; use format::elf::{shn}; use io; export type image = struct { fd: io::file, data: []u8, header: *elf::header64, // Cached sections shstrtab: nullable *elf::section64, symtab: nullable *elf::section64, strtab: nullable *elf::section64, debug_abbr: nullable *elf::section64, debug_aranges: nullable *elf::section64, debug_info: nullable *elf::section64, debug_line: nullable *elf::section64, debug_str: nullable *elf::section64, }; // Opens an [[io::file]] as a program image. export fn open( file: io::file, ) (image | io::error) = { const orig = io::tell(file)?; io::seek(file, 0, io::whence::END)?; const length = io::tell(file)?: size; io::seek(file, orig, io::whence::SET)?; const base = io::mmap(null, length, io::prot::READ, io::mflag::PRIVATE, file, 0z)?; const data = (base: *[*]u8)[..length]; const head = base: *elf::header64; let shstrtab: nullable *elf::section64 = null; if (head.e_shstrndx != shn::UNDEF) { const shoffs = head.e_shoff + head.e_shstrndx * head.e_shentsize; shstrtab = &data[shoffs]: *elf::section64; }; return image { fd = file, data = data, header = head, shstrtab = shstrtab, ... }; }; // Closes a program [[image]]. export fn close(image: *image) void = { io::munmap(&image.data[0], len(image.data))!; io::close(image.fd)!; }; hare-0.24.2/debug/image/sections.ha000066400000000000000000000051311464473310100170320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; use format::elf::{sht}; use types::c; use memio; // Check that this section is actually a reference to this image. fn section_validate(image: *image, sec: *elf::section64) void = { const addr = sec: uintptr; const min = &image.data[0]: uintptr; const max = min + len(image.data): uintptr; assert(min <= addr && max > addr, "section_name: invalid section"); }; // Returns a program section by name. Returns null if there is no such section, // or if the section names are not available in this image (e.g. because it was // stripped). export fn section_byname( image: *image, name: str, ) nullable *elf::section64 = { const cached = [ (".symtab", &image.symtab), (".strtab", &image.strtab), (".debug_abbr", &image.debug_abbr), (".debug_aranges", &image.debug_aranges), (".debug_info", &image.debug_info), (".debug_line", &image.debug_line), (".debug_str", &image.debug_str), ]; for (const (cand, val) .. cached) { if (cand == name) { match (*val) { case null => break; case let sec: *elf::section64 => return sec; }; }; }; const head = image.header; let r: nullable *elf::section64 = null; for (let i = 0u16; i < head.e_shnum; i += 1) { const shoffs = head.e_shoff + i * head.e_shentsize; const sec = &image.data[shoffs]: *elf::section64; if (sec.sh_type == sht::NULL) { continue; }; const cand = section_name(image, sec); if (cand == name) { r = sec; break; }; }; match (r) { case null => return null; case let sec: *elf::section64 => for (let (cand, val) .. cached) { if (cand == name) { *val = sec; break; }; }; }; return r; }; // Returns the name of this [[elf::section64]], returning "" if the section // names are not available in this image (i.e. it has been stripped). export fn section_name( image: *image, sec: *elf::section64, ) const str = { section_validate(image, sec); const shtab = match (image.shstrtab) { case let sec: *elf::section64 => yield sec; case null => return ""; }; const offs = shtab.sh_offset + sec.sh_name; return c::tostr(&image.data[offs]: *const c::char)!; }; // Returns a slice of the data contained with a given section. export fn section_data(image: *image, sec: *elf::section64) []u8 = { section_validate(image, sec); return image.data[sec.sh_offset..sec.sh_offset+sec.sh_size]; }; // Returns a [[memio::fixed]] reader for the given section. export fn section_reader(image: *image, sec: *elf::section64) memio::stream = { const data = section_data(image, sec); return memio::fixed(data); }; hare-0.24.2/debug/image/self+freebsd.ha000066400000000000000000000021331464473310100175410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use path; use rt; use types::c; // Opens the executing process's binary image. export fn self() (image | io::error | fs::error) = { // 1: sysctl let buf: [path::MAX * 2 + 1]u8 = [0...]; let pathsz = len(buf); match (rt::sysctlbyname("kern.proc.pathname", &buf[0], &pathsz, null, 0)) { case rt::errno => void; case void => const file = os::open(c::tostr(&buf[0]: *const c::char)!)?; match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; }; // 2. procfs (not mounted by default, but better than step 3) match (os::open("/proc/curproc/exe")) { case let file: io::file => match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; case => void; }; // 3. Fallback (os::args[0]) return self_argv(); }; hare-0.24.2/debug/image/self+linux.ha000066400000000000000000000011111464473310100172610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; // Opens the executing process's binary image. export fn self() (image | io::error | fs::error) = { const file = match (os::open("/proc/self/exe")) { case let file: io::file => yield file; case => // procfs may not be available, try fallback return self_argv(); }; match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; }; hare-0.24.2/debug/image/self+netbsd.ha000066400000000000000000000021471464473310100174130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use path; use rt; use types::c; // Opens the executing process's binary image. export fn self() (image | io::error | fs::error) = { // 1: sysctl let buf: [path::MAX * 2 + 1]u8 = [0...]; let pathsz = len(buf); match (rt::sysctl([rt::CTL_KERN, rt::KERN_PROC_PATHNAME], &buf[0], &pathsz, null, 0)) { case rt::errno => void; case void => const file = os::open(c::tostr(&buf[0]: *const c::char)!)?; match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; }; // 2. procfs (not mounted by default, but better than step 3) match (os::open("/proc/curproc/exe")) { case let file: io::file => match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; case => void; }; // 3. Fallback (os::args[0]) return self_argv(); }; hare-0.24.2/debug/image/self+openbsd.ha000066400000000000000000000004161464473310100175630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use io; // Opens the executing process's binary image. export fn self() (image | io::error | fs::error) = { // OpenBSD only supports the fallback approach. return self_argv(); }; hare-0.24.2/debug/image/self_argv.ha000066400000000000000000000011371464473310100171550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use os::exec; // Fallback implementation of self() that performs path resolution on argv[0] fn self_argv() (image | io::error | fs::error) = { match (exec::lookup(os::args[0])) { case let path: str => const file = os::open(path)?; match (open(file)) { case let img: image => return img; case let err: io::error => return err; case errors::invalid => abort("Running program image is not a valid ELF file"); }; case void => return errors::noentry: fs::error; }; }; hare-0.24.2/debug/symbols.ha000066400000000000000000000050271464473310100156150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use debug::image; use io; use format::elf; use strings; use types::c; // Returns symbol information by name. export fn symbol_byname( image: *image::image, name: str, ) (elf::sym64 | io::error | void) = { const strtab = match (image::section_byname(image, ".strtab")) { case let sec: *elf::section64 => yield sec; case null => return; }; const symtab = match (image::section_byname(image, ".symtab")) { case let sec: *elf::section64 => yield sec; case null => return; }; const st_name = scan_strtab(image, strtab, name) as u64; const data = image::section_data(image, symtab); const entsz = symtab.sh_entsize: size; const nsym = len(data) / entsz; for (let i = 0z; i < nsym; i += 1) { const sym = &data[i * entsz]: *elf::sym64; if (sym.st_name == st_name) { return *sym; }; }; }; // Returns the symbol that occupies a given address. export fn symbol_byaddr( image: *image::image, addr: uintptr, ) (elf::sym64 | io::error | void) = { const addr = addr: u64; const symtab = match (image::section_byname(image, ".symtab")) { case let sec: *elf::section64 => yield sec; case null => return; }; const data = image::section_data(image, symtab); const entsz = symtab.sh_entsize: size; const nsym = len(data) / entsz; for (let i = 0z; i < nsym; i += 1) { const sym = &data[i * entsz]: *elf::sym64; const min = sym.st_value; const max = sym.st_value + sym.st_size; if (min <= addr && addr < max) { return *sym; }; }; }; // Returns the name of the given symbol, or void if the executable was stripped. export fn symbol_name( image: *image::image, sym: *elf::sym64, ) (const str | io::error | void) = { const strtab = match (image::section_byname(image, ".strtab")) { case let sec: *elf::section64 => yield sec; case null => return; }; const data = image::section_data(image, strtab); return c::tostr(&data[sym.st_name]: *const c::char)!; }; // Scans a string table for a given name and returns the index of that name. fn scan_strtab( image: *image::image, strtab: *elf::section64, name: str, ) (u64 | io::error | void) = { let buf: [4096]u8 = [0...]; let namebuf: [MAX_SYMNAME]u8 = [0...]; // Prepare a nul-terminated byte slice of the name let name = strings::toutf8(name); namebuf[..len(name)] = name; namebuf[len(name)] = 0; name = namebuf[..len(name)+1]; const data = image::section_data(image, strtab); match (bytes::index(data, name)) { case let z: size => return z: u64; case void => void; }; }; hare-0.24.2/debug/testaddr.ha000066400000000000000000000010351464473310100157320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; fn isaddrmapped(addr: *opaque) bool = { // This is a hack, but it's a common pattern on POSIX for testing the // validity of an address. static let pipefd: [2]int = [0, 0]; if (pipefd[0] == 0) { match (rt::pipe2(&pipefd, 0)) { case rt::errno => return false; case void => yield; }; }; match (rt::write(pipefd[1], addr, 1)) { case let err: rt::errno => assert(err == rt::EFAULT); return false; case size => return true; }; }; hare-0.24.2/dirs/000077500000000000000000000000001464473310100134625ustar00rootroot00000000000000hare-0.24.2/dirs/README000066400000000000000000000003701464473310100143420ustar00rootroot00000000000000The dirs module provides access to common paths and directories used for storing application data. This module is compatible with the XDG base directories specification: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html hare-0.24.2/dirs/xdg.ha000066400000000000000000000065131464473310100145630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use fs; use os; use path; use unix; fn lookup(prog: str, var: str, default: str) str = { static let buf = path::buffer { ... }; path::set(&buf)!; match (os::getenv(var)) { case let s: str => const path = path::push(&buf, s, prog)!; if (!path::abs(path)) { yield; }; match (os::stat(path)) { case let err: fs::error => os::mkdirs(path, 0o755)!; return path; case let st: fs::filestat => if (fs::isdir(st.mode)) { return path; }; }; case void => void; }; const home = os::getenv("HOME") as str; const path = path::set(&buf, home, default, prog)!; match (os::mkdirs(path, 0o755)) { case let err: fs::error => fmt::fatalf("Error creating {}: {}", path, fs::strerror(err)); case void => void; }; return path; }; // Returns a directory suitable for storing config files. The "prog" parameter // should be a descriptive name unique to this program. The return value is // statically allocated and will be overwritten on subsequent calls to any // function in the dirs module. export fn config(prog: str) str = lookup(prog, "XDG_CONFIG_HOME", ".config"); // Returns a directory suitable for cache files. The "prog" parameter should be // a descriptive name unique to this program. The return value is statically // allocated and will be overwritten on subsequent calls to any function in the // dirs module. export fn cache(prog: str) str = lookup(prog, "XDG_CACHE_HOME", ".cache"); // Returns a directory suitable for persistent data files. The "prog" parameter // should be a descriptive name unique to this program. The return value is // statically allocated and will be overwritten on subsequent calls to any // function in the dirs module. export fn data(prog: str) str = { static let buf = path::buffer { ... }; const fragment = path::set(&buf, ".local", "share")!; return lookup(prog, "XDG_DATA_HOME", fragment); }; // Returns a directory suitable for storing program state data. The "prog" // parameter should be a descriptive name unique to this program. The return // value is statically allocated and will be overwritten on subsequent calls to // any function in the dirs module. export fn state(prog: str) str = { static let buf = path::buffer { ... }; const fragment = path::set(&buf, ".local", "state")!; return lookup(prog, "XDG_STATE_HOME", fragment); }; // Returns a directory suitable for storing non-essential runtime files and // other file objects (such as sockets, named pipes, and so on). Applications // should use this directory for communication and synchronization purposes and // should not place larger files in it, since it might reside in runtime memory // and cannot necessarily be swapped out to disk. // // The specification requires the directory to be owned by the current user and // not be world-readable. No fallback is implemented in case XDG_RUNTIME_DIR is // unset or incorrectly set up. export fn runtime() (str | fs::error) = { let path = match (os::getenv("XDG_RUNTIME_DIR")) { case let path: str => yield path; case void => return errors::noentry; }; const st = os::stat(path)?; const uid = unix::getuid(): uint; if (st.uid != uid || fs::mode_perm(st.mode) != fs::mode::USER_RWX) { return errors::noaccess; }; if (!fs::isdir(st.mode)) { return fs::wrongtype; }; return path; }; hare-0.24.2/docs/000077500000000000000000000000001464473310100134515ustar00rootroot00000000000000hare-0.24.2/docs/hare-build.1.scd000066400000000000000000000110161464473310100163160ustar00rootroot00000000000000hare-build(1) # NAME hare build - compile a Hare program or module # SYNOPSIS *hare build* [-hFqv]++ [-a _arch_]++ [-D _ident[:type]=value_]++ [-j _jobs_]++ [-L _libdir_]++ [-l _libname_]++ [-N _namespace_]++ [-o _path_]++ [-R]++ [-T _tagset_]++ [-t _type_]++ [_path_] # DESCRIPTION ; TODO: Decide on and document driver exit statuses *hare build* compiles a Hare program or module. The _path_ argument is a path to a Hare source file or to a directory which contains a Hare module (see *hare-module*(5)). If no path is given, the Hare module contained in the current working directory is built. # OPTIONS *-h* Print the help text. *-F* Build for freestanding (non-hosted) environment. See *FREESTANDING ENVIRONMENT*. *-q* Outside of errors, don't write anything to stdout while building. *-v* Enable verbose logging. Specify twice to increase verbosity. *-a* _arch_ Set the desired architecture for cross-compiling. See *ARCHITECTURES* for supported architecture names. *-D* _ident[:type]=value_ Define a constant in the type system. _ident_ is parsed as a Hare identifier (e.g. "foo::bar::baz"), _type_ as a Hare type (e.g. "str" or "struct { x: int, y: int }"), and _value_ as a Hare expression (e.g. "42"). Take care to address any necessary escaping to avoid conflicts between your shell syntax and Hare syntax. *-j* _jobs_ Set the maximum number of jobs to execute in parallel. The default is the number of processors available on the host. *-L* _libdir_ Add a directory to the linker library search path. *-l* _libname_ Link with the named system library. The name is passed directly to the linker. Linking with any library will also link with *libc*(7) and add the +libc tag to the default build tags (see *BUILD TAGS* in *hare-module*(5)). *-N* _namespace_ Override the namespace for the module. *-o* _path_ Set the output file to the given path. Setting the path to *-* causes output to be written to stdout. *-R* Build in release mode. In debug mode (the default), the debug:: module is imported as a dependency, which automatically installs a number of runtime debugging features in your executable. See this module's documentation for details on these features. *-T* _tagset_ Set or unset build tags. See *BUILD TAGS* in *hare-module*(5). *-t* _type_ Set the build type. _type_ should be one of s, o, or bin, for assembly, compiled object, or compiled binary, respectively. The default build type is compiled binary. # ARCHITECTURES The *-a* flag is used for cross-compilation to a target architecture different from the host architecture. The following architectures are currently supported: - aarch64 - riscv64 - x86_64 The system usually provides reasonable defaults for the *AR*, *AS*, *LD*, and *CC* tools based on the desired target. However, you may wish to set these variables yourself to control the cross toolchain in use. # FREESTANDING ENVIRONMENT If run with *-F*, hare build will target a freestanding environment. This has the following effects: - No constraints are imposed on the signature of "main" - Specifying external libraries with *-l* will *not* automatically: - Link with libc (add *-lc* manually if required) - Add the +libc flag (add *-T+libc* manually if required) - Use the C compiler for linking (use *LD=cc* if required) # ENVIRONMENT The following environment variables affect *hare build*'s execution: |[ *HARECACHE* :< The path to the build cache. Defaults to *$XDG_CACHE_HOME/hare*, or *~/.cache/hare* if *$XDG_CACHE_HOME* isn't set. | *HAREPATH* : The list of directories to search for module dependencies in. See *hare-module*(5). | *NO_COLOR* : Disables all color output when set to a non-empty string. | *HAREC_COLOR* : Disables color output for *harec* when set to 0, enables it when set to any other value. This overrides *NO_COLOR*. | *HAREC* : Name of the *harec* command to use. | *HARECFLAGS* : Additional flags to pass to *harec*. | *QBE* : Name of the *qbe* command to use. | *QBEFLAGS* : Additional flags to pass to *qbe*. | *AR* : Name of the *ar*(1) command to use. | *ARFLAGS* : Additional flags to pass to *ar*(1). | *AS* : Name of the *as*(1) command to use. | *ASFLAGS* : Additional flags to pass to *as*(1). | *LD* : Name of the *ld*(1) command to use. | *LDLINKFLAGS* : Additional flags to pass to *ld*(1). | *CC* : Name of the *cc*(1) command to use when linking external libraries. | *LDFLAGS* : Additional linker flags to pass to *cc*(1). # SEE ALSO *hare-run*(1), *hare-test*(1), *hare-module*(5), *ar*(1), *as*(1), *cc*(1), *ld*(1) hare-0.24.2/docs/hare-cache.1.scd000066400000000000000000000011261464473310100162630ustar00rootroot00000000000000hare-cache(1) # NAME hare cache - inspect and manage the build cache # SYNOPSIS *hare cache* [-hc] # DESCRIPTION *hare cache* provides tools to manage the build cache. If no options are supplied, the path and disk usage of the cache are printed. # OPTIONS *-h* Print the help text. *-c* Clear the cache. # ENVIRONMENT The following environment variables affect *hare cache*'s execution: |[ *HARECACHE* :< The path to the build cache. Defaults to *$XDG_CACHE_HOME/hare*, or *~/.cache/hare* if *$XDG_CACHE_HOME* isn't set. # SEE ALSO *hare-build*(1), *hare-run*(1), *hare-test*(1) hare-0.24.2/docs/hare-deps.1.scd000066400000000000000000000020551464473310100161550ustar00rootroot00000000000000hare-deps(1) # NAME hare deps - display the dependency tree of a Hare program or module # SYNOPSIS *hare deps* [-hd] [-T _tagset_] [_path_|_module_] # DESCRIPTION *hare deps* displays the dependency tree of a Hare program or module, as per the algorithm described in *DEPENDENCY RESOLUTION* in *hare-module*(5). The _path_ argument is a path to a Hare source file or a directory which contains a Hare module (see *hare-module*(5)). If no path is given, the Hare module contained in the current working directly is used. By default, the dependency tree is pretty-printed using Unicode box-drawing characters. # OPTIONS *-h* Print the help text. *-d* Print the dependency tree as a dot file for use with *graphviz*(1). *-T* _tagset_ Set or unset build tags. See *BUILD TAGS* in *hare-module*(5). # ENVIRONMENT The following environment variables affect *hare deps*' execution: |[ *HAREPATH* :< The list of directories to search for dependencies in. | *NO_COLOR* : Disables all color output when set to a non-empty string. # SEE ALSO *hare-module*(5) hare-0.24.2/docs/hare-module.5.scd000066400000000000000000000067221464473310100165200ustar00rootroot00000000000000hare-module(5) # NAME hare-module - Hare module layout # DESCRIPTION Hare modules are represented as directories in the filesystem. A directory is a valid Hare module if it contains at least one Hare source file (with the file extension *.ha*), or if it contains a file named *README*. All files which end in *.ha*, *.s*, and *.o* are treated as inputs to the module, and are respectively treated as Hare sources, assembly sources, and objects to be linked into the final binary. The list of files considered eligible may be filtered by build tags (see *BUILD TAGS* below). The format for the filename is _name_[_tagset_]._ext_, where the _name_ is user-defined, the _ext_ is either *ha*, *s*, or *o*, and a tagset (see *BUILD TAGS*) is optionally provided after the name. A file will only be included if all tags included (with +) in the tagset are present, and no tags excluded (with -) in the tagset are present. Only one file for a given combination of _name_ and _ext_ will be selected for the build; the file selected is the one with the most tag specifiers. If there are two or more such files, the build driver will error out. For example, if the following files are present in a directory: - foo.ha - bar.ha - bar+linux.ha - bar+plan9.ha - baz+x86_64.s - bat-x86_64.ha If the build tags are +linux+x86_64, then the files which are included in the module are foo.ha, bar+linux.ha, and baz+x86_64.s. If the following files are added: - meep+linux-libc.ha - meep+linux+x86_64.ha then the build driver will error out, unless +libc is added to the build tags. Additionally, subdirectories in a module will be considered part of that module if their name consists only of a tagset, e.g. "+linux" or "-x86_64". A directory with only a name (but without a tagset, e.g. "example") is considered a submodule, and as such must be imported separately. For example, "foo::bar" refers to foo/bar/. If a directory name contains both a name and a tagset, the build driver will error out. # DEPENDENCY RESOLUTION The "use" directives in each Hare source file used as an input to *hare-build*(1), *hare-run*(1), or *hare-test*(1) are scanned and used to determine the dependencies for a program. This process is repeated for each dependency to obtain a complete dependency tree. Dependencies are searched for by examining first the current working directory, then each component of the *HAREPATH*, which is a list of paths separated by colons. *HAREPATH* is obtained from the environment variable of the same name. If the environment variable is unset, a default value is used, which can be viewed with the *hare version -v* command. Typically, it is set to include the path to the standard library installed on the system, as well as a system-provided location for third-party modules installed via the system package manager. *hare-deps*(1) may be used to print the dependency tree of a Hare module. # BUILD TAGS Build tags allow you to add constraints on what features or platforms are enabled for your build. A tag is a name, consisting of characters which aren't any of '+', '-', or '.', and a '+' or '-' prefix to signal inclusivity or exclusivity. To add or remove build tags, use the *-T* flag. For example, *-T +foo-bar* will add the 'foo' tag and remove the 'bar' tag. Some tags are enabled by default, enabling features for the host platform. You can view the default tagset by running *hare version -v*. To remove all default tags, use *-T^*. # SEE ALSO *hare*(1), *hare-build*(1), *hare-run*(1), *hare-test*(1) hare-0.24.2/docs/hare-run.1.scd000066400000000000000000000013311464473310100160220ustar00rootroot00000000000000hare-run(1) # NAME hare run - compile and run a Hare program or module # SYNOPSIS *hare run* [-hqv]++ [-a _arch_]++ [-D _ident[:type]=value_]++ [-j _jobs_]++ [-L _libdir_]++ [-l _libname_]++ [-R]++ [-T _tagset_]++ [_path_ [_args_...]] # DESCRIPTION *hare run* compiles and runs a Hare program or module. The _path_ argument is a path to a Hare source file or to a directory which contains a Hare module (see *hare-module*(5)). If no path is given, the Hare module contained in the current working directory is run. The remaining _args_ are passed to the compiled program. # OPTIONS Refer to *hare-build*(1). # ENVIRONMENT Refer to *hare-build*(1). # SEE ALSO *hare-build*(1), *hare-test*(1), *hare-module*(5) hare-0.24.2/docs/hare-test.1.scd000066400000000000000000000017111464473310100161770ustar00rootroot00000000000000hare-test(1) # NAME hare test - compile and run tests for Hare code # SYNOPSIS *hare test* [-hqv]++ [-a _arch_]++ [-D _ident[:type]=value_]++ [-j _jobs_]++ [-L _libdir_]++ [-l _libname_]++ [-o _path_]++ [-R]++ [-T _tagset_]++ [_path_ [_tests_...]] # DESCRIPTION *hare test* compiles and runs tests for a Hare program or module. The +test tag is added to the default build tags (see *BUILD TAGS* in *hare-module*(5)). If no _path_ is given, all Hare modules in the current working directory are recursively discovered, built, and their tests made eligible for the test run. Otherwise, if a _path_ is given, the source file or module is built and tested. If no _tests_ are supplied, all eligible tests are run. Otherwise, each argument is interpreted as a *glob*(7) pattern, giving the names of the tests to run. # OPTIONS Refer to *hare-build*(1). # ENVIRONMENT Refer to *hare-build*(1). # SEE ALSO *hare-build*(1), *hare-run*(1), *hare-module*(5) hare-0.24.2/docs/hare.1.scd000066400000000000000000000024711464473310100152260ustar00rootroot00000000000000hare(1) # NAME hare - compile, run, test, and inspect Hare programs and modules # SYNOPSIS *hare* -h *hare* version [-hv] *hare* _command_ [_arguments_...] # DESCRIPTION *hare -h* prints help text. *hare version* prints version information for the *hare* program. If *-v* is supplied, it also prints information about the build parameters, in an output format that's consistent for machine reading: the first line is always *hare $version*, and subsequent lines give configuration values in the form of a name on its own line unindenteed, followed by any number of values, each on its own line indented with a single tab. *hare-build*(1) compiles a Hare program or module. *hare-cache*(1) manages the build cache. *hare-deps*(1) displays the dependency tree of a Hare program or module. *hare-run*(1) compiles and runs a Hare program or module. *hare-test*(1) compiles and runs tests for Hare code. # BUGS The quality of error messages is poor. # SEE ALSO *hare-module*(5), *haredoc*(1) See _https://harelang.org/community/_ for information on where to ask questions, send patches, submit bug reports, and chat with others in the community. Documentation for the language itself can be found at _https://harelang.org/documentation/_. The language specification is available at _https://harelang.org/specification/_. hare-0.24.2/docs/haredoc.1.scd000066400000000000000000000055631464473310100157210ustar00rootroot00000000000000haredoc(1) # NAME haredoc - read and format Hare documentation # SYNOPSIS *haredoc* [-hat] [-F _format_] [-T _tagset_] [_identifier_|_path_] # DESCRIPTION *haredoc* reads documentation from a source file or module. If no identifier or path is supplied, documentation is read from the Hare module contained in the current working directory, or from the root of the standard library if the current working directory doesn't contain a Hare module (see *hare-module*(5)). If an identifier is supplied, it's first looked up as a declaration. If no suitable declaration exists, it's looked up as a module instead. The identifier may also include a trailing ::, in which case it will always be treated as a module. The identifier is resolved using the algorithm described in *DEPENDENCY RESOLUTION* in *hare-module*(5). # OPTIONS *-h* Print the help text. *-a* Show undocumented members. *-F* _format_ Select output format (one of "html" or "tty"). The default is "tty". *-t* Disable HTML template (only applies to *-Fhtml*). *-T* _tagset_ Set or unset build tags. See *BUILD TAGS* in *hare-module*(5). # CUSTOMIZING COLORS Unless the *NO_COLOR* environment variable is set to a non-empty string, colors are rendered in the terminal with ANSI SGR escape sequences. These sequences can be customized with the *HAREDOC_COLORS* environment variable, which follows this whitespace-delimited format: HAREDOC\_COLORS='_key_=_seq_ _key_=_seq_ _..._' Each _key=seq_ entry assigns a valid _seq_ SGR sequence to a _key_ syntax category. A valid _seq_ must consist only of digits and semicolons, or must be a single underscore "\_". Here are the initial default entries: . normal "0" . primary "\_" (-> normal) . ident "\_" (-> normal) . comment "1" . constant "\_" (-> primary) . function "\_" (-> primary) . global "\_" (-> primary) . typedef "\_" (-> primary) . import_alias "\_" (-> normal) . secondary "\_" (-> normal) . keyword "94" . type "96" . attribute "33" . operator "1" . punctuation "\_" (-> normal) . rune_string "91" . number "95" . label "\_" (-> normal) Any number of entries can be specified. If a _seq_ is an underscore "\_", then the sequence specified for "normal" is used, unless _key_ is "constant", "function", "global", or "typedef", in which case the sequence specified for "primary" is used. Otherwise, if a _seq_ is invalid, blank, empty, or absent, its corresponding default sequence is used. For example: HAREDOC\_COLORS='comment=3 primary=1;4 attribute=41' haredoc log # ENVIRONMENT The following environment variables affect *haredoc*'s execution: |[ *HAREPATH* :< The list of directories to search for modules in. See *hare-module*(5). | *NO_COLOR* : Disables all color output when set to a non-empty string. | *HAREDOC_COLORS* : See *CUSTOMIZING COLORS*. # SEE ALSO *haredoc*(5) hare-0.24.2/docs/haredoc.5.scd000066400000000000000000000041241464473310100157150ustar00rootroot00000000000000haredoc(5) # NAME haredoc - Hare documentation format # DESCRIPTION Hare documentation is written in a simple markup language. *haredoc*(1) will display the documentation literally, without any additional formatting. Other tools may format Hare documentation into other formats. Text may be written normally, broken into several lines to conform to the 80-column limit. To begin a new paragraph, insert an empty line. References to other declarations and modules may be written in brackets, like this: [[os::stdout]]. References to modules should include a trailing :: in the identifier: [[os::exec::]]. A bulleted list can be started by opening a line with "-", optionally preceded by a space. Each line opened like this begins a new list item. To complete the list, insert an empty line. Code samples may be used by starting a line with a single tab, optionally preceded by a space. This markup language is extracted from Hare comments preceding exported symbols in your source code, and from a file named "README" in your module directory, if present. # EXAMPLE ``` // Foos the bars. See also [[foobar]]. // // If you instead want to bar the foos, use one of the functions in // [[bar::foo::]]. // // - First, the bars are obtained. // - They are then fooed. // - Finally, the result is returned. // // let x = example(); // assert(x == 0); export fn example() int = 0; ``` # NOTES It's expected that tools which parse documentation for the purpose of converting it into another format will perform additional processing to decouple the content from its original textual representation: - Line breaks within a paragraph or list item should be ignored. - Repeated whitespace outside of a code sample should be collapsed. - Multiple code samples separated by empty lines should be collapsed into one code sample, so the empty lines are moved into the code sample itself. *hare::parse::doc::* in the standard library handles all of this processing for you. Parsers are permitted (and encouraged) to error out on invalid input, such as a malformed or unterminated [[reference]]. # SEE ALSO *haredoc*(1) hare-0.24.2/docs/rfc-template.txt000066400000000000000000000030371464473310100166000ustar00rootroot00000000000000 RFC SUMMARY Free-form brief summary of the RFC's goals, 1-2 paragraphs in length. LANGUAGE IMPLICATIONS Enumerate proposed language changes in this section, if any. Put "None" here if there are no language implications. STANDARD LIBRARY IMPLICATIONS Enumerate proposed standard library changes in this section, if any. Focus on breaking changes to the standard library's API over implementation details, unless implementation details are particularly important. Put "None" here if there are no standard library implications. ECOSYSTEM IMPLICATIONS Include considerations for the broader Hare ecosystem here, such as a survey estimating how many third-party codebases will be affected and how difficult it will be to implement the changes. If necessary, make a plan for alleviating the impact, such as automated migration tools (e.g. a sed script, or a dedicated tool for more complex migrations). Put "None" here if there are no ecosystem implications (though in this case, why is there an RFC for it?). EXAMPLE CODE Include in this section samples of example code as it will appear under this RFC's proposed changes. This section is mandatory. RELATED RFCS Include a link to relevant RFCs (such as the prior version) on the hare-rfc web archives, as well as a brief summary of changes from that version or the reason why this RFC is relevant. Put "None" here if there are no relevant RFCs. hare-0.24.2/docs/rfc.md000066400000000000000000000077361464473310100145620ustar00rootroot00000000000000# RFC process Large and important changes to the Hare programming language are implemented by a formal process of consensus with a "request for comments" (RFC). ## When to prepare an RFC? You may prepare an RFC for any change that you want to have a structured discussion about, large or small. The author of a proposed change may opt-in to the RFC process if they would find it useful for their work, or a maintainer or reviewer may invoke the RFC process for a given change at their discretion. As a rule of thumb, a change is more likely to require an RFC if any of the following conditions are met: - A change is controversial and requires discussion to secure consensus - A standard library change breaks a widely-used API - A language change requires most Hare users to rewrite their code - A large number of subsystems are implicated ## 0. Prior to submitting an RFC Ideas can form anywhere, but once you want to turn an idea into action it is important to discuss it in the official community spaces so that you can keep those affected in the loop and prepare people to participate in the consensus process. You can discuss ideas and early proposals, workshop RFC text, and so on, in the Hare IRC channels and mailing lists. Do some research to see which community members should participate in the discussion, including at a minimum the maintainers of relevant subsystems and a global maintainer. Seek out their feedback and guidance on your propsal. ## 1. Submitting an RFC RFCs are formally submitted to the [hare-rfc] mailing list. The subject line should be "[RFC v1] Subject...", where v1 increments for each revision of the proposal. Work-in-progress proposals may be submitted to this list with the "[DRAFT RFC]" subject prefix. The body of the RFC is free-form text, which should be formatted in accordance with typical [mailing list etiquette][0], and should include at a minimum the details of the proposed change, the rationale for the change, and the predicted impact of the change to end-users. Illustrative code samples and other supporting materials are encouraged to be included. See doc/rfc-template.txt for a sample RFC to get started. [hare-rfc]: https://lists.sr.ht/~sircmpwn/hare-rfc [0]: https://man.sr.ht/lists.sr.ht/etiquette.md You can start implementing the change proposed by the RFC for research or illustrative purposes, but keep in mind that following the discussion of the RFC much of this code might have to be rewritten. ## 2. Discussion The proposal is discussed following its submission, and will likely be refined. Participants will narrow down the details, determine if the implications are completely enumerated, and make plans for the implementation. This process will generally result in the RFC draft being adjusted to incorporate feedback and resubmitted with a new version number. ## 3. Approval A RFC does not require explicit approval to proceed to the implementation, though patch authors would be wise to read the room to determine if the potential code reviewers are satisfied with the status of the proposal, lest you write code based on it which will ultimately be rejected for foreseeable reasons. ## 4. Implementation Once the discussion participants are satisfied with the proposed RFC, the proposal authors (and/or anyone they convinced to help out during the discussion) should move forward with implementing the proposal and sending out the relevant patches. Once the implementation is complete, the authors should follow-up on the original proposal thread on the hare-rfc mailing list with details about the implementation (such as links to the relevant patches) to close the proposal and record its implementation for posterity. Proposal authors are also encouraged during the implementation phase to continue commenting on the RFC thread to record new insights, document deviations from the proposal that occured in practice, or to go back to the drawing board and prepare a new revision with the lessons learned from the code. ## FAQ ### Who can submit an RFC? Anyone. hare-0.24.2/docs/stdlib.md000066400000000000000000000033161464473310100152570ustar00rootroot00000000000000# Hare stdlib mandate The Hare standard library shall provide: 2. An interface to the host operating system 3. Implementations of broadly useful algorithms 4. Implementations of broadly useful formats and protocols 1. Useful features to complement Hare language features 5. Introspective meta-features for Hare-aware programs Each of these services shall: 1. Have a concise and straightforward interface 2. Correctly and completely implement the useful subset of the required behavior* 3. Provide complete documentation for each exported symbol 4. Be sufficiently tested to provide confidence in the implementation \* This means read the RFC before you start writing the code Some examples of on-topic features include: ## Language features - Memory allocation - High-level string manipulation (e.g. concat, replace, split) - High-level slice manipulation (e.g. sort) - Test harness and testing support code ## Introspection - Hare lexing, parsing (and unparsing), and type checking - ELF, DWARF - Stack unwinding ## Operating system interface - I/O support - Filesystem access - Sockets ## Useful algorithms - Sorting, searching - Cryptography - Hashing - Compression - Date & time support - Regex ## Useful formats & protocols - Internet protocol suite - INI - tar, zip, cpio - MIME # Conventions See also the [Hare style guide](https://harelang.org/style/) 1. Tagged unions should be written from most to least common case, which generally puts the error cases last. 2. Prefer to design APIs which avoid allocation if it can be done without being at the expense of good API design. 3. Whatever the semantics, document the allocation and lifetime behaviors and expectations of each function to which they apply. hare-0.24.2/encoding/000077500000000000000000000000001464473310100143075ustar00rootroot00000000000000hare-0.24.2/encoding/README000066400000000000000000000000001464473310100151550ustar00rootroot00000000000000hare-0.24.2/encoding/asn1/000077500000000000000000000000001464473310100151515ustar00rootroot00000000000000hare-0.24.2/encoding/asn1/+test/000077500000000000000000000000001464473310100162035ustar00rootroot00000000000000hare-0.24.2/encoding/asn1/+test/decoder_test.ha000066400000000000000000000230771464473310100211720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; use os; use strings; use time::date; use types; // XXX: would be nice to just declare this as mem: memio::stream let mem: nullable *memio::stream = null; let rbuf: [os::BUFSZ]u8 = [0...]; fn d(i: []u8) decoder = { let buf = memio::fixed(i); let h = match (mem) { case null => let h = alloc(buf); mem = h; yield h; case let m: *memio::stream => *m = buf; yield m; }; return derdecoder(h); }; @fini fn freetdec() void = { match (mem) { case null => void; case let m: *memio::stream => free(m); mem = null; }; }; @test fn parsetag() void = { assert((next(&d([0x02, 0x01]))!).class == class::UNIVERSAL); assert((next(&d([0x02, 0x01]))!).tagid == 0x02); assert((next(&d([0x1e, 0x01]))!).tagid == 0x1e); assert((next(&d([0x1f, 0x7f, 0x01]))!).tagid == 0x7f); assert((next(&d([0x1f, 0x81, 0x00, 0x01]))!).tagid == 0x80); assert((next(&d([0x1f, 0x8f, 0xff, 0xff, 0xff, 0x7f, 0x01]))!).tagid == types::U32_MAX); assert(next(&d([0x1f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x01])) is invalid); }; @test fn parselen() void = { assert(dsz(next(&d([0x02, 0x1]))!) == 1); assert(dsz(next(&d([0x02, 0x7f]))!) == 127); assert(dsz(next(&d([0x02, 0x81, 0x80]))!) == 128); // must use minimal amount of bytes for length encoding assert(next(&d([0x02, 0x81, 0x01, 0x01])) is invalid); assert(next(&d([0x02, 0x81, 0x7f])) is invalid); assert(next(&d([0x02, 0x82, 0x00, 0xff])) is invalid); // indefinite form is not allowed in DER assert(next(&d([0x02, 0x80, 0x01, 0x00, 0x00])) is invalid); }; @test fn emptydata() void = { assert(read_bool(&d([])) is badformat); assert(open_set(&d([])) is badformat); }; @test fn seq() void = { let dat: [_]u8 = [ 0x30, 0x0a, // seq 0x01, 0x01, 0xff, // bool true 0x30, 0x05, // seq 0x30, 0x03, // seq 0x01, 0x01, 0x00, // bool false ]; let dc = &d(dat); open_seq(dc)!; assert(read_bool(dc)! == true); open_seq(dc)!; open_seq(dc)!; assert(read_bool(dc)! == false); close_seq(dc)!; close_seq(dc)!; close_seq(dc)!; finish(dc)!; let dc = &d(dat); open_seq(dc)!; assert(open_seq(dc) is invalid); let dc = &d(dat); open_seq(dc)!; assert(close_seq(dc) is badformat); let dat: [_]u8 = [ 0x30, 0x07, // seq 0x0c, 0x05, 0x65, 0x66, 0x67, 0xc3, 0x96, // utf8 string ]; let dc = &d(dat); open_seq(dc)!; let r = strreader(dc, utag::UTF8_STRING)!; let s = io::drain(&r)!; defer free(s); assert(bytes::equal([0x65, 0x66, 0x67, 0xc3, 0x96], s)); let dc = &d(dat); let buf: [4]u8 = [0...]; open_seq(dc)!; let r = strreader(dc, utag::UTF8_STRING)!; assert(io::read(&r, buf)! == 3); assert(close_seq(dc) is badformat); // check unclosed let dc = &d(dat); open_seq(dc)!; assert(finish(dc) is invalid); let dc = &d(dat); open_seq(dc)!; let r = strreader(dc, utag::UTF8_STRING)!; let s = io::drain(&r)!; defer free(s); assert(finish(dc) is invalid); }; @test fn invalid_seq() void = { let dat: [_]u8 = [ 0x30, 0x03, // seq containing data of size 3 0x02, 0x03, 0x01, 0x02, 0x03, // int 0x010203 overflows seq ]; let dc = &d(dat); open_seq(dc)!; let buf: [3]u8 = [0...]; assert(read_int(dc, buf) is invalid); }; @test fn read_implicit() void = { let dat: [_]u8 = [ 0x30, 0x06, // seq 0x85, 0x01, 0xff, // IMPLICIT bool true 0x01, 0x01, 0x00, // bool false ]; let dc = &d(dat); open_seq(dc)!; expect_implicit(dc, class::CONTEXT, 5)!; assert(read_bool(dc)! == true); assert(read_u16(dc) is badformat); }; @test fn read_bool() void = { assert(read_bool(&d([0x01, 0x01, 0xff]))!); assert(read_bool(&d([0x01, 0x01, 0x00]))! == false); assert(read_bool(&d([0x01, 0x02, 0x00, 0x00])) is invalid); // X.690, ch. 11.1 assert(read_bool(&d([0x01, 0x01, 0x01])) is invalid); // invalid class assert(read_bool(&d([0x81, 0x01, 0x01])) is badformat); // must be primitive assert(read_bool(&d([0x21, 0x01, 0x01])) is invalid); // invalid tag assert(read_bool(&d([0x02, 0x01, 0x01])) is badformat); }; @test fn read_null() void = { read_null(&d([0x05, 0x00]))!; read_null(&d([0x05, 0x01, 0x00])) is invalid; read_null(&d([0x85, 0x00])) is invalid; read_null(&d([0x01, 0x00])) is invalid; }; @test fn read_int() void = { let buf: [8]u8 = [0...]; assert(read_int(&d([0x02, 0x01, 0x01]), buf)! == 1); assert(buf[0] == 0x01); assert(read_int(&d([0x02, 0x01, 0x00]), buf)! == 1); assert(buf[0] == 0x00); assert(read_int(&d([0x02, 0x02, 0x01, 0x02]), buf)! == 2); assert(buf[0] == 0x01); assert(buf[1] == 0x02); // must have at least one byte assert(read_int(&d([0x02, 0x00]), buf) is invalid); // non minimal assert(read_int(&d([0x02, 0x02, 0x00, 0x01]), buf) is invalid); assert(read_int(&d([0x02, 0x02, 0xff, 0x81]), buf) is invalid); assert(read_u8(&d([0x02, 0x01, 0x00]))! == 0); assert(read_u8(&d([0x02, 0x01, 0x01]))! == 1); assert(read_u8(&d([0x02, 0x01, 0x7f]))! == 0x7f); assert(read_u8(&d([0x02, 0x01, 0x80])) is invalid); assert(read_u8(&d([0x02, 0x01, 0x81])) is invalid); assert(read_u8(&d([0x02, 0x02, 0x00, 0x80]))! == 0x80); assert(read_u8(&d([0x02, 0x02, 0x00, 0xff]))! == 0xff); assert(read_u16(&d([0x02, 0x01, 0x00]))! == 0); assert(read_u16(&d([0x02, 0x02, 0x0f, 0xff]))! == 0xfff); assert(read_u16(&d([0x02, 0x03, 0x00, 0xff, 0xff]))! == 0xffff); assert(read_u16(&d([0x02, 0x03, 0x01, 0xff, 0xff])) is invalid); assert(read_u32(&d([0x02, 0x03, 0x00, 0xff, 0xff]))! == 0xffff); let maxu64: [_]u8 = [ 0x02, 0x09, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]; assert(read_u64(&d(maxu64))! == 0xffffffffffffffff); maxu64[2] = 0x01; assert(read_u64(&d(maxu64)) is invalid); }; @test fn read_bitstr() void = { let buf: [8]u8 = [0...]; let bs = read_bitstr(&d([0x03, 0x01, 0x00]), buf)!; assert(len(bs.0) == 0 && bs.1 == 0); assert(bitstr_isset(bs, 0)! == false); let bs = read_bitstr(&d([0x03, 0x02, 0x00, 0xff]), buf)!; assert(bytes::equal(bs.0, [0xff]) && bs.1 == 0); assert(bitstr_isset(bs, 0)!); assert(bitstr_isset(bs, 7)!); let bs = read_bitstr(&d([0x03, 0x03, 0x04, 0xab, 0xc0]), buf)!; assert(bytes::equal(bs.0, [0xab, 0xc0]) && bs.1 == 4); assert(bitstr_isset(bs, 0)!); assert(bitstr_isset(bs, 1)! == false); assert(bitstr_isset(bs, 8)!); assert(bitstr_isset(bs, 9)!); assert(!bitstr_isset(bs, 11)!); assert(bitstr_isset(bs, 12) is invalid); // unused bits must be zero assert(read_bitstr(&d([0x03, 0x03, 0x04, 0xab, 0xc1]), buf) is invalid); assert(read_bitstr(&d([0x03, 0x03, 0x07, 0xab, 0x40]), buf) is invalid); }; let datbuf: [64]u8 = [0...]; fn newdatetime(s: str, tag: utag) []u8 = { let datetime = strings::toutf8(s); let datsz = len(datetime): u8; datbuf[..2] = [tag, datsz]; datbuf[2..2 + datsz] = datetime; return datbuf[..2 + datsz]; }; @test fn read_utctime() void = { let derdatetime = newdatetime("231030133710Z", utag::UTC_TIME); let dt = read_utctime(&d(derdatetime), 2046)!; let fbuf: [24]u8 = [0...]; assert(date::bsformat(fbuf, date::RFC3339, &dt)! == "2023-10-30T13:37:10+0000"); let dt = read_utctime(&d(derdatetime), 2020)!; assert(date::bsformat(fbuf, date::RFC3339, &dt)! == "1923-10-30T13:37:10+0000"); let derdatetime = newdatetime("2310301337100", utag::UTC_TIME); assert(read_utctime(&d(derdatetime), 2020) is error); let derdatetime = newdatetime("231030133710", utag::UTC_TIME); assert(read_utctime(&d(derdatetime), 2020) is error); let derdatetime = newdatetime("231030133a10Z", utag::UTC_TIME); assert(read_utctime(&d(derdatetime), 2020) is error); let derdatetime = newdatetime("231330133710Z", utag::UTC_TIME); assert(read_utctime(&d(derdatetime), 2020) is error); }; @test fn read_gtime() void = { let derdatetime = newdatetime("20231030133710Z", utag::GENERALIZED_TIME); let dt = read_gtime(&d(derdatetime))!; let fbuf: [32]u8 = [0...]; assert(date::bsformat(fbuf, date::RFC3339, &dt)! == "2023-10-30T13:37:10+0000"); let derdatetime = newdatetime("20231030133710.1Z", utag::GENERALIZED_TIME); let dt = read_gtime(&d(derdatetime))!; assert(date::bsformat(fbuf, date::STAMPNANO, &dt)! == "2023-10-30 13:37:10.100000000"); // must end with Z let derdatetime = newdatetime("20231030133710", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("202310301337100", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); // seconds must always be present let derdatetime = newdatetime("202310301337", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("202310301337Z", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); // fractional seconds must not end with 0. must be ommitted if 0 let derdatetime = newdatetime("20231030133710.", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("20231030133710.Z", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("20231030133710.0", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("20231030133710.0Z", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); let derdatetime = newdatetime("20231030133710.10Z", utag::GENERALIZED_TIME); assert(read_gtime(&d(derdatetime)) is error); // TODO midnight is YYYYMMDD000000Z }; @test fn read_oid() void = { let db = oiddb { lut = [0x03, 0x2b, 0x65, 0x70, 0x03, 0x55, 0x04, 0x03], index = [0, 4], names = ["ed25519", "id-at-commonName"], }; assert(read_oid(&d([0x06, 0x03, 0x55, 0x04, 0x03]), &db)! == 1); assert(stroid(&db, 1) == "id-at-commonName"); assert(bytes::equal([0x55, 0x04, 0x03], read_rawoid(&d([0x06, 0x03, 0x55, 0x04, 0x03]))!)); }; hare-0.24.2/encoding/asn1/+test/encoder_test.ha000066400000000000000000000063631464473310100212030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use memio; use types; @test fn write_id() void = { let buf = memio::dynamic(); defer io::close(&buf)!; let e = derencoder(&buf); write_fixedprim(&e, class::UNIVERSAL, 0x2aa, [0x00])!; encode(&e)!; assert(bytes::equal([0x1f, 0x85, 0x2a, 0x01, 0x00], memio::buffer(&buf))); io::seek(&buf, 0, io::whence::SET)!; let d = derdecoder(&buf); let h = peek(&d)!; assert(h.tagid == 0x2aa); let buf = memio::dynamic(); defer io::close(&buf)!; let e = derencoder(&buf); write_fixedprim(&e, class::UNIVERSAL, types::U32_MAX, [0x00])!; encode(&e)!; assert(bytes::equal([0x1f, 0x8f, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00], memio::buffer(&buf))); io::seek(&buf, 0, io::whence::SET)!; let d = derdecoder(&buf); let h = peek(&d)!; assert(h.tagid == types::U32_MAX); }; @test fn write_prim() void = { let buf = memio::dynamic(); defer io::close(&buf)!; let dest = memio::dynamic(); defer io::close(&dest)!; let enc = derencoder(&buf); create_prim(&enc, class::UNIVERSAL, utag::INTEGER)!; write(&enc, [0x01, 0x05, 0x07])!; finish_prim(&enc); assert(encodeto(&enc, &dest)! == 5); assert(bytes::equal(memio::buffer(&dest), [ 0x02, 0x03, 0x01, 0x05, 0x07 ])); }; @test fn encode_dsz() void = { assert(bytes::equal([0x7f], encode_dsz(0x7f))); assert(bytes::equal([0x81, 0x8f], encode_dsz(0x8f))); assert(bytes::equal([0x81, 0xff], encode_dsz(0xff))); assert(bytes::equal([0x82, 0x01, 0x00], encode_dsz(0x100))); }; @test fn write_seq() void = { let buf = memio::dynamic(); defer io::close(&buf)!; let dest = memio::dynamic(); defer io::close(&dest)!; let enc = derencoder(&buf); create_seq(&enc)!; write_bool(&enc, false)!; create_seq(&enc)!; write_int(&enc, [0x01, 0x02, 0x03])!; finish_seq(&enc); finish_seq(&enc); assert(encodeto(&enc, &dest)! == 12); assert(bytes::equal(memio::buffer(&dest), [ 0x30, 0x0a, // seq 0x01, 0x01, 0x00, // bool 0x30, 0x05, // seq 0x02, 0x03, 0x01, 0x02, 0x03, // int ])); }; @test fn write_bool() void = { let dest = memio::dynamic(); defer io::close(&dest)!; let buf = memio::dynamic(); defer io::close(&buf)!; let enc = derencoder(&buf); write_bool(&enc, true)!; encodeto(&enc, &dest)!; assert(bytes::equal(memio::buffer(&dest), [0x01, 0x01, 0xff])); }; @test fn write_int() void = { let dest = memio::dynamic(); defer io::close(&dest)!; let buf = memio::dynamic(); defer io::close(&buf)!; let enc = derencoder(&buf); write_int(&enc, [0x00, 0x00, 0x00, 0x00, 0x80])!; encodeto(&enc, &dest)!; assert(bytes::equal(memio::buffer(&dest), [0x02, 0x02, 0x00, 0x80])); memio::reset(&dest); memio::reset(&buf); let enc = derencoder(&buf); write_int(&enc, [0xff, 0xff, 0xff, 0x80, 0x10])!; encodeto(&enc, &dest)!; assert(bytes::equal(memio::buffer(&dest), [0x02, 0x02, 0x80, 0x10])); memio::reset(&dest); memio::reset(&buf); let enc = derencoder(&buf); write_int(&enc, [0x00, 0x00, 0x00])!; encodeto(&enc, &dest)!; assert(bytes::equal(memio::buffer(&dest), [0x02, 0x01, 0x00])); memio::reset(&dest); memio::reset(&buf); let enc = derencoder(&buf); write_uint(&enc, [0x8f, 0x01])!; encodeto(&enc, &dest)!; assert(bytes::equal(memio::buffer(&dest), [0x02, 0x03, 0x00, 0x8f, 0x01])); }; hare-0.24.2/encoding/asn1/+test/strings_test.ha000066400000000000000000000116621464473310100212530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use fmt; use io; use strings; fn c_checkrange(chars: []u8, f: *fn (c: u8) bool) void = { for (let i = 0z; i < 256; i += 1) { let expected = false; for (let j = 0z; j < len(chars); j += 1) { if (chars[j] == i: u8) { expected = true; break; }; }; if (f(i: u8) != expected) { fmt::println(i, expected, f(i: u8))!; }; assert(f(i: u8) == expected); }; }; @test fn c_is_num() void = { const chars: [_]u8 = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ]; c_checkrange(chars, &c_is_num); }; @test fn c_is_print() void = { const chars: [_]u8 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?', ]; c_checkrange(chars, &c_is_print); }; @test fn utf8() void = { let buf: [16]u8 = [0...]; let b: [_]u8 = [ 0x55, 0x56, 0xd0, 0x98, 0xe0, 0xa4, 0xb9, 0xf0, 0x90, 0x8d, 0x88 ]; const runesat: [_]size = [0, 1, 2, 2, 4, 4, 4, 7, 7, 7, 7, 8]; let expected: str = strings::fromutf8([0xf0, 0x90, 0x8d, 0x88])!; assert(read_utf8str(&d([0x0c, 0x04, 0xf0, 0x90, 0x8d, 0x88]), buf)! == expected); assert(read_utf8str(&d([0x0c, 0x03, 0xf0, 0x90, 0x8d]), buf) is invalid); bytes::zero(buf); let r = strreader(&d([0x0c, 0x04, 0xf0, 0x90, 0x8d, 0x88]), utag::UTF8_STRING)!; assert(io::read(&r, buf)! == 4); assert(bytes::equal(buf[..4], strings::toutf8(expected))); bytes::zero(buf); let expected: str = strings::fromutf8([0x55, 0x56, 0xf0, 0x90, 0x8d, 0x88])!; assert(read_utf8str(&d([0x0c, 0x06, 0x55, 0x56, 0xf0, 0x90, 0x8d, 0x88]), buf)! == expected); assert(read_utf8str(&d([0x0c, 0x05, 0x55, 0x56, 0xf0, 0x90, 0x8d]), buf) is invalid); bytes::zero(buf); let r = strreader(&d([0x0c, 0x06, 0x55, 0x56, 0xf0, 0x90, 0x8d, 0x88]), utag::UTF8_STRING)!; assert(io::read(&r, buf)! == 6); assert(bytes::equal(buf[..6], strings::toutf8(expected))); let r = strreader(&d([0x0c, 0x05, 0x55, 0x56, 0xf0, 0x90, 0x8d]), utag::UTF8_STRING)!; assert(unwrap_err(io::readall(&r, buf[2..]) as io::error) is invalid); bytes::zero(buf); let r = strreader(&d([0x0c, 0x06, 0x55, 0x56, 0xf0, 0x90, 0x8d, 0x88]), utag::UTF8_STRING)!; assert(io::read(&r, buf[..4])! == 2); assert(io::read(&r, buf[2..])! == 4); assert(bytes::equal(buf[..6], strings::toutf8(expected))); bytes::zero(buf); let r = strreader(&d([0x0c, 0x05, 0x55, 0x56, 0xf0, 0x90, 0x8d]), utag::UTF8_STRING)!; assert(io::read(&r, buf[..4])! == 2); assert(unwrap_err(io::readall(&r, buf[2..]) as io::error) is invalid); }; @test fn t61() void = { let input: [_]u8 = [ 0x14, 0x29, 0x42, 0xc8, 0x61, 0x72, 0x65, 0x6e, 0x20, 0x76, 0x65, 0x72, 0x7a, 0x65, 0x68, 0x72, 0x65, 0x6e, 0x20, 0x67, 0x65, 0x72, 0x6e, 0x65, 0x20, 0xc8, 0x75, 0x62, 0x65, 0x72, 0x6d, 0xc8, 0x61, 0xfb, 0x69, 0x67, 0x20, 0x48, 0x6f, 0x6e, 0x69, 0x67, 0x0a, ]; const expected: [_]u8 = [ 0x42, 0xc3, 0xa4, 0x72, 0x65, 0x6e, 0x20, 0x76, 0x65, 0x72, 0x7a, 0x65, 0x68, 0x72, 0x65, 0x6e, 0x20, 0x67, 0x65, 0x72, 0x6e, 0x65, 0x20, 0xc3, 0xbc, 0x62, 0x65, 0x72, 0x6d, 0xc3, 0xa4, 0xc3, 0x9f, 0x69, 0x67, 0x20, 0x48, 0x6f, 0x6e, 0x69, 0x67, 0x0a, ]; let dec = d(input); let r = strreader(&dec, utag::TELETEX_STRING)!; let result = io::drain(&r)!; defer free(result); assert(bytes::equal(expected, result)); assert(trypeek(&dec) is io::EOF); // cut off multibyte char input[1] = 0x2; let r = strreader(&d(input[..4]), utag::TELETEX_STRING)!; assert(unwrap_err(io::drain(&r) as io::error) is invalid); // not enough space for multibyte char let buf: [24]u8 = [0...]; let in = input[..27]; in[1] = (len(in) - 2): u8; let dec = d(in); let r = strreader(&dec, utag::TELETEX_STRING)!; assert(io::read(&r, buf)! == 23); assert(trypeek(&dec) is badformat); let r = strreader(&d([ 0x14, 0x0f, 0x63, 0x6c, 0xc2, 0x65, 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x73, ]), utag::TELETEX_STRING)!; let b = io::drain(&r)!; defer free(b); assert(strings::fromutf8(b)! == "cl\u00e9s publiques"); }; @test fn bmp() void = { let input: [_]u8 = [ 0x1e, 0x26, 0x00, 0x48, 0x00, 0xe4, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, 0x00, 0x69, 0x01, 0x61, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x20, 0x27, 0x64, ]; const expected: [_]u8 = [ 0x48, 0xc3, 0xa4, 0x72, 0x65, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x69, 0xc5, 0xa1, 0x20, 0x6e, 0x65, 0x61, 0x74, 0x6f, 0x20, 0xe2, 0x9d, 0xa4, ]; let dec = d(input); let r = strreader(&dec, utag::BMP_STRING)!; let result = io::drain(&r)!; defer free(result); assert(bytes::equal(expected, result)); assert(trypeek(&dec) is io::EOF); }; hare-0.24.2/encoding/asn1/README000066400000000000000000000004461464473310100160350ustar00rootroot00000000000000This module provides functions to decode and encode the distinguished encoding rules (DER) format as defined in the X.690 ITU-T standard. See [[derencoder]] and [[derdecoder]] for how to encode or decode values. This module also provides tools to work with oids. See [[oiddb]] for more info. hare-0.24.2/encoding/asn1/charset+test.ha000066400000000000000000000163411464473310100200740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bytes; use fmt; use io; use memio; // Encodes all characters from 0x00 to 0xff separated by \t. Invalid characters // will not be printed. All possible accents follow the table as defined in // the two bytes chapter at https://en.wikipedia.org/wiki/T.51/ISO/IEC_6937 fn print_t61_table(dest: io::handle) void = { for (let i = 0z; i < 16; i +=1 ) { fmt::fprintf(dest, "{:x}\t", i)!; }; fmt::fprintln(dest)!; for (let i = 0z; i < 256; i += 1) { if (i % 16 == 0) { fmt::fprintln(dest)!; }; match (t61_chardecode([i: u8])) { case insufficient => fmt::fprint(dest, "")!; case invalid => void; case let r: rune => if (i > 0xa0 || (ascii::isprint(r) && !ascii::isspace(r))) { fmt::fprint(dest, r)!; } else { fmt::fprintf(dest, "x{:.4x}", r: u32)!; }; }; if (i + 1 % 16 != 0) { fmt::fprint(dest, "\t")!; }; }; fmt::fprintln(dest)!; for (let i = 0xc1u8; i < 0xd0; i += 1) { if (i == 0xcc) continue; fmt::fprintf(dest, "{:.2x}\t", i)!; for (let j = 0x41u32; j < 0x7b; j += 1) { if (!ascii::isprint(j: rune)) { continue; }; if (!(t61_chardecode([i: u8]) is insufficient)) { assert(false); }; match (t61_chardecode([i: u8, j: u8])) { case let r: rune => fmt::fprint(dest, r)!; case => void; }; }; fmt::fprintln(dest)!; }; }; @test fn t61encode() void = { let table = memio::dynamic(); defer io::close(&table)!; print_t61_table(&table); assert(bytes::equal(t61_test_table, memio::buffer(&table))); }; // Print this table as UTF-8, to visual check the characters. const t61_test_table: [_]u8 = [ 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x33, 0x09, 0x34, 0x09, 0x35, 0x09, 0x36, 0x09, 0x37, 0x09, 0x38, 0x09, 0x39, 0x09, 0x61, 0x09, 0x62, 0x09, 0x63, 0x09, 0x64, 0x09, 0x65, 0x09, 0x66, 0x09, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x30, 0x30, 0x30, 0x61, 0x09, 0x09, 0x78, 0x30, 0x30, 0x30, 0x63, 0x09, 0x78, 0x30, 0x30, 0x30, 0x64, 0x09, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x30, 0x30, 0x31, 0x61, 0x09, 0x78, 0x30, 0x30, 0x31, 0x62, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x78, 0x30, 0x30, 0x32, 0x30, 0x09, 0x21, 0x09, 0x22, 0x09, 0x09, 0x09, 0x25, 0x09, 0x26, 0x09, 0x27, 0x09, 0x28, 0x09, 0x29, 0x09, 0x2a, 0x09, 0x2b, 0x09, 0x2c, 0x09, 0x2d, 0x09, 0x2e, 0x09, 0x2f, 0x09, 0x0a, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x33, 0x09, 0x34, 0x09, 0x35, 0x09, 0x36, 0x09, 0x37, 0x09, 0x38, 0x09, 0x39, 0x09, 0x3a, 0x09, 0x3b, 0x09, 0x3c, 0x09, 0x3d, 0x09, 0x3e, 0x09, 0x3f, 0x09, 0x0a, 0x40, 0x09, 0x41, 0x09, 0x42, 0x09, 0x43, 0x09, 0x44, 0x09, 0x45, 0x09, 0x46, 0x09, 0x47, 0x09, 0x48, 0x09, 0x49, 0x09, 0x4a, 0x09, 0x4b, 0x09, 0x4c, 0x09, 0x4d, 0x09, 0x4e, 0x09, 0x4f, 0x09, 0x0a, 0x50, 0x09, 0x51, 0x09, 0x52, 0x09, 0x53, 0x09, 0x54, 0x09, 0x55, 0x09, 0x56, 0x09, 0x57, 0x09, 0x58, 0x09, 0x59, 0x09, 0x5a, 0x09, 0x5b, 0x09, 0x09, 0x5d, 0x09, 0x09, 0x5f, 0x09, 0x0a, 0x09, 0x61, 0x09, 0x62, 0x09, 0x63, 0x09, 0x64, 0x09, 0x65, 0x09, 0x66, 0x09, 0x67, 0x09, 0x68, 0x09, 0x69, 0x09, 0x6a, 0x09, 0x6b, 0x09, 0x6c, 0x09, 0x6d, 0x09, 0x6e, 0x09, 0x6f, 0x09, 0x0a, 0x70, 0x09, 0x71, 0x09, 0x72, 0x09, 0x73, 0x09, 0x74, 0x09, 0x75, 0x09, 0x76, 0x09, 0x77, 0x09, 0x78, 0x09, 0x79, 0x09, 0x7a, 0x09, 0x09, 0x7c, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x30, 0x30, 0x38, 0x62, 0x09, 0x78, 0x30, 0x30, 0x38, 0x63, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x30, 0x30, 0x39, 0x62, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x78, 0x30, 0x30, 0x61, 0x30, 0x09, 0xc2, 0xa1, 0x09, 0xc2, 0xa2, 0x09, 0xc2, 0xa3, 0x09, 0x24, 0x09, 0xc2, 0xa5, 0x09, 0x23, 0x09, 0xc2, 0xa7, 0x09, 0xc2, 0xa4, 0x09, 0x09, 0x09, 0xc2, 0xab, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0xc2, 0xb0, 0x09, 0xc2, 0xb1, 0x09, 0xc2, 0xb2, 0x09, 0xc2, 0xb3, 0x09, 0xc3, 0x97, 0x09, 0xc2, 0xb5, 0x09, 0xc2, 0xb6, 0x09, 0xc2, 0xb7, 0x09, 0xc3, 0xb7, 0x09, 0x09, 0x09, 0xc2, 0xbb, 0x09, 0xc2, 0xbc, 0x09, 0xc2, 0xbd, 0x09, 0xc2, 0xbe, 0x09, 0xc2, 0xbf, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0xe2, 0x84, 0xa6, 0x09, 0xc3, 0x86, 0x09, 0xc3, 0x90, 0x09, 0xc2, 0xaa, 0x09, 0xc4, 0xa6, 0x09, 0x09, 0xc4, 0xb2, 0x09, 0xc4, 0xbf, 0x09, 0xc5, 0x81, 0x09, 0xc3, 0x98, 0x09, 0xc5, 0x92, 0x09, 0xc2, 0xba, 0x09, 0xc3, 0x9e, 0x09, 0xc5, 0xa6, 0x09, 0xc5, 0x8a, 0x09, 0xc5, 0x89, 0x09, 0x0a, 0xc4, 0xb8, 0x09, 0xc3, 0xa6, 0x09, 0xc4, 0x91, 0x09, 0xc3, 0xb0, 0x09, 0xc4, 0xa7, 0x09, 0xc4, 0xb1, 0x09, 0xc4, 0xb3, 0x09, 0xc5, 0x80, 0x09, 0xc5, 0x82, 0x09, 0xc3, 0xb8, 0x09, 0xc5, 0x93, 0x09, 0xc3, 0x9f, 0x09, 0xc3, 0xbe, 0x09, 0xc5, 0xa7, 0x09, 0xc5, 0x8b, 0x09, 0x09, 0x0a, 0x63, 0x31, 0x09, 0xc3, 0x80, 0xc3, 0x88, 0xc3, 0x8c, 0xc3, 0x92, 0xc3, 0x99, 0xc3, 0xa0, 0xc3, 0xa8, 0xc3, 0xac, 0xc3, 0xb2, 0xc3, 0xb9, 0x0a, 0x63, 0x32, 0x09, 0xc3, 0x81, 0xc4, 0x86, 0xc3, 0x89, 0xc3, 0x8d, 0xc4, 0xb9, 0xc5, 0x83, 0xc3, 0x93, 0xc5, 0x94, 0xc5, 0x9a, 0xc3, 0x9a, 0xc3, 0x9d, 0xc5, 0xb9, 0xc3, 0xa1, 0xc4, 0x87, 0xc3, 0xa9, 0xc4, 0xa3, 0xc3, 0xad, 0xc4, 0xba, 0xc5, 0x84, 0xc3, 0xb3, 0xc5, 0x95, 0xc5, 0x9b, 0xc3, 0xba, 0xc3, 0xbd, 0xc5, 0xba, 0x0a, 0x63, 0x33, 0x09, 0xc3, 0x82, 0xc4, 0x88, 0xc3, 0x8a, 0xc4, 0x9c, 0xc4, 0xa4, 0xc3, 0x8e, 0xc4, 0xb4, 0xc3, 0x94, 0xc5, 0x9c, 0xc3, 0x9b, 0xc5, 0xb4, 0xc5, 0xb6, 0xc3, 0xa2, 0xc4, 0x89, 0xc3, 0xaa, 0xc4, 0x9d, 0xc4, 0xa5, 0xc3, 0xae, 0xc4, 0xb5, 0xc3, 0xb4, 0xc5, 0x9d, 0xc3, 0xbb, 0xc5, 0xb5, 0xc5, 0xb7, 0x0a, 0x63, 0x34, 0x09, 0xc3, 0x83, 0xc4, 0xa8, 0xc3, 0x91, 0xc3, 0x95, 0xc5, 0xa8, 0xc3, 0xa3, 0xc4, 0xa9, 0xc3, 0xb1, 0xc3, 0xb5, 0xc5, 0xa9, 0x0a, 0x63, 0x35, 0x09, 0xc4, 0x80, 0xc4, 0x92, 0xc4, 0xaa, 0xc5, 0x8c, 0xc5, 0xaa, 0xc4, 0x81, 0xc4, 0x93, 0xc4, 0xab, 0xc5, 0x8d, 0xc5, 0xab, 0x0a, 0x63, 0x36, 0x09, 0xc4, 0x82, 0xc4, 0x9e, 0xc5, 0xac, 0xc4, 0x83, 0xc4, 0x9f, 0xc5, 0xad, 0x0a, 0x63, 0x37, 0x09, 0xc4, 0x8a, 0xc4, 0x96, 0xc4, 0xa0, 0xc4, 0xb0, 0xc5, 0xbb, 0xc4, 0x8b, 0xc4, 0x97, 0xc4, 0xa1, 0xc5, 0xbc, 0x0a, 0x63, 0x38, 0x09, 0xc3, 0x84, 0xc3, 0x8b, 0xc3, 0x8f, 0xc3, 0x96, 0xc3, 0x9c, 0xc5, 0xb8, 0xc3, 0xa4, 0xc3, 0xab, 0xc3, 0xaf, 0xc3, 0xb6, 0xc3, 0xbc, 0xc3, 0xbf, 0x0a, 0x63, 0x39, 0x09, 0xc3, 0x84, 0xc3, 0x8b, 0xc3, 0x8f, 0xc3, 0x96, 0xc3, 0x9c, 0xc5, 0xb8, 0xc3, 0xa4, 0xc3, 0xab, 0xc3, 0xaf, 0xc3, 0xb6, 0xc3, 0xbc, 0xc3, 0xbf, 0x0a, 0x63, 0x61, 0x09, 0xc3, 0x85, 0xc5, 0xae, 0xc3, 0xa5, 0xc5, 0xaf, 0x0a, 0x63, 0x62, 0x09, 0xc3, 0x87, 0xc4, 0xa2, 0xc4, 0xb6, 0xc4, 0xbb, 0xc5, 0x85, 0xc5, 0x96, 0xc5, 0x9e, 0xc5, 0xa2, 0xc3, 0xa7, 0xc4, 0xb7, 0xc4, 0xbc, 0xc5, 0x86, 0xc5, 0x97, 0xc5, 0x9f, 0xc5, 0xa3, 0x0a, 0x63, 0x64, 0x09, 0xc5, 0x90, 0xc5, 0xb0, 0xc5, 0x91, 0xc5, 0xb1, 0x0a, 0x63, 0x65, 0x09, 0xc4, 0x84, 0xc4, 0x98, 0xc4, 0xae, 0xc5, 0xb2, 0xc4, 0x85, 0xc4, 0x99, 0xc4, 0xaf, 0xc5, 0xb3, 0x0a, 0x63, 0x66, 0x09, 0xc4, 0x8c, 0xc4, 0x8e, 0xc4, 0x9a, 0xc4, 0xbd, 0xc5, 0x87, 0xc5, 0x98, 0xc5, 0xa0, 0xc5, 0xa4, 0xc5, 0xbd, 0xc4, 0x8d, 0xc4, 0x8f, 0xc4, 0x9b, 0xc4, 0xbe, 0xc5, 0x88, 0xc5, 0x99, 0xc5, 0xa1, 0xc5, 0xa5, 0xc5, 0xbe, 0x0a, ]; hare-0.24.2/encoding/asn1/decoder.ha000066400000000000000000000453441464473310100171020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use io; use math::{bit_size_u8}; use os; use strings; use time::chrono; use time::date; use types; def TAGMASK: u8 = 0x1f; def MAX_CONS_DEPTH: size = 32; // Each DER entry starts with an header that describes the content. export type head = struct { // Tells whether the data is constructed and encapsulates multiple // other data fields; or primitive and the value follows. cons: bool, // Class info class: class, // Tag id of the data tagid: u32, // Start position in stream start: size, // Start position of data in stream data: size, // End position in stream end: size, implicit: bool, }; fn head_endpos(d: head) size = d.end; // Size of current element (header size + data size) export fn sz(d: head) size = d.end - d.start; // Size of the encoded data. export fn dsz(d: head) size = d.end - d.data; export type decoder = struct { src: io::handle, pos: size, cstack: [MAX_CONS_DEPTH]head, cstackp: size, next: (void | head), cur: (void | head), unbuf: [3]u8, unbufn: u8, implicit: bool, }; // Creates a new DER decoder that reads from 'src'. A buffered stream (see // [[bufio::]]) is recommended for efficiency, as the decoder performs mostly // short reads. // // Each entry must be read in its entirety before the next one is attended to. // The user must call [[finish]] when finished with the decoder to ensure that // the entire input was read correctly. export fn derdecoder(src: io::handle) decoder = { return decoder { src = src, pos = 0, cstackp = 0, cur = void, next = void, implicit = false, ... }; }; // Verifies that the entire input to the decoder was read. export fn finish(d: *decoder) (void | error) = { if (d.cstackp != 0 || d.next is head) return invalid; match (d.cur) { case void => return; case let h: head => if (h.end != d.pos) return invalid; }; }; // Returns last opened cons or void if none is open. fn curcons(d: *decoder) (void | head) = { if (d.cstackp == 0) { return; }; return d.cstack[d.cstackp-1]; }; // Peeks the header of the next data field. Fails with [[badformat]] if no data // follows. export fn peek(d: *decoder) (head | error) = { match (trypeek(d)?) { case io::EOF => return badformat; case let h: head => return h; }; }; // Tries to peek the header of the next data field, or returns EOF if none // exists. export fn trypeek(d: *decoder) (head | error | io::EOF) = { if (!(d.next is void)) { return d.next: head; }; if (is_endofcons(d)) return io::EOF; match (parse_header(d)?) { case io::EOF => const unreaddata = d.unbufn > 0; if (d.cstackp != 0 || unreaddata) { return badformat; }; return io::EOF; case let dh: head => d.next = dh; return dh; }; }; // Cons is open and end is reached. fn is_endofcons(d: *decoder) bool = { match (curcons(d)) { case void => return false; case let cur: head => return d.pos == head_endpos(cur); }; }; // Returns the next data element, or [[badformat]] on EOF. fn next(d: *decoder) (head | error) = { match (trynext(d)?) { case io::EOF => return badformat; case let dh: head => return dh; }; }; fn trynext(d: *decoder) (head | error | io::EOF) = { if (d.next is head) { let dh = d.next: head; d.cur = dh; d.next = void; dh.implicit = d.implicit; d.implicit = false; return dh; }; if (is_endofcons(d)) return io::EOF; let dh = match (parse_header(d)?) { case io::EOF => return io::EOF; case let dh: head => yield dh; }; d.cur = dh; dh.implicit = d.implicit; d.implicit = false; return dh; }; fn parse_header(d: *decoder) (head | error | io::EOF) = { const consend = match (curcons(d)) { case void => yield types::SIZE_MAX; case let h: head => yield h.end; }; if (d.pos == consend) return invalid; const epos = d.pos; const id = match (tryscan_byte(d)?) { case io::EOF => d.cur = void; return io::EOF; case let id: u8 => yield id; }; const class = ((id & 0xc0) >> 6): class; let tagid: u32 = id & TAGMASK; if (tagid == TAGMASK) { tagid = parse_longtag(d, consend - d.pos)?; }; const l = parse_len(d, consend - d.pos)?; const hl = d.pos - epos; const end = epos + hl + l; if (end > consend) return invalid; return head { class = class, cons = ((id >> 5) & 1) == 1, tagid = tagid, start = epos, data = epos + hl, end = end, implicit = d.implicit, ... }; }; fn tryscan_byte(d: *decoder) (u8 | io::EOF | error) = { let buf: [1]u8 = [0...]; match (io::readall(d.src, buf)?) { case io::EOF => return io::EOF; case size => d.pos += 1; return buf[0]; }; }; fn scan_byte(d: *decoder) (u8 | error) = { match (tryscan_byte(d)?) { case io::EOF => return truncated; case let b: u8 => return b; }; }; // Reads data of current entry and advances pointer. Data must have been opened // using [[next]] or [[trynext]]. [[io::EOF]] is returned on end of data. fn dataread(d: *decoder, buf: []u8) (size | io::EOF | io::error) = { let cur = match (d.cur) { case void => abort("primitive must be opened with [[next]] or [[trynext]]"); case let dh: head => yield dh; }; const dataleft = head_endpos(cur) - d.pos + d.unbufn; if (dataleft == 0) { return io::EOF; }; let n = 0z; if (d.unbufn > 0) { const max = if (d.unbufn > len(buf)) len(buf): u8 else d.unbufn; buf[..max] = d.unbuf[..max]; d.unbufn -= max; n += max; }; const max = if (dataleft < len(buf) - n) dataleft else len(buf) - n; match (io::read(d.src, buf[n..n + max])?) { case io::EOF => // there should be data left return wrap_err(truncated); case let sz: size => d.pos += sz; return n + sz; }; }; // unread incomplete utf8 runes. fn dataunread(d: *decoder, buf: []u8) void = { assert(len(buf) + d.unbufn <= len(d.unbuf)); d.unbuf[d.unbufn..d.unbufn + len(buf)] = buf; d.unbufn += len(buf): u8; }; fn dataeof(d: *decoder) bool = { match (d.cur) { case void => return true; case let h: head => return d.pos + d.unbufn == head_endpos(h); }; }; fn parse_longtag(p: *decoder, max: size) (u32 | error) = { // XXX: u32 too much? let tag: u32 = 0; let maxbits = size(u32) * 8; let nbits = 0z; for (let i = 0z; i < max; i += 1) { let b = scan_byte(p)?; const part = b & 0x7f; nbits += if (tag == 0) bit_size_u8(part) else 7; if (nbits > maxbits) { // overflows u32 return invalid; }; tag = (tag << 7) + part; if (tag == 0) { // first tag part must not be 0 return invalid; }; if ((b >> 7) == 0) { return tag; }; }; return invalid; // max has been reached }; fn parse_len(p: *decoder, max: size) (size | error) = { if (max == 0) return invalid; const b = scan_byte(p)?; if (b == 0xff) { return invalid; }; if (b >> 7 == 0) { // short form return b: size; }; let l = 0z; const n = b & 0x7f; if (n == 0) { // Indefinite encoding is not supported in DER. return invalid; }; if (n > size(size)) { // would cause a size overflow return invalid; }; if (n + 1 > max) return invalid; for (let i = 0z; i < n; i += 1) { const b = scan_byte(p)?; l = (l << 8) + b; if (l == 0) { // Leading zeroes means minimum number of bytes for // length encoding has not been used. return invalid; }; }; if (l <= 0x7f) { // Could've used short form. return invalid; }; return l; }; // Expects an IMPLICIT defined data field having class 'c' and tag 'tag'. // If the requirements are met, a read call (i.e. one of the "read_" or "reader" // functions) must follow to read the actual data as stored. export fn expect_implicit(d: *decoder, c: class, tag: u32) (void | error) = { let h = peek(d)?; expect_tag(h, c, tag)?; d.implicit = true; }; // Opens an EXPLICIT encoded field of given class 'c' and 'tag'. The user must // call [[close_explicit]] after containing data has been read. export fn open_explicit(d: *decoder, c: class, tag: u32) (void | error) = open_cons(d, c, tag); // Closes an EXPLICIT encoded field. export fn close_explicit(d: *decoder) (void | badformat) = close_cons(d); // Opens a constructed value of given 'class' and 'tagid'. Fails if not a // constructed value or the encoded value has an unexpected tag. fn open_cons(d: *decoder, class: class, tagid: u32) (void | error) = { let dh = next(d)?; if (!dh.cons) { return invalid; }; expect_tag(dh, class, tagid)?; if (d.cstackp == len(d.cstack)) { return badformat; }; d.cstack[d.cstackp] = dh; d.cstackp += 1; }; // Closes current constructed value. badformat is returend, if not all data has // been read. fn close_cons(d: *decoder) (void | badformat) = { if (d.implicit) { // a datafield marked implicit has not been read return badformat; }; match (curcons(d)) { case void => abort("No constructed value open"); case let h: head => if (d.pos != head_endpos(h) || d.unbufn > 0) { // All data must have been read before closing the seq return badformat; }; }; d.cstackp -= 1; }; // Opens a sequence. Call [[close_seq]] after reading. export fn open_seq(d: *decoder) (void | error) = open_cons(d, class::UNIVERSAL, utag::SEQUENCE: u32)?; // Closes the current sequence. If the caller has not read all of the data // present in the encoded seqeunce, [[badformat]] is returned. export fn close_seq(d: *decoder) (void | badformat) = close_cons(d); // Opens a set. Note that sets must be ordered according to DER, but this module // does not validate this constraint. Call [[close_set]] after reading. export fn open_set(d: *decoder) (void | error) = open_cons(d, class::UNIVERSAL, utag::SET: u32)?; // Closes the current set. If the caller has not read all of the data present in // the encoded seqeunce, [[badformat]] is returned. export fn close_set(d: *decoder) (void | badformat) = close_cons(d); fn expect_tag(h: head, class: class, tagid: u32) (void | invalid | badformat) = { if (class == class::UNIVERSAL && (tagid == utag::SEQUENCE || tagid == utag::SET) && !h.cons) { return invalid; }; if (h.implicit) { return; }; if (h.class != class || h.tagid != tagid) { return badformat; }; }; fn expect_utag(dh: head, tag: utag) (void | invalid | badformat) = expect_tag(dh, class::UNIVERSAL, tag: u32); fn read_bytes(d: *decoder, buf: []u8) (size | error) = { match (dataread(d, buf)) { case io::EOF => return 0z; case let n: size => if (!dataeof(d)) { return badformat; }; return n; }; }; fn read_nbytes(d: *decoder, buf: []u8) (size | error) = { const n = read_bytes(d, buf)?; if (n != len(buf)) { return badformat; }; return n; }; // Reads a boolean value. export fn read_bool(d: *decoder) (bool | error) = { let dh = next(d)?; expect_utag(dh, utag::BOOLEAN)?; if (dsz(dh) != 1) { return invalid; }; let b = scan_byte(d)?; if (b != 0x00 && b != 0xff) { return invalid; }; return b == 0xff; }; fn validate_intprefix(i: []u8) (void | error) = { switch (len(i)) { case 0 => return invalid; case 1 => return; case => // An int must be encoded using the minimal number of bytes // possible as defined in X.690 s8.3.2 if ((i[0] == 0x00 && i[1] >> 7 == 0) || (i[0] == 0xff && i[1] >> 7 == 1)) { return invalid; }; }; }; // Reads an arbitrary-length integer into 'buf' and returns its length in bytes. // Fails if the encoded integer size exceeds the buffer size. The integer is // stored in big endian, and negative values are stored with two's compliment. // The minimum integer size is one byte. export fn read_int(d: *decoder, buf: []u8) (size | error) = { assert(len(buf) > 0); let dh = next(d)?; expect_utag(dh, utag::INTEGER)?; const n = read_bytes(d, buf)?; validate_intprefix(buf[..n])?; return n; }; // Similar to [[read_int]], but returns [[badformat]] if the encoded value is // signed. Discards the most significant zero bytes. export fn read_uint(d: *decoder, buf: []u8) (size | error) = { let s = read_int(d, buf)?; if (buf[0] & 0x80 == 0x80) { return badformat; }; if (buf[0] == 0) { buf[..s-1] = buf[1..s]; s -= 1; }; return s; }; fn read_ux(d: *decoder, x: u8) (u64 | error) = { assert(x <= 8); let b: [9]u8 = [0...]; const n = read_int(d, b[..x+1])?; if (b[0] & 0x80 != 0) { // sign bit is set return invalid; }; const s = if (b[0] == 0x00) 1u8 else 0u8; if (n - s > x) { return invalid; }; let r = 0u64; for (let i = s; i < n; i += 1) { r <<= 8; r += b[i]; }; return r; }; // Reads an integer that is expected to fit into u8. export fn read_u8(d: *decoder) (u8 | error) = read_ux(d, 1)?: u8; // Reads an integer that is expected to fit into u16. export fn read_u16(d: *decoder) (u16 | error) = read_ux(d, 2)?: u16; // Reads an integer that is expected to fit into u32. export fn read_u32(d: *decoder) (u32 | error) = read_ux(d, 4)?: u32; // Reads an integer that is expected to fit into u64. export fn read_u64(d: *decoder) (u64 | error) = read_ux(d, 8)?; // Reads a bitstring value. The result tuple contains the bitstring and the // number of unused bits in the last byte. The [[bitstr_isset]] function may be // used to check for set bits. export fn read_bitstr(d: *decoder, buf: []u8) (([]u8, u8) | error) = { let dh = next(d)?; expect_utag(dh, utag::BITSTRING)?; let unused: [1]u8 = [0...]; match (dataread(d, unused)?) { case io::EOF => return invalid; case let n: size => if (n != 1) { return invalid; }; }; const unused = unused[0]; if (unused > 7) { return invalid; }; const n = read_bytes(d, buf)?; const mask = (1 << unused) - 1; if (n > 0 && buf[n-1] & mask != 0) { // unused bits must be zero return invalid; }; return (buf[..n], unused); }; // Checks whether bit at 'pos' is set in given bitstring. 'pos' starts from 0, // which is the highest order bit in the first byte. export fn bitstr_isset(bitstr: ([]u8, u8), pos: size) (bool | invalid) = { const i = pos / 8; if (i >= len(bitstr.0)) { return false; }; let b = bitstr.0[i]; const j = pos - i * 8; if (i == len(bitstr.0) - 1 && j >= (8 - bitstr.1)) { return invalid; }; const mask = (1 << (7 - j)); return mask & b == mask; }; // Returns an [[io::reader]] for octet string data. export fn octetstrreader(d: *decoder) (bytestream | error) = { // TODO add limit? let dh = next(d)?; expect_utag(dh, utag::OCTET_STRING)?; return newbytereader(d); }; // Read an octet string into 'buf', returning its length. Returns [[badformat]] // if 'buf' is too small. export fn read_octetstr(d: *decoder, buf: []u8) (size | error) = { assert(len(buf) > 0); let dh = next(d)?; expect_utag(dh, utag::OCTET_STRING)?; return read_bytes(d, buf); }; // Reads a null entry. export fn read_null(d: *decoder) (void | error) = { let dh = next(d)?; expect_utag(dh, utag::NULL)?; if (dsz(dh) != 0) { return invalid; }; }; export type bytestream = struct { stream: io::stream, d: *decoder, }; fn newbytereader(d: *decoder) bytestream = { return bytestream { stream = &bytestream_vtable, d = d, ... }; }; const bytestream_vtable: io::vtable = io::vtable { reader = &bytestream_reader, ... }; fn bytestream_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = dataread((s: *bytestream).d, buf); // Returns an [[io::reader]] that reads raw data (in its ASN.1 encoded form) // from a [[decoder]]. Note that this reader will not perform any kind of // validation. export fn bytereader(d: *decoder, c: class, tagid: u32) (bytestream | error) = { let dh = next(d)?; expect_tag(dh, c, tagid)?; return newbytereader(d); }; // Reads an UTC time. Since the stored date only has a two digit year, 'maxyear' // is required to define the epoch. For example 'maxyear' = 2046 causes all // encoded years <= 46 to be after 2000 and all values > 46 will have 1900 as // the century. export fn read_utctime(d: *decoder, maxyear: u16) (date::date | error) = { assert(maxyear > 100); let dh = next(d)?; expect_utag(dh, utag::UTC_TIME)?; let time: [13]u8 = [0...]; read_nbytes(d, time[..])?; if (time[len(time)-1] != 'Z') { return invalid; }; let year: u16 = (time[0] - 0x30): u16 * 10 + (time[1] - 0x30): u16; let cent = maxyear - (maxyear % 100); if (year > maxyear % 100) { cent -= 100; }; let v = date::newvirtual(); v.vloc = chrono::UTC; v.year = (year + cent): int; v.zoff = 0; v.nanosecond = 0; let datestr = strings::fromutf8(time[2..])!; if (!(date::parse(&v, "%m%d%H%M%S%Z", datestr) is void)) { return invalid; }; let dt = match (date::realize(v)) { case let dt: date::date => yield dt; case let e: (date::insufficient | date::invalid) => return invalid; }; return dt; }; // Reads a generalized datetime value. export fn read_gtime(d: *decoder) (date::date | error) = { let dh = next(d)?; expect_utag(dh, utag::GENERALIZED_TIME)?; // The date begins with the encoded datetime def DATESZ = 14z; // followed by optional fractional seconds separated by '.' def NANOSZ = 10z; def NANOSEPPOS = 14; // and ends with the zone info 'Z' def ZONESZ = 1z; let time: [DATESZ + NANOSZ + ZONESZ]u8 = [0...]; let n = read_bytes(d, time[..])?; // zone info and seconds must always be present if (time[n-1] != 'Z' || n < DATESZ + ZONESZ) { return invalid; }; // validate fractional seconds if (n > DATESZ + ZONESZ) { // fractional seconds must not be empty if (time[NANOSEPPOS] != '.' || n == DATESZ + ZONESZ + 1) { return invalid; }; // fractional seconds must not end with 0 and must be > 0 if (time[n-2] == '0') return invalid; }; // right pad fractional seconds to make them valid nanoseconds time[n-1..] = ['0'...]; time[NANOSEPPOS] = '.'; match (date::from_str("%Y%m%d%H%M%S.%N", strings::fromutf8(time)!)) { case let d: date::date => return d; case => return invalid; }; }; // Skips an element and returns the size of the data that has been skipped. // Returns an error if the skipped data is invalid. // // Presently only supports BOOLEAN, INTEGER, NULL, OCTET_STRING, and BITSTRING // utags, and will abort when attempting to skip anything else. export fn skip(d: *decoder, tag: utag, max: size) (size | error) = { static let buf: [os::BUFSZ]u8 = [0...]; let s = 0z; switch (tag) { case utag::BOOLEAN => read_bool(d)?; return 1z; case utag::INTEGER => let br = bytereader(d, class::UNIVERSAL, utag::INTEGER)?; let n = match (io::read(&br, buf)?) { case let n: size => yield n; case io::EOF => return invalid; }; validate_intprefix(buf[..n])?; n += streamskip(&br, max, buf)?; return n; case utag::NULL => read_null(d)?; return 0z; case utag::OCTET_STRING => let r = octetstrreader(d)?; return streamskip(&r, max, buf)?; case utag::BITSTRING => assert(max <= len(buf)); let buf = buf[..max]; let p = read_bitstr(d, buf)?; bytes::zero(p.0); return len(p.0) + 1; case => abort("skip for given utag not implemented"); }; }; fn streamskip(r: io::handle, max: size, buf: []u8) (size | error) = { defer bytes::zero(buf); let buf = if (max < len(buf)) buf[..max] else buf[..]; let s = 0z; for (true) { match (io::read(r, buf)?) { case let n: size => s += n; case io::EOF => return s; }; if (s > max) { return badformat; }; }; }; hare-0.24.2/encoding/asn1/encoder.ha000066400000000000000000000244111464473310100171040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use endian; use errors; use io; use math::{bit_size_u8,bit_size_u32}; use memio; use strings; use types; export type datasz = u32; // XXX: might want to use size here let szput = &endian::beputu32; let szget = &endian::begetu32; def DATASZ_MAX = types::U32_MAX; // The maximum header size possible for u32 tag ids. export def MAXHEADSZ = 1 + 5 + 1 + size(datasz); // The maximum header size possible for entries of [[utag]]. export def MAXUTAGHEADSZ = 1 + 1 + size(datasz); export type encoder = struct { mem: *memio::stream, start: io::off, pos: size, bt: [MAX_CONS_DEPTH](size, datasz), btn: size, cur_dpos: size, cur_prim: bool, cur_fixed: bool, parent: nullable *bytewstream, }; // Creates a new DER encoder. The user must provide a [[memio::stream]] for // buffering data before it's encoded. The user may provide a dynamic or fixed // stream at their discretion; fixed may be preferred if the user knows the // required buffer size in advance. // // To encode DER data, the user must call one of the "create_" functions (e.g. // [[create_explicit]]), followed by the appropriate "write_" functions (e.g. // [[write_int]]). These operations will be buffered into the provided memio // buffer, and the encoded form may be finalized and retrieved via [[encode]] or // [[encodeto]]. // // To determine the required buffer size for a fixed buffer, consider the // maximum length of the input data (e.g. integer, string, etc length) plus the // necessary overhead, which is given by [[MAXUTAGHEADSZ]] if only using the // provided encoder functions (e.g. "write_" functions), or [[MAXHEADSZ]] if // using custom tag IDs. // // The encoder does not close the provided [[memio::stream]] after use; the // caller should manage its lifetime accordingly. export fn derencoder(mem: *memio::stream) encoder = encoder { mem = mem, start = io::tell(mem)!, ... }; // Creates a DER encoder nested within another DER entry, using the buffer of // the parent. export fn derencoder_nested(b: *bytewstream) encoder = encoder { mem = b.e.mem, start = io::tell(b.e.mem)!, parent = b, ... }; fn write(e: *encoder, buf: []u8) (void | overflow) = { if (len(buf) > (DATASZ_MAX - e.pos)) return overflow; match (io::write(e.mem, buf)) { case let n: size => if (n < len(buf)) { // short writes happen, if a fixed e.mem reaches its end return overflow; }; case errors::overflow => return overflow; case => // writing to mem does not throw any other errors abort(); }; e.pos += len(buf); }; fn write_id(e: *encoder, c: class, t: u32, cons: bool) (void | overflow) = { let head: u8 = c << 6; if (cons) { head |= (1 << 5); }; if (t < 31) { bt_add_sz(e, 1); return write(e, [head | t: u8]); }; write(e, [head | 0x1f])?; const bsz = bit_size_u32(t); const n = ((bsz + 6) / 7) - 1; for (let i = 0z; i < n; i += 1) { write(e, [0x80 | (t >> ((n - i) * 7)): u8])?; }; write(e, [t: u8 & 0x7f])?; }; fn write_fixedprim(e: *encoder, c: class, t: u32, b: []u8) (void | overflow) = { if (e.cur_prim) { finish_prim(e); }; e.cur_prim = true; e.cur_fixed = true; write_id(e, c, t, false)?; write(e, encode_dsz(len(b)))?; write(e, b)?; bt_add_dsz(e, len(b): datasz); }; fn create_prim(e: *encoder, class: class, tag: u32) (void | overflow) = { if (e.cur_prim) { finish_prim(e); }; e.cur_prim = true; e.cur_fixed = false; write_id(e, class, tag, false)?; // write size placeholder const placehsz = 0x80 | size(datasz): u8; let lbuf: [1 + size(datasz)]u8 = [placehsz, 0...]; write(e, lbuf)?; e.cur_dpos = e.pos; }; fn finish_prim(e: *encoder) void = { e.cur_prim = false; if (e.pos == 0 || e.cur_fixed) { return; }; const pos = io::tell(e.mem)!; defer io::seek(e.mem, pos, io::whence::SET)!; // write back size to placeholder const dszpos = e.start: size + e.cur_dpos - size(datasz); const dsz = e.pos - e.cur_dpos; let dszbuf: [size(datasz)]u8 = [0...]; szput(dszbuf, dsz: datasz); io::seek(e.mem, dszpos: io::off, io::whence::SET)!; io::write(e.mem, dszbuf)!; bt_add_dsz(e, dsz: datasz); }; // Push n empty size value to backtrace stack fn push_bt(e: *encoder, pos: size) (void | overflow) = { if (e.btn + 1 >= len(e.bt)) return overflow; e.bt[e.btn] = (pos, 0); e.btn += 1; }; // Add 'sz' to the current value of the backtrack stack fn bt_add_sz(e: *encoder, sz: size) void = { if (e.btn == 0) return; const csz = e.bt[e.btn - 1].1; e.bt[e.btn - 1].1 = csz + sz: datasz; }; // Add data size 'sz' + size length to current value of the backtrack stack fn bt_add_dsz(e: *encoder, sz: datasz) void = { if (e.btn == 0) return; const lsz = lensz(sz); return bt_add_sz(e, lsz + sz); }; // Pop current backtrace value from stack fn pop_bt(e: *encoder) (size, datasz) = { e.btn -= 1; let x = e.bt[e.btn]; e.bt[e.btn] = (0, 0); return x; }; fn lensz(l: datasz) u8 = if (l < 128) 1: u8 else (1 + (bit_size_u32(l) + 7) / 8); fn encode_dsz(sz: size) []u8 = { static let buf: [size(datasz) + 1]u8 = [0...]; if (sz < 128) { buf[0] = sz: u8; return buf[..1]; }; let n = lensz(sz: datasz); buf[0] = (n - 1) | 0x80; for (let i: size = n - 1; sz > 0; i -= 1) { buf[i] = sz: u8; sz >>= 8; }; return buf[..n]; }; // Creates an explicit constructed entry. The user must call [[finish_explicit]] // to close the associated DER entry. export fn create_explicit(e: *encoder, c: class, tag: u32) (void | overflow) = create_cons(e, c, tag); // Finishes an explicit constructed entry. export fn finish_explicit(e: *encoder) void = finish_cons(e); fn create_cons(e: *encoder, class: class, tagid: u32) (void | overflow) = { if (e.cur_prim) { finish_prim(e); }; write_id(e, class, tagid, true)?; const placehsz = 0x80 | size(datasz): u8; let lbuf: [1 + size(datasz)]u8 = [placehsz, 0...]; write(e, lbuf)?; push_bt(e, e.pos - size(datasz))?; return; }; fn finish_cons(e: *encoder) void = { if (e.cur_prim) { finish_prim(e); }; let (dszpos, sz) = pop_bt(e); let lbuf: [size(datasz)]u8 = [0...]; szput(lbuf, sz); const pos = io::tell(e.mem)!; defer io::seek(e.mem, pos, io::whence::SET)!; dszpos += e.start: size; io::seek(e.mem, dszpos: io::off, io::whence::SET)!; io::write(e.mem, lbuf)!; bt_add_dsz(e, sz); }; // Creates a sequence. The user must call [[finish_seq]] to close the associated // DER entry. export fn create_seq(e: *encoder) (void | overflow) = return create_cons(e, class::UNIVERSAL, utag::SEQUENCE); // Finishes a sequence. export fn finish_seq(e: *encoder) void = finish_cons(e); // Writes a boolean. export fn write_bool(e: *encoder, b: bool) (void | overflow) = { let v: u8 = if (b) 0xff else 0x00; write_fixedprim(e, class::UNIVERSAL, utag::BOOLEAN, [v])?; }; // Writes a null value. export fn write_null(e: *encoder) (void | overflow) = { write_fixedprim(e, class::UNIVERSAL, utag::NULL, [])?; }; export type bytewstream = struct { stream: io::stream, e: *encoder, }; fn bytewriter(e: *encoder, c: class, tagid: u32) (bytewstream | overflow) = { create_prim(e, c, tagid)?; return bytewstream { stream = &bytewriter_vtable, e = e, ... }; }; const bytewriter_vtable = io::vtable { writer = &bytewriter_write, ... }; fn bytewriter_write(s: *io::stream, buf: const []u8) (size | io::error) = { let w = s: *bytewstream; if (write(w.e, buf) is overflow) { return wrap_err(overflow); }; return len(buf); }; // Creates an [[io::writer]] that encodes data written to it as an OctetString. export fn octetstrwriter(e: *encoder) (bytewstream | overflow) = { return bytewriter(e, class::UNIVERSAL, utag::OCTET_STRING); }; // Writes an integer. 'n' must be stored in big endian order. The highest bit of // the first byte marks the sign. export fn write_int(e: *encoder, n: []u8) (void | overflow) = { const neg = n[0] & 0x80 == 0x80; // compact according to X.690 Chapt. 8.3.2 let i = 0z; for (i < len(n) - 1; i += 1) { if (neg && (n[i] != 0xff || n[i+1] & 0x80 != 0x80)) { break; }; if (!neg && (n[i] != 0x00 || n[i+1] & 0x80 == 0x80)) { break; }; }; write_fixedprim(e, class::UNIVERSAL, utag::INTEGER, n[i..])?; }; // Writes an integer asuming 'n' is unsigned. export fn write_uint(e: *encoder, n: []u8) (void | overflow) = { if (n[0] & 0x80 == 0) { return write_int(e, n); }; // prepend 0 so that the highest valued bit is not interpreted as sign create_prim(e, class::UNIVERSAL, utag::INTEGER)?; write(e, [0])?; write(e, n)?; finish_prim(e); }; // Writes 's' as Utf8String. export fn write_utf8str(e: *encoder, s: str) (void | overflow) = write_fixedprim(e, class::UNIVERSAL, utag::UTF8_STRING, strings::toutf8(s))?; // Encodes all buffered data in the [[encoder]] and returns a slice representing // the encoded entry, borrowed from the encoder's buffer. export fn encode(e: *encoder) ([]u8 | io::error) = { assert(e.btn == 0); assert(e.start >= 0); if (e.cur_prim) { finish_prim(e); }; let n = 0z; let buf = memio::buffer(e.mem)[e.start..]; // iterate entries to minify tag ids and data sizes. 't' is the write // index and 'i' is the read index. let t = 0z; for (let i = 0z; i < e.pos) { // TODO cast seems off // encode id const id = buf[i]; buf[t] = id; t += 1; i += 1; const cons = (id >> 5) & 1 == 1; if ((id & 0b11111) == 0b11111) { // id spans multiple bytes let id: u8 = 0x80; for (id & 0x80 == 0x80) { id = buf[i]; buf[t] = id; t += 1; i += 1; }; }; // encode dsz let dsz: datasz = 0; let l = buf[i]; i += 1; if (l < 128) { // data size fits in a single byte dsz = l; buf[t] = l; t += 1; } else { // decode multibyte size and minimize, since not all // placeholder bytes may have been used. const dn = l & 0x7f; for (let j = 0z; j < dn; j += 1) { dsz <<= 8; dsz |= buf[i]; i += 1; }; let dszbuf = encode_dsz(dsz); buf[t..t + len(dszbuf)] = dszbuf; t += len(dszbuf); }; if (cons) { continue; }; // write data of primitive fields buf[t..t+dsz] = buf[i..i+dsz]; t += dsz; i += dsz; }; bytes::zero(buf[t..]); match (e.parent) { case null => void; case let s: *bytewstream => s.e.pos += t; }; return buf[..t]; }; // Encodes all buffered data in the [[encoder]] and writes it to the provided // [[io::handle]]. export fn encodeto(e: *encoder, dest: io::handle) (size | io::error) = { const buf = encode(e)?; return io::writeall(dest, buf)?; }; hare-0.24.2/encoding/asn1/errors.ha000066400000000000000000000030421464473310100167760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; // Encountered invalid DER encoded data. export type invalid = !void; // Unexpected data format. export type badformat = !void; // Premature EOF. export type truncated = !void; // Data does not fit into the encoder buffer. export type overflow = !void; type asn1error = !(invalid | badformat | overflow | truncated); // Any error within the asn1 module. export type error = !(...io::error | ...asn1error); // Converts an [[error]] into a user-friendly string. export fn strerror(e: error) str = { match (e) { case invalid => return "Encountered invalid DER encoded data"; case badformat => return "Unexpected data format"; case truncated => return "Premature EOF"; case overflow => return "Data does not fit into the encoder buffer"; case let e: io::error => return io::strerror(e); }; }; fn wrap_err(e: error) io::error = { match (e) { case let e: io::error => return e; case let e: asn1error => static assert(size(asn1error) <= size(errors::opaque_data)); let w = errors::opaque_ { strerror = &wrap_strerror, ... }; let ptr = &w.data: *error; *ptr = e; return w; }; }; fn wrap_strerror(err: *errors::opaque_data) const str = { let e = err: *error; return strerror(*e); }; // Unwraps an [[io::error]] returned by ASN.1 readers as an [[error]]. export fn unwrap_err(e: io::error) error = { match (e) { case let e: errors::opaque_ => let ptr = &e.data: *error; return *ptr; case let e: io::error => return e; }; }; hare-0.24.2/encoding/asn1/oid.ha000066400000000000000000000067411464473310100162460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use errors; use fmt; use io; use math::{divu}; use memio; // An oid database that contains a lookup table of known oids in the DER format. // A database of oids required by the standard library can be found in // [[encoding::asn1::stdoid]]. // // The database can be used with [[oid_from_der]] and [[oid_to_der]] to convert // an oid between integer and DER encoding. [[read_oid]] and [[write_oid]] can // be used to decode or encode the oid directly from and to DER. // // If the standard oid database is missing entries for the given use case, an // individual database can be generated using the genoiddb command found in // cmd/. Take a look at encoding/asn1/stdoid/db.txt for an example database // file. export type oiddb = struct { lut: []u8, index: []size, names: []str, }; // Numeric id of an oid which is unique within an [[oiddb]]. export type oid = u32; // Reads an oid if present in 'db'. Returns [[badformat]] if the oid is unknown. export fn read_oid(d: *decoder, db: *oiddb) (oid | error) = { let raw = read_rawoid(d)?; match (oid_from_der(db, raw)) { case let o: oid => return o; case => return badformat; }; }; // Reads any [[oid]] and returns the DER encoded form. The returned value is // borrowed from a static buffer. export fn read_rawoid(d: *decoder) ([]u8 | error) = { def OIDBUFSZ: size = 64; // estimated static let oidbuf: [OIDBUFSZ]u8 = [0...]; const dh = next(d)?; expect_utag(dh, utag::OID)?; if (dsz(dh) < 2) { return invalid; }; const n = read_bytes(d, oidbuf)?; return oidbuf[..n]; }; // Writes given [[oid]] from the [[oiddb]] 'db'. export fn write_oid(e: *encoder, db: *oiddb, oid: oid) (void | overflow) = { let doid = oid_to_der(db, oid); write_fixedprim(e, class::UNIVERSAL, utag::OID, doid)?; }; // Looks up DER encoded oid 'raw' in 'db' and returns an [[oid]] if found, or // void otheriwse. export fn oid_from_der(db: *oiddb, raw: []u8) (void | oid) = { for (let i = 0z; i < len(db.index); i += 1) { const off = db.index[i]; const l = db.lut[off]; if (bytes::equal(raw, db.lut[off + 1..off + 1 + l])) { return i: oid; }; }; }; // Borrows the DER representation of a known oid from 'db'. export fn oid_to_der(db: *oiddb, o: oid) []u8 = { const off = db.index[o]; const l = db.lut[off]; return db.lut[off + 1..off + 1 + l]; }; // Looks up a str representation of an oid from the database. export fn stroid(db: *oiddb, o: oid) str = { return db.names[o]; }; // Returns the dot id as string. The caller must free returned value. This // function may fail if the oid overflows the internal buffer, or an invalid // value is provided. export fn strrawoid(der: []u8) (str | io::error) = { let s = memio::dynamic(); let ok = false; defer if (!ok) io::close(&s)!; if (len(der) < 1) { return errors::invalid; }; const (a, b) = divu(0, der[0], 40); fmt::fprintf(&s, "{}.{}", a, b)?; let j = 2z; let el = 0u32; let bits: int = size(u32): int * 8; for (let i = 1z; i < len(der); i += 1) { el += der[i] & 0x7f; if (der[i] & 0x80 != 0) { if (bits - 7 < 0) { return errors::overflow; }; el <<= 7; bits -= 7; } else { fmt::fprintf(&s, ".{}", el)?; el = 0; j += 1; bits = size(u32): int * 8; }; }; ok = true; return memio::string(&s)!; }; @test fn strrawoid() void = { let der: [_]u8 = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01]; let s = strrawoid(der)!; defer free(s); assert(s == "1.2.840.113549.1.1.1"); }; hare-0.24.2/encoding/asn1/stdoid/000077500000000000000000000000001464473310100164375ustar00rootroot00000000000000hare-0.24.2/encoding/asn1/stdoid/db.ha000066400000000000000000000117131464473310100173410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // This is an auto generated file. Do not edit. use encoding::asn1; const _db = asn1::oiddb { lut = [ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x03, 0x2b, 0x65, 0x70, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0e, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x01, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04, 0x03, 0x55, 0x04, 0x03, 0x03, 0x55, 0x04, 0x04, 0x03, 0x55, 0x04, 0x05, 0x03, 0x55, 0x04, 0x06, 0x03, 0x55, 0x04, 0x07, 0x03, 0x55, 0x04, 0x08, 0x03, 0x55, 0x04, 0x0a, 0x03, 0x55, 0x04, 0x0b, 0x03, 0x55, 0x04, 0x0c, 0x03, 0x55, 0x04, 0x2a, 0x03, 0x55, 0x04, 0x2b, 0x03, 0x55, 0x04, 0x2b, 0x03, 0x55, 0x04, 0x2e, 0x03, 0x55, 0x04, 0x41, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x03, 0x55, 0x1d, 0x0f, 0x03, 0x55, 0x1d, 0x11, 0x03, 0x55, 0x1d, 0x13, 0x03, 0x55, 0x1d, 0x25, ], index = [ 0x0000, 0x000a, 0x000e, 0x0018, 0x0022, 0x002c, 0x0036, 0x0040, 0x0046, 0x0050, 0x005a, 0x0064, 0x006e, 0x0076, 0x007f, 0x0088, 0x008e, 0x0094, 0x009c, 0x00a5, 0x00ae, 0x00b7, 0x00c0, 0x00c4, 0x00c8, 0x00cc, 0x00d0, 0x00d4, 0x00d8, 0x00dc, 0x00e0, 0x00e4, 0x00e8, 0x00ec, 0x00f0, 0x00f4, 0x00f8, 0x0103, 0x0107, 0x010b, 0x010f, ], names = [ "rsaEncryption", "ed25519", "sha1WithRSAEncryption", "sha224WithRSAEncryption", "sha256WithRSAEncryption", "sha384WithRSAEncryption", "sha512WithRSAEncryption", "id-sha1", "id-sha224", "id-sha256", "id-sha384", "id-sha512", "id-ecPublicKey", "prime256v1", "ansix9p256r1", "ansix9p384r1", "ansix9p521r1", "ecdsa-with-SHA1", "ecdsa-with-SHA224", "ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512", "id-at-commonName", "id-at-surname", "id-at-serialNumber", "id-at-countryName", "id-at-localityName", "id-at-stateOrProvinceName", "id-at-organizationName", "id-at-organizationalUnitName", "id-at-title", "id-at-givenName", "id-at-initials", "id-at-generationQualifier", "id-at-dnQualifier", "id-at-pseudonym", "id-domainComponent", "id-ce-keyUsage", "id-ce-subjectAltName", "id-ce-basicConstraints", "id-ce-extKeyUsage", ], }; export const db = &_db; export def RSA_ENCRYPTION: asn1::oid = 0; export def ED25519: asn1::oid = 1; export def SHA1_WITH_RSAENCRYPTION: asn1::oid = 2; export def SHA224_WITH_RSAENCRYPTION: asn1::oid = 3; export def SHA256_WITH_RSAENCRYPTION: asn1::oid = 4; export def SHA384_WITH_RSAENCRYPTION: asn1::oid = 5; export def SHA512_WITH_RSAENCRYPTION: asn1::oid = 6; export def ID_SHA1: asn1::oid = 7; export def ID_SHA224: asn1::oid = 8; export def ID_SHA256: asn1::oid = 9; export def ID_SHA384: asn1::oid = 10; export def ID_SHA512: asn1::oid = 11; export def ID_EC_PUBLIC_KEY: asn1::oid = 12; export def PRIME256V1: asn1::oid = 13; export def ANSIX9P256R1: asn1::oid = 14; export def ANSIX9P384R1: asn1::oid = 15; export def ANSIX9P521R1: asn1::oid = 16; export def ECDSA_WITH_SHA1: asn1::oid = 17; export def ECDSA_WITH_SHA224: asn1::oid = 18; export def ECDSA_WITH_SHA256: asn1::oid = 19; export def ECDSA_WITH_SHA384: asn1::oid = 20; export def ECDSA_WITH_SHA512: asn1::oid = 21; export def ID_AT_COMMON_NAME: asn1::oid = 22; export def ID_AT_SURNAME: asn1::oid = 23; export def ID_AT_SERIAL_NUMBER: asn1::oid = 24; export def ID_AT_COUNTRY_NAME: asn1::oid = 25; export def ID_AT_LOCALITY_NAME: asn1::oid = 26; export def ID_AT_STATE_OR_PROVINCE_NAME: asn1::oid = 27; export def ID_AT_ORGANIZATION_NAME: asn1::oid = 28; export def ID_AT_ORGANIZATIONAL_UNIT_NAME: asn1::oid = 29; export def ID_AT_TITLE: asn1::oid = 30; export def ID_AT_GIVEN_NAME: asn1::oid = 31; export def ID_AT_INITIALS: asn1::oid = 32; export def ID_AT_GENERATION_QUALIFIER: asn1::oid = 33; export def ID_AT_DN_QUALIFIER: asn1::oid = 34; export def ID_AT_PSEUDONYM: asn1::oid = 35; export def ID_DOMAIN_COMPONENT: asn1::oid = 36; export def ID_CE_KEY_USAGE: asn1::oid = 37; export def ID_CE_SUBJECT_ALT_NAME: asn1::oid = 38; export def ID_CE_BASIC_CONSTRAINTS: asn1::oid = 39; export def ID_CE_EXT_KEY_USAGE: asn1::oid = 40; hare-0.24.2/encoding/asn1/stdoid/db.txt000066400000000000000000000035731464473310100175750ustar00rootroot00000000000000# OIDs that will be translated into db.ha using `genoiddb` rsaEncryption 1.2.840.113549.1.1.1 ed25519 1.3.101.112 sha1WithRSAEncryption 1.2.840.113549.1.1.5 sha224WithRSAEncryption 1.2.840.113549.1.1.14 sha256WithRSAEncryption 1.2.840.113549.1.1.11 sha384WithRSAEncryption 1.2.840.113549.1.1.12 sha512WithRSAEncryption 1.2.840.113549.1.1.13 id-sha1 1.3.14.3.2.26 id-sha224 2.16.840.1.101.3.4.2.4 id-sha256 2.16.840.1.101.3.4.2.1 id-sha384 2.16.840.1.101.3.4.2.2 id-sha512 2.16.840.1.101.3.4.2.3 id-ecPublicKey 1.2.840.10045.2.1 prime256v1 1.2.840.10045.3.1.7 ansix9p256r1 1.2.840.10045.3.1.7 ansix9p384r1 1.3.132.0.34 ansix9p521r1 1.3.132.0.35 ecdsa-with-SHA1 1.2.840.10045.4.1 ecdsa-with-SHA224 1.2.840.10045.4.3.1 ecdsa-with-SHA256 1.2.840.10045.4.3.2 ecdsa-with-SHA384 1.2.840.10045.4.3.3 ecdsa-with-SHA512 1.2.840.10045.4.3.4 id-at-commonName 2.5.4.3 id-at-surname 2.5.4.4 id-at-serialNumber 2.5.4.5 id-at-countryName 2.5.4.6 id-at-localityName 2.5.4.7 id-at-stateOrProvinceName 2.5.4.8 id-at-organizationName 2.5.4.10 id-at-organizationalUnitName 2.5.4.11 id-at-title 2.5.4.12 id-at-givenName 2.5.4.42 id-at-initials 2.5.4.43 id-at-generationQualifier 2.5.4.43 id-at-dnQualifier 2.5.4.46 id-at-pseudonym 2.5.4.65 id-domainComponent 0.9.2342.19200300.100.1.25 id-ce-keyUsage 2.5.29.15 id-ce-subjectAltName 2.5.29.17 id-ce-basicConstraints 2.5.29.19 id-ce-extKeyUsage 2.5.29.37 hare-0.24.2/encoding/asn1/strings.ha000066400000000000000000000174461464473310100171700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use endian; use io; use strings; // numeric string def N: u8 = 0o1; // printable string def P: u8 = 0o2; // LUT of bitfields with character attributes const cclass: [_]u8 = [ // 0 1 2 3 4 5 6 7 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, // 10 0, 0, 0, 0, 0, 0, 0, 0, // 20 0, 0, 0, 0, 0, 0, 0, 0, // 30 N|P, 0, 0, 0, 0, 0, 0, P, // 40 P, P, 0, P, P, P, P, P, // 50 N|P, N|P, N|P, N|P, N|P, N|P, N|P, N|P, // 60 N|P, N|P, P, 0, 0, P, 0, P, // 70 0, P, P, P, P, P, P, P, // 100 P, P, P, P, P, P, P, P, // 110 P, P, P, P, P, P, P, P, // 120 P, P, P, 0, 0, 0, 0, 0, // 130 0, P, P, P, P, P, P, P, // 140 P, P, P, P, P, P, P, P, // 150 P, P, P, P, P, P, P, P, // 160 P, P, P, 0, 0, 0, 0, 0, // 170 ]; type char_validator = fn (c: u8) bool; // Whether 'c' is valid in a NumericString fn c_is_num(c: u8) bool = c & 0x80 == 0 && cclass[c] & N != 0; // Whether 'c' is valid in a PrintableString fn c_is_print(c: u8) bool = c & 0x80 == 0 && cclass[c] & P != 0; fn c_is_ia5(c: u8) bool = c & 0x80 == 0; // Returns the number of bytes of the biggest complete utf8 chunk. Returns // invalid, if the biggest complete chunk contains invalid utf8 characters. fn validutf8(buf: []u8) (size | invalid) = { if (len(buf) == 0) { return 0z; }; const min = if (len(buf) < 4) 0z else len(buf) - 4; let lastvalid = 0z; let lastsz = 0z; for (let i = min; i < len(buf); i += 1) { match (utf8::utf8sz(buf[i])) { case utf8::invalid => void; case let s: size => lastsz = s; lastvalid = i; }; }; if (lastsz == 0) return invalid; const n = if (len(buf) - lastvalid == lastsz) len(buf) else lastvalid; if (utf8::validate(buf[..n]) is utf8::invalid) { return invalid; }; return n; }; @test fn validutf8() void = { let b: [_]u8 = [ 0x55, 0x56, 0xd0, 0x98, 0xe0, 0xa4, 0xb9, 0xf0, 0x90, 0x8d, 0x88 ]; const runesat: [_]size = [0, 1, 2, 2, 4, 4, 4, 7, 7, 7, 7, 8]; for (let i = 0z; i < len(b); i += 1) { assert(validutf8(b[..i])! == runesat[i]); }; b[10] = 0x55; assert(validutf8(b[..10])! == 7); assert(validutf8(b) is invalid); }; // An io::stream reader that returns only valid utf8 chunks on read. export type utf8stream = struct { stream: io::stream, d: *decoder, strdec: *strdecoder, }; const utf8stream_vtable = io::vtable { reader = &utf8stream_reader, ... }; fn utf8stream_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { // at least a rune must fit in buf assert(len(buf) >= 4); let s = s: *utf8stream; let cur = match (s.d.cur) { case void => abort(); case let dh: head => yield dh; }; match (s.strdec(s, buf)?) { case let n: size => return n; case io::EOF => return io::EOF; }; }; export type strdecoder = fn( s: *utf8stream, buf: []u8, ) (size | io::EOF | io::error); fn no_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = dataread(s.d, buf); fn char_decoder( s: *utf8stream, buf: []u8, v: *char_validator, ) (size | io::EOF | io::error) = { let n = match (dataread(s.d, buf)?) { case let n: size => yield n; case io::EOF => return io::EOF; }; for (let i = 0z; i < n; i += 1) { if (!v(buf[i])) return wrap_err(invalid); }; return n; }; fn num_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = char_decoder(s, buf, &c_is_num); fn print_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = char_decoder(s, buf, &c_is_print); fn ia5_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = char_decoder(s, buf, &c_is_ia5); fn utf8_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = { let n = 0z; n += match (dataread(s.d, buf)?) { case let sz: size => yield sz; case io::EOF => if (s.d.unbufn > 0) return wrap_err(invalid); return io::EOF; }; const max = match (validutf8(buf[..n])) { case let s: size => yield s; case invalid => return wrap_err(invalid); }; if (max < n) { if (dataeof(s.d)) { // string ends with incomplete rune return wrap_err(invalid); }; dataunread(s.d, buf[max..n]); return max; }; return n; }; // A bmp string is an UTF-16 string. fn bmp_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = { const max = len(buf) - (len(buf) % 2); // TODO disallow control functions (X.690: 8.23.9) let n = 0z; let rbuf: [2]u8 = [0...]; for (true) { match (dataread(s.d, rbuf)?) { case let sz: size => if (sz < 2) return wrap_err(invalid); case io::EOF => return if (n == 0) io::EOF else n; }; let r = endian::begetu16(rbuf): rune; let rb = utf8::encoderune(r); if (len(buf) - n < len(rb)) { dataunread(s.d, rbuf); return n; }; buf[n..n + len(rb)] = rb; n += len(rb); }; }; // Universal string is an UTF32BE string. fn universal_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = { const max = len(buf) - (len(buf) % 4); let n = 0z; let rbuf: [4]u8 = [0...]; for (true) { match (dataread(s.d, rbuf)?) { case let sz: size => if (sz < 4) return wrap_err(invalid); case io::EOF => return if (n == 0) io::EOF else n; }; let r = endian::begetu32(rbuf): rune; let rb = utf8::encoderune(r); if (len(buf) - n < len(rb)) { dataunread(s.d, rbuf); return n; }; buf[n..n + len(rb)] = rb; n += len(rb); }; }; fn t61_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = { let inbuf: [2]u8 = [0...]; let in = inbuf[..0]; let n = 0z; for (true) { let chr: [1]u8 = [0]; match (dataread(s.d, chr)?) { case let sz: size => assert(sz == 1); static append(in, chr[0]); case io::EOF => if (len(in) > 0) return wrap_err(invalid); if (n > 0) return n; return io::EOF; }; match (t61_chardecode(in)) { case let r: rune => let raw = utf8::encoderune(r); const bufremain = len(buf) - n; if (len(raw) < bufremain) { buf[n..n + len(raw)] = raw[..]; n += len(raw); in = inbuf[..0]; } else { dataunread(s.d, in); break; }; case insufficient => // leave combining char in in void; case invalid => return wrap_err(invalid); }; }; return n; }; fn newstrreader(d: *decoder, t: utag) (utf8stream | error) = { let strdec: *strdecoder = switch (t) { case utag::NUMERIC_STRING => yield &num_decoder; case utag::PRINTABLE_STRING => yield &print_decoder; case utag::IA5_STRING => yield &ia5_decoder; case utag::UTF8_STRING => yield &utf8_decoder; case utag::TELETEX_STRING => yield &t61_decoder; case utag::BMP_STRING => yield &bmp_decoder; case utag::UNIVERSAL_STRING => yield &universal_decoder; case => return invalid; }; return utf8stream { stream = &utf8stream_vtable, d = d, strdec = strdec, ... }; }; // Returns an [[utf8stream]] for a supported utag 't', which is one of: // * utag::NUMERIC_STRING // * utag::PRINTABLE_STRING // * utag::IA5_STRING // * utag::UTF8_STRING // * utag::TELETEX_STRING // * utag::BMP_STRING // * utag::UNIVERSAL_STRING export fn strreader(d: *decoder, t: utag) (utf8stream | error) = { let dh = next(d)?; expect_utag(dh, t)?; return newstrreader(d, t)!; }; // Reads a printable string into 'buf'. export fn read_printstr(d: *decoder, buf: []u8) (size | error) = { let dh = next(d)?; expect_utag(dh, utag::PRINTABLE_STRING)?; const n = read_bytes(d, buf)?; for (let i = 0z; i < n; i += 1) { if (!c_is_print(buf[i])) { return invalid; }; }; return n; }; // Reads an utf8 string into 'buf' and returns a str that borrows from buf. export fn read_utf8str(d: *decoder, buf: []u8) (str | error) = { let dh = next(d)?; expect_utag(dh, utag::UTF8_STRING)?; let r = newstrreader(d, utag::UTF8_STRING)!; let n = 0z; for (true) { n += match (io::read(&r, buf[n..])) { case let sz: size => yield sz; case io::EOF => break; case let e: io::error => return unwrap_err(e); }; }; return strings::fromutf8(buf[..n])!; }; hare-0.24.2/encoding/asn1/t61.ha000066400000000000000000000236041464473310100161020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // https://en.wikipedia.org/wiki/ITU_T.61 const t61toascii: [_]u8 = [ // 0 1 2 3 4 5 6 7 // 8 9 a b c d e f 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0x0a, 0, 0x0c, 0x0d, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, // 10 0, 0, 0x1a, 0x1b, 0, 0, 0, 0, // 10 0x20, 0x21, 0x22, 0, 0, 0x25, 0x26, 0x27, // 20 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, // 20 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // 30 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, // 30 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // 40 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, // 40 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 50 0x58, 0x59, 0x5a, 0x5b, 0, 0x5d, 0, 0x5f, // 50 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // 60 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, // 60 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 70 0x78, 0x79, 0x7a, 0, 0x7c, 0, 0, 0, // 70 ]; const t61toutf8: [_]rune = [ // 0x80 '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u008b', '\u008c', '\u0000', '\u0000', '\u0000', // 0x90 '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u009b', '\u0000', '\u0000', '\u0000', '\u0000', // 0xa0 '\u00a0', '\u00a1', '\u00a2', '\u00a3', '\u0024', '\u00a5', '\u0023', '\u00a7', '\u00a4', '\u0000', '\u0000', '\u00ab', '\u0000', '\u0000', '\u0000', '\u0000', // 0x0b '\u00b0', '\u00b1', '\u00b2', '\u00b3', '\u00d7', '\u00b5', '\u00b6', '\u00b7', '\u00f7', '\u0000', '\u0000', '\u00bb', '\u00bc', '\u00bd', '\u00be', '\u00bf', // 0xc0 '\u0000', '\u0300', '\u0301', '\u0302', '\u0303', '\u0304', '\u0306', '\u0307', '\u0308', '\u0308', '\u030a', '\u0327', '\u0332', '\u030b', '\u0328', '\u030c', // 0xd0 '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', // 0xe0 '\u2126', '\u00c6', '\u00d0', '\u00aa', '\u0126', '\u0000', '\u0132', '\u013f', '\u0141', '\u00d8', '\u0152', '\u00ba', '\u00de', '\u0166', '\u014a', '\u0149', // 0xf0 '\u0138', '\u00e6', '\u0111', '\u00f0', '\u0127', '\u0131', '\u0133', '\u0140', '\u0142', '\u00f8', '\u0153', '\u00df', '\u00fe', '\u0167', '\u014b', '\u0000', ]; fn decode(out: []u8, in: []u8) void = { for (let i = 0z; i < len(in); i += 1) { const c = in[i]; const r: rune = if (c & 0x80 != 0) { // TODO special cases yield t61toutf8[c - 0x80]; } else { const c = t61toascii[in[i]]; yield c: u32: rune; }; // write r to out }; return; }; export type insufficient = !void; export fn t61_chardecode(in: []u8) (rune | insufficient | invalid) = { // 'in' is either one char or two if first is a combining character. if (len(in) == 2) { return t61_combine(in); }; const in = in[0]; if (in & 0x80 == 0) { const r = t61toascii[in]; return if (r == 0) invalid else r: u32: rune; }; const c = t61toutf8[in - 0x80]; if (c == '\u0000') { return invalid; }; if (in == 0xcc) { return invalid; }; if (in > 0xc0 && in <= 0xcf) { return insufficient; }; return c; }; fn t61_combine(in: []u8) (rune | invalid) = { const comb = in[0]; const in = in[1]; switch (comb) { case 0xc1 => switch (in: u32: rune) { case 'A' => return '\u00c0'; case 'E' => return '\u00c8'; case 'I' => return '\u00cc'; case 'O' => return '\u00d2'; case 'U' => return '\u00d9'; case 'a' => return '\u00e0'; case 'e' => return '\u00e8'; case 'i' => return '\u00ec'; case 'o' => return '\u00f2'; case 'u' => return '\u00f9'; case => return invalid; }; case 0xc2 => switch (in: u32: rune) { case 'A' => return '\u00c1'; case 'C' => return '\u0106'; case 'E' => return '\u00c9'; case 'I' => return '\u00cd'; case 'L' => return '\u0139'; case 'N' => return '\u0143'; case 'O' => return '\u00d3'; case 'R' => return '\u0154'; case 'S' => return '\u015a'; case 'U' => return '\u00da'; case 'Y' => return '\u00dd'; case 'Z' => return '\u0179'; case 'a' => return '\u00e1'; case 'c' => return '\u0107'; case 'e' => return '\u00e9'; case 'g' => return '\u0123'; case 'i' => return '\u00ed'; case 'l' => return '\u013a'; case 'n' => return '\u0144'; case 'o' => return '\u00f3'; case 'r' => return '\u0155'; case 's' => return '\u015b'; case 'u' => return '\u00fa'; case 'y' => return '\u00fd'; case 'z' => return '\u017a'; case => return invalid; }; case 0xc3 => switch (in: u32: rune) { case 'A' => return '\u00c2'; case 'C' => return '\u0108'; case 'E' => return '\u00ca'; case 'G' => return '\u011c'; case 'H' => return '\u0124'; case 'I' => return '\u00ce'; case 'J' => return '\u0134'; case 'O' => return '\u00d4'; case 'S' => return '\u015c'; case 'U' => return '\u00db'; case 'W' => return '\u0174'; case 'Y' => return '\u0176'; case 'a' => return '\u00e2'; case 'c' => return '\u0109'; case 'e' => return '\u00ea'; case 'g' => return '\u011d'; case 'h' => return '\u0125'; case 'i' => return '\u00ee'; case 'j' => return '\u0135'; case 'o' => return '\u00f4'; case 's' => return '\u015d'; case 'u' => return '\u00fb'; case 'w' => return '\u0175'; case 'y' => return '\u0177'; case => return invalid; }; case 0xc4 => switch (in: u32: rune) { case 'A' => return '\u00c3'; case 'I' => return '\u0128'; case 'N' => return '\u00d1'; case 'O' => return '\u00d5'; case 'U' => return '\u0168'; case 'a' => return '\u00e3'; case 'i' => return '\u0129'; case 'n' => return '\u00f1'; case 'o' => return '\u00f5'; case 'u' => return '\u0169'; case => return invalid; }; case 0xc5 => switch (in: u32: rune) { case 'A' => return '\u0100'; case 'E' => return '\u0112'; case 'I' => return '\u012a'; case 'O' => return '\u014c'; case 'U' => return '\u016a'; case 'a' => return '\u0101'; case 'e' => return '\u0113'; case 'i' => return '\u012b'; case 'o' => return '\u014d'; case 'u' => return '\u016b'; case => return invalid; }; case 0xc6 => switch (in: u32: rune) { case 'A' => return '\u0102'; case 'G' => return '\u011e'; case 'U' => return '\u016c'; case 'a' => return '\u0103'; case 'g' => return '\u011f'; case 'u' => return '\u016d'; case => return invalid; }; case 0xc7 => switch (in: u32: rune) { case 'C' => return '\u010a'; case 'E' => return '\u0116'; case 'G' => return '\u0120'; case 'I' => return '\u0130'; case 'Z' => return '\u017b'; case 'c' => return '\u010b'; case 'e' => return '\u0117'; case 'g' => return '\u0121'; case 'z' => return '\u017c'; case => return invalid; }; case 0xc8 => switch (in: u32: rune) { case 'A' => return '\u00c4'; case 'E' => return '\u00cb'; case 'I' => return '\u00cf'; case 'O' => return '\u00d6'; case 'U' => return '\u00dc'; case 'Y' => return '\u0178'; case 'a' => return '\u00e4'; case 'e' => return '\u00eb'; case 'i' => return '\u00ef'; case 'o' => return '\u00f6'; case 'u' => return '\u00fc'; case 'y' => return '\u00ff'; case => return invalid; }; case 0xc9 => switch (in: u32: rune) { case 'A' => return '\u00c4'; case 'E' => return '\u00cb'; case 'I' => return '\u00cf'; case 'O' => return '\u00d6'; case 'U' => return '\u00dc'; case 'Y' => return '\u0178'; case 'a' => return '\u00e4'; case 'e' => return '\u00eb'; case 'i' => return '\u00ef'; case 'o' => return '\u00f6'; case 'u' => return '\u00fc'; case 'y' => return '\u00ff'; case => return invalid; }; case 0xca => switch (in: u32: rune) { case 'A' => return '\u00c5'; case 'U' => return '\u016e'; case 'a' => return '\u00e5'; case 'u' => return '\u016f'; case => return invalid; }; case 0xcb => switch (in: u32: rune) { case 'C' => return '\u00c7'; case 'G' => return '\u0122'; case 'K' => return '\u0136'; case 'L' => return '\u013b'; case 'N' => return '\u0145'; case 'R' => return '\u0156'; case 'S' => return '\u015e'; case 'T' => return '\u0162'; case 'c' => return '\u00e7'; case 'k' => return '\u0137'; case 'l' => return '\u013c'; case 'n' => return '\u0146'; case 'r' => return '\u0157'; case 's' => return '\u015f'; case 't' => return '\u0163'; case => return invalid; }; case 0xcd => switch (in: u32: rune) { case 'O' => return '\u0150'; case 'U' => return '\u0170'; case 'o' => return '\u0151'; case 'u' => return '\u0171'; case => return invalid; }; case 0xce => switch (in: u32: rune) { case 'A' => return '\u0104'; case 'E' => return '\u0118'; case 'I' => return '\u012e'; case 'U' => return '\u0172'; case 'a' => return '\u0105'; case 'e' => return '\u0119'; case 'i' => return '\u012f'; case 'u' => return '\u0173'; case => return invalid; }; case 0xCf => switch (in: u32: rune) { case 'C' => return '\u010c'; case 'D' => return '\u010e'; case 'E' => return '\u011a'; case 'L' => return '\u013d'; case 'N' => return '\u0147'; case 'R' => return '\u0158'; case 'S' => return '\u0160'; case 'T' => return '\u0164'; case 'Z' => return '\u017d'; case 'c' => return '\u010d'; case 'd' => return '\u010f'; case 'e' => return '\u011b'; case 'l' => return '\u013e'; case 'n' => return '\u0148'; case 'r' => return '\u0159'; case 's' => return '\u0161'; case 't' => return '\u0165'; case 'z' => return '\u017e'; case => return invalid; }; case => return invalid; }; }; hare-0.24.2/encoding/asn1/types.ha000066400000000000000000000055721464473310100166400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use memio; // Data types specified in the standard export type class = enum u8 { UNIVERSAL = 0x0, APPLICATION = 0x1, CONTEXT = 0x2, PRIVATE = 0x3, }; // String representation of 'c'. export fn strclass(c: class) str = { switch (c) { case class::UNIVERSAL => return "UNIVERSAL"; case class::APPLICATION => return "APPLICATION"; case class::CONTEXT => return "CONTEXT_SPECIFIC"; case class::PRIVATE => return "PRIVATE"; }; }; // Universal tags as defined in x.690. Not all are supported by this // implemenation. export type utag = enum u8 { RESERVED = 0x00, BOOLEAN = 0x01, INTEGER = 0x02, BITSTRING = 0x03, OCTET_STRING = 0x04, NULL = 0x05, OID = 0x06, OBJECT_DESCRIPTOR = 0x07, EXTERNAL = 0x08, REAL = 0x09, ENUMERATED = 0x0a, EMBEDDED_PDV = 0x0b, UTF8_STRING = 0x0c, RELATIVE_OID = 0x0d, TIME = 0x0e, RESERVED2 = 0x0f, SEQUENCE = 0x10, SET = 0x11, NUMERIC_STRING = 0x12, PRINTABLE_STRING = 0x13, TELETEX_STRING = 0x14, // T61String VIDEOTEX_STRING = 0x15, IA5_STRING = 0x16, UTC_TIME = 0x17, GENERALIZED_TIME = 0x18, GRAPHIC_STRING = 0x19, VISIBLE_STRING = 0x1a, // iso646String GENERAL_STRING = 0x1b, UNIVERSAL_STRING = 0x1c, UNKNOWN = 0x1d, BMP_STRING = 0x1e, DATE = 0x1f, TIME_OF_DAY = 0x20, DATE_TIME = 0x21, DURATION = 0x22, OID_IRI = 0x23, OID_RELATIVE_IRI = 0x24, }; // String representation of universal tag ids. May return a statically allocated // string and will be overwritten on the next call. export fn strtag(dh: head) str = { static let tagstrbuf: [128]u8 = [0...]; if (dh.class != class::UNIVERSAL) { let tagstr = memio::fixed(tagstrbuf); fmt::fprint(&tagstr, "[")!; if (dh.class != class::CONTEXT) { fmt::fprintf(&tagstr, "{} ", strclass(dh.class))!; }; fmt::fprintf(&tagstr, "{:x}]", dh.tagid)!; return memio::string(&tagstr)!; }; if (dh.tagid >> 8 != 0) { return "UNKNOWN"; }; switch (dh.tagid: u8) { case utag::BOOLEAN => return "BOOLEAN"; case utag::INTEGER => return "INTEGER"; case utag::BITSTRING => return "BITSTRING"; case utag::OCTET_STRING => return "OCTET_STRING"; case utag::NULL => return "NULL"; case utag::OID => return "OBJECT_IDENTIFIER"; case utag::OBJECT_DESCRIPTOR => return "OBJECT_DESCRIPTOR"; case utag::EXTERNAL => return "EXTERNAL"; case utag::REAL => return "REAL"; case utag::ENUMERATED => return "ENUMERATED"; case utag::EMBEDDED_PDV => return "EMBEDDED_PDV"; case utag::UTF8_STRING => return "UTF8_STRING"; case utag::RELATIVE_OID => return "RELATIVE_OID"; case utag::TIME => return "TIME"; case utag::SEQUENCE => return "SEQUENCE"; case utag::SET => return "SET"; case utag::PRINTABLE_STRING => return "PRINTABLE_STRING"; case utag::TELETEX_STRING => return "TELETEX_STRING"; case utag::UTC_TIME => return "UTC_TIME"; case => return "UNKNOWN"; }; }; hare-0.24.2/encoding/base32/000077500000000000000000000000001464473310100153665ustar00rootroot00000000000000hare-0.24.2/encoding/base32/README000066400000000000000000000017131464473310100162500ustar00rootroot00000000000000Implementation of the base32 encoding scheme as defined by RFC 4648. A stream-based encoding and decoding interface is available via [[newencoder]] and [[newdecoder]], which transparently encode or decode bytes to or from base32 when writing to or reading from an underlying I/O handle. Convenience functions for encoding to or decoding from a byte slice or a string are also available; see [[encodeslice]], [[decodeslice]], [[encodestr]], and [[decodestr]]. These functions dynamically allocate their return values; use the stream interface if you require static allocation. Each function accepts the desired base32 encoding alphabet as its first argument. [[std_encoding]] and [[hex_encoding]], as defined by the RFC, are provided for your convenience, but you may create your own encoding using [[encoding_init]]. Due to security concerns described by the RFC, this implementation rejects invalid padding. https://datatracker.ietf.org/doc/html/rfc4648#section-12 hare-0.24.2/encoding/base32/base32.ha000066400000000000000000000273711464473310100167710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bytes; use errors; use io; use memio; use os; use strings; def PADDING: u8 = '='; export type encoding = struct { encmap: [32]u8, decmap: [256]u8, valid: [256]bool, }; // Represents the standard base-32 encoding alphabet as defined in RFC 4648. export const std_encoding: encoding = encoding { ... }; // Represents the "base32hex" alphabet as defined in RFC 4648. export const hex_encoding: encoding = encoding { ... }; // Initializes a new encoding based on the passed alphabet, which must be a // 32-byte ASCII string. export fn encoding_init(enc: *encoding, alphabet: str) void = { const alphabet = strings::toutf8(alphabet); assert(len(alphabet) == 32); for (let i: u8 = 0; i < 32; i += 1) { const ch = alphabet[i]; assert(ascii::valid(ch: rune)); enc.encmap[i] = ch; enc.decmap[ch] = i; enc.valid[ch] = true; }; }; @init fn init() void = { const std_alpha: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; const hex_alpha: str = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; encoding_init(&std_encoding, std_alpha); encoding_init(&hex_encoding, hex_alpha); }; export type encoder = struct { stream: io::stream, out: io::handle, enc: *encoding, buf: [4]u8, // leftover input avail: size, // bytes available in buf err: (void | io::error), }; const encoder_vtable: io::vtable = io::vtable { writer = &encode_writer, closer = &encode_closer, ... }; // Creates a stream that encodes writes as base-32 before writing them to a // secondary stream. The encoder stream must be closed to finalize any unwritten // bytes. Closing this stream will not close the underlying stream. export fn newencoder( enc: *encoding, out: io::handle, ) encoder = { return encoder { stream = &encoder_vtable, out = out, enc = enc, err = void, ... }; }; fn encode_writer( s: *io::stream, in: const []u8 ) (size | io::error) = { let s = s: *encoder; match(s.err) { case let err: io::error => return err; case void => void; }; let l = len(in); let i = 0z; for (i + 4 < l + s.avail; i += 5) { static let b: [5]u8 = [0...]; // 5 bytes -> (enc) 8 bytes if (i < s.avail) { for (let j = 0z; j < s.avail; j += 1) { b[j] = s.buf[i]; }; for (let j = s.avail; j < 5; j += 1) { b[j] = in[j - s.avail]; }; } else { for (let j = 0z; j < 5; j += 1) { b[j] = in[j - s.avail + i]; }; }; let encb: [8]u8 = [ s.enc.encmap[b[0] >> 3], s.enc.encmap[(b[0] & 0x7) << 2 | (b[1] & 0xC0) >> 6], s.enc.encmap[(b[1] & 0x3E) >> 1], s.enc.encmap[(b[1] & 0x1) << 4 | (b[2] & 0xF0) >> 4], s.enc.encmap[(b[2] & 0xF) << 1 | (b[3] & 0x80) >> 7], s.enc.encmap[(b[3] & 0x7C) >> 2], s.enc.encmap[(b[3] & 0x3) << 3 | (b[4] & 0xE0) >> 5], s.enc.encmap[b[4] & 0x1F], ]; match(io::write(s.out, encb)) { case let err: io::error => s.err = err; return err; case size => void; }; }; // storing leftover bytes if (l + s.avail < 5) { for (let j = s.avail; j < s.avail + l; j += 1) { s.buf[j] = in[j - s.avail]; }; } else { const begin = (l + s.avail) / 5 * 5; for (let j = begin; j < l + s.avail; j += 1) { s.buf[j - begin] = in[j - s.avail]; }; }; s.avail = (l + s.avail) % 5; return l; }; fn encode_closer(s: *io::stream) (void | io::error) = { let s = s: *encoder; if (s.avail == 0) { return; }; static let b: [5]u8 = [0...]; // the 5 bytes that will be encoded into 8 bytes for (let i = 0z; i < 5; i += 1) { b[i] = if (i < s.avail) s.buf[i] else 0; }; let encb: [8]u8 = [ s.enc.encmap[b[0] >> 3], s.enc.encmap[(b[0] & 0x7) << 2 | (b[1] & 0xC0) >> 6], s.enc.encmap[(b[1] & 0x3E) >> 1], s.enc.encmap[(b[1] & 0x1) << 4 | (b[2] & 0xF0) >> 4], s.enc.encmap[(b[2] & 0xF) << 1 | (b[3] & 0x80) >> 7], s.enc.encmap[(b[3] & 0x7C) >> 2], s.enc.encmap[(b[3] & 0x3) << 3 | (b[4] & 0xE0) >> 5], s.enc.encmap[b[4] & 0x1F], ]; // adding padding as input length was not a multiple of 5 // 0 1 2 3 4 static const npa: []u8 = [0, 6, 4, 3, 1]; const np = npa[s.avail]; for (let i = 0z; i < np; i += 1) { encb[7 - i] = PADDING; }; io::writeall(s.out, encb)?; }; // Encodes a byte slice in base-32, using the given encoding, returning a slice // of ASCII bytes. The caller must free the return value. export fn encodeslice(enc: *encoding, in: []u8) []u8 = { let out = memio::dynamic(); let encoder = newencoder(enc, &out); io::writeall(&encoder, in)!; io::close(&encoder)!; return memio::buffer(&out); }; // Encodes a byte slice in base-32, using the given encoding, returning a // string. The caller must free the return value. export fn encodestr(enc: *encoding, in: []u8) str = { return strings::fromutf8(encodeslice(enc, in))!; }; @test fn encode() void = { // RFC 4648 test vectors const in: [_]u8 = ['f', 'o', 'o', 'b', 'a', 'r']; const expect: [_]str = [ "", "MY======", "MZXQ====", "MZXW6===", "MZXW6YQ=", "MZXW6YTB", "MZXW6YTBOI======", ]; const expect_hex: [_]str = [ "", "CO======", "CPNG====", "CPNMU===", "CPNMUOG=", "CPNMUOJ1", "CPNMUOJ1E8======", ]; for (let i = 0z; i <= len(in); i += 1) { let out = memio::dynamic(); let enc = newencoder(&std_encoding, &out); io::writeall(&enc, in[..i]) as size; io::close(&enc)!; let outb = memio::buffer(&out); assert(bytes::equal(outb, strings::toutf8(expect[i]))); free(outb); // Testing encodestr should cover encodeslice too let s = encodestr(&std_encoding, in[..i]); defer free(s); assert(s == expect[i]); out = memio::dynamic(); enc = newencoder(&hex_encoding, &out); io::writeall(&enc, in[..i]) as size; io::close(&enc)!; let outb = memio::buffer(&out); assert(bytes::equal(outb, strings::toutf8(expect_hex[i]))); free(outb); let s = encodestr(&hex_encoding, in[..i]); defer free(s); assert(s == expect_hex[i]); }; }; export type decoder = struct { stream: io::stream, in: io::handle, enc: *encoding, avail: []u8, // leftover decoded output pad: bool, // if padding was seen in a previous read state: (void | io::EOF | io::error), }; const decoder_vtable: io::vtable = io::vtable { reader = &decode_reader, ... }; // Creates a stream that reads and decodes base-32 data from a secondary stream. // This stream does not need to be closed, and closing it will not close the // underlying stream. export fn newdecoder( enc: *encoding, in: io::handle, ) decoder = { return decoder { stream = &decoder_vtable, in = in, enc = enc, state = void, ... }; }; fn decode_reader( s: *io::stream, out: []u8 ) (size | io::EOF | io::error) = { let s = s: *decoder; let n = 0z; let l = len(out); match(s.state) { case let err: (io::EOF | io ::error) => return err; case void => void; }; if (len(s.avail) > 0) { n += if (l < len(s.avail)) l else len(s.avail); out[..n] = s.avail[0..n]; s.avail = s.avail[n..]; if (l == n) { return n; }; }; static let buf: [os::BUFSZ]u8 = [0...]; static let obuf: [os::BUFSZ / 8 * 5]u8 = [0...]; const nn = ((l - n) / 5 + 1) * 8; // 8 extra bytes may be read. let nr = 0z; for (nr < nn) { match (io::read(s.in, buf[nr..])) { case let n: size => nr += n; case io::EOF => s.state = io::EOF; break; case let err: io::error => s.state = err; return err; }; }; if (nr % 8 != 0) { s.state = errors::invalid; return errors::invalid; }; if (nr == 0) { // io::EOF already set return n; }; // Validating read buffer let valid = true; let np = 0; // Number of padding chars. let p = true; // Pad allowed in buf for (let i = nr; i > 0; i -= 1) { const ch = buf[i - 1]; if (ch == PADDING) { if(s.pad || !p) { valid = false; break; }; np += 1; } else { if (!s.enc.valid[ch]) { valid = false; break; }; // Disallow padding on seeing a non-padding char p = false; }; }; valid = valid && np <= 6 && np != 2 && np != 5; if (np > 0) { s.pad = true; }; if (!valid) { s.state = errors::invalid; return errors::invalid; }; for (let i = 0z; i < nr; i += 1) { buf[i] = s.enc.decmap[buf[i]]; }; for (let i = 0z, j = 0z; i < nr) { obuf[j] = (buf[i] << 3) | (buf[i + 1] & 0x1C) >> 2; obuf[j + 1] = (buf[i + 1] & 0x3) << 6 | buf[i + 2] << 1 | (buf[i + 3] & 0x10) >> 4; obuf[j + 2] = (buf[i + 3] & 0x0F) << 4 | (buf[i + 4] & 0x1E) >> 1; obuf[j + 3] = (buf[i + 4] & 0x1) << 7 | buf[i + 5] << 2 | (buf[i + 6] & 0x18) >> 3; obuf[j + 4] = (buf[i + 6] & 0x7) << 5 | buf[i + 7]; i += 8; j += 5; }; // Removing bytes added due to padding. // 0 1 2 3 4 5 6 // np static const npr: [7]u8 = [0, 1, 0, 2, 3, 0, 4]; // bytes to discard const navl = nr / 8 * 5 - npr[np]; const rem = if(l - n < navl) l - n else navl; out[n..n + rem] = obuf[..rem]; s.avail = obuf[rem..navl]; return n + rem; }; // Decodes a byte slice of ASCII-encoded base-32 data, using the given encoding, // returning a slice of decoded bytes. The caller must free the return value. export fn decodeslice( enc: *encoding, in: []u8, ) ([]u8 | errors::invalid) = { let in = memio::fixed(in); let decoder = newdecoder(enc, &in); let out = memio::dynamic(); match (io::copy(&out, &decoder)) { case io::error => io::close(&out)!; return errors::invalid; case size => return memio::buffer(&out); }; }; // Decodes a string of ASCII-encoded base-32 data, using the given encoding, // returning a slice of decoded bytes. The caller must free the return value. export fn decodestr(enc: *encoding, in: str) ([]u8 | errors::invalid) = { return decodeslice(enc, strings::toutf8(in)); }; @test fn decode() void = { const cases: [_](str, str, *encoding) = [ ("", "", &std_encoding), ("MY======", "f", &std_encoding), ("MZXQ====", "fo", &std_encoding), ("MZXW6===", "foo", &std_encoding), ("MZXW6YQ=", "foob", &std_encoding), ("MZXW6YTB", "fooba", &std_encoding), ("MZXW6YTBOI======", "foobar", &std_encoding), ("", "", &hex_encoding), ("CO======", "f", &hex_encoding), ("CPNG====", "fo", &hex_encoding), ("CPNMU===", "foo", &hex_encoding), ("CPNMUOG=", "foob", &hex_encoding), ("CPNMUOJ1", "fooba", &hex_encoding), ("CPNMUOJ1E8======", "foobar", &hex_encoding), ]; for (let i = 0z; i < len(cases); i += 1) { let in = memio::fixed(strings::toutf8(cases[i].0)); let dec = newdecoder(cases[i].2, &in); let out: []u8 = io::drain(&dec)!; defer free(out); assert(bytes::equal(out, strings::toutf8(cases[i].1))); // Testing decodestr should cover decodeslice too let decb = decodestr(cases[i].2, cases[i].0) as []u8; defer free(decb); assert(bytes::equal(decb, strings::toutf8(cases[i].1))); }; // Repeat of the above, but with a larger buffer for (let i = 0z; i < len(cases); i += 1) { let in = memio::fixed(strings::toutf8(cases[i].0)); let dec = newdecoder(cases[i].2, &in); let out: []u8 = io::drain(&dec)!; defer free(out); assert(bytes::equal(out, strings::toutf8(cases[i].1))); }; const invalid: [_](str, *encoding) = [ // invalid padding ("=", &std_encoding), ("==", &std_encoding), ("===", &std_encoding), ("=====", &std_encoding), ("======", &std_encoding), ("=======", &std_encoding), ("========", &std_encoding), ("=========", &std_encoding), // invalid characters ("1ZXW6YQ=", &std_encoding), ("êZXW6YQ=", &std_encoding), ("MZXW1YQ=", &std_encoding), // data after padding is encountered ("CO======CO======", &std_encoding), ("CPNG====CPNG====", &std_encoding), ]; for (let i = 0z; i < len(invalid); i += 1) { let in = memio::fixed(strings::toutf8(invalid[i].0)); let dec = newdecoder(invalid[i].1, &in); let buf: [1]u8 = [0...]; let valid = false; for (true) match(io::read(&dec, buf)) { case errors::invalid => break; case size => valid = true; case io::EOF => break; }; assert(valid == false, "valid is not false"); // Testing decodestr should cover decodeslice too assert(decodestr(invalid[i].1, invalid[i].0) is errors::invalid); }; }; hare-0.24.2/encoding/base64/000077500000000000000000000000001464473310100153735ustar00rootroot00000000000000hare-0.24.2/encoding/base64/README000066400000000000000000000017131464473310100162550ustar00rootroot00000000000000Implementation of the base64 encoding scheme as defined by RFC 4648. A stream-based encoding and decoding interface is available via [[newencoder]] and [[newdecoder]], which transparently encode or decode bytes to or from base64 when writing to or reading from an underlying I/O handle. Convenience functions for encoding to or decoding from a byte slice or a string are also available; see [[encodeslice]], [[decodeslice]], [[encodestr]], and [[decodestr]]. These functions dynamically allocate their return values; use the stream interface if you require static allocation. Each function accepts the desired base64 encoding alphabet as its first argument. [[std_encoding]] and [[url_encoding]], as defined by the RFC, are provided for your convenience, but you may create your own encoding using [[encoding_init]]. Due to security concerns described by the RFC, this implementation rejects invalid padding. https://datatracker.ietf.org/doc/html/rfc4648#section-12 hare-0.24.2/encoding/base64/base64.ha000066400000000000000000000313131464473310100167720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bytes; use errors; use io; use memio; use os; use strings; def PADDING: u8 = '='; export type encoding = struct { encmap: [64]u8, decmap: [128]u8, }; // Represents the standard base-64 encoding alphabet as defined in RFC 4648. export const std_encoding: encoding = encoding { ... }; // Represents the "base64url" alphabet as defined in RFC 4648, suitable for use // in URLs and file paths. export const url_encoding: encoding = encoding { ... }; // Initializes a new encoding based on the passed alphabet, which must be a // 64-byte ASCII string. export fn encoding_init(enc: *encoding, alphabet: str) void = { const alphabet = strings::toutf8(alphabet); enc.decmap[..] = [-1...]; assert(len(alphabet) == 64); for (let i: u8 = 0; i < 64; i += 1) { const ch = alphabet[i]; assert(ascii::valid(ch: rune) && enc.decmap[ch] == -1); enc.encmap[i] = ch; enc.decmap[ch] = i; }; }; @init fn init() void = { const std_alpha: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const url_alpha: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; encoding_init(&std_encoding, std_alpha); encoding_init(&url_encoding, url_alpha); }; export type encoder = struct { stream: io::stream, out: io::handle, enc: *encoding, ibuf: [3]u8, obuf: [4]u8, iavail: u8, oavail: u8, }; const encoder_vtable: io::vtable = io::vtable { writer = &encode_writer, closer = &encode_closer, ... }; // Creates a stream that encodes writes as base64 before writing them to a // secondary stream. Afterwards [[io::close]] must be called to write any // unwritten bytes, in case of padding. Closing this stream will not close the // underlying stream. After a write returns an error, the stream must not be // written to again or closed. export fn newencoder( enc: *encoding, out: io::handle, ) encoder = { return encoder { stream = &encoder_vtable, out = out, enc = enc, ... }; }; fn encode_writer( s: *io::stream, in: const []u8 ) (size | io::error) = { let s = s: *encoder; let i = 0z; for (i < len(in)) { let b = s.ibuf[..]; // fill ibuf for (let j = s.iavail; j < 3 && i < len(in); j += 1) { b[j] = in[i]; i += 1; s.iavail += 1; }; if (s.iavail != 3) { return i; }; fillobuf(s); match (writeavail(s)) { case let e: io::error => if (i == 0) { return e; }; return i; case void => void; }; }; return i; }; fn fillobuf(s: *encoder) void = { assert(s.iavail == 3); let b = s.ibuf[..]; s.obuf[..] = [ s.enc.encmap[b[0] >> 2], s.enc.encmap[(b[0] & 0x3) << 4 | b[1] >> 4], s.enc.encmap[(b[1] & 0xf) << 2 | b[2] >> 6], s.enc.encmap[b[2] & 0x3f], ][..]; s.oavail = 4; }; fn writeavail(s: *encoder) (void | io::error) = { if (s.oavail == 0) { return; }; for (s.oavail > 0) { let n = io::write(s.out, s.obuf[len(s.obuf) - s.oavail..])?; s.oavail -= n: u8; }; if (s.oavail == 0) { s.iavail = 0; }; }; // Flushes pending writes to the underlying stream. fn encode_closer(s: *io::stream) (void | io::error) = { let s = s: *encoder; let finished = false; defer if (finished) clear(s); if (s.oavail > 0) { for (s.oavail > 0) { writeavail(s)?; }; finished = true; return; }; if (s.iavail == 0) { finished = true; return; }; // prepare padding as input length was not a multiple of 3 // 0 1 2 static const npa: []u8 = [0, 2, 1]; const np = npa[s.iavail]; for (let i = s.iavail; i < 3; i += 1) { s.ibuf[i] = 0; s.iavail += 1; }; fillobuf(s); for (let i = 0z; i < np; i += 1) { s.obuf[3 - i] = PADDING; }; for (s.oavail > 0) { writeavail(s)?; }; finished = true; }; fn clear(e: *encoder) void = { bytes::zero(e.ibuf); bytes::zero(e.obuf); }; @test fn partialwrite() void = { const raw: [_]u8 = [ 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, ]; const expected: str = `AAAAB3NzaC1yc2EA`; let buf = memio::dynamic(); let e = newencoder(&std_encoding, &buf); io::writeall(&e, raw[..4])!; io::writeall(&e, raw[4..11])!; io::writeall(&e, raw[11..])!; io::close(&e)!; assert(memio::string(&buf)! == expected); let encb = memio::buffer(&buf); free(encb); }; // Encodes a byte slice in base 64, using the given encoding, returning a slice // of ASCII bytes. The caller must free the return value. export fn encodeslice(enc: *encoding, in: []u8) []u8 = { let out = memio::dynamic(); let encoder = newencoder(enc, &out); io::writeall(&encoder, in)!; io::close(&encoder)!; return memio::buffer(&out); }; // Encodes base64 data using the given alphabet and writes it to a stream, // returning the number of bytes of data written (i.e. len(buf)). export fn encode( out: io::handle, enc: *encoding, buf: []u8, ) (size | io::error) = { const enc = newencoder(enc, out); match (io::writeall(&enc, buf)) { case let z: size => io::close(&enc)?; return z; case let err: io::error => clear(&enc); return err; }; }; // Encodes a byte slice in base 64, using the given encoding, returning a // string. The caller must free the return value. export fn encodestr(enc: *encoding, in: []u8) str = { return strings::fromutf8(encodeslice(enc, in))!; }; @test fn encode() void = { // RFC 4648 test vectors const in: [_]u8 = ['f', 'o', 'o', 'b', 'a', 'r']; const expect: [_]str = [ "", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy" ]; for (let i = 0z; i <= len(in); i += 1) { let out = memio::dynamic(); let encoder = newencoder(&std_encoding, &out); io::writeall(&encoder, in[..i])!; io::close(&encoder)!; let encb = memio::buffer(&out); defer free(encb); assert(bytes::equal(encb, strings::toutf8(expect[i]))); // Testing encodestr should cover encodeslice too let s = encodestr(&std_encoding, in[..i]); defer free(s); assert(s == expect[i]); }; }; export type decoder = struct { stream: io::stream, in: io::handle, enc: *encoding, obuf: [3]u8, // leftover decoded output ibuf: [4]u8, iavail: u8, oavail: u8, pad: bool, // if padding was seen in a previous read }; const decoder_vtable: io::vtable = io::vtable { reader = &decode_reader, ... }; // Creates a stream that reads and decodes base 64 data from a secondary stream. // This stream does not need to be closed, and closing it will not close the // underlying stream. If a read returns an error, the stream must not be read // from again. export fn newdecoder( enc: *encoding, in: io::handle, ) decoder = { return decoder { stream = &decoder_vtable, in = in, enc = enc, ... }; }; fn decode_reader( s: *io::stream, out: []u8 ) (size | io::EOF | io::error) = { let s = s: *decoder; if (len(out) == 0) { return 0z; }; let n = 0z; if (s.oavail != 0) { if (len(out) <= s.oavail) { out[..] = s.obuf[..len(out)]; s.obuf[..len(s.obuf) - len(out)] = s.obuf[len(out)..]; s.oavail = s.oavail - len(out): u8; return len(out); }; n = s.oavail; s.oavail = 0; out[..n] = s.obuf[..n]; out = out[n..]; }; let buf: [os::BUFSZ]u8 = [0...]; buf[..s.iavail] = s.ibuf[..s.iavail]; let want = encodedsize(len(out)); let nr = s.iavail: size; let lim = if (want > len(buf)) len(buf) else want; match (io::readall(s.in, buf[s.iavail..lim])) { case let n: size => nr += n; case io::EOF => return if (s.iavail != 0) errors::invalid else if (n != 0) n else io::EOF; case let err: io::error => if (!(err is io::underread)) { return err; }; nr += err: io::underread; }; if (s.pad) { return errors::invalid; }; s.iavail = nr: u8 % 4; s.ibuf[..s.iavail] = buf[nr - s.iavail..nr]; nr -= s.iavail; if (nr == 0) { return 0z; }; // Validating read buffer let np = 0z; // Number of padding chars. for (let i = 0z; i < nr; i += 1) { if (buf[i] == PADDING) { for (i + np < nr; np += 1) { if (np > 2 || buf[i + np] != PADDING) { return errors::invalid; }; }; s.pad = true; break; }; if (!ascii::valid(buf[i]: u32: rune) || s.enc.decmap[buf[i]] == -1) { return errors::invalid; }; buf[i] = s.enc.decmap[buf[i]]; }; if (nr / 4 * 3 - np < len(out)) { out = out[..nr / 4 * 3 - np]; }; let i = 0z, j = 0z; nr -= 4; for (i < nr) { out[j ] = buf[i ] << 2 | buf[i + 1] >> 4; out[j + 1] = buf[i + 1] << 4 | buf[i + 2] >> 2; out[j + 2] = buf[i + 2] << 6 | buf[i + 3]; i += 4; j += 3; }; s.obuf = [ buf[i ] << 2 | buf[i + 1] >> 4, buf[i + 1] << 4 | buf[i + 2] >> 2, buf[i + 2] << 6 | buf[i + 3], ]; out[j..] = s.obuf[..len(out) - j]; s.oavail = (len(s.obuf) - (len(out) - j)): u8; s.obuf[..s.oavail] = s.obuf[len(s.obuf) - s.oavail..]; s.oavail -= np: u8; return n + len(out); }; // Decodes a byte slice of ASCII-encoded base 64 data, using the given encoding, // returning a slice of decoded bytes. The caller must free the return value. export fn decodeslice( enc: *encoding, in: []u8, ) ([]u8 | errors::invalid) = { if (len(in) == 0) { return []; }; if (len(in) % 4 != 0) { return errors::invalid; }; let ins = memio::fixed(in); let decoder = newdecoder(enc, &ins); let out = alloc([0u8...], decodedsize(len(in))); let outs = memio::fixed(out); match (io::copy(&outs, &decoder)) { case io::error => free(out); return errors::invalid; case let sz: size => return memio::buffer(&outs)[..sz]; }; }; // Decodes a string of ASCII-encoded base 64 data, using the given encoding, // returning a slice of decoded bytes. The caller must free the return value. export fn decodestr(enc: *encoding, in: str) ([]u8 | errors::invalid) = { return decodeslice(enc, strings::toutf8(in)); }; // Decodes base64 data from a stream using the given alphabet, returning the // number of bytes of bytes read (i.e. len(buf)). export fn decode( in: io::handle, enc: *encoding, buf: []u8, ) (size | io::EOF | io::error) = { const dec = newdecoder(enc, in); return io::readall(&dec, buf); }; @test fn decode() void = { // RFC 4648 test vectors const cases: [_](str, str, *encoding) = [ ("", "", &std_encoding), ("Zg==", "f", &std_encoding), ("Zm8=", "fo", &std_encoding), ("Zm9v", "foo", &std_encoding), ("Zm9vYg==", "foob", &std_encoding), ("Zm9vYmE=", "fooba", &std_encoding), ("Zm9vYmFy", "foobar", &std_encoding), ]; const invalid: [_](str, *encoding) = [ // invalid padding ("=", &std_encoding), ("==", &std_encoding), ("===", &std_encoding), ("=====", &std_encoding), ("======", &std_encoding), // invalid characters ("@Zg=", &std_encoding), ("ê==", &std_encoding), ("êg==", &std_encoding), ("$3d==", &std_encoding), ("%3d==", &std_encoding), ("[==", &std_encoding), ("!", &std_encoding), // data after padding is encountered ("Zg===", &std_encoding), ("Zg====", &std_encoding), ("Zg==Zg==", &std_encoding), ("Zm8=Zm8=", &std_encoding), ]; let buf: [12]u8 = [0...]; for (let bufsz = 1z; bufsz <= 12; bufsz += 1) { for (let (input, expected, encoding) .. cases) { let in = memio::fixed(strings::toutf8(input)); let decoder = newdecoder(encoding, &in); let buf = buf[..bufsz]; let decb: []u8 = []; defer free(decb); for (true) match (io::read(&decoder, buf)!) { case let z: size => if (z > 0) { append(decb, buf[..z]...); }; case io::EOF => break; }; assert(bytes::equal(decb, strings::toutf8(expected))); // Testing decodestr should cover decodeslice too let decb = decodestr(encoding, input) as []u8; defer free(decb); assert(bytes::equal(decb, strings::toutf8(expected))); }; for (let (input, encoding) .. invalid) { let in = memio::fixed(strings::toutf8(input)); let decoder = newdecoder(encoding, &in); let buf = buf[..bufsz]; let valid = false; for (true) match(io::read(&decoder, buf)) { case errors::invalid => break; case size => void; case io::EOF => abort(); }; // Testing decodestr should cover decodeslice too assert(decodestr(encoding, input) is errors::invalid); }; }; }; // Given the length of the message, returns the size of its base64 encoding export fn encodedsize(sz: size) size = if (sz == 0) 0 else ((sz - 1)/ 3 + 1) * 4; // Given the size of base64 encoded data, returns maximal length of decoded message. // The message may be at most 2 bytes shorter than the returned value. Input // size must be a multiple of 4. export fn decodedsize(sz: size) size = { assert(sz % 4 == 0); return sz / 4 * 3; }; @test fn sizecalc() void = { let enc: [_](size, size) = [(1, 4), (2, 4), (3, 4), (4, 8), (10, 16), (119, 160), (120, 160), (121, 164), (122, 164), (123, 164) ]; assert(encodedsize(0) == 0 && decodedsize(0) == 0); for (let i = 0z; i < len(enc); i += 1) { let (decoded, encoded) = enc[i]; assert(encodedsize(decoded) == encoded); assert(decodedsize(encoded) == ((decoded - 1) / 3 + 1) * 3); }; }; hare-0.24.2/encoding/hex/000077500000000000000000000000001464473310100150735ustar00rootroot00000000000000hare-0.24.2/encoding/hex/README000066400000000000000000000013661464473310100157610ustar00rootroot00000000000000This module implements hexadecimal encoding and decoding. A stream-based encoding and decoding interface is available via [[newencoder]] and [[newdecoder]], which transparently encode or decode bytes to or from hexadecimal representation when writing to or reading from an underlying I/O handle. Convenience functions for encoding a byte slice into a hexadecimal string or decoding from a string into a byte slice are also available; see [[encodestr]] and [[decodestr]]. These functions dynamically allocate their return values; use the stream interface if you require static allocation. Note that writes are always encoded as lowercase hexidecimal characters, but the functions in this module can decode both upper- and lower-case hexidecimal characters.hare-0.24.2/encoding/hex/hex.ha000066400000000000000000000135161464473310100161770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bytes; use errors; use fmt; use io; use memio; use os; use strconv; use strings; export type encoder = struct { stream: io::stream, out: io::handle, err: (void | io::error), }; const encoder_vtable: io::vtable = io::vtable { writer = &encode_writer, ... }; // Creates a stream that encodes writes as lowercase hexadecimal before writing // them to a secondary stream. Closing this stream will not close the underlying // stream. export fn newencoder(out: io::handle) encoder = { return encoder { stream = &encoder_vtable, out = out, err = void, }; }; fn encode_writer(s: *io::stream, in: const []u8) (size | io::error) = { const s = s: *encoder; match(s.err) { case let err: io::error => return err; case void => void; }; let z = 0z; for (let i = 0z; i < len(in); i += 1) { const r = strconv::u8tos(in[i], strconv::base::HEX_LOWER); if (len(r) == 1) { match(fmt::fprint(s.out, "0")) { case let b: size => z += b; case let err: io::error => s.err = err; return err; }; }; match(fmt::fprint(s.out, r)) { case let b: size => z += b; case let err: io::error => s.err = err; return err; }; }; return z; }; // Encodes a byte slice as a hexadecimal string and returns it. The caller must // free the return value. export fn encodestr(in: []u8) str = { const out = memio::dynamic(); const enc = newencoder(&out); io::writeall(&enc, in)!; return memio::string(&out)!; }; @test fn encodestr() void = { let in: [_]u8 = [0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D]; let s = encodestr(in); defer free(s); assert(s == "cafebabedeadf00d"); }; // Encodes a byte slice as a hexadecimal string and writes it to an // [[io::handle]]. export fn encode(out: io::handle, in: []u8) (size | io::error) = { const enc = newencoder(out); return io::writeall(&enc, in); }; @test fn encode() void = { const in: [_]u8 = [0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D]; let out = memio::dynamic(); defer io::close(&out)!; encode(&out, in)!; assert(memio::string(&out)! == "cafebabedeadf00d"); }; export type decoder = struct { stream: io::stream, in: io::handle, state: (void | io::EOF | io::error), }; const decoder_vtable: io::vtable = io::vtable { reader = &decode_reader, ... }; // Creates a stream that reads and decodes hexadecimal data from a secondary // stream. This stream does not need to be closed, and closing it will not // close the underlying stream. export fn newdecoder(in: io::handle) decoder = { return decoder { stream = &decoder_vtable, in = in, state = void, ... }; }; fn decode_reader(s: *io::stream, out: []u8) (size | io::EOF | io::error) = { const s = s: *decoder; match(s.state) { case let err: (io::EOF | io::error) => return err; case void => void; }; static let buf: [os::BUFSZ]u8 = [0...]; let n = len(out) * 2; if (n > os::BUFSZ) { n = os::BUFSZ; }; let nr = 0z; for (nr < n) { match(io::read(s.in, buf[nr..n])) { case let n: size => nr += n; case io::EOF => s.state = io::EOF; break; case let err: io::error => s.state = err; return err; }; }; if (nr % 2 != 0) { s.state = errors::invalid; return errors::invalid; }; const l = nr / 2; for (let i = 0z; i < l; i += 1) { const oct = strings::fromutf8_unsafe(buf[i * 2..i * 2 + 2]); const u = match (strconv::stou8(oct, 16)) { case (strconv::invalid | strconv::overflow) => s.state = errors::invalid; return errors::invalid; case let u: u8 => yield u; }; out[i] = u; }; return l; }; // Decodes a string of hexadecimal bytes into a byte slice. The caller must free // the return value. export fn decodestr(s: str) ([]u8 | io::error) = { let s = strings::toutf8(s); const in = memio::fixed(s); const decoder = newdecoder(&in); const out = memio::dynamic(); match(io::copy(&out, &decoder)) { case size => return memio::buffer(&out); case let err: io::error => return err; }; }; @test fn decode() void = { let s = decodestr("cafebabedeadf00d") as []u8; defer free(s); assert(bytes::equal(s, [0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D])); decodestr("this is not hex") as io::error as errors::invalid: void; }; // Outputs a dump of hex data alongside the offset and an ASCII representation // (if applicable). // // Example output: // // 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| // 00000010 03 00 3e 00 01 00 00 00 80 70 01 00 00 00 00 00 |..>......p......| // // If the addr parameter is provided, the address column will start from this // address (but the data slice will still be printed from index 0). export fn dump(out: io::handle, data: []u8, addr: u64 = 0) (void | io::error) = { let datalen = len(data): u64; for (let off = 0u64; off < datalen; off += 16) { fmt::fprintf(out, "{:.8x} ", addr + off)?; let toff = 0z; for (let i = 0u64; i < 16 && off + i < datalen; i += 1) { let val = data[off + i]; toff += fmt::fprintf(out, "{}{:.2x} ", if (i == 8) " " else "", val)?; }; // Align ASCII representation, max width of hex part (48) + // spacing around it for (toff < 50; toff += 1) { fmt::fprint(out, " ")?; }; fmt::fprint(out, "|")?; for (let i = 0u64; i < 16 && off + i < datalen; i += 1) { let r = data[off + i]: rune; fmt::fprint(out, if (ascii::isprint(r)) r else '.')?; }; fmt::fprint(out, "|\n")?; }; }; @test fn dump() void = { let in: [_]u8 = [ 0x7F, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0xCA, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D, 0xCE, 0xFE, 0xBA, 0xBE, 0xDE, 0xAD, 0xF0, 0x0D ]; let sink = memio::dynamic(); defer io::close(&sink)!; dump(&sink, in) as void; let s = memio::string(&sink)!; assert(s == "00000000 7f 45 4c 46 02 01 01 00 ca fe ba be de ad f0 0d |.ELF............|\n" "00000010 ce fe ba be de ad f0 0d |........|\n"); }; hare-0.24.2/encoding/pem/000077500000000000000000000000001464473310100150705ustar00rootroot00000000000000hare-0.24.2/encoding/pem/+test.ha000066400000000000000000000177621464473310100164510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use fmt; use io; use memio; use strings; @test fn read() void = { const testcert_str = fmt::asprintf( "garbage\ngarbage\ngarbage\n{}garbage\n", cert_str); defer free(testcert_str); const in = memio::fixed(strings::toutf8(testcert_str)); const dec = newdecoder(&in); defer finish(&dec); const stream = next(&dec)! as (str, pemdecoder); assert(stream.0 == "CERTIFICATE"); static let buf: [1024]u8 = [0...]; assert(len(buf) >= len(testcert_bin)); const data = io::drain(&stream.1)!; defer free(data); assert(bytes::equal(data, testcert_bin)); assert(next(&dec) is io::EOF); }; @test fn read_many() void = { const testmany = fmt::asprintf("{}{}", cert_str, privkey_str); defer free(testmany); const in = memio::fixed(strings::toutf8(testmany)); const dec = newdecoder(&in); defer finish(&dec); static let buf: [1024]u8 = [0...]; const stream = next(&dec)! as (str, pemdecoder); assert(stream.0 == "CERTIFICATE"); const data = io::drain(&stream.1)!; defer free(data); assert(bytes::equal(data, testcert_bin)); const stream = next(&dec)! as (str, pemdecoder); assert(stream.0 == "PRIVATE KEY"); const data = io::drain(&stream.1)!; defer free(data); assert(bytes::equal(data, testprivkey_bin)); assert(next(&dec) is io::EOF); }; @test fn write() void = { let out = memio::dynamic(); const stream = newencoder("CERTIFICATE", &out)!; io::writeall(&stream, testcert_bin)!; io::close(&stream)!; assert(memio::string(&out)! == cert_str); io::close(&out)!; let out = memio::dynamic(); const stream = newencoder("PRIVATE KEY", &out)!; io::writeall(&stream, testprivkey_bin)!; io::close(&stream)!; assert(memio::string(&out)! == privkey_str); io::close(&out)!; // test short writes let out = memio::dynamic(); const stream = newencoder("CERTIFICATE", &out)!; for (let i = 0z; i < len(testcert_bin); i += 1) { io::write(&stream, [testcert_bin[i]])!; }; io::close(&stream)!; assert(memio::string(&out)! == cert_str); io::close(&out)!; }; const cert_str: str = `-----BEGIN CERTIFICATE----- MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0 ZSBhdXRob3JpdHkwHhcNMTEwNTIzMjAzODIxWhcNMTIxMjIyMDc0MTUxWjB9MQsw CQYDVQQGEwJCRTEPMA0GA1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2Vy dGlmaWNhdGUgYXV0aG9yaXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdu dVRMUyBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMB BwNCAARS2I0jiuNn14Y2sSALCX3IybqiIJUvxUpj+oNfzngvj/Niyv2394BWnW4X uQ4RTEiywK87WRcWMGgJB5kX/t2no0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo= -----END CERTIFICATE----- `; const testcert_bin: [_]u8 = [ 0x30, 0x82, 0x02, 0x2c, 0x30, 0x82, 0x01, 0xd2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x06, 0x4c, 0x65, 0x75, 0x76, 0x65, 0x6e, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x35, 0x32, 0x33, 0x32, 0x30, 0x33, 0x38, 0x32, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x32, 0x31, 0x32, 0x32, 0x32, 0x30, 0x37, 0x34, 0x31, 0x35, 0x31, 0x5a, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x06, 0x4c, 0x65, 0x75, 0x76, 0x65, 0x6e, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6e, 0x75, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x52, 0xd8, 0x8d, 0x23, 0x8a, 0xe3, 0x67, 0xd7, 0x86, 0x36, 0xb1, 0x20, 0x0b, 0x09, 0x7d, 0xc8, 0xc9, 0xba, 0xa2, 0x20, 0x95, 0x2f, 0xc5, 0x4a, 0x63, 0xfa, 0x83, 0x5f, 0xce, 0x78, 0x2f, 0x8f, 0xf3, 0x62, 0xca, 0xfd, 0xb7, 0xf7, 0x80, 0x56, 0x9d, 0x6e, 0x17, 0xb9, 0x0e, 0x11, 0x4c, 0x48, 0xb2, 0xc0, 0xaf, 0x3b, 0x59, 0x17, 0x16, 0x30, 0x68, 0x09, 0x07, 0x99, 0x17, 0xfe, 0xdd, 0xa7, 0xa3, 0x43, 0x30, 0x41, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x05, 0x03, 0x03, 0x07, 0x06, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf0, 0xb4, 0x81, 0xfe, 0x98, 0x12, 0xbf, 0xb5, 0x28, 0xb9, 0x64, 0x40, 0x03, 0xcb, 0xcc, 0x1f, 0x66, 0x4e, 0x28, 0x03, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x31, 0xae, 0xc0, 0x3d, 0x4a, 0x3f, 0x21, 0xbe, 0x85, 0x17, 0xfc, 0xf0, 0xc7, 0xb2, 0x31, 0x07, 0x2a, 0x38, 0x56, 0x43, 0xd1, 0x36, 0xd5, 0x95, 0xe1, 0x7e, 0x52, 0xc0, 0x06, 0x43, 0x87, 0xa7, 0x02, 0x21, 0x00, 0x97, 0x8c, 0x0e, 0xb8, 0x3c, 0x0a, 0x41, 0xaf, 0xae, 0xa5, 0xcf, 0x06, 0x7e, 0xd5, 0xc4, 0xd8, 0x2f, 0xff, 0xe2, 0x62, 0x80, 0x34, 0x10, 0xba, 0x22, 0xdd, 0x35, 0x81, 0x46, 0x93, 0x22, 0x9a, ]; const privkey_str: str = `-----BEGIN PRIVATE KEY----- MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgVcB/UNPxalR9zDYAjQIf jojUDiQuGnSJrFEEzZPT/92hRANCAASc7UJtgnF/abqWM60T3XNJEzBv5ez9TdwK H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ -----END PRIVATE KEY----- `; const testprivkey_bin: [_]u8 = [ 0x30, 0x81, 0x84, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x55, 0xc0, 0x7f, 0x50, 0xd3, 0xf1, 0x6a, 0x54, 0x7d, 0xcc, 0x36, 0x00, 0x8d, 0x02, 0x1f, 0x8e, 0x88, 0xd4, 0x0e, 0x24, 0x2e, 0x1a, 0x74, 0x89, 0xac, 0x51, 0x04, 0xcd, 0x93, 0xd3, 0xff, 0xdd, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x9c, 0xed, 0x42, 0x6d, 0x82, 0x71, 0x7f, 0x69, 0xba, 0x96, 0x33, 0xad, 0x13, 0xdd, 0x73, 0x49, 0x13, 0x30, 0x6f, 0xe5, 0xec, 0xfd, 0x4d, 0xdc, 0x0a, 0x1f, 0x43, 0x3a, 0xc6, 0x93, 0x36, 0xab, 0xee, 0x77, 0xc2, 0x6b, 0x0d, 0xfd, 0xe6, 0x0b, 0x76, 0x0b, 0x63, 0x80, 0x17, 0x77, 0x0c, 0x19, 0x87, 0xb4, 0xf8, 0xa5, 0x0a, 0x48, 0x85, 0x20, 0x25, 0xf2, 0x68, 0x0f, 0x33, 0xf4, 0xb9, 0x09, ]; @test fn readcrlf() void = { const test_str = fmt::asprintf( "garbage\r\ngarbage\r\ngarbage\r\n{}garbage\r\n", testcrlf_str); defer free(test_str); const in = memio::fixed(strings::toutf8(test_str)); const dec = newdecoder(&in); defer finish(&dec); const stream = next(&dec)! as (str, pemdecoder); assert(stream.0 == "TEST"); static let buf: [1024]u8 = [0...]; assert(len(buf) >= len(testcert_bin)); const data = io::drain(&stream.1)!; defer free(data); assert(bytes::equal(data, testcrlf_bin)); assert(next(&dec) is io::EOF); }; const testcrlf_str: str = "-----BEGIN TEST-----\r\ndGVzdA==\r\n-----END TEST-----\r\n"; const testcrlf_bin: [_]u8 = [0x74, 0x65, 0x73, 0x74]; hare-0.24.2/encoding/pem/README000066400000000000000000000001731464473310100157510ustar00rootroot00000000000000The PEM module implements RFC 7468, commonly known as the PEM format, which is widely used for cryptographic data formats. hare-0.24.2/encoding/pem/pem.ha000066400000000000000000000132661464473310100161730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bufio; use encoding::base64; use errors; use fmt; use io; use memio; use os; use strings; const begin: str = "-----BEGIN "; const end: str = "-----END "; const suffix: str = "-----"; export type decoder = struct { in: b64stream, label: memio::stream, buf: []u8, }; export type b64stream = struct { stream: io::stream, in: bufio::stream, }; export type pemdecoder = struct { stream: io::stream, b64: base64::decoder, }; const pemdecoder_vt: io::vtable = io::vtable { reader = &pem_read, ... }; const b64stream_r_vt: io::vtable = io::vtable { reader = &b64_read, ... }; // Creates a new PEM decoder. The caller must either read it until it returns // [[io::EOF]], or call [[finish]] to free state associated with the parser. export fn newdecoder(in: io::handle) decoder = { let buf: []u8 = alloc([0...], os::BUFSZ); return decoder { in = b64stream { stream = &b64stream_r_vt, in = bufio::init(in, buf, []), }, buf = buf, label = memio::dynamic(), }; }; // Frees state associated with this [[decoder]]. export fn finish(dec: *decoder) void = { io::close(&dec.label)!; free(dec.buf); }; // Converts an I/O error returned from a PEM decoder into a human-friendly // string. export fn strerror(err: io::error) const str = { match (err) { case errors::invalid => return "Invalid PEM data"; case => return io::strerror(err); }; }; // Finds the next PEM boundary in the stream, ignoring any non-PEM data, and // returns the label and a [[pemdecoder]] from which the encoded data may be // read, or [[io::EOF]] if no further PEM boundaries are found. The user must // completely read the pemdecoder until it returns [[io::EOF]] before calling // [[next]] again. // // The label returned by this function is borrowed from the decoder state and // does not contain "-----BEGIN " or "-----". export fn next(dec: *decoder) ((str, pemdecoder) | io::EOF | io::error) = { for (true) { // XXX: This can be improved following // https://todo.sr.ht/~sircmpwn/hare/562 const line = match (bufio::read_line(&dec.in.in)?) { case io::EOF => return io::EOF; case let line: []u8 => yield match (strings::fromutf8(line)) { case let s: str => yield s; case => return errors::invalid; }; }; defer free(line); const line = strings::rtrim(line, '\r'); if (!strings::hasprefix(line, begin) || !strings::hassuffix(line, suffix)) { continue; }; memio::reset(&dec.label); const label = strings::sub(line, len(begin), len(line) - len(suffix)); memio::concat(&dec.label, label)!; return (memio::string(&dec.label)!, pemdecoder { stream = &pemdecoder_vt, b64 = base64::newdecoder(&base64::std_encoding, &dec.in), }); }; }; fn pem_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = { // We need to set up two streams. This is the stream which is actually // returned to the caller, which calls the base64 decoder against a // special stream (b64stream) which trims out whitespace and EOF's on // -----END. const st = st: *pemdecoder; assert(st.stream.reader == &pem_read); match (io::read(&st.b64, buf)?) { case let z: size => return z; case io::EOF => void; }; const line = match (bufio::read_line(st.b64.in)?) { case io::EOF => return io::EOF; case let line: []u8 => yield match (strings::fromutf8(line)) { case let s: str => yield s; case => return errors::invalid; }; }; defer free(line); const line = strings::rtrim(line, '\r'); if (!strings::hasprefix(line, end) || !strings::hassuffix(line, suffix)) { return errors::invalid; }; // XXX: We could verify the trailer matches but the RFC says it's // optional. return io::EOF; }; fn b64_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = { const st = st: *b64stream; assert(st.stream.reader == &b64_read); const z = match (io::read(&st.in, buf)?) { case let z: size => yield z; case io::EOF => return errors::invalid; // Missing -----END }; // Trim off whitespace and look for -----END let sub = buf[..z]; for (let i = 0z; i < len(sub); i += 1) { if (sub[i] == '-') { bufio::unread(&st.in, sub[i..]); sub = sub[..i]; break; }; if (ascii::isspace(sub[i]: rune)) { static delete(sub[i]); i -= 1; continue; }; }; if (len(sub) == 0) { return io::EOF; }; return len(sub); }; export type pemencoder = struct { stream: io::stream, out: io::handle, b64: base64::encoder, label: str, buf: [48]u8, ln: u8, }; const pemencoder_vt: io::vtable = io::vtable { writer = &pem_write, closer = &pem_wclose, ... }; // Creates a new PEM encoder stream. The stream has to be closed to write the // trailer. export fn newencoder(label: str, s: io::handle) (pemencoder | io::error) = { fmt::fprintf(s, "{}{}{}\n", begin, label, suffix)?; return pemencoder { stream = &pemencoder_vt, out = s, b64 = base64::newencoder(&base64::std_encoding, s), label = label, ... }; }; fn pem_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *pemencoder; let buf = buf: []u8; if (len(buf) < len(s.buf) - s.ln) { s.buf[s.ln..s.ln+len(buf)] = buf[..]; s.ln += len(buf): u8; return len(buf); }; let z = 0z; s.buf[s.ln..] = buf[..len(s.buf) - s.ln]; z += io::writeall(&s.b64, s.buf)?; z += io::write(s.out, ['\n'])?; buf = buf[len(s.buf) - s.ln..]; for (len(buf) >= 48; buf = buf[48..]) { z += io::writeall(&s.b64, buf[..48])?; z += io::write(s.out, ['\n'])?; }; s.ln = len(buf): u8; s.buf[..s.ln] = buf; return z + s.ln; }; fn pem_wclose(s: *io::stream) (void | io::error) = { let s = s: *pemencoder; io::writeall(&s.b64, s.buf[..s.ln])?; io::close(&s.b64)?; fmt::fprintf(s.out, "\n{}{}{}\n", end, s.label, suffix)?; }; hare-0.24.2/encoding/utf8/000077500000000000000000000000001464473310100151755ustar00rootroot00000000000000hare-0.24.2/encoding/utf8/README000066400000000000000000000001441464473310100160540ustar00rootroot00000000000000encoding::utf8 provides helper functions for working with runes, strings, and UTF-8-encoded slices. hare-0.24.2/encoding/utf8/decode.ha000066400000000000000000000104411464473310100167320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type decoder = struct { offs: size, src: []u8, }; // Initializes a new UTF-8 decoder. export fn decode(src: []u8) decoder = decoder { src = src, offs = 0, }; const masks: [2][8]u8 = [ [0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f], [0x7f, 0x1f, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07], ]; // Returns the next rune from a decoder. done is returned when there are no // remaining codepoints. export fn next(d: *decoder) (rune | done | more | invalid) = { if (d.offs == len(d.src)) { return done; }; // from https://github.com/skeeto/scratch/blob/master/parsers/utf8_decode.c // See https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // and https://nullprogram.com/blog/2020/12/31/ for an explanation of // the algorithm. let next = 0, state = 0; let r = 0u32; for (d.offs < len(d.src); d.offs += 1) { next = table[state][d.src[d.offs]]; r = r << 6 | d.src[d.offs] & masks[(state - 1): uint >> 31][next & 7]; if (next <= 0) { d.offs += 1; return if (next == 0) r: rune else invalid; }; state = next; }; return more; }; // Returns the previous rune from a decoder. done is returned when there are no // previous codepoints. export fn prev(d: *decoder) (rune | done | more | invalid) = { if (d.offs == 0) { return done; }; let n = d.offs; d.offs -= 1; for (d.offs < len(d.src); d.offs -= 1) { if (table[0][d.src[d.offs]] != -1) { let t = d.offs; defer d.offs = t; let r = next(d); return if (n != d.offs || r is more) invalid else r; }; if (n - d.offs == 4) { // Too many continuation bytes in a row return invalid; }; }; return more; }; @test fn decode() void = { const input: [_]u8 = [ 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xA1, 0xE3, 0x81, 0xAF, 0x00, ]; assert(validate(input) is void); const expected = ['こ', 'ん', 'に', 'ち', 'は', '\0']; let decoder = decode(input); for (let i = 0z; i < len(expected); i += 1) { match (next(&decoder)) { case (invalid | more | done) => abort(); case let r: rune => assert(r == expected[i]); }; }; assert(next(&decoder) is done); assert(decoder.offs == len(decoder.src)); for (let i = 0z; i < len(expected); i += 1) { match (prev(&decoder)) { case (invalid | more | done) => abort(); case let r: rune => assert(r == expected[len(expected) - i - 1]); }; }; assert(prev(&decoder) is done); const inv: [_]u8 = [0xA0, 0xA1]; decoder = decode(inv); assert(next(&decoder) is invalid); decoder.offs = 2; assert(prev(&decoder) is more); assert(validate(inv) is invalid); const incomplete: [_]u8 = [0xE3, 0x81]; decoder = decode(incomplete); assert(next(&decoder) is more); decoder.offs = 2; assert(prev(&decoder) is invalid); assert(validate(incomplete) is invalid); const surrogate: [_]u8 = [0xED, 0xA0, 0x80]; decoder = decode(surrogate); assert(next(&decoder) is invalid); decoder.offs = 3; assert(prev(&decoder) is invalid); assert(validate(surrogate) is invalid); const overlong: [_]u8 = [0xF0, 0x82, 0x82, 0xAC]; decoder = decode(overlong); assert(next(&decoder) is invalid); decoder.offs = 4; assert(prev(&decoder) is invalid); assert(validate(overlong) is invalid); const badcont: [_]u8 = [0xC2, 0xFF]; decoder = decode(badcont); assert(next(&decoder) is invalid); assert(validate(badcont) is invalid); const extracont: [_]u8 = [0xC2, 0xA3, 0x95]; decoder = decode(extracont); decoder.offs = 3; assert(prev(&decoder) is invalid); assert(validate(extracont) is invalid); const maxinrange: [_]u8 = [0xF4, 0x8F, 0xBF, 0xBF]; decoder = decode(maxinrange); match (next(&decoder)) { case let r: rune => assert(r == 0x10FFFFu32: rune); case => abort(); }; decoder.offs = 4; match (prev(&decoder)) { case let r: rune => assert(r == 0x10FFFFu32: rune); case => abort(); }; const minoutofrange: [_]u8 = [0xF5, 0x94, 0x80, 0x80]; decoder = decode(minoutofrange); assert(next(&decoder) is invalid); decoder.offs = 4; assert(prev(&decoder) is invalid); }; // Returns void if a given byte slice contains only valid UTF-8 sequences, // otherwise returns invalid. export fn validate(src: []u8) (void | invalid) = { let state = 0; for (let i = 0z; i < len(src) && state >= 0; i += 1) { state = table[state][src[i]]; }; return if (state == 0) void else invalid; }; hare-0.24.2/encoding/utf8/decodetable.ha000066400000000000000000000205641464473310100177510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors let table: [8][256]i8 = [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 5, 6, 6, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] ]; hare-0.24.2/encoding/utf8/encode.ha000066400000000000000000000021231464473310100167420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Encodes a rune as UTF-8 and returns the result as a slice. The return value // is statically allocated, and will not be consistent after subsequent calls to // encoderune. export fn encoderune(r: rune) []u8 = { let ch = r: u32, n = 0z, first = 0u8; assert((ch < 0xD800 || ch > 0xDFFF) && ch <= 0x10FFFF, "the rune is not a valid Unicode codepoint"); if (ch < 0x80) { first = 0; n = 1; } else if (ch < 0x800) { first = 0xC0; n = 2; } else if (ch < 0x10000) { first = 0xE0; n = 3; } else { first = 0xF0; n = 4; }; static let buf: [4]u8 = [0...]; for (let i = n - 1; i > 0; i -= 1) { buf[i] = ch: u8 & 0x3F | 0x80; ch >>= 6; }; buf[0] = ch: u8 | first; return buf[..n]; }; @test fn encode() void = { const expected: [_][]u8 = [ [0], [0x25], [0xE3, 0x81, 0x93], ]; const inputs = ['\0', '%', 'こ']; for (let i = 0z; i < len(inputs); i += 1) { const out = encoderune(inputs[i]); for (let j = 0z; j < len(expected[i]); j += 1) { assert(out[j] == expected[i][j]); }; }; }; hare-0.24.2/encoding/utf8/rune.ha000066400000000000000000000016521464473310100164640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors type rsize = struct { mask: u8, result: u8, octets: size, }; const sizes: [_]rsize = [ rsize { mask = 0x80, result = 0x00, octets = 1 }, rsize { mask = 0xE0, result = 0xC0, octets = 2 }, rsize { mask = 0xF0, result = 0xE0, octets = 3 }, rsize { mask = 0xF8, result = 0xF0, octets = 4 }, ]; // Returns the size of a rune, in octets, when encoded as UTF-8. export fn runesz(r: rune) size = { const ch = r: u32; return if (ch < 0x80) 1 else if (ch < 0x800) 2 else if (ch < 0x10000) 3 else 4; }; // Returns the expected length of a UTF-8 codepoint in bytes given its first // byte, or [[invalid]] if the given byte doesn't begin a valid UTF-8 sequence. export fn utf8sz(c: u8) (size | invalid) = { for (let i = 0z; i < len(sizes); i += 1) { if (c & sizes[i].mask == sizes[i].result) { return sizes[i].octets; }; }; return invalid; }; hare-0.24.2/encoding/utf8/types.ha000066400000000000000000000006111464473310100166510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returned when more data is needed, i.e. when an incomplete UTF-8 sequence is // encountered. export type more = void; // Returned when an invalid UTF-8 sequence was found. export type invalid = !void; // Converts an error into a human-friendly string. export fn strerror(err: invalid) str = "Invalid UTF-8"; hare-0.24.2/endian/000077500000000000000000000000001464473310100137575ustar00rootroot00000000000000hare-0.24.2/endian/README000066400000000000000000000005421464473310100146400ustar00rootroot00000000000000The endian module provides support functions for converting the byte encoding ("endianness") of integers. The following abbreviations are used throughout the module: - be - big endian; most significant byte first - le - little endian; least significant byte first - h - the endianness of the host system - n - the endianness of the network (big endian) hare-0.24.2/endian/big.ha000066400000000000000000000035271464473310100150410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Reads a u16 from a buffer in big-endian order. export fn begetu16(buf: []u8) u16 = { return (buf[0] << 8u16) | (buf[1] << 0); }; // Writes a u16 into a buffer in big-endian order. export fn beputu16(buf: []u8, in: u16) void = { buf[1] = (in >> 0): u8; buf[0] = (in >> 8): u8; }; // Reads a u32 from a buffer in big-endian order. export fn begetu32(buf: []u8) u32 = { return (buf[0] << 24u32) | (buf[1] << 16u32) | (buf[2] << 8u32) | (buf[3] << 0); }; // Writes a u32 into a buffer in big-endian order. export fn beputu32(buf: []u8, in: u32) void = { buf[3] = (in >> 0): u8; buf[2] = (in >> 8): u8; buf[1] = (in >> 16): u8; buf[0] = (in >> 24): u8; }; // Reads a u64 from a buffer in big-endian order. export fn begetu64(buf: []u8) u64 = { return (buf[0] << 56u64) | (buf[1] << 48u64) | (buf[2] << 40u64) | (buf[3] << 32u64) | (buf[4] << 24u64) | (buf[5] << 16u64) | (buf[6] << 8u64) | (buf[7] << 0); }; // Writes a u64 into a buffer in big-endian order. export fn beputu64(buf: []u8, in: u64) void = { buf[7] = (in >> 0): u8; buf[6] = (in >> 8): u8; buf[5] = (in >> 16): u8; buf[4] = (in >> 24): u8; buf[3] = (in >> 32): u8; buf[2] = (in >> 40): u8; buf[1] = (in >> 48): u8; buf[0] = (in >> 56): u8; }; @test fn big() void = { let buf: [8]u8 = [0...]; beputu16(buf, 0x1234); assert(buf[0] == 0x12 && buf[1] == 0x34); assert(begetu16(buf) == 0x1234); beputu32(buf, 0x12345678); assert(buf[0] == 0x12 && buf[1] == 0x34 && buf[2] == 0x56 && buf[3] == 0x78); assert(begetu32(buf) == 0x12345678); beputu64(buf, 0x1234567887654321); assert(buf[0] == 0x12 && buf[1] == 0x34 && buf[2] == 0x56 && buf[3] == 0x78 && buf[4] == 0x87 && buf[5] == 0x65 && buf[6] == 0x43 && buf[7] == 0x21); assert(begetu64(buf) == 0x1234567887654321); }; hare-0.24.2/endian/endian.ha000066400000000000000000000013731464473310100155330ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The set of functions used for endian-aware encoding. export type endian = struct { getu16: *fn(buf: []u8) u16, putu16: *fn(buf: []u8, in: u16) void, getu32: *fn(buf: []u8) u32, putu32: *fn(buf: []u8, in: u32) void, getu64: *fn(buf: []u8) u64, putu64: *fn(buf: []u8, in: u64) void, }; // Big endian; MSB first. export const big: endian = endian { getu16 = &begetu16, putu16 = &beputu16, getu32 = &begetu32, putu32 = &beputu32, getu64 = &begetu64, putu64 = &beputu64, }; // Little endian; LSB first. export const little: endian = endian { getu16 = &legetu16, putu16 = &leputu16, getu32 = &legetu32, putu32 = &leputu32, getu64 = &legetu64, putu64 = &leputu64, }; hare-0.24.2/endian/host+aarch64.ha000066400000000000000000000002661464473310100164760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The [[endian]] functions which map to the host architecture. export const host: *endian = &little; hare-0.24.2/endian/host+riscv64.ha000066400000000000000000000002661464473310100165460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The [[endian]] functions which map to the host architecture. export const host: *endian = &little; hare-0.24.2/endian/host+x86_64.ha000066400000000000000000000002661464473310100162040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The [[endian]] functions which map to the host architecture. export const host: *endian = &little; hare-0.24.2/endian/little.ha000066400000000000000000000035471464473310100155770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Reads a u16 from a buffer in little-endian order. export fn legetu16(buf: []u8) u16 = { return (buf[1] << 8u16) | (buf[0] << 0); }; // Writes a u16 into a buffer in little-endian order. export fn leputu16(buf: []u8, in: u16) void = { buf[0] = (in >> 0): u8; buf[1] = (in >> 8): u8; }; // Reads a u32 from a buffer in little-endian order. export fn legetu32(buf: []u8) u32 = { return (buf[3] << 24u32) | (buf[2] << 16u32) | (buf[1] << 8u32) | (buf[0] << 0); }; // Writes a u32 into a buffer in little-endian order. export fn leputu32(buf: []u8, in: u32) void = { buf[0] = (in): u8; buf[1] = (in >> 8): u8; buf[2] = (in >> 16): u8; buf[3] = (in >> 24): u8; }; // Reads a u64 from a buffer in little-endian order. export fn legetu64(buf: []u8) u64 = { return (buf[7] << 56u64) | (buf[6] << 48u64) | (buf[5] << 40u64) | (buf[4] << 32u64) | (buf[3] << 24u64) | (buf[2] << 16u64) | (buf[1] << 8u64) | (buf[0] << 0); }; // Writes a u64 into a buffer in little-endian order. export fn leputu64(buf: []u8, in: u64) void = { buf[0] = (in >> 0): u8; buf[1] = (in >> 8): u8; buf[2] = (in >> 16): u8; buf[3] = (in >> 24): u8; buf[4] = (in >> 32): u8; buf[5] = (in >> 40): u8; buf[6] = (in >> 48): u8; buf[7] = (in >> 56): u8; }; @test fn little() void = { let buf: [8]u8 = [0...]; leputu16(buf, 0x1234); assert(buf[0] == 0x34 && buf[1] == 0x12); assert(legetu16(buf) == 0x1234); leputu32(buf, 0x12345678); assert(buf[0] == 0x78 && buf[1] == 0x56 && buf[2] == 0x34 && buf[3] == 0x12); assert(legetu32(buf) == 0x12345678); leputu64(buf, 0x1234567887654321); assert(buf[0] == 0x21 && buf[1] == 0x43 && buf[2] == 0x65 && buf[3] == 0x87 && buf[4] == 0x78 && buf[5] == 0x56 && buf[6] == 0x34 && buf[7] == 0x12); assert(legetu64(buf) == 0x1234567887654321); }; hare-0.24.2/endian/network.ha000066400000000000000000000024361464473310100157670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Converts a u16 from host order to network order. export fn htonu16(in: u16) u16 = { if (host == &big) return in; return in >> 8 | (in & 0xFF) << 8; }; // Converts a u32 from host order to network order. export fn htonu32(in: u32) u32 = { if (host == &big) return in; return in >> 24 | in >> 8 & 0xFF00 | in << 8 & 0xFF0000 | in << 24; }; // Converts a u64 from host order to network order. export fn htonu64(in: u64) u64 = { if (host == &big) return in; return (htonu32(in: u32): u64 << 32u64) | htonu32((in >> 32): u32): u64; }; @test fn hton() void = { if (host == &big) return; assert(htonu16(0xCAFE) == 0xFECA); assert(htonu32(0xDEADBEEF) == 0xEFBEADDE); assert(htonu64(0xCAFEBABEDEADBEEF) == 0xEFBEADDEBEBAFECA); }; // Converts a u16 from network order to host order. export fn ntohu16(in: u16) u16 = htonu16(in); // Converts a u32 from network order to host order. export fn ntohu32(in: u32) u32 = htonu32(in); // Converts a u64 from network order to host order. export fn ntohu64(in: u64) u64 = htonu64(in); @test fn ntoh() void = { if (host == &big) return; assert(htonu16(0xFECA) == 0xCAFE); assert(htonu32(0xEFBEADDE) == 0xDEADBEEF); assert(htonu64(0xEFBEADDEBEBAFECA) == 0xCAFEBABEDEADBEEF); }; hare-0.24.2/errors/000077500000000000000000000000001464473310100140355ustar00rootroot00000000000000hare-0.24.2/errors/README000066400000000000000000000006751464473310100147250ustar00rootroot00000000000000The errors module provides a number of error types which describe error conditions common to many types of code, as well as convenience functions for turning these errors into strings, and an error type which may be used to wrap some implementation-defined error data. If your program's error cases can be modelled by the errors offered in this module, you may use them to make your error types compatible with a wider range of support modules. hare-0.24.2/errors/common.ha000066400000000000000000000026271464473310100156460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The requested resource is not available. export type busy = !void; // An attempt was made to create a resource which already exists. export type exists = !void; // A function was called with an invalid combination of arguments. export type invalid = !void; // The user does not have permission to use this resource. export type noaccess = !void; // An entry was requested which does not exist. export type noentry = !void; // The requested operation caused a numeric overflow condition. export type overflow = !void; // The requested operation is not supported. export type unsupported = !void; // The requested operation timed out. export type timeout = !void; // The requested operation was cancelled. export type cancelled = !void; // A connection attempt was refused. export type refused = !void; // Unable to allocate sufficient memory for the requested operation. export type nomem = !void; // An operation was interrupted. export type interrupted = !void; // The user should attempt an operation again. export type again = !void; // Network unreachable export type netunreachable = !void; // A tagged union of all error types. export type error = !( busy | exists | invalid | noaccess | noentry | overflow | unsupported | timeout | cancelled | refused | nomem | interrupted | again | netunreachable | opaque_ ); hare-0.24.2/errors/opaque.ha000066400000000000000000000020671464473310100156460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An "opaque" error is used as a portable error type for an underlying error // which is implementation-specific. It provides a function which can be used to // produce a string describing the error, and a small storage area for arbitrary // implementation-specific storage. // // The following example shows the usage of this type for custom errors: // // fn wraperror(err: myerror) error::opaque_ = { // static assert(size(myerror) <= size(errors::opaque_data)); // let wrapped = errors::opaque_ { strerror = &opaque_strerror, ... }; // let myptr = &wrapped.data: *myerror; // *myptr = err; // return wrapped; // }; // // fn opaque_strerror(err: *errors::opaque_data) const str = { // let ptr = &err: *myerr; // return strerror(*ptr); // }; export type opaque_ = !struct { strerror: *fn(op: *opaque_data) const str, data: opaque_data, }; // Up to 24 bytes of arbitrary data that the opaque error type may use for // domain-specific storage. export type opaque_data = [24]u8; hare-0.24.2/errors/rt.ha000066400000000000000000000021341464473310100147740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Wraps an [[rt::errno]] to produce an [[error]], which may be [[opaque_]]. // This is a non-portable interface which is mainly provided to support internal // stdlib requirements. export fn errno(errno: rt::errno) error = { switch (errno) { case rt::ECONNREFUSED => return refused; case rt::ECANCELED => return cancelled; case rt::EOVERFLOW => return overflow; case rt::EACCES => return noaccess; case rt::EINVAL => return invalid; case rt::EEXIST => return exists; case rt::ENOENT => return noentry; case rt::ETIMEDOUT => return timeout; case rt::EBUSY => return busy; case rt::EINTR => return interrupted; case rt::EAGAIN => return again; case rt::ENETUNREACH => return netunreachable; case => void; }; static assert(size(rt::errno) <= size(opaque_data)); let err = opaque_ { strerror = &rt_strerror, ... }; let ptr = &err.data: *rt::errno; *ptr = errno; return err; }; fn rt_strerror(err: *opaque_data) const str = { let err = err: *rt::errno; return rt::strerror(*err); }; hare-0.24.2/errors/string.ha000066400000000000000000000034251464473310100156610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Converts an [[error]] into a human-friendly string representation. // // Note that this strerror implementation lacks any context-specific information // about the error types supported. For example, [[exists]] is stringified as "An // attempt was made to create a resource which already exists", but if source of // the error is, say, creating a file, it would likely be more appropriate to // use the term "file" rather than "resource". For this reason, it is preferred // that modules which return an error type from this module provide their own // strerror function which provides more context-appropriate error messages for // each of those types. export fn strerror(err: error) const str = match (err) { case busy => yield "The requested resource is not available"; case exists => yield "An attempt was made to create a resource which already exists"; case invalid => yield "A function was called with an invalid combination of arguments"; case noaccess => yield "The user does not have permission to use this resource"; case noentry => yield "An entry was requested which does not exist"; case overflow => yield "The requested operation caused a numeric overflow condition"; case unsupported => yield "The requested operation is not supported"; case timeout => yield "The requested operation timed out"; case cancelled => yield "The requested operation was cancelled"; case refused => yield "A connection attempt was refused"; case nomem => yield "Unable to allocate sufficient memory for the requested operation"; case interrupted => yield "Operation interrupted"; case again => yield "Try again"; case netunreachable => yield "Network unreachable"; case let op: opaque_ => yield op.strerror(&op.data); }; hare-0.24.2/fmt/000077500000000000000000000000001464473310100133075ustar00rootroot00000000000000hare-0.24.2/fmt/+test.ha000066400000000000000000000071511464473310100146570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math; use strconv; @test fn print() void = { let buf: [1024]u8 = [0...]; assert(bsprint(buf, "hello world") == "hello world"); assert(bsprintf(buf, "hello world") == "hello world"); assert(bsprintf(buf, "{} {}", "hello", "world") == "hello world"); assert(bsprintf(buf, "{0} {1}", "hello", "world") == "hello world"); assert(bsprintf(buf, "{0} {0}", "hello", "world") == "hello hello"); assert(bsprintf(buf, "{1} {0} {1}", "hello", "world") == "world hello world"); const mod = &mods { width = 7, pad = ' ', ... }; assert(bsprintf(buf, "{%}", "hello", mod) == " hello"); assert(bsprintf(buf, "{%1}", "hello", mod) == " hello"); assert(bsprintf(buf, "{0%1}", "hello", mod) == " hello"); assert(bsprintf(buf, "{0%2}", "hello", 0, mod) == " hello"); assert(bsprintf(buf, "{1%2}", 0, "hello", mod) == " hello"); assert(bsprintf(buf, "{2%0}", mod, 0, "hello") == " hello"); assert(bsprintf(buf, "{2%}", mod, 0, "hello") == " hello"); assert(bsprintf(buf, "|{1%}|{}|", mod, "hello") == "| hello|hello|"); assert(bsprintf(buf, "|{}|{2%}|", "hello", mod, "world") == "|hello| world|"); assert(bsprintf(buf, "|{%}|{%}|{%}|{%}|", "hello", &mods { ... }, "world", &mods { width = 10, pad = ' ', ... }, 123, &mods { prec = 10, ... }, 0xBEEF, &mods { base = strconv::base::HEX, ... }, ) == "|hello| world|0000000123|BEEF|"); assert(bsprintf(buf, "|{%}|{%}|{0%1}|", "hello", &mods { ... }, "world", &mods { ... }, ) == "|hello|world|hello|"); assert(bsprintf(buf, "x: {:8X}", 0xBEEF) == "x: BEEF"); assert(bsprintf(buf, "x: {:8X}", -0xBEEF) == "x: -BEEF"); assert(bsprintf(buf, "x: {: 8X}", 0xBEEF) == "x: BEEF"); assert(bsprintf(buf, "x: {:+ 8X}", 0xBEEF) == "x: BEEF"); assert(bsprintf(buf, "x: {:+8X}", 0xBEEF) == "x: +BEEF"); assert(bsprintf(buf, "x: {: +8X}", 0xBEEF) == "x: +BEEF"); assert(bsprintf(buf, "x: {:-8X}", 0xBEEF) == "x: BEEF "); assert(bsprintf(buf, "x: {:-8X}", -0xBEEF) == "x: -BEEF "); assert(bsprintf(buf, "x: {:-+8X}", 0xBEEF) == "x: +BEEF "); assert(bsprintf(buf, "x: {:- 8X}", 0xBEEF) == "x: BEEF "); assert(bsprintf(buf, "x: {:.8x}", 0xBEEF) == "x: 0000beef"); assert(bsprintf(buf, "x: {:.8x}", -0xBEEF) == "x: -000beef"); assert(bsprintf(buf, "x: {:+.8x}", 0xBEEF) == "x: +000beef"); assert(bsprintf(buf, "x: {: .8x}", 0xBEEF) == "x: 000beef"); assert(bsprintf(buf, "x: {:-_08X}", 0xBEEF) == "x: BEEF0000"); assert(bsprintf(buf, "x: {:o}", 0o755) == "x: 755"); assert(bsprintf(buf, "x: {:b}", 0b11011) == "x: 11011"); assert(bsprintf(buf, "x: {:8}", "hello") == "x: hello"); assert(bsprintf(buf, "x: {:-8}", "hello") == "x: hello "); assert(bsprintf(buf, "x: {:_08}", "hello") == "x: 000hello"); assert(bsprintf(buf, "{:.5}", "hello world") == "hello"); assert(bsprintf(buf, "{:.5}", "hi") == "hi"); assert(bsprintf(buf, "{:5.2}", "hello") == " he"); assert(bsprintf(buf, "{:.1}", 123.0) == "100"); assert(bsprintf(buf, "{:.5}", 123.0) == "123"); assert(bsprintf(buf, "{:f}", 1.0e4) == "10000"); assert(bsprintf(buf, "{:e}", 123.45) == "1.2345e2"); assert(bsprintf(buf, "{:Fs}", 1.0) == "+1"); assert(bsprintf(buf, "{:F.}", 1.0) == "1.0"); assert(bsprintf(buf, "{:FU}", math::INF) == "INFINITY"); assert(bsprintf(buf, "{:FE}", 1.0e4) == "1E4"); assert(bsprintf(buf, "{:FS}", 1.0e4) == "1e+4"); assert(bsprintf(buf, "{:F2}", 1.0e4) == "1e04"); assert(bsprintf(buf, "{:=5}", "hi") == " hi "); assert(bsprintf(buf, "{:=6}", "hi") == " hi "); assert(bsprintf(buf, "{} {} {} {} {}", true, false, null, 'x', void) == "true false (null) x void"); }; hare-0.24.2/fmt/README000066400000000000000000000105601464473310100141710ustar00rootroot00000000000000A format string consists of a string of literal characters, to be printed verbatim, and format sequences, which describe how to format arguments from a set of variadic parameters for printing. A format sequence is enclosed in curly braces "{}". An empty sequence takes the next argument from the parameter list, in order. A specific parameter can be selected by indexing it from zero: "{0}", "{1}", and so on. To print "{", use "{{", and for "}", use "}}". There are two ways to specify how an argument will be formatted: inline format modifiers, and parametric format modifiers. Inline format modifiers are a series of characters within a format sequence. You can use a colon to add format modifiers; for example, "{:x}" will format an argument in hexadecimal, and "{3:-10}" will left-align the 4th argument (zero indexed) to at least 10 characters. Format modifiers can be written in any order, and can also be repeated. If a modifier is repeated (or two conflicting modifiers are given, such as both "x" and "X") the one furthest to the right will be used. A format modifier can be any of the following: - a number N: Sets the width to N. If the value would otherwise be shorter than N runes, insert padding characters in order to make it N runes long. By default, the value is right-aligned, with padding inserted on the left side, and the padding character is " " (a space). - "-": Left-align the value, inserting padding characters on the right side of the value in order to meet the width requirement. - "=": Center-align the value, inserting the same amount of padding on the left as on the right. If an odd number of padding characters need to be placed, the extra one will be on the left of the value. - "_" followed by a rune: Use the given rune as the padding character rather than the default of " " (a space). - " " (a space): Insert a space before positive integers, where "-" would be if it were negative. - "+": Insert a "+" before positive integers. - "x": Format numbers in lowercase hexadecimal. - "X": Format numbers in uppercase hexadecimal. - "o": Format numbers in octal. - "b": Format numbers in binary. - "e": Format floats in scientific notation. - "f": Format floats in fixed-point notation. - "g": Format floats in whichever of scientific and fixed-point notation is shortest. This is the default. - "F" followed by "s": Use a sign for both positive and negative numbers. - "F" followed by ".": Always include at least one digit after the decimal point. - "F" followed by "U": Uppercase INFINITY and NAN. - "F" followed by "E": Uppercase exponent symbols (E and P rather than e and p). - "F" followed by "S": Use a sign for both positive and negative exponents. - "F" followed by "2": Show at least two digits of the exponent. - "." followed by a number N: Sets the precision to N. Integers will be left-padded with "0"s between the sign and the number itself. Strings will be truncated to N runes. Floats will include up to N digits, counted as per [[strconv::ftosf]], including those before the decimal point in the default case ("g"), excluding them when "f" or "e" are set. Some inline modifier examples: fmt::printf("hello {}", "world"); // "hello world" fmt::printf("{1} {0}", "hello", "world"); // "world hello" fmt::printf("{:x} {:X}", 51966, 61453); // "cafe F00D" fmt::printf("{:-5}", 42); // "42 " fmt::printf("{:5}", 42); // " 42" fmt::printf("{:.5}", 42); // "00042" fmt::printf("{:.2f}", 42.87934); // "42.88" A parametric format modifier is a secondary argument from the parameter list, which is a pointer to an instance of [[mods]]. This modifier parameter describes how the primary formattable argument is formatted. A parametric format sequence of this sort takes the form of "{i%j}", where i is the formattable parameter index, j is the modifiers parameter index, and i & j are optional. If either i or j aren't explicitly provided by the user, they will evaluate to the index of the next unused argument. Some parametric modifier examples: // "hello world hello" fmt::printf("{%} {%} {0%1}", // evaluates to "{0%1} {2%3} {0%1}" "hello", &fmt::mods { ... }, "world", &fmt::mods { ... }); // "|hello| world|0000000123|BEEF|" fmt::printf("|{%}|{%}|{%}|{%}|", "hello", &fmt::mods { ... }, "world", &fmt::mods { pad = ' ', width = 10, ... }, 123, &fmt::mods { prec = 10, ... }, 0xBEEF, &fmt::mods { base = strconv::base::HEX, ... }); hare-0.24.2/fmt/iter.ha000066400000000000000000000112351464473310100145660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use strings; use strconv; use types; // Tagged union of the [[formattable]] types and [[mods]]. Used for // functions which accept format strings. export type field = (...formattable | *mods); // Tagged union of all types which are formattable. export type formattable = (...types::numeric | uintptr | str | rune | bool | nullable *opaque | void); // Negative modifier. Specifies for numerical arguments when to prepend a plus // or minus sign or a blank space. export type neg = enum { NONE, SPACE, PLUS, }; // Alignment modifier. Specifies how to align an argument within a given width. export type alignment = enum { RIGHT, CENTER, LEFT, }; // Specifies how to format an argument. export type mods = struct { alignment: alignment, pad: rune, neg: neg, width: size, prec: size, base: strconv::base, ffmt: strconv::ffmt, fflags: strconv::fflags, }; type iterator = struct { iter: strings::iterator, args: []field, idx: size, checkunused: bool, }; fn iter(fmt: str, args: []field) iterator = iterator { iter = strings::iter(fmt), args = args, idx = 0, checkunused = true, }; fn next(it: *iterator) (str | (formattable, mods) | done) = { let r = match (strings::next(&it.iter)) { case done => return done; case let r: rune => yield r; }; switch (r) { case '{' => void; // handled below case '}' => match (strings::next(&it.iter)) { case done => abort("Invalid format string (hanging '}')"); case let r: rune => assert(r == '}', "Invalid format string (hanging '}')"); }; return "}"; case => strings::prev(&it.iter); let start = it.iter; for (let r => strings::next(&it.iter)) { if (r == '{' || r == '}') { strings::prev(&it.iter); break; }; }; return strings::slice(&start, &it.iter); }; r = getrune(it); if (r == '{') { return "{"; }; let idx = if (ascii::isdigit(r)) { strings::prev(&it.iter); it.checkunused = false; defer r = getrune(it); yield scan_sz(it); } else { defer it.idx += 1; yield it.idx; }; assert(idx < len(it.args), "Not enough parameters given"); let arg = it.args[idx] as formattable; let mod = mods { ... }; switch (r) { case ':' => scan_modifiers(it, &mod); case '%' => r = getrune(it); let idx = if (ascii::isdigit(r)) { strings::prev(&it.iter); it.checkunused = false; defer r = getrune(it); yield scan_sz(it); } else { defer it.idx += 1; yield it.idx; }; assert(idx < len(it.args), "Not enough parameters given"); mod = *(it.args[idx] as *mods); assert(r == '}', "Invalid format string (didn't find '}' after modifier index)"); case '}' => void; case => abort("Invalid format string"); }; return (arg, mod); }; fn scan_modifiers(it: *iterator, mod: *mods) void = { mod.pad = ' '; for (true) switch (getrune(it)) { // alignment case '-' => mod.alignment = alignment::LEFT; case '=' => mod.alignment = alignment::CENTER; // padding case '_' => mod.pad = getrune(it); // negation case ' ' => mod.neg = neg::SPACE; case '+' => mod.neg = neg::PLUS; // base case 'x' => mod.base = strconv::base::HEX_LOWER; case 'X' => mod.base = strconv::base::HEX_UPPER; case 'o' => mod.base = strconv::base::OCT; case 'b' => mod.base = strconv::base::BIN; // ffmt case 'e' => mod.ffmt = strconv::ffmt::E; case 'f' => mod.ffmt = strconv::ffmt::F; case 'g' => mod.ffmt = strconv::ffmt::G; // fflags case 'F' => switch (getrune(it)) { case 's' => mod.fflags |= strconv::fflags::SHOW_POS; case '.' => mod.fflags |= strconv::fflags::SHOW_POINT; case 'U' => mod.fflags |= strconv::fflags::UPPERCASE; case 'E' => mod.fflags |= strconv::fflags::UPPER_EXP; case 'S' => mod.fflags |= strconv::fflags::SHOW_POS_EXP; case '2' => mod.fflags |= strconv::fflags::SHOW_TWO_EXP_DIGITS; case => abort("Invalid float flag"); }; // precision case '.' => mod.prec = scan_sz(it); // width case '1', '2', '3', '4', '5', '6', '7', '8', '9' => strings::prev(it); mod.width = scan_sz(it); case => strings::prev(it); break; }; assert(getrune(it) == '}', "Invalid format string (unterminated '{')"); }; fn scan_sz(it: *iterator) size = { let start = it.iter; assert(ascii::isdigit(getrune(it))); for (ascii::isdigit(getrune(it))) void; strings::prev(&it.iter); match (strconv::stoz(strings::slice(&start, &it.iter))) { case strconv::invalid => abort("Invalid format string (invalid integer)"); case strconv::overflow => abort("Invalid format string (integer overflow)"); case let z: size => return z; }; }; fn getrune(it: *iterator) rune = match (strings::next(&it.iter)) { case done => abort("Invalid format string (unterminated '{')"); case let r: rune => return r; }; hare-0.24.2/fmt/print.ha000066400000000000000000000071141464473310100147600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use io; use math; use strconv; use strings; use types; // Formats values for printing using the default format modifiers and writes // them to an [[io::handle]] separated by spaces. export fn fprint(h: io::handle, args: formattable...) (size | io::error) = { let mod = mods { ... }; let n = 0z; for (let i = 0z; i < len(args); i += 1) { n += format(h, args[i], &mod)?; if (i != len(args) - 1) { n += format(h, " ", &mod)?; }; }; return n; }; // Formats text for printing and writes it to an [[io::handle]]. export fn fprintf( h: io::handle, fmt: str, args: field... ) (size | io::error) = { let n = 0z; let it = iter(fmt, args); for (true) match (next(&it)) { case done => break; case let s: str => n += format(h, s, &mods { ... })?; case let f: (formattable, mods) => n += format(h, f.0, &f.1)?; }; assert(!it.checkunused || it.idx == len(args), "Too many parameters given"); return n; }; fn format( out: io::handle, arg: formattable, mod: *mods, ) (size | io::error) = { let start = 0z; // guaranteed not to have starting padding in either of these cases // saves the extra format_raw() if (mod.width > 0 && mod.alignment != alignment::LEFT) { let width = format_raw(io::empty, arg, mod)?; let pad = if (width > mod.width) 0z else mod.width - width; switch (mod.alignment) { case alignment::LEFT => abort(); case alignment::CENTER => start = (pad + 1) / 2; case alignment::RIGHT => start = pad; }; }; let z = 0z; for (z < start) { z += io::write(out, utf8::encoderune(mod.pad))?; }; z += format_raw(out, arg, mod)?; for (z < mod.width) { z += io::write(out, utf8::encoderune(mod.pad))?; }; return z; }; fn format_raw( out: io::handle, arg: formattable, mod: *mods, ) (size | io::error) = match (arg) { case void => return io::write(out, strings::toutf8("void")); case let r: rune => return io::write(out, utf8::encoderune(r)); case let s: str => if (mod.prec > 0 && mod.prec < len(s)) { s = strings::sub(s, 0, mod.prec); }; return io::write(out, strings::toutf8(s)); case let b: bool => return io::write(out, strings::toutf8(if (b) "true" else "false")); case let p: uintptr => const s = strconv::uptrtos(p, mod.base); return io::write(out, strings::toutf8(s)); case let v: nullable *opaque => match (v) { case let v: *opaque => let z = io::write(out, strings::toutf8("0x"))?; const s = strconv::uptrtos(v: uintptr, strconv::base::HEX_LOWER); z += io::write(out, strings::toutf8(s))?; return z; case null => return io::write(out, strings::toutf8("(null)")); }; case let f: types::floating => assert(mod.base == strconv::base::DEFAULT || mod.base == strconv::base::DEC); // TODO assert(mod.prec <= types::UINT_MAX); // TODO: mod.prec should be (size | void) but that needs @default return strconv::fftosf(out, f, mod.ffmt, if (mod.prec != 0) mod.prec: uint else void, mod.fflags)?; case let i: types::integer => let neg = match (i) { case types::unsigned => yield false; case let s: types::signed => i = math::absi(s); yield math::signi(s) < 0; }; let sign = if (neg) "-" else { yield switch (mod.neg) { case neg::PLUS => yield "+"; case neg::SPACE => yield " "; case neg::NONE => yield ""; }; }; let i = strconv::integertos(i, mod.base); let pad = if (mod.prec < len(sign) + len(i)) { yield 0z; } else { yield mod.prec - len(sign) - len(i); }; let z = io::write(out, strings::toutf8(sign))?; for (let i = 0z; i < pad) { i += io::write(out, ['0'])?; }; z += pad; return z + io::write(out, strings::toutf8(i))?; }; hare-0.24.2/fmt/wrappers.ha000066400000000000000000000103051464473310100154630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use memio; use os; use strings; // Formats text for printing and writes it to [[os::stdout]]. export fn printf(fmt: str, args: field...) (size | io::error) = fprintf(os::stdout, fmt, args...); // Formats text for printing and writes it to [[os::stdout]], followed by a line // feed. export fn printfln(fmt: str, args: field...) (size | io::error) = fprintfln(os::stdout, fmt, args...); // Formats text for printing and writes it to [[os::stderr]]. export fn errorf(fmt: str, args: field...) (size | io::error) = fprintf(os::stderr, fmt, args...); // Formats text for printing and writes it to [[os::stderr]], followed by a line // feed. export fn errorfln(fmt: str, args: field...) (size | io::error) = fprintfln(os::stderr, fmt, args...); // Formats text for printing and writes it into a heap-allocated string. The // caller must free the return value. export fn asprintf(fmt: str, args: field...) str = { let buf = memio::dynamic(); assert(fprintf(&buf, fmt, args...) is size); return strings::fromutf8_unsafe(memio::buffer(&buf)); }; // Formats text for printing and writes it into a caller supplied buffer. The // returned string is borrowed from this buffer. Aborts if the buffer isn't // large enough to hold the formatted text. export fn bsprintf(buf: []u8, fmt: str, args: field...) str = { let sink = memio::fixed(buf); let l = fprintf(&sink, fmt, args...)!; return strings::fromutf8_unsafe(buf[..l]); }; // Formats text for printing and writes it to [[os::stderr]], followed by a line // feed, then exits the program with an error status. export fn fatalf(fmt: str, args: field...) never = { fprintfln(os::stderr, fmt, args...): void; os::exit(255); }; // Formats values for printing using the default format modifiers and writes // them to [[os::stderr]] separated by spaces and followed by a line feed, then // exits the program with an error status. export fn fatal(args: formattable...) never = { fprintln(os::stderr, args...): void; os::exit(255); }; // Formats text for printing and writes it to an [[io::handle]], followed by a // line feed. export fn fprintfln( h: io::handle, fmt: str, args: field... ) (size | io::error) = fprintf(h, fmt, args...)? + io::write(h, ['\n'])?; // Formats values for printing using the default format modifiers and writes // them to [[os::stdout]] separated by spaces. export fn print(args: formattable...) (size | io::error) = fprint(os::stdout, args...); // Formats values for printing using the default format modifiers and writes // them to [[os::stdout]] separated by spaces and followed by a line feed. export fn println(args: formattable...) (size | io::error) = fprintln(os::stdout, args...); // Formats values for printing using the default format modifiers and writes // them to [[os::stderr]] separated by spaces. export fn error(args: formattable...) (size | io::error) = fprint(os::stderr, args...); // Formats values for printing using the default format modifiers and writes // them to [[os::stderr]] separated by spaces and followed by a line feed. export fn errorln(args: formattable...) (size | io::error) = fprintln(os::stderr, args...); // Formats values for printing using the default format modifiers and writes // them into a heap-allocated string separated by spaces. The caller must free // the return value. export fn asprint(args: formattable...) str = { let buf = memio::dynamic(); assert(fprint(&buf, args...) is size); return strings::fromutf8_unsafe(memio::buffer(&buf)); }; // Formats values for printing using the default format modifiers and writes // them into a caller supplied buffer separated by spaces. The returned string // is borrowed from this buffer. Aborts if the buffer isn't large enough to hold // the formatted text. export fn bsprint(buf: []u8, args: formattable...) str = { let sink = memio::fixed(buf); let l = fprint(&sink, args...)!; return strings::fromutf8_unsafe(buf[..l]); }; // Formats values for printing using the default format modifiers and writes // them to an [[io::handle]] separated by spaces and followed by a line feed. export fn fprintln(h: io::handle, args: formattable...) (size | io::error) = fprint(h, args...)? + io::write(h, ['\n'])?; hare-0.24.2/fnmatch/000077500000000000000000000000001464473310100141415ustar00rootroot00000000000000hare-0.24.2/fnmatch/+test.ha000066400000000000000000000136201464473310100155070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors type testcase = (str, str, bool, []flag); const testcases: [_]testcase = [ // homegrown tests ("a", "a", true, []), ("b", "b", true, []), ("ε", "ε", true, []), ("\0", "\0", true, []), ("abcde", "abcde", true, []), ("aaa", "bbb", false, []), ("わたし", "わたし", true, []), ("わした", "わたし", false, []), ("わaし", "わたし", false, []), ("ab*cde", "abcde", true, []), ("g*a", "gordana", true, []), ("ab*cde*foo*bar", "abcdefooba", false, []), ("*", "foo", true, []), ("aa*", "aafoo", true, []), ("bb*", "foo", false, []), ("*cc", "foocc", true, []), ("*dd", "foo", false, []), ("ra**ra", "rarara", true, []), ("x*yy*x", "xxyyyyyxxx", true, []), ("*", "*", true, []), ("*", "", true, []), ("****", "a", true, []), ("**a**", "a", true, []), ("****", "", true, []), ("*", "わたし", true, []), ("?", "ε", true, []), ("?", "\0", true, []), ("?", "*", true, []), ("?", "", false, []), ("??", "a", false, []), ("??", "abc", false, []), ("?aa", "bbb", false, []), ("わ?し", "わたし", true, []), ("???", "わたし", true, []), ("**?**", "", false, []), ("*?*?*?*?", "abcd", true, []), ("*?*?*?*?", "abc", false, []), ("[b]", "b", true, []), ("a[b]c", "abc", true, []), ("a[b]c", "axc", false, []), ("[a-c]", "b", true, []), ("[a-z]", "a", true, []), ("[c-a]", "b", false, []), ("x[a-c]y", "xay", true, []), ("x[a-c]y", "xby", true, []), ("x[a-c]y", "xcy", true, []), ("x[a-c]y", "xzy", false, []), ("x[a-c]y", "xy", false, []), ("[a-c]*[a-c]", "axxxb", true, []), ("わ[た]し", "わたし", true, []), ("[-]", "-", true, []), ("[.]", ".", true, []), ("[:ias]", ":", true, []), ("[-]", "a", false, []), ("[-ac]", "a", true, []), ("[-ac]", "-", true, []), ("[-ac]", "b", false, []), ("[ac-]", "a", true, []), ("[ac-]", "-", true, []), ("[ac-]", "b", false, []), ("[.a.]", "a", false, []), ("[[:alnum:]]", "7", true, []), ("[[:alpha:]]", "[", false, []), ("[[:alpha:]]", "[[", false, []), ("[[alpha:]]", "a]", true, []), ("[[alpha:]]", ":]", true, []), ("[[:alpha:]]", "a", true, []), ("[[:blank:]]", " ", true, []), ("[[:alnum:]]a", "a]a", false, []), ("[[:alnum:][[:digit:]]", "a", true, []), ("[!b]", "b", false, []), ("a[!b]c", "abc", false, []), ("a[!b]c", "axc", true, []), ("[!a-c]", "b", false, []), ("[!c-a]", "b", true, []), ("x[!a-c]y", "xay", false, []), ("x[!a-c]y", "xby", false, []), ("x[!a-c]y", "xcy", false, []), ("x[!a-c]y", "xzy", true, []), ("x[!a-c]y", "xy", false, []), ("[!a-c]*[!a-c]", "axxxb", false, []), ("わ[!た]し", "わたし", false, []), ("[!-]", "-", false, []), ("[!-]", "a", true, []), ("[!-ac]", "a", false, []), ("[!-ac]", "-", false, []), ("[!-ac]", "b", true, []), ("[![:alnum:]]", "a", false, []), ("[![:alpha:]]", "[", true, []), ("[![:alnum:]]a", "a]a", false, []), ("[![:alpha:]]a", "[a", true, []), ("[![:alnum:][:digit:]]", "a", false, []), (".", ".", true, [flag::PERIOD]), ("*", ".", false, [flag::PERIOD]), ("?", ".", false, [flag::PERIOD]), ("[.]", ".", false, [flag::PERIOD]), (".*", ".asdf", true, [flag::PERIOD]), (".*", "asdf", false, [flag::PERIOD]), ("\\", "\\", true, [flag::NOESCAPE]), ("\\*", "\\asdf", true, [flag::NOESCAPE]), // adapted from musl tests ("*.c", "foo.c", true, []), ("*.c", ".c", true, []), ("*.a", "foo.c", false, []), ("*.c", ".foo.c", true, []), ("a\\*.c", "ax.c", false, []), ("a[xy].c", "ax.c", true, []), ("a[!y].c", "ax.c", true, []), ("-O[01]", "-O1", true, []), ("[[?*\\]", "\\", true, []), ("[]?*\\]", "]", true, []), ("[!]a-]", "b", true, []), ("[]-_]", "^", true, []), ("[!]-_]", "X", true, []), ("??", "-", false, []), ("[*]/b", "a/b", false, []), ("[*]/b", "*/b", true, []), ("[?]/b", "a/b", false, []), ("[?]/b", "?/b", true, []), ("[[a]/b", "a/b", true, []), ("[[a]/b", "[/b", true, []), ("\\*/b", "a/b", false, []), ("\\*/b", "*/b", true, []), ("\\?/b", "a/b", false, []), ("\\?/b", "?/b", true, []), ("[/b", "[/b", false, []), ("\\[/b", "[/b", true, []), ("??""/b", "aa/b", true, []), ("???b", "aa/b", true, []), ("a[/]b", "a/b", true, []), ("*[/]b", "a", false, []), ("[![:d-d]", "b", false, []), ("[[:d-d]", "[", false, []), ("[![:d-d]", "[", false, []), ("[a-z]/[a-z]", "a/b", true, [flag::PATHNAME]), ("a[/]b", "a/b", false, [flag::PATHNAME]), ("*", "a/b", false, [flag::PATHNAME]), ("*[/]b", "a/b", false, [flag::PATHNAME]), ("*[b]", "a/b", false, [flag::PATHNAME]), ("a[a/z]*.c", "a/x.c", false, [flag::PATHNAME]), ("a/*.c", "a/x.c", true, [flag::PATHNAME]), ("a*.c", "a/x.c", false, [flag::PATHNAME]), ("*/foo", "/foo", true, [flag::PATHNAME]), ("*.c", ".foo.c", false, [flag::PERIOD]), ("*.c", "foo.c", true, [flag::PERIOD]), ("a\\*.c", "a*.c", false, [flag::NOESCAPE]), ("???b", "aa/b", false, [flag::PATHNAME]), ("?a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]), ("a/?b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]), ("*a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]), ("a/*b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]), ("[.]a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]), ("a/[.]b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]), ("*/?", "a/b", true, [flag::PATHNAME, flag::PERIOD]), ("?/*", "a/b", true, [flag::PATHNAME, flag::PERIOD]), (".*/?", ".a/b", true, [flag::PATHNAME, flag::PERIOD]), ("*/.?", "a/.b", true, [flag::PATHNAME, flag::PERIOD]), ("*/*", "a/.b", false, [flag::PATHNAME, flag::PERIOD]), ("*?*/*", "a/.b", true, [flag::PERIOD]), ("*[.]/b", "a./b", true, [flag::PATHNAME, flag::PERIOD]), ("*[[:alpha:]]/*[[:alnum:]]", "a/b", true, [flag::PATHNAME]), ("a?b", "a.b", true, [flag::PATHNAME, flag::PERIOD]), ("a*b", "a.b", true, [flag::PATHNAME, flag::PERIOD]), ("a[.]b", "a.b", true, [flag::PATHNAME, flag::PERIOD]), ]; @test fn fnmatch() void = { for (let tc .. testcases) { let flags = flag::NONE; for (let fl .. tc.3) { flags |= fl; }; assert(fnmatch(tc.0, tc.1, flags) == tc.2); }; }; hare-0.24.2/fnmatch/README000066400000000000000000000002471464473310100150240ustar00rootroot00000000000000The fnmatch module provides an implementation of fnmatch string matching as defined by POSIX. https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html hare-0.24.2/fnmatch/fnmatch.ha000066400000000000000000000210341464473310100160730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use errors; use strings; // A set of flags that alter the matching behavior of [[fnmatch]] export type flag = enum uint { NONE = 0, // If this flag is set, slashes in the string will only be matched by // literal slashes in the pattern PATHNAME = 1u << 0, // If this flag is set, backslash will be treated as an ordinary // character NOESCAPE = 1u << 1, // If this flag is set, a '.' at the beginning of the string can only // be matched by a literal '.' in the pattern. If [[flag::PATHNAME]] is // set simultaneously, this behavior also apply to any periods // immediately following a slash. PERIOD = 1u << 2, }; type bracket = void; type star = void; type question = void; type end = void; type token = (rune | bracket | star | question | end); // Check whether the 'string' matches the 'pattern', which is a shell wildcard // pattern with the following matching rules: // // - '?' matches any single character // - '*' matches any string, including the empty string // - '[' and ']' enclose a bracket expression. Matching rules for bracket // expressions are identical to those of bracket subexpressions in regular // expressions, except that '!' takes the role of '^' when placed right after // the opening '['. // - '\' escapes the following character, e. g. "\*" only matches literal '*' // and has no special meaning // - all other characters only match themselves // // A set of flags that alter the matching behavior may be passed to // [[fnmatch]]. For an explanation of their meaning, see [[flag]]. export fn fnmatch(pattern: str, string: str, flags: flag = flag::NONE) bool = { let b = if (flags & flag::PATHNAME != 0) { yield fnmatch_pathname(pattern, string, flags); } else { yield fnmatch_internal(pattern, string, flags); }; return b is bool && b: bool; }; // Split the pattern and the string on every '/' and process each part // separately fn fnmatch_pathname( pattern: str, string: str, fl: flag, ) (bool | errors::unsupported | errors::invalid) = { let tok = strings::tokenize(string, "/"); let p_iter = strings::iter(pattern); let start = p_iter; for :outer (true) { start = p_iter; for (true) match (pat_next(&p_iter, fl)?) { case end => break :outer; case let r: rune => if (r == '/') break; case bracket => match_bracket(&p_iter, '\0')?; case (question | star) => void; }; let s = match (strings::next_token(&tok)) { case done => return false; case let s: str => yield s; }; strings::prev(&p_iter); let p = strings::slice(&start, &p_iter); strings::next(&p_iter); if (!fnmatch_internal(p, s, fl)?) { return false; }; }; let s = match(strings::next_token(&tok)) { case done => return false; case let s: str => yield s; }; let p = strings::iterstr(&start); return fnmatch_internal(p, s, fl)? && strings::next_token(&tok) is done; }; // Core fnmatch function, implementing the "Sea of stars" algorithm that is also // used in Musl libc. First we make sure the parts before the first star and // after the last star produce exact matches and then proceed to greedily match // everything in between. Because of the greedy property this algorithm does not // have exponential corner cases. fn fnmatch_internal( pattern: str, string: str, fl: flag, ) (bool | errors::invalid | errors::unsupported) = { if (fl & flag::PERIOD != 0) { if (strings::hasprefix(string, ".") && !strings::hasprefix(pattern, ".")) { return false; }; }; let p = strings::iter(pattern); let s = strings::iter(string); // match up to the first * for (true) { let copy = s; let rn = strings::next(©); let t = match (pat_next(&p, fl)?) { case star => break; case end => return rn is done; case question => yield rn is rune; case bracket => yield rn is rune && match_bracket(&p, rn: rune)?; case let r: rune => yield rn is rune && rn: rune == r; }; if (!t) { return false; }; s = copy; }; // find the tail of the pattern let p_copy = p, p_last = (p, 0z); let cnt = 0z; for (true; cnt += 1) { match (pat_next(&p, fl)?) { case end => break; case star => p_last = (p, cnt + 1); case bracket => match_bracket(&p, '\0')?; case (question | rune) => void; }; }; p = p_last.0; cnt = cnt - p_last.1; let s_copy = s; s = strings::riter(string); for (let i = 0z; i < cnt; i += 1) { strings::next(&s); }; // match the tail let s_last = s; for (true) { let rn = strings::prev(&s); let matches = match (pat_next(&p, fl)?) { case end => if (rn is done) { break; } else { return false; }; case question => yield rn is rune; case bracket => yield rn is rune && match_bracket(&p, rn: rune)?; case let r: rune => yield rn is rune && rn: rune == r; case star => abort(); }; if (!matches) { return false; }; }; // match the "sea of stars" in the middle s_copy = strings::iter(strings::slice(&s_copy, &s_last)); p_copy = strings::iter(strings::slice(&p_copy, &p_last.0)); for :outer (true) { p = p_copy; if (len(strings::iterstr(&p)) == 0) { return true; }; s = s_copy; for (true) { let copy = s; let rn = strings::next(©); let matched = match (pat_next(&p, fl)?) { case end => abort(); case question => yield rn is rune; case bracket => yield rn is rune && match_bracket(&p, rn: rune)?; case let r: rune => yield rn is rune && r == rn: rune; case star => p_copy = p; s_copy = s; continue :outer; }; if (!matched) { break; }; s = copy; }; match (strings::next(&s_copy)) { case done => return false; case rune => void; }; }; }; fn match_bracket( it: *strings::iterator, c: rune, ) (bool | errors::invalid | errors::unsupported) = { let old = *it; let first = advance_or_err(it)?; let inv = false; if (first == '^') { return errors::invalid; }; if (first == '!') { inv = true; first = advance_or_err(it)?; }; let found = (first != '[' && first == c); let last: (rune | void) = first; if (first == ']') { first = advance_or_err(it)?; }; for (let r = first; true; r = advance_or_err(it)?) { switch (r) { case ']' => break; case '-' => let end = advance_or_err(it)?; if (end == ']') { // '-' at the end matches itself strings::prev(it); last = '-'; found ||= (c == '-'); continue; }; match (last) { case void => return errors::invalid; case let l: rune => found ||= (l: u32 <= c: u32 && c: u32 <= end: u32); last = void; // forbid 'a-f-n' }; case '[' => let next_rune = advance_or_err(it)?; switch (next_rune) { // TODO localization case '=', '.' => return errors::unsupported; case ':' => let t = match_ctype(it, c)?; found ||= t; case => strings::prev(it); found ||= (c == '['); }; last = '['; case => found ||= (c == r); last = r; }; }; let cnt = len(strings::iterstr(&old)) - len(strings::iterstr(it)); if (last is rune && first == last: rune && cnt >= 4 && (first == '=' || first == '.' || first == ':')) { return errors::invalid; }; return found ^^ inv; }; fn match_ctype(it: *strings::iterator, c: rune) (bool | errors::invalid) = { let s = strings::iterstr(it); let i = 0z; for (let r = '\0'; r != ':'; i += 1) { r = advance_or_err(it)?; if (!ascii::valid(r)) { return errors::invalid; }; }; if (advance_or_err(it)? != ']') { return errors::invalid; }; let name = strings::sub(s, 0, i - 1); const map: [_](str, *fn(rune) bool) = [ ("alnum", &ascii::isalnum), ("alpha", &ascii::isalpha), ("blank", &ascii::isblank), ("cntrl", &ascii::iscntrl), ("digit", &ascii::isdigit), ("graph", &ascii::isgraph), ("lower", &ascii::islower), ("print", &ascii::isprint), ("punct", &ascii::ispunct), ("space", &ascii::isspace), ("upper", &ascii::isupper), ("xdigit",&ascii::isxdigit), ]; for (let i = 0z; i < len(map); i += 1) { if (map[i].0 == name) { return map[i].1(c); }; }; return errors::invalid; }; fn pat_next(pat: *strings::iterator, fl: flag) (token | errors::invalid) = { let r = match (strings::next(pat)) { case done => return end; case let r: rune => yield r; }; switch (r) { case '*' => return star; case '?' => return question; case '[' => return bracket; case '\\' => // TODO: remove ? (harec bug workaround) return if (fl & flag::NOESCAPE == 0) advance_or_err(pat)? else '\\'; case => return r; }; }; fn advance_or_err(it: *strings::iterator) (rune | errors::invalid) = { match (strings::next(it)) { case let r: rune => return r; case done => return errors::invalid; }; }; hare-0.24.2/format/000077500000000000000000000000001464473310100140115ustar00rootroot00000000000000hare-0.24.2/format/README000066400000000000000000000000001464473310100146570ustar00rootroot00000000000000hare-0.24.2/format/elf/000077500000000000000000000000001464473310100145575ustar00rootroot00000000000000hare-0.24.2/format/elf/README000066400000000000000000000001671464473310100154430ustar00rootroot00000000000000An implementation of the ELF64 file format. Best accompanied with a reading of the ELF-64 Object Format (Version 1.5). hare-0.24.2/format/elf/arch+aarch64.ha000066400000000000000000000002741464473310100172350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The machine (architecture) of the target. export def TARGET_MACHINE: elf_machine = elf_machine::AARCH64; hare-0.24.2/format/elf/arch+riscv64.ha000066400000000000000000000002721464473310100173030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The machine (architecture) of the target. export def TARGET_MACHINE: elf_machine = elf_machine::RISCV; hare-0.24.2/format/elf/arch+x86_64.ha000066400000000000000000000002731464473310100167420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The machine (architecture) of the target. export def TARGET_MACHINE: elf_machine = elf_machine::X86_64; hare-0.24.2/format/elf/platform+freebsd.ha000066400000000000000000000002361464473310100203240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The ABI of the target. export def TARGET_ABI: ident_abi = ident_abi::SYSV; hare-0.24.2/format/elf/platform+linux.ha000066400000000000000000000002361464473310100200510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The ABI of the target. export def TARGET_ABI: ident_abi = ident_abi::SYSV; hare-0.24.2/format/elf/platform+netbsd.ha000066400000000000000000000002361464473310100201710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The ABI of the target. export def TARGET_ABI: ident_abi = ident_abi::SYSV; hare-0.24.2/format/elf/platform+openbsd.ha000066400000000000000000000002361464473310100203440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The ABI of the target. export def TARGET_ABI: ident_abi = ident_abi::SYSV; hare-0.24.2/format/elf/types.ha000066400000000000000000000562071464473310100162470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: // - Flesh out ELF32 structures export def MAGIC: str = "\x7FELF"; export def EI_MAG0: uint = 0; export def EI_MAG1: uint = 1; export def EI_MAG2: uint = 2; export def EI_MAG3: uint = 3; export def EI_CLASS: uint = 4; export def EI_DATA: uint = 5; export def EI_VERSION: uint = 6; export def EI_OSABI: uint = 7; export def EI_ABIVERSION: uint = 8; export def EI_PAD: uint = 9; export def EI_NIDENT: uint = 16; export def EV_CURRENT: u32 = 1; // ELF header for ELF64 export type header64 = struct { // ELF identification e_ident: [EI_NIDENT]u8, // Object file type e_type: elf_type, // Machine type e_machine: elf_machine, // Object file version ([EV_CURRENT]) e_version: u32, // Entry point address e_entry: u64, // Program header offset e_phoff: u64, // Section header offset e_shoff: u64, // Processor-specific flags e_flags: u32, // ELF header size e_ehsize: u16, // Size of program header entry e_phentsize: u16, // Number of program header entries e_phnum: u16, // Size of section header entry e_shentsize: u16, // Number of section header entries e_shnum: u16, // Section name string table index, or [shn::UNDEF] e_shstrndx: u16, }; // Section header for ELF64 export type section64 = struct { // Section name sh_name: u32, // Section type sh_type: u32, // Section attributes sh_flags: u64, // Virtual address in memory sh_addr: u64, // Offset in file sh_offset: u64, // Size of section sh_size: u64, // Link to other section sh_link: u32, // Miscellaenous information sh_info: u32, // Address alignment boundary sh_addralign: u64, // Size of entries, if section has table sh_entsize: u64, }; // ELF file class export type ident_class = enum u8 { // 32-bit objects ELF32 = 1, // 64-bit objects ELF64 = 2, }; // Byte ordering export type ident_data = enum u8 { // Object file data structures are little-endian LSB = 1, // Object file data structures are big-endian MSB = 2, }; // Machine architecture export type elf_machine = enum u16 { // Unknown machine NONE = 0, // AT&T WE32100 M32 = 1, // Sun SPARC SPARC = 2, // Intel i386 I386 = 3, // Motorola 68000 M68K = 4, // Motorola 88000 M88K = 5, // Intel i860 M860 = 7, // MIPS R3000 Big-Endian only MIPS = 8, // IBM System/370 S370 = 9, // MIPS R3000 Little-Endian MIPS_RS3_LE = 10, // HP PA-RISC PARISC = 15, // Fujitsu VPP500 VPP500 = 17, // SPARC v8plus SPARC32PLUS = 18, // Intel 80960 I960 = 19, // PowerPC 32-bit PPC = 20, // PowerPC 64-bit PPC64 = 21, // IBM System/390 S390 = 22, // NEC V800 V800 = 36, // Fujitsu FR20 FR20 = 37, // TRW RH-32 RH32 = 38, // Motorola RCE RCE = 39, // ARM ARM = 40, // Hitachi SH SH = 42, // SPARC v9 64-bit SPARCV9 = 43, // Siemens TriCore embedded processor TRICORE = 44, // Argonaut RISC Core ARC = 45, // Hitachi H8/300 H8_300 = 46, // Hitachi H8/300H H8_300H = 47, // Hitachi H8S H8S = 48, // Hitachi H8/500 H8_500 = 49, // Intel IA-64 Processor IA_64 = 50, // Stanford MIPS-X MIPS_X = 51, // Motorola ColdFire COLDFIRE = 52, // Motorola M68HC12 M68HC12 = 53, // Fujitsu MMA MMA = 54, // Siemens PCP PCP = 55, // Sony nCPU NCPU = 56, // Denso NDR1 microprocessor NDR1 = 57, // Motorola Star*Core processor STARCORE = 58, // Toyota ME16 processor ME16 = 59, // STMicroelectronics ST100 processor ST100 = 60, // Advanced Logic Corp. TinyJ processor TINYJ = 61, // Advanced Micro Devices x86-64 X86_64 = 62, // Sony DSP Processor PDSP = 63, // Digital Equipment Corp. PDP-10 PDP10 = 64, // Digital Equipment Corp. PDP-11 PDP11 = 65, // Siemens FX66 microcontroller FX66 = 66, // STMicroelectronics ST9+ 8/16 bit microcontroller ST9PLUS = 67, // STMicroelectronics ST7 8-bit microcontroller ST7 = 68, // Motorola MC68HC16 Microcontroller M68HC16 = 69, // Motorola MC68HC11 Microcontroller M68HC11 = 70, // Motorola MC68HC08 Microcontroller M68HC08 = 71, // Motorola MC68HC05 Microcontroller M68HC05 = 72, // Silicon Graphics SVx SVX = 73, // STMicroelectronics ST19 8-bit microcontroller ST19 = 74, // Digital VAX VAX = 75, // Axis Communications 32-bit embedded processor CRIS = 76, // Infineon Technologies 32-bit embedded processor JAVELIN = 77, // Element 14 64-bit DSP Processor FIREPATH = 78, // LSI Logic 16-bit DSP Processor ZSP = 79, // Donald Knuth's educational 64-bit processor MMIX = 80, // Harvard University machine-independent object files HUANY = 81, // SiTera Prism PRISM = 82, // Atmel AVR 8-bit microcontroller AVR = 83, // Fujitsu FR30 FR30 = 84, // Mitsubishi D10V D10V = 85, // Mitsubishi D30V D30V = 86, // NEC v850 V850 = 87, // Mitsubishi M32R M32R = 88, // Matsushita MN10300 MN10300 = 89, // Matsushita MN10200 MN10200 = 90, // picoJava PJ = 91, // OpenRISC 32-bit embedded processor OPENRISC = 92, // ARC International ARCompact processor ARC_COMPACT = 93, // Tensilica Xtensa Architecture XTENSA = 94, // Alphamosaic VideoCore processor VIDEOCORE = 95, // Thompson Multimedia General Purpose Processor TMM_GPP = 96, // National Semiconductor 32000 series NS32K = 97, // Tenor Network TPC processor TPC = 98, // Trebia SNP 1000 processor SNP1K = 99, // STMicroelectronics (www.st.com) ST200 microcontroller ST200 = 100, // Ubicom IP2xxx microcontroller family IP2K = 101, // MAX Processor MAX = 102, // National Semiconductor CompactRISC microprocessor CR = 103, // Fujitsu F2MC16 F2MC16 = 104, // Texas Instruments embedded microcontroller msp430 MSP430 = 105, // Analog Devices Blackfin (DSP) processor BLACKFIN = 106, // S1C33 Family of Seiko Epson processors SE_C33 = 107, // Sharp embedded microprocessor SEP = 108, // Arca RISC Microprocessor ARCA = 109, // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University UNICORE = 110, // eXcess: 16/32/64-bit configurable embedded CPU EXCESS = 111, // Icera Semiconductor Inc. Deep Execution Processor DXP = 112, // Altera Nios II soft-core processor ALTERA_NIOS2 = 113, // National Semiconductor CompactRISC CRX microprocessor CRX = 114, // Motorola XGATE embedded processor XGATE = 115, // Infineon C16x/XC16x processor C166 = 116, // Renesas M16C series microprocessors M16C = 117, // Microchip Technology dsPIC30F Digital Signal Controller DSPIC30F = 118, // Freescale Communication Engine RISC core CE = 119, // Renesas M32C series microprocessors M32C = 120, // Altium TSK3000 core TSK3000 = 131, // Freescale RS08 embedded processor RS08 = 132, // Analog Devices SHARC family of 32-bit DSP processors SHARC = 133, // Cyan Technology eCOG2 microprocessor ECOG2 = 134, // Sunplus S+core7 RISC processor SCORE7 = 135, // New Japan Radio (NJR) 24-bit DSP Processor DSP24 = 136, // Broadcom VideoCore III processor VIDEOCORE3 = 137, // RISC processor for Lattice FPGA architecture LATTICEMICO32 = 138, // Seiko Epson C17 family SE_C17 = 139, // The Texas Instruments TMS320C6000 DSP family TI_C6000 = 140, // The Texas Instruments TMS320C2000 DSP family TI_C2000 = 141, // The Texas Instruments TMS320C55x DSP family TI_C5500 = 142, // Texas Instruments Application Specific RISC Processor, 32bit fetch TI_ARP32 = 143, // Texas Instruments Programmable Realtime Unit TI_PRU = 144, // STMicroelectronics 64bit VLIW Data Signal Processor MMDSP_PLUS = 160, // Cypress M8C microprocessor CYPRESS_M8C = 161, // Renesas R32C series microprocessors R32C = 162, // NXP Semiconductors TriMedia architecture family TRIMEDIA = 163, // QUALCOMM DSP6 Processor QDSP6 = 164, // Intel 8051 and variants I8051 = 165, // STMicroelectronics STxP7x family of configurable and extensible RISC processors STXP7X = 166, // Andes Technology compact code size embedded RISC processor family NDS32 = 167, // Cyan Technology eCOG1X family ECOG1 = 168, // Cyan Technology eCOG1X family ECOG1X = 168, // Dallas Semiconductor MAXQ30 Core Micro-controllers MAXQ30 = 169, // New Japan Radio (NJR) 16-bit DSP Processor XIMO16 = 170, // M2000 Reconfigurable RISC Microprocessor MANIK = 171, // Cray Inc. NV2 vector architecture CRAYNV2 = 172, // Renesas RX family RX = 173, // Imagination Technologies META processor architecture METAG = 174, // MCST Elbrus general purpose hardware architecture MCST_ELBRUS = 175, // Cyan Technology eCOG16 family ECOG16 = 176, // National Semiconductor CompactRISC CR16 16-bit microprocessor CR16 = 177, // Freescale Extended Time Processing Unit ETPU = 178, // Infineon Technologies SLE9X core SLE9X = 179, // Intel L10M L10M = 180, // Intel K10M K10M = 181, // ARM 64-bit Architecture (AArch64) AARCH64 = 183, // Atmel Corporation 32-bit microprocessor family AVR32 = 185, // STMicroeletronics STM8 8-bit microcontroller STM8 = 186, // Tilera TILE64 multicore architecture family TILE64 = 187, // Tilera TILEPro multicore architecture family TILEPRO = 188, // Xilinx MicroBlaze 32-bit RISC soft processor core MICROBLAZE = 189, // NVIDIA CUDA architecture CUDA = 190, // Tilera TILE-Gx multicore architecture family TILEGX = 191, // CloudShield architecture family CLOUDSHIELD = 192, // KIPO-KAIST Core-A 1st generation processor family COREA_1ST = 193, // KIPO-KAIST Core-A 2nd generation processor family COREA_2ND = 194, // Synopsys ARCompact V2 ARC_COMPACT2 = 195, // Open8 8-bit RISC soft processor core OPEN8 = 196, // Renesas RL78 family RL78 = 197, // Broadcom VideoCore V processor VIDEOCORE5 = 198, // Renesas 78KOR family R78KOR = 199, // Freescale 56800EX Digital Signal Controller (DSC) F56800EX = 200, // Beyond BA1 CPU architecture BA1 = 201, // Beyond BA2 CPU architecture BA2 = 202, // XMOS xCORE processor family XCORE = 203, // Microchip 8-bit PIC(r) family MCHP_PIC = 204, // Reserved by Intel INTEL205 = 205, // Reserved by Intel INTEL206 = 206, // Reserved by Intel INTEL207 = 207, // Reserved by Intel INTEL208 = 208, // Reserved by Intel INTEL209 = 209, // KM211 KM32 32-bit processor KM32 = 210, // KM211 KMX32 32-bit processor KMX32 = 211, // KM211 KMX16 16-bit processor KMX16 = 212, // KM211 KMX8 8-bit processor KMX8 = 213, // KM211 KVARC processor KVARC = 214, // Paneve CDP architecture family CDP = 215, // Cognitive Smart Memory Processor COGE = 216, // Bluechip Systems CoolEngine COOL = 217, // Nanoradio Optimized RISC NORC = 218, // CSR Kalimba architecture family CSR_KALIMBA = 219, // Zilog Z80 Z80 = 220, // Controls and Data Services VISIUMcore processor VISIUM = 221, // FTDI Chip FT32 high performance 32-bit RISC architecture FT32 = 222, // Moxie processor family MOXIE = 223, // AMD GPU architecture AMDGPU = 224, // RISC-V RISCV = 243, // Lanai 32-bit processor LANAI = 244, // Linux BPF – in-kernel virtual machine BPF = 247, // Intel i486 (deprecated) I486 = 6, // MIPS R4000 Big-Endian (deprecated) MIPS_RS4_BE = 10, // Digital Alpha (deprecated) ALPHA_STD = 41, // Alpha (deprecated) ALPHA = 0x9026, }; // ELF file type export type elf_type = enum u16 { // No file type NONE = 0, // Relocatable object file REL = 1, // Executable file EXEC = 2, // Shared object file DYN = 3, // Core file CORE = 4, // Environment-specific use LOOS = 0xFE00, // Environment-specific use HIOS = 0xFEFF, // Processor-specific use LOPROC = 0xFF00, // Processor-specific use HIPROC = 0xFFFF, }; // Application binary interface export type ident_abi = enum u8 { // System-V ABI SYSV = 0, // HP-UX operating system HPUX = 1, // Standalone (embedded) application STANDALONE = 255, }; // Special section indicies export type shn = enum u16 { // Used to mark an undefined or meaningless section reference UNDEF = 0, // Processor-specific use LOPROC = 0xFF00, // Processor-specific use HIPROC = 0xFF1F, // Environment-specific-use LOOS = 0xFF20, // Environment-specific-use HIOS = 0xFF3F, // Indicates that the corresponding reference is an absolute value ABS = 0xFFF1, // Indicates a symbol that has been declared as a common block COMMON = 0xFFF2, }; // Section type export type sht = enum u32 { // Marks an unused section header NULL = 0, // Contains information defined by the program PROGBITS = 1, // Contains a linker symbol table SYMTAB = 2, // Contains a string table STRTAB = 3, // Contains "Rela" type relocation entries RELA = 4, // Contains a symbol hash table HASH = 5, // Contains dynamic linking tables DYNAMIC = 6, // Contains note information NOTE = 7, // Contains uninitialized space; does not occupy any space in the file NOBITS = 8, // Contains "Rel" type relocation entries REL = 9, // Reserved SHLIB = 10, // Contains a dynamic loader symbol table DYNSYM = 11, // Environment-specific use LOOS = 0x60000000, // Environment-specific use HIOS = 0x6FFFFFFF, // Processor-specific use LOPROC = 0x70000000, // Processor-specific use HIPROC = 0x7FFFFFFF, }; // Section flags export type shf = enum u32 { // Section contains no data NONE = 0, // Section contains writable data WRITE = 0x1, // Section is allocated in memory image of program ALLOC = 0x2, // Section contains executable instructions EXECINSTR = 0x4, // Environment-specific use MASKOS = 0x0F000000, // Processor-specific use MASKPROC = 0xF0000000, }; // Symbol table entry export type sym64 = struct { // Symbol name offset st_name: u32, // Type and binding attributes st_info: u8, // Reserved st_other: u8, // Section table index st_shndx: u16, // Symbol value st_value: u64, // Size of object st_size: u64, }; // Symbol bindings export type stb = enum u8 { // Not visible outside the object file LOCAL = 0, // Global symbol, visible to all object files GLOBAL = 1, // Global scope, but with lower precedence than global symbols WEAK = 2, // Environment-specific use LOOS = 10, // Environment-specific use HIOS = 12, // Processor-specific use LOPROC = 13, // Processor-specific use HIPROC = 15, }; // Obtains the binding part of [sym64.st_info]. // // Equivalent to the ELF64_ST_BIND macro. export fn st_bind(i: u8) stb = (i >> 4): stb; // Symbol types export type stt = enum u8 { // No type specified (e.g. an absolute symbol) NOTYPE = 0, // Data object OBJECT = 1, // Function entry point FUNC = 2, // Symbol is associated with a section SECTION = 3, // Source file associated with the object FILE = 4, // Symbol is a common data object COMMON = 5, // Environment-specific use LOOS = 10, // Environment-specific use HIOS = 12, // Processor-specific use LOPROC = 13, // Processor-specific use HIPROC = 15, }; // Obtains the type part of [sym64.st_info]. // // Equivalent to the ELF64_ST_TYPE macro. export fn st_type(i: u8) stt = (i & 0xF): stt; // Converts symbol bindings and type into [sym64.st_info]. // // Equivalent to the ELF64_ST_INFO macro. export fn st_info(b: stb, t: stt) u8 = b: u8 << 4 + t: u8 & 0xF; // Relocation entry export type rel64 = struct { // Address of reference r_offset: u64, // Symbol table index and type of relocation r_info: u64, }; // Relocation entry with explicit addend export type rela64 = struct { // Address of reference r_offset: u64, // Symbol table index and type of relocation r_info: u64, // Constant part of expression r_addend: i64, }; // Obtains the symbol table index part of [rel64.r_info]. // // Equivalent to the ELF64_R_SYM macro. export fn r64_sym(info: u64) u64 = info >> 32; // Obtains the relocation type part of [rel64.r_info]. // // Equivalent to the ELF64_R_TYPE macro. export fn r64_type(info: u64) u64 = info & 0xFFFFFFFF; // Converts symbol table index and a relocation type into [rel64.r_info]. // // Equivalent to the ELF64_R_INFO macro. export fn r64_info(sym: u64, stype: u64) u64 = sym << 32 | stype & 0xFFFFFFFF; // Program header table entry (segment) export type phdr64 = struct { // Type of segment p_type: pt, // Segment attributes p_flags: u32, // Offset in file p_offset: u64, // Virtual address in memory p_vaddr: u64, // Reserved p_paddr: u64, // Size of segment in file p_filesz: u64, // Size of segment in memory p_memsz: u64, // Alignment of segment p_align: u64, }; // Segment types export type pt = enum u32 { // Unused entry NULL = 0, // Loadable segment LOAD = 1, // Dynamic linking tables DYNAMIC = 2, // Program interpreter path name INTERP = 3, // Note sections NOTE = 4, // Reserved SHLIB = 5, // Program header table PHDR = 6, // Environment-specific use LOOS = 0x60000000, // Environment-specific use HIOS = 0x6FFFFFFF, // Processor-specific use LOPROC = 0x70000000, // Processor-specific use HIPROC = 0x7FFFFFFF, }; // Segment attributes export type pf = enum u32 { // No permission NONE = 0, // Execute permission X = 0x1, // Write permission W = 0x2, // Read permission R = 0x4, // Reserved for environment-specific use MASKOS = 0x00FF0000, // Reserved for processor-specific use MASKPROC = 0xFF000000, }; // Dynamic table entry export type dyn64 = struct { // The type of this entry d_tag: dt, // Additional data associated with this entry. The value which is valid // is selected based on the entry type. union { d_val: u64, d_ptr: u64, }, }; // Dynamic table entry type export type dt = enum i64 { // Marks the end of the dynamic array. NULL = 0, // The string table offset of the name of a needed library. NEEDED = 1, // Total size, in bytes, of the relocation entries associated with the // procedure linkage table. PLTRELSZ = 2, // Contains an address associated with the linkage table. The specific // meaning of this field is processor-dependent. PLTGOT = 3, // Address of the symbol hash table. HASH = 4, // Address of the dynamic string table. STRTAB = 5, // Address of the dynamic symbol table. SYMTAB = 6, // Address of a relocation table with rela64 entries. RELA = 7, // Total size, in bytes, of the RELA relocation table. RELASZ = 8, // Size, in bytes, of each RELA relocation entry. RELAENT = 9, // Total size, in bytes, of the string table. STRSZ = 10, // Size, in bytes, of each symbol table entry. SYMENT = 11, // Address of the initialization function. INIT = 12, // Address of the termination function. FINI = 13, // The string table offset of the name of this shared object. SONAME = 14, // The string table offset of a shared library search path string. RPATH = 15, // The presence of this dynamic table entry modifies the symbol // resolution algorithm for references within the library. Symbols // defined within the library are used to resolve references before the // dynamic linker searches the usual search path. SYMBOLIC = 16, // Address of a relocation table with rel64 entries. REL = 17, // Total size, in bytes, of the REL relocation table. RELSZ = 18, // Size, in bytes, of each REL relocation entry. RELENT = 19, // Type of relocation entry used for the procedure linkage table. The // d_val member contains either [dt::REL] or [dt::RELA]. PLTREL = 20, // Reserved for debugger use. DEBUG = 21, // The presence of this dynamic table entry signals that the relocation // table contains relocations for a non-writable segment. TEXTREL = 22, // Address of the relocations associated with the procedure linkage // table. JMPREL = 23, // The presence of this dynamic table entry signals that the dynamic // loader should process all relocations for this object before // transferring control to the program. BIND_NOW = 24, // Pointer to an array of initialiation functions. INIT_ARRAY = 25, // Pointer to an array of termination functions. FINI_ARRAY = 26, // Size, in bytes, of the array of initialization functions. INIT_ARRAYSZ = 27, // Size, in bytes, of the array of termination functions. FINI_ARRAYSZ = 28, // Reserved for environment-specific use. LOOS = 0x60000000, // Symbol versioning entry types, GNU extension // Version table records // .gnu.version section address VERSYM = 0x6FFFFFF0, // .gnu.version_d section address VERDEF = 0x6FFFFFFC, // Number of version definitions VERDEFNUM = 0x6FFFFFFD, // .gnu.version_r section address VERNEED = 0x6FFFFFFE, // Number of needed versions VERNEEDNUM = 0x6FFFFFFF, // Reserved for environment-specific use. HIOS = 0x6FFFFFFF, // Reserved for processor-specific use. LOPROC = 0x70000000, // Reserved for processor-specific use. HIPROC = 0x7FFFFFFF, }; // Auxiliary vector export type auxv64 = struct { // Entry type a_type: at, union { // Integer value a_val: u64, a_ptr: *opaque, a_fnc: *fn() void, } }; // Legal auxiliary vector entry types export type at = enum u64 { // End of vector NULL = 0, // Entry should be ignored IGNORE = 1, // File descriptor of program EXECFD = 2, // Program headers for program PHDR = 3, // Size of program header entry PHENT = 4, // Number of program headers PHNUM = 5, // System page size PAGESZ = 6, // Base address of interpreter BASE = 7, // Flags FLAGS = 8, // Entry point of program ENTRY = 9, // Program is not ELF NOTELF = 10, // Real uid UID = 11, // Effective uid EUID = 12, // Real gid GID = 13, // Effective gid EGID = 14, // Frequency of times() CLKTCK = 17, // String identifying platform. PLATFORM = 15, // Machine-dependent hints about processor capabilities. HWCAP = 16, // Used FPU control word. FPUCW = 18, // Data cache block size. DCACHEBSIZE = 19, // Instruction cache block size. ICACHEBSIZE = 20, // Unified cache block size. UCACHEBSIZE = 21, // A special ignored value for PPC, used by the kernel to control the // interpretation of the AUXV. Must be > 16. // Entry should be ignored. IGNOREPPC = 22, // Boolean, was exec setuid-like? SECURE = 23, // String identifying real platforms. BASE_PLATFORM = 24, // Address of 16 random bytes. RANDOM = 25, // More machine-dependent hints about processor capabilities. HWCAP2 = 26, // Filename of executable. EXECFN = 31, // Pointer to the global system page used for system calls and other // nice things. SYSINFO = 32, SYSINFO_EHDR = 33, // Shapes of the caches. Bits 0-3 contains associativity, bits 4-7 contains // log2 of line size, mask those to get cache size. L1I_CACHESHAPE = 34, L1D_CACHESHAPE = 35, L2_CACHESHAPE = 36, L3_CACHESHAPE = 37, // Shapes of the caches, with more room to describe them. // *GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits // and the cache associativity in the next 16 bits. L1I_CACHESIZE = 40, L1I_CACHEGEOMETRY = 41, L1D_CACHESIZE = 42, L1D_CACHEGEOMETRY = 43, L2_CACHESIZE = 44, L2_CACHEGEOMETRY = 45, L3_CACHESIZE = 46, L3_CACHEGEOMETRY = 47, // Stack needed for signal delivery (AArch64). MINSIGSTKSZ = 51, }; // Version definition section export type verdef64 = struct { // Version revision vd_version: u16, // Version information vd_flags: u16, // Version Index vd_ndx: u16, // Number of associated aux entries vd_cnt: u16, // Version name hash value vd_hash: u32, // Offset in bytes to verdaux array vd_aux: u32, // Offset in bytes to next verdef entry vd_next: u32, }; // Auxiliary version information export type verdaux64 = struct { vda_name: u32, vda_next: u32, }; // Version revision values export type ver_def = enum u16 { NONE = 0, CURRENT = 1, NUM = 2, }; // Version information flags export type ver_flg = enum u16 { BASE = 0x1, WEAK = 0x2, }; // Versym index values export type ver_ndx = enum u16 { LOCAL = 0, GLOBAL = 1, LORESERVE = 0xff00, ELIMINATE = 0xff01, }; // DT_HASH section header export type hashhdr = struct { nbucket: u32, nchain: u32, }; hare-0.24.2/format/ini/000077500000000000000000000000001464473310100145705ustar00rootroot00000000000000hare-0.24.2/format/ini/+test.ha000066400000000000000000000037421464473310100161420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use memio; use strings; @test fn simple() void = { const buf = memio::fixed(strings::toutf8( "# This is a comment [sourcehut.org] name=Sourcehut description=The hacker's forge [harelang.org] name=Hare description=The Hare programming language")); const sc = scan(&buf); defer finish(&sc); // [sourcehut.org] ini_test(&sc, "sourcehut.org", "name", "Sourcehut"); ini_test(&sc, "sourcehut.org", "description", "The hacker's forge"); // [harelang.org] ini_test(&sc, "harelang.org", "name", "Hare"); ini_test(&sc, "harelang.org", "description", "The Hare programming language"); assert(next(&sc) is io::EOF); }; @test fn extended() void = { // TODO: expand? const buf = memio::fixed(strings::toutf8( "# Equal sign in the value exec=env VARIABLE=value binary # Unicode trademark=™ ")); const sc = scan(&buf); defer finish(&sc); ini_test(&sc, "", "exec", "env VARIABLE=value binary"); ini_test(&sc, "", "trademark", "™"); assert(next(&sc) is io::EOF); }; @test fn invalid() void = { // Missing equal sign const buf = memio::fixed(strings::toutf8("novalue\n")); const sc = scan(&buf); defer finish(&sc); assert(next(&sc) as error as syntaxerr == 1); // Unterminated section header const buf = memio::fixed(strings::toutf8("[dangling\n")); const sc = scan(&buf); defer finish(&sc); assert(next(&sc) as error as syntaxerr == 1); // Line numbering and recovery const buf = memio::fixed(strings::toutf8( "[a] b=c d=e [f] g=h i j=k ")); const sc = scan(&buf); defer finish(&sc); ini_test(&sc, "a", "b", "c"); ini_test(&sc, "a", "d", "e"); ini_test(&sc, "f", "g", "h"); assert(next(&sc) as error as syntaxerr == 7); ini_test(&sc, "f", "j", "k"); assert(next(&sc) is io::EOF); }; fn ini_test( sc: *scanner, section: const str, key: const str, value: const str, ) void = { const ent = next(sc)! as entry; assert(ent.0 == section); assert(ent.1 == key); assert(ent.2 == value); }; hare-0.24.2/format/ini/README000066400000000000000000000003061464473310100154470ustar00rootroot00000000000000format::ini provides a parser for DOS-style INI files: # This is a comment [harelang.org] name=Hare description=The Hare programming language [blablabla] key=value # Unicode trademark=™ hare-0.24.2/format/ini/scan.ha000066400000000000000000000036601464473310100160330ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use strings; export type scanner = struct { scan: bufio::scanner, lineno: size, section: str, }; // Creates an INI file scanner. Use [[next]] to read entries. The caller must // call [[finish]] once they're done with this object. export fn scan(in: io::handle) scanner = { return scanner { scan = bufio::newscanner(in), lineno = 1, ... }; }; // Frees resources associated with a [[scanner]]. export fn finish(sc: *scanner) void = { bufio::finish(&sc.scan); free(sc.section); }; // An entry in an INI file: (section, key, value). export type entry = (const str, const str, const str); // Duplicates an [[entry]]. Use [[entry_finish]] to get rid of it. export fn entry_dup(ent: entry) entry = ( strings::dup(ent.0), strings::dup(ent.1), strings::dup(ent.2), ); // Frees an [[entry]] previously duplicated with [[entry_dup]]. export fn entry_finish(ent: entry) void = { free(ent.0); free(ent.1); free(ent.2); }; // Returns the next entry from an INI file. The return value is borrowed from // the [[scanner]]. Use [[entry_dup]] to retain a copy. export fn next(sc: *scanner) (entry | io::EOF | error) = { for (const line => bufio::scan_line(&sc.scan)?) { defer sc.lineno += 1; const line = strings::trim(line); if (len(line) == 0 || strings::hasprefix(line, "#")) { continue; }; if (strings::hasprefix(line, "[")) { const end = match (strings::index(line, ']')) { case let idx: size => yield idx; case void => return sc.lineno: syntaxerr; }; free(sc.section); sc.section = strings::dup(strings::sub(line, 1, end)); continue; }; const eq = match (strings::index(line, '=')) { case let idx: size => yield idx; case void => return sc.lineno: syntaxerr; }; return ( sc.section, strings::sub(line, 0, eq), strings::sub(line, eq + 1, strings::end), ); }; return io::EOF; }; hare-0.24.2/format/ini/types.ha000066400000000000000000000012571464473310100162530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use fmt; use io; // A syntax error occurred during parsing. export type syntaxerr = !size; // Any error that may occur during parsing. export type error = !(io::error | utf8::invalid | syntaxerr); // Returns a user-friendly representation of [[error]]. The result may be // statically allocated. export fn strerror(err: error) const str = match (err) { case let err: io::error => return io::strerror(err); case utf8::invalid => return "File is invalid UTF-8"; case let s: syntaxerr => static let buf: [1024]u8 = [0...]; yield fmt::bsprintf(buf, "{}: Invalid syntax", s: size); }; hare-0.24.2/fs/000077500000000000000000000000001464473310100131315ustar00rootroot00000000000000hare-0.24.2/fs/README000066400000000000000000000004231464473310100140100ustar00rootroot00000000000000The fs module provides an abstracted interface for accessing an arbitrary filesystem. If you want to work with the host filesystem, you probably want to refer to the functions available in [[os::]] instead, which provides an implementation of [[fs]] for the host filesystem. hare-0.24.2/fs/fs.ha000066400000000000000000000235761464473310100140700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use path; use time; // Closes a filesystem. The fs cannot be used after this function is called. export fn close(fs: *fs) void = { match (fs.close) { case null => void; case let f: *closefunc => f(fs); }; }; // Opens a file. // // [[flag::CREATE]] isn't very useful with this function, since the new file's // mode is set to zero. For this use-case, use [[create]] instead. export fn open( fs: *fs, path: str, flags: flag = flag::RDONLY, ) (io::handle | error) = { match (fs.open) { case null => return errors::unsupported; case let f: *openfunc => return f(fs, path, flags); }; }; // Opens a file, as an [[io::file]]. This file will be backed by an open file // handle on the host operating system, which may not be possible with all // filesystem implementations (such cases will return [[io::unsupported]]). // // [[flag::CREATE]] isn't very useful with this function, since the new file's // mode is set to zero. For this use-case, use [[create_file]] instead. export fn open_file( fs: *fs, path: str, flags: flag = flag::RDONLY, ) (io::file | error) = { match (fs.openfile) { case null => return errors::unsupported; case let f: *openfilefunc => return f(fs, path, flags); }; }; // Creates a new file with the given mode if it doesn't already exist, and opens // it for writing. export fn create( fs: *fs, path: str, mode: mode, flags: flag = flag::WRONLY | flag::TRUNC, ) (io::handle | error) = { match (fs.create) { case null => return errors::unsupported; case let f: *createfunc => return f(fs, path, mode, flags); }; }; // Creates a new file with the given mode if it doesn't already exist, and opens // it as an [[io::file]] for writing. This file will be backed by an open file // handle on the host operating system, which may not be possible with all // filesystem implementations (such cases will return [[io::unsupported]]). export fn create_file( fs: *fs, path: str, mode: mode, flags: flag = flag::WRONLY | flag::TRUNC, ) (io::file | error) = { match (fs.createfile) { case null => return errors::unsupported; case let f: *createfilefunc => return f(fs, path, mode, flags); }; }; // Removes a file. export fn remove(fs: *fs, path: str) (void | error) = { match (fs.remove) { case null => return errors::unsupported; case let f: *removefunc => return f(fs, path); }; }; // Renames a file. This generally only works if the source and destination path // are both on the same filesystem. See [[move]] for an implementation which // falls back on a "copy & remove" procedure in this situation. export fn rename(fs: *fs, oldpath: str, newpath: str) (void | error) = { match (fs.rename) { case null => return errors::unsupported; case let f: *renamefunc => return f(fs, oldpath, newpath); }; }; // Moves a file. This will use [[rename]] if possible, and will fall back to // copy and remove if necessary. export fn move(fs: *fs, oldpath: str, newpath: str) (void | error) = { match (rename(fs, oldpath, newpath)) { case let err: error => match (err) { case (cannotrename | errors::unsupported) => void; // Fallback case => return err; }; case void => return; // Success }; // TODO: // - Move non-regular files let st = stat(fs, oldpath)?; assert(isfile(st.mode), "TODO: move non-regular files"); let old = open(fs, oldpath)?; let new = match (create(fs, newpath, st.mode)) { case let h: io::handle => yield h; case let err: error => io::close(old): void; return err; }; match (io::copy(new, old)) { case let err: io::error => io::close(new): void; io::close(old): void; remove(fs, newpath)?; return err; case size => void; }; io::close(new)?; io::close(old)?; remove(fs, oldpath)?; }; // Returns an iterator for a path, which yields the contents of a directory. // Pass empty string to yield from the root. The order in which entries are // returned is undefined. The return value must be finished with [[finish]]. export fn iter(fs: *fs, path: str) (*iterator | error) = { match (fs.iter) { case null => return errors::unsupported; case let f: *iterfunc => return f(fs, path); }; }; // Frees state associated with an [[iterator]]. export fn finish(iter: *iterator) void = { match (iter.finish) { case null => void; case let f: *finishfunc => return f(iter); }; }; // Obtains information about a file or directory. If the target is a symlink, // information is returned about the link, not its target. export fn stat(fs: *fs, path: str) (filestat | error) = { match (fs.stat) { case null => return errors::unsupported; case let f: *statfunc => return f(fs, path); }; }; // Obtains information about an [[io::file]]. export fn fstat(fs: *fs, fd: io::file) (filestat | error) = { match (fs.fstat) { case null => return errors::unsupported; case let f: *fstatfunc => return f(fs, fd); }; }; // Returns true if a node exists at the given path, or false if not. // // Note that testing for file existence before using the file can often lead to // race conditions. If possible, prefer to simply attempt to use the file (e.g. // via "open"), and handle the resulting error should the file not exist. export fn exists(fs: *fs, path: str) bool = { match (stat(fs, path)) { case filestat => return true; case error => return false; }; }; // Returns the path referred to by a symbolic link. The return value is // statically allocated and will be overwritten on subsequent calls. export fn readlink(fs: *fs, path: str) (str | error) = { match (fs.readlink) { case null => return errors::unsupported; case let f: *readlinkfunc => return f(fs, path); }; }; // Creates a directory. export fn mkdir(fs: *fs, path: str, mode: mode) (void | error) = { match (fs.mkdir) { case null => return errors::unsupported; case let f: *mkdirfunc => return f(fs, path, mode); }; }; // Makes a directory, and all non-extant directories in its path. export fn mkdirs(fs: *fs, path: str, mode: mode) (void | error) = { let parent = path::dirname(path); if (path != parent) { match (mkdirs(fs, parent, mode)) { case errors::exists => void; case void => void; case let err: error => return err; }; }; match (mkdir(fs, path, mode)) { case errors::exists => void; case void => void; case let err: error => return err; }; }; // Removes a directory. The target directory must be empty; see [[rmdirall]] to // remove its contents as well. export fn rmdir(fs: *fs, path: str) (void | error) = { if (path == "") { return errors::invalid; }; match (fs.rmdir) { case null => return errors::unsupported; case let f: *rmdirfunc => return f(fs, path); }; }; // Changes mode flags on a file or directory. export fn chmod(fs: *fs, path: str, mode: mode) (void | error) = { match (fs.chmod) { case null => return errors::unsupported; case let f: *chmodfunc => return f(fs, path, mode); }; }; // Changes mode flags on a [[io::file]]. export fn fchmod(fs: *fs, fd: io::file, mode: mode) (void | error) = { match (fs.fchmod) { case null => return errors::unsupported; case let f: *fchmodfunc => return f(fd, mode); }; }; // Changes ownership of a file. export fn chown(fs: *fs, path: str, uid: uint, gid: uint) (void | error) = { match (fs.chown) { case null => return errors::unsupported; case let f: *chownfunc => return f(fs, path, uid, gid); }; }; // Changes ownership of a [[io::file]]. export fn fchown(fs: *fs, fd: io::file, uid: uint, gid: uint) (void | error) = { match (fs.fchown) { case null => return errors::unsupported; case let f: *fchownfunc => return f(fd, uid, gid); }; }; // Changes the access and modification time of a file. A void value will leave // the corresponding time unchanged. export fn chtimes( fs: *fs, path: str, atime: (time::instant | void), mtime: (time::instant | void) ) (void | error) = { match (fs.chtimes) { case null => return errors::unsupported; case let f: *chtimesfunc => return f(fs, path, atime, mtime); }; }; // Changes the access and modification time of an [[io::file]]. A void value // will leave the corresponding time unchanged. export fn fchtimes( fs: *fs, fd: io::file, atime: (time::instant | void), mtime: (time::instant | void) ) (void | error) = { match (fs.fchtimes) { case null => return errors::unsupported; case let f: *fchtimesfunc => return f(fd, atime, mtime); }; }; // Resolves a path to its absolute, normalized value. Relative paths will be // rooted (if supported by the fs implementation), and "." and ".." components // will be reduced. This function does not follow symlinks; see [[realpath]] if // you need this behavior. The return value is statically allocated; use // [[strings::dup]] to extend its lifetime. export fn resolve(fs: *fs, path: str) str = { match (fs.resolve) { case null => void; case let f: *resolvefunc => return f(fs, path); }; static let buf = path::buffer { ... }; path::set(&buf, path)!; return path::string(&buf); }; // Creates a new (hard) link at 'new' for the file at 'old'. export fn link(fs: *fs, old: str, new: str) (void | error) = { match (fs.link) { case null => return errors::unsupported; case let f: *linkfunc => return f(fs, old, new); }; }; // Creates a new symbolic link at 'path' which points to 'target'. export fn symlink(fs: *fs, target: str, path: str) (void | error) = { match (fs.symlink) { case null => return errors::unsupported; case let f: *symlinkfunc => return f(fs, target, path); }; }; // Returns the next directory entry from an iterator, or done if none remain. // '.' and '..' are skipped. It is a programming error to call this again after // it has returned void. Calling this again after an error is safe. The list is // not guaranteed to be complete when an error has been returned. The file stat // returned may only have the type bits set on the file mode; callers should // call [[stat]] to obtain the detailed file mode. export fn next(iter: *iterator) (dirent | done | error) = iter.next(iter); hare-0.24.2/fs/types.ha000066400000000000000000000242331464473310100146130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use errors; use io; use strings; use time; // An entry of a particular type was sought, but is something else in practice. // For example, opening a file with [[iter]]. export type wrongtype = !void; // Returned from [[rename]] if this rename is not possible due to technical // constraints, such as if it would cause a file to move between filesystems. In // this situation, other operations (such as copy & remove) may succeed if // attempted. export type cannotrename = !void; // All possible fs error types. export type error = !( errors::noentry | errors::noaccess | errors::exists | errors::busy | errors::invalid | errors::unsupported | utf8::invalid | wrongtype | cannotrename | io::error); // Returns a human-friendly representation of an error. export fn strerror(err: error) const str = match (err) { case wrongtype => yield "Wrong entry type for requested operation"; case cannotrename => yield "Unable to perform rename operation (try move instead)"; case errors::noentry => yield "File or directory not found"; case errors::noaccess => yield "Permission denied"; case errors::exists => yield "File or directory exists"; case errors::invalid => yield "Invalid argument"; case errors::busy => yield "Device is busy"; case errors::unsupported => yield "Operation not supported"; case let err: utf8::invalid => yield utf8::strerror(err); case let err: io::error => yield io::strerror(err); }; // File mode information. These bits do not necessarily reflect the underlying // operating system's mode representation, though they were chosen to be // consistent with typical Unix file permissions. All implementations shall // support at least USER_RW, DIR, and REG. export type mode = enum uint { // Read, write, and execute permissions for the file owner USER_RWX = 0o700, // Read and write permissions for the file owner USER_RW = 0o600, // Read and execute permissions for the file owner USER_RX = 0o500, // Read permissions for the file owner USER_R = 0o400, // Write permissions for the file owner USER_W = 0o200, // Execute permissions for the file owner USER_X = 0o100, // Read, write, and execute permissions for group members GROUP_RWX = 0o070, // Read and write permissions for group members GROUP_RW = 0o060, // Read and execute permissions for group members GROUP_RX = 0o050, // Read permissions for group members GROUP_R = 0o040, // Write permissions for group members GROUP_W = 0o020, // Execute permissions for group members GROUP_X = 0o010, // Read, write, and execute permissions for other users OTHER_RWX = 0o007, // Read and write permissions for other users OTHER_RW = 0o006, // Read and execute permissions for other users OTHER_RX = 0o005, // Read permissions for other users OTHER_R = 0o004, // Write permissions for other users OTHER_W = 0o002, // Execute permissions for other users OTHER_X = 0o001, // Entry has the set-uid bit set SETUID = 0o4000, // Entry has the set-gid bit set SETGID = 0o2000, // Entry has the sticky bit set STICKY = 0o1000, // Entry is of an unknown type UNKNOWN = 0, // Entry is a FIFO (named pipe) FIFO = 0o010000, // Entry is a directory DIR = 0o040000, // Entry is a character device CHR = 0o020000, // Entry is a block device BLK = 0o060000, // Entry is a regular file REG = 0o100000, // Entry is a symbolic link LINK = 0o120000, // Entry is a Unix socket SOCK = 0o140000, }; // A mask defining what items are populated in the stat structure. export type stat_mask = enum uint { UID = 1 << 0, GID = 1 << 1, SIZE = 1 << 2, INODE = 1 << 3, ATIME = 1 << 4, MTIME = 1 << 5, CTIME = 1 << 6, }; // Information about a file or directory. The mask field defines what other // fields are set; mode is always set. export type filestat = struct { mask: stat_mask, mode: mode, uid: uint, gid: uint, sz: size, inode: u64, atime: time::instant, mtime: time::instant, ctime: time::instant, }; // An entry in a directory. This may be borrowed from the filesystem's internal // state. If you want to keep this around beyond one call to [[next]], use // [[dirent_dup]]. export type dirent = struct { // The name of this entry. Not fully qualified: for example, // "foo/bar/baz.txt" would store "baz.txt" here. name: str, // The type of this entry. The permission bits may be unset. ftype: mode, }; // Duplicates a [[dirent]] object. Call [[dirent_finish]] to get rid of it // later. export fn dirent_dup(e: *dirent) dirent = { let new = *e; new.name = strings::dup(e.name); return new; }; // Frees memory associated with a [[dirent]] object which was duplicated with // [[dirent_dup]]. export fn dirent_finish(e: *dirent) void = free(e.name); // Flags to use for opening a file. Not all operating systems support all flags; // at a minimum, RDONLY, WRONLY, RDWR, CREATE, and TRUNC will be supported. // Note that NOCTTY and CLOEXEC are on by default, and the CTTY/NOCLOEXEC flags // respectively disable them. export type flag = enum int { RDONLY = 0, WRONLY = 1, RDWR = 2, CREATE = 0o100, EXCL = 0o200, CTTY = 0o400, TRUNC = 0o1000, APPEND = 0o2000, NONBLOCK = 0o4000, DSYNC = 0o10000, SYNC = 0o4010000, RSYNC = 0o4010000, DIRECTORY = 0o200000, NOFOLLOW = 0o400000, NOATIME = 0o1000000, NOCLOEXEC = 0o2000000, PATH = 0o10000000, TMPFILE = 0o20200000, }; export type closefunc = fn(fs: *fs) void; export type removefunc = fn(fs: *fs, path: str) (void | error); export type renamefunc = fn(fs: *fs, oldpath: str, newpath: str) (void | error); export type iterfunc = fn(fs: *fs, path: str) (*iterator | error); export type statfunc = fn(fs: *fs, path: str) (filestat | error); export type fstatfunc = fn(fs: *fs, file: io::file) (filestat | error); export type mkdirfunc = fn(fs: *fs, path: str, mode: mode) (void | error); export type rmdirfunc = fn(fs: *fs, path: str) (void | error); export type chmodfunc = fn(fs: *fs, path: str, mode: mode) (void | error); export type fchmodfunc = fn(fd: io::file, mode: mode) (void | error); export type chownfunc = fn(fs: *fs, path: str, uid: uint, gid: uint) (void | error); export type fchownfunc = fn(fd: io::file, uid: uint, gid: uint) (void | error); export type chtimesfunc = fn(fs: *fs, path: str, atime: (time::instant | void), mtime: (time::instant | void)) (void | error); export type fchtimesfunc = fn(fd: io::file, atime: (time::instant | void), mtime: (time::instant | void)) (void | error); export type resolvefunc = fn(fs: *fs, path: str) str; export type readlinkfunc = fn(fs: *fs, path: str) (str | error); export type linkfunc = fn(fs: *fs, old: str, new: str) (void | error); export type symlinkfunc = fn(fs: *fs, target: str, path: str) (void | error); export type openfunc = fn( fs: *fs, path: str, flags: flag, ) (io::handle | error); export type openfilefunc = fn( fs: *fs, path: str, flags: flag, ) (io::file | error); export type createfunc = fn( fs: *fs, path: str, mode: mode, flags: flag, ) (io::handle | error); export type createfilefunc = fn( fs: *fs, path: str, mode: mode, flags: flag, ) (io::file | error); // An abstract implementation of a filesystem, which provides common filesystem // operations such as file creation and deletion, but which may be backed by any // underlying storage system. See [[os::cwd]] for access to the host filesystem. // // To create a custom filesystem implementation, embed this type as the first // member of a struct with user-specific data and fill out these fields as // appropriate. export type fs = struct { // Frees resources associated with this filesystem. close: nullable *closefunc, // Opens a file. open: nullable *openfunc, // Opens a file as an [[io::file]]. openfile: nullable *openfilefunc, // Creates a new file. create: nullable *createfunc, // Creates a new file as an [[io::file]]. createfile: nullable *createfilefunc, // Removes a file. remove: nullable *removefunc, // Renames a file. rename: nullable *renamefunc, // Returns an iterator for a path, which yields the contents of a // directory. Pass empty string to yield from the root. // // The iterator must return all entries without error. If an error would // occur, it should be identified here and returned upfront. iter: nullable *iterfunc, // Obtains information about a file or directory. If the target is a // symbolic link, information is returned about the link, not its // target. stat: nullable *statfunc, // Obtains information about an [[io::file]]. fstat: nullable *fstatfunc, // Returns the path referred to by a symbolic link. The caller will free // the return value. readlink: nullable *readlinkfunc, // Creates a directory. mkdir: nullable *mkdirfunc, // Removes a directory. The target directory must be empty. rmdir: nullable *rmdirfunc, // Changes mode flags on a file or directory. chmod: nullable *chmodfunc, // Changes mode flags on a [[io::file]]. fchmod: nullable *fchmodfunc, // Changes ownership of a file. chown: nullable *chownfunc, // Changes ownership of a [[io::file]]. fchown: nullable *fchownfunc, // Changes access and modification time of a file. chtimes: nullable *chtimesfunc, // Changes access and modification time of an [[io::file]]. fchtimes: nullable *fchtimesfunc, // Resolves a path to its absolute, normalized value. If the fs // implementation does not provide this, [resolve] presumes that // relative paths are rooted (i.e. "foo" == "/foo"). resolve: nullable *resolvefunc, // Creates a new (hard) link. link: nullable *linkfunc, // Creates a new symbolic link. symlink: nullable *symlinkfunc, }; // A function which returns the next directory from an [[iterator]]. export type nextfunc = fn(iter: *iterator) (dirent | done | error); // A function which frees state associated with an [[iterator]]. export type finishfunc = fn(iter: *iterator) void; // A directory iterator. To implement a directory iterator for a filesystem, // subtype this struct to store any necessary state and populate the pointers // with your implementation. export type iterator = struct { // Returns the next member of the directory, or done if there are none // remaining. next: *nextfunc, // Frees resources associated with the iterator. finish: nullable *finishfunc, }; hare-0.24.2/fs/util.ha000066400000000000000000000112371464473310100144240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use path; use strings; // Converts a mode into a Unix-like mode string (e.g. "-rw-r--r--"). The string // is statically allocated, use [[strings::dup]] to duplicate it or it will be // overwritten on subsequent calls. export fn mode_str(m: mode) const str = { static let buf: [10]u8 = [0...]; buf = [ (if (m & mode::DIR == mode::DIR) 'd' else if (m & mode::FIFO == mode::FIFO) 'p' else if (m & mode::SOCK == mode::SOCK) 's' else if (m & mode::BLK == mode::BLK) 'b' else if (m & mode::LINK == mode::LINK) 'l' else if (m & mode::CHR == mode::CHR) 'c' else '-'): u8, (if (m & mode::USER_R == mode::USER_R) 'r' else '-'): u8, (if (m & mode::USER_W == mode::USER_W) 'w' else '-'): u8, (if (m & mode::SETUID == mode::SETUID) 's' else if (m & mode::USER_X == mode::USER_X) 'x' else '-'): u8, (if (m & mode::GROUP_R == mode::GROUP_R) 'r' else '-'): u8, (if (m & mode::GROUP_W == mode::GROUP_W) 'w' else '-'): u8, (if (m & mode::SETGID == mode::SETGID) 's' else if (m & mode::GROUP_X == mode::GROUP_X) 'x' else '-'): u8, (if (m & mode::OTHER_R == mode::OTHER_R) 'r' else '-'): u8, (if (m & mode::OTHER_W == mode::OTHER_W) 'w' else '-'): u8, (if (m & mode::STICKY == mode::STICKY) 't' else if (m & mode::OTHER_X == mode::OTHER_X) 'x' else '-'): u8, ]; return strings::fromutf8(buf)!; }; @test fn mode_str() void = { assert(mode_str(0o777: mode) == "-rwxrwxrwx"); assert(mode_str(mode::DIR | 0o755: mode) == "drwxr-xr-x"); assert(mode_str(0o755: mode | mode::SETUID) == "-rwsr-xr-x"); assert(mode_str(0o644: mode) == "-rw-r--r--"); assert(mode_str(0: mode) == "----------"); }; // Returns the permission bits of a file mode. export fn mode_perm(m: mode) mode = (m: uint & 0o777u): mode; // Returns the type bits of a file mode. export fn mode_type(m: mode) mode = (m: uint & ~0o777u): mode; // bit mask for the file type bit field def IFMT: mode = 0o0170000u: mode; // Returns true if this item is a regular file. export fn isfile(mode: mode) bool = mode & IFMT == mode::REG; // Returns true if this item is a FIFO (named pipe). export fn isfifo(mode: mode) bool = mode & IFMT == mode::FIFO; // Returns true if this item is a directory. export fn isdir(mode: mode) bool = mode & IFMT == mode::DIR; // Returns true if this item is a character device. export fn ischdev(mode: mode) bool = mode & IFMT == mode::CHR; // Returns true if this item is a block device. export fn isblockdev(mode: mode) bool = mode & IFMT == mode::BLK; // Returns true if this item is a symbolic link. export fn islink(mode: mode) bool = mode & IFMT == mode::LINK; // Returns true if this item is a Unix socket. export fn issocket(mode: mode) bool = mode & IFMT == mode::SOCK; @test fn modes() void = { const foo = mode::LINK | 0o755: mode; assert(islink(foo)); assert(!isfile(foo)); }; // Reads all entries from a directory. The caller must free the return value // with [[dirents_free]]. export fn readdir(fs: *fs, path: str) ([]dirent | error) = { let i = iter(fs, path)?; defer finish(i); let ents: []dirent = []; for (let d => next(i)?) { append(ents, dirent_dup(&d)); }; return ents; }; // Frees a slice of [[dirent]]s. export fn dirents_free(dirents: []dirent) void = { for (let d &.. dirents) { dirent_finish(d); }; free(dirents); }; // Removes a directory, and anything in it. export fn rmdirall(fs: *fs, path: str) (void | error) = { let buf = path::init(path)!; return rmdirall_path(fs, &buf); }; fn rmdirall_path(fs: *fs, buf: *path::buffer) (void | error) = { let it = iter(fs, path::string(buf))?; defer finish(it); for (let ent => next(it)?) { path::push(buf, ent.name)!; switch (ent.ftype & mode::DIR) { case mode::DIR => rmdirall_path(fs, buf)?; case => remove(fs, path::string(buf))?; }; path::pop(buf); }; return rmdir(fs, path::string(buf)); }; // Canonicalizes a path in this filesystem by resolving all symlinks and // collapsing any "." or ".." path components. The return value is statically // allocated and will be overwritten on subsequent calls. export fn realpath(fs: *fs, path: str) (str | error) = { static let res = path::buffer { ... }; path::set(&res)!; static let pathbuf = path::buffer { ... }; path::set(&pathbuf, resolve(fs, path))!; const iter = path::iter(&pathbuf); for (let item => path::nextiter(&iter)) { const item = path::push(&res, item)!; const link = match (readlink(fs, item)) { case let link: str => yield link; case wrongtype => continue; case let err: error => return err; }; if (!path::abs(link)) { path::push(&res, "..", link)!; } else { path::set(&res, link)!; }; }; return path::string(&res); }; hare-0.24.2/getopt/000077500000000000000000000000001464473310100140235ustar00rootroot00000000000000hare-0.24.2/getopt/README000066400000000000000000000046601464473310100147110ustar00rootroot00000000000000getopt provides an interface for parsing command line arguments and automatically generates a brief help message explaining the command usage. See [[parse]] or [[tryparse]] for the main entry point. The caller provides [[help]] arguments to specify which command line flags and parameters are supported, and to provide some brief help text which describes their use. Provide [[flag_help]] to add a flag which does not take a parameter, and [[parameter_help]] to add a flag with a required parameter. The first [[cmd_help]] is used as a short, one-line summary of the command's purpose, and any later [[cmd_help]] arguments are used to provide the name of any arguments which follow the options list. By convention, the caller should sort the list of options, first providing all flags, then all parameters, alpha-sorted within each group by the flag rune. // Usage for sed const cmd = getopt::parse(os::args, "stream editor", ('E', "use extended regular expressions"), ('i', "edit files in place"), ('s', "treat files as separate, rather than one continuous stream"), ('z', "separate lines by NUL characters"), ('e', "script", "execute commands from script"), ('f', "file", "execute commands from a file"), "files...", ); defer getopt::finish(&cmd); for (let opt .. cmd.opts) { switch (opt.0) { case 'E' => extended = true; case 'i' => in_place = true; case 's' => continuous = false; case 'z' => sep = '\0'; case 'e' => script = opt.1; case 'f' => file = opt.1; case => abort(); // unreachable }; }; for (let arg .. cmd.args) { // ... }; If any non-option arguments are provided on the command line, the options list is terminated by the first non-option argument, or by a "--" argument if one is present. The arguments list is NOT reordered to accomodate for options which appear after other arguments. Overriding the behavior of "--" is not supported; providing '-' as a flag or parameter rune will have no effect. If "-h" is not among the options defined by the caller, the "-h" option will cause a summary of the command usage to be printed to [[os::stderr]] (see also [[printhelp]]), and [[os::exit]] will be called with [[os::status::SUCCESS]]. The help text is brief and should serve only as a reminder. It is recommended that your command line program be accompanied by a man page to provide detailed usage information. 'h' may be provided as a flag or parameter rune to override the default behavior. hare-0.24.2/getopt/getopts.ha000066400000000000000000000225501464473310100160260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use io; use os; use strings; // The result of parsing the set of command line arguments, including any // options specified and the list of non-option arguments. If a subcommand // is present in the help passed to [[parse]], then there will be no args. export type command = struct { opts: [](rune, str), subcmd: (void | (str, *command)), args: []str, help: []help, }; // Help text providing a short, one-line summary of the command; or providing // the name of an argument. export type cmd_help = str; // Help text for a flag, formatted as "-a: help text". export type flag_help = (rune, str); // Help text for a parameter, formatted as "-a param: help text" where "param" // is the first string and "help text" is the second string. export type parameter_help = (rune, str, str); // Definition of a named subcommand. export type subcmd_help = (str, []help); // Help text for a command or option. [[cmd_help]], [[flag_help]], and // [[parameter_help]] compose such that the following []help: // // [ // "foo bars in order", // ('a', "a help text"), // ('b', "b help text"), // ('c', "cflag", "c help text"), // ('d', "dflag", "d help text"), // "files...", // ] // // will produce this help text: // // foo: foo bars in order // // Usage: foo [-ab] [-c ] [-d ] files... // // -a: a help text // -b: b help text // -c : c help text // -d : d help text export type help = (cmd_help | flag_help | parameter_help | subcmd_help); export type requires_arg = rune; export type unknown_option = rune; export type unknown_subcmd = str; export type error = !( str, []help, (requires_arg | unknown_option | unknown_subcmd), ); // Converts a parsing error into a human-friendly string. The result may be // statically allocated. export fn strerror(err: error) str = { static let buf: [1024]u8 = [0...]; match (err.2) { case let r: requires_arg => return fmt::bsprintf(buf, "{}: option -{} requires an argument", err.0, r: rune); case let r: unknown_option => return fmt::bsprintf(buf, "{}: unrecognized option: -{}", err.0, r: rune); case let s: unknown_subcmd => return fmt::bsprintf(buf, "{}: unrecognized subcommand: {}", err.0, s: str); }; }; // A wrapper for [[tryparse]] in which if an error occurs, details are printed // to [[os::stderr]] (as in [[printusage]]), and [[os::exit]] is called with // [[os::status::FAILURE]]. export fn parse(args: []str, help: help...) command = { match (tryparse(args, help...)) { case let c: command => return c; case let e: error => fmt::errorln(strerror(e))!; if (e.2 is unknown_subcmd) { printsubcmds(os::stderr, e.1)!; fmt::errorln()!; }; printusage(os::stderr, e.0, e.1)!; os::exit(os::status::FAILURE); }; }; // Parses command line arguments and returns a [[command]], or an [[error]] // if an error occurs. The argument list must include the command name as // the first item; [[os::args]] fulfills this criteria. export fn tryparse(args: []str, help: help...) (command | error) = { let opts: [](rune, str) = []; let i = 1z; for :arg (i < len(args); i += 1) { const arg = args[i]; if (len(arg) == 0 || arg == "-" || !strings::hasprefix(arg, "-")) { break; }; if (arg == "--") { i += 1; break; }; let iter = strings::iter(arg); assert(strings::next(&iter) as rune == '-'); for (let r => strings::next(&iter)) { let found = false; for (let j = 0z; j < len(help); j += 1) match (help[j]) { case let f: flag_help => if (r == f.0) { append(opts, (r, "")); found = true; break; }; case let p: parameter_help => if (r == p.0) { let value = strings::iterstr(&iter); if (len(value) == 0) { if (i == len(args) - 1) { free(opts); return (args[0], help, r: requires_arg): error; }; i += 1; append(opts, (r, args[i])); } else { append(opts, (r, value)); }; continue :arg; }; case => continue; }; if (found) continue; if (r =='h') { printhelp(os::stderr, args[0], help)!; os::exit(os::status::SUCCESS); }; free(opts); return (args[0], help, r: unknown_option): error; }; }; let subcmd: (void | (str, *command)) = void; if (i < len(args)) { let expects_subcmd = false; for (let j = 0z; j < len(help); j += 1) match (help[j]) { case let s: subcmd_help => expects_subcmd = true; if (s.0 == args[i]) match (tryparse(args[i..], s.1...)) { case let c: command => subcmd = (s.0, alloc(c)); case let e: error => free(opts); return e; }; case => continue; }; if (expects_subcmd && subcmd is void) { free(opts); return (args[0], help, args[i]: unknown_subcmd): error; }; }; return command { opts = opts, subcmd = subcmd, args = if (subcmd is void) args[i..] else [], help = help, }; }; // Frees resources associated with the return value of [[parse]]. export fn finish(cmd: *command) void = { free(cmd.opts); match (cmd.subcmd) { case void => void; case let s: (str, *command) => finish(s.1); free(s.1); }; }; // Prints command usage to the provided stream. export fn printusage( out: io::handle, name: str, help: []help ) (void | io::error) = { let h = contains_h(help); let z = _printusage(io::empty, name, false, h, help)?; _printusage(out, name, if (z > 72) true else false, h, help)?; }; fn _printusage( out: io::handle, name: str, indent: bool, contains_h: bool, help: []help, ) (size | io::error) = { let z = fmt::fprint(out, "Usage:", name)?; let started_flags = false; if (!contains_h) { z += fmt::fprint(out, " [-h")?; started_flags = true; }; for (let h .. help) { match (h) { case let h: flag_help => if (!started_flags) { z += fmt::fprint(out, " [-")?; started_flags = true; }; z += fmt::fprint(out, h.0)?; case => void; }; }; if (started_flags) { z += fmt::fprint(out, "]")?; }; for (let h .. help) { match (h) { case let h: parameter_help => if (indent) { z += fmt::fprintf(out, "\n\t")?; }; z += fmt::fprintf(out, " [-{} <{}>]", h.0, h.1)?; case => void; }; }; let first_arg = true; for (let i = 1z; i < len(help); i += 1) if (help[i] is cmd_help) { if (first_arg) { if (indent) { z += fmt::fprintf(out, "\n\t")?; }; first_arg = false; }; z += fmt::fprintf(out, " {}", help[i] as cmd_help: str)?; }; return z + fmt::fprint(out, "\n")?; }; fn contains_h(help: []help) bool = { for (let h .. help) { const r = match (h) { case let h: flag_help => yield h.0; case let h: parameter_help => yield h.0; case => continue; }; if (r == 'h') { return true; }; }; return false; }; // Prints command help to the provided stream. export fn printhelp( out: io::handle, name: str, help: []help ) (void | io::error) = { if (len(help) == 0) { return; }; if (help[0] is cmd_help) { fmt::fprintfln(out, "{}: {}\n", name, help[0] as cmd_help: str)?; }; let contains_h = contains_h(help); let z = _printusage(io::empty, name, false, contains_h, help)?; _printusage(out, name, if (z > 72) true else false, contains_h, help)?; fmt::fprint(out, "\n")?; if (!contains_h) { fmt::fprintln(out, "-h: print this help text")?; }; for (let h .. help) { match (h) { case let f: flag_help => fmt::fprintfln(out, "-{}: {}", f.0, f.1)?; case let p: parameter_help => fmt::fprintfln(out, "-{} <{}>: {}", p.0, p.1, p.2)?; case => void; }; }; printsubcmds(out, help)?; }; fn printsubcmds(out: io::handle, help: []help) (void | io::error) = { let first = true; for (let h .. help) { match (h) { case let s: subcmd_help => // Only print this if there are subcommands to show if (first) { fmt::fprintln(out, "\nSubcommands:")?; first = false; }; if (len(s.1) == 0 || !(s.1[0] is cmd_help)) { fmt::fprintfln(out, " {}", s.0)?; } else { fmt::fprintfln(out, " {}: {}", s.0, s.1[0] as cmd_help: str)?; }; case => void; }; }; }; @test fn parse() void = { let args: []str = ["cat", "-v", "a.out"]; let cat = parse(args, "concatenate files", ('v', "cause Rob Pike to make a USENIX presentation"), "files...", ); defer finish(&cat); assert(len(cat.args) == 1 && cat.args[0] == "a.out"); assert(len(cat.opts) == 1 && cat.opts[0].0 == 'v' && cat.opts[0].1 == ""); args = ["ls", "-Fahs", "--", "-j"]; let ls = parse(args, "list files", ('F', "Do some stuff"), ('h', "Do some other stuff"), ('s', "Do a third type of stuff"), ('a', "Do a fourth type of stuff"), "files...", ); defer finish(&ls); assert(len(ls.args) == 1 && ls.args[0] == "-j"); assert(len(ls.opts) == 4); assert(ls.opts[0].0 == 'F' && ls.opts[0].1 == ""); assert(ls.opts[1].0 == 'a' && ls.opts[1].1 == ""); assert(ls.opts[2].0 == 'h' && ls.opts[2].1 == ""); assert(ls.opts[3].0 == 's' && ls.opts[3].1 == ""); args = ["sed", "-e", "s/C++//g", "-f/tmp/turing.sed", "-"]; let sed = parse(args, "edit streams", ('e', "script", "Add the editing commands specified by the " "script option to the end of the script of editing " "commands"), ('f', "script_file", "Add the editing commands in the file " "script_file to the end of the script of editing " "commands"), "files...", ); defer finish(&sed); assert(len(sed.args) == 1 && sed.args[0] == "-"); assert(len(sed.opts) == 2); assert(sed.opts[0].0 == 'e' && sed.opts[0].1 == "s/C++//g"); assert(sed.opts[1].0 == 'f' && sed.opts[1].1 == "/tmp/turing.sed"); }; hare-0.24.2/glob/000077500000000000000000000000001464473310100134445ustar00rootroot00000000000000hare-0.24.2/glob/+test.ha000066400000000000000000000057111464473310100150140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fnmatch; use strings; @test fn glob() void = { const cases: [_](str, flag) = [ ("/u??/*in/a*", flag::NONE), ("/u*r/l?[bc]*/[bg]*", flag::NOSORT), ("/?sr/[sb]in/*[[:digit:]]*", flag::MARK), ("/h??\\e/*/.*", flag::NOSORT | flag::MARK), ("/\\h??e/*/.*", flag::NOSORT | flag::NOESCAPE), ("/r*/*", flag::NOSORT), ("/*.?a", flag::NOCHECK), ("./*.[[:alpha:]]a", flag::NONE), ("./\\a[bd]c", flag::NOESCAPE), ("./\\a[be]c", flag::NONE), ("[[:punct:]]*", flag::NONE), ("/", flag::NONE), ("//", flag::NONE), (".", flag::NONE), ("..", flag::NONE), ("\\*", flag::NONE), ]; for (let c .. cases) { let gen = glob(c.0, c.1); defer finish(&gen); for (true) match (next(&gen)) { case done => break; case failure => continue; case let s: str => let bs = fnmatch::flag::PATHNAME; if (c.1 & flag::NOESCAPE != 0) { bs |= fnmatch::flag::NOESCAPE; }; assert(fnmatch::fnmatch(c.0, s, bs) || c.1 & flag::MARK != 0 && fnmatch::fnmatch( c.0, strings::rtrim(s, '/'), bs ) ); }; }; }; @test fn pattern_parse() void = { const cases: [_](str, bool, str, str, str) = [ ("foo/bar/baz", true, "foo/bar/baz", "", ""), ("foo/b\\ar/baz", true, "foo/b\\ar/baz", "", ""), ("foo/b\\ar/baz", false, "foo/bar/baz", "", ""), ("/foo/bar/baz", true, "/foo/bar/baz", "", ""), ("/foo\\/bar/baz", true, "/foo\\/bar/baz", "", ""), ("/foo\\/bar/baz", false, "/foo/bar/baz", "", ""), ("/foo/bar\\/baz", true, "/foo/bar\\/baz", "", ""), ("/foo/bar\\/baz", false, "/foo/bar/baz", "", ""), ("/foobarbaz", true, "/foobarbaz", "", ""), ("foo/bar/baz/", true, "foo/bar/baz/", "", ""), ("foobarbaz/", true, "foobarbaz/", "", ""), ("foobarbaz", true, "foobarbaz", "", ""), ("foo/b?r/baz", true, "foo/", "b?r/", "baz"), ("foo/b?r\\/baz", true, "foo/", "b?r\\/", "baz"), ("foo/b?r\\/baz", false, "foo/", "b?r/", "baz"), ("foob*rbaz/", true, "", "foob*rbaz/", ""), ("foo[bar]baz", true, "", "foo[bar]baz", ""), ("foo/b[ar]/baz/", true, "foo/", "b[ar]/", "baz/"), ("foo/b[a\\r]/baz/", false, "foo/", "b[a\\r]/", "baz/"), ("foo/b[a\\r]/baz/", true, "foo/", "b[a\\r]/", "baz/"), ("foo/b[ar]/baz\\/", true, "foo/", "b[ar]/", "baz\\/"), ("foo/b[ar]/baz\\/", false, "foo/", "b[ar]/", "baz\\/"), ("foo/b\\[ar]/baz\\/", true, "foo/", "b\\[ar]/", "baz\\/"), ("foo/b\\[ar]/baz\\/", false, "foo/b[ar]/baz/", "", ""), ("fo[o/ba[r/baz", true, "fo[o/ba[r/baz", "", ""), ("fo]o/bar/b[az", false, "fo]o/bar/b[az", "", ""), ("foo/ba]r/b]az", true, "foo/ba]r/b]az", "", ""), ("foo/ba[r/b]az", false, "foo/ba[r/", "b]az", ""), ("fo[o/bar/b]az", true, "fo[o/bar/", "b]az", ""), ]; let p = pattern_init(); defer pattern_free(&p); for (let c .. cases) { pattern_parse(&p, c.0, c.1); const dir = pattern_dir(&p); const pat = pattern_pat(&p); const rem = pattern_rem(&p); assert(dir == c.2); assert(pat == c.3); assert(rem == c.4); }; }; hare-0.24.2/glob/README000066400000000000000000000002631464473310100143250ustar00rootroot00000000000000The glob module provides an implementation of file globbing compatible with the behavior described by POSIX. https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html hare-0.24.2/glob/glob.ha000066400000000000000000000166641464473310100147160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use fnmatch; use fs; use io; use memio; use os; use path; use sort; use strings; // Flags used to control the behavior of [[next]]. export type flag = enum uint { NONE = 0, // Slash appending is enabled. A slash character is appended to each // pathname that is a directory that matches the pattern. MARK = 1, // If the pattern does not match any pathname, the pattern string is // returned. NOCHECK = 1 << 1, // Backslash escaping is disabled. A backslash character is treated as // an ordinary character. NOESCAPE = 1 << 2, // Pathname sorting is disabled. The order of pathnames returned is // unspecified. NOSORT = 1 << 3, }; export type generator = struct { pats: strstack, matc: size, flgs: flag, tmpp: pattern, }; export type strstack = struct { bufv: []memio::stream, bufc: size, }; export type pattern = struct { // TODO: look into working with a couple of string iterators instead dir: memio::stream, pat: memio::stream, rem: memio::stream, }; // Information about an unsuccessful search. export type failure = !struct { // The path that cannot be opened or read. path: str, // The actual filesystem error. error: fs::error, }; // Converts an error info a human-friendly string. The result is statically // allocated. export fn strerror(err: failure) str = { static let buf: [path::MAX + 1024]u8 = [0...]; return fmt::bsprintf(buf, "{}: {}", err.path, fs::strerror(err.error)); }; // Returns a generator of pathnames matching a pattern. The result must be // freed using [[finish]]. export fn glob(pattern: str, flags: flag = flag::NONE) generator = { let ss = strstack_init(); memio::concat(strstack_push(&ss), pattern)!; return generator { pats = ss, matc = 0, flgs = flags, tmpp = pattern_init(), }; }; // Frees all memory allocated by the generator. export fn finish(gen: *generator) void = { strstack_free(&gen.pats); pattern_free(&gen.tmpp); }; // Returns a generated pathname. The returned string is valid until [[next]] // is called again. If, during the search, a directory is encountered that // cannot be opened or read, a [[failure]] object is returned instead. // [[next]] can be repeatedly called until void is returned. export fn next(gen: *generator) (str | done | failure) = { const init = strstack_size(&gen.pats) == 1 && len(memio::string(&gen.tmpp.dir)!) == 0 && len(memio::string(&gen.tmpp.pat)!) == 0 && len(memio::string(&gen.tmpp.rem)!) == 0; match (next_match(gen)?) { case let s: str => return s; case void => void; }; if (init && gen.flgs & flag::NOCHECK != 0) { return memio::string(&gen.pats.bufv[0])!; }; return done; }; fn next_match(gen: *generator) (str | void | failure) = { match (strstack_pop(&gen.pats)) { case void => return; case let s: str => if (gen.matc > 0) { gen.matc -= 1; return s; }; pattern_parse(&gen.tmpp, s, gen.flgs & flag::NOESCAPE != 0); }; const l = strstack_size(&gen.pats); const dir = pattern_dir(&gen.tmpp); let pat = pattern_pat(&gen.tmpp); if (pat == "") { assert(pattern_rem(&gen.tmpp) == ""); return if (os::exists(dir)) dir else void; }; const patm = strings::hassuffix(pat, '/'); if (patm) { pat = strings::sub(pat, 0, len(pat) - 1); }; const rem = pattern_rem(&gen.tmpp); let flgs = fnmatch::flag::PERIOD; if (gen.flgs & flag::NOESCAPE != 0) { flgs |= fnmatch::flag::NOESCAPE; }; let it = match(os::iter(if (len(dir) > 0) dir else ".")) { case let i: *fs::iterator => yield i; case let e: fs::error => return failure { path = dir, error = e, }; }; defer fs::finish(it); for (true) match (fs::next(it)) { case done => break; case let de: fs::dirent => if (patm && !fs::isdir(de.ftype) && !fs::islink(de.ftype)) { continue; }; if (!fnmatch::fnmatch(pat, de.name, flgs)) { continue; }; let b = strstack_push(&gen.pats); if (len(rem) > 0) { memio::concat(b, dir, de.name, "/", rem)!; continue; }; memio::concat(b, dir, de.name)!; if (patm || gen.flgs & flag::MARK != 0) { let m = fs::isdir(de.ftype); // POSIX does not specify the behavior when a pathname // that matches the pattern is a symlink to a // directory. But in major implementation a slash // character is appended in this case. if (fs::islink(de.ftype)) { match (os::realpath(memio::string(b)!)) { case let r: str => match (os::stat(r)) { case let s: fs::filestat => m = fs::isdir(s.mode); case fs::error => void; }; case fs::error => void; }; }; if (m) { memio::concat(b, "/")!; } else if (patm) { strstack_pop(&gen.pats); continue; }; }; gen.matc += 1; case let e: fs::error => return failure { path = dir, error = e, }; }; if (gen.flgs & flag::NOSORT == 0) { strstack_sort(&gen.pats, l); }; return next_match(gen); }; fn pattern_init() pattern = pattern { dir = memio::dynamic(), pat = memio::dynamic(), rem = memio::dynamic(), }; fn pattern_free(p: *pattern) void = { io::close(&p.dir)!; io::close(&p.pat)!; io::close(&p.rem)!; }; fn pattern_reset(p: *pattern) void = { memio::reset(&p.dir); memio::reset(&p.pat); memio::reset(&p.rem); }; fn pattern_dir(p: *pattern) str = memio::string(&p.dir)!; fn pattern_pat(p: *pattern) str = memio::string(&p.pat)!; fn pattern_rem(p: *pattern) str = memio::string(&p.rem)!; fn pattern_parse(p: *pattern, pstr: str, noesc: bool) void = { pattern_reset(p); let itdir = strings::iter(pstr); let itpat = itdir; // p.dir is the longest directory name which contains no special // characters. for (let brk = false, esc = false; true) { const r = match (strings::next(&itdir)) { case done => memio::concat(&p.dir, memio::string(&p.pat)!)!; memio::reset(&p.pat); return; case let r: rune => yield r; }; if (!esc) switch (r) { case '*', '?' => break; case '[' => brk = true; case ']' => if (brk) { break; }; case '\\' => if (!noesc) { esc = true; continue; }; case => void; }; memio::appendrune(&p.pat, r)!; if (r == '/') { memio::concat(&p.dir, memio::string(&p.pat)!)!; memio::reset(&p.pat); itpat = itdir; }; esc = false; }; // p.pat is the first path component which contains special // characters. memio::reset(&p.pat); let esc = false; for (let r => strings::next(&itpat)) { if (!esc && r == '\\' && !noesc) { esc = true; continue; }; if (esc && r != '/') { memio::appendrune(&p.pat, '\\')!; }; memio::appendrune(&p.pat, r)!; if (r == '/') { break; }; esc = false; }; memio::concat(&p.rem, strings::iterstr(&itpat))!; }; fn strstack_init() strstack = strstack { bufv = [], bufc = 0, }; fn strstack_free(ss: *strstack) void = { for (let stream &.. ss.bufv) { io::close(stream)!; }; free(ss.bufv); }; fn strstack_size(ss: *strstack) size = ss.bufc; fn strstack_push(ss: *strstack) *memio::stream = { if (ss.bufc == len(ss.bufv)) { append(ss.bufv, memio::dynamic()); }; let b = &ss.bufv[ss.bufc]; memio::reset(b); ss.bufc += 1; return b; }; fn strstack_pop(ss: *strstack) (str | void) = { if (ss.bufc == 0) { return; }; ss.bufc -= 1; return memio::string(&ss.bufv[ss.bufc])!; }; fn strstack_sort(ss: *strstack, pos: size) void = { if (pos > ss.bufc) { return; }; let s = ss.bufv[pos..ss.bufc]; sort::sort(s, size(memio::stream), &bufcmp); }; fn bufcmp(a: const *opaque, b: const *opaque) int = strings::compare( memio::string(b: *memio::stream)!, memio::string(a: *memio::stream)!, ); hare-0.24.2/hare/000077500000000000000000000000001464473310100134405ustar00rootroot00000000000000hare-0.24.2/hare/README000066400000000000000000000002031464473310100143130ustar00rootroot00000000000000The hare namespace provides various modules which can be used to work with Hare code itself (how meta). The modules available are: hare-0.24.2/hare/ast/000077500000000000000000000000001464473310100142275ustar00rootroot00000000000000hare-0.24.2/hare/ast/README000066400000000000000000000000721464473310100151060ustar00rootroot00000000000000hare::ast provides an abstract syntax tree for Hare code. hare-0.24.2/hare/ast/decl.ha000066400000000000000000000041411464473310100154500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::lex; // A constant declaration. // // def foo: int = 0; export type decl_const = struct { ident: ident, _type: nullable *_type, init: *expr, }; // A global declaration. // // let foo: int = 0; // const foo: int = 0; export type decl_global = struct { is_const: bool, is_threadlocal: bool, symbol: str, ident: ident, _type: nullable *_type, init: nullable *expr, }; // A type declaration. // // type foo = int; export type decl_type = struct { ident: ident, _type: *_type, }; // Attributes applicable to a function declaration. export type fndecl_attr = enum { NONE, FINI, INIT, TEST, }; // A function declaration. // // fn main() void = void; export type decl_func = struct { symbol: str, ident: ident, prototype: *_type, body: nullable *expr, attrs: fndecl_attr, }; // A Hare declaration. export type decl = struct { exported: bool, start: lex::location, end: lex::location, decl: ([]decl_const | []decl_global | []decl_type | decl_func | assert_expr), // Only valid if the lexer has comments enabled docs: str, }; // Frees resources associated with a declaration. export fn decl_finish(d: decl) void = { free(d.docs); match (d.decl) { case let g: []decl_global => for (let i = 0z; i < len(g); i += 1) { free(g[i].symbol); ident_free(g[i].ident); type_finish(g[i]._type); free(g[i]._type); expr_finish(g[i].init); free(g[i].init); }; free(g); case let t: []decl_type => for (let i = 0z; i < len(t); i += 1) { ident_free(t[i].ident); type_finish(t[i]._type); free(t[i]._type); }; free(t); case let f: decl_func => free(f.symbol); ident_free(f.ident); type_finish(f.prototype); free(f.prototype); expr_finish(f.body); free(f.body); case let c: []decl_const => for (let i = 0z; i < len(c); i += 1) { ident_free(c[i].ident); type_finish(c[i]._type); free(c[i]._type); expr_finish(c[i].init); free(c[i].init); }; free(c); case let e: assert_expr => expr_finish(e.cond); free(e.cond); expr_finish(e.message); free(e.message); }; }; hare-0.24.2/hare/ast/expr.ha000066400000000000000000000327301464473310100155240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::lex; // An identifier access expression. // // foo export type access_identifier = ident; // An index access expression. // // foo[0] export type access_index = struct { object: *expr, index: *expr, }; // A struct field access expression. // // foo.bar export type access_field = struct { object: *expr, field: str, }; // A tuple field access expression. // // foo.1 export type access_tuple = struct { object: *expr, value: *expr, }; // An access expression. export type access_expr = (access_identifier | access_index | access_field | access_tuple); // An align expression. // // align(int) export type align_expr = *_type; // The form of an allocation expression. // // alloc(foo) // OBJECT // alloc(foo...) // COPY export type alloc_form = enum { OBJECT, COPY, }; // An allocation expression. // // alloc(foo) // alloc(foo...) // alloc(foo, bar) export type alloc_expr = struct { init: *expr, form: alloc_form, capacity: nullable *expr, }; // An append expression. // // append(foo, bar); // append(foo, bar...); // append(foo, [0...], bar); export type append_expr = struct { object: *expr, value: *expr, length: nullable *expr, variadic: bool, is_static: bool, }; // An assertion expression. // // assert(foo) // assert(foo, "error") // abort() // abort("error") export type assert_expr = struct { cond: nullable *expr, message: nullable *expr, is_static: bool, }; // An assignment expression. // // foo = bar export type assign_expr = struct { op: (binarithm_op | void), object: *expr, value: *expr, }; // A binary arithmetic operator export type binarithm_op = enum { // TODO: Rehome this with the checked AST? BAND, // & BOR, // | DIV, // / GT, // > GTEQ, // >= LAND, // && LEQUAL, // == LESS, // < LESSEQ, // <= LOR, // || LSHIFT, // << LXOR, // ^^ MINUS, // - MODULO, // % NEQUAL, // != PLUS, // + RSHIFT, // >> TIMES, // * BXOR, // ^ }; // A binary arithmetic expression. // // foo * bar export type binarithm_expr = struct { op: binarithm_op, lvalue: *expr, rvalue: *expr, }; // A single variable biding. // // foo: int = bar // (foo, foo2): int = bar export type binding = struct { name: (str | binding_unpack), _type: nullable *_type, init: *expr, }; // Tuple unpacking binding. // // (foo, _, bar) export type binding_unpack = [](str | void); // The kind of binding expression being used. export type binding_kind = enum { CONST, DEF, LET, }; // A variable binding expression. // // let foo: int = bar, ... export type binding_expr = struct { is_static: bool, kind: binding_kind, bindings: []binding, }; // A break expression. The label is set to empty string if absent. // // break :label export type break_expr = label; // A function call expression. // // foo(bar) export type call_expr = struct { lvalue: *expr, variadic: bool, args: []*expr, }; // The kind of cast expression being used. export type cast_kind = enum { // TODO: Should this be rehomed with the checked AST? CAST, ASSERTION, TEST, }; // A cast expression. // // foo: int // foo as int // foo is int export type cast_expr = struct { kind: cast_kind, value: *expr, _type: *_type, }; // A compound expression. // // { // foo; // bar; // // ... // } export type compound_expr = struct { exprs: []*expr, label: label, }; // An array literal. // // [foo, bar, ...] export type array_literal = struct { expand: bool, values: []*expr, }; // A single struct field and value. // // foo: int = 10 export type struct_value = struct { name: str, _type: nullable *_type, init: *expr, }; // A struct literal. // // struct { foo: int = bar, struct { baz = quux }, ... } export type struct_literal = struct { autofill: bool, alias: ident, // [] for anonymous fields: [](struct_value | *struct_literal), }; // A tuple literal. // // (foo, bar, ...) export type tuple_literal = []*expr; // The value "null". export type _null = void; // A scalar value. export type value = (bool | done | _null | str | rune | void); // An integer or float literal. export type number_literal = struct { suff: lex::ltok, value: (i64 | u64 | f64), sign: bool, // true if negative, false otherwise }; // A literal expression. export type literal_expr = (value | array_literal | number_literal | struct_literal | tuple_literal); // A continue expression. The label is set to empty string if absent. // // continue :label export type continue_expr = label; // A deferred expression. // // defer foo export type defer_expr = *expr; // A delete expression. // // delete(foo[10]) // delete(foo[4..42]) export type delete_expr = struct { object: *expr, is_static: bool, }; // The kind of for expression being used. export type for_kind = enum { ACCUMULATOR, EACH_VALUE, EACH_POINTER, ITERATOR, }; // A for loop. // // for (let foo = 0; foo < bar; baz) quux // for (let line => next_line()) quux // for (let number .. [1, 2, 3]) quux // for (let ptr &.. [1, 2, 3]) quux export type for_expr = struct { kind: for_kind, bindings: nullable *expr, cond: nullable *expr, afterthought: nullable *expr, body: *expr, label: label, }; // A free expression. // // free(foo) export type free_expr = *expr; // An if or if..else expression. // // if (foo) bar else baz export type if_expr = struct { cond: *expr, tbranch: *expr, fbranch: nullable *expr, }; // An insert expression. // // insert(foo[0], bar); // insert(foo[0], bar...); // insert(foo[0], [0...], bar); export type insert_expr = append_expr; // :label. The ":" character is not included. export type label = str; // A length expression. // // len(foo) export type len_expr = *expr; // A match case. // // case type => exprs // case let name: type => exprs export type match_case = struct { name: str, _type: nullable *_type, // null for default case exprs: []*expr, }; // A match expression. // // match (foo) { case int => bar; ... } export type match_expr = struct { value: *expr, cases: []match_case, label: label, }; // An offset expression. // // offset(foo.bar) export type offset_expr = *expr; // An error propagation expression. // // foo? export type propagate_expr = *expr; // An error assertion expression. // // foo! export type error_assert_expr = *expr; // A return statement. // // return foo export type return_expr = nullable *expr; // A size expression. // // size(int) export type size_expr = *_type; // A slicing expression. // // foo[bar..baz] export type slice_expr = struct { object: *expr, start: nullable *expr, end: nullable *expr, }; // A switch case. // // case value => exprs export type switch_case = struct { options: []*expr, // [] for default case exprs: []*expr, }; // A switch expression. // // switch (foo) { case bar => baz; ... } export type switch_expr = struct { value: *expr, cases: []switch_case, label: label, }; // A unary operator export type unarithm_op = enum { // TODO: Should this be rehomed with the checked AST? ADDR, // & BNOT, // ~ DEREF, // * LNOT, // ! MINUS, // - }; // A unary arithmetic expression. // // !example export type unarithm_expr = struct { op: unarithm_op, operand: *expr, }; // A vastart expression. // // vastart() export type vastart_expr = void; // A vaarg expression. // // vaarg(ap) export type vaarg_expr = *expr; // A vaend expression. // // vaend(ap) export type vaend_expr = *expr; // A C-style variadic expression. export type variadic_expr = (vastart_expr | vaarg_expr | vaend_expr); // A yield expression. // // yield foo export type yield_expr = struct { label: label, value: nullable *expr, }; // A Hare expression. export type expr = struct { start: lex::location, end: lex::location, expr: (access_expr | align_expr | alloc_expr | append_expr | assert_expr | assign_expr | binarithm_expr | binding_expr | break_expr | call_expr | cast_expr | literal_expr | continue_expr | defer_expr | delete_expr | for_expr | free_expr | error_assert_expr | if_expr | insert_expr | compound_expr | match_expr | len_expr | size_expr | offset_expr | propagate_expr | return_expr | slice_expr | switch_expr | unarithm_expr | variadic_expr | yield_expr), }; // Frees resources associated with a Hare [[expr]]ession. export fn expr_finish(e: nullable *expr) void = match (e) { case null => void; case let e: *expr => match (e.expr) { case let a: access_expr => match (a) { case let i: access_identifier => ident_free(i); case let i: access_index => expr_finish(i.object); free(i.object); expr_finish(i.index); free(i.index); case let f: access_field => expr_finish(f.object); free(f.object); free(f.field); case let t: access_tuple => expr_finish(t.object); free(t.object); expr_finish(t.value); free(t.value); }; case let a: align_expr => type_finish(a); free(a); case let a: alloc_expr => expr_finish(a.init); free(a.init); expr_finish(a.capacity); free(a.capacity); case let a: append_expr => expr_finish(a.object); free(a.object); expr_finish(a.value); free(a.value); expr_finish(a.length); free(a.length); case let a: assert_expr => expr_finish(a.cond); free(a.cond); expr_finish(a.message); free(a.message); case let a: assign_expr => expr_finish(a.object); free(a.object); expr_finish(a.value); free(a.value); case let b: binarithm_expr => expr_finish(b.lvalue); free(b.lvalue); expr_finish(b.rvalue); free(b.rvalue); case let b: binding_expr => for (let i = 0z; i < len(b.bindings); i += 1) { match (b.bindings[i].name) { case let s: str => free(s); case let u: binding_unpack => for (let i = 0z; i < len(u); i += 1) { match (u[i]) { case let s: str => free(s); case => void; }; }; free(u); }; type_finish(b.bindings[i]._type); free(b.bindings[i]._type); expr_finish(b.bindings[i].init); free(b.bindings[i].init); }; free(b.bindings); case let b: break_expr => free(b); case let c: call_expr => expr_finish(c.lvalue); free(c.lvalue); for (let i = 0z; i < len(c.args); i += 1) { expr_finish(c.args[i]); free(c.args[i]); }; free(c.args); case let c: cast_expr => expr_finish(c.value); free(c.value); type_finish(c._type); free(c._type); case let c: compound_expr => for (let i = 0z; i < len(c.exprs); i += 1) { expr_finish(c.exprs[i]); free(c.exprs[i]); }; free(c.exprs); free(c.label); case let c: literal_expr => match (c) { case let a: array_literal => for (let i = 0z; i < len(a.values); i += 1) { expr_finish(a.values[i]); free(a.values[i]); }; free(a.values); case let s: struct_literal => struct_literal_finish(&s); case let t: tuple_literal => for (let i = 0z; i < len(t); i += 1) { expr_finish(t[i]); free(t[i]); }; free(t); case (value | number_literal) => void; }; case let c: continue_expr => free(c); case let d: defer_expr => expr_finish(d); free(d); case let d: delete_expr => expr_finish(d.object); free(d.object); case let e: error_assert_expr => expr_finish(e); free(e); case let f: for_expr => expr_finish(f.bindings); free(f.bindings); expr_finish(f.cond); free(f.cond); expr_finish(f.afterthought); free(f.afterthought); expr_finish(f.body); free(f.body); case let f: free_expr => expr_finish(f); free(f); case let i: if_expr => expr_finish(i.cond); free(i.cond); expr_finish(i.tbranch); free(i.tbranch); expr_finish(i.fbranch); free(i.fbranch); case let e: insert_expr => expr_finish(e.object); free(e.object); expr_finish(e.value); free(e.value); expr_finish(e.length); free(e.length); case let l: len_expr => expr_finish(l); free(l); case let m: match_expr => free(m.label); expr_finish(m.value); free(m.value); for (let i = 0z; i < len(m.cases); i += 1) { free(m.cases[i].name); type_finish(m.cases[i]._type); free(m.cases[i]._type); const exprs = m.cases[i].exprs; for (let i = 0z; i < len(exprs); i += 1) { expr_finish(exprs[i]); free(exprs[i]); }; free(exprs); }; free(m.cases); case let o: offset_expr => expr_finish(o); free(o); case let p: propagate_expr => expr_finish(p); free(p); case let r: return_expr => expr_finish(r); free(r); case let s: size_expr => type_finish(s); free(s); case let s: slice_expr => expr_finish(s.object); free(s.object); expr_finish(s.start); free(s.start); expr_finish(s.end); free(s.end); case let s: switch_expr => free(s.label); expr_finish(s.value); free(s.value); for (let i = 0z; i < len(s.cases); i += 1) { let opts = s.cases[i].options; for (let j = 0z; j < len(opts); j += 1) { expr_finish(opts[j]); free(opts[j]); }; free(opts); let exprs = s.cases[i].exprs; for (let j = 0z; j < len(exprs); j += 1) { expr_finish(exprs[j]); free(exprs[j]); }; free(exprs); }; free(s.cases); case let u: unarithm_expr => expr_finish(u.operand); free(u.operand); case let v: variadic_expr => match (v) { case vastart_expr => void; case let v: vaarg_expr => expr_finish(v); free(v); case let v: vaend_expr => expr_finish(v); free(v); }; case let y: yield_expr => free(y.label); expr_finish(y.value); free(y.value); }; }; fn struct_literal_finish(s: *struct_literal) void = { ident_free(s.alias); for (let i = 0z; i < len(s.fields); i += 1) { match (s.fields[i]) { case let v: struct_value => free(v.name); type_finish(v._type); free(v._type); expr_finish(v.init); free(v.init); case let c: *struct_literal => struct_literal_finish(c); free(c); }; }; free(s.fields); }; hare-0.24.2/hare/ast/ident.ha000066400000000000000000000015051464473310100156450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; // Identifies a single object, e.g. foo::bar::baz. export type ident = []str; // Maximum length of an identifier, as the sum of the lengths of its parts plus // one for each namespace deliniation. // // In other words, the length of "a::b::c" is 5. export def IDENT_MAX: size = 255; // Frees resources associated with an [[ident]]ifier. export fn ident_free(ident: ident) void = strings::freeall(ident); // Returns true if two [[ident]]s are identical. export fn ident_eq(a: ident, b: ident) bool = { if (len(a) != len(b)) { return false; }; for (let i = 0z; i < len(a); i += 1) { if (a[i] != b[i]) { return false; }; }; return true; }; // Duplicates an [[ident]]. export fn ident_dup(id: ident) ident = strings::dupall(id); hare-0.24.2/hare/ast/import.ha000066400000000000000000000022041464473310100160510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::lex; use strings; // An imported module. // // use foo; // use foo = bar; // use foo::{bar, baz}; // use foo::*; export type import = struct { start: lex::location, end: lex::location, ident: ident, bindings: (void | import_alias | import_members | import_wildcard), }; // An import alias. // // use foo = bar; export type import_alias = str; // An import members list. // // use foo::{bar, baz}; export type import_members = []str; // An import wildcard. // // use foo::*; export type import_wildcard = void; // Frees resources associated with an [[import]]. export fn import_finish(import: import) void = { ident_free(import.ident); match (import.bindings) { case let alias: import_alias => free(alias); case let objects: import_members => strings::freeall(objects); case => void; }; }; // Frees resources associated with each [[import]] in a slice, and then // frees the slice itself. export fn imports_finish(imports: []import) void = { for (let i = 0z; i < len(imports); i += 1) { import_finish(imports[i]); }; free(imports); }; hare-0.24.2/hare/ast/type.ha000066400000000000000000000110411464473310100155170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::lex; // A type alias. export type alias_type = struct { unwrap: bool, ident: ident, }; // A built-in primitive type (int, bool, str, etc). export type builtin_type = enum { BOOL, DONE, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VALIST, VOID, }; // An enumeration field (and optional value). export type enum_field = struct { name: str, value: nullable *expr, loc: lex::location, docs: str, }; // enum { FOO = 0, BAR, ... } export type enum_type = struct { storage: builtin_type, values: []enum_field, }; // The variadism strategy for a function type. export type variadism = enum { NONE, C, HARE, }; // A parameter to a function type. export type func_param = struct { loc: lex::location, name: str, _type: *_type, default_value: (void | expr), }; // fn(foo: int, baz: int...) int export type func_type = struct { result: *_type, variadism: variadism, params: []func_param, }; // The length for a list type which is a slice (e.g. []int). export type len_slice = void; // The length for a list type which is unbounded (e.g. [*]int). export type len_unbounded = void; // The length for a list type which is inferred from context (e.g. [_]int). export type len_contextual = void; // []int, [*]int, [_]int, [foo]int export type list_type = struct { length: (*expr | len_slice | len_unbounded | len_contextual), members: *_type, }; // Flags which apply to a pointer type. export type pointer_flag = enum uint { NONE = 0, NULLABLE = 1 << 0, }; // *int export type pointer_type = struct { referent: *_type, flags: pointer_flag, }; // A single field of a struct type. export type struct_field = struct { name: str, _type: *_type, }; // An embedded struct type. export type struct_embedded = *_type; // An embedded type alias. export type struct_alias = ident; // struct { @offset(10) foo: int, struct { bar: int }, baz::quux } export type struct_member = struct { _offset: nullable *expr, member: (struct_field | struct_embedded | struct_alias), // Only valid if the lexer has comments enabled docs: str, }; // struct { ... } export type struct_type = struct { packed: bool, members: []struct_member, }; // union { ... } export type union_type = []struct_member; export type struct_union_type = (struct_type | union_type); // (int | bool) export type tagged_type = []*_type; // (int, bool, ...) export type tuple_type = []*_type; // Flags which apply to types. export type type_flag = enum uint { NONE = 0, CONST = 1 << 0, ERROR = 1 << 1, }; // A Hare type. export type _type = struct { start: lex::location, end: lex::location, flags: type_flag, repr: (alias_type | builtin_type | enum_type | func_type | list_type | pointer_type | struct_type | union_type | tagged_type | tuple_type), }; fn struct_members_free(membs: []struct_member) void = { for (let i = 0z; i < len(membs); i += 1) { free(membs[i].docs); expr_finish(membs[i]._offset); free(membs[i]._offset); match (membs[i].member) { case let f: struct_field => free(f.name); type_finish(f._type); free(f._type); case let e: struct_embedded => type_finish(e); free(e); case let a: struct_alias => ident_free(a); }; }; free(membs); }; // Frees resources associated with a [[_type]]. export fn type_finish(t: nullable *_type) void = match (t) { case null => void; case let t: *_type => match (t.repr) { case let a: alias_type => ident_free(a.ident); case builtin_type => void; case let e: enum_type => for (let i = 0z; i < len(e.values); i += 1) { free(e.values[i].name); expr_finish(e.values[i].value); free(e.values[i].value); }; free(e.values); case let f: func_type => type_finish(f.result); free(f.result); for (let i = 0z; i < len(f.params); i += 1) { free(f.params[i].name); type_finish(f.params[i]._type); free(f.params[i]._type); }; free(f.params); case let l: list_type => match (l.length) { case let e: *expr => expr_finish(e); free(e); case => void; }; type_finish(l.members); free(l.members); case let p: pointer_type => type_finish(p.referent); free(p.referent); case let s: struct_type => struct_members_free(s.members); case let t: tagged_type => for (let i = 0z; i < len(t); i += 1) { type_finish(t[i]); free(t[i]); }; free(t); case let t: tuple_type => for (let i = 0z; i < len(t); i += 1) { type_finish(t[i]); free(t[i]); }; free(t); case let u: union_type => struct_members_free(u); }; }; hare-0.24.2/hare/ast/unit.ha000066400000000000000000000006571464473310100155300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A sub-unit, typically representing a single source file. export type subunit = struct { imports: []import, decls: []decl, }; // Frees resources associated with a [[subunit]]. export fn subunit_finish(u: subunit) void = { imports_finish(u.imports); for (let i = 0z; i < len(u.decls); i += 1) { decl_finish(u.decls[i]); }; free(u.decls); }; hare-0.24.2/hare/lex/000077500000000000000000000000001464473310100142305ustar00rootroot00000000000000hare-0.24.2/hare/lex/+test.ha000066400000000000000000000353511464473310100156030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use io; use memio; use strings; fn initbuf(in: []u8, flags: flag = flag::NONE) lexer = { static let buf: [256]u8 = [0...]; static let s = memio::stream { stream = null: io::stream, ... }; static let sc = bufio::scanner { stream = null: io::stream, src = 0, ... }; s = memio::fixed(in); sc = bufio::newscanner_static(&s, buf); return init(&sc, "", flags); }; fn initstr(in: str, flags: flag = flag::NONE) lexer = { return initbuf(strings::toutf8(in), flags); }; @test fn unlex() void = { let sc = bufio::newscanner_static(io::empty, []); let lexer = init(&sc, ""); unlex(&lexer, (ltok::IF, void, location { path = "", line = 1234, col = 1234, })); let t = lex(&lexer) as token; assert(t.0 == ltok::IF); assert(t.1 is void); assert(t.2.path == ""); assert(t.2.line == 1234 && t.2.col == 1234); }; fn vassert(expected: value, actual: value) void = { match (expected) { case let expected: str => assert(actual as str == expected); case let expected: rune => assert(actual as rune == expected); case let expected: u64 => assert(actual as u64 == expected); case let expected: f64 => assert(actual as f64 == expected); case void => assert(actual is void); }; }; fn lextest(in: str, expected: []token) void = { let lexer = initstr(in); for (let i = 0z; i < len(expected); i += 1) { let etok = expected[i]; let tl = match (lex(&lexer)) { case let tl: token => yield tl; case let err: error => fmt::errorfln("{}: {}", i, strerror(err))!; abort(); }; if (tl.0 != etok.0) { fmt::errorfln("Expected {}, got {}", tokstr(etok), tokstr(tl))!; }; assert(tl.0 == etok.0); vassert(tl.1, etok.1); if (tl.2.line != etok.2.line || tl.2.col != etok.2.col || tl.2.path != etok.2.path) { fmt::errorfln("{}:{}:{} != {}:{}:{}", tl.2.path, tl.2.line, tl.2.col, etok.2.path, etok.2.line, etok.2.col)!; abort(); }; }; let t = lex(&lexer) as token; assert(t.0 == ltok::EOF); }; fn loc(line: uint, col: uint) location = location { path = "", line = line, col = col, }; @test fn lex1() void = { const in = "~,{[(}]);"; const expected: [_]token = [ (ltok::BNOT, void, loc(1, 1)), (ltok::COMMA, void, loc(1, 2)), (ltok::LBRACE, void, loc(1, 3)), (ltok::LBRACKET, void, loc(1, 4)), (ltok::LPAREN, void, loc(1, 5)), (ltok::RBRACE, void, loc(1, 6)), (ltok::RBRACKET, void, loc(1, 7)), (ltok::RPAREN, void, loc(1, 8)), (ltok::SEMICOLON, void, loc(1, 9)), ]; lextest(in, expected); }; @test fn lex2() void = { // Ends with = to test =, EOF const in = "* *= % %= + += - -= : :: = == / /= ="; const expected: [_]token = [ (ltok::TIMES, void, loc(1, 1)), (ltok::TIMESEQ, void, loc(1, 3)), (ltok::MODULO, void, loc(1, 6)), (ltok::MODEQ, void, loc(1, 8)), (ltok::PLUS, void, loc(1, 11)), (ltok::PLUSEQ, void, loc(1, 13)), (ltok::MINUS, void, loc(1, 16)), (ltok::MINUSEQ, void, loc(1, 18)), (ltok::COLON, void, loc(1, 21)), (ltok::DOUBLE_COLON, void, loc(1, 23)), (ltok::EQUAL, void, loc(1, 26)), (ltok::LEQUAL, void, loc(1, 28)), (ltok::DIV, void, loc(1, 31)), (ltok::DIVEQ, void, loc(1, 33)), (ltok::EQUAL, void, loc(1, 36)), ]; lextest(in, expected); }; @test fn lex3() void = { const in = ". .. ... < << <= <<= > >> >= >>= >>"; const expected: [_]token = [ (ltok::DOT, void, loc(1, 1)), (ltok::DOUBLE_DOT, void, loc(1, 3)), (ltok::ELLIPSIS, void, loc(1, 6)), (ltok::LESS, void, loc(1, 10)), (ltok::LSHIFT, void, loc(1, 12)), (ltok::LESSEQ, void, loc(1, 15)), (ltok::LSHIFTEQ, void, loc(1, 18)), (ltok::GT, void, loc(1, 22)), (ltok::RSHIFT, void, loc(1, 24)), (ltok::GTEQ, void, loc(1, 27)), (ltok::RSHIFTEQ, void, loc(1, 30)), (ltok::RSHIFT, void, loc(1, 34)), ]; lextest(in, expected); const in = "& && &= &&= | || |= ||= ^ ^^ ^= ^^= ^"; const expected: [_]token = [ (ltok::BAND, void, loc(1, 1)), (ltok::LAND, void, loc(1, 3)), (ltok::BANDEQ, void, loc(1, 6)), (ltok::LANDEQ, void, loc(1, 9)), (ltok::BOR, void, loc(1, 13)), (ltok::LOR, void, loc(1, 15)), (ltok::BOREQ, void, loc(1, 18)), (ltok::LOREQ, void, loc(1, 21)), (ltok::BXOR, void, loc(1, 25)), (ltok::LXOR, void, loc(1, 27)), (ltok::BXOREQ, void, loc(1, 30)), (ltok::LXOREQ, void, loc(1, 33)), (ltok::BXOR, void, loc(1, 37)), ]; lextest(in, expected); }; @test fn lexname() void = { const in = "hello world return void foobar :foobaz"; const expected: [_]token = [ (ltok::NAME, "hello", loc(1, 1)), (ltok::NAME, "world", loc(1, 7)), (ltok::RETURN, void, loc(1, 13)), (ltok::VOID, void, loc(1, 20)), (ltok::NAME, "foobar", loc(1, 25)), (ltok::COLON, void, loc(1, 32)), (ltok::NAME, "foobaz", loc(1, 33)), ]; lextest(in, expected); }; @test fn keywords() void = { let keywords = bmap[..ltok::LAST_KEYWORD+1]; for (let i = 0z; i < len(keywords); i += 1) { let lexer = initstr(keywords[i]); let tok = lex(&lexer) as token; assert(tok.0 == i: ltok); }; }; @test fn comments() void = { const in = "hello world // foo\nbar"; const expected: [_]token = [ (ltok::NAME, "hello", loc(1, 1)), (ltok::NAME, "world", loc(1, 7)), (ltok::NAME, "bar", loc(2, 1)), ]; lextest(in, expected); let lexer = initstr("// foo\n// bar\nhello world// baz\n\n// bad\ntest", flag::COMMENTS); assert(lex(&lexer) is token); assert(comment(&lexer) == " foo\n bar\n"); assert(lex(&lexer) is token); assert(comment(&lexer) == " baz\n"); assert(lex(&lexer) is token); assert(comment(&lexer) == " bad\n"); }; @test fn runes() void = { const in = "'a' 'b' '\\a' '\\b' '\\f' '\\n' '\\r' '\\t' '\\v' '\\0' " "'\\\\' '\\\'' '\\x0A' '\\u1234' '\\U0010abcd'"; const expected: [_]token = [ (ltok::LIT_RCONST, 'a', loc(1, 1)), (ltok::LIT_RCONST, 'b', loc(1, 5)), (ltok::LIT_RCONST, '\a', loc(1, 9)), (ltok::LIT_RCONST, '\b', loc(1, 14)), (ltok::LIT_RCONST, '\f', loc(1, 19)), (ltok::LIT_RCONST, '\n', loc(1, 24)), (ltok::LIT_RCONST, '\r', loc(1, 29)), (ltok::LIT_RCONST, '\t', loc(1, 34)), (ltok::LIT_RCONST, '\v', loc(1, 39)), (ltok::LIT_RCONST, '\0', loc(1, 44)), (ltok::LIT_RCONST, '\\', loc(1, 49)), (ltok::LIT_RCONST, '\'', loc(1, 54)), (ltok::LIT_RCONST, '\x0A', loc(1, 59)), (ltok::LIT_RCONST, '\u1234', loc(1, 66)), (ltok::LIT_RCONST, '\U0010abcd', loc(1, 75)), ]; lextest(in, expected); }; @test fn strings() void = { const in = `"a" "b" "\a" "\b" "\f" "\n" "\r" "\t" "\v" "\0" "\\" "\'"`; const expected: [_]token = [ (ltok::LIT_STR, "ab\a\b\f\n\r\t\v\0\\\'", loc(1, 1)), ]; lextest(in, expected); const in = `"ab\a\b\f\n\r\t\v\0\\\'"`; const expected: [_]token = [ (ltok::LIT_STR, "ab\a\b\f\n\r\t\v\0\\\'", loc(1, 1)), ]; lextest(in, expected); const in = `"hello world", "こんにちは", "return", "foo"`; const expected: [_]token = [ (ltok::LIT_STR, "hello world", loc(1, 1)), (ltok::COMMA, void, loc(1, 14)), (ltok::LIT_STR, "こんにちは", loc(1, 16)), (ltok::COMMA, void, loc(1, 23)), (ltok::LIT_STR, "return", loc(1, 25)), (ltok::COMMA, void, loc(1, 33)), (ltok::LIT_STR, "foo", loc(1, 35)), ]; lextest(in, expected); const in = "\"foo\"\n" "// bar\n" "\"baz\""; const expected: [_]token = [ (ltok::LIT_STR, "foobaz", loc(1, 1)), ]; lextest(in, expected); const in = `"\x7f" "\x1b" "\uabcd" "\U0010abcd"`; const expected: [_]token = [ (ltok::LIT_STR, "\x7f\x1b\uabcd\U0010abcd", loc(1, 1)), ]; lextest(in, expected); }; @test fn literals() void = { const in = "1e5 -1i32 9223372036854775809 1e2z 255u8 0o42u16\n" "0b1000101u32 0xDEADBEEFu64 -0b10i8 -5e0i16 -0o16i32\n" "0b00000010000001100000011100001111000000100000011000000111i64\n" "13.37 13.37f32 13.37f64 6.022e23 1.616255e-35f64 1e-1 0x1p-2"; const expected: [_]token = [ (ltok::LIT_ICONST, 1e5u64, loc(1, 1)), (ltok::MINUS, void, loc(1, 5)), (ltok::LIT_I32, 1u64, loc(1, 6)), (ltok::LIT_ICONST, 9223372036854775809u64, loc(1, 11)), (ltok::LIT_SIZE, 1e2u64, loc(1, 31)), (ltok::LIT_U8, 255u64, loc(1, 36)), (ltok::LIT_U16, 0o42u64, loc(1, 42)), (ltok::LIT_U32, 0b1000101u64, loc(2, 1)), (ltok::LIT_U64, 0xDEADBEEFu64, loc(2, 14)), (ltok::MINUS, void, loc(2, 28)), (ltok::LIT_I8, 0b10u64, loc(2, 29)), (ltok::MINUS, void, loc(2, 36)), (ltok::LIT_I16, 5e0u64, loc(2, 37)), (ltok::MINUS, void, loc(2, 44)), (ltok::LIT_I32, 0o16u64, loc(2, 45)), (ltok::LIT_I64, 0b00000010000001100000011100001111000000100000011000000111u64, loc(3, 1)), (ltok::LIT_FCONST, 13.37, loc(4, 1)), (ltok::LIT_F32, 13.37, loc(4, 7)), (ltok::LIT_F64, 13.37, loc(4, 16)), (ltok::LIT_FCONST, 6.022e23, loc(4, 25)), (ltok::LIT_F64, 1.616255e-35, loc(4, 34)), (ltok::LIT_FCONST, 1e-1, loc(4, 50)), (ltok::LIT_FCONST, 0x1p-2, loc(4, 55)), ]; lextest(in, expected); }; @test fn literals_underscores() void = { const in = "1_0e5 -1_0i32 9_223_372_036_854_775_809 1_0e2z 2_55u8 0o4_2u16\n" "0b100_0101u32 0xDE_AD_BE_EFu64 -0b1_0i8 -5_0e0i16 -0o1_6i32\n" "0b0000_0010_0000_0110_0000_0111_0000_1111_0000_0010_0000_0110_0000_0111i64\n" "1_3.3_7 1_3.3_7f32 1_3.3_7f64 6.0_2_2e23 1.6_1_6_2_5_5e-35f64 1_0e-1 0x0_1p-2"; const expected: [_]token = [ (ltok::LIT_ICONST, 10e5u64, loc(1, 1)), (ltok::MINUS, void, loc(1, 7)), (ltok::LIT_I32, 10u64, loc(1, 8)), (ltok::LIT_ICONST, 9223372036854775809u64, loc(1, 15)), (ltok::LIT_SIZE, 10e2u64, loc(1, 41)), (ltok::LIT_U8, 255u64, loc(1, 48)), (ltok::LIT_U16, 0o42u64, loc(1, 55)), (ltok::LIT_U32, 0b1000101u64, loc(2, 1)), (ltok::LIT_U64, 0xDEADBEEFu64, loc(2, 15)), (ltok::MINUS, void, loc(2, 32)), (ltok::LIT_I8, 0b10u64, loc(2, 33)), (ltok::MINUS, void, loc(2, 41)), (ltok::LIT_I16, 50e0u64, loc(2, 42)), (ltok::MINUS, void, loc(2, 51)), (ltok::LIT_I32, 0o16u64, loc(2, 52)), (ltok::LIT_I64, 0b00000010000001100000011100001111000000100000011000000111u64, loc(3, 1)), (ltok::LIT_FCONST, 13.37, loc(4, 1)), (ltok::LIT_F32, 13.37, loc(4, 9)), (ltok::LIT_F64, 13.37, loc(4, 20)), (ltok::LIT_FCONST, 6.022e23, loc(4, 31)), (ltok::LIT_F64, 1.616255e-35, loc(4, 42)), (ltok::LIT_FCONST, 10e-1, loc(4, 63)), (ltok::LIT_FCONST, 0x1p-2, loc(4, 70)), ]; lextest(in, expected); }; @test fn invalid() void = { // Using \x80 within a string literal will cause this to output an // empty string let lexer = initbuf(['1', 0x80]); const s = lex(&lexer) as error as syntax; assert(s.1 == "Source file is not valid UTF-8"); // Regression: invalid UTF-8 at the beginning of a token used to cause // a crash in nextw let lexer = initbuf([0x80]); const s = lex(&lexer) as error as syntax; assert(s.1 == "Source file is not valid UTF-8"); const invalid_tokens: [](str, str) = [ // Regression: invalid escape sequences such as "\^" used to // cause a crash (`"\^"`, "unknown escape sequence"), // Regression: e followed by another token used to cause a // crash ("0e)", "expected exponent"), // Invalid digit separators ("1_", "Expected digit after separator"), ("100_", "Expected digit after separator"), ("1_000_", "Expected digit after separator"), ("1__0", "Expected digit after separator"), ("1__000_0", "Expected digit after separator"), ("1_000__0", "Expected digit after separator"), ("1___0", "Expected digit after separator"), ("2e_8", "Exponents may not contain separators"), ("2_e8", "Expected digit after separator"), ("2e8_", "Exponents may not contain separators"), ("3e1__1", "Exponents may not contain separators"), ("2e+_5", "Exponents may not contain separators"), ("2e_+5", "Exponents may not contain separators"), ("0x_FFFF", "Expected integer literal"), ("0b_1010", "Expected integer literal"), ("0b1111_0000_", "Expected digit after separator"), ("0o6__6", "Expected digit after separator"), ("0_b1010", "Expected digit after separator"), ("0_o77", "Expected digit after separator"), ("0_xFF", "Expected digit after separator"), ("2e1_6", "Exponents may not contain separators"), ("0x2p1_0", "Exponents may not contain separators"), ("2e-1_0", "Exponents may not contain separators"), ("100u3_2", "Suffixes may not contain separators"), ("100u32_", "Suffixes may not contain separators"), ("100u_32", "Suffixes may not contain separators"), ("100_u32", "Expected digit after separator"), ]; for (const invalid_token .. invalid_tokens) { let lexer = initstr(invalid_token.0); const s = lex(&lexer) as error as syntax; assert(s.1 == invalid_token.1); }; }; // Small virtual machine for testing mkloc/prevloc. // NEXT, UNGET, LEX, and UNLEX call the obvious functions (with UNGET and UNLEX // pulling from a buffer that NEXT/LEX feed into). // After each instruction, the results of mkloc/prevloc are checked against the // next element of the test vector. type op = enum { LEX, NEXT, UNGET, UNLEX, }; @test fn loc() void = { let lexer = initstr("h ello: my name is\nInigo Montoya."); const ops: [_]op = [ op::NEXT, op::NEXT, op::NEXT, op::UNGET, op::UNGET, op::NEXT, op::NEXT, op::LEX, op::LEX, op::UNLEX, op::LEX, op::LEX, op::UNLEX, op::LEX, op::LEX, op::LEX, op::LEX, ]; const vector: [_](location, location) = [ (loc(1, 2), loc(1, 1)), (loc(1, 3), loc(1, 2)), (loc(1, 9), loc(1, 3)), (loc(1, 3), loc(1, 2)), (loc(1, 2), loc(1, 1)), (loc(1, 3), loc(1, 2)), (loc(1, 9), loc(1, 3)), (loc(1, 13), loc(1, 12)), (loc(1, 14), loc(1, 13)), (loc(1, 13), loc(1, 12)), (loc(1, 14), loc(1, 13)), (loc(1, 17), loc(1, 16)), (loc(1, 14), loc(1, 13)), (loc(1, 17), loc(1, 16)), (loc(1, 29), loc(1, 28)), (loc(1, 32), loc(1, 31)), (loc(2, 6), loc(2, 5)), (loc(2, 14), loc(2, 13)), ]; // We could statically allocate r and t, but what's the point let r: [](rune, location) = []; defer free(r); let t: []token = []; defer free(t); for (let i = 0z; i < len(ops); i += 1) { switch (ops[i]) { case op::LEX => append(t, lex(&lexer)!); case op::NEXT => append(r, next(&lexer) as (rune, location)); case op::UNGET => unget(&lexer, r[len(r) - 1].0); delete(r[len(r) - 1]); case op::UNLEX => unlex(&lexer, t[len(t) - 1]); delete(t[len(t) - 1]); }; let loc = mkloc(&lexer); let ploc = prevloc(&lexer); assert(loc.path == vector[i].0.path && loc.line == vector[i].0.line && loc.col == vector[i].0.col); assert(ploc.path == vector[i].1.path && ploc.line == vector[i].1.line && ploc.col == vector[i].1.col); }; }; @test fn access_tuple() void = { const in = "((0, 1), 2).0.1"; const expected: []token = [ (ltok::LPAREN, void, loc(1, 1)), (ltok::LPAREN, void, loc(1, 2)), (ltok::LIT_ICONST, 0, loc(1, 3)), (ltok::COMMA, void, loc(1, 4)), (ltok::LIT_ICONST, 1, loc(1, 6)), (ltok::RPAREN, void, loc(1, 7)), (ltok::COMMA, void, loc(1, 8)), (ltok::LIT_ICONST, 2, loc(1, 10)), (ltok::RPAREN, void, loc(1, 11)), (ltok::DOT, void, loc(1, 12)), (ltok::LIT_ICONST, 0, loc(1, 13)), (ltok::DOT, void, loc(1, 14)), (ltok::LIT_ICONST, 1, loc(1, 15)), ]; lextest(in, expected); }; hare-0.24.2/hare/lex/README000066400000000000000000000003131464473310100151050ustar00rootroot00000000000000hare::lex provides a lexer for Hare source code. A lexer takes an [[io::handle]] and returns a series of Hare [[token]]s. See the Hare specification for more details: https://harelang.org/specification hare-0.24.2/hare/lex/lex.ha000066400000000000000000000472411464473310100153420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bufio; use encoding::utf8; use fmt; use io; use memio; use path; use sort; use sort::cmp; use strconv; use strings; use types; export type lexer = struct { in: *bufio::scanner, path: str, loc: (uint, uint), prevrloc: (uint, uint), un: token, // ltok::EOF when no token was unlexed prevunlocs: [2]((uint, uint), (uint, uint)), flags: flag, comment: str, require_int: bool, }; // Flags which apply to this lexer export type flag = enum uint { NONE = 0, // Enables lexing comments COMMENTS = 1 << 0, }; // A syntax error export type syntax = !(location, str); // All possible lexer errors export type error = !(io::error | syntax); // Returns a human-friendly string for a given error. The result may be // statically allocated. export fn strerror(err: error) const str = { static let buf: [2048]u8 = [0...]; match (err) { case let err: io::error => return io::strerror(err); case let s: syntax => return fmt::bsprintf(buf, "{}:{}:{}: syntax error: {}", s.0.path, s.0.line, s.0.col, s.1); }; }; // Initializes a new lexer for the given [[bufio::scanner]]. The path is // borrowed. export fn init( in: *bufio::scanner, path: str, flags: flag = flag::NONE, ) lexer = { const loc = location { path = path, line = 1, col = 1 }; return lexer { in = in, path = path, loc = (1, 1), prevrloc = (1, 1), un = (ltok::EOF, void, loc), prevunlocs = [((1, 1), (1, 1))...], flags = flags, ... }; }; // Returns the current value of the comment buffer, or empty string if unset (or // if [[flag::COMMENTS]] was not enabled for this lexer). export fn comment(lex: *lexer) str = lex.comment; // Returns the next token from the lexer. export fn lex(lex: *lexer) (token | error) = { if (lex.un.0 != ltok::EOF) { defer lex.un.0 = ltok::EOF; return lex.un; }; defer { lex.prevunlocs[1] = lex.prevunlocs[0]; const prev = prevloc(lex); const loc = mkloc(lex); lex.prevunlocs[0] = ( (prev.line, prev.col), (loc.line, loc.col), ); }; let r = match (nextw(lex)?) { case io::EOF => return (ltok::EOF, void, mkloc(lex)); case let r: (rune, location) => yield r; }; if (ascii::isdigit(r.0)) { unget(lex, r.0); return lex_literal(lex); }; lex.require_int = false; if (is_name(r.0, false)) { unget(lex, r.0); return lex_name(lex, r.1); }; let tok = switch (r.0) { case '"', '\'', '`' => unget(lex, r.0); return lex_rn_str(lex); case '.', '<', '>', '&', '|', '^' => unget(lex, r.0); return lex3(lex); case '*', '%', '/', '+', '-', ':', '!', '=' => unget(lex, r.0); return lex2(lex); case '~' => yield ltok::BNOT; case ',' => yield ltok::COMMA; case '{' => yield ltok::LBRACE; case '[' => yield ltok::LBRACKET; case '(' => yield ltok::LPAREN; case '}' => yield ltok::RBRACE; case ']' => yield ltok::RBRACKET; case ')' => yield ltok::RPAREN; case ';' => yield ltok::SEMICOLON; case '?' => yield ltok::QUESTION; case => return syntaxerr(r.1, "invalid character"); }; line_comment(lex)?; return (tok, void, r.1); }; fn is_name(r: rune, num: bool) bool = ascii::isalpha(r) || r == '_' || r == '@' || (num && ascii::isdigit(r)); fn lex_unicode(lex: *lexer, loc: location, n: size) (rune | error) = { assert(n < 9); let buf: [8]u8 = [0...]; for (let i = 0z; i < n; i += 1z) { let r = match (next(lex)?) { case io::EOF => return syntaxerr(loc, "unexpected EOF scanning for escape"); case let r: (rune, location) => yield r.0; }; if (!ascii::isxdigit(r)) { return syntaxerr(loc, "unexpected rune scanning for escape"); }; buf[i] = r: u8; }; let s = strings::fromutf8_unsafe(buf[..n]); return strconv::stou32(s, strconv::base::HEX) as u32: rune; }; fn lex_rune(lex: *lexer, loc: location) (rune | error) = { let r = match (next(lex)?) { case io::EOF => return syntaxerr(loc, "unexpected EOF scanning for rune"); case let r: (rune, location) => yield r.0; }; if (r != '\\') { return r; }; r = match (next(lex)?) { case io::EOF => return syntaxerr(loc, "unexpected EOF scanning for escape"); case let r: (rune, location) => yield r.0; }; switch (r) { case '\\' => return '\\'; case '\'' => return '\''; case '0' => return '\0'; case 'a' => return '\a'; case 'b' => return '\b'; case 'f' => return '\f'; case 'n' => return '\n'; case 'r' => return '\r'; case 't' => return '\t'; case 'v' => return '\v'; case '"' => return '\"'; case 'x' => return lex_unicode(lex, loc, 2); case 'u' => return lex_unicode(lex, loc, 4); case 'U' => return lex_unicode(lex, loc, 8); case => return syntaxerr(mkloc(lex), "unknown escape sequence"); }; }; fn lex_string(lex: *lexer, loc: location, delim: rune) (token | error) = { let ret: token = (ltok::LIT_STR, "", loc); let buf = memio::dynamic(); for (true) match (next(lex)?) { case io::EOF => return syntaxerr(loc, "unexpected EOF scanning string literal"); case let r: (rune, location) => if (r.0 == delim) break else if (delim == '"' && r.0 == '\\') { unget(lex, r.0); let r = lex_rune(lex, loc)?; memio::appendrune(&buf, r)?; } else { memio::appendrune(&buf, r.0)?; }; }; for (true) match (nextw(lex)?) { case io::EOF => break; case let r: (rune, location) => switch (r.0) { case '"', '`' => const tok = lex_string(lex, loc, r.0)?; const next = tok.1 as str; memio::concat(&buf, next)!; free(next); break; case '/' => match (nextw(lex)?) { case io::EOF => unget(lex, r.0); case let s: (rune, location) => if (s.0 == '/') { lex_comment(lex)?; continue; } else { unget(lex, s.0); unget(lex, r.0); }; }; break; case => unget(lex, r.0); break; }; }; return (ltok::LIT_STR, memio::string(&buf)!, loc); }; fn lex_rn_str(lex: *lexer) (token | error) = { const loc = mkloc(lex); let r = match (next(lex)) { case let r: (rune, location) => yield r.0; case (io::EOF | io::error) => abort(); }; switch (r) { case '\'' => void; case '\"', '`' => return lex_string(lex, loc, r); case => abort(); // Invariant }; // Rune literal let ret: token = (ltok::LIT_RCONST, lex_rune(lex, loc)?, loc); match (next(lex)?) { case io::EOF => return syntaxerr(loc, "unexpected EOF"); case let n: (rune, location) => if (n.0 != '\'') { return syntaxerr(n.1, "expected \"\'\""); }; }; line_comment(lex)?; return ret; }; fn lex_name(lex: *lexer, loc: location) (token | error) = { let buf = memio::dynamic(); match (next(lex)) { case let r: (rune, location) => assert(is_name(r.0, false)); memio::appendrune(&buf, r.0)!; case (io::EOF | io::error) => abort(); }; for (true) match (next(lex)?) { case io::EOF => break; case let r: (rune, location) => if (!is_name(r.0, true)) { unget(lex, r.0); break; }; memio::appendrune(&buf, r.0)?; }; line_comment(lex)?; let n = memio::string(&buf)!; match (sort::search(bmap[..ltok::LAST_KEYWORD+1], size(str), &n, &cmp::strs)) { case void => return (ltok::NAME, n, loc); case let i: size => free(n); return (i: ltok, void, loc); }; }; fn line_comment(lex: *lexer) (void | error) = { if (lex.flags & flag::COMMENTS != flag::COMMENTS) { return; }; let r: (rune, location) = ('\0', location { ... }); for (true) match (try(lex, '\t', ' ', '/')?) { case void => return; case let v: (rune, location) => switch (v.0) { case '\t', ' ' => void; case '/' => r = v; break; case => abort(); // unreachable }; }; if (try(lex, '/')? is void) { unget(lex, r.0); return; }; free(lex.comment); lex.comment = ""; lex_comment(lex)?; }; fn lex_comment(lexr: *lexer) (void | error) = { if (lexr.flags & flag::COMMENTS != flag::COMMENTS) { for (true) match (next(lexr)?) { case io::EOF => break; case let r: (rune, location) => if (r.0 == '\n') { break; }; }; return; }; let buf = memio::dynamic(); defer io::close(&buf)!; for (true) match (next(lexr)?) { case io::EOF => break; case let r: (rune, location) => memio::appendrune(&buf, r.0)!; if (r.0 == '\n') { break; }; }; let bytes = strings::toutf8(lexr.comment); append(bytes, strings::toutf8(memio::string(&buf)!)...); lexr.comment = strings::fromutf8(bytes)!; }; fn lex_literal(lex: *lexer) (token | error) = { const loc = mkloc(lex); let chars: []u8 = []; let r = match (next(lex)?) { case io::EOF => return (ltok::EOF, void, loc); case let r: (rune, location) => yield r; }; let started = false; let base = strconv::base::DEC; if (r.0 == '0') { append(chars, utf8::encoderune(r.0)...); r = match (next(lex)?) { case io::EOF => return (ltok::LIT_ICONST, 0u64, loc); case let r: (rune, location) => yield r; }; switch (r.0) { case 'b' => base = strconv::base::BIN; case 'o' => base = strconv::base::OCT; case 'x' => base = strconv::base::HEX; case => if (ascii::isdigit(r.0)) { return syntaxerr(loc, "Leading zeros in number literals aren't permitted (for octal, use the 0o prefix instead)"); }; started = true; unget(lex, r.0); }; } else unget(lex, r.0); let basechrs = switch (base) { case strconv::base::BIN => yield "01"; case strconv::base::OCT => yield "01234567"; case strconv::base::DEC => yield "0123456789"; case strconv::base::HEX => yield "0123456789ABCDEFabcdef"; case => abort(); // unreachable }; let suff: (size | void) = void; let exp: (size | void) = void; let end = 0z; let float = false; let last_rune_was_separator = false; for (true) { r = match (next(lex)?) { case io::EOF => if (last_rune_was_separator) { return syntaxerr(loc, "Expected digit after separator"); }; break; case let r: (rune, location) => yield r; }; if (!strings::contains(basechrs, r.0)) { if (last_rune_was_separator) { return syntaxerr(loc, "Expected digit after separator"); }; switch (r.0) { case '.' => if (!started) { return syntaxerr(loc, "Expected integer literal"); }; if (float || exp is size || suff is size || lex.require_int) { unget(lex, r.0); break; } else { r = match (next(lex)?) { case io::EOF => break; case let r: (rune, location) => yield r; }; if (!strings::contains(basechrs, r.0)) { unget(lex, r.0); unget(lex, '.'); break; }; unget(lex, r.0); float = true; append(chars, utf8::encoderune('.')...); }; case 'e', 'E', 'p', 'P' => if (!started) { return syntaxerr(loc, "Expected integer literal"); }; if ((r.0 == 'e' || r.0 == 'E') != (base == strconv::base::DEC)) { unget(lex, r.0); break; }; if (exp is size || suff is size) { unget(lex, r.0); break; } else { if (end == 0) end = len(chars); append(chars, utf8::encoderune(r.0)...); exp = len(chars); r = match (next(lex)?) { case io::EOF => break; case let r: (rune, location) => yield r; }; switch (r.0) { case '+', '-' => append(chars, utf8::encoderune(r.0)...); case => unget(lex, r.0); }; basechrs = "0123456789"; }; case 'i', 'u', 'f', 'z' => if (!started) { return syntaxerr(loc, "Expected integer literal"); }; if (suff is size || r.0 != 'f' && float || r.0 == 'f' && base != strconv::base::DEC) { unget(lex, r.0); break; } else { suff = len(chars); if (end == 0) end = len(chars); append(chars, utf8::encoderune(r.0)...); basechrs = "0123456789"; }; case '_' => if (!started) { return syntaxerr(loc, "Expected integer literal"); }; if (exp is size) { return syntaxerr(loc, "Exponents may not contain separators"); }; if (suff is size) { return syntaxerr(loc, "Suffixes may not contain separators"); }; last_rune_was_separator = true; case => unget(lex, r.0); break; }; } else { last_rune_was_separator = false; append(chars, utf8::encoderune(r.0)...); }; started = true; }; if (!started) { return syntaxerr(loc, "expected integer literal"); }; if (end == 0) end = len(chars); lex.require_int = false; let exp = match (exp) { case void => yield "0"; case let exp: size => let end = match (suff) { case void => yield len(chars); case let suff: size => yield suff; }; yield strings::fromutf8(chars[exp..end])!; }; let exp = match (strconv::stoi(exp)) { case let exp: int => yield exp; case strconv::invalid => return syntaxerr(mkloc(lex), "expected exponent"); case strconv::overflow => return syntaxerr(loc, "overflow in exponent"); }; let floatend = match (suff) { case let suff: size => yield suff; case void => yield len(chars); }; let suff = match (suff) { case let suff: size => yield strings::fromutf8(chars[suff..])!; case void => yield ""; }; let (suff, signed) = if (suff == "u8") (ltok::LIT_U8, false) else if (suff == "u16") (ltok::LIT_U16, false) else if (suff == "u32") (ltok::LIT_U32, false) else if (suff == "u64") (ltok::LIT_U64, false) else if (suff == "u") (ltok::LIT_UINT, false) else if (suff == "z") (ltok::LIT_SIZE, false) else if (suff == "i8") (ltok::LIT_I8, true) else if (suff == "i16") (ltok::LIT_I16, true) else if (suff == "i32") (ltok::LIT_I32, true) else if (suff == "i64") (ltok::LIT_I64, true) else if (suff == "i") (ltok::LIT_INT, true) else if (suff == "" && !float && exp >= 0) (ltok::LIT_ICONST, false) else if (suff == "f32") (ltok::LIT_F32, false) else if (suff == "f64") (ltok::LIT_F64, false) else if (suff == "" && (float || exp < 0)) (ltok::LIT_FCONST, false) else return syntaxerr(loc, "invalid literal suffix"); let exp = if (exp < 0) switch (suff) { case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => yield exp: size; case => return syntaxerr(loc, "invalid negative exponent of integer"); } else exp: size; let val = strings::fromutf8(chars[..end])!; let val = switch (suff) { case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => val = strings::fromutf8(chars[..floatend])!; yield strconv::stof64(val, base); case => yield strconv::stou64(val, base); }; let val = match (val) { case let val: u64 => for (let i = 0z; i < exp; i += 1) { let old = val; val *= 10; if (val / 10 != old) { return syntaxerr(loc, "overflow in exponent"); }; }; if (signed && val > types::I64_MIN: u64) { return syntaxerr(loc, "overflow in exponent"); }; yield val; case let val: f64 => yield val; case strconv::invalid => abort(); // Shouldn't be lexed in case strconv::overflow => return syntaxerr(loc, "literal overflow"); }; line_comment(lex)?; return (suff, val, loc); }; fn lex2(lexr: *lexer) (token | error) = { let first = next(lexr)? as (rune, location); let tok: (ltok, [](rune, ltok)) = switch (first.0) { case '*' => yield (ltok::TIMES, [('=', ltok::TIMESEQ)]); case '%' => yield (ltok::MODULO, [('=', ltok::MODEQ)]); case '/' => match (next(lexr)?) { case let r: (rune, location) => switch (r.0) { case '=' => line_comment(lexr)?; return (ltok::DIVEQ, void, first.1); case '/' => lex_comment(lexr)?; return lex(lexr); case => unget(lexr, r.0); return (ltok::DIV, void, first.1); }; case io::EOF => return (ltok::DIV, void, first.1); }; case '+' => yield (ltok::PLUS, [('=', ltok::PLUSEQ)]); case '-' => yield (ltok::MINUS, [('=', ltok::MINUSEQ)]); case ':' => yield (ltok::COLON, [(':', ltok::DOUBLE_COLON)]); case '!' => yield (ltok::LNOT, [('=', ltok::NEQUAL)]); case '=' => yield (ltok::EQUAL, [('=', ltok::LEQUAL), ('>', ltok::ARROW)]); case => return syntaxerr(first.1, "unknown token sequence"); }; match (next(lexr)?) { case let r: (rune, location) => for (let i = 0z; i < len(tok.1); i += 1) { if (tok.1[i].0 == r.0) { line_comment(lexr)?; return (tok.1[i].1, void, first.1); }; }; unget(lexr, r.0); line_comment(lexr)?; case io::EOF => void; }; return (tok.0, void, first.1); }; fn lex3(lex: *lexer) (token | error) = { let r = next(lex)? as (rune, location); let toks = switch (r.0) { case '.' => let tok = if (try(lex, '.')? is void) { lex.require_int = true; yield ltok::DOT; } else if (try(lex, '.')? is void) { yield ltok::DOUBLE_DOT; } else ltok::ELLIPSIS; line_comment(lex)?; return (tok, void, r.1); case '<' => yield [ltok::LESS, ltok::LESSEQ, ltok::LSHIFT, ltok::LSHIFTEQ]; case '>' => yield [ltok::GT, ltok::GTEQ, ltok::RSHIFT, ltok::RSHIFTEQ]; case '&' => yield [ltok::BAND, ltok::BANDEQ, ltok::LAND, ltok::LANDEQ]; case '|' => yield [ltok::BOR, ltok::BOREQ, ltok::LOR, ltok::LOREQ]; case '^' => yield [ltok::BXOR, ltok::BXOREQ, ltok::LXOR, ltok::LXOREQ]; case => return syntaxerr(r.1, "unknown token sequence"); }; let idx = match (try(lex, r.0, '=')?) { case void => yield 0; // X case let n: (rune, location) => yield switch (n.0) { case '=' => yield 1; // X= case => yield match (try(lex, '=')?) { case void => yield 2; // XX case (rune, location) => yield 3; // XX= }; }; }; line_comment(lex)?; return (toks[idx], void, r.1); }; // Unlex a single token. The next call to [[lex]] will return this token. Only one // unlex is supported at a time; you must call [[lex]] before calling [[unlex]] // again. export fn unlex(lex: *lexer, tok: token) void = { assert(lex.un.0 == ltok::EOF, "attempted to unlex more than one token"); lex.un = tok; }; fn next(lex: *lexer) ((rune, location) | syntax | io::EOF | io::error) = { match (bufio::scan_rune(lex.in)) { case let e: (io::EOF | io::error) => return e; case let r: rune => const loc = mkloc(lex); lexloc(lex, r); return (r, loc); case utf8::invalid => return syntaxerr(mkloc(lex), "Source file is not valid UTF-8"); }; }; fn nextw(lex: *lexer) ((rune, location) | io::EOF | error) = { for (true) match (next(lex)?) { case io::EOF => return io::EOF; case let r: (rune, location) => if (ascii::isspace(r.0)) { if (r.0 == '\n') { free(lex.comment); lex.comment = ""; }; continue; }; if (!is_name(r.0, true) && r.0 != '/') { free(lex.comment); lex.comment = ""; }; return r; }; }; fn try( lex: *lexer, want: rune... ) ((rune, location) | syntax | void | io::error) = { let r = match (next(lex)?) { case io::EOF => return; case let r: (rune, location) => yield r; }; assert(len(want) > 0); for (let i = 0z; i < len(want); i += 1) { if (r.0 == want[i]) { return r; }; }; unget(lex, r.0); }; fn unget(lex: *lexer, r: rune) void = { bufio::unreadrune(lex.in, r); // here, we set the current location to the previous location, then // subtract one from the previous location's column. this is always // correct, even for tabs and newlines, since a tab or newline will // never be ungot after a previous unget call. besides tabs and // newlines, the rune will always be a printable ASCII character assert(ascii::isprint(r) || r == '\t' || r == '\n'); assert(r != '\n' || lex.prevrloc.0 == lex.loc.0 - 1); lex.loc = lex.prevrloc; lex.prevrloc.1 -= 1; }; fn lexloc(lex: *lexer, r: rune) void = { lex.prevrloc = lex.loc; switch (r) { case '\n' => lex.loc.0 += 1; lex.loc.1 = 1; case '\t' => lex.loc.1 += 8 - lex.loc.1 % 8 + 1; case => lex.loc.1 += 1; }; }; export fn mkloc(lex: *lexer) location = { const loc = if (lex.un.0 == ltok::EOF) lex.loc else lex.prevunlocs[1].1; return location { path = lex.path, line = loc.0, col = loc.1, }; }; export fn prevloc(lex: *lexer) location = { const loc = if (lex.un.0 == ltok::EOF) lex.prevrloc else lex.prevunlocs[1].0; return location { path = lex.path, line = loc.0, col = loc.1, }; }; export fn syntaxerr(loc: location, why: str) error = { static let buf = path::buffer{...}; path::set(&buf, loc.path)!; loc.path = path::string(&buf); return (loc, why); }; hare-0.24.2/hare/lex/token.ha000066400000000000000000000075151464473310100156720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A lexical token class. export type ltok = enum uint { // Keep ordered with bmap // Alpha sorted ATTR_FINI, ATTR_INIT, ATTR_OFFSET, ATTR_PACKED, ATTR_SYMBOL, ATTR_TEST, ATTR_THREADLOCAL, UNDERSCORE, ABORT, ALIGN, ALLOC, APPEND, AS, ASSERT, BOOL, BREAK, CASE, CONST, CONTINUE, DEF, DEFER, DELETE, DONE, ELSE, ENUM, EXPORT, F32, F64, FALSE, FN, FOR, FREE, I16, I32, I64, I8, IF, INSERT, INT, IS, LEN, LET, MATCH, NEVER, NULL, NULLABLE, OFFSET, OPAQUE, RETURN, RUNE, SIZE, STATIC, STR, STRUCT, SWITCH, TRUE, TYPE, U16, U32, U64, U8, UINT, UINTPTR, UNION, USE, VAARG, VAEND, VALIST, VASTART, VOID, YIELD, LAST_KEYWORD = YIELD, // Operators ARROW, BAND, BANDEQ, BNOT, BOR, BOREQ, BXOR, BXOREQ, COLON, COMMA, DIV, DIVEQ, DOT, DOUBLE_COLON, DOUBLE_DOT, ELLIPSIS, EQUAL, GT, GTEQ, LAND, LANDEQ, LBRACE, LBRACKET, LEQUAL, LESS, LESSEQ, LNOT, LOR, LOREQ, LPAREN, LSHIFT, LSHIFTEQ, LXOR, LXOREQ, MINUS, MINUSEQ, MODEQ, MODULO, NEQUAL, PLUS, PLUSEQ, QUESTION, RBRACE, RBRACKET, RPAREN, RSHIFT, RSHIFTEQ, SEMICOLON, TIMES, TIMESEQ, LAST_BTOK = TIMESEQ, LIT_U8, LIT_U16, LIT_U32, LIT_U64, LIT_UINT, LIT_SIZE, LIT_I8, LIT_I16, LIT_I32, LIT_I64, LIT_INT, LIT_ICONST, LIT_F32, LIT_F64, LIT_FCONST, LIT_RCONST, LIT_STR, LAST_LITERAL = LIT_STR, NAME, EOF, }; const bmap: [_]str = [ // Keep ordered with tok "@fini", "@init", "@offset", "@packed", "@symbol", "@test", "@threadlocal", "_", "abort", "align", "alloc", "append", "as", "assert", "bool", "break", "case", "const", "continue", "def", "defer", "delete", "done", "else", "enum", "export", "f32", "f64", "false", "fn", "for", "free", "i16", "i32", "i64", "i8", "if", "insert", "int", "is", "len", "let", "match", "never", "null", "nullable", "offset", "opaque", "return", "rune", "size", "static", "str", "struct", "switch", "true", "type", "u16", "u32", "u64", "u8", "uint", "uintptr", "union", "use", "vaarg", "vaend", "valist", "vastart", "void", "yield", "=>", "&", "&=", "~", "|", "|=", "^", "^=", ":", ",", "/", "/=", ".", "::", "..", "...", "=", ">", ">=", "&&", "&&=", "{", "[", "==", "<", "<=", "!", "||", "||=", "(", "<<", "<<=", "^^", "^^=", "-", "-=", "%=", "%", "!=", "+", "+=", "?", "}", "]", ")", ">>", ">>=", ";", "*", "*=", ]; static assert(len(bmap) == ltok::LAST_BTOK: size + 1); // A token value, used for tokens such as '1337' (an integer). export type value = (str | rune | u64 | f64 | void); // A location within a source file. // The path is borrowed from the file name given to the lexer. export type location = struct { path: str, line: uint, col: uint }; // A single lexical token. export type token = (ltok, value, location); // Converts a token to its string representation. export fn tokstr(tok: token) const str = { if (tok.0 <= ltok::LAST_BTOK) { return bmap[tok.0: int]; }; switch (tok.0) { case ltok::LIT_U8 => return "u8"; case ltok::LIT_U16 => return "u16"; case ltok::LIT_U32 => return "u32"; case ltok::LIT_U64 => return "u64"; case ltok::LIT_UINT => return "uint"; case ltok::LIT_SIZE => return "size"; case ltok::LIT_I8 => return "i8"; case ltok::LIT_I16 => return "i16"; case ltok::LIT_I32 => return "i32"; case ltok::LIT_I64 => return "i64"; case ltok::LIT_INT => return "int"; case ltok::LIT_ICONST => return "iconst"; case ltok::LIT_F32 => return "f32"; case ltok::LIT_F64 => return "f64"; case ltok::LIT_FCONST => return "fconst"; case ltok::LIT_RCONST => return "rconst"; case ltok::LIT_STR => return "str"; case ltok::NAME => return tok.1 as str; case ltok::EOF => return "EOF"; case => abort(); }; }; hare-0.24.2/hare/module/000077500000000000000000000000001464473310100147255ustar00rootroot00000000000000hare-0.24.2/hare/module/README000066400000000000000000000005341464473310100156070ustar00rootroot00000000000000hare::module provides an interface to the module system used by this Hare implementation, as well as to the Hare cache. Note that these interfaces may not be portable to other Hare implementations. Note that much of this module's design is an implementation detail of the Hare toolchain, and is not subject to any future compatibility guarantees. hare-0.24.2/hare/module/cache.ha000066400000000000000000000007601464473310100163050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use path; // Gets the cache directory for a given module, given the value of 'harecache'. // The result is statically allocated and will be overwritten on subsequent // calls. An error is returned if the resulting path would be longer than // [[path::MAX]]. export fn get_cache(harecache: str, modpath: str) (str | error) = { static let buf = path::buffer { ... }; return path::set(&buf, harecache, modpath)?; }; hare-0.24.2/hare/module/deps.ha000066400000000000000000000117501464473310100161760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use fs; use hare::ast; use hare::lex; use hare::parse; use hare::unparse; use io; use memio; use os; use path; use sort; use strings; // A hare module. export type module = struct { name: str, ns: ast::ident, path: str, srcs: srcset, // [](Index to the module, Identifier of of the module) deps: [](size, ast::ident), }; // Get the list of dependencies referred to by a set of source files. // The list will be sorted alphabetically and deduplicated. export fn parse_deps(files: str...) ([]ast::ident | error) = { let deps: []ast::ident = []; for (let file .. files) { let handle = match (os::open(file)) { case let f: io::file => yield f; case let e: fs::error => return attach(strings::dup(file), e); }; defer io::close(handle)!; let sc = bufio::newscanner(handle); defer bufio::finish(&sc); let lexer = lex::init(&sc, file); let imports = parse::imports(&lexer)?; defer ast::imports_finish(imports); // dedupe + insertion sort for (let import &.. imports) { let id = import.ident; let idx = sort::rbisect(deps, size(ast::ident), &id, &idcmp); if (idx == 0 || idcmp(&deps[idx - 1], &id) != 0) { insert(deps[idx], ast::ident_dup(id)); }; }; }; return deps; }; fn idcmp(a: const *opaque, b: const *opaque) int = { const a = a: const *ast::ident, b = b: const *ast::ident; for (let i = 0z; i < len(a) && i < len(b); i += 1) { let cmp = strings::compare(a[i], b[i]); if (cmp != 0) { return cmp; }; }; if (len(a) < len(b)) { return -1; } else if (len(a) == len(b)) { return 0; } else { return 1; }; }; // Get the dependencies for a module from the cache, recalculating // them if necessary. cachedir should be calculated with [[get_cache]], // and srcset should be calculated with [[find]]. fn get_deps(cachedir: str, srcs: *srcset) ([]ast::ident | error) = { static let buf = path::buffer{...}; path::set(&buf, cachedir, "deps")?; let rest = memio::fixed(buf.buf[buf.end..]); buf.end += format_tags(&rest, srcs.seentags)?; buf.end += memio::concat(&rest, ".txt")?; let outofdate = outdated(path::string(&buf), srcs.ha, srcs.mtime); os::mkdirs(cachedir, 0o755)?; let depsfile = os::create(path::string(&buf), 0o644, fs::flag::RDWR)?; defer io::close(depsfile)!; io::lock(depsfile, true, io::lockop::EXCLUSIVE)?; let deps: []ast::ident = []; if (outofdate) { deps = parse_deps(srcs.ha...)?; io::trunc(depsfile, 0)?; let out = bufio::init(depsfile, [], buf.buf); for (let dep .. deps) { unparse::ident(&out, dep)?; fmt::fprintln(&out)?; }; } else { let in = bufio::newscanner_static(depsfile, buf.buf); for (let s => bufio::scan_line(&in)?) { append(deps, parse::identstr(s)?); }; }; return deps; }; // Gather a [[module]] and all its dependencies, appending them to an existing // slice, deduplicated, in reverse topological order, returning the index of the // input module within the slice. Dependencies will also be written to the // cache. export fn gather( ctx: *context, out: *[]module, mod: location, ) (size | error) = { let stack: []str = []; defer free(stack); return _gather(ctx, out, &stack, mod)?; }; fn _gather( ctx: *context, out: *[]module, stack: *[]str, mod: location, ) (size | error) = { let (modpath, srcs) = match (find(ctx, mod)) { case let r: (str, srcset) => yield r; case let e: error => if (len(stack) == 0) { return e; }; return attach(strings::dup(stack[len(stack) - 1]), e); }; modpath = strings::dup(modpath); defer free(modpath); for (let j = 0z; j < len(stack); j += 1) { if (modpath == stack[j]) { append(stack, modpath); return strings::dupall(stack[j..]): dep_cycle; }; }; for (let j = 0z; j < len(out); j += 1) { if (modpath == out[j].path) { return j; }; }; append(stack, modpath); defer delete(stack[len(stack) - 1]); let cache = get_cache(ctx.harecache, modpath)?; let depids = get_deps(cache, &srcs)?; defer free(depids); let deps: [](size, ast::ident) = alloc([], len(depids)); for (let i = 0z; i < len(depids); i += 1) { static append(deps, (_gather(ctx, out, stack, depids[i])?, depids[i]) ); }; append(out, module { name = match (mod) { case let mod: *path::buffer => yield strings::dup(path::string(mod)); case let mod: ast::ident => yield unparse::identstr(mod); }, ns = match (mod) { case let mod: *path::buffer => yield []; case let mod: ast::ident => yield ast::ident_dup(mod); }, path = strings::dup(modpath), srcs = srcs, deps = deps, }); return len(out) - 1; }; // Free the resources associated with a [[module]]. export fn finish(mod: *module) void = { free(mod.name); ast::ident_free(mod.ns); free(mod.path); finish_srcset(&mod.srcs); for (let (_, ident) .. mod.deps) { ast::ident_free(ident); }; free(mod.deps); }; // Free all the [[module]]s in a slice of modules, and then the slice itself. export fn free_slice(mods: []module) void = { for (let mod &.. mods) { finish(mod); }; free(mods); }; hare-0.24.2/hare/module/format.ha000066400000000000000000000033751464473310100165370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::unparse; use io; use time::chrono; use time::date; // Formats a set of tags to an [[io::handle]] in "+tag1-tag2" format. export fn format_tags( out: io::handle, tags: ([]str | []tag), ) (size | io::error) = { let n = 0z; match (tags) { case let tags: []str => for (let tag .. tags) { n += fmt::fprintf(out, "+{}", tag)?; }; case let tags: []tag => for (let tag .. tags) { n += fmt::fprintf( out, if (tag.include) "+{}" else "-{}", tag.name)?; }; }; return n; }; // Formats a [[srcset]] to an [[io::handle]]. export fn format_srcset(out: io::handle, srcs: *srcset) (size | io::error) = { let n = 0z; n += fmt::fprint(out, "relevant tags: ")?; n += format_tags(out, srcs.seentags)?; n += fmt::fprintln(out)?; const dt = date::from_instant(chrono::LOCAL, srcs.mtime); n += date::format(out, "last change to source list: %F %T\n", &dt)?; n += fmt::fprintln(out, "hare sources:")?; for (let ha .. srcs.ha) { n += fmt::fprintln(out, " ", ha)?; }; n += fmt::fprintln(out, "assembly sources:")?; for (let s .. srcs.s) { n += fmt::fprintln(out, " ", s)?; }; n += fmt::fprintln(out, "object sources:")?; for (let o .. srcs.o) { n += fmt::fprintln(out, " ", o)?; }; return n; }; // Formats a [[module]] to an [[io::handle]]. export fn format(out: io::handle, mod: *module) (size | io::error) = { let n = 0z; n += fmt::fprintln(out, "module:", mod.name)?; n += fmt::fprintln(out, "path:", mod.path)?; n += format_srcset(out, &mod.srcs)?; n += fmt::fprintln(out, "dependencies:")?; for (let (_, ident) .. mod.deps) { n += fmt::fprint(out, " ")?; n += unparse::ident(out, ident)?; n += fmt::fprintln(out)?; }; return n; }; hare-0.24.2/hare/module/srcs.ha000066400000000000000000000244541464473310100162220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use fs; use hare::ast; use os; use path; use sort; use sort::cmp; use strings; use time; // A file tag, e.g. +x86_64, or -libc. export type tag = struct { // The name of the tag. name: str, // Whether the tag is inclusive (+tag) or not (-tag). include: bool, }; // A set of sources for a module, filtered by a set of tags. export type srcset = struct { // The last time the list of source files changed. Note that this is not // the last time that the source files themselves changed. mtime: time::instant, // Source directories traversed while finding these source files. dirs: []str, // The list of tags that were actually encountered while finding these // source files. These are sorted alphabetically, and are the set of // tags that should be used to find this module in the cache. seentags: []str, // hare source files (.ha) ha: []str, // assembly source files (.s) s: []str, // object source files (.o) o: []str, // linker scripts (.sc) sc: []str, }; // Frees the resources associated with a [[srcset]]. export fn finish_srcset(srcs: *srcset) void = { strings::freeall(srcs.dirs); strings::freeall(srcs.seentags); strings::freeall(srcs.ha); strings::freeall(srcs.s); strings::freeall(srcs.o); strings::freeall(srcs.sc); }; // Find the on-disk path and set of source files for a given module. The path is // statically allocated and may be overwritten on subsequent calls. export fn find(ctx: *context, loc: location) ((str, srcset) | error) = { match (loc) { case let buf: *path::buffer => match (path_find(ctx, buf)) { case let s: srcset => return (path::string(buf), s); case not_found => return attach(locstr(loc), not_found); case let e: error => return e; }; case let ident: ast::ident => let tok = strings::tokenize(ctx.harepath, ":"); let next: (str | done) = "."; for (next is str; next = strings::next_token(&tok)) { if (!os::exists(next as str)) { continue; }; static let buf = path::buffer { ... }; path::set(&buf, os::realpath(next as str)?)?; for (let part .. ident) { path::push(&buf, part)?; }; match (path_find(ctx, &buf)) { case let s: srcset => return (path::string(&buf), s); case not_found => void; case let e: error => return attach(strings::dup(path::string(&buf)), e); }; }; return attach(locstr(ident), not_found); }; }; fn path_find(ctx: *context, buf: *path::buffer) (srcset | error) = { // list of sources to return, with 3 extra fields prepended to allow // quick lookup and comparison. each item is e.g.: // ("basename", "ha", 2 (# of tags), ["path/-tag1/basename+tag2.ha"]) // if len(srcs.3) != 1 at the end of _findsrcs() then there's a conflict let srcs: [](str, str, size, []str) = []; defer { for (let i = 0z; i < len(srcs); i += 1) { free(srcs[i].0); free(srcs[i].1); free(srcs[i].3); }; free(srcs); }; let mtime = time::INSTANT_MIN; let res = srcset { mtime = time::INSTANT_MIN, ... }; _findsrcs(buf, ctx.tags, &srcs, &res, 0)?; for (let i = 0z; i < len(srcs); i += 1) { if (len(srcs[i].3) != 1) { return alloc(srcs[i].3...): file_conflict; }; let out = switch (srcs[i].1) { case "ha" => yield &res.ha; case "s" => yield &res.s; case "o" => yield &res.o; case "sc" => yield &res.sc; case => abort(); }; append(out, srcs[i].3[0]); }; // module needs either a hare source file or a README in order to be // valid. used to allow eg. shadowing foo::bar:: without accidentally // shadowing foo:: if (len(res.ha) == 0) { path::push(buf, "README")?; defer path::pop(buf); if (!os::exists(path::string(buf))) { finish_srcset(&res); return not_found; }; }; sort::sort(res.dirs, size(str), &cmp::strs); sort::sort(res.ha, size(str), &cmp::strs); sort::sort(res.s, size(str), &cmp::strs); sort::sort(res.o, size(str), &cmp::strs); sort::sort(res.sc, size(str), &cmp::strs); return res; }; // simple implementation but the reasons for it are delicate // // finding the right sources is conceptually simple: just collect all the // files compatible with the tagset and then pick the best ones for each // conflicting filename // // the mtime is the first weird part: you want to find the last time a file // was added, moved, or deleted, but only for parts of the module relevant to // the input tags. the edge-case here is "what if i renamed a subdirectory so // that it's tags don't match". the solution is that you can just find the // latest mtime of directories that get traversed, i.e. have matching tags. // this is because the tag-compatible subset of the filetree constitutes // a filetree in its own right, where a file being renamed to no longer be // part of the tag-filetree is equivalent to it being deleted from the // tag-filetree. the mtime-checking does not distinguish between renames // and deletions, so we get this for free by checking mtimes in the underlying // filesystem // // the second weird part is the seentags: the goal here is finding the subset // of the input tags which were actually used while finding the srcset, // so that the cache can be reused for two sets of input tags which don't // produce different srcsets. the method used here is just to take note of // the tags which were encountered while traversing the tree, and not to // continue down a file path beyond the first incompatible tag. exploring // this method, you could look at e.g "mod/+linux/+x86_64.ha". you might think // that this should, in theory, produce 4 different cache versions, since // there are 2 tags, each of which has 2 states; and using the method here // would produce only 3: none, +linux, and +linux+x86_64. however, there are // actually only 2 options: none, and +linux+x86_64, and the method here adds // one redundant slot for +linux. this is because either tag on their own // doesn't change whether the path matches, only both together. in practice, // the redundancy in the method used here will cause minimal overhead, because // it's likely that you do actually have a file with just one of the tags // somewhere else in your module, or else you would have combined them into // one tag. in any case, the method used here is fast because it gets to stop // searching as soon as it can fn _findsrcs( buf: *path::buffer, in_tags: []str, srcs: *[](str, str, size, []str), res: *srcset, tagdepth: size, ) (void | error) = { const pathstr = path::string(buf); const stat = match (os::stat(pathstr)) { case let stat: fs::filestat => yield stat; case fs::error => return; }; let tmp = pathstr; for (fs::islink(stat.mode)) { if (time::compare(res.mtime, stat.mtime) < 0) { res.mtime = stat.mtime; }; tmp = os::realpath(tmp)?; stat = os::stat(tmp)?; }; if (fs::isfile(stat.mode)) { let ext = match (path::pop_ext(buf)) { case void => return; case let ext: str => yield ext; }; switch (ext) { case "ha", "s", "o", "sc" => void; case => return; }; let filebytes = strings::toutf8(path::peek(buf) as str); path::push_ext(buf, ext)?; let split = tagindex(filebytes); let (base, tags) = ( strings::fromutf8_unsafe(filebytes[..split]), strings::fromutf8_unsafe(filebytes[split..]), ); let wanttags = match (parse_tags(tags)) { case let tags: []tag => yield tags; case let e: error => return attach(strings::dup(path::string(buf)), e); }; defer free(wanttags); if (!seentags_compat(in_tags, wanttags, &res.seentags)) { return; }; let ntags = tagdepth + len(wanttags); let bufstr = path::string(buf); for (let i = 0z; i < len(srcs); i += 1) { if (srcs[i].0 == base && srcs[i].1 == ext) { if (srcs[i].2 > ntags) { return; }; if (srcs[i].2 < ntags) { srcs[i].2 = ntags; strings::freeall(srcs[i].3); srcs[i].3 = []; }; append(srcs[i].3, strings::dup(bufstr)); return; }; }; append(srcs, ( strings::dup(base), strings::dup(ext), ntags, alloc([strings::dup(bufstr)]), )); return; }; if (!fs::isdir(stat.mode)) return; // ignore special files append(res.dirs, strings::dup(pathstr)); if (time::compare(res.mtime, stat.mtime) < 0) { res.mtime = stat.mtime; }; let iter = match (os::iter(pathstr)) { case let i: *fs::iterator => yield i; case let e: fs::error => return attach(strings::dup(pathstr), e); }; defer fs::finish(iter); for (let d => fs::next(iter)?) { path::push(buf, d.name)?; defer path::pop(buf); if (fs::isdir(d.ftype)) { if (tagindex(strings::toutf8(d.name)) != 0) { continue; }; let wanttags = match (parse_tags(d.name)) { case let tags: []tag => yield tags; case let e: error => return attach(strings::dup(path::string(buf)), e); }; defer free(wanttags); if (!seentags_compat(in_tags, wanttags, &res.seentags)) { continue; }; _findsrcs(buf, in_tags, srcs, res, tagdepth+len(wanttags))?; } else if (fs::isfile(d.ftype)) { _findsrcs(buf, in_tags, srcs, res, tagdepth)?; }; }; }; fn tagindex(bs: []u8) size = { let i = 0z; for (i < len(bs) && bs[i] != '+' && bs[i] != '-'; i += 1) void; return i; }; // Parses tags from a string. The tag themselves are borrowed from the input, // but the caller must free the slice returned. export fn parse_tags(s: str) ([]tag | error) = { let bs = strings::toutf8(s); if (bytes::contains(bs, '.')) { return tag_has_dot; }; let tags: []tag = []; let start = tagindex(bs); if (start != 0) { return tag_bad_format; }; for (start < len(bs)) { const end = start + 1 + tagindex(bs[start+1..]); append(tags, tag { name = strings::fromutf8_unsafe(bs[start+1..end]), include = bs[start] == '+', }); start = end; }; return tags; }; // Checks if a set of tags are compatible with a tag requirement. export fn tags_compat(have: []str, want: []tag) bool = { for (let t .. want) { let found = false; for (let ht .. have) { if (ht == t.name) { found = true; break; }; }; if (t.include ^^ found) { return false; }; }; return true; }; // same as tags_compat, but also adds any relevant tags to a seentags list // for use in _findsrcs. fn seentags_compat(have: []str, want: []tag, seen: *[]str) bool = { for (let t .. want) { let found = false; for (let ht .. have) { if (ht == t.name) { insert_uniq(seen, t.name); found = true; break; }; }; if (t.include ^^ found) { return false; }; }; return true; }; hare-0.24.2/hare/module/types.ha000066400000000000000000000062141464473310100164060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use fs; use hare::ast; use hare::parse; use hare::unparse; use io; use memio; use path; use strings; // A module was not found. export type not_found = !void; // A tag contains a dot. export type tag_has_dot = !void; // Generic badly formatted tag error. export type tag_bad_format = !void; // A dependency cycle error. export type dep_cycle = ![]str; // Two files in a module have the same basename and extension, and the // same number of compatible tags with the input tagset, so it is unknown // which should be used. export type file_conflict = ![]str; // Context for another error. export type errcontext = !(str, *error); // Tagged union of all possible error types. Must be freed with [[finish_error]] // unless it's passed to [[strerror]]. export type error = !( fs::error | io::error | path::error | parse::error | utf8::invalid | file_conflict | not_found | dep_cycle | tag_has_dot | tag_bad_format | errcontext | ); // A container struct for context, used by [[gather]]. export type context = struct { harepath: str, harecache: str, tags: []str, }; // The location of a module export type location = (*path::buffer | ast::ident); // Returns a string representation of a [[location]]. The result must be freed // by the caller. export fn locstr(loc: location) str = { match (loc) { case let buf: *path::buffer => return strings::dup(path::string(buf)); case let id: ast::ident => return unparse::identstr(id); }; }; // XXX: this shouldn't be necessary, the language should have some built-in way // to carry context with errors fn attach(ctx: str, e: error) errcontext = (ctx, alloc(e)): errcontext; // Free the resources associated with an [[error]]. export fn finish_error(e: error) void = { match (e) { case let e: dep_cycle => strings::freeall(e); case let e: file_conflict => strings::freeall(e); case let ctx: errcontext => finish_error(*ctx.1); free(ctx.0); free(ctx.1); case => void; }; }; // Turns an [[error]] into a human-readable string. The result is // statically allocated. Consumes the error. export fn strerror(e: error) str = { defer finish_error(e); static let buf: [2*path::MAX]u8 = [0...]; let buf = memio::fixed(buf[..]); _strerror(e, &buf); return memio::string(&buf)!; }; fn _strerror(e: error, buf: *memio::stream) void = { let s = match (e) { case let e: fs::error => yield fs::strerror(e); case let e: io::error => yield io::strerror(e); case let e: parse::error => yield parse::strerror(e); case let e: path::error => yield path::strerror(e); case utf8::invalid => yield "Invalid UTF-8"; case not_found => yield "Module not found"; case tag_has_dot => yield "Tag contains a '.'"; case tag_bad_format => yield "Bad tag format"; case let e: dep_cycle => memio::concat(buf, "Dependency cycle: ")!; memio::join(buf, " -> ", e...)!; return; case let e: file_conflict => memio::concat(buf, "File conflict: ")!; memio::join(buf, ", ", e...)!; return; case let ctx: errcontext => memio::concat(buf, ctx.0, ": ")!; _strerror(*ctx.1, buf); return; }; memio::concat(buf, s)!; }; hare-0.24.2/hare/module/util.ha000066400000000000000000000033321464473310100162150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use fs; use os; use strings; use time; // insert a string into a sorted list of strings, deduplicated. fn insert_uniq(into: *[]str, s: str) void = { let i = 0z; // the `into` slice is generally small enough that a linear search is // fine for (i < len(into) && strings::compare(into[i], s) < 0) { i += 1; }; if (i == len(into) || into[i] != s) { insert(into[i], strings::dup(s)); }; }; // Checks if the file at 'target' is out-of-date, given a list of dependency // files, and the last time the deps list changed. If "target" doesn't exist, // returns true. If any of the deps don't exist, they are skipped. export fn outdated(target: str, deps: []str, mtime: time::instant) bool = { let current = match (os::stat(target)) { case fs::error => return true; case let stat: fs::filestat => yield stat.mtime; }; if (time::compare(current, mtime) < 0) { return true; }; for (let dep .. deps) { match (os::stat(dep)) { case fs::error => continue; case let stat: fs::filestat => if (time::compare(current, stat.mtime) < 0) { return true; }; }; }; return false; }; // Wrapper for [[fs::next]] that only returns valid submodule directories. export fn next(it: *fs::iterator) (fs::dirent | done | fs::error) = { for (let d => fs::next(it)?) { if (!fs::isdir(d.ftype)) { continue; }; if (is_submodule(d.name)) { return d; }; }; return done; }; fn is_submodule(path: str) bool = { let it = strings::iter(path); let first = true; for (let r => strings::next(&it)) { if (!ascii::isalpha(r) && r != '_' && (first || !ascii::isdigit(r))) { return false; }; first = false; }; return true; }; hare-0.24.2/hare/parse/000077500000000000000000000000001464473310100145525ustar00rootroot00000000000000hare-0.24.2/hare/parse/+test/000077500000000000000000000000001464473310100156045ustar00rootroot00000000000000hare-0.24.2/hare/parse/+test/expr_test.ha000066400000000000000000000164051464473310100201410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn assignment() void = { roundtrip("export fn main() void = { x = y; *x = *y + 10; *x = *foo(); *y() = bar(); x[y] = z; x[y][z] = foo(); x.y = z; x.y.z = foo(); x[y].z = foo(); x.y[z] = foo(); x += 10; x -= 10; x *= 10; x /= 10; x %= 10; x &= 10; x |= 10; x ^= 10; x >>= 10; x <<= 10; x &&= true; x ||= true; x ^^= true; }; "); }; @test fn binarithm() void = { roundtrip("export fn main() void = *void + void * void / void;\n"); }; @test fn binding() void = { roundtrip("export fn main() void = { let x: int = 1337, y = 7331; const z: int = 42, q: int = 24; const (foo, bar): (int, bool) = (42, true); const (foo, _, bar): (int, uint, bool) = (42, 12u, true); def X: int = 1337, y = 7331; static let p: int = 62893, o = 39826; static const w: int = 62893, t = 39826; }; "); }; @test fn builtin() void = { roundtrip(`export fn main() void = { align(u32); alloc(1234); alloc(1234...); alloc(4321, 1234); append(x, 10); append(x, [10]...); append(x, [10...], 20); static append(x, 10); abort(); abort("surprize"); static abort(); static abort("surprize"); assert(x == 12); assert(x == 12, "number mismatch"); static assert(x == 12); static assert(x == 12, "number mismatch"); delete(x[10]); delete(x[10..20]); delete(x[..]); delete(x.y.z[..]); static delete(x[10]); free(x); insert(x[0], foo); insert(x[0], foo...); insert(x[0], foo, bar); static insert(x[0], foo); len([1, 2, 3, 4]); offset(foo.bar); size(u32); vastart(); vaarg(va); vaend(va); }; `); }; @test fn call() void = { roundtrip("export fn main() void = test();\n\n" "export fn main() void = test(void, void, void);\n\n" "export fn main() void = test(void, void, void...);\n\n" "export fn main() void = test()()(void);\n"); roundtrip_reparse("export fn main() void = test(void,);\n"); }; @test fn cast() void = { roundtrip("export fn main() void = void: int;\n\n" "export fn main() void = void as int;\n\n" "export fn main() void = void is int;\n\n" "export fn main() void = void as null;\n\n" "export fn main() void = void is null;\n\n" "export fn main() void = void: int: uint: u16: u8;\n\n" "export fn main() void = void: int as uint: u16 is u8;\n\n" "export fn main() void = void: int as null: u16 is null;\n\n" "export fn main() void = {\n\tyield void;\n}: int;\n"); }; @test fn compound() void = { roundtrip("export fn main() void = :label {\n" "\tvoid;\n" "};\n"); }; @test fn constant() void = { roundtrip(`export fn main() void = { 2 + (-4 + void) * true % done / ("hello" << '?'); [1, 2, 3, 4]; [1, 2, 3, 4...]; (1, 2, 3); struct { x: int = 10, y: int = 20, }; coords { x: int = 10, y: int = 20, ... }; coords { x = 10, y = 20, }; struct { x: int = 10, struct { y: int = 20, }, }; struct { x: int = 10, coords { y: int = 20, }, }; struct { x: int = 10, namespace::coords { y: int = 20, }, }; coords { ... }; 13.37; 13.37f32; 13.37f64; 6.022e23; 1.616255e-35; 1337z; 1337u; 1337i8; 1337u8; 1337i16; 1337u16; 1337i32; 1337u32; 1337i64; 1337u64; "backslashes\\and \"double quotes\""; '\''; '\\'; }; `); roundtrip_reparse(`export fn main() void = { struct { x: int = 10, y: int = 20 }; coords { x: int = 10, y: int = 20 }; "string " "concatenation"; }; `); }; @test fn control() void = { roundtrip("export fn main() void = { break; break :foo; continue; continue :foo; return; return 2 + 2; }; "); }; @test fn defer_expr() void = { roundtrip("export fn main() void = { defer foo(); }; "); }; @test fn for_expr() void = { roundtrip("fn next() (int | done) = 4; export fn main() void = { for (true) { x; }; for :label (true) { x; }; for (let x = 0; x < 10) { x; }; for (x < 10; x) { x; }; for (let x = 10; x < 10; x) { x; }; for (let x => next()) { x; }; for (let x .. [1, 2, 3]) { x; }; for (let x &.. [1, 2, 3]) { x; }; }; "); }; @test fn if_expr() void = { roundtrip("export fn main() void = { if (x == y) { z; }; if (y == x) z; if (z == q) r else p; if (a == b) c else if (d == e) f else g; }; "); }; @test fn list() void = { roundtrip("export fn main() void = { 2 + 2; call(); }; "); }; @test fn postfix() void = { roundtrip("export fn main() void = x.y;\n\n" "export fn main() void = x.y.z.q;\n\n" "export fn main() void = x().y;\n\n" "export fn main() void = x.42;\n\n" "export fn main() void = x().y.0.q;\n\n" "export fn main() void = x?;\n\n" "export fn main() void = x!;\n\n" "export fn main() void = x()?.y;\n\n" "export fn main() void = x[10];\n\n" "export fn main() void = x[10 + 10][20];\n"); }; @test fn slice() void = { roundtrip("export fn main() void = x[..];\n\n" "export fn main() void = x[123..];\n\n" "export fn main() void = x[123..321];\n\n" "export fn main() void = x[..321];\n"); }; @test fn switch_expr() void = { roundtrip("export fn main() void = { switch (x) { case 1234, 4321 => return y; case 1337 => let x = 0; case => void; case => abort(); case => defer x; }; switch :label (x) { case => void; }; }; "); }; @test fn match_expr() void = { roundtrip("export fn main() void = { match (x) { case let i: size => return y; case foo => return bar; case *int => return bar; case foo::bar => return baz; case null => void; case => abort(); }; match :label (x) { case let s: matchdata => return y; case str => let x = 0; case => defer x; }; }; "); }; @test fn unarithm() void = { roundtrip("export fn main() void = -void;\n\n" "export fn main() void = *void;\n\n" "export fn main() void = ~void;\n\n" "export fn main() void = !void;\n\n" "export fn main() void = &void;\n\n" "export fn main() void = &switch (0) {\n" "case => void;\n" "};\n\n" "export fn main() void = &match (0) {\n" "case => void;\n" "};\n"); }; @test fn yield_expr() void = { roundtrip("export fn main() void = yield;\n\n" "export fn main() void = yield void;\n\n" "export fn main() void = yield :foo;\n\n" "export fn main() void = yield :foo, void;\n"); }; @test fn parenthesis() void = { roundtrip( "export fn main() void = -((2 + 2) * 2);\n\n" "export fn main() void = &(1: uint);\n\n" "export fn main() void = **x;\n\n" "export fn main() void = *alloc(2);\n\n" "export fn main() void = &(&x);\n\n" "export fn main() void = &*&*&x;\n\n" "export fn main() void = x: int: uint: u8;\n\n" "export fn main() void = &array[idx];\n\n" "export fn main() void = &array[idx..];\n\n" "export fn main() void = (array: *[*]u8)[idx];\n\n" "export fn main() void = (s: *object).field;\n\n" "export fn main() void = (s: *object).0;\n\n" "export fn main() void = &offset(header.x);\n\n" "export fn main() void = *((a + b): uintptr);\n\n" "export fn main() void = *value();\n\n" "export fn main() void = (ptr: function)();\n\n" "export fn main() void = func()?.field;\n\n" "export fn main() void = (x: thing)?;\n\n" "export fn main() void = (x: thing)!;\n\n" "export fn main() void = (hey: *[*]u8)[1..2];\n\n" "export fn main() void = (hey: *[*]u8)[0];\n\n" "export fn main() void = &{\n" "\t" "yield 12;\n" "};\n\n" "export fn main() void = ({\n" "\t" "yield err;\n" "})!;\n\n" "export fn main() void = &(if (true) 1 else 2);\n\n" "export fn main() void = (a + b): uintptr: size;\n"); }; hare-0.24.2/hare/parse/+test/ident_test.ha000066400000000000000000000027661464473310100202730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use hare::ast; use hare::lex; use hare::lex::{ltok}; use io::{mode}; use memio; use strings; fn ident_test(in: str, expected: ast::ident, extra: ltok...) void = { let buf = memio::fixed(strings::toutf8(in)); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); match (ident(&lexer)) { case let id: ast::ident => defer ast::ident_free(id); assert(ast::ident_eq(id, expected)); case lex::syntax => assert(len(expected) == 0); case error => abort(); }; for (let i = 0z; i < len(extra); i += 1) { let tok = lex::lex(&lexer)!; defer if (tok.1 is str) free(tok.1 as str); assert(tok.0 == extra[i]); }; let tok = lex::lex(&lexer)!; defer if (tok.1 is str) free(tok.1 as str); assert(tok.0 == ltok::EOF); }; @test fn ident() void = { ident_test(";", [], ltok::SEMICOLON); ident_test("foo", ["foo"]); ident_test("foo::bar", ["foo", "bar"]); ident_test("foo::bar::baz", ["foo", "bar", "baz"]); ident_test("foo::bar;", ["foo", "bar"], ltok::SEMICOLON); // identifier exceeds maximum length let buf: [ast::IDENT_MAX / 2 + ast::IDENT_MAX + 3]u8 = [0...]; let buf = buf[..0]; static append(buf, 'a'); for (let i = 0z; i < ast::IDENT_MAX / 2; i += 1) { static append(buf, [':', ':', 'a']...); }; ident_test(strings::fromutf8(buf)!, ["a"...]: [ast::IDENT_MAX / 2 + 1]str); static append(buf, [':', ':', 'a']...); ident_test(strings::fromutf8(buf)!, []); }; hare-0.24.2/hare/parse/+test/loc.ha000066400000000000000000000104111464473310100166700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use hare::ast; use hare::lex; use io::{mode}; use memio; use strings; fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { let buf = memio::fixed(strings::toutf8(srcs[i])); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let exp = match (expr(&lexer)) { case let exp: ast::expr => yield exp; case let err: error => fmt::errorfln("{}: {}", srcs[i], strerror(err))!; abort(); }; defer ast::expr_finish(&exp); let runes = 0z; let it = strings::iter(srcs[i]); for (strings::next(&it) is rune) { runes += 1; }; assert(exp.start.line == 1 && exp.start.col == 1); assert(exp.end.line == 1 && exp.end.col == runes); }; @test fn expr_loc() void = { expr_testloc("foo", "foo[bar]", "foo.bar", "foo.1"); expr_testloc("alloc(foo)"); expr_testloc("append(foo, bar)", "append(foo, bar, baz)"); expr_testloc("assert(foo)", `assert(foo, "bar")`, "abort()", `abort("foo")`); expr_testloc("foo is bar", "foo as bar"); expr_testloc("foo = bar"); expr_testloc("foo * bar", "foo && bar"); expr_testloc("break", "break :foo"); expr_testloc("foo(bar)"); expr_testloc("foo: bar"); expr_testloc("[foo, bar]", "[foo, bar...]"); expr_testloc("foo { bar = baz, ... }", "struct { foo: bar = baz, }"); expr_testloc("(foo, bar)"); expr_testloc("null", "void", "true", `"שלום"`, "'a'"); expr_testloc("[foo, bar]"); expr_testloc("123", "-123.456", "123z", "123e+3"); expr_testloc("continue", "continue :foo"); expr_testloc("delete(foo[bar])", "delete(foo[bar..baz])"); expr_testloc("for (let foo = 0; bar; baz) quux", "for (let bar = 0; baz; quux) quuux"); expr_testloc("free(foo)"); expr_testloc("if (foo) bar", "if (foo) bar else baz"); expr_testloc("insert(foo[0], bar)", "insert(foo[0], bar, baz)"); expr_testloc("len(foo)"); expr_testloc("{ foo; bar; }", "{ defer foo; }", "{ let foo: bar = baz; }", "{ let foo: bar = baz, quux = quuux; }", "{ const foo: bar = baz; }", "{ const foo: bar = baz, quux = quuux; }"); expr_testloc("match (foo) { case => bar; }"); expr_testloc("offset(foo)"); expr_testloc("foo?", "foo!"); expr_testloc("return", "return foo"); expr_testloc("size(int)"); expr_testloc("switch (foo) { case => bar; }"); expr_testloc("foo[bar..baz]"); expr_testloc("&foo"); expr_testloc("vastart()", "vaarg(ap)", "vaend(ap)"); expr_testloc("yield", "yield foo", "yield :foo, bar"); // We want to check the location of nested expressions, so this can't // use expr_testloc let buf = memio::fixed(strings::toutf8("foo: bar: baz")); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let exp = match (expr(&lexer)) { case let exp: ast::expr => yield exp; case let err: error => fmt::errorln(strerror(err))!; abort(); }; defer ast::expr_finish(&exp); assert(exp.start.line == 1 && exp.start.col == 1); assert(exp.end.line == 1 && exp.end.col == 13); let c = exp.expr as ast::cast_expr; exp = *c.value; assert(exp.start.line == 1 && exp.start.col == 1); assert(exp.end.line == 1 && exp.end.col == 8); c = exp.expr as ast::cast_expr; exp = *c.value; assert(exp.start.line == 1 && exp.start.col == 1); assert(exp.end.line == 1 && exp.end.col == 3); }; fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { let buf = memio::fixed(strings::toutf8(srcs[i])); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let typ = match (_type(&lexer)) { case let typ: ast::_type => yield typ; case let err: error => fmt::errorln(strerror(err))!; abort(); }; defer ast::type_finish(&typ); let runes = 0z; let it = strings::iter(srcs[i]); for (strings::next(&it) is rune) { runes += 1; }; assert(typ.start.line == 1 && typ.start.col == 1); assert(typ.end.line == 1 && typ.end.col == runes); }; @test fn type_loc() void = { type_testloc("foo", "...foo"); type_testloc("int"); type_testloc("enum { FOO = bar }"); type_testloc("fn(foo: bar) baz"); type_testloc("[foo]bar", "[*]foo", "[]foo", "[_]int"); type_testloc("*foo", "nullable *int"); type_testloc("struct { foo: bar }"); type_testloc("union { foo: bar }"); type_testloc("(foo | bar)"); type_testloc("(foo, bar)"); }; hare-0.24.2/hare/parse/+test/roundtrip.ha000066400000000000000000000021361464473310100201460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use hare::ast; use hare::lex; use hare::unparse; use io::{mode}; use memio; use strings; fn roundtrip(src: str) void = { let unsrc = _roundtrip(src); defer free(unsrc); if (unsrc != src) { fmt::errorfln("=== wanted\n{}", src)!; fmt::errorfln("=== got\n{}", unsrc)!; abort(); }; }; fn roundtrip_reparse(src: str) void = { let unsrc = _roundtrip(src); defer free(unsrc); roundtrip(unsrc); }; fn _roundtrip(src: str) str = { let buf = memio::fixed(strings::toutf8(src)); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, "", lex::flag::COMMENTS); let u = ast::subunit { imports = [], decls: []ast::decl = match (decls(&lexer)) { case let decls: []ast::decl => yield decls; case let err: error => fmt::errorln(strerror(err))!; abort(); }, }; defer ast::subunit_finish(u); let out = memio::dynamic(); let z = unparse::subunit(&out, &unparse::syn_wrap, u)!; let unsrc = memio::string(&out)!; assert(z == len(unsrc)); return unsrc; }; hare-0.24.2/hare/parse/+test/types.ha000066400000000000000000000052551464473310100172710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn struct_union() void = { roundtrip("export type foo = struct { @offset(void) x: int, y: int, }; export type bar = union { x: int, // docs docs docs y: int, }; export type baz = struct { embedded, struct { x: int, y: int, }, }; "); roundtrip_reparse("export type foo = struct { x: int, y: int };\n" "export type bar = union { x: int, y: int };\n" "export type baz = struct { embedded, struct { x: int, y: int } };\n"); }; @test fn array_slice() void = { roundtrip("export type foo = []int; export type bar = [*]int; export type baz = [_]int; export type bat = [void]int; "); }; @test fn enum_type() void = { roundtrip("export type foo = enum { X = void, // foo // bar Y = void, Z, // foo Q, // bar }; export type bar = enum uint { X = void, Y = void, Z, Q, }; export type baz = enum rune { X = void, Y = void, Z, Q, }; "); roundtrip_reparse("export type foo = enum { X, Y, Z };\n"); }; @test fn tuple() void = { roundtrip("export type foo = (int, str); export type bar = (a, b::c, d); export type baz = (bat, foo::bar::baz, long_type_name, yet_another_very_long_type_name, this_spans_multiple_lines, for_readability, never_gonna_give_you_up, never_gonna_let_you_down); "); roundtrip_reparse("export type foo = (int, str,);\n"); }; @test fn tagged_union() void = { roundtrip("export type foo = (size | void); export type bar = (a | b::c | ...d); export type baz = (bat | foo::bar::baz | long_type_name | yet_another_very_long_type_name | this_spans_multiple_lines | for_readability | never_gonna_give_you_up | never_gonna_let_you_down); "); }; @test fn enum_comments() void = { roundtrip("type foo = enum { A, // comment B, C, }; "); }; @test fn func() void = { roundtrip("export type foo = fn(int) void; export type foo = fn(int...) void; export type foo = fn(int, ...) void; export type foo = fn( long_param_name: long_type_name, another_one: blablablabla, this_spans: multiple_lines, for_readability: and_stuff, ) void; export type foo = fn( long_param_name: long_type_name, another_one: blablablabla, this_spans: multiple_lines, for_readability: and_stuff... ) void; export type foo = fn( long_param_name: long_type_name, another_one: blablablabla, this_spans: multiple_lines, for_readability: and_stuff, ... ) void; export type foo = fn( long_type_name, blablablabla, multiple_lines, and_stuff = 4, ) void; export type foo = fn( long_type_name, blablablabla, multiple_lines, and_stuff... ) void; export type foo = fn( long_type_name, blablablabla, multiple_lines, and_stuff, ... ) void; "); roundtrip_reparse("type foo = fn(int,) void;"); }; hare-0.24.2/hare/parse/+test/unit_test.ha000066400000000000000000000065221464473310100201410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use hare::ast; use hare::lex; use io::{mode}; use memio; use strings; fn import_eq(i1: ast::import, i2: ast::import) bool = { if (!ast::ident_eq(i1.ident, i2.ident)) { return false; }; let (o1, o2) = match (i1.bindings) { case void => return i2.bindings is void; case let s1: ast::import_alias => match (i2.bindings) { case let s2: ast::import_alias => return s1 == s2; case => return false; }; case let o1: ast::import_members => yield match (i2.bindings) { case let o2: ast::import_members => if (len(o1) != len(o2)) { return false; }; yield (o1, o2); case => return false; }; case ast::import_wildcard => return i2.bindings is ast::import_wildcard; }; for (let i = 0z; i < len(o1); i += 1) { if (o1[i] != o2[i]) { return false; }; }; return true; }; type import_tuple = (ast::ident, (void | ast::import_alias | ast::import_members | ast::import_wildcard)); fn tup_to_import(tup: import_tuple) ast::import = ast::import { ident = tup.0, bindings = tup.1, ... }; @test fn imports() void = { const in = "use foo;\n" "use bar;\n" "use baz::bat;\n\n" "use foo = bar;\n" "use baz = bat;\n" "use qux = quux::corge;\n" "use foo::*;" "use foo::bar::quux::*;" "use foo::{bar};\n" "use foo::{bar,};\n" "use baz::{bat, qux};\n" "use quux::corge::{grault, garply,};\n" "export fn main() void = void;"; let buf = memio::fixed(strings::toutf8(in)); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let mods = imports(&lexer)!; defer ast::imports_finish(mods); let expected: [_]import_tuple = [ (["foo"], void), (["bar"], void), (["baz", "bat"], void), (["bar"], "foo"), (["bat"], "baz"), (["quux", "corge"], "qux"), (["foo"], ast::import_wildcard), (["foo", "bar", "quux"], ast::import_wildcard), (["foo"], ["bar"]), (["foo"], ["bar"]), (["baz"], ["bat", "qux"]), (["quux", "corge"], ["grault", "garply"]), ]; assert(len(mods) == len(expected)); for (let i = 0z; i < len(mods); i += 1) { assert(import_eq(mods[i], tup_to_import(expected[i]))); }; let tok = lex::lex(&lexer) as lex::token; assert(tok.0 == lex::ltok::EXPORT); }; @test fn decls() void = { roundtrip("export type foo::bar = *int, baz = const void;\n\n" "type foo = ...bar;\n\n" "type foo = nullable *fn(x: rune, int) void;\n\n" "export let @symbol(\"_\") foo::bar: int = void, baz: int = void, bat = void;\n\n" "def foo::bar: int = void;\n\n" "def foo::bar = void;\n\n" "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n\n" "@test fn foo(int, ...) void;\n\n" "@test fn foo(...) void;\n\n" "fn foo(bar) void;\n\n" "fn foo(bar::baz) void;\n\n" "export fn main() void = void;\n\n" "fn long(\n" "\tfirst: *const void,\n" "\tsecond: (void | rune | str),\n" "\tthird: size...\n" ") nullable *const void;\n\n" "static abort();\n\n" "static assert(true);\n"); }; @test fn docs() void = { roundtrip("// According to all known laws of aviation, there is no\n" "// way that a bee should be able to fly. Its wings are too\n" "// small to get its fat little body off the ground. The bee,\n" "// of course, flies anyway, because bees don't care what\n" "// humans think is impossible.\n" "export fn main() void = void;\n"); }; hare-0.24.2/hare/parse/README000066400000000000000000000006731464473310100154400ustar00rootroot00000000000000hare::parse provides a parser for Hare source code. The [[subunit]] function will parse a single Hare source file and return a [[hare::ast::subunit]]. Other functions provide parsers for various important Hare sub-terminals, such as [[decls]] and [[imports]]. See the Hare specification for more details: https://harelang.org/specification Most of these functions require the caller to provide a Hare lexer, see [[hare::lex::]] for details. hare-0.24.2/hare/parse/decl.ha000066400000000000000000000133101464473310100157710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use hare::ast; use hare::lex; use hare::lex::{ltok}; use strings; fn attr_symbol(lexer: *lex::lexer) (str | error) = { want(lexer, ltok::LPAREN)?; let t = want(lexer, ltok::LIT_STR)?; let s = t.1 as str; let d = strings::iter(s); match (strings::next(&d)) { case done => void; case let r: rune => synassert(t.2, ascii::isalpha(r) || r == '.' || r == '_', "Invalid symbol")?; }; for (let r => strings::next(&d)) { synassert(t.2, ascii::isalnum(r) || r == '$' || r == '.' || r == '_', "Invalid symbol")?; }; want(lexer, ltok::RPAREN)?; return s; }; // Parses a command-line definition export fn define(lexer: *lex::lexer) (ast::decl_const | error) = { const ident = ident(lexer)?; const _type: nullable *ast::_type = match (try(lexer, ltok::COLON)?) { case lex::token => yield alloc(_type(lexer)?); case void => yield null; }; want(lexer, ltok::EQUAL)?; const init: *ast::expr = alloc(expr(lexer)?); return ast::decl_const { ident = ident, _type = _type, init = init, }; }; fn decl_const( lexer: *lex::lexer, tok: ltok, ) ([]ast::decl_const | error) = { let decl: []ast::decl_const = []; for (true) { append(decl, define(lexer)?); if (try(lexer, ltok::COMMA)? is void) { break; }; }; return decl; }; fn decl_global( lexer: *lex::lexer, tok: ltok, ) ([]ast::decl_global | error) = { let decl: []ast::decl_global = []; for (true) { const (symbol, threadlocal) = match (try(lexer, ltok::ATTR_SYMBOL, ltok::ATTR_THREADLOCAL)?) { case void => yield ("", false); case let t: lex::token => yield if (t.0 == ltok::ATTR_SYMBOL) { yield (attr_symbol(lexer)?, false); } else { yield ("", true); }; }; const ident = ident(lexer)?; const _type: nullable *ast::_type = match (try(lexer, ltok::COLON)?) { case lex::token => yield alloc(_type(lexer)?); case void => yield null; }; const init: nullable *ast::expr = match (try(lexer, ltok::EQUAL)?) { case lex::token => yield alloc(expr(lexer)?); case void => yield null; }; const btok = try(lexer, ltok::COMMA)?; append(decl, ast::decl_global { is_const = tok == ltok::CONST, is_threadlocal = threadlocal, symbol = symbol, ident = ident, _type = _type, init = init, }); if (btok is void) { break; }; }; return decl; }; fn decl_type(lexer: *lex::lexer) ([]ast::decl_type | error) = { let decl: []ast::decl_type = []; for (true) { let ident = ident(lexer)?; want(lexer, ltok::EQUAL)?; let _type = _type(lexer)?; let btok = try(lexer, ltok::COMMA)?; append(decl, ast::decl_type { ident = ident, _type = alloc(_type), }); if (btok is void) { break; }; }; return decl; }; fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { let attr = ast::fndecl_attr::NONE, sym = ""; const attrs = [ ltok::ATTR_FINI, ltok::ATTR_INIT, ltok::ATTR_TEST, ltok::ATTR_SYMBOL ]; for (true) match (try(lexer, attrs...)?) { case void => break; case let t: lex::token => synassert(t.2, t.0 == ltok::ATTR_SYMBOL || attr == 0, "Only one of @init, @fini, or @test may be provided")?; switch (t.0) { case ltok::ATTR_FINI => attr = ast::fndecl_attr::FINI; case ltok::ATTR_INIT => attr = ast::fndecl_attr::INIT; case ltok::ATTR_TEST => attr = ast::fndecl_attr::TEST; case ltok::ATTR_SYMBOL => sym = attr_symbol(lexer)?; case => abort("unreachable"); }; }; want(lexer, ltok::FN)?; let ident_loc = lex::mkloc(lexer); let ident = ident(lexer)?; let proto_start = lex::mkloc(lexer); let prototype = prototype(lexer)?; let proto_end = lex::prevloc(lexer); let tok = want(lexer, ltok::EQUAL, ltok::SEMICOLON)?; let body = switch (tok.0) { case ltok::EQUAL => for (let param &.. prototype.params) { synassert(param.loc, len(param.name) > 0, "Expected parameter name in function declaration")?; }; yield alloc(expr(lexer)?); case ltok::SEMICOLON => lex::unlex(lexer, tok); yield null; case => abort(); // unreachable }; return ast::decl_func { symbol = sym, ident = ident, prototype = alloc(ast::_type { start = proto_start, end = proto_end, flags = 0, repr = prototype, }), body = body, attrs = attr, }; }; // Parses a declaration. export fn decl(lexer: *lex::lexer) (ast::decl | error) = { const start = lex::mkloc(lexer); let comment = ""; if (try(lexer, ltok::STATIC)? is lex::token) { comment = strings::dup(lex::comment(lexer)); let expr = assert_expr(lexer, true)?; want(lexer, ltok::SEMICOLON)?; return ast::decl { exported = false, start = start, end = expr.end, decl = expr.expr as ast::assert_expr, docs = comment, }; }; let exported = match (try(lexer, ltok::EXPORT)?) { case void => yield false; case lex::token => comment = strings::dup(lex::comment(lexer)); yield true; }; const toks = [ltok::CONST, ltok::LET, ltok::DEF, ltok::TYPE]; const next = try(lexer, toks...)?; if (comment == "") { comment = strings::dup(lex::comment(lexer)); }; let decl = match (next) { case void => yield decl_func(lexer)?; case let t: lex::token => yield switch (t.0) { case ltok::TYPE => yield decl_type(lexer)?; case ltok::LET, ltok::CONST => yield decl_global(lexer, t.0)?; case ltok::DEF => yield decl_const(lexer, t.0)?; case => abort(); }; }; want(lexer, ltok::SEMICOLON)?; return ast::decl { exported = exported, start = start, end = lex::mkloc(lexer), decl = decl, docs = comment, }; }; // Parses the declarations for a sub-unit. export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = { let decls: []ast::decl = []; for (true) { if (peek(lexer, ltok::EOF)? is lex::token) break; append(decls, decl(lexer)?); }; return decls; }; hare-0.24.2/hare/parse/doc/000077500000000000000000000000001464473310100153175ustar00rootroot00000000000000hare-0.24.2/hare/parse/doc/+test.ha000066400000000000000000000075511464473310100166730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use hare::lex; use hare::unparse; use memio; use os; use strings; fn assert_doc_eq(a: doc, b: doc) void = { assert(len(a) == len(b)); for (let i = 0z; i < len(a); i += 1) { match (a[i]) { case let a: paragraph => const b = b[i] as paragraph; assert_paragraph_eq(a, b); case let a: list => const b = b[i] as list; assert(len(a) == len(b)); for (let i = 0z; i < len(a); i += 1) { assert_paragraph_eq(a[i], b[i]); }; case let a: code_sample => const b = b[i] as code_sample; if (a != b) { fmt::errorfln("=== wanted code sample\n{}", b)!; fmt::errorfln("=== got code sample\n{}", a)!; abort(); }; }; }; }; fn assert_paragraph_eq(a: paragraph, b: paragraph) void = { fmt::errorln(len(a), len(b))!; assert(len(a) == len(b)); for (let i = 0z; i < len(a); i += 1) { match (a[i]) { case let a: str => const b = b[i] as str; if (a != b) { fmt::errorfln("=== wanted text\n{}", b)!; fmt::errorfln("=== got text\n{}", a)!; abort(); }; case let a: decl_ref => const b = b[i] as decl_ref; if (!ast::ident_eq(a, b)) { fmt::error("=== wanted decl_ref ")!; unparse::ident(os::stderr, b)!; fmt::error("\n=== got decl_ref ")!; unparse::ident(os::stderr, a)!; fmt::errorln()!; abort(); }; case let a: mod_ref => const b = b[i] as mod_ref; if (!ast::ident_eq(a, b)) { fmt::error("=== wanted mod_ref ")!; unparse::ident(os::stderr, b)!; fmt::error("\n=== got mod_ref ")!; unparse::ident(os::stderr, a)!; fmt::errorln()!; abort(); }; }; }; }; @test fn doc() void = { // if you have some way in your editor to distinguish tabs from spaces // you're gonna want to use it here let in = memio::fixed(strings::toutf8( ` Blablabla asdfghjkl qwerty[[uiop::]] zxcvbnm new paragraph - list starting immediately after paragraph - another list item - yet another but this one spans multiple lines -no leading space still multiple lines code sample line 2 no leading space continuing the same code sample indentation is preserved as well as multiple spaces this is now a paragraph because of the [[leading::spaces]] - list starting [[after]] [[empty::line::]] but with only [one item]] - code sample starting immediately after list with one empty item` )); const doc = parse(&in, lex::location { ... })!; defer freeall(doc); assert_doc_eq(doc, [ [ "Blablabla asdfghjkl qwerty", ["uiop"]: mod_ref, " zxcvbnm", ]: paragraph, ["new paragraph"]: paragraph, [ ["list starting immediately after paragraph"], ["another list item"], ["yet another but this one spans multiple lines"], ["no leading space still multiple lines"], ]: list, `code sample line 2 no leading space continuing the same code sample indentation is preserved as well as multiple spaces`: code_sample, [ " this is now a paragraph because of the ", ["leading", "spaces"]: decl_ref, ]: paragraph, [ [ "list starting ", ["after"]: decl_ref, " ", ["empty", "line"]: mod_ref, ], ]: list, ["but with only [one item]]"]: paragraph, [[]]: list, "code sample starting immediately after list with one empty item": code_sample, ]); }; @test fn invalid_ref() void = { const tests: [_](str, uint, uint) = [ ("[[abort]]", 1, 3), ("[[::foo]]", 1, 3), ("[[]]", 1, 3), ("[[foo]", 1, 7), (" \t\n a\n asdf\t [[]]", 3, 12), ]; for (let i = 0u; i < len(tests): uint; i += 1) { let in = memio::fixed(strings::toutf8(tests[i].0)); fmt::errorln(tests[i].0)!; const err = parse(&in, lex::location { path = "", line = i + 1, col = i + 1, }) as lex::syntax; assert(err.0.path == ""); assert(err.0.line == i + tests[i].1); assert(err.0.col == i + tests[i].2); }; }; hare-0.24.2/hare/parse/doc/README000066400000000000000000000001771464473310100162040ustar00rootroot00000000000000hare::parse::doc parses haredoc markup into an abstract representation. The haredoc markup format is documented in haredoc(5). hare-0.24.2/hare/parse/doc/doc.ha000066400000000000000000000153161464473310100164040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use encoding::utf8; use hare::ast; use hare::lex; use hare::parse; use io; use memio; use strings; // A representation of a complete haredoc document. export type doc = [](paragraph | list | code_sample); // A paragraph of text. export type paragraph = [](str | decl_ref | mod_ref); // A bulleted list. export type list = []paragraph; // A code sample. export type code_sample = str; // A reference to a declaration. export type decl_ref = ast::ident; // A reference to a module. export type mod_ref = ast::ident; // All possible error types. export type error = !lex::error; // Converts an error into a human-friendly string. The result may be statically // allocated. export fn strerror(err: error) const str = lex::strerror(err); // Parses a haredoc document from an [[io::handle]]. 'start' is the location of // the top-left corner of the document, for accurate locations in error messages // (e.g. declaration documentation starts at col=3; READMEs start at col=1). export fn parse(in: io::handle, start: lex::location) (doc | error) = { let sc = bufio::newscanner(in); defer bufio::finish(&sc); match (_parse(&sc)) { case let doc: doc => return doc; case let err: lex::syntax => err.0.path = start.path; err.0.line += start.line; err.0.col += start.col; return err; case let err: io::error => return err; case utf8::invalid => // XXX: the location for this error is inaccurate return lex::syntaxerr(start, "Invalid UTF-8"); }; }; fn _parse(sc: *bufio::scanner) (doc | ...error | utf8::invalid) = { let loc = lex::location { ... }; let doc: doc = []; for (let r => bufio::scan_rune(sc)?) { if (r == ' ') { r = match (bufio::scan_rune(sc)?) { case io::EOF => break; case let r: rune => loc.col = 1; yield r; }; }; switch (r) { case '\t' => loc.col = 8; append(doc, scan_code_sample(sc, &loc)?); case '\n' => loc.line += 1; loc.col = 0; case '-' => loc.col += 1; append(doc, scan_list(sc, &loc)?); case => bufio::unreadrune(sc, r); append(doc, scan_paragraph(sc, &loc)?); }; }; return doc; }; fn scan_code_sample( sc: *bufio::scanner, loc: *lex::location, ) (code_sample | ...error | utf8::invalid) = { let s = memio::dynamic(); for (let r => bufio::scan_rune(sc)?) { switch (r) { case '\t' => loc.col += 8 - loc.col % 8; memio::appendrune(&s, r)!; case '\n' => loc.line += 1; loc.col = 0; let (r, space) = match (bufio::scan_rune(sc)?) { case io::EOF => break; case let r: rune => if (r != ' ') yield (r, false); yield match (bufio::scan_rune(sc)?) { case io::EOF => break; case let r: rune => yield (r, true); }; }; switch (r) { case '\t' => loc.col = 8; memio::appendrune(&s, '\n')!; case '\n' => memio::appendrune(&s, '\n')!; bufio::unreadrune(sc, '\n'); case => bufio::unreadrune(sc, r); if (space) { bufio::unreadrune(sc, ' '); }; break; }; case => loc.col += 1; memio::appendrune(&s, r)!; }; }; return memio::string(&s)!; }; fn scan_list( sc: *bufio::scanner, loc: *lex::location, ) (list | ...error | utf8::invalid) = { let li: list = []; for (true) { match (bufio::scan_rune(sc)?) { case io::EOF => append(li, []); break; case let r: rune => if (r != ' ') { bufio::unreadrune(sc, r); }; }; append(li, scan_paragraph(sc, loc)?); match (bufio::scan_rune(sc)?) { case io::EOF => break; case let r: rune => if (r != '-') { bufio::unreadrune(sc, r); break; }; }; }; return li; }; // XXX: should be local to scan_paragraph, once that's possible type state = enum { NORMAL, SPACE, NEWLINE, }; fn scan_paragraph( sc: *bufio::scanner, loc: *lex::location, ) (paragraph | ...error | utf8::invalid) = { let p: paragraph = []; let s = memio::dynamic(); defer io::close(&s)!; let state = state::NORMAL; for (let r => bufio::scan_rune(sc)?) { switch (r) { case '\t' => if (state == state::NEWLINE && loc.col <= 1) { bufio::unreadrune(sc, r); break; }; loc.col += 8 - loc.col % 8; if (state == state::NORMAL) { state = state::SPACE; }; continue; case '\n' => loc.line += 1; loc.col = 0; if (state == state::NEWLINE) { break; }; state = state::NEWLINE; continue; case ' ' => loc.col += 1; if (state == state::NORMAL) { state = state::SPACE; }; continue; case '-' => if (state != state::NEWLINE || loc.col > 1) yield; // XXX: we may want to reconsider if recognizing '-' // here is too lenient (what if a line begins with a // negative number?) bufio::unreadrune(sc, r); break; case => void; }; if (state != state::NORMAL) { memio::appendrune(&s, ' ')!; }; state = state::NORMAL; loc.col += 1; if (r != '[') { memio::appendrune(&s, r)!; continue; }; r = match (bufio::scan_rune(sc)?) { case io::EOF => memio::appendrune(&s, '[')!; break; case let r: rune => yield r; }; if (r != '[') { memio::appendrune(&s, '[')!; bufio::unreadrune(sc, r); continue; }; loc.col += 1; const part = memio::string(&s)!; if (part != "") { append(p, strings::dup(part)); memio::reset(&s); }; let lexer = lex::init(sc, loc.path); const (ident, mod) = match (parse::ident_trailing(&lexer)) { case let id: (ast::ident, bool) => yield id; case let err: lex::syntax => if (err.0.line == 1) { err.0.col += loc.col - 1; }; err.0.line += loc.line - 1; return err; case let err: io::error => return err; }; // intentionally not using lex::mkloc, so whitespace is // accounted for if (lexer.loc.0 == 1) { loc.col += lexer.loc.1 - 1; } else { loc.col = 0; }; loc.line += lexer.loc.0 - 1; append(p, if (mod) ident: mod_ref else ident: decl_ref); if (lexer.un.0 == lex::ltok::RBRACKET) { match (bufio::scan_rune(sc)?) { case io::EOF => void; case let r: rune => if (r == ']') { loc.col += 1; continue; }; }; }; return lex::syntaxerr(*loc, "Unterminated reference"); }; const part = memio::string(&s)!; if (part != "") { append(p, strings::dup(part)); }; return p; }; // Frees resources associated with a [[doc]]. export fn freeall(doc: doc) void = { for (let d .. doc) { match (d) { case let p: paragraph => free_paragraph(p); case let l: list => for (let p .. l) { free_paragraph(p); }; free(l); case let c: code_sample => free(c); }; }; free(doc); }; fn free_paragraph(p: paragraph) void = { for (let entry .. p) { match (entry) { case let s: str => free(s); case let d: decl_ref => ast::ident_free(d); case let m: mod_ref => ast::ident_free(m); }; }; free(p); }; hare-0.24.2/hare/parse/expr.ha000066400000000000000000001045631464473310100160530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; use hare::lex::{ltok}; use math; use strings; use types; // Parses an expression. export fn expr(lexer: *lex::lexer) (ast::expr | error) = { const loc = lex::mkloc(lexer); // All assignment-op tokens const atoks: []ltok = [ ltok::EQUAL, ltok::BANDEQ, ltok::BOREQ, ltok::BXOREQ, ltok::DIVEQ, ltok::LANDEQ, ltok::LOREQ, ltok::LXOREQ, ltok::LSHIFTEQ, ltok::MINUSEQ, ltok::MODEQ, ltok::PLUSEQ, ltok::RSHIFTEQ, ltok::TIMESEQ, ]; const ex = match (peek(lexer, ltok::IF, ltok::FOR, ltok::BREAK, ltok::CONTINUE, ltok::RETURN, ltok::YIELD)?) { case void => yield binarithm(lexer, void, 0)?; case let tok: lex::token => yield switch (tok.0) { case ltok::IF => yield if_expr(lexer)?; case ltok::FOR => yield for_expr(lexer)?; case ltok::BREAK, ltok::CONTINUE, ltok::RETURN => yield control(lexer)?; case ltok::YIELD => yield yield_expr(lexer)?; case => abort(); // Invariant }; }; const tok = match (try(lexer, atoks...)?) { case let tok: lex::token => yield tok; case => return ex; }; const is_obj_selector = match (ex.expr) { case (ast::access_expr | ast::slice_expr) => yield true; case let ex: ast::unarithm_expr => yield ex.op == ast::unarithm_op::DEREF; case => yield false; }; synassert(lex::mkloc(lexer), is_obj_selector, "Expected an object-selector, pointer dereference, or slice for assignment target")?; const ex = ast::assign_expr { op = switch (tok.0) { case ltok::EQUAL => yield void; case ltok::BANDEQ => yield ast::binarithm_op::BAND; case ltok::BOREQ => yield ast::binarithm_op::BOR; case ltok::BXOREQ => yield ast::binarithm_op::BXOR; case ltok::DIVEQ => yield ast::binarithm_op::DIV; case ltok::LANDEQ => yield ast::binarithm_op::LAND; case ltok::LOREQ => yield ast::binarithm_op::LOR; case ltok::LSHIFTEQ => yield ast::binarithm_op::LSHIFT; case ltok::LXOREQ => yield ast::binarithm_op::LXOR; case ltok::MINUSEQ => yield ast::binarithm_op::MINUS; case ltok::MODEQ => yield ast::binarithm_op::MODULO; case ltok::PLUSEQ => yield ast::binarithm_op::PLUS; case ltok::RSHIFTEQ => yield ast::binarithm_op::RSHIFT; case ltok::TIMESEQ => yield ast::binarithm_op::TIMES; case => abort(); // unreachable }, object = alloc(ex), value = alloc(expr(lexer)?), }; return ast::expr { start = loc, end = lex::prevloc(lexer), expr = ex, }; }; fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const tok = want(lexer, ltok::ABORT, ltok::ASSERT)?; let expr = switch (tok.0) { case ltok::ABORT => want(lexer, ltok::LPAREN)?; const msg: nullable *ast::expr = match (peek(lexer, ltok::RPAREN)?) { case lex::token => yield null; case => yield alloc(expr(lexer)?); }; want(lexer, ltok::RPAREN)?; yield ast::assert_expr { cond = null, message = msg, is_static = is_static, }; case ltok::ASSERT => want(lexer, ltok::LPAREN)?; const cond: nullable *ast::expr = alloc(expr(lexer)?); const msg: nullable *ast::expr = match (try(lexer, ltok::COMMA)?) { case lex::token => yield alloc(expr(lexer)?); case => yield null; }; want(lexer, ltok::RPAREN)?; yield ast::assert_expr { cond = cond, message = msg, is_static = is_static, }; case => abort(); // unreachable }; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::ALLOC)?; want(lexer, ltok::LPAREN)?; const init = alloc(expr(lexer)?); const expr = switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) { case ltok::COMMA => const capacity = alloc(expr(lexer)?); want(lexer, ltok::RPAREN)?; yield ast::alloc_expr { init = init, form = ast::alloc_form::COPY, capacity = capacity, }; case ltok::ELLIPSIS => want(lexer, ltok::RPAREN)?; yield ast::alloc_expr { init = init, form = ast::alloc_form::COPY, capacity = null, }; case ltok::RPAREN => yield ast::alloc_expr { init = init, form = ast::alloc_form::OBJECT, capacity = null, }; case => abort(); // unreachable }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = expr, }; }; fn append_insert_expr( lexer: *lex::lexer, is_static: bool, ) (ast::expr | error) = { const tok = want(lexer, ltok::APPEND, ltok::INSERT)?; want(lexer, ltok::LPAREN)?; const object = if (tok.0 == ltok::APPEND) objsel(lexer)? else idxexpr(lexer)?; want(lexer, ltok::COMMA)?; const value = expr(lexer)?; let length: nullable *ast::expr = null; let variadic = false; match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) { case let tok: lex::token => switch (tok.0) { case ltok::COMMA => length = alloc(expr(lexer)?); case ltok::ELLIPSIS => variadic = true; case => abort(); }; case void => void; }; want(lexer, ltok::RPAREN)?; let expr = ast::append_expr { object = alloc(object), value = alloc(value), length = length, variadic = variadic, is_static = is_static, }; const expr = if (tok.0 == ltok::INSERT) { yield expr: ast::insert_expr; } else expr; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn measurement(lexer: *lex::lexer) (ast::expr | error) = { const tok = want(lexer, ltok::LEN, ltok::ALIGN, ltok::SIZE, ltok::OFFSET)?; want(lexer, ltok::LPAREN)?; const expr = switch (tok.0) { case ltok::LEN => yield alloc(expr(lexer)?): ast::len_expr; case ltok::ALIGN => yield alloc(_type(lexer)?): ast::align_expr; case ltok::SIZE => yield alloc(_type(lexer)?): ast::size_expr; case ltok::OFFSET => yield alloc(expr(lexer)?): ast::offset_expr; case => abort(); // unreachable }; want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn binarithm( lexer: *lex::lexer, lvalue: (ast::expr | void), i: int, ) (ast::expr | error) = { // Precedence climbing parser // https://en.wikipedia.org/wiki/Operator-precedence_parser let lvalue = match (lvalue) { case void => yield cast(lexer, void)?; case let expr: ast::expr => yield expr; }; let tok = lex::lex(lexer)?; for (let j = precedence(tok); j >= i; j = precedence(tok)) { const op = binop_for_tok(tok); let rvalue = cast(lexer, void)?; tok = lex::lex(lexer)?; for (let k = precedence(tok); k > j; k = precedence(tok)) { lex::unlex(lexer, tok); rvalue = binarithm(lexer, rvalue, k)?; tok = lex::lex(lexer)?; }; const expr = ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::binarithm_expr { op = op, lvalue = alloc(lvalue), rvalue = alloc(rvalue), }, }; lvalue = expr; }; lex::unlex(lexer, tok); return lvalue; }; fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = { let fields: ast::binding_unpack = []; for (true) { const (tok, value, _) = want(lexer, ltok::NAME, ltok::UNDERSCORE)?; if (tok == ltok::UNDERSCORE) { append(fields, void); } else { append(fields, value as str); }; if (len(fields) == 1) { want(lexer, ltok::COMMA)?; } else { match (try(lexer, ltok::COMMA)?) { case void => break; case lex::token => void; }; }; }; want(lexer, ltok::RPAREN)?; return fields; }; fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const loc = lex::mkloc(lexer); const tok = want(lexer, ltok::DEF, ltok::CONST, ltok::LET)?.0; const kind = switch (tok) { case ltok::DEF => assert(!is_static); yield ast::binding_kind::DEF; case ltok::CONST => yield ast::binding_kind::CONST; case ltok::LET => yield ast::binding_kind::LET; case => abort(); // unreachable }; let bindings: []ast::binding = []; for (true) { const (tok, value, _) = want(lexer, ltok::NAME, ltok::LPAREN)?; const name = switch (tok) { case ltok::NAME => yield value as str; case ltok::LPAREN => if (kind == ast::binding_kind::DEF) { return syntaxerr(lex::mkloc(lexer), "Can't use tuple unpacking with def"); }; yield binding_unpack(lexer)?; case => abort(); }; const btype: nullable *ast::_type = if (try(lexer, ltok::COLON)? is lex::token) { yield alloc(_type(lexer)?); } else null; want(lexer, ltok::EQUAL)?; const init = alloc(expr(lexer)?); append(bindings, ast::binding { name = name, _type = btype, init = init, }); match (try(lexer, ltok::COMMA)?) { case void => break; case lex::token => void; }; }; return ast::expr { start = loc, end = lex::prevloc(lexer), expr = ast::binding_expr { is_static = is_static, kind = kind, bindings = bindings, }, }; }; fn builtin(lexer: *lex::lexer) (ast::expr | error) = { const tok = match (peek(lexer, ltok::ALIGN, ltok::ALLOC, ltok::APPEND, ltok::FREE, ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT, ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET, ltok::VASTART, ltok::VAARG, ltok::VAEND)?) { case let tok: lex::token => yield tok; case void => return postfix(lexer, void); }; switch (tok.0) { case ltok::ALLOC => return alloc_expr(lexer); case ltok::APPEND, ltok::INSERT => return append_insert_expr(lexer, false); case ltok::DELETE => return delete_expr(lexer, false); case ltok::FREE => return free_expr(lexer); case ltok::ABORT, ltok::ASSERT => return assert_expr(lexer, false); case ltok::STATIC => want(lexer, ltok::STATIC)!; return static_expr(lexer); case ltok::ALIGN, ltok::SIZE, ltok::LEN, ltok::OFFSET => return measurement(lexer); case ltok::VASTART => want(lexer, ltok::VASTART)?; want(lexer, ltok::LPAREN)?; want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = void: ast::vastart_expr: ast::variadic_expr, }; case ltok::VAARG => want(lexer, ltok::VAARG)?; want(lexer, ltok::LPAREN)?; const expr = alloc(objsel(lexer)?); want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr: ast::vaarg_expr: ast::variadic_expr, }; case ltok::VAEND => want(lexer, ltok::VAEND)?; want(lexer, ltok::LPAREN)?; const expr = alloc(objsel(lexer)?); want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr: ast::vaend_expr: ast::variadic_expr, }; case => abort(); // Invariant }; }; fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { let args: []*ast::expr = []; let variadic = false; for (true) { match (try(lexer, ltok::RPAREN)?) { case lex::token => break; case void => void; }; append(args, alloc(expr(lexer)?)); match (try(lexer, ltok::ELLIPSIS)?) { case lex::token => variadic = true; want(lexer, ltok::RPAREN)?; break; case void => void; }; switch (want(lexer, ltok::COMMA, ltok::RPAREN)?.0) { case ltok::RPAREN => break; case => void; }; }; return ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::call_expr { lvalue = alloc(lvalue), variadic = variadic, args = args, }, }; }; fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { const lvalue = match (lvalue) { case void => yield unarithm(lexer)?; case let e: ast::expr => yield e; }; const tok = match (try(lexer, ltok::COLON, ltok::AS, ltok::IS)?) { case void => return lvalue; case let tok: lex::token => yield tok.0; }; const kind = switch (tok) { case ltok::COLON => yield ast::cast_kind::CAST; case ltok::AS => yield ast::cast_kind::ASSERTION; case ltok::IS => yield ast::cast_kind::TEST; case => abort(); }; let typ = match (try(lexer, ltok::NULL)?) { case let t: lex::token => yield alloc(ast::_type { start = t.2, end = lex::prevloc(lexer), flags = 0, repr = ast::builtin_type::NULL, }); case void => yield alloc(_type(lexer)?); }; return cast(lexer, ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::cast_expr { kind = kind, value = alloc(lvalue), _type = typ, }, })?; }; fn literal(lexer: *lex::lexer) (ast::expr | error) = { const tok = want(lexer)?; const expr: ast::literal_expr = switch (tok.0) { case ltok::LIT_RCONST, ltok::LIT_STR => yield tok.1 as (rune | str); case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64, ltok::LIT_UINT, ltok::LIT_SIZE => yield ast::number_literal { suff = tok.0, value = tok.1 as u64, sign = false, }; case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64, ltok::LIT_INT => const n = tok.1 as u64; yield ast::number_literal { suff = tok.0, value = n: i64, sign = false, }; case ltok::LIT_ICONST => const n = tok.1 as u64; yield ast::number_literal { suff = tok.0, value = if (n <= types::I64_MAX: u64) n: i64 else n, sign = false, }; case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => yield ast::number_literal { suff = tok.0, value = tok.1 as f64, sign = false, }; case ltok::VOID => yield void; case ltok::DONE => yield done; case ltok::TRUE => yield true; case ltok::FALSE => yield false; case ltok::NULL => yield ast::_null; case => return syntaxerr(lex::mkloc(lexer), "Expected literal expression"); }; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn control(lexer: *lex::lexer) (ast::expr | error) = { let tok = want(lexer, ltok::BREAK, ltok::CONTINUE, ltok::RETURN)?; let label = if (tok.0 == ltok::BREAK || tok.0 == ltok::CONTINUE) { yield match (try(lexer, ltok::COLON)?) { case lex::token => yield want(lexer, ltok::NAME)?.1 as str; case void => yield ""; }; } else ""; const expr = switch (tok.0) { case ltok::BREAK => yield label: ast::break_expr; case ltok::CONTINUE => yield label: ast::continue_expr; case ltok::RETURN => yield match (peek(lexer, ltok::COMMA, ltok::ELSE, ltok::RBRACE, ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON, ltok::EOF)?) { case void => yield alloc(expr(lexer)?): ast::return_expr; case lex::token => yield null: ast::return_expr; }; case => abort(); // unreachable }; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn delete_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const start = want(lexer, ltok::DELETE)?; want(lexer, ltok::LPAREN)?; const expr = alloc(postfix(lexer, void)?); // TODO: Assert that this was an indexing expression want(lexer, ltok::RPAREN)?; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::delete_expr { object = expr, is_static = is_static, }, }; }; fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = { let items: []*ast::expr = []; const start = want(lexer, ltok::LBRACE, ltok::COLON)?; const label = switch (start.0) { case ltok::COLON => const tok = want(lexer, ltok::NAME)?; want(lexer, ltok::LBRACE)?; yield tok.1 as str; case => yield ""; }; for (true) { append(items, alloc(stmt(lexer)?)); if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::compound_expr { exprs = items, label = label, }, }; }; fn stmt(lexer: *lex::lexer) (ast::expr | error) = { const expr = match (try(lexer, ltok::DEFER, ltok::DEF, ltok::LET, ltok::CONST, ltok::STATIC)?) { case let tok: lex::token => yield switch (tok.0) { case ltok::DEFER => let expr = alloc(expr(lexer)?); yield ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr: ast::defer_expr, }; case ltok::DEF, ltok::CONST, ltok::LET => lex::unlex(lexer, tok); yield binding(lexer, false)?; case ltok::STATIC => yield match (peek(lexer, ltok::LET, ltok::CONST)?) { case lex::token => yield binding(lexer, true)?; case void => yield static_expr(lexer)?; }; case => abort(); // unreachable }; case void => yield expr(lexer)?; }; want(lexer, ltok::SEMICOLON)?; return expr; }; fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { const tok = want(lexer, ltok::FOR)?; const label = if (try(lexer, ltok::COLON)? is lex::token) { const tok = want(lexer, ltok::NAME)?; yield tok.1 as str; } else ""; want(lexer, ltok::LPAREN)?; let kind = void: (ast::for_kind | void); let predicate_loc = lex::mkloc(lexer); const bindings = match (try(lexer, ltok::LET, ltok::CONST)?) { case let tok: lex::token => const binding_kind = switch (tok.0) { case ltok::LET => yield ast::binding_kind::LET; case ltok::CONST => yield ast::binding_kind::CONST; case => abort(); // unreachable }; let bindings: []ast::binding = []; for (true) { const (tok, value, _) = want(lexer, ltok::NAME, ltok::LPAREN)?; const binding_name = switch (tok) { case ltok::NAME => yield value as str; case ltok::LPAREN => yield binding_unpack(lexer)?; case => abort(); // unreachable }; const btype: nullable *ast::_type = if (try(lexer, ltok::COLON)? is lex::token) { yield alloc(_type(lexer)?); } else null; const (tok, _, _) = want(lexer, ltok::EQUAL, ltok::DOUBLE_DOT, ltok::BAND, ltok::ARROW)?; if (kind is void) { switch (tok) { case ltok::EQUAL => kind = ast::for_kind::ACCUMULATOR; case ltok::DOUBLE_DOT => kind = ast::for_kind::EACH_VALUE; case ltok::BAND => want(lexer, ltok::DOUBLE_DOT)?; kind = ast::for_kind::EACH_POINTER; case ltok::ARROW => kind = ast::for_kind::ITERATOR; case => abort(); // unreachable }; } else if (kind as ast::for_kind != ast::for_kind::ACCUMULATOR || tok != ltok::EQUAL) { return syntaxerr(lex::mkloc(lexer), "Cannot create multiple bindings in non-c-style loop"); }; const init_expr = alloc(expr(lexer)?); append(bindings, ast::binding { name = binding_name, _type = btype, init = init_expr, }); match (try(lexer, ltok::COMMA)?) { case lex::token => void; case void => break; }; }; if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) { want(lexer, ltok::SEMICOLON)?; }; yield alloc(ast::expr { start = predicate_loc, end = lex::prevloc(lexer), expr = ast::binding_expr { is_static = false, kind = binding_kind, bindings = bindings, }, }); case void => kind = ast::for_kind::ACCUMULATOR; yield null; }; const cond: nullable *ast::expr = null; const afterthought: nullable *ast::expr = null; if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) { cond = alloc(expr(lexer)?); match (try(lexer, ltok::SEMICOLON)) { case lex::token => afterthought = alloc(expr(lexer)?); case void => void; }; }; want(lexer, ltok::RPAREN)?; const body = alloc(expr(lexer)?); return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = ast::for_expr { kind = kind as ast::for_kind, bindings = bindings, cond = cond, afterthought = afterthought, body = body, label = label, }, }; }; fn free_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::FREE)?; want(lexer, ltok::LPAREN)?; const expr = alloc(expr(lexer)?); want(lexer, ltok::RPAREN)?; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = expr: ast::free_expr, }; }; fn if_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::IF)?; want(lexer, ltok::LPAREN)?; const cond = alloc(expr(lexer)?); want(lexer, ltok::RPAREN)?; const tbranch = alloc(expr(lexer)?); const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) { case void => yield null; case lex::token => yield alloc(expr(lexer)?); }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::if_expr { cond = cond, tbranch = tbranch, fbranch = fbranch, }, }; }; fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { let is_slice = false; let start: nullable *ast::expr = null, end: nullable *ast::expr = null; if (try(lexer, ltok::DOUBLE_DOT)? is lex::token) { is_slice = true; } else { start = alloc(expr(lexer)?); }; if (!is_slice && try(lexer, ltok::DOUBLE_DOT)? is lex::token) { is_slice = true; }; if (is_slice && peek(lexer, ltok::RBRACKET)? is void) { end = alloc(expr(lexer)?); }; want(lexer, ltok::RBRACKET)?; return ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = if (is_slice) ast::slice_expr { object = alloc(lvalue), start = start, end = end, } else ast::access_index { object = alloc(lvalue), index = { assert(end == null); yield start as *ast::expr; }, }, }; }; fn objsel(lexer: *lex::lexer) (ast::expr | error) = { let expr = postfix(lexer, void)?; synassert(lex::mkloc(lexer), expr.expr is ast::access_expr, "Expected object selector")?; return expr; }; fn idxexpr(lexer: *lex::lexer) (ast::expr | error) = { const expr = postfix(lexer, void)?; synassert(lex::mkloc(lexer), expr.expr is ast::access_expr && expr.expr as ast::access_expr is ast::access_index, "Expected indexing expression")?; return expr; }; fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = { let tok = peek(lexer)? as lex::token; if (tok.0 >= ltok::LIT_U8 && tok.0 <= ltok::LAST_LITERAL) { return literal(lexer); }; switch (tok.0) { case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID, ltok::DONE => return literal(lexer); case ltok::LBRACKET => return plain_array(lexer)?; case ltok::STRUCT => let s = plain_struct(lexer, [])?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = s, }; case ltok::LPAREN => want(lexer, ltok::LPAREN)?; let ex = expr(lexer)?; switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) { case ltok::RPAREN => return ex; case ltok::COMMA => return plain_tuple(lexer, ex, tok.2)?; case => abort(); }; case ltok::NAME => let id = ident(lexer)?; match (peek(lexer, ltok::LBRACE)?) { case void => return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = id: ast::access_identifier, }; case lex::token => let s = plain_struct(lexer, id)?; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = s, }; }; case => return syntaxerr(lex::mkloc(lexer), "Unexpected {}, was expecting an expression", lex::tokstr(tok)); }; }; fn plain_array(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::LBRACKET)?; let values: []*ast::expr = []; let expand = false; for (true) { match (try(lexer, ltok::RBRACKET)?) { case lex::token => break; case void => void; }; append(values, alloc(expr(lexer)?)); match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) { case void => want(lexer, ltok::RBRACKET)?; break; case let tok: lex::token => switch (tok.0) { case ltok::ELLIPSIS => expand = true; want(lexer, ltok::RBRACKET)?; break; case ltok::COMMA => void; case => abort(); }; }; }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::array_literal { expand = expand, values = values, }, }; }; fn plain_struct( lexer: *lex::lexer, alias: ast::ident, ) (ast::struct_literal | error) = { if (len(alias) == 0) { want(lexer, ltok::STRUCT)?; }; want(lexer, ltok::LBRACE)?; let autofill = false; let fields: [](ast::struct_value | *ast::struct_literal) = []; for (true) { const tok = want(lexer, ltok::ELLIPSIS, ltok::NAME, ltok::STRUCT)?; switch (tok.0) { case ltok::ELLIPSIS => synassert(lex::mkloc(lexer), len(alias) != 0, "Cannot use auto-fill with anonymous struct")?; autofill = true; want(lexer, ltok::RBRACE)?; break; case ltok::NAME, ltok::STRUCT => lex::unlex(lexer, tok); append(fields, struct_field(lexer)?); case => abort(); // unreachable }; switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { case ltok::RBRACE => break; case ltok::COMMA => if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; case => abort(); // unreachable }; }; return ast::struct_literal { autofill = autofill, alias = alias, fields = fields, }; }; fn struct_field( lexer: *lex::lexer, ) (ast::struct_value | *ast::struct_literal | error) = { const tok = want(lexer, ltok::NAME, ltok::STRUCT)?; switch (tok.0) { case ltok::NAME => const name = strings::dup(tok.1 as str); const tok = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON, ltok::EQUAL)?) { case let tok: lex::token => yield tok; case void => let id: ast::ident = alloc([name]); return alloc(plain_struct(lexer, id)?); }; switch (tok.0) { case ltok::COLON => const _type = alloc(_type(lexer)?); want(lexer, ltok::EQUAL)?; const init = alloc(expr(lexer)?); return ast::struct_value { name = name, _type = _type, init = init, }; case ltok::DOUBLE_COLON => let id: ast::ident = alloc([name]); let rest = ident(lexer)?; append(id, rest...); return alloc(plain_struct(lexer, id)?); case ltok::EQUAL => return ast::struct_value { name = name, _type = null, init = alloc(expr(lexer)?), }; case => abort(); // Invariant }; case ltok::STRUCT => lex::unlex(lexer, tok); return alloc(plain_struct(lexer, [])?); case => abort(); // Invariant }; }; fn plain_tuple( lexer: *lex::lexer, ex: ast::expr, start: lex::location ) (ast::expr | error) = { let values: []*ast::expr = []; append(values, alloc(ex)); for (true) { append(values, alloc(expr(lexer)?)); match (try(lexer, ltok::COMMA)?) { case lex::token => match (try(lexer, ltok::RPAREN)) { case lex::token => break; case => void; }; case void => want(lexer, ltok::RPAREN)?; break; }; }; return ast::expr { start = start, end = lex::prevloc(lexer), expr = values: ast::tuple_literal, }; }; fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { let lvalue = match (lvalue) { case void => yield plain_expression(lexer)?; case let ex: ast::expr => yield ex; }; let tok = match (try(lexer, ltok::LPAREN, ltok::DOT, ltok::LBRACKET, ltok::QUESTION, ltok::LNOT)?) { case void => return lvalue; case let tok: lex::token => yield tok; }; let next = switch (tok.0) { case ltok::LPAREN => yield call(lexer, lvalue)?; case ltok::DOT => yield postfix_dot(lexer, lvalue)?; case ltok::LBRACKET => yield indexing(lexer, lvalue)?; case ltok::QUESTION => yield ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = alloc(lvalue): ast::propagate_expr, }; case ltok::LNOT => yield ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = alloc(lvalue): ast::error_assert_expr, }; case => abort(); }; return postfix(lexer, next); }; fn postfix_dot( lexer: *lex::lexer, lvalue: ast::expr, ) (ast::expr | error) = { match (try(lexer, ltok::NAME)?) { case let tok: lex::token => return ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::access_field { object = alloc(lvalue), field = tok.1 as str, }, }; case void => let lit = literal(lexer)?; let val = lit.expr as ast::literal_expr; synassert(lex::mkloc(lexer), val is ast::number_literal, "Expected integer literal")?; let val = val as ast::number_literal; return ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::access_tuple { object = alloc(lvalue), value = alloc(lit), }, }; }; }; fn static_expr(lexer: *lex::lexer) (ast::expr | error) = { const tok = want(lexer, ltok::ABORT, ltok::ASSERT, ltok::APPEND, ltok::INSERT, ltok::DELETE)?; lex::unlex(lexer, tok); switch (tok.0) { case ltok::ABORT, ltok::ASSERT => return assert_expr(lexer, true); case ltok::APPEND, ltok::INSERT => return append_insert_expr(lexer, true); case ltok::DELETE => return delete_expr(lexer, true); case => abort(); // unreachable }; }; fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::SWITCH)?; const label = if (try(lexer, ltok::COLON)? is lex::token) { const tok = want(lexer, ltok::NAME)?; yield tok.1 as str; } else ""; want(lexer, ltok::LPAREN)?; const value = expr(lexer)?; want(lexer, ltok::RPAREN)?; want(lexer, ltok::LBRACE)?; let cases: []ast::switch_case = []; for (true) { want(lexer, ltok::CASE)?; let opts: []*ast::expr = []; if (try(lexer, ltok::ARROW)? is void) for (true) { append(opts, alloc(expr(lexer)?)); switch (want(lexer, ltok::ARROW, ltok::COMMA)?.0) { case ltok::ARROW => break; case ltok::COMMA => if (try(lexer, ltok::ARROW)? is lex::token) { break; }; case => abort(); // unreachable }; }; let exprs: []*ast::expr = []; for (true) { append(exprs, alloc(stmt(lexer)?)); match (peek(lexer, ltok::CASE, ltok::RBRACE)?) { case lex::token => break; case void => void; }; }; append(cases, ast::switch_case { options = opts, exprs = exprs, }); if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::switch_expr { value = alloc(value), cases = cases, label = label, }, }; }; fn match_case(lexer: *lex::lexer) (ast::match_case | error) = { want(lexer, ltok::CASE)?; let tok = lex::lex(lexer)?; let loc = tok.2; let name: str = "", typ: nullable *ast::_type = null; switch (tok.0) { case ltok::NULL => typ = alloc(ast::_type { start = loc, end = lex::prevloc(lexer), flags = 0, repr = ast::builtin_type::NULL, }); case ltok::LET => name = want(lexer, ltok::NAME)?.1 as str; want(lexer, ltok::COLON)?; typ = alloc(_type(lexer)?); case ltok::ARROW => lex::unlex(lexer, tok); case => lex::unlex(lexer, tok); typ = alloc(_type(lexer)?); }; want(lexer, ltok::ARROW)?; let exprs: []*ast::expr = []; for (true) { append(exprs, alloc(stmt(lexer)?)); if (peek(lexer, ltok::CASE, ltok::RBRACE)? is lex::token) { break; }; }; return ast::match_case { name = name, _type = typ, exprs = exprs, }; }; fn match_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::MATCH)?; const label = if (try(lexer, ltok::COLON)? is lex::token) { const tok = want(lexer, ltok::NAME)?; yield tok.1 as str; } else ""; want(lexer, ltok::LPAREN)?; const value = expr(lexer)?; want(lexer, ltok::RPAREN)?; want(lexer, ltok::LBRACE)?; let cases: []ast::match_case = []; for (true) { append(cases, match_case(lexer)?); if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::match_expr { value = alloc(value), cases = cases, label = label, }, }; }; fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { const tok = match (try(lexer, ltok::MINUS, ltok::BNOT, ltok::LNOT, ltok::TIMES, ltok::BAND, ltok::SWITCH, ltok::MATCH, ltok::COLON, ltok::LBRACE)?) { case void => return builtin(lexer); case let tok: lex::token => yield switch (tok.0) { case ltok::SWITCH => lex::unlex(lexer, tok); return switch_expr(lexer); case ltok::MATCH => lex::unlex(lexer, tok); return match_expr(lexer); case ltok::COLON, ltok::LBRACE => lex::unlex(lexer, tok); return compound_expr(lexer); case => yield tok; }; }; const op = switch (tok.0) { case ltok::MINUS => yield ast::unarithm_op::MINUS; case ltok::BNOT => yield ast::unarithm_op::BNOT; case ltok::LNOT => yield ast::unarithm_op::LNOT; case ltok::TIMES => yield ast::unarithm_op::DEREF; case ltok::BAND => yield ast::unarithm_op::ADDR; case => abort(); }; const operand = unarithm(lexer)?; const expr = :blk { if (op == ast::unarithm_op::MINUS) match (operand.expr) { case let c: ast::literal_expr => match (c) { case let n: ast::number_literal => let sign = false; const val = match (n.value) { case let i: i64 => sign = i < 0; yield -i; case let u: u64 => void; case let f: f64 => sign = math::signf64(f) < 0; yield -f; }; if (val is void) yield; yield :blk, ast::number_literal { suff = n.suff, value = val as (i64 | f64), sign = sign, }: ast::literal_expr; case => void; }; case => void; }; yield ast::unarithm_expr { op = op, operand = alloc(operand), }; }; return ast::expr { start = tok.2, end = lex::prevloc(lexer), expr = expr, }; }; fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::YIELD)?; let label = ""; let value: nullable *ast::expr = null; match (try(lexer, ltok::COLON, ltok::COMMA, ltok::ELSE, ltok::RBRACE, ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON, ltok::EOF)?) { case void => value = alloc(expr(lexer)?); case let t: lex::token => if (t.0 == ltok::COLON) { label = want(lexer, ltok::NAME)?.1 as str; match (try(lexer, ltok::COMMA)?) { case void => void; case lex::token => value = alloc(expr(lexer)?); }; } else { lex::unlex(lexer, t); }; }; return ast::expr { start = start.2, end = lex::prevloc(lexer), expr = ast::yield_expr { label = label, value = value, }, }; }; fn binop_for_tok(tok: lex::token) ast::binarithm_op = { switch (tok.0) { case ltok::BAND => return ast::binarithm_op::BAND; case ltok::BOR => return ast::binarithm_op::BOR; case ltok::BXOR => return ast::binarithm_op::BXOR; case ltok::DIV => return ast::binarithm_op::DIV; case ltok::GT => return ast::binarithm_op::GT; case ltok::GTEQ => return ast::binarithm_op::GTEQ; case ltok::LAND => return ast::binarithm_op::LAND; case ltok::LEQUAL => return ast::binarithm_op::LEQUAL; case ltok::LESS => return ast::binarithm_op::LESS; case ltok::LESSEQ => return ast::binarithm_op::LESSEQ; case ltok::LOR => return ast::binarithm_op::LOR; case ltok::LSHIFT => return ast::binarithm_op::LSHIFT; case ltok::LXOR => return ast::binarithm_op::LXOR; case ltok::MINUS => return ast::binarithm_op::MINUS; case ltok::MODULO => return ast::binarithm_op::MODULO; case ltok::NEQUAL => return ast::binarithm_op::NEQUAL; case ltok::PLUS => return ast::binarithm_op::PLUS; case ltok::RSHIFT => return ast::binarithm_op::RSHIFT; case ltok::TIMES => return ast::binarithm_op::TIMES; case => abort(); }; }; fn precedence(tok: lex::token) int = { switch (tok.0) { case ltok::LOR => return 0; case ltok::LXOR => return 1; case ltok::LAND => return 2; case ltok::LEQUAL, ltok::NEQUAL => return 3; case ltok::LESS, ltok::LESSEQ, ltok::GT, ltok::GTEQ => return 4; case ltok::BOR => return 5; case ltok::BXOR => return 6; case ltok::BAND => return 7; case ltok::LSHIFT, ltok::RSHIFT => return 8; case ltok::PLUS, ltok::MINUS => return 9; case ltok::TIMES, ltok::DIV, ltok::MODULO => return 10; case => return -1; }; }; hare-0.24.2/hare/parse/ident.ha000066400000000000000000000032231464473310100161670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use hare::ast; use hare::lex; use hare::lex::{ltok}; use memio; use strings; // Parses a single identifier, possibly with a trailing ::, i.e. 'foo::bar::'. // Returns the identifier and whether there's a trailing ::. export fn ident_trailing(lexer: *lex::lexer) ((ast::ident, bool) | error) = { let ident: []str = []; let trailing = false; const tok = want(lexer, ltok::NAME)?; append(ident, tok.1 as str); const loc = tok.2; let z = len(ident[0]); for (true) { match (try(lexer, ltok::DOUBLE_COLON)?) { case void => break; case => void; // Grab the next ident }; z += 1; let name = match (try(lexer, ltok::NAME)?) { case let t: lex::token => yield t.1 as str; case void => trailing = true; break; }; append(ident, name); z += len(name); }; if (z > ast::IDENT_MAX) { ast::ident_free(ident: ast::ident); return syntaxerr(loc, "Identifier exceeds maximum length"); }; return (ident: ast::ident, trailing); }; // Parses a single identifier, i.e. 'foo::bar::baz'. export fn ident(lexer: *lex::lexer) (ast::ident | error) = { let ident = ident_trailing(lexer)?; synassert(lex::mkloc(lexer), !ident.1, "Unexpected trailing :: in ident")?; return ident.0; }; // A convenience function which parses an identifier from a string, so the // caller needn't provide a lexer instance. export fn identstr(in: str) (ast::ident | error) = { let in = memio::fixed(strings::toutf8(in)); let sc = bufio::newscanner(&in); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); let ret = ident(&lexer); want(&lexer, ltok::EOF)?; return ret; }; hare-0.24.2/hare/parse/import.ha000066400000000000000000000035371464473310100164060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; use hare::lex::{ltok}; fn name_list(lexer: *lex::lexer) (ast::import_members | error) = { let names: []str = []; for (true) { append(names, want(lexer, ltok::NAME)?.1 as str); switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { case ltok::COMMA => match (try(lexer, ltok::RBRACE)?) { case void => void; case => return names; }; case ltok::RBRACE => return names; case => abort(); // Unreachable }; }; }; // Parses the import list for a sub-unit export fn imports(lexer: *lex::lexer) ([]ast::import | error) = { let imports: []ast::import = []; for (true) { match (try(lexer, ltok::USE)?) { case void => break; case => void; }; append(imports, ast::import { bindings = void, ... }); let import = &imports[len(imports) - 1]; import.start = lex::mkloc(lexer); let (name, trailing) = ident_trailing(lexer)?; import.ident = name; switch (want(lexer, ltok::SEMICOLON, ltok::LBRACE, ltok::EQUAL, ltok::TIMES)?.0) { case ltok::SEMICOLON => synassert(lex::mkloc(lexer), !trailing, "Unexpected trailing :: in ident")?; case ltok::LBRACE => synassert(lex::mkloc(lexer), trailing, "Expected trailing :: in ident")?; import.bindings = name_list(lexer)?; want(lexer, ltok::SEMICOLON)?; case ltok::EQUAL => synassert(lex::mkloc(lexer), len(name) == 1 && !trailing, "Expected name, not ident")?; import.bindings = name[0]; free(name); import.ident = ident(lexer)?; want(lexer, ltok::SEMICOLON)?; case ltok::TIMES => synassert(lex::mkloc(lexer), trailing, "Expected trailing :: in ident")?; import.bindings = ast::import_wildcard; want(lexer, ltok::SEMICOLON)?; case => abort(); // Unreachable }; import.end = lex::mkloc(lexer); }; return imports; }; hare-0.24.2/hare/parse/parse.ha000066400000000000000000000045021464473310100161770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::lex; use hare::lex::{ltok}; use io; use memio; // All possible error types. export type error = !lex::error; // Convert an error into a human-friendly string. The result may be statically // allocated. export fn strerror(err: error) const str = lex::strerror(err: lex::error); fn syntaxerr( loc: lex::location, fmt: str, args: fmt::field... ) lex::error = { static let buf: [4096]u8 = [0...]; let why = fmt::bsprintf(buf, fmt, args...); return lex::syntaxerr(loc, why); }; // Requires the next token to have a matching ltok. Returns that token, or an // error. fn want(lexer: *lex::lexer, want: lex::ltok...) (lex::token | error) = { let tok = lex::lex(lexer)?; if (len(want) == 0) { return tok; }; for (let i = 0z; i < len(want); i += 1) { if (tok.0 == want[i]) { return tok; }; }; let buf = memio::dynamic(); defer io::close(&buf)!; for (let i = 0z; i < len(want); i += 1) { const tstr = if (want[i] == ltok::NAME) "name" else lex::tokstr((want[i], void, lex::mkloc(lexer))); fmt::fprintf(&buf, "'{}'", tstr)!; if (i + 1 < len(want)) { fmt::fprint(&buf, ", ")!; }; }; lex::unlex(lexer, tok); return syntaxerr(lex::mkloc(lexer), "Unexpected '{}', was expecting {}", lex::tokstr(tok), memio::string(&buf)!); }; // Looks for a matching ltok from the lexer, and if not present, unlexes the // token and returns void. If found, the token is consumed from the lexer and is // returned. fn try( lexer: *lex::lexer, want: lex::ltok... ) (lex::token | error | void) = { let tok = lex::lex(lexer)?; assert(len(want) > 0); for (let i = 0z; i < len(want); i += 1) { if (tok.0 == want[i]) { return tok; }; }; lex::unlex(lexer, tok); }; // Looks for a matching ltok from the lexer, unlexes the token, and returns // it; or void if it was not an ltok. fn peek( lexer: *lex::lexer, want: lex::ltok... ) (lex::token | error | void) = { let tok = lex::lex(lexer)?; lex::unlex(lexer, tok); if (len(want) == 0) { return tok; }; for (let i = 0z; i < len(want); i += 1) { if (tok.0 == want[i]) { return tok; }; }; }; // Returns a syntax error if cond is false and void otherwise fn synassert(loc: lex::location, cond: bool, msg: str) (void | error) = { if (!cond) { return syntaxerr(loc, "{}", msg); }; }; hare-0.24.2/hare/parse/type.ha000066400000000000000000000304131464473310100160460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::ast::{builtin_type}; use hare::lex; use hare::lex::{ltok}; use strings; fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { let variadism = ast::variadism::NONE; let params: []ast::func_param = []; want(lexer, ltok::LPAREN)?; for (try(lexer, ltok::RPAREN)? is void) { let loc = lex::mkloc(lexer); match (try(lexer, ltok::ELLIPSIS)?) { case lex::token => variadism = ast::variadism::C; want(lexer, ltok::RPAREN)?; break; case void => void; }; let name_or_type = _type(lexer)?; match (try(lexer, ltok::COLON)?) { case void => append(params, ast::func_param { loc = loc, name = "", _type = alloc(name_or_type), default_value = void, }); case lex::token => // Bit of a hack because we can't unlex twice. synassert(loc, name_or_type.repr is ast::alias_type, "Invalid parameter name")?; let ns = (name_or_type.repr as ast::alias_type).ident; synassert(loc, len(ns) == 1, "Invalid parameter name")?; append(params, ast::func_param { loc = loc, name = ns[0], _type = alloc(_type(lexer)?), default_value = void, }); }; match (try(lexer, ltok::EQUAL)?) { case void => yield void; case lex::token => params[len(params) - 1].default_value = expr(lexer)?; }; match (try(lexer, ltok::ELLIPSIS)?) { case lex::token => variadism = ast::variadism::HARE; want(lexer, ltok::RPAREN)?; break; case void => void; }; match (try(lexer, ltok::COMMA)?) { case void => want(lexer, ltok::RPAREN)?; break; case lex::token => void; }; }; let t = _type(lexer)?; return ast::func_type { result = alloc(t), variadism = variadism, params = params, }; }; fn integer_type( lexer: *lex::lexer, ) (builtin_type | error) = { switch (want(lexer)?.0) { case ltok::INT => return builtin_type::INT; case ltok::I8 => return builtin_type::I8; case ltok::I16 => return builtin_type::I16; case ltok::I32 => return builtin_type::I32; case ltok::I64 => return builtin_type::I64; case ltok::SIZE => return builtin_type::SIZE; case ltok::UINT => return builtin_type::UINT; case ltok::UINTPTR => return builtin_type::UINTPTR; case ltok::U8 => return builtin_type::U8; case ltok::U16 => return builtin_type::U16; case ltok::U32 => return builtin_type::U32; case ltok::U64 => return builtin_type::U64; case => return syntaxerr(lex::mkloc(lexer), "Expected integer type"); }; }; fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = { let tok = want(lexer)?; let builtin = switch (tok.0) { case ltok::I8, ltok::I16, ltok::I32, ltok::I64, ltok::INT, ltok::UINT, ltok::UINTPTR, ltok::SIZE, ltok::U8, ltok::U16, ltok::U32, ltok::U64 => lex::unlex(lexer, tok); yield integer_type(lexer)?; case ltok::RUNE => yield builtin_type::RUNE; case ltok::STR => yield builtin_type::STR; case ltok::F32 => yield builtin_type::F32; case ltok::F64 => yield builtin_type::F64; case ltok::BOOL => yield builtin_type::BOOL; case ltok::DONE => yield builtin_type::DONE; case ltok::VALIST => yield builtin_type::VALIST; case ltok::VOID => yield builtin_type::VOID; case ltok::OPAQUE => yield builtin_type::OPAQUE; case ltok::NEVER => yield builtin_type::NEVER; case => return syntaxerr(lex::mkloc(lexer), "Unexected {}, was expecting primitive type", lex::tokstr(tok)); }; return ast::_type { start = tok.2, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = builtin, }; }; fn alias_type(lexer: *lex::lexer) (ast::_type | error) = { const start = lex::mkloc(lexer); let unwrap = try(lexer, ltok::ELLIPSIS)? is lex::token; let ident = ident(lexer)?; return ast::_type { start = start, end = lex::prevloc(lexer), flags = 0, repr = ast::alias_type { unwrap = unwrap, ident = ident, }, }; }; fn pointer_type(lexer: *lex::lexer) (ast::_type | error) = { const start = lex::mkloc(lexer); let flags = match (try(lexer, ltok::NULLABLE)?) { case void => yield ast::pointer_flag::NONE; case => yield ast::pointer_flag::NULLABLE; }; want(lexer, ltok::TIMES)?; let _type = _type(lexer)?; return ast::_type { start = start, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = ast::pointer_type { referent = alloc(_type), flags = flags, }, }; }; fn tagged_type( lexer: *lex::lexer, first: ast::_type, start: lex::location ) (ast::_type | error) = { let tagged: ast::tagged_type = []; append(tagged, alloc(first)); for (true) { append(tagged, alloc(_type(lexer)?)); match (try(lexer, ltok::BOR)?) { case lex::token => match (try(lexer, ltok::RPAREN)) { case lex::token => break; case => void; }; case void => want(lexer, ltok::RPAREN)?; break; }; }; return ast::_type { start = start, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = tagged, }; }; fn tuple_type( lexer: *lex::lexer, first: ast::_type, start: lex::location ) (ast::_type | error) = { let tuple: ast::tuple_type = []; append(tuple, alloc(first)); for (true) { append(tuple, alloc(_type(lexer)?)); match (try(lexer, ltok::COMMA)?) { case lex::token => match (try(lexer, ltok::RPAREN)) { case lex::token => break; case => void; }; case void => want(lexer, ltok::RPAREN)?; break; }; }; return ast::_type { start = start, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = tuple, }; }; fn fn_type(lexer: *lex::lexer) (ast::_type | error) = { const start = lex::mkloc(lexer); want(lexer, ltok::FN)?; let proto = prototype(lexer)?; return ast::_type { start = start, end = lex::prevloc(lexer), flags = 0, repr = proto, }; }; fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = { let membs: []ast::struct_member = []; let kind = want(lexer, ltok::STRUCT, ltok::UNION)?; let packed = false; if (kind.0 == ltok::STRUCT && try(lexer, ltok::ATTR_PACKED)? is lex::token) { packed = true; }; want(lexer, ltok::LBRACE)?; for (true) { if (try(lexer, ltok::RBRACE)? is lex::token) { synassert(lex::mkloc(lexer), len(membs) != 0, "Expected field list")?; break; }; let comment = ""; let offs: nullable *ast::expr = match (try(lexer, ltok::ATTR_OFFSET)?) { case void => yield null; case lex::token => comment = strings::dup(lex::comment(lexer)); want(lexer, ltok::LPAREN)?; let ex = expr(lexer)?; want(lexer, ltok::RPAREN)?; yield alloc(ex); }; let tok = want(lexer, ltok::NAME, ltok::STRUCT, ltok::UNION)?; if (comment == "") { comment = strings::dup(lex::comment(lexer)); }; switch (tok.0) { case ltok::NAME => lex::unlex(lexer, tok); let memb = struct_embed_or_field(lexer, offs, comment)?; append(membs, memb); case ltok::STRUCT, ltok::UNION => lex::unlex(lexer, tok); let subtype = struct_union_type(lexer)?; append(membs, ast::struct_member { _offset = offs, member = alloc(subtype), docs = comment, }); case => abort(); }; switch (want(lexer, ltok::RBRACE, ltok::COMMA)?.0) { case ltok::RBRACE => break; case ltok::COMMA => const linecomment = lex::comment(lexer); const docs = &membs[len(membs) - 1].docs; if (linecomment != "" && *docs == "") { *docs = strings::dup(linecomment); free(lexer.comment); lexer.comment = ""; }; case => abort(); }; }; return ast::_type { start = kind.2, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = switch (kind.0) { case ltok::STRUCT => yield ast::struct_type { members = membs, packed = packed, ...}; case ltok::UNION => yield membs: ast::union_type; case => abort(); }, }; }; fn struct_embed_or_field( lexer: *lex::lexer, offs: nullable *ast::expr, comment: str, ) (ast::struct_member | error) = { // Disambiguates between `name: type` and `identifier` // // struct-union-field // name : type // identifier // // identifier // name // name :: identifier let name = want(lexer, ltok::NAME)?; let id: ast::ident = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON)?) { case void => yield alloc([name.1 as str]); case let tok: lex::token => yield switch (tok.0) { case ltok::COLON => let field = ast::struct_field { name = name.1 as str, _type = alloc(_type(lexer)?), }; return ast::struct_member { _offset = offs, member = field, docs = comment, }; case ltok::DOUBLE_COLON => let id = ident(lexer)?; insert(id[0], name.1 as str); yield id; case => abort(); }; }; return ast::struct_member { _offset = offs, member = id: ast::struct_alias, docs = comment, }; }; fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = { let start = want(lexer, ltok::LBRACKET)?; let length = match (try(lexer, ltok::UNDERSCORE, ltok::TIMES, ltok::RBRACKET)?) { case void => yield alloc(expr(lexer)?); case let tok: lex::token => yield switch (tok.0) { case ltok::UNDERSCORE => yield ast::len_contextual; case ltok::TIMES => yield ast::len_unbounded; case ltok::RBRACKET => yield ast::len_slice; case => abort(); }; }; if (!(length is ast::len_slice)) { want(lexer, ltok::RBRACKET)?; }; let _type = _type(lexer)?; return ast::_type { start = start.2, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = ast::list_type { length = length, members = alloc(_type), }, }; }; fn enum_type(lexer: *lex::lexer) (ast::_type | error) = { let start = want(lexer, ltok::ENUM)?; const storage = match (try(lexer, ltok::LBRACE, ltok::RUNE)?) { case void => let storage = integer_type(lexer)?; want(lexer, ltok::LBRACE)?; yield storage; case let tok: lex::token => yield switch (tok.0) { case ltok::LBRACE => yield builtin_type::INT; case ltok::RUNE => want(lexer, ltok::LBRACE)?; yield builtin_type::RUNE; case => abort(); // unreachable }; }; let membs: []ast::enum_field = []; for (true) { if (try(lexer, ltok::RBRACE)? is lex::token) { synassert(lex::mkloc(lexer), len(membs) != 0, "Expected member list")?; break; }; const loc = lex::mkloc(lexer); let name = want(lexer, ltok::NAME)?; let comment = strings::dup(lex::comment(lexer)); let value: nullable *ast::expr = if (try(lexer, ltok::EQUAL)? is lex::token) alloc(expr(lexer)?) else null; defer append(membs, ast::enum_field { name = name.1 as str, value = value, loc = loc, docs = comment, }); switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { case ltok::COMMA => const linecomment = lex::comment(lexer); if (linecomment != "" && comment == "") { free(comment); comment = strings::dup(linecomment); free(lexer.comment); lexer.comment = ""; }; case ltok::RBRACE => break; case => abort(); }; }; return ast::_type { start = start.2, end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = ast::enum_type { storage = storage, values = membs, }, }; }; // Parses a type, e.g. '[]int'. export fn _type(lexer: *lex::lexer) (ast::_type | error) = { let flags = ast::type_flag::NONE; if (try(lexer, ltok::CONST)? is lex::token) { flags |= ast::type_flag::CONST; }; if (try(lexer, ltok::LNOT)? is lex::token) { flags |= ast::type_flag::ERROR; }; let tok = peek(lexer)? as lex::token; let typ: ast::_type = switch (tok.0) { case ltok::RUNE, ltok::STR, ltok::BOOL, ltok::DONE, ltok::I8, ltok::I16, ltok::I32, ltok::I64, ltok::U8, ltok::U16, ltok::U32, ltok::U64, ltok::INT, ltok::UINT, ltok::UINTPTR, ltok::SIZE, ltok::F32, ltok::F64, ltok::VALIST, ltok::VOID, ltok::OPAQUE, ltok::NEVER => yield primitive_type(lexer)?; case ltok::ENUM => yield enum_type(lexer)?; case ltok::NULLABLE, ltok::TIMES => yield pointer_type(lexer)?; case ltok::STRUCT, ltok::UNION => yield struct_union_type(lexer)?; case ltok::LBRACKET => yield array_slice_type(lexer)?; case ltok::LPAREN => want(lexer, ltok::LPAREN)?; let t = _type(lexer)?; yield switch (want(lexer, ltok::BOR, ltok::COMMA)?.0) { case ltok::BOR => yield tagged_type(lexer, t, tok.2)?; case ltok::COMMA => yield tuple_type(lexer, t, tok.2)?; case => abort("unreachable"); }; case ltok::FN => yield fn_type(lexer)?; case ltok::ELLIPSIS, ltok::NAME => yield alias_type(lexer)?; case => return syntaxerr(lex::mkloc(lexer), "Unexpected {}, was expecting type", lex::tokstr(tok)); }; typ.flags |= flags; return typ; }; hare-0.24.2/hare/parse/unit.ha000066400000000000000000000005251464473310100160450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; // Parses an entire subunit (i.e. one Hare source file). export fn subunit(lexer: *lex::lexer) (ast::subunit | error) = { let i = imports(lexer)?; let d = decls(lexer)?; return ast::subunit { imports = i, decls = d, }; }; hare-0.24.2/hare/types/000077500000000000000000000000001464473310100146045ustar00rootroot00000000000000hare-0.24.2/hare/types/+aarch64/000077500000000000000000000000001464473310100161075ustar00rootroot00000000000000hare-0.24.2/hare/types/+aarch64/writesize.ha000066400000000000000000000002271464473310100204470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hash; fn writesize(h: *hash::hash, u: size) void = write64(h, u); hare-0.24.2/hare/types/+riscv64/000077500000000000000000000000001464473310100161575ustar00rootroot00000000000000hare-0.24.2/hare/types/+riscv64/writesize.ha000066400000000000000000000002271464473310100205170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hash; fn writesize(h: *hash::hash, u: size) void = write64(h, u); hare-0.24.2/hare/types/+test.ha000066400000000000000000000251161464473310100161550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use hare::ast; use hare::lex; use hare::parse; use memio; use strings; fn parse_type(in: str) ast::_type = { let buf = memio::fixed(strings::toutf8(in)); let sc = bufio::newscanner(&buf); defer bufio::finish(&sc); let lex = lex::init(&sc, ""); return parse::_type(&lex)!; }; @test fn store() void = { let st = store(x86_64, null, null); defer store_free(st); let atype = parse_type("int"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.repr as builtin == builtin::INT); assert(htype.sz == x86_64._int && htype._align == x86_64._int); let type2 = lookup(st, &atype)!; assert(htype == type2, "types should be singletons"); let atype = parse_type("*int"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == x86_64._pointer && htype._align == x86_64._pointer); let htype = htype.repr as pointer; assert(htype.referent.repr as builtin == builtin::INT); }; fn resolve( rstate: nullable *opaque, store: *typestore, expr: const *ast::expr, ) (size | deferred | error) = { let expr = expr.expr as ast::literal_expr; let n = expr as ast::number_literal; let ival = n.value as i64; assert(ival >= 0); return ival: size; }; @test fn structs() void = { let st = store(x86_64, &resolve, null); defer store_free(st); // Basic struct let atype = parse_type("struct { x: int, y: int }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 8); assert(htype._align == 4); let stype = htype.repr as _struct; assert(stype.kind == struct_union::STRUCT); assert(len(stype.fields) == 2); let x = stype.fields[0]; assert(x.name == "x"); assert(x.offs == 0); assert(x._type.repr as builtin == builtin::INT); let y = stype.fields[1]; assert(y.name == "y"); assert(y.offs == 4); assert(y._type.repr as builtin == builtin::INT); // Basic union let atype = parse_type("union { x: int, y: int }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 4); assert(htype._align == 4); let stype = htype.repr as _struct; assert(stype.kind == struct_union::UNION); assert(len(stype.fields) == 2); let x = stype.fields[0]; assert(x.name == "x"); assert(x.offs == 0); assert(x._type.repr as builtin == builtin::INT); let y = stype.fields[1]; assert(y.name == "y"); assert(y.offs == 0); assert(y._type.repr as builtin == builtin::INT); // Padding let atype = parse_type("struct { w: u8, x: u32, y: u8, z: u64 }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); let stype = htype.repr as _struct; assert(stype.kind == struct_union::STRUCT); let w = stype.fields[0]; assert(w.offs == 0); let x = stype.fields[1]; assert(x.offs == 4); let y = stype.fields[2]; assert(y.offs == 8); let z = stype.fields[3]; assert(z.offs == 16); let atype = parse_type("struct { x: u8, y: size, z: u8 }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); // Sort order let atype = parse_type("struct { z: u8, y: u8, x: u8, q: u8 }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; let stype = htype.repr as _struct; assert(stype.fields[0].name == "q"); assert(stype.fields[1].name == "x"); assert(stype.fields[2].name == "y"); assert(stype.fields[3].name == "z"); // Embedded struct let atype = parse_type("struct { x: int, y: int, struct { z: int, q: int, }, p: int, }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 20); assert(htype._align == 4); let stype = htype.repr as _struct; assert(stype.fields[0].name == "p"); assert(stype.fields[0].offs == 16); assert(stype.fields[1].name == "q"); assert(stype.fields[1].offs == 12); assert(stype.fields[2].name == "x"); assert(stype.fields[2].offs == 0); assert(stype.fields[3].name == "y"); assert(stype.fields[3].offs == 4); assert(stype.fields[4].name == "z"); assert(stype.fields[4].offs == 8); // Embedded union let atype = parse_type("struct { x: int, y: int, union { z: int, q: int, }, p: int, }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 16); assert(htype._align == 4); let stype = htype.repr as _struct; assert(stype.fields[0].name == "p"); assert(stype.fields[0].offs == 12); assert(stype.fields[1].name == "q"); assert(stype.fields[1].offs == 8); assert(stype.fields[2].name == "x"); assert(stype.fields[2].offs == 0); assert(stype.fields[3].name == "y"); assert(stype.fields[3].offs == 4); assert(stype.fields[4].name == "z"); assert(stype.fields[4].offs == 8); // Embedded (struct) alias // TODO // Embedded (union) alias // TODO // Explicit offsets let atype = parse_type("struct { @offset(8) x: int, @offset(16) y: int, @offset(32) z: int, }"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 36); assert(htype._align == 4); let stype = htype.repr as _struct; assert(stype.fields[0].name == "x"); assert(stype.fields[0].offs == 8); assert(stype.fields[1].name == "y"); assert(stype.fields[1].offs == 16); assert(stype.fields[2].name == "z"); assert(stype.fields[2].offs == 32); }; @test fn tuples() void = { let st = store(x86_64, &resolve, null); defer store_free(st); // Basic case let atype = parse_type("(int, int)"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 8); assert(htype._align == 4); let tup = htype.repr as tuple; assert(len(tup) == 2); assert(tup[0].offs == 0); assert(tup[0]._type.repr as builtin == builtin::INT); assert(tup[1].offs == 4); assert(tup[1]._type.repr as builtin == builtin::INT); // Padding let atype = parse_type("(i8, i32, i8, i64)"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); let tup = htype.repr as tuple; assert(tup[0].offs == 0); assert(tup[1].offs == 4); assert(tup[2].offs == 8); assert(tup[3].offs == 16); }; @test fn lists() void = { let st = store(x86_64, &resolve, null); defer store_free(st); // Slice let atype = parse_type("[]int"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 24); assert(htype._align == 8); let slice = htype.repr as slice; assert(slice.repr as builtin == builtin::INT); // Normal array let atype = parse_type("[5]i32"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 4 * 5); assert(htype._align == 4); let arr = htype.repr as array; assert(arr.member.repr as builtin == builtin::I32); assert(arr.length == 5); // Unbounded array let atype = parse_type("[*]i32"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == 4); let arr = htype.repr as array; assert(arr.member.repr as builtin == builtin::I32); assert(arr.length == SIZE_UNDEFINED); // Contextual array (equivalent to unbounded at this compilation stage) let atype = parse_type("[_]i32"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == 4); let arr = htype.repr as array; assert(arr.member.repr as builtin == builtin::I32); assert(arr.length == SIZE_UNDEFINED); }; @test fn funcs() void = { let st = store(x86_64, &resolve, null); defer store_free(st); let atype = parse_type("fn() never"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == SIZE_UNDEFINED); let f = htype.repr as func; assert(f.result.repr as builtin == builtin::NEVER); assert(f.variadism == variadism::NONE); assert(len(f.params) == 0); let atype = parse_type("fn(foo: int, bar: str...) int"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == SIZE_UNDEFINED); assert(htype._align == SIZE_UNDEFINED); let f = htype.repr as func; assert(f.result.repr as builtin == builtin::INT); assert(f.variadism == variadism::HARE); assert(len(f.params) == 2); assert(f.params[0].repr as builtin == builtin::INT); assert(f.params[1].repr as builtin == builtin::STR); }; @test fn tagged() void = { let st = store(x86_64, &resolve, null); defer store_free(st); let atype = parse_type("(int | int | void)"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == st.arch._int * 2); assert(htype._align == st.arch._int); let t = htype.repr as tagged; assert(len(t) == 2); assert(t[0].repr as builtin == builtin::INT); assert(t[1].repr as builtin == builtin::VOID); let atype = parse_type("(int | (int | str | void))"); defer ast::type_finish(&atype); let htype = lookup(st, &atype)!; assert(htype.sz == 32); assert(htype._align == 8); let t = htype.repr as tagged; assert(len(t) == 3); assert(t[0].repr as builtin == builtin::INT); assert(t[1].repr as builtin == builtin::VOID); assert(t[2].repr as builtin == builtin::STR); }; @test fn alias() void = { let st = store(x86_64, &resolve, null); defer store_free(st); const of = lookup_builtin(st, ast::builtin_type::U64); const al = newalias(st, ["myalias"], of); assert(al.sz == 8); assert(al._align == 8); assert(al.flags == 0); assert((al.repr as alias).secondary == of); const atype = parse_type("myalias"); defer ast::type_finish(&atype); const htype = lookup(st, &atype)!; assert(htype == al); }; @test fn forwardref() void = { let st = store(x86_64, &resolve, null); defer store_free(st); const atype = parse_type("myalias"); defer ast::type_finish(&atype); const htype = lookup(st, &atype)!; assert((htype.repr as alias).secondary == null); const of = lookup_builtin(st, ast::builtin_type::U64); const al = newalias(st, ["myalias"], of); assert(htype.sz == 8); assert(htype._align == 8); assert(htype.flags == 0); assert((htype.repr as alias).secondary == of); }; @test fn builtins() void = { const builtins = [ (&builtin_bool, "bool"), (&builtin_done, "done"), (&builtin_f32, "f32"), (&builtin_f64, "f64"), (&builtin_i8, "i8"), (&builtin_i16, "i16"), (&builtin_i32, "i32"), (&builtin_i64, "i64"), (&builtin_opaque, "opaque"), (&builtin_rune, "rune"), (&builtin_u8, "u8"), (&builtin_u16, "u16"), (&builtin_u32, "u32"), (&builtin_u64, "u64"), (&builtin_void, "void"), ]; for (let i = 0z; i < len(builtins); i += 1) { const expected = hash(builtins[i].0); const actual = builtins[i].0.id; if (expected != actual) { fmt::errorfln("expected type {} to have ID {}, but got {}", builtins[i].1, expected, actual)!; abort(); }; }; }; hare-0.24.2/hare/types/+x86_64/000077500000000000000000000000001464473310100156155ustar00rootroot00000000000000hare-0.24.2/hare/types/+x86_64/writesize.ha000066400000000000000000000002271464473310100201550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hash; fn writesize(h: *hash::hash, u: size) void = write64(h, u); hare-0.24.2/hare/types/README000066400000000000000000000002751464473310100154700ustar00rootroot00000000000000hare::types provides an implementation of the Hare type system. See [[store]] to initialize a type store and [[lookup]] for looking up Hare types from their [[hare::ast::]] representation. hare-0.24.2/hare/types/arch.ha000066400000000000000000000013001464473310100160250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Configuration for a specific architecture. export type arch = struct { _int: size, _pointer: size, _size: size, valist_size: size, valist_align: size, }; // [[arch]] configuration for x86_64. export const x86_64: arch = arch { _int = 4, _pointer = 8, _size = 8, valist_size = 24, valist_align = 8, }; // [[arch]] configuration for aarch64. export const aarch64: arch = arch { _int = 4, _pointer = 8, _size = 8, valist_size = 32, valist_align = 8, }; // [[arch]] configuration for riscv64. export const riscv64: arch = arch { _int = 4, _pointer = 8, _size = 8, valist_size = 8, valist_align = 8, }; hare-0.24.2/hare/types/builtins.ha000066400000000000000000000051001464473310100167430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // IDs are precomputed, but a test verifies that they match what they would be // if computed at runtime // [[_type]] representation of bool. export const builtin_bool: _type = _type { repr = builtin::BOOL, sz = 1, _align = 1, id = 292984781, ... }; // [[_type]] representation of done. export const builtin_done: _type = _type { repr = builtin::DONE, sz = 0, _align = 0, id = 3950255460, ... }; // [[_type]] representation of f32. export const builtin_f32: _type = _type { repr = builtin::F32, sz = 4, _align = 4, id = 1568378015, ... }; // [[_type]] representation of f64. export const builtin_f64: _type = _type { repr = builtin::F64, sz = 8, _align = 8, id = 930681398, ... }; // [[_type]] representation of i8. export const builtin_i8: _type = _type { repr = builtin::I8, sz = 1, _align = 1, id = 2674862226, ... }; // [[_type]] representation of i16. export const builtin_i16: _type = _type { repr = builtin::I16, sz = 2, _align = 2, id = 2037165609, ... }; // [[_type]] representation of i32. export const builtin_i32: _type = _type { repr = builtin::I32, sz = 4, _align = 4, id = 1399468992, ... }; // [[_type]] representation of i64. export const builtin_i64: _type = _type { repr = builtin::I64, sz = 8, _align = 8, id = 3312558843, ... }; // [[_type]] representation of opaque. export const builtin_opaque: _type = _type { repr = builtin::OPAQUE, sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED, id = 1737287038, ... }; // [[_type]] representation of never. export const builtin_never: _type = _type { repr = builtin::NEVER, sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED, id = 1737287038, ... }; // [[_type]] representation of rune. export const builtin_rune: _type = _type { repr = builtin::RUNE, sz = 4, _align = 4, id = 2843771249, ... }; // [[_type]] representation of u8. export const builtin_u8: _type = _type { repr = builtin::U8, sz = 1, _align = 1, id = 3181589295, ... }; // [[_type]] representation of u16. export const builtin_u16: _type = _type { repr = builtin::U16, sz = 2, _align = 2, id = 3481467866, ... }; // [[_type]] representation of u32. export const builtin_u32: _type = _type { repr = builtin::U32, sz = 4, _align = 4, id = 1906196061, ... }; // [[_type]] representation of u64. export const builtin_u64: _type = _type { repr = builtin::U64, sz = 8, _align = 8, id = 1268499444, ... }; // [[_type]] representation of void. export const builtin_void: _type = _type { repr = builtin::VOID, sz = 0, _align = 0, id = 3012680272, ... }; hare-0.24.2/hare/types/class.ha000066400000000000000000000030421464473310100162220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returns true if the given type is a signed type. export fn is_signed(ty: const *_type) bool = { match (ty.repr) { case let al: alias => return is_signed(al.secondary as const *_type); case let bi: builtin => switch (bi) { case builtin::F32, builtin::F64, builtin::I16, builtin::I32, builtin::I64, builtin::I8, builtin::INT => return true; case => return false; }; case let e: _enum => switch (e.storage) { case builtin::I16, builtin::I32, builtin::I64, builtin::I8, builtin::INT => return true; case => return false; }; case => return false; }; }; // Returns true if the given type is a floating-point type. export fn is_float(ty: const *_type) bool = { match (ty.repr) { case let al: alias => return is_float(al.secondary as const *_type); case let bi: builtin => switch (bi) { case builtin::F32, builtin::F64 => return true; case => return false; }; case => return false; }; }; // Returns true if the given type is an integer type. export fn is_integer(ty: const *_type) bool = { match (ty.repr) { case let al: alias => return is_integer(al.secondary as const *_type); case let bi: builtin => switch (bi) { case builtin::INT, builtin::UINT, builtin::I16, builtin::I32, builtin::I64, builtin::I8, builtin::U16, builtin::U32, builtin::U64, builtin::U8, builtin::SIZE, builtin::UINTPTR => return true; case => return false; }; case _enum => return true; case => return false; }; }; hare-0.24.2/hare/types/hash.ha000066400000000000000000000101771464473310100160470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use hash::fnv; use strings; // Keep ordered with respect to bootstrap harec:include/types.h type storage = enum u8 { BOOL, DONE, F32, F64, I16, I32, I64, I8, INT, NEVER, NULL, OPAQUE, RUNE, SIZE, STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM, FUNCTION, POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, VALIST, }; fn builtin_storage(b: builtin) u8 = { switch (b) { case builtin::BOOL => return storage::BOOL; case builtin::DONE => return storage::DONE; case builtin::F32 => return storage::F32; case builtin::F64 => return storage::F64; case builtin::I16 => return storage::I16; case builtin::I32 => return storage::I32; case builtin::I64 => return storage::I64; case builtin::I8 => return storage::I8; case builtin::INT => return storage::INT; case builtin::NEVER => return storage::NEVER; case builtin::NULL => return storage::NULL; case builtin::OPAQUE => return storage::OPAQUE; case builtin::RUNE => return storage::RUNE; case builtin::SIZE => return storage::SIZE; case builtin::STR => return storage::STRING; case builtin::U16 => return storage::U16; case builtin::U32 => return storage::U32; case builtin::U64 => return storage::U64; case builtin::U8 => return storage::U8; case builtin::UINT => return storage::UINT; case builtin::UINTPTR => return storage::UINTPTR; case builtin::VALIST => return storage::VALIST; case builtin::VOID => return storage::VOID; case builtin::FCONST, builtin::ICONST, builtin::RCONST => abort(); // unreachable }; }; fn type_storage(t: *_type) u8 = { match (t.repr) { case alias => return storage::ALIAS; case array => return storage::ARRAY; case let b: builtin => return builtin_storage(b); case _enum => return storage::ENUM; case func => return storage::FUNCTION; case pointer => return storage::POINTER; case slice => return storage::SLICE; case let st: _struct => if (st.kind == struct_union::STRUCT) { return storage::STRUCT; } else { return storage::UNION; }; case tuple => return storage::TUPLE; case tagged => return storage::TAGGED; }; }; fn write8(h: *hash::hash, u: u8) void = { let buf = &u: *[*]u8; hash::write(h, buf[..1]); }; fn write32(h: *hash::hash, u: u32) void = { static let buf: [size(u32)]u8 = [0...]; endian::leputu32(buf, u); hash::write(h, buf); }; fn write64(h: *hash::hash, u: u64) void = { static let buf: [size(u64)]u8 = [0...]; endian::leputu64(buf, u); hash::write(h, buf); }; // Returns the hash of a type. These hashes are deterministic and universally // unique: different computers will generate the same hash for the same type. export fn hash(t: *_type) u32 = { // Note that this function should produce the same hashes as harec; see // bootstrap harec:src/types.c:type_hash let id = fnv::fnv32a(); write8(&id, type_storage(t)); write8(&id, t.flags); match (t.repr) { case let a: alias => for (let i = len(a.id); i > 0; i -= 1) { hash::write(&id, strings::toutf8(a.id[i - 1])); write8(&id, 0); }; case let a: array => write32(&id, hash(a.member)); writesize(&id, a.length); case builtin => void; case let e: _enum => write8(&id, builtin_storage(e.storage)); for (let i = 0z; i < len(e.values); i += 1) { hash::write(&id, strings::toutf8(e.values[i].0)); write64(&id, e.values[i].1); }; case let f: func => write32(&id, hash(f.result)); write8(&id, f.variadism: u8); for (let i = 0z; i < len(f.params); i += 1) { write32(&id, hash(f.params[i])); }; case let p: pointer => write8(&id, p.flags); write32(&id, hash(p.referent)); case let s: slice => write32(&id, hash(s)); case let st: _struct => for (let i = 0z; i < len(st.fields); i += 1) { const field = st.fields[i]; hash::write(&id, strings::toutf8(field.name)); write32(&id, hash(field._type)); writesize(&id, field.offs); }; case let tu: tuple => for (let i = 0z; i < len(tu); i += 1) { write32(&id, hash(tu[i]._type)); }; case let ta: tagged => for (let i = 0z; i < len(ta); i += 1) { write32(&id, hash(ta[i])); }; }; return fnv::sum32(&id); }; hare-0.24.2/hare/types/lookup.ha000066400000000000000000000007751464473310100164400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; // Unwraps a type which may be aliased and returns the underlying type. export fn dealias(t: *_type) const *_type = { for (true) match (t.repr) { case let a: alias => t = a.secondary as const *_type; case => break; }; return t; }; // Looks up a built-in type. export fn lookup_builtin( store: *typestore, _type: ast::builtin_type, ) const *_type = lookup(store, &ast::_type { repr = _type, ... })!; hare-0.24.2/hare/types/store.ha000066400000000000000000000350221464473310100162540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use hare::ast; use sort; use strings; export def BUCKETS: size = 65535; // A function which evaluates a [[hare::ast::expr]], providing either a size // result or an error. export type resolver = fn( rstate: nullable *opaque, store: *typestore, expr: const *ast::expr, ) (size | deferred | error); export type typestore = struct { // This hash map provides the canonical address for all types owned by // this type store. Any type which has a reference to another type has // borrowed it from this map. map: [BUCKETS][]_type, arch: arch, resolve: nullable *resolver, rstate: nullable *opaque, }; // Initializes a new type store. Optionally, provide a function which // type-checks and evaluates an [[hare::ast::expr]]. If a resolver is not // provided, looking up types with an expression component (e.g. [2 + 2]int) // will return [[noresolver]]. export fn store( arch: arch, resolver: nullable *resolver, rstate: nullable *opaque, ) *typestore = alloc(typestore { arch = arch, resolve = resolver, rstate = rstate, ... }); // Frees state associated with a [[typestore]]. export fn store_free(store: *typestore) void = { for (let i = 0z; i < len(store.map); i += 1) { for (let j = 0z; j < len(store.map[i]); j += 1) { type_finish(&store.map[i][j]); }; free(store.map[i]); }; free(store); }; // Creates a new type alias. export fn newalias( store: *typestore, ident: const ast::ident, of: const *_type, ) const *_type = { const atype: _type = _type { flags = of.flags, repr = alias { id = ast::ident_dup(ident), secondary = of, }, id = 0, sz = of.sz, _align = of._align, }; const id = hash(&atype); atype.id = id; // Fill in forward-referenced aliases match (lookup(store, &ast::_type { repr = ast::alias_type { unwrap = false, ident = ident, }, ... })) { case error => void; case deferred => void; case let ty: const *_type => let ty = ty: *_type; *ty = atype; return ty; }; // Or create a new alias let bucket = &store.map[id % BUCKETS]; append(bucket, atype); return &bucket[len(bucket) - 1]; }; // Returned from [[lookup]] when we are unable to resolve this type, but it does // not necessarily have an error. This occurs when a type includes an unknown // forward reference. export type deferred = !void; // A resolver function was not provided to [[store]], but was required to look // up this type. export type noresolver = !void; // All possible errors for [[lookup]]. export type error = !(noresolver | errors::opaque_); // Convert an error into a human-friendly string. export fn strerror(err: error) const str = match (err) { case noresolver => return "Resolver function not provided, but required"; case let err: errors::opaque_ => return errors::strerror(err); }; // Retrieves a [[_type]] for a given [[hare::ast::_type]]. export fn lookup( store: *typestore, ty: *ast::_type, ) (const *_type | deferred | error) = { const ty = fromast(store, ty)?; if (ty.flags == 0) match (ty.repr) { case let b: builtin => switch (b) { case builtin::F32 => return &builtin_f32; case builtin::F64 => return &builtin_f64; case builtin::I8 => return &builtin_i8; case builtin::I16 => return &builtin_i16; case builtin::I32 => return &builtin_i32; case builtin::I64 => return &builtin_i64; case builtin::OPAQUE => return &builtin_opaque; case builtin::RUNE => return &builtin_rune; case builtin::U8 => return &builtin_u8; case builtin::U16 => return &builtin_u16; case builtin::U32 => return &builtin_u32; case builtin::U64 => return &builtin_u64; case builtin::VOID => return &builtin_void; case builtin::DONE => return &builtin_done; case => void; }; case => void; }; const id = hash(&ty); let bucket = &store.map[id % BUCKETS]; for (let i = 0z; i < len(bucket); i += 1) { if (bucket[i].id == id) { type_finish(&ty); return &bucket[i]; }; }; ty.id = id; append(bucket, ty); return &bucket[len(bucket) - 1]; }; fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = { let sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED; const repr = match (atype.repr) { case let a: ast::alias_type => // TODO: This is incomplete assert(!a.unwrap); yield alias { id = ast::ident_dup(a.ident), secondary = null, }; case let b: ast::builtin_type => // TODO: Tuple unpacking could improve this yield switch (b) { case ast::builtin_type::BOOL => sz = store.arch._int; _align = store.arch._int; yield builtin::BOOL; case ast::builtin_type::DONE => sz = 0; _align = 0; yield builtin::DONE; case ast::builtin_type::F32 => sz = 4; _align = 4; yield builtin::F32; case ast::builtin_type::F64 => sz = 8; _align = 8; yield builtin::F64; case ast::builtin_type::I16 => sz = 2; _align = 2; yield builtin::I16; case ast::builtin_type::I32 => sz = 4; _align = 4; yield builtin::I32; case ast::builtin_type::I64 => sz = 8; _align = 8; yield builtin::I64; case ast::builtin_type::I8 => sz = 1; _align = 1; yield builtin::I8; case ast::builtin_type::INT => sz = store.arch._int; _align = store.arch._int; yield builtin::INT; case ast::builtin_type::RUNE => sz = 4; _align = 4; yield builtin::RUNE; case ast::builtin_type::SIZE => sz = store.arch._size; _align = store.arch._size; yield builtin::SIZE; case ast::builtin_type::STR => sz = store.arch._pointer; sz += sz % store.arch._size + store.arch._size; sz += store.arch._size; _align = if (store.arch._size > store.arch._pointer) store.arch._size else store.arch._pointer; yield builtin::STR; case ast::builtin_type::U16 => sz = 2; _align = 2; yield builtin::U16; case ast::builtin_type::U32 => sz = 4; _align = 4; yield builtin::U32; case ast::builtin_type::U64 => sz = 8; _align = 8; yield builtin::U64; case ast::builtin_type::U8 => sz = 1; _align = 1; yield builtin::U8; case ast::builtin_type::UINT => sz = store.arch._int; _align = store.arch._int; yield builtin::UINT; case ast::builtin_type::UINTPTR => sz = store.arch._pointer; _align = store.arch._pointer; yield builtin::UINTPTR; case ast::builtin_type::VOID => sz = 0; _align = 0; yield builtin::VOID; case ast::builtin_type::NULL => sz = store.arch._pointer; _align = store.arch._pointer; yield builtin::NULL; case ast::builtin_type::ICONST, ast::builtin_type::FCONST, ast::builtin_type::RCONST => abort(); // TODO? case ast::builtin_type::OPAQUE => sz = SIZE_UNDEFINED; _align = SIZE_UNDEFINED; yield builtin::OPAQUE; case ast::builtin_type::NEVER => sz = SIZE_UNDEFINED; _align = SIZE_UNDEFINED; yield builtin::NEVER; case ast::builtin_type::VALIST => sz = store.arch.valist_size; _align = store.arch.valist_align; yield builtin::VALIST; }; case let f: ast::func_type => yield func_from_ast(store, &f)?; case let p: ast::pointer_type => sz = store.arch._pointer; _align = store.arch._pointer; yield pointer { referent = lookup(store, p.referent)?, flags = p.flags: pointer_flag, }; case let st: ast::struct_type => let st = struct_from_ast(store, st, false)?; sz = 0; _align = 0; for (let i = 0z; i < len(st.fields); i += 1) { const field = st.fields[i]; if (field.offs + field._type.sz > sz) { sz = field.offs + field._type.sz; }; if (field._type._align > _align) { _align = field._type._align; }; }; yield st; case let un: ast::union_type => let st = struct_from_ast(store, un, true)?; sz = 0; _align = 0; for (let i = 0z; i < len(st.fields); i += 1) { const field = st.fields[i]; if (field.offs + field._type.sz > sz) { sz = field.offs + field._type.sz; }; if (field._type._align > _align) { _align = field._type._align; }; }; yield st; case let ta: ast::tagged_type => let ta = tagged_from_ast(store, ta)?; sz = 0; _align = 0; for (let i = 0z; i < len(ta); i += 1) { if (ta[i].sz > sz) { sz = ta[i].sz; }; if (ta[i]._align > _align) { _align = ta[i]._align; }; }; if (store.arch._int > _align) { _align = store.arch._int; }; sz += store.arch._int % _align + store.arch._int; yield ta; case let tu: ast::tuple_type => let tu = tuple_from_ast(store, tu)?; sz = 0; _align = 0; for (let i = 0z; i < len(tu); i += 1) { const value = tu[i]; if (value.offs + value._type.sz > sz) { sz = value.offs + value._type.sz; }; if (value._type._align > _align) { _align = value._type._align; }; }; yield tu; case let lt: ast::list_type => let r = list_from_ast(store, <)?; sz = r.0; _align = r.1; yield r.2; case let et: ast::enum_type => abort(); // TODO }; if (sz != SIZE_UNDEFINED && sz != 0 && sz % _align != 0) { sz += _align - (sz - _align) % _align; }; return _type { id = 0, // filled in later flags = atype.flags: flag, repr = repr, sz = sz, _align = _align, }; }; fn func_from_ast( store: *typestore, ft: *ast::func_type, ) (func | deferred | error) = { let f = func { result = lookup(store, ft.result)?, variadism = switch (ft.variadism) { case ast::variadism::NONE => yield variadism::NONE; case ast::variadism::C => yield variadism::C; case ast::variadism::HARE => yield variadism::HARE; }, params = alloc([], len(ft.params)), }; for (let i = 0z; i < len(ft.params); i += 1) { append(f.params, lookup(store, ft.params[i]._type)?); }; return f; }; fn list_from_ast( store: *typestore, lt: *ast::list_type ) ((size, size, (slice | array)) | deferred | error) = { let sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED; let memb = lookup(store, lt.members)?; let t = match (lt.length) { case ast::len_slice => sz = store.arch._pointer; if (sz % store.arch._size != 0) { sz += store.arch._size - (sz % store.arch._size); }; sz += store.arch._size * 2; _align = if (store.arch._pointer > store.arch._size) store.arch._pointer else store.arch._size; yield memb: slice; case (ast::len_unbounded | ast::len_contextual) => // Note: contextual length is handled by hare::unit when // initializing bindings. We treat it like unbounded here and // it's fixed up later on. _align = memb._align; yield array { length = SIZE_UNDEFINED, member = memb, }; case let ex: *ast::expr => const resolv = match (store.resolve) { case null => return noresolver; case let r: *resolver => yield r; }; const length = resolv(store.rstate, store, ex)?; sz = memb.sz * length; assert(sz / length == memb.sz, "overflow"); _align = memb._align; yield array { length = length, member = memb, }; }; return (sz, _align, t); }; fn _struct_from_ast( store: *typestore, atype: ast::struct_union_type, is_union: bool, fields: *[]struct_field, offs: *size, ) (void | deferred | error) = { const nfields = len(fields); const membs = match(atype) { case let atype: ast::struct_type => yield atype.members; case let atype: ast::union_type => yield atype: []ast::struct_member; }; for (let i = 0z; i < len(membs); i += 1) { *offs = match (membs[i]._offset) { case let ex: *ast::expr => yield match (store.resolve) { case null => return noresolver; case let res: *resolver => yield res(store.rstate, store, ex)?; }; case null => yield *offs; }; const memb = match (membs[i].member) { case let se: ast::struct_embedded => let membs: []ast::struct_member = match (se.repr) { case let st: ast::struct_type => yield st.members; case let ut: ast::union_type => yield ut; case => abort(); // Invariant }; _struct_from_ast(store, membs, se.repr is ast::union_type, fields, offs)?; continue; case let se: ast::struct_alias => abort(); // TODO case let sf: ast::struct_field => yield sf; }; const _type = lookup(store, memb._type)?; if (*offs % _type._align != 0) { *offs += _type._align - (*offs % _type._align); }; append(fields, struct_field { name = memb.name, offs = *offs, _type = _type, }); if (!is_union) { *offs += _type.sz; }; }; if (is_union) { let max = 0z; for (let i = nfields; i < len(fields); i += 1) { if (fields[i].offs + fields[i]._type.sz > max) { max = fields[i].offs + fields[i]._type.sz; }; }; *offs = max; }; }; fn struct_from_ast( store: *typestore, atype: ast::struct_union_type, is_union: bool, ) (_struct | deferred | error) = { let fields: []struct_field = []; let offs = 0z; _struct_from_ast(store, atype, is_union, &fields, &offs)?; sort::sort(fields, size(struct_field), &field_cmp); return _struct { kind = if (is_union) struct_union::UNION else struct_union::STRUCT, fields = fields, }; }; fn tagged_collect( store: *typestore, atype: ast::tagged_type, types: *[]const *_type, ) (void | deferred | error) = { for (let i = 0z; i < len(atype); i += 1) match (atype[i].repr) { case let ta: ast::tagged_type => tagged_collect(store, ta, types)?; case => append(types, lookup(store, atype[i])?); }; }; fn tagged_cmp(a: const *opaque, b: const *opaque) int = { const a = a: const **_type, b = b: const **_type; return if (a.id < b.id) -1 else if (a.id == b.id) 0 else 1; }; fn tagged_from_ast( store: *typestore, atype: ast::tagged_type, ) (tagged | deferred | error) = { let types: []const *_type = []; //defer! free(types); tagged_collect(store, atype, &types)?; sort::sort(types, size(const *_type), &tagged_cmp); for (let i = 1z; i < len(types); i += 1) { if (types[i].id == types[i - 1].id) { delete(types[i]); i -= 1; }; }; // TODO: Handle this gracefully assert(len(types) > 1); return types; }; fn tuple_from_ast( store: *typestore, membs: ast::tuple_type, ) (tuple | deferred | error) = { let values: []tuple_value = []; let offs = 0z; for (let i = 0z; i < len(membs); i += 1) { const val = membs[i]; const vtype = lookup(store, val)?; if (offs % vtype._align != 0) { offs += vtype._align - (offs % vtype._align); }; append(values, tuple_value { _type = vtype, offs = offs, }); offs += vtype.sz; }; return values; }; fn field_cmp(a: const *opaque, b: const *opaque) int = { const a = a: const *struct_field, b = b: *const struct_field; return strings::compare(a.name, b.name); }; fn type_finish(t: *_type) void = { match (t.repr) { case let a: alias => ast::ident_free(a.id); case array => void; case builtin => void; case let e: _enum => free(e.values); case let f: func => free(f.params); case pointer => void; case let s: slice => void; case let st: _struct => free(st.fields); case let tu: tuple => free(tu); case let ta: tagged => free(ta); }; }; hare-0.24.2/hare/types/types.ha000066400000000000000000000047621464473310100162730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; // A type alias. export type alias = struct { id: ast::ident, // null for forward referenced types secondary: const nullable *_type, }; // An array type, e.g. [10]int export type array = struct { // [[SIZE_UNDEFINED]] for [*]type length: size, member: const *_type, }; // A built-in primitive type (int, bool, str, etc). export type builtin = enum u8 { // Keep me consistent with ast::builtin BOOL, DONE, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VALIST, VOID }; // An enum type, e.g. enum { FOO = 0 } export type _enum = struct { storage: builtin, values: [](str, u64), }; // Indicates the variadism of a [[func]] export type variadism = enum { NONE, C, HARE, }; // A function type, e.g. fn(x: int, y: int) int export type func = struct { result: const *_type, variadism: variadism, params: []const *_type, }; // Flags which apply to a pointer type. export type pointer_flag = enum u8 { // Keep me consistent with ast::pointer_flag NONE = 0, NULLABLE = 1 << 0, }; // *int export type pointer = struct { referent: const *_type, flags: pointer_flag, }; // []int export type slice = const *_type; // Indicates if a [[_struct]] was declared as a struct or union type. export type struct_union = enum { STRUCT, UNION, }; // struct { ... } or union { ... } // // Note that embedded anonymous structs will have been merged into their parent // type. export type _struct = struct { kind: struct_union, fields: []struct_field, }; // A single struct field. export type struct_field = struct { // "" for an anonymous field name: str, offs: size, _type: const *_type, }; // A tagged union type, e.g. (int | uint | void). export type tagged = []const *_type; // A tuple type, e.g. (a, b, c) export type tuple = []tuple_value; // A single value of a tuple type. export type tuple_value = struct { offs: size, _type: const *_type, }; // Flags for a Hare type. export type flag = enum u8 { // Keep me consistent with ast::type_flag NONE = 0, CONST = 1 << 0, ERROR = 1 << 1, }; // The sz field of [[_type]] is set to this value to indicate that the size of // the type is undefined. export def SIZE_UNDEFINED: size = -1: size; // A Hare type. export type _type = struct { flags: flag, repr: (alias | array | builtin | _enum | func | pointer | slice | _struct | tagged | tuple), id: u32, sz: size, _align: size, }; hare-0.24.2/hare/unit/000077500000000000000000000000001464473310100144175ustar00rootroot00000000000000hare-0.24.2/hare/unit/+test.ha000066400000000000000000000104201464473310100157600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use hare::ast; use hare::lex; use hare::parse; use hare::types; use memio; use strings; fn parse_expr(src: str) *ast::expr = { let stream = memio::fixed(strings::toutf8(src)); let sc = bufio::newscanner(&stream); defer bufio::finish(&sc); let lexer = lex::init(&sc, ""); return alloc(parse::expr(&lexer)!); }; fn mktestctx() context = context { store = types::store(types::x86_64, null, null), scope = alloc(scope { ... }), ... }; fn freetestctx(ctx: *context) void = { // TODO: Some of this should be in -test types::store_free(ctx.store); }; @test fn access() void = { // TODO: Test error cases, more access types const ctx = mktestctx(); defer freetestctx(&ctx); const object = scope_insert(&ctx, object { kind = object_kind::BIND, ident = ["hello"], name = ["hello"], _type = &types::builtin_u32, ... }); const aexpr = parse_expr("hello"); defer ast::expr_finish(aexpr); const expr = process_access(&ctx, aexpr)!; const access = expr.expr as access; const ao = access as access_object; assert(ao == object); assert(expr.result == &types::builtin_u32); }; @test fn compound() void = { const ctx = mktestctx(); defer freetestctx(&ctx); const aexpr = parse_expr("{ void; void; void; }"); defer ast::expr_finish(aexpr); const expr = process_compound(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == types::builtin::VOID); const compound = expr.expr as compound; assert(len(compound) == 3); const aexpr = parse_expr("{ return; }"); defer ast::expr_finish(aexpr); const expr = process_compound(&ctx, aexpr)!; assert(expr.terminates); // TODO: test yields }; @test fn constant() void = { const ctx = mktestctx(); defer freetestctx(&ctx); const aexpr = parse_expr("void"); defer ast::expr_finish(aexpr); const expr = process_constant(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == types::builtin::VOID); const constexpr = expr.expr as constant; assert(constexpr is void); const aexpr = parse_expr("true"); defer ast::expr_finish(aexpr); const expr = process_constant(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == types::builtin::BOOL); const constexpr = expr.expr as constant; assert(constexpr as bool == true); const aexpr = parse_expr("false"); defer ast::expr_finish(aexpr); const expr = process_constant(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == types::builtin::BOOL); const constexpr = expr.expr as constant; assert(constexpr as bool == false); const aexpr = parse_expr("null"); defer ast::expr_finish(aexpr); const expr = process_constant(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == types::builtin::NULL); assert(expr.expr is constant); const cases: [_](str, types::builtin, constant) = [ ("1234", types::builtin::INT, 1234), ("1234u", types::builtin::UINT, 1234u), ("\"hello world\"", types::builtin::STR, "hello world"), ("'!'", types::builtin::RUNE, '!'), ("13.37", types::builtin::F64, 13.37f64), ]; for (let i = 0z; i < len(cases); i += 1) { const _case = cases[i]; const aexpr = parse_expr(_case.0); defer ast::expr_finish(aexpr); const expr = process_constant(&ctx, aexpr)!; assert(expr.result.repr as types::builtin == _case.1); const constexpr = expr.expr as constant; match (_case.2) { case let s: str => assert(constexpr as str == s); case let r: rune => assert(constexpr as rune == r); case let i: i64 => assert(constexpr as i64 == i); case let u: u64 => assert(constexpr as u64 == u); case let f: f64 => assert(constexpr as f64 == f); case void => abort(); }; }; }; @test fn _return() void = { const ctx = mktestctx(); defer freetestctx(&ctx); const aexpr = parse_expr("return;"); defer ast::expr_finish(aexpr); const ret_expr = process_return(&ctx, aexpr)!; assert(ret_expr.terminates); assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); const rval = ret_expr.expr as _return; assert(rval == null); const aexpr = parse_expr("return 10;"); defer ast::expr_finish(aexpr); const ret_expr = process_return(&ctx, aexpr)!; assert(ret_expr.terminates); assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); const rval = ret_expr.expr as _return; assert((rval as *expr).expr is constant); }; hare-0.24.2/hare/unit/check.ha000066400000000000000000000011161464473310100160050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::types; // Type checks a set of [[hare::ast::subunit]]s and determines if it is // logically consistent, then returns the corresponding [[unit]], which from // then on is guaranteed to be compilable. export fn check( store: *types::typestore, ident: ast::ident, subunits: const []ast::subunit, ) (unit | error) = { let ctx = context { store = store, scope = alloc(scope { class = scope_class::UNIT, ... }), ... }; scan(&ctx, subunits)?; return process(&ctx, subunits); }; hare-0.24.2/hare/unit/context.ha000066400000000000000000000003101464473310100164070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::types; type context = struct { store: *types::typestore, scope: *scope, fntype: nullable *types::func, }; hare-0.24.2/hare/unit/errors.ha000066400000000000000000000002431464473310100162440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::types; // TODO: More errors export type error = !(types::error | void); hare-0.24.2/hare/unit/expr.ha000066400000000000000000000025731464473310100157160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; use hare::types; // A type-checked and validated Hare expression. export type expr = struct { start: lex::location, end: lex::location, result: const *types::_type, terminates: bool, expr: (access | bindings | compound | constant | _return), }; // An access expression. export type access = (access_object | access_field | access_index | access_tuple); // An access expression for an object. export type access_object = *object; // An access expression for a struct field. export type access_field = struct { object: *expr, field: const *types::struct_field, }; // An access expression for a slice or array index. export type access_index = struct { object: *expr, index: *expr, }; // An access expression for a tuple value. export type access_tuple = struct { object: *expr, value: const *types::tuple_value, }; // A single variable biding. // // foo: int = bar export type binding = struct { object: *object, init: *expr, }; // A list of variable bindings. export type bindings = []binding; // A compound expression, i.e. { ... } export type compound = []*expr; // The value of a constant expression. export type constant = (...ast::value | i64 | u64 | f64); // TODO: composite types // A return expression, i.e. return export type _return = nullable *expr; hare-0.24.2/hare/unit/process.ha000066400000000000000000000174561464473310100164240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; use hare::types; fn process(ctx: *context, subunits: const []ast::subunit) (unit | error) = { let unit = unit { ident = [], // TODO decls = [], }; for (let i = 0z; i < len(subunits); i += 1) { let subunit = subunits[i]; for (let j = 0z; j < len(subunit.decls); j += 1) { let adecl = &subunit.decls[j]; let decl = match (process_decl(ctx, adecl)) { case let d: decl => yield d; case error => abort(); // TODO }; append(unit.decls, decl); }; }; return unit; }; fn process_decl( ctx: *context, decl: *ast::decl, ) (decl | error) = { // TODO: match on &decl.decl match (decl.decl) { case let co: []ast::decl_const => abort(); // TODO case let gl: []ast::decl_global => abort(); // TODO case let ty: []ast::decl_type => abort(); // TODO case let fu: ast::decl_func => return process_func(ctx, decl, &fu); case let ex: ast::assert_expr => abort(); // TODO }; }; fn process_func( ctx: *context, adecl: *ast::decl, func: *ast::decl_func, ) (decl | error) = { assert(func.attrs & ast::fndecl_attr::TEST == 0); // TODO const afndecl = adecl.decl as ast::decl_func; const prototype = types::lookup(ctx.store, func.prototype)!; const fntype = prototype.repr as types::func; assert(fntype.variadism == types::variadism::NONE); // TODO assert(len(fntype.params) == 0); // TODO ctx.fntype = &fntype; const body: nullable *expr = match (afndecl.body) { case let abody: *ast::expr => yield process_expr(ctx, abody)?; case null => yield null; }; return decl { exported = adecl.exported, start = adecl.start, end = adecl.end, decl = decl_func { symbol = afndecl.symbol, // TODO: Add namespace to ident ident = ast::ident_dup(afndecl.ident), prototype = prototype, body = body, // TODO: We should make these enums inherited attrs = afndecl.attrs: ast::fndecl_attr, }, }; }; fn process_expr( ctx: *context, expr: *ast::expr, ) (*expr | error) = { match (expr.expr) { case ast::access_expr => return process_access(ctx, expr); case ast::alloc_expr => abort(); // TODO case ast::append_expr => abort(); // TODO case ast::assert_expr => abort(); // TODO case ast::assign_expr => abort(); // TODO case ast::binarithm_expr => abort(); // TODO case ast::binding_expr => return process_binding(ctx, expr); case ast::break_expr => abort(); // TODO case ast::call_expr => abort(); // TODO case ast::cast_expr => abort(); // TODO case ast::compound_expr => return process_compound(ctx, expr); case ast::literal_expr => return process_constant(ctx, expr); case ast::continue_expr => abort(); // TODO case ast::defer_expr => abort(); // TODO case ast::delete_expr => abort(); // TODO case ast::error_assert_expr => abort(); // TODO case ast::for_expr => abort(); // TODO case ast::free_expr => abort(); // TODO case ast::if_expr => abort(); // TODO case ast::match_expr => abort(); // TODO case ast::len_expr => abort(); // TODO case ast::size_expr => abort(); // TODO case ast::offset_expr => abort(); // TODO case ast::propagate_expr => abort(); // TODO case ast::return_expr => return process_return(ctx, expr); case ast::slice_expr => abort(); // TODO case ast::switch_expr => abort(); // TODO case ast::unarithm_expr => abort(); // TODO }; }; fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const access_expr = aexpr.expr as ast::access_expr; const (result, ex) = match (access_expr) { case let ai: ast::access_identifier => const object = match (ctx_lookup(ctx, ai)) { case null => abort(); // TODO: Error case let obj: *object => yield obj; }; yield (object._type, object); case let ai: ast::access_index => abort(); // TODO case let af: ast::access_field => abort(); // TODO case let at: ast::access_tuple => abort(); // TODO }; return alloc(expr { start = aexpr.start, end = aexpr.end, result = result, expr = ex, terminates = false, }); }; fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const bind = aexpr.expr as ast::binding_expr; assert(!bind.is_static && bind.kind == ast::binding_kind::LET); let bindings: bindings = []; for (let i = 0z; i < len(bind.bindings); i += 1) { const item = bind.bindings[i]; const init = process_expr(ctx, item.init)?; const _type = match (item._type) { case null => abort(); // TODO case let ty: *ast::_type => yield types::lookup(ctx.store, ty)!; }; const object = scope_insert(ctx, object { kind = object_kind::BIND, // TODO: tuple unpacking ident = ast::ident_dup([item.name as str]), name = ast::ident_dup([item.name as str]), _type = _type, ... }); append(bindings, binding { object = object, init = init, }); }; return alloc(expr { start = aexpr.start, end = aexpr.end, result = &types::builtin_void, expr = bindings, ... }); }; fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const compound_expr = aexpr.expr as ast::compound_expr; const scope = scope_push(ctx, scope_class::COMPOUND); let exprs: compound = alloc([], len(compound_expr.exprs)); let i = 0z; for (i < len(compound_expr.exprs); i += 1) { append(exprs, process_expr(ctx, compound_expr.exprs[i])?); }; scope_pop(ctx); return alloc(expr { start = aexpr.start, end = aexpr.end, result = &types::builtin_void, // TODO: Pick result type expr = exprs, terminates = exprs[i - 1].terminates, ... }); }; fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const constexpr = aexpr.expr as ast::literal_expr; const (result, ex) = match (constexpr) { case let v: ast::value => yield ( // TODO: iconst/fconst lowering types::lookup_builtin(ctx.store, match (v) { case ast::_null => yield ast::builtin_type::NULL; case let b: bool => yield ast::builtin_type::BOOL; case let s: str => yield ast::builtin_type::STR; case let r: rune => yield ast::builtin_type::RUNE; case void => yield ast::builtin_type::VOID; }), v: constant, ); case ast::array_literal => abort(); // TODO case let v: ast::number_literal => yield ( types::lookup_builtin(ctx.store, switch (v.suff) { case lex::ltok::LIT_U8 => yield ast::builtin_type::U8; case lex::ltok::LIT_U16 => yield ast::builtin_type::U16; case lex::ltok::LIT_U32 => yield ast::builtin_type::U32; case lex::ltok::LIT_U64 => yield ast::builtin_type::U64; case lex::ltok::LIT_UINT => yield ast::builtin_type::UINT; case lex::ltok::LIT_SIZE => yield ast::builtin_type::SIZE; case lex::ltok::LIT_I8 => yield ast::builtin_type::I8; case lex::ltok::LIT_I16 => yield ast::builtin_type::I16; case lex::ltok::LIT_I32 => yield ast::builtin_type::I32; case lex::ltok::LIT_I64 => yield ast::builtin_type::I64; case lex::ltok::LIT_INT, lex::ltok::LIT_ICONST => yield ast::builtin_type::INT; case lex::ltok::LIT_F32 => yield ast::builtin_type::F32; case lex::ltok::LIT_F64, lex::ltok::LIT_FCONST => yield ast::builtin_type::F64; case => abort(); // unreachable }), v.value: constant, ); case ast::struct_literal => abort(); // TODO case ast::tuple_literal => abort(); // TODO }; return alloc(expr { start = aexpr.start, end = aexpr.end, result = result, expr = ex, ... }); }; fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const ret = aexpr.expr as ast::return_expr; const rval = match (ret) { case null => yield null; case let aexpr: *ast::expr => yield process_expr(ctx, aexpr)?; }; // TODO: assert(types::assignable(ctx.fntype.result as *types::func, rval.type)); return alloc(expr { start = aexpr.start, end = aexpr.end, terminates = true, result = &types::builtin_void, expr = rval: _return, }); }; hare-0.24.2/hare/unit/scan.ha000066400000000000000000000034021464473310100156540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::types; // The scan phase determines the types of all declarations in the unit, and // handles forward references, so that the next phase (validate) is simplified. fn scan(ctx: *context, subunits: const []ast::subunit) (void | error) = { for (let i = 0z; i < len(subunits); i += 1) { let subunit = &subunits[i]; assert(len(subunit.imports) == 0); // TODO scope_push(ctx, scope_class::SUBUNIT); for (let j = 0z; j < len(subunit.decls); j += 1) { let decl = &subunit.decls[j]; match (scan_decl(ctx, decl)) { case void => void; case types::deferred => abort(); // TODO case error => abort(); // TODO }; }; scope_pop(ctx); }; }; fn scan_decl( ctx: *context, decl: *ast::decl, ) (void | types::deferred | error) = { // TODO: match on &decl.decl match (decl.decl) { case let co: []ast::decl_const => abort(); // TODO case let gl: []ast::decl_global => abort(); // TODO case let ty: []ast::decl_type => abort(); // TODO case let fu: ast::decl_func => return scan_func(ctx, decl, &fu); case let ex: ast::assert_expr => abort(); // TODO }; }; fn scan_func( ctx: *context, decl: *ast::decl, func: *ast::decl_func, ) (void | types::deferred | error) = { assert(func.attrs & ast::fndecl_attr::TEST == 0); // TODO const fntype = match (types::lookup(ctx.store, func.prototype)) { case let err: types::error => return err; case types::deferred => return types::deferred; case let fntype: const *types::_type => yield fntype; }; scope_insert(ctx, object { kind = object_kind::DECL, // TODO: Add namespace to ident ident = ast::ident_dup(func.ident), name = ast::ident_dup(func.ident), _type = fntype, ... }); }; hare-0.24.2/hare/unit/scope.ha000066400000000000000000000046531464473310100160520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::types; use hash; use hash::fnv; use strings; // What sort of [[object]] is represented. export type object_kind = enum { BIND, CONST, DECL, TYPE, }; // An object is a named object in a scope, such as a binding, type, or // declaration. export type object = struct { kind: object_kind, hash: u64, // The fully qualified identifier ident: ast::ident, // Local name, if different from the fully qualified identifier name: ast::ident, _type: const *types::_type, // TODO: store value for constants }; export def SCOPE_BUCKETS: size = 4096; // What kind of [[scope]] is represented. export type scope_class = enum { COMPOUND, ENUM, FUNC, LOOP, MATCH, SUBUNIT, UNIT, }; // A scope is a member of a hierarchy of storage containers which hold named // [[object]]s, such as variables or function parameters. export type scope = struct { class: scope_class, parent: nullable *scope, objects: []object, hashmap: [SCOPE_BUCKETS][]*object, }; fn scope_push(ctx: *context, class: scope_class) *scope = { let new = alloc(scope { class = class, parent = ctx.scope, ... }); ctx.scope = new; return new; }; fn scope_pop(ctx: *context) *scope = { const top_scope = ctx.scope; ctx.scope = ctx.scope.parent: *scope; // TODO: as *scope return top_scope; }; fn ident_hash(ident: ast::ident) u64 = { let hash = fnv::fnv64a(); const zerobuf = [0u8]; for (let i = len(ident); i > 0; i -= 1) { hash::write(&hash, strings::toutf8(ident[i - 1])); hash::write(&hash, zerobuf[..]); }; return fnv::sum64(&hash); }; fn scope_insert(ctx: *context, obj: object) *object = { const scope = ctx.scope; append(scope.objects, obj); let obj = &scope.objects[len(scope.objects) - 1]; const hash = ident_hash(obj.ident); obj.hash = hash; append(scope.hashmap[hash: size % SCOPE_BUCKETS], obj); return obj; }; fn ctx_lookup(ctx: *context, ident: ast::ident) nullable *object = scope_lookup(ctx.scope, ident); fn scope_lookup(scp: *scope, ident: ast::ident) nullable *object = { const hash = ident_hash(ident); const bucket = scp.hashmap[hash: size % SCOPE_BUCKETS]; for (let i = 0z; i < len(bucket); i += 1) { if (ast::ident_eq(bucket[i].name, ident) || ast::ident_eq(bucket[i].ident, ident)) { return bucket[i]; }; }; match (scp.parent) { case null => return null; case let s: *scope => return scope_lookup(s, ident); }; }; hare-0.24.2/hare/unit/unit.ha000066400000000000000000000012711464473310100157110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use hare::lex; use hare::types; // A function declaration. export type decl_func = struct { symbol: str, ident: ast::ident, prototype: const *types::_type, body: nullable *expr, attrs: ast::fndecl_attr, }; // A declaration within a unit. export type decl = struct { exported: bool, start: lex::location, end: lex::location, decl: (decl_func | void), // TODO: Other decl types }; // A single compilation unit, representing all of the members of a namespace. export type unit = struct { ident: ast::ident, decls: []decl, }; export fn unit_finish(unit: unit) void = { // TODO return; }; hare-0.24.2/hare/unparse/000077500000000000000000000000001464473310100151155ustar00rootroot00000000000000hare-0.24.2/hare/unparse/README000066400000000000000000000002231464473310100157720ustar00rootroot00000000000000hare::unparse provides an unparser for Hare. All functions take in some part of the AST and write formatted Hare source code to an [[io::handle]]. hare-0.24.2/hare/unparse/decl.ha000066400000000000000000000163721464473310100163470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use hare::lex; use io; use memio; use strings; // Unparses a [[hare::ast::decl]]. export fn decl( out: io::handle, syn: *synfunc, d: *ast::decl, ) (size | io::error) = { let n = 0z; let ctx = context { out = out, stack = &stack { cur = d, ... }, ... }; if (len(d.docs) > 0) { n += comment(&ctx, syn, d.docs)?; }; if (d.exported) { n += syn(&ctx, "export", synkind::KEYWORD)?; n += space(&ctx)?; }; match (d.decl) { case let c: []ast::decl_const => n += syn(&ctx, "def", synkind::KEYWORD)?; n += space(&ctx)?; for (let i = 0z; i < len(c); i += 1) { n += _ident(&ctx, syn, c[i].ident, synkind::CONSTANT)?; match (c[i]._type) { case null => void; case let ty: *ast::_type => n += syn(&ctx, ":", synkind::PUNCTUATION)?; n += space(&ctx)?; n += __type(&ctx, syn, ty)?; }; n += space(&ctx)?; n += syn(&ctx, "=", synkind::OPERATOR)?; n += space(&ctx)?; n += _expr(&ctx, syn, c[i].init)?; if (i + 1 < len(c)) { n += syn(&ctx, ",", synkind::PUNCTUATION)?; n += space(&ctx)?; }; }; case let g: []ast::decl_global => n += syn(&ctx, if (g[0].is_const) "const" else "let", synkind::KEYWORD)?; n += space(&ctx)?; for (let i = 0z; i < len(g); i += 1) { if (len(g[i].symbol) != 0) { n += syn(&ctx, "@symbol(", synkind::ATTRIBUTE)?; n += literal(&ctx, syn, g[i].symbol)?; n += syn(&ctx, ")", synkind::ATTRIBUTE)?; n += space(&ctx)?; } else if (g[i].is_threadlocal) { n += syn(&ctx, "@threadlocal", synkind::ATTRIBUTE)?; n += space(&ctx)?; }; n += _ident(&ctx, syn, g[i].ident, synkind::GLOBAL)?; match (g[i]._type) { case null => void; case let ty: *ast::_type => n += syn(&ctx, ":", synkind::PUNCTUATION)?; n += space(&ctx)?; n += __type(&ctx, syn, ty)?; }; match (g[i].init) { case null => void; case let ex: *ast::expr => n += space(&ctx)?; n += syn(&ctx, "=", synkind::OPERATOR)?; n += space(&ctx)?; n += _expr(&ctx, syn, ex)?; }; if (i + 1 < len(g)) { n += syn(&ctx, ",", synkind::OPERATOR)?; n += space(&ctx)?; }; }; case let t: []ast::decl_type => n += syn(&ctx, "type", synkind::KEYWORD)?; n += space(&ctx)?; for (let i = 0z; i < len(t); i += 1) { n += _ident(&ctx, syn, t[i].ident, synkind::TYPEDEF)?; n += space(&ctx)?; n += syn(&ctx, "=", synkind::OPERATOR)?; n += space(&ctx)?; n += __type(&ctx, syn, t[i]._type)?; if (i + 1 < len(t)) { n += syn(&ctx, ",", synkind::PUNCTUATION)?; n += space(&ctx)?; }; }; case let f: ast::decl_func => ctx.stack = &stack { cur = f.prototype, up = ctx.stack, ... }; defer { let stack = &(ctx.stack as *stack); match (stack.extra) { case let p: *opaque => free(p); case null => void; }; ctx.stack = stack.up; }; switch (f.attrs) { case ast::fndecl_attr::NONE => void; case ast::fndecl_attr::FINI => n += syn(&ctx, "@fini", synkind::ATTRIBUTE)?; n += space(&ctx)?; case ast::fndecl_attr::INIT => n += syn(&ctx, "@init", synkind::ATTRIBUTE)?; n += space(&ctx)?; case ast::fndecl_attr::TEST => n += syn(&ctx, "@test", synkind::ATTRIBUTE)?; n += space(&ctx)?; }; let p = f.prototype.repr as ast::func_type; if (len(f.symbol) != 0) { n += syn(&ctx, "@symbol(", synkind::ATTRIBUTE)?; n += literal(&ctx, syn, f.symbol)?; n += syn(&ctx, ")", synkind::ATTRIBUTE)?; n += space(&ctx)?; }; n += syn(&ctx, "fn", synkind::KEYWORD)?; n += space(&ctx)?; n += _ident(&ctx, syn, f.ident, synkind::FUNCTION)?; const fntype = f.prototype.repr as ast::func_type; n += prototype(&ctx, syn, &fntype)?; match (f.body) { case null => void; case let e: *ast::expr => n += space(&ctx)?; n += syn(&ctx, "=", synkind::OPERATOR)?; n += space(&ctx)?; n += _expr(&ctx, syn, e)?; }; case let e: ast::assert_expr => n += assert_expr(&ctx, syn, &e)?; }; n += syn(&ctx, ";", synkind::PUNCTUATION)?; return n; }; fn comment(ctx: *context, syn: *synfunc, s: str) (size | io::error) = { let n = 0z; let s = strings::trimsuffix(s, "\n"); let s = strings::tokenize(s, "\n"); for (let line => strings::next_token(&s)) { for (let i = 0z; i < ctx.indent; i += 1) { n += syn(ctx, "\t", synkind::COMMENT)?; ctx.linelen += 8; }; n += syn(ctx, "//", synkind::COMMENT)?; n += syn(ctx, line, synkind::COMMENT)?; n += syn(ctx, "\n", synkind::COMMENT)?; ctx.linelen = 0; }; return n; }; fn decl_test(d: *ast::decl, expected: str) bool = { let buf = memio::dynamic(); decl(&buf, &syn_nowrap, d)!; let s = memio::string(&buf)!; defer free(s); fmt::println(s)!; return s == expected; }; @test fn decl() void = { let loc = lex::location { path = "", line = 0, col = 0, }; let type_int = ast::_type { start = loc, end = loc, flags = 0, repr = ast::builtin_type::INT, }; let type_fn = ast::_type { start = loc, end = loc, flags = 0, repr = ast::func_type { result = &type_int, variadism = ast::variadism::HARE, params = [ ast::func_param { loc = loc, name = "foo", _type = &type_int, default_value = void, }, ast::func_param { loc = loc, name = "bar", _type = &type_int, default_value = void, }, ], }, }; let expr_void = ast::expr { start = lex::location { ... }, end = lex::location { ... }, expr = void, }; let d = ast::decl { exported = false, start = loc, end = loc, decl = [ ast::decl_global { is_const = false, is_threadlocal = false, symbol = "", ident = ["foo", "bar"], _type = &type_int, init = alloc(expr_void), }, ast::decl_global { is_const = false, is_threadlocal = true, symbol = "", ident = ["boo"], _type = &type_int, init = alloc(expr_void), }, ast::decl_global { is_const = false, is_threadlocal = false, symbol = "foobar", ident = ["baz"], _type = &type_int, init = alloc(expr_void), }, ], ... }; assert(decl_test(&d, "let foo::bar: int = void, @threadlocal boo: int = void, @symbol(\"foobar\") baz: int = void;")); d.exported = true; d.decl = [ ast::decl_const { ident = ["foo"], _type = &type_int, init = alloc(expr_void), }, ]; assert(decl_test(&d, "export def foo: int = void;")); d.exported = false; d.decl = [ ast::decl_type { ident = ["foo"], _type = &type_int, }, ast::decl_type { ident = ["bar"], _type = &type_int, }, ]; assert(decl_test(&d, "type foo = int, bar = int;")); d.decl = ast::decl_func { symbol = "foo", ident = ["foo"], prototype = &type_fn, body = null, attrs = ast::fndecl_attr::FINI, }; assert(decl_test(&d, "@fini @symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); type_fn.repr = ast::func_type { result = &type_int, variadism = ast::variadism::NONE, params = [ ast::func_param { loc = loc, name = "", _type = &type_int, default_value = ast::expr { expr = ast::number_literal { value = 4u64, sign = false, suff = lex::ltok::LIT_ICONST, }, ... }, }, ], }; d.decl = ast::decl_func { symbol = "", ident = ["foo"], prototype = &type_fn, body = &expr_void, attrs = 0, }; assert(decl_test(&d, "fn foo(int = 4) int = void;")); }; hare-0.24.2/hare/unparse/expr.ha000066400000000000000000000645751464473310100164260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use hare::ast::{binarithm_op}; use hare::lex::{ltok}; use io; use strings; // Unparses a [[hare::ast::expr]]. export fn expr( out: io::handle, syn: *synfunc, e: *ast::expr, ) (size | io::error) = { let ctx = context { out = out, ... }; return _expr(&ctx, syn, e); }; fn _expr(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = { ctx.stack = &stack { cur = e, up = ctx.stack, ... }; defer { let stack = &(ctx.stack as *stack); match (stack.extra) { case let p: *opaque => free(p); case null => void; }; ctx.stack = stack.up; }; match (e.expr) { case let e: ast::access_expr => match (e) { case let id: ast::access_identifier => return _ident(ctx, syn, id, synkind::IDENT); case let ix: ast::access_index => let z = 0z; const needs_parens = !is_postfix(ix.object); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, ix.object)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, "[", synkind::PUNCTUATION)?; z += _expr(ctx, syn, ix.index)?; z += syn(ctx, "]", synkind::PUNCTUATION)?; return z; case let fi: ast::access_field => let z = 0z; const needs_parens = !is_postfix(fi.object); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, fi.object)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, ".", synkind::OPERATOR)?; z += syn(ctx, fi.field, synkind::SECONDARY)?; return z; case let tp: ast::access_tuple => let z = 0z; const needs_parens = !is_postfix(tp.object); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, tp.object)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, ".", synkind::OPERATOR)?; z += _expr(ctx, syn, tp.value)?; return z; }; case let e: ast::align_expr => let z = syn(ctx, "align", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += __type(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::alloc_expr => let z = syn(ctx, "alloc", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.init)?; match (e.capacity) { case null => if (e.form == ast::alloc_form::COPY) { z += syn(ctx, "...", synkind::OPERATOR)?; }; case let e: *ast::expr => z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, e)?; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case ast::append_expr => return append_insert_expr(ctx, syn, e); case let e: ast::assert_expr => return assert_expr(ctx, syn, &e); case let e: ast::assign_expr => let z = 0z; z += _expr(ctx, syn, e.object)?; const op = match (e.op) { case void => yield "="; case let op: binarithm_op => yield switch (op) { case binarithm_op::BAND => yield "&="; case binarithm_op::LAND => yield "&&="; case binarithm_op::BOR => yield "|="; case binarithm_op::LOR => yield "||="; case binarithm_op::DIV => yield "/="; case binarithm_op::LSHIFT => yield "<<="; case binarithm_op::MINUS => yield "-="; case binarithm_op::MODULO => yield "%="; case binarithm_op::PLUS => yield "+="; case binarithm_op::RSHIFT => yield ">>="; case binarithm_op::TIMES => yield "*="; case binarithm_op::BXOR => yield "^="; case binarithm_op::LXOR => yield "^^="; case binarithm_op::GT, binarithm_op::GTEQ, binarithm_op::LESS, binarithm_op::LESSEQ, binarithm_op::LEQUAL, binarithm_op::NEQUAL => abort(); // unreachable }; }; z += space(ctx)?; z += syn(ctx, op, synkind::OPERATOR)?; z += space(ctx)?; z += _expr(ctx, syn, e.value)?; return z; case let e: ast::binarithm_expr => const prec = binprecedence(e.op); let z = binexprval(ctx, syn, e.lvalue, prec)?; z += space(ctx)?; z += syn(ctx, switch (e.op) { case binarithm_op::BAND => yield "&"; case binarithm_op::BOR => yield "|"; case binarithm_op::DIV => yield "/"; case binarithm_op::GT => yield ">"; case binarithm_op::GTEQ => yield ">="; case binarithm_op::LAND => yield "&&"; case binarithm_op::LEQUAL => yield "=="; case binarithm_op::LESS => yield "<"; case binarithm_op::LESSEQ => yield "<="; case binarithm_op::LOR => yield "||"; case binarithm_op::LSHIFT => yield "<<"; case binarithm_op::LXOR => yield "^^"; case binarithm_op::MINUS => yield "-"; case binarithm_op::MODULO => yield "%"; case binarithm_op::NEQUAL => yield "!="; case binarithm_op::PLUS => yield "+"; case binarithm_op::RSHIFT => yield ">>"; case binarithm_op::TIMES => yield "*"; case binarithm_op::BXOR => yield "^"; }, synkind::OPERATOR)?; z += space(ctx)?; z += binexprval(ctx, syn, e.rvalue, prec)?; return z; case let e: ast::binding_expr => return binding_expr(ctx, syn, &e, "=")?; case let e: ast::break_expr => let z = syn(ctx, "break", synkind::KEYWORD)?; if (e != "") { z += space(ctx)?; z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e, synkind::LABEL)?; }; return z; case let e: ast::call_expr => let z = 0z; const needs_parens = !is_postfix(e.lvalue); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e.lvalue)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, "(", synkind::PUNCTUATION)?; for (let i = 0z; i < len(e.args); i += 1) { z += _expr(ctx, syn, e.args[i])?; if (i + 1 < len(e.args)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; if (e.variadic) { z += syn(ctx, "...", synkind::OPERATOR)?; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::cast_expr => let z = 0z; const needs_parens = !is_cast(e.value); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e.value)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; switch (e.kind) { case ast::cast_kind::CAST => z += syn(ctx, ":", synkind::OPERATOR)?; z += space(ctx)?; case ast::cast_kind::ASSERTION => z += space(ctx)?; z += syn(ctx, "as", synkind::OPERATOR)?; z += space(ctx)?; case ast::cast_kind::TEST => z += space(ctx)?; z += syn(ctx, "is", synkind::OPERATOR)?; z += space(ctx)?; }; z += __type(ctx, syn, e._type)?; return z; case let e: ast::literal_expr => return literal(ctx, syn, e)?; case let e: ast::continue_expr => let z = syn(ctx, "continue", synkind::KEYWORD)?; if (e != "") { z += space(ctx)?; z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e, synkind::LABEL)?; }; return z; case let e: ast::defer_expr => let z = syn(ctx, "defer", synkind::KEYWORD)?; z += space(ctx)?; z += _expr(ctx, syn, e)?; return z; case let e: ast::delete_expr => let z = 0z; if (e.is_static) { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; z += syn(ctx, "delete", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.object)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::error_assert_expr => let z = 0z; const needs_parens = !is_postfix(e); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, "!", synkind::OPERATOR)?; return z; case let e: ast::for_expr => return for_expr(ctx, syn, &e)?; case let e: ast::free_expr => let z = syn(ctx, "free", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::if_expr => let z = syn(ctx, "if", synkind::KEYWORD)?; z += space(ctx)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.cond)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, e.tbranch)?; match (e.fbranch) { case null => void; case let e: *ast::expr => z += space(ctx)?; z += syn(ctx, "else", synkind::KEYWORD)?; z += space(ctx)?; z += _expr(ctx, syn, e)?; }; return z; case ast::insert_expr => return append_insert_expr(ctx, syn, e); case let e: ast::compound_expr => let z = 0z; if (e.label != "") { z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e.label, synkind::LABEL)?; z += space(ctx)?; }; z += syn(ctx, "{", synkind::PUNCTUATION)?; ctx.indent += 1; for (let expr .. e.exprs) { z += newline(ctx)?; z += stmt(ctx, syn, expr)?; }; ctx.indent -= 1; z += newline(ctx)?; z += syn(ctx, "}", synkind::PUNCTUATION)?; return z; case let e: ast::match_expr => return match_expr(ctx, syn, &e)?; case let e: ast::len_expr => let z = syn(ctx, "len", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::size_expr => let z = syn(ctx, "size", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += __type(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::offset_expr => let z = syn(ctx, "offset", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::propagate_expr => let z = 0z; const needs_parens = !is_postfix(e); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, "?", synkind::OPERATOR)?; return z; case let e: ast::return_expr => let z = syn(ctx, "return", synkind::KEYWORD)?; match (e) { case null => void; case let e: *ast::expr => z += space(ctx)?; z += _expr(ctx, syn, e)?; }; return z; case let e: ast::slice_expr => let z = 0z; const needs_parens = !is_postfix(e.object); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e.object)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; z += syn(ctx, "[", synkind::PUNCTUATION)?; match (e.start) { case null => void; case let e: *ast::expr => z += _expr(ctx, syn, e)?; }; z += syn(ctx, "..", synkind::OPERATOR)?; match (e.end) { case null => void; case let e: *ast::expr => z += _expr(ctx, syn, e)?; }; z += syn(ctx, "]", synkind::PUNCTUATION)?; return z; case let e: ast::switch_expr => return switch_expr(ctx, syn, &e)?; case let e: ast::unarithm_expr => let z = syn(ctx, switch (e.op) { case ast::unarithm_op::ADDR => yield "&"; case ast::unarithm_op::BNOT => yield "~"; case ast::unarithm_op::DEREF => yield "*"; case ast::unarithm_op::LNOT => yield "!"; case ast::unarithm_op::MINUS => yield "-"; }, synkind::OPERATOR)?; const needs_parens = match (e.operand.expr) { case let inner: ast::unarithm_expr => yield e.op == ast::unarithm_op::ADDR && inner.op == e.op; case => yield !is_unary(e.operand); }; if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e.operand)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; return z; case let e: ast::variadic_expr => match (e) { case ast::vastart_expr => let z = syn(ctx, "vastart", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::vaarg_expr => let z = syn(ctx, "vaarg", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; case let e: ast::vaend_expr => let z = syn(ctx, "vaend", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; }; case let e: ast::yield_expr => let z = syn(ctx, "yield", synkind::KEYWORD)?; if (e.label != "") { z += space(ctx)?; z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e.label, synkind::LABEL)?; }; match (e.value) { case null => void; case let v: *ast::expr => if (e.label != "") { z += syn(ctx, ",", synkind::PUNCTUATION)?; }; z += space(ctx)?; z += _expr(ctx, syn, v)?; }; return z; }; }; fn binprecedence(op: binarithm_op) uint = { switch (op) { case binarithm_op::DIV, binarithm_op::MODULO, binarithm_op::TIMES => return 10; case binarithm_op::MINUS, binarithm_op::PLUS => return 9; case binarithm_op::LSHIFT, binarithm_op::RSHIFT => return 8; case binarithm_op::BAND => return 7; case binarithm_op::BXOR => return 6; case binarithm_op::BOR => return 5; case binarithm_op::GT, binarithm_op::GTEQ, binarithm_op::LESS, binarithm_op::LESSEQ => return 4; case binarithm_op::LEQUAL, binarithm_op::NEQUAL => return 3; case binarithm_op::LAND => return 2; case binarithm_op::LXOR => return 1; case binarithm_op::LOR => return 0; }; }; fn binexprval( ctx: *context, syn: *synfunc, e: *ast::expr, prec: uint, ) (size | io::error) = { let z = 0z; match (e.expr) { case let b: ast::binarithm_expr => if (binprecedence(b.op) < prec) { z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; }; case => void; }; const needs_parens = !is_cast(e) && !(e.expr is ast::binarithm_expr); if (needs_parens) { z += syn(ctx, "(", synkind::PUNCTUATION)?; }; z += _expr(ctx, syn, e)?; if (needs_parens) { z += syn(ctx, ")", synkind::PUNCTUATION)?; }; return z; }; fn stmt(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = { let n = _expr(ctx, syn, e)?; n += syn(ctx, ";", synkind::PUNCTUATION)?; return n; }; fn literal( ctx: *context, syn: *synfunc, e: ast::literal_expr, ) (size | io::error) = { match (e) { case void => return syn(ctx, "void", synkind::KEYWORD)?; case let v: ast::value => match (v) { case void => abort(); case ast::_null => return syn(ctx, "null", synkind::KEYWORD)?; case done => return syn(ctx, "done", synkind::KEYWORD)?; case let b: bool => return syn(ctx, if (b) "true" else "false", synkind::KEYWORD)?; case let s: str => const s = strings::multireplace(s, (`\`, `\\`), (`"`, `\"`)); defer free(s); const s = fmt::asprintf(`"{}"`, s); defer free(s); return syn(ctx, s, synkind::RUNE_STRING)?; case let r: rune => // 4 for unicode codepoint + 2 's let buf: [6]u8 = [0...]; if (r == '\'' || r == '\\') { return syn(ctx, fmt::bsprintf(buf, `'\{}'`, r), synkind::RUNE_STRING)?; } else { return syn(ctx, fmt::bsprintf(buf, "'{}'", r), synkind::RUNE_STRING)?; }; }; case let ac: ast::array_literal => let z = syn(ctx, "[", synkind::PUNCTUATION)?; for (let i = 0z; i < len(ac.values); i += 1) { z += _expr(ctx, syn, ac.values[i])?; if (i + 1 < len(ac.values)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; if (ac.expand) { z += syn(ctx, "...", synkind::OPERATOR)?; }; z += syn(ctx, "]", synkind::PUNCTUATION)?; return z; case let v: ast::number_literal => const s = fmt::asprintf("{}{}", v.value, switch (v.suff) { case ltok::LIT_U8 => yield "u8"; case ltok::LIT_U16 => yield "u16"; case ltok::LIT_U32 => yield "u32"; case ltok::LIT_U64 => yield "u64"; case ltok::LIT_UINT => yield "u"; case ltok::LIT_SIZE => yield "z"; case ltok::LIT_I8 => yield "i8"; case ltok::LIT_I16 => yield "i16"; case ltok::LIT_I32 => yield "i32"; case ltok::LIT_I64 => yield "i64"; case ltok::LIT_INT => yield "i"; case ltok::LIT_ICONST, ltok::LIT_FCONST => yield ""; case ltok::LIT_F32 => yield "f32"; case ltok::LIT_F64 => yield "f64"; case => abort(); }); defer free(s); return syn(ctx, s, synkind::NUMBER)?; case let sc: ast::struct_literal => return struct_literal(ctx, syn, sc)?; case let tu: ast::tuple_literal => let z = syn(ctx, "(", synkind::PUNCTUATION)?; for (let i = 0z; i < len(tu); i += 1) { z += _expr(ctx, syn, tu[i])?; if (i + 1 < len(tu)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; }; }; fn struct_literal( ctx: *context, syn: *synfunc, sc: ast::struct_literal, ) (size | io::error) = { let z = 0z; z += if (len(sc.alias) != 0) { yield _ident(ctx, syn, sc.alias, synkind::IDENT)?; } else { yield syn(ctx, "struct", synkind::KEYWORD)?; }; z += space(ctx)?; z += syn(ctx, "{", synkind::PUNCTUATION)?; ctx.indent += 1; for (let field .. sc.fields) { z += newline(ctx)?; match (field) { case let sv: ast::struct_value => z += syn(ctx, sv.name, synkind::SECONDARY)?; match (sv._type) { case null => void; case let t: *ast::_type => z += syn(ctx, ":", synkind::PUNCTUATION)?; z += space(ctx)?; z += __type(ctx, syn, t)?; }; z += space(ctx)?; z += syn(ctx, "=", synkind::OPERATOR)?; z += space(ctx)?; z += _expr(ctx, syn, sv.init)?; case let sc: *ast::struct_literal => z += literal(ctx, syn, *sc)?; }; z += syn(ctx, ",", synkind::PUNCTUATION)?; }; if (sc.autofill) { z += newline(ctx)?; z += syn(ctx, "...", synkind::OPERATOR)?; }; ctx.indent -= 1; z += newline(ctx)?; z += syn(ctx, "}", synkind::PUNCTUATION)?; return z; }; fn binding_expr( ctx: *context, syn: *synfunc, e: *ast::binding_expr, assign_op: str ) (size | io::error) = { let z = 0z; if (e.is_static) { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; switch (e.kind) { case ast::binding_kind::DEF => z += syn(ctx, "def", synkind::KEYWORD)?; case ast::binding_kind::CONST => z += syn(ctx, "const", synkind::KEYWORD)?; case ast::binding_kind::LET => z += syn(ctx, "let", synkind::KEYWORD)?; }; z += space(ctx)?; for (let i = 0z; i < len(e.bindings); i += 1) { let binding = e.bindings[i]; match (binding.name) { case let s: str => z += syn(ctx, s, synkind::IDENT)?; case let u: ast::binding_unpack => z += syn(ctx, "(", synkind::PUNCTUATION)?; for (let i = 0z; i < len(u); i += 1) { match (u[i]) { case let s: str => z += syn(ctx, s, synkind::IDENT)?; case void => z += syn(ctx, "_", synkind::OPERATOR)?; }; if (i + 1 < len(u)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; }; match (binding._type) { case let t: *ast::_type => z += syn(ctx, ":", synkind::PUNCTUATION)?; z += space(ctx)?; z += __type(ctx, syn, t)?; case null => void; }; z += space(ctx)?; z += syn(ctx, assign_op, synkind::OPERATOR)?; z += space(ctx)?; z += _expr(ctx, syn, binding.init)?; if (i + 1 < len(e.bindings)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; return z; }; fn for_expr( ctx: *context, syn: *synfunc, e: *ast::for_expr, ) (size | io::error) = { let z = syn(ctx, "for", synkind::KEYWORD)?; z += space(ctx)?; if (e.label != "") { z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e.label, synkind::LABEL)?; z += space(ctx)?; }; z += syn(ctx, "(", synkind::PUNCTUATION)?; let assign_op = switch (e.kind) { case ast::for_kind::ACCUMULATOR => yield "="; case ast::for_kind::EACH_VALUE => yield ".."; case ast::for_kind::EACH_POINTER => yield "&.."; case ast::for_kind::ITERATOR => yield "=>"; }; match (e.bindings) { case let bind_expr: *ast::expr => z += binding_expr(ctx, syn, &(bind_expr.expr as ast::binding_expr), assign_op)?; if (e.kind == ast::for_kind::ACCUMULATOR) { z += syn(ctx, ";", synkind::PUNCTUATION)?; z += space(ctx)?; }; case null => void; }; if (e.kind == ast::for_kind::ACCUMULATOR) { z += _expr(ctx, syn, e.cond as *ast::expr)?; match (e.afterthought) { case null => void; case let e: *ast::expr => z += syn(ctx, ";", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, e)?; }; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, e.body)?; return z; }; fn switch_expr( ctx: *context, syn: *synfunc, e: *ast::switch_expr, ) (size | io::error) = { let z = syn(ctx, "switch", synkind::KEYWORD)?; z += space(ctx)?; if (e.label != "") { z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e.label, synkind::LABEL)?; z += space(ctx)?; }; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.value)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; z += space(ctx)?; z += syn(ctx, "{", synkind::PUNCTUATION)?; for (let item .. e.cases) { z += newline(ctx)?; z += syn(ctx, "case", synkind::KEYWORD)?; z += space(ctx)?; if (len(item.options) == 0) { z += syn(ctx, "=>", synkind::OPERATOR)?; } else { for (let j = 0z; j < len(item.options); j += 1) { const opt = item.options[j]; z += _expr(ctx, syn, opt)?; if (j + 1 < len(item.options)) { z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; }; z += space(ctx)?; z += syn(ctx, "=>", synkind::OPERATOR)?; }; z += case_exprs(ctx, syn, item.exprs)?; }; z += newline(ctx)?; z += syn(ctx, "}", synkind::PUNCTUATION)?; return z; }; fn match_expr( ctx: *context, syn: *synfunc, e: *ast::match_expr, ) (size | io::error) = { let z = syn(ctx, "match", synkind::KEYWORD)?; z += space(ctx)?; if (e.label != "") { z += syn(ctx, ":", synkind::LABEL)?; z += syn(ctx, e.label, synkind::LABEL)?; z += space(ctx)?; }; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.value)?; z += syn(ctx, ")", synkind::PUNCTUATION)?; z += space(ctx)?; z += syn(ctx, "{", synkind::PUNCTUATION)?; for (let item .. e.cases) { z += newline(ctx)?; z += syn(ctx, "case", synkind::KEYWORD)?; if (len(item.name) > 0) { z += space(ctx)?; z += syn(ctx, "let", synkind::KEYWORD)?; z += space(ctx)?; z += syn(ctx, item.name, synkind::IDENT)?; }; match (item._type) { case let typ: *ast::_type => if (len(item.name) > 0) { z += syn(ctx, ":", synkind::PUNCTUATION)?; }; z += space(ctx)?; z += __type(ctx, syn, typ)?; case null => void; }; z += space(ctx)?; z += syn(ctx, "=>", synkind::OPERATOR)?; z += case_exprs(ctx, syn, item.exprs)?; }; z += newline(ctx)?; z += syn(ctx, "}", synkind::PUNCTUATION)?; return z; }; fn case_exprs( ctx: *context, syn: *synfunc, exprs: []*ast::expr, ) (size | io::error) = { let z = 0z; if (len(exprs) == 1) match (exprs[0].expr) { case let e: ast::assert_expr => if (e.cond == null) { // abort() expression z += space(ctx)?; z += assert_expr(ctx, syn, &e)?; z += syn(ctx, ";", synkind::PUNCTUATION)?; return z; }; case let e: ast::value => if (e is void) { z += space(ctx)?; { ctx.stack = &stack { cur = exprs[0], up = ctx.stack, ... }; defer ctx.stack = (ctx.stack as *stack).up; z += syn(ctx, "void", synkind::KEYWORD)?; }; z += syn(ctx, ";", synkind::PUNCTUATION)?; return z; }; case => void; }; ctx.indent += 1; for (let expr .. exprs) { z += newline(ctx)?; z += stmt(ctx, syn, expr)?; }; ctx.indent -= 1; return z; }; fn is_plain(e: *ast::expr) bool = { match (e.expr) { case ast::literal_expr => return true; case ast::access_identifier => return true; case => return false; }; }; fn is_postfix(e: *ast::expr) bool = { if (is_plain(e)) { return true; }; match (e.expr) { case ast::call_expr => return true; case ast::access_expr => return true; case ast::slice_expr => return true; case ast::error_assert_expr => return true; case ast::propagate_expr => return true; case => return false; }; }; fn is_builtin(e: *ast::expr) bool = { if (is_postfix(e)) { return true; }; match (e.expr) { case ast::alloc_expr => return true; case ast::assert_expr => return true; case ast::variadic_expr => return true; // measurement-expression case ast::len_expr => return true; case ast::align_expr => return true; case ast::size_expr => return true; case ast::offset_expr => return true; // slice-mutation-expression case ast::append_expr => return true; case ast::insert_expr => return true; case => return false; }; }; fn is_unary(e: *ast::expr) bool = { if (is_builtin(e)) { return true; }; match (e.expr) { case ast::compound_expr => return true; case ast::match_expr => return true; case ast::switch_expr => return true; case ast::unarithm_expr => return true; case => return false; }; }; fn is_cast(e: *ast::expr) bool = { return is_unary(e) || (e.expr is ast::cast_expr); }; fn assert_expr( ctx: *context, syn: *synfunc, e: *ast::assert_expr, ) (size | io::error) = { let z = 0z; if (e.is_static) { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; // assert without a condition = abort match (e.cond) { case let e: *ast::expr => z += syn(ctx, "assert", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e)?; case null => z += syn(ctx, "abort", synkind::KEYWORD)?; z += syn(ctx, "(", synkind::PUNCTUATION)?; }; match (e.message) { case let m: *ast::expr => match (e.cond) { case null => void; case *ast::expr => z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; }; z += _expr(ctx, syn, m)?; case null => void; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; }; fn append_insert_expr( ctx: *context, syn: *synfunc, e: *ast::expr, ) (size | io::error) = { let z = 0z; const e: *ast::append_expr = match (e.expr) { case let e: ast::append_expr => if (e.is_static) { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; z += syn(ctx, "append", synkind::KEYWORD)?; yield &e; case let e: ast::insert_expr => if (e.is_static) { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; z += syn(ctx, "insert", synkind::KEYWORD)?; yield &e; case => abort(); // unreachable }; z += syn(ctx, "(", synkind::PUNCTUATION)?; z += _expr(ctx, syn, e.object)?; z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, e.value)?; if (e.variadic) { z += syn(ctx, "...", synkind::OPERATOR)?; }; match (e.length) { case null => void; case let l: *ast::expr => z += syn(ctx, ",", synkind::PUNCTUATION)?; z += space(ctx)?; z += _expr(ctx, syn, l)?; }; z += syn(ctx, ")", synkind::PUNCTUATION)?; return z; }; hare-0.24.2/hare/unparse/ident.ha000066400000000000000000000017141464473310100165350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use io; use memio; // Unparses an identifier. export fn ident(out: io::handle, id: ast::ident) (size | io::error) = { let ctx = context { out = out, ... }; return _ident(&ctx, &syn_nowrap, id, synkind::IDENT); }; fn _ident( ctx: *context, syn: *synfunc, id: ast::ident, kind: synkind, ) (size | io::error) = { let n = 0z; for (let i = 0z; i < len(id); i += 1) { n += syn(ctx, id[i], kind)?; if (i + 1 < len(id)) { n += syn(ctx, "::", kind)?; }; }; return n; }; // Unparses an identifier into a string. The caller must free the return value. export fn identstr(id: ast::ident) str = { let buf = memio::dynamic(); ident(&buf, id)!; return memio::string(&buf)!; }; @test fn ident() void = { let s = identstr(["foo", "bar", "baz"]); defer free(s); assert(s == "foo::bar::baz"); let s = identstr(["foo"]); defer free(s); assert(s == "foo"); }; hare-0.24.2/hare/unparse/import.ha000066400000000000000000000040751464473310100167470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hare::ast; use io; use memio; // Unparses a [[hare::ast::import]]. export fn import( out: io::handle, syn: *synfunc, import: *ast::import, ) (size | io::error) = { let n = 0z; let ctx = context { out = out, stack = &stack { cur = import, ... }, ... }; n += syn(&ctx, "use", synkind::KEYWORD)?; n += space(&ctx)?; match (import.bindings) { case void => n += _ident(&ctx, syn, import.ident, synkind::IDENT)?; case let alias: ast::import_alias => n += syn(&ctx, alias, synkind::IMPORT_ALIAS)?; n += space(&ctx)?; n += syn(&ctx, "=", synkind::OPERATOR)?; n += space(&ctx)?; n += _ident(&ctx, syn, import.ident, synkind::IDENT)?; case let objects: ast::import_members => n += _ident(&ctx, syn, import.ident, synkind::IDENT)?; n += syn(&ctx, "::", synkind::IDENT)?; n += syn(&ctx, "{", synkind::PUNCTUATION)?; for (let i = 0z; i < len(objects); i += 1) { n += syn(&ctx, objects[i], synkind::SECONDARY)?; if (i + 1 < len(objects)) { n += syn(&ctx, ",", synkind::PUNCTUATION)?; n += space(&ctx)?; }; }; n += syn(&ctx, "}", synkind::PUNCTUATION)?; case ast::import_wildcard => n += _ident(&ctx, syn, import.ident, synkind::IDENT)?; n += syn(&ctx, "::", synkind::IDENT)?; n += syn(&ctx, "*", synkind::PUNCTUATION)?; }; n += syn(&ctx, ";", synkind::PUNCTUATION)?; return n; }; @test fn import() void = { let tests: [_](ast::import, str) = [ (ast::import { ident = ["foo", "bar", "baz"], bindings = void, ... }, "use foo::bar::baz;"), (ast::import { ident = ["foo"], bindings = "bar", ... }, "use bar = foo;"), (ast::import { ident = ["foo"], bindings = ["bar", "baz"], ... }, "use foo::{bar, baz};"), (ast::import { ident = ["foo", "bar"], bindings = ast::import_wildcard, ... }, "use foo::bar::*;"), ]; for (let (ast_import, str_import) .. tests) { let buf = memio::dynamic(); import(&buf, &syn_nowrap, &ast_import)!; let s = memio::string(&buf)!; assert(s == str_import); free(s); }; }; hare-0.24.2/hare/unparse/syn.ha000066400000000000000000000123521464473310100162430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use io; // A user-supplied function which writes unparsed Hare source code to a handle, // optionally including extra stylistic features. The function is expected to // write to, at the minimum, write the provided string to ctx.out, and update // ctx.linelen based on how much data was written. // // [[syn_nowrap]] and [[syn_wrap]] are provided for when no additional styling // is desired. export type synfunc = fn( ctx: *context, s: str, kind: synkind, ) (size | io::error); // The kind of thing being unparsed. export type synkind = enum { IDENT, COMMENT, CONSTANT, FUNCTION, GLOBAL, TYPEDEF, IMPORT_ALIAS, SECONDARY, KEYWORD, TYPE, ATTRIBUTE, OPERATOR, PUNCTUATION, RUNE_STRING, NUMBER, LABEL, }; // Context about the unparsing state supplied to a [[synfunc]]. The linelen and // indent fields may be mutated. export type context = struct { out: io::handle, stack: nullable *stack, linelen: size, indent: size, }; // A linked list of AST nodes currently being unparsed. export type stack = struct { cur: (*ast::decl | *ast::expr | *ast::_type | *ast::import), up: nullable *stack, extra: nullable *opaque, }; // A [[synfunc]] implementation which unparses without additional styling, and // without wrapping any long lines. export fn syn_nowrap( ctx: *context, s: str, kind: synkind, ) (size | io::error) = { const z = fmt::fprint(ctx.out, s)?; ctx.linelen += z; return z; }; type syn_wrap_extra = enum { NONE, MULTILINE_FN_PARAM, MULTILINE_FN_OTHER, MULTILINE_TAGGED_OR_TUPLE, }; // A [[synfunc]] implementation which unparses without additional styling, but // which wraps some long lines at 80 columns, in accordance with the style // guide. export fn syn_wrap(ctx: *context, s: str, kind: synkind) (size | io::error) = { let extra = :extra { let st = match (ctx.stack) { case let st: *stack => yield st; case null => yield :extra, &syn_wrap_extra::NONE; }; match (st.extra) { case let p: *opaque => yield :extra, p: *syn_wrap_extra; case null => match (st.up) { case let st: *stack => match (st.extra) { case let p: *opaque => const p = p: *syn_wrap_extra; if (*p == syn_wrap_extra::MULTILINE_FN_PARAM) { yield :extra, p; }; case null => void; }; case null => void; }; }; if (s == "(") match (st.cur) { case let t: *ast::_type => match (t.repr) { case ast::func_type => void; case => yield :extra, &syn_wrap_extra::NONE; }; let z = _type(io::empty, &syn_nowrap, t)!; if (ctx.linelen + z < 80) yield; st.extra = alloc(syn_wrap_extra::MULTILINE_FN_PARAM); z = fmt::fprintln(ctx.out, s)?; ctx.linelen = 0; ctx.indent += 1; return z; case => yield :extra, &syn_wrap_extra::NONE; }; // use 72 as max linelen instead of 80 to give a bit of leeway. // XXX: this probably could be made more accurate if (ctx.linelen < 72 || (s != "," && s != "|")) { yield :extra, &syn_wrap_extra::NONE; }; const t = match (st.cur) { case let t: *ast::_type => yield t; case => yield :extra, &syn_wrap_extra::NONE; }; match (t.repr) { case (ast::tagged_type | ast::tuple_type) => void; case => yield :extra, &syn_wrap_extra::NONE; }; st.extra = alloc(syn_wrap_extra::MULTILINE_TAGGED_OR_TUPLE); let z = fmt::fprintln(ctx.out, s)?; ctx.indent += 1; ctx.linelen = ctx.indent * 8; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; }; return z; }; let z = 0z; switch (*extra) { case syn_wrap_extra::NONE => void; case syn_wrap_extra::MULTILINE_FN_PARAM => switch (s) { case ")" => match (ctx.stack) { case let st: *stack => free(st.extra); st.extra = null; case null => void; }; ctx.indent -= 1; case "..." => match (ctx.stack) { case let st: *stack => free(st.extra); st.extra = null; case null => void; }; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; }; z += fmt::fprintln(ctx.out, s)?; ctx.indent -= 1; ctx.linelen = 0; return z; case => *extra = syn_wrap_extra::MULTILINE_FN_OTHER; ctx.linelen = ctx.indent * 8; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; }; }; case syn_wrap_extra::MULTILINE_FN_OTHER => switch (s) { case ")" => match (ctx.stack) { case let st: *stack => free(st.extra); st.extra = null; case null => void; }; ctx.indent -= 1; ctx.linelen = ctx.indent * 8; z += fmt::fprintln(ctx.out, ",")?; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; }; case ",", "..." => *extra = syn_wrap_extra::MULTILINE_FN_PARAM; ctx.linelen = 0; return fmt::fprintln(ctx.out, s)?; case => void; }; case syn_wrap_extra::MULTILINE_TAGGED_OR_TUPLE => switch (s) { case ")" => let st = ctx.stack as *stack; free(st.extra); st.extra = null; ctx.indent -= 1; case ",", "|" => if (ctx.linelen < 72) yield; z += fmt::fprintln(ctx.out, s)?; ctx.linelen = ctx.indent * 8; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; }; return z; case => void; }; }; z += syn_nowrap(ctx, s, kind)?; return z; }; hare-0.24.2/hare/unparse/type.ha000066400000000000000000000255071464473310100164210ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use hare::ast::{variadism}; use hare::lex; use io; use memio; use strings; // Returns a builtin type as a string. export fn builtin_type(b: ast::builtin_type) str = switch (b) { case ast::builtin_type::FCONST, ast::builtin_type::ICONST, ast::builtin_type::RCONST => abort("ICONST, FCONST, and RCONST have no lexical representation"); case ast::builtin_type::BOOL => yield "bool"; case ast::builtin_type::DONE => yield "done"; case ast::builtin_type::F32 => yield "f32"; case ast::builtin_type::F64 => yield "f64"; case ast::builtin_type::I16 => yield "i16"; case ast::builtin_type::I32 => yield "i32"; case ast::builtin_type::I64 => yield "i64"; case ast::builtin_type::I8 => yield "i8"; case ast::builtin_type::INT => yield "int"; case ast::builtin_type::NEVER => yield "never"; case ast::builtin_type::NULL => yield "null"; case ast::builtin_type::OPAQUE => yield "opaque"; case ast::builtin_type::RUNE => yield "rune"; case ast::builtin_type::SIZE => yield "size"; case ast::builtin_type::STR => yield "str"; case ast::builtin_type::U16 => yield "u16"; case ast::builtin_type::U32 => yield "u32"; case ast::builtin_type::U64 => yield "u64"; case ast::builtin_type::U8 => yield "u8"; case ast::builtin_type::UINT => yield "uint"; case ast::builtin_type::UINTPTR => yield "uintptr"; case ast::builtin_type::VALIST => yield "valist"; case ast::builtin_type::VOID => yield "void"; }; fn prototype( ctx: *context, syn: *synfunc, t: *ast::func_type, ) (size | io::error) = { let n = 0z; n += syn(ctx, "(", synkind::PUNCTUATION)?; for (let i = 0z; i < len(t.params); i += 1) { const param = &t.params[i]; if (param.name != "") { n += syn(ctx, param.name, synkind::SECONDARY)?; n += syn(ctx, ":", synkind::PUNCTUATION)?; n += space(ctx)?; }; n += __type(ctx, syn, param._type)?; match (param.default_value) { case void => yield; case let e: ast::expr => n += space(ctx)?; n += syn(ctx, "=", synkind::PUNCTUATION)?; n += space(ctx)?; n += _expr(ctx, syn, &e)?; }; if (i + 1 < len(t.params) || t.variadism == variadism::C) { n += syn(ctx, ",", synkind::PUNCTUATION)?; n += space(ctx)?; }; }; if (t.variadism != variadism::NONE) { n += syn(ctx, "...", synkind::OPERATOR)?; }; n += syn(ctx, ")", synkind::PUNCTUATION)?; n += space(ctx)?; n += __type(ctx, syn, t.result)?; return n; }; fn struct_union_type( ctx: *context, syn: *synfunc, t: *ast::_type, ) (size | io::error) = { let z = 0z; let membs = match (t.repr) { case let st: ast::struct_type => z += syn(ctx, "struct", synkind::TYPE)?; z += space(ctx)?; if (st.packed) { z += syn(ctx, "@packed", synkind::ATTRIBUTE)?; z += space(ctx)?; }; z += syn(ctx, "{", synkind::PUNCTUATION)?; yield st.members: []ast::struct_member; case let ut: ast::union_type => z += syn(ctx, "union", synkind::TYPE)?; z += space(ctx)?; z += syn(ctx, "{", synkind::PUNCTUATION)?; yield ut: []ast::struct_member; case => abort(); // unreachable }; ctx.indent += 1z; for (let memb .. membs) { z += fmt::fprintln(ctx.out)?; ctx.linelen = 0; if (memb.docs != "") { z += comment(ctx, syn, memb.docs)?; }; for (let i = 0z; i < ctx.indent; i += 1) { z += fmt::fprint(ctx.out, "\t")?; ctx.linelen += 8; }; match (memb._offset) { case null => void; case let ex: *ast::expr => z += syn(ctx, "@offset(", synkind::ATTRIBUTE)?; z += _expr(ctx, syn, ex)?; z += syn(ctx, ")", synkind::ATTRIBUTE)?; z += space(ctx)?; }; match (memb.member) { case let se: ast::struct_embedded => z += __type(ctx, syn, se)?; case let sa: ast::struct_alias => z += _ident(ctx, syn, sa, synkind::IDENT)?; case let sf: ast::struct_field => z += syn(ctx, sf.name, synkind::SECONDARY)?; z += syn(ctx, ":", synkind::PUNCTUATION)?; z += space(ctx)?; z += __type(ctx, syn, sf._type)?; }; z += syn(ctx, ",", synkind::PUNCTUATION)?; }; ctx.indent -= 1; z += newline(ctx)?; z += syn(ctx, "}", synkind::PUNCTUATION)?; return z; }; fn multiline_comment(s: str) bool = strings::byteindex(s, '\n') as size != len(s) - 1; // Unparses a [[hare::ast::_type]]. export fn _type( out: io::handle, syn: *synfunc, t: *ast::_type, ) (size | io::error) = { let ctx = context { out = out, ... }; return __type(&ctx, syn, t); }; fn __type(ctx: *context, syn: *synfunc, t: *ast::_type) (size | io::error) = { ctx.stack = &stack { cur = t, up = ctx.stack, ... }; defer { let stack = &(ctx.stack as *stack); match (stack.extra) { case let p: *opaque => free(p); case null => void; }; ctx.stack = stack.up; }; let n = 0z; if (t.flags & ast::type_flag::CONST != 0) { n += syn(ctx, "const", synkind::TYPE)?; n += space(ctx)?; }; if (t.flags & ast::type_flag::ERROR != 0) { n += syn(ctx, "!", synkind::TYPE)?; }; match (t.repr) { case let a: ast::alias_type => if (a.unwrap) { n += syn(ctx, "...", synkind::TYPE)?; }; n += _ident(ctx, syn, a.ident, synkind::TYPE)?; case let b: ast::builtin_type => n += syn(ctx, builtin_type(b), synkind::TYPE)?; case let e: ast::enum_type => n += syn(ctx, "enum", synkind::TYPE)?; n += space(ctx)?; if (e.storage != ast::builtin_type::INT) { n += syn(ctx, builtin_type(e.storage), synkind::TYPE)?; n += space(ctx)?; }; n += syn(ctx, "{", synkind::PUNCTUATION)?; ctx.indent += 1; n += fmt::fprintln(ctx.out)?; ctx.linelen = 0; for (let value .. e.values) { let wrotedocs = false; if (value.docs != "") { // Check if comment should go above or next to // field if (multiline_comment(value.docs)) { n += comment(ctx, syn, value.docs)?; wrotedocs = true; }; }; for (let i = 0z; i < ctx.indent; i += 1) { n += fmt::fprint(ctx.out, "\t")?; ctx.linelen += 8; }; n += syn(ctx, value.name, synkind::SECONDARY)?; match (value.value) { case null => void; case let e: *ast::expr => n += space(ctx)?; n += syn(ctx, "=", synkind::OPERATOR)?; n += space(ctx)?; n += _expr(ctx, syn, e)?; }; n += syn(ctx, ",", synkind::PUNCTUATION)?; if (value.docs != "" && !wrotedocs) { n += space(ctx)?; const oldindent = ctx.indent; ctx.indent = 0; n += comment(ctx, syn, value.docs)?; ctx.indent = oldindent; } else { n += fmt::fprintln(ctx.out)?; ctx.linelen = 0; }; }; ctx.indent -= 1; for (let i = 0z; i < ctx.indent; i += 1) { n += fmt::fprint(ctx.out, "\t")?; ctx.linelen += 8; }; n += syn(ctx, "}", synkind::PUNCTUATION)?; case let f: ast::func_type => n += syn(ctx, "fn", synkind::TYPE)?; n += prototype(ctx, syn, &f)?; case let l: ast::list_type => n += syn(ctx, "[", synkind::TYPE)?; match (l.length) { case ast::len_slice => void; case ast::len_unbounded => n += syn(ctx, "*", synkind::TYPE)?; case ast::len_contextual => n += syn(ctx, "_", synkind::TYPE)?; case let e: *ast::expr => n += _expr(ctx, syn, e)?; }; n += syn(ctx, "]", synkind::TYPE)?; n += __type(ctx, syn, l.members)?; case let p: ast::pointer_type => if (p.flags & ast::pointer_flag::NULLABLE != 0) { n += syn(ctx, "nullable", synkind::TYPE)?; n += space(ctx)?; }; n += syn(ctx, "*", synkind::TYPE)?; n += __type(ctx, syn, p.referent)?; case ast::struct_type => n += struct_union_type(ctx, syn, t)?; case ast::union_type => n += struct_union_type(ctx, syn, t)?; case let t: ast::tagged_type => n += syn(ctx, "(", synkind::TYPE)?; for (let i = 0z; i < len(t); i += 1) { n += __type(ctx, syn, t[i])?; if (i + 1 == len(t)) break; n += space(ctx)?; n += syn(ctx, "|", synkind::TYPE)?; n += space(ctx)?; }; n += syn(ctx, ")", synkind::TYPE)?; case let t: ast::tuple_type => n += syn(ctx, "(", synkind::TYPE)?; for (let i = 0z; i < len(t); i += 1) { n += __type(ctx, syn, t[i])?; if (i + 1 == len(t)) break; n += syn(ctx, ",", synkind::TYPE)?; n += space(ctx)?; }; n += syn(ctx, ")", synkind::TYPE)?; }; return n; }; fn type_test(t: *ast::_type, expected: str) void = { let buf = memio::dynamic(); _type(&buf, &syn_nowrap, t)!; let s = memio::string(&buf)!; defer free(s); if (s != expected) { fmt::errorfln("=== wanted\n{}", expected)!; fmt::errorfln("=== got\n{}", s)!; abort(); }; }; @test fn _type() void = { let loc = lex::location { path = "", line = 0, col = 0, }; let t = ast::_type { start = loc, end = loc, flags = ast::type_flag::CONST, repr = ast::alias_type { unwrap = false, ident = ["foo", "bar"], }, }; let type_int = ast::_type { start = loc, end = loc, flags = 0, repr = ast::builtin_type::INT, }; let expr_void = ast::expr { start = lex::location { ... }, end = lex::location { ... }, expr = void, }; type_test(&t, "const foo::bar"); t.flags = 0; t.repr = ast::alias_type { unwrap = true, ident = ["baz"], }; type_test(&t, "...baz"); t.flags = ast::type_flag::ERROR; t.repr = ast::builtin_type::INT; type_test(&t, "!int"); t.flags = ast::type_flag::CONST | ast::type_flag::ERROR; t.repr = ast::enum_type { storage = ast::builtin_type::U32, values = [ ast::enum_field { name = "FOO", value = null, loc = loc, docs = "", }, ast::enum_field { name = "BAR", value = &expr_void, loc = loc, docs = "", }, ], }; type_test(&t, "const !enum u32 {\n\tFOO,\n\tBAR = void,\n}"); t.flags = 0; t.repr = ast::func_type { result = &type_int, variadism = variadism::NONE, params = [], }; type_test(&t, "fn() int"); t.repr = ast::func_type { result = &type_int, variadism = variadism::C, params = [ ast::func_param { loc = loc, name = "", _type = &type_int, default_value = void, }, ], }; type_test(&t, "fn(int, ...) int"); t.repr = ast::func_type { result = &type_int, variadism = variadism::HARE, params = [ ast::func_param { loc = loc, name = "foo", _type = &type_int, default_value = void, }, ast::func_param { loc = loc, name = "bar", _type = &type_int, default_value = void, }, ], }; type_test(&t, "fn(foo: int, bar: int...) int"); t.repr = ast::list_type { length = ast::len_slice, members = &type_int, }; type_test(&t, "[]int"); t.repr = ast::list_type { length = ast::len_unbounded, members = &type_int, }; type_test(&t, "[*]int"); t.repr = ast::list_type { length = ast::len_contextual, members = &type_int, }; type_test(&t, "[_]int"); t.repr = ast::list_type { length = &expr_void, members = &type_int, }; type_test(&t, "[void]int"); t.repr = ast::pointer_type { referent = &type_int, flags = 0, }; type_test(&t, "*int"); t.repr = ast::pointer_type { referent = &type_int, flags = ast::pointer_flag::NULLABLE, }; type_test(&t, "nullable *int"); t.repr = [&type_int, &type_int]: ast::tagged_type; type_test(&t, "(int | int)"); t.repr = [&type_int, &type_int]: ast::tuple_type; type_test(&t, "(int, int)"); }; hare-0.24.2/hare/unparse/unit.ha000066400000000000000000000011241464473310100164040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use hare::ast; use io; // Unparses a [[hare::ast::subunit]]. export fn subunit( out: io::handle, syn: *synfunc, s: ast::subunit, ) (size | io::error) = { let n = 0z; for (let imp &.. s.imports) { n += import(out, syn, imp)?; n += fmt::fprintln(out)?; }; if (len(s.imports) > 0) { n += fmt::fprintln(out)?; }; for (let i = 0z; i < len(s.decls); i += 1) { n += decl(out, syn, &s.decls[i])?; if (i < len(s.decls) - 1) n += fmt::fprintln(out)?; n += fmt::fprintln(out)?; }; return n; }; hare-0.24.2/hare/unparse/util.ha000066400000000000000000000007531464473310100164110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use io; fn newline(ctx: *context) (size | io::error) = { let n = 0z; n += fmt::fprint(ctx.out, "\n")?; ctx.linelen = 0; for (let i = 0z; i < ctx.indent; i += 1) { n += fmt::fprint(ctx.out, "\t")?; ctx.linelen += 8; }; return n; }; fn space(ctx: *context) (size | io::error) = { if (ctx.linelen <= ctx.indent * 8) { return 0z; }; ctx.linelen += 1; return fmt::fprint(ctx.out, " "); }; hare-0.24.2/hash/000077500000000000000000000000001464473310100134445ustar00rootroot00000000000000hare-0.24.2/hash/README000066400000000000000000000001021464473310100143150ustar00rootroot00000000000000hash provides a generic interface for use with hashing functions. hare-0.24.2/hash/adler32/000077500000000000000000000000001464473310100147005ustar00rootroot00000000000000hare-0.24.2/hash/adler32/README000066400000000000000000000001201464473310100155510ustar00rootroot00000000000000Implements the Adler-32 checksum algorithm. It is a non-cryptographic checksum. hare-0.24.2/hash/adler32/adler32.ha000066400000000000000000000041411464473310100164460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use io; use strings; // The size, in bytes, of an Adler-32 checksum. export def SZ: size = 4; export type state = struct { hash::hash, a: u32, b: u32, }; const adler32_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[hash::hash]] which computes the Adler-32 checksum algorithm. This // hash does not allocate any state, so you do not need to call [[hash::close]] // when you are done with it. export fn adler32() state = state { stream = &adler32_vtable, sum = &sum, reset = &reset, sz = 4, a = 1, b = 0, ... }; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state; for (let i = 0z; i < len(buf); i += 1) { s.a = (s.a + buf[i]) % 65521; s.b = (s.b + s.a) % 65521; }; return len(buf); }; fn reset(h: *hash::hash) void = { let h = h: *state; h.a = 1; h.b = 0; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; // RFC 1950 specifies that Adler-32 checksums are stored in network // order. endian::beputu32(buf, (h.b << 16) | h.a); }; export fn sum32(h: *hash::hash) u32 = { assert(h.reset == &reset); let h = h: *state; return h.b << 16 | h.a; }; @test fn adler32() void = { const vectors: [](str, u32) = [ ("", 1), ("hello world", 436929629), ("Hare is a cool language", 1578567727), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", 2140876731), ("'Life is too short to run proprietary software' - Bdale Garbee", 3135706652), ("'The central enemy of reliability is complexity.' - Geer et al", 3170309588), ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", 1148528899), ]; let hash = adler32(); let s: [4]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(&hash); hash::write(&hash, strings::toutf8(vec.0)); hash::sum(&hash, s); assert(endian::begetu32(s) == vec.1); assert(sum32(&hash) == vec.1); }; }; hare-0.24.2/hash/crc16/000077500000000000000000000000001464473310100143625ustar00rootroot00000000000000hare-0.24.2/hash/crc16/README000066400000000000000000000001161464473310100152400ustar00rootroot00000000000000Implements the CRC-16 checksum algorithm. It is a non-cryptographic checksum. hare-0.24.2/hash/crc16/crc16.ha000066400000000000000000000310431464473310100156130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use io; use strings; // The size, in bytes, of a CRC-16 checksum. export def SZ: size = 2; // CRC-CCITT polynomial for CRC-16. The most commonly used polynomial, used in // Bluetooth, X.25, XMODEM, and many other places. Also known as CRC-X25. export def CCITT: u16 = 0x8408; // CMDA200 polynomial for CRC-16. Used in the infrastructure of mobile networks. export def CMDA2000: u16 = 0xE613; // DECT polynomial for CRC-16. Typically used in cordless phones. export def DECT: u16 = 0x91A0; // ANSI polynomial for CRC-16. Another widely used polynomial, it's seen in USB // devices, Modbus, ANSI X3.28, and many others places. Also known as CRC-IBM. export def ANSI: u16 = 0xA001; // Table of memoized values for each byte with the CCITT polynomial. export const ccitt_table: [256]u16 = [ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78, ]; // Table of memoized values for each byte with the CMDA2000 polynomial. export const cmda2000_table: [256]u16 = [ 0x0000, 0x5A7A, 0xB4F4, 0xEE8E, 0xA5CF, 0xFFB5, 0x113B, 0x4B41, 0x87B9, 0xDDC3, 0x334D, 0x6937, 0x2276, 0x780C, 0x9682, 0xCCF8, 0xC355, 0x992F, 0x77A1, 0x2DDB, 0x669A, 0x3CE0, 0xD26E, 0x8814, 0x44EC, 0x1E96, 0xF018, 0xAA62, 0xE123, 0xBB59, 0x55D7, 0x0FAD, 0x4A8D, 0x10F7, 0xFE79, 0xA403, 0xEF42, 0xB538, 0x5BB6, 0x01CC, 0xCD34, 0x974E, 0x79C0, 0x23BA, 0x68FB, 0x3281, 0xDC0F, 0x8675, 0x89D8, 0xD3A2, 0x3D2C, 0x6756, 0x2C17, 0x766D, 0x98E3, 0xC299, 0x0E61, 0x541B, 0xBA95, 0xE0EF, 0xABAE, 0xF1D4, 0x1F5A, 0x4520, 0x951A, 0xCF60, 0x21EE, 0x7B94, 0x30D5, 0x6AAF, 0x8421, 0xDE5B, 0x12A3, 0x48D9, 0xA657, 0xFC2D, 0xB76C, 0xED16, 0x0398, 0x59E2, 0x564F, 0x0C35, 0xE2BB, 0xB8C1, 0xF380, 0xA9FA, 0x4774, 0x1D0E, 0xD1F6, 0x8B8C, 0x6502, 0x3F78, 0x7439, 0x2E43, 0xC0CD, 0x9AB7, 0xDF97, 0x85ED, 0x6B63, 0x3119, 0x7A58, 0x2022, 0xCEAC, 0x94D6, 0x582E, 0x0254, 0xECDA, 0xB6A0, 0xFDE1, 0xA79B, 0x4915, 0x136F, 0x1CC2, 0x46B8, 0xA836, 0xF24C, 0xB90D, 0xE377, 0x0DF9, 0x5783, 0x9B7B, 0xC101, 0x2F8F, 0x75F5, 0x3EB4, 0x64CE, 0x8A40, 0xD03A, 0xE613, 0xBC69, 0x52E7, 0x089D, 0x43DC, 0x19A6, 0xF728, 0xAD52, 0x61AA, 0x3BD0, 0xD55E, 0x8F24, 0xC465, 0x9E1F, 0x7091, 0x2AEB, 0x2546, 0x7F3C, 0x91B2, 0xCBC8, 0x8089, 0xDAF3, 0x347D, 0x6E07, 0xA2FF, 0xF885, 0x160B, 0x4C71, 0x0730, 0x5D4A, 0xB3C4, 0xE9BE, 0xAC9E, 0xF6E4, 0x186A, 0x4210, 0x0951, 0x532B, 0xBDA5, 0xE7DF, 0x2B27, 0x715D, 0x9FD3, 0xC5A9, 0x8EE8, 0xD492, 0x3A1C, 0x6066, 0x6FCB, 0x35B1, 0xDB3F, 0x8145, 0xCA04, 0x907E, 0x7EF0, 0x248A, 0xE872, 0xB208, 0x5C86, 0x06FC, 0x4DBD, 0x17C7, 0xF949, 0xA333, 0x7309, 0x2973, 0xC7FD, 0x9D87, 0xD6C6, 0x8CBC, 0x6232, 0x3848, 0xF4B0, 0xAECA, 0x4044, 0x1A3E, 0x517F, 0x0B05, 0xE58B, 0xBFF1, 0xB05C, 0xEA26, 0x04A8, 0x5ED2, 0x1593, 0x4FE9, 0xA167, 0xFB1D, 0x37E5, 0x6D9F, 0x8311, 0xD96B, 0x922A, 0xC850, 0x26DE, 0x7CA4, 0x3984, 0x63FE, 0x8D70, 0xD70A, 0x9C4B, 0xC631, 0x28BF, 0x72C5, 0xBE3D, 0xE447, 0x0AC9, 0x50B3, 0x1BF2, 0x4188, 0xAF06, 0xF57C, 0xFAD1, 0xA0AB, 0x4E25, 0x145F, 0x5F1E, 0x0564, 0xEBEA, 0xB190, 0x7D68, 0x2712, 0xC99C, 0x93E6, 0xD8A7, 0x82DD, 0x6C53, 0x3629, ]; // Table of memoized values for each byte with the DECT polynomial. export const dect_table: [256]u16 = [ 0x0000, 0x49F3, 0x93E6, 0xDA15, 0x048D, 0x4D7E, 0x976B, 0xDE98, 0x091A, 0x40E9, 0x9AFC, 0xD30F, 0x0D97, 0x4464, 0x9E71, 0xD782, 0x1234, 0x5BC7, 0x81D2, 0xC821, 0x16B9, 0x5F4A, 0x855F, 0xCCAC, 0x1B2E, 0x52DD, 0x88C8, 0xC13B, 0x1FA3, 0x5650, 0x8C45, 0xC5B6, 0x2468, 0x6D9B, 0xB78E, 0xFE7D, 0x20E5, 0x6916, 0xB303, 0xFAF0, 0x2D72, 0x6481, 0xBE94, 0xF767, 0x29FF, 0x600C, 0xBA19, 0xF3EA, 0x365C, 0x7FAF, 0xA5BA, 0xEC49, 0x32D1, 0x7B22, 0xA137, 0xE8C4, 0x3F46, 0x76B5, 0xACA0, 0xE553, 0x3BCB, 0x7238, 0xA82D, 0xE1DE, 0x48D0, 0x0123, 0xDB36, 0x92C5, 0x4C5D, 0x05AE, 0xDFBB, 0x9648, 0x41CA, 0x0839, 0xD22C, 0x9BDF, 0x4547, 0x0CB4, 0xD6A1, 0x9F52, 0x5AE4, 0x1317, 0xC902, 0x80F1, 0x5E69, 0x179A, 0xCD8F, 0x847C, 0x53FE, 0x1A0D, 0xC018, 0x89EB, 0x5773, 0x1E80, 0xC495, 0x8D66, 0x6CB8, 0x254B, 0xFF5E, 0xB6AD, 0x6835, 0x21C6, 0xFBD3, 0xB220, 0x65A2, 0x2C51, 0xF644, 0xBFB7, 0x612F, 0x28DC, 0xF2C9, 0xBB3A, 0x7E8C, 0x377F, 0xED6A, 0xA499, 0x7A01, 0x33F2, 0xE9E7, 0xA014, 0x7796, 0x3E65, 0xE470, 0xAD83, 0x731B, 0x3AE8, 0xE0FD, 0xA90E, 0x91A0, 0xD853, 0x0246, 0x4BB5, 0x952D, 0xDCDE, 0x06CB, 0x4F38, 0x98BA, 0xD149, 0x0B5C, 0x42AF, 0x9C37, 0xD5C4, 0x0FD1, 0x4622, 0x8394, 0xCA67, 0x1072, 0x5981, 0x8719, 0xCEEA, 0x14FF, 0x5D0C, 0x8A8E, 0xC37D, 0x1968, 0x509B, 0x8E03, 0xC7F0, 0x1DE5, 0x5416, 0xB5C8, 0xFC3B, 0x262E, 0x6FDD, 0xB145, 0xF8B6, 0x22A3, 0x6B50, 0xBCD2, 0xF521, 0x2F34, 0x66C7, 0xB85F, 0xF1AC, 0x2BB9, 0x624A, 0xA7FC, 0xEE0F, 0x341A, 0x7DE9, 0xA371, 0xEA82, 0x3097, 0x7964, 0xAEE6, 0xE715, 0x3D00, 0x74F3, 0xAA6B, 0xE398, 0x398D, 0x707E, 0xD970, 0x9083, 0x4A96, 0x0365, 0xDDFD, 0x940E, 0x4E1B, 0x07E8, 0xD06A, 0x9999, 0x438C, 0x0A7F, 0xD4E7, 0x9D14, 0x4701, 0x0EF2, 0xCB44, 0x82B7, 0x58A2, 0x1151, 0xCFC9, 0x863A, 0x5C2F, 0x15DC, 0xC25E, 0x8BAD, 0x51B8, 0x184B, 0xC6D3, 0x8F20, 0x5535, 0x1CC6, 0xFD18, 0xB4EB, 0x6EFE, 0x270D, 0xF995, 0xB066, 0x6A73, 0x2380, 0xF402, 0xBDF1, 0x67E4, 0x2E17, 0xF08F, 0xB97C, 0x6369, 0x2A9A, 0xEF2C, 0xA6DF, 0x7CCA, 0x3539, 0xEBA1, 0xA252, 0x7847, 0x31B4, 0xE636, 0xAFC5, 0x75D0, 0x3C23, 0xE2BB, 0xAB48, 0x715D, 0x38AE, ]; // Table of memoized values for each byte with the ANSI polynomial. export const ansi_table: [256]u16 = [ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, ]; // Populate a user-provided buffer with the memoized values for a custom // polynomial. // // The user-provided polynomial must be in the reversed form. export fn memoize(polynomial: u16, buf: *[256]u16) void = { for (let i = 0z; i < 256; i += 1) { let value = i: u16; for (let z = 0z; z < 8; z += 1) { value = if (value & 0x1 == 1) { yield (value >> 1) ^ polynomial; } else { yield value >> 1; }; }; buf[i] = value; }; }; export type state = struct { hash::hash, table: *[256]u16, cval: u16, }; const crc16_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[hash::hash]] which computes the CRC-16 algorithm. This hash // function does not allocate any state, so you do not need to call // [[hash::close]] when you are done with it. // // It takes a table of memoized values for a given polynomail (for example, // [[ccitt_table]], [[dect_table]], or [[ansi_table]]); a table for a // custom polynomial, populated by [[memoize]] function, may also be used. export fn crc16(table: *[256]u16) state = state { stream = &crc16_vtable, sum = &sum, reset = &reset, sz = SZ, table = table, cval = ~0u16, ... }; fn close(s: *io::stream) void = void; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state; for (let i = 0z; i < len(buf); i += 1) { let rightbits = s.cval & 0xFF; s.cval = s.table[rightbits ^ buf[i]] ^ (s.cval >> 8); }; return len(buf); }; fn reset(h: *hash::hash) void = { let h = h: *state; h.cval = ~0u16; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; endian::host.putu16(buf, ~h.cval); }; export fn sum16(h: *hash::hash) u16 = { assert(h.reset == &reset); let h = h: *state; return ~h.cval; }; @test fn crc16() void = { const vectors: [](str, u16, u16, u16, u16) = [ ("", 0, 0, 0, 0), ("Always be sincere, even if you don't mean it. -- Harry Truman", 0x38DF, 0x2441, 0x8E44, 0xEF5E), ("You get along very well with everyone except animals and people.", 0xB6AE, 0xFED0, 0x8739, 0xCF56), ("All generalizations are false, including this one. -- Mark Twain", 0xCA68, 0x65EC, 0x98A, 0x45B4), ("I want peace and I'm willing to fight for it. -- Harry Truman", 0xB0E8, 0xFE1F, 0x4659, 0x5062), ]; let crc_ccitt = crc16(&ccitt_table); let crc_cmda2000 = crc16(&cmda2000_table); let crc_dect = crc16(&dect_table); let crc_ansi = crc16(&ansi_table); let buf: [SZ]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(&crc_ccitt); hash::write(&crc_ccitt, strings::toutf8(vec.0)); hash::sum(&crc_ccitt, buf); assert(endian::host.getu16(buf) == vec.1); assert(sum16(&crc_ccitt) == vec.1); hash::reset(&crc_cmda2000); hash::write(&crc_cmda2000, strings::toutf8(vec.0)); hash::sum(&crc_cmda2000, buf); assert(endian::host.getu16(buf) == vec.2); assert(sum16(&crc_cmda2000) == vec.2); hash::reset(&crc_dect); hash::write(&crc_dect, strings::toutf8(vec.0)); hash::sum(&crc_dect, buf); assert(endian::host.getu16(buf) == vec.3); assert(sum16(&crc_dect) == vec.3); hash::reset(&crc_ansi); hash::write(&crc_ansi, strings::toutf8(vec.0)); hash::sum(&crc_ansi, buf); assert(endian::host.getu16(buf) == vec.4); assert(sum16(&crc_ansi) == vec.4); }; }; hare-0.24.2/hash/crc32/000077500000000000000000000000001464473310100143605ustar00rootroot00000000000000hare-0.24.2/hash/crc32/README000066400000000000000000000001161464473310100152360ustar00rootroot00000000000000Implements the CRC-32 checksum algorithm. It is a non-cryptographic checksum. hare-0.24.2/hash/crc32/crc32.ha000066400000000000000000000327121464473310100156130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use io; use strings; // The size, in bytes, of a CRC-32 checksum. export def SZ: size = 4; // IEEE polynomial for CRC-32. Used in ethernet, SATA, MPEG-2, gzip, bzip2, // cksum, PNG, etc. It is by far the most common polynomial used. export def IEEE: u32 = 0xedb88320; // Castagnoli polynomial for CRC-32. Used in iSCSI, SCTP, SSE4.2, btrfs, ext4, // and others. It's known to have better error detection than IEEE. export def CASTAGNOLI: u32 = 0x82f63b78; // Koopman polnomial for CRC-32. It has good performance for small datasets, but // poor performance for large ones. Like the Castagnoli polynomial, it has // better error detection than the IEEE polynomial. export def KOOPMAN: u32 = 0xeb31d82e; // Table of memoized values for each byte with the IEEE polynomial. export const ieee_table: [256]u32 = [ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ]; // Table of memoized values for each byte with the Castagnoli polynomial. export const castagnoli_table: [256]u32 = [ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 ]; // Table of memoized values for each byte with the Koopman polynomial. export const koopman_table: [256]u32 = [ 0x00000000, 0x9695C4CA, 0xFB4839C9, 0x6DDDFD03, 0x20F3C3CF, 0xB6660705, 0xDBBBFA06, 0x4D2E3ECC, 0x41E7879E, 0xD7724354, 0xBAAFBE57, 0x2C3A7A9D, 0x61144451, 0xF781809B, 0x9A5C7D98, 0x0CC9B952, 0x83CF0F3C, 0x155ACBF6, 0x788736F5, 0xEE12F23F, 0xA33CCCF3, 0x35A90839, 0x5874F53A, 0xCEE131F0, 0xC22888A2, 0x54BD4C68, 0x3960B16B, 0xAFF575A1, 0xE2DB4B6D, 0x744E8FA7, 0x199372A4, 0x8F06B66E, 0xD1FDAE25, 0x47686AEF, 0x2AB597EC, 0xBC205326, 0xF10E6DEA, 0x679BA920, 0x0A465423, 0x9CD390E9, 0x901A29BB, 0x068FED71, 0x6B521072, 0xFDC7D4B8, 0xB0E9EA74, 0x267C2EBE, 0x4BA1D3BD, 0xDD341777, 0x5232A119, 0xC4A765D3, 0xA97A98D0, 0x3FEF5C1A, 0x72C162D6, 0xE454A61C, 0x89895B1F, 0x1F1C9FD5, 0x13D52687, 0x8540E24D, 0xE89D1F4E, 0x7E08DB84, 0x3326E548, 0xA5B32182, 0xC86EDC81, 0x5EFB184B, 0x7598EC17, 0xE30D28DD, 0x8ED0D5DE, 0x18451114, 0x556B2FD8, 0xC3FEEB12, 0xAE231611, 0x38B6D2DB, 0x347F6B89, 0xA2EAAF43, 0xCF375240, 0x59A2968A, 0x148CA846, 0x82196C8C, 0xEFC4918F, 0x79515545, 0xF657E32B, 0x60C227E1, 0x0D1FDAE2, 0x9B8A1E28, 0xD6A420E4, 0x4031E42E, 0x2DEC192D, 0xBB79DDE7, 0xB7B064B5, 0x2125A07F, 0x4CF85D7C, 0xDA6D99B6, 0x9743A77A, 0x01D663B0, 0x6C0B9EB3, 0xFA9E5A79, 0xA4654232, 0x32F086F8, 0x5F2D7BFB, 0xC9B8BF31, 0x849681FD, 0x12034537, 0x7FDEB834, 0xE94B7CFE, 0xE582C5AC, 0x73170166, 0x1ECAFC65, 0x885F38AF, 0xC5710663, 0x53E4C2A9, 0x3E393FAA, 0xA8ACFB60, 0x27AA4D0E, 0xB13F89C4, 0xDCE274C7, 0x4A77B00D, 0x07598EC1, 0x91CC4A0B, 0xFC11B708, 0x6A8473C2, 0x664DCA90, 0xF0D80E5A, 0x9D05F359, 0x0B903793, 0x46BE095F, 0xD02BCD95, 0xBDF63096, 0x2B63F45C, 0xEB31D82E, 0x7DA41CE4, 0x1079E1E7, 0x86EC252D, 0xCBC21BE1, 0x5D57DF2B, 0x308A2228, 0xA61FE6E2, 0xAAD65FB0, 0x3C439B7A, 0x519E6679, 0xC70BA2B3, 0x8A259C7F, 0x1CB058B5, 0x716DA5B6, 0xE7F8617C, 0x68FED712, 0xFE6B13D8, 0x93B6EEDB, 0x05232A11, 0x480D14DD, 0xDE98D017, 0xB3452D14, 0x25D0E9DE, 0x2919508C, 0xBF8C9446, 0xD2516945, 0x44C4AD8F, 0x09EA9343, 0x9F7F5789, 0xF2A2AA8A, 0x64376E40, 0x3ACC760B, 0xAC59B2C1, 0xC1844FC2, 0x57118B08, 0x1A3FB5C4, 0x8CAA710E, 0xE1778C0D, 0x77E248C7, 0x7B2BF195, 0xEDBE355F, 0x8063C85C, 0x16F60C96, 0x5BD8325A, 0xCD4DF690, 0xA0900B93, 0x3605CF59, 0xB9037937, 0x2F96BDFD, 0x424B40FE, 0xD4DE8434, 0x99F0BAF8, 0x0F657E32, 0x62B88331, 0xF42D47FB, 0xF8E4FEA9, 0x6E713A63, 0x03ACC760, 0x953903AA, 0xD8173D66, 0x4E82F9AC, 0x235F04AF, 0xB5CAC065, 0x9EA93439, 0x083CF0F3, 0x65E10DF0, 0xF374C93A, 0xBE5AF7F6, 0x28CF333C, 0x4512CE3F, 0xD3870AF5, 0xDF4EB3A7, 0x49DB776D, 0x24068A6E, 0xB2934EA4, 0xFFBD7068, 0x6928B4A2, 0x04F549A1, 0x92608D6B, 0x1D663B05, 0x8BF3FFCF, 0xE62E02CC, 0x70BBC606, 0x3D95F8CA, 0xAB003C00, 0xC6DDC103, 0x504805C9, 0x5C81BC9B, 0xCA147851, 0xA7C98552, 0x315C4198, 0x7C727F54, 0xEAE7BB9E, 0x873A469D, 0x11AF8257, 0x4F549A1C, 0xD9C15ED6, 0xB41CA3D5, 0x2289671F, 0x6FA759D3, 0xF9329D19, 0x94EF601A, 0x027AA4D0, 0x0EB31D82, 0x9826D948, 0xF5FB244B, 0x636EE081, 0x2E40DE4D, 0xB8D51A87, 0xD508E784, 0x439D234E, 0xCC9B9520, 0x5A0E51EA, 0x37D3ACE9, 0xA1466823, 0xEC6856EF, 0x7AFD9225, 0x17206F26, 0x81B5ABEC, 0x8D7C12BE, 0x1BE9D674, 0x76342B77, 0xE0A1EFBD, 0xAD8FD171, 0x3B1A15BB, 0x56C7E8B8, 0xC0522C72 ]; // Populate a user-provided buffer with the memoized values for a custom // polynomial. // // The user-provided polynomial must be in the reversed form. export fn memoize(polynomial: u32, buf: *[256]u32) void = { for (let i = 0z; i < 256; i += 1) { let value = i: u32; for (let z = 0z; z < 8; z += 1) { value = if (value & 0x1 == 1) { yield (value >> 1) ^ polynomial; } else { yield value >> 1; }; }; buf[i] = value; }; }; export type state = struct { hash::hash, table: *[256]u32, cval: u32, }; const crc32_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[hash::hash]] which computes the CRC-32 algorithm. This hash // function does not allocate any state, so you do not need to call // [[hash::close]] when you are done with it. // // It takes a table of memoized values for a given polynomail (for example, // [[ieee_table]], [[castagnoli_table]], or [[koopman_table]]); a table for a // custom polynomial, populated by [[memoize]] function, may also be used. export fn crc32(table: *[256]u32) state = state { stream = &crc32_vtable, sum = &sum, reset = &reset, sz = SZ, table = table, cval = ~0u32, ... }; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state; for (let i = 0z; i < len(buf); i += 1) { let rightbits = s.cval & 0xFF; s.cval = s.table[rightbits ^ buf[i]] ^ (s.cval >> 8); }; return len(buf); }; fn reset(h: *hash::hash) void = { let h = h: *state; h.cval = ~0u32; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; endian::host.putu32(buf, ~h.cval); }; // Returns the computed 32-bit CRC. export fn sum32(h: *hash::hash) u32 = { assert(h.reset == &reset); let h = h: *state; return ~h.cval; }; @test fn crc32() void = { const vectors: [](str, u32, u32, u32) = [ ("", 0, 0, 0), ("Give a man a fire, they be warm for a day", 4026734998, 2112273292, 1263149916), ("Set a man on fire, they be warm for the rest of their life", 3931092334, 4172943610, 3071632577), ("By trying we can easily learn to endure adversity. Another man's, I mean.", 3101256971, 2228454711, 3853172117), ("Civilization is the limitless multiplication of unnecessary necessities.", 3294636496, 2539066349, 896967959), ("Black lives matter", 2370964079, 2068416418, 4151357773), ("UNIX is simple and coherent", 3254252081, 1650777601, 340189632), ("GNU's not UNIX", 224734747, 200511816, 332335539) ]; let crc_ieee = crc32(&ieee_table); let crc_castagnoli = crc32(&castagnoli_table); let crc_koopman = crc32(&koopman_table); let buf: [SZ]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(&crc_ieee); hash::write(&crc_ieee, strings::toutf8(vec.0)); hash::sum(&crc_ieee, buf); assert(endian::host.getu32(buf) == vec.1); assert(sum32(&crc_ieee) == vec.1); hash::reset(&crc_castagnoli); hash::write(&crc_castagnoli, strings::toutf8(vec.0)); hash::sum(&crc_castagnoli, buf); assert(endian::host.getu32(buf) == vec.2); assert(sum32(&crc_castagnoli) == vec.2); hash::reset(&crc_koopman); hash::write(&crc_koopman, strings::toutf8(vec.0)); hash::sum(&crc_koopman, buf); assert(endian::host.getu32(buf) == vec.3); assert(sum32(&crc_koopman) == vec.3); }; }; hare-0.24.2/hash/crc64/000077500000000000000000000000001464473310100143655ustar00rootroot00000000000000hare-0.24.2/hash/crc64/README000066400000000000000000000001161464473310100152430ustar00rootroot00000000000000Implements the CRC-64 checksum algorithm. It is a non-cryptographic checksum. hare-0.24.2/hash/crc64/crc64.ha000066400000000000000000000327421464473310100156300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use io; use strings; // The size, in bytes, of a CRC-64 checksum. export def SZ: size = 8; // ECMA polynomial for CRC-64. Used in ECMA-182 and xz-utils. export def ECMA: u64 = 0xC96C5795D7870F42; // ISO polynomial for CRC-64. Used in ISO 3309 (high-level data link controls). export def ISO: u64 = 0xD800000000000000; // Table of memoized values for each byte with the ECMA polynomial. export const ecma_table: [256]u64 = [ 0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, 0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E, 0xCBDB3E64AB761D61, 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D, 0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, 0x8A3A2631AE2DDA2F, 0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73, 0x056ED3E2F9E22447, 0xB6409F5CFA457B28, 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9, 0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95, 0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7, 0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4, 0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3, 0xBAD65A25A73D0BDC, 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989, 0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, 0x64B62BCAEBC387A1, 0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD, 0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C, 0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0, 0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB, 0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1, 0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6, 0xD2F6B4961186FC89, 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407, 0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, 0x6820EEB3B6BBF755, 0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609, 0xE7741B60E174093D, 0x545A57DEE2D35652, 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21, 0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D, 0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F, 0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, 0xC96C5795D7870F42, 0x7A421B2BD420502D, 0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A, 0xF516EEF883EFAE45, 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10, 0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, 0xB4F7F6AD86B4690B, 0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857, 0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536, 0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A, 0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3, 0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9, 0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE, 0xF9802B81DE97DEB1, 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD, 0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, 0xB86133D4DBCC19FF, 0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3, 0x3735C6078C03E797, 0x841B8AB98FA4B8F8, 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8, 0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4, 0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6, 0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5, 0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2, 0xEC3B640A391F4FAD, 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8, 0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, 0x56ED3E2F9E224471, 0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D, 0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C, 0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910, 0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B, 0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, 0xDCD7181E300F9E5E, 0x6FF954A033A8C131, 0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036, 0xE0ADA17364673F59, ]; // Table of memoized values for each byte with the ISO polynomial. export const iso_table: [256]u64 = [ 0x0000000000000000, 0x01B0000000000000, 0x0360000000000000, 0x02D0000000000000, 0x06C0000000000000, 0x0770000000000000, 0x05A0000000000000, 0x0410000000000000, 0x0D80000000000000, 0x0C30000000000000, 0x0EE0000000000000, 0x0F50000000000000, 0x0B40000000000000, 0x0AF0000000000000, 0x0820000000000000, 0x0990000000000000, 0x1B00000000000000, 0x1AB0000000000000, 0x1860000000000000, 0x19D0000000000000, 0x1DC0000000000000, 0x1C70000000000000, 0x1EA0000000000000, 0x1F10000000000000, 0x1680000000000000, 0x1730000000000000, 0x15E0000000000000, 0x1450000000000000, 0x1040000000000000, 0x11F0000000000000, 0x1320000000000000, 0x1290000000000000, 0x3600000000000000, 0x37B0000000000000, 0x3560000000000000, 0x34D0000000000000, 0x30C0000000000000, 0x3170000000000000, 0x33A0000000000000, 0x3210000000000000, 0x3B80000000000000, 0x3A30000000000000, 0x38E0000000000000, 0x3950000000000000, 0x3D40000000000000, 0x3CF0000000000000, 0x3E20000000000000, 0x3F90000000000000, 0x2D00000000000000, 0x2CB0000000000000, 0x2E60000000000000, 0x2FD0000000000000, 0x2BC0000000000000, 0x2A70000000000000, 0x28A0000000000000, 0x2910000000000000, 0x2080000000000000, 0x2130000000000000, 0x23E0000000000000, 0x2250000000000000, 0x2640000000000000, 0x27F0000000000000, 0x2520000000000000, 0x2490000000000000, 0x6C00000000000000, 0x6DB0000000000000, 0x6F60000000000000, 0x6ED0000000000000, 0x6AC0000000000000, 0x6B70000000000000, 0x69A0000000000000, 0x6810000000000000, 0x6180000000000000, 0x6030000000000000, 0x62E0000000000000, 0x6350000000000000, 0x6740000000000000, 0x66F0000000000000, 0x6420000000000000, 0x6590000000000000, 0x7700000000000000, 0x76B0000000000000, 0x7460000000000000, 0x75D0000000000000, 0x71C0000000000000, 0x7070000000000000, 0x72A0000000000000, 0x7310000000000000, 0x7A80000000000000, 0x7B30000000000000, 0x79E0000000000000, 0x7850000000000000, 0x7C40000000000000, 0x7DF0000000000000, 0x7F20000000000000, 0x7E90000000000000, 0x5A00000000000000, 0x5BB0000000000000, 0x5960000000000000, 0x58D0000000000000, 0x5CC0000000000000, 0x5D70000000000000, 0x5FA0000000000000, 0x5E10000000000000, 0x5780000000000000, 0x5630000000000000, 0x54E0000000000000, 0x5550000000000000, 0x5140000000000000, 0x50F0000000000000, 0x5220000000000000, 0x5390000000000000, 0x4100000000000000, 0x40B0000000000000, 0x4260000000000000, 0x43D0000000000000, 0x47C0000000000000, 0x4670000000000000, 0x44A0000000000000, 0x4510000000000000, 0x4C80000000000000, 0x4D30000000000000, 0x4FE0000000000000, 0x4E50000000000000, 0x4A40000000000000, 0x4BF0000000000000, 0x4920000000000000, 0x4890000000000000, 0xD800000000000000, 0xD9B0000000000000, 0xDB60000000000000, 0xDAD0000000000000, 0xDEC0000000000000, 0xDF70000000000000, 0xDDA0000000000000, 0xDC10000000000000, 0xD580000000000000, 0xD430000000000000, 0xD6E0000000000000, 0xD750000000000000, 0xD340000000000000, 0xD2F0000000000000, 0xD020000000000000, 0xD190000000000000, 0xC300000000000000, 0xC2B0000000000000, 0xC060000000000000, 0xC1D0000000000000, 0xC5C0000000000000, 0xC470000000000000, 0xC6A0000000000000, 0xC710000000000000, 0xCE80000000000000, 0xCF30000000000000, 0xCDE0000000000000, 0xCC50000000000000, 0xC840000000000000, 0xC9F0000000000000, 0xCB20000000000000, 0xCA90000000000000, 0xEE00000000000000, 0xEFB0000000000000, 0xED60000000000000, 0xECD0000000000000, 0xE8C0000000000000, 0xE970000000000000, 0xEBA0000000000000, 0xEA10000000000000, 0xE380000000000000, 0xE230000000000000, 0xE0E0000000000000, 0xE150000000000000, 0xE540000000000000, 0xE4F0000000000000, 0xE620000000000000, 0xE790000000000000, 0xF500000000000000, 0xF4B0000000000000, 0xF660000000000000, 0xF7D0000000000000, 0xF3C0000000000000, 0xF270000000000000, 0xF0A0000000000000, 0xF110000000000000, 0xF880000000000000, 0xF930000000000000, 0xFBE0000000000000, 0xFA50000000000000, 0xFE40000000000000, 0xFFF0000000000000, 0xFD20000000000000, 0xFC90000000000000, 0xB400000000000000, 0xB5B0000000000000, 0xB760000000000000, 0xB6D0000000000000, 0xB2C0000000000000, 0xB370000000000000, 0xB1A0000000000000, 0xB010000000000000, 0xB980000000000000, 0xB830000000000000, 0xBAE0000000000000, 0xBB50000000000000, 0xBF40000000000000, 0xBEF0000000000000, 0xBC20000000000000, 0xBD90000000000000, 0xAF00000000000000, 0xAEB0000000000000, 0xAC60000000000000, 0xADD0000000000000, 0xA9C0000000000000, 0xA870000000000000, 0xAAA0000000000000, 0xAB10000000000000, 0xA280000000000000, 0xA330000000000000, 0xA1E0000000000000, 0xA050000000000000, 0xA440000000000000, 0xA5F0000000000000, 0xA720000000000000, 0xA690000000000000, 0x8200000000000000, 0x83B0000000000000, 0x8160000000000000, 0x80D0000000000000, 0x84C0000000000000, 0x8570000000000000, 0x87A0000000000000, 0x8610000000000000, 0x8F80000000000000, 0x8E30000000000000, 0x8CE0000000000000, 0x8D50000000000000, 0x8940000000000000, 0x88F0000000000000, 0x8A20000000000000, 0x8B90000000000000, 0x9900000000000000, 0x98B0000000000000, 0x9A60000000000000, 0x9BD0000000000000, 0x9FC0000000000000, 0x9E70000000000000, 0x9CA0000000000000, 0x9D10000000000000, 0x9480000000000000, 0x9530000000000000, 0x97E0000000000000, 0x9650000000000000, 0x9240000000000000, 0x93F0000000000000, 0x9120000000000000, 0x9090000000000000, ]; // Populate a user-provided buffer with the memoized values for a custom // polynomial. // // The user-provided polynomial must be in the reversed form. export fn memoize(polynomial: u64, buf: *[256]u64) void = { for (let i = 0z; i < 256; i += 1) { let value = i: u64; for (let z = 0z; z < 8; z += 1) { value = if (value & 0x1 == 1) { yield (value >> 1) ^ polynomial; } else { yield value >> 1; }; }; buf[i] = value; }; }; export type state = struct { hash::hash, table: *[256]u64, cval: u64, }; const crc64_vtable: io::vtable = io::vtable { writer = &write, ... }; // Creates a [[hash::hash]] which computes the CRC-64 algorithm. This hash // function does not allocate any state, so you do not need to call // [[hash::close]] when you are done with it. // // It takes a table of memoized values for a given polynomail (for example, // [[iso_table]] or [[ecma_table]]); a table for a custom polynomial, populated // by [[memoize]] function, may also be used. export fn crc64(table: *[256]u64) state = state { stream = &crc64_vtable, sum = &sum, reset = &reset, sz = SZ, table = table, cval = ~0u64, ... }; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state; for (let i = 0z; i < len(buf); i += 1) { let rightbits = s.cval & 0xFF; s.cval = s.table[rightbits ^ buf[i]] ^ (s.cval >> 8); }; return len(buf); }; fn reset(h: *hash::hash) void = { let h = h: *state; h.cval = ~0u64; }; fn sum(h: *hash::hash, buf: []u8) void = { let h = h: *state; endian::host.putu64(buf, ~h.cval); }; // Returns the 64-bit computed CRC. export fn sum64(h: *hash::hash) u64 = { assert(h.reset == &reset); let h = h: *state; return ~h.cval; }; @test fn crc64() void = { const vectors: [](str, u64, u64) = [ ("", 0, 0), ("Man can believe the impossible, but can never believe the improbable. -- Oscar Wilde", 0x17F71EF3BB851DC7, 0xD0E8ED57865D6AC6), ("We learn from history that we do not learn from history. -- Georg Hegel", 0xAA3C335BB49ABE9D, 0x5FD192CC516BBEC3), ("The final delusion is the belief that one has lost all delusions. -- Maurice Chapelain", 0x7DFC4F7CE9552D23, 0xF71B429C925D99AE), ]; let crc_ecma = crc64(&ecma_table); let crc_iso = crc64(&iso_table); let buf: [SZ]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(&crc_ecma); hash::write(&crc_ecma, strings::toutf8(vec.0)); hash::sum(&crc_ecma, buf); assert(endian::host.getu64(buf) == vec.1); assert(sum64(&crc_ecma) == vec.1); hash::reset(&crc_iso); hash::write(&crc_iso, strings::toutf8(vec.0)); hash::sum(&crc_iso, buf); assert(endian::host.getu64(buf) == vec.2); assert(sum64(&crc_iso) == vec.2); }; }; hare-0.24.2/hash/fnv/000077500000000000000000000000001464473310100142355ustar00rootroot00000000000000hare-0.24.2/hash/fnv/+aarch64.ha000066400000000000000000000003041464473310100160470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Hashes a string, returning a size key, for use in a hash map. export fn string(s: str) size = string64(s): size; hare-0.24.2/hash/fnv/+riscv64.ha000066400000000000000000000003041464473310100161170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Hashes a string, returning a size key, for use in a hash map. export fn string(s: str) size = string64(s): size; hare-0.24.2/hash/fnv/+x86_64.ha000066400000000000000000000003041464473310100155550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Hashes a string, returning a size key, for use in a hash map. export fn string(s: str) size = string64(s): size; hare-0.24.2/hash/fnv/README000066400000000000000000000002761464473310100151220ustar00rootroot00000000000000Implements the Fowler–Noll–Vo (FNV) hash function. This hash is recommended for hash map keys and similar applications when hash flooding isn't an issue. It is a non-cryptographic hash. hare-0.24.2/hash/fnv/fnv.ha000066400000000000000000000114651464473310100153470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use io; use strings; def PRIME32: u32 = 16777619; def PRIME64: u64 = 1099511628211; def BASIS32: u32 = 2166136261; def BASIS64: u64 = 14695981039346656037; export type state32 = struct { hash::hash, v: u32, }; export type state64 = struct { hash::hash, v: u64, }; // Hashes a string, returning a 32-bit key. export fn string32(s: str) u32 = { let hash = fnv32a(); hash::write(&hash, strings::toutf8(s)); return sum32(&hash); }; // Hashes a string, returning a 64-bit key. export fn string64(s: str) u64 = { let hash = fnv64a(); hash::write(&hash, strings::toutf8(s)); return sum64(&hash); }; const fnv32_vtable: io::vtable = io::vtable { writer = &fnv32_write, ... }; // Creates a [[hash::hash]] which computes the FNV-1 32-bit hash function. This // hash does not allocate any state, so you do not need to call [[hash::close]] // when you're done with it. // // Unless you have a reason to use this, [[fnv32a]] is recommended instead. export fn fnv32() state32 = state32 { stream = &fnv32_vtable, sum = &fnv32_sum, reset = &fnv32_reset, sz = 4, v = BASIS32, ... }; const fnv32a_vtable: io::vtable = io::vtable { writer = &fnv32a_write, ... }; // Creates a [[hash::hash]] which computes the FNV-1a 32-bit hash function. This // hash does not allocate any state, so you do not need to call [[hash::close]] // when you're done with it. export fn fnv32a() state32 = state32 { stream = &fnv32a_vtable, sum = &fnv32_sum, reset = &fnv32_reset, sz = 4, v = BASIS32, ... }; const fnv64_vtable: io::vtable = io::vtable { writer = &fnv64_write, ... }; // Creates a [[hash::hash]] which computes the FNV-1 64-bit hash function. This // hash does not allocate any state, so you do not need to call [[hash::close]] // when you're done with it. // // Unless you have a reason to use this, [[fnv64a]] is recommended instead. export fn fnv64() state64 = state64 { stream = &fnv64_vtable, sum = &fnv64_sum, reset = &fnv64_reset, sz = 8, v = BASIS64, ... }; const fnv64a_vtable: io::vtable = io::vtable { writer = &fnv64a_write, ... }; // Creates a [[hash::hash]] which computes the FNV-1a 64-bit hash function. This // hash does not allocate any state, so you do not need to call [[hash::close]] // when you're done with it. export fn fnv64a() state64 = state64 { stream = &fnv64a_vtable, sum = &fnv64_sum, reset = &fnv64_reset, sz = 8, v = BASIS64, ... }; fn fnv32_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state32; for (let i = 0z; i < len(buf); i += 1) { s.v *= PRIME32; s.v ^= buf[i]; }; return len(buf); }; fn fnv32a_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state32; for (let i = 0z; i < len(buf); i += 1) { s.v ^= buf[i]; s.v *= PRIME32; }; return len(buf); }; fn fnv32_reset(h: *hash::hash) void = { let h = h: *state32; h.v = BASIS32; }; fn fnv32_sum(h: *hash::hash, buf: []u8) void = { let h = h: *state32; endian::host.putu32(buf, h.v); }; fn fnv64_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state64; for (let i = 0z; i < len(buf); i += 1) { s.v *= PRIME64; s.v ^= buf[i]; }; return len(buf); }; fn fnv64a_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state64; for (let i = 0z; i < len(buf); i += 1) { s.v ^= buf[i]; s.v *= PRIME64; }; return len(buf); }; fn fnv64_reset(h: *hash::hash) void = { let h = h: *state64; h.v = BASIS64; }; fn fnv64_sum(h: *hash::hash, buf: []u8) void = { let h = h: *state64; endian::host.putu64(buf, h.v); }; // Returns the sum of a 32-bit FNV hash. export fn sum32(h: *hash::hash) u32 = { assert(h.reset == &fnv32_reset); let h = h: *state32; return h.v; }; // Returns the sum of a 64-bit FNV hash. export fn sum64(h: *hash::hash) u64 = { assert(h.reset == &fnv64_reset); let h = h: *state64; return h.v; }; @test fn fnv32() void = { // TODO: Expand these tests // I am too tired const vectors: [_](str, u32) = [ ("", 2166136261), ("hello world", 1418570095), ("Hare is a cool language", 2663852071), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", 1203174417), ("'Life is too short to run proprietary software' - Bdale Garbee", 493463614), ("'The central enemy of reliability is complexity.' - Geer et al", 3263526736), ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", 3069348265), ]; let hash = fnv32(); let s: [4]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(&hash); hash::write(&hash, strings::toutf8(vec.0)); hash::sum(&hash, s); assert(endian::host.getu32(s) == vec.1); assert(sum32(&hash) == vec.1); }; }; hare-0.24.2/hash/hash.ha000066400000000000000000000030461464473310100147040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; // TODO: Use a vtable-based approach for this like io::stream // The general purpose interface for a hashing function. export type hash = struct { // A stream which only supports writes and never returns errors. stream: io::stream, // Returns the current hash. sum: *fn(hash: *hash, buf: []u8) void, // Resets the hash function to its initial state. reset: nullable *fn(hash: *hash) void, // Size of the hash in bytes. sz: size, // Internal block size of the hash. Writing data to the hash // function in chunks of this size will not require padding to // obtain the final hash. bsz: size, }; // Writes an input to the hash function. export fn write(h: *hash, buf: const []u8) size = io::write(h, buf) as size; // Closes a hash, freeing its resources and discarding the checksum. export fn close(h: *hash) void = io::close(h)!; // Populates the user-provided buffer with the current sum. export fn sum(h: *hash, buf: []u8) void = { assert(len(buf) >= h.sz, "hash::sum buffer does not meet minimum required size for this hash function"); h.sum(h, buf); }; // Resets the hash function to its initial state. export fn reset(h: *hash) void = match (h.reset) { case let f: *fn(hash: *hash) void => f(h); case null => abort("this hash cannot be reset"); }; // Returns the size of the hash in bytes. This is consistent regardless // of the hash state. export fn sz(h: *hash) size = h.sz; // Returns the block size of the hash. export fn bsz(h: *hash) size = h.bsz; hare-0.24.2/hash/siphash/000077500000000000000000000000001464473310100151035ustar00rootroot00000000000000hare-0.24.2/hash/siphash/+test.ha000066400000000000000000000063051464473310100164530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use hash; use strings; @test fn siphash() void = { // same data and test procedure as the reference implementation const vectors: [64]u64 = [ 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572, ]; let key: [16]u8 = [0...]; for (let i = 0u8; i < 16; i += 1) { key[i] = i; }; let sip = siphash(2, 4, &key); defer hash::close(&sip); let buf: [8]u8 = [0...]; for (let i = 0u8; i < 64; i += 1) { hash::sum(&sip, &buf); assert(endian::legetu64(buf) == vectors[i]); hash::write(&sip, [i]); }; const vectors: [_](str, u64) = [ ("", 0x726fdb47dd0e0e31), ("abc", 0x5dbcfa53aa2007a5), ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 0x62da29967a36b79f), ("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 0x3ddf92b5dac6728b), ("hello world", 0xed5159c956cd5602), ("Hare is a cool language", 0xb459a8d06410857e), ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", 0x8f2787e694a9cced), ("'Life is too short to run proprietary software' - Bdale Garbee", 0xfe97befe3823b15c), ("'The central enemy of reliability is complexity.' - Geer et al", 0x61ea79c94e39ed29), ]; for (let i = 0z; i < len(vectors); i += 1) { const vector = vectors[i]; let sip = siphash(2, 4, &key); defer hash::close(&sip); hash::write(&sip, strings::toutf8(vector.0)); assert(sum(&sip) == vector.1); }; // Uncomment this to run the 1G test vector (I promise it works): // const input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; // const expected = 0x439f9847c050d927u64; // let sip = siphash(2, 4, &key); // defer hash::close(&sip); // for (let i = 0z; i < 16777216; i += 1) { // hash::write(&sip, strings::toutf8(input)); // }; // assert(sum(&sip) == expected); }; hare-0.24.2/hash/siphash/README000066400000000000000000000003451464473310100157650ustar00rootroot00000000000000Implements the SipHash keyed hash function. Output of SipHash(secret, input) for any input does not reveal anything about the secret used, which makes it a good choice for use cases that require resistance against hash flooding. hare-0.24.2/hash/siphash/siphash.ha000066400000000000000000000054051464473310100170600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::math::{rotl64}; use endian::{leputu64, legetu64}; use hash; use io; export type state = struct { hash::hash, v: [4]u64, x: [CHUNKSZ]u8, x_len: u8, c: u8, d: u8, ln: size, }; def CHUNKSZ: size = 8; const sip_vtable: io::vtable = io::vtable { writer = &write, closer = &close, ... }; // Creates a [hash::hash] that computes SipHash-c-d with the given 16 byte key, // where c denotes number of compression rounds and d denotes number of // finalization rounds. Recommended values for c and d are 2 and 4 respectively. // Calling [[hash::close]] on this function will erase its state information. // This function does not provide reset functionality and calling // [[hash::reset]] on it will terminate execution. export fn siphash(c: u8, d: u8, key: *[16]u8) state = { let h = state { stream = &sip_vtable, sum = &sum64_bytes, sz = CHUNKSZ, c = c, d = d, ... }; let s = legetu64(key[..8]); h.v[0] = 0x736f6d6570736575 ^ s; h.v[2] = 0x6c7967656e657261 ^ s; let s = legetu64(key[8..]); h.v[1] = 0x646f72616e646f6d ^ s; h.v[3] = 0x7465646279746573 ^ s; return h; }; fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let h = s: *state; h.ln += len(buf); let n = CHUNKSZ - h.x_len; if (len(buf) < n) { // not enough data to fill a chunk h.x[h.x_len..h.x_len + len(buf)] = buf; h.x_len += len(buf): u8; return len(buf); }; h.x[h.x_len..] = buf[..n]; let b = legetu64(h.x); h.v[3] ^= b; for (let i = 0u8; i < h.c; i += 1) { round(h); }; h.v[0] ^= b; let buf = buf[n..]; for (len(buf) >= CHUNKSZ) { let b = legetu64(buf); h.v[3] ^= b; for (let i = 0u8; i < h.c; i += 1) { round(h); }; h.v[0] ^= b; buf = buf[CHUNKSZ..]; }; h.x_len = len(buf): u8; h.x[..h.x_len] = buf; return len(buf); }; // Returns the sum as a u64 export fn sum(h: *state) u64 = { let h = *h; for (let i = h.x_len; i < 7; i += 1) { h.x[i] = 0; }; h.x[7] = h.ln: u8; let b = legetu64(h.x); h.v[3] ^= b; for (let i = 0u8; i < h.c; i += 1) { round(&h); }; h.v[0] ^= b; h.v[2] ^= 0xff; for (let i = 0u8; i < h.d; i += 1) { round(&h); }; return h.v[0] ^ h.v[1] ^ h.v[2] ^ h.v[3]; }; fn sum64_bytes(h: *hash::hash, buf: []u8) void = leputu64(buf, sum(h: *state)); fn round(h: *state) void = { h.v[0] += h.v[1]; h.v[1] = rotl64(h.v[1], 13); h.v[1] ^= h.v[0]; h.v[0] = rotl64(h.v[0], 32); h.v[2] += h.v[3]; h.v[3] = rotl64(h.v[3], 16); h.v[3] ^= h.v[2]; h.v[0] += h.v[3]; h.v[3] = rotl64(h.v[3], 21); h.v[3] ^= h.v[0]; h.v[2] += h.v[1]; h.v[1] = rotl64(h.v[1], 17); h.v[1] ^= h.v[2]; h.v[2] = rotl64(h.v[2], 32); }; fn close(h: *io::stream) (void | io::error) = { let h = h: *state; h.v = [0...]; h.x = [0...]; h.ln = 0; h.x_len = 0; }; hare-0.24.2/io/000077500000000000000000000000001464473310100131305ustar00rootroot00000000000000hare-0.24.2/io/+freebsd/000077500000000000000000000000001464473310100146155ustar00rootroot00000000000000hare-0.24.2/io/+freebsd/dup.ha000066400000000000000000000023661464473310100157260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Flags for [[dup]] and [[dup2]] operations. export type dupflag = enum { NONE = 0, // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the // duplicated file descriptor. By default, CLOEXEC is set. NOCLOEXEC = rt::FD_CLOEXEC, }; // Duplicates a file descriptor. export fn dup(old: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, -1)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | rt::FD_CLOEXEC)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; // Duplicates a file descriptor and stores the new file at a specific file // descriptor number. If the file indicated by "new" already refers to an open // file, this file will be closed before the file descriptor is reused. export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, new)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | flags)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+freebsd/mmap.ha000066400000000000000000000026631464473310100160700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE // values are portable. export type prot = enum uint { NONE = rt::PROT_NONE, READ = rt::PROT_READ, WRITE = rt::PROT_WRITE, EXEC = rt::PROT_EXEC, }; // Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED // values are portable. export type mflag = enum uint { SHARED = rt::MAP_SHARED, PRIVATE = rt::MAP_PRIVATE, FIXED = rt::MAP_FIXED, HASSEMAPHORE = rt::MAP_HASSEMAPHORE , STACK = rt::MAP_STACK, NOSYNC = rt::MAP_NOSYNC, FILE = rt::MAP_FILE, ANON = rt::MAP_ANON, GUARD = rt::MAP_GUARD, EXCL = rt::MAP_EXCL, NOCORE = rt::MAP_NOCORE, PREFAULT_READ = rt::MAP_PREFAULT_READ, _32BIT = rt::MAP_32BIT, }; // Performs the mmap syscall. Consult your system for documentation on this // function. export fn mmap( addr: nullable *opaque, length: size, prot: prot, flags: mflag, fd: file, offs: size ) (*opaque | errors::error) = { match (rt::mmap(addr, length, prot, flags, fd, offs)) { case let ptr: *opaque => return ptr; case let err: rt::errno => return errors::errno(err); }; }; // Unmaps memory previously mapped with [[mmap]]. export fn munmap(addr: *opaque, length: size) (void | errors::error) = { match (rt::munmap(addr, length)) { case void => return; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/io/+freebsd/platform_file.ha000066400000000000000000000037101464473310100177530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // This is an opaque type which encloses an OS-level file handle resource. It // can be used as a [[handle]] in most situations, but there are some APIs which // require a [[file]] with some OS-level handle backing it - this type is used // for such APIs. // // On FreeBSD, [[file]] is a file descriptor. export type file = int; // Opens a Unix file descriptor as a file. This is a low-level interface, to // open files most programs will use something like [[os::open]]. This function // is not portable. export fn fdopen(fd: int) file = fd; fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { match (rt::read(fd, buf: *[*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; fn fd_write(fd: file, buf: const []u8) (size | error) = { match (rt::write(fd, buf: *const [*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; fn fd_close(fd: file) (void | error) = { match (rt::close(fd)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; fn fd_seek( fd: file, offs: off, whence: whence, ) (off | error) = { match (rt::lseek(fd, offs: i64, whence: int)) { case let err: rt::errno => return errors::errno(err); case let n: i64 => return n: off; }; }; fn fd_copy(to: file, from: file) (size | error) = errors::unsupported; fn fd_lock(fd: file, flags: int) (bool | error) = { match (rt::flock(fd: int, flags)) { case void => return true; case let e: rt::errno => if (e == rt::EWOULDBLOCK: rt::errno) { return false; } else { return errors::errno(e); }; }; }; fn fd_trunc(fd: file, ln: size) (void | error) = { match (rt::ftruncate(fd: int, ln: rt::off_t)) { case void => void; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+freebsd/vector.ha000066400000000000000000000025041464473310100164320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use types; export type vector = rt::iovec; // Creates a vector for use with [[writev]] and [[readv]]. export fn mkvector(buf: []u8) vector = vector { iov_base = buf: *[*]u8, iov_len = len(buf), }; // Performs a vectored read on the given file. A read is performed on each of // the vectors, prepared with [[mkvector]], in order, and the total number of // bytes read is returned. export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; // Performs a vectored write on the given file. Each of the vectors, prepared // with [[mkvector]], are written to the file in order, and the total number of // bytes written is returned. export fn writev(fd: file, vectors: vector...) (size | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/io/+linux/000077500000000000000000000000001464473310100143425ustar00rootroot00000000000000hare-0.24.2/io/+linux/dup.ha000066400000000000000000000022271464473310100154470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Flags for [[dup]] and [[dup2]] operations. export type dupflag = enum { NONE = 0, // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the // duplicated file descriptor. By default, CLOEXEC is set. NOCLOEXEC = rt::FD_CLOEXEC, }; // Duplicates a file descriptor. export fn dup(old: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup(old)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | flags)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; // Duplicates a file descriptor and stores the new file at a specific file // descriptor number. If the file indicated by "new" already refers to an open // file, this file will be closed before the file descriptor is reused. export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup3(old, new, flags)) { case let fd: int => return fd; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+linux/mmap.ha000066400000000000000000000041071464473310100156100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE // values are portable. export type prot = enum uint { NONE = rt::PROT_NONE, READ = rt::PROT_READ, WRITE = rt::PROT_WRITE, EXEC = rt::PROT_EXEC, GROWSDOWN = rt::PROT_GROWSDOWN, GROWSUP = rt::PROT_GROWSUP, }; // Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED // values are portable. export type mflag = enum uint { SHARED = rt::MAP_SHARED, PRIVATE = rt::MAP_PRIVATE, SHARED_VALIDATE = rt::MAP_SHARED_VALIDATE, FIXED = rt::MAP_FIXED, ANON = rt::MAP_ANON, NORESERVE = rt::MAP_NORESERVE, GROWSDOWN = rt::MAP_GROWSDOWN, DENYWRITE = rt::MAP_DENYWRITE, EXECUTABLE = rt::MAP_EXECUTABLE, LOCKED = rt::MAP_LOCKED, POPULATE = rt::MAP_POPULATE, NONBLOCK = rt::MAP_NONBLOCK, STACK = rt::MAP_STACK, HUGETLB = rt::MAP_HUGETLB, SYNC = rt::MAP_SYNC, FIXED_NOREPLACE = rt::MAP_FIXED_NOREPLACE, FILE = rt::MAP_FILE, HUGE_SHIFT = rt::MAP_HUGE_SHIFT, HUGE_MASK = rt::MAP_HUGE_MASK, HUGE_64KB = rt::MAP_HUGE_64KB, HUGE_512KB = rt::MAP_HUGE_512KB, HUGE_1MB = rt::MAP_HUGE_1MB, HUGE_2MB = rt::MAP_HUGE_2MB, HUGE_8MB = rt::MAP_HUGE_8MB, HUGE_16MB = rt::MAP_HUGE_16MB, HUGE_32MB = rt::MAP_HUGE_32MB, HUGE_256MB = rt::MAP_HUGE_256MB, HUGE_512MB = rt::MAP_HUGE_512MB, HUGE_1GB = rt::MAP_HUGE_1GB, HUGE_2GB = rt::MAP_HUGE_2GB, HUGE_16GB = rt::MAP_HUGE_16GB, }; // Performs the mmap syscall. Consult your system for documentation on this // function. export fn mmap( addr: nullable *opaque, length: size, prot: prot, flags: mflag, fd: file, offs: size ) (*opaque | errors::error) = { match (rt::mmap(addr, length, prot, flags, fd, offs)) { case let ptr: *opaque => return ptr; case let err: rt::errno => return errors::errno(err); }; }; // Unmaps memory previously mapped with [[mmap]]. export fn munmap(addr: *opaque, length: size) (void | errors::error) = { match (rt::munmap(addr, length)) { case void => return; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/io/+linux/platform_file.ha000066400000000000000000000043701464473310100175030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // This is an opaque type which encloses an OS-level file handle resource. It // can be used as a [[handle]] in most situations, but there are some APIs which // require a [[file]] with some OS-level handle backing it - this type is used // for such APIs. // // On Linux, [[file]] is a file descriptor. export type file = int; // Opens a Unix file descriptor as a file. This is a low-level interface, to // open files most programs will use something like [[os::open]]. This function // is not portable. export fn fdopen(fd: int) file = fd; fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { match (rt::read(fd, buf: *[*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; fn fd_write(fd: file, buf: const []u8) (size | error) = { match (rt::write(fd, buf: *const [*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; fn fd_close(fd: file) (void | error) = { match (rt::close(fd)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; fn fd_seek( fd: file, offs: off, whence: whence, ) (off | error) = { match (rt::lseek(fd, offs: i64, whence: int)) { case let err: rt::errno => return errors::errno(err); case let n: i64 => return n: off; }; }; def SENDFILE_MAX: size = 2147479552z; fn fd_copy(to: file, from: file) (size | error) = { let sum = 0z; for (true) match (rt::sendfile(to, from, null, SENDFILE_MAX)) { case let err: rt::errno => if (err == rt::EINVAL && sum == 0) { return errors::unsupported; }; return errors::errno(err); case let n: size => if (n == 0) break; sum += n; }; return sum; }; fn fd_lock(fd: file, flags: int) (bool | error) = { match (rt::flock(fd: int, flags)) { case void => return true; case let e: rt::errno => if (e == rt::EWOULDBLOCK: rt::errno) { return false; } else { return errors::errno(e); }; }; }; fn fd_trunc(fd: file, ln: size) (void | error) = { match (rt::ftruncate(fd: int, ln: rt::off_t)) { case void => void; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+linux/vector.ha000066400000000000000000000025041464473310100161570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use types; export type vector = rt::iovec; // Creates a vector for use with [[writev]] and [[readv]]. export fn mkvector(buf: []u8) vector = vector { iov_base = buf: *[*]u8, iov_len = len(buf), }; // Performs a vectored read on the given file. A read is performed on each of // the vectors, prepared with [[mkvector]], in order, and the total number of // bytes read is returned. export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; // Performs a vectored write on the given file. Each of the vectors, prepared // with [[mkvector]], are written to the file in order, and the total number of // bytes written is returned. export fn writev(fd: file, vectors: vector...) (size | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/io/+netbsd/000077500000000000000000000000001464473310100144625ustar00rootroot00000000000000hare-0.24.2/io/+netbsd/dup.ha000066400000000000000000000023661464473310100155730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Flags for [[dup]] and [[dup2]] operations. export type dupflag = enum { NONE = 0, // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the // duplicated file descriptor. By default, CLOEXEC is set. NOCLOEXEC = rt::FD_CLOEXEC, }; // Duplicates a file descriptor. export fn dup(old: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, -1)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | rt::FD_CLOEXEC)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; // Duplicates a file descriptor and stores the new file at a specific file // descriptor number. If the file indicated by "new" already refers to an open // file, this file will be closed before the file descriptor is reused. export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, new)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | flags)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+netbsd/mmap.ha000066400000000000000000000026631464473310100157350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE // values are portable. export type prot = enum uint { NONE = rt::PROT_NONE, READ = rt::PROT_READ, WRITE = rt::PROT_WRITE, EXEC = rt::PROT_EXEC, }; // Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED // values are portable. export type mflag = enum uint { SHARED = rt::MAP_SHARED, PRIVATE = rt::MAP_PRIVATE, FIXED = rt::MAP_FIXED, HASSEMAPHORE = rt::MAP_HASSEMAPHORE , STACK = rt::MAP_STACK, NOSYNC = rt::MAP_NOSYNC, FILE = rt::MAP_FILE, ANON = rt::MAP_ANON, GUARD = rt::MAP_GUARD, EXCL = rt::MAP_EXCL, NOCORE = rt::MAP_NOCORE, PREFAULT_READ = rt::MAP_PREFAULT_READ, _32BIT = rt::MAP_32BIT, }; // Performs the mmap syscall. Consult your system for documentation on this // function. export fn mmap( addr: nullable *opaque, length: size, prot: prot, flags: mflag, fd: file, offs: size ) (*opaque | errors::error) = { match (rt::mmap(addr, length, prot, flags, fd, offs)) { case let ptr: *opaque => return ptr; case let err: rt::errno => return errors::errno(err); }; }; // Unmaps memory previously mapped with [[mmap]]. export fn munmap(addr: *opaque, length: size) (void | errors::error) = { match (rt::munmap(addr, length)) { case void => return; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/io/+netbsd/platform_file.ha000066400000000000000000000037071464473310100176260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // This is an opaque type which encloses an OS-level file handle resource. It // can be used as a [[handle]] in most situations, but there are some APIs which // require a [[file]] with some OS-level handle backing it - this type is used // for such APIs. // // On NetBSD, [[file]] is a file descriptor. export type file = int; // Opens a Unix file descriptor as a file. This is a low-level interface, to // open files most programs will use something like [[os::open]]. This function // is not portable. export fn fdopen(fd: int) file = fd; fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { match (rt::read(fd, buf: *[*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; fn fd_write(fd: file, buf: const []u8) (size | error) = { match (rt::write(fd, buf: *const [*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; fn fd_close(fd: file) (void | error) = { match (rt::close(fd)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; fn fd_seek( fd: file, offs: off, whence: whence, ) (off | error) = { match (rt::lseek(fd, offs: i64, whence: int)) { case let err: rt::errno => return errors::errno(err); case let n: i64 => return n: off; }; }; fn fd_copy(to: file, from: file) (size | error) = errors::unsupported; fn fd_lock(fd: file, flags: int) (bool | error) = { match (rt::flock(fd: int, flags)) { case void => return true; case let e: rt::errno => if (e == rt::EWOULDBLOCK: rt::errno) { return false; } else { return errors::errno(e); }; }; }; fn fd_trunc(fd: file, ln: size) (void | error) = { match (rt::ftruncate(fd: int, ln: rt::off_t)) { case void => void; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+netbsd/vector.ha000066400000000000000000000025041464473310100162770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use types; export type vector = rt::iovec; // Creates a vector for use with [[writev]] and [[readv]]. export fn mkvector(buf: []u8) vector = vector { iov_base = buf: *[*]u8, iov_len = len(buf), }; // Performs a vectored read on the given file. A read is performed on each of // the vectors, prepared with [[mkvector]], in order, and the total number of // bytes read is returned. export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; // Performs a vectored write on the given file. Each of the vectors, prepared // with [[mkvector]], are written to the file in order, and the total number of // bytes written is returned. export fn writev(fd: file, vectors: vector...) (size | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/io/+openbsd/000077500000000000000000000000001464473310100146355ustar00rootroot00000000000000hare-0.24.2/io/+openbsd/dup.ha000066400000000000000000000023661464473310100157460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Flags for [[dup]] and [[dup2]] operations. export type dupflag = enum { NONE = 0, // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the // duplicated file descriptor. By default, CLOEXEC is set. NOCLOEXEC = rt::FD_CLOEXEC, }; // Duplicates a file descriptor. export fn dup(old: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, -1)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | rt::FD_CLOEXEC)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; // Duplicates a file descriptor and stores the new file at a specific file // descriptor number. If the file indicated by "new" already refers to an open // file, this file will be closed before the file descriptor is reused. export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC match (rt::dup2(old, new)) { case let fd: int => const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; rt::fcntl(fd, rt::F_SETFD, fl | flags)!; return fd; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+openbsd/mmap.ha000066400000000000000000000023611464473310100161030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE // values are portable. export type prot = enum int { NONE = rt::PROT_NONE, READ = rt::PROT_READ, WRITE = rt::PROT_WRITE, EXEC = rt::PROT_EXEC, }; // Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED // values are portable. export type mflag = enum int { SHARED = rt::MAP_SHARED, PRIVATE = rt::MAP_PRIVATE, FIXED = rt::MAP_FIXED, ANON = rt::MAP_ANON, STACK = rt::MAP_STACK, CONCEAL = rt::MAP_CONCEAL }; // Performs the mmap syscall. Consult your system for documentation on this // function. export fn mmap( addr: nullable *opaque, length: size, prot: prot, flags: mflag, fd: file, offs: size ) (*opaque | errors::error) = { match (rt::mmap(addr, length, prot, flags, fd, offs: i64)) { case let ptr: *opaque => return ptr; case let err: rt::errno => return errors::errno(err); }; }; // Unmaps memory previously mapped with [[mmap]]. export fn munmap(addr: *opaque, length: size) (void | errors::error) = { match (rt::munmap(addr, length)) { case void => return; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/io/+openbsd/platform_file.ha000066400000000000000000000037101464473310100177730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // This is an opaque type which encloses an OS-level file handle resource. It // can be used as a [[handle]] in most situations, but there are some APIs which // require a [[file]] with some OS-level handle backing it - this type is used // for such APIs. // // On OpenBSD, [[file]] is a file descriptor. export type file = int; // Opens a Unix file descriptor as a file. This is a low-level interface, to // open files most programs will use something like [[os::open]]. This function // is not portable. export fn fdopen(fd: int) file = fd; fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { match (rt::read(fd, buf: *[*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; fn fd_write(fd: file, buf: const []u8) (size | error) = { match (rt::write(fd, buf: *const [*]u8, len(buf))) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; fn fd_close(fd: file) (void | error) = { match (rt::close(fd)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; fn fd_seek( fd: file, offs: off, whence: whence, ) (off | error) = { match (rt::lseek(fd, offs: i64, whence: int)) { case let err: rt::errno => return errors::errno(err); case let n: i64 => return n: off; }; }; fn fd_copy(to: file, from: file) (size | error) = errors::unsupported; fn fd_lock(fd: file, flags: int) (bool | error) = { match (rt::flock(fd: int, flags)) { case void => return true; case let e: rt::errno => if (e == rt::EWOULDBLOCK: rt::errno) { return false; } else { return errors::errno(e); }; }; }; fn fd_trunc(fd: file, ln: size) (void | error) = { match (rt::ftruncate(fd: int, ln: rt::off_t)) { case void => void; case let e: rt::errno => return errors::errno(e); }; }; hare-0.24.2/io/+openbsd/vector.ha000066400000000000000000000025041464473310100164520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use types; export type vector = rt::iovec; // Creates a vector for use with [[writev]] and [[readv]]. export fn mkvector(buf: []u8) vector = vector { iov_base = buf: *[*]u8, iov_len = len(buf), }; // Performs a vectored read on the given file. A read is performed on each of // the vectors, prepared with [[mkvector]], in order, and the total number of // bytes read is returned. export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case 0 => return EOF; case => return n; }; }; }; // Performs a vectored write on the given file. Each of the vectors, prepared // with [[mkvector]], are written to the file in order, and the total number of // bytes written is returned. export fn writev(fd: file, vectors: vector...) (size | error) = { if (len(vectors) > types::INT_MAX: size) { return errors::invalid; }; match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { case let err: rt::errno => return errors::errno(err); case let n: size => return n; }; }; hare-0.24.2/io/+test/000077500000000000000000000000001464473310100141625ustar00rootroot00000000000000hare-0.24.2/io/+test/limit_test.ha000066400000000000000000000016341464473310100166550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; @test fn limit() void = { let buf: [15z]u8 = [0...]; let source = teststream_open(); let rlimit = limitreader(&source, 20); match (write(&rlimit, buf)) { case errors::unsupported => void; case => abort(); }; match (read(&rlimit, buf)) { case let n: size => assert(n == 15); case error => abort(); }; match (read(&rlimit, buf)) { case let n: size => assert(n == 5); case error => abort(); }; assert(read(&rlimit, buf) is EOF); let wlimit = limitwriter(&source, 20); match (read(&wlimit, buf)) { case errors::unsupported => void; case => abort(); }; match (write(&wlimit, buf)) { case let n: size => assert(n == 15); case error => abort(); }; match (write(&wlimit, buf)) { case let n: size => assert(n == 5); case error => abort(); }; assert(write(&wlimit, buf) as size == 0z); }; hare-0.24.2/io/+test/stream_test.ha000066400000000000000000000017011464473310100170250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors const teststream_vtable: vtable = vtable { reader = &teststream_read, writer = &teststream_write, ... }; type teststream = struct { stream: stream, r: size, nreads: size, w: size, nwrites: size, }; fn teststream_open() teststream = teststream { stream = &teststream_vtable, ... }; fn teststream_read(s: *stream, buf: []u8) (size | EOF | error) = { let stream = s: *teststream; stream.r += len(buf); stream.nreads += 1; return len(buf); }; fn teststream_write(s: *stream, buf: const []u8) (size | error) = { let stream = s: *teststream; stream.w += len(buf); stream.nwrites += 1; return len(buf); }; fn teststream_write_short(s: *stream, buf: const []u8) (size | error) = { let stream = s: *teststream; stream.nwrites += 1; if (len(buf) > 10) { stream.w += len(buf) / 2; return len(buf) / 2; } else { stream.w += len(buf); return len(buf); }; }; hare-0.24.2/io/README000066400000000000000000000024141464473310100140110ustar00rootroot00000000000000The io module provides input and output (I/O) functionality for Hare programs, such as reading from or writing to files. The I/O module is not generally responsible for provisioning the I/O objects themselves; see modules like [[os::]] and [[net::]] for this purpose. I/O operations such as [[read]] or [[write]] accept an I/O handle, [[handle]], to specify the object of the I/O operation. This type is a tagged union of [[file]] and *[[stream]]. Most programmers should prefer to use [[handle]] unless they specifically require the special semantics of one of its subtypes. The [[file]] type provides access to an object, usually a file descriptor, which is provided by the host operating system. It represents objects such as a file on disk, an open network connection, and so on. The use of [[file]] is generally required when working with host I/O, such as with [[unix::poll::]]. The [[stream]] type is an abstraction that allows Hare programs to implement their own I/O objects by providing implementations of [[read]], [[write]], and other functions, for an [[handle]]. Several standard library modules offer implementations of [[stream]] for one reason or another, such as [[bufio::]]. Additionally, the io module provides some useful general-purpose I/O streams, such as [[tee]]. hare-0.24.2/io/arch+aarch64.ha000066400000000000000000000002061464473310100156010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An offset for a [[handle]]. export type off = i64; hare-0.24.2/io/arch+riscv64.ha000066400000000000000000000002061464473310100156510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An offset for a [[handle]]. export type off = i64; hare-0.24.2/io/arch+x86_64.ha000066400000000000000000000002061464473310100153070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An offset for a [[handle]]. export type off = i64; hare-0.24.2/io/copy.ha000066400000000000000000000025551464473310100144230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // Copies data from one handle into another. If reading from the source file // returns zero (underread), the copy is terminated and the amount of data // copied is returned. Note that this function will never return if the source // handle is infinite. export fn copy(dest: handle, src: handle) (size | error) = { match (dest) { case let fd: file => if (src is file) { match (fd_copy(fd, src as file)) { case let err: error => if (!(err is errors::unsupported)) { return err; }; // Use fallback case let z: size => return z; }; }; return copy_fallback(dest, src); case let st: *stream => if (!(src is *stream)) { return copy_fallback(dest, src); }; return copy_streams(st, src as *stream); }; }; fn copy_streams(dest: *stream, src: *stream) (size | error) = { match (dest.copier) { case null => void; case let c: *copier => match (c(dest, src)) { case let err: error => match (err) { case errors::unsupported => void; case => return err; }; case let s: size => return s; }; }; return copy_fallback(dest, src); }; fn copy_fallback(dest: handle, src: handle) (size | error) = { let w = 0z; let buf: [4096]u8 = [0...]; for (let n => read(src, buf[..])?) { w += writeall(dest, buf[..n])?; }; return w; }; hare-0.24.2/io/drain.ha000066400000000000000000000006471464473310100145460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Reads an entire stream into a []u8. The caller must free the return value. // Note that this function will never return if the handle is infinite. export fn drain(in: handle) ([]u8 | error) = { let sink: []u8 = []; static let buf: [4096]u8 = [0...]; for (let n => read(in, buf[..])?) { append(sink, buf[..n]...); }; return sink; }; hare-0.24.2/io/empty.ha000066400000000000000000000007001464473310100145750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors const _empty_vt: vtable = vtable { reader = &empty_read, writer = &empty_write, ... }; const _empty: stream = &_empty_vt; // A [[stream]] which always reads EOF and discards any writes. export const empty: *stream = &_empty; fn empty_read(s: *stream, buf: []u8) (size | EOF | error) = EOF; fn empty_write(s: *stream, buf: const []u8) (size | error) = len(buf); hare-0.24.2/io/file.ha000066400000000000000000000013371464473310100143650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Lock operation to use with [[lock]]. export type lockop = enum int { // shared file lock SHARED = rt::LOCK_SH, // exclusive file lock EXCLUSIVE = rt::LOCK_EX, // unlock file UNLOCK = rt::LOCK_UN, }; // Apply or remove an advisory lock on an open file. If block is true, the // request will block while waiting for the lock. export fn lock(fd: file, block: bool, op: lockop) (bool | error) = { let flags = op: int; if (!block) flags |= rt::LOCK_NB; return fd_lock(fd, flags); }; // Truncate a file to a specified length. The file must be open for writing. export fn trunc(fd: file, ln: size) (void | error) = fd_trunc(fd, ln); hare-0.24.2/io/handle.ha000066400000000000000000000043561464473310100147050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: Examine the ABI constraints of [[handle]]. Would it be better to make // stream an integer representing an internal handle into a stream table? This // would reduce performance for streams somewhat via the indirect lookup, but // improve the ABI performance for files. // An I/O handle is a resource which I/O operations may be performed on. It is // either a [[stream]], which is a userspace I/O abstraction, or a [[file]], // which is backed by a resource on the host OS, such as a file descriptor. export type handle = (file | *stream); // Reads up to len(buf) bytes from a [[handle]] into the given buffer, returning // the number of bytes read. export fn read(h: handle, buf: []u8) (size | EOF | error) = { match (h) { case let fd: file => return fd_read(fd, buf); case let st: *stream => return st_read(st, buf); }; }; // Writes up to len(buf) bytes to the [[handle]] from the given buffer, // returning the number of bytes written. export fn write(h: handle, buf: const []u8) (size | error) = { match (h) { case let fd: file => return fd_write(fd, buf); case let st: *stream => return st_write(st, buf); case => abort(); }; }; // Closes a [[handle]]. No further operations against this handle are permitted // after calling this function. Closing a file handle can fail only under // certain conditions (for example, closing a file twice, or an interrupted // syscall). However, the user should not attempt to close the file again on // failure - at best the user should print a diagnostic message and move on. See // close(2) for details. export fn close(h: handle) (void | error) = { match (h) { case let fd: file => fd_close(fd)?; case let st: *stream => st_close(st)?; }; }; // Sets the offset within a [[handle]], returning the new offset. The new offset // is obtained by adding [[off]] to the position specified by [[whence]]. export fn seek(h: handle, off: off, w: whence) (off | error) = { match (h) { case let fd: file => return fd_seek(fd, off, w); case let st: *stream => return st_seek(st, off, w); }; }; // Returns the current offset within a [[handle]]. export fn tell(h: handle) (off | error) = { return seek(h, 0, whence::CUR); }; hare-0.24.2/io/limit.ha000066400000000000000000000035471464473310100145710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type limitstream = struct { vtable: stream, source: handle, limit: size, }; const limit_vtable_reader: vtable = vtable { reader = &limit_read, ... }; const limit_vtable_writer: vtable = vtable { writer = &limit_write, ... }; // Create an overlay stream that only allows a limited amount of bytes to be // read from the underlying stream. This stream does not need to be closed, and // closing it does not close the underlying stream. Reading any data beyond the // given limit causes the reader to return [[EOF]]. export fn limitreader(source: handle, limit: size) limitstream = { return limitstream { vtable = &limit_vtable_reader, source = source, limit = limit, }; }; // Create an overlay stream that only allows a limited amount of bytes to be // written to the underlying stream. This stream does not need to be closed, and // closing it does not close the underlying stream. Writing beyond the given // limit causes the writer to return short writes (as few as zero bytes). export fn limitwriter(source: handle, limit: size) limitstream = { return limitstream { vtable = &limit_vtable_writer, source = source, limit = limit, }; }; fn limit_read(s: *stream, buf: []u8) (size | EOF | error) = { let stream = s: *limitstream; if (stream.limit == 0) { return EOF; }; if (len(buf) > stream.limit) { buf = buf[..stream.limit]; }; match (read(stream.source, buf)) { case EOF => return EOF; case let z: size => stream.limit -= z; return z; }; }; fn limit_write(s: *stream, buf: const []u8) (size | error) = { let stream = s: *limitstream; if (stream.limit == 0) { return 0z; }; let slice = if (len(buf) > stream.limit) { yield buf[..stream.limit]; } else { yield buf[..]; }; const z = write(stream.source, slice)?; stream.limit -= z; return z; }; hare-0.24.2/io/stream.ha000066400000000000000000000032331464473310100147360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // A stream is a pointer to a [[vtable]] which allows for user-defined I/O // abstractions to implement some subset of read, write, seek, close, and other // I/O functionality in userspace. Embed to create a custom stream type: // // export type my_stream = struct { // vtable: io::stream, // fd: int, // }; // // const my_vtable: io::vtable = io::vtable { // reader = &my_stream_read, // writer = &my_stream_write, // closer = null, // ... // }; // // export fn open(path: str) my_stream = { // let fd = // ... // return my_stream { // vtable = &my_vtable, // fd = fd, // ... // }); // }; // // let stream = open("example"); // io::read(&stream, buf)!; export type stream = *vtable; // The vtable type defines a set of virtual functions for a [[stream]]. export type vtable = struct { reader: nullable *reader, writer: nullable *writer, closer: nullable *closer, seeker: nullable *seeker, copier: nullable *copier, }; fn st_read(s: *stream, buf: []u8) (size | EOF | error) = { match (s.reader) { case null => return errors::unsupported; case let r: *reader => return r(s, buf); }; }; fn st_write(s: *stream, buf: const []u8) (size | error) = { match (s.writer) { case null => return errors::unsupported; case let w: *writer => return w(s, buf); }; }; fn st_close(s: *stream) (void | error) = { match (s.closer) { case null => void; case let c: *closer => c(s)?; }; }; fn st_seek(s: *stream, off: off, w: whence) (off | error) = { match (s.seeker) { case null => return errors::unsupported; case let sk: *seeker => return sk(s, off, w); }; }; hare-0.24.2/io/tee.ha000066400000000000000000000017121464473310100142200ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type teestream = struct { vtable: stream, h: handle, sink: handle, }; const tee_vtable: vtable = vtable { reader = &tee_read, writer = &tee_write, ... }; // Creates a stream which copies writes and reads into 'sink' after forwarding // them to the handle 'h'. This stream does not need to be closed, and closing // it will not close the secondary stream. export fn tee(h: handle, sink: handle) teestream = { return teestream { vtable = &tee_vtable, h = h, sink = sink, ... }; }; fn tee_read(s: *stream, buf: []u8) (size | EOF | error) = { let s = s: *teestream; let z = match (read(s.h, buf)?) { case EOF => return EOF; case let z: size => yield z; }; writeall(s.sink, buf[..z])?; return z; }; fn tee_write(s: *stream, buf: const []u8) (size | error) = { let s = s: *teestream; const z = write(s.h, buf)?; writeall(s.sink, buf[..z])?; return z; }; hare-0.24.2/io/types.ha000066400000000000000000000055161464473310100146150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // Returned by [[readall]] if the I/O handle returned [[EOF]] prior to // completely reading an item. Stores the amount that was succesfully read. export type underread = !size; // Any error which may be returned from an I/O function. export type error = !(...errors::error | underread); // Indicates an end-of-file condition. export type EOF = done; // Converts an I/O [[error]] into a user-friendly string. export fn strerror(err: error) str = { match (err) { case underread => return "Insufficient data to read entire item"; case let err: errors::error => return errors::strerror(err); }; }; // Used to indicate if a stream should be used for reading, or writing, or both. export type mode = enum u8 { NONE = 0, READ = 1 << 0, WRITE = 1 << 1, RDWR = READ | WRITE, }; // From "whence" a seek operation should occur. export type whence = enum { SET = 0, // Relative to beginning (i.e. set absolute position). CUR = 1, // Relative to current position. END = 2, // Relative to end of handle. }; // The interface for a stream which can be read from. Reads up to len(buf) // bytes from the reader into the given buffer, returning the number of bytes // read or an error. export type reader = fn(s: *stream, buf: []u8) (size | EOF | error); // The interface for a stream which can be written to. Writes up to len(buf) // bytes to the writer from the given buffer, returning the number of bytes // written or an error. export type writer = fn(s: *stream, buf: const []u8) (size | error); // The interface for a stream which can be closed. This function should close // and free any underlying resources, and cannot be used again. export type closer = fn(s: *stream) (void | error); // The interface for a stream which has first-class support for copying data // from another stream. Often this only works if the second stream is of the // same underlying stream type. This is optional, [[copy]] still works even with // a stream which does not implement this (it falls back to calling read and // write in a loop). // // Returns the number of bytes copied, or an error if one occured. Do not close // either stream. If the operation is unsupported for this particular pair of // streams, return [[errors::unsupported]] to have [[copy]] proceed with its // fallback implementation. export type copier = fn(to: *stream, from: *stream) (size | error); // The interface for a stream which can be seeked. Sets the offset for the next // read or write to offset, interpreted according to whence: // whence::SET means relative to the start of the file, // whence::CUR means relative to the current offset, and // whence::END means relative to the end. // // Returns the new offset relative to the start or an error. export type seeker = fn(s: *stream, off: off, w: whence) (off | error); hare-0.24.2/io/util.ha000066400000000000000000000021361464473310100144210ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Reads an entire buffer, perhaps issuing several [[read]] calls to do so. If // EOF is immediately encountered, it is returned; if [[EOF]] is encountered // partway through reading the buffer, [[underread]] is returned. export fn readall(in: handle, buf: []u8) (size | EOF | error) = { let z: size = 0; for (z < len(buf)) { match (read(in, buf[z..])?) { case EOF => if (z == 0) { return EOF; }; return z: underread: error; case let n: size => z += n; }; }; return z; }; // Writes an entire buffer, perhaps issuing several [[write]] calls to do so. // Aborts on errors after partial writes. Hence it should only be used if it is // certain that the underlying writes will not fail after an initial write. export fn writeall(out: handle, buf: const []u8) (size | error) = { let z: size = 0; for (z < len(buf)) { z += match (write(out, buf[z..])) { case let s: size => yield s; case let e: error => if (z == 0) { return e; }; abort("error after partial write"); }; }; return z; }; hare-0.24.2/io/zero.ha000066400000000000000000000006451464473310100144260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; const _zero_vt: vtable = vtable { reader = &zero_read, writer = &empty_write, ... }; const _zero: stream = &_zero_vt; // A [[stream]] which always reads zeroes and discards any writes. export const zero: *stream = &_zero; fn zero_read(s: *stream, buf: []u8) (size | EOF | error) = { bytes::zero(buf); return len(buf); }; hare-0.24.2/linux/000077500000000000000000000000001464473310100136605ustar00rootroot00000000000000hare-0.24.2/linux/+linux/000077500000000000000000000000001464473310100150725ustar00rootroot00000000000000hare-0.24.2/linux/+linux/README000066400000000000000000000001151464473310100157470ustar00rootroot00000000000000The linux module provides support for Linux-specific platform functionality. hare-0.24.2/linux/+linux/env.ha000066400000000000000000000003211464473310100161700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; // System V auxillary vector for the current process export let auxv: *[*]elf::auxv64 = null: *[*]elf::auxv64; hare-0.24.2/linux/+linux/start+libc.ha000066400000000000000000000003561464473310100174520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; use rt; @init fn init_linux() void = { let i = 0; for (rt::envp[i] != null) { i += 1; }; auxv = &rt::envp[i + 1]: *[*]elf::auxv64; }; hare-0.24.2/linux/+linux/start.ha000066400000000000000000000003561464473310100165450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; use rt; @init fn init_linux() void = { let i = 0; for (rt::envp[i] != null) { i += 1; }; auxv = &rt::envp[i + 1]: *[*]elf::auxv64; }; hare-0.24.2/linux/keyctl/000077500000000000000000000000001464473310100151535ustar00rootroot00000000000000hare-0.24.2/linux/keyctl/+linux/000077500000000000000000000000001464473310100163655ustar00rootroot00000000000000hare-0.24.2/linux/keyctl/+linux/README000066400000000000000000000003141464473310100172430ustar00rootroot00000000000000linux::keyctl provides an interface to the Linux kernel's key management facilities. Documentation for this module is sparse; the reader is encouraged to consult the Linux man pages for complete details. hare-0.24.2/linux/keyctl/+linux/keyctl.ha000066400000000000000000000054141464473310100201760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use types::c; fn errno(errno: rt::errno) error = { switch (errno) { case rt::ENOKEY => return nokey; case => return errors::errno(errno); }; }; // Adds a key to the kernel's key management facility. export fn add_key( keytype: str, name: str, payload: []u8, keyring: serial, ) (serial | error) = { const keytype = c::fromstr(keytype); defer free(keytype); const name = c::fromstr(name); defer free(name); match (rt::add_key(keytype: *const u8, name: *const u8, payload: *[*]u8: *opaque, len(payload), keyring)) { case let err: rt::errno => return errno(err); case let n: int => return n: serial; }; }; fn keyctl( cmd: command, arg2: u64, arg3: u64, arg4: u64, arg5: u64, ) (int | error) = { match (rt::keyctl(cmd, arg2, arg3, arg4, arg5)) { case let err: rt::errno => return errno(err); case let n: int => return n; }; }; // Maps a special key or keyring ID to the serial number of the key actually // representing that feature. If it does not exist and 'create' is true, then // the key or keyring will be created if it is appropriate to do so. export fn get_keyring_id(key: serial, create: bool) (serial | error) = { return keyctl(command::GET_KEYRING_ID, key: u64, if (create) 1 else 0, 0, 0)?: serial; }; // Replace the session keyring this process subscribes to with a new session // keyring using the given name, or, given an empty string, "_ses". export fn join_session_keyring(name: str) (serial | error) = { let name = if (name == "") { yield null; } else { yield c::fromstr(name); }; defer free(name); return keyctl(command::JOIN_SESSION_KEYRING, name: uintptr: u64, 0, 0, 0)?: serial; }; // Update a key's payload. export fn update(id: serial, payload: []u8) (void | error) = { keyctl(command::UPDATE, id: u64, payload: *[*]u8: uintptr: u64, len(payload): u64, 0)?; }; // Revoke the key with the provided ID. export fn revoke(id: serial) (void | error) = { keyctl(command::REVOKE, id: u64, 0, 0, 0)?; }; // Reads the payload from a key, returning the size of the key data. The // provided buffer may be empty to probe the key size without reading. export fn read(id: serial, buf: []u8) (size | error) = { const bufln = len(buf); const buf = if (len(buf) == 0) { yield null; } else { yield buf: *[*]u8: *opaque; }; return keyctl(command::READ, id: u64, buf: uintptr: u64, bufln: u64, 0)?: size; }; // Changes the user and group ownership of the key. export fn chown(id: serial, uid: uint, gid: uint) (void | error) = { keyctl(command::CHOWN, id: u64, uid: u64, gid: u64, 0)?; }; // Changes the permissions mask of the key. export fn setperm(id: serial, perm: perm) (void | error) = { keyctl(command::SETPERM, id: u64, perm, 0, 0)?; }; hare-0.24.2/linux/keyctl/+linux/types.ha000066400000000000000000000075141464473310100200520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use types::c; // A key ID. export type serial = i32; // Returned when a desired key was not found. export type nokey = !void; // A tagged union of all possible error types. export type error = !(nokey | errors::error); // The caller's thread-specific keyring. export def THREAD_KEYRING: serial = -1; // The caller's process-specific keyring. export def PROCESS_KEYRING: serial = -2; // The caller's session-specific keyring. export def SESSION_KEYRING: serial = -3; // The caller's UID-specific keyring. export def USER_KEYRING: serial = -4; // The caller's UID-session keyring. export def USER_SESSION_KEYRING: serial = -5; // The caller's GID-specific keyring. export def GROUP_KEYRING: serial = -6; // The caller's GID-session keyring. export def REQKEY_AUTH_KEY: serial = -7; // The Key ID for the [[reqkey]] destination keyring. export def REQUESTOR_KEYRING: serial = -8; // request-key default keyrings export type reqkey = enum int { NO_CHANGE = -1, DEFAULT = 0, THREAD_KEYRING = 1, PROCESS_KEYRING = 2, SESSION_KEYRING = 3, USER_KEYRING = 4, USER_SESSION_KEYRING = 5, GROUP_KEYRING = 6, REQUESTOR_KEYRING = 7, }; // keyctl commands export type command = enum int { GET_KEYRING_ID = 0, JOIN_SESSION_KEYRING = 1, UPDATE = 2, REVOKE = 3, CHOWN = 4, SETPERM = 5, DESCRIBE = 6, CLEAR = 7, LINK = 8, UNLINK = 9, SEARCH = 10, READ = 11, INSTANTIATE = 12, NEGATE = 13, SET_REQKEY_KEYRING = 14, SET_TIMEOUT = 15, ASSUME_AUTHORITY = 16, GET_SECURITY = 17, SESSION_TO_PARENT = 18, REJECT = 19, INSTANTIATE_IOV = 20, INVALIDATE = 21, GET_PERSISTENT = 22, DH_COMPUTE = 23, PKEY_QUERY = 24, PKEY_ENCRYPT = 25, PKEY_DECRYPT = 26, PKEY_SIGN = 27, PKEY_VERIFY = 28, RESTRICT_KEYRING = 29, MOVE = 30, CAPABILITIES = 31, WATCH_KEY = 32, }; // Input for [[command::DH_COMPUTE]] export type dh_params = struct { private: i32, prime: i32, base: i32, }; // Output for [[command::DH_COMPUTE]] export type kdf_params = struct { hashname: *c::char, otherinfo: *c::char, otherinfolen: u32, __spare: [8]u32, }; export type support = enum u32 { SUPPORTS_ENCRYPT = 0x01, SUPPORTS_DECRYPT = 0x02, SUPPORTS_SIGN = 0x04, SUPPORTS_VERIFY = 0x08, }; export type pkey_query = struct { supported_ops: u32, key_size: u32, max_data_size: u16, max_sig_size: u16, max_enc_size: u16, max_dec_size: u16, __spare: [10]u32, }; export type pkey_params = struct { key_id: i32, in_len: u32, union { out_len: u32, in2_len: u32, }, __spare: [7]u32, }; export type caps = enum u8 { CAPS0_CAPABILITIES = 0x01, CAPS0_PERSISTENT_KEYRINGS = 0x02, CAPS0_DIFFIE_HELLMAN = 0x04, CAPS0_PUBLIC_KEY = 0x08, CAPS0_BIG_KEY = 0x10, CAPS0_INVALIDATE = 0x20, CAPS0_RESTRICT_KEYRING = 0x40, CAPS0_MOVE = 0x80, CAPS1_NS_KEYRING_NAME = 0x01, CAPS1_NS_KEY_TAG = 0x02, CAPS1_NOTIFICATIONS = 0x04, }; export type perm = enum u32 { KEY_OTH_VIEW = 0x01, KEY_OTH_READ = 0x02, KEY_OTH_WRITE = 0x04, KEY_OTH_SEARCH = 0x08, KEY_OTH_LINK = 0x10, KEY_OTH_SETATTR = 0x20, KEY_OTH_ALL = 0x3f, KEY_GRP_VIEW = 0x0100, KEY_GRP_READ = 0x0200, KEY_GRP_WRITE = 0x0400, KEY_GRP_SEARCH = 0x0800, KEY_GRP_LINK = 0x1000, KEY_GRP_SETATTR = 0x2000, KEY_GRP_ALL = 0x3f00, KEY_USR_VIEW = 0x010000, KEY_USR_READ = 0x020000, KEY_USR_WRITE = 0x040000, KEY_USR_SEARCH = 0x080000, KEY_USR_LINK = 0x100000, KEY_USR_SETATTR = 0x200000, KEY_USR_ALL = 0x3f0000, KEY_POS_VIEW = 0x01000000, KEY_POS_READ = 0x02000000, KEY_POS_WRITE = 0x04000000, KEY_POS_SEARCH = 0x08000000, KEY_POS_LINK = 0x10000000, KEY_POS_SETATTR = 0x20000000, KEY_POS_ALL = 0x3f000000, }; // Converts an [[error]] into a human-friendly string. export fn strerror(err: error) const str = match (err) { case nokey => return "A desired key was not found"; case let err: errors::error => return errors::strerror(err); }; hare-0.24.2/linux/timerfd/000077500000000000000000000000001464473310100153125ustar00rootroot00000000000000hare-0.24.2/linux/timerfd/+linux/000077500000000000000000000000001464473310100165245ustar00rootroot00000000000000hare-0.24.2/linux/timerfd/+linux/README000066400000000000000000000001671464473310100174100ustar00rootroot00000000000000This module provides support for Linux's timerfd interface. For details, consult the Linux man page timerfd_create(2). hare-0.24.2/linux/timerfd/+linux/timerfd.ha000066400000000000000000000077261464473310100205040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use errors; use io; use rt; use time; // The timer will trigger only once, after the set duration and never after. export type oneshot = time::duration; // The timer will trigger once after a configured delay, then periodically at // the given interval. export type interval_delayed = (time::duration, time::duration); // The timer will trigger periodically at the given interval. export type interval = time::duration; // The expiration configuration for the timer. export type expiration = (oneshot | interval | interval_delayed); const empty_timerspec: rt::itimerspec = rt::itimerspec { it_interval = rt::timespec { tv_sec = 0, tv_nsec = 0 }, it_value = rt::timespec { tv_sec = 0, tv_nsec = 0 }, }; // Flags to use in [[new]]. CLOEXEC is enabled by default, use NOCLOEXEC to // disable it. export type new_flag = enum int { NONE = 0, NONBLOCK = rt::O_NONBLOCK, NOCLOEXEC = rt::O_CLOEXEC, }; // Flags to use in [[set]]. export type set_flag = enum int { NONE = 0, ABSTIME = 1, CANCEL_ON_SET = 2, }; // Creates a new timerfd. The timer is initially configured without an // expiration; see [[set]] to configure it. export fn new( clockid: time::clock, flags: new_flag, ) (io::file | errors::error) = { flags ^= new_flag::NOCLOEXEC; match (rt::timerfd_create(clockid, flags)) { case let fd: int => return fd; case let err: rt::errno => return errors::errno(err); }; }; // Sets the expiration configuration for a timerfd, overwriting any // previously set expiration. export fn set( t: io::file, exp: expiration, flags: set_flag, ) (void | errors::error) = { const timerspec = match (exp) { case let o: oneshot => yield rt::itimerspec { it_interval = rt::timespec { tv_sec = 0, tv_nsec = 0 }, it_value = time::duration_to_timespec(o), }; case let i: interval => const interval_timespec = time::duration_to_timespec(i); yield rt::itimerspec { it_interval = interval_timespec, it_value = interval_timespec, }; case let id: interval_delayed => yield rt::itimerspec { it_interval = time::duration_to_timespec(id.0), it_value = time::duration_to_timespec(id.1), }; }; match (rt::timerfd_settime(t, flags, &timerspec, null)) { case let ok: int => return; case let err: rt::errno => return errors::errno(err); }; }; // Unsets any expiration that was previously set on the given timer. export fn unset( t: io::file, ) (void | errors::error) = { match (rt::timerfd_settime(t, 0, &empty_timerspec, null)) { case int => return; case let err: rt::errno => return errors::errno(err); }; }; // Reading from the timerfd returns the number of times the timer has expired // since the last call to [[set]] or [[read]]. This call can be blocking or not // depending on the flags passed to [[new]]. Reading from a blocking unset // timerfd will block forever. export fn read( t: io::file ) (u64 | errors::error) = { let expirations: [8]u8 = [0...]; match (rt::read(t, &expirations, len(expirations))) { case let err: rt::errno => return errors::errno(err); case let z: size => assert(z == len(expirations)); }; return endian::host.getu64(expirations); }; @test fn timerfd() void = { let blocking_fd = new(time::clock::MONOTONIC, new_flag::NONE)!; // one-shot blocking // the first read should block and eventually return 1 // subsequent reads will block indefinitely set(blocking_fd, 100: oneshot, set_flag::NONE)!; let one = read(blocking_fd)!; assert(one == 1); // interval blocking // the first read should block and eventually return the number of times // the timer expired // subsequent reads should return instantly with the number of times the // timer expired since the last read set(blocking_fd, 100: interval, set_flag::NONE)!; let first = read(blocking_fd)!; let second = read(blocking_fd)!; assert(first > 0); assert(second > 0); // unset blocking timer // reading here would block us forever unset(blocking_fd)!; io::close(blocking_fd)!; }; hare-0.24.2/linux/vdso/000077500000000000000000000000001464473310100146335ustar00rootroot00000000000000hare-0.24.2/linux/vdso/+linux/000077500000000000000000000000001464473310100160455ustar00rootroot00000000000000hare-0.24.2/linux/vdso/+linux/vdso.ha000066400000000000000000000105111464473310100173300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use format::elf; use linux; use types::c; let ehdr: nullable *elf::header64 = null; fn sys_infoehdr() nullable *elf::header64 = { static let ehdr_checked = false; if (ehdr_checked) { return ehdr; }; ehdr_checked = true; for (let i = 0; linux::auxv[i].a_type != 0; i += 1) { if (linux::auxv[i].a_type != elf::at::SYSINFO_EHDR) continue; ehdr = linux::auxv[i].a_val: uintptr: *elf::header64; return ehdr; }; return null; }; type vdso_ctx = struct { segbase: uintptr, stringtab: *c::char, symtab: *[*]elf::sym64, hashhdr: *elf::hashhdr, versym: nullable *[*]u16, verdef: nullable *elf::verdef64, }; let ctx: nullable *vdso_ctx = null; fn get_vdso_ctx() nullable *vdso_ctx = { static let vdso_checked = false; if (vdso_checked) { return ctx; }; vdso_checked = true; const eh = match (sys_infoehdr()) { case null => return null; case let x: *elf::header64 => yield x; }; const ehui = eh: uintptr; let phui = ehui + eh.e_phoff: uintptr; let dynvec: nullable *[*]elf::dyn64 = null; let baseseg: nullable *opaque = null; for (let i: u16 = 0; i < eh.e_phnum; i += 1) { const ph = phui: *elf::phdr64; switch (ph.p_type) { case elf::pt::LOAD => baseseg = (ehui + ph.p_offset: uintptr - ph.p_vaddr: uintptr): nullable *opaque; case elf::pt::DYNAMIC => dynvec = (ehui + ph.p_offset: uintptr): *[*]elf::dyn64; case => void; }; phui += eh.e_phentsize: uintptr; }; if (dynvec == null || baseseg == null) { return null; }; const dynv = dynvec: *[*]elf::dyn64; let segbase = baseseg: uintptr; let stringtab: nullable *c::char = null; let symtab: nullable *[*]elf::sym64 = null; let hashhdr: nullable *elf::hashhdr = null; let versym: nullable *[*]u16 = null; let verdef: nullable *elf::verdef64 = null; for (let i = 0; dynv[i].d_tag != elf::dt::NULL; i += 1) { const tabptr = (segbase + dynv[i].d_val: uintptr): *opaque; switch (dynv[i].d_tag) { case elf::dt::STRTAB => stringtab = tabptr: *c::char; case elf::dt::SYMTAB => symtab = tabptr: *[*]elf::sym64; case elf::dt::HASH => hashhdr = tabptr: *elf::hashhdr; case elf::dt::VERSYM => versym = tabptr: *[*]u16; case elf::dt::VERDEF => verdef = tabptr: *elf::verdef64; case => continue; }; }; if (stringtab == null || symtab == null || hashhdr == null) { return null; }; if (verdef == null) { versym = null; }; // TODO: use a static variable here somehow(?) const vctx = alloc(vdso_ctx { segbase = segbase, stringtab = stringtab: *c::char, symtab = symtab: *[*]elf::sym64, hashhdr = hashhdr: *elf::hashhdr, verdef = verdef, versym = versym, }); ctx = vctx; return ctx; }; fn vdso_checkver(ctx: *vdso_ctx, version: str, num: u32) bool = { let prev = null: *elf::verdef64; let cur = match (ctx.verdef) { case null => return true; case let vd: *elf::verdef64 => yield vd; }; const versym = match (ctx.versym) { case null => return true; case let vs: *[*]u16 => yield vs[num] & 0x7ff; }; for (cur != prev) { if (cur.vd_flags & elf::ver_flg::BASE: u16 == 0 && cur.vd_ndx & 0x7fff == versym) { const aux = (cur: uintptr + cur.vd_aux: uintptr): *elf::verdaux64; const name = ctx.stringtab: uintptr + aux.vda_name: uintptr; return version == c::tostr(name: *c::char)!; }; prev = cur; cur = (cur: uintptr + cur.vd_next: uintptr): *elf::verdef64; }; return false; }; export fn getsym(symname: str, symver: str) nullable *opaque = { const ctx = match (get_vdso_ctx()) { case null => return null; case let x: *vdso_ctx => yield x; }; const sym_types = (1 << elf::stt::NOTYPE | 1 << elf::stt::OBJECT | 1 << elf::stt::FUNC | 1 << elf::stt::COMMON): size; const sym_binds = (1 << elf::stb::GLOBAL | 1 << elf::stb::WEAK): size; for (let i = 0u32; i < ctx.hashhdr.nchain; i += 1) { const sym = ctx.symtab[i]; const symtype = 1 << (sym.st_info & 0xf): size; const symbind = 1 << (sym.st_info >> 4): size; if (symtype & sym_types == 0 || symbind & sym_binds == 0 || sym.st_shndx == 0) { continue; }; const name = ctx.stringtab: uintptr + sym.st_name: uintptr; const s: str = c::tostr(name: *const c::char)!; if (s != symname) continue; if (!vdso_checkver(ctx, symver, i)) continue; return (ctx.segbase + sym.st_value: uintptr): *opaque; }; return null; }; hare-0.24.2/log/000077500000000000000000000000001464473310100133025ustar00rootroot00000000000000hare-0.24.2/log/README000066400000000000000000000010211464473310100141540ustar00rootroot00000000000000The log module provides a simple interface for application logging. The [[logger]] interface provides an abstraction that users may implement for custom logging logic. We provide a simple logger implementation that prefixes each line with the current timestamp; to initialize such a logger see [[new]]. A global logger is also provided for simple applications to use, [[global]], which is an instance of the standard logger that writes to [[os::stderr]] by default. The user may configure a new global logger via [[setlogger]]. hare-0.24.2/log/funcs.ha000066400000000000000000000027531464473310100147410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use os; // Prints data to the log, with a newline. export fn lprintln(log: *logger, fields: fmt::formattable...) void = { log.println(log, fields...); }; // Formats and prints data to the log, with a newline. export fn lprintfln(log: *logger, fmt: str, fields: fmt::field...) void = { log.printfln(log, fmt, fields...); }; // Prints data to the global log, with a newline. export fn println(fields: fmt::formattable...) void = { lprintln(global, fields...); }; // Formats and prints data to the global log, with a newline. export fn printfln(fmt: str, fields: fmt::field...) void = { lprintfln(global, fmt, fields...); }; // Prints data to the log with a newline, then terminates the process. export fn lfatal(log: *logger, fields: fmt::formattable...) never = { lprintln(log, fields...); os::exit(255); }; // Formats and prints data to the log with new line, then terminates the // process. export fn lfatalf( log: *logger, fmt: str, fields: fmt::field... ) never = { lprintfln(log, fmt, fields...); os::exit(255); }; // Prints data to the global log with new line, then terminates the process. export fn fatal(fields: fmt::formattable...) never = { lprintln(global, fields...); os::exit(255); }; // Formats and prints data to the global log with new line, then terminates the // process. export fn fatalf(fmt: str, fields: fmt::field...) never = { lprintfln(global, fmt, fields...); os::exit(255); }; hare-0.24.2/log/global.ha000066400000000000000000000011321464473310100150510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use os; // The global logger instance. export let global: *logger = &_default; // Default logger that writes to [[os::stderr]]. export const default: *logger = &_default; let _default: stdlogger = stdlogger { println = &log_println, printfln = &log_printfln, sink = -1: io::file, }; @init fn init() void = { // XXX: Would be nice not to have to do this _default.sink = os::stderr; }; // Sets the global logger instance to the provided logger. export fn setlogger(log: *logger) void = { global = log; }; hare-0.24.2/log/logger.ha000066400000000000000000000023571464473310100151020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use io; use time::date; // Interface for implementing a logger. export type logger = struct { println: *fn(logger: *logger, fields: fmt::formattable...) void, printfln: *fn(logger: *logger, fmt: str, fields: fmt::field...) void, }; export type stdlogger = struct { logger, sink: io::handle, }; // Creates a new standard logger. export fn new(sink: io::handle) stdlogger = { return stdlogger { println = &log_println, printfln = &log_printfln, sink = sink, }; }; fn log_println(sink: *logger, fields: fmt::formattable...) void = { const sink = sink: *stdlogger; assert(sink.println == &log_println); const now = date::localnow(); fmt::fprint(sink.sink, "["): void; date::format(sink.sink, date::STAMP, &now): void; fmt::fprint(sink.sink, "] "): void; fmt::fprintln(sink.sink, fields...): void; }; fn log_printfln(sink: *logger, fmt: str, fields: fmt::field...) void = { const sink = sink: *stdlogger; assert(sink.printfln == &log_printfln); const now = date::localnow(); fmt::fprint(sink.sink, "["): void; date::format(sink.sink, date::STAMP, &now): void; fmt::fprint(sink.sink, "] "): void; fmt::fprintfln(sink.sink, fmt, fields...): void; }; hare-0.24.2/log/silent.ha000066400000000000000000000006501464473310100151130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; // A logger that does not print any messages. export const silent: *logger = &_silent; let _silent: logger = logger { println = &silent_println, printfln = &silent_printfln, }; fn silent_println(l: *logger, fields: fmt::formattable...) void = return; fn silent_printfln(l: *logger, fmt: str, fields: fmt::field...) void = return; hare-0.24.2/makefiles/000077500000000000000000000000001464473310100144615ustar00rootroot00000000000000hare-0.24.2/makefiles/freebsd.aarch64.mk000066400000000000000000000513661464473310100176660ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+freebsd/start+aarch64-libc.s rt/+freebsd/syscall+aarch64.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+freebsd/dup.ha io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pgid.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/freebsd.riscv64.mk000066400000000000000000000513661464473310100177360ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+riscv64-libc.s rt/+freebsd/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+freebsd/dup.ha io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pgid.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/freebsd.x86_64.mk000066400000000000000000000513501464473310100173650ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+x86_64-libc.s rt/+freebsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+freebsd/dup.ha io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pgid.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/linux.aarch64.mk000066400000000000000000000536251464473310100174130ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+linux/restore+aarch64.s rt/+linux/start+aarch64-libc.s rt/+linux/syscall+aarch64.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+linux/dup.ha io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) format_elf_ha = format/elf/arch+aarch64.ha format/elf/platform+linux.ha format/elf/types.ha $(HARECACHE)/format_elf.ssa: $(format_elf_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha) linux_ha = linux/+linux/env.ha linux/+linux/start.ha $(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha) types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) linux_vdso_ha = linux/vdso/+linux/vdso.ha $(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha) time_ha = time/+linux/+aarch64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pgid.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/linux.riscv64.mk000066400000000000000000000536251464473310100174630ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+linux/restore+riscv64.s rt/+linux/start+riscv64-libc.s rt/+linux/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+linux/dup.ha io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) format_elf_ha = format/elf/arch+riscv64.ha format/elf/platform+linux.ha format/elf/types.ha $(HARECACHE)/format_elf.ssa: $(format_elf_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha) linux_ha = linux/+linux/env.ha linux/+linux/start.ha $(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha) types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) linux_vdso_ha = linux/vdso/+linux/vdso.ha $(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha) time_ha = time/+linux/+riscv64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pgid.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/linux.x86_64.mk000066400000000000000000000536031464473310100171150ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+linux/restore+x86_64.s rt/+linux/start+x86_64-libc.s rt/+linux/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+linux/dup.ha io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) format_elf_ha = format/elf/arch+x86_64.ha format/elf/platform+linux.ha format/elf/types.ha $(HARECACHE)/format_elf.ssa: $(format_elf_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha) linux_ha = linux/+linux/env.ha linux/+linux/start.ha $(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha) types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) linux_vdso_ha = linux/vdso/+linux/vdso.ha $(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha) time_ha = time/+linux/+x86_64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pgid.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/netbsd.aarch64.mk000066400000000000000000000512371464473310100175300ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/shm.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+netbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/netbsd.riscv64.mk000066400000000000000000000512371464473310100176000ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/shm.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+netbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/netbsd.x86_64.mk000066400000000000000000000513451464473310100172360ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+netbsd/start+x86_64-libc.s rt/+netbsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/shm.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+netbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/time.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/openbsd.aarch64.mk000066400000000000000000000512051464473310100176760ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+openbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+openbsd/+aarch64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+openbsd/start.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+openbsd/dup.ha io/+openbsd/mmap.ha io/+openbsd/platform_file.ha io/+openbsd/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+openbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+openbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+openbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+openbsd/exec.ha os/exec/+openbsd/platform_cmd.ha os/exec/+openbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+openbsd/isatty.ha unix/tty/+openbsd/open.ha unix/tty/+openbsd/pgid.ha unix/tty/+openbsd/pty.ha unix/tty/+openbsd/termios.ha unix/tty/+openbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -N "" -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/openbsd.riscv64.mk000066400000000000000000000512051464473310100177460ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+openbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+openbsd/+riscv64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+openbsd/dup.ha io/+openbsd/mmap.ha io/+openbsd/platform_file.ha io/+openbsd/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+openbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+openbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+openbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+openbsd/exec.ha os/exec/+openbsd/platform_cmd.ha os/exec/+openbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+openbsd/isatty.ha unix/tty/+openbsd/open.ha unix/tty/+openbsd/pgid.ha unix/tty/+openbsd/pty.ha unix/tty/+openbsd/termios.ha unix/tty/+openbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -N "" -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/makefiles/openbsd.x86_64.mk000066400000000000000000000511711464473310100174060ustar00rootroot00000000000000# generated by cmd/genbootstrap # DO NOT EDIT BY HAND. run 'make bootstrap' to update TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td RTSCRIPT = rt/+openbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o rt_ha = rt/+openbsd/+x86_64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s $(HARECACHE)/rt.o: $(rt_s) @printf 'AS\t%s\n' "$@" @$(AS) $(ASFLAGS) -o $@ $(rt_s) encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha $(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) sort_cmp_ha = sort/cmp/cmp.ha $(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha $(HARECACHE)/types.ssa: $(types_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha $(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha $(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha $(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha $(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) io_ha = io/+openbsd/dup.ha io/+openbsd/mmap.ha io/+openbsd/platform_file.ha io/+openbsd/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha $(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) bufio_ha = bufio/scanner.ha bufio/stream.ha $(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha $(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha $(HARECACHE)/endian.ssa: $(endian_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) hash_ha = hash/hash.ha $(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) crypto_sha256_ha = crypto/sha256/sha256.ha $(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha $(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) memio_ha = memio/ops.ha memio/stream.ha $(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) path_ha = path/+openbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha $(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) time_ha = time/+openbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha $(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/errors.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) fs_ha = fs/fs.ha fs/types.ha fs/util.ha $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha $(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha $(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha $(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) encoding_hex_ha = encoding/hex/hex.ha $(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha $(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha $(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha $(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha $(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha $(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) time_chrono_ha = time/chrono/+openbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha $(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha $(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) os_exec_ha = os/exec/+openbsd/exec.ha os/exec/+openbsd/platform_cmd.ha os/exec/+openbsd/process.ha os/exec/cmd.ha os/exec/types.ha $(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) shlex_ha = shlex/escape.ha shlex/split.ha $(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) unix_tty_ha = unix/tty/+openbsd/isatty.ha unix/tty/+openbsd/open.ha unix/tty/+openbsd/pgid.ha unix/tty/+openbsd/pty.ha unix/tty/+openbsd/termios.ha unix/tty/+openbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha $(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha $(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) dirs_ha = dirs/xdg.ha $(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) getopt_ha = getopt/getopts.ha $(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha $(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -N "" -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) hare-0.24.2/math/000077500000000000000000000000001464473310100134525ustar00rootroot00000000000000hare-0.24.2/math/+test/000077500000000000000000000000001464473310100145045ustar00rootroot00000000000000hare-0.24.2/math/+test/data.ha000066400000000000000000000331641464473310100157360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The test data below is based on Go's implementation, and came with the // following note and copyright notice: // // The expected results below were computed by the high precision calculators // at https://keisan.casio.com/. More exact input values (array vf[], above) // were obtained by printing them with "%.26f". The answers were calculated // to 26 digits (by using the "Digit number" drop-down control of each // calculator). // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== const TEST_INPUTS: [_]f64 = [ 4.9790119248836735e+00, 7.7388724745781045e+00, -2.7688005719200159e-01, -5.0106036182710749e+00, 9.6362937071984173e+00, 2.9263772392439646e+00, 5.2290834314593066e+00, 2.7279399104360102e+00, 1.8253080916808550e+00, -8.6859247685756013e+00, ]; const TEST_ACOS: [_]f64 = [ 1.0496193546107222142571536e+00, 6.8584012813664425171660692e-01, 1.5984878714577160325521819e+00, 2.0956199361475859327461799e+00, 2.7053008467824138592616927e-01, 1.2738121680361776018155625e+00, 1.0205369421140629186287407e+00, 1.2945003481781246062157835e+00, 1.3872364345374451433846657e+00, 2.6231510803970463967294145e+00, ]; const TEST_ACOSH: [_]f64 = [ 2.4743347004159012494457618e+00, 2.8576385344292769649802701e+00, 7.2796961502981066190593175e-01, 2.4796794418831451156471977e+00, 3.0552020742306061857212962e+00, 2.044238592688586588942468e+00, 2.5158701513104513595766636e+00, 1.99050839282411638174299e+00, 1.6988625798424034227205445e+00, 2.9611454842470387925531875e+00, ]; const TEST_ASIN: [_]f64 = [ 5.2117697218417440497416805e-01, 8.8495619865825236751471477e-01, -2.769154466281941332086016e-02, -5.2482360935268931351485822e-01, 1.3002662421166552333051524e+00, 2.9698415875871901741575922e-01, 5.5025938468083370060258102e-01, 2.7629597861677201301553823e-01, 1.83559892257451475846656e-01, -1.0523547536021497774980928e+00, ]; const TEST_ASINH: [_]f64 = [ 2.3083139124923523427628243e+00, 2.743551594301593620039021e+00, -2.7345908534880091229413487e-01, -2.3145157644718338650499085e+00, 2.9613652154015058521951083e+00, 1.7949041616585821933067568e+00, 2.3564032905983506405561554e+00, 1.7287118790768438878045346e+00, 1.3626658083714826013073193e+00, -2.8581483626513914445234004e+00, ]; const TEST_ATAN: [_]f64 = [ 1.372590262129621651920085e+00, 1.442290609645298083020664e+00, -2.7011324359471758245192595e-01, -1.3738077684543379452781531e+00, 1.4673921193587666049154681e+00, 1.2415173565870168649117764e+00, 1.3818396865615168979966498e+00, 1.2194305844639670701091426e+00, 1.0696031952318783760193244e+00, -1.4561721938838084990898679e+00, ]; const TEST_ATAN2: [_]f64 = [ 1.1088291730037004444527075e+00, 9.1218183188715804018797795e-01, 1.5984772603216203736068915e+00, 2.0352918654092086637227327e+00, 8.0391819139044720267356014e-01, 1.2861075249894661588866752e+00, 1.0889904479131695712182587e+00, 1.3044821793397925293797357e+00, 1.3902530903455392306872261e+00, 2.2859857424479142655411058e+00, ]; const TEST_ATANH: [_]f64 = [ 5.4651163712251938116878204e-01, 1.0299474112843111224914709e+00, -2.7695084420740135145234906e-02, -5.5072096119207195480202529e-01, 1.9943940993171843235906642e+00, 3.01448604578089708203017e-01, 5.8033427206942188834370595e-01, 2.7987997499441511013958297e-01, 1.8459947964298794318714228e-01, -1.3273186910532645867272502e+00, ]; const TEST_CEIL: [_]f64 = [ 5.0000000000000000e+00, 8.0000000000000000e+00, -0.0000000000000000e+00, -5.0000000000000000e+00, 1.0000000000000000e+01, 3.0000000000000000e+00, 6.0000000000000000e+00, 3.0000000000000000e+00, 2.0000000000000000e+00, -8.0000000000000000e+00, ]; const TEST_COS: [_]f64 = [ 2.634752140995199110787593e-01, 1.148551260848219865642039e-01, 9.6191297325640768154550453e-01, 2.938141150061714816890637e-01, -9.777138189897924126294461e-01, -9.7693041344303219127199518e-01, 4.940088096948647263961162e-01, -9.1565869021018925545016502e-01, -2.517729313893103197176091e-01, -7.39241351595676573201918e-01, ]; // Results for 100000 * PI + TEST_INPUTS[i] const TEST_COSLARGE: [_]f64 = [ 2.634752141185559426744e-01, 1.14855126055543100712e-01, 9.61912973266488928113e-01, 2.9381411499556122552e-01, -9.777138189880161924641e-01, -9.76930413445147608049e-01, 4.940088097314976789841e-01, -9.15658690217517835002e-01, -2.51772931436786954751e-01, -7.3924135157173099849e-01, ]; const TEST_COSH: [_]f64 = [ 7.2668796942212842775517446e+01, 1.1479413465659254502011135e+03, 1.0385767908766418550935495e+00, 7.5000957789658051428857788e+01, 7.655246669605357888468613e+03, 9.3567491758321272072888257e+00, 9.331351599270605471131735e+01, 7.6833430994624643209296404e+00, 3.1829371625150718153881164e+00, 2.9595059261916188501640911e+03, ]; const TEST_EXP: [_]f64 = [ 1.4533071302642137507696589e+02, 2.2958822575694449002537581e+03, 7.5814542574851666582042306e-01, 6.6668778421791005061482264e-03, 1.5310493273896033740861206e+04, 1.8659907517999328638667732e+01, 1.8662167355098714543942057e+02, 1.5301332413189378961665788e+01, 6.2047063430646876349125085e+00, 1.6894712385826521111610438e-04, ]; const TEST_EXP2: [_]f64 = [ 3.1537839463286288034313104e+01, 2.1361549283756232296144849e+02, 8.2537402562185562902577219e-01, 3.1021158628740294833424229e-02, 7.9581744110252191462569661e+02, 7.6019905892596359262696423e+00, 3.7506882048388096973183084e+01, 6.6250893439173561733216375e+00, 3.5438267900243941544605339e+00, 2.4281533133513300984289196e-03, ]; const TEST_ABSF: [_]f64 = [ 4.9790119248836735e+00, 7.7388724745781045e+00, 2.7688005719200159e-01, 5.0106036182710749e+00, 9.6362937071984173e+00, 2.9263772392439646e+00, 5.2290834314593066e+00, 2.7279399104360102e+00, 1.8253080916808550e+00, 8.6859247685756013e+00, ]; const TEST_FLOOR: [_]f64 = [ 4.0000000000000000e+00, 7.0000000000000000e+00, -1.0000000000000000e+00, -6.0000000000000000e+00, 9.0000000000000000e+00, 2.0000000000000000e+00, 5.0000000000000000e+00, 2.0000000000000000e+00, 1.0000000000000000e+00, -9.0000000000000000e+00, ]; const TEST_MODF: [_]f64 = [ 4.197615023265299782906368e-02, 2.261127525421895434476482e+00, 3.231794108794261433104108e-02, 4.989396381728925078391512e+00, 3.637062928015826201999516e-01, 1.220868282268106064236690e+00, 4.770916568540693347699744e+00, 1.816180268691969246219742e+00, 8.734595415957246977711748e-01, 1.314075231424398637614104e+00, ]; const TEST_FREXP: [_](f64, i64) = [ (6.2237649061045918750e-01, 3), (9.6735905932226306250e-01, 3), (-5.5376011438400318000e-01, -1), (-6.2632545228388436250e-01, 3), (6.02268356699901081250e-01, 4), (7.3159430981099115000e-01, 2), (6.5363542893241332500e-01, 3), (6.8198497760900255000e-01, 2), (9.1265404584042750000e-01, 1), (-5.4287029803597508250e-01, 4), ]; const TEST_LOG: [_]f64 = [ 1.605231462693062999102599e+00, 2.0462560018708770653153909e+00, -1.2841708730962657801275038e+00, 1.6115563905281545116286206e+00, 2.2655365644872016636317461e+00, 1.0737652208918379856272735e+00, 1.6542360106073546632707956e+00, 1.0035467127723465801264487e+00, 6.0174879014578057187016475e-01, 2.161703872847352815363655e+00, ]; const TEST_LOG10: [_]f64 = [ 6.9714316642508290997617083e-01, 8.886776901739320576279124e-01, -5.5770832400658929815908236e-01, 6.998900476822994346229723e-01, 9.8391002850684232013281033e-01, 4.6633031029295153334285302e-01, 7.1842557117242328821552533e-01, 4.3583479968917773161304553e-01, 2.6133617905227038228626834e-01, 9.3881606348649405716214241e-01, ]; const TEST_LOG2: [_]f64 = [ 2.3158594707062190618898251e+00, 2.9521233862883917703341018e+00, -1.8526669502700329984917062e+00, 2.3249844127278861543568029e+00, 3.268478366538305087466309e+00, 1.5491157592596970278166492e+00, 2.3865580889631732407886495e+00, 1.447811865817085365540347e+00, 8.6813999540425116282815557e-01, 3.118679457227342224364709e+00, ]; const TEST_LOG1P: []f64 = [ 4.8590257759797794104158205e-02, 7.4540265965225865330849141e-02, -2.7726407903942672823234024e-03, -5.1404917651627649094953380e-02, 9.1998280672258624681335010e-02, 2.8843762576593352865894824e-02, 5.0969534581863707268992645e-02, 2.6913947602193238458458594e-02, 1.8088493239630770262045333e-02, -9.0865245631588989681559268e-02, ]; const TEST_MODFRAC: [_](f64, f64) = [ (4f64, 9.7901192488367350108546816e-01), (7f64, 7.3887247457810456552351752e-01), (-0f64, -2.7688005719200159404635997e-01), (-5f64, -1.060361827107492160848778e-02), (9f64, 6.3629370719841737980004837e-01), (2f64, 9.2637723924396464525443662e-01), (5f64, 2.2908343145930665230025625e-01), (2f64, 7.2793991043601025126008608e-01), (1f64, 8.2530809168085506044576505e-01), (-8f64, -6.8592476857560136238589621e-01), ]; const TEST_POW: [_]f64 = [ 9.5282232631648411840742957e+04, 5.4811599352999901232411871e+07, 5.2859121715894396531132279e-01, 9.7587991957286474464259698e-06, 4.328064329346044846740467e+09, 8.4406761805034547437659092e+02, 1.6946633276191194947742146e+05, 5.3449040147551939075312879e+02, 6.688182138451414936380374e+01, 2.0609869004248742886827439e-09, ]; const TEST_ROUND: [_]f64 = [ 5.0f64, 8.0f64, -0.0f64, -5.0f64, 10.0f64, 3.0f64, 5.0f64, 3.0f64, 2.0f64, -9.0f64, ]; const TEST_SIGNF: [_]i8 = [ 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, ]; const TEST_SIN: [_]f64 = [ -9.6466616586009283766724726e-01, 9.9338225271646545763467022e-01, -2.7335587039794393342449301e-01, 9.5586257685042792878173752e-01, -2.099421066779969164496634e-01, 2.135578780799860532750616e-01, -8.694568971167362743327708e-01, 4.019566681155577786649878e-01, 9.6778633541687993721617774e-01, -6.734405869050344734943028e-01, ]; // Results for 100000 * PI + TEST_INPUTS[i] const TEST_SINLARGE: [_]f64 = [ -9.646661658548936063912e-01, 9.933822527198506903752e-01, -2.7335587036246899796e-01, 9.55862576853689321268e-01, -2.099421066862688873691e-01, 2.13557878070308981163e-01, -8.694568970959221300497e-01, 4.01956668098863248917e-01, 9.67786335404528727927e-01, -6.7344058693131973066e-01, ]; const TEST_SINH: [_]f64 = [ 7.2661916084208532301448439e+01, 1.1479409110035194500526446e+03, -2.8043136512812518927312641e-01, -7.499429091181587232835164e+01, 7.6552466042906758523925934e+03, 9.3031583421672014313789064e+00, 9.330815755828109072810322e+01, 7.6179893137269146407361477e+00, 3.021769180549615819524392e+00, -2.95950575724449499189888e+03, ]; const TEST_SQRT: [_]f64 = [ 2.2313699659365484748756904e+00, 2.7818829009464263511285458e+00, 5.2619393496314796848143251e-01, 2.2384377628763938724244104e+00, 3.1042380236055381099288487e+00, 1.7106657298385224403917771e+00, 2.286718922705479046148059e+00, 1.6516476350711159636222979e+00, 1.3510396336454586262419247e+00, 2.9471892997524949215723329e+00, ]; const TEST_TAN: [_]f64 = [ -3.661316565040227801781974e+00, 8.64900232648597589369854e+00, -2.8417941955033612725238097e-01, 3.253290185974728640827156e+00, 2.147275640380293804770778e-01, -2.18600910711067004921551e-01, -1.760002817872367935518928e+00, -4.389808914752818126249079e-01, -3.843885560201130679995041e+00, 9.10988793377685105753416e-01, ]; // Results for 100000 * PI + TEST_INPUTS[i] const TEST_TANLARGE: [_]f64 = [ -3.66131656475596512705e+00, 8.6490023287202547927e+00, -2.841794195104782406e-01, 3.2532901861033120983e+00, 2.14727564046880001365e-01, -2.18600910700688062874e-01, -1.760002817699722747043e+00, -4.38980891453536115952e-01, -3.84388555942723509071e+00, 9.1098879344275101051e-01, ]; const TEST_TANH: [_]f64 = [ 9.9990531206936338549262119e-01, 9.9999962057085294197613294e-01, -2.7001505097318677233756845e-01, -9.9991110943061718603541401e-01, 9.9999999146798465745022007e-01, 9.9427249436125236705001048e-01, 9.9994257600983138572705076e-01, 9.9149409509772875982054701e-01, 9.4936501296239685514466577e-01, -9.9999994291374030946055701e-01, ]; const TEST_TRUNC: [_]f64 = [ 4.0000000000000000e+00, 7.0000000000000000e+00, -0.0000000000000000e+00, -5.0000000000000000e+00, 9.0000000000000000e+00, 2.0000000000000000e+00, 5.0000000000000000e+00, 2.0000000000000000e+00, 1.0000000000000000e+00, -8.0000000000000000e+00, ]; hare-0.24.2/math/+test/floats_test.ha000066400000000000000000000245561464473310100173610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn floatbits() void = { const a: [_]f64 = [INF, -INF, 0.0, 1.0, -1.0, 123456789.0, F64_MIN, F64_MIN_NORMAL, F64_MAX_NORMAL]; for (let i = 0z; i < len(a); i += 1) { assert(f64frombits(f64bits(a[i])) == a[i]); }; const a: [_]f32 = [INF, -INF, 0.0, 1.0, -1.0, -123456.0, F32_MIN, F32_MIN_NORMAL, F32_MAX_NORMAL]; for (let i = 0z; i < len(a); i += 1) { assert(f32frombits(f32bits(a[i])) == a[i]); }; }; @test fn isnan() void = { assert(isnan(NAN)); assert(isnan(-NAN)); assert(isnan(f64frombits(0xfffabcdef1234567))); assert(!isnan(INF)); assert(!isnan(1.23f32)); }; @test fn float_normality() void = { assert(isnormal(0.0)); assert(isnormal(1.0)); assert(!isnormal(NAN)); assert(!isnormal(INF)); assert(!isnormal(1.0e-310)); assert(!isnormal(1.0e-40f32)); assert(isnormalf32(1.0)); assert(isnormalf32(0.0)); assert(!isnormalf32(NAN)); assert(!isnormalf32(INF)); assert(!isnormalf32(-1.0e-40)); assert(isnormalf32(-1.0e-50)); assert(isnormalf64(1.0)); assert(isnormalf64(0.0)); assert(!isnormalf64(NAN)); assert(!isnormalf64(INF)); assert(!isnormalf64(-1.0e-320)); assert(isnormalf64(-1.0e-330)); assert(issubnormal(1.0e-320)); assert(issubnormal(1.0e-42f32)); assert(!issubnormal(NAN)); assert(!issubnormal(INF)); assert(!issubnormal(1.0)); assert(!issubnormal(0.0)); assert(issubnormalf32(1.0e-45)); assert(issubnormalf32(-1.0e-39)); assert(!issubnormalf32(-NAN)); assert(!issubnormalf32(-INF)); assert(!issubnormalf32(0.0)); assert(!issubnormalf32(-1.0e-49)); assert(issubnormalf64(5.0e-324)); assert(issubnormalf64(-2.0e-310)); assert(!issubnormalf64(-NAN)); assert(!issubnormalf64(-INF)); assert(!issubnormalf64(-1.0e-400)); assert(!issubnormalf64(0.0)); }; @test fn absf() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(absf(TEST_INPUTS[idx]) == TEST_ABSF[idx]); }; assert(absf64(2f64) == 2f64); assert(absf32(2.0f32) == 2.0f32); assert(absf(2f64) == 2f64); assert(absf(2.0f32) == 2f64); assert(absf(-2f64) == 2f64); assert(absf(-2.0f32) == 2.0f32); assert(absf(0f32) == 0f32); assert(absf(0f64) == 0f64); }; @test fn copysign() void = { assert(copysign(100f64, 1f64) == 100f64); assert(copysign(100f64, -1f64) == -100f64); assert(copysign(100.0f32, 1.0f32) == 100.0f32); assert(copysign(100.0f32, -1.0f32) == -100.0f32); assert(copysign(100f64, 0f64) == 100f64); assert(copysign(100f64, -0f64) == -100f64); assert(copysign(0f64, 100f64) == 0f64); assert(signf(copysign(0f64, 100f64)) > 0); assert(copysign(0f64, -100f64) == 0f64); assert(signf(copysign(0f64, -100f64)) < 0); }; @test fn signf() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(signf(TEST_INPUTS[idx]) == TEST_SIGNF[idx]); }; assert(signf(0f64) == 1i64); assert(signf(-0f64) == -1i64); assert(signf(0.0f32) == 1i64); assert(signf(-0.0f32) == -1i64); assert(signf(1.5f64) == 1i64); assert(signf(-1.5f64) == -1i64); assert(ispositive(1f64)); assert(!ispositive(-1f64)); assert(isnegative(-1f64)); assert(!isnegative(1f64)); }; @test fn normalize() void = { let res = normalizef64(5.0e-320); assert(res.0 > F64_MIN_NORMAL); assert(res.1 < 0i64); res = normalizef64(5.0e-300); assert(res.0 == 5.0e-300); assert(res.1 == 0i64); }; @test fn frexp() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { let res = frexp(TEST_INPUTS[idx]); let expected = TEST_FREXP[idx]; assert(res.0 == expected.0); assert(res.1 == expected.1); }; let res = frexp(3f64); assert(res.0 == 0.75f64); assert(res.1 == 2i64); res = frexp(2.42f64); assert(res.0 == 0.605f64); assert(res.1 == 2i64); res = frexp(NAN); assert(res.1 == 0); res = frexp(INF); assert(res.1 == 0); }; @test fn frexp_ldexp() void = { const tests64: [_]f64 = [INF, -INF, 0.0, 1.0, -1.0, 2.42, 123456789.0, F64_MIN_NORMAL, F64_MAX_NORMAL, 3.0e-310f64]; for (let i = 0z; i < len(tests64); i += 1) { const parts = frexpf64(tests64[i]); const res64 = ldexpf64(parts.0, parts.1); assert(res64 == tests64[i]); }; assert(ldexpf64(1f64, -1076i64) == 0f64); assert(ldexpf64(-1f64, -1076i64) == -0f64); assert(signf(ldexpf64(-1f64, -1076i64)) < 0); assert(ldexpf64(2f64, 1024i64) == INF); assert(ldexpf64(-2f64, 1024i64) == -INF); const tests32: [_]f32 = [INF, -INF, 0.0, 1.0, -1.0, 2.42, 123456789.0, F32_MIN_NORMAL, F32_MAX_NORMAL, 3.0e-39f32]; for (let i = 0z; i < len(tests32); i += 1) { const parts = frexpf32(tests32[i]); const res = ldexpf32(parts.0, parts.1); assert(res == tests32[i]); }; assert(ldexpf32(1.0f32, -1076i32) == 0.0f32); assert(ldexpf32(-1.0f32, -1076i32) == -0.0f32); assert(signf(ldexpf32(-1.0f32, -1076i32)) < 0); assert(ldexpf32(2.0f32, 1024i32) == INF); assert(ldexpf32(-2.0f32, 1024i32) == -INF); }; @test fn modfrac() void = { // 64 for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { let res = modfracf64(TEST_INPUTS[idx]); assert(res.0 == TEST_MODFRAC[idx].0); assert(isclose(res.1, TEST_MODFRAC[idx].1)); }; let res = modfracf64(1.75f64); assert(res.0 == 1f64); assert(res.1 == 0.75f64); res = modfracf64(0.75f64); assert(res.0 == 0f64); assert(res.1 == 0.75f64); res = modfracf64(-0.75f64); assert(res.0 == -0f64); assert(res.1 == -0.75f64); res = modfracf64(0f64); assert(res.0 == 0f64); assert(res.1 == 0f64); assert(signf(res.1) > 0); res = modfracf64(-0f64); assert(res.0 == -0f64); assert(res.1 == -0f64); assert(signf(res.1) < 0); res = modfracf64(23.50f64); assert(res.0 == 23f64); assert(res.1 == 0.50f64); res = modfracf64(F64_MAX_NORMAL); assert(res.0 == F64_MAX_NORMAL); assert(res.1 == 0f64); // 32 let res = modfracf32(1.75f32); assert(res.0 == 1f32); assert(res.1 == 0.75f32); res = modfracf32(0.75f32); assert(res.0 == 0f32); assert(res.1 == 0.75f32); res = modfracf32(-0.75f32); assert(res.0 == -0f32); assert(res.1 == -0.75f32); res = modfracf32(0.0f32); assert(res.0 == 0f32); assert(res.1 == 0.0f32); assert(signf(res.1) > 0); res = modfracf32(-0.0f32); assert(res.0 == -0f32); assert(res.1 == -0.0f32); assert(signf(res.1) < 0); res = modfracf32(23.50f32); assert(res.0 == 23f32); assert(res.1 == 0.50f32); res = modfracf32(F32_MAX_NORMAL); assert(res.0 == F32_MAX_NORMAL); assert(res.1 == 0f32); }; @test fn nextafter() void = { let f = &f64frombits; // from musl's testsuite assert(nextafterf64(f(0xc0202239f3c6a8f1), f(0x40122484b9ef31f0)) == f(0xc0202239f3c6a8f0)); assert(nextafterf64(f(0x401161868e18bc67), f(0xc021c6a6cdce75e8)) == f(0x401161868e18bc66)); assert(nextafterf64(f(0xc020c34b3e01e6e7), f(0xc0061bde29e83f6d)) == f(0xc020c34b3e01e6e6)); assert(nextafterf64(f(0xc01a206f0a19dcc4), f(0x40124527f7b576ac)) == f(0xc01a206f0a19dcc3)); assert(nextafterf64(f(0x402288bbb0d6a1e6), f(0x40133edd910a3c01)) == f(0x402288bbb0d6a1e5)); assert(nextafterf64(f(0xc019ccd8be03f495), f(0x3fe52fb12ef638a1)) == f(0xc019ccd8be03f494)); assert(nextafterf64(f(0x401f6f80ed2eab44), f(0x3faab3ff8575b21d)) == f(0x401f6f80ed2eab43)); assert(nextafterf64(f(0xbfe95882b433fad3), f(0x401eb4a2e7ce0693)) == f(0xbfe95882b433fad2)); assert(nextafterf64(f(0x3fe3b3d617ae3c4a), f(0x40001860611d75e1)) == f(0x3fe3b3d617ae3c4b)); assert(nextafterf64(f(0xbfe1e159e36313ee), f(0x3fa081bd34224213)) == f(0xbfe1e159e36313ed)); assert(nextafterf64(f(0xbfe1e159e36313ee), f(0xbfe1e159e36313ee)) == f(0xbfe1e159e36313ee)); assert(nextafterf64(0.0f64, 1.0f64) == f(0x1)); assert(nextafterf64(0.0f64, -1.0f64) == f(0x8000000000000001)); assert(nextafterf64(-0.0f64, 1.0f64) == f(0x1)); assert(nextafterf64(-0.0f64, -1.0f64) == f(0x8000000000000001)); assert(nextafterf64(0.0f64, 0.0f64) == 0.0f64); assert(nextafterf64(-0.0f64, 0.0f64) == 0.0f64); assert(nextafterf64(0.0f64, -0.0f64) == -0.0f64); assert(isnan(nextafterf64(1.0f64, NAN))); assert(isnan(nextafterf64(NAN, -2f64))); assert(isnan(nextafterf64(NAN, NAN))); let f = &f32frombits; assert(nextafterf32(f(0xc10111d0), f(0x40912426)) == f(0xc10111cf)); assert(nextafterf32(f(0x408b0c34), f(0xc10e3536)) == f(0x408b0c33)); assert(nextafterf32(f(0xc1061a5a), f(0xc030def1)) == f(0xc1061a59)); assert(nextafterf32(f(0xc0d10378), f(0x40922940)) == f(0xc0d10377)); assert(nextafterf32(f(0x411445de), f(0x4099f6ed)) == f(0x411445dd)); assert(nextafterf32(f(0xc0ce66c6), f(0x3f297d89)) == f(0xc0ce66c5)); assert(nextafterf32(f(0x40fb7c07), f(0x3d559ffc)) == f(0x40fb7c06)); assert(nextafterf32(f(0xbf4ac416), f(0x40f5a517)) == f(0xbf4ac415)); assert(nextafterf32(f(0x3f1d9eb1), f(0x4000c303)) == f(0x3f1d9eb2)); assert(nextafterf32(f(0xbf0f0acf), f(0x3d040dea)) == f(0xbf0f0ace)); assert(nextafterf32(f(0xbf0f0acf), f(0xbf0f0acf)) == f(0xbf0f0acf)); assert(nextafterf32(0.0f32, 1.0f32) == f(0x1)); assert(nextafterf32(0.0f32, -1.0f32) == f(0x80000001)); assert(nextafterf32(-0.0f32, 1.0f32) == f(0x1)); assert(nextafterf32(-0.0f32, -1.0f32) == f(0x80000001)); assert(nextafterf32(0.0f32, 0.0f32) == 0.0f32); assert(nextafterf32(-0.0f32, 0.0f32) == 0.0f32); assert(nextafterf32(0.0f32, -0.0f32) == -0.0f32); assert(isnan(nextafterf32(1.0f32, NAN))); assert(isnan(nextafterf32(NAN, -2f32))); assert(isnan(nextafterf32(NAN, NAN))); }; @test fn nearbyint() void = { // from musl's testsuite let f = &f64frombits; assert(nearbyintf64(f(0xc0202239f3c6a8f1)) == f(0xc020000000000000)); assert(nearbyintf64(f(0x401161868e18bc67)) == f(0x4010000000000000)); assert(nearbyintf64(f(0xc020c34b3e01e6e7)) == f(0xc020000000000000)); assert(nearbyintf64(f(0xc01a206f0a19dcc4)) == f(0xc01c000000000000)); assert(nearbyintf64(f(0x402288bbb0d6a1e6)) == f(0x4022000000000000)); assert(nearbyintf64(f(0x3fe52efd0cd80497)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfda05cc754481d1)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3fe1f9ef934745cb)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0x3fe8c5db097f7442)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfe5b86ea8118a0e)) == f(0xbff0000000000000)); let f = &f32frombits; assert(nearbyintf32(f(0xc10111d0)) == f(0xc1000000)); assert(nearbyintf32(f(0x408b0c34)) == f(0x40800000)); assert(nearbyintf32(f(0xc1061a5a)) == f(0xc1000000)); assert(nearbyintf32(f(0xc0d10378)) == f(0xc0e00000)); assert(nearbyintf32(f(0x411445de)) == f(0x41100000)); assert(nearbyintf32(f(0x3f2977e8)) == f(0x3f800000)); assert(nearbyintf32(f(0xbed02e64)) == f(0x80000000)); assert(nearbyintf32(f(0x3f0fcf7d)) == f(0x3f800000)); assert(nearbyintf32(f(0x3f462ed8)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf2dc375)) == f(0xbf800000)); }; hare-0.24.2/math/+test/math_test.ha000066400000000000000000000217101464473310100170070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn eqwithin() void = { assert(eqwithin(1f64, 2f64, 2f64)); assert(eqwithin(1.0f32, 2.0f32, 2.0f32)); assert(!eqwithin(1.0005f32, 1.0004f32, 0.00001f32)); assert(isclose(1f64, 1.0000000000000000000000000001f64)); assert(isclose(1.0f32, 1.0000000000000000000000000001f32)); assert(!isclose(1.0005f32, 1.0004f32)); }; @test fn logf64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose( logf64(absf64(TEST_INPUTS[idx])), TEST_LOG[idx])); }; assert(logf64(E) == 1f64); assert(logf64(54.598150033144239078110261202860878402790f64) == 4f64); assert(isnan(logf64(-1f64))); assert(logf64(INF) == INF); assert(logf64(0f64) == -INF); assert(isnan(logf64(NAN))); }; @test fn log10f64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose( log10f64(absf64(TEST_INPUTS[idx])), TEST_LOG10[idx])); }; }; @test fn log2f64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose( log2f64(absf64(TEST_INPUTS[idx])), TEST_LOG2[idx])); }; }; @test fn log1p() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( log1pf64(TEST_INPUTS[idx] / 100f64), TEST_LOG1P[idx])); }; assert(isnan(log1pf64(-INF))); assert(isnan(log1pf64(-PI))); assert(log1pf64(-1f64) == -INF); assert(log1pf64(-0f64) == -0f64); assert(log1pf64(0f64) == 0f64); assert(log1pf64(INF) == INF); assert(isnan(log1pf64(NAN))); }; @test fn expf64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose(expf64(TEST_INPUTS[idx]), TEST_EXP[idx])); }; assert(expf64(1f64) == E); assert(isnan(expf64(NAN))); assert(isinf(expf64(INF))); assert(expf64(-INF) == 0f64); assert(isinf(expf64(99999f64))); assert(expf64(-99999f64) == 0f64); assert(expf64(0.5e-20) == 1f64); }; @test fn exp2f64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose(exp2f64(TEST_INPUTS[idx]), TEST_EXP2[idx])); }; assert(exp2f64(0f64) == 1f64); assert(exp2f64(3f64) == 8f64); assert(exp2f64(-2f64) == 0.25f64); assert(!isinf(exp2f64(256f64))); assert(isinf(exp2f64(99999f64))); assert(exp2f64(-99999f64) == 0f64); assert(isnan(exp2f64(NAN))); assert(isinf(exp2f64(INF))); assert(exp2f64(-INF) == 0f64); }; @test fn sqrt() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(isclose( sqrtf64(absf64(TEST_INPUTS[idx])), TEST_SQRT[idx])); }; assert(sqrtf64(2f64) == SQRT_2); assert(sqrtf64(4f64) == 2f64); assert(sqrtf64(16f64) == 4f64); assert(sqrtf64(65536f64) == 256f64); assert(sqrtf64(powf64(123f64, 2f64)) == 123f64); assert(sqrtf64(0f64) == 0f64); assert(isnan(sqrtf64(NAN))); assert(sqrtf64(INF) == INF); assert(isnan(sqrtf64(-2f64))); }; @test fn powf64() void = { for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { assert(eqwithin( powf64(10f64, TEST_INPUTS[idx]), TEST_POW[idx], 1e-8f64)); }; // Positive integer assert(powf64(2f64, 2f64) == 4f64); assert(powf64(3f64, 3f64) == 27f64); // Very large positive integer assert(!isinf(powf64(2f64, 1020f64))); assert(isinf(powf64(2f64, 1050f64))); // Very very large positive integer assert(isinf(powf64(2f64, F64_MAX_NORMAL))); assert(powf64(0.5f64, F64_MAX_NORMAL) == 0f64); // Negative integer assert(powf64(2f64, -1f64) == 0.5f64); assert(powf64(2f64, -2f64) == 0.25f64); // Very small negative integer assert(powf64(2f64, -1020f64) > 0f64); assert(powf64(2f64, -1080f64) == 0f64); // Very very small negative integer assert(powf64(2f64, -F64_MAX_NORMAL) == 0f64); assert(isinf(powf64(0.5f64, -F64_MAX_NORMAL))); // Positive fractional powers assert(eqwithin(powf64(2f64, 1.5f64), 2.8284271247461900976033774f64, 1e-10f64)); assert(eqwithin(powf64(2f64, 5.5f64), 45.254833995939041561654039f64, 1e-10f64)); // Negative fractional powers assert(eqwithin(powf64(2f64, -1.5f64), 0.3535533905932737622004221f64, 1e-10f64)); assert(eqwithin(powf64(2f64, -5.5f64), 0.0220970869120796101375263f64, 1e-10f64)); // Special cases // pow(x, ±0) = 1 for any x assert(powf64(123f64, 0f64) == 1f64); // pow(1, y) = 1 for any y assert(powf64(1f64, 123f64) == 1f64); // pow(x, 1) = x for any x assert(powf64(123f64, 1f64) == 123f64); // pow(NaN, y) = NaN assert(isnan(powf64(NAN, 123f64))); // pow(x, NaN) = NaN assert(isnan(powf64(123f64, NAN))); // pow(±0, y) = ±Inf for y an odd integer < 0 assert(powf64(0f64, -3f64) == INF); assert(powf64(-0f64, -3f64) == -INF); // pow(±0, -Inf) = +Inf assert(powf64(0f64, -INF) == INF); assert(powf64(-0f64, -INF) == INF); // pow(±0, +Inf) = +0 assert(powf64(0f64, INF) == 0f64); assert(powf64(-0f64, INF) == 0f64); // pow(±0, y) = +Inf for finite y < 0 and not an odd integer assert(powf64(0f64, -2f64) == INF); assert(powf64(0f64, -2f64) == INF); //pow(±0, y) = ±0 for y an odd integer > 0 assert(powf64(0f64, 123f64) == 0f64); const neg_zero = powf64(-0f64, 123f64); assert(neg_zero == 0f64); assert(isnegative(neg_zero)); // pow(±0, y) = +0 for finite y > 0 and not an odd integer assert(powf64(0f64, 8f64) == 0f64); // pow(-1, ±Inf) = 1 assert(powf64(-1f64, INF) == 1f64); assert(powf64(-1f64, -INF) == 1f64); // pow(x, +Inf) = +Inf for |x| > 1 assert(powf64(123f64, INF) == INF); // pow(x, -Inf) = +0 for |x| > 1 assert(powf64(123f64, -INF) == 0f64); // pow(x, +Inf) = +0 for |x| < 1 assert(powf64(0.5f64, INF) == 0f64); assert(powf64(-0.5f64, INF) == 0f64); // pow(x, -Inf) = +Inf for |x| < 1 assert(powf64(0.5f64, -INF) == INF); assert(powf64(-0.5f64, -INF) == INF); // pow(+Inf, y) = +Inf for y > 0 assert(powf64(INF, 123f64) == INF); // pow(+Inf, y) = +0 for y < 0 assert(powf64(INF, -1f64) == 0f64); // pow(-Inf, y) = pow(-0, -y) assert(powf64(-INF, 123f64) == powf64(-0f64, -123f64)); // pow(x, y) = NaN for finite x < 0 and finite non-integer y assert(isnan(powf64(-2f64, 1.23f64))); // sqrt assert(powf64(4f64, 0.5f64) == sqrtf64(4f64)); assert(powf64(4f64, 0.5f64) == 2f64); assert(powf64(4f64, -0.5f64) == (1f64 / sqrtf64(4f64))); assert(powf64(4f64, -0.5f64) == (1f64 / 2f64)); }; @test fn floor() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( floorf64(TEST_INPUTS[idx]), TEST_FLOOR[idx])); }; assert(floorf64(-INF) == -INF); assert(floorf64(-0f64) == -0f64); assert(floorf64(0f64) == 0f64); assert(floorf64(INF) == INF); assert(isnan(floorf64(NAN))); }; @test fn ceil() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( ceilf64(TEST_INPUTS[idx]), TEST_CEIL[idx])); }; assert(ceilf64(-INF) == -INF); assert(ceilf64(-F64_MAX_NORMAL) == -F64_MAX_NORMAL); assert(ceilf64(-0f64) == -0f64); assert(ceilf64(0f64) == 0f64); assert(ceilf64(F64_MAX_NORMAL) == F64_MAX_NORMAL); assert(ceilf64(INF) == INF); assert(isnan(ceilf64(NAN))); }; @test fn trunc() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( truncf64(TEST_INPUTS[idx]), TEST_TRUNC[idx])); }; assert(truncf64(-INF) == -INF); assert(truncf64(-F64_MAX_NORMAL) == -F64_MAX_NORMAL); assert(truncf64(-0f64) == -0f64); assert(truncf64(0f64) == 0f64); assert(truncf64(F64_MAX_NORMAL) == F64_MAX_NORMAL); assert(truncf64(INF) == INF); assert(isnan(truncf64(NAN))); }; @test fn round() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( roundf64(TEST_INPUTS[idx]), TEST_ROUND[idx])); }; assert(roundf64(-INF) == -INF); assert(roundf64(-F64_MAX_NORMAL) == -F64_MAX_NORMAL); assert(roundf64(-0f64) == -0f64); assert(roundf64(0f64) == 0f64); assert(roundf64(F64_MAX_NORMAL) == F64_MAX_NORMAL); assert(roundf64(INF) == INF); assert(isnan(roundf64(NAN))); }; @test fn modf64() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( modf64(10f64, TEST_INPUTS[idx]), TEST_MODF[idx])); }; assert(isnan(modf64(-INF, -INF))); assert(isnan(modf64(-INF, -PI))); assert(isnan(modf64(-INF, 0f64))); assert(isnan(modf64(-INF, PI))); assert(isnan(modf64(-INF, INF))); assert(isnan(modf64(-INF, NAN))); assert(modf64(-PI, -INF) == -PI); assert(isnan(modf64(-PI, 0f64))); assert(modf64(-PI, INF) == -PI); assert(isnan(modf64(-PI, NAN))); assert(modf64(-0f64, -INF) == -0f64); assert(isnan(modf64(-0f64, 0f64))); assert(modf64(-0f64, INF) == -0f64); assert(isnan(modf64(-0f64, NAN))); assert(modf64(0f64, -INF) == 0f64); assert(isnan(modf64(0f64, 0f64))); assert(modf64(0f64, INF) == 0f64); assert(isnan(modf64(0f64, NAN))); assert(modf64(PI, -INF) == PI); assert(isnan(modf64(PI, 0f64))); assert(modf64(PI, INF) == PI); assert(isnan(modf64(PI, NAN))); assert(isnan(modf64(INF, -INF))); assert(isnan(modf64(INF, -PI))); assert(isnan(modf64(INF, 0f64))); assert(isnan(modf64(INF, PI))); assert(isnan(modf64(INF, INF))); assert(isnan(modf64(INF, NAN))); assert(isnan(modf64(NAN, -INF))); assert(isnan(modf64(NAN, -PI))); assert(isnan(modf64(NAN, 0f64))); assert(isnan(modf64(NAN, PI))); assert(isnan(modf64(NAN, INF))); assert(isnan(modf64(NAN, NAN))); assert(modf64(5.9790119248836734e+200, 1.1258465975523544) == 0.6447968302508578); }; hare-0.24.2/math/+test/trig_test.ha000066400000000000000000000132541464473310100170270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @test fn trig_reduce() void = { for (let idx = 0z; idx < 10; idx += 1) { const reduced = trig_reduce(TEST_INPUTS[idx]); const j = reduced.0; const z = reduced.1; const xred = (j: i64: f64) * (PI / 4f64) + z; assert(isclose( sinf64(TEST_INPUTS[idx]), sinf64(xred))); }; }; @test fn cos() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( cosf64(TEST_INPUTS[idx]), TEST_COS[idx])); }; assert(isnan(cosf64(-INF))); assert(isnan(cosf64(INF))); assert(isnan(cosf64(NAN))); }; @test fn sin() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( sinf64(TEST_INPUTS[idx]), TEST_SIN[idx])); }; assert(isnan(sinf64(-INF))); assert(sinf64(-0f64) == -0f64); assert(sinf64(0f64) == 0f64); assert(isnan(sinf64(INF))); assert(isnan(sinf64(NAN))); }; @test fn tan() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( tanf64(TEST_INPUTS[idx]), TEST_TAN[idx])); }; assert(isnan(sinf64(-INF))); assert(sinf64(-0f64) == -0f64); assert(sinf64(0f64) == 0f64); assert(isnan(sinf64(INF))); assert(isnan(sinf64(NAN))); }; @test fn asin() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( asinf64(TEST_INPUTS[idx] / 10f64), TEST_ASIN[idx])); }; assert(isnan(asinf64(-PI))); assert(asinf64(-0f64) == -0f64); assert(asinf64(0f64) == 0f64); assert(isnan(asinf64(PI))); assert(isnan(asinf64(NAN))); }; @test fn acos() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( acosf64(TEST_INPUTS[idx] / 10f64), TEST_ACOS[idx])); }; assert(isnan(acosf64(-PI))); assert(acosf64(1f64) == 0f64); assert(isnan(acosf64(PI))); assert(isnan(acosf64(NAN))); }; @test fn atan() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( atanf64(TEST_INPUTS[idx]), TEST_ATAN[idx])); }; assert(atanf64(-INF) == -PI / 2f64); assert(atanf64(-0f64) == -0f64); assert(atanf64(0f64) == 0f64); assert(atanf64(INF) == PI / 2f64); assert(isnan(atanf64(NAN))); }; @test fn sinh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(eqwithin( sinhf64(TEST_INPUTS[idx]), TEST_SINH[idx], 1e-6f64)); }; assert(sinhf64(-INF) == -INF); assert(sinhf64(-0f64) == -0f64); assert(sinhf64(0f64) == 0f64); assert(sinhf64(INF) == INF); assert(isnan(sinhf64(NAN))); }; @test fn cosh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( coshf64(TEST_INPUTS[idx]), TEST_COSH[idx])); }; assert(coshf64(-INF) == INF); assert(coshf64(-0f64) == 1f64); assert(coshf64(0f64) == 1f64); assert(coshf64(INF) == INF); assert(isnan(coshf64(NAN))); }; @test fn tanh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( tanhf64(TEST_INPUTS[idx]), TEST_TANH[idx])); }; assert(tanhf64(-INF) == -1f64); assert(tanhf64(-0f64) == -0f64); assert(tanhf64(0f64) == 0f64); assert(tanhf64(INF) == 1f64); assert(isnan(tanhf64(NAN))); }; @test fn asinh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( asinhf64(TEST_INPUTS[idx]), TEST_ASINH[idx])); }; assert(asinhf64(-INF) == -INF); assert(asinhf64(-0f64) == -0f64); assert(asinhf64(0f64) == 0f64); assert(asinhf64(INF) == INF); assert(isnan(asinhf64(NAN))); }; @test fn acosh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( acoshf64(1f64 + absf64(TEST_INPUTS[idx])), TEST_ACOSH[idx])); }; assert(isnan(acoshf64(-INF))); assert(isnan(acoshf64(0.5f64))); assert(acoshf64(1f64) == 0f64); assert(acoshf64(INF) == INF); assert(isnan(acoshf64(NAN))); }; @test fn atanh() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( atanhf64(TEST_INPUTS[idx] / 10f64), TEST_ATANH[idx])); }; assert(isnan(atanhf64(-INF))); assert(isnan(atanhf64(-PI))); assert(atanhf64(-1f64) == -INF); assert(atanhf64(-0f64) == -0f64); assert(atanhf64(0f64) == 0f64); assert(atanhf64(1f64) == INF); assert(isnan(atanhf64(PI))); assert(isnan(atanhf64(INF))); assert(isnan(atanhf64(NAN))); }; @test fn atan2() void = { for (let idx = 0z; idx < 10; idx += 1) { assert(isclose( atan2f64(10f64, TEST_INPUTS[idx]), TEST_ATAN2[idx])); }; assert(isnan(atan2f64(-INF, NAN))); assert(atan2f64(-PI, INF) == -0f64); assert(isnan(atan2f64(-PI, NAN))); assert(atan2f64(-0f64, 0f64) == -0f64); assert(atan2f64(-0f64, PI) == -0f64); assert(atan2f64(-0f64, INF) == -0f64); assert(isnan(atan2f64(-0f64, NAN))); assert(atan2f64(0f64, 0f64) == 0f64); assert(atan2f64(0f64, PI) == 0f64); assert(atan2f64(0f64, INF) == 0f64); assert(isnan(atan2f64(0f64, NAN))); assert(atan2f64(PI, INF) == 0f64); assert(atan2f64(1f64, INF) == 0f64); assert(atan2f64(-1f64, INF) == -0f64); assert(isnan(atan2f64(PI, NAN))); assert(isnan(atan2f64(INF, NAN))); assert(isnan(atan2f64(NAN, NAN))); }; @test fn hypot() void = { for (let idx = 0z; idx < 10; idx += 1) { const a = absf64(1e200f64 * TEST_TANH[idx] * SQRT_2); assert(isclose( hypotf64(1e200f64 * TEST_TANH[idx], 1e200f64 * TEST_TANH[idx]), a)); }; assert(hypotf64(-INF, -INF) == INF); assert(hypotf64(-INF, 0f64) == INF); assert(hypotf64(-INF, INF) == INF); assert(hypotf64(-INF, NAN) == INF); assert(hypotf64(-0f64, -0f64) == 0f64); assert(hypotf64(-0f64, 0f64) == 0f64); assert(hypotf64(0f64, -0f64) == 0f64); assert(hypotf64(0f64, 0f64) == 0f64); assert(hypotf64(0f64, -INF) == INF); assert(hypotf64(0f64, INF) == INF); assert(isnan(hypotf64(0f64, NAN))); assert(hypotf64(INF, -INF) == INF); assert(hypotf64(INF, 0f64) == INF); assert(hypotf64(INF, INF) == INF); assert(hypotf64(INF, NAN) == INF); assert(hypotf64(NAN, -INF) == INF); assert(isnan(hypotf64(NAN, 0f64))); assert(hypotf64(NAN, INF) == INF); assert(isnan(hypotf64(NAN, NAN))); }; hare-0.24.2/math/README000066400000000000000000000001731464473310100143330ustar00rootroot00000000000000The math module provides implementations of common math functionality and support for dealing with floating point numbers. hare-0.24.2/math/checked/000077500000000000000000000000001464473310100150405ustar00rootroot00000000000000hare-0.24.2/math/checked/README000066400000000000000000000010041464473310100157130ustar00rootroot00000000000000math::checked provides safe integer arithmetic functions that check for overflow. The functions add*, sub* and mul* perform wrapping integer arithmetic, with the same semantics as the +, -, and * operators. const (res, overflow) = math::addi32(types::I32_MAX, 1); assert(res == types::I32_MIN); assert(overflow); The functions sat_* perform saturating integer arithmetic, which clamp the result value to the range of the type. const res = math::sat_addi32(types::I32_MAX, 1); assert(res == types::I32_MAX); hare-0.24.2/math/checked/checked.ha000066400000000000000000000256361464473310100167540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math; use types; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addi8(a: i8, b: i8) (i8, bool) = { const res = a + b; const overflow = a < 0 == b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn addi8() void = { const (res, overflow) = addi8(100, 20); assert(res == 120); assert(!overflow); const (res, overflow) = addi8(100, 50); assert(res == -106); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addi16(a: i16, b: i16) (i16, bool) = { const res = a + b; const overflow = a < 0 == b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn addi16() void = { const (res, overflow) = addi16(32700, 60); assert(res == 32760); assert(!overflow); const (res, overflow) = addi16(32700, 100); assert(res == -32736); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addi32(a: i32, b: i32) (i32, bool) = { const res = a + b; const overflow = a < 0 == b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn addi32() void = { const (res, overflow) = addi32(2147483600, 40); assert(res == 2147483640); assert(!overflow); const (res, overflow) = addi32(2147483600, 100); assert(res == -2147483596); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addi64(a: i64, b: i64) (i64, bool) = { const res = a + b; const overflow = a < 0 == b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn addi64() void = { const (res, overflow) = addi64(9223372036854775800, 5); assert(res == 9223372036854775805); assert(!overflow); const (res, overflow) = addi64(9223372036854775800, 10); assert(res == -9223372036854775806); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addu8(a: u8, b: u8) (u8, bool) = { const res = a + b; const overflow = res < a; return (res, overflow); }; @test fn addu8() void = { const (res, overflow) = addu8(200, 50); assert(res == 250); assert(!overflow); const (res, overflow) = addu8(200, 100); assert(res == 44); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addu16(a: u16, b: u16) (u16, bool) = { const res = a + b; const overflow = res < a; return (res, overflow); }; @test fn addu16() void = { const (res, overflow) = addu16(65500, 30); assert(res == 65530); assert(!overflow); const (res, overflow) = addu16(65500, 50); assert(res == 14); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addu32(a: u32, b: u32) (u32, bool) = { const res = a + b; const overflow = res < a; return (res, overflow); }; @test fn addu32() void = { const (res, overflow) = addu32(4294967200, 90); assert(res == 4294967290); assert(!overflow); const (res, overflow) = addu32(4294967200, 100); assert(res == 4); assert(overflow); }; // Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addu64(a: u64, b: u64) (u64, bool) = { const res = a + b; const overflow = res < a; return (res, overflow); }; @test fn addu64() void = { const (res, overflow) = addu64(18446744073709551600, 10); assert(res == 18446744073709551610); assert(!overflow); const (res, overflow) = addu64(18446744073709551610, 50); assert(res == 44); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subi8(a: i8, b: i8) (i8, bool) = { const res = a - b; const overflow = a < 0 != b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn subi8() void = { const (res, overflow) = subi8(-100, 20); assert(res == -120); assert(!overflow); const (res, overflow) = subi8(-100, 50); assert(res == 106); assert(overflow); const (res, overflow) = subi8(types::I8_MAX, types::I8_MIN); assert(res == -1); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subi16(a: i16, b: i16) (i16, bool) = { const res = a - b; const overflow = a < 0 != b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn subi16() void = { const (res, overflow) = subi16(-32700, 60); assert(res == -32760); assert(!overflow); const (res, overflow) = subi16(-32700, 100); assert(res == 32736); assert(overflow); const (res, overflow) = subi16(types::I16_MAX, types::I16_MIN); assert(res == -1); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subi32(a: i32, b: i32) (i32, bool) = { const res = a - b; const overflow = a < 0 != b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn subi32() void = { const (res, overflow) = subi32(-2147483600, 40); assert(res == -2147483640); assert(!overflow); const (res, overflow) = subi32(-2147483600, 100); assert(res == 2147483596); assert(overflow); const (res, overflow) = subi32(types::I32_MAX, types::I32_MIN); assert(res == -1); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subi64(a: i64, b: i64) (i64, bool) = { const res = a - b; const overflow = a < 0 != b < 0 && a < 0 != res < 0; return (res, overflow); }; @test fn subi64() void = { const (res, overflow) = subi64(-9223372036854775800, 5); assert(res == -9223372036854775805); assert(!overflow); const (res, overflow) = subi64(-9223372036854775800, 10); assert(res == 9223372036854775806); assert(overflow); const (res, overflow) = subi64(types::I64_MAX, types::I64_MIN); assert(res == -1); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subu8(a: u8, b: u8) (u8, bool) = { const res = a - b; const overflow = res > a; return (res, overflow); }; @test fn subu8() void = { const (res, overflow) = subu8(250, 50); assert(res == 200); assert(!overflow); const (res, overflow) = subu8(44, 100); assert(res == 200); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subu16(a: u16, b: u16) (u16, bool) = { const res = a - b; const overflow = res > a; return (res, overflow); }; @test fn subu16() void = { const (res, overflow) = subu16(65530, 30); assert(res == 65500); assert(!overflow); const (res, overflow) = subu16(14, 50); assert(res == 65500); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subu32(a: u32, b: u32) (u32, bool) = { const res = a - b; const overflow = res > a; return (res, overflow); }; @test fn subu32() void = { const (res, overflow) = subu32(4294967290, 90); assert(res == 4294967200); assert(!overflow); const (res, overflow) = subu32(4, 100); assert(res == 4294967200); assert(overflow); }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subu64(a: u64, b: u64) (u64, bool) = { const res = a - b; const overflow = res > a; return (res, overflow); }; @test fn subu64() void = { const (res, overflow) = subu64(18446744073709551610, 10); assert(res == 18446744073709551600); assert(!overflow); const (res, overflow) = subu64(44, 50); assert(res == 18446744073709551610); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn muli8(a: i8, b: i8) (i8, bool) = { const fullres = a: int * b: int; const res = fullres: i8; const overflow = res != fullres; return (res, overflow); }; @test fn muli8() void = { const (res, overflow) = muli8(11, 11); assert(res == 121); assert(!overflow); const (res, overflow) = muli8(12, 12); assert(res == -112); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn muli16(a: i16, b: i16) (i16, bool) = { const fullres = a: int * b: int; const res = fullres: i16; const overflow = res != fullres; return (res, overflow); }; @test fn muli16() void = { const (res, overflow) = muli16(181, 181); assert(res == 32761); assert(!overflow); const (res, overflow) = muli16(182, 182); assert(res == -32412); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn muli32(a: i32, b: i32) (i32, bool) = { const fullres = a: i64 * b: i64; const res = fullres: i32; const overflow = res != fullres; return (res, overflow); }; @test fn muli32() void = { const (res, overflow) = muli32(46340, 46340); assert(res == 2147395600); assert(!overflow); const (res, overflow) = muli32(46341, 46341); assert(res == -2147479015); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn muli64(a: i64, b: i64) (i64, bool) = { const (hi, lo) = math::mulu64(math::absi64(a), math::absi64(b)); const res = a * b; const overflow = hi != 0 || lo & (1 << 63) != 0; return (res, overflow); }; @test fn muli64() void = { const (res, overflow) = muli64(3037000499, 3037000499); assert(res == 9223372030926249001); assert(!overflow); const (res, overflow) = muli64(3037000500, 3037000500); assert(res == -9223372036709301616); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn mulu8(a: u8, b: u8) (u8, bool) = { const fullres = a: uint * b: uint; const res = fullres: u8; const overflow = res != fullres; return (res, overflow); }; @test fn mulu8() void = { const (res, overflow) = mulu8(15, 15); assert(res == 225); assert(!overflow); const (res, overflow) = mulu8(16, 16); assert(res == 0); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn mulu16(a: u16, b: u16) (u16, bool) = { const fullres = a: uint * b: uint; const res = fullres: u16; const overflow = res != fullres; return (res, overflow); }; @test fn mulu16() void = { const (res, overflow) = mulu16(255, 255); assert(res == 65025); assert(!overflow); const (res, overflow) = mulu16(256, 256); assert(res == 0); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn mulu32(a: u32, b: u32) (u32, bool) = { const fullres = a: u64 * b: u64; const res = fullres: u32; const overflow = res != fullres; return (res, overflow); }; @test fn mulu32() void = { const (res, overflow) = mulu32(65535, 65535); assert(res == 4294836225); assert(!overflow); const (res, overflow) = mulu32(65536, 65536); assert(res == 0); assert(overflow); }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn mulu64(a: u64, b: u64) (u64, bool) = { const (hi, lo) = math::mulu64(a, b); const res = lo; const overflow = hi != 0; return (res, overflow); }; @test fn mulu64() void = { const (res, overflow) = mulu64(4294967295, 4294967295); assert(res == 18446744065119617025); assert(!overflow); const (res, overflow) = mulu64(4294967296, 4294967296); assert(res == 0); assert(overflow); }; hare-0.24.2/math/checked/saturating.ha000066400000000000000000000224101464473310100175320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math; use types; // Computes the saturating addition of 'a' and 'b'. export fn sat_addi8(a: i8, b: i8) i8 = { const res = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { return if (res < 0) types::I8_MAX else types::I8_MIN; }; return res; }; @test fn sat_addi8() void = { assert(sat_addi8(100, 20) == 120); assert(sat_addi8(100, 50) == types::I8_MAX); assert(sat_addi8(-100, -50) == types::I8_MIN); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addi16(a: i16, b: i16) i16 = { const res = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { return if (res < 0) types::I16_MAX else types::I16_MIN; }; return res; }; @test fn sat_addi16() void = { assert(sat_addi16(32700, 60) == 32760); assert(sat_addi16(32700, 100) == types::I16_MAX); assert(sat_addi16(-32700, -100) == types::I16_MIN); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addi32(a: i32, b: i32) i32 = { const res = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { return if (res < 0) types::I32_MAX else types::I32_MIN; }; return res; }; @test fn sat_addi32() void = { assert(sat_addi32(2147483600, 40) == 2147483640); assert(sat_addi32(2147483600, 100) == types::I32_MAX); assert(sat_addi32(-2147483600, -100) == types::I32_MIN); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addi64(a: i64, b: i64) i64 = { const res = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { return if (res < 0) types::I64_MAX else types::I64_MIN; }; return res; }; @test fn sat_addi64() void = { assert(sat_addi64(9223372036854775800, 5) == 9223372036854775805); assert(sat_addi64(9223372036854775800, 10) == types::I64_MAX); assert(sat_addi64(-9223372036854775800, -10) == types::I64_MIN); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addu8(a: u8, b: u8) u8 = { return if (a + b < a) types::U8_MAX else a + b; }; @test fn sat_addu8() void = { assert(sat_addu8(200, 50) == 250); assert(sat_addu8(200, 100) == types::U8_MAX); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addu16(a: u16, b: u16) u16 = { return if (a + b < a) types::U16_MAX else a + b; }; @test fn sat_addu16() void = { assert(sat_addu16(65500, 30) == 65530); assert(sat_addu16(65500, 50) == types::U16_MAX); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addu32(a: u32, b: u32) u32 = { return if (a + b < a) types::U32_MAX else a + b; }; @test fn sat_addu32() void = { assert(sat_addu32(4294967200, 90) == 4294967290); assert(sat_addu32(4294967200, 100) == types::U32_MAX); }; // Computes the saturating addition of 'a' and 'b'. export fn sat_addu64(a: u64, b: u64) u64 = { return if (a + b < a) types::U64_MAX else a + b; }; @test fn sat_addu64() void = { assert(sat_addu64(18446744073709551600, 10) == 18446744073709551610); assert(sat_addu64(18446744073709551600, 50) == types::U64_MAX); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subi8(a: i8, b: i8) i8 = { const res = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { return if (res < 0) types::I8_MAX else types::I8_MIN; }; return res; }; @test fn sat_subi8() void = { assert(sat_subi8(-100, 20) == -120); assert(sat_subi8(-100, 50) == types::I8_MIN); assert(sat_subi8(100, -50) == types::I8_MAX); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subi16(a: i16, b: i16) i16 = { const res = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { return if (res < 0) types::I16_MAX else types::I16_MIN; }; return res; }; @test fn sat_subi16() void = { assert(sat_subi16(-32700, 60) == -32760); assert(sat_subi16(-32700, 100) == types::I16_MIN); assert(sat_subi16(32700, -100) == types::I16_MAX); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subi32(a: i32, b: i32) i32 = { const res = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { return if (res < 0) types::I32_MAX else types::I32_MIN; }; return res; }; @test fn sat_subi32() void = { assert(sat_subi32(-2147483600, 40) == -2147483640); assert(sat_subi32(-2147483600, 100) == types::I32_MIN); assert(sat_subi32(2147483600, -100) == types::I32_MAX); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subi64(a: i64, b: i64) i64 = { const res = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { return if (res < 0) types::I64_MAX else types::I64_MIN; }; return res; }; @test fn sat_subi64() void = { assert(sat_subi64(-9223372036854775800, 5) == -9223372036854775805); assert(sat_subi64(-9223372036854775800, 10) == types::I64_MIN); assert(sat_subi64(9223372036854775800, -10) == types::I64_MAX); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subu8(a: u8, b: u8) u8 = { return if (a - b > a) types::U8_MIN else a - b; }; @test fn sat_subu8() void = { assert(sat_subu8(250, 50) == 200); assert(sat_subu8(44, 100) == types::U8_MIN); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subu16(a: u16, b: u16) u16 = { return if (a - b > a) types::U16_MIN else a - b; }; @test fn sat_subu16() void = { assert(sat_subu16(65530, 30) == 65500); assert(sat_subu16(14, 50) == types::U16_MIN); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subu32(a: u32, b: u32) u32 = { return if (a - b > a) types::U32_MIN else a - b; }; @test fn sat_subu32() void = { assert(sat_subu32(4294967290, 90) == 4294967200); assert(sat_subu32(4, 100) == types::U32_MIN); }; // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subu64(a: u64, b: u64) u64 = { return if (a - b > a) types::U64_MIN else a - b; }; @test fn sat_subu64() void = { assert(sat_subu64(18446744073709551610, 10) == 18446744073709551600); assert(sat_subu64(44, 50) == types::U64_MIN); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_muli8(a: i8, b: i8) i8 = { const fullres = a: int * b: int; const res = fullres: i8; if (res != fullres) { return if (res < 0) types::I8_MAX else types::I8_MIN; }; return res; }; @test fn sat_muli8() void = { assert(sat_muli8(11, 11) == 121); assert(sat_muli8(12, 12) == types::I8_MAX); assert(sat_muli8(12, -12) == types::I8_MIN); assert(sat_muli8(-12, 12) == types::I8_MIN); assert(sat_muli8(-12, -12) == types::I8_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_muli16(a: i16, b: i16) i16 = { const fullres = a: int * b: int; const res = fullres: i16; if (res != fullres) { return if (res < 0) types::I16_MAX else types::I16_MIN; }; return res; }; @test fn sat_muli16() void = { assert(sat_muli16(181, 181) == 32761); assert(sat_muli16(182, 182) == types::I16_MAX); assert(sat_muli16(182, -182) == types::I16_MIN); assert(sat_muli16(-182, 182) == types::I16_MIN); assert(sat_muli16(-182, -182) == types::I16_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_muli32(a: i32, b: i32) i32 = { const fullres = a: i64 * b: i64; const res = fullres: i32; if (res != fullres) { return if (res < 0) types::I32_MAX else types::I32_MIN; }; return res; }; @test fn sat_muli32() void = { assert(sat_muli32(46340, 46340) == 2147395600); assert(sat_muli32(46341, 46341) == types::I32_MAX); assert(sat_muli32(46341, -46341) == types::I32_MIN); assert(sat_muli32(-46341, 46341) == types::I32_MIN); assert(sat_muli32(-46341, -46341) == types::I32_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_muli64(a: i64, b: i64) i64 = { const (hi, lo) = math::mulu64(math::absi64(a), math::absi64(b)); if (hi != 0 || lo & (1 << 63) != 0) { return if (a < 0 == b < 0) types::I64_MAX else types::I64_MIN; }; return a * b; }; @test fn sat_muli64() void = { assert(sat_muli64(3037000499, 3037000499) == 9223372030926249001); assert(sat_muli64(3037000500, 3037000500) == types::I64_MAX); assert(sat_muli64(3037000500, -3037000500) == types::I64_MIN); assert(sat_muli64(-3037000500, 3037000500) == types::I64_MIN); assert(sat_muli64(-3037000500, -3037000500) == types::I64_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_mulu8(a: u8, b: u8) u8 = { const res = a: uint * b: uint; return if (res > types::U8_MAX) types::U8_MAX else res: u8; }; @test fn sat_mulu8() void = { assert(sat_mulu8(15, 15) == 225); assert(sat_mulu8(16, 16) == types::U8_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_mulu16(a: u16, b: u16) u16 = { const res = a: uint * b: uint; return if (res > types::U16_MAX) types::U16_MAX else res: u16; }; @test fn sat_mulu16() void = { assert(sat_mulu16(255, 255) == 65025); assert(sat_mulu16(256, 256) == types::U16_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_mulu32(a: u32, b: u32) u32 = { const res = a: u64 * b: u64; return if (res > types::U32_MAX) types::U32_MAX else res: u32; }; @test fn sat_mulu32() void = { assert(sat_mulu32(65535, 65535) == 4294836225); assert(sat_mulu32(65536, 65536) == types::U32_MAX); }; // Computes the saturating multiplication of 'a' and 'b'. export fn sat_mulu64(a: u64, b: u64) u64 = { const (hi, lo) = math::mulu64(a, b); return if (hi != 0) types::U64_MAX else lo; }; @test fn sat_mulu64() void = { assert(sat_mulu64(4294967295, 4294967295) == 18446744065119617025); assert(sat_mulu64(4294967296, 4294967296) == types::U64_MAX); }; hare-0.24.2/math/complex/000077500000000000000000000000001464473310100151215ustar00rootroot00000000000000hare-0.24.2/math/complex/+test.ha000066400000000000000000001332571464473310100165000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The test data below is based on Go's implementation, and came with the // following note and copyright notice: // // The expected results below were computed by the high precision calculators // at https://keisan.casio.com/. More exact input values (array vf[], above) // were obtained by printing them with "%.26f". The answers were calculated // to 26 digits (by using the "Digit number" drop-down control of each // calculator). // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== use math; // The higher-precision values in VC26 were used to derive the // input arguments VC. For reference only (do not delete). const VC26: []c128 = [ (4.97901192488367350108546816, 7.73887247457810456552351752), (7.73887247457810456552351752, -0.27688005719200159404635997), (-0.27688005719200159404635997, -5.01060361827107492160848778), (-5.01060361827107492160848778, 9.63629370719841737980004837), (9.63629370719841737980004837, 2.92637723924396464525443662), (2.92637723924396464525443662, 5.22908343145930665230025625), (5.22908343145930665230025625, 2.72793991043601025126008608), (2.72793991043601025126008608, 1.82530809168085506044576505), (1.82530809168085506044576505, -8.68592476857560136238589621), (-8.68592476857560136238589621, 4.97901192488367350108546816), ]; const VC: []c128 = [ (4.9790119248836735e+00, 7.7388724745781045e+00), (7.7388724745781045e+00, -2.7688005719200159e-01), (-2.7688005719200159e-01, -5.0106036182710749e+00), (-5.0106036182710749e+00, 9.6362937071984173e+00), (9.6362937071984173e+00, 2.9263772392439646e+00), (2.9263772392439646e+00, 5.2290834314593066e+00), (5.2290834314593066e+00, 2.7279399104360102e+00), (2.7279399104360102e+00, 1.8253080916808550e+00), (1.8253080916808550e+00, -8.6859247685756013e+00), (-8.6859247685756013e+00, 4.9790119248836735e+00), ]; // The expected results below were computed by the high precision calculators // at https://keisan.casio.com/. More exact input values (array vc[], above) // were obtained by printing them with "%.26f". The answers were calculated // to 26 digits (by using the "Digit number" drop-down control of each // calculator). const TEST_ABS: []f64 = [ 9.2022120669932650313380972e+00, 7.7438239742296106616261394e+00, 5.0182478202557746902556648e+00, 1.0861137372799545160704002e+01, 1.0070841084922199607011905e+01, 5.9922447613166942183705192e+00, 5.8978784056736762299945176e+00, 3.2822866700678709020367184e+00, 8.8756430028990417290744307e+00, 1.0011785496777731986390856e+01, ]; const TEST_ACOS: []c128 = [ (1.0017679804707456328694569, -2.9138232718554953784519807), (0.03606427612041407369636057, 2.7358584434576260925091256), (1.6249365462333796703711823, 2.3159537454335901187730929), (2.0485650849650740120660391, -3.0795576791204117911123886), (0.29621132089073067282488147, -3.0007392508200622519398814), (1.0664555914934156601503632, -2.4872865024796011364747111), (0.48681307452231387690013905, -2.463655912283054555225301), (0.6116977071277574248407752, -1.8734458851737055262693056), (1.3649311280370181331184214, 2.8793528632328795424123832), (2.6189310485682988308904501, -2.9956543302898767795858704), ]; const TEST_ACOSH: []c128 = [ (2.9138232718554953784519807, 1.0017679804707456328694569), (2.7358584434576260925091256, -0.03606427612041407369636057), (2.3159537454335901187730929, -1.6249365462333796703711823), (3.0795576791204117911123886, 2.0485650849650740120660391), (3.0007392508200622519398814, 0.29621132089073067282488147), (2.4872865024796011364747111, 1.0664555914934156601503632), (2.463655912283054555225301, 0.48681307452231387690013905), (1.8734458851737055262693056, 0.6116977071277574248407752), (2.8793528632328795424123832, -1.3649311280370181331184214), (2.9956543302898767795858704, 2.6189310485682988308904501), ]; const TEST_ASIN: []c128 = [ (0.56902834632415098636186476, 2.9138232718554953784519807), (1.5347320506744825455349611, -2.7358584434576260925091256), (-0.054140219438483051139860579, -2.3159537454335901187730929), (-0.47776875817017739283471738, 3.0795576791204117911123886), (1.2745850059041659464064402, 3.0007392508200622519398814), (0.50434073530148095908095852, 2.4872865024796011364747111), (1.0839832522725827423311826, 2.463655912283054555225301), (0.9590986196671391943905465, 1.8734458851737055262693056), (0.20586519875787848611290031, -2.8793528632328795424123832), (-1.0481347217734022116591284, 2.9956543302898767795858704), ]; const TEST_ASINH: []c128 = [ (2.9113760469415295679342185, 0.99639459545704326759805893), (2.7441755423994259061579029, -0.035468308789000500601119392), (-2.2962136462520690506126678, -1.5144663565690151885726707), (-3.0771233459295725965402455, 1.0895577967194013849422294), (3.0048366100923647417557027, 0.29346979169819220036454168), (2.4800059370795363157364643, 1.0545868606049165710424232), (2.4718773838309585611141821, 0.47502344364250803363708842), (1.8910743588080159144378396, 0.56882925572563602341139174), (2.8735426423367341878069406, -1.362376149648891420997548), (-2.9981750586172477217567878, 0.5183571985225367505624207), ]; const TEST_ATAN: []c128 = [ (1.5115747079332741358607654, 0.091324403603954494382276776), (1.4424504323482602560806727, -0.0045416132642803911503770933), (-1.5593488703630532674484026, -0.20163295409248362456446431), (-1.5280619472445889867794105, 0.081721556230672003746956324), (1.4759909163240799678221039, 0.028602969320691644358773586), (1.4877353772046548932715555, 0.14566877153207281663773599), (1.4206983927779191889826, 0.076830486127880702249439993), (1.3162236060498933364869556, 0.16031313000467530644933363), (1.5473450684303703578810093, -0.11064907507939082484935782), (-1.4841462340185253987375812, 0.049341850305024399493142411), ]; const TEST_ATANH: []c128 = [ (0.058375027938968509064640438, 1.4793488495105334458167782), (0.12977343497790381229915667, -1.5661009410463561327262499), (-0.010576456067347252072200088, -1.3743698658402284549750563), (-0.042218595678688358882784918, 1.4891433968166405606692604), (0.095218997991316722061828397, 1.5416884098777110330499698), (0.079965459366890323857556487, 1.4252510353873192700350435), (0.15051245471980726221708301, 1.4907432533016303804884461), (0.25082072933993987714470373, 1.392057665392187516442986), (0.022896108815797135846276662, -1.4609224989282864208963021), (-0.08665624101841876130537396, 1.5207902036935093480142159), ]; const TEST_CONJ: []c128 = [ (4.9790119248836735e+00, -7.7388724745781045e+00), (7.7388724745781045e+00, 2.7688005719200159e-01), (-2.7688005719200159e-01, 5.0106036182710749e+00), (-5.0106036182710749e+00, -9.6362937071984173e+00), (9.6362937071984173e+00, -2.9263772392439646e+00), (2.9263772392439646e+00, -5.2290834314593066e+00), (5.2290834314593066e+00, -2.7279399104360102e+00), (2.7279399104360102e+00, -1.8253080916808550e+00), (1.8253080916808550e+00, 8.6859247685756013e+00), (-8.6859247685756013e+00, -4.9790119248836735e+00), ]; const TEST_COS: []c128 = [ (3.024540920601483938336569e+02, 1.1073797572517071650045357e+03), (1.192858682649064973252758e-01, 2.7857554122333065540970207e-01), (7.2144394304528306603857962e+01, -2.0500129667076044169954205e+01), (2.24921952538403984190541e+03, -7.317363745602773587049329e+03), (-9.148222970032421760015498e+00, 1.953124661113563541862227e+00), (-9.116081175857732248227078e+01, -1.992669213569952232487371e+01), (3.795639179042704640002918e+00, 6.623513350981458399309662e+00), (-2.9144840732498869560679084e+00, -1.214620271628002917638748e+00), (-7.45123482501299743872481e+02, 2.8641692314488080814066734e+03), (-5.371977967039319076416747e+01, 4.893348341339375830564624e+01), ]; const TEST_COSH: []c128 = [ (8.34638383523018249366948e+00, 7.2181057886425846415112064e+01), (1.10421967379919366952251e+03, -3.1379638689277575379469861e+02), (3.051485206773701584738512e-01, -2.6805384730105297848044485e-01), (-7.33294728684187933370938e+01, 1.574445942284918251038144e+01), (-7.478643293945957535757355e+03, 1.6348382209913353929473321e+03), (4.622316522966235701630926e+00, -8.088695185566375256093098e+00), (-8.544333183278877406197712e+01, 3.7505836120128166455231717e+01), (-1.934457815021493925115198e+00, 7.3725859611767228178358673e+00), (-2.352958770061749348353548e+00, -2.034982010440878358915409e+00), (7.79756457532134748165069e+02, 2.8549350716819176560377717e+03), ]; const TEST_EXP: []c128 = [ (1.669197736864670815125146e+01, 1.4436895109507663689174096e+02), (2.2084389286252583447276212e+03, -6.2759289284909211238261917e+02), (2.227538273122775173434327e-01, 7.2468284028334191250470034e-01), (-6.5182985958153548997881627e-03, -1.39965837915193860879044e-03), (-1.4957286524084015746110777e+04, 3.269676455931135688988042e+03), (9.218158701983105935659273e+00, -1.6223985291084956009304582e+01), (-1.7088175716853040841444505e+02, 7.501382609870410713795546e+01), (-3.852461315830959613132505e+00, 1.4808420423156073221970892e+01), (-4.586775503301407379786695e+00, -4.178501081246873415144744e+00), (4.451337963005453491095747e-05, -1.62977574205442915935263e-04), ]; const TEST_LOG: []c128 = [ (2.2194438972179194425697051e+00, 9.9909115046919291062461269e-01), (2.0468956191154167256337289e+00, -3.5762575021856971295156489e-02), (1.6130808329853860438751244e+00, -1.6259990074019058442232221e+00), (2.3851910394823008710032651e+00, 2.0502936359659111755031062e+00), (2.3096442270679923004800651e+00, 2.9483213155446756211881774e-01), (1.7904660933974656106951860e+00, 1.0605860367252556281902109e+00), (1.7745926939841751666177512e+00, 4.8084556083358307819310911e-01), (1.1885403350045342425648780e+00, 5.8969634164776659423195222e-01), (2.1833107837679082586772505e+00, -1.3636647724582455028314573e+00), (2.3037629487273259170991671e+00, 2.6210913895386013290915234e+00), ]; const TEST_LOG10: []c128 = [ (9.6389223745559042474184943e-01, 4.338997735671419492599631e-01), (8.8895547241376579493490892e-01, -1.5531488990643548254864806e-02), (7.0055210462945412305244578e-01, -7.0616239649481243222248404e-01), (1.0358753067322445311676952e+00, 8.9043121238134980156490909e-01), (1.003065742975330237172029e+00, 1.2804396782187887479857811e-01), (7.7758954439739162532085157e-01, 4.6060666333341810869055108e-01), (7.7069581462315327037689152e-01, 2.0882857371769952195512475e-01), (5.1617650901191156135137239e-01, 2.5610186717615977620363299e-01), (9.4819982567026639742663212e-01, -5.9223208584446952284914289e-01), (1.0005115362454417135973429e+00, 1.1383255270407412817250921e+00), ]; const TEST_POLAR: []c128 = [ (9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01), (7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02), (5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00), (1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00), (1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01), (5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00), (5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01), (3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01), (8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00), (1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00), ]; const TEST_POW: []c128 = [ (-2.499956739197529585028819e+00, 1.759751724335650228957144e+00), (7.357094338218116311191939e+04, -5.089973412479151648145882e+04), (1.320777296067768517259592e+01, -3.165621914333901498921986e+01), (-3.123287828297300934072149e-07, -1.9849567521490553032502223e-7), (8.0622651468477229614813e+04, -7.80028727944573092944363e+04), (-1.0268824572103165858577141e+00, -4.716844738244989776610672e-01), (-4.35953819012244175753187e+01, 2.2036445974645306917648585e+02), (8.3556092283250594950239e-01, -1.2261571947167240272593282e+01), (1.582292972120769306069625e+03, 1.273564263524278244782512e+04), (6.592208301642122149025369e-08, 2.584887236651661903526389e-08), ]; const TEST_SIN: []c128 = [ (-1.1073801774240233539648544e+03, 3.024539773002502192425231e+02), (1.0317037521400759359744682e+00, -3.2208979799929570242818e-02), (-2.0501952097271429804261058e+01, -7.2137981348240798841800967e+01), (7.3173638080346338642193078e+03, 2.249219506193664342566248e+03), (-1.964375633631808177565226e+00, -9.0958264713870404464159683e+00), (1.992783647158514838337674e+01, -9.11555769410191350416942e+01), (-6.680335650741921444300349e+00, 3.763353833142432513086117e+00), (1.2794028166657459148245993e+00, -2.7669092099795781155109602e+00), (2.8641693949535259594188879e+03, 7.451234399649871202841615e+02), (-4.893811726244659135553033e+01, -5.371469305562194635957655e+01), ]; const TEST_SINH: []c128 = [ (8.34559353341652565758198e+00, 7.2187893208650790476628899e+01), (1.1042192548260646752051112e+03, -3.1379650595631635858792056e+02), (-8.239469336509264113041849e-02, 9.9273668758439489098514519e-01), (7.332295456982297798219401e+01, -1.574585908122833444899023e+01), (-7.4786432301380582103534216e+03, 1.63483823493980029604071e+03), (4.595842179016870234028347e+00, -8.135290105518580753211484e+00), (-8.543842533574163435246793e+01, 3.750798997857594068272375e+01), (-1.918003500809465688017307e+00, 7.4358344619793504041350251e+00), (-2.233816733239658031433147e+00, -2.143519070805995056229335e+00), (-7.797564130187551181105341e+02, -2.8549352346594918614806877e+03), ]; const TEST_SQRT: []c128 = [ (2.6628203086086130543813948e+00, 1.4531345674282185229796902e+00), (2.7823278427251986247149295e+00, -4.9756907317005224529115567e-02), (1.5397025302089642757361015e+00, -1.6271336573016637535695727e+00), (1.7103411581506875260277898e+00, 2.8170677122737589676157029e+00), (3.1390392472953103383607947e+00, 4.6612625849858653248980849e-01), (2.1117080764822417640789287e+00, 1.2381170223514273234967850e+00), (2.3587032281672256703926939e+00, 5.7827111903257349935720172e-01), (1.7335262588873410476661577e+00, 5.2647258220721269141550382e-01), (2.3131094974708716531499282e+00, -1.8775429304303785570775490e+00), (8.1420535745048086240947359e-01, 3.0575897587277248522656113e+00), ]; const TEST_TAN: []c128 = [ (-1.928757919086441129134525e-07, 1.0000003267499169073251826e+00), (1.242412685364183792138948e+00, -3.17149693883133370106696e+00), (-4.6745126251587795225571826e-05, -9.9992439225263959286114298e-01), (4.792363401193648192887116e-09, 1.0000000070589333451557723e+00), (2.345740824080089140287315e-03, 9.947733046570988661022763e-01), (-2.396030789494815566088809e-05, 9.9994781345418591429826779e-01), (-7.370204836644931340905303e-03, 1.0043553413417138987717748e+00), (-3.691803847992048527007457e-02, 9.6475071993469548066328894e-01), (-2.781955256713729368401878e-08, -1.000000049848910609006646e+00), (9.4281590064030478879791249e-05, 9.9999119340863718183758545e-01), ]; const TEST_TANH: []c128 = [ (1.0000921981225144748819918e+00, 2.160986245871518020231507e-05), (9.9999967727531993209562591e-01, -1.9953763222959658873657676e-07), (-1.765485739548037260789686e+00, 1.7024216325552852445168471e+00), (-9.999189442732736452807108e-01, 3.64906070494473701938098e-05), (9.9999999224622333738729767e-01, -3.560088949517914774813046e-09), (1.0029324933367326862499343e+00, -4.948790309797102353137528e-03), (9.9996113064788012488693567e-01, -4.226995742097032481451259e-05), (1.0074784189316340029873945e+00, -4.194050814891697808029407e-03), (9.9385534229718327109131502e-01, 5.144217985914355502713437e-02), (-1.0000000491604982429364892e+00, -2.901873195374433112227349e-08), ]; // huge values along the real axis for testing reducepi in tan // TODO: these probably shouldn't have to be casted twice (harec bug?) const TEST_HUGEIN: []c128 = [ ((1 << 28): u64: f64, 0f64), ((1 << 29): u64: f64, 0f64), ((1 << 30): u64: f64, 0f64), ((1 << 35): u64: f64, 0f64), (-1.329227995784916e+36, 0f64), (1.7668470647783843e+72, 0f64), (2.037035976334486e+90, 0f64), (-3.1217485503159922e+144, 0f64), (1.8919697882131776e+69, 0f64), (-2.514859209672214e+105, 0f64), ]; // Results for TEST_TANHUGE[i] calculated with https://github.com/robpike/ivy // using 4096 bits of working precision. const TEST_TANHUGE: []c128 = [ ((5.95641897939639421): f64, 0f64), ((-0.34551069233430392): f64, 0f64), ((-0.78469661331920043): f64, 0f64), ((0.84276385870875983): f64, 0f64), ((0.40806638884180424): f64, 0f64), ((-0.37603456702698076): f64, 0f64), ((4.60901287677810962): f64, 0f64), ((3.39135965054779932): f64, 0f64), ((-6.76813854009065030): f64, 0f64), ((-0.76417695016604922): f64, 0f64), ]; const TEST_VCABSSC: []c128 = [ (math::NAN, math::NAN), ]; const TEST_ABSSC: []f64 = [ math::NAN, ]; const TEST_ACOSSC: [](c128, c128) = [ // G.6.1.1 ((0f64, 0f64), (math::PI / 2f64, -0f64)), ((-0f64, 0f64), (math::PI / 2f64, -0f64)), ((0f64, math::NAN), (math::PI / 2f64, math::NAN)), ((-0f64, math::NAN), (math::PI / 2f64, math::NAN)), ((1f64, math::INF), (math::PI / 2f64, -math::INF)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((-math::INF, 1f64), (math::PI, -math::INF)), ((math::INF, 1f64), (0f64, -math::INF)), ((-math::INF, math::INF), (3f64 * math::PI / 4f64, -math::INF)), ((math::INF, math::INF), (math::PI / 4f64, -math::INF)), ((math::INF, math::NAN), (math::NAN, -math::INF)), // imaginary sign unspecified ((-math::INF, math::NAN), (math::NAN, math::INF)), // imaginary sign unspecified ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, -math::INF)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_ACOSHSC: [](c128, c128) = [ // G.6.2.1 ((0f64, 0f64), (0f64, math::PI / 2f64)), ((-0f64, 0f64), (0f64, math::PI / 2f64)), ((1f64, math::INF), (math::INF, math::PI / 2f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((-math::INF, 1f64), (math::INF, math::PI)), ((math::INF, 1f64), (math::INF, 0f64)), ((-math::INF, math::INF), (math::INF, 3f64 * math::PI / 4f64)), ((math::INF, math::INF), (math::INF, math::PI / 4f64)), ((math::INF, math::NAN), (math::INF, math::NAN)), ((-math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::INF, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_ASINSC: [](c128, c128) = [ // Derived from Asin(z) = -i * Asinh(i * z), G.6 #7 ((0f64, 0f64), (0f64, 0f64)), ((1f64, math::INF), (0f64, math::INF)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (math::PI / 2f64, math::INF)), ((math::INF, math::INF), (math::PI / 4f64, math::INF)), ((math::INF, math::NAN), (math::NAN, math::INF)), // imaginary sign unspecified ((math::NAN, 0f64), (math::NAN, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::INF)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_ASINHSC: [](c128, c128) = [ // G.6.2.2 ((0f64, 0f64), (0f64, 0f64)), ((1f64, math::INF), (math::INF, math::PI / 2f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (math::INF, 0f64)), ((math::INF, math::INF), (math::INF, math::PI / 4f64)), ((math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 0f64), (math::NAN, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::INF, math::NAN)), // sign of real part unspecified ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_ATANSC: [](c128, c128) = [ // Derived from Atan(z) = -i * Atanh(i * z), G.6 #7 ((0f64, 0f64), (0f64, 0f64)), ((0f64, math::NAN), (math::NAN, math::NAN)), ((1f64, 0f64), (math::PI / 4f64, 0f64)), ((1f64, math::INF), (math::PI / 2f64, 0f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (math::PI / 2f64, 0f64)), ((math::INF, math::INF), (math::PI / 2f64, 0f64)), ((math::INF, math::NAN), (math::PI / 2f64, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, 0f64)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_ATANHSC: [](c128, c128) = [ // G.6.2.3 ((0f64, 0f64), (0f64, 0f64)), ((0f64, math::NAN), (0f64, math::NAN)), ((1f64, 0f64), (math::INF, 0f64)), ((1f64, math::INF), (0f64, math::PI / 2f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (0f64, math::PI / 2f64)), ((math::INF, math::INF), (0f64, math::PI / 2f64)), ((math::INF, math::NAN), (0f64, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (0f64, math::PI / 2f64)), // sign of real part not specified. ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_VCCONJSC: []c128 = [ (math::NAN, math::NAN), ]; const TEST_CONJSC: []c128 = [ (math::NAN, math::NAN), ]; const TEST_COSSC: [](c128, c128) = [ // Derived from Cos(z) = Cosh(i * z), G.6 #7 ((0f64, 0f64), (1f64, -0f64)), ((0f64, math::INF), (math::INF, -0f64)), ((0f64, math::NAN), (math::NAN, 0f64)), // imaginary sign unspecified ((1f64, math::INF), (math::INF, -math::INF)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 0f64), (math::NAN, -0f64)), ((math::INF, 1f64), (math::NAN, math::NAN)), ((math::INF, math::INF), (math::INF, math::NAN)), // real sign unspecified ((math::INF, math::NAN), (math::NAN, math::NAN)), ((math::NAN, 0f64), (math::NAN, -0f64)), // imaginary sign unspecified ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::INF, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_COSHSC: [](c128, c128) = [ // G.6.2.4 ((0f64, 0f64), (1f64, 0f64)), ((0f64, math::INF), (math::NAN, 0f64)), // imaginary sign unspecified ((0f64, math::NAN), (math::NAN, 0f64)), // imaginary sign unspecified ((1f64, math::INF), (math::NAN, math::NAN)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 0f64), (math::INF, 0f64)), ((math::INF, 1f64), (math::INF, math::INF)), // +(math::INF, 0f64) cis(y) ((math::INF, math::INF), (math::INF, math::NAN)), // real sign unspecified ((math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 0f64), (math::NAN, 0f64)), // imaginary sign unspecified ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_EXPSC: [](c128, c128) = [ // G.6.3.1 ((0f64, 0f64), (1f64, 0f64)), ((-0f64, 0f64), (1f64, 0f64)), ((1f64, math::INF), (math::NAN, math::NAN)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 0f64), (math::INF, 0f64)), ((-math::INF, 1f64), (0f64, 0f64)), ((math::INF, 1f64), (math::INF, math::INF)), ((-math::INF, math::INF), (0f64, 0f64)), // real and imaginary sign unspecified ((math::INF, math::INF), (math::INF, math::NAN)), // real sign unspecified ((-math::INF, math::NAN), (0f64, 0f64)), // real and imaginary sign unspecified ((math::INF, math::NAN), (math::INF, math::NAN)), // real sign unspecified ((math::NAN, 0f64), (math::NAN, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_VCISNANSC: []c128 = [ (-math::INF, -math::INF), (-math::INF, math::NAN), (math::NAN, -math::INF), (0f64, math::NAN), (math::NAN, 0f64), (math::INF, math::INF), (math::INF, math::NAN), (math::NAN, math::INF), (math::NAN, math::NAN), ]; const TEST_ISNANSC: []bool = [ false, false, false, true, true, false, false, false, true, ]; // XXX: math::PI doesn't have suitable precision here for some reason const TEST_LOGSC: [](c128, c128) = [ // G.6.3.2 ((0f64, 0f64), (-math::INF, 0f64)), //((-0f64, 0f64), // (-math::INF, math::PI)), //((1f64, math::INF), // (math::INF, math::PI / 2f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), //((-math::INF, 1f64), // (math::INF, math::PI)), ((math::INF, 1f64), (math::INF, 0f64)), //((-math::INF, math::INF), // (math::INF, 3f64 * math::PI / 4f64)), //((math::INF, math::INF), // (math::INF, math::PI / 4f64)), ((-math::INF, math::NAN), (math::INF, math::NAN)), ((math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::INF, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_LOG10SC: [](c128, c128) = [ // derived from Log special cases via Log10(x) = math.Log10E*Log(x) ((0f64, 0f64), (-math::INF, 0f64)), ((-0f64, 0f64), (-math::INF, math::LOG10_E * math::PI)), ((1f64, math::INF), (math::INF, math::LOG10_E * math::PI / 2f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((-math::INF, 1f64), (math::INF, math::LOG10_E * math::PI)), ((math::INF, 1f64), (math::INF, 0f64)), ((-math::INF, math::INF), (math::INF, math::LOG10_E * 3f64 * math::PI / 4f64)), ((math::INF, math::INF), (math::INF, math::LOG10_E * math::PI / 4f64)), ((-math::INF, math::NAN), (math::INF, math::NAN)), ((math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::INF, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_VCPOLARSC: []c128 = [ (math::NAN, math::NAN), ]; const TEST_POLARSC: [](f64, f64) = [ (math::NAN, math::NAN), ]; const TEST_VCPOWSC: [](c128, c128) = [ ((math::NAN, math::NAN), (math::NAN, math::NAN)), ((0f64, 0f64), (math::NAN, math::NAN)), ]; const TEST_POWSC: []c128 = [ (math::NAN, math::NAN), (math::NAN, math::NAN), ]; const TEST_SINSC: [](c128, c128) = [ // Derived from Sin(z) = -i * Sinh(i * z), G.6 #7 ((0f64, 0f64), (0f64, 0f64)), ((0f64, math::INF), (0f64, math::INF)), ((0f64, math::NAN), (0f64, math::NAN)), ((1f64, math::INF), (math::INF, math::INF)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 0f64), (math::NAN, 0f64)), ((math::INF, 1f64), (math::NAN, math::NAN)), ((math::INF, math::INF), (math::NAN, math::INF)), ((math::INF, math::NAN), (math::NAN, math::NAN)), ((math::NAN, 0f64), (math::NAN, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::INF)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_SINHSC: [](c128, c128) = [ // G.6.2.5 ((0f64, 0f64), (0f64, 0f64)), ((0f64, math::INF), (0f64, math::NAN)), // real sign unspecified ((0f64, math::NAN), (0f64, math::NAN)), // real sign unspecified ((1f64, math::INF), (math::NAN, math::NAN)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 0f64), (math::INF, 0f64)), ((math::INF, 1f64), (math::INF, math::INF)), // +math::INF cis(y) ((math::INF, math::INF), (math::INF, math::NAN)), // real sign unspecified ((math::INF, math::NAN), (math::INF, math::NAN)), // real sign unspecified ((math::NAN, 0f64), (math::NAN, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_SQRTSC: [](c128, c128) = [ // G.6.4.2 ((0f64, 0f64), (0f64, 0f64)), ((-0f64, 0f64), (0f64, 0f64)), ((1f64, math::INF), (math::INF, math::INF)), ((math::NAN, math::INF), (math::INF, math::INF)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((-math::INF, 1f64), (0f64, math::INF)), ((math::INF, 1f64), (math::INF, 0f64)), ((-math::INF, math::NAN), (math::NAN, math::INF)), // imaginary sign unspecified ((math::INF, math::NAN), (math::INF, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_TANSC: [](c128, c128) = [ // Derived from Tan(z) = -i * Tanh(i * z), G.6 #7 ((0f64, 0f64), (0f64, 0f64)), ((0f64, math::NAN), (0f64, math::NAN)), ((1f64, math::INF), (0f64, 1f64)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (math::NAN, math::NAN)), ((math::INF, math::INF), (0f64, 1f64)), ((math::INF, math::NAN), (math::NAN, math::NAN)), ((math::NAN, 0f64), (math::NAN, math::NAN)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (0f64, 1f64)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; const TEST_TANHSC: [](c128, c128) = [ // G.6.2.6 ((0f64, 0f64), (0f64, 0f64)), ((1f64, math::INF), (math::NAN, math::NAN)), ((1f64, math::NAN), (math::NAN, math::NAN)), ((math::INF, 1f64), (1f64, 0f64)), // 1 + i 0 sin(2y) ((math::INF, math::INF), (1f64, 0f64)), // imaginary sign unspecified ((math::INF, math::NAN), (1f64, 0f64)), // imaginary sign unspecified ((math::NAN, 0f64), (math::NAN, 0f64)), ((math::NAN, 1f64), (math::NAN, math::NAN)), ((math::NAN, math::INF), (math::NAN, math::NAN)), ((math::NAN, math::NAN), (math::NAN, math::NAN)), ]; // branch cut continuity checks // points on each axis at |z| > 1 are checked for one-sided continuity from both // the positive and negative side // all possible branch cuts for the elementary functions are at one of these // points // TODO: this probably shouldn't need to be casted twice (harec bug?) def EPS: f64 = 1f64 / (1 << 53): u64: f64; const BRANCHPOINTS: [](c128, c128) = [ ((2f64, 0f64), (2f64, EPS)), ((2f64, -0f64), (2f64, -EPS)), ((-2.0, 0f64), (-2.0, EPS)), ((-2.0, -0f64), (-2.0, -EPS)), ((0f64, 2f64), (EPS, 2f64)), ((-0f64, 2f64), (-EPS, 2f64)), ((0f64, -2.0), (EPS, -2.0)), ((-0f64, -2.0), (-EPS, -2.0)), ]; fn tolerance(actual: f64, expected: f64, e: f64) bool = { const err = math::absf64(actual - expected); if (expected != 0f64) { e = math::absf64(e * expected); }; return err < e; }; fn veryclose(a: f64, b: f64) bool = tolerance(a, b, 4e-16); fn alike(a: f64, b: f64) bool = { if (math::isnan(a) && math::isnan(b)) { return true; }; if (a == b) { return math::signf64(a) == math::signf64(b); }; return false; }; fn csoclose(a: c128, b: c128, e: f64) bool = { const d = absc128(subc128(a, b)); if (b.0 != 0f64 || b.1 != 0f64) { e *= absc128(b); if (e < 0f64) { e = -e; }; }; return d < e; }; fn cveryclose(a: c128, b: c128) bool = csoclose(a, b, 4e-16); fn calike(a: c128, b: c128) bool = { let realalike = false, imagalike = false; realalike = if (isexact(b.0)) { yield alike(a.0, b.0); } else { // Allow non-exact special cases to have errors in ULP. yield veryclose(a.0, b.0); }; imagalike = if (isexact(b.1)) { yield alike(a.1, b.1); } else { // Allow non-exact special cases to have errors in ULP. yield veryclose(a.1, b.1); }; return realalike && imagalike; }; // Special cases that should match exactly. Other cases are multiples of pi that // may not be last bit identical on all platforms. fn isexact(x: f64) bool = math::isnan(x) || math::isinf(x) || x == 0f64 || x == 1f64 || x == -1f64; @test fn abs() void = { for (let i = 0z; i < len(VC); i += 1) { assert(veryclose(TEST_ABS[i], absc128(VC[i]))); }; for (let i = 0z; i < len(TEST_VCABSSC); i += 1) { assert(alike(TEST_ABSSC[i], absc128(TEST_VCABSSC[i]))); }; }; @test fn acos() void = { for (let i = 0z; i < len(VC); i += 1) { // XXX: should have 1e-14 precision assert(csoclose(TEST_ACOS[i], acosc128(VC[i]), 1e-7)); }; for (let i = 0z; i < len(TEST_ACOSSC); i += 1) { const v = TEST_ACOSSC[i]; assert(calike(v.1, acosc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // acos(conj(z)) == conj(acos(z)) assert(calike(conjc128(v.1), acosc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(acosc128(pt.0), acosc128(pt.1))); }; }; @test fn acosh() void = { for (let i = 0z; i < len(VC); i += 1) { // XXX: should have 1e-14 precision assert(csoclose(TEST_ACOSH[i], acoshc128(VC[i]), 1e-7)); }; for (let i = 0z; i < len(TEST_ACOSHSC); i += 1) { const v = TEST_ACOSHSC[i]; assert(calike(v.1, acoshc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // acosh(conj(z)) == conj(acosh(z)) assert(calike(conjc128(v.1), acoshc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(acoshc128(pt.0), acoshc128(pt.1))); }; }; @test fn asin() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_ASIN[i], asinc128(VC[i]), 1e-14)); }; for (let i = 0z; i < len(TEST_ASINSC); i += 1) { const v = TEST_ASINSC[i]; assert(calike(v.1, asinc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // asin(conj(z)) == asin(sinh(z)) assert(calike(conjc128(v.1), asinc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // asin(-z) == -asin(z) assert(calike((-v.1.0, -v.1.1), asinc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(asinc128(pt.0), asinc128(pt.1))); }; }; @test fn asinh() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_ASINH[i], asinhc128(VC[i]), 4e-15)); }; for (let i = 0z; i < len(TEST_ASINHSC); i += 1) { const v = TEST_ASINHSC[i]; assert(calike(v.1, asinhc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // asinh(conj(z)) == asinh(sinh(z)) assert(calike(conjc128(v.1), asinhc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // asinh(-z) == -asinh(z) assert(calike((-v.1.0, -v.1.1), asinhc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(asinhc128(pt.0), asinhc128(pt.1))); }; }; @test fn atan() void = { for (let i = 0z; i < len(VC); i += 1) { assert(cveryclose(TEST_ATAN[i], atanc128(VC[i]))); }; for (let i = 0z; i < len(TEST_ATANSC); i += 1) { const v = TEST_ATANSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, atanc128(v.0))); // atan(conj(z)) == conj(atan(z)) assert(calike(conjc128(v.1), atanc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // atan(-z) == -atan(z) assert(calike((-v.1.0, -v.1.1), atanc128((-v.0.0, -v.0.1))) || calike((v.0), conjc128(v.0))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(atanc128(pt.0), atanc128(pt.1))); }; }; @test fn atanh() void = { for (let i = 0z; i < len(VC); i += 1) { assert(cveryclose(TEST_ATANH[i], atanhc128(VC[i]))); }; for (let i = 0z; i < len(TEST_ATANHSC); i += 1) { const v = TEST_ATANHSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, atanhc128(v.0))); // atanh(conj(z)) == conj(atanh(z)) assert(calike(conjc128(v.1), atanhc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // atanh(-z) == -atanh(z) assert(calike((-v.1.0, -v.1.1), atanhc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(atanhc128(pt.0), atanhc128(pt.1))); }; }; @test fn conj() void = { for (let i = 0z; i < len(VC); i += 1) { assert(cveryclose(TEST_CONJ[i], conjc128(VC[i]))); }; for (let i = 0z; i < len(TEST_VCCONJSC); i += 1) { assert(calike(TEST_CONJSC[i], conjc128(TEST_VCCONJSC[i]))); }; }; @test fn cos() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_COS[i], cosc128(VC[i]), 3e-15)); }; for (let i = 0z; i < len(TEST_COSSC); i += 1) { const v = TEST_COSSC[i]; if (isnan(v.0) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, cosc128(v.0))); // cos(conj(z)) == cos(cosh(z)) assert (calike(conjc128(v.1), cosc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // cos(-z) == cos(z) assert(calike(v.1, cosc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn cosh() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_COSH[i], coshc128(VC[i]), 2e-15)); }; for (let i = 0z; i < len(TEST_COSHSC); i += 1) { const v = TEST_COSHSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, coshc128(v.0))); // cosh(conj(z)) == conj(cosh(z)) assert(calike(conjc128(v.1), coshc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // cosh(-z) == cosh(z) assert(calike(v.1, coshc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn exp() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_EXP[i], expc128(VC[i]), 1e-15)); }; for (let i = 0z; i < len(TEST_EXPSC); i += 1) { const v = TEST_EXPSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, expc128(v.0))); // exp(conj(z)) == exp(cosh(z)) assert(calike(conjc128(v.1), expc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); }; }; @test fn isnan() void = { for (let i = 0z; i < len(TEST_VCISNANSC); i += 1) { assert(TEST_ISNANSC[i] == isnan(TEST_VCISNANSC[i])); }; }; @test fn log() void = { for (let i = 0z; i < len(VC); i += 1) { assert(cveryclose(TEST_LOG[i], logc128(VC[i]))); }; for (let i = 0z; i < len(TEST_LOGSC); i += 1) { const v = TEST_LOGSC[i]; assert(calike(v.1, logc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // log(conj(z)) == conj(log(z)) assert(calike(conjc128(v.1), logc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(logc128(pt.0), logc128(pt.1))); }; }; @test fn polar() void = { for (let i = 0z; i < len(VC); i += 1) { const p = polarc128(VC[i]); assert(veryclose(TEST_POLAR[i].0, p.0) || veryclose(TEST_POLAR[i].1, p.1)); }; for (let i = 0z; i < len(TEST_VCPOLARSC); i += 1) { const p = polarc128(TEST_VCPOLARSC[i]); assert(alike(TEST_POLARSC[i].0, p.0) || alike(TEST_POLARSC[i].1, p.1)); }; }; @test fn pow() void = { // Special cases for pow(0, c). const zeropowers: [](c128, c128) = [ ((0f64, 0f64), (1f64, 0f64)), ((1.5, 0f64), (0f64, 0f64)), ((-1.5, 0f64), (math::INF, 0f64)), ((-1.5, 1.5), (math::INF, math::INF)), ]; for (let i = 0z; i < len(zeropowers); i += 1) { const zp = zeropowers[i]; assert(equalc128(powc128((0f64, 0f64), zp.0), zp.1)); }; const a = (3f64, 3f64); for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_POW[i], powc128(a, VC[i]), 4e-15)); }; for (let i = 0z; i < len(TEST_VCPOWSC); i += 1) { const f = TEST_VCPOWSC[i]; assert(calike(TEST_POWSC[i], powc128(f.0, f.1))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(powc128(pt.0, (0.1, 0f64)), powc128(pt.1, (0.1, 0f64)))); }; }; @test fn rect() void = { for (let i = 0z; i < len(VC); i += 1) { const f = TEST_POLAR[i]; assert(cveryclose(VC[i], rectc128(f.0, f.1))); }; for (let i = 0z; i < len(TEST_VCPOLARSC); i += 1) { const f = TEST_POLARSC[i]; assert(calike(TEST_VCPOLARSC[i], rectc128(f.0, f.1))); }; }; @test fn sin() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_SIN[i], sinc128(VC[i]), 2e-15)); }; for (let i = 0z; i < len(TEST_SINSC); i += 1) { const v = TEST_SINSC[i]; assert(calike(v.1, sinc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // sin(conj(z)) == conj(sin(z)) assert(calike(conjc128(sinc128(v.0)), sinc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // sin(-z) == -sin(z) assert(calike((-v.1.0, -v.1.1), sinc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn sinh() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_SINH[i], sinhc128(VC[i]), 2e-15)); }; for (let i = 0z; i < len(TEST_SINHSC); i += 1) { const v = TEST_SINHSC[i]; assert(calike(v.1, sinhc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // sinh(conj(z)) == conj(sinh(z)) assert(calike(conjc128(v.1), sinhc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // sinh(-z) == -sinh(z) assert(calike((-v.1.0, -v.1.1), sinhc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn sqrt() void = { for (let i = 0z; i < len(VC); i += 1) { assert(cveryclose(TEST_SQRT[i], sqrtc128(VC[i]))); }; for (let i = 0z; i < len(TEST_SQRTSC); i += 1) { const v = TEST_SQRTSC[i]; assert(calike(v.1, sqrtc128(v.0))); if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // sqrt(conj(z)) == conj(sqrt(z)) assert(calike(conjc128(v.1), sqrtc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); }; for (let i = 0z; i < len(BRANCHPOINTS); i += 1) { const pt = BRANCHPOINTS[i]; assert(cveryclose(sqrtc128(pt.0), sqrtc128(pt.1))); }; }; @test fn tan() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_TAN[i], tanc128(VC[i]), 3e-15)); }; for (let i = 0z; i < len(TEST_TANSC); i += 1) { const v = TEST_TANSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; if (math::isnan(v.0.0) && math::isinf(v.0.1)) { const r = tanc128(v.0); assert(r.0 == v.1.0 && r.1 == v.1.1); continue; }; assert(calike(v.1, tanc128(v.0))); // tan(conj(z)) == conj(tan(z)) assert (calike(conjc128(v.1), tanc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // tan(-z) == -tan(z) assert(calike((-v.1.0, -v.1.1), tanc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn tanh() void = { for (let i = 0z; i < len(VC); i += 1) { assert(csoclose(TEST_TANH[i], tanhc128(VC[i]), 2e-15)); }; for (let i = 0z; i < len(TEST_TANHSC); i += 1) { const v = TEST_TANHSC[i]; if (math::isnan(v.0.1) || math::isnan(v.1.1)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; assert(calike(v.1, tanhc128(v.0))); // tanh(conj(z)) == conj(tanh(z)) assert(calike(conjc128(v.1), tanhc128(conjc128(v.0))) || calike(v.0, conjc128(v.0))); if (math::isnan(v.0.0) || math::isnan(v.1.0)) { // Negating NaN is undefined with regard to the sign bit // produced. continue; }; // tanh(-z) == -tanh(z) assert(calike((-v.1.0, -v.1.1), tanhc128((-v.0.0, -v.0.1))) || calike(v.0, (-v.0.0, -v.0.1))); }; }; @test fn tanhuge() void = { for (let i = 0z; i < len(TEST_HUGEIN); i += 1) { assert(csoclose(TEST_TANHUGE[i], tanc128(TEST_HUGEIN[i]), 1e-15)); }; }; hare-0.24.2/math/complex/README000066400000000000000000000001221464473310100157740ustar00rootroot00000000000000math::complex provides functions for working with complex floating-point numbers. hare-0.24.2/math/complex/complex.ha000066400000000000000000000507661464473310100171200ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Sections of the code below are based on Go's implementation, which is, in // turn, based on Cephes Math Library. The original C code can be found at // http://netlib.sandia.gov/cephes/c9x-complex/. // // Cephes Math Library Release 2.8: June, 2000 // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier // // The readme file at http://netlib.sandia.gov/cephes/ says: // Some software in this archive may be from the book _Methods and // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster // International, 1989) or from the Cephes Mathematical Library, a // commercial product. In either event, it is copyrighted by the author. // What you see here may be used freely but it comes with no support or // guarantee. // // The two known misprints in the book are repaired here in the // source listings for the gamma function and the incomplete beta // integral. // // Stephen L. Moshier // moshier@na-net.ornl.gov // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== use math; // A complex number containing a real component and an imaginary component, // represented as two single-precision floating point numbers. export type c64 = (f32, f32); // A complex number containing a real component and an imaginary component, // represented as two double-precision floating point numbers. export type c128 = (f64, f64); // A tagged union of all complex types. export type complex = (c64 | c128); // Converts a [[c64]] to a [[c128]]. export fn c64to128(z: c64) c128 = (z.0: f64, z.1: f64); // Truncates a [[c128]] to a [[c64]]. Precision may be lost. export fn c128to64(z: c128) c64 = (z.0: f32, z.1: f32); // Adds two complex numbers export fn addc64(a: c64, b: c64) c64 = (a.0 + b.0, a.1 + b.1); // Adds two complex numbers. export fn addc128(a: c128, b: c128) c128 = (a.0 + b.0, a.1 + b.1); // Subtracts two complex numbers. export fn subc64(a: c64, b: c64) c64 = (a.0 - b.0, a.1 - b.1); // Subtracts two complex numbers. export fn subc128(a: c128, b: c128) c128 = (a.0 - b.0, a.1 - b.1); // Multiplies two complex numbers. export fn mulc64(a: c64, b: c64) c64 = (a.0 * b.0 - a.1 * b.1, a.1 * b.0 + a.0 * b.1); // Multiplies two complex numbers. export fn mulc128(a: c128, b: c128) c128 = (a.0 * b.0 - a.1 * b.1, a.1 * b.0 + a.0 * b.1); // Divides two complex numbers. export fn divc64(a: c64, b: c64) c64 = { const denom = b.0 * b.0 + b.1 * b.1; return ( (a.0 * b.0 + a.1 * b.1) / denom, (a.1 * b.0 - a.0 * b.1) / denom, ); }; // Divides two complex numbers. export fn divc128(a: c128, b: c128) c128 = { const denom = b.0 * b.0 + b.1 * b.1; return ( (a.0 * b.0 + a.1 * b.1) / denom, (a.1 * b.0 - a.0 * b.1) / denom, ); }; // Takes the conjugate of a complex number by negating the imaginary component. export fn conjc64(z: c64) c64 = (z.0, -z.1); // Takes the conjugate of a complex number by negating the imaginary component. export fn conjc128(z: c128) c128 = (z.0, -z.1); // Takes the absolute value of a complex number. export fn absc128(z: c128) f64 = math::hypotf64(z.0, z.1); // Gets the argument, or phase, of a complex number. export fn argc128(z: c128) f64 = math::atan2f64(z.1, z.0); // Checks if two complex numbers are equal. Be sure to take floating point // round-off errors into account. export fn equalc64(a: c64, b: c64) bool = a.0 == b.0 && a.1 == b.1; // Checks if two complex numbers are equal. Be sure to take floating point // round-off errors into account. export fn equalc128(a: c128, b: c128) bool = a.0 == b.0 && a.1 == b.1; // Checks if two complex numbers are equal. Be sure to take floating point // round-off errors into account. export fn equal(a: complex, b: complex) bool = { match (a) { case let a: c64 => return equalc64(a, b as c64); case let a: c128 => return equalc128(a, b as c128); }; }; // Returns [[math::E]] raised to the power of z. export fn expc128(z: c128) c128 = { if (math::isinf(z.0)) { if (z.0 > 0f64 && z.1 == 0f64) { return z; }; if (math::isinf(z.1) || math::isnan(z.1)) { if (z.0 < 0f64) { return (0f64, math::copysignf64(0f64, z.1)); } else { return (math::INF, math::NAN); }; }; } else if (math::isnan(z.0) && z.1 == 0f64) { return (math::NAN, z.1); }; return rectc128(math::expf64(z.0), z.1); }; // Returns true if the given complex number is infinite. export fn isinf(z: c128) bool = math::isinf(z.0) || math::isinf(z.1); // Returns true if the given complex number is NaN -- that is -- either // component is NaN and neither component is an infinity. export fn isnan(z: c128) bool = !isinf(z) && (math::isnan(z.0) || math::isnan(z.1)); // Returns the natural logarithm of z. export fn logc128(z: c128) c128 = (math::logf64(absc128(z)), argc128(z)); // Negates z. export fn negc64(z: c64) c64 = (-z.0, -z.1); // Negates z. export fn negc128(z: c128) c128 = (-z.0, -z.1); // Creates a new [[c128]] from the polar coordinates (r, theta). export fn rectc128(r: f64, theta: f64) c128 = (r * math::cosf64(theta), r * math::sinf64(theta)); // Returns the polar coordinates of z. export fn polarc128(z: c128) (f64, f64) = (absc128(z), argc128(z)); // Returns a raised to the power of b. export fn powc128(a: c128, b: c128) c128 = { if (a.0 == 0f64 && a.1 == 0f64) { if (isnan(b)) { return (math::NAN, math::NAN); } else if (b.0 == 0f64) { return (1f64, 0f64); } else if (b.0 < 0f64) { return (math::INF, if (b.1 == 0f64) 0f64 else math::INF); } else { assert(b.0 > 0f64); return (0f64, 0f64); }; }; const mod = absc128(a); if (mod == 0f64) { return (0f64, 0f64); }; let r = math::powf64(mod, b.0); const phase = argc128(a); let theta = b.0 * phase; if (b.1 != 0f64) { r *= math::expf64(-b.1 * phase); theta += b.1 * math::logf64(mod); }; return rectc128(r, theta); }; // Projects z onto the surface of a Riemann Sphere. If z is finite, it projects // to itself. If z is infinite, it projects to positive infinity on the real // axis. export fn projc64(z: c64) c64 = if (!isinf(c64to128(z))) z else (math::INF, math::copysignf32(0f32, z.1)); // Projects z onto the surface of a Riemann Sphere. If z is finite, it projects // to itself. If z is infinite, it projects to positive infinity on the real // axis. export fn projc128(z: c128) c128 = if (!isinf(z)) z else (math::INF, math::copysignf64(0f64, z.1)); // Returns the square root of z. export fn sqrtc128(z: c128) c128 = { if (z.1 == 0f64) { if (z.0 == 0f64) { return (0f64, z.1); }; if (z.0 < 0f64) { return (0f64, math::copysignf64(math::sqrtf64(-z.0), z.1)); }; return (math::sqrtf64(z.0), z.1); }; if (math::isinf(z.1)) { return (math::INF, z.1); }; if (z.0 == 0f64) { if (z.1 < 0f64) { const r = math::sqrtf64(-0.5 * z.1); return (r, -r); } else { const r = math::sqrtf64(0.5 * z.1); return (r, r); }; }; let a = z.0, b = z.1; const scale = if (math::absf64(a) > 4f64 || math::absf64(b) > 4f64) { a *= 0.25; b *= 0.25; yield 2f64; } else { a *= 1.8014398509481984e16; // 2**54 b *= 1.8014398509481984e16; yield 7.450580596923828125e-9; // 2**-27 }; let r = math::hypotf64(a, b); const t = if (a > 0f64) { const t = math::sqrtf64(0.5 * r + 0.5 * a); r = scale * math::absf64(0.5 * b / t); yield t * scale; } else { r = math::sqrtf64(0.5 * r - 0.5 * a); const t = scale * math::absf64(0.5 * b / r); r *= scale; yield t; }; return (t, if (b < 0f64) -r else r); }; // Returns the sine of z, in radians. export fn sinc128(z: c128) c128 = { if (z.1 == 0f64 && (math::isinf(z.0) || math::isnan(z.0))) { return (math::NAN, z.1); } else if (math::isinf(z.1)) { if (z.0 == 0f64) { return z; } else if (math::isinf(z.0) || math::isnan(z.0)) { return (math::NAN, z.1); }; } else if (z.0 == 0f64 && math::isnan(z.1)) { return z; }; const shch = sinhcosh(z.1); return (math::sinf64(z.0) * shch.1, math::cosf64(z.0) * shch.0); }; // Returns the hyperbolic sine of z. export fn sinhc128(z: c128) c128 = { if (z.0 == 0f64 && (math::isinf(z.1) || math::isnan(z.1))) { return (z.0, math::NAN); } else if (math::isinf(z.0)) { if (z.1 == 0f64) { return z; } else if (math::isinf(z.1) || math::isnan(z.1)) { return (z.0, math::NAN); }; } else if (z.1 == 0f64 && math::isnan(z.0)) { return (math::NAN, z.1); }; const shch = sinhcosh(z.0); return (math::cosf64(z.1) * shch.0, math::sinf64(z.1) * shch.1); }; // Returns the arcsine, in radians, of z. export fn asinc128(z: c128) c128 = { if (z.1 == 0f64 && math::absf64(z.0) <= 1f64) { return (math::asinf64(z.0), z.1); } else if (z.0 == 0f64 && math::absf64(z.1) <= 1f64) { return (z.0, math::asinhf64(z.1)); } else if (math::isnan(z.1)) { if (z.0 == 0f64) { return (z.0, math::NAN); } else if (math::isinf(z.0)) { return (math::NAN, z.0); } else { return (math::NAN, math::NAN); }; } else if (math::isinf(z.1)) { if (math::isnan(z.0)) { return z; } else if (math::isinf(z.0)) { return (math::copysignf64(math::PI / 4f64, z.0), z.1); } else { return (math::copysignf64(0f64, z.0), z.1); }; } else if (math::isinf(z.0)) { return (math::copysignf64(math::PI / 2f64, z.0), math::copysignf64(z.0, z.1)); }; const ct = (-z.1, z.0); // i * z const zz = mulc128(z, z); const z1 = (1f64 - zz.0, -zz.1); // 1 - z * z const z2 = sqrtc128(z1); // z2 = sqrt(1 - z * z) const w = logc128(addc128(ct, z2)); return (w.1, -w.0); // -i * w }; // Returns the inverse hyperbolic sine of z. export fn asinhc128(z: c128) c128 = { if (z.1 == 0f64 && math::absf64(z.0) <= 1f64) { return (math::asinhf64(z.0), z.1); } else if (z.0 == 0f64 && math::absf64(z.1) <= 1f64) { return (z.0, math::asinf64(z.1)); } else if (math::isinf(z.0)) { if (math::isinf(z.1)) { return (z.0, math::copysignf64(math::PI / 4f64, z.1)); } else if (math::isnan(z.1)) { return z; } else { return (z.0, math::copysignf64(0f64, z.1)); }; } else if (math::isnan(z.0)) { if (z.1 == 0f64) { return z; } else if (math::isinf(z.1)) { return (z.1, z.0); } else { return (math::NAN, math::NAN); }; } else if (math::isinf(z.1)) { return (math::copysignf64(z.1, z.0), math::copysign(math::PI / 2f64, z.1)); }; const zz = mulc128(z, z); const z1 = (1f64 + zz.0, zz.1); // 1 + z * z return logc128(addc128(z, sqrtc128(z1))); // log(x + sqrt(1 + x * x)) }; // Returns the cosine of z, in radians. export fn cosc128(z: c128) c128 = { if (z.1 == 0f64 && (math::isinf(z.0) || math::isnan(z.0))) { return (math::NAN, -z.1 * math::copysignf64(0f64, z.0)); } else if (math::isinf(z.1)) { if (z.0 == 0f64) { return (math::INF, -z.0 * math::copysignf64(0f64, z.1)); } else if (math::isinf(z.0) || math::isnan(z.0)) { return (math::INF, math::NAN); }; } else if (z.0 == 0f64 && math::isnan(z.1)) { return (math::NAN, 0f64); }; const shch = sinhcosh(z.1); return (math::cosf64(z.0) * shch.1, -math::sinf64(z.0) * shch.0); }; // Returns the hyperbolic cosine of z. export fn coshc128(z: c128) c128 = { if (z.0 == 0f64 && (math::isinf(z.1) || math::isnan(z.1))) { return (math::NAN, z.0 * math::copysignf64(0f64, z.1)); } else if (math::isinf(z.0)) { if (z.1 == 0f64) { return (math::INF, z.1 * math::copysignf64(0f64, z.0)); } else if (math::isinf(z.1) || math::isnan(z.1)) { return (math::INF, math::NAN); }; } else if (z.1 == 0f64 && math::isnan(z.0)) { return (math::NAN, z.1); }; const shch = sinhcosh(z.0); return (math::cosf64(z.1) * shch.1, math::sinf64(z.1) * shch.0); }; // Returns the arccosine, in radians, of z. export fn acosc128(z: c128) c128 = { const w = asinc128(z); return (math::PI / 2f64 - w.0, -w.1); }; // Returns the inverse hyperbolic cosine of z. export fn acoshc128(z: c128) c128 = { if (z.0 == 0f64 && z.1 == 0f64) { return (0f64, math::copysignf64(math::PI / 2f64, z.1)); }; const w = acosc128(z); if (w.1 <= 0f64) { return (-w.1, w.0); // i * w }; return (w.1, -w.0); // -i * w }; fn sinhcosh(x: f64) (f64, f64) = { if (math::absf64(x) <= 0.5) { return (math::sinhf64(x), math::coshf64(x)); }; let e = math::expf64(x); const ei = 0.5 / e; e *= 0.5; return (e - ei, e + ei); }; // reducePi reduces the input argument x to the range (-Pi/2, Pi/2]. // x must be greater than or equal to 0. For small arguments it // uses Cody-Waite reduction in 3 f64 parts based on: // "Elementary Function Evaluation: Algorithms and Implementation" // Jean-Michel Muller, 1997. // For very large arguments it uses Payne-Hanek range reduction based on: // "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" // K. C. Ng et al, March 24, 1992. fn reducePi(x: f64) f64 = { // reduceThreshold is the maximum value of x where the reduction using // Cody-Waite reduction still gives accurate results. This threshold // is set by t*PIn being representable as a f64 without error // where t is given by t = floor(x * (1 / Pi)) and PIn are the leading partial // terms of Pi. Since the leading terms, PI1 and PI2 below, have 30 and 32 // trailing zero bits respectively, t should have less than 30 significant bits. // t < 1<<30 -> floor(x*(1/Pi)+0.5) < 1<<30 -> x < (1<<30-1) * Pi - 0.5 // So, conservatively we can take x < 1<<30. const reduceThreshold = (1u64 << 30): f64; if (math::absf64(x) < reduceThreshold) { // Use Cody-Waite reduction in three parts. // PI1, PI2 and PI3 comprise an extended precision value of PI // such that PI ~= PI1 + PI2 + PI3. The parts are chosen so // that PI1 and PI2 have an approximately equal number of trailing // zero bits. This ensures that t*PI1 and t*PI2 are exact for // large integer values of t. The full precision PI3 ensures the // approximation of PI is accurate to 102 bits to handle cancellation // during subtraction. const PI1 = 3.141592502593994; // 0x400921fb40000000 const PI2 = 1.5099578831723193e-07; // 0x3e84442d00000000 const PI3 = 1.0780605716316238e-14; // 0x3d08469898cc5170 let t = x / math::PI; t += 0.5; t = (t: i64): f64; return ((x - t*PI1) - t*PI2) - t*PI3; }; // Must apply Payne-Hanek range reduction const mask: u64 = 0x7FF; const shift: u64 = 64 - 11 - 1; const bias: u64 = 1023; const fracMask: u64 = (1u64 << shift) - 1; // Extract out the integer and exponent such that, // x = ix * 2 ** exp. let ix: u64 = math::f64bits(x); let exp: u64 = (ix >> shift & mask) - bias - shift; ix &= fracMask; ix |= 1u64 << shift; // mPi is the binary digits of 1/Pi as a u64 array, // that is, 1/Pi = Sum mPi[i]*2^(-64*i). // 19 64-bit digits give 1216 bits of precision // to handle the largest possible float64 exponent. let mPi: [_]u64 = [ 0x0000000000000000, 0x517cc1b727220a94, 0xfe13abe8fa9a6ee0, 0x6db14acc9e21c820, 0xff28b1d5ef5de2b0, 0xdb92371d2126e970, 0x0324977504e8c90e, 0x7f0ef58e5894d39f, 0x74411afa975da242, 0x74ce38135a2fbf20, 0x9cc8eb1cc1a99cfa, 0x4e422fc5defc941d, 0x8ffc4bffef02cc07, 0xf79788c5ad05368f, 0xb69b3f6793e584db, 0xa7a31fb34f2ff516, 0xba93dd63f5f2f8bd, 0x9e839cfbc5294975, 0x35fdafd88fc6ae84, 0x2b0198237e3db5d5, ]; // Use the exponent to extract the 3 appropriate u64 digits from mPi, // B ~ (z0, z1, z2), such that the product leading digit has the exponent -64. // Note, exp >= 50 since x >= reduceThreshold and exp < 971 for maximum f64. let digit: u64 = (exp + 64): u64 / 64; let bitshift: u64 = (exp + 64): u64 % 64; let z0: u64 = (mPi[digit] << bitshift) | (mPi[digit+1] >> (64 - bitshift)); let z1: u64 = (mPi[digit+1] << bitshift) | (mPi[digit+2] >> (64 - bitshift)); let z2: u64 = (mPi[digit+2] << bitshift) | (mPi[digit+3] >> (64 - bitshift)); // Multiply mantissa by the digits and extract the upper two digits (hi, lo). let (z2hi, z2lo) = math::mulu64(z2, ix); let (z1hi, z1lo) = math::mulu64(z1, ix); let z0lo: u64 = z0 * ix; let (lo, c) = math::addu64(z1lo, z2hi, 0); let (hi, _) = math::addu64(z0lo, z1hi, c); // Find the magnitude of the fraction. let lz: u8 = math::leading_zeros_u64(hi); let e: u64 = (bias - (lz + 1)): u64; // Clear implicit mantissa bit and shift into place. hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))); hi >>= 64 - shift; // Include the exponent and convert to a float. hi |= e << shift; x = math::f64frombits(hi); // map to (-Pi/2, Pi/2] if (x > 0.5) { x -= 1f64; }; return math::PI * x; }; // Taylor series expansion for cosh(2y) - cos(2x) fn tanSeries(z: c128) f64 = { const MACHEP = 1f64/(1u64 << 53): f64; let x = math::absf64(2f64 * z.0); let y = math::absf64(2f64 * z.1); x = reducePi(x); x = x * x; y = y * y; let x2 = 1f64; let y2 = 1f64; let f = 1f64; let rn = 0f64; let d = 0f64; for (true) { rn += 1f64; f *= rn; rn += 1f64; f *= rn; x2 *= x; y2 *= y; let t = y2 + x2; t /= f; d += t; rn += 1f64; f *= rn; rn += 1f64; f *= rn; x2 *= x; y2 *= y; t = y2 - x2; t /= f; d += t; if (!(math::absf64(t/d) > MACHEP)) { // Caution: Use ! and > instead of <= for correct behavior if t/d is NaN. // See issue https://github.com/golang/go/issues/17577. break; }; }; return d; }; // Returns the tangent of x. export fn tanc128(x: c128) c128 = { if (math::isinf(x.1)) { if (math::isinf(x.0) || math::isnan(x.0)) { return (math::copysign(0f64, x.0), math::copysign(1f64, x.1)); }; return (math::copysign(0f64, math::sinf64(2f64*x.0)), math::copysign(1f64, x.1)); }; if (x.0 == 0f64 && math::isnan(x.1)) { return x; }; let d = math::cosf64(2f64*x.0) + math::coshf64(2f64*x.1); if (math::absf64(d) < 0.25f64) { d = tanSeries(x); }; if (d == 0f64) { return (math::INF, math::INF); }; return (math::sinf64(2f64*x.0)/d, math::sinhf64(2f64*x.1)/d); }; // Returns the hyperbolic tangent of x. export fn tanhc128(x: c128) c128 = { if (math::isinf(x.0)) { if (math::isinf(x.1) || math::isnan(x.1)) { return (math::copysign(1f64, x.0), math::copysign(0f64, x.1)); }; return (math::copysign(1f64, x.0), math::copysign(0f64, math::sinf64(2f64*x.1))); }; if (x.1 == 0f64 && math::isnan(x.0)) { return x; }; let d = math::coshf64(2f64*x.0) + math::cosf64(2f64*x.1); if (d == 0f64) { return (math::INF, math::INF); }; return (math::sinhf64(2f64*x.0)/d, math::sinf64(2f64*x.1)/d); }; // Returns the inverse tangent of x. export fn atanc128(x: c128) c128 = { if (x.1 == 0f64) { return (math::atanf64(x.0), x.1); } else if (x.0 == 0f64 && math::absf64(x.1) <= 1f64) { return (x.0, math::atanhf64(x.1)); } else if (math::isinf(x.1) || math::isinf(x.0)) { if (math::isnan(x.0)) { return (math::NAN, math::copysign(0f64, x.1)); }; return (math::copysign(math::PI/2f64, x.0), math::copysign(0f64, x.1)); } else if (math::isnan(x.0) || math::isnan(x.1)) { return (math::NAN, math::NAN); }; let x2 = x.0 * x.0; let a = 1f64 - x2 - x.1 * x.1; if (a == 0f64) { return (math::NAN, math::NAN); }; let t = 0.5f64 * math::atan2f64(2f64*x.0, a); let w = reducePi(t); t = x.1 - 1f64; let b = x2 + t*t; if (b == 0f64) { return (math::NAN, math::NAN); }; t = x.1 + 1f64; let c = (x2 + t*t) / b; return (w, 0.25f64*math::logf64(c)); }; // Returns the inverse hyperbolic tangent of x. export fn atanhc128(x: c128) c128 = { let z = (-x.1, x.0); // z = i * x z = atanc128(z); return (z.1, -z.0); // z = -i * z }; hare-0.24.2/math/fenv+aarch64.ha000066400000000000000000000207371464473310100161570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Defines flags characterizing types of floating point exceptions, // Each of the flags is only defined when the target platform supports handling // the corresponding exception. Flags NONE and ALL are always // defined and correspond to a bitwise OR of none and all defined flags // respectively. Platforms may define additional nonstandard flags. // // Examples: // math::raiseexcept(math::fexcept::UNDERFLOW); // raise UNDERFLOW // math::clearexcept(math::fexcept::ALL); // clear all exceptions // // // e will be math::fexcept::INVALID // math::clearexcept(math::fexcept::ALL); // let a = 0.0/0.0; // let e = math::testexcept(math::fexcept::INVALID | math::fexcept::INEXACT); export type fexcept = enum uint { // No flags set NONE = 0, // Occurs when there is no well-defined result of an operation, such as // with 0/0 or sqrt(-1) INVALID = 1 << 0, // Occurs when an operation on finite numbers produces infinity DIVBYZERO = 1 << 1, // Occurs when the result of an operation is much bigger (by // absolute value) than the biggest representable finite number OVERFLOW = 1 << 2, // Occurs when the result of an operation is too small (by // absolute value) to be stored as a normalized number UNDERFLOW = 1 << 3, // Occurs when the result of an operation is rounded to a // value that differs from the infinite precision result. INEXACT = 1 << 4, // Combination of all flags ALL = INVALID | DIVBYZERO | OVERFLOW | UNDERFLOW | INEXACT, }; // Defines values characterizing different floating point rounding behaviors. // Each of the values is only definined when the target platform supports the // corresponding rounding mode. export type fround = enum uint { // Round towards nearest integer, with ties rounding to even TONEAREST = 0, // Round towards negative infinity DOWNWARD = 0x800000, // Round towards positive infinity UPWARD = 0x400000, // Round towards zero TOWARDZERO = 0xC00000, }; @test fn fexcept() void = { assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); raiseexcept(fexcept::INEXACT | fexcept::DIVBYZERO); assert(testexcept(fexcept::INEXACT) == fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO) == fexcept::DIVBYZERO); assert(testexcept(fexcept::UNDERFLOW) == fexcept::NONE); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO | fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT | fexcept::INVALID) == fexcept::DIVBYZERO | fexcept::INEXACT); clearexcept(fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO); raiseexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::ALL); assert(testexcept(fexcept::NONE) == fexcept::NONE); clearexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); }; @test fn fround() void = { // from musl's testsuite let f = &f64frombits; assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xc000000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0xbff0000000000000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x4000000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); let f = &f32frombits; setround(fround::TONEAREST); assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xc0000000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x0)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0xbf800000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x40000000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0x80000000)); assert(nearbyintf32(f(0xd800000)) == f(0x3f800000)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); }; hare-0.24.2/math/fenv+riscv64.ha000066400000000000000000000207261464473310100162250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Defines flags characterizing types of floating point exceptions, // Each of the flags is only defined when the target platform supports handling // the corresponding exception. Flags NONE and ALL are always // defined and correspond to a bitwise OR of none and all defined flags // respectively. Platforms may define additional nonstandard flags. // // Examples: // math::raiseexcept(math::fexcept::UNDERFLOW); // raise UNDERFLOW // math::clearexcept(math::fexcept::ALL); // clear all exceptions // // // e will be math::fexcept::INVALID // math::clearexcept(math::fexcept::ALL); // let a = 0.0/0.0; // let e = math::testexcept(math::fexcept::INVALID | math::fexcept::INEXACT); export type fexcept = enum uint { // No flags set NONE = 0, // Occurs when there is no well-defined result of an operation, such as // with 0/0 or sqrt(-1) INVALID = 1 << 0, // Occurs when an operation on finite numbers produces infinity DIVBYZERO = 1 << 3, // Occurs when the result of an operation is much bigger (by // absolute value) than the biggest representable finite number OVERFLOW = 1 << 2, // Occurs when the result of an operation is too small (by // absolute value) to be stored as a normalized number UNDERFLOW = 1 << 1, // Occurs when the result of an operation is rounded to a // value that differs from the infinite precision result. INEXACT = 1 << 4, // Combination of all flags ALL = INVALID | DIVBYZERO | OVERFLOW | UNDERFLOW | INEXACT, }; // Defines values characterizing different floating point rounding behaviors. // Each of the values is only definined when the target platform supports the // corresponding rounding mode. export type fround = enum uint { // Round towards nearest integer, with ties rounding to even TONEAREST = 0, // Round towards negative infinity DOWNWARD = 0b010, // Round towards positive infinity UPWARD = 0b011, // Round towards zero TOWARDZERO = 0b001, }; @test fn fexcept() void = { assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); raiseexcept(fexcept::INEXACT | fexcept::DIVBYZERO); assert(testexcept(fexcept::INEXACT) == fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO) == fexcept::DIVBYZERO); assert(testexcept(fexcept::UNDERFLOW) == fexcept::NONE); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO | fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT | fexcept::INVALID) == fexcept::DIVBYZERO | fexcept::INEXACT); clearexcept(fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO); raiseexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::ALL); assert(testexcept(fexcept::NONE) == fexcept::NONE); clearexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); }; @test fn fround() void = { // from musl's testsuite let f = &f64frombits; assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xc000000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0xbff0000000000000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x4000000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); let f = &f32frombits; setround(fround::TONEAREST); assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xc0000000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x0)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0xbf800000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x40000000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0x80000000)); assert(nearbyintf32(f(0xd800000)) == f(0x3f800000)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); }; hare-0.24.2/math/fenv+x86_64.ha000066400000000000000000000210061464473310100156530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Defines flags characterizing types of floating point exceptions, // Each of the flags is only defined when the target platform supports handling // the corresponding exception. Flags NONE and ALL are always // defined and correspond to a bitwise OR of none and all defined flags // respectively. Platforms may define additional nonstandard flags. // // Examples: // math::raiseexcept(math::fexcept::UNDERFLOW); // raise UNDERFLOW // math::clearexcept(math::fexcept::ALL); // clear all exceptions // // // e will be math::fexcept::INVALID // math::clearexcept(math::fexcept::ALL); // let a = 0.0/0.0; // let e = math::testexcept(math::fexcept::INVALID | math::fexcept::INEXACT); export type fexcept = enum uint { // No flags set NONE = 0, // Occurs when there is no well-defined result of an operation, such as // with 0/0 or sqrt(-1) INVALID = 1 << 0, __DENORM = 1 << 1, // arch-specific // Occurs when an operation on finite numbers produces infinity DIVBYZERO = 1 << 2, // Occurs when the result of an operation is much bigger (by // absolute value) than the biggest representable finite number OVERFLOW = 1 << 3, // Occurs when the result of an operation is too small (by // absolute value) to be stored as a normalized number UNDERFLOW = 1 << 4, // Occurs when the result of an operation is rounded to a // value that differs from the infinite precision result. INEXACT = 1 << 5, // Combination of all flags ALL = INVALID | __DENORM | DIVBYZERO | OVERFLOW | UNDERFLOW | INEXACT, }; // Defines values characterizing different floating point rounding behaviors. // Each of the values is only definined when the target platform supports the // corresponding rounding mode. export type fround = enum uint { // Round towards nearest integer, with ties rounding to even TONEAREST = 0, // Round towards negative infinity DOWNWARD = 0x400, // Round towards positive infinity UPWARD = 0x800, // Round towards zero TOWARDZERO = 0xC00, }; @test fn fexcept() void = { assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); raiseexcept(fexcept::INEXACT | fexcept::DIVBYZERO); assert(testexcept(fexcept::INEXACT) == fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO) == fexcept::DIVBYZERO); assert(testexcept(fexcept::UNDERFLOW) == fexcept::NONE); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO | fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT | fexcept::INVALID) == fexcept::DIVBYZERO | fexcept::INEXACT); clearexcept(fexcept::INEXACT); assert(testexcept(fexcept::DIVBYZERO | fexcept::INEXACT) == fexcept::DIVBYZERO); raiseexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::ALL); assert(testexcept(fexcept::NONE) == fexcept::NONE); clearexcept(fexcept::ALL); assert(testexcept(fexcept::ALL) == fexcept::NONE); assert(testexcept(fexcept::NONE) == fexcept::NONE); }; @test fn fround() void = { // from musl's testsuite let f = &f64frombits; assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xc000000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x0)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x0)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0xbff0000000000000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf64(f(0x7ff8000000000000)))); assert(nearbyintf64(f(0x7ff0000000000000)) == INF); assert(nearbyintf64(f(0xfff0000000000000)) == -INF); assert(nearbyintf64(f(0x0)) == f(0x0)); assert(nearbyintf64(f(0x8000000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbff0000000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3fe0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfe0000000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x3ff0001000000000)) == f(0x4000000000000000)); assert(nearbyintf64(f(0xbff0001000000000)) == f(0xbff0000000000000)); assert(nearbyintf64(f(0x3feffff000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xbfeffff000000000)) == f(0x8000000000000000)); assert(nearbyintf64(f(0x39b0000000000000)) == f(0x3ff0000000000000)); assert(nearbyintf64(f(0xb9b0000000000000)) == f(0x8000000000000000)); let f = &f32frombits; setround(fround::TONEAREST); assert(getround() == fround::TONEAREST); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); setround(fround::DOWNWARD); assert(getround() == fround::DOWNWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x0)); assert(nearbyintf32(f(0xbf000000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f800080)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800080)) == f(0xc0000000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x0)); assert(nearbyintf32(f(0xbf7fff80)) == f(0xbf800000)); assert(nearbyintf32(f(0xd800000)) == f(0x0)); assert(nearbyintf32(f(0x8d800000)) == f(0xbf800000)); setround(fround::UPWARD); assert(getround() == fround::UPWARD); assert(isnan(nearbyintf32(f(0x7fc00000)))); assert(nearbyintf32(f(0x7f800000)) == INF); assert(nearbyintf32(f(0xff800000)) == -INF); assert(nearbyintf32(f(0x0)) == f(0x0)); assert(nearbyintf32(f(0x80000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf800000)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f000000)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf000000)) == f(0x80000000)); assert(nearbyintf32(f(0x3f800080)) == f(0x40000000)); assert(nearbyintf32(f(0xbf800080)) == f(0xbf800000)); assert(nearbyintf32(f(0x3f7fff80)) == f(0x3f800000)); assert(nearbyintf32(f(0xbf7fff80)) == f(0x80000000)); assert(nearbyintf32(f(0xd800000)) == f(0x3f800000)); assert(nearbyintf32(f(0x8d800000)) == f(0x80000000)); }; hare-0.24.2/math/fenv_func.ha000066400000000000000000000015751464473310100157450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Accepts a set of flags from [[fexcept]] ORed together and clears // exceptions corresponding to the given flags. export fn clearexcept(ex: fexcept) void = rt::feclearexcept(ex: uint); // Accepts a set of flags from [[fexcept]] ORed together and raises // exceptions corresponding to the given flags. export fn raiseexcept(ex: fexcept) void = rt::feraiseexcept(ex: uint); // Accepts a set of flags from [[fexcept]] ORed together and returns // the subset that is currently raised export fn testexcept(ex: fexcept) fexcept = rt::fetestexcept(ex: uint): fexcept; // Returns the value corresponding to the current rounding mode export fn getround() fround = rt::fegetround(): fround; // Sets the rounding mode to the specified value export fn setround(mode: fround) void = rt::fesetround(mode: uint); hare-0.24.2/math/floats.ha000066400000000000000000000427341464473310100152660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Returns the binary representation of the given f64. export fn f64bits(n: f64) u64 = *(&n: *u64); // Returns the binary representation of the given f32. export fn f32bits(n: f32) u32 = *(&n: *u32); // Returns f64 with the given binary representation. export fn f64frombits(n: u64) f64 = *(&n: *f64); // Returns f32 with the given binary representation. export fn f32frombits(n: u32) f32 = *(&n: *f32); // The number of bits in the significand of the binary representation of f64. export def F64_MANTISSA_BITS: u64 = 52; // The number of bits in the exponent of the binary representation of f64. export def F64_EXPONENT_BITS: u64 = 11; // The bias of the exponent of the binary representation of f64. Subtract this // from the exponent in the binary representation to get the actual exponent. export def F64_EXPONENT_BIAS: u16 = 1023; // The number of bits in the significand of the binary representation of f32. export def F32_MANTISSA_BITS: u64 = 23; // The number of bits in the exponent of the binary representation of f32. export def F32_EXPONENT_BITS: u64 = 8; // The bias of the exponent of the binary representation of f32. Subtract this // from the exponent in the binary representation to get the actual exponent. export def F32_EXPONENT_BIAS: u16 = 127; // Mask with each bit of an f64's mantissa set. export def F64_MANTISSA_MASK: u64 = (1 << F64_MANTISSA_BITS) - 1; // Mask with each bit of an f64's exponent set. export def F64_EXPONENT_MASK: u64 = (1 << F64_EXPONENT_BITS) - 1; // Mask with each bit of an f32's mantissa set. export def F32_MANTISSA_MASK: u64 = (1 << F32_MANTISSA_BITS) - 1; // Mask with each bit of an f32's exponent set. export def F32_EXPONENT_MASK: u64 = (1 << F32_EXPONENT_BITS) - 1; // The largest representable f64 value which is less than Infinity. export def F64_MAX_NORMAL: f64 = 1.7976931348623157e+308; // The smallest representable normal f64 value. export def F64_MIN_NORMAL: f64 = 2.2250738585072014e-308; // The smallest (subnormal) f64 value greater than zero. export def F64_MIN: f64 = 5.0e-324; // The difference between 1 and the smallest f64 representable value that is // greater than 1. export def F64_EPS: f64 = 2.22040000000000004884e-16; // The largest representable f32 value which is less than Infinity. export def F32_MAX_NORMAL: f32 = 3.4028234e+38; // The smallest representable normal f32 value. export def F32_MIN_NORMAL: f32 = 1.1754944e-38; // The smallest (subnormal) f32 value greater than zero. export def F32_MIN: f32 = 1.0e-45; // The difference between 1 and the smallest f32 representable value that is // greater than 1. export def F32_EPS: f32 = 1.1920928955078125e-7; // The mask that gets an f64's sign. def F64_SIGN_MASK: u64 = 1u64 << 63; // The mask that sets all exponent bits to 0. // NOTE: Replace with the following expression once the lexer supports it // 0u64 & ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS); def F64_EXP_REMOVAL_MASK: u64 = 0b1000000000001111111111111111111111111111111111111111111111111111; // The f64 that contains only an exponent that evaluates to zero. def F64_EXP_ZERO: u64 = ((F64_EXPONENT_BIAS: u64) - 1) << F64_MANTISSA_BITS; // The mask that gets an f32's sign. def F32_SIGN_MASK: u32 = 1u32 << 31; // The mask that sets all exponent bits to 0. // NOTE: Replace with the following expression once the lexer supports it // 0u32 & ~(F32_EXPONENT_MASK << F32_MANTISSA_BITS); def F32_EXP_REMOVAL_MASK: u32 = 0b10000000011111111111111111111111; // The f32 that contains only an exponent that evaluates to zero. def F32_EXP_ZERO: u32 = ((F32_EXPONENT_BIAS: u32) - 1) << (F32_MANTISSA_BITS: u32); // The bits that represent the number 1f64. def F64_ONE: u64 = 0x3FF0000000000000; // Contains information about the structure of a specific floating point number // type. export type floatinfo = struct { // Bits in significand. mantbits: u64, // Bits in exponent. expbits: u64, // Bias of exponent. expbias: int, // Mask for mantissa. mantmask: u64, // Mask for exponent. expmask: u64, }; // A [[floatinfo]] structure defining the structure of the f64 type. export const f64info: floatinfo = floatinfo { mantbits = 52, expbits = 11, expbias = 1023, mantmask = (1 << 52) - 1, expmask = (1 << 11) - 1, }; // A [[floatinfo]] structure defining the structure of the f32 type. export const f32info: floatinfo = floatinfo { mantbits = 23, expbits = 8, expbias = 127, mantmask = (1 << 23) - 1, expmask = (1 << 8) - 1, }; // The floating point value representing Not a Number, i.e. an undefined or // unrepresentable value. You cannot test if a number is NaN by comparing to // this value; see [[isnan]] instead. export def NAN: f32 = 0.0 / 0.0; // The floating point value representing positive infinity. Use -[[INF]] for // negative infinity. export def INF: f32 = 1.0 / 0.0; // Returns true if the given floating-point number is NaN. export fn isnan(n: f64) bool = n != n; // Returns true if the given floating-point number is infinite. export fn isinf(n: f64) bool = { const bits = f64bits(n); const mant = bits & F64_MANTISSA_MASK; const exp = bits >> F64_MANTISSA_BITS & F64_EXPONENT_MASK; return exp == F64_EXPONENT_MASK && mant == 0; }; @test fn isinf() void = { assert(isinf(INF)); assert(isinf(-INF)); assert(!isinf(NAN)); assert(!isinf(1.23)); assert(!isinf(-1.23f32)); }; // Returns true if the given floating-point number is normal. export fn isnormal(n: types::floating) bool = { match (n) { case let n: f32 => return isnormalf32(n); case let n: f64 => return isnormalf64(n); }; }; // Returns true if the given f64 is normal. export fn isnormalf64(n: f64) bool = { const bits = f64bits(n); const mant = bits & F64_MANTISSA_MASK; const exp = bits >> F64_MANTISSA_BITS & F64_EXPONENT_MASK; return exp != F64_EXPONENT_MASK && (exp > 0 || mant == 0); }; // Returns true if the given f32 is normal. export fn isnormalf32(n: f32) bool = { const bits = f32bits(n); const mant = bits & F32_MANTISSA_MASK; const exp = bits >> F32_MANTISSA_BITS & F32_EXPONENT_MASK; return exp != F32_EXPONENT_MASK && (exp > 0 || mant == 0); }; // Returns true if the given floating-point number is subnormal. export fn issubnormal(n: types::floating) bool = { match (n) { case let n: f32 => return issubnormalf32(n); case let n: f64 => return issubnormalf64(n); }; }; // Returns true if the given f64 is subnormal. export fn issubnormalf64(n: f64) bool = { const bits = f64bits(n); const mant = bits & F64_MANTISSA_MASK; const exp = bits >> F64_MANTISSA_BITS & F64_EXPONENT_MASK; return exp == 0 && mant != 0; }; // Returns true if the given f32 is subnormal. export fn issubnormalf32(n: f32) bool = { const bits = f32bits(n); const mant = bits & F32_MANTISSA_MASK; const exp = bits >> F32_MANTISSA_BITS & F32_EXPONENT_MASK; return exp == 0 && mant != 0; }; // Returns the absolute value of f64 n. export fn absf64(n: f64) f64 = { if (isnan(n)) { return n; }; return f64frombits(f64bits(n) & ~F64_SIGN_MASK); }; // Returns the absolute value of f32 n. export fn absf32(n: f32) f32 = { if (isnan(n)) { return n; }; return f32frombits(f32bits(n) & ~F32_SIGN_MASK); }; // Returns the absolute value of floating-point number n. export fn absf(n: types::floating) f64 = { match (n) { case let n: f64 => return absf64(n); case let n: f32 => return (absf32(n): f64); }; }; // Returns 1 if x is positive and -1 if x is negative. Note that zero is also // signed. export fn signf64(x: f64) i64 = { if (f64bits(x) & F64_SIGN_MASK == 0) { return 1i64; } else { return -1i64; }; }; // Returns 1 if x is positive and -1 if x is negative. Note that zero is also // signed. export fn signf32(x: f32) i64 = { if (f32bits(x) & F32_SIGN_MASK == 0) { return 1i64; } else { return -1i64; }; }; // Returns 1 if x is positive and -1 if x is negative. Note that zero is also // signed. export fn signf(x: types::floating) i64 = { match (x) { case let n: f64 => return signf64(n); case let n: f32 => return signf32(n); }; }; // Returns whether or not x is positive. export fn ispositivef64(x: f64) bool = signf64(x) == 1i64; // Returns whether or not x is positive. export fn ispositivef32(x: f32) bool = signf32(x) == 1i32; // Returns whether or not x is positive. export fn ispositive(x: types::floating) bool = { match (x) { case let n: f64 => return ispositivef64(n); case let n: f32 => return ispositivef32(n); }; }; // Returns whether or not x is negative. export fn isnegativef64(x: f64) bool = signf64(x) == -1i64; // Returns whether or not x is negative. export fn isnegativef32(x: f32) bool = signf32(x) == -1i32; // Returns whether or not x is negative. export fn isnegative(x: types::floating) bool = { match (x) { case let n: f64 => return isnegativef64(n); case let n: f32 => return isnegativef32(n); }; }; // Returns x, but with the sign of y. export fn copysignf64(x: f64, y: f64) f64 = { return f64frombits((f64bits(x) & ~F64_SIGN_MASK) | (f64bits(y) & F64_SIGN_MASK)); }; // Returns x, but with the sign of y. export fn copysignf32(x: f32, y: f32) f32 = { return f32frombits((f32bits(x) & ~F32_SIGN_MASK) | (f32bits(y) & F32_SIGN_MASK)); }; // Returns x, but with the sign of y. export fn copysign(x: types::floating, y: types::floating) f64 = { match (x) { case let n: f64 => return copysignf64(n, (y: f64)); case let n: f32 => return (copysignf32(n, (y: f32)): f64); }; }; // Takes a potentially subnormal f64 n and returns a normal f64 normal_float // and an exponent exp such that n == normal_float * 2^{exp}. export fn normalizef64(n: f64) (f64, i64) = { if (issubnormalf64(n)) { const factor = 1i64 << (F64_MANTISSA_BITS: i64); const normal_float = (n * (factor: f64)); return (normal_float, -(F64_MANTISSA_BITS: i64)); }; return (n, 0); }; // Takes a potentially subnormal f32 n and returns a normal f32 normal_float // and an exponent exp such that n == normal_float * 2^{exp}. export fn normalizef32(n: f32) (f32, i64) = { if (issubnormalf32(n)) { const factor = 1i32 << (F32_MANTISSA_BITS: i32); const normal_float = n * factor: f32; return (normal_float, -(F32_MANTISSA_BITS: i64)); }; return (n, 0); }; // Breaks a f64 down into its mantissa and exponent. The mantissa will be // between 0.5 and 1. export fn frexpf64(n: f64) (f64, i64) = { if (isnan(n) || isinf(n) || n == 0f64) { return (n, 0); }; const normalized = normalizef64(n); const normal_float = normalized.0; const normalization_exp = normalized.1; const bits = f64bits(normal_float); const raw_exp: u64 = (bits >> F64_MANTISSA_BITS) & F64_EXPONENT_MASK; const exp: i64 = normalization_exp + (raw_exp: i64) - (F64_EXPONENT_BIAS: i64) + 1; const mantissa: f64 = f64frombits((bits & F64_EXP_REMOVAL_MASK) | F64_EXP_ZERO); return (mantissa, exp); }; // Breaks a f32 down into its mantissa and exponent. The mantissa will be // between 0.5 and 1. export fn frexpf32(n: f32) (f32, i64) = { if (isnan(n) || isinf(n) || n == 0f32) { return (n, 0); }; const normalized = normalizef32(n); const normal_float = normalized.0; const normalization_exp = normalized.1; const bits = f32bits(normal_float); const raw_exp: u64 = ((bits >> (F32_MANTISSA_BITS: u32)) & (F32_EXPONENT_MASK: u32)); const exp: i64 = normalization_exp + (raw_exp: i64) - (F32_EXPONENT_BIAS: i64) + 1; const mantissa: f32 = f32frombits((bits & F32_EXP_REMOVAL_MASK) | F32_EXP_ZERO); return (mantissa, exp); }; // Breaks a float down into its mantissa and exponent. The mantissa will be // between 0.5 and 1. export fn frexp(n: types::floating) (f64, i64) = { match (n) { case let n: f64 => return frexpf64(n); case let n: f32 => let (mantissa, exp) = frexpf32(n); return (mantissa, exp); }; }; // Creates an f64 from a mantissa and an exponent. export fn ldexpf64(mantissa: f64, exp: i64) f64 = { if (isnan(mantissa) || isinf(mantissa) || mantissa == 0f64) { return mantissa; }; const normalized = normalizef64(mantissa); const normal_float = normalized.0; const normalization_exp = normalized.1; const bits = f64bits(normal_float); const mantissa_exp = (((bits >> F64_MANTISSA_BITS) & F64_EXPONENT_MASK): i64) - (F64_EXPONENT_BIAS: i64); let res_exp = exp + normalization_exp + mantissa_exp; // Underflow if (res_exp < -(F64_EXPONENT_BIAS: i64) - (F64_MANTISSA_BITS: i64)) { return copysign(0f64, mantissa); }; // Overflow if (res_exp > (F64_EXPONENT_BIAS: i64)) { if (mantissa < 0f64) { return -INF; } else { return INF; }; }; // Subnormal let subnormal_factor = 1f64; if (res_exp < -(F64_EXPONENT_BIAS: i64) + 1) { res_exp += (F64_MANTISSA_BITS: i64) - 1; subnormal_factor = 1f64 / ((1i64 << ((F64_MANTISSA_BITS: i64) - 1)): f64); }; const res: u64 = (bits & F64_EXP_REMOVAL_MASK) | ( ((res_exp: u64) + F64_EXPONENT_BIAS) << F64_MANTISSA_BITS ); return subnormal_factor * f64frombits(res); }; // Creates an f32 from a mantissa and an exponent. export fn ldexpf32(mantissa: f32, exp: i64) f32 = { if (isnan(mantissa) || isinf(mantissa) || mantissa == 0f32) { return mantissa; }; const normalized = normalizef32(mantissa); const normal_float = normalized.0; const normalization_exp = normalized.1; const bits = f32bits(normal_float); const mantissa_exp = (((bits >> F32_MANTISSA_BITS) & F32_EXPONENT_MASK): i32) - (F32_EXPONENT_BIAS: i32); let res_exp = exp + normalization_exp + mantissa_exp; // Underflow if (res_exp < -(F32_EXPONENT_BIAS: i32) - (F32_MANTISSA_BITS: i32)) { return copysignf32(0.0f32, mantissa); }; // Overflow if (res_exp > (F32_EXPONENT_BIAS: i32)) { if (mantissa < 0.0f32) { return -INF; } else { return INF; }; }; // Subnormal let subnormal_factor = 1.0f32; if (res_exp < -(F32_EXPONENT_BIAS: i32) + 1) { res_exp += (F32_MANTISSA_BITS: i32) - 1; subnormal_factor = 1.0f32 / ((1i32 << ((F32_MANTISSA_BITS: i32) - 1)): f32); }; const res: u32 = (bits & F32_EXP_REMOVAL_MASK) | ( ((res_exp: u32) + F32_EXPONENT_BIAS) << (F32_MANTISSA_BITS: u32) ); return subnormal_factor * f32frombits(res); }; // Returns the integer and fractional parts of an f64. export fn modfracf64(n: f64) (f64, f64) = { if (n < 1f64) { if (n < 0f64) { let positive_parts = modfracf64(-n); return (-positive_parts.0, -positive_parts.1); }; if (n == 0f64) { return (n, n); }; return (0f64, n); }; let bits = f64bits(n); const exp = (((bits >> F64_MANTISSA_BITS) & F64_EXPONENT_MASK): i64) - (F64_EXPONENT_BIAS: i64); // For exponent exp, all integers can be represented with the top exp // bits of the mantissa const sign_and_exp_bits = 64u64 - (F64_EXPONENT_BITS: u64) - 1u64; if (exp < (sign_and_exp_bits: i64)) { const bits_to_shift = (((sign_and_exp_bits: i64) - exp): u64); bits = bits & ~((1u64 << bits_to_shift) - 1); }; const int_part = f64frombits(bits); const frac_part = n - int_part; return (int_part, frac_part); }; // Returns the integer and fractional parts of an f32. export fn modfracf32(n: f32) (f32, f32) = { if (n < 1.0f32) { if (n < 0.0f32) { let positive_parts = modfracf32(-n); return (-positive_parts.0, -positive_parts.1); }; if (n == 0.0f32) { return (n, n); }; return (0f32, n); }; let bits = f32bits(n); const exp = (((bits >> F32_MANTISSA_BITS) & F32_EXPONENT_MASK): i32) - (F32_EXPONENT_BIAS: i32); // For exponent exp, all integers can be represented with the top exp // bits of the mantissa const sign_and_exp_bits = 32u32 - (F32_EXPONENT_BITS: u32) - 1u32; if (exp < (sign_and_exp_bits: i32)) { const bits_to_shift = (((sign_and_exp_bits: i32) - exp): u32); bits = bits & ~((1u32 << bits_to_shift) - 1); }; const int_part = f32frombits(bits); const frac_part = n - int_part; return (int_part, frac_part); }; // Returns the f32 that is closest to 'x' in direction of 'y'. Returns NaN // if either parameter is NaN. Returns 'x' if both parameters are same. export fn nextafterf32(x: f32, y: f32) f32 = { if (isnan(x) || isnan(y)) { return x + y; }; let ux = f32bits(x); let uy = f32bits(y); if (ux == uy) { return x; }; let absx = ux & 0x7fffffff, absy = uy & 0x7fffffff; if (absx == 0) { if (absy == 0) { return x; }; ux = uy & 0x80000000 | 1; } else if (absx > absy || (ux ^ uy) & 0x80000000 != 0) { ux -= 1; } else { ux += 1; }; // TODO handle over/underflow return f32frombits(ux); }; // Returns the f64 that is closest to 'x' in direction of 'y' Returns NaN // if either parameter is NaN. Returns 'x' if both parameters are same. export fn nextafterf64(x: f64, y: f64) f64 = { if (isnan(x) || isnan(y)) { return x + y; }; let ux = f64bits(x); let uy = f64bits(y); if (ux == uy) { return x; }; let absx = ux & ~(1u64 << 63), absy = uy & ~(1u64 << 63); if (absx == 0) { if (absy == 0) { return x; }; ux = uy & (1u64 << 63) | 1u64; } else if (absx > absy || (ux ^ uy) & (1u64 << 63) != 0) { ux -= 1; } else { ux += 1; }; // TODO handle over/underflow return f64frombits(ux); }; // Round a f32 to nearest integer value in floating point format fn nearbyintf32(x: f32) f32 = { let n = f32bits(x); let e = n >> 23 & 0xff; if (e >= 0x7f + 23) { return x; }; let s = n >> 31; let y = if (s != 0) x - 1.0 / F32_EPS + 1.0 / F32_EPS else x + 1.0 / F32_EPS - 1.0 / F32_EPS; if (y == 0.0f32) return if (s != 0) -0.0f32 else 0.0f32 else return y; }; // Round a f64 to nearest integer value in floating point format fn nearbyintf64(x: f64) f64 = { let n = f64bits(x); let e = n >> 52 & 0x7ff; if (e >= 0x3ff + 52) { return x; }; let s = n >> 63; let y = if (s != 0) x - 1.0 / F64_EPS + 1.0 / F64_EPS else x + 1.0 / F64_EPS - 1.0 / F64_EPS; if (y == 0.0f64) return if (s != 0) -0.0f64 else 0.0f64 else return y; }; hare-0.24.2/math/ints.ha000066400000000000000000000072451464473310100147510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Returns the absolute value of signed integer n. export fn absi8(n: i8) u8 = { if (n < 0i8) { return -n: u8; } else { return n: u8; }; }; // Returns the absolute value of signed integer n. export fn absi16(n: i16) u16 = { if (n < 0i16) { return -n: u16; } else { return n: u16; }; }; // Returns the absolute value of signed integer n. export fn absi32(n: i32) u32 = { if (n < 0i32) { return -n: u32; } else { return n: u32; }; }; // Returns the absolute value of signed integer n. export fn absi64(n: i64) u64 = { if (n < 0i64) { return -n: u64; } else { return n: u64; }; }; // Returns the absolute value of signed integer n. export fn absi(n: types::signed) u64 = { match (n) { case let n: i8 => return absi8(n): u64; case let n: i16 => return absi16(n): u64; case let n: i32 => return absi32(n): u64; case let n: i64 => return absi64(n): u64; case let n: int => return absi64(n): u64; }; }; @test fn absi() void = { // Workaround casting issue where (-types::I8_MIN: u8) has a value not // equal to (-types::I8_MIN: u16) let m8 = (-types::I8_MIN: u8); let m16 = (-types::I16_MIN: u16); let m32 = (-types::I32_MIN: u32); let m64 = (-types::I64_MIN: u64); assert(absi8(2i8) == 2u8); assert(absi8(-2i8) == 2u8); assert(absi8(types::I8_MIN) == m8); assert(absi16(2i16) == 2u16); assert(absi16(-2i16) == 2u16); assert(absi16(types::I16_MIN) == m16); assert(absi32(2i32) == 2u32); assert(absi32(-2i32) == 2u32); assert(absi32(types::I32_MIN) == m32); assert(absi64(2i64) == 2u64); assert(absi64(-2i64) == 2u64); assert(absi64(types::I64_MIN) == m64); assert(absi(2i8) == 2u64); assert(absi(-2i8) == 2u64); assert(absi(types::I8_MIN) == (m8: u64)); assert(absi(2i16) == 2u64); assert(absi(-2i16) == 2u64); assert(absi(types::I16_MIN) == (m16: u64)); assert(absi(2i32) == 2u64); assert(absi(-2i32) == 2u64); assert(absi(types::I32_MIN) == (m32: u64)); assert(absi(2i64) == 2u64); assert(absi(-2i64) == 2u64); assert(absi(types::I64_MIN) == (m64: u64)); }; // Return 1 if n is positive, -1 if it's negative and 0 if it's 0. export fn signi8(n: i8) i8 = { if (n > 0i8) { return 1i8; }; if (n < 0i8) { return -1i8; }; return 0i8; }; // Return 1 if n is positive, -1 if it's negative and 0 if it's 0. export fn signi16(n: i16) i16 = { if (n > 0i16) { return 1i16; }; if (n < 0i16) { return -1i16; }; return 0i16; }; // Return 1 if n is positive, -1 if it's negative and 0 if it's 0. export fn signi32(n: i32) i32 = { if (n > 0i32) { return 1i32; }; if (n < 0i32) { return -1i32; }; return 0i32; }; // Return 1 if n is positive, -1 if it's negative and 0 if it's 0. export fn signi64(n: i64) i64 = { if (n > 0i64) { return 1i64; }; if (n < 0i64) { return -1i64; }; return 0i64; }; // Return 1 if n is positive, -1 if it's negative and 0 if it's 0. export fn signi(n: types::signed) i64 = { match (n) { case let n: i8 => return signi8(n): i64; case let n: i16 => return signi16(n): i64; case let n: i32 => return signi32(n): i64; case let n: i64 => return signi64(n): i64; case let n: int => return signi64(n): i64; }; }; @test fn signi() void = { assert(signi8(2i8) == 1i8); assert(signi8(-2i8) == -1i8); assert(signi8(0i8) == 0i8); assert(signi16(2i16) == 1i16); assert(signi16(-2i16) == -1i16); assert(signi16(0i16) == 0i16); assert(signi32(2i32) == 1i32); assert(signi32(-2i32) == -1i32); assert(signi32(0i32) == 0i32); assert(signi64(2i64) == 1i64); assert(signi64(-2i64) == -1i64); assert(signi64(0i64) == 0i64); assert(signi(2i16) == 1i64); assert(signi(-2i16) == -1i64); assert(signi(0i16) == 0i64); }; hare-0.24.2/math/math.ha000066400000000000000000000654231464473310100147270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Sections of the code below, in particular log() and exp(), are based on Go's // implementation, which is, in turn, based on FreeBSD's. The original C code, // as well as the respective comments and constants are from // /usr/src/lib/msun/src/{e_log,e_exp}.c. // // The FreeBSD copyright notice: // ==================================================== // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. // // Developed at SunPro, a Sun Microsystems, Inc. business. // Permission to use, copy, modify, and distribute this // software is freely granted, provided that this notice // is preserved. // ==================================================== // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== use types; // The standard tolerance used by isclose(), which is just an arbitrary way to // measure whether two floating-point numbers are "sufficiently" close to each // other. export def STANDARD_TOL: f64 = 1e-14; // Returns whether x and y are within tol of each other. export fn eqwithinf64(x: f64, y: f64, tol: f64) bool = { if (isnan(x) || isnan(y) || isnan(tol)) { return false; }; return absf64(x - y) < tol; }; // Returns whether x and y are within tol of each other. export fn eqwithinf32(x: f32, y: f32, tol: f32) bool = { if (isnan(x) || isnan(y) || isnan(tol)) { return false; }; return absf32(x - y) < tol; }; // Returns whether x and y are within tol of each other. export fn eqwithin( x: types::floating, y: types::floating, tol: types::floating, ) bool = { match (x) { case let n: f64 => return eqwithinf64(n, y as f64, tol as f64); case let n: f32 => return eqwithinf32(n, y as f32, tol as f32); }; }; // Returns whether x and y are within [[STANDARD_TOL]] of each other. export fn isclosef64(x: f64, y: f64) bool = { return eqwithinf64(x, y, STANDARD_TOL); }; // Returns whether x and y are within [[STANDARD_TOL]] of each other. export fn isclosef32(x: f32, y: f32) bool = { return eqwithinf32(x, y, STANDARD_TOL: f32); }; // Returns whether x and y are within [[STANDARD_TOL]] of each other. export fn isclose(x: types::floating, y: types::floating) bool = { match (x) { case let n: f64 => return isclosef64(n, y as f64); case let n: f32 => return isclosef32(n, y as f32); }; }; // e - https://oeis.org/A001113 export def E: f64 = 2.71828182845904523536028747135266249775724709369995957496696763; // pi - https://oeis.org/A000796 export def PI: f64 = 3.14159265358979323846264338327950288419716939937510582097494459; // tau - https://oeis.org/A019692 export def TAU: f64 = 6.2831853071795864769252867665590057683943387987502116419498892; // phi - https://oeis.org/A001622 export def PHI: f64 = 1.61803398874989484820458683436563811772030917980576286213544862; // sqrt(2) - https://oeis.org/A002193 export def SQRT_2: f64 = 1.41421356237309504880168872420969807856967187537694807317667974; // sqrt(e) - https://oeis.org/A019774 export def SQRT_E: f64 = 1.64872127070012814684865078781416357165377610071014801157507931; // sqrt(pi) - https://oeis.org/A002161 export def SQRT_PI: f64 = 1.77245385090551602729816748334114518279754945612238712821380779; // sqrt(phi) - https://oeis.org/A139339 export def SQRT_PHI: f64 = 1.27201964951406896425242246173749149171560804184009624861664038; // ln(2) - https://oeis.org/A002162 export def LN_2: f64 = 0.693147180559945309417232121458176568075500134360255254120680009; // ln(2) - https://oeis.org/A002162 export def LN2_HI: f64 = 6.93147180369123816490e-01; // ln(2) - https://oeis.org/A002162 export def LN2_LO: f64 = 1.90821492927058770002e-10; // log_{2}(e) export def LOG2_E: f64 = 1f64 / LN_2; // ln(10) - https://oeis.org/A002392 export def LN_10: f64 = 2.30258509299404568401799145468436420760110148862877297603332790; // log_{10}(e) export def LOG10_E: f64 = 1f64 / LN_10; // __ieee754_log(x) // Return the logarithm of x // // Method : // 1. Argument Reduction: find k and f such that // x = 2**k * (1+f), // where sqrt(2)/2 < 1+f < sqrt(2) . // // 2. Approximation of log(1+f). // Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) // = 2s + 2/3 s**3 + 2/5 s**5 + ....., // = 2s + s*R // We use a special Reme algorithm on [0,0.1716] to generate // a polynomial of degree 14 to approximate R. The maximum error // of this polynomial approximation is bounded by 2**-58.45. In // other words, // 2 4 6 8 10 12 14 // R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s // (the values of L1 to L7 are listed in the program) and // | 2 14 | -58.45 // | L1*s +...+L7*s - R(z) | <= 2 // | | // Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. // In order to guarantee error in log below 1ulp, we compute log by // log(1+f) = f - s*(f - R) (if f is not too large) // log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) // // 3. Finally, log(x) = k*Ln2 + log(1+f). // = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo))) // Here Ln2 is split into two floating point number: // Ln2_hi + Ln2_lo, // where n*Ln2_hi is always exact for |n| < 2000. // // Special cases: // log(x) is NaN with signal if x < 0 (including -INF) ; // log(+INF) is +INF; log(0) is -INF with signal; // log(NaN) is that NaN with no signal. // // Accuracy: // according to an error analysis, the error is always less than // 1 ulp (unit in the last place). // // Constants: // The hexadecimal values are the intended ones for the following // constants. The decimal values may be used, provided that the // compiler will convert from decimal to binary accurately enough // to produce the hexadecimal values shown. // Returns the natural logarithm of x. export fn logf64(x: f64) f64 = { const L1 = 6.666666666666735130e-01; // 3fe55555 55555593 const L2 = 3.999999999940941908e-01; // 3fd99999 9997fa04 const L3 = 2.857142874366239149e-01; // 3fd24924 94229359 const L4 = 2.222219843214978396e-01; // 3fcc71c5 1d8e78af const L5 = 1.818357216161805012e-01; // 3fc74664 96cb03de const L6 = 1.531383769920937332e-01; // 3fc39a09 d078c69f const L7 = 1.479819860511658591e-01; // 3fc2f112 df3e5244 // special cases if (isnan(x) || x == INF) { return x; } else if (x < 0f64) { return NAN; } else if (x == 0f64) { return -INF; }; // Reduce const f1_and_ki = frexp(x); let f1 = f1_and_ki.0; let ki = f1_and_ki.1; if (f1 < (SQRT_2 / 2f64)) { f1 *= 2f64; ki -= 1i64; }; let f = f1 - 1f64; let k = (ki: f64); // Compute const s = f / (2f64 + f); const s2 = s * s; const s4 = s2 * s2; const t1 = s2 * (L1 + s4 * (L3 + s4 * (L5 + s4 * L7))); const t2 = s4 * (L2 + s4 * (L4 + s4 * L6)); const R = t1 + t2; const hfsq = 0.5f64 * f * f; return k * LN2_HI - ((hfsq - (s * (hfsq + R) + k * LN2_LO)) - f); }; // Returns the decimal logarithm of x. export fn log10f64(x: f64) f64 = { return logf64(x) * (1f64 / LN_10); }; // Returns the binary logarithm of x. export fn log2f64(x: f64) f64 = { const frexp_res = frexpf64(x); let frac = frexp_res.0; let exp = frexp_res.1; // Make sure exact powers of two give an exact answer. // Don't depend on log(0.5) * (1 / LN_2) + exp being exactly exp - 1. if (frac == 0.5f64) { return ((exp - 1): f64); }; return logf64(frac) * (1f64 / LN_2) + (exp: f64); }; // double log1p(double x) // // Method : // 1. Argument Reduction: find k and f such that // 1+x = 2**k * (1+f), // where sqrt(2)/2 < 1+f < sqrt(2) . // // Note. If k=0, then f=x is exact. However, if k!=0, then f // may not be representable exactly. In that case, a correction // term is need. Let u=1+x rounded. Let c = (1+x)-u, then // log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), // and add back the correction term c/u. // (Note: when x > 2**53, one can simply return log(x)) // // 2. Approximation of log1p(f). // Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) // = 2s + 2/3 s**3 + 2/5 s**5 + ....., // = 2s + s*R // We use a special Reme algorithm on [0,0.1716] to generate // a polynomial of degree 14 to approximate R The maximum error // of this polynomial approximation is bounded by 2**-58.45. In // other words, // 2 4 6 8 10 12 14 // R(z) ~ LP1*s +LP2*s +LP3*s +LP4*s +LP5*s +LP6*s +LP7*s // (the values of LP1 to LP7 are listed in the program) // and // | 2 14 | -58.45 // | LP1*s +...+LP7*s - R(z) | <= 2 // | | // Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. // In order to guarantee error in log below 1ulp, we compute log // by // log1p(f) = f - (hfsq - s*(hfsq+R)). // // 3. Finally, log1p(x) = k*ln2 + log1p(f). // = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) // Here ln2 is split into two floating point number: // ln2_hi + ln2_lo, // where n*ln2_hi is always exact for |n| < 2000. // // Special cases: // log1p(x) is NaN with signal if x < -1 (including -INF) ; // log1p(+INF) is +INF; log1p(-1) is -INF with signal; // log1p(NaN) is that NaN with no signal. // // Accuracy: // according to an error analysis, the error is always less than // 1 ulp (unit in the last place). // // Constants: // The hexadecimal values are the intended ones for the following // constants. The decimal values may be used, provided that the // compiler will convert from decimal to binary accurately enough // to produce the hexadecimal values shown. // // Note: Assuming log() return accurate answer, the following // algorithm can be used to compute log1p(x) to within a few ULP: // // u = 1+x; // if(u==1.0) return x ; else // return log(u)*(x/(u-1.0)); // // See HP-15C Advanced Functions Handbook, p.193. // Returns the natural logarithm of 1 plus its argument x. // It is more accurate than log(1 + x) when x is near zero. export fn log1pf64(x: f64) f64 = { // sqrt(2) - 1 const SQRT2M1 = 4.142135623730950488017e-01; // 0x3fda827999fcef34 // sqrt(2) / 2 - 1 const SQRT2HALFM1 = -2.928932188134524755992e-01; // 0xbfd2bec333018866 const SMALL = 1f64 / ((1i64 << 29): f64); // 2**-29 const TINY = 1f64 / ((1i64 << 54): f64); // 2**-54 const TWO53 = ((1i64 << 53): f64); // 2**53 const LN2HI = 6.93147180369123816490e-01; // 3fe62e42fee00000 const LN2LO = 1.90821492927058770002e-10; // 3dea39ef35793c76 const LP1 = 6.666666666666735130e-01; // 3fe5555555555593 const LP2 = 3.999999999940941908e-01; // 3fd999999997fa04 const LP3 = 2.857142874366239149e-01; // 3fd2492494229359 const LP4 = 2.222219843214978396e-01; // 3fcc71c51d8e78af const LP5 = 1.818357216161805012e-01; // 3fc7466496cb03de const LP6 = 1.531383769920937332e-01; // 3fc39a09d078c69f const LP7 = 1.479819860511658591e-01; // 3fc2f112df3e5244 if (x < -1f64 || isnan(x)) { return NAN; } else if (x == -1f64) { return -INF; } else if (x == INF) { return INF; }; const absx = absf64(x); let f = 0f64; let iu = 0u64; let k = 1i64; if (absx < SQRT2M1) { // |x| < Sqrt(2)-1 if (absx < SMALL) { // |x| < 2**-29 if (absx < TINY) { // |x| < 2**-54 return x; }; return x - (x * x * 0.5f64); }; if (x > SQRT2HALFM1) { // Sqrt(2)/2-1 < x // (Sqrt(2)/2-1) < x < (Sqrt(2)-1) k = 0; f = x; iu = 1; }; }; let c = 0f64; if (k != 0) { let u = 0f64; if (absx < TWO53) { // 1<<53 u = 1.0 + x; iu = f64bits(u); k = (((iu >> 52) - 1023): i64); // Correction term if (k > 0) { c = 1f64 - (u - x); } else { c = x - (u - 1f64); }; c /= u; } else { u = x; iu = f64bits(u); k = (((iu >> 52) - 1023): i64); c = 0f64; }; iu &= 0x000fffffffffffff; if (iu < 0x0006a09e667f3bcd) { // Mantissa of Sqrt(2) // Normalize u u = f64frombits(iu | 0x3ff0000000000000); } else { k += 1; // Normalize u/2 u = f64frombits(iu | 0x3fe0000000000000); iu = (0x0010000000000000 - iu) >> 2; }; f = u - 1f64; // Sqrt(2)/2 < u < Sqrt(2) }; const hfsq = 0.5 * f * f; let s = 0f64; let R = 0f64; let z = 0f64; if (iu == 0) { // |f| < 2**-20 if (f == 0f64) { if (k == 0) { return 0f64; }; c += (k: f64) * LN2LO; return (k: f64) * LN2HI + c; }; R = hfsq * (1.0 - 0.66666666666666666 * f); // Avoid division if (k == 0) { return f - R; }; return (k: f64) * LN2HI - ((R - ((k: f64) * LN2LO + c)) - f); }; s = f / (2f64 + f); z = s * s; R = z * (LP1 + z * (LP2 + z * (LP3 + z * (LP4 + z * (LP5 + z * (LP6 + z * LP7)))))); if (k == 0) { return f - (hfsq - s * (hfsq + R)); }; return (k: f64) * LN2HI - ((hfsq - (s * (hfsq + R) + ((k: f64) * LN2LO + c))) - f); }; // exp(x) // Returns the exponential of x. // // Method // 1. Argument reduction: // Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. // Given x, find r and integer k such that // // x = k*ln2 + r, |r| <= 0.5*ln2. // // Here r will be represented as r = hi-lo for better // accuracy. // // 2. Approximation of exp(r) by a special rational function on // the interval [0,0.34658]: // Write // R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... // We use a special Remez algorithm on [0,0.34658] to generate // a polynomial of degree 5 to approximate R. The maximum error // of this polynomial approximation is bounded by 2**-59. In // other words, // R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 // (where z=r*r, and the values of P1 to P5 are listed below) // and // | 5 | -59 // | 2.0+P1*z+...+P5*z - R(z) | <= 2 // | | // The computation of exp(r) thus becomes // 2*r // exp(r) = 1 + ------- // R - r // r*R1(r) // = 1 + r + ----------- (for better accuracy) // 2 - R1(r) // where // 2 4 10 // R1(r) = r - (P1*r + P2*r + ... + P5*r ). // // 3. Scale back to obtain exp(x): // From step 1, we have // exp(x) = 2**k * exp(r) // // Special cases: // exp(INF) is INF, exp(NaN) is NaN; // exp(-INF) is 0, and // for finite argument, only exp(0)=1 is exact. // // Accuracy: // according to an error analysis, the error is always less than // 1 ulp (unit in the last place). // // Misc. info. // For IEEE double // if x > 7.09782712893383973096e+02 then exp(x) overflow // if x < -7.45133219101941108420e+02 then exp(x) underflow // // Constants: // The hexadecimal values are the intended ones for the following // constants. The decimal values may be used, provided that the // compiler will convert from decimal to binary accurately enough // to produce the hexadecimal values shown. // Returns e^r * 2^k where r = hi - lo and |r| <= (ln(2) / 2). export fn expmultif64(hi: f64, lo: f64, k: i64) f64 = { const P1 = 1.66666666666666657415e-01; // 0x3fc55555; 0x55555555 const P2 = -2.77777777770155933842e-03; // 0xbf66c16c; 0X16bebd9n const P3 = 6.61375632143793436117e-05; // 0x3f11566a; 0Xaf25de2c const P4 = -1.65339022054652515390e-06; // 0xbebbbd41; 0Xc5d26bf1 const P5 = 4.13813679705723846039e-08; // 0x3e663769; 0X72bea4d0 let r = hi - lo; let t = r * r; let c = r - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); const y = 1f64 - ((lo - (r * c) / (2f64 - c)) - hi); return ldexpf64(y, k); }; // Returns e^x. export fn expf64(x: f64) f64 = { const overflow = 7.09782712893383973096e+02; const underflow = -7.45133219101941108420e+02; const near_zero = 1f64 / ((1i64 << 28i64): f64); if (isnan(x) || x == INF) { return x; } else if (x == -INF) { return 0f64; } else if (x > overflow) { return INF; } else if (x < underflow) { return 0f64; } else if (-near_zero < x && x < near_zero) { return 1f64 + x; }; // Reduce; computed as r = hi - lo for extra precision. let k = 0i64; if (x < 0f64) { k = (((LOG2_E * x) - 0.5): i64); } else if (x > 0f64) { k = (((LOG2_E * x) + 0.5): i64); }; const hi = x - ((k: f64) * LN2_HI); const lo = (k: f64) * LN2_LO; // Compute return expmultif64(hi, lo, k); }; // Returns 2^x. export fn exp2f64(x: f64) f64 = { const overflow = 1.0239999999999999e+03; const underflow = -1.0740e+03; if (isnan(x) || x == INF) { return x; } else if (x == -INF) { return 0f64; } else if (x > overflow) { return INF; } else if (x < underflow) { return 0f64; }; // Argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2. // Computed as r = hi - lo for extra precision. let k = 0i64; if (x > 0f64) { k = ((x + 0.5): i64); } else if (x < 0f64) { k = ((x - 0.5): i64); }; const t = x - (k: f64); const hi = t * LN2_HI; const lo = -t * LN2_LO; // Compute return expmultif64(hi, lo, k); }; // __ieee754_sqrt(x) // Return correctly rounded sqrt. // ----------------------------------------- // | Use the hardware sqrt if you have one | // ----------------------------------------- // Method: // Bit by bit method using integer arithmetic. (Slow, but portable) // 1. Normalization // Scale x to y in [1,4) with even powers of 2: // find an integer k such that 1 <= (y=x*2**(2k)) < 4, then // sqrt(x) = 2**k * sqrt(y) // 2. Bit by bit computation // Let q = sqrt(y) truncated to i bit after binary point (q = 1), // i 0 // i+1 2 // s = 2*q , and y = 2 * ( y - q ). (1) // i i i i // // To compute q from q , one checks whether // i+1 i // // -(i+1) 2 // (q + 2 ) <= y. (2) // i // -(i+1) // If (2) is false, then q = q ; otherwise q = q + 2 . // i+1 i i+1 i // // With some algebraic manipulation, it is not difficult to see // that (2) is equivalent to // -(i+1) // s + 2 <= y (3) // i i // // The advantage of (3) is that s and y can be computed by // i i // the following recurrence formula: // if (3) is false // // s = s , y = y ; (4) // i+1 i i+1 i // // otherwise, // -i -(i+1) // s = s + 2 , y = y - s - 2 (5) // i+1 i i+1 i i // // One may easily use induction to prove (4) and (5). // Note. Since the left hand side of (3) contain only i+2 bits, // it is not necessary to do a full (53-bit) comparison // in (3). // 3. Final rounding // After generating the 53 bits result, we compute one more bit. // Together with the remainder, we can decide whether the // result is exact, bigger than 1/2ulp, or less than 1/2ulp // (it will never equal to 1/2ulp). // The rounding mode can be detected by checking whether // huge + tiny is equal to huge, and whether huge - tiny is // equal to huge for some floating point number "huge" and "tiny". // Returns the square root of x. export fn sqrtf64(x: f64) f64 = { if (x == 0f64) { return x; } else if (isnan(x) || x == INF) { return x; } else if (x < 0f64) { return NAN; }; let bits = f64bits(x); // Normalize x let exp = (((bits >> F64_MANTISSA_BITS) & F64_EXPONENT_MASK): i64); if (exp == 0i64) { // Subnormal x for (bits & (1 << F64_MANTISSA_BITS) == 0) { bits <<= 1; exp -= 1; }; exp += 1; }; // Unbias exponent exp -= (F64_EXPONENT_BIAS: i64); bits = bits & ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS); bits = bits | (1u64 << (F64_MANTISSA_BITS: u64)); // Odd exp, double x to make it even if (exp & 1i64 == 1i64) { bits <<= 1; }; // exp = exp/2, exponent of square root exp >>= 1; // Generate sqrt(x) bit by bit bits <<= 1; // q = sqrt(x) let q = 0u64; let s = 0u64; // r = moving bit from MSB to LSB let r = ((1u64 << (F64_MANTISSA_BITS + 1u64)): u64); for (r != 0) { const t = s + r; if (t <= bits) { s = t + r; bits -= t; q += r; }; bits <<= 1u64; r >>= 1u64; }; // Final rounding if (bits != 0) { // Remainder, result not exact // Round according to extra bit q += q & 1; }; // significand + biased exponent bits = (q >> 1) + ( ((exp - 1i64 + (F64_EXPONENT_BIAS: i64)): u64) << F64_MANTISSA_BITS); return f64frombits(bits); }; fn is_f64_odd_int(x: f64) bool = { const (x_int, x_frac) = modfracf64(x); const has_no_frac = (x_frac == 0f64); const is_odd = ((x_int: i64 & 1i64) == 1i64); return has_no_frac && is_odd; }; // Returns x^p. export fn powf64(x: f64, p: f64) f64 = { if (x == 1f64 || p == 0f64) { return 1f64; } else if (p == 1f64) { return x; } else if (isnan(x)) { return NAN; } else if (isnan(p)) { return NAN; } else if (x == 0f64) { if (p < 0f64) { if (is_f64_odd_int(p)) { return copysignf64(INF, x); } else { return INF; }; } else if (p > 0f64) { if (is_f64_odd_int(p)) { return x; } else { return 0f64; }; }; } else if (isinf(p)) { if (x == -1f64) { return 1f64; } else if ((absf64(x) < 1f64) == (p == INF)) { return 0f64; }; return INF; } else if (isinf(x)) { if (x == -INF) { return powf64(-0f64, -p); } else if (p < 0f64) { return 0f64; } else if (p > 0f64) { return INF; }; } else if (p == 0.5f64) { return sqrtf64(x); } else if (p == -0.5f64) { return 1f64 / sqrtf64(x); }; let (p_int, p_frac) = modfracf64(absf64(p)); if (p_frac != 0f64 && x < 0f64) { return NAN; }; if (p_int > types::I64_MAX: f64) { if (x == -1f64) { return 1f64; } else if ((absf64(x) < 1f64) == (p > 0f64)) { return 0f64; } else { return INF; }; }; let res_mantissa = 1f64; let res_exp = 0i64; // The method used later in this function doesn't apply to fractional // powers, so we have to handle these separately with // x^p = e^{p * ln(x)} if (p_frac != 0f64) { if (p_frac > 0.5f64) { p_frac -= 1f64; p_int += 1f64; }; res_mantissa = expf64(p_frac * logf64(x)); }; // Repeatedly square our number x, for each bit in our power p. // If the current bit is 1 in p, add the respective power of x to our // result. let (x_mantissa, x_exp) = frexp(x); for (let i = p_int: i64; i != 0; i >>= 1) { // Check for over/underflow. if (x_exp <= -1i64 << (F64_EXPONENT_BITS: i64)) { return 0f64; }; if (x_exp >= 1i64 << (F64_EXPONENT_BITS: i64)) { return INF; }; // Perform squaring. if (i & 1i64 == 1i64) { res_mantissa *= x_mantissa; res_exp += x_exp; }; x_mantissa *= x_mantissa; x_exp <<= 1; // Correct mantisa to be in [0.5, 1). if (x_mantissa < 0.5f64) { x_mantissa += x_mantissa; x_exp -= 1; }; }; if (p < 0f64) { res_mantissa = 1f64 / res_mantissa; res_exp = -res_exp; }; return ldexpf64(res_mantissa, res_exp); }; // Returns the greatest integer value less than or equal to x. export fn floorf64(x: f64) f64 = { if (x == 0f64 || isnan(x) || isinf(x)) { return x; }; if (x < 0f64) { let (int_part, frac_part) = modfracf64(-x); if (frac_part != 0f64) { int_part += 1f64; }; return -int_part; }; return modfracf64(x).0; }; // Returns the least integer value greater than or equal to x. export fn ceilf64(x: f64) f64 = -floorf64(-x); // Returns the integer value of x. export fn truncf64(x: f64) f64 = { if (x == 0f64 || isnan(x) || isinf(x)) { return x; }; return modfracf64(x).0; }; // Returns the nearest integer, rounding half away from zero. export fn roundf64(x: f64) f64 = { let bits = f64bits(x); let e = (bits >> F64_MANTISSA_BITS) & F64_EXPONENT_MASK; if (e < F64_EXPONENT_BIAS) { // Round abs(x) < 1 including denormals. bits &= F64_SIGN_MASK; // +-0 if (e == F64_EXPONENT_BIAS - 1) { bits |= F64_ONE; // +-1 }; } else if (e < F64_EXPONENT_BIAS + F64_MANTISSA_BITS) { // Round any abs(x) >= 1 containing a fractional component // [0,1). // Numbers with larger exponents are returned unchanged since // they must be either an integer, infinity, or NaN. const half = 1 << (F64_MANTISSA_BITS - 1); e -= F64_EXPONENT_BIAS; bits += half >> e; bits = bits & ~(F64_MANTISSA_MASK >> e); }; return f64frombits(bits); }; // Returns the floating-point remainder of x / y. The magnitude of the result // is less than y and its sign agrees with that of x. export fn modf64(x: f64, y: f64) f64 = { if (y == 0f64) { return NAN; }; if (isinf(x) || isnan(x) || isnan(y)) { return NAN; }; y = absf64(y); const y_frexp = frexpf64(y); const y_frac = y_frexp.0; const y_exp = y_frexp.1; let r = x; if (x < 0f64) { r = -x; }; for (r >= y) { const r_frexp = frexpf64(r); const r_frac = r_frexp.0; let r_exp = r_frexp.1; if (r_frac < y_frac) { r_exp -= 1i64; }; r = r - ldexpf64(y, r_exp - y_exp); }; if (x < 0f64) { r = -r; }; return r; }; hare-0.24.2/math/random/000077500000000000000000000000001464473310100147325ustar00rootroot00000000000000hare-0.24.2/math/random/README000066400000000000000000000004761464473310100156210ustar00rootroot00000000000000math::random provides a pseudorandom number generator, which yields a deterministic sequence of psuedo-random numbers based on a seed value. Beware! This module is NOT suitable for generating genuinely random data for cryptographic use. See [[crypto::random::]] for cryptographically secure random number generation. hare-0.24.2/math/random/random.ha000066400000000000000000000045231464473310100165300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // State for a pseudorandom number generator. export type random = u64; // Initializes a pseudorandom number generator with a given seed. This seed will // yield the same sequence of psuedo-random numbers if used again. export fn init(seed: u64) random = seed; // Returns a psuedo-random 64-bit unsigned integer. export fn next(r: *random) u64 = { // SplitMix64 *r += 0x9e3779b97f4a7c15; *r = (*r ^ *r >> 30) * 0xbf58476d1ce4e5b9; *r = (*r ^ *r >> 27) * 0x94d049bb133111eb; return *r ^ *r >> 31; }; // Returns a pseudo-random 32-bit unsigned integer in the half-open interval // [0,n). n must be greater than zero. export fn u32n(r: *random, n: u32) u32 = { // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ // https://lemire.me/blog/2016/06/30/fast-random-shuffling/ assert(n != 0); let prod = next(r): u32: u64 * n: u64; let leftover = prod: u32; if (leftover < n) { let thresh = -n % n; for (leftover < thresh) { prod = next(r): u32: u64 * n: u64; leftover = prod: u32; }; }; return (prod >> 32): u32; }; // Returns a pseudo-random 64-bit unsigned integer in the half-open interval // [0,n). n must be greater than zero. export fn u64n(r: *random, n: u64) u64 = { assert(n != 0); // Powers of 2 can be handled more efficiently if (n & n - 1 == 0) return next(r) & n - 1; // Equivalent to 2^64 - 1 - 2^64 % n let max = -1 - -n % n; let out = next(r); for (out > max) out = next(r); return out % n; }; // Returns a pseudo-random 64-bit floating-point number in the interval // [0.0, 1.0) export fn f64rand(r: *random) f64 = { // 1.0 x 2^-53 const d: f64 = 1.1102230246251565e-16; // Take the upper 53 bits let n = next(r) >> 11; return d * n: f64; }; @test fn rng() void = { let r = init(0); let expected: [_]u64 = [ 16294208416658607535, 15501543990041496116, 15737388954706874752, 15091258616627000950, ]; for (let i = 0z; i < len(expected); i += 1) { assert(next(&r) == expected[i]); }; for (let i = 0z; i < 1000; i += 1) { assert(u32n(&r, 3) < 3); }; for (let i = 0z; i < 1000; i += 1) { assert(u64n(&r, 3) < 3); }; for (let i = 0z; i < 1000; i += 1) { // Powers of 2 have a separate codepath assert(u64n(&r, 2) < 2); }; for (let i = 0z; i < 1000; i += 1) { assert(f64rand(&r) < 1.0); }; }; hare-0.24.2/math/trig.ha000066400000000000000000000567421464473310100147470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Sections of the code below are based on Go's implementation, which is, in // turn, based on: // * the Cephes Mathematical Library (cephes/cmath/{sin,..}), available from // http://www.netlib.org/cephes/cmath.tgz. // * FreeBSD's /usr/src/lib/msun/src/{s_asinh.c,...} // The original C code, as well as the respective comments and constants are // from these libraries. // // The Cephes copyright notice: // ==================================================== // Cephes Math Library Release 2.8: June, 2000 // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier // // The readme file at http://netlib.sandia.gov/cephes/ says: // Some software in this archive may be from the book _Methods and // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster // International, 1989) or from the Cephes Mathematical Library, a // commercial product. In either event, it is copyrighted by the author. // What you see here may be used freely but it comes with no support or // guarantee. // // The two known misprints in the book are repaired here in the // source listings for the gamma function and the incomplete beta // integral. // // Stephen L. Moshier // moshier@na-net.ornl.gov // ==================================================== // // The FreeBSD copyright notice: // ==================================================== // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. // // Developed at SunPro, a Sun Microsystems, Inc. business. // Permission to use, copy, modify, and distribute this // software is freely granted, provided that this notice // is preserved. // ==================================================== // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== // sin coefficients const SIN_CF: [_]f64 = [ 1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd -2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d 2.75573136213857245213e-6, // 0x3ec71de3567d48a1 -1.98412698295895385996e-4, // 0xbf2a01a019bfdf03 8.33333333332211858878e-3, // 0x3f8111111110f7d0 -1.66666666666666307295e-1, // 0xbfc5555555555548 ]; // cos coefficients const COS_CF: [_]f64 = [ -1.13585365213876817300e-11, // 0xbda8fa49a0861a9b 2.08757008419747316778e-9, // 0x3e21ee9d7b4e3f05 -2.75573141792967388112e-7, // 0xbe927e4f7eac4bc6 2.48015872888517045348e-5, // 0x3efa01a019c844f5 -1.38888888888730564116e-3, // 0xbf56c16c16c14f91 4.16666666666665929218e-2, // 0x3fa555555555554b ]; // PI / 4 split into three parts def PI4A: f64 = 7.85398125648498535156e-1; // 0x3fe921fb40000000 def PI4B: f64 = 3.77489470793079817668e-8; // 0x3e64442d00000000 def PI4C: f64 = 2.69515142907905952645e-15; // 0x3ce8469898cc5170 // reduce_threshold is the maximum value of x where the reduction using PI/4 // in 3 float64 parts still gives accurate results. This threshold // is set by y*C being representable as a float64 without error // where y is given by y = floor(x * (4 / PI)) and C is the leading partial // terms of 4/PI. Since the leading terms (PI4A and PI4B in sin.go) have 30 // and 32 trailing zero bits, y should have less than 30 significant bits. // y < 1<<30 -> floor(x*4/PI) < 1<<30 -> x < (1<<30 - 1) * PI/4 // So, conservatively we can take x < 1<<29. // Above this threshold Payne-Hanek range reduction must be used. def REDUCE_THRESHOLD: f64 = ((1u64 << 29): f64); // MPI4 is the binary digits of 4/pi as a uint64 array, // that is, 4/pi = Sum MPI4[i]*2^(-64*i) // 19 64-bit digits and the leading one bit give 1217 bits // of precision to handle the largest possible float64 exponent. const MPI4: [_]u64 = [ 0x0000000000000001, 0x45f306dc9c882a53, 0xf84eafa3ea69bb81, 0xb6c52b3278872083, 0xfca2c757bd778ac3, 0x6e48dc74849ba5c0, 0x0c925dd413a32439, 0xfc3bd63962534e7d, 0xd1046bea5d768909, 0xd338e04d68befc82, 0x7323ac7306a673e9, 0x3908bf177bf25076, 0x3ff12fffbc0b301f, 0xde5e2316b414da3e, 0xda6cfd9e4f96136e, 0x9e8c7ecd3cbfd45a, 0xea4f758fd7cbe2f6, 0x7a0e73ef14a525d4, 0xd7f6bf623f1aba10, 0xac06608df8f6d757, ]; // trig_reduce implements Payne-Hanek range reduction by PI/4 for x > 0. It // returns the integer part mod 8 (j) and the fractional part (z) of x / (PI/4). fn trig_reduce(x: f64) (u64, f64) = { // The implementation is based on: "ARGUMENT REDUCTION FOR HUGE // ARGUMENTS: Good to the Last Bit" K. C. Ng et al, March 24, 1992 // The simulated multi-precision calculation of x * B uses 64-bit // integer arithmetic. const PI4 = PI / 4f64; if (x < PI4) { return (0u64, x); }; // Extract out the integer and exponent such that x = ix * 2 ** exp let ix = f64bits(x); const exp = ((ix >> F64_MANTISSA_BITS & F64_EXPONENT_MASK): i64) - (F64_EXPONENT_BIAS: i64) - (F64_MANTISSA_BITS: i64); ix = ix & ~(F64_EXPONENT_MASK << F64_MANTISSA_BITS); ix |= 1 << F64_MANTISSA_BITS; // Use the exponent to extract the 3 appropriate uint64 digits from // MPI4, B ~ (z0, z1, z2), such that the product leading digit has the // exponent -61. Note, exp >= -53 since x >= PI4 and exp < 971 for // maximum float64. const digit = ((exp + 61): u64) / 64; const bitshift = ((exp + 61): u64) % 64; const z0 = (MPI4[digit] << bitshift) | (MPI4[digit + 1] >> (64 - bitshift)); const z1 = (MPI4[digit + 1] << bitshift) | (MPI4[digit + 2] >> (64 - bitshift)); const z2 = (MPI4[digit + 2] << bitshift) | (MPI4[digit + 3] >> (64 - bitshift)); // Multiply mantissa by the digits and extract the upper two digits // (hi, lo). const z2 = mulu64(z2, ix); const z2hi = z2.0; const z1 = mulu64(z1, ix); const z1hi = z1.0; const z1lo = z1.1; const z0lo = z0 * ix; const add1 = addu64(z1lo, z2hi, 0); const lo = add1.0; const c = add1.1; const add2 = addu64(z0lo, z1hi, c); let hi = add2.0; // The top 3 bits are j. let j = hi >> 61; // Extract the fraction and find its magnitude. hi = hi << 3 | lo >> 61; const lz = ((leading_zeros_u64(hi)): uint); const e = ((F64_EXPONENT_BIAS - (lz + 1)): u64); // Clear implicit mantissa bit and shift into place. hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))); hi >>= 64 - F64_MANTISSA_BITS; // Include the exponent and convert to a float. hi |= e << F64_MANTISSA_BITS; let z = f64frombits(hi); // Map zeros to origin. if (j & 1 == 1) { j += 1; j &= 7; z -= 1f64; }; // Multiply the fractional part by pi/4. return (j, z * PI4); }; // cos.c // // Circular cosine // // SYNOPSIS: // // double x, y, cos(); // y = cos( x ); // // DESCRIPTION: // // Range reduction is into intervals of pi/4. The reduction error is nearly // eliminated by contriving an extended precision modular arithmetic. // // Two polynomial approximating functions are employed. // Between 0 and pi/4 the cosine is approximated by // 1 - x**2 Q(x**2). // Between pi/4 and pi/2 the sine is represented as // x + x**3 P(x**2). // // ACCURACY: // // Relative error: // arithmetic domain # trials peak rms // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 // DEC 0,+1.07e9 17000 3.0e-17 7.2e-18 // Returns the cosine of x, in radians. export fn cosf64(x: f64) f64 = { if (isnan(x) || isinf(x)) { return NAN; }; // Make argument positive let is_negative = false; x = absf(x); let j = 0u64; let y = 0f64; let z = 0f64; if (x >= REDUCE_THRESHOLD) { const reduce_res = trig_reduce(x); j = reduce_res.0; z = reduce_res.1; } else { // Integer part of x/(PI/4), as integer for tests on the phase // angle j = ((x * (4f64 / PI)): i64: u64); // Integer part of x/(PI/4), as float y = (j: i64: f64); // Map zeros to origin if (j & 1 == 1) { j += 1; y += 1f64; }; // Octant modulo 2PI radians (360 degrees) j &= 7; // Extended precision modular arithmetic z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); }; if (j > 3) { j -= 4; is_negative = !is_negative; }; if (j > 1) { is_negative = !is_negative; }; const zz = z * z; if (j == 1 || j == 2) { y = z + z * zz * ((((((SIN_CF[0] * zz) + SIN_CF[1]) * zz + SIN_CF[2]) * zz + SIN_CF[3]) * zz + SIN_CF[4]) * zz + SIN_CF[5]); } else { y = 1.0 - 0.5 * zz + zz * zz * ((((((COS_CF[0] * zz) + COS_CF[1]) * zz + COS_CF[2]) * zz + COS_CF[3]) * zz + COS_CF[4]) * zz + COS_CF[5]); }; if (is_negative) { y = -y; }; return y; }; // sin.c // // Circular sine // // SYNOPSIS: // // double x, y, sin(); // y = sin( x ); // // DESCRIPTION: // // Range reduction is into intervals of pi/4. The reduction error is nearly // eliminated by contriving an extended precision modular arithmetic. // // Two polynomial approximating functions are employed. // Between 0 and pi/4 the sine is approximated by // x + x**3 P(x**2). // Between pi/4 and pi/2 the cosine is represented as // 1 - x**2 Q(x**2). // // ACCURACY: // // Relative error: // arithmetic domain # trials peak rms // DEC 0, 10 150000 3.0e-17 7.8e-18 // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 // // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss // is not gradual, but jumps suddenly to about 1 part in 10e7. Results may // be meaningless for x > 2**49 = 5.6e14. // Returns the sine of x, in radians. export fn sinf64(x: f64) f64 = { if (x == 0f64 || isnan(x)) { return x; } else if (isinf(x)) { return NAN; }; // Make argument positive but save the sign let is_negative = false; if (x < 0f64) { x = -x; is_negative = true; }; let j = 0u64; let y = 0f64; let z = 0f64; if (x >= REDUCE_THRESHOLD) { const reduce_res = trig_reduce(x); j = reduce_res.0; z = reduce_res.1; } else { // Integer part of x/(PI/4), as integer for tests on the phase // angle j = ((x * (4f64 / PI)): i64: u64); // Integer part of x/(PI/4), as float y = (j: i64: f64); // Map zeros to origin if (j & 1 == 1) { j += 1; y += 1f64; }; // Octant modulo 2PI radians (360 degrees) j &= 7; // Extended precision modular arithmetic z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); }; // Reflect in x axis if (j > 3) { j -= 4; is_negative = !is_negative; }; const zz = z * z; if (j == 1 || j == 2) { y = 1.0 - 0.5 * zz + zz * zz * ((((((COS_CF[0] * zz) + COS_CF[1]) * zz + COS_CF[2]) * zz + COS_CF[3]) * zz + COS_CF[4]) * zz + COS_CF[5]); } else { y = z + z * zz * ((((((SIN_CF[0] * zz) + SIN_CF[1]) * zz + SIN_CF[2]) * zz + SIN_CF[3]) * zz + SIN_CF[4]) * zz + SIN_CF[5]); }; if (is_negative) { y = -y; }; return y; }; // tan.c // // Circular tangent // // SYNOPSIS: // // double x, y, tan(); // y = tan( x ); // // DESCRIPTION: // // Returns the circular tangent of the radian argument x. // // Range reduction is modulo pi/4. A rational function // x + x**3 P(x**2)/Q(x**2) // is employed in the basic interval [0, pi/4]. // // ACCURACY: // Relative error: // arithmetic domain # trials peak rms // DEC +-1.07e9 44000 4.1e-17 1.0e-17 // IEEE +-1.07e9 30000 2.9e-16 8.1e-17 // // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss // is not gradual, but jumps suddenly to about 1 part in 10e7. Results may // be meaningless for x > 2**49 = 5.6e14. // [Accuracy loss statement from sin.go comments.] // tan coefficients const TAN_P: [_]f64 = [ -1.30936939181383777646e4, // 0xc0c992d8d24f3f38 1.15351664838587416140e6, // 0x413199eca5fc9ddd -1.79565251976484877988e7, // 0xc1711fead3299176 ]; const TAN_Q: [_]f64 = [ 1.00000000000000000000e0, 1.36812963470692954678e4, // 0x40cab8a5eeb36572 -1.32089234440210967447e6, // 0xc13427bc582abc96 2.50083801823357915839e7, // 0x4177d98fc2ead8ef -5.38695755929454629881e7, // 0xc189afe03cbe5a31 ]; // Returns the tangent of x, in radians. export fn tanf64(x: f64) f64 = { if (x == 0f64 || isnan(x)) { return x; } else if (isinf(x)) { return NAN; }; // Make argument positive but save the sign let is_negative = false; if (x < 0f64) { x = -x; is_negative = true; }; let j = 0u64; let y = 0f64; let z = 0f64; if (x >= REDUCE_THRESHOLD) { const reduce_res = trig_reduce(x); j = reduce_res.0; z = reduce_res.1; } else { // Integer part of x/(PI/4), as integer for tests on the phase // angle j = ((x * (4f64 / PI)): i64: u64); // Integer part of x/(PI/4), as float y = (j: i64: f64); // Map zeros and singularities to origin if (j & 1 == 1) { j += 1; y += 1f64; }; z = ((x - (y * PI4A)) - (y * PI4B)) - (y * PI4C); }; const zz = z * z; if (zz > 1e-14) { y = z + z * (zz * (((TAN_P[0] * zz) + TAN_P[1]) * zz + TAN_P[2]) / ((((zz + TAN_Q[1]) * zz + TAN_Q[2]) * zz + TAN_Q[3]) * zz + TAN_Q[4])); } else { y = z; }; if (j & 2 == 2) { y = -1f64 / y; }; if (is_negative) { y = -y; }; return y; }; // Evaluates a series valid in the range [0, 0.66]. fn xatan(x: f64) f64 = { const P0 = -8.750608600031904122785e-01; const P1 = -1.615753718733365076637e+01; const P2 = -7.500855792314704667340e+01; const P3 = -1.228866684490136173410e+02; const P4 = -6.485021904942025371773e+01; const Q0 = 2.485846490142306297962e+01; const Q1 = 1.650270098316988542046e+02; const Q2 = 4.328810604912902668951e+02; const Q3 = 4.853903996359136964868e+02; const Q4 = 1.945506571482613964425e+02; let z = x * x; z = z * ((((P0 * z + P1) * z + P2) * z + P3) * z + P4) / (((((z + Q0) * z + Q1) * z + Q2) * z + Q3) * z + Q4); z = (x * z) + x; return z; }; // Reduces argument (known to be positive) to the range [0, 0.66] and calls // xatan. fn satan(x: f64) f64 = { // pi / 2 = PIO2 + morebits const morebits = 6.123233995736765886130e-17; // tan(3 * pi / 8) const tan3pio8 = 2.41421356237309504880; if (x <= 0.66) { return xatan(x); }; if (x > tan3pio8) { return (PI / 2f64) - xatan(1f64 / x) + morebits; }; return (PI / 4f64) + xatan((x - 1f64) / (x + 1f64)) + (0.5f64 * morebits); }; // Returns the arcsine, in radians, of x. export fn asinf64(x: f64) f64 = { if (x == 0f64) { return x; }; let is_negative = false; if (x < 0.064) { x = -x; is_negative = true; }; if (x > 1f64) { return NAN; }; let temp = sqrtf64(1f64 - x * x); if (x > 0.7f64) { temp = PI / 2f64 - satan(temp / x); } else { temp = satan(x / temp); }; if (is_negative) { temp = -temp; }; return temp; }; // Returns the arccosine, in radians, of x. export fn acosf64(x: f64) f64 = { return PI / 2f64 - asinf64(x); }; // atan.c // Inverse circular tangent (arctangent) // // SYNOPSIS: // double x, y, atan(); // y = atan( x ); // // DESCRIPTION: // Returns radian angle between -pi/2 and +pi/2 whose tangent is x. // // Range reduction is from three intervals into the interval from zero to 0.66. // The approximant uses a rational function of degree 4/5 of the form // x + x**3 P(x)/Q(x). // // ACCURACY: // Relative error: // arithmetic domain # trials peak rms // DEC -10, 10 50000 2.4e-17 8.3e-18 // IEEE -10, 10 10^6 1.8e-16 5.0e-17 // Returns the arctangent, in radians, of x. export fn atanf64(x: f64) f64 = { if (x == 0f64) { return x; }; if (x > 0f64) { return satan(x); }; return -satan(-x); }; // Floating-point hyperbolic sine and cosine. // The exponential func is called for arguments greater in magnitude than 0.5. // A series is used for arguments smaller in magnitude than 0.5. // Cosh(x) is computed from the exponential func for all arguments. // Returns the hyperbolic sine of x. export fn sinhf64(x: f64) f64 = { // The coefficients are #2029 from Hart & Cheney. (20.36D) const P0 = -0.6307673640497716991184787251e+6; const P1 = -0.8991272022039509355398013511e+5; const P2 = -0.2894211355989563807284660366e+4; const P3 = -0.2630563213397497062819489e+2; const Q0 = -0.6307673640497716991212077277e+6; const Q1 = 0.1521517378790019070696485176e+5; const Q2 = -0.173678953558233699533450911e+3; let is_negative = false; if (x < 0f64) { x = -x; is_negative = true; }; let temp = 0f64; if (x > 21f64) { temp = expf64(x) * 0.5f64; } else if (x > 0.5f64) { const ex = expf64(x); temp = (ex - (1f64 / ex)) * 0.5f64; } else { const sq = x * x; temp = (((P3 * sq + P2) * sq + P1) * sq + P0) * x; temp = temp / (((sq + Q2) * sq + Q1) * sq + Q0); }; if (is_negative) { temp = -temp; }; return temp; }; // Returns the hyperbolic cosine of x. export fn coshf64(x: f64) f64 = { x = absf64(x); if (x > 21f64) { return expf64(x) * 0.5f64; }; const ex = expf64(x); return (ex + 1f64 / ex) * 0.5f64; }; // tanh.c // // Hyperbolic tangent // // SYNOPSIS: // // double x, y, tanh(); // // y = tanh( x ); // // DESCRIPTION: // // Returns hyperbolic tangent of argument in the range MINLOG to MAXLOG. // MAXLOG = 8.8029691931113054295988e+01 = log(2**127) // MINLOG = -8.872283911167299960540e+01 = log(2**-128) // // A rational function is used for |x| < 0.625. The form // x + x**3 P(x)/Q(x) of Cody & Waite is employed. // Otherwise, // tanh(x) = sinh(x)/cosh(x) = 1 - 2/(exp(2x) + 1). // // ACCURACY: // // Relative error: // arithmetic domain # trials peak rms // IEEE -2,2 30000 2.5e-16 5.8e-17 // tanh coefficients const TANH_P: [_]f64 = [ -9.64399179425052238628e-1, -9.92877231001918586564e1, -1.61468768441708447952e3, ]; const TANH_Q: [_]f64 = [ 1.12811678491632931402e2, 2.23548839060100448583e3, 4.84406305325125486048e3, ]; // Returns the hyperbolic tangent of x. export fn tanhf64(x: f64) f64 = { const MAXLOG = 8.8029691931113054295988e+01; // log(2**127) let z = absf64(x); if (z > 0.5f64 * MAXLOG) { if (x < 0f64) { return -1f64; }; return 1f64; } else if (z >= 0.625f64) { const s = expf64(2f64 * z); z = 1f64 - 2f64 / (s + 1f64); if (x < 0f64) { z = -z; }; } else { if (x == 0f64) { return x; }; const s = x * x; z = x + x * s * ((TANH_P[0] * s + TANH_P[1]) * s + TANH_P[2]) / (((s + TANH_Q[0]) * s + TANH_Q[1]) * s + TANH_Q[2]); }; return z; }; // asinh(x) // Method : // Based on // asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] // we have // asinh(x) := x if 1+x*x=1, // := sign(x)*(log(x)+ln2)) for large |x|, else // := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else // := sign(x)*log1p(|x| + x**2/(1 + sqrt(1+x**2))) // // Returns the inverse hyperbolic sine of x. export fn asinhf64(x: f64) f64 = { const NEAR_ZERO = 1f64 / ((1i64 << 28): f64); const LARGE = ((1i64 << 28): f64); if (isnan(x) || isinf(x)) { return x; }; let is_negative = false; if (x < 0f64) { x = -x; is_negative = true; }; let temp = 0f64; if (x > LARGE) { // |x| > 2**28 temp = logf64(x) + LN_2; } else if (x > 2f64) { // 2**28 > |x| > 2.0 temp = logf64(2f64 * x + 1f64 / (sqrtf64(x * x + 1f64) + x)); } else if (x < NEAR_ZERO) { // |x| < 2**-28 temp = x; } else { // 2.0 > |x| > 2**-28 temp = log1pf64(x + x * x / (1f64 + sqrtf64(1f64 + x * x))); }; if (is_negative) { temp = -temp; }; return temp; }; // __ieee754_acosh(x) // Method : // Based on // acosh(x) = log [ x + sqrt(x*x-1) ] // we have // acosh(x) := log(x)+ln2, if x is large; else // acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else // acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. // // Special cases: // acosh(x) is NaN with signal if x<1. // acosh(NaN) is NaN without signal. // // Returns the inverse hyperbolic cosine of x. export fn acoshf64(x: f64) f64 = { const LARGE = ((1i64 << 28): f64); if (x < 1f64 || isnan(x)) { return NAN; } else if (x == 1f64) { return 0f64; } else if (x >= LARGE) { // x > 2**28 return logf64(x) + LN_2; } else if (x > 2f64) { // 2**28 > x > 2 return logf64(2f64 * x - 1f64 / (x + sqrtf64(x * x - 1f64))); }; const t = x - 1f64; // 2 >= x > 1 return log1pf64(t + sqrtf64(2f64 * t + t * t)); }; // __ieee754_atanh(x) // Method : // 1. Reduce x to positive by atanh(-x) = -atanh(x) // 2. For x>=0.5 // 1 2x x // atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) // 2 1 - x 1 - x // // For x<0.5 // atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) // // Special cases: // atanh(x) is NaN if |x| > 1 with signal; // atanh(NaN) is that NaN with no signal; // atanh(+-1) is +-INF with signal. // // Returns the inverse hyperbolic tangent of x. export fn atanhf64(x: f64) f64 = { const NEAR_ZERO = 1f64 / ((1i64 << 28): f64); if (x < -1f64 || x > 1.064) { return NAN; } else if (isnan(x)) { return NAN; } else if (x == 1f64) { return INF; } else if (x == -1f64) { return -INF; }; let is_negative = false; if (x < 0f64) { x = -x; is_negative = true; }; let temp = 0f64; if (x < NEAR_ZERO) { temp = x; } else if (x < 0.5f64) { temp = x + x; temp = 0.5f64 * log1pf64(temp + temp * x / (1f64 - x)); } else { temp = 0.5f64 * log1pf64((x + x) / (1f64 - x)); }; if (is_negative) { temp = -temp; }; return temp; }; // Returns the arctangent, in radians, of y / x. export fn atan2f64(y: f64, x: f64) f64 = { if (isnan(y) || isnan(x)) { return NAN; } else if (y == 0f64) { x = if (x >= 0f64 && signf64(x) > 0) 0f64 else PI; return copysignf64(x, y); } else if (x == 0f64) { return copysignf64(PI / 2f64, y); } else if (isinf(x)) { if (signf64(x) > 0) { x = if (isinf(y)) PI / 4f64 else 0f64; return copysignf64(x, y); } else { x = if (isinf(y)) 3f64 * PI / 4f64 else PI; return copysignf64(x, y); }; } else if (isinf(y)) { return copysignf64(PI / 2f64, y); }; const q = atanf64(y / x); if (x < 0f64) { return if (q <= 0f64) q + PI else q - PI; }; return q; }; // Returns the square root of a*a + b*b, taking care to avoid unnecessary // overflow and underflow. export fn hypotf64(a: f64, b: f64) f64 = { if (isinf(a) || isinf(b)) { return INF; } else if (isnan(a) || isnan(b)) { return NAN; }; a = absf64(a); b = absf64(b); if (a < b) { const temp = a; a = b; b = temp; }; if (a == 0f64) { return 0f64; }; b = b / a; return a * sqrtf64(1f64 + b * b); }; hare-0.24.2/math/uints.ha000066400000000000000000000533051464473310100151340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Sections of the code below are based on Go's implementation, in particular // https://raw.githubusercontent.com/golang/go/master/src/math/bits/bits.go. // // The Go copyright notice: // ==================================================== // Copyright (c) 2009 The Go Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ==================================================== // The number of bits required to represent the first 256 numbers. const LEN8TAB: [256]u8 = [ 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, ]; const NTZ8TAB: [256]u8 = [ 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, ]; // See http://supertech.csail.mit.edu/papers/debruijn.pdf def DEBRUIJN32: u32 = 0x077CB531; const DEBRUIJN32TAB: [32]u8 = [ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, ]; def DEBRUIJN64: u64 = 0x03f79d71b4ca8b09; const DEBRUIJN64TAB: [64]u8 = [ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, ]; // The size of an unsigned int: 32 or 64 def UINT_SIZE: u8 = (size(uint): u8) * 8; // Returns the minimum number of bits required to represent x. export fn bit_size_u8(x: u8) u8 = { return LEN8TAB[x]; }; // Returns the minimum number of bits required to represent x. export fn bit_size_u16(x: u16) u8 = { let res = 0u8; if (x >= 1u16 << 8) { x >>= 8; res += 8; }; return res + LEN8TAB[x]; }; // Returns the minimum number of bits required to represent x. export fn bit_size_u32(x: u32) u8 = { let res = 0u8; if (x >= 1u32 << 16) { x >>= 16; res += 16; }; if (x >= 1u32 << 8) { x >>= 8; res += 8; }; return res + LEN8TAB[x]; }; // Returns the minimum number of bits required to represent x. export fn bit_size_u64(x: u64) u8 = { let res = 0u8; if (x >= 1u64 << 32) { x >>= 32; res += 32; }; if (x >= 1u64 << 16) { x >>= 16; res += 16; }; if (x >= 1u64 << 8) { x >>= 8; res += 8; }; return res + LEN8TAB[x]; }; // Returns the minimum number of bits required to represent x. export fn bit_size_u(x: uint) u8 = { if (UINT_SIZE == 32) { return bit_size_u32(x: u32); }; return bit_size_u64(x: u64); }; @test fn bit_size_u() void = { assert(bit_size_u8(0) == 0); assert(bit_size_u8(2) == 2); assert(bit_size_u8(5) == 3); assert(bit_size_u16(5) == 3); assert(bit_size_u32(5) == 3); assert(bit_size_u64(5) == 3); assert(bit_size_u16(31111) == 15); assert(bit_size_u32(536870911) == 29); assert(bit_size_u64(8589934591) == 33); assert(bit_size_u(0) == 0); assert(bit_size_u(1) == 1); }; // Returns the number of leading zero bits in x // The result is UINT_SIZE for x == 0. export fn leading_zeros_u(x: uint) u8 = UINT_SIZE - bit_size_u(x); // Returns the number of leading zero bits in x // The result is 8 for x == 0. export fn leading_zeros_u8(x: u8) u8 = 8 - bit_size_u8(x); // Returns the number of leading zero bits in x // The result is 16 for x == 0. export fn leading_zeros_u16(x: u16) u8 = 16 - bit_size_u16(x); // Returns the number of leading zero bits in x // The result is 32 for x == 0. export fn leading_zeros_u32(x: u32) u8 = 32 - bit_size_u32(x); // Returns the number of leading zero bits in x // The result is 64 for x == 0. export fn leading_zeros_u64(x: u64) u8 = 64 - bit_size_u64(x); @test fn leading_zeros_u() void = { assert(leading_zeros_u(0) == UINT_SIZE); assert(leading_zeros_u(1) == UINT_SIZE - 1); assert(leading_zeros_u8(0) == 8); assert(leading_zeros_u8(1) == 8 - 1); assert(leading_zeros_u16(0) == 16); assert(leading_zeros_u16(1) == 16 - 1); assert(leading_zeros_u32(0) == 32); assert(leading_zeros_u32(1) == 32 - 1); assert(leading_zeros_u64(0) == 64); assert(leading_zeros_u64(1) == 64 - 1); }; // Returns the number of trailing zero bits in x // The result is UINT_SIZE for x == 0. export fn trailing_zeros_u(x: uint) u8 = { if (UINT_SIZE == 32) { return trailing_zeros_u32(x: u32); }; return trailing_zeros_u64(x: u64); }; // Returns the number of trailing zero bits in x // The result is 8 for x == 0. export fn trailing_zeros_u8(x: u8) u8 = NTZ8TAB[x]; // Returns the number of trailing zero bits in x // The result is 16 for x == 0. export fn trailing_zeros_u16(x: u16) u8 = { if (x == 0) { return 16; }; return DEBRUIJN32TAB[(x & -x): u32 * DEBRUIJN32 >> (32 - 5)]; }; // Returns the number of trailing zero bits in x // The result is 32 for x == 0. export fn trailing_zeros_u32(x: u32) u8 = { if (x == 0) { return 32; }; return DEBRUIJN32TAB[(x & -x) * DEBRUIJN32 >> (32 - 5)]; }; // Returns the number of trailing zero bits in x // The result is 64 for x == 0. export fn trailing_zeros_u64(x: u64) u8 = { if (x == 0) { return 64; }; return DEBRUIJN64TAB[(x & -x) * DEBRUIJN64 >> (64 - 6)]; }; @test fn trailing_zeros_u() void = { assert(trailing_zeros_u8(0) == 8); for (let x: u8 = 1 << 7, i = 7u8; x > 0; x >>= 1) { assert(trailing_zeros_u8(x) == i); i -= 1; }; assert(trailing_zeros_u16(0) == 16); for (let x: u16 = 1 << 15, i = 15u8; x > 0; x >>= 1) { assert(trailing_zeros_u16(x) == i); i -= 1; }; assert(trailing_zeros_u32(0) == 32); for (let x: u32 = 1 << 31, i = 31u8; x > 0; x >>= 1) { assert(trailing_zeros_u32(x) == i); i -= 1; }; assert(trailing_zeros_u64(0) == 64); for (let x: u64 = 1 << 63, i = 63u8; x > 0; x >>= 1) { assert(trailing_zeros_u64(x) == i); i -= 1; }; assert(trailing_zeros_u(0) == UINT_SIZE); assert(trailing_zeros_u(1) == 0); }; // Returns the number of bits set (the population count) of x. export fn popcount(x: u64) u8 = { let i = 0u8; for (x != 0; x >>= 1) { if (x & 1 == 1) { i += 1; }; }; return i; }; @test fn popcount() void = { assert(popcount(0) == 0); assert(popcount(0b11010110) == 5); assert(popcount(~0) == 64); }; // Returns the sum with carry of x, y and carry: sum = x + y + carry. // The carry input must be 0 or 1, otherwise the behavior is undefined. // The carry_out output is guaranteed to be 0 or 1. export fn addu32(x: u32, y: u32, carry: u32) (u32, u32) = { const sum64 = (x: u64) + (y: u64) + (carry: u64); const sum = (sum64: u32); const carry_out = ((sum64 >> 32): u32); return (sum, carry_out); }; // Returns the sum with carry of x, y and carry: sum = x + y + carry. // The carry input must be 0 or 1, otherwise the behavior is undefined. // The carry_out output is guaranteed to be 0 or 1. export fn addu64(x: u64, y: u64, carry: u64) (u64, u64) = { const sum = x + y + carry; // The sum will overflow if both top bits are set (x & y) or if one of // them is (x | y), and a carry from the lower place happened. If such a // carry happens, the top bit will be 1 + 0 + 1 = 0 (& ~sum). const carry_out = ((x & y) | ((x | y) & ~sum)) >> 63; return (sum, carry_out); }; // Calls either addu32() or addu64() depending on size(uint). export fn addu(x: uint, y: uint, carry: uint) (uint, uint) = { if (UINT_SIZE == 32) { const res = addu32((x: u32), (y: u32), (carry: u32)); return ((res.0: uint), (res.1: uint)); }; const res = addu64((x: u64), (y: u64), (carry: u64)); return ((res.0: uint), (res.1: uint)); }; @test fn addu() void = { // 32 let res = addu32(2u32, 2u32, 0u32); assert(res.0 == 4u32); assert(res.1 == 0u32); let res = addu32(2u32, 2u32, 1u32); assert(res.0 == 5u32); assert(res.1 == 0u32); let res = addu32(~0u32, 0u32, 0u32); assert(res.0 == ~0u32); assert(res.1 == 0u32); let res = addu32(~0u32, 1u32, 0u32); assert(res.0 == 0u32); assert(res.1 == 1u32); // 64 let res = addu64(2u64, 2u64, 0u64); assert(res.0 == 4u64); assert(res.1 == 0u64); let res = addu64(2u64, 2u64, 1u64); assert(res.0 == 5u64); assert(res.1 == 0u64); let res = addu64(~0u64, 0u64, 0u64); assert(res.0 == ~0u64); assert(res.1 == 0u64); let res = addu64(~0u64, 1u64, 0u64); assert(res.0 == 0u64); assert(res.1 == 1u64); // addu() let res = addu(2u, 2u, 0u); assert(res.0 == 4u); assert(res.1 == 0u); let res = addu(2u, 2u, 1u); assert(res.0 == 5u); assert(res.1 == 0u); }; // Returns the difference of x, y and borrow, diff = x - y - borrow. // The borrow input must be 0 or 1, otherwise the behavior is undefined. // The borrow_out output is guaranteed to be 0 or 1. export fn subu32(x: u32, y: u32, borrow: u32) (u32, u32) = { const diff = x - y - borrow; // The difference will underflow if the top bit of x is not set and the // top bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a // borrow from the lower place happens. If that borrow happens, the // result will be 1 - 1 - 1 = 0 - 0 - 1 = 1 (& diff). const borrow_out = ((~x & y) | (~(x ^ y) & diff)) >> 31; return (diff, borrow_out); }; // Returns the difference of x, y and borrow, diff = x - y - borrow. // The borrow input must be 0 or 1, otherwise the behavior is undefined. // The borrow_out output is guaranteed to be 0 or 1. export fn subu64(x: u64, y: u64, borrow: u64) (u64, u64) = { const diff = x - y - borrow; // See subu32 for the bit logic. const borrow_out = ((~x & y) | (~(x ^ y) & diff)) >> 63; return (diff, borrow_out); }; // Calls either mulu32() or mulu64() depending on size(uint). export fn subu(x: uint, y: uint, carry: uint) (uint, uint) = { if (UINT_SIZE == 32) { const res = subu32((x: u32), (y: u32), (carry: u32)); return ((res.0: uint), (res.1: uint)); }; const res = subu64((x: u64), (y: u64), (carry: u64)); return ((res.0: uint), (res.1: uint)); }; @test fn subu() void = { // 32 let res = subu32(4u32, 2u32, 0u32); assert(res.0 == 2u32); assert(res.1 == 0u32); let res = subu32(4u32, 2u32, 1u32); assert(res.0 == 1u32); assert(res.1 == 0u32); let res = subu32(0u32, 0u32, 0u32); assert(res.0 == 0u32); assert(res.1 == 0u32); let res = subu32(0u32, 1u32, 0u32); assert(res.0 == ~0u32); assert(res.1 == 1u32); // 64 let res = subu64(4u64, 2u64, 0u64); assert(res.0 == 2u64); assert(res.1 == 0u64); let res = subu64(4u64, 2u64, 1u64); assert(res.0 == 1u64); assert(res.1 == 0u64); let res = subu64(0u64, 0u64, 0u64); assert(res.0 == 0u64); assert(res.1 == 0u64); let res = subu64(0u64, 1u64, 0u64); assert(res.0 == ~0u64); assert(res.1 == 1u64); // subu() let res = subu(4u, 2u, 0u); assert(res.0 == 2u); assert(res.1 == 0u); let res = subu(4u, 2u, 1u); assert(res.0 == 1u); assert(res.1 == 0u); }; // Returns the 64-bit product of x and y: (hi, lo) = x * y // with the product bits' upper half returned in hi and the lower // half returned in lo. export fn mulu32(x: u32, y: u32) (u32, u32) = { const product = (x: u64) * (y: u64); const hi = ((product >> 32): u32); const lo = (product: u32); return (hi, lo); }; // Returns the 128-bit product of x and y: (hi, lo) = x * y // with the product bits' upper half returned in hi and the lower // half returned in lo. export fn mulu64(x: u64, y: u64) (u64, u64) = { const mask32 = (1u64 << 32) - 1; const x0 = x & mask32; const x1 = x >> 32; const y0 = y & mask32; const y1 = y >> 32; const w0 = x0 * y0; const t = (x1 * y0) + (w0 >> 32); let w1 = t & mask32; const w2 = t >> 32; w1 += x0 * y1; const hi = (x1 * y1) + w2 + (w1 >> 32); const lo = x * y; return (hi, lo); }; // Calls either mulu32() or mulu64() depending on size(uint). export fn mulu(x: uint, y: uint) (uint, uint) = { if (UINT_SIZE == 32) { const res = mulu32((x: u32), (y: u32)); return ((res.0: uint), (res.1: uint)); }; const res = mulu64((x: u64), (y: u64)); return ((res.0: uint), (res.1: uint)); }; @test fn mulu() void = { // 32 let res = mulu32(2u32, 3u32); assert(res.0 == 0u32); assert(res.1 == 6u32); let res = mulu32(~0u32, 2u32); assert(res.0 == 1u32); assert(res.1 == ~0u32 - 1); // 64 let res = mulu64(2u64, 3u64); assert(res.0 == 0u64); assert(res.1 == 6u64); let res = mulu64(~0u64, 2u64); assert(res.0 == 1u64); assert(res.1 == ~0u64 - 1); // mulu() let res = mulu(2u, 3u); assert(res.0 == 0u); assert(res.1 == 6u); let res = mulu(~0u, 2u); assert(res.0 == 1u); assert(res.1 == ~0u - 1); }; // Returns the quotient and remainder of (hi, lo) divided by y: // quo = (hi, lo) / y, rem = (hi, lo) % y with the dividend bits' upper // half in parameter hi and the lower half in parameter lo. // Panics for y == 0 (division by zero) or y <= hi (quotient overflow). export fn divu32(hi: u32, lo: u32, y: u32) (u32, u32) = { assert(y != 0); assert(y > hi); const z = (hi: u64) << 32 | (lo: u64); const quo = ((z / (y: u64)): u32); const rem = ((z % (y: u64)): u32); return (quo, rem); }; // Returns the quotient and remainder of (hi, lo) divided by y: // quo = (hi, lo) / y, rem = (hi, lo) % y with the dividend bits' upper // half in parameter hi and the lower half in parameter lo. // Panics for y == 0 (division by zero) or y <= hi (quotient overflow). export fn divu64(hi: u64, lo: u64, y: u64) (u64, u64) = { const two32 = 1u64 << 32; const mask32 = two32 - 1; assert(y != 0); assert(y > hi); const s = leading_zeros_u64(y); y <<= s; const yn1 = y >> 32; const yn0 = y & mask32; const un32 = (hi << s) | (lo >> (64 - s)); const un10 = lo << s; const un1 = un10 >> 32; const un0 = un10 & mask32; let q1 = un32 / yn1; let rhat = un32 - (q1 * yn1); for (q1 >= two32 || (q1 * yn0) > ((two32 * rhat) + un1)) { q1 -= 1; rhat += yn1; if (rhat >= two32) { break; }; }; const un21 = (un32 * two32) + un1 - (q1 * y); let q0 = un21 / yn1; rhat = un21 - (q0 * yn1); for (q0 >= two32 || (q0 * yn0) > ((two32 * rhat) + un0)) { q0 -= 1; rhat += yn1; if (rhat >= two32) { break; }; }; const quo = (q1 * two32) + q0; const rem = ((un21 * two32) + un0 - (q0 * y)) >> s; return (quo, rem); }; // Calls either divu32() or divu64() depending on size(uint). export fn divu(hi: uint, lo: uint, y: uint) (uint, uint) = { if (UINT_SIZE == 32) { const res = divu32((hi: u32), (lo: u32), (y: u32)); return ((res.0: uint), (res.1: uint)); }; const res = divu64((hi: u64), (lo: u64), (y: u64)); return ((res.0: uint), (res.1: uint)); }; @test fn divu() void = { // 32 let res = divu32(0u32, 4u32, 2u32); assert(res.0 == 2u32); assert(res.1 == 0u32); let res = divu32(0u32, 5u32, 2u32); assert(res.0 == 2u32); assert(res.1 == 1u32); let res = divu32(1u32, 0u32, 2u32); assert(res.0 == (1u32 << 31)); assert(res.1 == 0u32); // These should panic. // let res = divu32(1u32, 1u32, 0u32); // let res = divu32(1u32, 0u32, 1u32); // 64 let res = divu64(0u64, 4u64, 2u64); assert(res.0 == 2u64); assert(res.1 == 0u64); let res = divu64(0u64, 5u64, 2u64); assert(res.0 == 2u64); assert(res.1 == 1u64); let res = divu64(1u64, 0u64, 2u64); assert(res.0 == (1u64 << 63)); assert(res.1 == 0u64); // These should panic. // let res = divu64(1u64, 1u64, 0u64); // let res = divu64(1u64, 0u64, 1u64); // divu() let res = divu(0u, 4u, 2u); assert(res.0 == 2u); assert(res.1 == 0u); let res = divu(0u, 5u, 2u); assert(res.0 == 2u); assert(res.1 == 1u); let res = divu(1u, 0u, 2u); assert(res.0 == (1u << 31)); assert(res.1 == 0u); // These should panic. // divu(1u, 1u, 0u); // divu(1u, 0u, 1u); }; // Returns the remainder of (hi, lo) divided by y. // Panics for y == 0 (division by zero) but, unlike divu(), it doesn't panic on // a quotient overflow. export fn remu32(hi: u32, lo: u32, y: u32) u32 = { assert(y != 0); const res = ((hi: u64) << 32 | (lo: u64)) % (y: u64); return (res: u32); }; // Returns the remainder of (hi, lo) divided by y. // Panics for y == 0 (division by zero) but, unlike divu(), it doesn't panic on // a quotient overflow. export fn remu64(hi: u64, lo: u64, y: u64) u64 = { assert(y != 0); // We scale down hi so that hi < y, then use divu() to compute the // rem with the guarantee that it won't panic on quotient overflow. // Given that // hi ≡ hi%y (mod y) // we have // hi<<64 + lo ≡ (hi%y)<<64 + lo (mod y) const res = divu64(hi % y, lo, y); return res.1; }; // Calls either remu32() or remu64() depending on size(uint). export fn remu(hi: uint, lo: uint, y: uint) uint = { if (UINT_SIZE == 32) { return (remu32((hi: u32), (lo: u32), (y: u32)): uint); }; return (remu64((hi: u64), (lo: u64), (y: u64)): uint); }; @test fn remu() void = { // 32 assert(remu32(0u32, 4u32, 2u32) == 0u32); assert(remu32(0u32, 5u32, 2u32) == 1u32); assert(remu32(0u32, 5u32, 3u32) == 2u32); assert(remu32(1u32, 1u32, 2u32) == 1u32); // These should panic. // remu32(0u32, 4u32, 0u32); // 64 assert(remu64(0u64, 4u64, 2u64) == 0u64); assert(remu64(0u64, 5u64, 2u64) == 1u64); assert(remu64(0u64, 5u64, 3u64) == 2u64); assert(remu64(1u32, 1u32, 2u32) == 1u32); // These should panic. // remu64(0u64, 4u64, 0u64); // remu() assert(remu(0u, 4u, 2u) == 0u); assert(remu(0u, 5u, 2u) == 1u); assert(remu(0u, 5u, 3u) == 2u); assert(remu(1u, 1u, 2u) == 1u); // These should panic. // remu(0u, 4u, 0u); }; // Returns the greatest common divisor of a and b. export fn gcd(a: u64, b: u64) u64 = { if (a == b) { return a; }; if (a == 0) { return b; }; if (b == 0) { return a; }; const i = trailing_zeros_u64(a); const j = trailing_zeros_u64(b); a >>= i; b >>= j; const k = if (i < j) i else j; for (true) { if (a > b) { const t = a; a = b; b = t; }; b -= a; if (b == 0) { return a << k; }; b >>= trailing_zeros_u64(b); }; }; @test fn gcd() void = { assert(gcd(2 * 3 * 5, 3 * 7) == 3); assert(gcd(2, 7) == 1); assert(gcd(2, 0) == 2); assert(gcd(0, 2) == 2); // gcd(123 * 2^55 * 3, 123 * 7) assert(gcd((123 << 55) * 3, 123 * 7) == 123); }; hare-0.24.2/memio/000077500000000000000000000000001464473310100136275ustar00rootroot00000000000000hare-0.24.2/memio/README000066400000000000000000000012771464473310100145160ustar00rootroot00000000000000memio provides implementations of [[io::stream]] which can read from or write to byte slices. [[fixed]] uses a caller-supplied buffer for storage, while [[dynamic]] uses a dynamically allocated buffer which will grow instead of erroring when writing past the end of the buffer. All memio streams are seekable; the read-write head works the same way as an operating system file. You can access the contents of the buffer via [[buffer]] and [[string]]. Additionally, memio provides string-related I/O operations. Each of the utility functions (e.g. [[appendrune]]) work correctly with any [[io::handle]], but for efficiency reasons it is recommended that they are either a memio:: or [[bufio::]] stream. hare-0.24.2/memio/ops.ha000066400000000000000000000103121464473310100147370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use io; use strings; // Appends zero or more strings to an [[io::handle]]. The output needn't be a // memio stream, but it's generally more efficient if it is. Returns the number // of bytes written, or an error. export fn concat(out: io::handle, strs: str...) (size | io::error) = join(out, "", strs...); @test fn concat() void = { let st = dynamic(); defer io::close(&st)!; let tests: [_]([]str, str) = [ ([], ""), ([""], ""), (["", ""], ""), (["hello"], "hello"), (["hello", " ", "world"], "hello world"), (["", "hello", " ", "world"], "hello world"), (["hello", " ", "world", ""], "hello world"), (["hello", "", " ", "world"], "hello world") ]; for (let i = 0z; i < len(tests); i += 1) { let ln = concat(&st, tests[i].0...) as size; assert(ln == len(tests[i].1) && string(&st)! == tests[i].1); reset(&st); }; }; // Joins several strings together by a delimiter and writes them to a handle. // The output needn't be a memio stream, but it's generally more efficient if it // is. Returns the number of bytes written, or an error. export fn join(out: io::handle, delim: str, strs: str...) (size | io::error) = { let n = 0z; let delim = strings::toutf8(delim); for (let i = 0z; i < len(strs); i += 1) { n += io::writeall(out, strings::toutf8(strs[i]))?; if (len(delim) != 0 && i + 1 < len(strs)) { n += io::writeall(out, delim)?; }; }; return n; }; @test fn join() void = { let st = dynamic(); defer io::close(&st)!; let tests: [_](str, []str, str) = [ ("::", [], ""), ("::", [""], ""), ("::", ["", ""], "::"), ("::", ["", "", ""], "::::"), ("::", ["hello"], "hello"), ("::", ["hello", "world"], "hello::world"), ("::", ["", "hello", "world"], "::hello::world"), ("::", ["hello", "world", ""], "hello::world::"), ("::", ["hello", "", "world"], "hello::::world"), ]; for (let i = 0z; i < len(tests); i += 1) { let ln = join(&st, tests[i].0, tests[i].1...) as size; assert(ln == len(tests[i].2) && string(&st)! == tests[i].2); reset(&st); }; }; // Appends zero or more strings to an [[io::handle]], in reverse order. The // output needn't be a memio stream, but it's generally more efficient if it is. // Returns the number of bytes written, or an error. export fn rconcat(out: io::handle, strs: str...) (size | io::error) = rjoin(out, "", strs...); @test fn rconcat() void = { let st = dynamic(); defer io::close(&st)!; let tests: [_]([]str, str) = [ ([], ""), ([""], ""), (["", ""], ""), (["hello"], "hello"), (["hello", " ", "world"], "world hello"), (["", "hello", " ", "world"], "world hello"), (["hello", " ", "world", ""], "world hello"), (["hello", "", " ", "world"], "world hello") ]; for (let i = 0z; i < len(tests); i += 1) { let ln = rconcat(&st, tests[i].0...) as size; assert(ln == len(tests[i].1) && string(&st)! == tests[i].1); reset(&st); }; }; // Joins several strings together by a delimiter and writes them to a handle, in // reverse order. The output needn't be a memio stream, but it's generally more // efficient if it is. Returns the number of bytes written, or an error. export fn rjoin(out: io::handle, delim: str, strs: str...) (size | io::error) = { let n = 0z; let delim = strings::toutf8(delim); for (let i = len(strs); i > 0; i -= 1) { n += io::writeall(out, strings::toutf8(strs[i - 1]))?; if (len(delim) != 0 && i - 1 > 0) { n += io::writeall(out, delim)?; }; }; return n; }; @test fn rjoin() void = { let st = dynamic(); defer io::close(&st)!; let tests: [_](str, []str, str) = [ ("::", [], ""), ("::", [""], ""), ("::", ["", ""], "::"), ("::", ["", "", ""], "::::"), ("::", ["hello"], "hello"), ("::", ["hello", "world"], "world::hello"), ("::", ["", "hello", "world"], "world::hello::"), ("::", ["hello", "world", ""], "::world::hello"), ("::", ["hello", "", "world"], "world::::hello"), ]; for (let i = 0z; i < len(tests); i += 1) { let ln = rjoin(&st, tests[i].0, tests[i].1...) as size; assert(ln == len(tests[i].2) && string(&st)! == tests[i].2); reset(&st); }; }; // Appends a rune to a stream. export fn appendrune(out: io::handle, r: rune) (size | io::error) = io::writeall(out, utf8::encoderune(r)); hare-0.24.2/memio/stream.ha000066400000000000000000000203101464473310100154300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; use errors; use io; use strings; export type stream = struct { stream: io::stream, buf: []u8, pos: size, }; const fixed_vt: io::vtable = io::vtable { seeker = &seek, copier = ©, reader = &read, writer = &fixed_write, ... }; const dynamic_vt: io::vtable = io::vtable { seeker = &seek, copier = ©, reader = &read, writer = &dynamic_write, closer = &dynamic_close, ... }; // Creates a stream for a fixed, caller-supplied buffer. Seeking a stream will // cause subsequent writes to overwrite existing contents of the buffer. // Writes return an error if they would exceed the buffer's capacity. The // stream doesn't have to be closed. export fn fixed(in: []u8) stream = stream { stream = &fixed_vt, buf = in, pos = 0, }; // Creates an [[io::stream]] which dynamically allocates a buffer to store // writes into. Seeking the stream and reading will read the written data. // Calling [[io::close]] on this stream will free the buffer. If a stream's // data is referenced via [[buffer]], the stream shouldn't be closed as // long as the data is used. export fn dynamic() stream = dynamic_from([]); // Like [[dynamic]], but takes an existing slice as input. Writes will // overwrite the buffer and reads consume bytes from the initial buffer. // Ownership of the provided slice is transferred to the returned [[stream]]. // Calling [[io::close]] will free the buffer. export fn dynamic_from(in: []u8) stream = stream { stream = &dynamic_vt, buf = in, pos = 0, }; // Returns a stream's buffer, up to the current cursor position. // [[io::seek]] to the end first in order to return the entire buffer. // The return value is borrowed from the input. export fn buffer(in: *stream) []u8 = { return in.buf[..in.pos]; }; // Returns a stream's buffer, up to the current cursor position, as a string. // [[io::seek]] to the end first in order to return the entire buffer. // The return value is borrowed from the input. export fn string(in: *stream) (str | utf8::invalid) = { return strings::fromutf8(in.buf[..in.pos]); }; // A convenience function that sets the read-write cursor to zero, so that // the buffer can be overwritten and reused. export fn reset(in: *stream) void = { in.pos = 0; in.buf = in.buf[..0]; }; // Reads data from a [[dynamic]] or [[fixed]] stream and returns a slice // borrowed from the internal buffer. export fn borrowedread(st: *stream, amt: size) ([]u8 | io::EOF) = { if (len(st.buf) - st.pos < amt) { return io::EOF; }; let buf = st.buf[st.pos..st.pos + amt]; st.pos += len(buf); return buf; }; fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let s = s: *stream; if (len(s.buf) == s.pos) { return io::EOF; }; const n = if (len(s.buf) - s.pos < len(buf)) { yield len(s.buf) - s.pos; } else { yield len(buf); }; assert(s.pos + n <= len(s.buf)); buf[..n] = s.buf[s.pos..s.pos + n]; s.pos += n; return n; }; fn seek( s: *io::stream, off: io::off, w: io::whence ) (io::off | io::error) = { let s = s: *stream; let start = switch (w) { case io::whence::SET => yield 0z; case io::whence::CUR => yield s.pos; case io::whence::END => yield len(s.buf); }; if (off < 0) { if (start < (-off): size) return errors::invalid; } else { if (len(s.buf) - start < off: size) return errors::invalid; }; s.pos = start + off: size; return s.pos: io::off; }; fn copy(dest: *io::stream, src: *io::stream) (size | io::error) = { if (src.reader != &read || dest.writer == null) { return errors::unsupported; }; let src = src: *stream; return (dest.writer: *io::writer)(dest, src.buf[src.pos..]); }; fn fixed_write(s: *io::stream, buf: const []u8) (size | io::error) = { if (len(buf) == 0) { return 0z; }; let s = s: *stream; if (s.pos >= len(s.buf)) { return errors::overflow; }; const n = if (len(buf) > len(s.buf[s.pos..])) { yield len(s.buf[s.pos..]); } else { yield len(buf); }; s.buf[s.pos..s.pos+n] = buf[..n]; s.pos += n; return n; }; fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *stream; let spare = len(s.buf) - s.pos; let bufend = if (spare < len(buf)) spare else len(buf); s.buf[s.pos..s.pos+bufend] = buf[..bufend]; s.pos += bufend; if (bufend < len(buf)) { append(s.buf, buf[bufend..]...); s.pos += len(buf[bufend..]); }; return len(buf); }; fn dynamic_close(s: *io::stream) (void | io::error) = { const s = s: *stream; free(s.buf); s.buf = []; s.pos = 0; }; @test fn fixed() void = { let buf: [1024]u8 = [0...]; let stream = fixed(buf); defer io::close(&stream)!; let n = 0z; n += io::writeall(&stream, strings::toutf8("hello ")) as size; n += io::writeall(&stream, strings::toutf8("world")) as size; assert(bytes::equal(buf[..n], strings::toutf8("hello world"))); assert(io::seek(&stream, 6, io::whence::SET) as io::off == 6: io::off); io::writeall(&stream, strings::toutf8("asdf")) as size; assert(bytes::equal(buf[..n], strings::toutf8("hello asdfd"))); let out: [2]u8 = [0...]; let s = fixed([1u8, 2u8]); defer io::close(&s)!; assert(io::read(&s, out[..1]) as size == 1 && out[0] == 1); assert(io::seek(&s, 1, io::whence::CUR) as io::off == 2: io::off); assert(io::read(&s, buf[..]) is io::EOF); assert(io::writeall(&s, [1, 2]) as io::error is errors::overflow); let in: [6]u8 = [0, 1, 2, 3, 4, 5]; let out: [6]u8 = [0...]; let source = fixed(in); let sink = fixed(out); io::copy(&sink, &source)!; assert(bytes::equal(in, out)); assert(io::write(&sink, [])! == 0); static let buf: [1024]u8 = [0...]; let stream = fixed(buf); assert(string(&stream)! == ""); io::writeall(&stream, strings::toutf8("hello ")) as size; assert(string(&stream)! == "hello "); io::writeall(&stream, strings::toutf8("world")) as size; assert(string(&stream)! == "hello world"); }; @test fn dynamic() void = { let s = dynamic(); defer io::close(&s)!; assert(io::writeall(&s, [1, 2, 3]) as size == 3); assert(bytes::equal(buffer(&s), [1, 2, 3])); assert(io::writeall(&s, [4, 5]) as size == 2); assert(bytes::equal(buffer(&s), [1, 2, 3, 4, 5])); let buf: [2]u8 = [0...]; assert(io::seek(&s, 0, io::whence::SET) as io::off == 0: io::off); assert(io::read(&s, buf[..]) as size == 2 && bytes::equal(buf, [1, 2])); assert(io::read(&s, buf[..]) as size == 2 && bytes::equal(buf, [3, 4])); assert(io::read(&s, buf[..]) as size == 1 && buf[0] == 5); assert(io::read(&s, buf[..]) is io::EOF); assert(io::writeall(&s, [6, 7, 8]) as size == 3); assert(bytes::equal(buffer(&s), [1, 2, 3, 4, 5, 6, 7, 8])); reset(&s); assert(len(buffer(&s)) == 0); assert(io::writeall(&s, [1, 2, 3]) as size == 3); let sl: []u8 = alloc([1, 2, 3]); let s = dynamic_from(sl); defer io::close(&s)!; assert(io::writeall(&s, [0, 0]) as size == 2); assert(io::seek(&s, 0, io::whence::END) as io::off == 3: io::off); assert(io::writeall(&s, [4, 5, 6]) as size == 3); assert(bytes::equal(buffer(&s), [0, 0, 3, 4, 5, 6])); assert(io::read(&s, buf[..]) is io::EOF); sl = alloc([1, 2]); let s = dynamic_from(sl); defer io::close(&s)!; assert(io::read(&s, buf[..1]) as size == 1 && buf[0] == 1); assert(io::seek(&s, 1, io::whence::CUR) as io::off == 2: io::off); assert(io::read(&s, buf[..]) is io::EOF); assert(io::writeall(&s, [3, 4]) as size == 2 && bytes::equal(buffer(&s), [1, 2, 3, 4])); io::close(&s)!; assert(io::writeall(&s, [5, 6]) as size == 2 && bytes::equal(buffer(&s), [5, 6])); let in: [6]u8 = [0, 1, 2, 3, 4, 5]; let source = dynamic_from(in); let sink = dynamic(); defer io::close(&sink)!; io::copy(&sink, &source)!; assert(bytes::equal(in, buffer(&sink))); let in: [6]u8 = [0, 1, 2, 3, 4, 5]; let source = dynamic_from(in); const borrowed = borrowedread(&source, len(in)-1) as []u8; assert(bytes::equal(borrowed, [0, 1, 2, 3, 4])); let source = dynamic_from(in); const borrowed = borrowedread(&source, len(in)) as []u8; assert(bytes::equal(borrowed, [0, 1, 2, 3, 4, 5])); let source = dynamic_from(in); assert(borrowedread(&source, len(in)+1) is io::EOF); let stream = dynamic(); defer io::close(&stream)!; assert(string(&stream)! == ""); io::writeall(&stream, strings::toutf8("hello ")) as size; assert(string(&stream)! == "hello "); io::writeall(&stream, strings::toutf8("world")) as size; assert(string(&stream)! == "hello world"); }; hare-0.24.2/mime/000077500000000000000000000000001464473310100134505ustar00rootroot00000000000000hare-0.24.2/mime/+freebsd.ha000066400000000000000000000002441464473310100154470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Path to the system MIME database. export def SYSTEM_DB: str = "/etc/mime.types"; hare-0.24.2/mime/+linux.ha000066400000000000000000000002441464473310100151740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Path to the system MIME database. export def SYSTEM_DB: str = "/etc/mime.types"; hare-0.24.2/mime/+netbsd.ha000066400000000000000000000002441464473310100153140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Path to the system MIME database. export def SYSTEM_DB: str = "/etc/mime.types"; hare-0.24.2/mime/+openbsd.ha000066400000000000000000000002571464473310100154730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Path to the system MIME database. export def SYSTEM_DB: str = "/usr/share/misc/mime.types"; hare-0.24.2/mime/README000066400000000000000000000010041464473310100143230ustar00rootroot00000000000000The mime module implements a subset of RFC 2045, namely the subset necessary to handle parsing and encoding Media Types (formerly "MIME types"), and to map them with file extensions. This module implements a "reasonable subset" of the specification which aims to address contemporary use-cases of Media Types outside of the broader context of the Content-Type header as it's used by emails. The implementation should not parse any Media Types which are not conformant, but may not parse all conformant Media Types. hare-0.24.2/mime/database.ha000066400000000000000000000031151464473310100155260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hash::fnv; use strings; // A pair of a Media Type and a list of file extensions associated with it. The // extension list does not include the leading '.' character. export type mimetype = struct { mime: str, exts: []str, }; // List of media types with statically allocated fields (though the list itself // is dynamically allocated). let static_db: []*mimetype = []; // List of media types with heap-allocated fields, used when loading mime types // from the system database. let heap_db: []*mimetype = []; def MIME_BUCKETS: size = 256; // Hash tables for efficient database lookup by mimetype or extension let mimetable: [MIME_BUCKETS][]*mimetype = [[]...]; let exttable: [MIME_BUCKETS][]*mimetype = [[]...]; // Registers a Media Type and its extensions in the internal MIME database. This // function is designed to be used by @init functions for modules which // implement new Media Types. export fn register(mime: *mimetype...) void = { let i = len(static_db); append(static_db, mime...); for (i < len(static_db); i += 1) { hashtable_insert(static_db[i]); }; }; fn hashtable_insert(item: *mimetype) void = { const hash = fnv::string(item.mime); let bucket = &mimetable[hash % len(mimetable)]; append(bucket, item); for (let ext .. item.exts) { const hash = fnv::string(ext); let bucket = &exttable[hash % len(exttable)]; append(bucket, item); }; }; @fini fn fini() void = { for (let m .. heap_db) { free(m.mime); strings::freeall(m.exts); free(m); }; free(heap_db); free(static_db); }; hare-0.24.2/mime/entries+test.ha000066400000000000000000000030131464473310100164030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors const text_plain: mimetype = mimetype { mime = "text/plain", exts = ["txt"], }; const text_hare: mimetype = mimetype { mime = "text/x-hare", exts = ["ha"], }; @init fn init() void = { register(&text_plain, &text_hare); }; @test fn lookup_mime() void = { assert(lookup_mime("foo/bar") == null); const result = lookup_mime("text/plain") as *mimetype; assert(result.mime == "text/plain"); assert(len(result.exts) >= 1); let extfound = false; for (let ext .. result.exts) { if (ext == "txt") { extfound = true; }; }; assert(extfound); const result = lookup_mime("text/x-hare") as *mimetype; assert(result.mime == "text/x-hare"); assert(len(result.exts) >= 1); let extfound = false; for (let ext .. result.exts) { if (ext == "ha") { extfound = true; }; }; assert(extfound); }; @test fn lookup_ext() void = { assert(lookup_ext("foo") == null); assert(lookup_ext(".foo") == null); const result = lookup_ext("txt") as *mimetype; assert(result.mime == "text/plain"); let extfound = false; for (let ext .. result.exts) { if (ext == "txt") { extfound = true; }; }; assert(extfound); const result = lookup_ext(".txt") as *mimetype; assert(result.mime == "text/plain"); const result = lookup_ext("ha") as *mimetype; assert(result.mime == "text/x-hare"); assert(len(result.exts) >= 1); let extfound = false; for (let ext .. result.exts) { if (ext == "ha") { extfound = true; }; }; assert(extfound); }; hare-0.24.2/mime/lookup.ha000066400000000000000000000016001464473310100152700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use hash::fnv; use strings; // Looks up a Media Type based on the mime type string, returning null if // unknown. export fn lookup_mime(mime: str) const nullable *mimetype = { const hash = fnv::string(mime); const bucket = &mimetable[hash % len(mimetable)]; for (let item .. *bucket) { if (item.mime == mime) { return item; }; }; return null; }; // Looks up a Media Type based on a file extension, with or without the leading // '.' character, returning null if unknown. export fn lookup_ext(ext: str) const nullable *mimetype = { ext = strings::ltrim(ext, '.'); const hash = fnv::string(ext); const bucket = &exttable[hash % len(exttable)]; for (let item .. *bucket) { for (let j = 0z; j < len(item.exts); j += 1) { if (item.exts[j] == ext) { return item; }; }; }; return null; }; hare-0.24.2/mime/parse.ha000066400000000000000000000072231464473310100151000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use errors; use strings; const tspecial: str = "()<>@,;:\\/[]?="; export type type_params = strings::tokenizer; // Parses a Media Type, returning a tuple of the content type (e.g. // "text/plain") and a parameter parser object, or [[errors::invalid]] if the // input cannot be parsed. // // To enumerate the Media Type parameter list, pass the type_params object into // [[next_param]]. If you do not need the parameter list, you can safely discard // the object. Note that any format errors following the ";" token will not // cause [[errors::invalid]] to be returned unless [[next_param]] is used to // enumerate all of the parameters. export fn parse(in: str) ((str, type_params) | errors::invalid) = { const items = strings::cut(in, ";"); const mtype = items.0, params = items.1; const items = strings::cut(mtype, "/"); if (len(items.0) < 1 || len(items.1) < 1) { return errors::invalid; }; typevalid(items.0)?; typevalid(items.1)?; return (mtype, strings::tokenize(params, ";")); }; // Returns the next parameter as a (key, value) tuple from a [[type_params]] // object that was prepared via [[parse]], done if there are no remaining // parameters, and [[errors::invalid]] if a syntax error was encountered. export fn next_param(in: *type_params) ((str, str) | done | errors::invalid) = { const tok = match (strings::next_token(in: *strings::tokenizer)) { case let s: str => if (s == "") { // empty parameter return errors::invalid; }; yield s; case done => return done; }; const items = strings::cut(tok, "="); // The RFC does not permit whitespace here, but whitespace is very // common in the wild. ¯\_(ツ)_/¯ items.0 = strings::trim(items.0); items.1 = strings::trim(items.1); if (len(items.0) == 0 || len(items.1) == 0) { return errors::invalid; }; if (strings::hasprefix(items.1, "\"")) { items.1 = quoted(items.1)?; }; return (items.0, items.1); }; fn quoted(in: str) (str | errors::invalid) = { // We have only a basic implementation of quoted-string. It has a couple // of problems: // // 1. The RFC does not define it very well // 2. The parts of the RFC which are ill-defined are rarely used // 3. Implementing quoted-pair would require allocating a new string // // This implementation should handle most Media Types seen in practice // unless they're doing something weird and ill-advised with them. in = strings::trim(in, '"'); if (strings::contains(in, "\\") || strings::contains(in, "\r") || strings::contains(in, "\n")) { return errors::invalid; }; return in; }; fn typevalid(in: str) (void | errors::invalid) = { const miter = strings::iter(in); for (let rn => strings::next(&miter)) { if (!ascii::valid(rn) || rn == ' ' || ascii::iscntrl(rn) || strings::contains(tspecial, rn)) { return errors::invalid; }; }; }; @test fn parse() void = { const res = parse("text/plain")!; assert(res.0 == "text/plain"); const res = parse("image/png")!; assert(res.0 == "image/png"); const res = parse("application/svg+xml; charset=utf-8; foo=\"bar baz\"")!; assert(res.0 == "application/svg+xml"); const params = res.1; const param = next_param(¶ms)! as (str, str); assert(param.0 == "charset" && param.1 == "utf-8"); const param = next_param(¶ms)! as (str, str); assert(param.0 == "foo" && param.1 == "bar baz"); assert(next_param(¶ms) is done); assert(parse("hi") is errors::invalid); assert(parse("text/ spaces ") is errors::invalid); assert(parse("text/@") is errors::invalid); const res = parse("text/plain;charset")!; assert(res.0 == "text/plain"); assert(next_param(&res.1) is errors::invalid); }; hare-0.24.2/mime/system.ha000066400000000000000000000022351464473310100153100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use encoding::utf8; use fs; use io; use os; use strings; @init fn init() void = { // Done in a separate function so we can discard errors here load_systemdb(): void; }; fn load_systemdb() (void | fs::error | io::error | utf8::invalid) = { const file = os::open(SYSTEM_DB)?; defer io::close(file)!; let sc = bufio::newscanner(file); defer bufio::finish(&sc); for (let line => bufio::scan_line(&sc)?) { line = strings::trim(line); if (strings::hasprefix(line, "#") || len(line) == 0) { continue; }; const items = strings::cut(line, "\t"); const mime = strings::trim(items.0), exts = strings::trim(items.1); if (len(exts) == 0) { continue; }; const tok = strings::tokenize(exts, " "); let entry = alloc(mimetype { mime = strings::dup(mime), exts = [], }); for (let ext => strings::next_token(&tok)) { append(entry.exts, strings::dup(ext)); }; register_heap(entry); }; }; fn register_heap(mime: *mimetype) void = { let i = len(heap_db); append(heap_db, mime); for (i < len(heap_db); i += 1) { hashtable_insert(heap_db[i]); }; }; hare-0.24.2/net/000077500000000000000000000000001464473310100133075ustar00rootroot00000000000000hare-0.24.2/net/+freebsd.ha000066400000000000000000000054241464473310100153130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // A network socket. export type socket = io::file; // Optional flags to [[accept]] to be set on the returned [[socket]]. // See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. // Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. export type sockflag = enum int { NOCLOEXEC = rt::SOCK_CLOEXEC, NONBLOCK = rt::SOCK_NONBLOCK }; // Accepts the next connection from a socket. Blocks until a new connection is // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are // supplied, the [[io::file]] returned will have the supplied flags set. export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC const fd = match (rt::accept4(sock, null, null, flags)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn msg_to_native(msg: *msghdr) *rt::msghdr = { let native = &msg.native; if (len(msg.vectors) != 0) { native.msg_iov = msg.vectors: *[*]rt::iovec; native.msg_iovlen = len(msg.vectors): int; }; if (len(msg.control) != 0) { native.msg_control = msg.control: *[*]u8; native.msg_controllen = len(msg.control): rt::socklen_t; }; return native; }; // Sends a message to a socket. See [[newmsg]] for details. export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::sendmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Receives a message from a socket. See [[newmsg]] for details. export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::recvmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Closes a [[socket]]. No further operations against this socket are permitted // after calling this function. Closing a socket can fail only under certain // conditions (for example, closing a socket twice, or an interrupted syscall). // However, the user should not attempt to close the file again on failure - at // best the user should print a diagnostic message and move on. See close(2) for // details. // // On FreeBSD, this function is an alias for [[io::close]]. export fn close(sock: socket) (void | error) = match (io::close(sock)) { case void => void; case io::underread => abort(); case let err: errors::error => yield err; }; // Shuts down part of a full-duplex connection. export fn shutdown(sock: socket, how: shut) (void | error) = { match (rt::shutdown(sock, how)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/net/+linux.ha000066400000000000000000000053761464473310100150460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // A network socket. export type socket = io::file; // Optional flags to [[accept]] to be set on the returned [[socket]]. // See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. // Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. export type sockflag = enum int { NOCLOEXEC = rt::SOCK_CLOEXEC, NONBLOCK = rt::SOCK_NONBLOCK }; // Accepts the next connection from a socket. Blocks until a new connection is // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are // supplied, the [[io::file]] returned will have the supplied flags set. export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC const fd = match (rt::accept4(sock, null, null, flags)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn msg_to_native(msg: *msghdr) *rt::msghdr = { let native = &msg.native; if (len(msg.vectors) != 0) { native.msg_iov = msg.vectors: *[*]rt::iovec; native.msg_iovlen = len(msg.vectors); }; if (len(msg.control) != 0) { native.msg_control = msg.control: *[*]u8; native.msg_controllen = len(msg.control); }; return native; }; // Sends a message to a socket. See [[newmsg]] for details. export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::sendmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Receives a message from a socket. See [[newmsg]] for details. export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::recvmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Closes a [[socket]]. No further operations against this socket are permitted // after calling this function. Closing a socket can fail only under certain // conditions (for example, closing a socket twice, or an interrupted syscall). // However, the user should not attempt to close the file again on failure - at // best the user should print a diagnostic message and move on. See close(2) for // details. // // On Linux, this function is an alias for [[io::close]]. export fn close(sock: socket) (void | error) = match (io::close(sock)) { case void => void; case io::underread => abort(); case let err: errors::error => yield err; }; // Shuts down part of a full-duplex connection. export fn shutdown(sock: socket, how: shut) (void | error) = { match (rt::shutdown(sock, how)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/net/+netbsd.ha000066400000000000000000000054231464473310100151570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // A network socket. export type socket = io::file; // Optional flags to [[accept]] to be set on the returned [[socket]]. // See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. // Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. export type sockflag = enum int { NOCLOEXEC = rt::SOCK_CLOEXEC, NONBLOCK = rt::SOCK_NONBLOCK }; // Accepts the next connection from a socket. Blocks until a new connection is // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are // supplied, the [[io::file]] returned will have the supplied flags set. export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC const fd = match (rt::accept4(sock, null, null, flags)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn msg_to_native(msg: *msghdr) *rt::msghdr = { let native = &msg.native; if (len(msg.vectors) != 0) { native.msg_iov = msg.vectors: *[*]rt::iovec; native.msg_iovlen = len(msg.vectors): int; }; if (len(msg.control) != 0) { native.msg_control = msg.control: *[*]u8; native.msg_controllen = len(msg.control): rt::socklen_t; }; return native; }; // Sends a message to a socket. See [[newmsg]] for details. export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::sendmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Receives a message from a socket. See [[newmsg]] for details. export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::recvmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Closes a [[socket]]. No further operations against this socket are permitted // after calling this function. Closing a socket can fail only under certain // conditions (for example, closing a socket twice, or an interrupted syscall). // However, the user should not attempt to close the file again on failure - at // best the user should print a diagnostic message and move on. See close(2) for // details. // // On NetBSD, this function is an alias for [[io::close]]. export fn close(sock: socket) (void | error) = match (io::close(sock)) { case void => void; case io::underread => abort(); case let err: errors::error => yield err; }; // Shuts down part of a full-duplex connection. export fn shutdown(sock: socket, how: shut) (void | error) = { match (rt::shutdown(sock, how)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/net/+openbsd.ha000066400000000000000000000055761464473310100153430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // A network socket. export type socket = io::file; // Optional flags to [[accept]] to be set on the returned [[socket]]. // See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. // Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. export type sockflag = enum int { NOCLOEXEC = rt::SOCK_CLOEXEC, NONBLOCK = rt::SOCK_NONBLOCK }; // Accepts the next connection from a socket. Blocks until a new connection is // available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are // supplied, the [[io::file]] returned will have the supplied flags set. export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC const fd = match (rt::accept4(sock, null, null, flags)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn msg_to_native(msg: *msghdr) *rt::msghdr = { let native = &msg.native; if (len(msg.vectors) != 0) { native.msg_iov = msg.vectors: *[*]rt::iovec; // XXX: size -> uint could overflow here. native.msg_iovlen = len(msg.vectors): uint; }; if (len(msg.control) != 0) { native.msg_control = msg.control: *[*]u8; // XXX: size -> uint could overflow here. native.msg_controllen = len(msg.control): uint; }; return native; }; // Sends a message to a socket. See [[newmsg]] for details. export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::sendmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Receives a message from a socket. See [[newmsg]] for details. export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { // TODO: Flags match (rt::recvmsg(sock, msg_to_native(msg), 0)) { case let n: int => return n: size; case let err: rt::errno => return errors::errno(err); }; }; // Closes a [[socket]]. No further operations against this socket are permitted // after calling this function. Closing a socket can fail only under certain // conditions (for example, closing a socket twice, or an interrupted syscall). // However, the user should not attempt to close the file again on failure - at // best the user should print a diagnostic message and move on. See close(2) for // details. // // On OpenBSD, this function is an alias for [[io::close]]. export fn close(sock: socket) (void | error) = match (io::close(sock)) { case void => void; case io::underread => abort(); case io::mode => abort(); case let err: errors::error => yield err; }; // Shuts down part of a full-duplex connection. export fn shutdown(sock: socket, how: shut) (void | error) = { match (rt::shutdown(sock, how)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/net/README000066400000000000000000000006011464473310100141640ustar00rootroot00000000000000The net module provides some general-purpose interfaces and support code, but generally users are directed to the submodules, where implementations of various network protocols are provided, such as [[net::tcp::]] or [[net::dns::]]. A porcelain API for establishing an outgoing connection, able to automatically handle matters such as DNS resolution, is available at [[net::dial::]]. hare-0.24.2/net/dial/000077500000000000000000000000001464473310100142205ustar00rootroot00000000000000hare-0.24.2/net/dial/README000066400000000000000000000014041464473310100150770ustar00rootroot00000000000000net::dial provides a single function to facilitate the establishment of outgoing network connections. It handles port selection, address parsing, protocol and service lookup, DNS lookup (via /etc/hosts, /etc/resolv.conf, etc), SRV record resolution, and so on. See [[dial]] for details. Modules implementing their own network protocols are also able to add themselves to the protocol and service registry. The protocol registry is used for transport-level protocols (such as TCP) and is managed via [[registerproto]]; the service registry is used for application-level protocols (such as SSH) and is managed via [[registersvc]]. Some useful functions for IP-related protocols to interpret the "addr" parameter of the dial function are also provided, namely [[resolve]]. hare-0.24.2/net/dial/dial.ha000066400000000000000000000064341464473310100154520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use net; use net::ip; use net::uri; // Dials a remote address, establishing a connection and returning the resulting // [[net::socket]]. The proto parameter should be the transport protocol (e.g. // "tcp"), the address parameter should be the remote address, and the service // should be the name of the service, or the default port to use. // // The interpretation of the address and service parameters is dependent on the // protocol in use. For IP-based protocols (such as TCP or UDP), the address // parameter may be either an IPv4 or IPv6 address, or a name, and may include a // port separated by a colon (':'). If an IPv6 address and a port are both // desired, use brackets ('[' and ']') to separate the address from the port // (e.g. "[::1]:80"). If the port is not specified, it is inferred from the // service parameter. If a name is used instead of an IP address, a DNS lookup // is performed, consulting the local /etc/hosts file or equivalent, if // possible. // // The service parameter can be a service name (e.g. "submission") or a default // port to use, if one is not specified by address. If a service name is used, // an internal list of services is consulted (see [[registersvc]]), and if not // known to Hare, the system service list (e.g. /etc/services) will be // consulted. If the connection port cannot be established, [[errors::invalid]] // is returned. The special service name "unknown" will always consult the // address parameter for a desired port, and will return [[errors::invalid]] if // one is not provided there. // // If the address parameter includes a name, but not a port, an SRV lookup will // be performed alongside the A or AAAA record lookup for that name. If the name // server provides an SRV record for the given service, it will be utilized in // lieu of the service database. export fn dial( proto: str, address: str, service: str, ) (net::socket | error) = { for (let i = 0z; i < len(default_protocols); i += 1) { const p = default_protocols[i]; if (p.name == proto) { return p.dial(address, service); }; }; for (let i = 0z; i < len(protocols); i += 1) { const p = protocols[i]; if (p.name == proto) { return p.dial(address, service); }; }; return net::unknownproto: net::error; }; def HOST_MAX: size = 255; // Performs a [[dial]] operation for a given URI, taking the service name from // the URI scheme and forming an address from the URI host and port. export fn dial_uri(proto: str, uri: *uri::uri) (net::socket | error) = { // XXX: Should the code to convert a URI to e.g. "[::1]:80" be // generalized for end-user use? if (uri.host is str && len(uri.host as str) > HOST_MAX) { return invalid_address; }; static let addr: [HOST_MAX + len("[]:65535")]u8 = [0...]; const colon = if (uri.port != 0) ":" else ""; const port: fmt::formattable = if (uri.port != 0) uri.port else ""; let addr = match (uri.host) { case let host: str => yield fmt::bsprintf(addr, "{}{}{}", host, colon, port); case let ip: ip::addr4 => const host = ip::string(ip); yield fmt::bsprintf(addr, "{}{}{}", host, colon, port); case let ip: ip::addr6 => const host = ip::string(ip); yield fmt::bsprintf(addr, "[{}]{}{}", host, colon, port); }; return dial(proto, addr, uri.scheme); }; hare-0.24.2/net/dial/ip.ha000066400000000000000000000020371464473310100151440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Provides default dialers for tcp and udp use net; use net::tcp; use net::udp; fn dial_tcp(addr: str, service: str) (net::socket | error) = { const result = resolve("tcp", addr, service)?; const addrs = result.0, port = result.1; defer free(addrs); for (let i = 0z; i < len(addrs); i += 1) { const addr = addrs[i]; match (tcp::connect(addr, port)) { case let conn: net::socket => return conn; case let err: net::error => if (i + 1 >= len(addrs)) { return err; }; }; }; abort(); // Unreachable }; fn dial_udp(addr: str, service: str) (net::socket | error) = { const result = resolve("udp", addr, service)?; const addrs = result.0, port = result.1; defer free(addrs); for (let i = 0z; i < len(addrs); i += 1) { const addr = addrs[i]; match (udp::connect(addr, port)) { case let sock: net::socket => return sock; case let err: net::error => if (i + 1 >= len(addrs)) { return err; }; }; }; abort(); // Unreachable }; hare-0.24.2/net/dial/registry.ha000066400000000000000000000070721464473310100164100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; use net::dns; use unix::hosts; // Returned if the address parameter was invalid, for example if it specifies an // invalid port number. export type invalid_address = !void; // Returned if the service parameter does not name a service known to the // system. export type unknown_service = !void; // Errors which can occur from dial. export type error = !(invalid_address | unknown_service | net::error | dns::error | hosts::error); // Converts an [[error]] to a human-readable string. The result may be // statically allocated. export fn strerror(err: error) const str = { // TODO: These could be better match (err) { case invalid_address => return "Attempted to dial an invalid address"; case unknown_service => return "Unknown service"; case let err: net::error => return net::strerror(err); case let err: dns::error => return dns::strerror(err); case let err: hosts::error => return hosts::strerror(err); }; }; // A dialer is a function which implements dial for a specific protocol. export type dialer = fn(addr: str, service: str) (net::socket | error); type protocol = struct { name: str, dial: *dialer, }; type service = struct { proto: str, name: str, alias: []str, port: u16, }; let default_protocols: [_]protocol = [ protocol { name = "tcp", dial = &dial_tcp }, protocol { name = "udp", dial = &dial_udp }, ]; let default_services: [_]service = [ service { proto = "tcp", name = "ssh", alias = [], port = 22 }, service { proto = "tcp", name = "smtp", alias = ["mail"], port = 25 }, service { proto = "tcp", name = "domain", alias = ["dns"], port = 53 }, service { proto = "tcp", name = "http", alias = ["www"], port = 80 }, service { proto = "tcp", name = "imap2", alias = ["imap"], port = 143 }, service { proto = "tcp", name = "https", alias = [], port = 443 }, service { proto = "tcp", name = "submission", alias = [], port = 587 }, service { proto = "tcp", name = "imaps", alias = [], port = 993 }, service { proto = "udp", name = "domain", alias = ["dns"], port = 53 }, service { proto = "udp", name = "ntp", alias = [], port = 123 }, ]; let protocols: []protocol = []; let services: []service = []; @fini fn fini() void = { free(protocols); free(services); }; // Registers a new transport-level protocol (e.g. TCP) with the dialer. The name // should be statically allocated. export fn registerproto(name: str, dial: *dialer) void = { append(protocols, protocol { name = name, dial = dial, }); }; // Registers a new application-level service (e.g. SSH) with the dialer. Note // that the purpose of services is simply to establish the default outgoing // port for TCP and UDP connections. The name and alias list should be // statically allocated. export fn registersvc( proto: str, name: str, alias: []str, port: u16, ) void = { append(services, service { proto = proto, name = name, alias = alias, port = port, }); }; fn lookup_service(proto: str, service: str) (u16 | void) = { for (let i = 0z; i < len(default_services); i += 1) { const serv = &default_services[i]; if (service_match(serv, proto, service)) { return serv.port; }; }; for (let i = 0z; i < len(services); i += 1) { const serv = &services[i]; if (service_match(serv, proto, service)) { return serv.port; }; }; }; fn service_match(candidate: *service, proto: str, service: str) bool = { if (candidate.name == service) { return true; }; for (let j = 0z; j < len(candidate.alias); j += 1) { if (candidate.alias[j] == service) { return true; }; }; return false; }; hare-0.24.2/net/dial/resolve.ha000066400000000000000000000072511464473310100162160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::random; use net::dns; use net::ip; use strconv; use strings; use unix::hosts; // Splits an address:port/service string into separate address and port // components. The return value is borrowed from the input. export fn splitaddr(addr: str, service: str) ((str, u16) | invalid_address) = { let port = 0u16; if (strings::hasprefix(addr, '[')) { // [::1]:80 (IPv6) match (strings::index(addr, "]:")) { case let i: size => const sub = strings::sub(addr, i + 2, strings::end); addr = strings::sub(addr, 1, i); match (strconv::stou16(sub)) { case let u: u16 => port = u; case => return invalid_address; }; case void => match (strconv::stou16(service)) { case let u: u16 => port = u; case => void; }; }; return (addr, port); }; // 1.1.1.1:80 (IPv4) match (strings::index(addr, ':')) { case void => match (strconv::stou16(service)) { case let u: u16 => port = u; case => void; }; case let i: size => const sub = strings::sub(addr, i + 1, strings::end); addr = strings::sub(addr, 0, i); match (strconv::stou16(sub)) { case let u: u16 => port = u; case => return invalid_address; }; }; return (addr, port); }; // Performs DNS resolution on a given address string for a given service, // including /etc/hosts lookup and SRV resolution, and returns a list of // candidate IP addresses and the appropriate port, or an error. // // The caller must free the [[net::ip::addr]] slice. export fn resolve( proto: str, addr: str, service: str, ) (([]ip::addr, u16) | error) = { const (addr, port) = splitaddr(addr, service)?; if (service == "unknown" && port == 0) { return unknown_service; }; let addrs = resolve_addr(addr)?; if (port == 0) match (lookup_service(proto, service)) { case let p: u16 => port = p; case void => void; }; // TODO: // - Consult /etc/services // - Fetch the SRV record if (port == 0) { return unknown_service; }; if (len(addrs) == 0) { return dns::name_error; }; return (addrs, port); }; fn resolve_addr(addr: str) ([]ip::addr | error) = { match (ip::parse(addr)) { case let addr: ip::addr => return alloc([addr]); case ip::invalid => void; }; const addrs = hosts::lookup(addr)?; if (len(addrs) != 0) { return addrs; }; const domain = dns::parse_domain(addr); defer free(domain); let rand: []u8 = [0, 0]; random::buffer(rand); let id = *(&rand[0]: *u16); const query6 = dns::message { header = dns::header { id = id, op = dns::op { qr = dns::qr::QUERY, opcode = dns::opcode::QUERY, rd = true, ... }, qdcount = 1, ... }, questions = [ dns::question { qname = domain, qtype = dns::qtype::AAAA, qclass = dns::qclass::IN, }, ], ... }; const query4 = dns::message { header = dns::header { id = id + 1, op = dns::op { qr = dns::qr::QUERY, opcode = dns::opcode::QUERY, rd = true, ... }, qdcount = 1, ... }, questions = [ dns::question { qname = domain, qtype = dns::qtype::A, qclass = dns::qclass::IN, }, ], ... }; const resp6 = dns::query(&query6)?; defer dns::message_free(resp6); const resp4 = dns::query(&query4)?; defer dns::message_free(resp4); let addrs: []ip::addr = []; collect_answers(&addrs, &resp6.answers); collect_answers(&addrs, &resp4.answers); return addrs; }; fn collect_answers(addrs: *[]ip::addr, answers: *[]dns::rrecord) void = { for (let i = 0z; i < len(answers); i += 1) { match (answers[i].rdata) { case let addr: dns::aaaa => append(addrs, addr: ip::addr); case let addr: dns::a => append(addrs, addr: ip::addr); case => void; }; }; }; hare-0.24.2/net/dns/000077500000000000000000000000001464473310100140735ustar00rootroot00000000000000hare-0.24.2/net/dns/README000066400000000000000000000004131464473310100147510ustar00rootroot00000000000000net::dns implements low-level DNS message encoding and decoding, as well as a porcelain DNS resolver. TODO: - DNS over TCP - Porcelain resolver API (resolv.conf) - Decoders for various record types - Complete RFC 2535 support - Look for other RFCs worth addressing hare-0.24.2/net/dns/decode.ha000066400000000000000000000232121464473310100156300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use endian; use net::ip; use strings; type decoder = struct { buf: []u8, cur: []u8, }; // Decodes a DNS message, heap allocating the resources necessary to represent // it in Hare's type system. The caller must use [[message_free]] to free the // return value. export fn decode(buf: []u8) (*message | format) = { let success = false; let msg = alloc(message { ... }); defer if (!success) message_free(msg); let dec = decoder_init(buf); decode_header(&dec, &msg.header)?; for (let i = 0z; i < msg.header.qdcount; i += 1) { append(msg.questions, decode_question(&dec)?); }; decode_rrecords(&dec, msg.header.ancount, &msg.answers)?; decode_rrecords(&dec, msg.header.nscount, &msg.authority)?; decode_rrecords(&dec, msg.header.arcount, &msg.additional)?; success = true; return msg; }; fn decode_rrecords( dec: *decoder, count: u16, out: *[]rrecord, ) (void | format) = { for (let i = 0z; i < count; i += 1) { append(out, decode_rrecord(dec)?); }; }; fn decoder_init(buf: []u8) decoder = decoder { buf = buf, cur = buf, ... }; fn decode_u8(dec: *decoder) (u8 | format) = { if (len(dec.cur) < 1) { return format; }; const val = dec.cur[0]; dec.cur = dec.cur[1..]; return val; }; fn decode_u16(dec: *decoder) (u16 | format) = { if (len(dec.cur) < 2) { return format; }; const val = endian::begetu16(dec.cur); dec.cur = dec.cur[2..]; return val; }; fn decode_u32(dec: *decoder) (u32 | format) = { if (len(dec.cur) < 4) { return format; }; const val = endian::begetu32(dec.cur); dec.cur = dec.cur[4..]; return val; }; fn decode_u48(dec: *decoder) (u64 | format) = { if (len(dec.cur) < 6) { return format; }; let buf: [8]u8 = [0...]; buf[2..] = dec.cur[..6]; const val = endian::begetu64(buf[..]); dec.cur = dec.cur[6..]; return val; }; fn decode_header(dec: *decoder, head: *header) (void | format) = { head.id = decode_u16(dec)?; const rawop = decode_u16(dec)?; decode_op(rawop, &head.op); head.qdcount = decode_u16(dec)?; head.ancount = decode_u16(dec)?; head.nscount = decode_u16(dec)?; head.arcount = decode_u16(dec)?; }; fn decode_op(in: u16, out: *op) void = { out.qr = ((in & 0b1000000000000000) >> 15): qr; out.opcode = ((in & 0b0111100000000000u16) >> 11): opcode; out.aa = in & 0b0000010000000000u16 != 0; out.tc = in & 0b0000001000000000u16 != 0; out.rd = in & 0b0000000100000000u16 != 0; out.ra = in & 0b0000000010000000u16 != 0; out.rcode = (in & 0b1111): rcode; }; fn decode_name(dec: *decoder) ([]str | format) = { let success = false; let names: []str = []; defer if (!success) strings::freeall(names); let totalsize = 0z; let sub = decoder { buf = dec.buf, ... }; for (let i = 0z; i < len(dec.buf); i += 2) { if (len(dec.cur) < 1) { return format; }; const z = dec.cur[0]; if (z & 0b11000000 == 0b11000000) { const offs = decode_u16(dec)? & ~0b1100000000000000u16; if (len(dec.buf) < offs) { return format; }; sub.cur = dec.buf[offs..]; dec = ⊂ continue; }; dec.cur = dec.cur[1..]; totalsize += z + 1; if (totalsize > 255) { return format; }; if (z == 0) { success = true; return names; }; if (len(dec.cur) < z) { return format; }; const name = match (strings::fromutf8(dec.cur[..z])) { case let name: str => yield name; case => return format; }; dec.cur = dec.cur[z..]; if (!ascii::validstr(name)) { return format; }; append(names, strings::dup(name)); }; return format; }; fn decode_question(dec: *decoder) (question | format) = { let success = false; const qname = decode_name(dec)?; defer if (!success) strings::freeall(qname); const qtype = decode_u16(dec)?: qtype; const qclass = decode_u16(dec)?: qclass; success = true; return question { qname = qname, qtype = qtype, qclass = qclass, }; }; fn decode_rrecord(dec: *decoder) (rrecord | format) = { let success = false; const name = decode_name(dec)?; defer if (!success) strings::freeall(name); const rtype = decode_u16(dec)?: rtype; const class = decode_u16(dec)?: class; const ttl = decode_u32(dec)?; const rlen = decode_u16(dec)?; const rdata = decode_rdata(dec, rtype, rlen)?; success = true; return rrecord { name = name, rtype = rtype, class = class, ttl = ttl, rdata = rdata }; }; fn decode_rdata(dec: *decoder, rtype: rtype, rlen: size) (rdata | format) = { if (len(dec.cur) < rlen) { return format; }; let sub = decoder { cur = dec.cur[..rlen], buf = dec.buf, }; dec.cur = dec.cur[rlen..]; switch (rtype) { case rtype::A => return decode_a(&sub); case rtype::AAAA => return decode_aaaa(&sub); case rtype::CAA => return decode_caa(&sub); case rtype::CNAME => return decode_cname(&sub); case rtype::DNSKEY => return decode_dnskey(&sub); case rtype::MX => return decode_mx(&sub); case rtype::NS => return decode_ns(&sub); case rtype::OPT => return decode_opt(&sub); case rtype::NSEC => return decode_nsec(&sub); case rtype::PTR => return decode_ptr(&sub); case rtype::RRSIG => return decode_rrsig(&sub); case rtype::SOA => return decode_soa(&sub); case rtype::SRV => return decode_srv(&sub); case rtype::SSHFP => return decode_sshfp(&sub); case rtype::TSIG => return decode_tsig(&sub); case rtype::TXT => return decode_txt(&sub); case => return sub.cur: unknown_rdata; }; }; fn decode_a(dec: *decoder) (rdata | format) = { if (len(dec.cur) < 4) { return format; }; let ip: ip::addr4 = [0...]; ip[..] = dec.cur[..4]; dec.cur = dec.cur[4..]; return ip: a; }; fn decode_aaaa(dec: *decoder) (rdata | format) = { if (len(dec.cur) < 16) { return format; }; let ip: ip::addr6 = [0...]; ip[..] = dec.cur[..16]; dec.cur = dec.cur[16..]; return ip: aaaa; }; fn decode_caa(dec: *decoder) (rdata | format) = { let flags = decode_u8(dec)?; let tag_len = decode_u8(dec)?; if (len(dec.cur) < tag_len) { return format; }; let tag = match(strings::fromutf8(dec.cur[..tag_len])) { case let t: str => yield t; case => return format; }; let value = match (strings::fromutf8(dec.cur[tag_len..])) { case let v: str => yield v; case => return format; }; return caa { flags = flags, tag = strings::dup(tag), value = strings::dup(value), }; }; fn decode_cname(dec: *decoder) (rdata | format) = { return cname { name = decode_name(dec)?, }; }; fn decode_dnskey(dec: *decoder) (rdata | format) = { let r = dnskey { flags = decode_u16(dec)?, protocol = decode_u8(dec)?, algorithm = decode_u8(dec)?, key = [], }; append(r.key, dec.cur[..]...); return r; }; fn decode_mx(dec: *decoder) (rdata | format) = { return mx { priority = decode_u16(dec)?, name = decode_name(dec)?, }; }; fn decode_ns(dec: *decoder) (rdata | format) = { return ns { name = decode_name(dec)?, }; }; fn decode_opt(dec: *decoder) (rdata | format) = { let success = false; let r = opt { options = [], }; defer if (!success) { for (let i = 0z; i < len(r.options); i += 1) { free(r.options[i].data); }; free(r.options); }; for (len(dec.cur) > 0) { let o = edns_opt { code = decode_u16(dec)?, data = [], }; let sz = decode_u16(dec)?; if (len(dec.cur) < sz) { return format; }; append(o.data, dec.cur[..sz]...); dec.cur = dec.cur[sz..]; append(r.options, o); }; success = true; return r; }; fn decode_nsec(dec: *decoder) (rdata | format) = { let r = nsec { next_domain = decode_name(dec)?, type_bitmaps = [], }; append(r.type_bitmaps, dec.cur[..]...); return r; }; fn decode_ptr(dec: *decoder) (rdata | format) = { return ptr { name = decode_name(dec)?, }; }; fn decode_rrsig(dec: *decoder) (rdata | format) = { let r = rrsig { type_covered = decode_u16(dec)?, algorithm = decode_u8(dec)?, labels = decode_u8(dec)?, orig_ttl = decode_u32(dec)?, sig_expiration = decode_u32(dec)?, sig_inception = decode_u32(dec)?, key_tag = decode_u16(dec)?, signer_name = decode_name(dec)?, signature = [], }; append(r.signature, dec.cur[..]...); return r; }; fn decode_soa(dec: *decoder) (rdata | format) = { return soa { mname = decode_name(dec)?, rname = decode_name(dec)?, serial = decode_u32(dec)?, refresh = decode_u32(dec)?, retry = decode_u32(dec)?, expire = decode_u32(dec)?, }; }; fn decode_srv(dec: *decoder) (rdata | format) = { return srv { priority = decode_u16(dec)?, weight = decode_u16(dec)?, port = decode_u16(dec)?, target = decode_name(dec)?, }; }; fn decode_sshfp(dec: *decoder) (rdata | format) = { let r = sshfp { algorithm = decode_u8(dec)?, fp_type = decode_u8(dec)?, fingerprint = [], }; append(r.fingerprint, dec.cur[..]...); return r; }; fn decode_tsig(dec: *decoder) (rdata | format) = { let success = false; let r = tsig { algorithm = decode_name(dec)?, ... }; defer if (!success) free(r.algorithm); r.time_signed = decode_u48(dec)?; r.fudge = decode_u16(dec)?; r.mac_len = decode_u16(dec)?; if (len(dec.cur) < r.mac_len) { return format; }; append(r.mac, dec.cur[..r.mac_len]...); defer if (!success) free(r.mac); dec.cur = dec.cur[r.mac_len..]; r.orig_id = decode_u16(dec)?; r.error = decode_u16(dec)?; r.other_len = decode_u16(dec)?; if (len(dec.cur) != r.other_len) { return format; }; if (r.other_len > 0) { append(r.other_data, dec.cur[..]...); }; success = true; return r; }; fn decode_txt(dec: *decoder) (rdata | format) = { let success = false; let items: txt = []; defer if (!success) bytes_free(items); for (len(dec.cur) != 0) { const ln = decode_u8(dec)?; if (len(dec.cur) < ln) { return format; }; let item: []u8 = []; append(item, dec.cur[..ln]...); dec.cur = dec.cur[ln..]; append(items, item); }; success = true; return items; }; // TODO: Expand breadth of supported rdata decoders hare-0.24.2/net/dns/encode.ha000066400000000000000000000104651464473310100156500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use errors; use fmt; type encoder = struct { buf: []u8, offs: size, }; // Encodes a DNS message, returning its size, or an error. export fn encode(buf: []u8, msg: *message) (size | error) = { let enc = encoder { buf = buf, offs = 0z }; encode_u16(&enc, msg.header.id)?; encode_u16(&enc, encode_op(&msg.header.op))?; encode_u16(&enc, msg.header.qdcount)?; encode_u16(&enc, msg.header.ancount)?; encode_u16(&enc, msg.header.nscount)?; encode_u16(&enc, msg.header.arcount)?; for (let i = 0z; i < len(msg.questions); i += 1) { question_encode(&enc, &msg.questions[i])?; }; for (let i = 0z; i < len(msg.answers); i += 1) { rrecord_encode(&enc, &msg.answers[i])?; }; for (let i = 0z; i < len(msg.authority); i += 1) { rrecord_encode(&enc, &msg.authority[i])?; }; for (let i = 0z; i < len(msg.additional); i += 1) { rrecord_encode(&enc, &msg.additional[i])?; }; return enc.offs; }; fn encode_u8(enc: *encoder, val: u8) (void | error) = { if (len(enc.buf) <= enc.offs + 1) { return errors::overflow; }; enc.buf[enc.offs] = val; enc.offs += 1; }; fn encode_u16(enc: *encoder, val: u16) (void | error) = { if (len(enc.buf) <= enc.offs + 2) { return errors::overflow; }; endian::beputu16(enc.buf[enc.offs..], val); enc.offs += 2; }; fn encode_u32(enc: *encoder, val: u32) (void | error) = { if (len(enc.buf) <= enc.offs + 4) { return errors::overflow; }; endian::beputu32(enc.buf[enc.offs..], val); enc.offs += 4; }; fn encode_raw(enc: *encoder, val: []u8) (void | error) = { let end = enc.offs + len(val); if (len(enc.buf) < end) { return errors::overflow; }; enc.buf[enc.offs..end] = val; enc.offs += len(val); }; fn encode_labels(enc: *encoder, names: []str) (void | error) = { // TODO: Assert that the labels are all valid ASCII? for (let i = 0z; i < len(names); i += 1) { if (len(names[i]) > 63) { return format; }; if (len(enc.buf) <= enc.offs + 1 + len(names[i])) { return errors::overflow; }; encode_u8(enc, len(names[i]): u8)?; let label = fmt::bsprintf(enc.buf[enc.offs..], "{}", names[i]); enc.offs += len(label); }; encode_u8(enc, 0)?; }; fn question_encode(enc: *encoder, q: *question) (void | error) = { encode_labels(enc, q.qname)?; encode_u16(enc, q.qtype)?; encode_u16(enc, q.qclass)?; }; fn rrecord_encode(enc: *encoder, r: *rrecord) (void | error) = { encode_labels(enc, r.name)?; encode_u16(enc, r.rtype)?; encode_u16(enc, r.class)?; encode_u32(enc, r.ttl)?; let ln_enc = *enc; // save state for rdata len encode_u16(enc, 0)?; // write dummy rdata len encode_rdata(enc, r.rdata)?; // write rdata let rdata_len = enc.offs - ln_enc.offs - 2; encode_u16(&ln_enc, rdata_len: u16)?; // write rdata len to its place }; fn encode_rdata(enc: *encoder, rdata: rdata) (void | error) = { match (rdata) { case let d: unknown_rdata => return encode_raw(enc, d); case let d: opt => return encode_opt(enc, d); case let d: txt => return encode_txt(enc, d); case => abort(); // TODO }; }; fn encode_opt(enc: *encoder, opt: opt) (void | error) = { for (let i = 0z; i < len(opt.options); i += 1) { if (len(opt.options[i].data) > 65535) { return errors::invalid; }; encode_u16(enc, opt.options[i].code)?; encode_u16(enc, len(opt.options[i].data): u16)?; encode_raw(enc, opt.options[i].data)?; }; }; fn encode_txt(enc: *encoder, txt: txt) (void | error) = { for (let i = 0z; i < len(txt); i += 1) { if (len(txt[i]) > 255) return errors::invalid; encode_u8(enc, len(txt[i]): u8)?; encode_raw(enc, txt[i])?; }; }; fn encode_op(op: *op) u16 = (op.qr: u16 << 15u16) | (op.opcode: u16 << 11u16) | (if (op.aa) 0b0000010000000000u16 else 0u16) | (if (op.tc) 0b0000001000000000u16 else 0u16) | (if (op.rd) 0b0000000100000000u16 else 0u16) | (if (op.ra) 0b0000000010000000u16 else 0u16) | op.rcode: u16; @test fn opcode() void = { let opcode = op { qr = qr::RESPONSE, opcode = opcode::IQUERY, aa = false, tc = true, rd = false, ra = true, rcode = rcode::SERVFAIL, }; let enc = encode_op(&opcode); let opcode2 = op { ... }; decode_op(enc, &opcode2); assert(opcode.qr == opcode2.qr && opcode.opcode == opcode2.opcode && opcode.aa == opcode2.aa && opcode.tc == opcode2.tc && opcode.rd == opcode2.rd && opcode.ra == opcode2.ra && opcode.rcode == opcode2.rcode); }; hare-0.24.2/net/dns/error.ha000066400000000000000000000105011464473310100155330ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use io; use net; // The DNS message was poorly formatted. export type format = !void; // The name server was unable to process this query due to a problem with the // name server. export type server_failure = !void; // The domain name referenced in the query does not exist. Meaningful only for // responses from an authoritative name server. export type name_error = !void; // The name server does not support the requested kind of query. export type not_implemented = !void; // The name server refuses to perform the specified operation for policy // reasons. export type refused = !void; // Dynamic update prerequisite unsatisfied: a domain name exists when it // shouldn't. export type name_exists = !void; // Dynamic update prerequisite unsatisfied: a resource record set exists when it // shouldn't. export type rrset_exists = !void; // Dynamic update prerequisite unsatisfied: a resource record set doesn't exists // when it should. export type rrset_error = !void; // Server not authoritative for the zone or request not authorized. export type not_auth = !void; // Name not contained in zone. export type not_zone = !void; // TSIG signature validation failed. export type bad_sig = !void; // Key not recognized. export type bad_key = !void; // Signature out of time window. export type bad_time = !void; // Any other server-provided error condition not known to Hare. export type unknown_error = !u8; // All error types which might be returned from functions in this module. export type error = !(format | server_failure | name_error | not_implemented | refused | name_exists | rrset_exists | rrset_error | not_auth | not_zone | bad_sig | bad_key | bad_time | unknown_error | errors::invalid | errors::overflow | errors::timeout | net::error | io::error); // Converts an error into a human-friendly string. The result may be statically // allocated. export fn strerror(err: error) const str = { static let buf: [64]u8 = [0...]; match (err) { case format => return "The DNS message was poorly formatted"; case server_failure => return "The name server was unable to process this query due to a problem with the name server"; case name_error => return "The domain name referenced in the query does not exist"; case not_implemented => return "The name server does not support the requested kind of query"; case refused => return "The name server refuses to perform the specified operation for policy reasons"; case name_exists => return "Dynamic update prerequisite unsatisfied: a domain name exists when it shouldn't"; case rrset_exists => return "Dynamic update prerequisite unsatisfied: a resource record set exists when it shouldn't"; case rrset_error => return "Dynamic update prerequisite unsatisfied: a resource record set doesn't exist when it should"; case not_auth => return "Server not authoritative for the zone or request not authorized"; case not_zone => return "Name not contained in zone"; case bad_sig => return "TSIG signature validation failed"; case bad_key => return "Key not recognized"; case bad_time => return "Signature out of time window"; case let ue: unknown_error => return fmt::bsprintf(buf, "Unknown DNS error {}", ue: u8); case errors::invalid => return "The message contains one or more field with invalid values"; case errors::overflow => return "The encoded message would exceed the buffer size"; case errors::timeout => return "The DNS request timed out"; case let err: net::error => return net::strerror(err); case let err: io::error => return io::strerror(err); }; }; fn check_rcode(rcode: rcode) (void | error) = { switch (rcode) { case rcode::NOERROR => void; case rcode::FORMERR => return format; case rcode::SERVFAIL => return server_failure; case rcode::NXDOMAIN => return name_error; case rcode::NOTIMP => return not_implemented; case rcode::REFUSED => return refused; case rcode::YXDOMAIN => return name_exists; case rcode::YXRRSET => return rrset_exists; case rcode::NXRRSET => return rrset_error; case rcode::NOTAUTH => return not_auth; case rcode::NOTZONE => return not_zone; case rcode::BADSIG => return bad_sig; case rcode::BADKEY => return bad_key; case rcode::BADTIME => return bad_time; case => return rcode: unknown_error; }; }; hare-0.24.2/net/dns/query.ha000066400000000000000000000063521464473310100155600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use errors; use io; use net; use net::ip; use net::tcp; use net::udp; use time; use types; use unix::poll; use unix::resolvconf; // TODO: Let user customize this? def timeout: time::duration = 3 * time::SECOND; // Performs a DNS query using the provided list of DNS servers. The caller must // free the return value with [[message_free]]. // // If no DNS servers are provided, the system default servers (if any) are used. export fn query(query: *message, servers: ip::addr...) (*message | error) = { if (len(servers) == 0) { servers = resolvconf::load().nameservers; }; if (len(servers) == 0) { // Fall back to localhost servers = [ip::LOCAL_V6, ip::LOCAL_V4]; }; let socket4 = udp::listen(ip::ANY_V4, 0)?; defer net::close(socket4)!; let socket6 = udp::listen(ip::ANY_V6, 0)?; defer net::close(socket6)!; const pollfd: [_]poll::pollfd = [ poll::pollfd { fd = socket4, events = poll::event::POLLIN, ... }, poll::pollfd { fd = socket6, events = poll::event::POLLIN, ... }, ]; let buf: [512]u8 = [0...]; let z = encode(buf, query)?; // We send requests in parallel to all configured servers and take the // first one which sends us a reasonable answer. for (let i = 0z; i < len(servers); i += 1) match (servers[i]) { case ip::addr4 => udp::sendto(socket4, buf[..z], servers[i], 53)?; case ip::addr6 => udp::sendto(socket6, buf[..z], servers[i], 53)?; }; let header = header { ... }; let src: ip::addr = ip::ANY_V4; for (true) { let nevent = poll::poll(pollfd, timeout)!; if (nevent == 0) { return errors::timeout; }; if (pollfd[0].revents & poll::event::POLLIN != 0) { z = udp::recvfrom(socket4, buf, &src, null)?; }; if (pollfd[1].revents & poll::event::POLLIN != 0) { z = udp::recvfrom(socket6, buf, &src, null)?; }; let expected = false; for (let i = 0z; i < len(servers); i += 1) { if (ip::equal(src, servers[i])) { expected = true; break; }; }; if (!expected) { continue; }; const dec = decoder_init(buf[..z]); decode_header(&dec, &header)?; if (header.id == query.header.id && header.op.qr == qr::RESPONSE) { break; }; }; if (!header.op.tc) { check_rcode(header.op.rcode)?; return decode(buf[..z])?; }; // Response was truncated, retry over TCP. In TCP mode, the // query is preceded by two bytes indicating the query length z = encode(buf, query)?; if (z > types::U16_MAX) { return errors::overflow; }; let zbuf: [2]u8 = [0...]; endian::beputu16(zbuf, z: u16); let socket = tcp::connect(src, 53)?; defer net::close(socket)!; io::writeall(socket, zbuf)!; io::writeall(socket, buf[..z])!; let rz: u16 = match (io::readall(socket, zbuf)?) { case let s: size => if (s != 2) { return format; }; yield endian::begetu16(zbuf); case => return format; }; let tcpbuf: []u8 = alloc([0...], rz); defer free(tcpbuf); match (io::readall(socket, tcpbuf)?) { case let s: size => if (s != rz) { return format; }; case => return format; }; const dec = decoder_init(tcpbuf); decode_header(&dec, &header)?; if ((header.id != query.header.id) || header.op.tc) { return format; }; check_rcode(header.op.rcode)?; return decode(tcpbuf)?; }; hare-0.24.2/net/dns/strdomain.ha000066400000000000000000000011701464473310100164040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; // Converts a human-readable domain name (e.g. "example.org") into a DNS-ready // name slice (e.g. ["example", "org"]). The slice returned must be freed by the // caller, but the members of the slice themselves are borrowed from the input. export fn parse_domain(in: str) []str = strings::split(in, "."); // Converts a DNS name slice (e.g. ["example", "org"]) into a human-readable // domain name (e.g. "example.org"). The return value must be freed by the // caller. export fn unparse_domain(in: []str) str = strings::join(".", in...); hare-0.24.2/net/dns/types.ha000066400000000000000000000136341464473310100155600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net::ip; use strings; // Record type. export type rtype = enum u16 { A = 1, NS = 2, CNAME = 5, SOA = 6, PTR = 12, MX = 15, TXT = 16, AAAA = 28, SRV = 33, OPT = 41, SSHFP = 44, RRSIG = 46, NSEC = 47, DNSKEY = 48, TSIG = 250, CAA = 257, }; // Question type (superset of [[rtype]]). export type qtype = enum u16 { A = 1, NS = 2, CNAME = 5, SOA = 6, PTR = 12, MX = 15, TXT = 16, AAAA = 28, SRV = 33, OPT = 41, SSHFP = 44, RRSIG = 46, NSEC = 47, DNSKEY = 48, // ... AXFR = 252, // * ALL = 255, CAA = 257, }; // Class type (e.g. Internet). export type class = enum u16 { IN = 1, CS = 2, CH = 3, HS = 4, }; // Query class (superset of [[class]]). export type qclass = enum u16 { IN = 1, CS = 2, CH = 3, HS = 4, // * NONE = 254, ANY = 255, }; // DNS message header. export type header = struct { id: u16, op: op, // Number of questions qdcount: u16, // Number of answers ancount: u16, // Number of name servers nscount: u16, // Number of additional resources arcount: u16, }; // Bit indicating if a header precedes a query or response. export type qr = enum u8 { QUERY = 0, RESPONSE = 1, }; // Operation requested from resolver. export type opcode = enum u8 { QUERY = 0, IQUERY = 1, STATUS = 2, UPDATE = 5, }; // Response code from resolver. export type rcode = enum u8 { NOERROR = 0, FORMERR = 1, SERVFAIL = 2, NXDOMAIN = 3, NOTIMP = 4, REFUSED = 5, // RFC 2136 UPDATE YXDOMAIN = 6, YXRRSET = 7, NXRRSET = 8, NOTAUTH = 9, NOTZONE = 10, // RFC 2845 TSIG BADSIG = 16, BADKEY = 17, BADTIME = 18, }; // Operational information for this message. export type op = struct { // Is this a query or a response? qr: qr, // Operation code opcode: opcode, // Authoritative answer bit aa: bool, // Truncation bit tc: bool, // Recursion desired bit rd: bool, // Recursion available bit ra: bool, // Response code rcode: rcode, }; // A question section item. export type question = struct { qname: []str, qtype: qtype, qclass: qclass, }; // A resource record item. export type rrecord = struct { name: []str, rtype: rtype, class: class, ttl: u32, rdata: rdata, }; // An EDNS (RFC 6891) option, as contained in [[opt]] records. export type edns_opt = struct { code: u16, data: []u8, }; // An A record. export type a = ip::addr4; // An AAAA record. export type aaaa = ip::addr6; // A CAA record. export type caa = struct { flags: u8, tag: str, value: str, }; // A CNAME record. export type cname = struct { name: []str, }; // A DNSKEY record. export type dnskey = struct { flags: u16, protocol: u8, algorithm: u8, key: []u8, }; // An MX record. export type mx = struct { priority: u16, name: []str, }; // An NS record. export type ns = struct { name: []str, }; // An OPT record (EDNS, RFC 6891). export type opt = struct { options: []edns_opt, }; // An NSEC record. export type nsec = struct { next_domain: []str, type_bitmaps: []u8, }; // A PTR record. export type ptr = struct { name: []str, }; // An RRSIG record. export type rrsig = struct { type_covered: u16, algorithm: u8, labels: u8, orig_ttl: u32, sig_expiration: u32, sig_inception: u32, key_tag: u16, signer_name: []str, signature: []u8, }; // An SOA record. export type soa = struct { mname: []str, rname: []str, serial: u32, refresh: u32, retry: u32, expire: u32, }; // An SRV record. export type srv = struct { priority: u16, weight: u16, port: u16, target: []str, }; // An SSHFP record. export type sshfp = struct { algorithm: u8, fp_type: u8, fingerprint: []u8, }; // A TSIG record. export type tsig = struct { algorithm: []str, time_signed: u64, fudge: u16, mac_len: u16, mac: []u8, orig_id: u16, error: u16, other_len: u16, other_data: []u8, }; // A TXT record. export type txt = [][]u8; // The raw rdata field for an [[rrecord]] with an unknown [[rtype]]. export type unknown_rdata = []u8; // Tagged union of supported rdata types. export type rdata = (a | aaaa | caa | cname | dnskey | mx | ns | nsec | opt | ptr | rrsig | soa | srv | sshfp | tsig | txt | unknown_rdata); // A DNS message, Hare representation. See [[encode]] and [[decode]] for the DNS // representation. export type message = struct { header: header, questions: []question, answers: []rrecord, authority: []rrecord, additional: []rrecord, }; // Frees a [[message]] and the resources associated with it. export fn message_free(msg: *message) void = { for (let i = 0z; i < len(msg.questions); i += 1) { strings::freeall(msg.questions[i].qname); }; free(msg.questions); rrecords_free(msg.answers); rrecords_free(msg.authority); rrecords_free(msg.additional); free(msg); }; fn bytes_free(in: [][]u8) void = { for (let i = 0z; i < len(in); i += 1) { free(in[i]); }; free(in); }; fn rrecords_free(rrs: []rrecord) void = { for (let i = 0z; i < len(rrs); i += 1) { rrecord_finish(&rrs[i]); }; free(rrs); }; fn rrecord_finish(rr: *rrecord) void = { strings::freeall(rr.name); match (rr.rdata) { case let cn: cname => strings::freeall(cn.name); case let ca: caa => free(ca.tag); free(ca.value); case let dk: dnskey => free(dk.key); case let mx: mx => strings::freeall(mx.name); case let ns: ns => strings::freeall(ns.name); case let opt: opt => for (let i = 0z; i < len(opt.options); i += 1) { free(opt.options[i].data); }; free(opt.options); case let nsec: nsec => strings::freeall(nsec.next_domain); free(nsec.type_bitmaps); case let ptr: ptr => strings::freeall(ptr.name); case let rrsig: rrsig => strings::freeall(rrsig.signer_name); free(rrsig.signature); case let so: soa => strings::freeall(so.mname); strings::freeall(so.rname); case let sr: srv => strings::freeall(sr.target); case let sf: sshfp => free(sf.fingerprint); case let ts: tsig => strings::freeall(ts.algorithm); free(ts.mac); free(ts.other_data); case let tx: txt => bytes_free(tx: [][]u8); case => void; }; }; hare-0.24.2/net/errors.ha000066400000000000000000000010451464473310100151350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // An attempt was made to use an unsupported protocol. export type unknownproto = !void; // All error types which can be returned from networking functions. export type error = !(unknownproto | ...errors::error); // Converts an [[error]] into a human-readable string. export fn strerror(err: error) const str = { match (err) { case unknownproto => return "Unsupported protocol"; case let err: errors::error => return errors::strerror(err); }; }; hare-0.24.2/net/ip/000077500000000000000000000000001464473310100137175ustar00rootroot00000000000000hare-0.24.2/net/ip/+freebsd.ha000066400000000000000000000024561464473310100157250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use rt; export fn to_native(a: addr, port: u16) rt::sockaddr = { match (a) { case let v4: addr4 => return rt::sockaddr { in = rt::sockaddr_in { sin_len = size(rt::in_addr): u8, sin_family = rt::AF_INET, sin_port = endian::htonu16(port), sin_addr = rt::in_addr { s_addr = *(&v4[0]: *opaque: *u32) }, ... }, ... }; case let v6: addr6 => return rt::sockaddr { in6 = rt::sockaddr_in6 { sin6_len = size(rt::in6_addr): u8, sin6_family = rt::AF_INET6, sin6_port = endian::htonu16(port), sin6_addr = rt::in6_addr { s6_addr = v6 }, ... }, ... }; }; }; export fn from_native(a: rt::sockaddr) (addr, u16) = { let family = a.in.sin_family; switch (family) { case rt::AF_INET => let addr = a.in.sin_addr.s_addr; return ( [addr: u8, (addr >> 8): u8, (addr >> 16): u8, (addr >> 24): u8]: addr4, endian::ntohu16(a.in.sin_port) ); case rt::AF_INET6 => return ( a.in6.sin6_addr.s6_addr: addr6, endian::ntohu16(a.in6.sin6_port) ); case => abort("Wrong address family!"); }; }; export fn native_addrlen(a: addr) u32 = { match (a) { case addr4 => return size(rt::sockaddr_in): u32; case addr6 => return size(rt::sockaddr_in6): u32; }; }; hare-0.24.2/net/ip/+linux.ha000066400000000000000000000020721464473310100154440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use rt; export fn to_native(a: addr, port: u16) rt::sockaddr = { match (a) { case let v4: addr4 => return rt::sockaddr { in = rt::sockaddr_in { sin_family = rt::AF_INET, sin_port = endian::htonu16(port), sin_addr = rt::in_addr { s_addr = *(&v4[0]: *opaque: *u32) }, ... }, ... }; case let v6: addr6 => return rt::sockaddr { in6 = rt::sockaddr_in6 { sin6_family = rt::AF_INET6, sin6_port = endian::htonu16(port), sin6_addr = rt::in6_addr { s6_addr = v6 }, ... }, ... }; }; }; export fn from_native(a: rt::sockaddr) (addr, u16) = { let family = a.in.sin_family; switch (family) { case rt::AF_INET => let addr = a.in.sin_addr.s_addr; return ( [addr: u8, (addr >> 8): u8, (addr >> 16): u8, (addr >> 24): u8]: addr4, endian::ntohu16(a.in.sin_port) ); case rt::AF_INET6 => return ( a.in6.sin6_addr.s6_addr: addr6, endian::ntohu16(a.in6.sin6_port) ); case => abort("Wrong address family!"); }; }; hare-0.24.2/net/ip/+netbsd.ha000066400000000000000000000024561464473310100155720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use rt; export fn to_native(a: addr, port: u16) rt::sockaddr = { match (a) { case let v4: addr4 => return rt::sockaddr { in = rt::sockaddr_in { sin_len = size(rt::in_addr): u8, sin_family = rt::AF_INET, sin_port = endian::htonu16(port), sin_addr = rt::in_addr { s_addr = *(&v4[0]: *opaque: *u32) }, ... }, ... }; case let v6: addr6 => return rt::sockaddr { in6 = rt::sockaddr_in6 { sin6_len = size(rt::in6_addr): u8, sin6_family = rt::AF_INET6, sin6_port = endian::htonu16(port), sin6_addr = rt::in6_addr { s6_addr = v6 }, ... }, ... }; }; }; export fn from_native(a: rt::sockaddr) (addr, u16) = { let family = a.in.sin_family; switch (family) { case rt::AF_INET => let addr = a.in.sin_addr.s_addr; return ( [addr: u8, (addr >> 8): u8, (addr >> 16): u8, (addr >> 24): u8]: addr4, endian::ntohu16(a.in.sin_port) ); case rt::AF_INET6 => return ( a.in6.sin6_addr.s6_addr: addr6, endian::ntohu16(a.in6.sin6_port) ); case => abort("Wrong address family!"); }; }; export fn native_addrlen(a: addr) u32 = { match (a) { case addr4 => return size(rt::sockaddr_in): u32; case addr6 => return size(rt::sockaddr_in6): u32; }; }; hare-0.24.2/net/ip/+openbsd.ha000066400000000000000000000024451464473310100157430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use endian; use rt; export fn to_native(a: addr, port: u16) rt::sockaddr = { match (a) { case let v4: addr4 => return rt::sockaddr { in = rt::sockaddr_in { sin_len = size(rt::in_addr): u8, sin_family = rt::AF_INET, sin_port = endian::htonu16(port), sin_addr = rt::in_addr { s_addr = *(&v4[0]: *u32) }, ... }, ... }; case let v6: addr6 => return rt::sockaddr { in6 = rt::sockaddr_in6 { sin6_len = size(rt::in6_addr): u8, sin6_family = rt::AF_INET6, sin6_port = endian::htonu16(port), sin6_addr = rt::in6_addr { s6_addr = v6 }, ... }, ... }; }; }; export fn from_native(a: rt::sockaddr) (addr, u16) = { let family = a.in.sin_family; switch (family) { case rt::AF_INET => let addr = a.in.sin_addr.s_addr; return ( [addr: u8, (addr >> 8): u8, (addr >> 16): u8, (addr >> 24): u8]: addr4, endian::ntohu16(a.in.sin_port) ); case rt::AF_INET6 => return ( a.in6.sin6_addr.s6_addr: addr6, endian::ntohu16(a.in6.sin6_port) ); case => abort("Wrong address family!"); }; }; export fn native_addrlen(a: addr) u32 = { match (a) { case addr4 => return size(rt::sockaddr_in): u32; case addr6 => return size(rt::sockaddr_in6): u32; }; }; hare-0.24.2/net/ip/ip.ha000066400000000000000000000204611464473310100146440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use endian; use fmt; use io; use memio; use strconv; use strings; // An IPv4 address. export type addr4 = [4]u8; // An IPv6 address. export type addr6 = [16]u8; // An IP address. export type addr = (addr4 | addr6); // An IP subnet. export type subnet = struct { addr: addr, mask: addr, }; // An IPv4 address which represents "any" address, i.e. "0.0.0.0". Binding to // this address will listen on all available IPv4 interfaces on most systems. export const ANY_V4: addr4 = [0, 0, 0, 0]; // An IPv6 address which represents "any" address, i.e. "::". Binding to this // address will listen on all available IPv6 interfaces on most systems. export const ANY_V6: addr6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // An IPv4 address which represents the loopback address, i.e. "127.0.0.1". export const LOCAL_V4: addr4 = [127, 0, 0, 1]; // An IPv6 address which represents the loopback address, i.e. "::1". export const LOCAL_V6: addr6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // Invalid parse result. export type invalid = !void; // Test if two [[addr]]s are equal. export fn equal(l: addr, r: addr) bool = { match (l) { case let l: addr4 => if (!(r is addr4)) { return false; }; let r = r as addr4; return bytes::equal(l, r); case let l: addr6 => if (!(r is addr6)) { return false; }; let r = r as addr6; return bytes::equal(l, r); }; }; // Parses an IPv4 address. export fn parsev4(st: str) (addr4 | invalid) = { let ret: addr4 = [0...]; let tok = strings::tokenize(st, "."); let i = 0z; for (i < 4; i += 1) { let s = wanttoken(&tok)?; if (len(s) != 1 && strings::hasprefix(s, "0")) { return invalid; }; ret[i] = match (strconv::stou8(s)) { case let term: u8 => yield term; case => return invalid; }; }; if (i < 4 || !(strings::next_token(&tok) is done)) { return invalid; }; return ret; }; // Parses an IPv6 address. export fn parsev6(st: str) (addr6 | invalid) = { let ret: addr6 = [0...]; if (st == "::") { return ret; }; let tok = strings::tokenize(st, ":"); let ells = -1; if (strings::hasprefix(st, "::")) { wanttoken(&tok)?; wanttoken(&tok)?; ells = 0; } else if (strings::hasprefix(st, ":")) { return invalid; }; let i = 0; for (i < 16) { let s = match (strings::next_token(&tok)) { case let s: str => yield s; case done => break; }; if (s == "") { if (ells != -1) { return invalid; }; ells = i; continue; }; match (strconv::stou16(s, strconv::base::HEX)) { case let val: u16 => endian::beputu16(ret[i..], val); i += 2; case => ret[i..i + 4] = parsev4(s)?; i += 4; break; }; }; if (!(strings::next_token(&tok) is done)) { return invalid; }; if (ells >= 0) { if (i >= 15) { return invalid; }; const n = i - ells; ret[16 - n..16] = ret[ells..ells + n]; ret[ells..ells + n] = [0...]; } else if (i != 16) { return invalid; }; return ret; }; // Parses an IP address. export fn parse(s: str) (addr | invalid) = { match (parsev4(s)) { case let v4: addr4 => return v4; case invalid => void; }; match (parsev6(s)) { case let v6: addr6 => return v6; case invalid => void; }; return invalid; }; fn fmtv4(s: io::handle, a: addr4) (size | io::error) = { let ret = 0z; for (let i = 0; i < 4; i += 1) { if (i > 0) { ret += fmt::fprintf(s, ".")?; }; ret += fmt::fprintf(s, "{}", a[i])?; }; return ret; }; fn fmtv6(s: io::handle, a: addr6) (size | io::error) = { let ret = 0z; let zstart: int = -1; let zend: int = -1; for (let i = 0; i < 16; i += 2) { let j = i; for (j < 16 && a[j] == 0 && a[j + 1] == 0) { j += 2; }; if (j > i && j - i > zend - zstart) { zstart = i; zend = j; i = j; }; }; if (zend - zstart <= 2) { zstart = -1; zend = -1; }; for (let i = 0; i < 16; i += 2) { if (i == zstart) { ret += fmt::fprintf(s, "::")?; i = zend; if (i >= 16) break; } else if (i > 0) { ret += fmt::fprintf(s, ":")?; }; let term = (a[i]: u16) << 8 | a[i + 1]; ret += fmt::fprintf(s, "{:x}", term)?; }; return ret; }; // Fills a netmask according to the CIDR value // e.g. 23 -> [0xFF, 0xFF, 0xFD, 0x00] fn fillmask(mask: []u8, val: u8) void = { mask[..] = [0xFF...]; let i: int = len(mask): int - 1; val = len(mask): u8 * 8 - val; for (val >= 8) { mask[i] = 0x00; val -= 8; i -= 1; }; if (i >= 0) { mask[i] = ~((1 << val) - 1); }; }; // Returns an addr representing a netmask fn cidrmask(addr: addr, val: u8) (addr | invalid) = { let a_len: u8 = match (addr) { case addr4 => yield 4; case addr6 => yield 16; }; if (val > 8 * a_len) return invalid; if (a_len == 4) { let ret: addr4 = [0...]; fillmask(ret[..], val); return ret; }; if (a_len == 16) { let ret: addr6 = [0...]; fillmask(ret[..], val); return ret; }; return invalid; }; // Parse an IP subnet in CIDR notation e.g. 192.168.1.0/24 export fn parsecidr(st: str) (subnet | invalid) = { let tok = strings::tokenize(st, "/"); let ips = wanttoken(&tok)?; let addr = parse(ips)?; let masks = wanttoken(&tok)?; let val = match (strconv::stou8(masks)) { case let x: u8 => yield x; case => return invalid; }; if (!(strings::next_token(&tok) is done)) { return invalid; }; return subnet { addr = addr, mask = cidrmask(addr, val)? }; }; fn masklen(addr: []u8) (void | size) = { let n = 0z; for (let i = 0z; i < len(addr); i += 1) { if (addr[i] == 0xff) { n += 8; continue; }; let val = addr[i]; for (val & 0x80 != 0) { n += 1; val <<= 1; }; if (val != 0) return; for (let j = i + 1; j < len(addr); j += 1) { if (addr[j] != 0) return; }; break; }; return n; }; fn fmtmask(s: io::handle, mask: addr) (size | io::error) = { let ret = 0z; let slice = match (mask) { case let v4: addr4 => yield v4[..]; case let v6: addr6 => yield v6[..]; }; match (masklen(slice)) { case void => // Format as hex, if zero runs are not contiguous // (like golang does) for (let part .. slice) { ret += fmt::fprintf(s, "{:x}", part)?; }; case let n: size => // Standard CIDR integer ret += fmt::fprintf(s, "{}", n)?; }; return ret; }; fn fmtsubnet(s: io::handle, subnet: subnet) (size | io::error) = { let ret = 0z; ret += fmt(s, subnet.addr)?; ret += fmt::fprintf(s, "/")?; ret += fmtmask(s, subnet.mask)?; return ret; }; // Formats an [[addr]] or [[subnet]] and prints it to a stream. export fn fmt(s: io::handle, item: (...addr | subnet)) (size | io::error) = { match (item) { case let v4: addr4 => return fmtv4(s, v4)?; case let v6: addr6 => return fmtv6(s, v6)?; case let sub: subnet => return fmtsubnet(s, sub); }; }; // Formats an [[addr]] or [[subnet]] as a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] to // extend its lifetime. export fn string(item: (...addr | subnet)) str = { // Maximum length of an IPv6 address plus its netmask in hexadecimal static let buf: [64]u8 = [0...]; let stream = memio::fixed(buf); fmt(&stream, item) as size; return memio::string(&stream)!; }; fn wanttoken(tok: *strings::tokenizer) (str | invalid) = { match (strings::next_token(tok)) { case let s: str => return s; case done => return invalid; }; }; // Returns whether an [[addr]] (or another [[subnet]]) is contained // within a [[subnet]]. export fn subnet_contains(sub: subnet, item: (addr | subnet)) bool = { let a: subnet = match (item) { case let a: addr => yield subnet { addr = a, mask = sub.mask, }; case let sub: subnet => yield sub; }; // Get byte slices for both addresses and masks. let ipa = match (sub.addr) { case let v4: addr4 => yield v4[..]; case let v6: addr6 => yield v6[..]; }; let maska = match (sub.mask) { case let v4: addr4 => yield v4[..]; case let v6: addr6 => yield v6[..]; }; let ipb = match (a.addr) { case let v4: addr4 => yield v4[..]; case let v6: addr6 => yield v6[..]; }; let maskb = match (a.mask) { case let v4: addr4 => yield v4[..]; case let v6: addr6 => yield v6[..]; }; if (len(ipa) != len(ipb) || len(maska) != len(maskb) || len(ipa) != len(maska)) { // Mismatched addr4 and addr6 addresses / masks. return false; }; for (let i = 0z; i < len(ipa); i += 1) { if (ipa[i] & maska[i] != ipb[i] & maska[i] || maska[i] > maskb[i]) { return false; }; }; return true; }; hare-0.24.2/net/ip/test+test.ha000066400000000000000000000064001464473310100161630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; fn ip_test(s: str, expected: (addr|invalid)) void = { let pr = parse(s); let ip = if (pr is invalid) { assert(expected is invalid); return; } else { assert(expected is addr); assert(equal(pr as addr, expected as addr)); yield pr as addr; }; let fmted = string(ip); let iprp = parse(fmted); assert(iprp is addr); let ipr = iprp as addr; assert(equal(ip, ipr)); if (ip is addr4) { assert(fmted == s); } else { const dup = strings::dup(fmted); defer free(dup); assert(dup == string(ipr)); }; }; @test fn parse_ip() void = { let tests: [](str, (addr|invalid)) = [ ("127.0.0.1", [127, 0, 0, 1]: addr4), ("192.168.18.1", [192, 168, 18, 1]: addr4), ("-127.0.0.1", invalid), ("127.-0.0.1", invalid), ("0.011.001.000", invalid), ("::", [0...]: addr6), ("::1", [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]: addr6), ("::FFFF:FFFF", [0,0,0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,0xFF,0xFF]: addr6), ("::FFFF", [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xFF,0xFF]: addr6), (":FFFF", invalid), ("::1:1", [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1]: addr6), ("1::1", [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1]: addr6), (":::1:1", invalid), (":::", invalid), ("::1::1", invalid), ("1::::1", invalid), ("FFFF::FFFF::1", invalid), ("::127.0.0.1", [0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,1]: addr6), ("FFFF:FFFF", invalid), ("DEAD::BEef", [0xDE, 0xAD, 0,0,0,0,0,0,0,0,0,0,0,0, 0xBE, 0xEF]: addr6), ("DEAD::BEef:A12D", [0xDE, 0xAD, 0,0,0,0,0,0,0,0,0,0, 0xBE, 0xEF, 0xA1, 0x2D]: addr6), ("DEAD:BEef::0102:A12D", [0xDE, 0xAD,0xBE,0xEF,0,0,0,0,0,0,0,0,0x01,0x02,0xA1,0x2D]: addr6), ("DEAD:BEef:::A12D", invalid), ("1980:cafe:a:babe::1", [0x19, 0x80, 0xca, 0xfe, 0x0, 0xa, 0xba, 0xbe, 0, 0, 0, 0, 0, 0, 0, 1]: addr6), ("a1:a2:a3:a4::b1:b2:b3:b4", invalid), ("", invalid), ]; for (let (string, expected) .. tests) { ip_test(string, expected); }; }; fn subnet_test_simple(s: str) void = { let net = match (parsecidr(s)) { case let a: subnet => yield a; case => return; }; let fmted = string(net); assert(fmted == s); let netrp = parsecidr(fmted); assert(netrp is subnet); let netr = netrp as subnet; assert(equal(net.addr, netr.addr)); assert(equal(net.mask, netr.mask)); }; @test fn parse_subnet() void = { let subnet_tests: []str = [ "192.168.1.0/0", "192.168.1.0/23", "192.168.1.0/24", "192.168.1.0/32", ]; for (let test .. subnet_tests) { subnet_test_simple(test); }; }; @test fn test_subnet_contains() void = { let addr_tests: [](str, str, bool) = [ // a, b, want ("10.10.10.0/24", "10.10.10.0", true), ("10.10.10.0/24", "10.10.10.255", true), ("10.10.10.0/24", "10.10.11.0", false), ("127.0.0.1/24", "::1", false), ("::1/8", "::1", true), ]; let cidr_tests: [](str, str, bool) = [ // a, b, want ("10.10.10.0/24", "10.10.10.0/24", true), ("10.10.10.0/24", "10.10.10.0/25", true), ("10.10.10.0/24", "10.10.10.0/23", false), ("10.10.10.0/24", "10.10.11.0/24", false), ]; for (let (a, b, want) .. addr_tests) { let a = parsecidr(a)!; let b = parse(b)!; assert(subnet_contains(a, b) == want); }; for (let (a, b, want) .. cidr_tests) { let a = parsecidr(a)!; let b = parsecidr(b)!; assert(subnet_contains(a, b) == want); }; }; hare-0.24.2/net/msg.ha000066400000000000000000000074571464473310100144240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: // - Set name field // - Figure out the portability mess that is this interface use rt; export type msghdr = struct { native: rt::msghdr, vectors: []rt::iovec, control: []u8, }; // Creates a new message header for advanced socket usage, with configurable I/O // vectors, control messages, and other details, for use with [[sendmsg]] and // [[recvmsg]]. // // The user must call [[finish]] when they are done using this message for // sending or receiving. The same message may be used for multiple operations // before calling [[finish]]. [[reset]] may be used to "reset" a [[msghdr]] to // an empty list of I/O vectors and control messages without freeing the // underlying memory, which may be useful if future messages are expected to // have similar characteristics. export fn newmsg() msghdr = msghdr { ... }; // Frees resources associated with a [[msghdr]]. export fn finish(msg: *msghdr) void = { free(msg.control); free(msg.vectors); }; // Resets a message header, clearing out any I/O vectors or control messages, // without freeing the underlying memory. This allows the user to configure new // vectors or control messages without a re-allocation, which improves // performance if the new configuration fits into the same amount of memory. export fn reset(msg: *msghdr) void = { msg.control = msg.control[..0]; msg.vectors = msg.vectors[..0]; }; // Adds an I/O vector to the message. export fn addvector(msg: *msghdr, vec: []u8) void = { append(msg.vectors, rt::iovec { iov_base = vec: *[*]u8, iov_len = len(vec), }); }; // Sets flags for this message. export fn setflags(msg: *msghdr, flags: int) void = { msg.native.msg_flags = flags; }; // Get flags for this message. export fn getflags(msg: *msghdr) int = { return msg.native.msg_flags; }; // Sets name for this message. export fn setname(msg: *msghdr, name: *opaque, length: size) void = { msg.native.msg_name = name; msg.native.msg_namelen = length: u32; }; // Adds a control message of the desired length to a [[msghdr]], returning a // buffer in which the ancillary data may be written in a domain-specific // format. // // This is a low-level interface, and is not generally used by users. More // often, users will call functions like [[net::unix::addfiles]] or // [[net::unix::allocfiles]], which provide a high-level interface to this // function for domain-specific use-cases. export fn addcontrol( msg: *msghdr, length: size, level: int, ctype: int, ) []u8 = { const prev = len(msg.control); const space = cmsg_space(length); append(msg.control, [0...], space); let newbuf = msg.control[prev..prev + space]: *[*]rt::cmsghdr; newbuf[0].cmsg_len = cmsg_len(length): uint; newbuf[0].cmsg_level = level; newbuf[0].cmsg_type = ctype; let user = &newbuf[1]: *[*]u8; return user[..length]; }; // Retrieves a control header from a message, returning a slice of // domain-specific data. // // This is a low-level interface, and is not generally used by users. More // often, users will call functions like [[net::unix::addfiles]] or // [[net::unix::allocfiles]], which provide a high-level interface to this // function for domain-specific use-cases. export fn getcontrol( msg: *msghdr, length: size, level: int, ctype: int, ) ([]u8 | void) = { let native = &msg.native; let cbuf = native.msg_control: *[*]u8; for (let i = 0z; i < native.msg_controllen) { let next = &cbuf[i]: *rt::cmsg; if (next.hdr.cmsg_len >= length && next.hdr.cmsg_level == level && next.hdr.cmsg_type == ctype) { return next.cmsg_data[..length]; }; i += next.hdr.cmsg_len; }; }; fn cmsg_align(z: size) size = (z + size(size) - 1) & ~(size(size) - 1); fn cmsg_len(z: size) size = cmsg_align(size(rt::cmsghdr)) + z; fn cmsg_space(z: size) size = cmsg_align(size(rt::cmsghdr)) + cmsg_align(z); hare-0.24.2/net/tcp/000077500000000000000000000000001464473310100140755ustar00rootroot00000000000000hare-0.24.2/net/tcp/+freebsd.ha000066400000000000000000000071341464473310100161010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Opens a TCP connection to the given host and port. Blocks until the // connection is established. export fn connect( addr: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => if (err != rt::EINPROGRESS) { return errors::errno(err); }; assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK); case int => void; }; return io::fdopen(sockfd); }; // Binds a TCP socket to the given address. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case let b: backlog => bk = b; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return sockfd; }; // Returns the remote address for a given connection, or void if none is // available. export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { let sn = rt::sockaddr {...}; let sz = size(rt::sockaddr): u32; if (rt::getpeername(peer, &sn, &sz) is rt::errno) { return; }; return ip::from_native(sn); }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/tcp/+linux.ha000066400000000000000000000071121464473310100156220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Opens a TCP connection to the given host and port. Blocks until the // connection is established. export fn connect( addr: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case => void; }; }; const sz = size(rt::sockaddr): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => if (err != rt::EINPROGRESS) { return errors::errno(err); }; assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK); case int => void; }; return io::fdopen(sockfd); }; // Binds a TCP socket to the given address. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case let b: backlog => bk = b; case => void; }; }; match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return sockfd; }; // Returns the remote address for a given connection, or void if none is // available. export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { let sn = rt::sockaddr {...}; let sz = size(rt::sockaddr): u32; if (rt::getpeername(peer, &sn, &sz) is rt::errno) { return; }; return ip::from_native(sn); }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/tcp/+netbsd.ha000066400000000000000000000071341464473310100157460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Opens a TCP connection to the given host and port. Blocks until the // connection is established. export fn connect( addr: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => if (err != rt::EINPROGRESS) { return errors::errno(err); }; assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK); case int => void; }; return io::fdopen(sockfd); }; // Binds a TCP socket to the given address. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case let b: backlog => bk = b; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return sockfd; }; // Returns the remote address for a given connection, or void if none is // available. export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { let sn = rt::sockaddr {...}; let sz = size(rt::sockaddr): u32; if (rt::getpeername(peer, &sn, &sz) is rt::errno) { return; }; return ip::from_native(sn); }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/tcp/+openbsd.ha000066400000000000000000000071131464473310100161160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Opens a TCP connection to the given host and port. Blocks until the // connection is established. export fn connect( addr: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let flags = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => flags |= fl; case => void; }; }; flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | flags, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => if (err != rt::EINPROGRESS) { return errors::errno(err); }; case void => void; }; return io::fdopen(sockfd); }; // Binds a TCP socket to the given address. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const sockaddr = ip::to_native(addr, port); const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let flags = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => flags |= fl; case => void; }; }; flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_STREAM | flags, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; case let b: backlog => bk = b; case => void; }; }; const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case void => void; }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case void => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return sockfd; }; // Returns the remote address for a given connection, or void if none is // available. export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { let sn = rt::sockaddr {...}; let sz = size(rt::sockaddr): u32; if (rt::getpeername(peer, &sn, &sz) is rt::errno) { return; }; return ip::from_native(sn); }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case void => void; }; }; hare-0.24.2/net/tcp/listener.ha000066400000000000000000000005471464473310100162420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; // Accepts the next connection from a socket. Blocks until a new connection is // available. This is a convenience wrapper around [[net::accept]]. export fn accept( sock: net::socket, flags: net::sockflag = 0, ) (net::socket | net::error) = net::accept(sock, flags); hare-0.24.2/net/tcp/options.ha000066400000000000000000000016251464473310100161060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; // Enables keep-alive for a socket. export type keepalive = void; // Configures the backlog size for a listener. If not specified, a sensible // default (10) is used. export type backlog = u32; // Enables port re-use for a TCP listener. export type reuseport = void; // Enables address re-use for a TCP listener. export type reuseaddr = void; // To have the system select an arbitrary unused port for [[listen]], set port to // zero. To retrieve the assigned port, provide this as one of the options and // the addressed u16 will be filled in with the port. export type portassignment = *u16; // Options for [[connect]]. export type connect_option = (keepalive | net::sockflag); // Options for [[listen]]. export type listen_option = ( keepalive | reuseport | reuseaddr | backlog | portassignment | net::sockflag); hare-0.24.2/net/types.ha000066400000000000000000000004711464473310100147670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The end of the full-duplex connection that should be [[shutdown]]. export type shut = enum { RD, // Disables further receptions. WR, // Disables further transmissions. RDWR, // Disables further receptions and transmissions. }; hare-0.24.2/net/udp/000077500000000000000000000000001464473310100140775ustar00rootroot00000000000000hare-0.24.2/net/udp/+freebsd.ha000066400000000000000000000105611464473310100161010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Creates a UDP socket and sets the default destination to the given address. export fn connect( dest: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const family = match (dest) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::connect(sockfd, &sockaddr, sz)) { case int => return io::fdopen(sockfd); case let err: rt::errno => return errors::errno(err); }; }; // Creates a UDP socket bound to an interface. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case => void; }; }; const sockaddr = ip::to_native(addr, port); const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case int => void; case let err: rt::errno => return errors::errno(err); }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return io::fdopen(sockfd); }; // Sends a UDP packet to a [[connect]]ed UDP socket. export fn send(sock: net::socket, buf: []u8) (size | net::error) = { match (rt::send(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Sends a UDP packet using this socket. export fn sendto( sock: net::socket, buf: []u8, dest: ip::addr, port: u16, ) (size | net::error) = { const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a [[connect]]ed UDP socket. export fn recv( sock: net::socket, buf: []u8, ) (size | net::error) = { match (rt::recv(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a bound socket. export fn recvfrom( sock: net::socket, buf: []u8, src: nullable *ip::addr, port: nullable *u16, ) (size | net::error) = { let addrsz = size(rt::sockaddr): u32; const sockaddr = rt::sockaddr { ... }; const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, &sockaddr, &addrsz)) { case let sz: size => yield sz; case let err: rt::errno => return errors::errno(err); }; assert(addrsz <= size(rt::sockaddr)); const peer = ip::from_native(sockaddr); match (src) { case null => void; case let src: *ip::addr => *src = peer.0; }; match (port) { case null => void; case let port: *u16 => *port = peer.1; }; return sz; }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/udp/+linux.ha000066400000000000000000000105561464473310100156320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Creates a UDP socket and sets the default destination to the given address. export fn connect( dest: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const family = match (dest) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sockaddr = ip::to_native(dest, port); const sz = size(rt::sockaddr): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case int => return io::fdopen(sockfd); case let err: rt::errno => return errors::errno(err); }; }; // Creates a UDP socket bound to an interface. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case => void; }; }; const sockaddr = ip::to_native(addr, port); const sz = size(rt::sockaddr): u32; match (rt::bind(sockfd, &sockaddr, sz)) { case int => void; case let err: rt::errno => return errors::errno(err); }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return io::fdopen(sockfd); }; // Sends a UDP packet to a [[connect]]ed UDP socket. export fn send(sock: net::socket, buf: []u8) (size | net::error) = { match (rt::send(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Sends a UDP packet using this socket. export fn sendto( sock: net::socket, buf: []u8, dest: ip::addr, port: u16, ) (size | net::error) = { const sockaddr = ip::to_native(dest, port); const sz = size(rt::sockaddr): u32; match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a [[connect]]ed UDP socket. export fn recv( sock: net::socket, buf: []u8, ) (size | net::error) = { match (rt::recv(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a bound socket. export fn recvfrom( sock: net::socket, buf: []u8, src: nullable *ip::addr, port: nullable *u16, ) (size | net::error) = { let addrsz = size(rt::sockaddr): u32; const sockaddr = rt::sockaddr { ... }; const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, &sockaddr, &addrsz)) { case let sz: size => yield sz; case let err: rt::errno => return errors::errno(err); }; assert(addrsz <= size(rt::sockaddr)); const peer = ip::from_native(sockaddr); match (src) { case null => void; case let src: *ip::addr => *src = peer.0; }; match (port) { case null => void; case let port: *u16 => *port = peer.1; }; return sz; }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/udp/+netbsd.ha000066400000000000000000000105611464473310100157460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Creates a UDP socket and sets the default destination to the given address. export fn connect( dest: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const family = match (dest) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::connect(sockfd, &sockaddr, sz)) { case int => return io::fdopen(sockfd); case let err: rt::errno => return errors::errno(err); }; }; // Creates a UDP socket bound to an interface. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case => void; }; }; const sockaddr = ip::to_native(addr, port); const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case int => void; case let err: rt::errno => return errors::errno(err); }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case int => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return io::fdopen(sockfd); }; // Sends a UDP packet to a [[connect]]ed UDP socket. export fn send(sock: net::socket, buf: []u8) (size | net::error) = { match (rt::send(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Sends a UDP packet using this socket. export fn sendto( sock: net::socket, buf: []u8, dest: ip::addr, port: u16, ) (size | net::error) = { const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a [[connect]]ed UDP socket. export fn recv( sock: net::socket, buf: []u8, ) (size | net::error) = { match (rt::recv(sock, buf: *[*]u8, len(buf), 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a bound socket. export fn recvfrom( sock: net::socket, buf: []u8, src: nullable *ip::addr, port: nullable *u16, ) (size | net::error) = { let addrsz = size(rt::sockaddr): u32; const sockaddr = rt::sockaddr { ... }; const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, &sockaddr, &addrsz)) { case let sz: size => yield sz; case let err: rt::errno => return errors::errno(err); }; assert(addrsz <= size(rt::sockaddr)); const peer = ip::from_native(sockaddr); match (src) { case null => void; case let src: *ip::addr => *src = peer.0; }; match (port) { case null => void; case let port: *u16 => *port = peer.1; }; return sz; }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; }; hare-0.24.2/net/udp/+openbsd.ha000066400000000000000000000106601464473310100161210ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use net::ip; use rt; // Creates a UDP socket and sets the default destination to the given address. export fn connect( dest: ip::addr, port: u16, options: connect_option... ) (net::socket | net::error) = { const family = match (dest) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let flags = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now flags |= options[i]; }; flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | flags, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::connect(sockfd, &sockaddr, sz)) { case void => return io::fdopen(sockfd); case let err: rt::errno => return errors::errno(err); }; }; // Creates a UDP socket bound to an interface. export fn listen( addr: ip::addr, port: u16, options: listen_option... ) (net::socket | net::error) = { const family = match (addr) { case ip::addr4 => yield rt::AF_INET: int; case ip::addr6 => yield rt::AF_INET6: int; }; let flags = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => flags |= fl; case => void; }; }; flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | flags, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?; case reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?; case => void; }; }; const sockaddr = ip::to_native(addr, port); const sz = ip::native_addrlen(addr); match (rt::bind(sockfd, &sockaddr, sz)) { case void => void; case let err: rt::errno => return errors::errno(err); }; for (let i = 0z; i < len(options); i += 1) { let portout = match (options[i]) { case let p: portassignment => yield p; case => continue; }; let sn = rt::sockaddr {...}; let al = size(rt::sockaddr): u32; match (rt::getsockname(sockfd, &sn, &al)) { case let err: rt::errno => return errors::errno(err); case void => void; }; const addr = ip::from_native(sn); *portout = addr.1; }; return io::fdopen(sockfd); }; // Sends a UDP packet to a [[connect]]ed UDP socket. export fn send(sock: net::socket, buf: []u8) (size | net::error) = { match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, null, 0)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Sends a UDP packet using this socket. export fn sendto( sock: net::socket, buf: []u8, dest: ip::addr, port: u16, ) (size | net::error) = { const sockaddr = ip::to_native(dest, port); const sz = ip::native_addrlen(dest); match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a [[connect]]ed UDP socket. export fn recv( sock: net::socket, buf: []u8, ) (size | net::error) = { match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, null, null)) { case let sz: size => return sz; case let err: rt::errno => return errors::errno(err); }; }; // Receives a UDP packet from a bound socket. export fn recvfrom( sock: net::socket, buf: []u8, src: nullable *ip::addr, port: nullable *u16, ) (size | net::error) = { let addrsz = size(rt::sockaddr): u32; const sockaddr = rt::sockaddr { ... }; const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, &sockaddr, &addrsz)) { case let sz: size => yield sz; case let err: rt::errno => return errors::errno(err); }; assert(addrsz <= size(rt::sockaddr)); const peer = ip::from_native(sockaddr); match (src) { case null => void; case let src: *ip::addr => *src = peer.0; }; match (port) { case null => void; case let port: *u16 => *port = peer.1; }; return sz; }; fn setsockopt( sockfd: int, option: int, value: bool, ) (void | net::error) = { let val: int = if (value) 1 else 0; match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, &val: *opaque, size(int): u32)) { case let err: rt::errno => return errors::errno(err); case void => void; }; }; hare-0.24.2/net/udp/options.ha000066400000000000000000000013231464473310100161030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; // Enables port re-use for a UDP listener. export type reuseport = void; // Enables address re-use for a UDP listener. export type reuseaddr = void; // To have the system select an arbitrary unused port for [[listen]], set port to // zero. To retrieve the assigned port, provide this as one of the options and // the addressed u16 will be filled in with the port. export type portassignment = *u16; // Options for [[connect]]. export type connect_option = net::sockflag; // Options available for [[listen]]. export type listen_option = ( reuseport | reuseaddr | portassignment | net::sockflag); // TODO: Add send/recv flags hare-0.24.2/net/unix/000077500000000000000000000000001464473310100142725ustar00rootroot00000000000000hare-0.24.2/net/unix/+freebsd.ha000066400000000000000000000051201464473310100162670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use rt; use types; // Opens a UNIX socket connection to the path. Blocks until the connection is // established. export fn connect( addr: addr, options: connect_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sz = size(rt::sockaddr_un): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return io::fdopen(sockfd); }; // Binds a UNIX socket to the given path. export fn listen( addr: addr, options: listen_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let b: backlog => bk = b; case => void; }; }; match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return sockfd; }; // Converts a UNIX socket address to a native sockaddr. fn to_native(addr: addr) (rt::sockaddr | invalid) = { // sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX if (len(addr) > rt::UNIX_PATH_MAX - 1) { return invalid; }; let ret = rt::sockaddr { un = rt::sockaddr_un { sun_len = size(rt::sockaddr_un): u8, sun_family = rt::AF_UNIX, ... } }; match ((&addr: *types::string).data) { case null => void; case let data: *[*]u8 => ret.un.sun_path[..len(addr)] = data[..len(addr)]; }; ret.un.sun_path[len(addr)] = 0; return ret; }; hare-0.24.2/net/unix/+linux.ha000066400000000000000000000050501464473310100160160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use rt; use types; // Opens a UNIX socket connection to the path. Blocks until the connection is // established. export fn connect( addr: addr, options: connect_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sz = size(rt::sockaddr_un): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return io::fdopen(sockfd); }; // Binds a UNIX socket to the given path. export fn listen( addr: addr, options: listen_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let b: backlog => bk = b; case => void; }; }; match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return sockfd; }; // Converts a UNIX socket address to a native sockaddr. fn to_native(addr: addr) (rt::sockaddr | invalid) = { // sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX if (len(addr) > rt::UNIX_PATH_MAX - 1) { return invalid; }; let ret = rt::sockaddr { un = rt::sockaddr_un { sun_family = rt::AF_UNIX, ... } }; match ((&addr: *types::string).data) { case null => void; case let data: *[*]u8 => ret.un.sun_path[..len(addr)] = data[..len(addr)]; }; ret.un.sun_path[len(addr)] = 0; return ret; }; hare-0.24.2/net/unix/+netbsd.ha000066400000000000000000000051201464473310100161340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use rt; use types; // Opens a UNIX socket connection to the path. Blocks until the connection is // established. export fn connect( addr: addr, options: connect_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now f |= options[i]; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sz = size(rt::sockaddr_un): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return io::fdopen(sockfd); }; // Binds a UNIX socket to the given path. export fn listen( addr: addr, options: listen_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let b: backlog => bk = b; case => void; }; }; match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) { case let err: rt::errno => return errors::errno(err); case int => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case int => void; }; return sockfd; }; // Converts a UNIX socket address to a native sockaddr. fn to_native(addr: addr) (rt::sockaddr | invalid) = { // sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX if (len(addr) > rt::UNIX_PATH_MAX - 1) { return invalid; }; let ret = rt::sockaddr { un = rt::sockaddr_un { sun_len = size(rt::sockaddr_un): u8, sun_family = rt::AF_UNIX, ... } }; match ((&addr: *types::string).data) { case null => void; case let data: *[*]u8 => ret.un.sun_path[..len(addr)] = data[..len(addr)]; }; ret.un.sun_path[len(addr)] = 0; return ret; }; hare-0.24.2/net/unix/+openbsd.ha000066400000000000000000000051431464473310100163140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use rt; use types; // Opens a UNIX socket connection to the path. Blocks until the connection is // established. export fn connect( addr: addr, options: connect_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let flags = 0i; for (let i = 0z; i < len(options); i += 1) { // Only sockflag for now flags |= options[i]; }; flags ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | flags, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; const sz = size(rt::sockaddr_un): u32; match (rt::connect(sockfd, &sockaddr, sz)) { case let err: rt::errno => return errors::errno(err); case void => void; }; return io::fdopen(sockfd); }; // Binds a UNIX socket to the given path. export fn listen( addr: addr, options: listen_option... ) (net::socket | net::error) = { let sockaddr = match (to_native(addr)) { case let a: rt::sockaddr => yield a; case invalid => return errors::unsupported; // path too long }; let f = 0i; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let fl: net::sockflag => f |= fl; case => void; }; }; f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { case let err: rt::errno => return errors::errno(err); case let fd: int => yield fd; }; let bk: u32 = 10; for (let i = 0z; i < len(options); i += 1) { match (options[i]) { case let b: backlog => bk = b; case => void; }; }; match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::listen(sockfd, bk)) { case let err: rt::errno => return errors::errno(err); case void => void; }; return sockfd; }; // Converts a UNIX socket address to a native sockaddr. fn to_native(addr: addr) (rt::sockaddr | invalid) = { // sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX if (len(addr) > rt::UNIX_PATH_MAX - 1) { return invalid; }; let ret = rt::sockaddr { un = rt::sockaddr_un { sun_len = size(rt::sockaddr_un): u8, sun_family = rt::AF_UNIX, ... } }; match ((&addr: *types::string).data) { case null => void; case let data: *[*]u8 => ret.un.sun_path[..len(addr)] = data[..len(addr)]; }; ret.un.sun_path[len(addr)] = 0; return ret; }; hare-0.24.2/net/unix/README000066400000000000000000000003271464473310100151540ustar00rootroot00000000000000net::unix provides access to Unix sockets for networking. A protocol provider for [[net::dial::]] is provided by this module, but you must import net::unix at least once in order for it to be visible to net::dial. hare-0.24.2/net/unix/addr.ha000066400000000000000000000002751464473310100155220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A UNIX socket address. export type addr = str; // Invalid UNIX socket path. export type invalid = !void; hare-0.24.2/net/unix/cmsg.ha000066400000000000000000000020311464473310100155310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use net; use rt; // Adds a list of file descriptors to the ancillary data for a sendmsg // operation. export fn addfiles(buf: *net::msghdr, files: io::file...) void = { const msgsz = size(io::file) * len(files); let buf = net::addcontrol(buf, msgsz, rt::SOL_SOCKET, rt::SCM_RIGHTS); let buf = buf: *[*]io::file; buf[..len(files)] = files[..]; }; // Prepares an ancillary data buffer to receive files during a recvmsg // operation. export fn allocfiles(buf: *net::msghdr, nfile: size) void = { const msgsz = size(io::file) * nfile; net::addcontrol(buf, msgsz, rt::SOL_SOCKET, rt::SCM_RIGHTS); }; // Receives files from an ancillary data buffer which was previously prepared // with [[allocfiles]]. export fn recvfiles(buf: *net::msghdr, nfile: size) []io::file = { match (net::getcontrol(buf, nfile * size(io::file), rt::SOL_SOCKET, rt::SCM_RIGHTS)) { case let buf: []u8 => return (buf: *[*]io::file)[..nfile]; case void => return []; }; }; hare-0.24.2/net/unix/dial.ha000066400000000000000000000005701464473310100155170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; use net::dial; fn dial_unix(addr: str, service: str) (net::socket | dial::error) = { match (connect(addr)) { case let conn: net::socket => return conn; case let err: net::error => return err; }; }; @init fn registerproto() void = { dial::registerproto("unix", &dial_unix); }; hare-0.24.2/net/unix/listener.ha000066400000000000000000000005471464473310100164370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; // Accepts the next connection from a socket. Blocks until a new connection is // available. This is a convenience wrapper around [[net::accept]]. export fn accept( sock: net::socket, flags: net::sockflag = 0, ) (net::socket | net::error) = net::accept(sock, flags); hare-0.24.2/net/unix/options.ha000066400000000000000000000005661464473310100163060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net; // Configures the backlog size for a listener. If not specified, a sensible // default (10) is used. export type backlog = u32; // Options for [[connect]]. export type connect_option = net::sockflag; // Options for [[listen]]. export type listen_option = (backlog | net::sockflag); hare-0.24.2/net/unix/socketpair.ha000066400000000000000000000012141464473310100167460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use net; use rt; // A thin wrapper around socketpair(2) that presumes [[rt::AF_UNIX]] for the // domain and returns an unnamed pair of sockets of type [[rt::SOCK_STREAM]]. export fn socketpair(flags: net::sockflag = 0) ((net::socket, net::socket) | net::error) = { let sv: [2]int = [0...]; flags ^= rt::SOCK_CLOEXEC: net::sockflag; // invert CLOEXEC match (rt::socketpair(rt::AF_UNIX: int, rt::SOCK_STREAM | flags, 0, &sv)) { case let err: rt::errno => return errors::errno(err); case => return (io::fdopen(sv[0]), io::fdopen(sv[1])); }; }; hare-0.24.2/net/uri/000077500000000000000000000000001464473310100141065ustar00rootroot00000000000000hare-0.24.2/net/uri/+test.ha000066400000000000000000000076761464473310100154720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use net::ip; @test fn roundtrip() void = { test_uri_roundtrip( "file:///my/path/to/file", uri { scheme = "file", host = "", path = "/my/path/to/file", ... }, )!; test_uri_roundtrip( "http://harelang.org/", uri { scheme = "http", host = "harelang.org", path = "/", ... }, )!; test_uri_roundtrip( "irc+insecure://chat.sr.ht:6667", uri { scheme = "irc+insecure", host = "chat.sr.ht", port = 6667, ... }, )!; test_uri_roundtrip( "ldap://13.37.73.31:1234/", uri { scheme = "ldap", host = [13, 37, 73, 31]: ip::addr4, port = 1234, path = "/", ... }, )!; test_uri_roundtrip( "http://[::1]/test", uri { scheme = "http", host = ip::parse("::1")!, path = "/test", ... }, )!; // Some non-URL variants like mailto: or URN test_uri_roundtrip( "urn:example:animal:ferret:nose", uri { scheme = "urn", host = "", path = "example:animal:ferret:nose", ... }, )!; test_uri_roundtrip( "mailto:~sircmpwn/hare-dev@lists.sr.ht", uri { scheme = "mailto", host = "", path = "~sircmpwn/hare-dev@lists.sr.ht", ... }, )!; test_uri_roundtrip( "https://sr.ht/projects?search=%23risc-v&sort=longest-active#foo", uri { scheme = "https", host = "sr.ht", path = "/projects", query = "search=%23risc-v&sort=longest-active", fragment = "foo", ... }, )!; test_uri_roundtrip( "https://en.wiktionary.org/wiki/%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86#Japanese", uri { scheme = "https", host = "en.wiktionary.org", path = "/wiki/おはよう", fragment = "Japanese", ... } )!; }; @test fn invalid() void = { // Scheme assert(parse(":") is invalid); assert(parse("hello*:") is invalid); assert(parse("hello") is invalid); // Unexpected character assert(parse("https://^harelang.org") is invalid); // Trailing stuff after port assert(parse("https://harelang.org:1foo2") is invalid); // Something other than IPv6 address inside [ ... ] assert(parse("https://[1.2.3.4]") is invalid); assert(parse("https://[example]") is invalid); // '@' in userinfo assert(parse("https://a@b@example") is invalid); assert(parse("https://@@example") is invalid); }; @test fn percent_encoding() void = { test_uri( "https://git%2esr.ht/~sircmpw%6e/hare#Build%20status", uri { scheme = "https", host = "git.sr.ht", path = "/~sircmpwn/hare", fragment = "Build status", ... }, "https://git.sr.ht/~sircmpwn/hare#Build%20status", )!; // IPv6 test_uri( "ldap://[2001:db8::7]/c=GB?objectClass?one", uri { scheme = "ldap", host = ip::parse("2001:db8::7")!, path = "/c=GB", query = "objectClass?one", ... }, "ldap://[2001:db8::7]/c=GB?objectClass?one", )!; // https://bugs.chromium.org/p/chromium/issues/detail?id=841105 test_uri( "https://web-safety.net/..;@www.google.com:%3443", uri { scheme = "https", host = "web-safety.net", path = "/..;@www.google.com:443", ... }, "https://web-safety.net/..;@www.google.com:443", )!; }; fn test_uri_roundtrip(in: str, expected: uri) (void | invalid) = { test_uri(in, expected, in)?; }; fn test_uri(in: str, expected_uri: uri, expected_str: str) (void | invalid) = { const u = parse(in)?; defer finish(&u); assert_str(u.scheme, expected_uri.scheme); match (u.host) { case let s: str => assert_str(s, expected_uri.host as str); case let i: ip::addr => assert(ip::equal(i, expected_uri.host as ip::addr)); }; assert(u.port == expected_uri.port); assert_str(u.userinfo, expected_uri.userinfo); assert_str(u.path, expected_uri.path); assert_str(u.query, expected_uri.query); assert_str(u.fragment, expected_uri.fragment); const s = string(&u); defer free(s); assert_str(s, expected_str); }; fn assert_str(got: str, expected: str) void = { if (got != expected) { fmt::errorfln("=== wanted\n{}", expected)!; fmt::errorfln("=== got\n{}", got)!; abort(); }; }; hare-0.24.2/net/uri/README000066400000000000000000000001341464473310100147640ustar00rootroot00000000000000The net::uri module provides utilities for parsing Uniform Resource Identifiers (RFC 3986). hare-0.24.2/net/uri/fmt.ha000066400000000000000000000060571464473310100152160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use encoding::utf8; use fmt; use io; use memio; use net::ip; use strings; // Extract from RFC3986 ABNF // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" // reg-name = *( unreserved / pct-encoded / sub-delims ) // host = IP-literal / IPv4address / reg-name // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" // query = *( pchar / "/" / "?" ) // fragment = *( pchar / "/" / "?" ) def unres_host: str = "-._~!$&'()*+,;="; def unres_query_frag: str = "-._~!$&'()*+,;=:@/?"; def unres_path: str = "-._~!$&'()*+,;=:@/"; // Writes a formatted [[uri]] to an [[io::handle]]. Returns the number of bytes // written. export fn fmt(out: io::handle, u: *const uri) (size | io::error) = { let n = 0z; let slashes_w = false; let has_host = false; if (u.scheme != "") { n += fmt::fprintf(out, "{}:", u.scheme)?; }; if (len(u.userinfo) > 0) { assert(!(u.host is str) || len(u.host as str) > 0); n += fmt::fprintf(out, "//{}@", u.userinfo)?; slashes_w = true; }; match (u.host) { case let host: str => // file scheme is allowed an empty host if (len(host) > 0 || u.scheme == "file") { has_host = true; if (!slashes_w) { n += fmt::fprint(out, "//")?; }; let unres = if(u.scheme == "file") { yield unres_path; } else { yield unres_host; }; n += percent_encode(out, host, unres)?; }; case let addr: ip::addr => has_host = true; if (!slashes_w) { n += fmt::fprint(out, "//")?; }; n += fmtaddr(out, addr)?; }; if (u.port != 0) { n += fmt::fprintf(out, ":{}", u.port)?; }; if (has_host && len(u.path) > 0 && !strings::hasprefix(u.path, '/')) { n += fmt::fprint(out, "/")?; }; n += percent_encode(out, u.path, unres_path)?; if (len(u.query) > 0) { // Always percent-encoded, see parse and encodequery/decodequery n += fmt::fprintf(out, "?{}", u.query)?; }; if (len(u.fragment) > 0) { n += fmt::fprint(out, "#")?; n += percent_encode(out, u.fragment, unres_query_frag)?; }; return n; }; fn fmtaddr(out: io::handle, addr: ip::addr) (size | io::error) = { let n = 0z; match (addr) { case let addr: ip::addr4 => n += ip::fmt(out, addr)?; case let addr: ip::addr6 => n += fmt::fprintf(out, "[")?; n += ip::fmt(out, addr)?; n += fmt::fprintf(out, "]")?; }; return n; }; fn percent_encode(out: io::handle, src: str, allowed: str) (size | io::error) = { let iter = strings::iter(src); let n = 0z; for (let r => strings::next(&iter)) { if (ascii::isalnum(r) || strings::contains(allowed, r)) { n += fmt::fprint(out, r)?; } else { const en = utf8::encoderune(r); for (let elem .. en) { n += fmt::fprintf(out, "%{:X}", elem)?; }; }; }; return n; }; // Formats a [[uri]] into a string. The result must be freed by the caller. export fn string(u: *const uri) str = { const st = memio::dynamic(); fmt(&st, u)!; return memio::string(&st)!; }; hare-0.24.2/net/uri/parse.ha000066400000000000000000000204271464473310100155370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use ascii; use encoding::utf8; use io; use memio; use net::ip; use strconv; use strings; // The URI provided to [[parse]] is invalid. export type invalid = !void; // Parses a URI string into [[uri]] structure. The return value must be freed // using [[finish]]. export fn parse(in: str) (uri | invalid) = { let success = false; let in = strings::iter(in); const scheme = parse_scheme(&in)?; defer if (!success) free(scheme); // Determine hier-part variant let path = ""; let authority: ((str | ip::addr6), u16, str) = ("", 0u16, ""); defer if (!success) { free(path); free_host(authority.0); free(authority.2); }; match (strings::next(&in)) { case let r: rune => switch (r) { case '/' => // Either "//"+authority+path-abempty or path-absolute switch (wantrune(&in)?) { case '/' => // "//" + authority + path-abempty authority = parse_authority(&in)?; match (strings::next(&in)) { case let r: rune => switch (r) { case '?', '#' => // path-empty strings::prev(&in); case '/' => // path-absolute strings::prev(&in); path = parse_path(&in, path_mode::ABSOLUTE)?; case => return invalid; }; case => void; // path-empty }; case => // path-absolute strings::prev(&in); path = parse_path(&in, path_mode::ABSOLUTE)?; }; case => // path-rootless strings::prev(&in); path = parse_path(&in, path_mode::ROOTLESS)?; }; case => void; // path-empty }; let query = ""; defer if (!success) free(query); match (strings::next(&in)) { case let r: rune => if (r == '?') { query = parse_query(&in)?; } else { strings::prev(&in); }; case => void; }; let fragment = ""; match (strings::next(&in)) { case let r: rune => if (r == '#') { fragment = parse_fragment(&in)?; } else { strings::prev(&in); }; case => void; }; success = true; return uri { scheme = scheme, host = match (authority.0) { case let ip: ip::addr6 => yield ip; case let s: str => yield match (ip::parse(s)) { case let a: ip::addr => free(s); yield a; case ip::invalid => yield s; }; }, port = authority.1, userinfo = authority.2, path = path, query = query, fragment = fragment, }; }; fn parse_scheme(in: *strings::iterator) (str | invalid) = { let copy = *in; for (let i = 0z; true; i += 1) { const r = wantrune(in)?; if (i > 0 && r == ':') { strings::prev(in); break; }; if (i == 0) { if (!ascii::isalpha(r)) { return invalid; }; } else { if (!ascii::isalnum(r) && !strings::contains("+-.", r)) { return invalid; }; }; }; let s = strings::dup(strings::slice(©, in)); strings::next(in); return s; }; fn parse_authority( in: *strings::iterator, ) (((str | ip::addr6), u16, str) | invalid) = { // Scan everything until '@' or ':' or '/', then decide what it is let success = false; let buf = memio::dynamic(); defer io::close(&buf)!; let host: (str | ip::addr6) = ""; let port = 0u16; let userinfo = ""; let has_userinfo = false; defer if (!success) { free_host(host); free(userinfo); }; for (let r => strings::next(in)) { if (r == '[') { if (len(memio::string(&buf)!) > 0) { if (len(userinfo) > 0) { return invalid; } else { userinfo = percent_decode( memio::string(&buf)!)?; }; }; memio::reset(&buf); for (true) { const r = wantrune(in)?; if (r == ']') { break; }; memio::appendrune(&buf, r)!; }; const addr = percent_decode(memio::string(&buf)!)?; defer free(addr); match (ip::parse(addr)) { case let v6: ip::addr6 => host = v6; case => return invalid; }; } else if (r == ':' || !is_userinfo(r) && !is_host(r)) { switch (r) { case '@' => if (has_userinfo) { return invalid; }; // This was userinfo+host[+port] userinfo = percent_decode(memio::string(&buf)!)?; memio::reset(&buf); has_userinfo = true; case '/' => // This was just host strings::prev(in); host = percent_decode(memio::string(&buf)!)?; break; case ':' => // This was host+port host = percent_decode(memio::string(&buf)!)?; port = parse_port(in)?; break; case => return invalid; }; } else { memio::appendrune(&buf, r)!; }; }; match (host) { case let s: str => // In end of string case if (len(s) == 0) { host = percent_decode(memio::string(&buf)!)?; }; case => void; }; success = true; return (host, port, userinfo); }; type path_mode = enum { ABSOLUTE, ROOTLESS, }; fn parse_path(in: *strings::iterator, mode: path_mode) (str | invalid) = { let copy = *in; // With rootless path, we need at least one segment if (mode == path_mode::ROOTLESS) { for (let i = 0z; true; i += 1) { match (strings::next(in)) { case let r: rune => if (r == '?' || r == '#') { strings::prev(in); break; }; if (r == '/') { if (i == 0) { return invalid; } else { break; }; }; if (!is_pchar(r)) { return invalid; }; case done => break; }; }; }; for (let r => strings::next(in)) { if (r == '?' || r == '#') { strings::prev(in); break; }; if (!is_pchar(r) && r != '/') { return invalid; }; }; return percent_decode(strings::slice(©, in)); }; fn parse_query(in: *strings::iterator) (str | invalid) = { let copy = *in; for (let r => strings::next(in)) { if (r == '#') { strings::prev(in); break; }; if (!is_pchar(r) && r != '/' && r != '?') { return invalid; }; }; return strings::dup(strings::slice(©, in)); }; fn parse_fragment(in: *strings::iterator) (str | invalid) = { let copy = *in; for (let r => strings::next(in)) { if (!is_pchar(r) && r != '/' && r != '?') { return invalid; }; }; return percent_decode(strings::slice(©, in))?; }; fn parse_port(in: *strings::iterator) (u16 | invalid) = { let copy = *in; for (let r => strings::next(in)) { if (!ascii::isdigit(r)) { strings::prev(in); break; }; }; match (strconv::stou16(strings::slice(©, in))) { case let port: u16 => if (port == 0) { // There's no port 0 return invalid; }; return port; case => return invalid; }; }; fn percent_decode(s: str) (str | invalid) = { let buf = memio::dynamic(); percent_decode_static(&buf, s)?; return memio::string(&buf)!; }; fn percent_decode_static(out: io::handle, s: str) (void | invalid) = { let iter = strings::iter(s); let tmp = memio::dynamic(); defer io::close(&tmp)!; let percent_data: []u8 = []; for (true) { match (strings::next(&iter)) { case let r: rune => if (r == '%') { memio::reset(&tmp); for (let i = 0z; i < 2; i += 1) { const r = wantrune(&iter)?; memio::appendrune(&tmp, r)!; }; match (strconv::stou8(memio::string(&tmp)!, strconv::base::HEX)) { case let ord: u8 => append(percent_data, ord); case => return invalid; }; } else { if(len(percent_data) > 0) { match(strings::fromutf8(percent_data)) { case let stro: str => memio::concat(out, stro)!; case utf8::invalid => return invalid; }; free(percent_data); percent_data = []; }; memio::appendrune(out, r)!; }; case done => if(len(percent_data) > 0) { match(strings::fromutf8(percent_data)) { case let stro: str => memio::concat(out, stro)!; case utf8::invalid => return invalid; }; free(percent_data); percent_data = []; }; break; }; }; }; fn wantrune(iter: *strings::iterator) (rune | invalid) = { match (strings::next(iter)) { case let r: rune => return r; case => return invalid; }; }; fn free_host(in: (str | ip::addr6)) void = { match (in) { case let s: str => free(s); case => void; }; }; fn is_userinfo(r: rune) bool = // unreserved + sub-delim + ":" ascii::isalnum(r) || strings::contains("-._~!$&'()*+,;=:", r) // %-encoded || r == '%' || ascii::isxdigit(r); fn is_host(r: rune) bool = // unreserved + sub-delim ascii::isalnum(r) || strings::contains("-._~!$&'()*+,;=", r) // %-encoded || r == '%' || ascii::isxdigit(r); fn is_pchar(r: rune) bool = // unreserved + sub-delim + ":"/"@" ascii::isalnum(r) || strings::contains("-._~!$&'()*+,;=:@", r) // %-encoded || r == '%' || ascii::isxdigit(r); hare-0.24.2/net/uri/query.ha000066400000000000000000000051751464473310100155750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use memio; use strings; export type query_decoder = struct { tokenizer: strings::tokenizer, bufs: (memio::stream, memio::stream), }; // Initializes a decoder for a query string. Use [[query_next]] to walk it. The // caller must call [[query_finish]] once they're done using it. export fn decodequery(q: const str) query_decoder = query_decoder { tokenizer = strings::tokenize(q, "&"), bufs = (memio::dynamic(), memio::dynamic()), }; // Frees resources associated with the [[query_decoder]]. export fn query_finish(dec: *query_decoder) void = { io::close(&dec.bufs.0)!; io::close(&dec.bufs.1)!; }; // Retrieves the next (key, value) pair from the query. The return value is // borrowed from the decoder and will be replaced on the next call, use // [[strings::dup]] to extend its lifetime. export fn query_next(dec: *query_decoder) ((str, str) | invalid | void) = { const tok = match (strings::next_token(&dec.tokenizer)) { case let s: str => yield s; case => return; }; const raw = strings::cut(tok, "="); memio::reset(&dec.bufs.0); percent_decode_static(&dec.bufs.0, raw.0)?; memio::reset(&dec.bufs.1); percent_decode_static(&dec.bufs.1, raw.1)?; return ( memio::string(&dec.bufs.0)!, memio::string(&dec.bufs.1)!, ); }; // Encodes (key, value) pairs into a URI query string. The result must be // freed by the caller. export fn encodequery(pairs: [](str, str)) str = { const buf = memio::dynamic(); for (let i = 0z; i < len(pairs); i += 1) { const pair = pairs[i]; if (i > 0) memio::appendrune(&buf, '&')!; assert(len(pair.0) > 0); percent_encode(&buf, pair.0, unres_query_frag)!; if (len(pair.1) > 0) { memio::appendrune(&buf, '=')!; percent_encode(&buf, pair.1, unres_query_frag)!; }; }; return memio::string(&buf)!; }; @test fn decodequery() void = { const u = parse("https://sr.ht/projects?search=%23risc-v&sort=longest-active&quantity=100%25")!; defer finish(&u); const query = decodequery(u.query); defer query_finish(&query); const pair = query_next(&query)! as (str, str); assert(pair.0 == "search"); assert(pair.1 == "#risc-v"); const pair = query_next(&query)! as (str, str); assert(pair.0 == "sort"); assert(pair.1 == "longest-active"); const pair = query_next(&query)! as (str, str); assert(pair.0 == "quantity"); assert(pair.1 == "100%"); }; @test fn encodequery() void = { const pairs = [ ("search", "#risc-v"), ("sort", "longest-active"), ("quantity", "100%") ]; const encoded = encodequery(pairs); defer free(encoded); assert(encoded == "search=%23risc-v&sort=longest-active&quantity=100%25"); }; hare-0.24.2/net/uri/uri.ha000066400000000000000000000016271464473310100152250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net::ip; use strings; // Representation of a parsed URI. export type uri = struct { scheme: str, host: (str | ip::addr), port: u16, userinfo: str, path: str, query: str, fragment: str, }; // Duplicates a [[uri]]. export fn dup(u: *uri) uri = { return uri { scheme = strings::dup(u.scheme), host = match (u.host) { case let host: str => yield strings::dup(host); case let ip: ip::addr => yield ip; }, port = u.port, userinfo = strings::dup(u.userinfo), path = strings::dup(u.path), query = strings::dup(u.query), fragment = strings::dup(u.fragment), }; }; // Frees resources associated with a [[uri]]. export fn finish(u: *uri) void = { free(u.scheme); match (u.host) { case let s: str => free(s); case => void; }; free(u.userinfo); free(u.path); free(u.query); free(u.fragment); }; hare-0.24.2/os/000077500000000000000000000000001464473310100131425ustar00rootroot00000000000000hare-0.24.2/os/+freebsd/000077500000000000000000000000001464473310100146275ustar00rootroot00000000000000hare-0.24.2/os/+freebsd/dirfdfs.ha000066400000000000000000000254711464473310100165730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; use time; use types::c; type os_filesystem = struct { fs: fs::fs, dirfd: int, getdents_bufsz: size, }; // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { let ofs = alloc(os_filesystem { ... }); let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; }; fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = { *filesystem = os_filesystem { fs = fs::fs { open = &fs_open, openfile = &fs_open_file, create = &fs_create, createfile = &fs_create_file, remove = &fs_remove, rename = &fs_rename, iter = &fs_iter, stat = &fs_stat, readlink = &fs_readlink, mkdir = &fs_mkdir, rmdir = &fs_rmdir, chmod = &fs_chmod, chown = &fs_chown, chtimes = &fs_chtimes, fchtimes = &fs_fchtimes, resolve = &fs_resolve, ... }, dirfd = fd, getdents_bufsz = 32768, // 32 KiB }; return &filesystem.fs; }; // Sets the buffer size to use with the getdents(2) system call, for use with // [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can // scan large directories faster. The default buffer size is 32 KiB. // // This function is not portable. export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; fs.getdents_bufsz = sz; }; // Returns an [[io::file]] for this filesystem. This function is not portable. export fn dirfile(fs: *fs::fs) io::file = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; return fs.dirfd; }; fn errno_to_fs(err: rt::errno) fs::error = { switch (err) { case rt::ENOENT => return errors::noentry; case rt::EEXIST => return errors::exists; case rt::EACCES => return errors::noaccess; case rt::EBUSY => return errors::busy; case rt::ENOTDIR => return fs::wrongtype; case rt::EOPNOTSUPP, rt::ENOSYS => return errors::unsupported; case rt::EXDEV => return fs::cannotrename; case => return errors::errno(err); }; }; fn _fs_open( fs: *fs::fs, path: str, flags: int, mode: uint, ) (io::file | fs::error) = { let fs = fs: *os_filesystem; let fd = match (rt::openat(fs.dirfd, path, flags, mode)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn fsflags_to_bsd(flags: fs::flag) (int | errors::unsupported) = { let out = rt::O_NOCTTY | rt::O_CLOEXEC; if (flags & fs::flag::WRONLY == fs::flag::WRONLY) { out |= rt::O_WRONLY; }; if (flags & fs::flag::RDWR == fs::flag::RDWR) { out |= rt::O_RDWR; }; if (flags & fs::flag::CREATE == fs::flag::CREATE) { out |= rt::O_CREAT; }; if (flags & fs::flag::EXCL == fs::flag::EXCL) { out |= rt::O_EXCL; }; if (flags & fs::flag::CTTY == fs::flag::CTTY) { out &= ~rt::O_NOCTTY; }; if (flags & fs::flag::TRUNC == fs::flag::TRUNC) { out |= rt::O_TRUNC; }; if (flags & fs::flag::APPEND == fs::flag::APPEND) { out |= rt::O_APPEND; }; if (flags & fs::flag::NONBLOCK == fs::flag::NONBLOCK) { out |= rt::O_NONBLOCK; }; if (flags & fs::flag::DSYNC == fs::flag::DSYNC) { out |= rt::O_DSYNC; }; if (flags & fs::flag::SYNC == fs::flag::SYNC) { out |= rt::O_SYNC; }; if (flags & fs::flag::RSYNC == fs::flag::RSYNC) { out |= rt::O_SYNC; }; if (flags & fs::flag::DIRECTORY == fs::flag::DIRECTORY) { out |= rt::O_DIRECTORY; }; if (flags & fs::flag::NOFOLLOW == fs::flag::NOFOLLOW) { out |= rt::O_NOFOLLOW; }; if (flags & fs::flag::NOCLOEXEC == fs::flag::NOCLOEXEC) { out &= ~rt::O_CLOEXEC; }; if (flags & fs::flag::PATH == fs::flag::PATH || flags & fs::flag::NOATIME == fs::flag::NOATIME || flags & fs::flag::TMPFILE == fs::flag::TMPFILE) { return errors::unsupported; }; return out; }; fn fs_open_file( fs: *fs::fs, path: str, flags: fs::flag, ) (io::file | fs::error) = { return _fs_open(fs, path, fsflags_to_bsd(flags)?, 0); }; fn fs_open( fs: *fs::fs, path: str, flags: fs::flag, ) (io::handle | fs::error) = fs_open_file(fs, path, flags)?; fn fs_create_file( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::file | fs::error) = { flags |= fs::flag::CREATE; return _fs_open(fs, path, fsflags_to_bsd(flags)?, mode)?; }; fn fs_create( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::handle | fs::error) = { return fs_create_file(fs, path, mode, flags)?; }; fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = { let fs = fs: *os_filesystem; let st = rt::st { ... }; match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; return fs::filestat { mask = fs::stat_mask::UID | fs::stat_mask::GID | fs::stat_mask::SIZE | fs::stat_mask::INODE | fs::stat_mask::ATIME | fs::stat_mask::MTIME | fs::stat_mask::CTIME, mode = st.mode: fs::mode, uid = st.uid, gid = st.gid, sz = st.sz: size, inode = st.ino, atime = time::instant { sec = st.atime.tv_sec, nsec = st.atime.tv_nsec, }, mtime = time::instant { sec = st.mtime.tv_sec, nsec = st.mtime.tv_nsec, }, ctime = time::instant { sec = st.ctime.tv_sec, nsec = st.ctime.tv_nsec, }, }; }; fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = { let fs = fs: *os_filesystem; static let buf: [rt::PATH_MAX]u8 = [0...]; let z = match (rt::readlinkat(fs.dirfd, path, buf[..])) { case let err: rt::errno => switch (err) { case rt::EINVAL => return fs::wrongtype; case => return errno_to_fs(err); }; case let z: size => yield z; }; return strings::fromutf8(buf[..z])!; }; fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_mkdir(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::mkdirat(fs.dirfd, path, mode: uint)) { case let err: rt::errno => switch (err) { case rt::EISDIR => return errors::exists; case => return errno_to_fs(err); }; case void => void; }; }; fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = { match (rt::fchmod(fd, mode: uint)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = { match (rt::fchown(fd, uid, gid)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn instant_to_timespec(time: (time::instant | void)) rt::timespec = { match (time) { case let t: time::instant => return time::instant_to_timespec(t); case void => return rt::timespec{ tv_sec = rt::UTIME_OMIT, tv_nsec = rt::UTIME_OMIT }; }; }; fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; let fs = fs: *os_filesystem; match (rt::utimensat(fs.dirfd, path, &utimes, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchtimes(fd: io::file, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; match (rt::futimens(fd, &utimes)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_resolve(fs: *fs::fs, path: str) str = { if (path::abs(path)) { return path; }; // XXX: This approach might not be right if this fs is based on a subdir static let buf = path::buffer { ... }; path::set(&buf, getcwd(), path)!; return path::string(&buf); }; fn fs_close(fs: *fs::fs) void = { let fs = fs: *os_filesystem; rt::close(fs.dirfd)!; }; // Based on musl's readdir type os_iterator = struct { iter: fs::iterator, fd: int, buf_pos: size, buf_end: size, buf: []u8, }; fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { let fs = fs: *os_filesystem; let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY; let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => return errors::nomem; }; let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, finish = &iter_finish, }, fd = fd, buf = buf[..fs.getdents_bufsz], ... }); return &iter.iter; }; fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = { let iter = iter: *os_iterator; if (iter.buf_pos >= iter.buf_end) { let n = match (rt::getdents(iter.fd, iter.buf: *[*]u8, len(iter.buf))) { case let err: rt::errno => return errno_to_fs(err); case let n: size => yield n; }; if (n == 0) { return done; }; iter.buf_end = n; iter.buf_pos = 0; }; let de = &iter.buf[iter.buf_pos]: *rt::freebsd11_dirent; iter.buf_pos += de.d_reclen; let name = c::tostr(&de.d_name: *const c::char)?; if (name == "." || name == "..") { return iter_next(iter); }; let ftype: fs::mode = switch (de.d_type) { case rt::DT_UNKNOWN => yield fs::mode::UNKNOWN; case rt::DT_FIFO => yield fs::mode::FIFO; case rt::DT_CHR => yield fs::mode::CHR; case rt::DT_DIR => yield fs::mode::DIR; case rt::DT_BLK => yield fs::mode::BLK; case rt::DT_REG => yield fs::mode::REG; case rt::DT_LNK => yield fs::mode::LINK; case rt::DT_SOCK => yield fs::mode::SOCK; case => yield fs::mode::UNKNOWN; }; return fs::dirent { name = name, ftype = ftype, }; }; fn iter_finish(iter: *fs::iterator) void = { let iter = iter: *os_iterator; rt::close(iter.fd)!; free(iter.buf); free(iter); }; hare-0.24.2/os/+freebsd/exit+libc-test.ha000066400000000000000000000002661464473310100200000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export @symbol("exit") fn exit(status: int) never; hare-0.24.2/os/+freebsd/exit+test.ha000066400000000000000000000003221464473310100170620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export fn exit(status: int) never = { abort("os::exit disabled in +test"); }; hare-0.24.2/os/+freebsd/exit.ha000066400000000000000000000003251464473310100161120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Exit the program with the provided status code. export fn exit(status: int) never = { rt::fini(); rt::exit(status); }; hare-0.24.2/os/+freebsd/fs.ha000066400000000000000000000042561464473310100155600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; use types::c; @init fn init_cwd() void = { static let cwd_fs = os_filesystem { ... }; cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); }; // Returns the current working directory. The return value is statically // allocated and must be duplicated (see [[strings::dup]]) before calling getcwd // again. export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; // Change the current working directory. export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { const path: str = match (target) { case let fs: *fs::fs => assert(fs.open == &fs_open); let fs = fs: *os_filesystem; match (rt::fchdir(fs.dirfd)) { case let err: rt::errno => return errno_to_fs(err); case void => return; }; case let s: str => yield s; }; match (rt::chdir(path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Changes the root directory of the process. Generally requires the caller to // have root or otherwise elevated permissions. // // This function is not appropriate for sandboxing. export fn chroot(target: str) (void | fs::error) = { match (rt::chroot(target)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Access modes for [[access]]. export type amode = enum int { F_OK = rt::F_OK, R_OK = rt::R_OK, W_OK = rt::W_OK, X_OK = rt::X_OK, }; // Returns true if the given mode of access is permissible. The use of this // function is discouraged as it can allow for a race condition to occur betwen // testing for the desired access mode and actually using the file should the // permissions of the file change between these operations. It is recommended // instead to attempt to use the file directly and to handle any errors that // should occur at that time. export fn access(path: str, mode: amode) (bool | fs::error) = { match (rt::access(path, mode)) { case let b: bool => return b; case let err: rt::errno => return errno_to_fs(err); }; }; // TODO: FreeBSD // export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { // export fn mkblk( // export fn mkchr( // export fn mkfile( hare-0.24.2/os/+freebsd/memfd.ha000066400000000000000000000020571464473310100162350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags for [[memfd]]. export type memfd_flag = enum uint { NONE = 0, // Unsets the close-on-exec flag when creating a memfd. NOCLOEXEC = 1, // ALlows sealing operations on this file. ALLOW_SEALING = 2, }; // Creates a new anonyomous [[io::file]] backed by memory. // // The initial file size is zero. It can be written to normally, or the size can // be set manually with [[trunc]]. // // This function is available on Linux and FreeBSD. export fn memfd( name: str, flags: memfd_flag = memfd_flag::NONE, ) (io::file | errors::error) = { let oflag = rt::O_RDWR | rt::O_CLOEXEC; let shm_flag = rt::SHM_GROW_ON_WRITE; if (flags & memfd_flag::NOCLOEXEC != 0) { oflag &= ~rt::O_CLOEXEC; }; if (flags & memfd_flag::ALLOW_SEALING != 0) { shm_flag |= rt::SHM_ALLOW_SEALING; }; match (rt::shm_open(rt::SHM_ANON, oflag, 0, shm_flag, name)) { case let fd: int => return fd: io::file; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/os/+freebsd/platform_environ.ha000066400000000000000000000056521464473310100205350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use strings; use types::c; // The command line arguments provided to the program. By convention, the first // member is usually the name of the program. export let args: []str = []; // Statically allocate arg strings if there are few enough arguments, saves a // syscall if we don't need it. let args_static: [32]str = [""...]; @init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { args = alloc([], rt::argc); for (let i = 0z; i < rt::argc; i += 1) { append(args, c::tostr(rt::argv[i]: *const c::char)!); }; }; }; @fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; }; // Returns a slice of the environment strings in the form KEY=VALUE. export fn getenvs() []str = { if (len(envp) != 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; append(envp, strings::dup(s)); }; return envp; }; // Returns the host kernel name export fn sysname() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctlbyname("kern.ostype", &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host system hostname export fn hostname() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctlbyname("kern.hostname", &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host kernel version export fn release() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctlbyname("kern.osrelease", &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host operating system version export fn version() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctlbyname("kern.version", &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host CPU architecture, in a platform-specific format. See // [[architecture]] for a more portable wrapper. export fn machine() const str = { static let buf: [32]u8 = [0...]; let sz: size = len(buf); rt::sysctlbyname("hw.machine", &buf, &sz, null, 0)!; return strings::fromutf8(buf[..sz - 1])!; }; // Returns the host CPU architecture. export fn architecture() arch = { switch (machine()) { case "aarch64" => return arch::AARCH64; case "riscv64" => return arch::RISCV64; case "amd64" => return arch::X86_64; case => abort(); // unreachable }; }; // Returns the number of usable CPUs. export fn cpucount() (size | errors::error) = { let count = 0; let length = size(int); match (rt::sysctlbyname("hw.ncpu", &count, &length, null, 0)) { case void => void; case let err: rt::errno => return errors::errno(err); }; return count: size; }; hare-0.24.2/os/+freebsd/shm.ha000066400000000000000000000046661464473310100157440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; fn shm_path(name: str) (str | fs::error) = { const name = strings::ltrim(name, '/'); if (len(name) > rt::NAME_MAX) { return errors::invalid; }; if (name == "." || name == "..") { return errors::invalid; }; static let buf = path::buffer { ... }; path::set(&buf, "/", name)!; return path::string(&buf); }; // Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file // with the given name, suitable for use with [[io::mmap]] to establish shared // memory areas with other processes using the same name. // // The name must not contain any forward slashes (one is permissible at the // start, e.g. "/example") and cannot be "." or "..". // // The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]] // or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]], // [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], which are supported on all // POSIX-compatible platforms. Other platforms may support additional // non-standard flags; consult the shm_open(3) manual for your target system for // details. // // The new file descriptor always has CLOEXEC set regardless of the provided // flags. If creating a new shared memory object, set its initial size with // [[io::trunc]] before mapping it with [[io::mmap]]. // // Call [[shm_unlink]] to remove the global shared memory object. export fn shm_open( name: str, oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR, mode: fs::mode = 0o600, ) (io::file | fs::error) = { const path = shm_path(name)?; def VALID_FLAGS: int = rt::O_RDWR | rt::O_CREAT | rt::O_EXCL | rt::O_TRUNC; const oflag = (fsflags_to_bsd(oflag)? & VALID_FLAGS) | rt::O_CLOEXEC; match (rt::shm_open(path, oflag, mode: rt::mode_t, 0, null: *const u8)) { case let fd: int => return fd: io::file; case let err: rt::errno => return errors::errno(err): fs::error; }; }; // Removes the shared memory object with the given name. Processes which already // hold a reference to the file may continue to use the memory associated with // it. Once all processes have unmapped the associated shared memory object, or // exited, the memory is released. export fn shm_unlink(name: str) (void | fs::error) = { const path = shm_path(name)?; match (rt::shm_unlink(path)) { case let err: rt::errno => return errors::errno(err): fs::error; case void => return; }; }; hare-0.24.2/os/+freebsd/status.ha000066400000000000000000000003711464473310100164650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Values that may be passed to [[exit]] to indicate successful or unsuccessful // termination, respectively. export type status = enum { SUCCESS = 0, FAILURE = 1, }; hare-0.24.2/os/+freebsd/stdfd.ha000066400000000000000000000031021464473310100162410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use rt; let stdin_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 0, ... }; let stdout_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 1, ... }; // The standard input. This handle is buffered. export let stdin: io::handle = rt::STDIN_FILENO; // initialized by init_stdfd // The standard input, as an [[io::file]]. This handle is unbuffered. export let stdin_file: io::file = rt::STDIN_FILENO; // The standard output. This handle is buffered. export let stdout: io::handle = rt::STDOUT_FILENO; // initialized by init_stdfd // The standard output, as an [[io::file]]. This handle is unbuffered. export let stdout_file: io::file = rt::STDOUT_FILENO; // The standard error. This handle is unbuffered. export let stderr: io::handle = rt::STDERR_FILENO; // The standard error, as an [[io::file]]. This handle is unbuffered. export let stderr_file: io::file = rt::STDERR_FILENO; // The recommended buffer size for reading from disk. export def BUFSZ: size = 4096; // 4 KiB @init fn init_stdfd() void = { static let stdinbuf: [BUFSZ]u8 = [0...]; stdin_bufio = bufio::init(stdin_file, stdinbuf, []); stdin = &stdin_bufio; static let stdoutbuf: [BUFSZ]u8 = [0...]; stdout_bufio = bufio::init(stdout_file, [], stdoutbuf); stdout = &stdout_bufio; }; @fini fn fini_stdfd() void = { // Flush any pending writes io::close(stdout): void; }; hare-0.24.2/os/+linux/000077500000000000000000000000001464473310100143545ustar00rootroot00000000000000hare-0.24.2/os/+linux/dirfdfs.ha000066400000000000000000000305401464473310100163110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; use time; use types::c; // Controls how symlinks are followed (or not) in a dirfd filesystem. Support // for this feature varies, you should gate usage of this enum behind a build // tag. // // Note that on Linux, specifying BENEATH or IN_ROOT will also disable magic // symlinks. export type resolve_flag = enum u64 { NORMAL = 0, // Does not allow symlink resolution to occur for any symlinks which // would refer to any anscestor of the fd directory. This disables all // absolute symlinks, and any call to open or create with an absolute // path. BENEATH = rt::RESOLVE_BENEATH | rt::RESOLVE_NO_MAGICLINKS, // Treat the directory fd as the root directory. This affects // open/create for absolute paths, as well as absolute path resolution // of symlinks. The effects are similar to chroot. IN_ROOT = rt::RESOLVE_IN_ROOT | rt::RESOLVE_NO_MAGICLINKS, // Disables symlink resolution entirely. NO_SYMLINKS = rt::RESOLVE_NO_SYMLINKS, // Disallows traversal of mountpoints during path resolution. This is // not recommended for general use, as bind mounts are extensively used // on many systems. NO_XDEV = rt::RESOLVE_NO_XDEV, }; type os_filesystem = struct { fs: fs::fs, dirfd: int, resolve: resolve_flag, getdents_bufsz: size, }; // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen( fd: io::file, resolve_flags: resolve_flag = resolve_flag::NORMAL, ) *fs::fs = { let ofs = alloc(os_filesystem { resolve = resolve_flags, ... }); let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; }; fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = { *filesystem = os_filesystem { fs = fs::fs { open = &fs_open, openfile = &fs_open_file, create = &fs_create, createfile = &fs_create_file, remove = &fs_remove, rename = &fs_rename, iter = &fs_iter, stat = &fs_stat, fstat = &fs_fstat, readlink = &fs_readlink, mkdir = &fs_mkdir, rmdir = &fs_rmdir, chmod = &fs_chmod, fchmod = &fs_fchmod, chown = &fs_chown, fchown = &fs_fchown, chtimes = &fs_chtimes, fchtimes = &fs_fchtimes, resolve = &fs_resolve, link = &fs_link, symlink = &fs_symlink, ... }, dirfd = fd, getdents_bufsz = 32768, // 32 KiB ... }; return &filesystem.fs; }; // Clones a dirfd filesystem, optionally adding additional [[resolve_flag]] // constraints. export fn dirfs_clone( fs: *fs::fs, resolve_flags: resolve_flag = resolve_flag::NORMAL, ) *fs::fs = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; let new = alloc(*fs); fs.resolve |= resolve_flags; new.dirfd = rt::fcntl(new.dirfd, rt::F_DUPFD_CLOEXEC, 0) as int; return &new.fs; }; // Sets the buffer size to use with the getdents(2) system call, for use with // [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can // scan large directories faster. The default buffer size is 32 KiB. // // This function is not portable. export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; fs.getdents_bufsz = sz; }; // Returns an [[io::file]] for this filesystem. This function is not portable. export fn dirfile(fs: *fs::fs) io::file = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; return fs.dirfd; }; fn errno_to_fs(err: rt::errno) fs::error = { switch (err) { case rt::ENOENT => return errors::noentry; case rt::EEXIST => return errors::exists; case rt::EACCES => return errors::noaccess; case rt::EBUSY => return errors::busy; case rt::ENOTDIR => return fs::wrongtype; case rt::EOPNOTSUPP, rt::ENOSYS => return errors::unsupported; case rt::EXDEV => return fs::cannotrename; case => return errors::errno(err); }; }; fn _fs_open( fs: *fs::fs, path: str, oh: *rt::open_how, ) (io::file | fs::error) = { let fs = fs: *os_filesystem; oh.resolve = fs.resolve; let fd = match (rt::openat2(fs.dirfd, path, oh, size(rt::open_how))) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn fs_open_file( fs: *fs::fs, path: str, flags: fs::flag, ) (io::file | fs::error) = { flags ^= fs::flag::CTTY | fs::flag::NOCLOEXEC; // invert NOCTTY/CLOEXEC if ((flags & fs::flag::DIRECTORY) == fs::flag::DIRECTORY) { // This is arch-specific flags &= ~fs::flag::DIRECTORY; flags |= rt::O_DIRECTORY: fs::flag; }; let oh = rt::open_how { flags = flags: u64, ... }; return _fs_open(fs, path, &oh); }; fn fs_open( fs: *fs::fs, path: str, flags: fs::flag, ) (io::handle | fs::error) = fs_open_file(fs, path, flags)?; fn fs_create_file( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::file | fs::error) = { flags ^= fs::flag::CTTY | fs::flag::NOCLOEXEC; // invert NOCTTY/CLOEXEC flags |= fs::flag::CREATE; let oh = rt::open_how { flags = flags: u64, mode = mode: u64, ... }; return _fs_open(fs, path, &oh)?; }; fn fs_create( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::handle | fs::error) = { return fs_create_file(fs, path, mode, flags)?; }; fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = { let fs = fs: *os_filesystem; let st = rt::st { ... }; match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; return st_to_filestat(&st); }; fn fs_fstat(fs: *fs::fs, fd: io::file) (fs::filestat | fs::error) = { let fs = fs: *os_filesystem; let st = rt::st { ... }; match (rt::fstatat(fd, "", &st, rt::AT_EMPTY_PATH)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; return st_to_filestat(&st); }; fn st_to_filestat(st: *rt::st) fs::filestat = { return fs::filestat { mask = fs::stat_mask::UID | fs::stat_mask::GID | fs::stat_mask::SIZE | fs::stat_mask::INODE | fs::stat_mask::ATIME | fs::stat_mask::MTIME | fs::stat_mask::CTIME, mode = st.mode: fs::mode, uid = st.uid, gid = st.gid, sz = st.sz, inode = st.ino, atime = time::instant { sec = st.atime.tv_sec, nsec = st.atime.tv_nsec, }, mtime = time::instant { sec = st.mtime.tv_sec, nsec = st.mtime.tv_nsec, }, ctime = time::instant { sec = st.ctime.tv_sec, nsec = st.ctime.tv_nsec, }, }; }; fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = { let fs = fs: *os_filesystem; static let buf: [rt::PATH_MAX]u8 = [0...]; let z = match (rt::readlinkat(fs.dirfd, path, buf[..])) { case let err: rt::errno => switch (err) { case rt::EINVAL => return fs::wrongtype; case => return errno_to_fs(err); }; case let z: size => yield z; }; return strings::fromutf8(buf[..z])!; }; fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_mkdir(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::mkdirat(fs.dirfd, path, mode: uint)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = { match (rt::fchmod(fd, mode: uint)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = { match (rt::fchown(fd, uid, gid)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn instant_to_timespec(time: (time::instant | void)) rt::timespec = { match (time) { case let t: time::instant => return time::instant_to_timespec(t); case void => return rt::timespec{ tv_sec = rt::UTIME_OMIT, tv_nsec = rt::UTIME_OMIT }; }; }; fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; let fs = fs: *os_filesystem; match (rt::utimensat(fs.dirfd, path, &utimes, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchtimes(fd: io::file, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; match (rt::futimens(fd, &utimes)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_resolve(fs: *fs::fs, path: str) str = { if (path::abs(path)) { return path; }; // XXX: This approach might not be right if this fs is based on a subdir static let buf = path::buffer { ... }; path::set(&buf, getcwd(), path)!; return path::string(&buf); }; fn fs_link(fs: *fs::fs, old: str, new: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::linkat(fs.dirfd, old, fs.dirfd, new, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_symlink(fs: *fs::fs, target: str, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::symlinkat(target, fs.dirfd, path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_close(fs: *fs::fs) void = { let fs = fs: *os_filesystem; rt::close(fs.dirfd)!; free(fs); }; // Based on musl's readdir type os_iterator = struct { iter: fs::iterator, fd: int, buf_pos: size, buf_end: size, buf: []u8, }; fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { let fs = fs: *os_filesystem; let oh = rt::open_how { flags = (rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY): u64, ... }; let fd: int = match (rt::openat2(fs.dirfd, path, &oh, size(rt::open_how))) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => return errors::nomem; }; let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, finish = &iter_finish, }, fd = fd, buf = buf[..fs.getdents_bufsz], ... }); return &iter.iter; }; fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = { let iter = iter: *os_iterator; if (iter.buf_pos >= iter.buf_end) { let n = match (rt::getdents64(iter.fd, iter.buf: *[*]u8, len(iter.buf))) { case let err: rt::errno => return errno_to_fs(err); case let n: size => yield n; }; if (n == 0) { return done; }; iter.buf_end = n; iter.buf_pos = 0; }; let de = &iter.buf[iter.buf_pos]: *rt::dirent64; iter.buf_pos += de.d_reclen; let name = c::tostr(&de.d_name: *const c::char)?; if (name == "." || name == "..") { return iter_next(iter); }; let ftype: fs::mode = switch (de.d_type) { case rt::DT_UNKNOWN => yield fs::mode::UNKNOWN; case rt::DT_FIFO => yield fs::mode::FIFO; case rt::DT_CHR => yield fs::mode::CHR; case rt::DT_DIR => yield fs::mode::DIR; case rt::DT_BLK => yield fs::mode::BLK; case rt::DT_REG => yield fs::mode::REG; case rt::DT_LNK => yield fs::mode::LINK; case rt::DT_SOCK => yield fs::mode::SOCK; case => yield fs::mode::UNKNOWN; }; return fs::dirent { name = name, ftype = ftype, }; }; fn iter_finish(iter: *fs::iterator) void = { let iter = iter: *os_iterator; rt::close(iter.fd)!; free(iter.buf); free(iter); }; hare-0.24.2/os/+linux/exit+libc-test.ha000066400000000000000000000002661464473310100175250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export @symbol("exit") fn exit(status: int) never; hare-0.24.2/os/+linux/exit+test.ha000066400000000000000000000003221464473310100166070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export fn exit(status: int) never = { abort("os::exit disabled in +test"); }; hare-0.24.2/os/+linux/exit.ha000066400000000000000000000003251464473310100156370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Exit the program with the provided status code. export fn exit(status: int) never = { rt::fini(); rt::exit(status); }; hare-0.24.2/os/+linux/fs.ha000066400000000000000000000112131464473310100152740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use rt; use types::c; export type setxattr_flag = enum int { NONE = 0, XATTR_CREATE = 0x1, XATTR_REPLACE = 0x2, }; @init fn init_cwd() void = { static let cwd_fs = os_filesystem { ... }; cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); }; // Returns the current working directory. The return value is statically // allocated and must be duplicated (see [[strings::dup]]) before calling getcwd // again. export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; // Change the current working directory. export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { const path: str = match (target) { case let fs: *fs::fs => assert(fs.open == &fs_open); let fs = fs: *os_filesystem; match (rt::fchdir(fs.dirfd)) { case let err: rt::errno => return errno_to_fs(err); case void => return; }; case let s: str => yield s; }; match (rt::chdir(path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Changes the root directory of the process. Generally requires the caller to // have root or otherwise elevated permissions. // // This function is not appropriate for sandboxing. export fn chroot(target: str) (void | fs::error) = { match (rt::chroot(target)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Makes a FIFO node. This function is only available on Unix systems. export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFIFO, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Makes a block device node. This function is only available on Unix-like // systems. export fn mkblk( path: str, mode: fs::mode, major: uint, minor: uint, ) (void | fs::error) = { match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFBLK, rt::mkdev(major: u32, minor: u32))) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Makes a character device node. This function is only available on Unix-like // systems. export fn mkchr( path: str, mode: fs::mode, major: uint, minor: uint, ) (void | fs::error) = { match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFCHR, rt::mkdev(major: u32, minor: u32))) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Makes a regular file. This function is only available on Unix-like systems. // This function should only be used if you have a special reason; most of the // time you should use [[create]] instead. export fn mkfile(path: str, mode: fs::mode) (void | fs::error) = { match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFREG, 0)) { case let err: rt::errno => return errors::errno(err); case void => void; }; }; // Access modes for [[access]]. export type amode = enum int { F_OK = rt::F_OK, R_OK = rt::R_OK, W_OK = rt::W_OK, X_OK = rt::X_OK, }; // Returns true if the given mode of access is permissible. The use of this // function is discouraged as it can allow for a race condition to occur betwen // testing for the desired access mode and actually using the file should the // permissions of the file change between these operations. It is recommended // instead to attempt to use the file directly and to handle any errors that // should occur at that time. export fn access(path: str, mode: amode) (bool | fs::error) = { match (rt::access(path, mode)) { case let b: bool => return b; case let err: rt::errno => return errno_to_fs(err); }; }; // Sets an extended file attribute. export fn setxattr( path: str, name: str, value: []u8, flags: setxattr_flag = setxattr_flag::NONE, ) (void | fs::error) = { match (rt::setxattr(path, name, value, flags)) { case let err: rt::errno => return errno_to_fs(err); case void => return void; }; }; // Gets an extended file attribute. // The caller is responsible for freeing the returned slice. export fn getxattr(path: str, name: str) ([]u8 | fs::error) = { let empty: []u8 = []; let attr_size = match (rt::getxattr(path, name, empty)) { case let err: rt::errno => return errno_to_fs(err); case let s: u64 => yield s; }; let buf: []u8 = alloc([0...], attr_size); match (rt::getxattr(path, name, buf)) { case let err: rt::errno => return errno_to_fs(err); case let s: u64 => return buf; }; }; // Removes an extended file attribute. export fn removexattr(path: str, name: str) (void | fs::error) = { match (rt::removexattr(path, name)) { case let err: rt::errno => return errno_to_fs(err); case void => return void; }; }; hare-0.24.2/os/+linux/memfd.ha000066400000000000000000000017121464473310100157570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags for [[memfd]]. export type memfd_flag = enum uint { NONE = 0, // Unsets the close-on-exec flag when creating a memfd. NOCLOEXEC = rt::MFD_CLOEXEC, // ALlows sealing operations on this file. ALLOW_SEALING = rt::MFD_ALLOW_SEALING, // Create the memfd with huge pages using hugetlbfs. Linux-only. HUGETLB = rt::MFD_HUGETLB, }; // Creates a new anonyomous [[io::file]] backed by memory. // // The initial file size is zero. It can be written to normally, or the size can // be set manually with [[trunc]]. // // This function is available on Linux and FreeBSD. export fn memfd( name: str, flags: memfd_flag = memfd_flag::NONE, ) (io::file | errors::error) = { flags ^= memfd_flag::NOCLOEXEC; match (rt::memfd_create(name, flags: uint)) { case let i: int => return i: io::file; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/os/+linux/memory.ha000066400000000000000000000024161464473310100162010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: Implement FreeBSD version use errors; use rt; // Flags for the [[mlock]] family of operations. export type mcl = enum uint { CURRENT = 1, FUTURE = 2, ONFAULT = 4, }; // Locks a region of memory so that it will not be written to swap. export fn mlock( addr: *opaque, length: size, flags: mcl, ) (void | errors::error) = { match (rt::mlock2(addr, length, flags)) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; // Unlocks memory previously locked with [[mlock]]. export fn munlock(addr: *opaque, length: size) (void | errors::error) = { match (rt::munlock(addr, length)) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; // Locks the entire process's address space so that it will not be written to // swap. export fn mlockall(flags: mcl) (void | errors::error) = { match (rt::mlockall(flags)) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; // Unlocks all locked memory in the process's address space. export fn munlockall() (void | errors::error) = { match (rt::munlockall()) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; hare-0.24.2/os/+linux/platform_environ.ha000066400000000000000000000056171464473310100202630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use math; use rt; use strings; use types::c; // The command line arguments provided to the program. By convention, the first // member is usually the name of the program. export let args: []str = []; // Statically allocate arg strings if there are few enough arguments, saves a // syscall if we don't need it. let args_static: [32]str = [""...]; @init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { args = alloc([], rt::argc); for (let i = 0z; i < rt::argc; i += 1) { append(args, c::tostr(rt::argv[i]: *const c::char)!); }; }; }; @fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; }; // Returns a slice of the environment strings in the form KEY=VALUE. export fn getenvs() []str = { if (len(envp) != 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; append(envp, strings::dup(s)); }; return envp; }; let uts: rt::utsname = rt::utsname { ... }; let uts_valid: bool = false; // Returns the host kernel name export fn sysname() const str = { if (!uts_valid) { rt::uname(&uts) as void; uts_valid = true; }; return c::tostr(&uts.sysname: *const c::char)!; }; // Returns the host system hostname export fn hostname() const str = { if (!uts_valid) { rt::uname(&uts) as void; uts_valid = true; }; return c::tostr(&uts.nodename: *const c::char)!; }; // Returns the host kernel version export fn release() const str = { if (!uts_valid) { rt::uname(&uts) as void; uts_valid = true; }; return c::tostr(&uts.release: *const c::char)!; }; // Returns the host operating system version export fn version() const str = { if (!uts_valid) { rt::uname(&uts) as void; uts_valid = true; }; return c::tostr(&uts.version: *const c::char)!; }; // Returns the host CPU architecture, in a platform-specific format. See // [[architecture]] for a more portable wrapper. export fn machine() const str = { if (!uts_valid) { rt::uname(&uts) as void; uts_valid = true; }; return c::tostr(&uts.machine: *const c::char)!; }; // Returns the host CPU architecture. export fn architecture() arch = { switch (machine()) { case "aarch64" => return arch::AARCH64; case "riscv64" => return arch::RISCV64; case "x86_64" => return arch::X86_64; case => abort(); // unreachable }; }; // Returns the number of usable CPUs. export fn cpucount() (size | errors::error) = { let set = rt::cpu_set { ... }; match (rt::sched_getaffinity(rt::getpid(), size(rt::cpu_set), &set)) { case void => void; case let err: rt::errno => return errors::errno(err); }; let ret = 0z; for (let i = 0z; i < len(set.__bits); i += 1) { ret += math::popcount(set.__bits[i]); }; return ret; }; hare-0.24.2/os/+linux/shm.ha000066400000000000000000000040161464473310100154560ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; def SHM_PATH: str = "/dev/shm/"; fn shm_path(name: str) (str | fs::error) = { const name = strings::ltrim(name, '/'); if (len(name) > rt::NAME_MAX) { return errors::invalid; }; if (name == "." || name == "..") { return errors::invalid; }; static let buf = path::buffer { ... }; path::set(&buf, SHM_PATH, name)!; return path::string(&buf); }; // Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file // with the given name, suitable for use with [[io::mmap]] to establish shared // memory areas with other processes using the same name. // // The name must not contain any forward slashes (one is permissible at the // start, e.g. "/example") and cannot be "." or "..". // // The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]] // or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]], // [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], other flags are silently // ignored if set. // // The new file descriptor always has CLOEXEC set regardless of the provided // flags. If creating a new shared memory object, set its initial size with // [[io::trunc]] before mapping it with [[io::mmap]]. // // Call [[shm_unlink]] to remove the global shared memory object. export fn shm_open( name: str, oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR, mode: fs::mode = 0o600, ) (io::file | fs::error) = { const path = shm_path(name)?; oflag |= fs::flag::NOFOLLOW | fs::flag::NONBLOCK; oflag &= ~fs::flag::NOCLOEXEC; // Unconditionally set CLOEXEC return create(path, mode, oflag); }; // Removes the shared memory object with the given name. Processes which already // hold a reference to the file may continue to use the memory associated with // it. Once all processes have unmapped the associated shared memory object, or // exited, the memory is released. export fn shm_unlink(name: str) (void | fs::error) = { return remove(shm_path(name)?); }; hare-0.24.2/os/+linux/status.ha000066400000000000000000000003711464473310100162120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Values that may be passed to [[exit]] to indicate successful or unsuccessful // termination, respectively. export type status = enum { SUCCESS = 0, FAILURE = 1, }; hare-0.24.2/os/+linux/stdfd.ha000066400000000000000000000031021464473310100157660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use rt; let stdin_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 0, ... }; let stdout_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 1, ... }; // The standard input. This handle is buffered. export let stdin: io::handle = rt::STDIN_FILENO; // initialized by init_stdfd // The standard input, as an [[io::file]]. This handle is unbuffered. export let stdin_file: io::file = rt::STDIN_FILENO; // The standard output. This handle is buffered. export let stdout: io::handle = rt::STDOUT_FILENO; // initialized by init_stdfd // The standard output, as an [[io::file]]. This handle is unbuffered. export let stdout_file: io::file = rt::STDOUT_FILENO; // The standard error. This handle is unbuffered. export let stderr: io::handle = rt::STDERR_FILENO; // The standard error, as an [[io::file]]. This handle is unbuffered. export let stderr_file: io::file = rt::STDERR_FILENO; // The recommended buffer size for reading from disk. export def BUFSZ: size = 4096; // 4 KiB @init fn init_stdfd() void = { static let stdinbuf: [BUFSZ]u8 = [0...]; stdin_bufio = bufio::init(stdin_file, stdinbuf, []); stdin = &stdin_bufio; static let stdoutbuf: [BUFSZ]u8 = [0...]; stdout_bufio = bufio::init(stdout_file, [], stdoutbuf); stdout = &stdout_bufio; }; @fini fn fini_stdfd() void = { // Flush any pending writes io::close(stdout): void; }; hare-0.24.2/os/+netbsd/000077500000000000000000000000001464473310100144745ustar00rootroot00000000000000hare-0.24.2/os/+netbsd/dirfdfs.ha000066400000000000000000000257651464473310100164460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; use time; use types::c; type os_filesystem = struct { fs: fs::fs, dirfd: int, getdents_bufsz: size, }; // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { let ofs = alloc(os_filesystem { ... }); let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; }; fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = { *filesystem = os_filesystem { fs = fs::fs { open = &fs_open, openfile = &fs_open_file, create = &fs_create, createfile = &fs_create_file, remove = &fs_remove, rename = &fs_rename, iter = &fs_iter, stat = &fs_stat, readlink = &fs_readlink, mkdir = &fs_mkdir, rmdir = &fs_rmdir, chmod = &fs_chmod, chown = &fs_chown, chtimes = &fs_chtimes, fchtimes = &fs_fchtimes, resolve = &fs_resolve, ... }, dirfd = fd, getdents_bufsz = 32768, // 32 KiB }; return &filesystem.fs; }; // Sets the buffer size to use with the getdents(2) system call, for use with // [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can // scan large directories faster. The default buffer size is 32 KiB. // // This function is not portable. export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; fs.getdents_bufsz = sz; }; // Returns an [[io::file]] for this filesystem. This function is not portable. export fn dirfile(fs: *fs::fs) io::file = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; return fs.dirfd; }; fn errno_to_fs(err: rt::errno) fs::error = { switch (err) { case rt::ENOENT => return errors::noentry; case rt::EEXIST => return errors::exists; case rt::EACCES => return errors::noaccess; case rt::EBUSY => return errors::busy; case rt::ENOTDIR => return fs::wrongtype; case rt::EOPNOTSUPP, rt::ENOSYS => return errors::unsupported; case rt::EXDEV => return fs::cannotrename; case => return errors::errno(err); }; }; fn _fs_open( fs: *fs::fs, path: str, flags: int, mode: uint, ) (io::file | fs::error) = { let fs = fs: *os_filesystem; let fd = match (rt::openat(fs.dirfd, path, flags, mode)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn fsflags_to_bsd(flags: fs::flag) (int | errors::unsupported) = { let out = rt::O_NOCTTY | rt::O_CLOEXEC; if (flags & fs::flag::WRONLY == fs::flag::WRONLY) { out |= rt::O_WRONLY; }; if (flags & fs::flag::RDWR == fs::flag::RDWR) { out |= rt::O_RDWR; }; if (flags & fs::flag::CREATE == fs::flag::CREATE) { out |= rt::O_CREAT; }; if (flags & fs::flag::EXCL == fs::flag::EXCL) { out |= rt::O_EXCL; }; if (flags & fs::flag::CTTY == fs::flag::CTTY) { out &= ~rt::O_NOCTTY; }; if (flags & fs::flag::TRUNC == fs::flag::TRUNC) { out |= rt::O_TRUNC; }; if (flags & fs::flag::APPEND == fs::flag::APPEND) { out |= rt::O_APPEND; }; if (flags & fs::flag::NONBLOCK == fs::flag::NONBLOCK) { out |= rt::O_NONBLOCK; }; if (flags & fs::flag::DSYNC == fs::flag::DSYNC) { out |= rt::O_DSYNC; }; if (flags & fs::flag::SYNC == fs::flag::SYNC) { out |= rt::O_SYNC; }; if (flags & fs::flag::RSYNC == fs::flag::RSYNC) { out |= rt::O_SYNC; }; if (flags & fs::flag::DIRECTORY == fs::flag::DIRECTORY) { out |= rt::O_DIRECTORY; }; if (flags & fs::flag::NOFOLLOW == fs::flag::NOFOLLOW) { out |= rt::O_NOFOLLOW; }; if (flags & fs::flag::NOCLOEXEC == fs::flag::NOCLOEXEC) { out &= ~rt::O_CLOEXEC; }; if (flags & fs::flag::PATH == fs::flag::PATH || flags & fs::flag::NOATIME == fs::flag::NOATIME || flags & fs::flag::TMPFILE == fs::flag::TMPFILE) { return errors::unsupported; }; return out; }; fn fs_open_file( fs: *fs::fs, path: str, flags: fs::flag, ) (io::file | fs::error) = { return _fs_open(fs, path, fsflags_to_bsd(flags)?, 0); }; fn fs_open( fs: *fs::fs, path: str, flags: fs::flag, ) (io::handle | fs::error) = fs_open_file(fs, path, flags)?; fn fs_create_file( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::file | fs::error) = { flags |= fs::flag::CREATE; return _fs_open(fs, path, fsflags_to_bsd(flags)?, mode)?; }; fn fs_create( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::handle | fs::error) = { return fs_create_file(fs, path, mode, flags)?; }; fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = { let fs = fs: *os_filesystem; let st = rt::st { ... }; match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; return fs::filestat { mask = fs::stat_mask::UID | fs::stat_mask::GID | fs::stat_mask::SIZE | fs::stat_mask::INODE | fs::stat_mask::ATIME | fs::stat_mask::MTIME | fs::stat_mask::CTIME, mode = st.mode: fs::mode, uid = st.uid, gid = st.gid, sz = st.sz: size, inode = st.ino, atime = time::instant { sec = st.atime.tv_sec, nsec = st.atime.tv_nsec, }, mtime = time::instant { sec = st.mtime.tv_sec, nsec = st.mtime.tv_nsec, }, ctime = time::instant { sec = st.ctime.tv_sec, nsec = st.ctime.tv_nsec, }, }; }; fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = { let fs = fs: *os_filesystem; static let buf: [rt::PATH_MAX]u8 = [0...]; let z = match (rt::readlinkat(fs.dirfd, path, buf[..])) { case let err: rt::errno => switch (err) { case rt::EINVAL => return fs::wrongtype; case => return errno_to_fs(err); }; case let z: size => yield z; }; return strings::fromutf8(buf[..z])!; }; fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_mkdir(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::mkdirat(fs.dirfd, path, mode: uint)) { case let err: rt::errno => switch (err) { case rt::EISDIR => return errors::exists; case => return errno_to_fs(err); }; case void => void; }; }; fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = { match (rt::fchmod(fd, mode: uint)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = { match (rt::fchown(fd, uid, gid)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn instant_to_timespec(time: (time::instant | void)) rt::timespec = { match (time) { case let t: time::instant => return time::instant_to_timespec(t); case void => return rt::timespec{ tv_sec = rt::UTIME_OMIT, tv_nsec = rt::UTIME_OMIT }; }; }; fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; let fs = fs: *os_filesystem; match (rt::utimensat(fs.dirfd, path, &utimes, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchtimes(fd: io::file, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; match (rt::futimens(fd, &utimes)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // TODO: cannot handle errors, i.e. path too long or cannot resolve. fn fs_resolve(fs: *fs::fs, path: str) str = { let fs = fs: *os_filesystem; static let buf = path::buffer { ... }; if (path::abs(path)) { return path; }; if (fs.dirfd == rt::AT_FDCWD) { path::set(&buf, getcwd(), path)!; } else { // XXX: this is the best we can for now. we should probably // return an error path::set(&buf, "", path)!; }; return path::string(&buf); }; fn fs_close(fs: *fs::fs) void = { let fs = fs: *os_filesystem; rt::close(fs.dirfd)!; }; // Based on musl's readdir type os_iterator = struct { iter: fs::iterator, fd: int, buf_pos: size, buf_end: size, buf: []u8, }; fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { let fs = fs: *os_filesystem; let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY; let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => return errors::nomem; }; let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, finish = &iter_finish, }, fd = fd, buf = buf[..fs.getdents_bufsz], ... }); return &iter.iter; }; fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = { let iter = iter: *os_iterator; if (iter.buf_pos >= iter.buf_end) { let n = match (rt::getdents(iter.fd, iter.buf: *[*]u8, len(iter.buf))) { case let err: rt::errno => return errno_to_fs(err); case let n: size => yield n; }; if (n == 0) { return done; }; iter.buf_end = n; iter.buf_pos = 0; }; let de = &iter.buf[iter.buf_pos]: *rt::dirent; iter.buf_pos += de.d_reclen; let name = c::tostr(&de.d_name: *const c::char)?; if (name == "." || name == "..") { return iter_next(iter); }; let ftype: fs::mode = switch (de.d_type) { case rt::DT_UNKNOWN => yield fs::mode::UNKNOWN; case rt::DT_FIFO => yield fs::mode::FIFO; case rt::DT_CHR => yield fs::mode::CHR; case rt::DT_DIR => yield fs::mode::DIR; case rt::DT_BLK => yield fs::mode::BLK; case rt::DT_REG => yield fs::mode::REG; case rt::DT_LNK => yield fs::mode::LINK; case rt::DT_SOCK => yield fs::mode::SOCK; case => yield fs::mode::UNKNOWN; }; return fs::dirent { name = name, ftype = ftype, }; }; fn iter_finish(iter: *fs::iterator) void = { let iter = iter: *os_iterator; rt::close(iter.fd)!; free(iter.buf); free(iter); }; hare-0.24.2/os/+netbsd/exit+test.ha000066400000000000000000000003221464473310100167270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export fn exit(status: int) never = { abort("os::exit disabled in +test"); }; hare-0.24.2/os/+netbsd/exit.ha000066400000000000000000000003251464473310100157570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Exit the program with the provided status code. export fn exit(status: int) never = { rt::fini(); rt::exit(status); }; hare-0.24.2/os/+netbsd/fs.ha000066400000000000000000000042551464473310100154240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; use types::c; @init fn init_cwd() void = { static let cwd_fs = os_filesystem { ... }; cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); }; // Returns the current working directory. The return value is statically // allocated and must be duplicated (see [[strings::dup]]) before calling getcwd // again. export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; // Change the current working directory. export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { const path: str = match (target) { case let fs: *fs::fs => assert(fs.open == &fs_open); let fs = fs: *os_filesystem; match (rt::fchdir(fs.dirfd)) { case let err: rt::errno => return errno_to_fs(err); case void => return; }; case let s: str => yield s; }; match (rt::chdir(path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Changes the root directory of the process. Generally requires the caller to // have root or otherwise elevated permissions. // // This function is not appropriate for sandboxing. export fn chroot(target: str) (void | fs::error) = { match (rt::chroot(target)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Access modes for [[access]]. export type amode = enum int { F_OK = rt::F_OK, R_OK = rt::R_OK, W_OK = rt::W_OK, X_OK = rt::X_OK, }; // Returns true if the given mode of access is permissible. The use of this // function is discouraged as it can allow for a race condition to occur betwen // testing for the desired access mode and actually using the file should the // permissions of the file change between these operations. It is recommended // instead to attempt to use the file directly and to handle any errors that // should occur at that time. export fn access(path: str, mode: amode) (bool | fs::error) = { match (rt::access(path, mode)) { case let b: bool => return b; case let err: rt::errno => return errno_to_fs(err); }; }; // TODO: NetBSD // export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { // export fn mkblk( // export fn mkchr( // export fn mkfile( hare-0.24.2/os/+netbsd/platform_environ.ha000066400000000000000000000057561464473310100204070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use strings; use types::c; // The command line arguments provided to the program. By convention, the first // member is usually the name of the program. export let args: []str = []; // Statically allocate arg strings if there are few enough arguments, saves a // syscall if we don't need it. let args_static: [32]str = [""...]; @init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { args = alloc([], rt::argc); for (let i = 0z; i < rt::argc; i += 1) { append(args, c::tostr(rt::argv[i]: *const c::char)!); }; }; }; @fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; }; // Returns a slice of the environment strings in the form KEY=VALUE. export fn getenvs() []str = { if (len(envp) != 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; append(envp, strings::dup(s)); }; return envp; }; // Returns the host kernel name export fn sysname() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctl([rt::CTL_KERN, rt::KERN_OSTYPE], &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host system hostname export fn hostname() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctl([rt::CTL_KERN, rt::KERN_HOSTNAME], &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host kernel version export fn release() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctl([rt::CTL_KERN, rt::KERN_OSRELEASE], &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host operating system version export fn version() const str = { static let buf: [512]u8 = [0...]; let sz: size = len(buf); rt::sysctl([rt::CTL_KERN, rt::KERN_VERSION], &buf, &sz, null, 0)!; return strings::fromutf8(buf[..(sz - 1)])!; }; // Returns the host CPU architecture, in a platform-specific format. See // [[architecture]] for a more portable wrapper. export fn machine() const str = { static let buf: [32]u8 = [0...]; let sz: size = len(buf); rt::sysctl([rt::CTL_HW, rt::HW_MACHINE], &buf, &sz, null, 0)!; return strings::fromutf8(buf[..sz - 1])!; }; // Returns the host CPU architecture. export fn architecture() arch = { switch (machine()) { case "aarch64" => return arch::AARCH64; case "riscv64" => return arch::RISCV64; case "amd64" => return arch::X86_64; case => abort(); // unreachable }; }; // Returns the number of usable CPUs. export fn cpucount() (size | errors::error) = { let count = 0; let length = size(int); match (rt::sysctl([rt::CTL_HW, rt::HW_NCPU], &count, &length, null, 0)) { case void => void; case let err: rt::errno => return errors::errno(err); }; return count: size; }; hare-0.24.2/os/+netbsd/shm.ha000066400000000000000000000073551464473310100156070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use errors; use fs; use io; use path; use rt; use strings; fn shm_check_fs() bool = { match (open(rt::SHMFS_DIR_PATH, fs::flag::DIRECTORY | fs::flag::RDONLY)) { case fs::error => return false; case let fd: io::file => defer io::close(fd)!; let sv = rt::statvfs{...}; let st = rt::st{...}; if (rt::fstatvfs1(fd, &sv, rt::MNT_NOWAIT) is rt::errno) return false; if (strings::fromutf8(sv.f_fstypename)! == rt::MOUNT_SHMFS) return false; if (rt::fstat(fd, &st) is rt::errno) return false; if ((st.mode & rt::SHMFS_DIR_MODE) != rt::SHMFS_DIR_MODE) return false; return true; }; }; fn shm_get_path(name: const str) (str | fs::error) = { if (!shm_check_fs()) return errors::errno(rt::ENOTSUP): fs::error; // The name may start with a slash character. if (strings::hasprefix(name, '/')) { name = strings::sub(name, 1); }; // We may disallow other slashes (implementation-defined behaviour). if (strings::contains(name, '/')) return errors::errno(rt::EINVAL): fs::error; const _path = strings::concat( rt::SHMFS_DIR_PATH, "/", rt::SHMFS_OBJ_PREFIX, name); if (len(_path) > path::MAX) return errors::errno(rt::ENAMETOOLONG): fs::error; return _path; }; // Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file // with the given name, suitable for use with [[io::mmap]] to establish shared // memory areas with other processes using the same name. // // The name must not contain any forward slashes (one is permissible at the // start, e.g. "/example") and cannot be "." or "..". // // The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]] // or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]], // [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], which are supported on all // POSIX-compatible platforms. Other platforms may support additional // non-standard flags; consult the shm_open(3) manual for your target system for // details. // // The new file descriptor always has CLOEXEC set regardless of the provided // flags. If creating a new shared memory object, set its initial size with // [[io::trunc]] before mapping it with [[io::mmap]]. // // Call [[shm_unlink]] to remove the global shared memory object. export fn shm_open( name: str, oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR, mode: fs::mode = 0o600, ) (io::file | fs::error) = { const _path = shm_get_path(name)?; const oflag = fsflags_to_bsd(oflag)? | rt::O_CLOEXEC | rt::O_NOFOLLOW; match (rt::open(_path, oflag, mode)) { case let fd: int => return fd: io::file; case let err: rt::errno => return errors::errno(err): fs::error; }; }; // Removes the shared memory object with the given name. Processes which already // hold a reference to the file may continue to use the memory associated with // it. Once all processes have unmapped the associated shared memory object, or // exited, the memory is released. export fn shm_unlink(name: str) (void | fs::error) = { const _path = shm_get_path(name)?; match (rt::unlink(_path)) { case void => void; case let err: rt::errno => return errors::errno(err): fs::error; }; }; @test fn shm_open() void = { const name = "/vizzini"; const value = "inconceivable"; def length = 13; const fd = shm_open(name)!; defer shm_unlink(name)!; io::trunc(fd, length)!; io::write(fd, strings::toutf8(value))!; { const fd = shm_open(name, fs::flag::RDONLY, 0o600)!; let b: [length]u8 = [0...]; io::read(fd, b)!; assert(strings::fromutf8(b)! == value); }; }; @test fn shm_get_path() void = { assert(shm_get_path("/ab/c") is fs::error); assert(shm_get_path("abc"): str == "/var/shm/.shmobj_abc"); assert(shm_get_path("/abc"): str == "/var/shm/.shmobj_abc"); }; hare-0.24.2/os/+netbsd/status.ha000066400000000000000000000003711464473310100163320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Values that may be passed to [[exit]] to indicate successful or unsuccessful // termination, respectively. export type status = enum { SUCCESS = 0, FAILURE = 1, }; hare-0.24.2/os/+netbsd/stdfd.ha000066400000000000000000000031021464473310100161060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use rt; let stdin_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 0, ... }; let stdout_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 1, ... }; // The standard input. This handle is buffered. export let stdin: io::handle = rt::STDIN_FILENO; // initialized by init_stdfd // The standard input, as an [[io::file]]. This handle is unbuffered. export let stdin_file: io::file = rt::STDIN_FILENO; // The standard output. This handle is buffered. export let stdout: io::handle = rt::STDOUT_FILENO; // initialized by init_stdfd // The standard output, as an [[io::file]]. This handle is unbuffered. export let stdout_file: io::file = rt::STDOUT_FILENO; // The standard error. This handle is unbuffered. export let stderr: io::handle = rt::STDERR_FILENO; // The standard error, as an [[io::file]]. This handle is unbuffered. export let stderr_file: io::file = rt::STDERR_FILENO; // The recommended buffer size for reading from disk. export def BUFSZ: size = 4096; // 4 KiB @init fn init_stdfd() void = { static let stdinbuf: [BUFSZ]u8 = [0...]; stdin_bufio = bufio::init(stdin_file, stdinbuf, []); stdin = &stdin_bufio; static let stdoutbuf: [BUFSZ]u8 = [0...]; stdout_bufio = bufio::init(stdout_file, [], stdoutbuf); stdout = &stdout_bufio; }; @fini fn fini_stdfd() void = { // Flush any pending writes io::close(stdout): void; }; hare-0.24.2/os/+openbsd/000077500000000000000000000000001464473310100146475ustar00rootroot00000000000000hare-0.24.2/os/+openbsd/dirfdfs.ha000066400000000000000000000267511464473310100166150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use rt; use strings; use io; use types::c; use time; use path; type os_filesystem = struct { fs: fs::fs, dirfd: int, getdents_bufsz: size, }; fn fsflags_to_bsd(flags: fs::flag) (int | errors::unsupported) = { let out = rt::O_CLOEXEC; if (flags & fs::flag::RDONLY == fs::flag::RDONLY) { out |= rt::O_RDONLY; }; if (flags & fs::flag::WRONLY == fs::flag::WRONLY) { out |= rt::O_WRONLY; }; if (flags & fs::flag::RDWR == fs::flag::RDWR) { out |= rt::O_RDWR; }; if (flags & fs::flag::CREATE == fs::flag::CREATE) { out |= rt::O_CREAT; }; if (flags & fs::flag::EXCL == fs::flag::EXCL) { out |= rt::O_EXCL; }; if (flags & fs::flag::TRUNC == fs::flag::TRUNC) { out |= rt::O_TRUNC; }; if (flags & fs::flag::APPEND == fs::flag::APPEND) { out |= rt::O_APPEND; }; if (flags & fs::flag::NONBLOCK == fs::flag::NONBLOCK) { out |= rt::O_NONBLOCK; }; if (flags & fs::flag::SYNC == fs::flag::SYNC || flags & fs::flag::DSYNC == fs::flag::DSYNC || flags & fs::flag::RSYNC == fs::flag::RSYNC) { out |= rt::O_SYNC; }; if (flags & fs::flag::DIRECTORY == fs::flag::DIRECTORY) { out |= rt::O_DIRECTORY; }; if (flags & fs::flag::NOFOLLOW == fs::flag::NOFOLLOW) { out |= rt::O_NOFOLLOW; }; if (flags & fs::flag::NOCLOEXEC == fs::flag::NOCLOEXEC) { out &= ~rt::O_CLOEXEC; }; if (flags & fs::flag::PATH == fs::flag::PATH || flags & fs::flag::NOATIME == fs::flag::NOATIME || flags & fs::flag::TMPFILE == fs::flag::TMPFILE || flags & fs::flag::CTTY == fs::flag::CTTY) { return errors::unsupported; }; return out; }; fn _fs_open( fs: *fs::fs, path: str, flags: int, mode: uint, ) (io::file | fs::error) = { let fs = fs: *os_filesystem; let fd = match (rt::openat(fs.dirfd, path, flags, mode)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; return io::fdopen(fd); }; fn fs_open_file( fs: *fs::fs, path: str, flags: fs::flag, ) (io::file | fs::error) = { return _fs_open(fs, path, fsflags_to_bsd(flags)?, 0); }; fn fs_open( fs: *fs::fs, path: str, flags: fs::flag, ) (io::handle | fs::error) = fs_open_file(fs, path, flags)?; fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = { let fs = fs: *os_filesystem; static let buf: [rt::PATH_MAX]u8 = [0...]; let sz = match (rt::readlinkat(fs.dirfd, path, buf[..])) { case let err: rt::errno => switch (err) { case rt::EINVAL => return fs::wrongtype; case => return errno_to_fs(err); }; case let sz: size => yield sz; }; return strings::fromutf8(buf[..sz])!; }; fn fs_create_file( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::file | fs::error) = { flags |= fs::flag::CREATE; return _fs_open(fs, path, fsflags_to_bsd(flags)?, mode)?; }; fn fs_create( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flag, ) (io::handle | fs::error) = fs_create_file(fs, path, mode, flags)?; fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; type os_iterator = struct { iter: fs::iterator, fd: int, buf_pos: int, buf_end: int, buf: []u8, }; fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = { let iter = iter: *os_iterator; for (true) { if (iter.buf_pos >= iter.buf_end) { let n = match (rt::getdents(iter.fd, iter.buf: *[*]u8, len(iter.buf))) { case let err: rt::errno => return errno_to_fs(err); case let n: int => yield n; }; if (n == 0) { return done; }; iter.buf_end = n; iter.buf_pos = 0; }; let de = &iter.buf[iter.buf_pos]: *rt::dirent; iter.buf_pos += de.d_reclen: int; // getdents() may return invalid entries which will have // d_fileno set to 0 if (de.d_fileno == 0) { continue; }; let name = c::tostr(&de.d_name: *const c::char)?; if (name == "." || name == "..") { continue; }; let ftype: fs::mode = switch (de.d_type) { case rt::DT_UNKNOWN => yield fs::mode::UNKNOWN; case rt::DT_FIFO => yield fs::mode::FIFO; case rt::DT_CHR => yield fs::mode::CHR; case rt::DT_DIR => yield fs::mode::DIR; case rt::DT_BLK => yield fs::mode::BLK; case rt::DT_REG => yield fs::mode::REG; case rt::DT_LNK => yield fs::mode::LINK; case rt::DT_SOCK => yield fs::mode::SOCK; case => yield fs::mode::UNKNOWN; }; return fs::dirent { name = name, ftype = ftype, }; }; }; fn iter_finish(iter: *fs::iterator) void = { let iter = iter: *os_iterator; rt::close(iter.fd)!; free(iter.buf); free(iter); }; fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { let fs = fs: *os_filesystem; let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY; let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) { case let err: rt::errno => return errno_to_fs(err); case let fd: int => yield fd; }; let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => return errors::nomem; }; let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, finish = &iter_finish, }, fd = fd, buf = buf[..fs.getdents_bufsz], ... }); return &iter.iter; }; fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = { let fs = fs: *os_filesystem; let stat = rt::stat { ... }; match (rt::fstatat(fs.dirfd, path, &stat, rt::AT_SYMLINK_NOFOLLOW)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; return fs::filestat { mask = fs::stat_mask::UID | fs::stat_mask::GID | fs::stat_mask::SIZE | fs::stat_mask::INODE | fs::stat_mask::ATIME | fs::stat_mask::MTIME | fs::stat_mask::CTIME, mode = stat.st_mode: fs::mode, uid = stat.st_uid, gid = stat.st_gid, sz = stat.st_size: size, inode = stat.st_ino, atime = time::instant { sec = stat.st_atim.tv_sec, nsec = stat.st_atim.tv_nsec, }, mtime = time::instant { sec = stat.st_mtim.tv_sec, nsec = stat.st_mtim.tv_nsec, }, ctime = time::instant { sec = stat.st_ctim.tv_sec, nsec = stat.st_ctim.tv_nsec, }, }; }; fn fs_mkdir(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::mkdirat(fs.dirfd, path, mode: uint)) { case let err: rt::errno => switch (err) { case rt::EISDIR => return errors::exists; case => return errno_to_fs(err); }; case void => void; }; }; fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = { match (rt::fchmod(fd, mode: uint)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = { match (rt::fchown(fd, uid, gid)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn instant_to_timespec(time: (time::instant | void)) rt::timespec = { match (time) { case let t: time::instant => return time::instant_to_timespec(t); case void => return rt::timespec{ tv_sec = rt::UTIME_OMIT, tv_nsec = rt::UTIME_OMIT }; }; }; fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; let fs = fs: *os_filesystem; match (rt::utimensat(fs.dirfd, path, &utimes, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_fchtimes(fd: io::file, atime: (time::instant | void), mtime: (time::instant | void)) (void | fs::error) = { let utimes: [2]rt::timespec = [ instant_to_timespec(atime), instant_to_timespec(mtime), ]; match (rt::futimens(fd, &utimes)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // TODO: cannot handle errors, i.e. path too long or cannot resolve. fn fs_resolve(fs: *fs::fs, path: str) str = { let fs = fs: *os_filesystem; static let buf = path::buffer { ... }; if (path::abs(path)) { return path; }; if (fs.dirfd == rt::AT_FDCWD) { path::set(&buf, getcwd(), path)!; } else { // XXX: this is the best we can for now. we should probably // return an error path::set(&buf, "", path)!; }; return path::string(&buf); }; fn fs_link(fs: *fs::fs, old: str, new: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::linkat(fs.dirfd, old, fs.dirfd, new, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_symlink(fs: *fs::fs, target: str, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; match (rt::symlinkat(target, fs.dirfd, path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; fn fs_close(fs: *fs::fs) void = { let fs = fs: *os_filesystem; rt::close(fs.dirfd)!; }; // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { let ofs = alloc(os_filesystem { ... }); let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; }; fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = { *filesystem = os_filesystem { fs = fs::fs { open = &fs_open, openfile = &fs_open_file, create = &fs_create, createfile = &fs_create_file, remove = &fs_remove, rename = &fs_rename, iter = &fs_iter, stat = &fs_stat, readlink = &fs_readlink, mkdir = &fs_mkdir, rmdir = &fs_rmdir, chmod = &fs_chmod, chown = &fs_chown, chtimes = &fs_chtimes, fchtimes = &fs_fchtimes, resolve = &fs_resolve, link = &fs_link, symlink = &fs_symlink, ... }, dirfd = fd, getdents_bufsz = 32768, // 32 KiB ... }; return &filesystem.fs; }; // Sets the buffer size to use with the getdents(2) system call, for use with // [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can // scan large directories faster. The default buffer size is 32 KiB. // // This function is not portable. export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; fs.getdents_bufsz = sz; }; fn errno_to_fs(err: rt::errno) fs::error = { switch (err) { case rt::ENOENT => return errors::noentry; case rt::EEXIST => return errors::exists; case rt::EACCES => return errors::noaccess; case rt::EBUSY => return errors::busy; case rt::ENOTDIR => return fs::wrongtype; case rt::EOPNOTSUPP, rt::ENOSYS => return errors::unsupported; case rt::EXDEV => return fs::cannotrename; case => return errors::errno(err); }; }; hare-0.24.2/os/+openbsd/exit+test.ha000066400000000000000000000003221464473310100171020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Exit the program with the provided status code. export fn exit(status: int) never = { abort("os::exit disabled in +test"); }; hare-0.24.2/os/+openbsd/exit.ha000066400000000000000000000003651464473310100161360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Exit the program with the provided status code. export fn exit(status: int) never = { // The @fini functions will be run by libc. rt::exit(status); }; hare-0.24.2/os/+openbsd/fs.ha000066400000000000000000000054771464473310100156060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use io; use rt; use types::c; @init fn init_cwd() void = { static let cwd_fs = os_filesystem { ... }; cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); }; // Returns the current working directory. The return value is statically // allocated and must be duplicated (see [[strings::dup]]) before calling getcwd // again. export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; // Change the current working directory. export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { const path: str = match (target) { case let fs: *fs::fs => assert(fs.open == &fs_open); let fs = fs: *os_filesystem; match (rt::fchdir(fs.dirfd)) { case let err: rt::errno => return errno_to_fs(err); case void => return; }; case let s: str => yield s; }; match (rt::chdir(path)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Changes the root directory of the process. Generally requires the caller to // have root or otherwise elevated permissions. // // This function is not appropriate for sandboxing. export fn chroot(target: str) (void | fs::error) = { match (rt::chroot(target)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Access modes for [[access]]. export type amode = enum int { F_OK = rt::F_OK, R_OK = rt::R_OK, W_OK = rt::W_OK, X_OK = rt::X_OK, }; // Returns true if the given mode of access is permissible. The use of this // function is discouraged as it can allow for a race condition to occur betwen // testing for the desired access mode and actually using the file should the // permissions of the file change between these operations. It is recommended // instead to attempt to use the file directly and to handle any errors that // should occur at that time. export fn access(path: str, mode: amode) (bool | fs::error) = { match (rt::access(path, mode)) { case let b: bool => return b; case let err: rt::errno => return errno_to_fs(err); }; }; // Makes a FIFO node. This function is only available on Unix-like systems. export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFIFO, 0)) { case let err: rt::errno => return errno_to_fs(err); case void => void; }; }; // Makes a regular file. This function is only available on Unix-like systems. // This function should only be used if you have a special reason; most of the // time you should use [[create]] instead. export fn mkfile(path: str, mode: fs::mode) (void | fs::error) = { let file = match(rt::openat(rt::AT_FDCWD, path, rt::O_RDONLY | rt::O_CREAT, mode: rt::mode_t)) { case let f: int => yield f: io::file; case let err: rt::errno => return errno_to_fs(err); }; io::close(file)?; }; hare-0.24.2/os/+openbsd/platform_environ.ha000066400000000000000000000057721464473310100205600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use strings; use types::c; // The command line arguments provided to the program. By convention, the first // member is usually the name of the program. export let args: []str = []; // Statically allocate arg strings if there are few enough arguments, saves a // syscall if we don't need it. let args_static: [32]str = [""...]; @init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { args = alloc([], rt::argc); for (let i = 0z; i < rt::argc; i += 1) { append(args, c::tostr(rt::argv[i]: *const c::char)!); }; }; }; @fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; }; // Returns a slice of the environment strings in form KEY=VALUE. export fn getenvs() []str = { if (len(envp) > 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; append(envp, strings::dup(s)); }; return envp; }; // Returns the host kernel name export fn sysname() const str = { let name: [2]int = [rt::CTL_KERN, rt::KERN_OSTYPE]; static let buf: [32]u8 = [0...]; let buf_sz = len(buf); rt::sysctl(name, len(name): uint, &buf, &buf_sz, null, 0)!; return strings::fromutf8(buf[..(buf_sz -1)])!; }; // Returns the host system hostname export fn hostname() const str = { let name: [2]int = [rt::CTL_KERN, rt::KERN_HOSTNAME]; static let buf: [rt::MAXHOSTNAMELEN]u8 = [0...]; let buf_sz = len(buf); rt::sysctl(name, len(name): uint, &buf, &buf_sz, null, 0)!; return strings::fromutf8(buf[..(buf_sz -1)])!; }; // Returns the host operating system version export fn version() const str = { let name: [2]int = [rt::CTL_KERN, rt::KERN_OSRELEASE]; static let buf: [32]u8 = [0...]; let buf_sz = len(buf); rt::sysctl(name, len(name): uint, &buf, &buf_sz, null, 0)!; return strings::fromutf8(buf[..(buf_sz -1)])!; }; // Returns the host CPU architecture, in a platform-specific format. See // [[architecture]] for a more portable wrapper. export fn machine() const str = { let name: [2]int = [rt::CTL_HW, rt::HW_MACHINE]; static let buf: [32]u8 = [0...]; let buf_sz = len(buf); rt::sysctl(name, len(name): uint, &buf, &buf_sz, null, 0)!; return strings::fromutf8(buf[..(buf_sz - 1)])!; }; // Returns the host CPU architecture. export fn architecture() arch = { switch (machine()) { case "arm64" => return arch::AARCH64; case "riscv64" => return arch::RISCV64; case "amd64" => return arch::X86_64; case => abort(); // unreachable }; }; // Returns the number of usable CPUs. export fn cpucount() (size | errors::error) = { let name: [2]int = [rt::CTL_HW, rt::HW_NCPUONLINE]; let ncpu: int = 0; let ncpu_sz = size(int); match (rt::sysctl(name, len(name): uint, &ncpu, &ncpu_sz, null, 0)) { case void => return ncpu: size; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/os/+openbsd/shm.ha000066400000000000000000000044201464473310100157500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use path; use rt; use strings; fn shm_path(name: str) (str | fs::error) = { const name = strings::ltrim(name, '/'); if (len(name) > rt::NAME_MAX) { return errors::invalid; }; if (name == "." || name == "..") { return errors::invalid; }; static let buf = path::buffer { ... }; path::set(&buf, "/", name)!; return path::string(&buf); }; // Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file // with the given name, suitable for use with [[io::mmap]] to establish shared // memory areas with other processes using the same name. // // The name must not contain any forward slashes (one is permissible at the // start, e.g. "/example") and cannot be "." or "..". // // The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]] // or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]], // [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], other flags are silently // ignored if set. // // The new file descriptor always has CLOEXEC set regardless of the provided // flags. If creating a new shared memory object, set its initial size with // [[io::trunc]] before mapping it with [[io::mmap]]. // // Call [[shm_unlink]] to remove the global shared memory object. export fn shm_open( name: str, oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR, mode: fs::mode = 0o600, ) (io::file | fs::error) = { const path = shm_path(name)?; def VALID_FLAGS: int = rt::O_RDWR | rt::O_CREAT | rt::O_EXCL | rt::O_TRUNC; const oflag = (fsflags_to_bsd(oflag)? & VALID_FLAGS) | rt::O_CLOEXEC; match (rt::shm_open(path, oflag, mode: rt::mode_t)) { case let fd: int => return fd: io::file; case let err: rt::errno => return errors::errno(err): fs::error; }; }; // Removes the shared memory object with the given name. Processes which already // hold a reference to the file may continue to use the memory associated with // it. Once all processes have unmapped the associated shared memory object, or // exited, the memory is released. export fn shm_unlink(name: str) (void | fs::error) = { const path = shm_path(name)?; match (rt::shm_unlink(path)) { case let err: rt::errno => return errors::errno(err): fs::error; case void => return; }; }; hare-0.24.2/os/+openbsd/status.ha000066400000000000000000000003711464473310100165050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Values that may be passed to [[exit]] to indicate successful or unsuccessful // termination, respectively. export type status = enum { SUCCESS = 0, FAILURE = 1, }; hare-0.24.2/os/+openbsd/stdfd.ha000066400000000000000000000031021464473310100162610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use rt; let stdin_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 0, ... }; let stdout_bufio: bufio::stream = bufio::stream { // Will be overwritten, but must be initialized stream = null: io::stream, source = 1, ... }; // The standard input. This handle is buffered. export let stdin: io::handle = rt::STDIN_FILENO; // initialized by init_stdfd // The standard input, as an [[io::file]]. This handle is unbuffered. export let stdin_file: io::file = rt::STDIN_FILENO; // The standard output. This handle is buffered. export let stdout: io::handle = rt::STDOUT_FILENO; // initialized by init_stdfd // The standard output, as an [[io::file]]. This handle is unbuffered. export let stdout_file: io::file = rt::STDOUT_FILENO; // The standard error. This handle is unbuffered. export let stderr: io::handle = rt::STDERR_FILENO; // The standard error, as an [[io::file]]. This handle is unbuffered. export let stderr_file: io::file = rt::STDERR_FILENO; // The recommended buffer size for reading from disk. export def BUFSZ: size = 4096; // 4 KiB @init fn init_stdfd() void = { static let stdinbuf: [BUFSZ]u8 = [0...]; stdin_bufio = bufio::init(stdin_file, stdinbuf, []); stdin = &stdin_bufio; static let stdoutbuf: [BUFSZ]u8 = [0...]; stdout_bufio = bufio::init(stdout_file, [], stdoutbuf); stdout = &stdout_bufio; }; @fini fn fini_stdfd() void = { // Flush any pending writes io::close(stdout): void; }; hare-0.24.2/os/README000066400000000000000000000007401464473310100140230ustar00rootroot00000000000000The os module provides access to resources from the host operating system, particularly to the filesystem and standard I/O. [[cwd]] provides an implementation of [[fs::fs]] which is backed by the host filesystem, and this module provides equivalents of various [[fs::]] functions which infer the current working directory as the fs parameter. This module also provides various non-filesystem related features from the host, such as the hostname, environment variables, and so on. hare-0.24.2/os/environ.ha000066400000000000000000000035411464473310100151370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use strings; // All currently supported target architectures. This enum will be extended // whenever support for a new architecture is added. export type arch = enum { AARCH64, RISCV64, X86_64, }; // Returns a portable string for an [[arch]]. export fn arch_name(arch: arch) const str = { switch (arch) { case arch::AARCH64 => return "aarch64"; case arch::RISCV64 => return "riscv64"; case arch::X86_64 => return "x86_64"; }; }; let envp: []str = []; @fini fn envp() void = strings::freeall(envp); // Looks up an environment variable and returns its value, or void if unset. export fn getenv(name: const str) (str | void) = { getenvs(); // populate envp for (let ent .. envp) { let (key, value) = strings::cut(ent, "="); if (key == name) return value; }; }; // Looks up an environment variable and returns its value, or a default value if // unset. export fn tryenv(name: const str, default: str) str = match (getenv(name)) { case let s: str => return s; case void => return default; }; // Sets an environment variable, overwriting it if it's already set. The name // may not contain '=' or '\0', and the value may not contain '\0'. export fn setenv(name: const str, value: const str) (void | errors::invalid) = { if (strings::contains(value, '\0')) return errors::invalid; unsetenv(name)?; append(envp, strings::join("=", name, value)); }; // Unsets an environment variable. Does nothing if the variable isn't set. The // name may not contain '=' or '\0'. export fn unsetenv(name: const str) (void | errors::invalid) = { if (strings::contains(name, '=', '\0')) return errors::invalid; getenvs(); // populate envp for (let i = 0z; i < len(envp); i += 1) { if (strings::cut(envp[i], "=").0 == name) { free(envp[i]); delete(envp[i]); break; }; }; }; hare-0.24.2/os/exec/000077500000000000000000000000001464473310100140665ustar00rootroot00000000000000hare-0.24.2/os/exec/+freebsd/000077500000000000000000000000001464473310100155535ustar00rootroot00000000000000hare-0.24.2/os/exec/+freebsd/exec.ha000066400000000000000000000125231464473310100170140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use rt; use types::c; use unix; // Forks the current process, returning the [[process]] of the child (to the // parent) and void (to the child), or an error. export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let i: rt::pid_t => return i: process; case void => return void; }; }; // Creates an anonymous pipe for use with [[addfile]]. Any data written to the // second file may be read from the first file. The caller should close one or // both of the file descriptors after they have transferred them to another // process, and after they have finished using them themselves, if applicable. // // This function will abort the process if the system is unable to allocate the // resources for a pipe. If you need to handle this error gracefully, you may // call [[unix::pipe]] yourself, but this may reduce the portability of your // software. // // To capture the standard output of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, pipe.1, os::stdout_file); // let proc = exec::start(&cmd)!; // io::close(pipe.1)!; // // let data = io::drain(pipe.0)!; // io::close(pipe.0)!; // exec::wait(&proc)!; // // To write to the standard input of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, os::stdin_file, pipe.0); // let proc = exec::start(&cmd)!; // // io::writeall(data)!; // io::close(pipe.1)!; // io::close(pipe.0)!; // exec::wait(&proc)!; export fn pipe() (io::file, io::file) = { return unix::pipe()!; }; fn open(path: str) (platform_cmd | error) = { let fd = match (rt::open(path, rt::O_RDONLY, 0u)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; let success = false; defer if (!success) rt::close(fd)!; match (rt::faccessat(fd, "", rt::X_OK, rt::AT_EMPTY_PATH)) { case let err: rt::errno => return errors::errno(err); case let b: bool => if (!b) { return errors::noaccess; }; }; // Make sure we are not trying to execute anything weird. fstat() // already dereferences symlinks, so if this is anything other than a // regular file it cannot be executed. let s = rt::st { ... }; match (rt::fstat(fd, &s)) { case let err: rt::errno => return errors::errno(err); case void => if (s.mode & rt::S_IFREG == 0) { return errors::noaccess; }; }; success = true; return fd; }; fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); for (let arg .. cmd.argv) { append(argv, c::fromstr(arg)); }; append(argv, null); let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); for (let e .. cmd.env) { append(env, c::fromstr(e)); }; append(env, null); envp = env: *[*]nullable *const c::char; }; let need_devnull = false; for (let file &.. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => need_devnull = true; continue; case closefd => continue; }; file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; }; const devnull: io::file = if (need_devnull) { yield os::open("/dev/null", fs::flag::RDWR)!; } else -1; for (let file .. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => yield devnull; case closefd => io::close(file.1)?; continue; }; if (file.1 == from) { let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) { case let flags: int => yield flags; case let e: rt::errno => return errors::errno(e); }; rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!; } else { match (rt::dup2(from, file.1)) { case int => void; case let e: rt::errno => return errors::errno(e); }; }; }; if (cmd.dir != "") { os::chdir(cmd.dir)?; }; return errors::errno(rt::fexecve(cmd.platform, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8)); }; fn platform_start(cmd: *command) (process | errors::error) = { // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD) let pipe: [2]int = [0...]; match (rt::pipe2(&pipe, rt::O_CLOEXEC)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => rt::close(pipe[1])!; defer rt::close(pipe[0])!; let errno: int = 0; match (rt::read(pipe[0], &errno, size(int))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case size(int) => return errors::errno(errno); case 0 => return pid; case => abort("Unexpected rt::read result"); }; }; case void => rt::close(pipe[0])!; let err = platform_exec(cmd); if (!(err is errors::opaque_)) { rt::exit(1); }; let err = err as errors::opaque_; let err = &err.data: *rt::errno; rt::write(pipe[1], err, size(int))!; rt::exit(1); }; }; hare-0.24.2/os/exec/+freebsd/platform_cmd.ha000066400000000000000000000010411464473310100205300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use os; use strings; export type platform_cmd = io::file; // Same as [[cmd]] except that executable file is determined by [[io::file]]. // This function is not portable. export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, argv = alloc([], len(args) + 1), env = strings::dupall(os::getenvs()), files = [], dir = "", }; append(cmd.argv, name); append(cmd.argv, args...); return cmd; }; hare-0.24.2/os/exec/+freebsd/process.ha000066400000000000000000000135021464473310100175440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use rt; use time; use unix; use unix::signal; // Stores information about a child process. export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { return unix::getpid(); }; // Stores information about an exited process. export type status = struct { status: int, // Not all of these members are supported on all operating systems. // Only utime and stime are guaranteed to be available. rusage: struct { utime: time::instant, stime: time::instant, maxrss: i64, ixrss: i64, idrss: i64, isrss: i64, minflt: i64, majflt: i64, nswap: i64, inblock: i64, oublock: i64, msgsnd: i64, msgrcv: i64, nsignals: i64, nvcsw: i64, nivcsw: i64, }, }; fn rusage(st: *status, ru: *rt::rusage) void = { st.rusage.utime = time::instant { sec = ru.ru_utime.tv_sec, nsec = ru.ru_utime.tv_usec * time::MICROSECOND: i64, }; st.rusage.stime = time::instant { sec = ru.ru_stime.tv_sec, nsec = ru.ru_stime.tv_usec * time::MICROSECOND: i64, }; st.rusage.maxrss = ru.ru_maxrss; st.rusage.ixrss = ru.ru_ixrss; st.rusage.idrss = ru.ru_idrss; st.rusage.isrss = ru.ru_isrss; st.rusage.minflt = ru.ru_minflt; st.rusage.majflt = ru.ru_majflt; st.rusage.nswap = ru.ru_nswap; st.rusage.inblock = ru.ru_inblock; st.rusage.oublock = ru.ru_oublock; st.rusage.msgsnd = ru.ru_msgsnd; st.rusage.msgrcv = ru.ru_msgrcv; st.rusage.nsignals = ru.ru_nsignals; st.rusage.nvcsw = ru.ru_nvcsw; st.rusage.nivcsw = ru.ru_nivcsw; }; // Waits for a process to complete, then returns its status information. export fn wait(proc: *process) (status | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => assert(pid == *proc: int); }; rusage(&st, &ru); return st; }; // Waits for the first child process to complete, then returns its process info // and status export fn waitany() ((process, status) | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => rusage(&st, &ru); return (pid: process, st); }; }; // Waits for all children to terminate succesfully. If a child process exits // with a nonzero status, returns its process info and exit status immediately, // not waiting for the remaining children. export fn waitall() (uint | error | !(process, exit_status)) = { let st: status = status { ... }; let ru: rt::rusage = rt::rusage { ... }; for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => if (err == rt::ECHILD) { return i; } else { return errors::errno(err); }; case let pid: int => match (check(&st)) { case void => void; case let es: !exit_status => return (pid: process, es); }; }; }; // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => switch (pid) { case 0 => return; case => assert(pid == *proc: int); }; }; rusage(&st, &ru); return st; }; // Checks if any child process has completed, returning its process info and // status if so. export fn peekany() ((process, status) | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => switch (pid) { case 0 => return; case => return (pid: process, st); }; }; }; // The exit status code of a process. export type exited = int; // The signal number which caused a process to terminate. export type signaled = signal::sig; // The exit status of a process. export type exit_status = (exited | signaled); // Returns a human friendly string describing the exit status. The string is // statically allocated; use [[strings::dup]] to extend its lifetime. export fn exitstr(status: exit_status) const str = { static let buf: [1024]u8 = [0...]; match (status) { case let i: exited => switch (i) { case 0 => return "exited normally"; case => return fmt::bsprintf(buf, "exited with status {}", i: int); }; case let s: signaled => return fmt::bsprintf(buf, "exited with signal {}", signal::signame(s)); }; }; // Returns the exit status of a completed process. export fn exit(stat: *status) exit_status = { if (rt::wifexited(stat.status)) { return rt::wexitstatus(stat.status): exited; }; if (rt::wifsignaled(stat.status)) { return rt::wtermsig(stat.status): signaled; }; abort("Unexpected exit status"); }; // Checks the exit status of a completed process, returning void if successful, // or its status code as an error type if not. export fn check(stat: *status) (void | !exit_status) = { if (rt::wifexited(stat.status)) { switch (rt::wexitstatus(stat.status)) { case 0 => return void; case => return exit(stat); }; }; return exit(stat); }; // Terminates a process. On FreeBSD, this sends [[unix::signal::sig::TERM]] to // the process. export fn kill(proc: process) (void | errors::error) = { return sig(proc, signal::sig::TERM); }; // Sends a signal to a child process. This function is only supported on // Unix-like systems. export fn sig(proc: process, sig: signal::sig) (void | errors::error) = { match (rt::kill(proc, sig)) { case let errno: rt::errno => return errors::errno(errno); case void => return; }; }; hare-0.24.2/os/exec/+linux/000077500000000000000000000000001464473310100153005ustar00rootroot00000000000000hare-0.24.2/os/exec/+linux/exec.ha000066400000000000000000000132121464473310100165350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use rt; use types::c; use unix; // Forks the current process, returning the [[process]] of the child (to the // parent) and void (to the child), or an error. export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let i: rt::pid_t => return i: process; case void => return void; }; }; // Creates an anonymous pipe for use with [[addfile]]. Any data written to the // second file may be read from the first file. The caller should close one or // both of the file descriptors after they have transferred them to another // process, and after they have finished using them themselves, if applicable. // // This function will abort the process if the system is unable to allocate the // resources for a pipe. If you need to handle this error gracefully, you may // call [[unix::pipe]] yourself, but this may reduce the portability of your // software. // // To capture the standard output of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, os::stdout_file, pipe.1); // let proc = exec::start(&cmd)!; // io::close(pipe.1)!; // // let data = io::drain(pipe.0)!; // io::close(pipe.0)!; // exec::wait(&proc)!; // // To write to the standard input of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, os::stdin_file, pipe.0); // let proc = exec::start(&cmd)!; // // io::writeall(data)!; // io::close(pipe.1)!; // io::close(pipe.0)!; // exec::wait(&proc)!; export fn pipe() (io::file, io::file) = { return unix::pipe()!; }; fn open(path: str) (platform_cmd | error) = { // O_PATH is used because it allows us to use an executable for which we // have execute permissions, but not read permissions. let fd = match (rt::open(path, rt::O_PATH, 0u)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; let success = false; defer if (!success) rt::close(fd)!; match (rt::faccessat(fd, "", rt::X_OK, rt::AT_EMPTY_PATH)) { case let err: rt::errno => // not ideal, but better to do Something on old kernels rather // than just breaking entirely if (err != rt::ENOSYS) { return errors::errno(err); }; case let b: bool => if (!b) { return errors::noaccess; }; }; // Make sure we are not trying to execute anything weird. fstat() // already dereferences symlinks, so if this is anything other than a // regular file it cannot be executed. let s = rt::st { ... }; match (rt::fstat(fd, &s)) { case let err: rt::errno => return errors::errno(err); case void => if (s.mode & rt::S_IFREG == 0) { return errors::noaccess; }; }; success = true; return fd; }; fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); for (let arg .. cmd.argv) { append(argv, c::fromstr(arg)); }; append(argv, null); let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); for (let e .. cmd.env) { append(env, c::fromstr(e)); }; append(env, null); envp = env: *[*]nullable *const c::char; }; let need_devnull = false; for (let file &.. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => need_devnull = true; continue; case closefd => continue; }; file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; }; const devnull: io::file = if (need_devnull) { yield os::open("/dev/null", fs::flag::RDWR)!; } else -1; for (let file .. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => yield devnull; case closefd => io::close(file.1)?; continue; }; if (file.1 == from) { let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) { case let flags: int => yield flags; case let e: rt::errno => return errors::errno(e); }; rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!; } else { match (rt::dup2(from, file.1)) { case int => void; case let e: rt::errno => return errors::errno(e); }; }; }; if (cmd.dir != "") { os::chdir(cmd.dir)?; }; return errors::errno(rt::execveat(cmd.platform, "\0", argv: *[*]nullable *const u8, envp: *[*]nullable *const u8, rt::AT_EMPTY_PATH)); }; fn platform_start(cmd: *command) (process | errors::error) = { // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD) let pipe: [2]int = [0...]; match (rt::pipe2(&pipe, rt::O_CLOEXEC)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::clone(null, rt::SIGCHLD, null, null, 0)) { case let err: rt::errno => return errors::errno(err); case let pid: int => rt::close(pipe[1])!; defer rt::close(pipe[0])!; let errno: int = 0; match (rt::read(pipe[0], &errno, size(int))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case size(int) => return errors::errno(errno); case 0 => return pid; case => abort("Unexpected rt::read result"); }; }; case void => rt::close(pipe[0])!; let err = platform_exec(cmd); if (!(err is errors::opaque_)) { rt::exit(1); }; let err = err as errors::opaque_; let err = &err.data: *rt::errno; rt::write(pipe[1], err, size(int))!; rt::exit(1); }; }; hare-0.24.2/os/exec/+linux/platform_cmd.ha000066400000000000000000000010411464473310100202550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use os; use strings; export type platform_cmd = io::file; // Same as [[cmd]] except that executable file is determined by [[io::file]]. // This function is not portable. export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, argv = alloc([], len(args) + 1), env = strings::dupall(os::getenvs()), files = [], dir = "", }; append(cmd.argv, name); append(cmd.argv, args...); return cmd; }; hare-0.24.2/os/exec/+linux/process.ha000066400000000000000000000127621464473310100173000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use rt; use time; use unix; use unix::signal; // Stores information about a child process. export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { return unix::getpid(); }; // Stores information about an exited process. export type status = struct { status: int, // Not all of these members are supported on all operating systems. // Only utime and stime are guaranteed to be available. rusage: struct { utime: time::instant, stime: time::instant, maxrss: u64, minflt: u64, majflt: u64, inblock: u64, oublock: u64, nvcsw: u64, nivcsw: u64, }, }; fn rusage(st: *status, ru: *rt::rusage) void = { st.rusage.utime = time::instant { sec = ru.ru_utime.tv_sec, nsec = ru.ru_utime.tv_usec * time::MICROSECOND: i64, }; st.rusage.stime = time::instant { sec = ru.ru_stime.tv_sec, nsec = ru.ru_stime.tv_usec * time::MICROSECOND: i64, }; st.rusage.maxrss = ru.ru_maxrss; st.rusage.minflt = ru.ru_minflt; st.rusage.majflt = ru.ru_majflt; st.rusage.inblock = ru.ru_inblock; st.rusage.oublock = ru.ru_oublock; st.rusage.nvcsw = ru.ru_nvcsw; st.rusage.nivcsw = ru.ru_nivcsw; }; // Waits for a process to complete, then returns its status information. export fn wait(proc: *process) (status | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => assert(pid == *proc: rt::pid_t); }; rusage(&st, &ru); return st; }; // Waits for the first child process to complete, then returns its process info // and status export fn waitany() ((process, status) | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => rusage(&st, &ru); return (pid, st); }; }; // Waits for all children to terminate succesfully. If a child process exits // with a nonzero status, returns its process info and exit status immediately, // not waiting for the remaining children. export fn waitall() (uint | error | !(process, exit_status)) = { let st: status = status { ... }; let ru: rt::rusage = rt::rusage { ... }; for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => if (err == rt::ECHILD) { return i; }; return errors::errno(err); case let pid: rt::pid_t => match (check(&st)) { case void => void; case let es: !exit_status => return (pid, es); }; }; }; // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => switch (pid) { case 0 => return; case => assert(pid == *proc: rt::pid_t); }; }; rusage(&st, &ru); return st; }; // Checks if any child process has completed, returning its process info and // status if so. export fn peekany() ((process, status) | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => switch (pid) { case 0 => return; case => return (pid, st); }; }; }; // The exit status code of a process. export type exited = int; // The signal number which caused a process to terminate. export type signaled = signal::sig; // The exit status of a process. export type exit_status = (exited | signaled); // Returns a human friendly string describing the exit status. The string is // statically allocated; use [[strings::dup]] to extend its lifetime. export fn exitstr(status: exit_status) const str = { static let buf: [1024]u8 = [0...]; match (status) { case let i: exited => switch (i) { case 0 => return "exited normally"; case => return fmt::bsprintf(buf, "exited with status {}", i: int); }; case let s: signaled => return fmt::bsprintf(buf, "exited with signal {}", signal::signame(s)); }; }; // Returns the exit status of a completed process. export fn exit(stat: *status) exit_status = { if (rt::wifexited(stat.status)) { return rt::wexitstatus(stat.status): exited; }; if (rt::wifsignaled(stat.status)) { return rt::wtermsig(stat.status): signaled; }; abort("Unexpected exit status"); }; // Checks the exit status of a completed process, returning void if successful, // or its status code as an error type if not. export fn check(stat: *status) (void | !exit_status) = { if (rt::wifexited(stat.status)) { switch (rt::wexitstatus(stat.status)) { case 0 => return void; case => return exit(stat); }; }; return exit(stat); }; // Terminates a process. On Linux, this sends [[unix::signal::sig::TERM]] to the // process. export fn kill(proc: process) (void | errors::error) = { return sig(proc, signal::sig::TERM); }; // Sends a signal to a child process. This function is only supported on // Unix-like systems. export fn sig(proc: process, sig: signal::sig) (void | errors::error) = { match (rt::kill(proc, sig)) { case let errno: rt::errno => return errors::errno(errno); case void => return; }; }; hare-0.24.2/os/exec/+netbsd/000077500000000000000000000000001464473310100154205ustar00rootroot00000000000000hare-0.24.2/os/exec/+netbsd/exec.ha000066400000000000000000000124731464473310100166650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use rt; use types::c; use unix; // Forks the current process, returning the [[process]] of the child (to the // parent) and void (to the child), or an error. export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let i: rt::pid_t => return i: process; case void => return void; }; }; // Creates an anonymous pipe for use with [[addfile]]. Any data written to the // second file may be read from the first file. The caller should close one or // both of the file descriptors after they have transferred them to another // process, and after they have finished using them themselves, if applicable. // // This function will abort the process if the system is unable to allocate the // resources for a pipe. If you need to handle this error gracefully, you may // call [[unix::pipe]] yourself, but this may reduce the portability of your // software. // // To capture the standard output of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, pipe.1, os::stdout_file); // let proc = exec::start(&cmd)!; // io::close(pipe.1)!; // // let data = io::drain(pipe.0)!; // io::close(pipe.0)!; // exec::wait(&proc)!; // // To write to the standard input of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, os::stdin_file, pipe.0); // let proc = exec::start(&cmd)!; // // io::writeall(data)!; // io::close(pipe.1)!; // io::close(pipe.0)!; // exec::wait(&proc)!; export fn pipe() (io::file, io::file) = { return unix::pipe()!; }; fn open(path: str) (platform_cmd | error) = { let fd = match (rt::open(path, rt::O_RDONLY, 0u)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; let success = false; defer if (!success) rt::close(fd)!; match (rt::access(path, rt::X_OK)) { case let err: rt::errno => return errors::errno(err); case let b: bool => if (!b) { return errors::noaccess; }; }; // Make sure we are not trying to execute anything weird. fstat() // already dereferences symlinks, so if this is anything other than a // regular file it cannot be executed. let s = rt::st { ... }; match (rt::fstat(fd, &s)) { case let err: rt::errno => return errors::errno(err); case void => if (s.mode & rt::S_IFREG == 0) { return errors::noaccess; }; }; success = true; return fd; }; fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); for (let arg .. cmd.argv) { append(argv, c::fromstr(arg)); }; append(argv, null); let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); for (let e .. cmd.env) { append(env, c::fromstr(e)); }; append(env, null); envp = env: *[*]nullable *const c::char; }; let need_devnull = false; for (let file &.. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => need_devnull = true; continue; case closefd => continue; }; file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; }; const devnull: io::file = if (need_devnull) { yield os::open("/dev/null", fs::flag::RDWR)!; } else -1; for (let file .. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => yield devnull; case closefd => io::close(file.1)?; continue; }; if (file.1 == from) { let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) { case let flags: int => yield flags; case let e: rt::errno => return errors::errno(e); }; rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!; } else { match (rt::dup2(from, file.1)) { case int => void; case let e: rt::errno => return errors::errno(e); }; }; }; if (cmd.dir != "") { os::chdir(cmd.dir)?; }; return errors::errno(rt::fexecve(cmd.platform, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8)); }; fn platform_start(cmd: *command) (process | errors::error) = { // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD) let pipe: [2]int = [0...]; match (rt::pipe2(&pipe, rt::O_CLOEXEC)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => rt::close(pipe[1])!; defer rt::close(pipe[0])!; let errno: int = 0; match (rt::read(pipe[0], &errno, size(int))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case size(int) => return errors::errno(errno); case 0 => return pid; case => abort("Unexpected rt::read result"); }; }; case void => rt::close(pipe[0])!; let err = platform_exec(cmd); if (!(err is errors::opaque_)) { rt::exit(1); }; let err = err as errors::opaque_; let err = &err.data: *rt::errno; rt::write(pipe[1], err, size(int))!; rt::exit(1); }; }; hare-0.24.2/os/exec/+netbsd/platform_cmd.ha000066400000000000000000000010411464473310100203750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use os; use strings; export type platform_cmd = io::file; // Same as [[cmd]] except that executable file is determined by [[io::file]]. // This function is not portable. export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, argv = alloc([], len(args) + 1), env = strings::dupall(os::getenvs()), files = [], dir = "", }; append(cmd.argv, name); append(cmd.argv, args...); return cmd; }; hare-0.24.2/os/exec/+netbsd/process.ha000066400000000000000000000135011464473310100174100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use rt; use time; use unix; use unix::signal; // Stores information about a child process. export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { return unix::getpid(); }; // Stores information about an exited process. export type status = struct { status: int, // Not all of these members are supported on all operating systems. // Only utime and stime are guaranteed to be available. rusage: struct { utime: time::instant, stime: time::instant, maxrss: i64, ixrss: i64, idrss: i64, isrss: i64, minflt: i64, majflt: i64, nswap: i64, inblock: i64, oublock: i64, msgsnd: i64, msgrcv: i64, nsignals: i64, nvcsw: i64, nivcsw: i64, }, }; fn rusage(st: *status, ru: *rt::rusage) void = { st.rusage.utime = time::instant { sec = ru.ru_utime.tv_sec, nsec = ru.ru_utime.tv_usec * time::MICROSECOND: i64, }; st.rusage.stime = time::instant { sec = ru.ru_stime.tv_sec, nsec = ru.ru_stime.tv_usec * time::MICROSECOND: i64, }; st.rusage.maxrss = ru.ru_maxrss; st.rusage.ixrss = ru.ru_ixrss; st.rusage.idrss = ru.ru_idrss; st.rusage.isrss = ru.ru_isrss; st.rusage.minflt = ru.ru_minflt; st.rusage.majflt = ru.ru_majflt; st.rusage.nswap = ru.ru_nswap; st.rusage.inblock = ru.ru_inblock; st.rusage.oublock = ru.ru_oublock; st.rusage.msgsnd = ru.ru_msgsnd; st.rusage.msgrcv = ru.ru_msgrcv; st.rusage.nsignals = ru.ru_nsignals; st.rusage.nvcsw = ru.ru_nvcsw; st.rusage.nivcsw = ru.ru_nivcsw; }; // Waits for a process to complete, then returns its status information. export fn wait(proc: *process) (status | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => assert(pid == *proc: int); }; rusage(&st, &ru); return st; }; // Waits for the first child process to complete, then returns its process info // and status export fn waitany() ((process, status) | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => rusage(&st, &ru); return (pid: process, st); }; }; // Waits for all children to terminate succesfully. If a child process exits // with a nonzero status, returns its process info and exit status immediately, // not waiting for the remaining children. export fn waitall() (uint | error | !(process, exit_status)) = { let st: status = status { ... }; let ru: rt::rusage = rt::rusage { ... }; for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => if (err == rt::ECHILD) { return i; } else { return errors::errno(err); }; case let pid: int => match (check(&st)) { case void => void; case let es: !exit_status => return (pid: process, es); }; }; }; // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => switch (pid) { case 0 => return; case => assert(pid == *proc: int); }; }; rusage(&st, &ru); return st; }; // Checks if any child process has completed, returning its process info and // status if so. export fn peekany() ((process, status) | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(-1, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: int => switch (pid) { case 0 => return; case => return (pid: process, st); }; }; }; // The exit status code of a process. export type exited = int; // The signal number which caused a process to terminate. export type signaled = signal::sig; // The exit status of a process. export type exit_status = (exited | signaled); // Returns a human friendly string describing the exit status. The string is // statically allocated; use [[strings::dup]] to extend its lifetime. export fn exitstr(status: exit_status) const str = { static let buf: [1024]u8 = [0...]; match (status) { case let i: exited => switch (i) { case 0 => return "exited normally"; case => return fmt::bsprintf(buf, "exited with status {}", i: int); }; case let s: signaled => return fmt::bsprintf(buf, "exited with signal {}", signal::signame(s)); }; }; // Returns the exit status of a completed process. export fn exit(stat: *status) exit_status = { if (rt::wifexited(stat.status)) { return rt::wexitstatus(stat.status): exited; }; if (rt::wifsignaled(stat.status)) { return rt::wtermsig(stat.status): signaled; }; abort("Unexpected exit status"); }; // Checks the exit status of a completed process, returning void if successful, // or its status code as an error type if not. export fn check(stat: *status) (void | !exit_status) = { if (rt::wifexited(stat.status)) { switch (rt::wexitstatus(stat.status)) { case 0 => return void; case => return exit(stat); }; }; return exit(stat); }; // Terminates a process. On NetBSD, this sends [[unix::signal::sig::TERM]] to // the process. export fn kill(proc: process) (void | errors::error) = { return sig(proc, signal::sig::TERM); }; // Sends a signal to a child process. This function is only supported on // Unix-like systems. export fn sig(proc: process, sig: signal::sig) (void | errors::error) = { match (rt::kill(proc, sig)) { case let errno: rt::errno => return errors::errno(errno); case void => return; }; }; hare-0.24.2/os/exec/+openbsd/000077500000000000000000000000001464473310100155735ustar00rootroot00000000000000hare-0.24.2/os/exec/+openbsd/exec.ha000066400000000000000000000112741464473310100170360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use rt; use types::c; use unix; use path; // Forks the current process, returning the [[process]] of the child (to the // parent) and void (to the child), or an error. export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let i: int => return i: process; case void => return void; }; }; // Creates an anonymous pipe for use with [[addfile]]. Any data written to the // second file may be read from the first file. The caller should close one or // both of the file descriptors after they have transferred them to another // process, and after they have finished using them themselves, if applicable. // // This function will abort the process if the system is unable to allocate the // resources for a pipe. If you need to handle this error gracefully, you may // call [[unix::pipe]] yourself, but this may reduce the portability of your // software. // // To capture the standard output of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, pipe.1, os::stdout_file); // let proc = exec::start(&cmd)!; // io::close(pipe.1)!; // // let data = io::drain(pipe.0)!; // io::close(pipe.0)!; // exec::wait(&proc)!; // // To write to the standard input of a process: // // let pipe = exec::pipe(); // exec::addfile(&cmd, os::stdin_file, pipe.0); // let proc = exec::start(&cmd)!; // // io::writeall(data)!; // io::close(pipe.1)!; // io::close(pipe.0)!; // exec::wait(&proc)!; export fn pipe() (io::file, io::file) = { return unix::pipe()!; }; fn open(path: str) (platform_cmd | error) = { if (os::access(path, os::amode::X_OK)?) { // Length was already checked by access() return path::init(path)!; }; return errors::noaccess; }; fn platform_finish(cmd: *command) void = void; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); for (let arg .. cmd.argv) { append(argv, c::fromstr(arg)); }; append(argv, null); let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); for (let e .. cmd.env) { append(env, c::fromstr(e)); }; append(env, null); envp = env: *[*]nullable *const c::char; }; let need_devnull = false; for (let file &.. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => need_devnull = true; continue; case closefd => continue; }; file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) { case let fd: int => yield fd; case let err: rt::errno => return errors::errno(err); }; }; const devnull: io::file = if (need_devnull) { yield os::open("/dev/null", fs::flag::RDWR)!; } else -1; for (let file .. cmd.files) { const from = match (file.0) { case let file: io::file => yield file; case nullfd => yield devnull; case closefd => io::close(file.1)?; continue; }; if (file.1 == from) { let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) { case let flags: int => yield flags; case let e: rt::errno => return errors::errno(e); }; rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!; } else { match (rt::dup2(from, file.1)) { case int => void; case let e: rt::errno => return errors::errno(e); }; }; }; if (cmd.dir != "") { os::chdir(cmd.dir)?; }; return errors::errno(rt::execve(path::string(&cmd.platform), argv: *[*]nullable *const u8, envp: *[*]nullable *const u8)); }; fn platform_start(cmd: *command) (process | errors::error) = { // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD) let pipe: [2]int = [0...]; match (rt::pipe2(&pipe, rt::O_CLOEXEC)) { case let err: rt::errno => return errors::errno(err); case void => void; }; match (rt::fork()) { case let err: rt::errno => return errors::errno(err); case let pid: int => rt::close(pipe[1])!; defer rt::close(pipe[0])!; let errno: int = 0; match (rt::read(pipe[0], &errno, size(int))) { case let err: rt::errno => return errors::errno(err); case let n: size => switch (n) { case size(int) => return errors::errno(errno); case 0 => return pid; case => abort("Unexpected rt::read result"); }; }; case void => rt::close(pipe[0])!; let err = platform_exec(cmd); if (!(err is errors::opaque_)) { rt::exit(1); }; let err = err as errors::opaque_; let err = &err.data: *rt::errno; rt::write(pipe[1], err, size(int))!; rt::exit(1); }; }; hare-0.24.2/os/exec/+openbsd/platform_cmd.ha000066400000000000000000000002041464473310100205500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use path; export type platform_cmd = path::buffer; hare-0.24.2/os/exec/+openbsd/process.ha000066400000000000000000000133751464473310100175740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use rt; use time; use unix; use unix::signal; // Stores information about a child process. export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { return unix::getpid(); }; // Stores information about an exited process. export type status = struct { status: int, // Not all of these members are supported on all operating systems. // Only utime and stime are guaranteed to be available. rusage: struct { utime: time::instant, stime: time::instant, maxrss: i64, ixrss: i64, idrss: i64, isrss: i64, minflt: i64, majflt: i64, nswap: i64, inblock: i64, oublock: i64, msgsnd: i64, msgrcv: i64, nsignals: i64, nvcsw: i64, nivcsw: i64, }, }; fn rusage(st: *status, ru: *rt::rusage) void = { st.rusage.utime = time::instant { sec = ru.ru_utime.tv_sec, nsec = ru.ru_utime.tv_usec * time::MICROSECOND: i64, }; st.rusage.stime = time::instant { sec = ru.ru_stime.tv_sec, nsec = ru.ru_stime.tv_usec * time::MICROSECOND: i64, }; st.rusage.maxrss = ru.ru_maxrss; st.rusage.ixrss = ru.ru_ixrss; st.rusage.idrss = ru.ru_idrss; st.rusage.isrss = ru.ru_isrss; st.rusage.minflt = ru.ru_minflt; st.rusage.majflt = ru.ru_majflt; st.rusage.nswap = ru.ru_nswap; st.rusage.inblock = ru.ru_inblock; st.rusage.oublock = ru.ru_oublock; st.rusage.msgsnd = ru.ru_msgsnd; st.rusage.msgrcv = ru.ru_msgrcv; st.rusage.nsignals = ru.ru_nsignals; st.rusage.nvcsw = ru.ru_nvcsw; st.rusage.nivcsw = ru.ru_nivcsw; }; // Waits for a process to complete, then returns its status information. export fn wait(proc: *process) (status | error) = { let ru = rt::rusage { ... }; let st = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => assert(pid == *proc: rt::pid_t); }; rusage(&st, &ru); return st; }; // Waits for the first child process to complete, then returns its process info // and status export fn waitany() ((process, status) | error) = { let ru = rt::rusage { ... }; let st = status { ... }; match (rt::wait4(rt::WAIT_ANY, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => rusage(&st, &ru); return (pid: process, st); }; }; // Waits for all children to terminate succesfully. If a child process exits // with a nonzero status, returns its process info and exit status immediately, // not waiting for the remaining children. export fn waitall() (uint | error | !(process, exit_status)) = { let st = status { ... }; let ru = rt::rusage { ... }; for (let i = 0u; true; i += 1) { match (rt::wait4(rt::WAIT_ANY, &st.status, 0, &ru)) { case let err: rt::errno => if (err == rt::ECHILD) { return i; } else { return errors::errno(err); }; case let pid: rt::pid_t => match (check(&st)) { case void => void; case let es: !exit_status => return (pid: process, es); }; }; }; }; // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = { let ru = rt::rusage { ... }; let st = status { ... }; match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => switch (pid) { case 0 => return; case => assert(pid == *proc: rt::pid_t); }; }; rusage(&st, &ru); return st; }; // Checks if any child process has completed, returning its process info and // status if so. export fn peekany() ((process, status) | void | error) = { let ru = rt::rusage { ... }; let st = status { ... }; match (rt::wait4(rt::WAIT_ANY, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); case let pid: rt::pid_t => switch (pid) { case 0 => return; case => return (pid: process, st); }; }; }; // The exit status code of a process. export type exited = int; // The signal number which caused a process to terminate. export type signaled = signal::sig; // The exit status of a process. export type exit_status = (exited | signaled); // Returns a human friendly string describing the exit status. The string is // statically allocated; use [[strings::dup]] to extend its lifetime. export fn exitstr(status: exit_status) const str = { static let buf: [64]u8 = [0...]; match (status) { case let i: exited => switch (i) { case 0 => return "exited normally"; case => return fmt::bsprintf(buf, "exited with status {}", i: int); }; case let s: signaled => return fmt::bsprintf(buf, "exited with signal {}", signal::signame(s)); }; }; // Returns the exit status of a completed process. export fn exit(stat: *status) exit_status = { if (rt::wifexited(stat.status)) { return rt::wexitstatus(stat.status): exited; }; if (rt::wifsignaled(stat.status)) { return rt::wtermsig(stat.status): signaled; }; abort("Unexpected exit status"); }; // Checks the exit status of a completed process, returning void if successful, // or its status code as an error type if not. export fn check(stat: *status) (void | !exit_status) = { if (rt::wifexited(stat.status) && rt::wexitstatus(stat.status) == 0) { return; }; return exit(stat); }; // Terminates a process. On OpenBSD, this sends [[unix::signal::sig::TERM]] to // the process. export fn kill(proc: process) (void | errors::error) = { return sig(proc, signal::sig::TERM); }; // Sends a signal to a child process. This function is only supported on // Unix-like systems. export fn sig(proc: process, sig: signal::sig) (void | errors::error) = { match (rt::kill(proc, sig)) { case let errno: rt::errno => return errors::errno(errno); case void => return; }; }; hare-0.24.2/os/exec/README000066400000000000000000000006061464473310100147500ustar00rootroot00000000000000os::exec handles the execution of arbitrary commands. A programmer who needs to spawn an external command will usually utilize [[cmd]] to obtain a [[command]] instance (possibly using functions like [[setenv]] to customize it), then [[start]] to execute it and obtain a [[process]] (or, [[exec]] to replace the current process with it), then [[wait]] or [[peek]] to check in on its status. hare-0.24.2/os/exec/cmd.ha000066400000000000000000000156761464473310100151620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use os; use path; use strings; // Prepares a [[command]] based on its name and a list of arguments. The argument // list should not start with the command name; it will be added for you. The // argument list is borrowed from the strings you pass into this command. // // If 'name' does not contain a '/', the $PATH will be consulted to find the // correct executable. If path resolution fails, [[nocmd]] is returned. // // let cmd = exec::cmd("echo", "hello world")!; // let proc = exec::start(&cmd)!; // let status = exec::wait(&proc)!; // assert(exec::check(&status) is void); // // By default, the new command will inherit the current process's environment. export fn cmd(name: str, args: str...) (command | error) = { let platcmd = if (strings::contains(name, '/')) { yield match (open(name)) { case let p: platform_cmd => yield p; case let err: error => return err; case => return nocmd; }; } else { yield match (lookup_open(name)?) { case void => return nocmd; case let p: platform_cmd => yield p; }; }; let cmd = command { platform = platcmd, argv = alloc([], len(args) + 1), env = strings::dupall(os::getenvs()), files = [], dir = "", }; append(cmd.argv, name); append(cmd.argv, args...); return cmd; }; // Sets the 0th value of argv for this command. It is uncommon to need this. export fn setname(cmd: *command, name: str) void = { cmd.argv[0] = name; }; // Frees state associated with a command. You only need to call this if you do // not execute the command with [[exec]] or [[start]]; in those cases the state is // cleaned up for you. export fn finish(cmd: *command) void = { platform_finish(cmd); free(cmd.argv); free(cmd.files); strings::freeall(cmd.env); }; // Executes a prepared command in the current address space, overwriting the // running process with the new command. export fn exec(cmd: *command) never = { defer finish(cmd); // Note: doesn't happen if exec succeeds platform_exec(cmd): void; abort("os::exec::exec failed"); }; // Starts a prepared command in a new process. export fn start(cmd: *command) (process | error) = { defer finish(cmd); match (platform_start(cmd)) { case let err: errors::error => return err; case let proc: process => return proc; }; }; // Empties the environment variables for the command. By default, the command // inherits the environment of the parent process. export fn clearenv(cmd: *command) void = { strings::freeall(cmd.env); cmd.env = []; }; // Removes a variable in the command environment. This does not affect the // current process environment. The key may not contain '=' or '\0'. export fn unsetenv(cmd: *command, key: str) (void | errors::invalid) = { if (strings::contains(key, '=', '\0')) return errors::invalid; // XXX: This can be a binary search for (let i = 0z; i < len(cmd.env); i += 1) { if (strings::cut(cmd.env[i], "=").0 == key) { free(cmd.env[i]); delete(cmd.env[i]); break; }; }; }; // Adds or sets a variable in the command environment. This does not affect the // current process environment. The key may not contain '=' or '\0'. export fn setenv(cmd: *command, key: str, value: str) (void | errors::invalid) = { if (strings::contains(value, '\0')) return errors::invalid; unsetenv(cmd, key)?; append(cmd.env, strings::join("=", key, value)); }; // Configures a file in the child process's file table, such that the file // described by the 'source' parameter is mapped onto file descriptor slot // 'child' in the child process via dup(2). // // This operation is performed atomically, such that the following code swaps // stdout and stderr: // // exec::addfile(&cmd, os::stderr_file, os::stdout_file); // exec::addfile(&cmd, os::stdout_file, os::stderr_file); // // Pass [[nullfd]] in the 'source' argument to map the child's file descriptor // to /dev/null or the appropriate platform-specific equivalent. // // Pass [[closefd]] in the 'source' argument to close a file descriptor which // was not opened with the CLOEXEC flag. Note that Hare opens all files with // CLOEXEC by default, so this is not usually necessary. // // To write to a process's stdin, capture its stdout, or pipe two programs // together, see the [[pipe]] function. export fn addfile( cmd: *command, child: io::file, source: (io::file | nullfd | closefd), ) void = { append(cmd.files, (source, child)); }; // Closes all standard files (stdin, stdout, and stderr) in the child process. // Many programs do not work well under these conditions; you may want // [[nullstd]] instead. export fn closestd(cmd: *command) void = { addfile(cmd, os::stdin_file, closefd); addfile(cmd, os::stdout_file, closefd); addfile(cmd, os::stderr_file, closefd); }; // Redirects all standard files (stdin, stdout, and stderr) to /dev/null or the // platform-specific equivalent. export fn nullstd(cmd: *command) void = { addfile(cmd, os::stdin_file, nullfd); addfile(cmd, os::stdout_file, nullfd); addfile(cmd, os::stderr_file, nullfd); }; // Configures the child process's working directory. This does not affect the // process environment. The path is borrowed from the input, and must outlive // the command. export fn chdir(cmd: *command, dir: str) void = { cmd.dir = dir; }; // Similar to [[lookup]] but TOCTOU-proof fn lookup_open(name: str) (platform_cmd | void | error) = { static let buf = path::buffer { ... }; path::set(&buf)!; // Try to open file directly if (strings::contains(name, "/")) { match (open(name)) { case (errors::noaccess | errors::noentry) => void; case let err: error => return err; case let p: platform_cmd => return p; }; }; const path = match (os::getenv("PATH")) { case void => return; case let s: str => yield s; }; let tok = strings::tokenize(path, ":"); for (let item => strings::next_token(&tok)) { path::set(&buf, item, name)!; match (open(path::string(&buf))) { case (errors::noaccess | errors::noentry) => continue; case let err: error => return err; case let p: platform_cmd => return p; }; }; }; // Looks up an executable by name in the system PATH. The return value is // statically allocated. // // The use of this function is lightly discouraged if [[cmd]] is suitable; // otherwise you may have a TOCTOU issue. export fn lookup(name: str) (str | void) = { static let buf = path::buffer { ... }; path::set(&buf)!; // Try to open file directly if (strings::contains(name, "/")) { match (os::access(name, os::amode::X_OK)) { case let exec: bool => if (exec) { return name; }; case => void; // Keep looking }; }; const path = match (os::getenv("PATH")) { case void => return; case let s: str => yield s; }; let tok = strings::tokenize(path, ":"); for (let item => strings::next_token(&tok)) { path::set(&buf, item, name)!; match (os::access(path::string(&buf), os::amode::X_OK)) { case let exec: bool => if (exec) { return path::string(&buf); }; case => void; // Keep looking }; }; }; hare-0.24.2/os/exec/types.ha000066400000000000000000000017711464473310100155520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; // Represents a "null" file descriptor, e.g. /dev/null. export type nullfd = void; // Used to close a file descriptor which does not have the CLOEXEC flag set. export type closefd = void; export type command = struct { platform: platform_cmd, argv: []str, env: []str, files: []((io::file | nullfd | closefd), io::file), dir: str, }; // Returned when path resolution fails to find a command by its name. export type nocmd = !void; // All errors that can be returned from os::exec. export type error = !(nocmd | ...errors::error | io::error | fs::error); // Returns a human-readable message for the given error. export fn strerror(err: error) const str = { match (err) { case nocmd => return "Command not found"; case let err: errors::error => return errors::strerror(err); case let err: io::error => return io::strerror(err); case let err: fs::error => return fs::strerror(err); }; }; hare-0.24.2/os/os.ha000066400000000000000000000136161464473310100141040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use io; use time; // Provides an implementation of [[fs::fs]] for the current working directory. export let cwd: *fs::fs = null: *fs::fs; // Removes a file. export fn remove(path: str) (void | fs::error) = fs::remove(cwd, path); // Renames a file. This generally only works if the source and destination path // are both on the same filesystem. See [[move]] for an implementation which // falls back on a "copy & remove" procedure in this situation. export fn rename(oldpath: str, newpath: str) (void | fs::error) = fs::rename(cwd, oldpath, newpath); // Moves a file. This will use [[rename]] if possible, and will fall back to // copy and remove if necessary. export fn move(oldpath: str, newpath: str) (void | fs::error) = fs::move(cwd, oldpath, newpath); // Creates an [[fs::iterator]] for a given directory to read its contents. The // user should call [[fs::next]] to enumerate entries, and [[fs::finish]] when // done using the object. export fn iter(path: str) (*fs::iterator | fs::error) = fs::iter(cwd, path); // Reads all entries from a directory. The caller must free the return value // with [[fs::dirents_free]]. export fn readdir(path: str) ([]fs::dirent | fs::error) = fs::readdir(cwd, path); // Returns file information for a given path. If the target is a symlink, // information is returned about the link, not its target. export fn stat(path: str) (fs::filestat | fs::error) = fs::stat(cwd, path); // Returns file information for an [[io::file]]. export fn fstat(fd: io::file) (fs::filestat | fs::error) = fs::fstat(cwd, fd); // Returns true if a node exists at the given path, or false if not. // // Note that testing for file existence before using the file can often lead to // race conditions. If possible, prefer to simply attempt to use the file (e.g. // via "open"), and handle the resulting error should the file not exist. export fn exists(path: str) bool = fs::exists(cwd, path); // Creates a directory. export fn mkdir(path: str, mode: fs::mode) (void | fs::error) = fs::mkdir(cwd, path, mode); // Creates a directory, and all non-extant directories in its path. export fn mkdirs(path: str, mode: fs::mode) (void | fs::error) = fs::mkdirs(cwd, path, mode); // Removes a directory. The target directory must be empty; see [[rmdirall]] to // remove its contents as well. export fn rmdir(path: str) (void | fs::error) = fs::rmdir(cwd, path); // Removes a directory, and anything in it. export fn rmdirall(path: str) (void | fs::error) = fs::rmdirall(cwd, path); // Changes mode flags on a file or directory. Type bits are discared. export fn chmod(path: str, mode: fs::mode) (void | fs::error) = fs::chmod(cwd, path, mode); // Changes mode flags on a [[io::file]]. Type bits are discared. export fn fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = fs::fchmod(cwd, fd, mode); // Changes ownership of a file. export fn chown(path: str, uid: uint, gid: uint) (void | fs::error) = fs::chown(cwd, path, uid, gid); // Changes ownership of a [io::file]]. export fn fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = fs::fchown(cwd, fd, uid, gid); // Changes the access and modification time of a file. A void value will leave // the corresponding time unchanged. export fn chtimes( path: str, atime: (time::instant | void), mtime: (time::instant | void) ) (void | fs::error) = fs::chtimes(cwd, path, atime, mtime); // Changes the access and modification time of an [[io::file]]. A void value // will leave the corresponding time unchanged. export fn fchtimes( fd: io::file, atime: (time::instant | void), mtime: (time::instant | void) ) (void | fs::error) = fs::fchtimes(cwd, fd, atime, mtime); // Resolves a path to its absolute, normalized value. Relative paths will be // rooted (if supported by the host filesystem), and "." and ".." components // will be reduced. This function does not follow symlinks; see [[realpath]] if // you need this behavior. The return value is statically allocated; use // [[strings::dup]] to extend its lifetime. export fn resolve(path: str) str = fs::resolve(cwd, path); // Returns the path referred to by a symbolic link. The return value is // statically allocated and will be overwritten on subsequent calls. export fn readlink(path: str) (str | fs::error) = fs::readlink(cwd, path); // Creates a new (hard) link at 'new' for the file at 'old'. export fn link(old: str, new: str) (void | fs::error) = fs::link(cwd, old, new); // Creates a new symbolic link at 'path' which points to 'target'. export fn symlink(target: str, path: str) (void | fs::error) = fs::symlink(cwd, target, path); // Opens a file. // // [[fs::flag::CREATE]] isn't very useful with this function, since the new // file's mode is set to zero. For this use-case, use [[create]] instead. export fn open( path: str, flags: fs::flag = fs::flag::RDONLY, ) (io::file | fs::error) = fs::open_file(cwd, path, flags); // Creates a new file with the given mode if it doesn't already exist and opens // it for writing. // // Only the permission bits of the mode are used. If other bits are set, they // are discarded. // // To create a file without opening it, see [[mkfile]]. export fn create( path: str, mode: fs::mode, flags: fs::flag = fs::flag::WRONLY | fs::flag::TRUNC, ) (io::file | fs::error) = fs::create_file(cwd, path, mode, flags); // Canonicalizes a path in this filesystem by resolving all symlinks and // collapsing any "." or ".." path components. // // This function is a thin shim over [[fs::realpath]], and the return value is // statically allocated by [[fs::realpath]]. Thus, calls to this function or to // [[fs::realpath]] will overwrite the return value of either function. export fn realpath(path: str) (str | fs::error) = fs::realpath(cwd, path); // Opens a directory as a filesystem. export fn diropen(path: str) (*fs::fs | fs::error) = { const file = open(path, fs::flag::DIRECTORY | fs::flag::RDONLY)?; return dirfdopen(file); }; hare-0.24.2/path/000077500000000000000000000000001464473310100134555ustar00rootroot00000000000000hare-0.24.2/path/+freebsd.ha000066400000000000000000000004001464473310100154460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Platform-specific path separator byte. export def SEP: u8 = '/'; const sepstr: str = "/"; // Maximum length of a file path for this platform. export def MAX: size = 4095; hare-0.24.2/path/+linux.ha000066400000000000000000000004001464473310100151730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Platform-specific path separator byte. export def SEP: u8 = '/'; const sepstr: str = "/"; // Maximum length of a file path for this platform. export def MAX: size = 4095; hare-0.24.2/path/+netbsd.ha000066400000000000000000000004171464473310100153230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Platform-specific path separator byte. export def SEP: u8 = '/'; const sepstr: str = "/"; // Maximum length of a file path for this platform. export def MAX = rt::PATH_MAX - 1; hare-0.24.2/path/+openbsd.ha000066400000000000000000000004251464473310100154750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; // Platform-specific path separator byte. export def SEP: u8 = '/'; const sepstr: str = "/"; // Maximum length of a file path for this platform. export def MAX: size = rt::PATH_MAX - 1; hare-0.24.2/path/README000066400000000000000000000026011464473310100143340ustar00rootroot00000000000000The path module provides utilities for working with filesystem paths. Note that Hare expects paths to be valid UTF-8 strings. If you require the use of non-UTF-8 paths (ideally for only as long as it takes to delete or rename those files), see the low-level functions available from [[rt::]]. Use of the [[buffer]] type is recommended for efficient and consistent manipulation of filesystem paths. The path will always be normalized, which is to say that it will not include any of the following: - Redundant ".." components - Redundant path separators - Any "." components, except in the case of "." Assuming that [[SEP]] is '/', "/usr//bin/../bin/./hare/" becomes "/usr/bin/hare" and "../../foo/bar" is unchanged. Different [[fs::fs]] implementations may have different rules for normalizing paths. For use-cases in which this is relevant, [[fs::resolve]] should be used instead. The buffer object includes an array of length [[MAX]], which can be somewhat large; on Linux it's 4095 bytes. You can allocate this on the stack in most cases, but you may prefer to allocate it elsewhere depending on your needs. Functions in this module return [[too_long]] if the buffer's capacity would be exceeded. // Stack allocated let buf = path::init()!; // Statically allocated static let buf = path::buffer { ... }; path::set(&buf)!; // Heap allocated let buf = alloc(path::init()!); defer free(buf); hare-0.24.2/path/buffer.ha000066400000000000000000000033401464473310100152400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; export type buffer = struct { buf: [MAX]u8, end: size, }; // Initializes a new path buffer. export fn init(items: str...) (buffer | error) = { let buf = buffer { ... }; push(&buf, items...)?; return buf; }; // Sets the value of a path buffer to a list of components, overwriting any // previous value. Returns the new string value of the path. export fn set(buf: *buffer, items: str...) (str | error) = { buf.end = 0; return push(buf, items...); }; // Returns the current path stored in this buffer. // The return value is borrowed from the buffer. Use [[strings::dup]] to // extend the lifetime of the string. export fn string(buf: *buffer) str = { if (buf.end == 0) return "."; return strings::fromutf8_unsafe(buf.buf[..buf.end]); }; // Check if a path is an absolute path. export fn abs(path: (*buffer | str)) bool = match (path) { case let path: str => return strings::hasprefix(path, sepstr); case let buf: *buffer => return 0 < buf.end && buf.buf[0] == SEP; }; // Check if a path is the root directory. export fn isroot(path: (*buffer | str)) bool = match (path) { case let path: str => return path == sepstr; case let buf: *buffer => return buf.end == 1 && buf.buf[0] == SEP; }; // Replaces all instances of '/' in a string with [[SEP]]. The result is // statically-allocated. export fn local(path: str) str = { static let buf: [MAX]u8 = [0...]; return _local(path, &buf); }; fn _local(path: str, buf: *[MAX]u8) str = { let buf = buf[..0]; const bytes = strings::toutf8(path); for (let byte .. bytes) { if (byte == '/') { static append(buf, SEP); } else { static append(buf, byte); }; }; return strings::fromutf8(buf)!; }; hare-0.24.2/path/error.ha000066400000000000000000000014431464473310100151220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Returned when adding an extension if the path is root, or the final path // segment consists entirely of dots. export type cant_extend = !void; // Returned when a path buffer would have overflowed. export type too_long = !void; // Returned when [[trimprefix]] receives a prefix that is not present. export type not_prefix = !void; // Represents an error during a path manipulation export type error = !(cant_extend | too_long | not_prefix); // Convert an [[error]] into a descriptive string. export fn strerror(e: error) str = match (e) { case cant_extend => return "Can't add extension (filename is root or all dots)"; case too_long => return "Path buffer overflow"; case not_prefix => return "Prefix not present"; }; hare-0.24.2/path/ext_stack.ha000066400000000000000000000110131464473310100157500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use strings; // Add extensions onto the end of the final path segment. The separating '.' // will be inserted for you. If the final path segment consists entirely of dots // or the path is root, this function will return [[cant_extend]]. export fn push_ext(buf: *buffer, exts: str...) (str | error) = { match (peek(buf)) { case void => return cant_extend; case let s: str => if (strings::ltrim(s, '.') == "") return cant_extend; }; for (let ext .. exts) { const newend = buf.end + 1 + len(ext); if (MAX < newend) return too_long; buf.buf[buf.end] = '.'; buf.buf[buf.end+1..newend] = strings::toutf8(ext); buf.end = newend; }; return string(buf); }; // Remove and return the final extension in a path. The result will not // include the leading '.'. The result is borrowed from the buffer. Leading dots // will be ignored when looking for extensions, such that ".ssh" isn't // considered to have any extensions. export fn pop_ext(buf: *buffer) (str | void) = { const ext = split_ext(buf); buf.end = ext.0; return ext.1; }; // Examine the final extension in a path. The result will not // include the leading '.'. The result is borrowed from the buffer. Leading dots // will be ignored when looking for extensions, such that ".ssh" isn't // considered to have any extensions. export fn peek_ext(buf: *buffer) (str | void) = split_ext(buf).1; // helper function, returns (end of non-extension, extension string) fn split_ext(buf: *buffer) (size, (str | void)) = match (peek(buf)) { case void => return (buf.end, void); case let s: str => const bs = strings::toutf8(s); bs = bytes::ltrim(bs, '.'); match (bytes::rindex(bs, '.')) { case void => return (buf.end, void); case let i: size => return (buf.end - len(bs) + i, strings::fromutf8_unsafe(bs[i+1..])); }; }; // Remove and return all the extensions in a path. The result will not // include the leading '.', but will include separating dots. Leading dots // will be ignored when looking for extensions, such that ".ssh" isn't // considered to have any extensions. The result is borrowed from the buffer. export fn pop_exts(buf: *buffer) (str | void) = { const ext = split_exts(buf); buf.end = ext.0; return ext.1; }; // Examine all the extensions in a path. The result will not include the // leading '.', but will include separating dots. Leading dots will // be ignored when looking for extensions, such that ".ssh" isn't considered // to have any extensions. The result is borrowed from the buffer. export fn peek_exts(buf: *buffer) (str | void) = split_exts(buf).1; // helper function, returns (end of non-extension, extension string) fn split_exts(buf: *buffer) (size, (str | void)) = match (peek(buf)) { case void => return (buf.end, void); case let s: str => const bs = strings::toutf8(s); bs = bytes::ltrim(bs, '.'); match (bytes::index(bs, '.')) { case void => return (buf.end, void); case let i: size => return (buf.end - len(bs) + i, strings::fromutf8_unsafe(bs[i+1..])); }; }; @test fn ext() void = { // push_ext let buf = init()!; assert(push_ext(&buf, "bash") is cant_extend); set(&buf, sepstr)!; assert(push_ext(&buf, "bash") is cant_extend); set(&buf, "....")!; assert(push_ext(&buf, "bash") is cant_extend); set(&buf, "bashrc")!; assert(push_ext(&buf, "bash") as str == "bashrc.bash"); set(&buf, ".bashrc")!; assert(push_ext(&buf, "bash") as str == ".bashrc.bash"); // pop_ext set(&buf)!; assert(pop_ext(&buf) is void); set(&buf, "..")!; assert(pop_ext(&buf) is void); set(&buf, sepstr)!; assert(pop_ext(&buf) is void); set(&buf, "index.html.tmpl")!; assert(pop_ext(&buf) as str == "tmpl"); assert(string(&buf) == "index.html"); assert(pop_ext(&buf) as str == "html"); assert(string(&buf) == "index"); assert(pop_ext(&buf) is void); assert(string(&buf) == "index"); set(&buf, ".secret.tar.gz")!; assert(pop_ext(&buf) as str == "gz"); assert(string(&buf) == ".secret.tar"); assert(pop_ext(&buf) as str == "tar"); assert(string(&buf) == ".secret"); assert(pop_ext(&buf) is void); assert(string(&buf) == ".secret"); set(&buf, "..ext")!; assert(pop_ext(&buf) is void); assert(string(&buf) == "..ext"); // pop_exts set(&buf, "index.html.tmpl")!; assert(pop_exts(&buf) as str == "html.tmpl"); assert(string(&buf) == "index"); assert(pop_exts(&buf) is void); assert(string(&buf) == "index"); set(&buf, ".secret.tar.gz")!; assert(pop_exts(&buf) as str == "tar.gz"); assert(string(&buf) == ".secret"); assert(pop_ext(&buf) is void); assert(string(&buf) == ".secret"); }; hare-0.24.2/path/iter.ha000066400000000000000000000066231464473310100147410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use strings; export type iterator = struct { cur: []u8, reverse: bool, }; // Returns an [[iterator]] which yields each component of a path, moving down // through child dirs. If the path is absolute, the first component will be // the root. The iterator can be copied to save its state. export fn iter(buf: *buffer) iterator = iterator { cur = buf.buf[..buf.end], reverse = false, }; // Returns an [[iterator]] which yields each component of a path, moving up // through parent dirs. If the path is absolute, the last component will be // the root. The iterator can be copied to save its state. export fn riter(buf: *buffer) iterator = iterator { cur = buf.buf[..buf.end], reverse = true, }; // Returns the next path component from an [[iterator]], or void if none // remain. Does not advance the iterator. export fn peekiter(it: *iterator) (str | void) = { if (len(it.cur) == 0) return void; const (result, remaining) = split_iter(it); return strings::fromutf8_unsafe(result); }; // Returns the next path component from an [[iterator]], or done if none // remain. Advances the iterator. export fn nextiter(it: *iterator) (str | done) = { if (len(it.cur) == 0) return done; const (result, remaining) = split_iter(it); it.cur = remaining; return strings::fromutf8_unsafe(result); }; // helper function for nextiter and peekiter, returns (result, remaining) fn split_iter(it: *iterator) ([]u8, []u8) = { if (it.reverse) { match (bytes::rindex(it.cur, SEP)) { case let sep: size => let res = it.cur[sep+1..]; if (sep == 0) { if (len(it.cur) == 1) { res = it.cur; // return the root dir } else { sep = 1; // leave the root for next }; }; return (res, it.cur[..sep]); case void => return (it.cur, it.cur[..0]); }; } else { match (bytes::index(it.cur, SEP)) { case let i: size => return (it.cur[..if (i == 0) 1 else i], it.cur[i+1..]); case void => return (it.cur, it.cur[..0]); }; }; }; // Gets the remaining path from an iterator, without advancing the iterator. export fn iterrem(it: *iterator) str = strings::fromutf8_unsafe(it.cur); @test fn iter() void = { const buf = init(local("/foo/bar/baz"))!; let i = iter(&buf); assert(nextiter(&i) as str == local("/")); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) as str == "bar"); assert(nextiter(&i) as str == "baz"); assert(nextiter(&i) is done); i = riter(&buf); assert(nextiter(&i) as str == "baz"); assert(nextiter(&i) as str == "bar"); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) as str == local("/")); assert(nextiter(&i) is done); set(&buf, local("foo/bar/baz"))!; i = iter(&buf); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) as str == "bar"); assert(nextiter(&i) as str == "baz"); assert(nextiter(&i) is done); i = riter(&buf); assert(nextiter(&i) as str == "baz"); assert(nextiter(&i) as str == "bar"); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) is done); set(&buf, "foo")!; i = iter(&buf); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) is done); i = riter(&buf); assert(nextiter(&i) as str == "foo"); assert(nextiter(&i) is done); set(&buf, local("/"))!; i = iter(&buf); assert(nextiter(&i) as str == local("/")); assert(nextiter(&i) is done); i = riter(&buf); assert(nextiter(&i) as str == local("/")); assert(nextiter(&i) is done); }; hare-0.24.2/path/posix.ha000066400000000000000000000050041464473310100151300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use strings; // These functions have been confined here to POSIX jail. They are // POSIX-compliant, for their sins, but they do not fit in semantically // with the other stack-paradigm functions. Hence this POSIX-complaint. // They are based primarily off of `man 1p basename/dirname`, and secondarily // off of the examples in `man 3p basename`. // A POSIX-compliant implementation of dirname. See the POSIX specification // for more information. Note that this function does *not* normalize the // input. The return value is either borrowed from the input or statically // allocated; use [[strings::dup]] to extend its lifetime. export fn dirname(path: const str) const str = { let path = strings::toutf8(path); if (len(path) == 0) return "."; path = bytes::rtrim(path, SEP); if (len(path) == 0) return sepstr; match (bytes::rindex(path, SEP)) { case void => return "."; case let z: size => path = path[..z]; }; path = bytes::rtrim(path, SEP); if (len(path) == 0) return sepstr; return strings::fromutf8_unsafe(path); }; // A POSIX-compliant implementation of basename. See the POSIX specification // for more information. Note that this function does *not* normalize the // input. The return value is either borrowed from the input or statically // allocated; use [[strings::dup]] to extend its lifetime. export fn basename(path: const str) const str = { let path = strings::toutf8(path); if (len(path) == 0) return "."; path = bytes::rtrim(path, SEP); if (len(path) == 0) return sepstr; match (bytes::rindex(path, SEP)) { case void => void; case let z: size => path = path[z+1..]; }; return strings::fromutf8_unsafe(path); }; @test fn dirname_basename() void = { const table = [ // input , dirname , basename ["usr" , "." , "usr" ], ["usr/" , "." , "usr" ], ["" , "." , "." ], ["/" , "/" , "/" ], ["//" , "/" , "/" ], // implementation defined ["///" , "/" , "/" ], ["/usr/" , "/" , "usr" ], ["/usr/lib" , "/usr" , "lib" ], ["//usr//lib//" , "//usr" , "lib" ], ["/home//dwc//test", "/home//dwc", "test"], ]; for (let i = 0z; i < len(table); i += 1) { let input: [MAX]u8 = [0...]; const input = _local(table[i][0], &input); assert(dirname(input) == local(table[i][1])); assert(basename(input) == local(table[i][2])); }; }; hare-0.24.2/path/prefix.ha000066400000000000000000000047101464473310100152660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use strings; // Add a prefix to a buffer. The buffer will be modified, and it will // remain normalized, so any ".." components in the original buffer may be // collapsed. export fn prepend(buf: *buffer, prefix: str...) (str | error) = { static let tmp = buffer { ... }; tmp = *buf; set(buf, prefix...)?; return push(buf, string(&tmp)); }; // Returns a buffer without a prefix. The prefix is normalized before // processing, and this function will return [[too_long]] if the prefix is // longer than [[MAX]]. If the prefix is not present, returns [[not_prefix]]. // The resulting path will always be relative. // // This function does not modify the buffer. See [[popprefix]]. export fn trimprefix(buf: *buffer, prefix: str) (str | error) = { const start = splitprefix(buf, prefix)?; if (start == buf.end) return "."; return strings::fromutf8_unsafe(buf.buf[start..buf.end]); }; // Equivalent to [[trimprefix]], but modifies the buffer in the process. export fn popprefix(buf: *buffer, prefix: str) (str | error) = { const start = splitprefix(buf, prefix)?; static delete(buf.buf[..][..start]); buf.end -= start; return string(buf); }; // helper function for trimprefix and popprefix, returns the new // start of the buffer, or an error. fn splitprefix(buf: *buffer, prefix: str) (size | error) = { let pref = init(prefix)?; if (pref.end == 0) { if (abs(buf)) return not_prefix; } else if (pref.end < buf.end && pref.buf[pref.end-1] != SEP) { pref.buf[pref.end] = SEP; pref.end += 1; }; if (bytes::hasprefix(buf.buf[..buf.end], pref.buf[..pref.end])) { return pref.end; } else { return not_prefix; }; }; @test fn prepend() void = { const buf = init("a")!; // relative assert(prepend(&buf, "apple")! == local("apple/a")); assert(popprefix(&buf, "b") is error); assert(popprefix(&buf, "appl") is error); assert(popprefix(&buf, local("/")) is error); assert(popprefix(&buf, ".")! == local("apple/a")); assert(popprefix(&buf, "apple")! == "a"); assert(popprefix(&buf, "a")! == "."); // absolute assert(prepend(&buf, local("/apple/a"))! == local("/apple/a")); assert(popprefix(&buf, local("/b")) is error); assert(popprefix(&buf, local("/appl")) is error); assert(popprefix(&buf, ".") is error); assert(popprefix(&buf, local("/"))! == local("apple/a")); assert(prepend(&buf, local("/"))! == local("/apple/a")); assert(popprefix(&buf, local("/apple/a"))! == "."); }; hare-0.24.2/path/stack.ha000066400000000000000000000120621464473310100150750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use strings; // Appends path elements onto the end of a path buffer. // Returns the new string value of the path. export fn push(buf: *buffer, items: str...) (str | error) = { for (let item .. items) { let elem = strings::toutf8(item); for (true) match (bytes::index(elem, SEP)) { case void => buf.end = appendnorm(buf, elem)?; break; case let j: size => if (j == 0 && buf.end == 0) { buf.buf[0] = SEP; buf.end = 1; } else { buf.end = appendnorm(buf, elem[..j])?; }; elem = elem[j+1..]; }; }; return string(buf); }; const dot: []u8 = ['.']; const dotdot: []u8 = ['.', '.']; // append a path segment to a buffer, preserving normalization. // seg must not contain any [[SEP]]s. if you need to make the path absolute, you // should do that manually. returns the new end of the buffer. // x + => x // x + . => x // / + .. => / // + .. => .. // x/.. + .. => x/../.. // x/y + .. => x // x + y => x/y fn appendnorm(buf: *buffer, seg: []u8) (size | error) = { if (len(seg) == 0 || bytes::equal(dot, seg)) return buf.end; if (bytes::equal(dotdot, seg)) { if (isroot(buf)) return buf.end; const isep = match (bytes::rindex(buf.buf[..buf.end], SEP)) { case void => yield 0z; case let i: size => yield i + 1; }; if (buf.end == 0 || bytes::equal(buf.buf[isep..buf.end], dotdot)) { return appendlit(buf, dotdot)?; } else { return if (isep <= 1) isep else isep - 1; }; } else { return appendlit(buf, seg)?; }; }; // append a segment to a buffer, *without* preserving normalization. // returns the new end of the buffer fn appendlit(buf: *buffer, bs: []u8) (size | error) = { let newend = buf.end; if (buf.end == 0 || isroot(buf)) { if (MAX < buf.end + len(bs)) return too_long; } else { if (MAX < buf.end + len(bs) + 1) return too_long; buf.buf[buf.end] = SEP; newend += 1; }; buf.buf[newend..newend+len(bs)] = bs; return newend + len(bs); }; @test fn push() void = { let buf = init()!; assert(string(&buf) == "."); // current dir invariants assert(push(&buf, "")! == "."); assert(push(&buf, ".")! == "."); // parent dir invariants assert(push(&buf, "..")! == ".."); assert(push(&buf, "")! == ".."); assert(push(&buf, ".")! == ".."); assert(push(&buf, local("/"))! == ".."); assert(set(&buf)! == "."); // root dir invariants assert(push(&buf, local("/"))! == local("/")); assert(push(&buf, "")! == local("/")); assert(push(&buf, ".")! == local("/")); assert(push(&buf, "..")! == local("/")); assert(push(&buf, local("/"))! == local("/")); assert(set(&buf)! == "."); // regular path and parent assert(push(&buf, "foo")! == "foo"); assert(push(&buf, ".")! == "foo"); assert(push(&buf, local("/"))! == "foo"); assert(push(&buf, "..")! == "."); // multiple segments assert(push(&buf, "a", "b")! == local("a/b")); assert(push(&buf, "..", "c")! == local("a/c")); assert(push(&buf, "..")! == "a"); assert(push(&buf, local("/d"))! == local("a/d")); assert(push(&buf, "..", "..")! == "."); // multiple segments, absolute assert(push(&buf, local("/"), "a", "b")! == local("/a/b")); assert(push(&buf, "..", "c")! == local("/a/c")); assert(push(&buf, "..")! == local("/a")); assert(push(&buf, local("/d"))! == local("/a/d")); assert(push(&buf, "..", "..", "..")! == local("/")); }; // Examine the final path segment in a buffer. // Returns void if the path is empty or is the root dir. export fn peek(buf: *const buffer) (str | void) = split(buf).1; // Remove and return the final path segment in a buffer. // Returns void if the path is empty or is the root dir. export fn pop(buf: *buffer) (str | void) = { const (end, res) = split(buf); buf.end = end; return res; }; // helper function for pop/peek, returns (new end of buffer, result) fn split(buf: *buffer) (size, (str | void)) = { if (buf.end == 0 || isroot(buf)) return (buf.end, void); match (bytes::rindex(buf.buf[..buf.end], SEP)) { case void => return (0z, strings::fromutf8_unsafe(buf.buf[..buf.end])); case let i: size => return ( if (i == 0) 1z else i, strings::fromutf8_unsafe(buf.buf[i+1..buf.end]), ); }; }; @test fn pop() void = { // empty let buf = init()!; assert(pop(&buf) is void); assert(string(&buf) == "."); // root dir buf.end = 0; push(&buf, local("/"))!; assert(pop(&buf) is void); assert(string(&buf) == local("/")); // relative file buf.end = 0; push(&buf, "foo")!; assert(pop(&buf) as str == "foo"); assert(string(&buf) == "."); // abs file buf.end = 0; push(&buf, local("/foo"))!; assert(pop(&buf) as str == "foo"); assert(string(&buf) == local("/")); }; // Returns the parent directory for a given path, without modifying the buffer. // If the path is the root directory, the root directory is returned. The value // is either borrowed from the input or statically allocated; use // [[strings::dup]] to extend its lifetime or modify it. export fn parent(buf: *const buffer) (str | error) = { const newend = appendnorm(buf, dotdot)?; if (newend == 0) return "."; return strings::fromutf8_unsafe(buf.buf[..newend]); }; hare-0.24.2/regex/000077500000000000000000000000001464473310100136335ustar00rootroot00000000000000hare-0.24.2/regex/+test.ha000066400000000000000000000665571464473310100152220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use strings; use types; type matchres = enum { MATCH, NOMATCH, ERROR }; fn run_find_case( expr: str, string: str, expected: matchres, start: int, end: int ) void = { const re = match (compile(expr)) { case let re: regex => yield re; case let e: error => if (expected == matchres::MATCH) { fmt::errorln(e)!; fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it errored", expr, string)!; abort(); }; if (expected == matchres::NOMATCH) { fmt::errorln(e)!; fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it errored", expr, string)!; abort(); }; return; }; if (expected == matchres::ERROR) { fmt::errorfln("Expected expression /{}/ to have error caught during compilation, but it did not", expr)!; abort(); }; defer finish(&re); const result = find(&re, string); defer result_free(result); if (len(result) == 0) { if (expected == matchres::MATCH) { fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it did not", expr, string)!; abort(); }; return; } else if (expected == matchres::NOMATCH) { fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did", expr, string)!; abort(); }; if (start: size != result[0].start) { fmt::errorfln("Expected start of main capture to be {} but it was {}", start, result[0].start)!; abort(); }; if (end: size != result[0].end) { fmt::errorfln("Expected end of main capture to be {} but it was {}", end, result[0].end)!; abort(); }; }; fn run_submatch_case( expr: str, string: str, expected: matchres, targets: []str ) void = { const re = compile(expr)!; defer finish(&re); const result = find(&re, string); defer result_free(result); assert(len(result) == len(targets), "Invalid number of captures"); for (let i = 0z; i < len(targets); i += 1) { assert(targets[i] == result[i].content, "Invalid capture"); }; }; fn run_findall_case( expr: str, string: str, expected: matchres, targets: []str ) void = { const re = match (compile(expr)) { case let re: regex => yield re; case let e: error => if (expected != matchres::ERROR) { fmt::errorln(e)!; fmt::errorfln("Expected expression /{}/ to compile, but it errored", expr)!; abort(); }; return; }; defer finish(&re); if (expected == matchres::ERROR) { fmt::errorfln("Expected expression /{}/ to have error caught during compilation, but it did not", expr)!; abort(); }; const results = findall(&re, string); if (len(results) == 0 && expected == matchres::MATCH) { fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it did not", expr, string)!; abort(); }; defer result_freeall(results); if (expected == matchres::NOMATCH) { fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did", expr, string)!; abort(); }; if (len(targets) != len(results)) { fmt::errorfln("Expected expression /{}/ to find {} results but found {}", expr, len(targets), len(results))!; abort(); }; for (let i = 0z; i < len(results); i += 1) { if (results[i][0].content != targets[i]) { fmt::errorfln("Expected submatch of expression /{}/ to be {} but it was {}", expr, targets[i], results[i][0].content)!; abort(); }; }; }; fn run_replace_case( expr: str, string: str, target: str, n: size, expected: (str | void), ) void = { const re = match (compile(expr)) { case let re: regex => yield re; case let e: error => fmt::errorln(e)!; fmt::errorfln("Expected expression /{}/ to compile, but it errored", expr)!; abort(); }; defer finish(&re); match (replacen(&re, string, target, n)) { case let e: error => if (expected is str) { fmt::errorln(e)!; fmt::errorfln("expr=/{}/ string=\"{}\" target=\"{}\" n={} expected=\"{}\"", expr, string, target, n, expected as str)!; abort(); }; case let s: str => defer free(s); if (expected is void) { fmt::errorln("Expected replace to fail, but it did not")!; fmt::errorfln("expr=/{}/ string=\"{}\" target=\"{}\" n={} return=\"{}\"", expr, string, target, n, s)!; abort(); }; if (expected as str != s) { fmt::errorfln("expr=/{}/ string=\"{}\" target=\"{}\" n={} expected=\"{}\" return=\"{}\"", expr, string, target, n, expected as str, s)!; abort(); }; }; }; fn run_rawreplace_case( expr: str, string: str, target: str, n: size, expected: str, ) void = { const re = match (compile(expr)) { case let re: regex => yield re; case let e: error => fmt::errorln(e)!; fmt::errorfln("Expected expression /{}/ to compile, but it errored", expr)!; abort(); }; defer finish(&re); const s = rawreplacen(&re, string, target, n); defer free(s); if (expected != s) { fmt::errorfln("expr=/{}/ string=\"{}\" target=\"{}\" n={} expected=\"{}\" return=\"{}\"", expr, string, target, n, expected, s)!; abort(); }; }; @test fn find() void = { const cases = [ // literals (`^$`, "", matchres::MATCH, 0, 0), (``, "", matchres::MATCH, 0, -1), (`abcd`, "abcd", matchres::MATCH, 0, -1), (`abc`, "abcd", matchres::MATCH, 0, 3), (`bcd`, "abcd", matchres::MATCH, 1, 4), (`^abc$`, "abc", matchres::MATCH, 0, -1), (`^abc$`, "axc", matchres::NOMATCH, 0, -1), // . (`^.$`, "x", matchres::MATCH, 0, 1), (`^.$`, "y", matchres::MATCH, 0, 1), (`^.$`, "", matchres::NOMATCH, 0, 1), // + (`^a+$`, "a", matchres::MATCH, 0, 1), (`^a+$`, "aaa", matchres::MATCH, 0, 3), (`^a+$`, "", matchres::NOMATCH, 0, 0), (`^(abc)+$`, "abc", matchres::MATCH, 0, 3), (`^(abc)+$`, "abcabc", matchres::MATCH, 0, 6), (`^(abc)+$`, "", matchres::NOMATCH, 0, 0), // * (`^a*$`, "", matchres::MATCH, 0, 0), (`^a*$`, "aaaa", matchres::MATCH, 0, 4), (`^a*$`, "b", matchres::NOMATCH, 0, 0), (`^(abc)*$`, "", matchres::MATCH, 0, 0), (`^(abc)*$`, "abc", matchres::MATCH, 0, 3), (`^(abc)*$`, "abcabc", matchres::MATCH, 0, 6), (`^(abc)*$`, "bbb", matchres::NOMATCH, 0, 3), // ? (`^a?$`, "", matchres::MATCH, 0, 0), (`^a?$`, "a", matchres::MATCH, 0, 1), (`^a?$`, "b", matchres::NOMATCH, 0, 0), (`^(abc)?$`, "", matchres::MATCH, 0, 0), (`^(abc)?$`, "abc", matchres::MATCH, 0, 3), (`^(abc)?$`, "bbb", matchres::NOMATCH, 0, 0), // ^ and $ (`^a*`, "aaaa", matchres::MATCH, 0, 4), (`a*$`, "aaaa", matchres::MATCH, 0, 4), (`^a*$`, "aaaa", matchres::MATCH, 0, 4), (`a*`, "aaaa", matchres::MATCH, 0, 4), (`b*`, "aaaabbbb", matchres::MATCH, 4, 8), (`^b*`, "aaaabbbb", matchres::MATCH, 0, 0), (`b*$`, "aaaabbbb", matchres::MATCH, 4, 8), // (a|b) (`^(cafe|b)x$`, "cafex", matchres::MATCH, 0, 5), (`^(cafe|b)x$`, "bx", matchres::MATCH, 0, 2), (`^(cafe|b)x$`, "XXXx", matchres::NOMATCH, 0, 0), (`^(cafe|b)x$`, "bx", matchres::MATCH, 0, 2), ( `^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$`, "Jagdhaftpflichtversicherungsbetrag", matchres::MATCH, 0, -1 ), ( `^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$`, "Jagdhaftpflichtversicherungsbetrug", matchres::NOMATCH, 0, -1 ), ( `^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$`, "Jagdversicherungspolice", matchres::NOMATCH, 0, -1 ), (`)`, "", matchres::ERROR, 0, 0), // [abc] (`^test[abc]$`, "testa", matchres::MATCH, 0, -1), (`^test[abc]$`, "testb", matchres::MATCH, 0, -1), (`^test[abc]$`, "testc", matchres::MATCH, 0, -1), (`^test[abc]$`, "testd", matchres::NOMATCH, 0, -1), (`^test[abc]*$`, "test", matchres::MATCH, 0, -1), (`^test[abc]*$`, "testa", matchres::MATCH, 0, -1), (`^test[abc]*$`, "testaaa", matchres::MATCH, 0, -1), (`^test[abc]*$`, "testabc", matchres::MATCH, 0, -1), (`^test[abc]?$`, "test", matchres::MATCH, 0, -1), (`^test[abc]?$`, "testa", matchres::MATCH, 0, -1), (`^test[abc]+$`, "testa", matchres::MATCH, 0, -1), (`^test[abc]+$`, "test", matchres::NOMATCH, 0, -1), (`^test[]abc]$`, "test]", matchres::MATCH, 0, -1), (`^test[[abc]$`, "test[", matchres::MATCH, 0, -1), (`^test[^abc]$`, "testd", matchres::MATCH, 0, -1), (`^test[^abc]$`, "test!", matchres::MATCH, 0, -1), (`^test[^abc]$`, "testa", matchres::NOMATCH, 0, -1), (`^test[^abc]$`, "testb", matchres::NOMATCH, 0, -1), (`^test[^abc]$`, "testc", matchres::NOMATCH, 0, -1), (`^test[^]abc]$`, "test]", matchres::NOMATCH, 0, -1), (`^test[^abc[]$`, "test[", matchres::NOMATCH, 0, -1), (`^test[^abc]*$`, "testd", matchres::MATCH, 0, -1), (`^test[^abc]*$`, "testqqqqq", matchres::MATCH, 0, -1), (`^test[^abc]*$`, "test", matchres::MATCH, 0, -1), (`^test[^abc]*$`, "testc", matchres::NOMATCH, 0, -1), (`^test[^abc]?$`, "test", matchres::MATCH, 0, -1), (`^test[^abc]?$`, "testd", matchres::MATCH, 0, -1), (`^test[^abc]?$`, "testc", matchres::NOMATCH, 0, -1), (`^test[^abc]+$`, "testd", matchres::MATCH, 0, -1), (`^test[^abc]+$`, "testddd", matchres::MATCH, 0, -1), (`^test[^abc]+$`, "testc", matchres::NOMATCH, 0, -1), (`^test[^abc]+$`, "testcccc", matchres::NOMATCH, 0, -1), (`^test[a-c]$`, "testa", matchres::MATCH, 0, -1), (`^test[a-c]$`, "testb", matchres::MATCH, 0, -1), (`^test[a-c]$`, "testc", matchres::MATCH, 0, -1), (`^test[a-c]$`, "testd", matchres::NOMATCH, 0, -1), (`^test[a-c]$`, "test!", matchres::NOMATCH, 0, -1), (`^test[a-c]$`, "test-", matchres::NOMATCH, 0, -1), (`^test[-a-c]$`, "test-", matchres::MATCH, 0, -1), (`^test[a-c-]$`, "test-", matchres::MATCH, 0, -1), (`^test[a-c]*$`, "test", matchres::MATCH, 0, -1), (`^test[a-c]*$`, "testa", matchres::MATCH, 0, -1), (`^test[a-c]*$`, "testabb", matchres::MATCH, 0, -1), (`^test[a-c]*$`, "testddd", matchres::NOMATCH, 0, -1), (`^test[a-c]?$`, "test", matchres::MATCH, 0, -1), (`^test[a-c]?$`, "testb", matchres::MATCH, 0, -1), (`^test[a-c]?$`, "testd", matchres::NOMATCH, 0, -1), (`^test[a-c]+$`, "test", matchres::NOMATCH, 0, -1), (`^test[a-c]+$`, "testbcbc", matchres::MATCH, 0, -1), (`^test[a-c]+$`, "testd", matchres::NOMATCH, 0, -1), (`^test[^a-c]$`, "testa", matchres::NOMATCH, 0, -1), (`^test[^a-c]$`, "testb", matchres::NOMATCH, 0, -1), (`^test[^a-c]$`, "testc", matchres::NOMATCH, 0, -1), (`^test[^a-c]$`, "testd", matchres::MATCH, 0, -1), (`^test[^a-c]$`, "test!", matchres::MATCH, 0, -1), (`^test[^a-c]$`, "test-", matchres::MATCH, 0, -1), (`^test[^-a-c]$`, "test-", matchres::NOMATCH, 0, -1), (`^test[^a-c-]$`, "test-", matchres::NOMATCH, 0, -1), (`^test[^a-c-]*$`, "test", matchres::MATCH, 0, -1), (`^test[^a-c-]*$`, "test--", matchres::NOMATCH, 0, -1), (`^test[^a-c-]*$`, "testq", matchres::MATCH, 0, -1), (`^test[^a-c-]?$`, "test", matchres::MATCH, 0, -1), (`^test[^a-c-]?$`, "testq", matchres::MATCH, 0, -1), (`^test[^a-c-]?$`, "test-", matchres::NOMATCH, 0, -1), (`^test[^a-c-]+$`, "test", matchres::NOMATCH, 0, -1), (`^test[^a-c-]+$`, "testb", matchres::NOMATCH, 0, -1), (`^test[^a-c-]+$`, "testddd", matchres::MATCH, 0, -1), (`([a-z][a-z0-9]*,)+`, "a5,b7,c9,", matchres::MATCH, 0, -1), // [:alpha:] etc. (`^test[[:alnum:]]+$`, "testaA1", matchres::MATCH, 0, -1), (`^test[[:alnum:]]+$`, "testa_1", matchres::NOMATCH, 0, -1), (`^test[[:alpha:]]+$`, "testa", matchres::MATCH, 0, -1), (`^test[[:alpha:]]+$`, "testa1", matchres::NOMATCH, 0, -1), (`^test[[:blank:]]+$`, "testa", matchres::NOMATCH, 0, -1), (`^test[[:blank:]]+$`, "test ", matchres::MATCH, 0, -1), (`^test[^[:blank:]]+$`, "testx", matchres::MATCH, 0, -1), (`^test[[:blank:]]+$`, "test ", matchres::MATCH, 0, -1), (`^test[^[:cntrl:]]+$`, "testa", matchres::MATCH, 0, -1), (`^test[[:digit:]]$`, "test1", matchres::MATCH, 0, -1), (`^test[[:digit:]]$`, "testa", matchres::NOMATCH, 0, -1), (`^test[[:graph:]]+$`, "test\t", matchres::NOMATCH, 0, -1), (`^test[[:lower:]]+$`, "testa", matchres::MATCH, 0, -1), (`^test[[:lower:]]+$`, "testA", matchres::NOMATCH, 0, -1), (`^test[[:print:]]+$`, "test\t", matchres::NOMATCH, 0, -1), (`^test[[:punct:]]+$`, "testA", matchres::NOMATCH, 0, -1), (`^test[[:punct:]]+$`, "test!", matchres::MATCH, 0, -1), (`^test[[:space:]]+$`, "test ", matchres::MATCH, 0, -1), (`^test[[:upper:]]+$`, "testa", matchres::NOMATCH, 0, -1), (`^test[[:upper:]]+$`, "testA", matchres::MATCH, 0, -1), (`^test[[:xdigit:]]+$`, "testCAFE", matchres::MATCH, 0, -1), // range expressions (`[a-z]+`, "onlylatinletters", matchres::MATCH, 0, -1), (`[x-z]+`, "xyz", matchres::MATCH, 0, -1), (`[x-z]+`, "wxyz", matchres::MATCH, 1, 4), (`[a-e]+`, "-abcdefg", matchres::MATCH, 1, 6), (`[a-z]`, "-1234567890@#$%^&*(!)-+=", matchres::NOMATCH, 0, -1), (`[0-9]+`, "9246", matchres::MATCH, 0, -1), // # Cyrillic (`[а-я]+`, "кирилица", matchres::MATCH, 0, -1), (`[а-д]`, "е", matchres::NOMATCH, 0, -1), (`[я-ф]`, "-", matchres::ERROR, 0, -1), (`[А-Я]+`, "АБВГд", matchres::MATCH, 0, 4), // because Macedonian uses cyrrilics, the broad range does // not include special symbols (`[а-ш]+`, "ѓљњќ", matchres::NOMATCH, 0, -1), // # Polish Alphabet (`[a-ż]+`, "polskialfabet", matchres::MATCH, 0, -1), (`[a-ż]+`, "źśółęćą", matchres::MATCH, 0, -1), // because Polish alphabet uses Latin with special characters, // other characters can be accepted (`[a-ż]+`, "englishspeak", matchres::MATCH, 0, -1), (`[a-ż]+`, "{|}~", matchres::MATCH, 0, -1), // # Thai Alphabet (`[ก-ฮ]+`, "ศอผจข", matchres::MATCH, 0, -1), // [:alpha:] etc. plus extra characters (`^test[[:digit:]][[:alpha:]]$`, "test1a", matchres::MATCH, 0, -1), (`^test[[:digit:]][[:alpha:]]$`, "testa1", matchres::NOMATCH, 0, -1), (`^test[[:alnum:]!]+$`, "testa!1", matchres::MATCH, 0, -1), (`^test[@[:alnum:]!]+$`, "testa!@1", matchres::MATCH, 0, -1), // Escaped characters such as \+ (`^a\+b$`, "a+b", matchres::MATCH, 0, -1), (`^a\?b$`, "a?b", matchres::MATCH, 0, -1), (`^a\*b$`, "a*b", matchres::MATCH, 0, -1), (`^a\^b$`, "a^b", matchres::MATCH, 0, -1), (`^a\$b$`, "a$b", matchres::MATCH, 0, -1), (`^a\[b$`, "a[b", matchres::MATCH, 0, -1), (`^a\]b$`, "a]b", matchres::MATCH, 0, -1), (`^a\(b$`, "a(b", matchres::MATCH, 0, -1), (`^a\)b$`, "a)b", matchres::MATCH, 0, -1), (`^a\|b$`, "a|b", matchres::MATCH, 0, -1), (`^a\.b$`, "a.b", matchres::MATCH, 0, -1), (`^a\\b$`, "a\\b", matchres::MATCH, 0, -1), (`^x(abc)\{,2\}$`, "xabc{,2}", matchres::MATCH, 0, -1), (`^x(abc)\{,2\}$`, "xabcabc{,2}", matchres::NOMATCH, 0, -1), (`^[\\]+$`, "\\", matchres::MATCH, 0, -1), (`^[\]]+$`, "]", matchres::MATCH, 0, -1), (`^[A-Za-z\[\]]+$`, "foo[bar]baz", matchres::MATCH, 0, -1), // {m,n} (`^x(abc){2}$`, "xabcabc", matchres::MATCH, 0, -1), (`^x(abc){3}$`, "xabcabc", matchres::NOMATCH, 0, -1), (`^x(abc){1,2}$`, "xabc", matchres::MATCH, 0, -1), (`^x(abc){1,2}$`, "xabcabc", matchres::MATCH, 0, -1), (`^x(abc){1,2}$`, "xabcabcabc", matchres::NOMATCH, 0, -1), (`^x(abc){,2}$`, "xabc", matchres::MATCH, 0, -1), (`^x(abc){,2}$`, "xabcabc", matchres::MATCH, 0, -1), (`^x(abc){,2}`, "xabcabcabc", matchres::MATCH, 0, 7), (`^x(abc){,2}$`, "xabcabcabc", matchres::NOMATCH, 0, -1), (`^x(abc){1,}$`, "xabc", matchres::MATCH, 0, -1), (`^x(abc){1,}$`, "xabcabc", matchres::MATCH, 0, -1), (`^x(abc){3,}$`, "xabcabc", matchres::NOMATCH, 0, -1), (`^x(abc){3,}$`, "xabcabcabc", matchres::MATCH, 0, -1), (`^x(abc){2,2}$`, "xabcabc", matchres::MATCH, 0, -1), (`^x(abc){2,2}$`, "xabc", matchres::NOMATCH, 0, -1), (`^x(abc){2,2}$`, "xabcabcabc", matchres::NOMATCH, 0, -1), (`^x(abc){-1,2}$`, "xabcabcabc", matchres::ERROR, 0, -1), (`^x(abc){x,2}$`, "xabcabcabc", matchres::ERROR, 0, -1), (`^x(abc){0,-2}$`, "xabcabcabc", matchres::ERROR, 0, -1), // various ( `^.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+$`, "X1024facefacecaaaaafffcafebabebabe", matchres::MATCH, 0, -1, ), ( `.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+`, "X1024facefacecaaaaafffcafebabebabe", matchres::MATCH, 0, -1, ), ( `^.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+$`, "1024facefacecaaaaafffcafebabebabe", matchres::NOMATCH, 0, 0, ), ( `.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+`, "1024facefacecaaaaafffcafebabebabe", matchres::MATCH, 3, -1, ), ( `^([a-zA-Z]{1,2}[[:digit:]]{1,2})[[:space:]]*([[:digit:]][a-zA-Z]{2})$`, "M15 4QN", matchres::MATCH, 0, -1 ), (`^[^-a]`, "-bcd", matchres::NOMATCH, 0, 0), (`^[-a]`, "-bcd", matchres::MATCH, 0, 1), (`[^ac-]`, "bde", matchres::MATCH, 0, 1), (`[-ac]`, "foo-de", matchres::MATCH, 3, 4), (`[-ac]`, "def", matchres::NOMATCH, 0, 0), (`foo[-ac]bar`, "foo-bar", matchres::MATCH, 0, 7), (`[ac-]$`, "bde-", matchres::MATCH, 3, 4), (`^[A-Za-z_-]+$`, "foo", matchres::MATCH, 0, 3), // tests from perl (`abc`, "abc", matchres::MATCH, 0, -1), (`abc`, "xbc", matchres::NOMATCH, 0, 0), (`abc`, "axc", matchres::NOMATCH, 0, 0), (`abc`, "abx", matchres::NOMATCH, 0, 0), (`abc`, "xabcy", matchres::MATCH, 1, 4), (`abc`, "ababc", matchres::MATCH, 2, -1), (`ab*c`, "abc", matchres::MATCH, 0, -1), (`ab*bc`, "abc", matchres::MATCH, 0, -1), (`ab*bc`, "abbc", matchres::MATCH, 0, -1), (`ab*bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab{0,}bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab+bc`, "abbc", matchres::MATCH, 0, -1), (`ab+bc`, "abc", matchres::NOMATCH, 0, 0), (`ab+bc`, "abq", matchres::NOMATCH, 0, 0), (`ab{1,}bc`, "abq", matchres::NOMATCH, 0, 0), (`ab+bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab{1,}bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab{1,3}bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab{3,4}bc`, "abbbbc", matchres::MATCH, 0, -1), (`ab{4,5}bc`, "abbbbc", matchres::NOMATCH, 0, 0), (`ab?bc`, "abbc", matchres::MATCH, 0, -1), (`ab?bc`, "abc", matchres::MATCH, 0, -1), (`ab{0,1}bc`, "abc", matchres::MATCH, 0, -1), (`ab?bc`, "abbbbc", matchres::NOMATCH, 0, 0), (`ab?c`, "abc", matchres::MATCH, 0, -1), (`ab{0,1}c`, "abc", matchres::MATCH, 0, -1), (`^abc$`, "abc", matchres::MATCH, 0, -1), (`^abc$`, "abcc", matchres::NOMATCH, 0, 0), (`^abc`, "abcc", matchres::MATCH, 0, 3), (`^abc$`, "aabc", matchres::NOMATCH, 0, 0), (`abc$`, "aabc", matchres::MATCH, 1, -1), (`^`, "abc", matchres::MATCH, 0, 0), (`$`, "abc", matchres::MATCH, 3, 3), (`a.c`, "abc", matchres::MATCH, 0, -1), (`a.c`, "axc", matchres::MATCH, 0, -1), (`a.*c`, "axyzc", matchres::MATCH, 0, -1), (`a.*c`, "axyzd", matchres::NOMATCH, 0, 0), (`a[bc]d`, "abc", matchres::NOMATCH, 0, 0), (`a[bc]d`, "abd", matchres::MATCH, 0, -1), (`a[b-d]e`, "abd", matchres::NOMATCH, 0, 0), (`a[b-d]e`, "ace", matchres::MATCH, 0, -1), (`a[b-d]`, "aac", matchres::MATCH, 1, -1), (`a[-b]`, "a-", matchres::MATCH, 0, -1), (`a[b-]`, "a-", matchres::MATCH, 0, -1), (`a[b-a]`, "-", matchres::ERROR, 0, 0), (`a[]b`, "-", matchres::ERROR, 0, 0), (`a[`, "-", matchres::ERROR, 0, 0), (`a]`, "a]", matchres::MATCH, 0, -1), (`a[]]b`, "a]b", matchres::MATCH, 0, -1), (`a[^bc]d`, "aed", matchres::MATCH, 0, -1), (`a[^bc]d`, "abd", matchres::NOMATCH, 0, 0), (`a[^-b]c`, "adc", matchres::MATCH, 0, -1), (`a[^-b]c`, "a-c", matchres::NOMATCH, 0, 0), (`a[^]b]c`, "a]c", matchres::NOMATCH, 0, 0), (`a[^]b]c`, "adc", matchres::MATCH, 0, -1), (`()ef`, "def", matchres::MATCH, 1, -1), (`*a`, "-", matchres::ERROR, 0, 0), (`(*)b`, "-", matchres::ERROR, 0, 0), (`$b`, "b", matchres::ERROR, 0, 0), (`a\`, "-", matchres::ERROR, 0, 0), (`a\(b`, "a(b", matchres::MATCH, 0, -1), (`a\(*b`, "ab", matchres::MATCH, 0, -1), (`a\(*b`, "a((b", matchres::MATCH, 0, -1), (`a\\b`, `a\b`, matchres::MATCH, 0, -1), (`abc)`, "-", matchres::ERROR, 0, 0), (`(abc`, "-", matchres::ERROR, 0, 0), (`(a)b(c)`, "abc", matchres::MATCH, 0, -1), (`a+b+c`, "aabbabc", matchres::MATCH, 4, -1), (`a{1,}b{1,}c`, "aabbabc", matchres::MATCH, 4, -1), (`a**`, "-", matchres::ERROR, 0, 0), (`)(`, "-", matchres::ERROR, 0, 0), (`[^ab]*`, "cde", matchres::MATCH, 0, -1), (`abc`, "", matchres::NOMATCH, 0, 0), (`a*`, "", matchres::MATCH, 0, -1), (`([abc])*d`, "abbbcd", matchres::MATCH, 0, -1), (`([abc])*bcd`, "abcd", matchres::MATCH, 0, -1), (`abcd*efg`, "abcdefg", matchres::MATCH, 0, -1), (`ab*`, "xabyabbbz", matchres::MATCH, 1, 3), (`ab*`, "xayabbbz", matchres::MATCH, 1, 2), (`(ab|cd)e`, "abcde", matchres::MATCH, 2, -1), (`[abhgefdc]ij`, "hij", matchres::MATCH, 0, -1), (`^(ab|cd)e`, "abcde", matchres::NOMATCH, 0, 0), (`(abc|)ef`, "abcdef", matchres::MATCH, 4, -1), (`(a|b)c*d`, "abcd", matchres::MATCH, 1, -1), (`(ab|ab*)bc`, "abc", matchres::MATCH, 0, -1), (`a([bc]*)c*`, "abc", matchres::MATCH, 0, -1), (`a([bc]*)(c*d)`, "abcd", matchres::MATCH, 0, -1), (`a([bc]+)(c*d)`, "abcd", matchres::MATCH, 0, -1), (`a([bc]*)(c+d)`, "abcd", matchres::MATCH, 0, -1), (`a[bcd]*dcdcde`, "adcdcde", matchres::MATCH, 0, -1), (`a[bcd]+dcdcde`, "adcdcde", matchres::NOMATCH, 0, 0), (`(ab|a)b*c`, "abc", matchres::MATCH, 0, -1), (`[a-zA-Z_][a-zA-Z0-9_]*`, "alpha", matchres::MATCH, 0, -1), (`^a(bc+|b[eh])g|.h$`, "abh", matchres::MATCH, 0, -1), (`multiple words of text`, "uh-uh", matchres::NOMATCH, 0, 0), (`multiple words`, "multiple words, yeah", matchres::MATCH, 0, 14), (`(.*)c(.*)`, "abcde", matchres::MATCH, 0, -1), (`\((.*), (.*)\)`, "(a, b)", matchres::MATCH, 0, -1), (`[k]`, "ab", matchres::NOMATCH, 0, 0), (`a[-]?c`, "ac", matchres::MATCH, 0, -1), (`.*d`, "abc\nabd", matchres::MATCH, 0, -1), (`(`, "", matchres::ERROR, 0, 0), (`(x?)?`, "x", matchres::MATCH, 0, -1), (`^*`, "", matchres::ERROR, 0, 0), // Submatch handling (`(a|ab)(c|bcd)(d*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(a|ab)(bcd|c)(d*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(ab|a)(c|bcd)(d*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(ab|a)(bcd|c)(d*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(a*)(b|abc)(c*)`, "abc", matchres::MATCH, 0, -1), // POSIX: (0,3)(0,1)(1,2)(2,3) (`(a*)(abc|b)(c*)`, "abc", matchres::MATCH, 0, -1), // POSIX: (0,3)(0,1)(1,2)(2,3) (`(a*)(b|abc)(c*)`, "abc", matchres::MATCH, 0, -1), // POSIX: (0,3)(0,1)(1,2)(2,3) (`(a*)(abc|b)(c*)`, "abc", matchres::MATCH, 0, -1), // POSIX: (0,3)(0,1)(1,2)(2,3) (`(a|ab)(c|bcd)(d|.*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(a|ab)(bcd|c)(d|.*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(ab|a)(c|bcd)(d|.*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) (`(ab|a)(bcd|c)(d|.*)`, "abcd", matchres::MATCH, 0, -1), // POSIX: (0,4)(0,2)(2,3)(3,4) // whole-expression alternation (`ab|cd`, "cd", matchres::MATCH, 0, 2), (`ab|cd`, "abc", matchres::MATCH, 0, 2), (`ab|cd`, "abcd", matchres::MATCH, 0, 2), // multiple alternation (`a|b|c|d|e`, "e", matchres::MATCH, 0, -1), (`(a|b|c|d|e)f`, "ef", matchres::MATCH, 0, -1), // TODO: nested capture groups (`((a))`, "abc", matchres::ERROR, 0, -1), // (`((a))`, "abc", matchres::MATCH, 0, -1), // (`((a)(b)c)(d)`, "abcd", matchres::MATCH, 0, -1), // (`(bc+d$|ef*g.|h?i(j|k))`, "effgz", matchres::MATCH, 0, -1), // (`(bc+d$|ef*g.|h?i(j|k))`, "ij", matchres::MATCH, 0, -1), // (`(bc+d$|ef*g.|h?i(j|k))`, "effg", matchres::NOMATCH, 0, 0), // (`(bc+d$|ef*g.|h?i(j|k))`, "bcdd", matchres::NOMATCH, 0, 0), // (`(bc+d$|ef*g.|h?i(j|k))`, "reffgz", matchres::MATCH, 0, -1), // (`((((((((((a))))))))))`, "a", matchres::MATCH, 0, -1), // (`(((((((((a)))))))))`, "a", matchres::MATCH, 0, -1), // (`(([a-z]+):)?([a-z]+)$`, "smil", matchres::MATCH, 0, -1), // (`^((a)c)?(ab)$`, "ab", matchres::MATCH, 0, -1), // TODO: multiple simultaneous capture groups // (`(a+|b)*`, "ab", matchres::MATCH, 0, -1), // (`(a+|b){0,}`, "ab", matchres::MATCH, 0, -1), // (`(a+|b)+`, "ab", matchres::MATCH, 0, -1), // (`(a+|b){1,}`, "ab", matchres::MATCH, 0, -1), // (`(a+|b)?`, "ab", matchres::MATCH, 0, -1), // (`(a+|b){0,1}`, "ab", matchres::MATCH, 0, -1), // NOTE: character sequences not currently supported // (`\0`, "\0", matchres::MATCH, 0, -1), // (`[\0a]`, "\0", matchres::MATCH, 0, -1), // (`[a\0]`, "\0", matchres::MATCH, 0, -1), // (`[^a\0]`, "\0", matchres::NOMATCH, 0, 0), // NOTE: octal sequences not currently supported // (`[\1]`, "\1", matchres::MATCH, 0, -1), // (`\09`, "\0(separate-me)9", matchres::MATCH, 0, -1), // (`\141`, "a", matchres::MATCH, 0, -1), // (`[\41]`, "!", matchres::MATCH, 0, -1), // NOTE: hex sequences not currently supported // (`\xff`, "\377", matchres::MATCH, 0, -1), // NOTE: non-greedy matching not currently supported // (`a.+?c`, "abcabc", matchres::MATCH, 0, -1), // (`.*?\S *:`, "xx:", matchres::MATCH, 0, -1), // (`a[ ]*?\ (\d+).*`, "a 10", matchres::MATCH, 0, -1), // (`a[ ]*?\ (\d+).*`, "a 10", matchres::MATCH, 0, -1), // (`"(\\"|[^"])*?"`, `"\""`, matchres::MATCH, 0, -1), // (`^.*?$`, "one\ntwo\nthree\n", matchres::NOMATCH, 0, 0), // (`a[^>]*?b`, "a>b", matchres::NOMATCH, 0, 0), // (`^a*?$`, "foo", matchres::NOMATCH, 0, 0), // (`^([ab]*?)(?=(b)?)c`, "abc", matchres::MATCH, 0, -1), // (`^([ab]*?)(?!(b))c`, "abc", matchres::MATCH, 0, -1), // (`^([ab]*?)(? Harriet rriet Finding all matches for an expression in a string: const results = regex::findall(&re, "Harriet is happy"); defer regex::result_freeall(results); for (let i = 0z; i < len(results); i += 1) { for (let j = 0z; j < len(results[i]); j += 1) { fmt::printf("{} ", results[i][j].content)!; }; fmt::println()!; }; // -> Harriet rriet; happy ppy Replacing matches for an expression: const re = regex::compile(`happy`)!; const result = regex::replace(&re, "Harriet is happy", `cute`)!; // -> Harriet is cute Replacing with capture group references: const re = regex::compile(`[a-z]+-([a-z]+)-[a-z]+`)!; const result = regex::replace(&re, "cat-dog-mouse; apple-pear-plum", `\1`)!; // -> dog; pear hare-0.24.2/regex/regex.ha000066400000000000000000000642021464473310100152630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bufio; use encoding::utf8; use io; use memio; use strconv; use strings; use types; // An error string describing a compilation error. export type error = !str; export type inst_lit = rune, inst_charset = struct { idx: size, is_positive: bool }, inst_any = void, inst_split = size, inst_jump = size, inst_skip = void, inst_match = bool, inst_groupstart = void, inst_groupend = void, inst_repeat = struct { id: size, origin: size, min: (void | size), max: (void | size), }; export type inst = (inst_lit | inst_any | inst_split | inst_jump | inst_skip | inst_match | inst_charset | inst_groupstart | inst_groupend | inst_repeat); // The resulting match of a [[regex]] applied to a string. // // The first [[capture]] corresponds to the implicit zeroth capture group, // i.e. the whole expression. // // The rest of the [[capture]]s correspond to the rest of the capture groups, // i.e. the sub-expressions. export type result = []capture; // A (sub)match corresponding to a regular expression's capture group. export type capture = struct { content: str, start: size, start_bytesize: size, end: size, end_bytesize: size }; type thread = struct { pc: size, start_idx: size, start_bytesize: size, root_capture: capture, captures: []capture, curr_capture: capture, curr_capture_inited: bool, rep_counters: []size, matched: bool, failed: bool, }; type newmatch = void; export type charclass = enum { ALNUM, ALPHA, BLANK, CNTRL, DIGIT, GRAPH, LOWER, PRINT, PUNCT, SPACE, UPPER, XDIGIT, }; export type charset = [](charset_lit_item | charset_range_item | charset_class_item), charset_lit_item = rune, charset_range_item = (u32, u32), charset_class_item = *fn(c: rune) bool; const charclass_map: [](str, *fn(c: rune) bool) = [ (":alnum:]", &ascii::isalnum), (":alpha:]", &ascii::isalpha), (":blank:]", &ascii::isblank), (":cntrl:]", &ascii::iscntrl), (":digit:]", &ascii::isdigit), (":graph:]", &ascii::isgraph), (":lower:]", &ascii::islower), (":print:]", &ascii::isprint), (":punct:]", &ascii::ispunct), (":space:]", &ascii::isspace), (":upper:]", &ascii::isupper), (":xdigit:]", &ascii::isxdigit), ]; export type regex = struct { insts: []inst, charsets: []charset, n_reps: size, }; // Frees resources associated with a [[regex]]. export fn finish(re: *regex) void = { free(re.insts); for (let charset .. re.charsets) { free(charset); }; free(re.charsets); }; fn find_last_groupstart(insts: *[]inst) (size | error) = { for (let i = len(insts); i > 0; i -= 1) { if (insts[i - 1] is inst_groupstart) { return i - 1; }; }; return `Unmatched ')'`: error; }; fn handle_bracket( insts: *[]inst, r: rune, r_idx: *size, bracket_idx: *int, iter: *strings::iterator, charsets: *[]charset, skip_charclass_rest: *bool, is_charset_positive: *bool, in_bracket: *bool ) (void | error) = { const peek1 = strings::next(iter); const peek2 = strings::next(iter); const peek3 = strings::next(iter); if (!(peek1 is done)) { strings::prev(iter); }; if (!(peek2 is done)) { strings::prev(iter); }; if (!(peek3 is done)) { strings::prev(iter); }; if (*bracket_idx == -1) { append(charsets, []); }; *bracket_idx += 1; if (*skip_charclass_rest) { if (r == ']') { *skip_charclass_rest = false; }; *r_idx += 1; return; }; const is_range = peek1 is rune && peek1 as rune == '-' && !(peek2 is done) && !(peek3 is done) && !(peek2 as rune == ']'); const range_end = peek2; const is_first_char = *bracket_idx == 0 || *bracket_idx == 1 && !*is_charset_positive; if (r == '\\') { if (peek1 is done) { return `Trailing backslash '\'`: error; } else { append(charsets[len(charsets) - 1], peek1: charset_lit_item); strings::next(iter); *r_idx += 1; }; } else if (r == ']' && !is_first_char) { const newinst = inst_charset { idx = len(charsets) - 1, is_positive = *is_charset_positive, }; append(insts, newinst); *in_bracket = false; *bracket_idx = -1; *is_charset_positive = true; } else if (r == '^' && *bracket_idx == 0) { *is_charset_positive = false; } else if (r == '[' && !(peek1 is done) && peek1 as rune == ':') { const rest = strings::iterstr(iter); const n_cc = len(charclass_map); for (let cc_idx = 0z; cc_idx < n_cc; cc_idx += 1) { if (strings::hasprefix(rest, charclass_map[cc_idx].0)) { append(charsets[len(charsets) - 1], charclass_map[cc_idx].1); *skip_charclass_rest = true; break; }; }; if (!*skip_charclass_rest) { return `No character class after '[:'`: error; }; } else if (is_range) { const start_b = r: u32; const end_b = range_end as rune: u32; if (end_b < start_b) { return `Descending bracket expression range '[z-a]'`: error; }; append(charsets[len(charsets) - 1], (start_b, end_b): charset_range_item); strings::next(iter); strings::next(iter); *r_idx += 2; } else { append(charsets[len(charsets) - 1], r: charset_lit_item); }; *r_idx += 1; }; // Compiles a regular expression string into a [[regex]]. export fn compile(expr: str) (regex | error) = { let insts: []inst = []; let charsets: []charset = []; let iter = strings::iter(expr); let r_idx = 0z; let anchored = false; let jump_idxs: []size = []; let in_bracket = false; let skip_charclass_rest = false; let bracket_idx = -1; let is_charset_positive = true; let n_reps = 0z; let n_groupstarts = 0; for (true) { const next = strings::next(&iter); if (r_idx == 0 && next is rune && next: rune != '^') { append(insts, inst_skip); }; if (in_bracket) { if (next is done) { return `Unmatched '['`: error; }; const r = next: rune; handle_bracket(&insts, r, &r_idx, &bracket_idx, &iter, &charsets, &skip_charclass_rest, &is_charset_positive, &in_bracket)?; continue; }; const r = match (next) { case done => if (n_groupstarts > 0) { return `Unmatched '('`: error; }; break; case let r: rune => yield r; }; switch (r) { case '\\' => const peek1 = strings::next(&iter); if (peek1 is done) { return `Trailing backslash '\'`: error; } else { append(insts, (peek1 as rune): inst_lit); r_idx += 1; }; case '^' => if (r_idx != 0) { return `Anchor '^' not at start`: error; }; case '$' => if (r_idx != len(expr) - 1) { return `Anchor '$' not at end`: error; }; anchored = true; case '[' => in_bracket = true; case ']' => append(insts, r: inst_lit); case '(' => if (n_groupstarts > 0) { return `Nested capture groups are unsupported`: error; }; append(insts, inst_groupstart); n_groupstarts += 1; case ')' => if (n_groupstarts == 0) { return `Unmatched ')'`: error; }; n_groupstarts -= 1; append(insts, inst_groupend); for (let jump_idx .. jump_idxs) { assert(insts[jump_idx] is inst_jump); insts[jump_idx] = (len(insts) - 1): inst_jump; }; jump_idxs = []; case '|' => append(insts, types::SIZE_MAX: inst_jump); const origin = match (find_last_groupstart(&insts)) { case error => yield 0z; case let sz: size => yield sz + 1; }; const newinst = (len(insts) + 1): inst_split; // add split after last jump (if any) or at origin const split_idx = if (len(jump_idxs) > 0) jump_idxs[len(jump_idxs) - 1] + 1 else origin; insert(insts[split_idx], newinst); append(jump_idxs, len(insts) - 1); case '{' => let origin = len(insts) - 1; if (insts[origin] is inst_groupend) { origin = find_last_groupstart(&insts)?; }; const rest = strings::iterstr(&iter); const rep_parts = parse_repetition(rest)?; const can_skip = rep_parts.0 == 0; const min = if (rep_parts.0 == 0) { yield 1z; } else { yield rep_parts.0; }; if (can_skip) { insert(insts[origin], len(insts) + 2: inst_split); origin += 1; }; const newinst = inst_repeat { id = n_reps, origin = origin, min = min, max = rep_parts.1, }; for (let i = 0z; i <= rep_parts.2; i += 1) { strings::next(&iter); r_idx += 1; }; append(insts, newinst); n_reps += 1; case '?' => if (r_idx == 0 || len(insts) == 0) { return `Unused '?'`: error; }; let term_start_idx = len(insts) - 1; match (insts[term_start_idx]) { case (inst_lit | inst_charset | inst_any) => void; case inst_groupend => term_start_idx = find_last_groupstart(&insts)?; case inst_groupstart => return `Unused '?'`: error; case => return `Misused '?'`: error; }; const after_idx = len(insts) + 1; insert(insts[term_start_idx], after_idx: inst_split); case '*' => if (r_idx == 0 || len(insts) == 0) { return `Unused '*'`: error; }; const new_inst_offset = 1z; const jump_idx = len(insts) + new_inst_offset; const after_idx = jump_idx + 1z; let term_start_idx = len(insts) - 1z; match (insts[term_start_idx]) { case (inst_lit | inst_charset | inst_any) => void; case inst_groupend => term_start_idx = find_last_groupstart(&insts)?; case inst_groupstart => return `Unused '*'`: error; case => return `Misused '*'`: error; }; const split_idx = term_start_idx; term_start_idx += new_inst_offset; insert(insts[split_idx], after_idx: inst_split); append(insts, split_idx: inst_jump); case '+' => if (r_idx == 0 || len(insts) == 0) { return `Unused '+'`: error; }; let term_start_idx = len(insts) - 1; match (insts[term_start_idx]) { case (inst_lit | inst_charset | inst_any) => void; case inst_groupend => term_start_idx = find_last_groupstart(&insts)?; case inst_groupstart => return `Unused '+'`: error; case => return `Misused '+'`: error; }; append(insts, term_start_idx: inst_split); case '.' => append(insts, inst_any); case => append(insts, r: inst_lit); }; r_idx += 1; }; // handle whole expression alternation for (let jump_idx .. jump_idxs) { assert(insts[jump_idx] is inst_jump); insts[jump_idx] = len(insts): inst_jump; }; jump_idxs = []; append(insts, anchored: inst_match); return regex { insts = insts, charsets = charsets, n_reps = n_reps, }; }; fn parse_repetition( s: str ) (((void | size), (void | size), size) | error) = { const first_comma = strings::index(s, ","); const first_endbrace = strings::index(s, "}"); if (first_endbrace is void) { return `Repetition expression syntax error '{n}'`: error; }; const first_endbrace = first_endbrace as size; let min_str = ""; let max_str = ""; let is_single_arg = false; if (first_comma is void || first_endbrace < first_comma as size) { const cut = strings::cut(s, "}"); min_str = cut.0; max_str = cut.0; is_single_arg = true; } else { const cut = strings::cut(s, ","); min_str = cut.0; max_str = strings::cut(cut.1, "}").0; }; let min: (void | size) = void; let max: (void | size) = void; if (len(min_str) > 0) { min = match (strconv::stoi(min_str)) { case let res: int => yield if (res < 0) { return `Negative repetition count '{-n}'`: error; } else { yield res: size; }; case => return `Repetition expression syntax error '{n}'`: error; }; } else { min = 0; }; if (len(max_str) > 0) { max = match (strconv::stoi(max_str)) { case let res: int => yield if (res < 0) { return `Negative repetition count '{-n}'`: error; } else { yield res: size; }; case => return `Repetition expression syntax error '{n}'`: error; }; }; const rep_len = if (is_single_arg) { yield len(min_str); } else { yield len(min_str) + 1 + len(max_str); }; return (min, max, rep_len); }; fn delete_thread(i: size, threads: *[]thread) void = { free(threads[i].captures); free(threads[i].rep_counters); delete(threads[i]); }; fn is_consuming_inst(a: inst) bool = { return a is (inst_lit | inst_any | inst_charset); }; fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) void = { // Do not add this thread if there is already another thread with // the same PC for (let thread &.. *threads) { if (thread.pc == new_pc && !thread.matched && thread.start_idx < threads[parent_idx].start_idx) { return; }; }; append(threads, thread { pc = new_pc, start_idx = threads[parent_idx].start_idx, start_bytesize = threads[parent_idx].start_bytesize, curr_capture = threads[parent_idx].curr_capture, curr_capture_inited = threads[parent_idx].curr_capture_inited, matched = threads[parent_idx].matched, failed = threads[parent_idx].failed, captures = alloc(threads[parent_idx].captures...), rep_counters = alloc(threads[parent_idx].rep_counters...), ... }); }; fn run_thread( i: size, re: *regex, string: str, threads: *[]thread, r_or_end: (rune | io::EOF), str_idx: size, str_bytesize: size ) (void | newmatch) = { const str_bytes = strings::toutf8(string); if (threads[i].matched) { return; }; for (!is_consuming_inst(re.insts[threads[i].pc])) { match (re.insts[threads[i].pc]) { case inst_lit => abort(); case inst_any => abort(); case inst_split => const new_pc = re.insts[threads[i].pc]: inst_split: size; add_thread(threads, i, new_pc); threads[i].pc += 1; case inst_jump => threads[i].pc = re.insts[threads[i].pc]: inst_jump: size; case inst_skip => const new_pc = threads[i].pc + 1; threads[i].start_idx = str_idx; threads[i].start_bytesize = str_bytesize; add_thread(threads, i, new_pc); break; case let anchored: inst_match => // Do not match if we need an end-anchored match, but we // have not exhausted our string if (anchored && !(r_or_end is io::EOF)) { threads[i].failed = true; return; }; const content = strings::fromutf8_unsafe(str_bytes[ threads[i].start_bytesize..str_bytesize]); threads[i].root_capture = capture { start = threads[i].start_idx, start_bytesize = threads[i].start_bytesize, end = str_idx, end_bytesize = str_bytesize, content = content, }; threads[i].matched = true; return newmatch; case inst_groupstart => assert(!threads[i].curr_capture_inited, "Found nested capture groups in expression, which are not supported"); threads[i].curr_capture.start = str_idx; threads[i].curr_capture.start_bytesize = str_bytesize; threads[i].curr_capture_inited = true; threads[i].pc += 1; case inst_groupend => assert(threads[i].curr_capture_inited, `Found a groupend token ")" without having previously seen a groupstart token "(". Please report this as a bug`); threads[i].curr_capture.end = str_idx; threads[i].curr_capture.end_bytesize = str_bytesize; threads[i].curr_capture.content = strings::fromutf8_unsafe(str_bytes[ threads[i].curr_capture.start_bytesize.. threads[i].curr_capture.end_bytesize]); append(threads[i].captures, threads[i].curr_capture); threads[i].curr_capture = capture { ... }; threads[i].curr_capture_inited = false; threads[i].pc += 1; case let ir: inst_repeat => assert(ir.id < len(threads[i].rep_counters)); threads[i].rep_counters[ir.id] += 1; if (ir.max is size && threads[i].rep_counters[ir.id] > ir.max as size) { threads[i].failed = true; return; }; const new_pc = threads[i].pc + 1; threads[i].pc = ir.origin; if (ir.min is void || threads[i].rep_counters[ir.id] >= ir.min as size) { add_thread(threads, i, new_pc); }; }; }; // From now on, we're only matching consuming instructions, and these // can't do anything without another rune. if (r_or_end is io::EOF) { threads[i].failed = true; return; }; const r = r_or_end as rune; match (re.insts[threads[i].pc]) { case inst_skip => return; case let lit: inst_lit => if (r != lit) { threads[i].failed = true; }; case inst_any => void; case let cs: inst_charset => const charset = re.charsets[cs.idx]; // Disprove the match if we're looking for a negative match // Prove the match if we're looking for a positive match let matched = !cs.is_positive; for (let i = 0z; i < len(charset); i += 1) match (charset[i]) { case let lit: charset_lit_item => if (r == lit) { // Succeeded if positive match // Failed if negative match matched = cs.is_positive; break; }; case let range: charset_range_item => const r_b = r: u32; if (r_b >= range.0 && r_b <= range.1) { // Succeeded if positive match // Failed if negative match matched = cs.is_positive; break; }; case let classfn: charset_class_item => if (classfn(r)) { // Succeeded if positive match // Failed if negative match matched = cs.is_positive; break; }; }; if (!matched) { threads[i].failed = true; }; case => abort(); // unreachable }; threads[i].pc += 1; }; // Attempts to match a regular expression against a string and returns the // either the longest leftmost match or all matches. fn search( re: *regex, string: str, handle: io::handle, need_captures: bool ) (void | []capture) = { let threads: []thread = alloc([ thread { captures = [], ... } ]); if (re.n_reps > 0) { threads[0].rep_counters = alloc([0...], re.n_reps); }; defer { for (let i = 0z; i < len(threads); i += 1) { free(threads[i].captures); free(threads[i].rep_counters); }; free(threads); }; let str_idx = 0z; let first_match_idx: (void | size) = void; let str_bytesize = 0z; let last_bytesize = 0z; const scan = bufio::newscanner(handle); defer bufio::finish(&scan); for (true) { str_bytesize += last_bytesize; if (len(threads) == 0) { return void; }; let all_matched = true; for (let i = 0z; i < len(threads); i += 1) { if (!threads[i].matched) { all_matched = false; break; }; }; if (all_matched) { let best_len = 0z; let best_n_captures = 0z; let best_idx = 0z; for (let i = 0z; i < len(threads); i += 1) { let match_len = threads[i].root_capture.end - threads[i].root_capture.start; const is_better = match_len > best_len || match_len == best_len && len(threads[i].captures) > best_n_captures; if (is_better) { best_len = match_len; best_idx = i; best_n_captures = len(threads[i].captures); }; }; let res: []capture = alloc([], len(threads[best_idx].captures) + 1); append(res, threads[best_idx].root_capture); append(res, threads[best_idx].captures...); return res; }; const r_or_end = bufio::scan_rune(&scan)!; if (r_or_end is rune) { last_bytesize = utf8::runesz(r_or_end as rune); }; for (let i = 0z; i < len(threads); i += 1) { const res = run_thread(i, re, string, &threads, r_or_end, str_idx, str_bytesize); const matchlen = threads[i].root_capture.end - threads[i].root_capture.start; if (res is newmatch && matchlen > 0 && !need_captures) { return []; }; const is_better = res is newmatch && matchlen > 0 && (first_match_idx is void || threads[i].start_idx < first_match_idx as size); if (is_better) { first_match_idx = threads[i].start_idx; }; }; str_idx += 1; // When we only want the leftmost match, delete all threads that // start after the earliest non-zero-length matched thread if (first_match_idx is size) { for (let thread &.. threads) { if (thread.start_idx > first_match_idx as size) { thread.failed = true; }; }; }; // Delete threads that have a PC that has already been // encountered in previous threads. Prioritise threads that // have an earlier start_idx, and threads that were added // earlier. for (let i = 0i64; i < len(threads): i64 - 1; i += 1) { for (let j = i + 1; j < len(threads): i64; j += 1) { const same_pc = threads[i].pc == threads[j].pc; const none_matched = !threads[j].matched && !threads[i].matched; if (same_pc && none_matched) { if (threads[i].start_idx <= threads[j].start_idx) { delete_thread(j: size, &threads); j -= 1; } else { delete_thread(i: size, &threads); i -= 1; break; }; }; }; }; for (let i = 0z; i < len(threads); i += 1) { if (threads[i].failed) { delete_thread(i, &threads); i -= 1; }; }; }; }; // Returns whether or not a [[regex]] matches any part of a given string. export fn test(re: *regex, string: str) bool = { let strm = memio::fixed(strings::toutf8(string)); return search(re, string, &strm, false) is []capture; }; // Attempts to match a [[regex]] against a string and returns the longest // leftmost match as a [[result]]. The caller must free the return value with // [[result_free]]. export fn find(re: *regex, string: str) result = { let strm = memio::fixed(strings::toutf8(string)); match (search(re, string, &strm, true)) { case let m: []capture => return m; case void => return []; }; }; // Attempts to match a [[regex]] against a string and returns all // non-overlapping matches as a slice of [[result]]s. The caller must free the // return value with [[result_freeall]]. export fn findall(re: *regex, string: str) []result = { let res: []result = []; let str_idx = 0z, str_bytesize = 0z; let strm = memio::fixed(strings::toutf8(string)); const str_bytes = strings::toutf8(string); for (true) { let substring = strings::fromutf8_unsafe( str_bytes[str_bytesize..]); match (search(re, substring, &strm, true)) { case let m: []capture => append(res, m); m[0].start += str_idx; m[0].end += str_idx; m[0].start_bytesize += str_bytesize; m[0].end_bytesize += str_bytesize; str_idx = m[0].end; str_bytesize = m[0].end_bytesize; if (m[0].start_bytesize == len(str_bytes)) { // end-of-string reached break; }; if (m[0].start_bytesize == m[0].end_bytesize) { // zero-length match // forward rune and byte indices str_idx += 1; str_bytesize += encoding::utf8::utf8sz( str_bytes[str_bytesize])!; }; io::seek(&strm, str_bytesize: io::off, io::whence::SET)!; case void => break; }; }; return res; }; // Replaces all non-overlapping matches of a regular expression against a string // with 'targetstr'. // // A backslash followed by a single decimal number within 'targetstr' is // replaced by the capture at that index (starting at 1), or an empty string if // no such capture exists. For example, `\1` is replaced with the first capture, // `\2` with the second, etc. `\0` is substituted with the entire substring that // was matched. `\\` is replaced with a literal backslash. The caller must free // the return value. // // An error is only returned if 'targetstr' isn't formatted correctly. export fn replace(re: *regex, string: str, targetstr: str) (str | error) = { return replacen(re, string, targetstr, types::SIZE_MAX); }; // Replaces up to 'n' non-overlapping matches of a regular expression against a // string with 'targetstr', in the same manner as [[replace]]. The caller must // free the return value. export fn replacen( re: *regex, string: str, targetstr: str, n: size, ) (str | error) = { const target = parse_replace_target(targetstr)?; defer free(target); // Check if n == 0 after parse_replace_target so errors are propagated if (n == 0) { return strings::dup(string); }; const matches = findall(re, string); if (len(matches) == 0) { return strings::dup(string); }; defer result_freeall(matches); const bytes = strings::toutf8(string); let buf = alloc(bytes[..matches[0][0].start_bytesize]...); const n = if (len(matches) > n) n else len(matches); for (let i = 0z; i < n; i += 1) { for (let j = 0z; j < len(target); j += 1) { match (target[j]) { case let b: []u8 => append(buf, b...); case let z: size => if (z >= len(matches[i])) yield; const b = strings::toutf8(matches[i][z].content); append(buf, b...); }; }; const start = matches[i][0].end_bytesize; const end = if (i == n - 1) len(bytes) else matches[i + 1][0].start_bytesize; append(buf, bytes[start..end]...); }; return strings::fromutf8(buf)!; }; fn parse_replace_target(targetstr: str) ([]([]u8 | size) | error) = { const bytes = strings::toutf8(targetstr); let target: []([]u8 | size) = alloc([], 1); let iter = strings::iter(targetstr); let start = 0z, end = 0z; for (true) match (strings::next(&iter)) { case done => if (start != end) { append(target, bytes[start..]); }; break; case let r: rune => if (r == '\\') { if (start != end) { append(target, bytes[start..end]); }; const r = match (strings::next(&iter)) { case done => free(target); return "Trailing backslash": error; case let r: rune => yield r; }; if (r == '\\') { append(target, '\\'); } else if (ascii::isdigit(r)) { append(target, r: u32: size - 0x30); } else { free(target); return "Backslash must be followed by positive decimal number or a backslash": error; }; end += 2; start = end; } else { end += utf8::runesz(r); }; }; return target; }; // Replaces all non-overlapping matches of a regular expression against a string // with 'targetstr'. 'targetstr' is isn't interpreted in any special way; all // backslashes are treated literally. The caller must free the return value. export fn rawreplace(re: *regex, string: str, targetstr: str) str = { return rawreplacen(re, string, targetstr, types::SIZE_MAX); }; // Replaces up to 'n' non-overlapping matches of a regular expression against a // string with 'targetstr', in the same manner as [[rawreplace]]. The caller // must free the return value. export fn rawreplacen(re: *regex, string: str, targetstr: str, n: size) str = { if (n == 0) { return strings::dup(string); }; const matches = findall(re, string); if (len(matches) == 0) { return strings::dup(string); }; defer result_freeall(matches); const target = strings::toutf8(targetstr); const bytes = strings::toutf8(string); let buf: []u8 = []; append(buf, bytes[..matches[0][0].start_bytesize]...); const n = if (len(matches) > n) n else len(matches); for (let i = 1z; i < n; i += 1) { append(buf, target...); const start = matches[i - 1][0].end_bytesize; const end = matches[i][0].start_bytesize; append(buf, bytes[start..end]...); }; append(buf, target...); append(buf, bytes[matches[n - 1][0].end_bytesize..]...); return strings::fromutf8(buf)!; }; // Frees a [[result]]. export fn result_free(s: result) void = { free(s); }; // Frees a slice of [[result]]s. export fn result_freeall(s: []result) void = { for (let res .. s) { result_free(res); }; free(s); }; // Converts an [[error]] into a user-friendly string. export fn strerror(err: error) str = err; hare-0.24.2/rt/000077500000000000000000000000001464473310100131465ustar00rootroot00000000000000hare-0.24.2/rt/+aarch64/000077500000000000000000000000001464473310100144515ustar00rootroot00000000000000hare-0.24.2/rt/+aarch64/arch_jmp.ha000066400000000000000000000001631464473310100165460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type arch_jmpbuf = [22]u64; hare-0.24.2/rt/+aarch64/cpuid.ha000066400000000000000000000001301464473310100160610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO hare-0.24.2/rt/+aarch64/cpuid.s000066400000000000000000000000001464473310100157270ustar00rootroot00000000000000hare-0.24.2/rt/+aarch64/fenv.s000066400000000000000000000050551464473310100156000ustar00rootroot00000000000000# This file is vendored from musl and is licensed under MIT license: # # ---------------------------------------------------------------------- # Copyright © 2005-2020 Rich Felker, et al. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ---------------------------------------------------------------------- .section ".text.rt.fegetround","ax" .global rt.fegetround .type rt.fegetround,%function rt.fegetround: mrs x0, fpcr and w0, w0, #0xc00000 ret .section ".text.rt.fesetround","ax" .global rt.fesetround .type rt.fesetround,%function rt.fesetround: mrs x1, fpcr bic w1, w1, #0xc00000 orr w1, w1, w0 msr fpcr, x1 mov w0, #0 ret .section ".text.rt.fetestexcept","ax" .global rt.fetestexcept .type rt.fetestexcept,%function rt.fetestexcept: and w0, w0, #0x1f mrs x1, fpsr and w0, w0, w1 ret .section ".text.rt.feclearexcept","ax" .global rt.feclearexcept .type rt.feclearexcept,%function rt.feclearexcept: and w0, w0, #0x1f mrs x1, fpsr bic w1, w1, w0 msr fpsr, x1 mov w0, #0 ret .section ".text.rt.feraiseexcept","ax" .global rt.feraiseexcept .type rt.feraiseexcept,%function rt.feraiseexcept: and w0, w0, #0x1f mrs x1, fpsr orr w1, w1, w0 msr fpsr, x1 mov w0, #0 ret .section ".text.rt.fegetenv","ax" .global rt.fegetenv .type rt.fegetenv,%function rt.fegetenv: mrs x1, fpcr mrs x2, fpsr stp w1, w2, [x0] mov w0, #0 ret // TODO preserve some bits .section ".text.rt.fesetenv","ax" .global rt.fesetenv .type rt.fesetenv,%function rt.fesetenv: mov x1, #0 mov x2, #0 cmn x0, #1 b.eq 1f ldp w1, w2, [x0] 1: msr fpcr, x1 msr fpsr, x2 mov w0, #0 ret hare-0.24.2/rt/+aarch64/longjmp.s000066400000000000000000000007241464473310100163060ustar00rootroot00000000000000.section ".text.rt.longjmp","ax" .global rt.longjmp .type rt.longjmp,@function rt.longjmp: // IHI0055B_aapcs64.pdf 5.1.1, 5.1.2 callee saved registers ldp x19, x20, [x0,#0] ldp x21, x22, [x0,#16] ldp x23, x24, [x0,#32] ldp x25, x26, [x0,#48] ldp x27, x28, [x0,#64] ldp x29, x30, [x0,#80] ldr x2, [x0,#104] mov sp, x2 ldp d8 , d9, [x0,#112] ldp d10, d11, [x0,#128] ldp d12, d13, [x0,#144] ldp d14, d15, [x0,#160] cmp w1, 0 csinc w0, w1, wzr, ne br x30 hare-0.24.2/rt/+aarch64/setjmp.s000066400000000000000000000006671464473310100161500ustar00rootroot00000000000000.section ".text.rt.setjmp","ax" .global rt.setjmp .type rt.setjmp,@function rt.setjmp: // IHI0055B_aapcs64.pdf 5.1.1, 5.1.2 callee saved registers stp x19, x20, [x0,#0] stp x21, x22, [x0,#16] stp x23, x24, [x0,#32] stp x25, x26, [x0,#48] stp x27, x28, [x0,#64] stp x29, x30, [x0,#80] mov x2, sp str x2, [x0,#104] stp d8, d9, [x0,#112] stp d10, d11, [x0,#128] stp d12, d13, [x0,#144] stp d14, d15, [x0,#160] mov x0, #0 ret hare-0.24.2/rt/+freebsd/000077500000000000000000000000001464473310100146335ustar00rootroot00000000000000hare-0.24.2/rt/+freebsd/+aarch64.ha000066400000000000000000000020461464473310100164520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type siginfo = struct { si_signo: int, si_errno: int, si_code: int, si_pid: pid_t, si_uid: uid_t, si_status: int, si_addr: *opaque, si_value: sigval, _reason: union { _fault: struct { _trapno: int, }, _timer: struct { _timerid: int, _overrun: int, }, _mesgq: struct { _mqd: int, }, _poll: struct { _band: i64, }, __spare__: struct { __spare1__: i64, __spare2__: [7]int, }, }, }; export type ucontext = struct { uc_sigmask: sigset, uc_mcontext: mcontext, uc_link: *ucontext, uc_stack: stack_t, uc_flags: int, __spare__: [4]int, }; export type mcontext = struct { mc_gpregs: gpregs, mc_fpregs: fpregs, mc_flags: int, mc_pad: int, mc_spare: [8]u64, }; export type gpregs = struct { gp_x: [30]u64, gp_lr: u64, gp_sp: u64, gp_elr: u64, gp_spsr: u64, gp_pad: int, }; export type fpregs = struct { fp_q: [64]u64, // XXX: Contains 32 128-bit integers fp_sr: u32, fp_cr: u32, fp_flags: int, fp_pad: int, }; hare-0.24.2/rt/+freebsd/+riscv64.ha000066400000000000000000000020441464473310100165200ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type siginfo = struct { si_signo: int, si_errno: int, si_code: int, si_pid: pid_t, si_uid: uid_t, si_status: int, si_addr: *opaque, si_value: sigval, _reason: union { _fault: struct { _trapno: int, }, _timer: struct { _timerid: int, _overrun: int, }, _mesgq: struct { _mqd: int, }, _poll: struct { _band: i64, }, __spare__: struct { __spare1__: i64, __spare2__: [7]int, }, }, }; export type ucontext = struct { uc_sigmask: sigset, uc_mcontext: mcontext, uc_link: *ucontext, uc_stack: stack_t, uc_flags: int, __spare__: [4]int, }; export type mcontext = struct { mc_gpregs: gpregs, mc_fpregs: fpregs, mc_flags: int, mc_pad: int, mc_spare: [8]u64, }; export type gpregs = struct { gp_ra: u64, gp_sp: u64, gp_gp: u64, gp_tp: u64, gp_t: [7]u64, gp_s: [12]u64, gp_a: [8]u64, gp_sepc: u64, gp_sstatus: u64, }; export type fpregs = struct { fp_x: [32][2]u64, fp_fcsr: u64, fp_flags: int, pad: int, }; hare-0.24.2/rt/+freebsd/+x86_64.ha000066400000000000000000000021421464473310100161550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type siginfo = struct { si_signo: int, si_errno: int, si_code: int, si_pid: pid_t, si_uid: uid_t, si_status: int, si_addr: *opaque, si_value: sigval, _reason: union { _fault: struct { _trapno: int, }, _timer: struct { _timerid: int, _overrun: int, }, _mesgq: struct { _mqd: int, }, _poll: struct { _band: i64, }, __spare__: struct { __spare1__: i64, __spare2__: [7]int, }, }, }; export type ucontext = struct { uc_sigmask: sigset, uc_mcontext: mcontext, uc_link: *ucontext, uc_stack: stack_t, uc_flags: int, __spare__: [4]int, }; export type mcontext = struct { mc_onstack: u64, mc_rdi: u64, mc_rsi: u64, mc_rdx: u64, mc_rcx: u64, mc_r8: u64, mc_r9: u64, mc_rax: u64, mc_rbx: u64, mc_rbp: u64, mc_r10: u64, mc_r11: u64, mc_r12: u64, mc_r13: u64, mc_r14: u64, mc_r15: u64, mc_trapno: u32, mc_fs: u16, mc_gs: u16, mc_addr: u64, mc_flags: u32, mc_es: u16, mc_ds: u16, mc_err: u64, mc_rip: u64, mc_cs: u64, mc_rflags: u64, mc_rsp: u64, mc_ss: u64, }; hare-0.24.2/rt/+freebsd/env.ha000066400000000000000000000003211464473310100157310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export let argc: size = 0; export let argv: *[*]*u8 = null: *[*]*u8; export let envp: *[*]nullable *u8 = null: *[*]nullable *u8; hare-0.24.2/rt/+freebsd/errno.ha000066400000000000000000000312741464473310100163010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Represents an error returned from the FreeBSD kernel. export type errno = !int; // Checks the return value from a FreeBSD syscall and, if found to be in error, // returns the appropriate error. Otherwise, returns the original value. fn wrap_return(r: u64) (errno | u64) = { if (r > -4096: u64) { return (-(r: i64)): errno; }; return r; }; // Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not // permitted"). The return value may be statically allocated. export fn strerror(err: errno) str = { switch (err) { case EPERM => return "Operation not permitted"; case ENOENT => return "No such file or directory"; case ESRCH => return "No such process"; case EINTR => return "Interrupted system call"; case EIO => return "Input/output error"; case ENXIO => return "No such device or address"; case E2BIG => return "Argument list too long"; case ENOEXEC => return "Exec format error"; case EBADF => return "Bad file descriptor"; case ECHILD => return "No child processes"; case EAGAIN => return "Resource temporarily unavailable"; case ENOMEM => return "Cannot allocate memory"; case EACCES => return "Permission denied"; case EFAULT => return "Bad address"; case ENOTBLK => return "Block device required"; case EBUSY => return "Device or resource busy"; case EEXIST => return "File exists"; case EXDEV => return "Invalid cross-device link"; case ENODEV => return "No such device"; case ENOTDIR => return "Not a directory"; case EISDIR => return "Is a directory"; case EINVAL => return "Invalid argument"; case ENFILE => return "Too many open files in system"; case EMFILE => return "Too many open files"; case ENOTTY => return "Inappropriate ioctl for device"; case ETXTBSY => return "Text file busy"; case EFBIG => return "File too large"; case ENOSPC => return "No space left on device"; case ESPIPE => return "Illegal seek"; case EROFS => return "Read-only file system"; case EMLINK => return "Too many links"; case EPIPE => return "Broken pipe"; case EDOM => return "Numerical argument out of domain"; case ERANGE => return "Numerical result out of range"; case EDEADLK => return "Resource deadlock avoided"; case ENAMETOOLONG => return "File name too long"; case ENOLCK => return "No locks available"; case ENOSYS => return "Function not implemented"; case ENOTEMPTY => return "Directory not empty"; case ELOOP => return "Too many levels of symbolic links"; case ENOMSG => return "No message of desired type"; case EIDRM => return "Identifier removed"; case EREMOTE => return "Object is remote"; case ENOLINK => return "Link has been severed"; case EPROTO => return "Protocol error"; case EMULTIHOP => return "Multihop attempted"; case EBADMSG => return "Bad message"; case EOVERFLOW => return "Value too large for defined data type"; case EILSEQ => return "Invalid or incomplete multibyte or wide character"; case EUSERS => return "Too many users"; case ENOTSOCK => return "Socket operation on non-socket"; case EDESTADDRREQ => return "Destination address required"; case EMSGSIZE => return "Message too long"; case EPROTOTYPE => return "Protocol wrong type for socket"; case ENOPROTOOPT => return "Protocol not available"; case EPROTONOSUPPORT => return "Protocol not supported"; case ESOCKTNOSUPPORT => return "Socket type not supported"; case EOPNOTSUPP => return "Operation not supported"; case EPFNOSUPPORT => return "Protocol family not supported"; case EAFNOSUPPORT => return "Address family not supported by protocol"; case EADDRINUSE => return "Address already in use"; case EADDRNOTAVAIL => return "Cannot assign requested address"; case ENETDOWN => return "Network is down"; case ENETUNREACH => return "Network is unreachable"; case ENETRESET => return "Network dropped connection on reset"; case ECONNABORTED => return "Software caused connection abort"; case ECONNRESET => return "Connection reset by peer"; case ENOBUFS => return "No buffer space available"; case EISCONN => return "Transport endpoint is already connected"; case ENOTCONN => return "Transport endpoint is not connected"; case ESHUTDOWN => return "Cannot send after transport endpoint shutdown"; case ETOOMANYREFS => return "Too many references: cannot splice"; case ETIMEDOUT => return "Connection timed out"; case ECONNREFUSED => return "Connection refused"; case EHOSTDOWN => return "Host is down"; case EHOSTUNREACH => return "No route to host"; case EALREADY => return "Operation already in progress"; case EINPROGRESS => return "Operation now in progress"; case ESTALE => return "Stale file handle"; case EDQUOT => return "Disk quota exceeded"; case ECANCELED => return "Operation canceled"; case EOWNERDEAD => return "Owner died"; case ENOTRECOVERABLE => return "State not recoverable"; case EAUTH => return "Authentication error"; case EBADRPC => return "RPC struct is bad"; case ECAPMODE => return "Not permitted in capability mode"; case EDOOFUS => return "Programming error"; case EINTEGRITY => return "Integrity check failed"; case ENEEDAUTH => return "Need authenticator"; case ENOATTR => return "Attribute not found"; case ENOTCAPABLE => return "Capabilities insufficient"; case EPROCLIM => return "Too many processes"; case EPROCUNAVAIL => return "Bad procedure for program"; case EPROGMISMATCH => return "Program version wrong"; case EPROGUNAVAIL => return "RPC program not available"; case ERPCMISMATCH => return "RPC version wrong"; case => return unknown_errno(err); }; }; // Gets the programmer-friendly name for an [[errno]] (e.g. EPERM). The return // value may be statically allocated. export fn errname(err: errno) str = { switch (err) { case EPERM => return "EPERM"; case ENOENT => return "ENOENT"; case ESRCH => return "ESRCH"; case EINTR => return "EINTR"; case EIO => return "EIO"; case ENXIO => return "ENXIO"; case E2BIG => return "E2BIG"; case ENOEXEC => return "ENOEXEC"; case EBADF => return "EBADF"; case ECHILD => return "ECHILD"; case EAGAIN => return "EAGAIN"; case ENOMEM => return "ENOMEM"; case EACCES => return "EACCES"; case EFAULT => return "EFAULT"; case ENOTBLK => return "ENOTBLK"; case EBUSY => return "EBUSY"; case EEXIST => return "EEXIST"; case EXDEV => return "EXDEV"; case ENODEV => return "ENODEV"; case ENOTDIR => return "ENOTDIR"; case EISDIR => return "EISDIR"; case EINVAL => return "EINVAL"; case ENFILE => return "ENFILE"; case EMFILE => return "EMFILE"; case ENOTTY => return "ENOTTY"; case ETXTBSY => return "ETXTBSY"; case EFBIG => return "EFBIG"; case ENOSPC => return "ENOSPC"; case ESPIPE => return "ESPIPE"; case EROFS => return "EROFS"; case EMLINK => return "EMLINK"; case EPIPE => return "EPIPE"; case EDOM => return "EDOM"; case ERANGE => return "ERANGE"; case EDEADLK => return "EDEADLK"; case ENAMETOOLONG => return "ENAMETOOLONG"; case ENOLCK => return "ENOLCK"; case ENOSYS => return "ENOSYS"; case ENOTEMPTY => return "ENOTEMPTY"; case ELOOP => return "ELOOP"; case ENOMSG => return "ENOMSG"; case EIDRM => return "EIDRM"; case EREMOTE => return "EREMOTE"; case ENOLINK => return "ENOLINK"; case EPROTO => return "EPROTO"; case EMULTIHOP => return "EMULTIHOP"; case EBADMSG => return "EBADMSG"; case EOVERFLOW => return "EOVERFLOW"; case EILSEQ => return "EILSEQ"; case EUSERS => return "EUSERS"; case ENOTSOCK => return "ENOTSOCK"; case EDESTADDRREQ => return "EDESTADDRREQ"; case EMSGSIZE => return "EMSGSIZE"; case EPROTOTYPE => return "EPROTOTYPE"; case ENOPROTOOPT => return "ENOPROTOOPT"; case EPROTONOSUPPORT => return "EPROTONOSUPPORT"; case ESOCKTNOSUPPORT => return "ESOCKTNOSUPPORT"; case EOPNOTSUPP => return "EOPNOTSUPP"; case EPFNOSUPPORT => return "EPFNOSUPPORT"; case EAFNOSUPPORT => return "EAFNOSUPPORT"; case EADDRINUSE => return "EADDRINUSE"; case EADDRNOTAVAIL => return "EADDRNOTAVAIL"; case ENETDOWN => return "ENETDOWN"; case ENETUNREACH => return "ENETUNREACH"; case ENETRESET => return "ENETRESET"; case ECONNABORTED => return "ECONNABORTED"; case ECONNRESET => return "ECONNRESET"; case ENOBUFS => return "ENOBUFS"; case EISCONN => return "EISCONN"; case ENOTCONN => return "ENOTCONN"; case ESHUTDOWN => return "ESHUTDOWN"; case ETOOMANYREFS => return "ETOOMANYREFS"; case ETIMEDOUT => return "ETIMEDOUT"; case ECONNREFUSED => return "ECONNREFUSED"; case EHOSTDOWN => return "EHOSTDOWN"; case EHOSTUNREACH => return "EHOSTUNREACH"; case EALREADY => return "EALREADY"; case EINPROGRESS => return "EINPROGRESS"; case ESTALE => return "ESTALE"; case EDQUOT => return "EDQUOT"; case ECANCELED => return "ECANCELED"; case EOWNERDEAD => return "EOWNERDEAD"; case ENOTRECOVERABLE => return "ENOTRECOVERABLE"; case EAUTH => return "EAUTH"; case EBADRPC => return "EBADRPC"; case ECAPMODE => return "ECAPMODE"; case EDOOFUS => return "EDOOFUS"; case EINTEGRITY => return "EINTEGRITY"; case ENEEDAUTH => return "ENEEDAUTH"; case ENOATTR => return "ENOATTR"; case ENOTCAPABLE => return "ENOTCAPABLE"; case EPROCLIM => return "EPROCLIM"; case EPROCUNAVAIL => return "EPROCUNAVAIL"; case EPROGMISMATCH => return "EPROGMISMATCH"; case EPROGUNAVAIL => return "EPROGUNAVAIL"; case ERPCMISMATCH => return "ERPCMISMATCH"; case => return unknown_errno(err); }; }; export def EPERM: errno = 1; export def ENOENT: errno = 2; export def ESRCH: errno = 3; export def EINTR: errno = 4; export def EIO: errno = 5; export def ENXIO: errno = 6; export def E2BIG: errno = 7; export def ENOEXEC: errno = 8; export def EBADF: errno = 9; export def ECHILD: errno = 10; export def EDEADLK: errno = 11; export def ENOMEM: errno = 12; export def EACCES: errno = 13; export def EFAULT: errno = 14; export def ENOTBLK: errno = 15; export def EBUSY: errno = 16; export def EEXIST: errno = 17; export def EXDEV: errno = 18; export def ENODEV: errno = 19; export def ENOTDIR: errno = 20; export def EISDIR: errno = 21; export def EINVAL: errno = 22; export def ENFILE: errno = 23; export def EMFILE: errno = 24; export def ENOTTY: errno = 25; export def ETXTBSY: errno = 26; export def EFBIG: errno = 27; export def ENOSPC: errno = 28; export def ESPIPE: errno = 29; export def EROFS: errno = 30; export def EMLINK: errno = 31; export def EPIPE: errno = 32; export def EDOM: errno = 33; export def ERANGE: errno = 34; export def EAGAIN: errno = 35; export def EWOULDBLOCK: errno = EAGAIN; export def EINPROGRESS: errno = 36; export def EALREADY: errno = 37; export def ENOTSOCK: errno = 38; export def EDESTADDRREQ: errno = 39; export def EMSGSIZE: errno = 40; export def EPROTOTYPE: errno = 41; export def ENOPROTOOPT: errno = 42; export def EPROTONOSUPPORT: errno = 43; export def ESOCKTNOSUPPORT: errno = 44; export def EOPNOTSUPP: errno = 45; export def ENOTSUP: errno = EOPNOTSUPP; export def EPFNOSUPPORT: errno = 46; export def EAFNOSUPPORT: errno = 47; export def EADDRINUSE: errno = 48; export def EADDRNOTAVAIL: errno = 49; export def ENETDOWN: errno = 50; export def ENETUNREACH: errno = 51; export def ENETRESET: errno = 52; export def ECONNABORTED: errno = 53; export def ECONNRESET: errno = 54; export def ENOBUFS: errno = 55; export def EISCONN: errno = 56; export def ENOTCONN: errno = 57; export def ESHUTDOWN: errno = 58; export def ETOOMANYREFS: errno = 59; export def ETIMEDOUT: errno = 60; export def ECONNREFUSED: errno = 61; export def ELOOP: errno = 62; export def ENAMETOOLONG: errno = 63; export def EHOSTDOWN: errno = 64; export def EHOSTUNREACH: errno = 65; export def ENOTEMPTY: errno = 66; export def EPROCLIM: errno = 67; export def EUSERS: errno = 68; export def EDQUOT: errno = 69; export def ESTALE: errno = 70; export def EREMOTE: errno = 71; export def EBADRPC: errno = 72; export def ERPCMISMATCH: errno = 73; export def EPROGUNAVAIL: errno = 74; export def EPROGMISMATCH: errno = 75; export def EPROCUNAVAIL: errno = 76; export def ENOLCK: errno = 77; export def ENOSYS: errno = 78; export def EFTYPE: errno = 79; export def EAUTH: errno = 80; export def ENEEDAUTH: errno = 81; export def EIDRM: errno = 82; export def ENOMSG: errno = 83; export def EOVERFLOW: errno = 84; export def ECANCELED: errno = 85; export def EILSEQ: errno = 86; export def ENOATTR: errno = 87; export def EDOOFUS: errno = 88; export def EBADMSG: errno = 89; export def EMULTIHOP: errno = 90; export def ENOLINK: errno = 91; export def EPROTO: errno = 92; export def ENOTCAPABLE: errno = 93; export def ECAPMODE: errno = 94; export def ENOTRECOVERABLE: errno = 95; export def EOWNERDEAD: errno = 96; export def EINTEGRITY: errno = 97; hare-0.24.2/rt/+freebsd/hare+libc.sc000066400000000000000000000004221464473310100170040ustar00rootroot00000000000000SECTIONS { .libc_init_array : { PROVIDE(__libc_init_array_start = .); KEEP(*(.init_array)) PROVIDE(__libc_init_array_end = .); } .test_array : { PROVIDE(__test_array_start = .); KEEP(*(.test_array*)) PROVIDE(__test_array_end = .); } } INSERT AFTER .dynamic; hare-0.24.2/rt/+freebsd/hare.sc000066400000000000000000000012671464473310100161070ustar00rootroot00000000000000PHDRS { headers PT_PHDR PHDRS; text PT_LOAD FILEHDR PHDRS; data PT_LOAD; } ENTRY(_start); SECTIONS { . = 0x8000000; .text : { KEEP (*(.text)) *(.text.*) } :text . = 0x80000000; .data : { KEEP (*(.data)) *(.data.*) } :data .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); } :data .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); } :data .test_array : { PROVIDE_HIDDEN (__test_array_start = .); KEEP (*(.test_array)) PROVIDE_HIDDEN (__test_array_end = .); } :data .bss : { KEEP (*(.bss)) *(.bss.*) } :data } hare-0.24.2/rt/+freebsd/initfini.ha000066400000000000000000000010161464473310100167540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Run all global initialization functions. export fn init() void = { const ninit = (&init_end: uintptr - &init_start: uintptr): size / size(*fn() void); for (let i = 0z; i < ninit; i += 1) { init_start[i](); }; }; // Run all global finalization functions. export fn fini() void = { const nfini = (&fini_end: uintptr - &fini_start: uintptr): size / size(*fn() void); for (let i = nfini; i > 0; i -= 1) { fini_start[i - 1](); }; }; hare-0.24.2/rt/+freebsd/platform_abort.ha000066400000000000000000000011711464473310100201600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn strvec(s: str) iovec = { return iovec { iov_base = *(&s: **opaque), iov_len = len(s), }; }; fn platform_abort(path: *str, line: u64, col: u64, msg: str) never = { let linebuf: [U64_BUFSZ]u8 = [0...]; let colbuf: [U64_BUFSZ]u8 = [0...]; const iov = [ strvec("Abort: "), strvec(*path), strvec(":"), strvec(u64tos(linebuf, line)), strvec(":"), strvec(u64tos(colbuf, col)), strvec(": "), strvec(msg), strvec("\n"), ]; writev(STDERR_FILENO, &iov, len(iov): int): void; for (true) { kill(getpid(), SIGABRT): void; }; }; hare-0.24.2/rt/+freebsd/platformstart-libc.ha000066400000000000000000000004101464473310100207510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn start_freebsd(iv: *[*]uintptr) never = { // TODO: Find & parse auxv argc = iv[0]: size; argv = &iv[1]: *[*]*u8; envp = &argv[argc + 1]: *[*]nullable *u8; start_ha(); }; hare-0.24.2/rt/+freebsd/segmalloc.ha000066400000000000000000000010331464473310100171100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Allocates a segment. fn segmalloc(n: size) nullable *opaque = { return match (mmap(null, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) { case let err: errno => assert(err == ENOMEM: errno); yield null; case let p: *opaque => yield p; }; }; // Frees a segment allocated with segmalloc. fn segfree(p: *opaque, s: size) void = { match (munmap(p, s)) { case let err: errno => abort("munmap failed"); case void => void; }; }; hare-0.24.2/rt/+freebsd/signal.ha000066400000000000000000000076341464473310100164340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: work when _NSIG != 32 export fn alarm(sec: uint) uint = { let nval = itimerval { ... }; let oval = itimerval { ... }; nval.it_value.tv_sec = sec: time_t; setitimer(ITIMER_REAL, &nval, &oval)!; if (oval.it_value.tv_usec != 0) { oval.it_value.tv_sec += 1; }; return oval.it_value.tv_sec: uint; }; export def ITIMER_REAL: int = 0; export def ITIMER_VIRTUAL: int = 1; export def ITIMER_PROF: int = 2; export type itimerval = struct { it_interval: timeval, it_value: timeval, }; export fn getitimer( which: int, cur: *itimerval, ) (void | errno) = { wrap_return(syscall2(SYS_getitimer, which: u64, cur: uintptr: u64))?; }; export fn setitimer( which: int, newval: *itimerval, oldval: nullable *itimerval, ) (void | errno) = { wrap_return(syscall3(SYS_setitimer, which: u64, newval: uintptr: u64, oldval: uintptr: u64))?; }; export fn sigwait(set: *sigset, sig: *int) (void | errno) = { *sig = sigwaitinfo(set, null)?; }; export fn sigwaitinfo( set: *sigset, info: nullable *siginfo, ) (int | errno) = { return wrap_return(syscall2(SYS_sigwaitinfo, set: uintptr: u64, info: uintptr: u64, ))?: int; }; export fn sigtimedwait( set: *sigset, info: nullable *siginfo, timeout: nullable *timespec, ) (int | errno) = { return wrap_return(syscall3(SYS_sigtimedwait, set: uintptr: u64, info: uintptr: u64, timeout: uintptr: u64, ))?: int; }; export fn sigemptyset(set: *sigset) void = { for (let i = 0z; i < len(set.__bits); i += 1) { set.__bits[i] = 0; }; }; export fn sigaddset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__bits[signum >> 5] |= (1 << signum): u32; }; export fn sigdelset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__bits[signum >> 5] &= ~(1 << signum: u32); }; export fn sigismember(set: *sigset, signum: int) (bool | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; return (set.__bits[signum >> 5] & (1 << signum: u32)) != 0; }; export fn sigfillset(set: *sigset) (void | errno) = { for (let i = 0z; i < len(set.__bits); i += 1) { set.__bits[i] = ~0u32; }; }; // Test sigset operations do not fail for valid signal numbers. @test fn sigset_valid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(!(sigismember(&set, 1) is errno), "Unexpected error"); assert(!(sigismember(&set, 15) is errno), "Unexpected error"); assert(!(sigismember(&set, NSIG) is errno), "Unexpected error"); assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigaddset(&set, 15) is errno), "Unexpected error"); assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error"); // It's ok to add a signal that is already present in the set. assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 15) is errno), "Unexpected error"); assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error"); // It's ok to delete a signal that is not present in the set. assert(!(sigdelset(&set, 10) is errno), "Unexpected error"); }; // Test sigset operations fail for invalid signal numbers. @test fn sigset_invalid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(sigismember(&set, -1) is errno, "Expected error"); assert(sigismember(&set, 0) is errno, "Expected error"); assert(sigismember(&set, NSIG + 1) is errno, "Expected error"); assert(sigaddset(&set, -1) is errno, "Expected error"); assert(sigaddset(&set, 0) is errno, "Expected error"); assert(sigaddset(&set, NSIG + 1) is errno, "Expected error"); assert(sigdelset(&set, -1) is errno, "Expected error"); assert(sigdelset(&set, 0) is errno, "Expected error"); assert(sigdelset(&set, NSIG + 1) is errno, "Expected error"); }; hare-0.24.2/rt/+freebsd/socket.ha000066400000000000000000000267711464473310100164520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sa_family_t = u8; export type socklen_t = u32; export type in_addr = struct { s_addr: u32 }; export type sockaddr_in = struct { sin_len: u8, sin_family: sa_family_t, sin_port: u16, sin_addr: in_addr, __pad: [8]u8, }; export type in6_addr = struct { union { s6_addr: [16]u8, s6_addr16: [8]u16, s6_addr32: [4]u32, } }; export type sockaddr_in6 = struct { sin6_len: u8, sin6_family: sa_family_t, sin6_port: u16, sin6_flowinfo: u32, sin6_addr: in6_addr, sin6_scope_id: u32, }; export def UNIX_PATH_MAX: size = 104; export type sockaddr_un = struct { sun_len: u8, sun_family: sa_family_t, sun_path: [UNIX_PATH_MAX]u8, }; export type sockaddr = struct { union { in: sockaddr_in, in6: sockaddr_in6, un: sockaddr_un, }, }; export def SCM_RIGHTS: int = 0x01; export def SCM_CREDENTIALS: int = 0x02; export type msghdr = struct { msg_name: nullable *opaque, msg_namelen: socklen_t, msg_iov: nullable *[*]iovec, msg_iovlen: int, msg_control: nullable *opaque, msg_controllen: socklen_t, msg_flags: int }; export type cmsghdr = struct { cmsg_len: socklen_t, cmsg_level: int, cmsg_type: int, }; export type cmsg = struct { hdr: cmsghdr, cmsg_data: [*]u8, }; export def AF_UNSPEC: sa_family_t = 0; export def AF_UNIX: sa_family_t = 1; export def AF_LOCAL: sa_family_t = AF_UNIX; export def AF_INET: sa_family_t = 2; export def AF_IMPLINK: sa_family_t = 3; export def AF_PUP: sa_family_t = 4; export def AF_CHAOS: sa_family_t = 5; export def AF_NETBIOS: sa_family_t = 6; export def AF_ISO: sa_family_t = 7; export def AF_OSI: sa_family_t = AF_ISO; export def AF_ECMA: sa_family_t = 8; export def AF_DATAKIT: sa_family_t = 9; export def AF_CCITT: sa_family_t = 10; export def AF_SNA: sa_family_t = 11; export def AF_DECnet: sa_family_t = 12; export def AF_DLI: sa_family_t = 13; export def AF_LAT: sa_family_t = 14; export def AF_HYLINK: sa_family_t = 15; export def AF_APPLETALK: sa_family_t = 16; export def AF_ROUTE: sa_family_t = 17; export def AF_LINK: sa_family_t = 18; export def pseudo_AF_XTP: sa_family_t = 19; export def AF_COIP: sa_family_t = 20; export def AF_CNT: sa_family_t = 21; export def pseudo_AF_RTIP: sa_family_t = 22; export def AF_IPX: sa_family_t = 23; export def AF_SIP: sa_family_t = 24; export def pseudo_AF_PIP: sa_family_t = 25; export def AF_ISDN: sa_family_t = 26; export def AF_E164: sa_family_t = AF_ISDN; export def AF_INET6: sa_family_t = 28; export def AF_NATM: sa_family_t = 29; export def AF_ATM: sa_family_t = 30; export def AF_NETGRAPH: sa_family_t = 32; export def AF_SLOW: sa_family_t = 33; export def AF_SCLUSTER: sa_family_t = 34; export def AF_ARP: sa_family_t = 35; export def AF_BLUETOOTH: sa_family_t = 36; export def AF_IEEE80211: sa_family_t = 37; export def AF_INET_SDP: sa_family_t = 40; export def AF_INET6_SDP: sa_family_t = 42; export def AF_HYPERV: sa_family_t = 43; export def AF_MAX: sa_family_t = 43; export def AF_VENDOR00: sa_family_t = 39; export def AF_VENDOR01: sa_family_t = 41; export def AF_VENDOR03: sa_family_t = 45; export def AF_VENDOR04: sa_family_t = 47; export def AF_VENDOR05: sa_family_t = 49; export def AF_VENDOR06: sa_family_t = 51; export def AF_VENDOR07: sa_family_t = 53; export def AF_VENDOR08: sa_family_t = 55; export def AF_VENDOR09: sa_family_t = 57; export def AF_VENDOR10: sa_family_t = 59; export def AF_VENDOR11: sa_family_t = 61; export def AF_VENDOR12: sa_family_t = 63; export def AF_VENDOR13: sa_family_t = 65; export def AF_VENDOR14: sa_family_t = 67; export def AF_VENDOR15: sa_family_t = 69; export def AF_VENDOR16: sa_family_t = 71; export def AF_VENDOR17: sa_family_t = 73; export def AF_VENDOR18: sa_family_t = 75; export def AF_VENDOR19: sa_family_t = 77; export def AF_VENDOR20: sa_family_t = 79; export def AF_VENDOR21: sa_family_t = 81; export def AF_VENDOR22: sa_family_t = 83; export def AF_VENDOR23: sa_family_t = 85; export def AF_VENDOR24: sa_family_t = 87; export def AF_VENDOR25: sa_family_t = 89; export def AF_VENDOR26: sa_family_t = 91; export def AF_VENDOR27: sa_family_t = 93; export def AF_VENDOR28: sa_family_t = 95; export def AF_VENDOR29: sa_family_t = 97; export def AF_VENDOR30: sa_family_t = 99; export def AF_VENDOR31: sa_family_t = 101; export def AF_VENDOR32: sa_family_t = 103; export def AF_VENDOR33: sa_family_t = 105; export def AF_VENDOR34: sa_family_t = 107; export def AF_VENDOR35: sa_family_t = 109; export def AF_VENDOR36: sa_family_t = 111; export def AF_VENDOR37: sa_family_t = 113; export def AF_VENDOR38: sa_family_t = 115; export def AF_VENDOR39: sa_family_t = 117; export def AF_VENDOR40: sa_family_t = 119; export def AF_VENDOR41: sa_family_t = 121; export def AF_VENDOR42: sa_family_t = 123; export def AF_VENDOR43: sa_family_t = 125; export def AF_VENDOR44: sa_family_t = 127; export def AF_VENDOR45: sa_family_t = 129; export def AF_VENDOR46: sa_family_t = 131; export def AF_VENDOR47: sa_family_t = 133; export def SOCK_STREAM: int = 1; export def SOCK_DGRAM: int = 2; export def SOCK_RAW: int = 3; export def SOCK_RDM: int = 4; export def SOCK_SEQPACKET: int = 5; export def SOCK_CLOEXEC: int = 0x10000000; export def SOCK_NONBLOCK: int = 0x20000000; export def IPPROTO_IP: int = 0; export def IPPROTO_ICMP: int = 1; export def IPPROTO_TCP: int = 6; export def IPPROTO_UDP: int = 17; export def IPPROTO_IPV6: int = 41; export def IPPROTO_RAW: int = 255; export def IPPROTO_HOPOPTS: int = 0; export def IPPROTO_IGMP: int = 2; export def IPPROTO_GGP: int = 3; export def IPPROTO_IPV4: int = 4; export def IPPROTO_IPIP: int = IPPROTO_IPV4; export def IPPROTO_ST: int = 7; export def IPPROTO_EGP: int = 8; export def IPPROTO_PIGP: int = 9; export def IPPROTO_RCCMON: int = 10; export def IPPROTO_NVPII: int = 11; export def IPPROTO_PUP: int = 12; export def IPPROTO_ARGUS: int = 13; export def IPPROTO_EMCON: int = 14; export def IPPROTO_XNET: int = 15; export def IPPROTO_CHAOS: int = 16; export def IPPROTO_MUX: int = 18; export def IPPROTO_MEAS: int = 19; export def IPPROTO_HMP: int = 20; export def IPPROTO_PRM: int = 21; export def IPPROTO_IDP: int = 22; export def IPPROTO_TRUNK1: int = 23; export def IPPROTO_TRUNK2: int = 24; export def IPPROTO_LEAF1: int = 25; export def IPPROTO_LEAF2: int = 26; export def IPPROTO_RDP: int = 27; export def IPPROTO_IRTP: int = 28; export def IPPROTO_TP: int = 29; export def IPPROTO_BLT: int = 30; export def IPPROTO_NSP: int = 31; export def IPPROTO_INP: int = 32; export def IPPROTO_DCCP: int = 33; export def IPPROTO_3PC: int = 34; export def IPPROTO_IDPR: int = 35; export def IPPROTO_XTP: int = 36; export def IPPROTO_DDP: int = 37; export def IPPROTO_CMTP: int = 38; export def IPPROTO_TPXX: int = 39; export def IPPROTO_IL: int = 40; export def IPPROTO_SDRP: int = 42; export def IPPROTO_ROUTING: int = 43; export def IPPROTO_FRAGMENT: int = 44; export def IPPROTO_IDRP: int = 45; export def IPPROTO_RSVP: int = 46; export def IPPROTO_GRE: int = 47; export def IPPROTO_MHRP: int = 48; export def IPPROTO_BHA: int = 49; export def IPPROTO_ESP: int = 50; export def IPPROTO_AH: int = 51; export def IPPROTO_INLSP: int = 52; export def IPPROTO_SWIPE: int = 53; export def IPPROTO_NHRP: int = 54; export def IPPROTO_MOBILE: int = 55; export def IPPROTO_TLSP: int = 56; export def IPPROTO_SKIP: int = 57; export def IPPROTO_ICMPV6: int = 58; export def IPPROTO_NONE: int = 59; export def IPPROTO_DSTOPTS: int = 60; export def IPPROTO_AHIP: int = 61; export def IPPROTO_CFTP: int = 62; export def IPPROTO_HELLO: int = 63; export def IPPROTO_SATEXPAK: int = 64; export def IPPROTO_KRYPTOLAN: int = 65; export def IPPROTO_RVD: int = 66; export def IPPROTO_IPPC: int = 67; export def IPPROTO_ADFS: int = 68; export def IPPROTO_SATMON: int = 69; export def IPPROTO_VISA: int = 70; export def IPPROTO_IPCV: int = 71; export def IPPROTO_CPNX: int = 72; export def IPPROTO_CPHB: int = 73; export def IPPROTO_WSN: int = 74; export def IPPROTO_PVP: int = 75; export def IPPROTO_BRSATMON: int = 76; export def IPPROTO_ND: int = 77; export def IPPROTO_WBMON: int = 78; export def IPPROTO_WBEXPAK: int = 79; export def IPPROTO_EON: int = 80; export def IPPROTO_VMTP: int = 81; export def IPPROTO_SVMTP: int = 82; export def IPPROTO_VINES: int = 83; export def IPPROTO_TTP: int = 84; export def IPPROTO_IGP: int = 85; export def IPPROTO_DGP: int = 86; export def IPPROTO_TCF: int = 87; export def IPPROTO_IGRP: int = 88; export def IPPROTO_OSPFIGP: int = 89; export def IPPROTO_SRPC: int = 90; export def IPPROTO_LARP: int = 91; export def IPPROTO_MTP: int = 92; export def IPPROTO_AX25: int = 93; export def IPPROTO_IPEIP: int = 94; export def IPPROTO_MICP: int = 95; export def IPPROTO_SCCSP: int = 96; export def IPPROTO_ETHERIP: int = 97; export def IPPROTO_ENCAP: int = 98; export def IPPROTO_APES: int = 99; export def IPPROTO_GMTP: int = 100; export def IPPROTO_IPCOMP: int = 108; export def IPPROTO_SCTP: int = 132; export def IPPROTO_MH: int = 135; export def IPPROTO_UDPLITE: int = 136; export def IPPROTO_HIP: int = 139; export def IPPROTO_SHIM6: int = 140; export def IPPROTO_PIM: int = 103; export def IPPROTO_CARP: int = 112; export def IPPROTO_PGM: int = 113; export def IPPROTO_MPLS: int = 137; export def IPPROTO_PFSYNC: int = 240; export def IPPROTO_RESERVED_253: int = 253; export def IPPROTO_RESERVED_254: int = 254; export def MSG_OOB: int = 0x00000001; export def MSG_PEEK: int = 0x00000002; export def MSG_DONTROUTE: int = 0x00000004; export def MSG_EOR: int = 0x00000008; export def MSG_TRUNC: int = 0x00000010; export def MSG_CTRUNC: int = 0x00000020; export def MSG_WAITALL: int = 0x00000040; export def MSG_DONTWAIT: int = 0x00000080; export def MSG_EOF: int = 0x00000100; export def MSG_NOTIFICATION: int = 0x00002000; export def MSG_NBIO: int = 0x00004000; export def MSG_COMPAT: int = 0x00008000; export def MSG_NOSIGNAL: int = 0x00020000; export def MSG_CMSG_CLOEXEC: int = 0x00040000; export def MSG_WAITFORONE: int = 0x00080000; export def SO_DEBUG: int = 0x00000001; export def SO_ACCEPTCONN: int = 0x00000002; export def SO_REUSEADDR: int = 0x00000004; export def SO_KEEPALIVE: int = 0x00000008; export def SO_DONTROUTE: int = 0x00000010; export def SO_BROADCAST: int = 0x00000020; export def SO_USELOOPBACK: int = 0x00000040; export def SO_LINGER: int = 0x00000080; export def SO_OOBINLINE: int = 0x00000100; export def SO_REUSEPORT: int = 0x00000200; export def SO_TIMESTAMP: int = 0x00000400; export def SO_NOSIGPIPE: int = 0x00000800; export def SO_ACCEPTFILTER: int = 0x00001000; export def SO_BINTIME: int = 0x00002000; export def SO_NO_OFFLOAD: int = 0x00004000; export def SO_NO_DDP: int = 0x00008000; export def SO_REUSEPORT_LB: int = 0x00010000; export def SO_SNDBUF: int = 0x1001; export def SO_RCVBUF: int = 0x1002; export def SO_SNDLOWAT: int = 0x1003; export def SO_RCVLOWAT: int = 0x1004; export def SO_SNDTIMEO: int = 0x1005; export def SO_RCVTIMEO: int = 0x1006; export def SO_ERROR: int = 0x1007; export def SO_TYPE: int = 0x1008; export def SO_LABEL: int = 0x1009; export def SO_PEERLABEL: int = 0x1010; export def SO_LISTENQLIMIT: int = 0x1011; export def SO_LISTENQLEN: int = 0x1012; export def SO_LISTENINCQLEN: int = 0x1013; export def SO_SETFIB: int = 0x1014; export def SO_USER_COOKIE: int = 0x1015; export def SO_PROTOCOL: int = 0x1016; export def SO_PROTOTYPE: int = SO_PROTOCOL; export def SO_TS_CLOCK: int = 0x1017; export def SO_MAX_PACING_RATE: int = 0x1018; export def SO_DOMAIN: int = 0x1019; export def SO_TS_REALTIME_MICRO: int = 0; export def SO_TS_BINTIME: int = 1; export def SO_TS_REALTIME: int = 2; export def SO_TS_MONOTONIC: int = 3; export def SO_TS_DEFAULT: int = SO_TS_REALTIME_MICRO; export def SO_TS_CLOCK_MAX: int = SO_TS_MONOTONIC; export def SOL_SOCKET: int = 0xffff; hare-0.24.2/rt/+freebsd/start+aarch64-libc.s000066400000000000000000000001351464473310100203060ustar00rootroot00000000000000.text .global _start _start: mov x29, #0 mov x30, #0 and sp, sp, #-16 b rt.start_freebsd hare-0.24.2/rt/+freebsd/start+libc.ha000066400000000000000000000014601464473310100172100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol(".main") fn main() void; @symbol("exit") fn c_exit(status: int) never; const @symbol("__libc_init_array_start") init_start: [*]*fn() void; const @symbol("__libc_init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export @symbol("main") fn start_ha(c_argc: int, c_argv: *[*]*u8) never = { argc = c_argc: size; argv = c_argv; envp = c_envp; // we deliberately prevent libc from running @init for us, in order to // be able to initialize argc/argv/envp beforehand. we can still get // away with just using libc for @fini though init(); main(); c_exit(0); }; let @symbol("environ") c_envp: *[*]nullable *u8; hare-0.24.2/rt/+freebsd/start+riscv64-libc.s000066400000000000000000000001061464473310100203540ustar00rootroot00000000000000.text .global _start _start: andi sp, sp, -16 tail rt.start_freebsd hare-0.24.2/rt/+freebsd/start+test+libc.ha000066400000000000000000000014631464473310100201660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("__test_main") fn test_main() size; const @symbol("__libc_init_array_start") init_start: [*]*fn() void; const @symbol("__libc_init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export @symbol("main") fn start_ha(c_argc: int, c_argv: *[*]*u8) int = { argc = c_argc: size; argv = c_argv; envp = c_envp; // we deliberately prevent libc from running @init for us, in order to // be able to initialize argc/argv/envp beforehand. we can still get // away with just using libc for @fini though init(); const nfail = test_main(); return if (nfail > 0) 1 else 0; }; let @symbol("environ") c_envp: *[*]nullable *u8; hare-0.24.2/rt/+freebsd/start+test.ha000066400000000000000000000007421464473310100172600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("__test_main") fn test_main() size; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); const nfail = test_main(); fini(); exit(if (nfail > 0) 1 else 0); }; hare-0.24.2/rt/+freebsd/start+x86_64-libc.s000066400000000000000000000001241464473310100200120ustar00rootroot00000000000000.text .global _start _start: xor %rbp, %rbp and $-16, %rsp call rt.start_freebsd hare-0.24.2/rt/+freebsd/start.ha000066400000000000000000000006551464473310100163100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("main") fn main() void; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); main(); fini(); exit(0); }; hare-0.24.2/rt/+freebsd/syscall+aarch64.s000066400000000000000000000015161464473310100177200ustar00rootroot00000000000000.section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: mov x8, x0 svc 0 ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: mov x8, x0 mov x0, x1 svc 0 ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: mov x8, x0 mov x0, x1 mov x1, x2 svc 0 ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 svc 0 ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 svc 0 ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 mov x4, x5 svc 0 ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 mov x4, x5 mov x5, x6 svc 0 ret hare-0.24.2/rt/+freebsd/syscall+riscv64.s000066400000000000000000000014621464473310100177700ustar00rootroot00000000000000.section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: mv a7, a0 ecall ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: mv a7, a0 mv a0, a1 ecall ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: mv a7, a0 mv a0, a1 mv a1, a2 ecall ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 ecall ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 ecall ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 mv a4, a5 ecall ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 mv a4, a5 mv a5, a6 ecall ret hare-0.24.2/rt/+freebsd/syscall+x86_64.s000066400000000000000000000021171464473310100174240ustar00rootroot00000000000000.section .text error: neg %rax ret .section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: movq %rdi, %rax syscall jc error ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: movq %rdi, %rax movq %rsi, %rdi syscall jc error ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi syscall jc error ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq 8(%rsp), %r9 movq %rcx, %rdx syscall jc error ret hare-0.24.2/rt/+freebsd/syscallno.ha000066400000000000000000000367151464473310100171700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def SYS_syscall: u64 = 0; export def SYS_exit: u64 = 1; export def SYS_fork: u64 = 2; export def SYS_read: u64 = 3; export def SYS_write: u64 = 4; export def SYS_open: u64 = 5; export def SYS_close: u64 = 6; export def SYS_wait4: u64 = 7; export def SYS_link: u64 = 9; export def SYS_unlink: u64 = 10; export def SYS_chdir: u64 = 12; export def SYS_fchdir: u64 = 13; export def SYS_freebsd11_mknod: u64 = 14; export def SYS_chmod: u64 = 15; export def SYS_chown: u64 = 16; export def SYS_break: u64 = 17; export def SYS_getpid: u64 = 20; export def SYS_mount: u64 = 21; export def SYS_unmount: u64 = 22; export def SYS_setuid: u64 = 23; export def SYS_getuid: u64 = 24; export def SYS_geteuid: u64 = 25; export def SYS_ptrace: u64 = 26; export def SYS_recvmsg: u64 = 27; export def SYS_sendmsg: u64 = 28; export def SYS_recvfrom: u64 = 29; export def SYS_accept: u64 = 30; export def SYS_getpeername: u64 = 31; export def SYS_getsockname: u64 = 32; export def SYS_access: u64 = 33; export def SYS_chflags: u64 = 34; export def SYS_fchflags: u64 = 35; export def SYS_sync: u64 = 36; export def SYS_kill: u64 = 37; export def SYS_getppid: u64 = 39; export def SYS_dup: u64 = 41; export def SYS_freebsd10_pipe: u64 = 42; export def SYS_getegid: u64 = 43; export def SYS_profil: u64 = 44; export def SYS_ktrace: u64 = 45; export def SYS_getgid: u64 = 47; export def SYS_getlogin: u64 = 49; export def SYS_setlogin: u64 = 50; export def SYS_acct: u64 = 51; export def SYS_sigaltstack: u64 = 53; export def SYS_ioctl: u64 = 54; export def SYS_reboot: u64 = 55; export def SYS_revoke: u64 = 56; export def SYS_symlink: u64 = 57; export def SYS_readlink: u64 = 58; export def SYS_execve: u64 = 59; export def SYS_umask: u64 = 60; export def SYS_chroot: u64 = 61; export def SYS_msync: u64 = 65; export def SYS_vfork: u64 = 66; export def SYS_sbrk: u64 = 69; export def SYS_sstk: u64 = 70; export def SYS_freebsd11_vadvise: u64 = 72; export def SYS_munmap: u64 = 73; export def SYS_mprotect: u64 = 74; export def SYS_madvise: u64 = 75; export def SYS_mincore: u64 = 78; export def SYS_getgroups: u64 = 79; export def SYS_setgroups: u64 = 80; export def SYS_getpgrp: u64 = 81; export def SYS_setpgid: u64 = 82; export def SYS_setitimer: u64 = 83; export def SYS_swapon: u64 = 85; export def SYS_getitimer: u64 = 86; export def SYS_getdtablesize: u64 = 89; export def SYS_dup2: u64 = 90; export def SYS_fcntl: u64 = 92; export def SYS_select: u64 = 93; export def SYS_fsync: u64 = 95; export def SYS_setpriority: u64 = 96; export def SYS_socket: u64 = 97; export def SYS_connect: u64 = 98; export def SYS_getpriority: u64 = 100; export def SYS_bind: u64 = 104; export def SYS_setsockopt: u64 = 105; export def SYS_listen: u64 = 106; export def SYS_gettimeofday: u64 = 116; export def SYS_getrusage: u64 = 117; export def SYS_getsockopt: u64 = 118; export def SYS_readv: u64 = 120; export def SYS_writev: u64 = 121; export def SYS_settimeofday: u64 = 122; export def SYS_fchown: u64 = 123; export def SYS_fchmod: u64 = 124; export def SYS_setreuid: u64 = 126; export def SYS_setregid: u64 = 127; export def SYS_rename: u64 = 128; export def SYS_flock: u64 = 131; export def SYS_mkfifo: u64 = 132; export def SYS_sendto: u64 = 133; export def SYS_shutdown: u64 = 134; export def SYS_socketpair: u64 = 135; export def SYS_mkdir: u64 = 136; export def SYS_rmdir: u64 = 137; export def SYS_utimes: u64 = 138; export def SYS_adjtime: u64 = 140; export def SYS_setsid: u64 = 147; export def SYS_quotactl: u64 = 148; export def SYS_nlm_syscall: u64 = 154; export def SYS_nfssvc: u64 = 155; export def SYS_lgetfh: u64 = 160; export def SYS_getfh: u64 = 161; export def SYS_sysarch: u64 = 165; export def SYS_rtprio: u64 = 166; export def SYS_semsys: u64 = 169; export def SYS_msgsys: u64 = 170; export def SYS_shmsys: u64 = 171; export def SYS_setfib: u64 = 175; export def SYS_ntp_adjtime: u64 = 176; export def SYS_setgid: u64 = 181; export def SYS_setegid: u64 = 182; export def SYS_seteuid: u64 = 183; export def SYS_freebsd11_stat: u64 = 188; export def SYS_freebsd11_fstat: u64 = 189; export def SYS_freebsd11_lstat: u64 = 190; export def SYS_pathconf: u64 = 191; export def SYS_fpathconf: u64 = 192; export def SYS_getrlimit: u64 = 194; export def SYS_setrlimit: u64 = 195; export def SYS_freebsd11_getdirentries: u64 = 196; export def SYS___syscall: u64 = 198; export def SYS___sysctl: u64 = 202; export def SYS_mlock: u64 = 203; export def SYS_munlock: u64 = 204; export def SYS_undelete: u64 = 205; export def SYS_futimes: u64 = 206; export def SYS_getpgid: u64 = 207; export def SYS_poll: u64 = 209; export def SYS_freebsd7___semctl: u64 = 220; export def SYS_semget: u64 = 221; export def SYS_semop: u64 = 222; export def SYS_freebsd7_msgctl: u64 = 224; export def SYS_msgget: u64 = 225; export def SYS_msgsnd: u64 = 226; export def SYS_msgrcv: u64 = 227; export def SYS_shmat: u64 = 228; export def SYS_freebsd7_shmctl: u64 = 229; export def SYS_shmdt: u64 = 230; export def SYS_shmget: u64 = 231; export def SYS_clock_gettime: u64 = 232; export def SYS_clock_settime: u64 = 233; export def SYS_clock_getres: u64 = 234; export def SYS_ktimer_create: u64 = 235; export def SYS_ktimer_delete: u64 = 236; export def SYS_ktimer_settime: u64 = 237; export def SYS_ktimer_gettime: u64 = 238; export def SYS_ktimer_getoverrun: u64 = 239; export def SYS_nanosleep: u64 = 240; export def SYS_ffclock_getcounter: u64 = 241; export def SYS_ffclock_setestimate: u64 = 242; export def SYS_ffclock_getestimate: u64 = 243; export def SYS_clock_nanosleep: u64 = 244; export def SYS_clock_getcpuclockid2: u64 = 247; export def SYS_ntp_gettime: u64 = 248; export def SYS_minherit: u64 = 250; export def SYS_rfork: u64 = 251; export def SYS_issetugid: u64 = 253; export def SYS_lchown: u64 = 254; export def SYS_aio_read: u64 = 255; export def SYS_aio_write: u64 = 256; export def SYS_lio_listio: u64 = 257; export def SYS_freebsd11_getdents: u64 = 272; export def SYS_lchmod: u64 = 274; export def SYS_lutimes: u64 = 276; export def SYS_freebsd11_nstat: u64 = 278; export def SYS_freebsd11_nfstat: u64 = 279; export def SYS_freebsd11_nlstat: u64 = 280; export def SYS_preadv: u64 = 289; export def SYS_pwritev: u64 = 290; export def SYS_fhopen: u64 = 298; export def SYS_freebsd11_fhstat: u64 = 299; export def SYS_modnext: u64 = 300; export def SYS_modstat: u64 = 301; export def SYS_modfnext: u64 = 302; export def SYS_modfind: u64 = 303; export def SYS_kldload: u64 = 304; export def SYS_kldunload: u64 = 305; export def SYS_kldfind: u64 = 306; export def SYS_kldnext: u64 = 307; export def SYS_kldstat: u64 = 308; export def SYS_kldfirstmod: u64 = 309; export def SYS_getsid: u64 = 310; export def SYS_setresuid: u64 = 311; export def SYS_setresgid: u64 = 312; export def SYS_aio_return: u64 = 314; export def SYS_aio_suspend: u64 = 315; export def SYS_aio_cancel: u64 = 316; export def SYS_aio_error: u64 = 317; export def SYS_yield: u64 = 321; export def SYS_mlockall: u64 = 324; export def SYS_munlockall: u64 = 325; export def SYS___getcwd: u64 = 326; export def SYS_sched_setparam: u64 = 327; export def SYS_sched_getparam: u64 = 328; export def SYS_sched_setscheduler: u64 = 329; export def SYS_sched_getscheduler: u64 = 330; export def SYS_sched_yield: u64 = 331; export def SYS_sched_get_priority_max: u64 = 332; export def SYS_sched_get_priority_min: u64 = 333; export def SYS_sched_rr_get_u64erval: u64 = 334; export def SYS_utrace: u64 = 335; export def SYS_kldsym: u64 = 337; export def SYS_jail: u64 = 338; export def SYS_nnpfs_syscall: u64 = 339; export def SYS_sigprocmask: u64 = 340; export def SYS_sigsuspend: u64 = 341; export def SYS_sigpending: u64 = 343; export def SYS_sigtimedwait: u64 = 345; export def SYS_sigwaitinfo: u64 = 346; export def SYS___acl_get_file: u64 = 347; export def SYS___acl_set_file: u64 = 348; export def SYS___acl_get_fd: u64 = 349; export def SYS___acl_set_fd: u64 = 350; export def SYS___acl_delete_file: u64 = 351; export def SYS___acl_delete_fd: u64 = 352; export def SYS___acl_aclcheck_file: u64 = 353; export def SYS___acl_aclcheck_fd: u64 = 354; export def SYS_extattrctl: u64 = 355; export def SYS_extattr_set_file: u64 = 356; export def SYS_extattr_get_file: u64 = 357; export def SYS_extattr_delete_file: u64 = 358; export def SYS_aio_waitcomplete: u64 = 359; export def SYS_getresuid: u64 = 360; export def SYS_getresgid: u64 = 361; export def SYS_kqueue: u64 = 362; export def SYS_freebsd11_kevent: u64 = 363; export def SYS_extattr_set_fd: u64 = 371; export def SYS_extattr_get_fd: u64 = 372; export def SYS_extattr_delete_fd: u64 = 373; export def SYS___setugid: u64 = 374; export def SYS_eaccess: u64 = 376; export def SYS_afs3_syscall: u64 = 377; export def SYS_nmount: u64 = 378; export def SYS___mac_get_proc: u64 = 384; export def SYS___mac_set_proc: u64 = 385; export def SYS___mac_get_fd: u64 = 386; export def SYS___mac_get_file: u64 = 387; export def SYS___mac_set_fd: u64 = 388; export def SYS___mac_set_file: u64 = 389; export def SYS_kenv: u64 = 390; export def SYS_lchflags: u64 = 391; export def SYS_uuidgen: u64 = 392; export def SYS_sendfile: u64 = 393; export def SYS_mac_syscall: u64 = 394; export def SYS_freebsd11_getfsstat: u64 = 395; export def SYS_freebsd11_statfs: u64 = 396; export def SYS_freebsd11_fstatfs: u64 = 397; export def SYS_freebsd11_fhstatfs: u64 = 398; export def SYS_ksem_close: u64 = 400; export def SYS_ksem_post: u64 = 401; export def SYS_ksem_wait: u64 = 402; export def SYS_ksem_trywait: u64 = 403; export def SYS_ksem_init: u64 = 404; export def SYS_ksem_open: u64 = 405; export def SYS_ksem_unlink: u64 = 406; export def SYS_ksem_getvalue: u64 = 407; export def SYS_ksem_destroy: u64 = 408; export def SYS___mac_get_pid: u64 = 409; export def SYS___mac_get_link: u64 = 410; export def SYS___mac_set_link: u64 = 411; export def SYS_extattr_set_link: u64 = 412; export def SYS_extattr_get_link: u64 = 413; export def SYS_extattr_delete_link: u64 = 414; export def SYS___mac_execve: u64 = 415; export def SYS_sigaction: u64 = 416; export def SYS_sigreturn: u64 = 417; export def SYS_getcontext: u64 = 421; export def SYS_setcontext: u64 = 422; export def SYS_swapcontext: u64 = 423; export def SYS_swapoff: u64 = 424; export def SYS___acl_get_link: u64 = 425; export def SYS___acl_set_link: u64 = 426; export def SYS___acl_delete_link: u64 = 427; export def SYS___acl_aclcheck_link: u64 = 428; export def SYS_sigwait: u64 = 429; export def SYS_thr_create: u64 = 430; export def SYS_thr_exit: u64 = 431; export def SYS_thr_self: u64 = 432; export def SYS_thr_kill: u64 = 433; export def SYS_jail_attach: u64 = 436; export def SYS_extattr_list_fd: u64 = 437; export def SYS_extattr_list_file: u64 = 438; export def SYS_extattr_list_link: u64 = 439; export def SYS_ksem_timedwait: u64 = 441; export def SYS_thr_suspend: u64 = 442; export def SYS_thr_wake: u64 = 443; export def SYS_kldunloadf: u64 = 444; export def SYS_audit: u64 = 445; export def SYS_auditon: u64 = 446; export def SYS_getauid: u64 = 447; export def SYS_setauid: u64 = 448; export def SYS_getaudit: u64 = 449; export def SYS_setaudit: u64 = 450; export def SYS_getaudit_addr: u64 = 451; export def SYS_setaudit_addr: u64 = 452; export def SYS_auditctl: u64 = 453; export def SYS__umtx_op: u64 = 454; export def SYS_thr_new: u64 = 455; export def SYS_sigqueue: u64 = 456; export def SYS_kmq_open: u64 = 457; export def SYS_kmq_setattr: u64 = 458; export def SYS_kmq_timedreceive: u64 = 459; export def SYS_kmq_timedsend: u64 = 460; export def SYS_kmq_notify: u64 = 461; export def SYS_kmq_unlink: u64 = 462; export def SYS_abort2: u64 = 463; export def SYS_thr_set_name: u64 = 464; export def SYS_aio_fsync: u64 = 465; export def SYS_rtprio_thread: u64 = 466; export def SYS_sctp_peeloff: u64 = 471; export def SYS_sctp_generic_sendmsg: u64 = 472; export def SYS_sctp_generic_sendmsg_iov: u64 = 473; export def SYS_sctp_generic_recvmsg: u64 = 474; export def SYS_pread: u64 = 475; export def SYS_pwrite: u64 = 476; export def SYS_mmap: u64 = 477; export def SYS_lseek: u64 = 478; export def SYS_truncate: u64 = 479; export def SYS_ftruncate: u64 = 480; export def SYS_thr_kill2: u64 = 481; export def SYS_freebsd12_shm_open: u64 = 482; export def SYS_shm_unlink: u64 = 483; export def SYS_cpuset: u64 = 484; export def SYS_cpuset_setid: u64 = 485; export def SYS_cpuset_getid: u64 = 486; export def SYS_cpuset_getaffinity: u64 = 487; export def SYS_cpuset_setaffinity: u64 = 488; export def SYS_faccessat: u64 = 489; export def SYS_fchmodat: u64 = 490; export def SYS_fchownat: u64 = 491; export def SYS_fexecve: u64 = 492; export def SYS_freebsd11_fstatat: u64 = 493; export def SYS_futimesat: u64 = 494; export def SYS_linkat: u64 = 495; export def SYS_mkdirat: u64 = 496; export def SYS_mkfifoat: u64 = 497; export def SYS_freebsd11_mknodat: u64 = 498; export def SYS_openat: u64 = 499; export def SYS_readlinkat: u64 = 500; export def SYS_renameat: u64 = 501; export def SYS_symlinkat: u64 = 502; export def SYS_unlinkat: u64 = 503; export def SYS_posix_openpt: u64 = 504; export def SYS_gssd_syscall: u64 = 505; export def SYS_jail_get: u64 = 506; export def SYS_jail_set: u64 = 507; export def SYS_jail_remove: u64 = 508; export def SYS_freebsd12_closefrom: u64 = 509; export def SYS___semctl: u64 = 510; export def SYS_msgctl: u64 = 511; export def SYS_shmctl: u64 = 512; export def SYS_lpathconf: u64 = 513; export def SYS___cap_rights_get: u64 = 515; export def SYS_cap_enter: u64 = 516; export def SYS_cap_getmode: u64 = 517; export def SYS_pdfork: u64 = 518; export def SYS_pdkill: u64 = 519; export def SYS_pdgetpid: u64 = 520; export def SYS_pselect: u64 = 522; export def SYS_getloginclass: u64 = 523; export def SYS_setloginclass: u64 = 524; export def SYS_rctl_get_racct: u64 = 525; export def SYS_rctl_get_rules: u64 = 526; export def SYS_rctl_get_limits: u64 = 527; export def SYS_rctl_add_rule: u64 = 528; export def SYS_rctl_remove_rule: u64 = 529; export def SYS_posix_fallocate: u64 = 530; export def SYS_posix_fadvise: u64 = 531; export def SYS_wait6: u64 = 532; export def SYS_cap_rights_limit: u64 = 533; export def SYS_cap_ioctls_limit: u64 = 534; export def SYS_cap_ioctls_get: u64 = 535; export def SYS_cap_fcntls_limit: u64 = 536; export def SYS_cap_fcntls_get: u64 = 537; export def SYS_bindat: u64 = 538; export def SYS_connectat: u64 = 539; export def SYS_chflagsat: u64 = 540; export def SYS_accept4: u64 = 541; export def SYS_pipe2: u64 = 542; export def SYS_aio_mlock: u64 = 543; export def SYS_procctl: u64 = 544; export def SYS_ppoll: u64 = 545; export def SYS_futimens: u64 = 546; export def SYS_utimensat: u64 = 547; export def SYS_fdatasync: u64 = 550; export def SYS_fstat: u64 = 551; export def SYS_fstatat: u64 = 552; export def SYS_fhstat: u64 = 553; export def SYS_getdirentries: u64 = 554; export def SYS_statfs: u64 = 555; export def SYS_fstatfs: u64 = 556; export def SYS_getfsstat: u64 = 557; export def SYS_fhstatfs: u64 = 558; export def SYS_mknodat: u64 = 559; export def SYS_kevent: u64 = 560; export def SYS_cpuset_getdomain: u64 = 561; export def SYS_cpuset_setdomain: u64 = 562; export def SYS_getrandom: u64 = 563; export def SYS_getfhat: u64 = 564; export def SYS_fhlink: u64 = 565; export def SYS_fhlinkat: u64 = 566; export def SYS_fhreadlink: u64 = 567; export def SYS_funlinkat: u64 = 568; export def SYS_copy_file_range: u64 = 569; export def SYS___sysctlbyname: u64 = 570; export def SYS_shm_open2: u64 = 571; export def SYS_shm_rename: u64 = 572; export def SYS_sigfastblock: u64 = 573; export def SYS___realpathat: u64 = 574; export def SYS_close_range: u64 = 575; export def SYS_rpctls_syscall: u64 = 576; export def SYS___specialfd: u64 = 577; export def SYS_aio_writev: u64 = 578; export def SYS_aio_readv: u64 = 579; hare-0.24.2/rt/+freebsd/syscalls.ha000066400000000000000000000464411464473310100170130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn syscall(num: u64, args: u64...) u64 = { switch (len(args)) { case 0 => return syscall0(num); case 1 => return syscall1(num, args[0]); case 2 => return syscall2(num, args[0], args[1]); case 3 => return syscall3(num, args[0], args[1], args[2]); case 4 => return syscall4(num, args[0], args[1], args[2], args[3]); case 5 => return syscall5(num, args[0], args[1], args[2], args[3], args[4]); case 6 => return syscall6(num, args[0], args[1], args[2], args[3], args[4], args[5]); case => abort("syscalls can't have more than 6 arguments"); }; }; fn syscall0(u64) u64; fn syscall1(u64, u64) u64; fn syscall2(u64, u64, u64) u64; fn syscall3(u64, u64, u64, u64) u64; fn syscall4(u64, u64, u64, u64, u64) u64; fn syscall5(u64, u64, u64, u64, u64, u64) u64; fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64; export def NAME_MAX: size = 255z; export def PATH_MAX: size = 1024z; export type path = (str | []u8 | *const u8); let pathbuf: [PATH_MAX]u8 = [0...]; fn copy_kpath(path: path, buf: []u8) (*const u8 | errno) = { let path = match (path) { case let c: *const u8 => return c; case let s: str => let ptr = &s: *struct { buf: *[*]u8, length: size, capacity: size, }; yield ptr.buf[..ptr.length]; case let b: []u8 => yield b; }; if (len(path) + 1 >= len(pathbuf)) { return ENAMETOOLONG; }; memcpy(buf: *[*]u8, path: *[*]u8, len(path)); buf[len(path)] = 0; return buf: *[*]u8: *const u8; }; // NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in // length. fn kpath(path: path) (*const u8 | errno) = { return copy_kpath(path, pathbuf); }; export fn read(fd: int, buf: *opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_read, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_write, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_readv, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_writev, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn close(fd: int) (void | errno) = { wrap_return(syscall1(SYS_close, fd: u64))?; }; export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = { return wrap_return(syscall3(SYS_lseek, fd: u64, off: u64, whence: u64))?: i64; }; export fn ftruncate(fd: int, ln: off_t) (void | errno) = { wrap_return(syscall2(SYS_ftruncate, fd: u64, ln: u32))?; }; export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = { wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?; }; export type ioctl_arg = (nullable *opaque | u64); export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = { let fd = fd: u64, req = req: u64; return wrap_return(match (arg) { case let u: u64 => yield syscall3(SYS_ioctl, fd, req, u); case let v: nullable *opaque => yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64); })?: int; }; export fn openat( dirfd: int, path: path, flags: int, mode: uint, ) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_openat, dirfd: u64, path: uintptr: u64, flags: u64, mode: u64))?: int; }; export fn open(path: str, flags: int, mode: uint) (int | errno) = { return openat(AT_FDCWD, path, flags, mode); }; export fn unlink(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, AT_FDCWD: u64, path: uintptr: u64, 0u64))?; }; export fn renameat( olddirfd: int, oldpath: str, newdirfd: int, newpath: str, ) (void | errno) = { let oldpath = kpath(oldpath)?; static let newpathbuf: [PATH_MAX]u8 = [0...]; let newpath = copy_kpath(newpath, newpathbuf)?; wrap_return(syscall4(SYS_renameat, olddirfd: u64, oldpath: uintptr: u64, newdirfd: u64, newpath: uintptr: u64))?; }; export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, dirfd: u64, path: uintptr: u64, flags: u64))?; }; export fn fstatat(fd: int, path: path, stat: *st, flag: int) (void | errno) = { let path = kpath(path)?; let fbstat = freebsd11_stat { ... }; wrap_return(syscall4(SYS_freebsd11_fstatat, fd: u64, path: uintptr: u64, &fbstat: uintptr: u64, flag: u64))?; stat.dev = fbstat.st_dev; stat.ino = fbstat.st_ino; stat.mode = fbstat.st_mode; stat.nlink = fbstat.st_nlink; stat.uid = fbstat.st_uid; stat.gid = fbstat.st_gid; stat.rdev = fbstat.st_rdev; stat.atime.tv_sec = fbstat.st_atim.tv_sec; stat.atime.tv_nsec = fbstat.st_atim.tv_nsec: i64; stat.mtime.tv_sec = fbstat.st_mtim.tv_sec; stat.mtime.tv_nsec = fbstat.st_mtim.tv_nsec: i64; stat.ctime.tv_sec = fbstat.st_ctim.tv_sec; stat.ctime.tv_nsec = fbstat.st_ctim.tv_nsec: i64; stat.btime.tv_sec = fbstat.st_birthtim.tv_sec; stat.btime.tv_nsec = fbstat.st_birthtim.tv_nsec: i64; stat.sz = fbstat.st_size; stat.blocks = fbstat.st_blocks; stat.blksz = fbstat.st_blksize; stat.flags = fbstat.st_flags; }; export fn fstat(fd: int, stat: *st) (errno | void) = fstatat(fd, "", stat, AT_EMPTY_PATH); export fn readlinkat( dirfd: int, path: path, buf: []u8, ) (size | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_readlinkat, dirfd: u64, path: uintptr: u64, buf: *[*]u8: uintptr: u64, len(buf): u64))?: size; }; export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_mkdirat, dirfd: u64, path: uintptr: u64, mode: u64))?; }; export fn fchmod(fd: int, mode: uint) (void | errno) = { wrap_return(syscall2(SYS_fchmod, fd: u64, mode: u64))?; }; export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_fchmodat, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?; }; export fn fchown(fd: int, uid: uint, gid: uint) (void | errno) = { wrap_return(syscall3(SYS_fchown, fd: u64, uid: u32, gid: u32))?; }; export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall5(SYS_fchownat, dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?; }; export fn utimensat(dirfd: int, path: str, ts: *[2]timespec, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_utimensat, dirfd: u64, path: uintptr: u64, ts: uintptr: u64, flags: u64))?; }; export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = { wrap_return(syscall2(SYS_futimens, fd: u64, ts: uintptr: u64))?; }; export fn faccessat( dirfd: int, path: path, mode: int, flags: int, ) (bool | errno) = { let path = kpath(path)?; match (wrap_return(syscall4(SYS_faccessat, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))) { case let err: errno => switch (err) { case EACCES => return false; case => return err; }; case let n: u64 => assert(n == 0); return true; }; }; // The use of this function is discouraged, as it can create race conditions. // TOCTOU is preferred: attempt to simply use the resource you need and handle // any access errors which occur. export fn access(path: path, mode: int) (bool | errno) = faccessat(AT_FDCWD, path, mode, 0); // TODO: Consider updating this to use SYS_freebsd11_getdirentries export fn getdents(dirfd: int, buf: *opaque, nbytes: size) (size | errno) = { return wrap_return(syscall3(SYS_freebsd11_getdents, dirfd: u64, buf: uintptr: u64, nbytes: u64))?: size; }; // The return value is statically allocated and must be duplicated before // calling getcwd again. export fn getcwd() (*const u8 | errno) = { static let pathbuf: [PATH_MAX]u8 = [0...]; wrap_return(syscall2(SYS___getcwd, &pathbuf: *[*]u8: uintptr: u64, PATH_MAX))?; return &pathbuf: *const u8; }; export fn fchdir(fd: int) (void | errno) = { wrap_return(syscall1(SYS_fchdir, fd: u64))?; }; export fn chdir(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?; }; export fn chroot(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?; }; export fn mmap( addr: nullable *opaque, length: size, prot: uint, flags: uint, fd: int, offs: size ) (errno | *opaque) = { return wrap_return(syscall6(SYS_mmap, addr: uintptr: u64, length: u64, prot: u64, flags: u64, fd: u64, offs: u64))?: uintptr: *opaque; }; export fn munmap(addr: *opaque, length: size) (void | errno) = { wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?; }; export fn exit(status: int) never = { syscall1(SYS_exit, status: u64); abort(); }; export fn kill(pid: pid_t, signal: int) (void | errno) = { wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; }; export fn fork() (pid_t | void | errno) = { let n = wrap_return(syscall0(SYS_fork))?: pid_t; switch (n) { case 0 => return; case => return n; }; }; export fn fexecve(fd: int, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8) errno = { return match (wrap_return(syscall3(SYS_fexecve, fd: u64, argv: uintptr: u64, envp: uintptr: u64))) { case let err: errno => yield err; case u64 => abort("unreachable"); }; }; export fn wait4( pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, ) (int | errno) = { return wrap_return(syscall4(SYS_wait4, pid: u64, wstatus: uintptr: u64, options: u64, rusage: uintptr: u64))?: int; }; export fn wifexited(status: int) bool = wtermsig(status) == 0; export fn wexitstatus(status: int) int = (status & 0xff00) >> 8; export fn wtermsig(status: int) int = status & 0x7f; export fn wifsignaled(status: int) bool = wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13; export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; export fn getpgrp() pid_t = syscall0(SYS_getpgrp): pid_t; export fn getpgid(pid: pid_t) (pid_t | errno) = { return wrap_return(syscall1(SYS_getpgid, pid))?: pid_t; }; export fn getsid(pid: pid_t) (pid_t | errno) = { return wrap_return(syscall1(SYS_getsid, pid))?: pid_t; }; export fn getpriority(which: int, who: id_t) (int | errno) = { return wrap_return(syscall2(SYS_getpriority, which: u64, who: u64))?: int; }; export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = { wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?; }; export fn umask(mode: mode_t) (mode_t | errno) = { return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t; }; export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = { wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?; }; export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = { wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?; }; export fn getgroups(gids: []gid_t) (uint | errno) = { return wrap_return(syscall2(SYS_getgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; }; export fn setgroups(gids: []gid_t) (void | errno) = { wrap_return(syscall2(SYS_setgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; }; export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = { wrap_return(syscall3(SYS_getresuid, uid: uintptr: u64, euid: uintptr: u64, suid: uintptr: u64))?; }; export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = { wrap_return(syscall3(SYS_getresgid, gid: uintptr: u64, egid: uintptr: u64, sgid: uintptr: u64))?; }; export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = { wrap_return(syscall2(SYS_clock_gettime, clock_id: u64, tp: uintptr: u64))?; }; export fn clock_settime(clock_id: int, tp: *const timespec) (void | errno) = { wrap_return(syscall2(SYS_clock_settime, clock_id: u64, tp: uintptr: u64))?; }; export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = { wrap_return(syscall2(SYS_nanosleep, req: uintptr: u64, rem: uintptr: u64))?; }; export fn getrandom(buf: *opaque, bufln: size, flags: uint) (size | errno) = { return wrap_return(syscall3(SYS_getrandom, buf: uintptr: u64, bufln: u64, flags: u64))?: size; }; export type fcntl_arg = (void | int | *st_flock | *u64); export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = { let _fd = fd: u64, _cmd = cmd: u64; return wrap_return(match (arg) { case void => yield syscall2(SYS_fcntl, _fd, _cmd); case let i: int => yield syscall3(SYS_fcntl, _fd, _cmd, i: u64); case let l: *st_flock => yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64); case let u: *u64 => yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64); })?: int; }; export fn ppoll( fds: *[*]pollfd, nfds: nfds_t, timeout: const nullable *timespec, sigmask: const nullable *sigset, ) (int | errno) = { return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64, timeout: uintptr: u64, sigmask: uintptr: u64))?: int; }; export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = { const ts = timespec { tv_sec = timeout % 1000, tv_nsec = timeout * 1000000, }; return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null); }; export fn socket(domain: int, type_: int, protocol: int) (int | errno) = { return wrap_return(syscall3(SYS_socket, domain: u64, type_: u64, protocol: u64))?: int; }; export fn socketpair( domain: int, type_: int, protocol: int, sv: *[*]int, ) (int | errno) = { return wrap_return(syscall4(SYS_socketpair, domain: u64, type_: u64, protocol: u64, sv: uintptr : u64))?: int; }; export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_connect, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_bind, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn listen(sockfd: int, backlog: u32) (int | errno) = { return wrap_return(syscall2(SYS_listen, sockfd: u64, backlog: u64))?: int; }; export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_accept, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { return wrap_return(syscall4(SYS_accept4, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int; }; export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int, src_addr: nullable *sockaddr, addrlen: nullable *u32 ) (size | errno) = { return wrap_return(syscall6(SYS_recvfrom, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, src_addr: uintptr: u64, addrlen: uintptr: u64))?: size; }; export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int, dest_addr: nullable *sockaddr, addrlen: u32 ) (size | errno) = { return wrap_return(syscall6(SYS_sendto, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, dest_addr: uintptr: u64, addrlen: u64))?: size; }; export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return recvfrom(sockfd, buf, len_, flags, null, null); }; export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return sendto(sockfd, buf, len_, flags, null, 0); }; export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_sendmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_recvmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32) (int | errno) = { return wrap_return(syscall5(SYS_getsockopt, sockfd: u64, level: u64, optname: u64, optval: uintptr: u64, optlen: uintptr: u64))?: int; }; export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = { return wrap_return(syscall5(SYS_setsockopt, sockfd: u64, level: u64, optname: u64, optval: uintptr: u64, optlen: u64))?: int; }; export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getsockname, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getpeername, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn sysctlbyname(name: str, oldp: nullable *opaque, oldlenp: nullable *size, newp: nullable *const opaque, newlen: size) (void | errno) = { let kname = kpath(name)?; wrap_return(syscall6(SYS___sysctlbyname, kname: uintptr: u64, len(name): u64, oldp: uintptr: u64, oldlenp: uintptr: u64, newp: uintptr: u64, newlen: u64))?; }; export fn dup2(oldfd: int, newfd: int) (int | errno) = { return wrap_return(syscall2(SYS_dup2, oldfd: u64, newfd: u64))?: int; }; export fn posix_openpt(flags: int) (int | errno) = { return wrap_return(syscall1(SYS_posix_openpt, flags: u64))?: int; }; export fn posix_fallocate(fd: int, off: i64, ln: i64) (void | errno) = { wrap_return(syscall3(SYS_posix_fallocate, fd: u64, off: u64, ln: u64))?; }; export fn flock(fd: int, op: int) (void | errno) = { wrap_return(syscall2(SYS_flock, fd: u64, op: u64))?; }; export fn shm_open( shm_path: path, oflags: int, mode: mode_t, shmflags: int, anon_path: path, ) (int | errno) = { const shm_path = match (shm_path) { case let string: *const u8 => if (string == SHM_ANON) yield SHM_ANON; yield kpath(shm_path)?; case => yield kpath(shm_path)?; }; const anon_path = kpath(anon_path)?; return wrap_return(syscall5(SYS_shm_open2, shm_path: uintptr: u64, oflags: u64, mode: u64, shmflags: u64, anon_path: uintptr: u64))?: int; }; export fn shm_unlink(shm_path: path) (void | errno) = { const path = kpath(shm_path)?; wrap_return(syscall1(SYS_shm_unlink, path: uintptr: u64))?; }; export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = { return syscall3(SYS_shmat, id: u64, addr: uintptr: u64, flag: u64): uintptr: *opaque; }; export fn getrlimit(resource: int, rlim: *rlimit) (void | errno) = { wrap_return(syscall2(SYS_getrlimit, resource: u64, rlim: uintptr: u64))?; }; export fn setrlimit(resource: int, rlim: *const rlimit) (void | errno) = { wrap_return(syscall2(SYS_setrlimit, resource: u64, rlim: uintptr: u64))?; }; export fn sigprocmask( how: int, set: nullable *const sigset, old: nullable *sigset, ) (int | errno) = { return wrap_return(syscall3(SYS_sigprocmask, how: u64, set: uintptr: u64, old: uintptr: u64))?: int; }; export fn sigaction( signum: int, act: *const sigact, old: nullable *sigact, ) (int | errno) = { return wrap_return(syscall3(SYS_sigaction, signum: u64, act: uintptr: u64, old: uintptr: u64))?: int; }; export fn sigaltstack( ss: nullable *stack_t, old_ss: nullable *stack_t, ) (void | errno) = { wrap_return(syscall2(SYS_sigaltstack, ss: uintptr: u64, old_ss: uintptr: u64))?; }; export fn shutdown(sockfd: int, how: int) (void | errno) = { wrap_return(syscall2(SYS_shutdown, sockfd: u64, how: u64))?; }; hare-0.24.2/rt/+freebsd/types.ha000066400000000000000000000276331464473310100163240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type time_t = i64; export type suseconds_t = i64; export type dev_t = u64; export type ino_t = u64; export type nlink_t = u64; export type id_t = uint; export type pid_t = uint; export type uid_t = uint; export type gid_t = uint; export type off_t = i64; export type blkcnt_t = i64; export type blksize_t = i32; export type fflags_t = u32; export type mode_t = u16; export type nfds_t = uint; export type rlim_t = u64; export def NGROUPS_MAX: size = 1023; export def NSIG: int = 32; export type sigset = struct { __bits: [4]u32, }; export def SA_ONSTACK: u64 = 0x0001; export def SA_RESTART: u64 = 0x0002; export def SA_RESETHAND: u64 = 0x0004; export def SA_NOCLDSTOP: u64 = 0x0008; export def SA_NODEFER: u64 = 0x0010; export def SA_NOCLDWAIT: u64 = 0x0020; export def SA_SIGINFO: u64 = 0x0040; export def SIG_ERR: uintptr = -1; export def SIG_DFL: uintptr = 0; export def SIG_IGN: uintptr = 1; export def SIG_CATCH: uintptr = 2; export def SIG_HOLD: uintptr = 3; export type sigact = struct { union { sa_handler: *fn (int) void, sa_sigaction: *fn (int, *siginfo, *opaque) void, }, sa_flags: int, sa_mask: sigset, }; export def SIG_BLOCK: int = 1; export def SIG_UNBLOCK: int = 2; export def SIG_SETMASK: int = 3; export type sigval = union { sival_t: int, sival_ptr: *opaque, }; export type stack_t = struct { ss_sp: *opaque, ss_size: size, ss_flags: int, }; export type pollfd = struct { fd: int, events: i16, revents: i16, }; export type timespec = struct { tv_sec: time_t, tv_nsec: i64, }; export def UTIME_OMIT = -0x2; export type timeval = struct { tv_sec: time_t, tv_usec: suseconds_t, }; export type st_flock = struct { l_start: off_t, l_len: off_t, l_pid: pid_t, l_type: i16, l_whence: i16, l_sysid: int, }; export type st = struct { dev: dev_t, ino: ino_t, nlink: nlink_t, mode: mode_t, uid: uid_t, gid: gid_t, rdev: dev_t, atime: timespec, mtime: timespec, ctime: timespec, btime: timespec, sz: off_t, blocks: blkcnt_t, blksz: blksize_t, flags: fflags_t, }; export type freebsd11_stat = struct { st_dev: u32, st_ino: u32, st_mode: mode_t, st_nlink: u16, st_uid: uid_t, st_gid: gid_t, st_rdev: u32, st_atim: timespec, st_mtim: timespec, st_ctim: timespec, st_size: off_t, st_blocks: blkcnt_t, st_blksize: blksize_t, st_flags: fflags_t, st_gen: u32, st_lspare: u32, st_birthtim: timespec, }; export type freebsd11_dirent = struct { d_fileno: u32, d_reclen: u16, d_type: u8, d_namlen: u8, d_name: [*]u8, }; export type iovec = struct { iov_base: *opaque, iov_len: size }; export type winsize = struct { ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, }; export type termios = struct { c_iflag: tcflag, c_oflag: tcflag, c_cflag: tcflag, c_lflag: tcflag, c_cc: [NCCS]cc, }; export def NCCS: size = 20; export type tcflag = enum uint { // c_iflag bits IGNBRK = 0x00000001, BRKINT = 0x00000002, IGNPAR = 0x00000004, PARMRK = 0x00000008, INPCK = 0x00000010, ISTRIP = 0x00000020, INLCR = 0x00000040, IGNCR = 0x00000080, ICRNL = 0x00000100, IXON = 0x00000200, IXOFF = 0x00000400, IXANY = 0x00000800, IMAXBEL = 0x00002000, // c_oflag bits OPOST = 0x00000001, ONLCR = 0x00000002, TABDLY = 0x00000004, TAB0 = 0x00000000, TAB3 = 0x00000004, ONOEOT = 0x00000008, OCRNL = 0x00000010, ONOCR = 0x00000020, ONLRET = 0x00000040, // c_cflag bits CIGNORE = 0x00000001, CSIZE = 0x00000300, CS5 = 0x00000000, CS6 = 0x00000100, CS7 = 0x00000200, CS8 = 0x00000300, CSTOPB = 0x00000400, CREAD = 0x00000800, PARENB = 0x00001000, PARODD = 0x00002000, HUPCL = 0x00004000, CLOCAL = 0x00008000, CCTS_OFLOW = 0x00010000, CRTS_IFLOW = 0x00020000, CRTSCTS = (CCTS_OFLOW | CRTS_IFLOW), CDTR_IFLOW = 0x00040000, CDSR_OFLOW = 0x00080000, CCAR_OFLOW = 0x00100000, CNO_RTSDTR = 0x00200000, // c_lflag bits ECHOKE = 0x00000001, ECHOE = 0x00000002, ECHOK = 0x00000004, ECHO = 0x00000008, ECHONL = 0x00000010, ECHOPRT = 0x00000020, ECHOCTL = 0x00000040, ISIG = 0x00000080, ICANON = 0x00000100, ALTWERASE = 0x00000200, IEXTEN = 0x00000400, EXTPROC = 0x00000800, TOSTOP = 0x00400000, FLUSHO = 0x00800000, NOKERNINFO = 0x02000000, PENDIN = 0x20000000, NOFLSH = 0x80000000, }; export type cc = enum u8 { VEOF = 0, VEOL = 1, VEOL2 = 2, VERASE = 3, VWERASE = 4, VKILL = 5, VREPRINT = 6, VERASE2 = 7, VINTR = 8, VQUIT = 9, VSUSP = 10, VDSUSP = 11, VSTART = 12, VSTOP = 13, VLNEXT = 14, VDISCARD = 15, VMIN = 16, VTIME = 17, VSTATUS = 18, }; export def TIOCGWINSZ: u64 = 0x40087468; export def TIOCSWINSZ: u64 = 0x80087467; export def TIOCGETA: u64 = 0x402c7413; export def TIOCSETA: u64 = 0x802c7414; export def TIOCPTMASTER: u64 = 0x2000741c; export def TIOCSPGRP: u64 = 0x80047476; export def FIODGNAME: u64 = 0x80106678; export type rusage = struct { ru_utime: timeval, ru_stime: timeval, ru_maxrss: i64, ru_ixrss: i64, ru_idrss: i64, ru_isrss: i64, ru_minflt: i64, ru_majflt: i64, ru_nswap: i64, ru_inblock: i64, ru_oublock: i64, ru_msgsnd: i64, ru_msgrcv: i64, ru_nsignals: i64, ru_nvcsw: i64, ru_nivcsw: i64, }; export def DT_UNKNOWN: u8 = 0; export def DT_FIFO: u8 = 1; export def DT_CHR: u8 = 2; export def DT_DIR: u8 = 4; export def DT_BLK: u8 = 6; export def DT_REG: u8 = 8; export def DT_LNK: u8 = 10; export def DT_SOCK: u8 = 12; export def DT_WHT: u8 = 14; export def O_RDONLY: int = 0x0000; export def O_WRONLY: int = 0x0001; export def O_RDWR: int = 0x0002; export def O_ACCMODE: int = 0x0003; export def O_NONBLOCK: int = 0x0004; export def O_APPEND: int = 0x0008; export def O_SHLOCK: int = 0x0010; export def O_EXLOCK: int = 0x0020; export def O_ASYNC: int = 0x0040; export def O_FSYNC: int = 0x0080; export def O_SYNC: int = 0x0080; export def O_NOFOLLOW: int = 0x0100; export def O_CREAT: int = 0x0200; export def O_TRUNC: int = 0x0400; export def O_EXCL: int = 0x0800; export def O_NOCTTY: int = 0x8000; export def O_DIRECT: int = 0x00010000; export def O_DIRECTORY: int = 0x00020000; export def O_EXEC: int = 0x00040000; export def O_TTY_INIT: int = 0x00080000; export def O_CLOEXEC: int = 0x00100000; export def O_DSYNC: int = 0x01000000; export def AT_FDCWD: int = -100; export def AT_EACCESS: int = 0x0100; export def AT_SYMLINK_NOFOLLOW: int = 0x0200; export def AT_SYMLINK_FOLLOW: int = 0x0400; export def AT_REMOVEDIR: int = 0x0800; export def AT_RESOLVE_BENEATH: int = 0x2000; export def AT_EMPTY_PATH: int = 0x4000; export def S_IFIFO: mode_t = 0o010000; export def S_IFCHR: mode_t = 0o020000; export def S_IFDIR: mode_t = 0o040000; export def S_IFBLK: mode_t = 0o060000; export def S_IFREG: mode_t = 0o100000; export def S_IFLNK: mode_t = 0o120000; export def S_IFSOCK: mode_t = 0o140000; export def MAP_SHARED: uint = 0x0001; export def MAP_PRIVATE: uint = 0x0002; export def MAP_FIXED: uint = 0x0010; export def MAP_HASSEMAPHORE: uint = 0x0200; export def MAP_STACK: uint = 0x0400; export def MAP_NOSYNC: uint = 0x0800; export def MAP_FILE: uint = 0x0000; export def MAP_ANON: uint = 0x1000; export def MAP_GUARD: uint = 0x00002000; export def MAP_EXCL: uint = 0x00004000; export def MAP_NOCORE: uint = 0x00020000; export def MAP_PREFAULT_READ: uint = 0x00040000; export def MAP_32BIT: uint = 0x00080000; export def PROT_NONE: uint = 0x00; export def PROT_READ: uint = 0x01; export def PROT_WRITE: uint = 0x02; export def PROT_EXEC: uint = 0x04; export def SIGHUP: int = 1; export def SIGINT: int = 2; export def SIGQUIT: int = 3; export def SIGILL: int = 4; export def SIGTRAP: int = 5; export def SIGABRT: int = 6; export def SIGIOT: int = SIGABRT; export def SIGEMT: int = 7; export def SIGFPE: int = 8; export def SIGKILL: int = 9; export def SIGBUS: int = 10; export def SIGSEGV: int = 11; export def SIGSYS: int = 12; export def SIGPIPE: int = 13; export def SIGALRM: int = 14; export def SIGTERM: int = 15; export def SIGURG: int = 16; export def SIGSTOP: int = 17; export def SIGTSTP: int = 18; export def SIGCONT: int = 19; export def SIGCHLD: int = 20; export def SIGTTIN: int = 21; export def SIGTTOU: int = 22; export def SIGIO: int = 23; export def SIGXCPU: int = 24; export def SIGXFSZ: int = 25; export def SIGVTALRM: int = 26; export def SIGPROF: int = 27; export def SIGWINCH: int = 28; export def SIGINFO: int = 29; export def SIGUSR1: int = 30; export def SIGUSR2: int = 31; export def SIGTHR: int = 32; export def SIGLWP: int = SIGTHR; export def SIGLIBRT: int = 33; export def F_DUPFD: int = 0; export def F_GETFD: int = 1; export def F_SETFD: int = 2; export def F_GETFL: int = 3; export def F_SETFL: int = 4; export def F_GETOWN: int = 5; export def F_SETOWN: int = 6; export def F_OGETLK: int = 7; export def F_OSETLK: int = 8; export def F_OSETLKW: int = 9; export def F_DUP2FD: int = 10; export def F_GETLK: int = 11; export def F_SETLK: int = 12; export def F_SETLKW: int = 13; export def F_SETLK_REMOTE: int = 14; export def F_READAHEAD: int = 15; export def F_RDAHEAD: int = 16; export def F_DUPFD_CLOEXEC: int = 17; export def F_DUP2FD_CLOEXEC: int = 18; export def F_ADD_SEALS: int = 19; export def F_GET_SEALS: int = 20; export def F_ISUNIONSTACK: int = 21; export def F_SEAL_SEAL: int = 0x0001; export def F_SEAL_SHRINK: int = 0x0002; export def F_SEAL_GROW: int = 0x0004; export def F_SEAL_WRITE: int = 0x0008; export def FD_CLOEXEC: int = 1; export def F_UNLCKSYS: int = 4; export def F_CANCEL: int = 5; export def F_RDLCK: i16 = 1; export def F_UNLCK: i16 = 2; export def F_WRLCK: i16 = 3; export def PRIO_PROCESS: int = 0; export def PRIO_PGRP: int = 1; export def PRIO_USER: int = 2; export def F_OK: int = 0; export def X_OK: int = 0x01; export def W_OK: int = 0x02; export def R_OK: int = 0x04; export def CLOCK_REALTIME: int = 0; export def CLOCK_MONOTONIC: int = 4; export def CLOCK_VIRTUAL: int = 1; export def CLOCK_PROF: int = 2; export def CLOCK_UPTIME: int = 5; export def CLOCK_UPTIME_PRECISE: int = 7; export def CLOCK_UPTIME_FAST: int = 8; export def CLOCK_REALTIME_PRECISE: int = 9; export def CLOCK_REALTIME_FAST: int = 10; export def CLOCK_MONOTONIC_PRECISE: int = 11; export def CLOCK_MONOTONIC_FAST: int = 12; export def CLOCK_SECOND: int = 13; export def CLOCK_THREAD_CPUTIME_ID: int = 14; export def CLOCK_PROCESS_CPUTIME_ID: int = 15; export def WNOHANG: int = 1; export def WUNTRACED: int = 2; export def WSTOPPED: int = WUNTRACED; export def WCONTINUED: int = 4; export def WNOWAIT: int = 8; export def WEXITED: int = 16; export def WTRAPPED: int = 32; export def STDIN_FILENO: int = 0; export def STDOUT_FILENO: int = 1; export def STDERR_FILENO: int = 2; export def SEEK_SET: int = 0; export def SEEK_CUR: int = 1; export def SEEK_END: int = 2; // Flock operations export def LOCK_SH: int = 1; export def LOCK_EX: int = 2; export def LOCK_NB: int = 4; export def LOCK_UN: int = 8; export type rlimit = struct { rlim_cur: rlim_t, rlim_max: rlim_t, }; export def RLIM_INFINITY: rlim_t = -1; export def RLIMIT_CPU: int = 0; export def RLIMIT_FSIZE: int = 1; export def RLIMIT_DATA: int = 2; export def RLIMIT_STACK: int = 3; export def RLIMIT_CORE: int = 4; export def RLIMIT_RSS: int = 5; export def RLIMIT_MEMLOCK: int = 6; export def RLIMIT_NPROC: int = 7; export def RLIMIT_NOFILE: int = 8; export def RLIMIT_SBSIZE: int = 9; export def RLIMIT_VMEM: int = 10; export def RLIMIT_AS: int = RLIMIT_VMEM; export def RLIMIT_NPTS: int = 11; export def RLIMIT_SWAP: int = 12; export def RLIMIT_KQUEUES: int = 13; export def RLIMIT_UMTXP: int = 14; export def SHUT_RD: int = 0; export def SHUT_WR: int = 1; export def SHUT_RDWR: int = 2; export let SHM_ANON: *const u8 = 1: uintptr: *const u8; export def SHM_ALLOW_SEALING: int = 0x00000001; export def SHM_GROW_ON_WRITE: int = 0x00000002; export def SHM_LARGEPAGE: int = 0x00000004; export def SHM_LARGEPAGE_ALLOC_DEFAULT: int = 0; export def SHM_LARGEPAGE_ALLOC_NOWAIT: int = 1; export def SHM_LARGEPAGE_ALLOC_HARD: int = 2; hare-0.24.2/rt/+linux/000077500000000000000000000000001464473310100143605ustar00rootroot00000000000000hare-0.24.2/rt/+linux/+aarch64.ha000066400000000000000000000025721464473310100162030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // #define __ADDR_BND_PKEY_PAD (_Alignof(void *) < sizeof(short) ? sizeof(short) : _Alignof(void *)) def __ADDR_BND_PKEY_PAD: size = 8; // Returns the new PID to the parent, void to the child, or errno if something // goes wrong. export fn clone( stack: nullable *opaque, flags: int, parent_tid: nullable *int, child_tid: nullable *int, tls: u64, ) (int | void | errno) = { match (wrap_return(syscall5(SYS_clone, flags: u64, stack: uintptr: u64, parent_tid: uintptr: u64, tls, child_tid: uintptr: u64))) { case let u: u64 => switch (u) { case 0 => return void; case => return u: int; }; case let err: errno => return err; }; }; export def O_DIRECTORY: int = 0o40000; export def O_DIRECT: int = 0o200000; export type cmsghdr = struct { cmsg_len: socklen_t, _padding: int, cmsg_level: int, cmsg_type: int, }; export def EDEADLOCK: int = EDEADLK; export type epoll_event = struct { events: u32, data: epoll_data, }; export type cpu_set = struct { __bits: [16]u64, }; export type ucontext = struct { uc_flags: u64, uc_link: *ucontext, uc_stack: stack_t, uc_sigmask: sigset, _u8: [1024 / 8 - size(sigset)]u8, uc_mcontext: sigcontext, }; export type sigcontext = struct { fault_address: u64, sp: u64, regs: [31]u64, pc: u64, pstate: u64, reserved: [4096]u8, }; hare-0.24.2/rt/+linux/+riscv64.ha000066400000000000000000000037571464473310100162610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // #define __ADDR_BND_PKEY_PAD (_Alignof(void *) < sizeof(short) ? sizeof(short) : _Alignof(void *)) def __ADDR_BND_PKEY_PAD: size = 8; // Returns the new PID to the parent, void to the child, or errno if something // goes wrong. export fn clone( stack: nullable *opaque, flags: int, parent_tid: nullable *int, child_tid: nullable *int, tls: u64, ) (int | void | errno) = { match (wrap_return(syscall5(SYS_clone, flags: u64, stack: uintptr: u64, parent_tid: uintptr: u64, tls, child_tid: uintptr: u64))) { case let u: u64 => switch (u) { case 0 => return; case => return u: int; }; case let err: errno => return err; }; }; export def O_DIRECTORY: int = 0o200000; export def O_DIRECT: int = 0o40000; export type cmsghdr = struct { cmsg_len: socklen_t, _padding: int, cmsg_level: int, cmsg_type: int, }; export def EDEADLOCK: int = EDEADLK; export type epoll_event = struct { events: u32, data: epoll_data, }; export type cpu_set = struct { __bits: [16]u64, }; export type ucontext = struct { uc_flags: u64, uc_link: *ucontext, uc_stack: stack_t, uc_sigmask: sigset, _u8: [1024 / 8 - size(sigset)]u8, uc_mcontext: sigcontext, }; export type sigcontext = struct { sc_regs: user_regs, sc_fpregs: fp_state, }; export type user_regs = struct { x0: u64, // XXX: Why is this here? pc: u64, ra: u64, sp: u64, gp: u64, tp: u64, t0: u64, t1: u64, t2: u64, s0: u64, s1: u64, a0: u64, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64, s2: u64, s3: u64, s4: u64, s5: u64, s6: u64, s7: u64, s8: u64, s9: u64, s10: u64, s11: u64, t3: u64, t4: u64, t5: u64, t6: u64, }; export type fp_state = union { f: f_ext_state, d: d_ext_state, q: q_ext_state, }; export type f_ext_state = struct { f: [32]u32, fcsr: u32, }; export type d_ext_state = struct { f: [32]u64, fcsr: u32, }; export type q_ext_state = struct { f: [64]u64, fcsr: u32, reserved: [3]u32, }; hare-0.24.2/rt/+linux/+x86_64.ha000066400000000000000000000031051464473310100157020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // #define __ADDR_BND_PKEY_PAD (_Alignof(void *) < sizeof(short) ? sizeof(short) : _Alignof(void *)) def __ADDR_BND_PKEY_PAD: size = 8; // Returns the new PID to the parent, void to the child, or errno if something // goes wrong. export fn clone( stack: nullable *opaque, flags: int, parent_tid: nullable *int, child_tid: nullable *int, tls: u64, ) (int | void | errno) = { match (wrap_return(syscall5(SYS_clone, flags: u64, stack: uintptr: u64, parent_tid: uintptr: u64, child_tid: uintptr: u64, tls))) { case let u: u64 => switch (u) { case 0 => return; case => return u: int; }; case let err: errno => return err; }; }; export def O_DIRECTORY: int = 0o200000; export def O_DIRECT: int = 0o40000; export type cmsghdr = struct { cmsg_len: socklen_t, _padding: int, cmsg_level: int, cmsg_type: int, }; export def EDEADLOCK: int = EDEADLK; export type epoll_event = struct @packed { // Packed on x86_64 events: u32, data: epoll_data, }; export type cpu_set = struct { __bits: [16]u64, }; export type ucontext = struct { uc_flags: u64, uc_link: *ucontext, uc_stack: stack_t, uc_mcontext: sigcontext, uc_sigmask: sigset, }; export type sigcontext = struct { r8: u64, r9: u64, r10: u64, r11: u64, r12: u64, r13: u64, r14: u64, r15: u64, di: u64, si: u64, bp: u64, bx: u64, dx: u64, ax: u64, cx: u64, sp: u64, ip: u64, flags: u64, cs: u16, gs: u16, fs: u16, ss: u16, err: u64, trapno: u64, oldmask: u64, cr2: u64, fpstate: u64, reserved1: [8]u64, }; hare-0.24.2/rt/+linux/env.ha000066400000000000000000000003211464473310100154560ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export let argc: size = 0; export let argv: *[*]*u8 = null: *[*]*u8; export let envp: *[*]nullable *u8 = null: *[*]nullable *u8; hare-0.24.2/rt/+linux/errno.ha000066400000000000000000000416411464473310100160250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Represents an error returned from the Linux kernel. export type errno = !int; // Checks the return value from a Linux syscall and, if found to be in error, // returns the appropriate error. Otherwise, returns the original value. fn wrap_return(r: u64) (errno | u64) = { if (r > -4096: u64) { return (-(r: i64)): errno; }; return r; }; // Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not // permitted"). The return value may be statically allocated. export fn strerror(err: errno) str = { switch (err) { case EPERM => return "Operation not permitted"; case ENOENT => return "No such file or directory"; case ESRCH => return "No such process"; case EINTR => return "Interrupted system call"; case EIO => return "Input/output error"; case ENXIO => return "No such device or address"; case E2BIG => return "Argument list too long"; case ENOEXEC => return "Exec format error"; case EBADF => return "Bad file descriptor"; case ECHILD => return "No child processes"; case EAGAIN => return "Resource temporarily unavailable"; case ENOMEM => return "Cannot allocate memory"; case EACCES => return "Permission denied"; case EFAULT => return "Bad address"; case ENOTBLK => return "Block device required"; case EBUSY => return "Device or resource busy"; case EEXIST => return "File exists"; case EXDEV => return "Invalid cross-device link"; case ENODEV => return "No such device"; case ENOTDIR => return "Not a directory"; case EISDIR => return "Is a directory"; case EINVAL => return "Invalid argument"; case ENFILE => return "Too many open files in system"; case EMFILE => return "Too many open files"; case ENOTTY => return "Inappropriate ioctl for device"; case ETXTBSY => return "Text file busy"; case EFBIG => return "File too large"; case ENOSPC => return "No space left on device"; case ESPIPE => return "Illegal seek"; case EROFS => return "Read-only file system"; case EMLINK => return "Too many links"; case EPIPE => return "Broken pipe"; case EDOM => return "Numerical argument out of domain"; case ERANGE => return "Numerical result out of range"; case EDEADLK => return "Resource deadlock avoided"; case ENAMETOOLONG => return "File name too long"; case ENOLCK => return "No locks available"; case ENOSYS => return "Function not implemented"; case ENOTEMPTY => return "Directory not empty"; case ELOOP => return "Too many levels of symbolic links"; case ENOMSG => return "No message of desired type"; case EIDRM => return "Identifier removed"; case ECHRNG => return "Channel number out of range"; case EL2NSYNC => return "Level 2 not synchronized"; case EL3HLT => return "Level 3 halted"; case EL3RST => return "Level 3 reset"; case ELNRNG => return "Link number out of range"; case EUNATCH => return "Protocol driver not attached"; case ENOCSI => return "No CSI structure available"; case EL2HLT => return "Level 2 halted"; case EBADE => return "Invalid exchange"; case EBADR => return "Invalid request descriptor"; case EXFULL => return "Exchange full"; case ENOANO => return "No anode"; case EBADRQC => return "Invalid request code"; case EBADSLT => return "Invalid slot"; case EBFONT => return "Bad font file format"; case ENOSTR => return "Device not a stream"; case ENODATA => return "No data available"; case ETIME => return "Timer expired"; case ENOSR => return "Out of streams resources"; case ENONET => return "Machine is not on the network"; case ENOPKG => return "Package not installed"; case EREMOTE => return "Object is remote"; case ENOLINK => return "Link has been severed"; case EADV => return "Advertise error"; case ESRMNT => return "Srmount error"; case ECOMM => return "Communication error on send"; case EPROTO => return "Protocol error"; case EMULTIHOP => return "Multihop attempted"; case EDOTDOT => return "RFS specific error"; case EBADMSG => return "Bad message"; case EOVERFLOW => return "Value too large for defined data type"; case ENOTUNIQ => return "Name not unique on network"; case EBADFD => return "File descriptor in bad state"; case EREMCHG => return "Remote address changed"; case ELIBACC => return "Can not access a needed shared library"; case ELIBBAD => return "Accessing a corrupted shared library"; case ELIBSCN => return ".lib section in a.out corrupted"; case ELIBMAX => return "Attempting to link in too many shared libraries"; case ELIBEXEC => return "Cannot exec a shared library directly"; case EILSEQ => return "Invalid or incomplete multibyte or wide character"; case ERESTART => return "Interrupted system call should be restarted"; case ESTRPIPE => return "Streams pipe error"; case EUSERS => return "Too many users"; case ENOTSOCK => return "Socket operation on non-socket"; case EDESTADDRREQ => return "Destination address required"; case EMSGSIZE => return "Message too long"; case EPROTOTYPE => return "Protocol wrong type for socket"; case ENOPROTOOPT => return "Protocol not available"; case EPROTONOSUPPORT => return "Protocol not supported"; case ESOCKTNOSUPPORT => return "Socket type not supported"; case EOPNOTSUPP => return "Operation not supported"; case EPFNOSUPPORT => return "Protocol family not supported"; case EAFNOSUPPORT => return "Address family not supported by protocol"; case EADDRINUSE => return "Address already in use"; case EADDRNOTAVAIL => return "Cannot assign requested address"; case ENETDOWN => return "Network is down"; case ENETUNREACH => return "Network is unreachable"; case ENETRESET => return "Network dropped connection on reset"; case ECONNABORTED => return "Software caused connection abort"; case ECONNRESET => return "Connection reset by peer"; case ENOBUFS => return "No buffer space available"; case EISCONN => return "Transport endpoint is already connected"; case ENOTCONN => return "Transport endpoint is not connected"; case ESHUTDOWN => return "Cannot send after transport endpoint shutdown"; case ETOOMANYREFS => return "Too many references: cannot splice"; case ETIMEDOUT => return "Connection timed out"; case ECONNREFUSED => return "Connection refused"; case EHOSTDOWN => return "Host is down"; case EHOSTUNREACH => return "No route to host"; case EALREADY => return "Operation already in progress"; case EINPROGRESS => return "Operation now in progress"; case ESTALE => return "Stale file handle"; case EUCLEAN => return "Structure needs cleaning"; case ENOTNAM => return "Not a XENIX named type file"; case ENAVAIL => return "No XENIX semaphores available"; case EISNAM => return "Is a named type file"; case EREMOTEIO => return "Remote I/O error"; case EDQUOT => return "Disk quota exceeded"; case ENOMEDIUM => return "No medium found"; case EMEDIUMTYPE => return "Wrong medium type"; case ECANCELED => return "Operation canceled"; case ENOKEY => return "Required key not available"; case EKEYEXPIRED => return "Key has expired"; case EKEYREVOKED => return "Key has been revoked"; case EKEYREJECTED => return "Key was rejected by service"; case EOWNERDEAD => return "Owner died"; case ENOTRECOVERABLE => return "State not recoverable"; case ERFKILL => return "Operation not possible due to RF-kill"; case EHWPOISON => return "Memory page has hardware error"; case => return unknown_errno(err); }; }; // Gets the programmer-friendly name for an [[errno]] (e.g. EPERM). The return // value may be statically allocated. export fn errname(err: errno) str = { switch (err) { case EPERM => return "EPERM"; case ENOENT => return "ENOENT"; case ESRCH => return "ESRCH"; case EINTR => return "EINTR"; case EIO => return "EIO"; case ENXIO => return "ENXIO"; case E2BIG => return "E2BIG"; case ENOEXEC => return "ENOEXEC"; case EBADF => return "EBADF"; case ECHILD => return "ECHILD"; case EAGAIN => return "EAGAIN"; case ENOMEM => return "ENOMEM"; case EACCES => return "EACCES"; case EFAULT => return "EFAULT"; case ENOTBLK => return "ENOTBLK"; case EBUSY => return "EBUSY"; case EEXIST => return "EEXIST"; case EXDEV => return "EXDEV"; case ENODEV => return "ENODEV"; case ENOTDIR => return "ENOTDIR"; case EISDIR => return "EISDIR"; case EINVAL => return "EINVAL"; case ENFILE => return "ENFILE"; case EMFILE => return "EMFILE"; case ENOTTY => return "ENOTTY"; case ETXTBSY => return "ETXTBSY"; case EFBIG => return "EFBIG"; case ENOSPC => return "ENOSPC"; case ESPIPE => return "ESPIPE"; case EROFS => return "EROFS"; case EMLINK => return "EMLINK"; case EPIPE => return "EPIPE"; case EDOM => return "EDOM"; case ERANGE => return "ERANGE"; case EDEADLK => return "EDEADLK"; case ENAMETOOLONG => return "ENAMETOOLONG"; case ENOLCK => return "ENOLCK"; case ENOSYS => return "ENOSYS"; case ENOTEMPTY => return "ENOTEMPTY"; case ELOOP => return "ELOOP"; case ENOMSG => return "ENOMSG"; case EIDRM => return "EIDRM"; case ECHRNG => return "ECHRNG"; case EL2NSYNC => return "EL2NSYNC"; case EL3HLT => return "EL3HLT"; case EL3RST => return "EL3RST"; case ELNRNG => return "ELNRNG"; case EUNATCH => return "EUNATCH"; case ENOCSI => return "ENOCSI"; case EL2HLT => return "EL2HLT"; case EBADE => return "EBADE"; case EBADR => return "EBADR"; case EXFULL => return "EXFULL"; case ENOANO => return "ENOANO"; case EBADRQC => return "EBADRQC"; case EBADSLT => return "EBADSLT"; case EBFONT => return "EBFONT"; case ENOSTR => return "ENOSTR"; case ENODATA => return "ENODATA"; case ETIME => return "ETIME"; case ENOSR => return "ENOSR"; case ENONET => return "ENONET"; case ENOPKG => return "ENOPKG"; case EREMOTE => return "EREMOTE"; case ENOLINK => return "ENOLINK"; case EADV => return "EADV"; case ESRMNT => return "ESRMNT"; case ECOMM => return "ECOMM"; case EPROTO => return "EPROTO"; case EMULTIHOP => return "EMULTIHOP"; case EDOTDOT => return "EDOTDOT"; case EBADMSG => return "EBADMSG"; case EOVERFLOW => return "EOVERFLOW"; case ENOTUNIQ => return "ENOTUNIQ"; case EBADFD => return "EBADFD"; case EREMCHG => return "EREMCHG"; case ELIBACC => return "ELIBACC"; case ELIBBAD => return "ELIBBAD"; case ELIBSCN => return "ELIBSCN"; case ELIBMAX => return "ELIBMAX"; case ELIBEXEC => return "ELIBEXEC"; case EILSEQ => return "EILSEQ"; case ERESTART => return "ERESTART"; case ESTRPIPE => return "ESTRPIPE"; case EUSERS => return "EUSERS"; case ENOTSOCK => return "ENOTSOCK"; case EDESTADDRREQ => return "EDESTADDRREQ"; case EMSGSIZE => return "EMSGSIZE"; case EPROTOTYPE => return "EPROTOTYPE"; case ENOPROTOOPT => return "ENOPROTOOPT"; case EPROTONOSUPPORT => return "EPROTONOSUPPORT"; case ESOCKTNOSUPPORT => return "ESOCKTNOSUPPORT"; case EOPNOTSUPP => return "EOPNOTSUPP"; case EPFNOSUPPORT => return "EPFNOSUPPORT"; case EAFNOSUPPORT => return "EAFNOSUPPORT"; case EADDRINUSE => return "EADDRINUSE"; case EADDRNOTAVAIL => return "EADDRNOTAVAIL"; case ENETDOWN => return "ENETDOWN"; case ENETUNREACH => return "ENETUNREACH"; case ENETRESET => return "ENETRESET"; case ECONNABORTED => return "ECONNABORTED"; case ECONNRESET => return "ECONNRESET"; case ENOBUFS => return "ENOBUFS"; case EISCONN => return "EISCONN"; case ENOTCONN => return "ENOTCONN"; case ESHUTDOWN => return "ESHUTDOWN"; case ETOOMANYREFS => return "ETOOMANYREFS"; case ETIMEDOUT => return "ETIMEDOUT"; case ECONNREFUSED => return "ECONNREFUSED"; case EHOSTDOWN => return "EHOSTDOWN"; case EHOSTUNREACH => return "EHOSTUNREACH"; case EALREADY => return "EALREADY"; case EINPROGRESS => return "EINPROGRESS"; case ESTALE => return "ESTALE"; case EUCLEAN => return "EUCLEAN"; case ENOTNAM => return "ENOTNAM"; case ENAVAIL => return "ENAVAIL"; case EISNAM => return "EISNAM"; case EREMOTEIO => return "EREMOTEIO"; case EDQUOT => return "EDQUOT"; case ENOMEDIUM => return "ENOMEDIUM"; case EMEDIUMTYPE => return "EMEDIUMTYPE"; case ECANCELED => return "ECANCELED"; case ENOKEY => return "ENOKEY"; case EKEYEXPIRED => return "EKEYEXPIRED"; case EKEYREVOKED => return "EKEYREVOKED"; case EKEYREJECTED => return "EKEYREJECTED"; case EOWNERDEAD => return "EOWNERDEAD"; case ENOTRECOVERABLE => return "ENOTRECOVERABLE"; case ERFKILL => return "ERFKILL"; case EHWPOISON => return "EHWPOISON"; case => return unknown_errno(err); }; }; export def EPERM: errno = 1; export def ENOENT: errno = 2; export def ESRCH: errno = 3; export def EINTR: errno = 4; export def EIO: errno = 5; export def ENXIO: errno = 6; export def E2BIG: errno = 7; export def ENOEXEC: errno = 8; export def EBADF: errno = 9; export def ECHILD: errno = 10; export def EAGAIN: errno = 11; export def EWOULDBLOCK: errno = EAGAIN; export def ENOMEM: errno = 12; export def EACCES: errno = 13; export def EFAULT: errno = 14; export def ENOTBLK: errno = 15; export def EBUSY: errno = 16; export def EEXIST: errno = 17; export def EXDEV: errno = 18; export def ENODEV: errno = 19; export def ENOTDIR: errno = 20; export def EISDIR: errno = 21; export def EINVAL: errno = 22; export def ENFILE: errno = 23; export def EMFILE: errno = 24; export def ENOTTY: errno = 25; export def ETXTBSY: errno = 26; export def EFBIG: errno = 27; export def ENOSPC: errno = 28; export def ESPIPE: errno = 29; export def EROFS: errno = 30; export def EMLINK: errno = 31; export def EPIPE: errno = 32; export def EDOM: errno = 33; export def ERANGE: errno = 34; export def EDEADLK: errno = 35; export def ENAMETOOLONG: errno = 36; export def ENOLCK: errno = 37; export def ENOSYS: errno = 38; export def ENOTEMPTY: errno = 39; export def ELOOP: errno = 40; export def ENOMSG: errno = 42; export def EIDRM: errno = 43; export def ECHRNG: errno = 44; export def EL2NSYNC: errno = 45; export def EL3HLT: errno = 46; export def EL3RST: errno = 47; export def ELNRNG: errno = 48; export def EUNATCH: errno = 49; export def ENOCSI: errno = 50; export def EL2HLT: errno = 51; export def EBADE: errno = 52; export def EBADR: errno = 53; export def EXFULL: errno = 54; export def ENOANO: errno = 55; export def EBADRQC: errno = 56; export def EBADSLT: errno = 57; export def EBFONT: errno = 59; export def ENOSTR: errno = 60; export def ENODATA: errno = 61; export def ETIME: errno = 62; export def ENOSR: errno = 63; export def ENONET: errno = 64; export def ENOPKG: errno = 65; export def EREMOTE: errno = 66; export def ENOLINK: errno = 67; export def EADV: errno = 68; export def ESRMNT: errno = 69; export def ECOMM: errno = 70; export def EPROTO: errno = 71; export def EMULTIHOP: errno = 72; export def EDOTDOT: errno = 73; export def EBADMSG: errno = 74; export def EOVERFLOW: errno = 75; export def ENOTUNIQ: errno = 76; export def EBADFD: errno = 77; export def EREMCHG: errno = 78; export def ELIBACC: errno = 79; export def ELIBBAD: errno = 80; export def ELIBSCN: errno = 81; export def ELIBMAX: errno = 82; export def ELIBEXEC: errno = 83; export def EILSEQ: errno = 84; export def ERESTART: errno = 85; export def ESTRPIPE: errno = 86; export def EUSERS: errno = 87; export def ENOTSOCK: errno = 88; export def EDESTADDRREQ: errno = 89; export def EMSGSIZE: errno = 90; export def EPROTOTYPE: errno = 91; export def ENOPROTOOPT: errno = 92; export def EPROTONOSUPPORT: errno = 93; export def ESOCKTNOSUPPORT: errno = 94; export def EOPNOTSUPP: errno = 95; export def ENOTSUP: errno = EOPNOTSUPP; export def EPFNOSUPPORT: errno = 96; export def EAFNOSUPPORT: errno = 97; export def EADDRINUSE: errno = 98; export def EADDRNOTAVAIL: errno = 99; export def ENETDOWN: errno = 100; export def ENETUNREACH: errno = 101; export def ENETRESET: errno = 102; export def ECONNABORTED: errno = 103; export def ECONNRESET: errno = 104; export def ENOBUFS: errno = 105; export def EISCONN: errno = 106; export def ENOTCONN: errno = 107; export def ESHUTDOWN: errno = 108; export def ETOOMANYREFS: errno = 109; export def ETIMEDOUT: errno = 110; export def ECONNREFUSED: errno = 111; export def EHOSTDOWN: errno = 112; export def EHOSTUNREACH: errno = 113; export def EALREADY: errno = 114; export def EINPROGRESS: errno = 115; export def ESTALE: errno = 116; export def EUCLEAN: errno = 117; export def ENOTNAM: errno = 118; export def ENAVAIL: errno = 119; export def EISNAM: errno = 120; export def EREMOTEIO: errno = 121; export def EDQUOT: errno = 122; export def ENOMEDIUM: errno = 123; export def EMEDIUMTYPE: errno = 124; export def ECANCELED: errno = 125; export def ENOKEY: errno = 126; export def EKEYEXPIRED: errno = 127; export def EKEYREVOKED: errno = 128; export def EKEYREJECTED: errno = 129; export def EOWNERDEAD: errno = 130; export def ENOTRECOVERABLE: errno = 131; export def ERFKILL: errno = 132; export def EHWPOISON: errno = 133; hare-0.24.2/rt/+linux/hare+libc.sc000066400000000000000000000004221464473310100165310ustar00rootroot00000000000000SECTIONS { .libc_init_array : { PROVIDE(__libc_init_array_start = .); KEEP(*(.init_array)) PROVIDE(__libc_init_array_end = .); } .test_array : { PROVIDE(__test_array_start = .); KEEP(*(.test_array*)) PROVIDE(__test_array_end = .); } } INSERT AFTER .dynamic; hare-0.24.2/rt/+linux/hare.sc000066400000000000000000000012671464473310100156340ustar00rootroot00000000000000PHDRS { headers PT_PHDR PHDRS; text PT_LOAD FILEHDR PHDRS; data PT_LOAD; } ENTRY(_start); SECTIONS { . = 0x8000000; .text : { KEEP (*(.text)) *(.text.*) } :text . = 0x80000000; .data : { KEEP (*(.data)) *(.data.*) } :data .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); } :data .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); } :data .test_array : { PROVIDE_HIDDEN (__test_array_start = .); KEEP (*(.test_array)) PROVIDE_HIDDEN (__test_array_end = .); } :data .bss : { KEEP (*(.bss)) *(.bss.*) } :data } hare-0.24.2/rt/+linux/initfini.ha000066400000000000000000000010161464473310100165010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Run all global initialization functions. export fn init() void = { const ninit = (&init_end: uintptr - &init_start: uintptr): size / size(*fn() void); for (let i = 0z; i < ninit; i += 1) { init_start[i](); }; }; // Run all global finalization functions. export fn fini() void = { const nfini = (&fini_end: uintptr - &fini_start: uintptr): size / size(*fn() void); for (let i = nfini; i > 0; i -= 1) { fini_start[i - 1](); }; }; hare-0.24.2/rt/+linux/platform_abort.ha000066400000000000000000000011711464473310100177050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn strvec(s: str) iovec = { return iovec { iov_base = *(&s: **opaque), iov_len = len(s), }; }; fn platform_abort(path: *str, line: u64, col: u64, msg: str) never = { let linebuf: [U64_BUFSZ]u8 = [0...]; let colbuf: [U64_BUFSZ]u8 = [0...]; const iov = [ strvec("Abort: "), strvec(*path), strvec(":"), strvec(u64tos(linebuf, line)), strvec(":"), strvec(u64tos(colbuf, col)), strvec(": "), strvec(msg), strvec("\n"), ]; writev(STDERR_FILENO, &iov, len(iov): int): void; for (true) { kill(getpid(), SIGABRT): void; }; }; hare-0.24.2/rt/+linux/platformstart-libc.ha000066400000000000000000000003521464473310100205030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn start_linux(iv: *[*]uintptr) never = { argc = iv[0]: size; argv = &iv[1]: *[*]*u8; envp = &argv[argc + 1]: *[*]nullable *u8; start_ha(); }; hare-0.24.2/rt/+linux/prctl.ha000066400000000000000000000116571464473310100160300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def PR_SET_PDEATHSIG = 1; export def PR_GET_PDEATHSIG = 2; export def PR_GET_DUMPABLE = 3; export def PR_SET_DUMPABLE = 4; export def PR_GET_UNALIGN = 5; export def PR_SET_UNALIGN = 6; export def PR_UNALIGN_NOPRINT = 1; export def PR_UNALIGN_SIGBUS = 2; export def PR_GET_KEEPCAPS = 7; export def PR_SET_KEEPCAPS = 8; export def PR_GET_FPEMU = 9; export def PR_SET_FPEMU = 10; export def PR_FPEMU_NOPRINT = 1; export def PR_FPEMU_SIGFPE = 2; export def PR_GET_FPEXC = 11; export def PR_SET_FPEXC = 12; export def PR_FP_EXC_SW_ENABLE = 0x80; export def PR_FP_EXC_DIV = 0x010000; export def PR_FP_EXC_OVF = 0x020000; export def PR_FP_EXC_UND = 0x040000; export def PR_FP_EXC_RES = 0x080000; export def PR_FP_EXC_INV = 0x100000; export def PR_FP_EXC_DISABLED = 0; export def PR_FP_EXC_NONRECOV = 1; export def PR_FP_EXC_ASYNC = 2; export def PR_FP_EXC_PRECISE = 3; export def PR_GET_TIMING = 13; export def PR_SET_TIMING = 14; export def PR_TIMING_STATISTICAL = 0; export def PR_TIMING_TIMESTAMP = 1; export def PR_SET_NAME = 15; export def PR_GET_NAME = 16; export def PR_GET_ENDIAN = 19; export def PR_SET_ENDIAN = 20; export def PR_ENDIAN_BIG = 0; export def PR_ENDIAN_LITTLE = 1; export def PR_ENDIAN_PPC_LITTLE = 2; export def PR_GET_SECCOMP = 21; export def PR_SET_SECCOMP = 22; export def PR_CAPBSET_READ = 23; export def PR_CAPBSET_DROP = 24; export def PR_GET_TSC = 25; export def PR_SET_TSC = 26; export def PR_TSC_ENABLE = 1; export def PR_TSC_SIGSEGV = 2; export def PR_GET_SECUREBITS = 27; export def PR_SET_SECUREBITS = 28; export def PR_SET_TIMERSLACK = 29; export def PR_GET_TIMERSLACK = 30; export def PR_TASK_PERF_EVENTS_DISABLE = 31; export def PR_TASK_PERF_EVENTS_ENABLE = 32; export def PR_MCE_KILL = 33; export def PR_MCE_KILL_CLEAR = 0; export def PR_MCE_KILL_SET = 1; export def PR_MCE_KILL_LATE = 0; export def PR_MCE_KILL_EARLY = 1; export def PR_MCE_KILL_DEFAULT = 2; export def PR_MCE_KILL_GET = 34; export def PR_SET_MM = 35; export def PR_SET_MM_START_CODE = 1; export def PR_SET_MM_END_CODE = 2; export def PR_SET_MM_START_DATA = 3; export def PR_SET_MM_END_DATA = 4; export def PR_SET_MM_START_STACK = 5; export def PR_SET_MM_START_BRK = 6; export def PR_SET_MM_BRK = 7; export def PR_SET_MM_ARG_START = 8; export def PR_SET_MM_ARG_END = 9; export def PR_SET_MM_ENV_START = 10; export def PR_SET_MM_ENV_END = 11; export def PR_SET_MM_AUXV = 12; export def PR_SET_MM_EXE_FILE = 13; export def PR_SET_MM_MAP = 14; export def PR_SET_MM_MAP_SIZE = 15; export type prctl_mm_map = struct { start_code: u64, end_code: u64, start_data: u64, end_data: u64, start_brk: u64, brk: u64, start_stack: u64, arg_start: u64, arg_end: u64, env_start: u64, env_end: u64, auxv: *u64, auxv_size: u32, exe_fd: u32, }; export def PR_SET_PTRACER = 0x59616d61; export def PR_SET_PTRACER_ANY = -1; export def PR_SET_CHILD_SUBREAPER = 36; export def PR_GET_CHILD_SUBREAPER = 37; export def PR_SET_NO_NEW_PRIVS = 38; export def PR_GET_NO_NEW_PRIVS = 39; export def PR_GET_TID_ADDRESS = 40; export def PR_SET_THP_DISABLE = 41; export def PR_GET_THP_DISABLE = 42; export def PR_MPX_ENABLE_MANAGEMENT = 43; export def PR_MPX_DISABLE_MANAGEMENT = 44; export def PR_SET_FP_MODE = 45; export def PR_GET_FP_MODE = 46; export def PR_FP_MODE_FR = 1 << 0; export def PR_FP_MODE_FRE = 1 << 1; export def PR_CAP_AMBIENT = 47; export def PR_CAP_AMBIENT_IS_SET = 1; export def PR_CAP_AMBIENT_RAISE = 2; export def PR_CAP_AMBIENT_LOWER = 3; export def PR_CAP_AMBIENT_CLEAR_ALL = 4; export def PR_SVE_SET_VL = 50; export def PR_SVE_SET_VL_ONEXEC = 1 << 18; export def PR_SVE_GET_VL = 51; export def PR_SVE_VL_LEN_MASK = 0xffff; export def PR_SVE_VL_INHERIT = 1 << 17; export def PR_GET_SPECULATION_CTRL = 52; export def PR_SET_SPECULATION_CTRL = 53; export def PR_SPEC_STORE_BYPASS = 0; export def PR_SPEC_INDIRECT_BRANCH = 1; export def PR_SPEC_NOT_AFFECTED = 0; export def PR_SPEC_PRCTL = 1 << 0; export def PR_SPEC_ENABLE = 1 << 1; export def PR_SPEC_DISABLE = 1 << 2; export def PR_SPEC_FORCE_DISABLE = 1 << 3; export def PR_SPEC_DISABLE_NOEXEC = 1 << 4; export def PR_PAC_RESET_KEYS = 54; export def PR_PAC_APIAKEY = 1 << 0; export def PR_PAC_APIBKEY = 1 << 1; export def PR_PAC_APDAKEY = 1 << 2; export def PR_PAC_APDBKEY = 1 << 3; export def PR_PAC_APGAKEY = 1 << 4; export def PR_SET_TAGGED_ADDR_CTRL = 55; export def PR_GET_TAGGED_ADDR_CTRL = 56; export def PR_TAGGED_ADDR_ENABLE = 1 << 0; export def PR_MTE_TCF_SHIFT = 1; export def PR_MTE_TCF_NONE = 0 << 1; export def PR_MTE_TCF_SYNC = 1 << 1; export def PR_MTE_TCF_ASYNC = 2 << 1; export def PR_MTE_TCF_MASK = 3 << 1; export def PR_MTE_TAG_SHIFT = 3; export def PR_MTE_TAG_MASK = 0xffff << 3; export def PR_SET_IO_FLUSHER = 57; export def PR_GET_IO_FLUSHER = 58; export def PR_SET_SYSCALL_USER_DISPATCH = 59; export def PR_SYS_DISPATCH_OFF = 0; export def PR_SYS_DISPATCH_ON = 1; export def SYSCALL_DISPATCH_FILTER_ALLOW = 0; export def SYSCALL_DISPATCH_FILTER_BLOCK = 1; hare-0.24.2/rt/+linux/restore+aarch64.s000066400000000000000000000003101464473310100174450ustar00rootroot00000000000000// Copied from musl .section ".text.rt.restore","ax" .global rt.restore .global rt.restore_si .type rt.restore,@function .type rt.restore_si,@function rt.restore: rt.restore_si: mov x8,#139 svc 0 hare-0.24.2/rt/+linux/restore+riscv64.s000066400000000000000000000002031464473310100175160ustar00rootroot00000000000000.section ".text.rt.restore","ax" .global rt.restore .type rt.restore, %function rt.restore: li a7, 139 # SYS_rt_sigreturn ecall hare-0.24.2/rt/+linux/restore+x86_64.s000066400000000000000000000003151464473310100171600ustar00rootroot00000000000000// Copied from musl .section ".text.rt.restore","ax" .global rt.restore .global rt.restore_si .type rt.restore,@function .type rt.restore_si,@function rt.restore: rt.restore_si: movl $15, %eax syscall hare-0.24.2/rt/+linux/segmalloc.ha000066400000000000000000000010331464473310100166350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Allocates a segment. fn segmalloc(n: size) nullable *opaque = { return match (mmap(null, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) { case let err: errno => assert(err == ENOMEM: errno); yield null; case let p: *opaque => yield p; }; }; // Frees a segment allocated with segmalloc. fn segfree(p: *opaque, s: size) void = { match (munmap(p, s)) { case let err: errno => abort("munmap failed"); case void => void; }; }; hare-0.24.2/rt/+linux/signal.ha000066400000000000000000000073201464473310100161510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: work when _NSIG != 64 export fn alarm(sec: uint) uint = { let nval = itimerval { ... }; let oval = itimerval { ... }; nval.it_value.tv_sec = sec: time_t; setitimer(ITIMER_REAL, &nval, &oval)!; if (oval.it_value.tv_usec != 0) { oval.it_value.tv_sec += 1; }; return oval.it_value.tv_sec: uint; }; export def ITIMER_REAL: int = 0; export def ITIMER_VIRTUAL: int = 1; export def ITIMER_PROF: int = 2; export type itimerval = struct { it_interval: timeval, it_value: timeval, }; export fn getitimer( which: int, cur: *itimerval, ) (void | errno) = { wrap_return(syscall2(SYS_getitimer, which: u64, cur: uintptr: u64))?; }; export fn setitimer( which: int, newval: *itimerval, oldval: nullable *itimerval, ) (void | errno) = { wrap_return(syscall3(SYS_setitimer, which: u64, newval: uintptr: u64, oldval: uintptr: u64))?; }; export fn sigwait(set: *sigset, sig: *int) (void | errno) = { *sig = sigtimedwait(set, null, null)?; }; export fn sigwaitinfo( set: *sigset, info: nullable *siginfo, ) (int | errno) = { return sigtimedwait(set, info, null); }; export fn sigtimedwait( set: *sigset, info: nullable *siginfo, timeout: nullable *timespec, ) (int | errno) = { return wrap_return(syscall3(SYS_rt_sigtimedwait, set: uintptr: u64, info: uintptr: u64, timeout: uintptr: u64, ))?: int; }; export fn sigemptyset(set: *sigset) void = { set.__val[0] = 0; }; export fn sigaddset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__val[0] |= (1 << signum): u64; }; export fn sigdelset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__val[0] &= ~(1 << signum: u64); }; export fn sigismember(set: *sigset, signum: int) (bool | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; return (set.__val[0] & (1 << signum: u64)) != 0; }; export fn sigfillset(set: *sigset) void = { set.__val[0] = ~0u64; }; // Test sigset operations do not fail for valid signal numbers. @test fn sigset_valid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(!(sigismember(&set, 1) is errno), "Unexpected error"); assert(!(sigismember(&set, 15) is errno), "Unexpected error"); assert(!(sigismember(&set, NSIG) is errno), "Unexpected error"); assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigaddset(&set, 15) is errno), "Unexpected error"); assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error"); // It's ok to add a signal that is already present in the set. assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 15) is errno), "Unexpected error"); assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error"); // It's ok to delete a signal that is not present in the set. assert(!(sigdelset(&set, 10) is errno), "Unexpected error"); }; // Test sigset operations fail for invalid signal numbers. @test fn sigset_invalid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(sigismember(&set, -1) is errno, "Expected error"); assert(sigismember(&set, 0) is errno, "Expected error"); assert(sigismember(&set, NSIG + 1) is errno, "Expected error"); assert(sigaddset(&set, -1) is errno, "Expected error"); assert(sigaddset(&set, 0) is errno, "Expected error"); assert(sigaddset(&set, NSIG + 1) is errno, "Expected error"); assert(sigdelset(&set, -1) is errno, "Expected error"); assert(sigdelset(&set, 0) is errno, "Expected error"); assert(sigdelset(&set, NSIG + 1) is errno, "Expected error"); }; hare-0.24.2/rt/+linux/socket.ha000066400000000000000000000314671464473310100161750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sa_family_t = u16; export type socklen_t = uint; export type in_addr = struct { s_addr: u32 }; export type sockaddr_in = struct { sin_family: sa_family_t, sin_port: u16, sin_addr: in_addr, __pad: [16]u8, }; export type in6_addr = struct { union { s6_addr: [16]u8, s6_addr16: [8]u16, s6_addr32: [4]u32, } }; export type sockaddr_in6 = struct { sin6_family: sa_family_t, sin6_port: u16, sin6_flowinfo: u32, sin6_addr: in6_addr, sin6_scope_id: u32, }; export def UNIX_PATH_MAX: size = 108; export type sockaddr_un = struct { sun_family: sa_family_t, sun_path: [UNIX_PATH_MAX]u8, }; export type sockaddr_nl = struct { nl_family: sa_family_t, nl_pad: u16, nl_pid: u32, nl_groups: u32, }; export type sockaddr_ll = struct { sll_family: sa_family_t, sll_protocol: u16, sll_ifindex: int, sll_hatype: u16, sll_pkttype: u8, sll_halen: u8, sll_addr: [8]u8, }; export type sockaddr = struct { union { in: sockaddr_in, in6: sockaddr_in6, un: sockaddr_un, nl: sockaddr_nl, ll: sockaddr_ll, }, }; export def SCM_RIGHTS: int = 0x01; export def SCM_CREDENTIALS: int = 0x02; export type msghdr = struct { msg_name: nullable *opaque, msg_namelen: u32, msg_iov: nullable *[*]iovec, msg_iovlen: size, msg_control: nullable *opaque, msg_controllen: size, msg_flags: int }; export type cmsg = struct { hdr: cmsghdr, cmsg_data: [*]u8, }; export type sock_filter = struct { __code: u16, __jt: u8, __jf: u8, __k: u32, }; export type sock_fprog = struct { __len: u16, __filter: *[*]sock_filter, }; // domain for socket(2) // Unspecified export def AF_UNSPEC: sa_family_t = 0; // Unix domain sockets export def AF_UNIX: sa_family_t = 1; // POSIX name for AF_UNIX export def AF_LOCAL: sa_family_t = 1; // Internet IP Protocol export def AF_INET: sa_family_t = 2; // Amateur Radio AX.25 export def AF_AX25: sa_family_t = 3; // Novell IPX export def AF_IPX: sa_family_t = 4; // AppleTalk DDP export def AF_APPLETALK: sa_family_t = 5; // Amateur Radio NET/ROM export def AF_NETROM: sa_family_t = 6; // Multiprotocol bridge export def AF_BRIDGE: sa_family_t = 7; // ATM PVCs export def AF_ATMPVC: sa_family_t = 8; // Reserved for X.25 project export def AF_X25: sa_family_t = 9; // IP version 6 export def AF_INET6: sa_family_t = 10; // Amateur Radio X.25 PLP export def AF_ROSE: sa_family_t = 11; // Reserved for DECnet project export def AF_DECnet: sa_family_t = 12; // Reserved for 802.2LLC project export def AF_NETBEUI: sa_family_t = 13; // Security callback pseudo AF export def AF_SECURITY: sa_family_t = 14; // PF_KEY key management API export def AF_KEY: sa_family_t = 15; // Linux netlink API export def AF_NETLINK: sa_family_t = 16; // Alias to emulate 4.4BSD export def AF_ROUTE: sa_family_t = AF_NETLINK; // Packet family export def AF_PACKET: sa_family_t = 17; // Ash export def AF_ASH: sa_family_t = 18; // Acorn Econet export def AF_ECONET: sa_family_t = 19; // ATM SVCs export def AF_ATMSVC: sa_family_t = 20; // RDS sockets export def AF_RDS: sa_family_t = 21; // Linux SNA Project (nutters!) export def AF_SNA: sa_family_t = 22; // IRDA sockets export def AF_IRDA: sa_family_t = 23; // PPPoX sockets export def AF_PPPOX: sa_family_t = 24; // Wanpipe API Sockets export def AF_WANPIPE: sa_family_t = 25; // Linux LLC export def AF_LLC: sa_family_t = 26; // Native InfiniBand address export def AF_IB: sa_family_t = 27; // MPLS export def AF_MPLS: sa_family_t = 28; // Controller Area Network export def AF_CAN: sa_family_t = 29; // TIPC sockets export def AF_TIPC: sa_family_t = 30; // Bluetooth sockets export def AF_BLUETOOTH: sa_family_t = 31; // IUCV sockets export def AF_IUCV: sa_family_t = 32; // RxRPC sockets export def AF_RXRPC: sa_family_t = 33; // mISDN sockets export def AF_ISDN: sa_family_t = 34; // Phonet sockets export def AF_PHONET: sa_family_t = 35; // IEEE802154 sockets export def AF_IEEE802154: sa_family_t = 36; // CAIF sockets export def AF_CAIF: sa_family_t = 37; // Algorithm sockets export def AF_ALG: sa_family_t = 38; // NFC sockets export def AF_NFC: sa_family_t = 39; // vSockets export def AF_VSOCK: sa_family_t = 40; // Kernel Connection Multiplexor export def AF_KCM: sa_family_t = 41; // Qualcomm IPC Router export def AF_QIPCRTR: sa_family_t = 42; // smc sockets export def AF_SMC: sa_family_t = 43; // XDP sockets export def AF_XDP: sa_family_t = 44; // type for socket(2) export def SOCK_STREAM: int = 1; export def SOCK_DGRAM: int = 2; export def SOCK_RAW: int = 3; export def SOCK_RDM: int = 4; export def SOCK_SEQPACKET: int = 5; export def SOCK_DCCP: int = 6; export def SOCK_PACKET: int = 10; export def SOCK_NONBLOCK: int = 0o4000; export def SOCK_CLOEXEC: int = 0o2000000; // protocol for socket(2) export def ETH_P_15: int = 0x88f7; export def ETH_P_8021AD: int = 0x88a8; export def ETH_P_8021AH: int = 0x88e7; export def ETH_P_8021Q: int = 0x8100; export def ETH_P_80221: int = 0x8917; export def ETH_P_802_2: int = 0x4; export def ETH_P_802_3: int = 0x1; export def ETH_P_802_3_MIN: int = 0x600; export def ETH_P_802_EX1: int = 0x88b5; export def ETH_P_AARP: int = 0x80f3; export def ETH_P_AF_IUCV: int = 0xfbfb; export def ETH_P_ALL: int = 0x3; export def ETH_P_AOE: int = 0x88a2; export def ETH_P_ARCNET: int = 0x1a; export def ETH_P_ARP: int = 0x806; export def ETH_P_ATALK: int = 0x809b; export def ETH_P_ATMFATE: int = 0x8884; export def ETH_P_ATMMPOA: int = 0x884c; export def ETH_P_AX25: int = 0x2; export def ETH_P_BATMAN: int = 0x4305; export def ETH_P_BPQ: int = 0x8ff; export def ETH_P_CAIF: int = 0xf7; export def ETH_P_CAN: int = 0xc; export def ETH_P_CANFD: int = 0xd; export def ETH_P_CANXL: int = 0xe; export def ETH_P_CFM: int = 0x8902; export def ETH_P_CONTROL: int = 0x16; export def ETH_P_CUST: int = 0x6006; export def ETH_P_DDCMP: int = 0x6; export def ETH_P_DEC: int = 0x6000; export def ETH_P_DIAG: int = 0x6005; export def ETH_P_DNA_DL: int = 0x6001; export def ETH_P_DNA_RC: int = 0x6002; export def ETH_P_DNA_RT: int = 0x6003; export def ETH_P_DSA: int = 0x1b; export def ETH_P_DSA_8021Q: int = 0xdadb; export def ETH_P_DSA_A5PSW: int = 0xe001; export def ETH_P_ECONET: int = 0x18; export def ETH_P_EDSA: int = 0xdada; export def ETH_P_ERSPAN: int = 0x88be; export def ETH_P_ERSPAN2: int = 0x22eb; export def ETH_P_ETHERCAT: int = 0x88a4; export def ETH_P_FCOE: int = 0x8906; export def ETH_P_FIP: int = 0x8914; export def ETH_P_HDLC: int = 0x19; export def ETH_P_HSR: int = 0x892f; export def ETH_P_IBOE: int = 0x8915; export def ETH_P_IEEE802154: int = 0xf6; export def ETH_P_IEEEPUP: int = 0xa00; export def ETH_P_IEEEPUPAT: int = 0xa01; export def ETH_P_IFE: int = 0xed3e; export def ETH_P_IP: int = 0x800; export def ETH_P_IPV6: int = 0x86dd; export def ETH_P_IPX: int = 0x8137; export def ETH_P_IRDA: int = 0x17; export def ETH_P_LAT: int = 0x6004; export def ETH_P_LINK_CTL: int = 0x886c; export def ETH_P_LLDP: int = 0x88cc; export def ETH_P_LOCALTALK: int = 0x9; export def ETH_P_LOOP: int = 0x60; export def ETH_P_LOOPBACK: int = 0x9000; export def ETH_P_MACSEC: int = 0x88e5; export def ETH_P_MAP: int = 0xf9; export def ETH_P_MCTP: int = 0xfa; export def ETH_P_MOBITEX: int = 0x15; export def ETH_P_MPLS_MC: int = 0x8848; export def ETH_P_MPLS_UC: int = 0x8847; export def ETH_P_MRP: int = 0x88e3; export def ETH_P_MVRP: int = 0x88f5; export def ETH_P_NCSI: int = 0x88f8; export def ETH_P_NSH: int = 0x894f; export def ETH_P_PAE: int = 0x888e; export def ETH_P_PAUSE: int = 0x8808; export def ETH_P_PHONET: int = 0xf5; export def ETH_P_PPPTALK: int = 0x10; export def ETH_P_PPP_DISC: int = 0x8863; export def ETH_P_PPP_MP: int = 0x8; export def ETH_P_PPP_SES: int = 0x8864; export def ETH_P_PREAUTH: int = 0x88c7; export def ETH_P_PROFINET: int = 0x8892; export def ETH_P_PRP: int = 0x88fb; export def ETH_P_PUP: int = 0x200; export def ETH_P_PUPAT: int = 0x201; export def ETH_P_QINQ1: int = 0x9100; export def ETH_P_QINQ2: int = 0x9200; export def ETH_P_QINQ3: int = 0x9300; export def ETH_P_RARP: int = 0x8035; export def ETH_P_REALTEK: int = 0x8899; export def ETH_P_SCA: int = 0x6007; export def ETH_P_SLOW: int = 0x8809; export def ETH_P_SNAP: int = 0x5; export def ETH_P_TDLS: int = 0x890d; export def ETH_P_TEB: int = 0x6558; export def ETH_P_TIPC: int = 0x88ca; export def ETH_P_TRAILER: int = 0x1c; export def ETH_P_TR_802_2: int = 0x11; export def ETH_P_TSN: int = 0x22f0; export def ETH_P_WAN_PPP: int = 0x7; export def ETH_P_WCCP: int = 0x883e; export def ETH_P_X25: int = 0x805; export def ETH_P_XDSA: int = 0xf8; // Dummy protocol for TCP export def IPPROTO_IP: int = 0; // Internet Control Message Protocol export def IPPROTO_ICMP: int = 1; // Internet Group Management Protocol export def IPPROTO_IGMP: int = 2; // IPIP tunnels (older KA9Q tunnels use 94) export def IPPROTO_IPIP: int = 4; // Transmission Control Protocol export def IPPROTO_TCP: int = 6; // Exterior Gateway Protocol export def IPPROTO_EGP: int = 8; // PUP protocol export def IPPROTO_PUP: int = 12; // User Datagram Protocol export def IPPROTO_UDP: int = 17; // XNS IDP protocol export def IPPROTO_IDP: int = 22; // SO Transport Protocol Class 4 export def IPPROTO_TP: int = 29; // Datagram Congestion Control Protocol export def IPPROTO_DCCP: int = 33; // IPv6-in-IPv4 tunnelling export def IPPROTO_IPV6: int = 41; // RSVP Protocol export def IPPROTO_RSVP: int = 46; // Cisco GRE tunnels (rfc 1701,1702) export def IPPROTO_GRE: int = 47; // Encapsulation Security Payload protocol export def IPPROTO_ESP: int = 50; // Authentication Header protocol export def IPPROTO_AH: int = 51; // ICMPv6 export def IPPROTO_ICMPV6: int = 58; // Multicast Transport Protocol export def IPPROTO_MTP: int = 92; // IP option pseudo header for BEET export def IPPROTO_BEETPH: int = 94; // Encapsulation Header export def IPPROTO_ENCAP: int = 98; // Protocol Independent Multicast export def IPPROTO_PIM: int = 103; // Compression Header Protocol export def IPPROTO_COMP: int = 108; // Stream Control Transport Protocol export def IPPROTO_SCTP: int = 132; // UDP-Lite (RFC 3828) export def IPPROTO_UDPLITE: int = 136; // MPLS in IP (RFC 4023) export def IPPROTO_MPLS: int = 137; // Ethernet-within-IPv6 Encapsulation export def IPPROTO_ETHERNET: int = 143; // Raw IP packets export def IPPROTO_RAW: int = 255; // Multipath TCP connection export def IPPROTO_MPTCP: int = 262; // send/rcv flags export def MSG_OOB: int = 1; export def MSG_PEEK: int = 2; export def MSG_DONTROUTE: int = 4; export def MSG_TRYHARD: int = 4; // Synonym for MSG_DONTROUTE for DECnet export def MSG_CTRUNC: int = 8; export def MSG_PROBE: int = 0x10; // Do not send. Only probe path f.e. for MTU export def MSG_TRUNC: int = 0x20; export def MSG_DONTWAIT: int = 0x40; // Nonblocking io export def MSG_EOR: int = 0x80; // End of record export def MSG_WAITALL: int = 0x100; // Wait for a full request export def MSG_FIN: int = 0x200; export def MSG_SYN: int = 0x400; export def MSG_CONFIRM: int = 0x800; // Confirm path validity export def MSG_RST: int = 0x1000; export def MSG_ERRQUEUE: int = 0x2000; // Fetch message from error queue export def MSG_NOSIGNAL: int = 0x4000; // Do not generate SIGPIPE export def MSG_MORE: int = 0x8000; // Sender will send more export def MSG_WAITFORONE: int = 0x10000; // recvmmsg(): block until 1+ packets avail export def MSG_SENDPAGE_NOPOLICY: int = 0x10000; // sendpage() internal : do no apply policy export def MSG_SENDPAGE_NOTLAST: int = 0x20000; // sendpage() internal : not the last page export def MSG_BATCH: int = 0x40000; // sendmmsg(): more messages coming export def MSG_EOF: int = MSG_FIN; export def MSG_NO_SHARED_FRAGS: int = 0x80000; // sendpage() internal : page frags are not shared export def MSG_SENDPAGE_DECRYPTED: int = 0x100000; // sendpage() internal : page may carry * plain text and require encryption export def MSG_ZEROCOPY: int = 0x4000000; // Use user data in kernel path export def MSG_FASTOPEN: int = 0x20000000; // Send data in TCP SYN export def MSG_CMSG_CLOEXEC: int = 0x40000000; // Set close_on_exec for file descriptor received through SCM_RIGHTS // setsockopt levels export def SOL_SOCKET: int = 1; // setsockopt options export def SO_DEBUG: int = 1; export def SO_REUSEADDR: int = 2; export def SO_TYPE: int = 3; export def SO_ERROR: int = 4; export def SO_DONTROUTE: int = 5; export def SO_BROADCAST: int = 6; export def SO_SNDBUF: int = 7; export def SO_RCVBUF: int = 8; export def SO_SNDBUFFORCE: int = 32; export def SO_RCVBUFFORCE: int = 33; export def SO_KEEPALIVE: int = 9; export def SO_OOBINLINE: int = 10; export def SO_NO_CHECK: int = 11; export def SO_PRIORITY: int = 12; export def SO_LINGER: int = 13; export def SO_BSDCOMPAT: int = 14; export def SO_REUSEPORT: int = 15; export def SO_ATTACH_FILTER: int = 26; export def SO_DETATCH_FILTER: int = 27; export def SO_LOCK_FILTER: int = 44; // the following differ on ppc export def SO_PASSCRED: int = 16; export def SO_PEERCRED: int = 17; export def SO_RCVLOWAT: int = 18; export def SO_SNDLOWAT: int = 19; export def SO_RCVTIMEO_OLD: int = 20; export def SO_SNDTIMEO_OLD: int = 21; hare-0.24.2/rt/+linux/start+aarch64-libc.s000066400000000000000000000001471464473310100200360ustar00rootroot00000000000000.text .global _start _start: mov x29, #0 mov x30, #0 mov x0, sp add sp, x0, #-16 b rt.start_linux hare-0.24.2/rt/+linux/start+libc.ha000066400000000000000000000014601464473310100167350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol(".main") fn main() void; @symbol("exit") fn c_exit(status: int) never; const @symbol("__libc_init_array_start") init_start: [*]*fn() void; const @symbol("__libc_init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export @symbol("main") fn start_ha(c_argc: int, c_argv: *[*]*u8) never = { argc = c_argc: size; argv = c_argv; envp = c_envp; // we deliberately prevent libc from running @init for us, in order to // be able to initialize argc/argv/envp beforehand. we can still get // away with just using libc for @fini though init(); main(); c_exit(0); }; let @symbol("environ") c_envp: *[*]nullable *u8; hare-0.24.2/rt/+linux/start+riscv64-libc.s000066400000000000000000000001171464473310100201030ustar00rootroot00000000000000.text .global _start _start: mv a0, sp andi sp, sp, -16 tail rt.start_linux hare-0.24.2/rt/+linux/start+test+libc.ha000066400000000000000000000014631464473310100177130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("__test_main") fn test_main() size; const @symbol("__libc_init_array_start") init_start: [*]*fn() void; const @symbol("__libc_init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export @symbol("main") fn start_ha(c_argc: int, c_argv: *[*]*u8) int = { argc = c_argc: size; argv = c_argv; envp = c_envp; // we deliberately prevent libc from running @init for us, in order to // be able to initialize argc/argv/envp beforehand. we can still get // away with just using libc for @fini though init(); const nfail = test_main(); return if (nfail > 0) 1 else 0; }; let @symbol("environ") c_envp: *[*]nullable *u8; hare-0.24.2/rt/+linux/start+test.ha000066400000000000000000000007421464473310100170050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("__test_main") fn test_main() size; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); const nfail = test_main(); fini(); exit(if (nfail > 0) 1 else 0); }; hare-0.24.2/rt/+linux/start+x86_64-libc.s000066400000000000000000000001441464473310100175410ustar00rootroot00000000000000.text .global _start _start: xor %rbp, %rbp movq %rsp, %rdi andq $-16, %rsp call rt.start_linux hare-0.24.2/rt/+linux/start.ha000066400000000000000000000006551464473310100160350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("main") fn main() void; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); main(); fini(); exit(0); }; hare-0.24.2/rt/+linux/stat.ha000066400000000000000000000033141464473310100156460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn mkdev(major: u32, minor: u32) dev_t = ((major: u64 & 0xFFFFF000) << 32) | ((major: u64 & 0x00000FFF) << 8) | ((minor: u64 & 0xFFFFFF00) << 12) | (minor: u64 & 0x000000FF); fn fstatat_statx( dirfd: int, path: path, flags: int, mask: uint, statbuf: *stx, ) (void | errno) = { let path = kpath(path)?; wrap_return(syscall5(SYS_statx, dirfd: u64, path: uintptr: u64, flags: u64, mask: u64, statbuf: uintptr: u64))?; return; }; export fn fstatat( dirfd: int, path: path, statbuf: *st, flags: int, ) (errno | void) = { let path = kpath(path)?; let statxbuf = stx { ... }; fstatat_statx(dirfd, path, flags, STATX_BASIC_STATS, &statxbuf)?; statbuf.dev = mkdev(statxbuf.dev_major, statxbuf.dev_minor); statbuf.ino = statxbuf.ino; statbuf.mode = statxbuf.mode; statbuf.nlink = statxbuf.nlink; statbuf.uid = statxbuf.uid; statbuf.gid = statxbuf.gid; statbuf.rdev = mkdev(statxbuf.dev_major, statxbuf.dev_minor); statbuf.sz = statxbuf.sz; statbuf.blksz = statxbuf.blksize; statbuf.blocks = statxbuf.blocks; statbuf.atime.tv_sec = statxbuf.atime.tv_sec; statbuf.atime.tv_nsec = statxbuf.atime.tv_nsec: i64; statbuf.mtime.tv_sec = statxbuf.mtime.tv_sec; statbuf.mtime.tv_nsec = statxbuf.mtime.tv_nsec: i64; statbuf.ctime.tv_sec = statxbuf.ctime.tv_sec; statbuf.ctime.tv_nsec = statxbuf.ctime.tv_nsec: i64; }; export fn stat(path: path, statbuf: *st) (errno | void) = fstatat(AT_FDCWD, path, statbuf, 0); export fn fstat(fd: int, statbuf: *st) (errno | void) = fstatat(fd, "", statbuf, AT_EMPTY_PATH); export fn lstat(path: path, statbuf: *st) (errno | void) = fstatat(AT_FDCWD, path, statbuf, AT_SYMLINK_NOFOLLOW); hare-0.24.2/rt/+linux/syscall+aarch64.s000066400000000000000000000015161464473310100174450ustar00rootroot00000000000000.section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: mov x8, x0 svc 0 ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: mov x8, x0 mov x0, x1 svc 0 ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: mov x8, x0 mov x0, x1 mov x1, x2 svc 0 ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 svc 0 ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 svc 0 ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 mov x4, x5 svc 0 ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: mov x8, x0 mov x0, x1 mov x1, x2 mov x2, x3 mov x3, x4 mov x4, x5 mov x5, x6 svc 0 ret hare-0.24.2/rt/+linux/syscall+riscv64.s000066400000000000000000000014621464473310100175150ustar00rootroot00000000000000.section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: mv a7, a0 ecall ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: mv a7, a0 mv a0, a1 ecall ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: mv a7, a0 mv a0, a1 mv a1, a2 ecall ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 ecall ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 ecall ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 mv a4, a5 ecall ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: mv a7, a0 mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 mv a4, a5 mv a5, a6 ecall ret hare-0.24.2/rt/+linux/syscall+x86_64.s000066400000000000000000000017431464473310100171550ustar00rootroot00000000000000.section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: movq %rdi, %rax syscall ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: movq %rdi, %rax movq %rsi, %rdi syscall ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi syscall ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq %rcx, %rdx syscall ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq 8(%rsp), %r9 movq %rcx, %rdx syscall ret hare-0.24.2/rt/+linux/syscallno+aarch64.ha000066400000000000000000000261271464473310100201350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def SYS_io_setup: u64 = 0; export def SYS_io_destroy: u64 = 1; export def SYS_io_submit: u64 = 2; export def SYS_io_cancel: u64 = 3; export def SYS_io_getevents: u64 = 4; export def SYS_setxattr: u64 = 5; export def SYS_lsetxattr: u64 = 6; export def SYS_fsetxattr: u64 = 7; export def SYS_getxattr: u64 = 8; export def SYS_lgetxattr: u64 = 9; export def SYS_fgetxattr: u64 = 10; export def SYS_listxattr: u64 = 11; export def SYS_llistxattr: u64 = 12; export def SYS_flistxattr: u64 = 13; export def SYS_removexattr: u64 = 14; export def SYS_lremovexattr: u64 = 15; export def SYS_fremovexattr: u64 = 16; export def SYS_getcwd: u64 = 17; export def SYS_lookup_dcookie: u64 = 18; export def SYS_eventfd2: u64 = 19; export def SYS_epoll_create1: u64 = 20; export def SYS_epoll_ctl: u64 = 21; export def SYS_epoll_pwait: u64 = 22; export def SYS_dup: u64 = 23; export def SYS_dup3: u64 = 24; export def SYS_fcntl: u64 = 25; export def SYS_inotify_init1: u64 = 26; export def SYS_inotify_add_watch: u64 = 27; export def SYS_inotify_rm_watch: u64 = 28; export def SYS_ioctl: u64 = 29; export def SYS_ioprio_set: u64 = 30; export def SYS_ioprio_get: u64 = 31; export def SYS_flock: u64 = 32; export def SYS_mknodat: u64 = 33; export def SYS_mkdirat: u64 = 34; export def SYS_unlinkat: u64 = 35; export def SYS_symlinkat: u64 = 36; export def SYS_linkat: u64 = 37; export def SYS_renameat: u64 = 38; export def SYS_umount2: u64 = 39; export def SYS_mount: u64 = 40; export def SYS_pivot_root: u64 = 41; export def SYS_nfsservctl: u64 = 42; export def SYS_statfs: u64 = 43; export def SYS_fstatfs: u64 = 44; export def SYS_truncate: u64 = 45; export def SYS_ftruncate: u64 = 46; export def SYS_fallocate: u64 = 47; export def SYS_faccessat: u64 = 48; export def SYS_chdir: u64 = 49; export def SYS_fchdir: u64 = 50; export def SYS_chroot: u64 = 51; export def SYS_fchmod: u64 = 52; export def SYS_fchmodat: u64 = 53; export def SYS_fchownat: u64 = 54; export def SYS_fchown: u64 = 55; export def SYS_openat: u64 = 56; export def SYS_close: u64 = 57; export def SYS_vhangup: u64 = 58; export def SYS_pipe2: u64 = 59; export def SYS_quotactl: u64 = 60; export def SYS_getdents64: u64 = 61; export def SYS_lseek: u64 = 62; export def SYS_read: u64 = 63; export def SYS_write: u64 = 64; export def SYS_readv: u64 = 65; export def SYS_writev: u64 = 66; export def SYS_pread64: u64 = 67; export def SYS_pwrite64: u64 = 68; export def SYS_preadv: u64 = 69; export def SYS_pwritev: u64 = 70; export def SYS_sendfile: u64 = 71; export def SYS_pselect6: u64 = 72; export def SYS_ppoll: u64 = 73; export def SYS_signalfd4: u64 = 74; export def SYS_vmsplice: u64 = 75; export def SYS_splice: u64 = 76; export def SYS_tee: u64 = 77; export def SYS_readlinkat: u64 = 78; export def SYS_newfstatat: u64 = 79; export def SYS_fstat: u64 = 80; export def SYS_sync: u64 = 81; export def SYS_fsync: u64 = 82; export def SYS_fdatasync: u64 = 83; export def SYS_sync_file_range: u64 = 84; export def SYS_timerfd_create: u64 = 85; export def SYS_timerfd_settime: u64 = 86; export def SYS_timerfd_gettime: u64 = 87; export def SYS_utimensat: u64 = 88; export def SYS_acct: u64 = 89; export def SYS_capget: u64 = 90; export def SYS_capset: u64 = 91; export def SYS_personality: u64 = 92; export def SYS_exit: u64 = 93; export def SYS_exit_group: u64 = 94; export def SYS_waitid: u64 = 95; export def SYS_set_tid_address: u64 = 96; export def SYS_unshare: u64 = 97; export def SYS_futex: u64 = 98; export def SYS_set_robust_list: u64 = 99; export def SYS_get_robust_list: u64 = 100; export def SYS_nanosleep: u64 = 101; export def SYS_getitimer: u64 = 102; export def SYS_setitimer: u64 = 103; export def SYS_kexec_load: u64 = 104; export def SYS_init_module: u64 = 105; export def SYS_delete_module: u64 = 106; export def SYS_timer_create: u64 = 107; export def SYS_timer_gettime: u64 = 108; export def SYS_timer_getoverrun: u64 = 109; export def SYS_timer_settime: u64 = 110; export def SYS_timer_delete: u64 = 111; export def SYS_clock_settime: u64 = 112; export def SYS_clock_gettime: u64 = 113; export def SYS_clock_getres: u64 = 114; export def SYS_clock_nanosleep: u64 = 115; export def SYS_syslog: u64 = 116; export def SYS_ptrace: u64 = 117; export def SYS_sched_setparam: u64 = 118; export def SYS_sched_setscheduler: u64 = 119; export def SYS_sched_getscheduler: u64 = 120; export def SYS_sched_getparam: u64 = 121; export def SYS_sched_setaffinity: u64 = 122; export def SYS_sched_getaffinity: u64 = 123; export def SYS_sched_yield: u64 = 124; export def SYS_sched_get_priority_max: u64 = 125; export def SYS_sched_get_priority_min: u64 = 126; export def SYS_sched_rr_get_interval: u64 = 127; export def SYS_restart_syscall: u64 = 128; export def SYS_kill: u64 = 129; export def SYS_tkill: u64 = 130; export def SYS_tgkill: u64 = 131; export def SYS_sigaltstack: u64 = 132; export def SYS_rt_sigsuspend: u64 = 133; export def SYS_rt_sigaction: u64 = 134; export def SYS_rt_sigprocmask: u64 = 135; export def SYS_rt_sigpending: u64 = 136; export def SYS_rt_sigtimedwait: u64 = 137; export def SYS_rt_sigqueueinfo: u64 = 138; export def SYS_rt_sigreturn: u64 = 139; export def SYS_setpriority: u64 = 140; export def SYS_getpriority: u64 = 141; export def SYS_reboot: u64 = 142; export def SYS_setregid: u64 = 143; export def SYS_setgid: u64 = 144; export def SYS_setreuid: u64 = 145; export def SYS_setuid: u64 = 146; export def SYS_setresuid: u64 = 147; export def SYS_getresuid: u64 = 148; export def SYS_setresgid: u64 = 149; export def SYS_getresgid: u64 = 150; export def SYS_setfsuid: u64 = 151; export def SYS_setfsgid: u64 = 152; export def SYS_times: u64 = 153; export def SYS_setpgid: u64 = 154; export def SYS_getpgid: u64 = 155; export def SYS_getsid: u64 = 156; export def SYS_setsid: u64 = 157; export def SYS_getgroups: u64 = 158; export def SYS_setgroups: u64 = 159; export def SYS_uname: u64 = 160; export def SYS_sethostname: u64 = 161; export def SYS_setdomainname: u64 = 162; export def SYS_getrlimit: u64 = 163; export def SYS_setrlimit: u64 = 164; export def SYS_getrusage: u64 = 165; export def SYS_umask: u64 = 166; export def SYS_prctl: u64 = 167; export def SYS_getcpu: u64 = 168; export def SYS_gettimeofday: u64 = 169; export def SYS_settimeofday: u64 = 170; export def SYS_adjtimex: u64 = 171; export def SYS_getpid: u64 = 172; export def SYS_getppid: u64 = 173; export def SYS_getuid: u64 = 174; export def SYS_geteuid: u64 = 175; export def SYS_getgid: u64 = 176; export def SYS_getegid: u64 = 177; export def SYS_gettid: u64 = 178; export def SYS_sysinfo: u64 = 179; export def SYS_mq_open: u64 = 180; export def SYS_mq_unlink: u64 = 181; export def SYS_mq_timedsend: u64 = 182; export def SYS_mq_timedreceive: u64 = 183; export def SYS_mq_notify: u64 = 184; export def SYS_mq_getsetattr: u64 = 185; export def SYS_msgget: u64 = 186; export def SYS_msgctl: u64 = 187; export def SYS_msgrcv: u64 = 188; export def SYS_msgsnd: u64 = 189; export def SYS_semget: u64 = 190; export def SYS_semctl: u64 = 191; export def SYS_semtimedop: u64 = 192; export def SYS_semop: u64 = 193; export def SYS_shmget: u64 = 194; export def SYS_shmctl: u64 = 195; export def SYS_shmat: u64 = 196; export def SYS_shmdt: u64 = 197; export def SYS_socket: u64 = 198; export def SYS_socketpair: u64 = 199; export def SYS_bind: u64 = 200; export def SYS_listen: u64 = 201; export def SYS_accept: u64 = 202; export def SYS_connect: u64 = 203; export def SYS_getsockname: u64 = 204; export def SYS_getpeername: u64 = 205; export def SYS_sendto: u64 = 206; export def SYS_recvfrom: u64 = 207; export def SYS_setsockopt: u64 = 208; export def SYS_getsockopt: u64 = 209; export def SYS_shutdown: u64 = 210; export def SYS_sendmsg: u64 = 211; export def SYS_recvmsg: u64 = 212; export def SYS_readahead: u64 = 213; export def SYS_brk: u64 = 214; export def SYS_munmap: u64 = 215; export def SYS_mremap: u64 = 216; export def SYS_add_key: u64 = 217; export def SYS_request_key: u64 = 218; export def SYS_keyctl: u64 = 219; export def SYS_clone: u64 = 220; export def SYS_execve: u64 = 221; export def SYS_mmap: u64 = 222; export def SYS_fadvise64: u64 = 223; export def SYS_swapon: u64 = 224; export def SYS_swapoff: u64 = 225; export def SYS_mprotect: u64 = 226; export def SYS_msync: u64 = 227; export def SYS_mlock: u64 = 228; export def SYS_munlock: u64 = 229; export def SYS_mlockall: u64 = 230; export def SYS_munlockall: u64 = 231; export def SYS_mincore: u64 = 232; export def SYS_madvise: u64 = 233; export def SYS_remap_file_pages: u64 = 234; export def SYS_mbind: u64 = 235; export def SYS_get_mempolicy: u64 = 236; export def SYS_set_mempolicy: u64 = 237; export def SYS_migrate_pages: u64 = 238; export def SYS_move_pages: u64 = 239; export def SYS_rt_tgsigqueueinfo: u64 = 240; export def SYS_perf_event_open: u64 = 241; export def SYS_accept4: u64 = 242; export def SYS_recvmmsg: u64 = 243; export def SYS_wait4: u64 = 260; export def SYS_prlimit64: u64 = 261; export def SYS_fanotify_init: u64 = 262; export def SYS_fanotify_mark: u64 = 263; export def SYS_name_to_handle_at: u64 = 264; export def SYS_open_by_handle_at: u64 = 265; export def SYS_clock_adjtime: u64 = 266; export def SYS_syncfs: u64 = 267; export def SYS_setns: u64 = 268; export def SYS_sendmmsg: u64 = 269; export def SYS_process_vm_readv: u64 = 270; export def SYS_process_vm_writev: u64 = 271; export def SYS_kcmp: u64 = 272; export def SYS_finit_module: u64 = 273; export def SYS_sched_setattr: u64 = 274; export def SYS_sched_getattr: u64 = 275; export def SYS_renameat2: u64 = 276; export def SYS_seccomp: u64 = 277; export def SYS_getrandom: u64 = 278; export def SYS_memfd_create: u64 = 279; export def SYS_bpf: u64 = 280; export def SYS_execveat: u64 = 281; export def SYS_userfaultfd: u64 = 282; export def SYS_membarrier: u64 = 283; export def SYS_mlock2: u64 = 284; export def SYS_copy_file_range: u64 = 285; export def SYS_preadv2: u64 = 286; export def SYS_pwritev2: u64 = 287; export def SYS_pkey_mprotect: u64 = 288; export def SYS_pkey_alloc: u64 = 289; export def SYS_pkey_free: u64 = 290; export def SYS_statx: u64 = 291; export def SYS_io_pgetevents: u64 = 292; export def SYS_rseq: u64 = 293; export def SYS_kexec_file_load: u64 = 294; export def SYS_pidfd_send_signal: u64 = 424; export def SYS_io_uring_setup: u64 = 425; export def SYS_io_uring_enter: u64 = 426; export def SYS_io_uring_register: u64 = 427; export def SYS_open_tree: u64 = 428; export def SYS_move_mount: u64 = 429; export def SYS_fsopen: u64 = 430; export def SYS_fsconfig: u64 = 431; export def SYS_fsmount: u64 = 432; export def SYS_fspick: u64 = 433; export def SYS_pidfd_open: u64 = 434; export def SYS_clone3: u64 = 435; export def SYS_openat2: u64 = 437; export def SYS_faccessat2: u64 = 439; hare-0.24.2/rt/+linux/syscallno+riscv64.ha000066400000000000000000000254701464473310100202050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def SYS_io_setup: u64 = 0; export def SYS_io_destroy: u64 = 1; export def SYS_io_submit: u64 = 2; export def SYS_io_cancel: u64 = 3; export def SYS_io_getevents: u64 = 4; export def SYS_setxattr: u64 = 5; export def SYS_lsetxattr: u64 = 6; export def SYS_fsetxattr: u64 = 7; export def SYS_getxattr: u64 = 8; export def SYS_lgetxattr: u64 = 9; export def SYS_fgetxattr: u64 = 10; export def SYS_listxattr: u64 = 11; export def SYS_llistxattr: u64 = 12; export def SYS_flistxattr: u64 = 13; export def SYS_removexattr: u64 = 14; export def SYS_lremovexattr: u64 = 15; export def SYS_fremovexattr: u64 = 16; export def SYS_getcwd: u64 = 17; export def SYS_lookup_dcookie: u64 = 18; export def SYS_eventfd2: u64 = 19; export def SYS_epoll_create1: u64 = 20; export def SYS_epoll_ctl: u64 = 21; export def SYS_epoll_pwait: u64 = 22; export def SYS_dup: u64 = 23; export def SYS_dup3: u64 = 24; export def SYS_fcntl: u64 = 25; export def SYS_inotify_init1: u64 = 26; export def SYS_inotify_add_watch: u64 = 27; export def SYS_inotify_rm_watch: u64 = 28; export def SYS_ioctl: u64 = 29; export def SYS_ioprio_set: u64 = 30; export def SYS_ioprio_get: u64 = 31; export def SYS_flock: u64 = 32; export def SYS_mknodat: u64 = 33; export def SYS_mkdirat: u64 = 34; export def SYS_unlinkat: u64 = 35; export def SYS_symlinkat: u64 = 36; export def SYS_linkat: u64 = 37; export def SYS_umount2: u64 = 39; export def SYS_mount: u64 = 40; export def SYS_pivot_root: u64 = 41; export def SYS_nfsservctl: u64 = 42; export def SYS_statfs: u64 = 43; export def SYS_fstatfs: u64 = 44; export def SYS_truncate: u64 = 45; export def SYS_ftruncate: u64 = 46; export def SYS_fallocate: u64 = 47; export def SYS_faccessat: u64 = 48; export def SYS_chdir: u64 = 49; export def SYS_fchdir: u64 = 50; export def SYS_chroot: u64 = 51; export def SYS_fchmod: u64 = 52; export def SYS_fchmodat: u64 = 53; export def SYS_fchownat: u64 = 54; export def SYS_fchown: u64 = 55; export def SYS_openat: u64 = 56; export def SYS_close: u64 = 57; export def SYS_vhangup: u64 = 58; export def SYS_pipe2: u64 = 59; export def SYS_quotactl: u64 = 60; export def SYS_getdents64: u64 = 61; export def SYS_lseek: u64 = 62; export def SYS_read: u64 = 63; export def SYS_write: u64 = 64; export def SYS_readv: u64 = 65; export def SYS_writev: u64 = 66; export def SYS_pread64: u64 = 67; export def SYS_pwrite64: u64 = 68; export def SYS_preadv: u64 = 69; export def SYS_pwritev: u64 = 70; export def SYS_sendfile: u64 = 71; export def SYS_pselect6: u64 = 72; export def SYS_ppoll: u64 = 73; export def SYS_signalfd4: u64 = 74; export def SYS_vmsplice: u64 = 75; export def SYS_splice: u64 = 76; export def SYS_tee: u64 = 77; export def SYS_readlinkat: u64 = 78; export def SYS_fstatat: u64 = 79; export def SYS_fstat: u64 = 80; export def SYS_sync: u64 = 81; export def SYS_fsync: u64 = 82; export def SYS_fdatasync: u64 = 83; export def SYS_sync_file_range: u64 = 84; export def SYS_timerfd_create: u64 = 85; export def SYS_timerfd_settime: u64 = 86; export def SYS_timerfd_gettime: u64 = 87; export def SYS_utimensat: u64 = 88; export def SYS_acct: u64 = 89; export def SYS_capget: u64 = 90; export def SYS_capset: u64 = 91; export def SYS_personality: u64 = 92; export def SYS_exit: u64 = 93; export def SYS_exit_group: u64 = 94; export def SYS_waitid: u64 = 95; export def SYS_set_tid_address: u64 = 96; export def SYS_unshare: u64 = 97; export def SYS_futex: u64 = 98; export def SYS_set_robust_list: u64 = 99; export def SYS_get_robust_list: u64 = 100; export def SYS_nanosleep: u64 = 101; export def SYS_getitimer: u64 = 102; export def SYS_setitimer: u64 = 103; export def SYS_kexec_load: u64 = 104; export def SYS_init_module: u64 = 105; export def SYS_delete_module: u64 = 106; export def SYS_timer_create: u64 = 107; export def SYS_timer_gettime: u64 = 108; export def SYS_timer_getoverrun: u64 = 109; export def SYS_timer_settime: u64 = 110; export def SYS_timer_delete: u64 = 111; export def SYS_clock_settime: u64 = 112; export def SYS_clock_gettime: u64 = 113; export def SYS_clock_getres: u64 = 114; export def SYS_clock_nanosleep: u64 = 115; export def SYS_syslog: u64 = 116; export def SYS_ptrace: u64 = 117; export def SYS_sched_setparam: u64 = 118; export def SYS_sched_setscheduler: u64 = 119; export def SYS_sched_getscheduler: u64 = 120; export def SYS_sched_getparam: u64 = 121; export def SYS_sched_setaffinity: u64 = 122; export def SYS_sched_getaffinity: u64 = 123; export def SYS_sched_yield: u64 = 124; export def SYS_sched_get_priority_max: u64 = 125; export def SYS_sched_get_priority_min: u64 = 126; export def SYS_sched_rr_get_interval: u64 = 127; export def SYS_restart_syscall: u64 = 128; export def SYS_kill: u64 = 129; export def SYS_tkill: u64 = 130; export def SYS_tgkill: u64 = 131; export def SYS_sigaltstack: u64 = 132; export def SYS_rt_sigsuspend: u64 = 133; export def SYS_rt_sigaction: u64 = 134; export def SYS_rt_sigprocmask: u64 = 135; export def SYS_rt_sigpending: u64 = 136; export def SYS_rt_sigtimedwait: u64 = 137; export def SYS_rt_sigqueueinfo: u64 = 138; export def SYS_rt_sigreturn: u64 = 139; export def SYS_setpriority: u64 = 140; export def SYS_getpriority: u64 = 141; export def SYS_reboot: u64 = 142; export def SYS_setregid: u64 = 143; export def SYS_setgid: u64 = 144; export def SYS_setreuid: u64 = 145; export def SYS_setuid: u64 = 146; export def SYS_setresuid: u64 = 147; export def SYS_getresuid: u64 = 148; export def SYS_setresgid: u64 = 149; export def SYS_getresgid: u64 = 150; export def SYS_setfsuid: u64 = 151; export def SYS_setfsgid: u64 = 152; export def SYS_times: u64 = 153; export def SYS_setpgid: u64 = 154; export def SYS_getpgid: u64 = 155; export def SYS_getsid: u64 = 156; export def SYS_setsid: u64 = 157; export def SYS_getgroups: u64 = 158; export def SYS_setgroups: u64 = 159; export def SYS_uname: u64 = 160; export def SYS_sethostname: u64 = 161; export def SYS_setdomainname: u64 = 162; export def SYS_getrlimit: u64 = 163; export def SYS_setrlimit: u64 = 164; export def SYS_getrusage: u64 = 165; export def SYS_umask: u64 = 166; export def SYS_prctl: u64 = 167; export def SYS_getcpu: u64 = 168; export def SYS_gettimeofday: u64 = 169; export def SYS_settimeofday: u64 = 170; export def SYS_adjtimex: u64 = 171; export def SYS_getpid: u64 = 172; export def SYS_getppid: u64 = 173; export def SYS_getuid: u64 = 174; export def SYS_geteuid: u64 = 175; export def SYS_getgid: u64 = 176; export def SYS_getegid: u64 = 177; export def SYS_gettid: u64 = 178; export def SYS_sysinfo: u64 = 179; export def SYS_mq_open: u64 = 180; export def SYS_mq_unlink: u64 = 181; export def SYS_mq_timedsend: u64 = 182; export def SYS_mq_timedreceive: u64 = 183; export def SYS_mq_notify: u64 = 184; export def SYS_mq_getsetattr: u64 = 185; export def SYS_msgget: u64 = 186; export def SYS_msgctl: u64 = 187; export def SYS_msgrcv: u64 = 188; export def SYS_msgsnd: u64 = 189; export def SYS_semget: u64 = 190; export def SYS_semctl: u64 = 191; export def SYS_semtimedop: u64 = 192; export def SYS_semop: u64 = 193; export def SYS_shmget: u64 = 194; export def SYS_shmctl: u64 = 195; export def SYS_shmat: u64 = 196; export def SYS_shmdt: u64 = 197; export def SYS_socket: u64 = 198; export def SYS_socketpair: u64 = 199; export def SYS_bind: u64 = 200; export def SYS_listen: u64 = 201; export def SYS_accept: u64 = 202; export def SYS_connect: u64 = 203; export def SYS_getsockname: u64 = 204; export def SYS_getpeername: u64 = 205; export def SYS_sendto: u64 = 206; export def SYS_recvfrom: u64 = 207; export def SYS_setsockopt: u64 = 208; export def SYS_getsockopt: u64 = 209; export def SYS_shutdown: u64 = 210; export def SYS_sendmsg: u64 = 211; export def SYS_recvmsg: u64 = 212; export def SYS_readahead: u64 = 213; export def SYS_brk: u64 = 214; export def SYS_munmap: u64 = 215; export def SYS_mremap: u64 = 216; export def SYS_add_key: u64 = 217; export def SYS_request_key: u64 = 218; export def SYS_keyctl: u64 = 219; export def SYS_clone: u64 = 220; export def SYS_execve: u64 = 221; export def SYS_mmap: u64 = 222; export def SYS_fadvise64: u64 = 223; export def SYS_swapon: u64 = 224; export def SYS_swapoff: u64 = 225; export def SYS_mprotect: u64 = 226; export def SYS_msync: u64 = 227; export def SYS_mlock: u64 = 228; export def SYS_munlock: u64 = 229; export def SYS_mlockall: u64 = 230; export def SYS_munlockall: u64 = 231; export def SYS_mincore: u64 = 232; export def SYS_madvise: u64 = 233; export def SYS_remap_file_pages: u64 = 234; export def SYS_mbind: u64 = 235; export def SYS_get_mempolicy: u64 = 236; export def SYS_set_mempolicy: u64 = 237; export def SYS_migrate_pages: u64 = 238; export def SYS_move_pages: u64 = 239; export def SYS_rt_tgsigqueueinfo: u64 = 240; export def SYS_perf_event_open: u64 = 241; export def SYS_accept4: u64 = 242; export def SYS_recvmmsg: u64 = 243; export def SYS_arch_specific_syscall: u64 = 244; export def SYS_wait4: u64 = 260; export def SYS_prlimit64: u64 = 261; export def SYS_fanotify_init: u64 = 262; export def SYS_fanotify_mark: u64 = 263; export def SYS_name_to_handle_at: u64 = 264; export def SYS_open_by_handle_at: u64 = 265; export def SYS_clock_adjtime: u64 = 266; export def SYS_syncfs: u64 = 267; export def SYS_setns: u64 = 268; export def SYS_sendmmsg: u64 = 269; export def SYS_process_vm_readv: u64 = 270; export def SYS_process_vm_writev: u64 = 271; export def SYS_kcmp: u64 = 272; export def SYS_finit_module: u64 = 273; export def SYS_sched_setattr: u64 = 274; export def SYS_sched_getattr: u64 = 275; export def SYS_renameat2: u64 = 276; export def SYS_seccomp: u64 = 277; export def SYS_getrandom: u64 = 278; export def SYS_memfd_create: u64 = 279; export def SYS_bpf: u64 = 280; export def SYS_execveat: u64 = 281; export def SYS_userfaultfd: u64 = 282; export def SYS_membarrier: u64 = 283; export def SYS_mlock2: u64 = 284; export def SYS_copy_file_range: u64 = 285; export def SYS_preadv2: u64 = 286; export def SYS_pwritev2: u64 = 287; export def SYS_pkey_mprotect: u64 = 288; export def SYS_pkey_alloc: u64 = 289; export def SYS_pkey_free: u64 = 290; export def SYS_statx: u64 = 291; export def SYS_io_pgetevents: u64 = 292; export def SYS_rseq: u64 = 293; export def SYS_kexec_file_load: u64 = 294; export def SYS_pidfd_send_signal: u64 = 424; export def SYS_io_uring_setup: u64 = 425; export def SYS_io_uring_enter: u64 = 426; export def SYS_io_uring_register: u64 = 427; export def SYS_open_tree: u64 = 428; export def SYS_move_mount: u64 = 429; export def SYS_fsopen: u64 = 430; export def SYS_fsconfig: u64 = 431; export def SYS_fsmount: u64 = 432; export def SYS_fspick: u64 = 433; export def SYS_pidfd_open: u64 = 434; export def SYS_clone3: u64 = 435; export def SYS_close_range: u64 = 436; export def SYS_openat2: u64 = 437; export def SYS_pidfd_getfd: u64 = 438; export def SYS_faccessat2: u64 = 439; // RISC-V specific export def SYS_sysriscv: u64 = SYS_arch_specific_syscall; export def SYS_riscv_flush_icache: u64 = SYS_sysriscv + 15; hare-0.24.2/rt/+linux/syscallno+x86_64.ha000066400000000000000000000320521464473310100176350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def SYS_read: u64 = 0; export def SYS_write: u64 = 1; export def SYS_open: u64 = 2; export def SYS_close: u64 = 3; export def SYS_stat: u64 = 4; export def SYS_fstat: u64 = 5; export def SYS_lstat: u64 = 6; export def SYS_poll: u64 = 7; export def SYS_lseek: u64 = 8; export def SYS_mmap: u64 = 9; export def SYS_mprotect: u64 = 10; export def SYS_munmap: u64 = 11; export def SYS_brk: u64 = 12; export def SYS_rt_sigaction: u64 = 13; export def SYS_rt_sigprocmask: u64 = 14; export def SYS_rt_sigreturn: u64 = 15; export def SYS_ioctl: u64 = 16; export def SYS_pread64: u64 = 17; export def SYS_pwrite64: u64 = 18; export def SYS_readv: u64 = 19; export def SYS_writev: u64 = 20; export def SYS_access: u64 = 21; export def SYS_pipe: u64 = 22; export def SYS_select: u64 = 23; export def SYS_sched_yield: u64 = 24; export def SYS_mremap: u64 = 25; export def SYS_msync: u64 = 26; export def SYS_mincore: u64 = 27; export def SYS_madvise: u64 = 28; export def SYS_shmget: u64 = 29; export def SYS_shmat: u64 = 30; export def SYS_shmctl: u64 = 31; export def SYS_dup: u64 = 32; export def SYS_dup2: u64 = 33; export def SYS_pause: u64 = 34; export def SYS_nanosleep: u64 = 35; export def SYS_getitimer: u64 = 36; export def SYS_alarm: u64 = 37; export def SYS_setitimer: u64 = 38; export def SYS_getpid: u64 = 39; export def SYS_sendfile: u64 = 40; export def SYS_socket: u64 = 41; export def SYS_connect: u64 = 42; export def SYS_accept: u64 = 43; export def SYS_sendto: u64 = 44; export def SYS_recvfrom: u64 = 45; export def SYS_sendmsg: u64 = 46; export def SYS_recvmsg: u64 = 47; export def SYS_shutdown: u64 = 48; export def SYS_bind: u64 = 49; export def SYS_listen: u64 = 50; export def SYS_getsockname: u64 = 51; export def SYS_getpeername: u64 = 52; export def SYS_socketpair: u64 = 53; export def SYS_setsockopt: u64 = 54; export def SYS_getsockopt: u64 = 55; export def SYS_clone: u64 = 56; export def SYS_fork: u64 = 57; export def SYS_vfork: u64 = 58; export def SYS_execve: u64 = 59; export def SYS_exit: u64 = 60; export def SYS_wait4: u64 = 61; export def SYS_kill: u64 = 62; export def SYS_uname: u64 = 63; export def SYS_semget: u64 = 64; export def SYS_semop: u64 = 65; export def SYS_semctl: u64 = 66; export def SYS_shmdt: u64 = 67; export def SYS_msgget: u64 = 68; export def SYS_msgsnd: u64 = 69; export def SYS_msgrcv: u64 = 70; export def SYS_msgctl: u64 = 71; export def SYS_fcntl: u64 = 72; export def SYS_flock: u64 = 73; export def SYS_fsync: u64 = 74; export def SYS_fdatasync: u64 = 75; export def SYS_truncate: u64 = 76; export def SYS_ftruncate: u64 = 77; export def SYS_getdents: u64 = 78; export def SYS_getcwd: u64 = 79; export def SYS_chdir: u64 = 80; export def SYS_fchdir: u64 = 81; export def SYS_rename: u64 = 82; export def SYS_mkdir: u64 = 83; export def SYS_rmdir: u64 = 84; export def SYS_creat: u64 = 85; export def SYS_link: u64 = 86; export def SYS_unlink: u64 = 87; export def SYS_symlink: u64 = 88; export def SYS_readlink: u64 = 89; export def SYS_chmod: u64 = 90; export def SYS_fchmod: u64 = 91; export def SYS_chown: u64 = 92; export def SYS_fchown: u64 = 93; export def SYS_lchown: u64 = 94; export def SYS_umask: u64 = 95; export def SYS_gettimeofday: u64 = 96; export def SYS_getrlimit: u64 = 97; export def SYS_getrusage: u64 = 98; export def SYS_sysinfo: u64 = 99; export def SYS_times: u64 = 100; export def SYS_ptrace: u64 = 101; export def SYS_getuid: u64 = 102; export def SYS_syslog: u64 = 103; export def SYS_getgid: u64 = 104; export def SYS_setuid: u64 = 105; export def SYS_setgid: u64 = 106; export def SYS_geteuid: u64 = 107; export def SYS_getegid: u64 = 108; export def SYS_setpgid: u64 = 109; export def SYS_getppid: u64 = 110; export def SYS_getpgrp: u64 = 111; export def SYS_setsid: u64 = 112; export def SYS_setreuid: u64 = 113; export def SYS_setregid: u64 = 114; export def SYS_getgroups: u64 = 115; export def SYS_setgroups: u64 = 116; export def SYS_setresuid: u64 = 117; export def SYS_getresuid: u64 = 118; export def SYS_setresgid: u64 = 119; export def SYS_getresgid: u64 = 120; export def SYS_getpgid: u64 = 121; export def SYS_setfsuid: u64 = 122; export def SYS_setfsgid: u64 = 123; export def SYS_getsid: u64 = 124; export def SYS_capget: u64 = 125; export def SYS_capset: u64 = 126; export def SYS_rt_sigpending: u64 = 127; export def SYS_rt_sigtimedwait: u64 = 128; export def SYS_rt_sigqueueinfo: u64 = 129; export def SYS_rt_sigsuspend: u64 = 130; export def SYS_sigaltstack: u64 = 131; export def SYS_utime: u64 = 132; export def SYS_mknod: u64 = 133; export def SYS_uselib: u64 = 134; export def SYS_personality: u64 = 135; export def SYS_ustat: u64 = 136; export def SYS_statfs: u64 = 137; export def SYS_fstatfs: u64 = 138; export def SYS_sysfs: u64 = 139; export def SYS_getpriority: u64 = 140; export def SYS_setpriority: u64 = 141; export def SYS_sched_setparam: u64 = 142; export def SYS_sched_getparam: u64 = 143; export def SYS_sched_setscheduler: u64 = 144; export def SYS_sched_getscheduler: u64 = 145; export def SYS_sched_get_priority_max: u64 = 146; export def SYS_sched_get_priority_min: u64 = 147; export def SYS_sched_rr_get_interval: u64 = 148; export def SYS_mlock: u64 = 149; export def SYS_munlock: u64 = 150; export def SYS_mlockall: u64 = 151; export def SYS_munlockall: u64 = 152; export def SYS_vhangup: u64 = 153; export def SYS_modify_ldt: u64 = 154; export def SYS_pivot_root: u64 = 155; export def SYS__sysctl: u64 = 156; export def SYS_prctl: u64 = 157; export def SYS_arch_prctl: u64 = 158; export def SYS_adjtimex: u64 = 159; export def SYS_setrlimit: u64 = 160; export def SYS_chroot: u64 = 161; export def SYS_sync: u64 = 162; export def SYS_acct: u64 = 163; export def SYS_settimeofday: u64 = 164; export def SYS_mount: u64 = 165; export def SYS_umount2: u64 = 166; export def SYS_swapon: u64 = 167; export def SYS_swapoff: u64 = 168; export def SYS_reboot: u64 = 169; export def SYS_sethostname: u64 = 170; export def SYS_setdomainname: u64 = 171; export def SYS_iopl: u64 = 172; export def SYS_ioperm: u64 = 173; export def SYS_create_module: u64 = 174; export def SYS_init_module: u64 = 175; export def SYS_delete_module: u64 = 176; export def SYS_get_kernel_syms: u64 = 177; export def SYS_query_module: u64 = 178; export def SYS_quotactl: u64 = 179; export def SYS_nfsservctl: u64 = 180; export def SYS_getpmsg: u64 = 181; export def SYS_putpmsg: u64 = 182; export def SYS_afs_syscall: u64 = 183; export def SYS_tuxcall: u64 = 184; export def SYS_security: u64 = 185; export def SYS_gettid: u64 = 186; export def SYS_readahead: u64 = 187; export def SYS_setxattr: u64 = 188; export def SYS_lsetxattr: u64 = 189; export def SYS_fsetxattr: u64 = 190; export def SYS_getxattr: u64 = 191; export def SYS_lgetxattr: u64 = 192; export def SYS_fgetxattr: u64 = 193; export def SYS_listxattr: u64 = 194; export def SYS_llistxattr: u64 = 195; export def SYS_flistxattr: u64 = 196; export def SYS_removexattr: u64 = 197; export def SYS_lremovexattr: u64 = 198; export def SYS_fremovexattr: u64 = 199; export def SYS_tkill: u64 = 200; export def SYS_time: u64 = 201; export def SYS_futex: u64 = 202; export def SYS_sched_setaffinity: u64 = 203; export def SYS_sched_getaffinity: u64 = 204; export def SYS_set_thread_area: u64 = 205; export def SYS_io_setup: u64 = 206; export def SYS_io_destroy: u64 = 207; export def SYS_io_getevents: u64 = 208; export def SYS_io_submit: u64 = 209; export def SYS_io_cancel: u64 = 210; export def SYS_get_thread_area: u64 = 211; export def SYS_lookup_dcookie: u64 = 212; export def SYS_epoll_create: u64 = 213; export def SYS_epoll_ctl_old: u64 = 214; export def SYS_epoll_wait_old: u64 = 215; export def SYS_remap_file_pages: u64 = 216; export def SYS_getdents64: u64 = 217; export def SYS_set_tid_address: u64 = 218; export def SYS_restart_syscall: u64 = 219; export def SYS_semtimedop: u64 = 220; export def SYS_fadvise64: u64 = 221; export def SYS_timer_create: u64 = 222; export def SYS_timer_settime: u64 = 223; export def SYS_timer_gettime: u64 = 224; export def SYS_timer_getoverrun: u64 = 225; export def SYS_timer_delete: u64 = 226; export def SYS_clock_settime: u64 = 227; export def SYS_clock_gettime: u64 = 228; export def SYS_clock_getres: u64 = 229; export def SYS_clock_nanosleep: u64 = 230; export def SYS_exit_group: u64 = 231; export def SYS_epoll_wait: u64 = 232; export def SYS_epoll_ctl: u64 = 233; export def SYS_tgkill: u64 = 234; export def SYS_utimes: u64 = 235; export def SYS_vserver: u64 = 236; export def SYS_mbind: u64 = 237; export def SYS_set_mempolicy: u64 = 238; export def SYS_get_mempolicy: u64 = 239; export def SYS_mq_open: u64 = 240; export def SYS_mq_unlink: u64 = 241; export def SYS_mq_timedsend: u64 = 242; export def SYS_mq_timedreceive: u64 = 243; export def SYS_mq_notify: u64 = 244; export def SYS_mq_getsetattr: u64 = 245; export def SYS_kexec_load: u64 = 246; export def SYS_waitid: u64 = 247; export def SYS_add_key: u64 = 248; export def SYS_request_key: u64 = 249; export def SYS_keyctl: u64 = 250; export def SYS_ioprio_set: u64 = 251; export def SYS_ioprio_get: u64 = 252; export def SYS_inotify_init: u64 = 253; export def SYS_inotify_add_watch: u64 = 254; export def SYS_inotify_rm_watch: u64 = 255; export def SYS_migrate_pages: u64 = 256; export def SYS_openat: u64 = 257; export def SYS_mkdirat: u64 = 258; export def SYS_mknodat: u64 = 259; export def SYS_fchownat: u64 = 260; export def SYS_futimesat: u64 = 261; export def SYS_newfstatat: u64 = 262; export def SYS_unlinkat: u64 = 263; export def SYS_renameat: u64 = 264; export def SYS_linkat: u64 = 265; export def SYS_symlinkat: u64 = 266; export def SYS_readlinkat: u64 = 267; export def SYS_fchmodat: u64 = 268; export def SYS_faccessat: u64 = 269; export def SYS_pselect6: u64 = 270; export def SYS_ppoll: u64 = 271; export def SYS_unshare: u64 = 272; export def SYS_set_robust_list: u64 = 273; export def SYS_get_robust_list: u64 = 274; export def SYS_splice: u64 = 275; export def SYS_tee: u64 = 276; export def SYS_sync_file_range: u64 = 277; export def SYS_vmsplice: u64 = 278; export def SYS_move_pages: u64 = 279; export def SYS_utimensat: u64 = 280; export def SYS_epoll_pwait: u64 = 281; export def SYS_signalfd: u64 = 282; export def SYS_timerfd_create: u64 = 283; export def SYS_eventfd: u64 = 284; export def SYS_fallocate: u64 = 285; export def SYS_timerfd_settime: u64 = 286; export def SYS_timerfd_gettime: u64 = 287; export def SYS_accept4: u64 = 288; export def SYS_signalfd4: u64 = 289; export def SYS_eventfd2: u64 = 290; export def SYS_epoll_create1: u64 = 291; export def SYS_dup3: u64 = 292; export def SYS_pipe2: u64 = 293; export def SYS_inotify_init1: u64 = 294; export def SYS_preadv: u64 = 295; export def SYS_pwritev: u64 = 296; export def SYS_rt_tgsigqueueinfo: u64 = 297; export def SYS_perf_event_open: u64 = 298; export def SYS_recvmmsg: u64 = 299; export def SYS_fanotify_init: u64 = 300; export def SYS_fanotify_mark: u64 = 301; export def SYS_prlimit64: u64 = 302; export def SYS_name_to_handle_at: u64 = 303; export def SYS_open_by_handle_at: u64 = 304; export def SYS_clock_adjtime: u64 = 305; export def SYS_syncfs: u64 = 306; export def SYS_sendmmsg: u64 = 307; export def SYS_setns: u64 = 308; export def SYS_getcpu: u64 = 309; export def SYS_process_vm_readv: u64 = 310; export def SYS_process_vm_writev: u64 = 311; export def SYS_kcmp: u64 = 312; export def SYS_finit_module: u64 = 313; export def SYS_sched_setattr: u64 = 314; export def SYS_sched_getattr: u64 = 315; export def SYS_renameat2: u64 = 316; export def SYS_seccomp: u64 = 317; export def SYS_getrandom: u64 = 318; export def SYS_memfd_create: u64 = 319; export def SYS_kexec_file_load: u64 = 320; export def SYS_bpf: u64 = 321; export def SYS_execveat: u64 = 322; export def SYS_userfaultfd: u64 = 323; export def SYS_membarrier: u64 = 324; export def SYS_mlock2: u64 = 325; export def SYS_copy_file_range: u64 = 326; export def SYS_preadv2: u64 = 327; export def SYS_pwritev2: u64 = 328; export def SYS_pkey_mprotect: u64 = 329; export def SYS_pkey_alloc: u64 = 330; export def SYS_pkey_free: u64 = 331; export def SYS_statx: u64 = 332; export def SYS_io_pgetevents: u64 = 333; export def SYS_rseq: u64 = 334; export def SYS_pidfd_send_signal: u64 = 424; export def SYS_io_uring_setup: u64 = 425; export def SYS_io_uring_enter: u64 = 426; export def SYS_io_uring_register: u64 = 427; export def SYS_open_tree: u64 = 428; export def SYS_move_mount: u64 = 429; export def SYS_fsopen: u64 = 430; export def SYS_fsconfig: u64 = 431; export def SYS_fsmount: u64 = 432; export def SYS_fspick: u64 = 433; export def SYS_openat2: u64 = 437; export def SYS_faccessat2: u64 = 439; hare-0.24.2/rt/+linux/syscalls.ha000066400000000000000000000725641464473310100165450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn syscall(num: u64, args: u64...) u64 = { switch (len(args)) { case 0 => return syscall0(num); case 1 => return syscall1(num, args[0]); case 2 => return syscall2(num, args[0], args[1]); case 3 => return syscall3(num, args[0], args[1], args[2]); case 4 => return syscall4(num, args[0], args[1], args[2], args[3]); case 5 => return syscall5(num, args[0], args[1], args[2], args[3], args[4]); case 6 => return syscall6(num, args[0], args[1], args[2], args[3], args[4], args[5]); case => abort("syscalls can't have more than 6 arguments"); }; }; fn syscall0(u64) u64; fn syscall1(u64, u64) u64; fn syscall2(u64, u64, u64) u64; fn syscall3(u64, u64, u64, u64) u64; fn syscall4(u64, u64, u64, u64, u64) u64; fn syscall5(u64, u64, u64, u64, u64, u64) u64; fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64; export def PATH_MAX: size = 4096z; export type path = (str | []u8 | *const u8); let pathbuf: [PATH_MAX]u8 = [0...]; fn copy_kpath(path: path, buf: []u8) (*const u8 | errno) = { let path = match (path) { case let c: *const u8 => return c; case let s: str => let ptr = &s: *struct { buf: *[*]u8, length: size, capacity: size, }; yield ptr.buf[..ptr.length]; case let b: []u8 => yield b; }; if (len(path) + 1 >= len(pathbuf)) { return ENAMETOOLONG; }; memcpy(buf: *[*]u8, path: *[*]u8, len(path)); buf[len(path)] = 0; return buf: *[*]u8: *const u8; }; // NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in // length. fn kpath(path: path) (*const u8 | errno) = { return copy_kpath(path, pathbuf); }; export fn read(fd: int, buf: *opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_read, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_write, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn open(path: path, flags: int, mode: uint) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_openat, AT_FDCWD: u64, path: uintptr: u64, flags: u64, mode: u64))?: int; }; fn openat( dirfd: int, path: path, flags: int, mode: uint, ) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_openat, dirfd: u64, path: uintptr: u64, flags: u64, mode: u64))?: int; }; export fn openat2( dirfd: int, path: path, how: *open_how, how_sz: size, ) (int | errno) = { let path = kpath(path)?; return openat(dirfd, path, how.flags: int, how.mode: uint); }; export fn readlinkat( dirfd: int, path: path, buf: []u8, ) (size | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_readlinkat, dirfd: u64, path: uintptr: u64, buf: *[*]u8: uintptr: u64, len(buf): u64))?: size; }; export fn unlink(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, AT_FDCWD: u64, path: uintptr: u64, 0u64))?; }; export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, dirfd: u64, path: uintptr: u64, flags: u64))?; }; export fn linkat( olddirfd: int, oldpath: path, newdirfd: int, newpath: path, flags: int, ) (void | errno) = { let oldpath = kpath(oldpath)?; static let newpathbuf: [PATH_MAX]u8 = [0...]; let newpath = copy_kpath(newpath, newpathbuf)?; wrap_return(syscall5(SYS_linkat, olddirfd: u64, oldpath: uintptr: u64, newdirfd: u64, newpath: uintptr: u64, flags: u64))?; }; export fn symlinkat( target: path, newdirfd: int, linkpath: path, ) (void | errno) = { let target = kpath(target)?; static let linkpathbuf: [PATH_MAX]u8 = [0...]; let linkpath = copy_kpath(linkpath, linkpathbuf)?; wrap_return(syscall3(SYS_symlinkat, target: uintptr: u64, newdirfd: u64, linkpath: uintptr: u64))?; }; export fn mknodat( dirfd: int, path: path, mode: mode_t, dev: dev_t, ) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_mknodat, dirfd: u64, path: uintptr: u64, mode: u64, dev: u64))?; }; export fn chmod(path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_fchmodat, AT_FDCWD: u64, path: uintptr: u64, mode: u64, 0))?; }; export fn fchmod(fd: int, mode: uint) (void | errno) = { wrap_return(syscall2(SYS_fchmod, fd: u64, mode: u64))?; }; export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_fchmodat, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?; }; export fn chown(path: path, uid: uint, gid: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall5(SYS_fchownat, AT_FDCWD: u64, path: uintptr: u64, uid: u32, gid: u32, 0))?; }; export fn fchown(fd: int, uid: uint, gid: uint) (void | errno) = { wrap_return(syscall3(SYS_fchown, fd: u64, uid: u32, gid: u32))?; }; export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall5(SYS_fchownat, dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?; }; export fn utimensat(dirfd: int, path: str, ts: *[2]timespec, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_utimensat, dirfd: u64, path: uintptr: u64, ts: uintptr: u64, flags: u64))?; }; export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = { wrap_return(syscall4(SYS_utimensat, fd: u64, 0, ts: uintptr: u64, 0))?; }; export fn renameat( olddirfd: int, oldpath: path, newdirfd: int, newpath: path, flags: uint, ) (void | errno) = { let oldpath = kpath(oldpath)?; static let newpathbuf: [PATH_MAX]u8 = [0...]; let newpath = copy_kpath(newpath, newpathbuf)?; wrap_return(syscall5(SYS_renameat2, olddirfd: u64, oldpath: uintptr: u64, newdirfd: u64, newpath: uintptr: u64, flags: u64))?; }; export fn dup(fd: int) (int | errno) = { return wrap_return(syscall1(SYS_dup, fd: u64))?: int; }; export fn dup2(oldfd: int, newfd: int) (int | errno) = { return dup3(oldfd, newfd, 0); }; export fn dup3(oldfd: int, newfd: int, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_dup3, oldfd: u64, newfd: u64, flags: u64))?: int; }; export fn close(fd: int) (void | errno) = { wrap_return(syscall1(SYS_close, fd: u64))?; }; export fn chdir(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?; }; export fn fchdir(fd: int) (void | errno) = { wrap_return(syscall1(SYS_fchdir, fd: u64))?; }; export fn chroot(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?; }; export fn mkdir(path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_mkdirat, AT_FDCWD: u64, path: uintptr: u64, mode: u64))?; }; export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_mkdirat, dirfd: u64, path: uintptr: u64, mode: u64))?; }; export fn execveat(dirfd: int, path: path, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8, flags: int) errno = { let path = kpath(path)?; return match (wrap_return(syscall5(SYS_execveat, dirfd: u64, path: uintptr: u64, argv: uintptr: u64, envp: uintptr: u64, flags: u64))) { case let err: errno => yield err; case u64 => abort("unreachable"); }; }; export fn execve(path: path, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8) errno = { let path = kpath(path)?; return match (wrap_return(syscall3(SYS_execve, path: uintptr: u64, argv: uintptr, envp: uintptr))) { case let err: errno => yield err; case u64 => abort("unreachable"); }; }; // Returns the new PID to the parent, void to the child, or errno if something // goes wrong. export fn fork() (pid_t | void | errno) = { match (clone(null, SIGCHLD, null, null, 0)?) { case let id: int => return id: pid_t; case void => return void; }; }; export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; export fn getpgrp() pid_t = getpgid(0)!; export fn getpgid(pid: pid_t) (pid_t | errno) = { return wrap_return(syscall1(SYS_getpgid, pid: u64))?: pid_t; }; export fn setpgid(pid: pid_t, pgid: pid_t) (void | errno) = { wrap_return(syscall2(SYS_setpgid, pid: u64, pgid: u64))?; }; export fn wait4( pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, ) (pid_t | errno) = { return wrap_return(syscall4(SYS_wait4, pid: u64, wstatus: uintptr: u64, options: u64, rusage: uintptr: u64))?: pid_t; }; export fn sendfile( out: int, in: int, offs: nullable *size, count: size, ) (size | errno) = wrap_return(syscall4(SYS_sendfile, out: u64, in: u64, offs: uintptr: u64, count: u64))?: size; export fn exit(status: int) never = { syscall1(SYS_exit_group, status: u64); abort(); }; export fn kill(pid: pid_t, signal: int) (void | errno) = { wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; }; export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = { wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?; }; export fn mmap( addr: nullable *opaque, length: size, prot: uint, flags: uint, fd: int, offs: size ) (*opaque | errno) = { let r = syscall6(SYS_mmap, addr: uintptr: u64, length: u64, prot: u64, flags: u64, fd: u64, offs: u64); match (wrap_return(r)) { case let err: errno => if (err == -EPERM && addr == null && (flags & MAP_ANON) > 0 && (flags & MAP_FIXED) == 0) { // Fix up incorrect EPERM from kernel: return ENOMEM; }; return err; case let n: u64 => return n: uintptr: *opaque; }; }; export fn mremap( old_addr: *opaque, old_len: size, new_len: size, flags: uint, new_addr: nullable *opaque, ) (*opaque | errno) = { let r = syscall5(SYS_mremap, old_addr: uintptr: u64, old_len: u64, new_len: u64, flags: u64, new_addr: uintptr: u64); return wrap_return(r)?: uintptr: *opaque; }; export fn munmap(addr: *opaque, length: size) (void | errno) = { wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?; }; export fn mprotect(addr: *opaque, length: size, prot: uint) (void | errno) = { wrap_return(syscall3(SYS_mprotect, addr: uintptr: u64, length: u64, prot: u64))?; }; export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = { return wrap_return(syscall3(SYS_lseek, fd: u64, off: u64, whence: u64))?: i64; }; export fn ftruncate(fd: int, ln: off_t) (void | errno) = { wrap_return(syscall2(SYS_ftruncate, fd: u64, ln: u32))?; }; fn faccessat1(dirfd: int, path: *const u8, mode: int) (bool | errno) = { return match (wrap_return(syscall3(SYS_faccessat, dirfd: u64, path: uintptr: u64, mode: u64))) { case let err: errno => yield switch (err) { case EACCES => yield false; case => yield err; }; case let n: u64 => assert(n == 0); yield true; }; }; // The use of this function is discouraged, as it can create race conditions. // TOCTOU is preferred: attempt to simply use the resource you need and handle // any access errors which occur. export fn faccessat( dirfd: int, path: path, mode: int, flags: int, ) (bool | errno) = { let path = kpath(path)?; match (wrap_return(syscall4(SYS_faccessat2, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))) { case let err: errno => switch (err) { case EACCES => return false; case ENOSYS => if (flags == 0) { return faccessat1(dirfd, path, mode); } else { return err; }; case => return err; }; case let n: u64 => assert(n == 0); return true; }; }; export fn getdents64(dirfd: int, dirp: *opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_getdents64, dirfd: u64, dirp: uintptr: u64, count: u64))?: size; }; // The use of this function is discouraged, as it can create race conditions. // TOCTOU is preferred: attempt to simply use the resource you need and handle // any access errors which occur. export fn access(path: path, mode: int) (bool | errno) = faccessat(AT_FDCWD, path, mode, 0); export type fcntl_arg = (void | int | *st_flock | *f_owner_ex | *u64); export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = { let _fd = fd: u64, _cmd = cmd: u64; return wrap_return(match (arg) { case void => yield syscall2(SYS_fcntl, _fd, _cmd); case let i: int => yield syscall3(SYS_fcntl, _fd, _cmd, i: u64); case let l: *st_flock => yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64); case let o: *f_owner_ex => yield syscall3(SYS_fcntl, _fd, _cmd, o: uintptr: u64); case let u: *u64 => yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64); })?: int; }; export fn getrandom(buf: *opaque, bufln: size, flags: uint) (size | errno) = { return wrap_return(syscall3(SYS_getrandom, buf: uintptr: u64, bufln: u64, flags: u64))?: size; }; export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = { wrap_return(syscall2(SYS_clock_gettime, clock_id: u64, tp: uintptr: u64))?; }; export fn clock_settime(clock_id: int, tp: *const timespec) (void | errno) = { wrap_return(syscall2(SYS_clock_settime, clock_id: u64, tp: uintptr: u64))?; }; export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = { wrap_return(syscall2(SYS_nanosleep, req: uintptr: u64, rem: uintptr: u64))?; }; export fn uname(uts: *utsname) (void | errno) = { wrap_return(syscall1(SYS_uname, uts: uintptr: u64))?; }; // The return value is statically allocated and must be duplicated before // calling getcwd again. export fn getcwd() (*const u8 | errno) = { static let pathbuf: [PATH_MAX]u8 = [0...]; wrap_return(syscall2(SYS_getcwd, &pathbuf: *[*]u8: uintptr: u64, PATH_MAX))?; return &pathbuf: *const u8; }; export fn ppoll( fds: *[*]pollfd, nfds: nfds_t, timeout: const nullable *timespec, sigmask: const nullable *sigset, ) (int | errno) = { return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64, timeout: uintptr: u64, sigmask: uintptr: u64))?: int; }; export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = { const ts = timespec { tv_sec = timeout % 1000, tv_nsec = timeout * 1000000, }; return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null); }; export fn epoll_create1(flags: int) (int | errno) = { return wrap_return(syscall1(SYS_epoll_create1, flags: u64))?: int; }; export fn epoll_create(size_: int) (int | errno) = { return epoll_create1(0); }; export fn epoll_ctl( epfd: int, op: int, fd: int, event: nullable *epoll_event ) (void | errno) = { wrap_return(syscall4(SYS_epoll_ctl, epfd: u64, op: u64, fd: u64, event: uintptr: u64))?; }; export fn epoll_pwait( epfd: int, events: *epoll_event, maxevents: int, timeout: int, sigmask: nullable *sigset ) (int | errno) = { return wrap_return(syscall6(SYS_epoll_pwait, epfd: u64, events: uintptr: u64, maxevents: u64, timeout: u64, sigmask: uintptr: u64, size(sigset): u64))?: int; }; export fn epoll_wait( epfd: int, events: *epoll_event, maxevents: int, timeout: int, ) (int | errno) = { return epoll_pwait(epfd, events, maxevents, timeout, null); }; export fn timerfd_create(clock_id: int, flags: int) (int | errno) = { return wrap_return(syscall2(SYS_timerfd_create, clock_id: u64, flags: u64))?: int; }; export fn eventfd(initval: uint, flags: int) (int | errno) = { return wrap_return(syscall2(SYS_eventfd2, initval: u64, flags: u64))?: int; }; export fn timerfd_settime( fd: int, flags: int, new_value: *const itimerspec, old_value: nullable *itimerspec ) (int | errno) = { return wrap_return(syscall4(SYS_timerfd_settime, fd: u64, flags: u64, new_value: uintptr: u64, old_value: uintptr: u64))?: int; }; export fn timerfd_gettime(fd: int, curr_value: *itimerspec) (int | errno) = { return wrap_return(syscall2(SYS_timerfd_gettime, fd: u64, curr_value: uintptr: u64))?: int; }; export fn signalfd(fd: int, mask: *const sigset, flags: int) (int | errno) = { return wrap_return(syscall4(SYS_signalfd4, fd: u64, mask: uintptr: u64, size(sigset): u64, flags: u64))?: int; }; export fn sigprocmask( how: int, set: nullable *const sigset, old: nullable *sigset ) (int | errno) = { return wrap_return(syscall4(SYS_rt_sigprocmask, how: u64, set: uintptr: u64, old: uintptr: u64, size(sigset): u64))?: int; }; fn restore() void; fn restore_si() void; export fn sigaction( signum: int, act: *const sigact, old: nullable *sigact ) (int | errno) = { let real_act = *act; real_act.sa_flags |= SA_RESTORER; let restore_fn = if ((act.sa_flags & SA_SIGINFO) != 0) &restore_si else &restore; real_act.sa_restorer = &restore; return wrap_return(syscall4(SYS_rt_sigaction, signum: u64, &real_act: uintptr: u64, old: uintptr: u64, size(sigset): u64))?: int; }; export fn sigaltstack( ss: nullable *stack_t, old_ss: nullable *stack_t, ) (void | errno) = { wrap_return(syscall2(SYS_sigaltstack, ss: uintptr: u64, old_ss: uintptr: u64))?; }; export fn socket(domain: int, type_: int, protocol: int) (int | errno) = { return wrap_return(syscall3(SYS_socket, domain: u64, type_: u64, protocol: u64))?: int; }; export fn socketpair( domain: int, type_: int, protocol: int, sv: *[2]int ) (int | errno) = { return wrap_return(syscall4(SYS_socketpair, domain: u64, type_: u64, protocol: u64, sv: uintptr : u64))?: int; }; export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_connect, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_bind, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn listen(sockfd: int, backlog: u32) (int | errno) = { return wrap_return(syscall2(SYS_listen, sockfd: u64, backlog: u64))?: int; }; export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_accept, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { return wrap_return(syscall4(SYS_accept4, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int; }; export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int, src_addr: nullable *sockaddr, addrlen: nullable *u32 ) (size | errno) = { return wrap_return(syscall6(SYS_recvfrom, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, src_addr: uintptr: u64, addrlen: uintptr: u64))?: size; }; export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int, dest_addr: nullable *sockaddr, addrlen: u32 ) (size | errno) = { return wrap_return(syscall6(SYS_sendto, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, dest_addr: uintptr: u64, addrlen: u64))?: size; }; export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return recvfrom(sockfd, buf, len_, flags, null, null); }; export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return sendto(sockfd, buf, len_, flags, null, 0); }; export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32) (int | errno) = { return wrap_return(syscall5(SYS_getsockopt, sockfd: u64, level: u64, optname: u64, optval: uintptr: u64, optlen: uintptr: u64))?: int; }; export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = { return wrap_return(syscall5(SYS_setsockopt, sockfd: u64, level: u64, optname: u64, optval: uintptr: u64, optlen: u64))?: int; }; export type ioctl_arg = (nullable *opaque | u64); export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = { let fd = fd: u64, req = req: u64; return wrap_return(match (arg) { case let u: u64 => yield syscall3(SYS_ioctl, fd, req, u); case let v: nullable *opaque => yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64); })?: int; }; export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getsockname, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getpeername, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_readv, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_writev, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_sendmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_recvmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn umask(mode: mode_t) (mode_t | errno) = { return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t; }; export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = { wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?; }; export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = { wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?; }; export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = { wrap_return(syscall3(SYS_getresuid, uid: uintptr: u64, euid: uintptr: u64, suid: uintptr: u64))?; }; export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = { wrap_return(syscall3(SYS_getresgid, gid: uintptr: u64, egid: uintptr: u64, sgid: uintptr: u64))?; }; export fn getgroups(gids: []gid_t) (uint | errno) = { return wrap_return(syscall2(SYS_getgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; }; export fn setgroups(gids: []gid_t) (void | errno) = { wrap_return(syscall2(SYS_setgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; }; export fn getpriority(which: int, who: id_t) (int | errno) = { return wrap_return(syscall2(SYS_setpriority, which: u64, who: u64))?: int; }; export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = { wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?; }; export fn io_uring_setup(entries: u32, params: *io_uring_params) (int | errno) = { return wrap_return(syscall2(SYS_io_uring_setup, entries: u64, params: uintptr: u64))?: int; }; export fn io_uring_register( fd: int, opcode: uint, arg: nullable *opaque, nr_args: uint, ) (int | errno) = wrap_return(syscall4(SYS_io_uring_register, fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?: int; export fn io_uring_enter( fd: int, to_submit: uint, min_complete: uint, flags: uint, sig: const nullable *sigset, ) (uint | errno) = { return wrap_return(syscall5(SYS_io_uring_enter, fd: u64, to_submit: u64, min_complete: u64, flags: u64, sig: uintptr: u64))?: uint; }; export fn io_uring_enter2( fd: int, to_submit: uint, min_complete: uint, flags: uint, arg: const nullable *opaque, argsz: size, ) (uint | errno) = { return wrap_return(syscall6(SYS_io_uring_enter, fd: u64, to_submit: u64, min_complete: u64, flags: u64, arg: uintptr: u64, argsz: u64))?: uint; }; export fn mlock2(addr: *opaque, length: size, flags: uint) (void | errno) = { return wrap_return(syscall3(SYS_mlock2, addr: uintptr: u64, length: u64, flags: u64))?: void; }; export fn munlock(addr: *opaque, length: size) (void | errno) = { return wrap_return(syscall2(SYS_munlock, addr: uintptr: u64, length: u64))?: void; }; export fn mlockall(flags: uint) (void | errno) = { return wrap_return(syscall1(SYS_mlockall, flags: u64))?: void; }; export fn munlockall() (void | errno) = { return wrap_return(syscall0(SYS_munlockall))?: void; }; export fn prctl( option: int, arg2: u64, arg3: u64, arg4: u64, arg5: u64, ) (int | errno) = { return wrap_return(syscall5(SYS_prctl, option: u64, arg2, arg3, arg4, arg5))?: int; }; export fn add_key( keytype: *const u8, name: *const u8, payload: *opaque, plen: size, keyring: int, ) (int | errno) = { return wrap_return(syscall5(SYS_add_key, keytype: uintptr: u64, name: uintptr: u64, payload: uintptr: u64, plen: u64, keyring: u64))?: int; }; export fn keyctl( operation: int, arg2: u64, arg3: u64, arg4: u64, arg5: u64, ) (int | errno) = { return wrap_return(syscall5(SYS_keyctl, operation: u64, arg2, arg3, arg4, arg5))?: int; }; export fn getsid(pid: pid_t) (pid_t | errno) = { return wrap_return(syscall1(SYS_getsid, pid: u64))?: pid_t; }; export fn setsid() (void | errno) = { return wrap_return(syscall0(SYS_setsid))?: void; }; export fn mount( source: path, target: path, filesystemtype: *const u8, mountflags: u64, data: nullable *opaque ) (void | errno) = { let source = kpath(source)?; let target = kpath(target)?; wrap_return(syscall5(SYS_mount, source: uintptr, target: uintptr, filesystemtype: uintptr, mountflags: u64, data: uintptr))?; }; export fn umount2(target: path, flags: int) (void | errno) = { let target = kpath(target)?; wrap_return(syscall2(SYS_umount2, target: uintptr, flags: u64))?; }; export fn ptrace( request: int, pid: pid_t, addr: uintptr, data: uintptr, ) (u64 | errno) = { // PTRACE_PEEK* requests write into *data instead of just returning // the word that they read let result = 0u64; const wrdata = request >= PTRACE_PEEKTEXT && request <= PTRACE_PEEKUSER; if (wrdata) { data = &result: uintptr; }; const ret = wrap_return(syscall4(SYS_ptrace, request: u64, pid: u64, addr, data))?: u64; if (wrdata) { return result; } else { return ret; }; }; export fn sync() void = { wrap_return(syscall0(SYS_sync))!; }; export fn memfd_create(name: path, flags: uint) (int | errno) = { let path = kpath(name)?; return wrap_return(syscall2(SYS_memfd_create, path: uintptr: u64, flags: u64))?: int; }; export fn splice( fd_in: int, off_in: nullable *u64, fd_out: int, off_out: nullable *u64, ln: size, flags: uint, ) (size | errno) = { return wrap_return(syscall6(SYS_splice, fd_in: u64, off_in: uintptr: u64, fd_out: u64, off_out: uintptr: u64, ln: u64, flags: u64))?: size; }; export fn tee(fd_in: int, fd_out: int, ln: size, flags: uint) (size | errno) = { return wrap_return(syscall4(SYS_tee, fd_in: u64, fd_out: u64, ln: u64, flags: u64))?: size; }; export fn fallocate(fd: int, mode: int, off: i64, ln: i64) (void | errno) = { wrap_return(syscall4(SYS_fallocate, fd: u64, mode: u64, off: u64, ln: u64))?; }; export fn posix_fallocate(fd: int, off: i64, ln: i64) (void | errno) = { fallocate(fd, 0, off, ln)?; }; export fn flock(fd: int, op: int) (void | errno) = { wrap_return(syscall2(SYS_flock, fd: u64, op: u64))?; }; export def NAME_MAX: size = 255z; export def INOTIFY_EVENT_MAX_SIZE: size = size(int) + size(u32)*3 + NAME_MAX + 1z; export fn inotify_init() (int | errno) = { return wrap_return(syscall1(SYS_inotify_init1, 0))?: int; }; export fn inotify_init1(flags: int) (int | errno) = { return wrap_return(syscall1(SYS_inotify_init1, flags: u64))?: int; }; export fn inotify_add_watch(fd: int, path: path, mask: u32) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall3(SYS_inotify_add_watch, fd: u64, path: uintptr: u64, mask))?: int; }; export fn inotify_rm_watch(fd: int, wd: int) (int | errno) = { return wrap_return(syscall2(SYS_inotify_rm_watch, fd: u64, wd: u64))?: int; }; export type inotify_event = struct { wd: int, mask: u32, cookie: u32, length: u32, name: [*]u8, }; export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = { return syscall3(SYS_shmat, id: u64, addr: uintptr: u64, flag: u64): uintptr: *opaque; }; export fn sched_getaffinity( pid: pid_t, cpusetsize: size, mask: *cpu_set, ) (void | errno) = { wrap_return(syscall3(SYS_sched_getaffinity, pid: u64, cpusetsize: u64, mask: uintptr: u64))?; }; export fn sched_setaffinity( pid: pid_t, cpusetsize: size, mask: *const cpu_set, ) (void | errno) = { wrap_return(syscall3(SYS_sched_setaffinity, pid: u64, cpusetsize: u64, mask: uintptr: u64))?; }; export fn getrlimit(resource: int, rlim: *rlimit) (void | errno) = { wrap_return(syscall2(SYS_getrlimit, resource: u64, rlim: uintptr: u64))?; }; export fn setrlimit(resource: int, rlim: *const rlimit) (void | errno) = { wrap_return(syscall2(SYS_setrlimit, resource: u64, rlim: uintptr: u64))?; }; export fn shutdown(sockfd: int, how: int) (void | errno) = { wrap_return(syscall2(SYS_shutdown, sockfd: u64, how: u64))?; }; // Sets an extended file attribute. export fn setxattr( path: path, name: str, value: []u8, flags: int = 0 ) (void | errno) = { let path = kpath(path)?; static let namebuf: [PATH_MAX]u8 = [0...]; let name = copy_kpath(name, namebuf)?; wrap_return(syscall5(SYS_setxattr, path: uintptr: u64, name: uintptr: u64, value: *[*]u8: uintptr: u64, len(value): u64, flags: u64 ))?; }; // Gets an extended file attribute. export fn getxattr(path: path, name: str, value: []u8) (u64 | errno) = { let path = kpath(path)?; static let namebuf: [PATH_MAX]u8 = [0...]; let name = copy_kpath(name, namebuf)?; return wrap_return(syscall4(SYS_getxattr, path: uintptr, name: uintptr, value: *[*]u8: uintptr: u64, len(value): u64, )); }; // Removes an extended file attribute. export fn removexattr(path: path, name: str) (void | errno) = { let path = kpath(path)?; static let namebuf: [PATH_MAX]u8 = [0...]; let name = copy_kpath(name, namebuf)?; wrap_return(syscall2(SYS_removexattr, path: uintptr, name: uintptr))?; }; hare-0.24.2/rt/+linux/types.ha000066400000000000000000001027751464473310100160520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type off_t = i64; export type dev_t = u64; export type ino_t = u64; export type nlink_t = u64; export type mode_t = uint; export type id_t = uint; export type uid_t = uint; export type gid_t = uint; export type time_t = i64; export type suseconds_t = i64; export type nfds_t = u64; export type pid_t = int; export type timer_t = *opaque; export type clock_t = i64; export type si_band_t = i64; export type rlim_t = u64; export def NGROUPS_MAX: size = 32; export def NSIG: int = 64; export type sigset = struct { __val: [1]u64, }; export type timeval = struct { tv_sec: time_t, tv_usec: suseconds_t, }; export type timespec = struct { tv_sec: time_t, tv_nsec: i64, }; export def UTIME_OMIT = 0x3ffffffe; export type itimerspec = struct { it_interval: timespec, it_value: timespec, }; export def AT_FDCWD: int = -100; export def AT_SYMLINK_NOFOLLOW: int = 0x100; export def AT_REMOVEDIR: int = 0x200; export def AT_SYMLINK_FOLLOW: int = 0x400; export def AT_EACCESS: int = 0x200; export def AT_NO_AUTOMOUNT: int = 0x800; export def AT_EMPTY_PATH: int = 0x1000; export def AT_STATX_SYNC_TYPE: int = 0x6000; export def AT_STATX_SYNC_AS_STAT: int = 0x0000; export def AT_STATX_FORCE_SYNC: int = 0x2000; export def AT_STATX_DONT_SYNC: int = 0x4000; export def AT_RECURSIVE: int = 0x8000; export def S_IFDIR: mode_t = 0o040000; export def S_IFCHR: mode_t = 0o020000; export def S_IFBLK: mode_t = 0o060000; export def S_IFREG: mode_t = 0o100000; export def S_IFIFO: mode_t = 0o010000; export def S_IFLNK: mode_t = 0o120000; export def S_IFSOCK: mode_t = 0o140000; // O_DIRECTORY is arch specific export def O_RDONLY: int = 0o0; export def O_WRONLY: int = 0o1; export def O_RDWR: int = 0o2; export def O_ACCMODE: int = 0o3; export def O_CREATE: int = 0o100; export def O_EXCLUSIVE: int = 0o200; export def O_NOCTTY: int = 0o400; export def O_TRUNC: int = 0o1000; export def O_APPEND: int = 0o2000; export def O_NONBLOCK: int = 0o4000; export def O_DSYNC: int = 0o10000; export def O_SYNC: int = 0o4010000; export def O_RSYNC: int = 0o4010000; export def O_NOFOLLOW: int = 0o400000; export def O_NOATIME: int = 0o1000000; export def O_CLOEXEC: int = 0o2000000; export def O_PATH: int = 0o10000000; export def O_TMPFILE: int = 0o20000000; type statx_timestamp = struct { tv_sec: i64, tv_nsec: u32, }; type stx = struct { mask: u32, blksize: u32, attributes: u64, nlink: u32, uid: u32, gid: u32, mode: u16, ino: u64, sz: u64, blocks: u64, attr_mask: u64, atime: statx_timestamp, btime: statx_timestamp, ctime: statx_timestamp, mtime: statx_timestamp, rdev_major: u32, rdev_minor: u32, dev_major: u32, dev_minor: u32, __reserved: [14]u64, }; // Note: the st type does not match the kernel API. The kernel API has a stat // buffer which varies from arch to arch, but because we always use statx(2) and // copy the data from the stx type, we don't have to deal with that nonsense. export type st = struct { dev: dev_t, ino: ino_t, mode: mode_t, nlink: nlink_t, uid: uid_t, gid: gid_t, rdev: dev_t, sz: u64, blksz: u64, blocks: u64, atime: timespec, mtime: timespec, ctime: timespec, }; def STATX_TYPE: uint = 0x00000001; def STATX_MODE: uint = 0x00000002; def STATX_NLINK: uint = 0x00000004; def STATX_UID: uint = 0x00000008; def STATX_GID: uint = 0x00000010; def STATX_ATIME: uint = 0x00000020; def STATX_MTIME: uint = 0x00000040; def STATX_CTIME: uint = 0x00000080; def STATX_INO: uint = 0x00000100; def STATX_SIZE: uint = 0x00000200; def STATX_BLOCKS: uint = 0x00000400; def STATX_BASIC_STATS: uint = 0x000007FF; def STATX_BTIME: uint = 0x00000800; def STATX_MNT_ID: uint = 0x00001000; export def SIGHUP: int = 1; export def SIGINT: int = 2; export def SIGQUIT: int = 3; export def SIGILL: int = 4; export def SIGTRAP: int = 5; export def SIGABRT: int = 6; export def SIGBUS: int = 7; export def SIGFPE: int = 8; export def SIGKILL: int = 9; export def SIGUSR1: int = 10; export def SIGSEGV: int = 11; export def SIGUSR2: int = 12; export def SIGPIPE: int = 13; export def SIGALRM: int = 14; export def SIGTERM: int = 15; export def SIGSTKFLT: int = 16; export def SIGCHLD: int = 17; export def SIGCONT: int = 18; export def SIGSTOP: int = 19; export def SIGTSTP: int = 20; export def SIGTTIN: int = 21; export def SIGTTOU: int = 22; export def SIGURG: int = 23; export def SIGXCPU: int = 24; export def SIGXFSZ: int = 25; export def SIGVTALRM: int = 26; export def SIGPROF: int = 27; export def SIGWINCH: int = 28; export def SIGIO: int = 29; export def SIGPOLL: int = 29; export def SIGPWR: int = 30; export def SIGSYS: int = 31; export def MAP_SHARED: uint = 0x01; export def MAP_PRIVATE: uint = 0x02; export def MAP_SHARED_VALIDATE: uint = 0x03; export def MAP_FIXED: uint = 0x10; export def MAP_ANON: uint = 0x20; export def MAP_NORESERVE: uint = 0x4000; export def MAP_GROWSDOWN: uint = 0x0100; export def MAP_DENYWRITE: uint = 0x0800; export def MAP_EXECUTABLE: uint = 0x1000; export def MAP_LOCKED: uint = 0x2000; export def MAP_POPULATE: uint = 0x8000; export def MAP_NONBLOCK: uint = 0x10000; export def MAP_STACK: uint = 0x20000; export def MAP_HUGETLB: uint = 0x40000; export def MAP_SYNC: uint = 0x80000; export def MAP_FIXED_NOREPLACE: uint = 0x100000; export def MAP_FILE: uint = 0; export def MAP_HUGE_SHIFT: uint = 26; export def MAP_HUGE_MASK: uint = 0x3F; export def MAP_HUGE_64KB: uint = 16 << 26; export def MAP_HUGE_512KB: uint = 19 << 26; export def MAP_HUGE_1MB: uint = 20 << 26; export def MAP_HUGE_2MB: uint = 21 << 26; export def MAP_HUGE_8MB: uint = 23 << 26; export def MAP_HUGE_16MB: uint = 24 << 26; export def MAP_HUGE_32MB: uint = 25 << 26; export def MAP_HUGE_256MB: uint = 28 << 26; export def MAP_HUGE_512MB: uint = 29 << 26; export def MAP_HUGE_1GB: uint = 30 << 26; export def MAP_HUGE_2GB: uint = 31 << 26; export def MAP_HUGE_16GB: uint = 34 << 26; export def PROT_NONE: uint = 0; export def PROT_READ: uint = 1; export def PROT_WRITE: uint = 2; export def PROT_EXEC: uint = 4; export def PROT_GROWSDOWN: uint = 0x01000000; export def PROT_GROWSUP: uint = 0x02000000; export def F_OK: int = 0; export def R_OK: int = 4; export def W_OK: int = 2; export def X_OK: int = 1; export def F_DUPFD: int = 0; export def F_DUPFD_CLOEXEC: int = 1030; export def F_GETFD: int = 1; export def F_SETFD: int = 2; export def F_GETFL: int = 3; export def F_SETFL: int = 4; export def F_SETOWN: int = 8; export def F_GETOWN: int = 9; export def F_SETSIG: int = 10; export def F_GETSIG: int = 11; export def F_GETLK: int = 12; export def F_SETLK: int = 13; export def F_SETLKW: int = 14; export def F_SETOWN_EX: int = 15; export def F_GETOWN_EX: int = 16; export def F_GETOWNER_UIDS: int = 17; export def F_RDLCK: i16 = 0; export def F_WRLCK: i16 = 1; export def F_UNLCK: i16 = 2; export def FD_CLOEXEC: int = 1; export type st_flock = struct { l_type: i16, l_whence: i16, l_start: i64, l_len: i64, pid: int, }; export type f_owner_ex = struct { _type: int, pid: int, }; export def CLOCK_REALTIME: int = 0; export def CLOCK_MONOTONIC: int = 1; export def CLOCK_PROCESS_CPUTIME_ID: int = 2; export def CLOCK_THREAD_CPUTIME_ID: int = 3; export def CLOCK_MONOTONIC_RAW: int = 4; export def CLOCK_REALTIME_COARSE: int = 5; export def CLOCK_MONOTONIC_COARSE: int = 6; export def CLOCK_BOOTTIME: int = 7; export def CLOCK_REALTIME_ALARM: int = 8; export def CLOCK_BOOTTIME_ALARM: int = 9; export def CLOCK_SGI_CYCLE: int = 10; export def CLOCK_TAI: int = 11; export type open_how = struct { flags: u64, mode: u64, resolve: u64, }; export def RESOLVE_NO_XDEV: u64 = 0x01; export def RESOLVE_NO_MAGICLINKS: u64 = 0x02; export def RESOLVE_NO_SYMLINKS: u64 = 0x04; export def RESOLVE_BENEATH: u64 = 0x08; export def RESOLVE_IN_ROOT: u64 = 0x10; export def DT_UNKNOWN: u8 = 0; export def DT_FIFO: u8 = 1; export def DT_CHR: u8 = 2; export def DT_DIR: u8 = 4; export def DT_BLK: u8 = 6; export def DT_REG: u8 = 8; export def DT_LNK: u8 = 10; export def DT_SOCK: u8 = 12; export type dirent64 = struct { d_ino: ino_t, d_off: off_t, d_reclen: u16, d_type: u8, d_name: [*]u8, }; export def WNOHANG: int = 1; export def WUNTRACED: int = 2; export def WSTOPPED: int = 2; export def WEXITED: int = 4; export def WCONTINUED: int = 8; export def WNOWAIT: int = 0x1000000; export fn wexitstatus(s: int) int = (s & 0xff00) >> 8; export fn wtermsig(s: int) int = s & 0x7f; export fn wstopsig(s: int) int = wexitstatus(s); export fn wcoredump(s: int) int = s & 0x80; export fn wifexited(s: int) bool = wtermsig(s) <= 0; export fn wifstopped(s: int) bool = (((s & 0xFFFF) * 0x10001) >> 8) > 0x7f00; export fn wifsignaled(s: int) bool = (s & 0xFFFF) - 1 < 0xFF; export fn wifcontinued(s: int) bool = s == 0xFFFF; export type rusage = struct { ru_utime: timeval, ru_stime: timeval, ru_maxrss: u64, ru_ixrss: u64, ru_idrss: u64, ru_isrss: u64, ru_minflt: u64, ru_majflt: u64, ru_nswap: u64, ru_inblock: u64, ru_oublock: u64, ru_msgsnd: u64, ru_msgrcv: u64, ru_nsignals: u64, ru_nvcsw: u64, ru_nivcsw: u64, __reserved: [16]u64, }; export type utsname = struct { sysname: [65]u8, nodename: [65]u8, release: [65]u8, version: [65]u8, machine: [65]u8, domainname: [65]u8, }; export def POLLIN: i16 = 0x001; export def POLLPRI: i16 = 0x002; export def POLLOUT: i16 = 0x004; export def POLLERR: i16 = 0x008; export def POLLHUP: i16 = 0x010; export def POLLVAL: i16 = 0x020; export type pollfd = struct { fd: int, events: i16, revents: i16, }; export def EPOLL_CLOEXEC: int = O_CLOEXEC; // Valid opcodes to issue to sys_epoll_ctl() export def EPOLL_CTL_ADD: int = 1; export def EPOLL_CTL_DEL: int = 2; export def EPOLL_CTL_MOD: int = 3; // Epoll event masks export def EPOLLIN: u32 = 0x00000001; export def EPOLLPRI: u32 = 0x00000002; export def EPOLLOUT: u32 = 0x00000004; export def EPOLLERR: u32 = 0x00000008; export def EPOLLHUP: u32 = 0x00000010; export def EPOLLNVAL: u32 = 0x00000020; export def EPOLLRDNORM: u32 = 0x00000040; export def EPOLLRDBAND: u32 = 0x00000080; export def EPOLLWRNORM: u32 = 0x00000100; export def EPOLLWRBAND: u32 = 0x00000200; export def EPOLLMSG: u32 = 0x00000400; export def EPOLLRDHUP: u32 = 0x00002000; export def EPOLLWAKEUP: u32 = 1 << 29; export def EPOLLONESHOT: u32 = 1 << 30; export def EPOLLET: u32 = 1 << 31; export type epoll_data = union { ptr: *opaque, fd: int, u32_: u32, u64_: u64, }; export def EFD_CLOEXEC: int = O_CLOEXEC; export def EFD_NONBLOCK: int = O_NONBLOCK; export def EFD_SEMAPHORE: int = 1; export def TFD_CLOEXEC: int = O_CLOEXEC; export def TFD_NONBLOCK: int = O_NONBLOCK; export def TFD_TIMER_ABSTIME: int = 1; export def TFD_TIMER_CANCEL_ON_SET: int = 2; export def SIG_BLOCK: int = 0; export def SIG_UNBLOCK: int = 1; export def SIG_SETMASK: int = 2; def SI_MAX_SIZE: size = 128; export type sigval = union { sival_t: int, sival_ptr: *opaque, }; export type siginfo = union { struct { si_signo: int, si_errno: int, si_code: int, union { // kill() struct { si_pid: pid_t, si_uid: u32, }, // POSIX.1b timers struct { si_tid: timer_t, si_overrun: int, _sigval: sigval, // @ signals si_sys_private: int, }, // POSIX.1b signals struct { _sig_pid: pid_t, // @kill _sig_uid: u32, // @ kill union { si_value: sigval, si_int: int, si_ptr: *opaque, } }, // SIGCHLD struct { _chld_pid: pid_t, // @ kill _chld_uid: u32, // @ kill si_status: int, si_utime: clock_t, si_stime: clock_t, }, // SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT struct { si_addr: *opaque, union { // used when si_code=BUS_MCEERR_AR or // used when si_code=BUS_MCEERR_AO si_addr_lsb: i16, struct { _dummy_bnd: [__ADDR_BND_PKEY_PAD]u8, si_lower: *opaque, si_upper: *opaque, }, struct { _dummy_pkey: [__ADDR_BND_PKEY_PAD]u8, si_pkey: u32, }, }, }, // SIGPOLL struct { si_band: si_band_t, si_fd: int, }, // SIGSYS struct { si_call_addr: *opaque, si_syscall: int, si_arch: uint, }, }, }, _si_pad: [SI_MAX_SIZE - 3 * size(int)]u8, }; export def SA_NOCLDSTOP: u64 = 0x00000001; export def SA_NOCLDWAIT: u64 = 0x00000002; export def SA_SIGINFO: u64 = 0x00000004; export def SA_ONSTACK: u64 = 0x08000000; export def SA_RESTART: u64 = 0x10000000; export def SA_NODEFER: u64 = 0x40000000; export def SA_RESETHAND: u64 = 0x80000000; export def SA_NOMASK: u64 = SA_NODEFER; export def SA_ONESHOT: u64 = SA_RESETHAND; export def SA_RESTORER: u64 = 0x04000000; export def SIG_ERR: uintptr = -1; export def SIG_DFL: uintptr = 0; export def SIG_IGN: uintptr = 1; export def SIG_HOLD: uintptr = 2; export type sigact = struct { union { sa_handler: *fn (int) void, sa_sigaction: *fn (int, *siginfo, *opaque) void, }, sa_flags: u64, sa_restorer: *fn () void, sa_mask: sigset, }; export type stack_t = struct { ss_sp: *opaque, ss_flags: int, ss_size: size, }; export def SFD_NONBLOCK: int = O_NONBLOCK; export def SFD_CLOEXEC: int = O_CLOEXEC; export type signalfd_siginfo = struct { ssi_signo: u32, ssi_errno: i32, ssi_code: i32, ssi_pid: u32, ssi_uid: u32, ssi_fd: i32 , ssi_tid: u32, ssi_band: u32, ssi_overrun: u32, ssi_trapno: u32, ssi_status: i32, ssi_int: i32, ssi_ptr: u64, ssi_utime: u64, ssi_stime: u64, ssi_addr: u64, ssi_addr_lsb: u16, __pad2: u16, ssi_syscall: i32, ssi_call_addr: u64, ssi_arch: u32, __pad: [28]u8, // pad to 128 bytes }; export type iovec = struct { iov_base: *opaque, iov_len: size }; export def PRIO_PROCESS: int = 0; export def PRIO_PGRP: int = 1; export def PRIO_USER: int = 2; export type winsize = struct { ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, }; export type termios = struct { c_iflag: tcflag, c_oflag: tcflag, c_cflag: tcflag, c_lflag: tcflag, c_line: cc, c_cc: [NCCS]cc, }; export def NCCS: size = 19; export type cc = enum u8 { VINTR = 0, VQUIT = 1, VERASE = 2, VKILL = 3, VEOF = 4, VTIME = 5, VMIN = 6, VSWTC = 7, VSTART = 8, VSTOP = 9, VSUSP = 10, VEOL = 11, VREPRINT = 12, VDISCARD = 13, VWERASE = 14, VLNEXT = 15, VEOL2 = 16, }; export type tcflag = enum uint { // c_iflag bit meaning IGNBRK = 0o00001, BRKINT = 0o00002, IGNPAR = 0o00004, PARMRK = 0o00010, INPCK = 0o00020, ISTRIP = 0o00040, INLCR = 0o00100, IGNCR = 0o00200, ICRNL = 0o00400, IUCLC = 0o01000, IXON = 0o02000, IXANY = 0o04000, IXOFF = 0o10000, IMAXBEL = 0o20000, IUTF8 = 0o40000, // c_oflag bit meaning OPOST = 0o000001, OLCUC = 0o000002, ONLCR = 0o000004, OCRNL = 0o000010, ONOCR = 0o000020, ONLRET = 0o000040, OFILL = 0o000100, OFDEL = 0o000200, NLDLY = 0o000400, NL0 = 0o000000, NL1 = 0o000400, CRDLY = 0o003000, CR0 = 0o000000, CR1 = 0o001000, CR2 = 0o002000, CR3 = 0o003000, TABDLY = 0o014000, TAB0 = 0o000000, TAB1 = 0o004000, TAB2 = 0o010000, TAB3 = 0o014000, XTABS = 0o014000, BSDLY = 0o020000, BS0 = 0o000000, BS1 = 0o020000, VTDLY = 0o040000, VT0 = 0o000000, VT1 = 0o040000, FFDLY = 0o100000, FF0 = 0o000000, FF1 = 0o100000, // c_cflag bit meaning CBAUD = 0o010017, B0 = 0o000000, B50 = 0o000001, B75 = 0o000002, B110 = 0o000003, B134 = 0o000004, B150 = 0o000005, B200 = 0o000006, B300 = 0o000007, B600 = 0o000010, B1200 = 0o000011, B1800 = 0o000012, B2400 = 0o000013, B4800 = 0o000014, B9600 = 0o000015, B19200 = 0o000016, B38400 = 0o000017, EXTA = B19200, EXTB = B38400, CSIZE = 0o000060, CS5 = 0o000000, CS6 = 0o000020, CS7 = 0o000040, CS8 = 0o000060, CSTOPB = 0o000100, CREAD = 0o000200, PARENB = 0o000400, PARODD = 0o001000, HUPCL = 0o002000, CLOCAL = 0o004000, CBAUDEX = 0o010000, BOTHER = 0o010000, B57600 = 0o010001, B115200 = 0o010002, B230400 = 0o010003, B460800 = 0o010004, B500000 = 0o010005, B576000 = 0o010006, B921600 = 0o010007, B1000000 = 0o010010, B1152000 = 0o010011, B1500000 = 0o010012, B2000000 = 0o010013, B2500000 = 0o010014, B3000000 = 0o010015, B3500000 = 0o010016, B4000000 = 0o010017, CIBAUD = 0o02003600000, CMSPAR = 0o10000000000, CRTSCTS = 0o20000000000, // c_lflag bit meaning ISIG = 0o000001, ICANON = 0o000002, XCASE = 0o000004, ECHO = 0o000010, ECHOE = 0o000020, ECHOK = 0o000040, ECHONL = 0o000100, NOFLSH = 0o000200, TOSTOP = 0o000400, ECHOCTL = 0o001000, ECHOPRT = 0o002000, ECHOKE = 0o004000, FLUSHO = 0o010000, PENDIN = 0o040000, IEXTEN = 0o100000, EXTPROC = 0o200000, }; export def TIOCSPGRP: u64 = 0x5410; export def TIOCGWINSZ: u64 = 0x5413; export def TIOCSWINSZ: u64 = 0x5414; export def TIOCSCTTY: u64 = 0x540e; export def TIOCNOTTY: u64 = 0x5422; export def TIOCGPTN: u64 = 0x80045430; export def TIOCGPTPEER: u64 = 0x5441; export def TIOCSPTLCK: u64 = 0x40045431; export def TCGETS: u64 = 0x5401; export def TCSETS: u64 = 0x5402; export def MLOCK_ONFAULT: uint = 0x01; export def MCL_CURRENT: uint = 1; export def MCL_FUTURE: uint = 2; export def MCL_ONFAULT: uint = 4; export def PTRACE_TRACEME: int = 0; export def PTRACE_PEEKTEXT: int = 1; export def PTRACE_PEEKDATA: int = 2; export def PTRACE_PEEKUSER: int = 3; export def PTRACE_POKETEXT: int = 4; export def PTRACE_POKEDATA: int = 5; export def PTRACE_POKEUSER: int = 6; export def PTRACE_CONT: int = 7; export def PTRACE_KILL: int = 8; export def PTRACE_SINGLESTEP: int = 9; export def PTRACE_GETREGS: int = 12; export def PTRACE_SETREGS: int = 13; export def PTRACE_GETFPREGS: int = 14; export def PTRACE_SETFPREGS: int = 15; export def PTRACE_ATTACH: int = 16; export def PTRACE_DETACH: int = 17; export def PTRACE_GETFPXREGS: int = 18; export def PTRACE_SETFPXREGS: int = 19; export def PTRACE_SYSCALL: int = 24; export def PTRACE_SETOPTIONS: int = 0x4200; export def PTRACE_GETEVENTMSG: int = 0x4201; export def PTRACE_GETSIGINFO: int = 0x4202; export def PTRACE_SETSIGINFO: int = 0x4203; export def PTRACE_GETREGSET: int = 0x4204; export def PTRACE_SETREGSET: int = 0x4205; export def PTRACE_SEIZE: int = 0x4206; export def PTRACE_INTERRUPT: int = 0x4207; export def PTRACE_LISTEN: int = 0x4208; export def PTRACE_PEEKSIGINFO: int = 0x4209; export def PTRACE_GETSIGMASK: int = 0x420a; export def PTRACE_SETSIGMASK: int = 0x420b; export def PTRACE_SECCOMP_GET_FILTER: int = 0x420c; export def PTRACE_SECCOMP_GET_METADATA: int = 0x420d; export def PTRACE_GET_SYSCALL_INFO: int = 0x420e; export def PTRACE_GET_RSEQ_CONFIGURATION: int = 0x420f; export def PTRACE_O_TRACESYSGOOD: u64 = 0x00000001; export def PTRACE_O_TRACEFORK: u64 = 0x00000002; export def PTRACE_O_TRACEVFORK: u64 = 0x00000004; export def PTRACE_O_TRACECLONE: u64 = 0x00000008; export def PTRACE_O_TRACEEXEC: u64 = 0x00000010; export def PTRACE_O_TRACEVFORKDONE: u64 = 0x00000020; export def PTRACE_O_TRACEEXIT: u64 = 0x00000040; export def PTRACE_O_TRACESECCOMP: u64 = 0x00000080; export def PTRACE_O_EXITKILL: u64 = 0x00100000; export def PTRACE_O_SUSPEND_SECCOMP: u64 = 0x00200000; export def PTRACE_O_MASK: u64 = 0x003000ff; export def PTRACE_EVENT_FORK: int = 1; export def PTRACE_EVENT_VFORK: int = 2; export def PTRACE_EVENT_CLONE: int = 3; export def PTRACE_EVENT_EXEC: int = 4; export def PTRACE_EVENT_VFORK_DONE: int = 5; export def PTRACE_EVENT_EXIT: int = 6; export def PTRACE_EVENT_SECCOMP: int = 7; export def PTRACE_EVENT_STOP: int = 128; export def PTRACE_SYSCALL_INFO_NONE: u8 = 0; export def PTRACE_SYSCALL_INFO_ENTRY: u8 = 1; export def PTRACE_SYSCALL_INFO_EXIT: u8 = 2; export def PTRACE_SYSCALL_INFO_SECCOMP: u8 = 3; export def PTRACE_PEEKSIGINFO_SHARED: u32 = 1; export type ptrace_peeksiginfo_args = struct { off: u64, flags: u32, nr: i32, }; export type ptrace_syscall_info = struct { op: u8, arch: u32, instruction_pointer: u64, stack_pointer: u64, union { entry: struct { nr: u64, args: [6]u64, }, exit: struct { rval: i64, is_error: u8, }, seccomp: struct { nr: u64, args: [6]u64, ret_data: u64, }, }, }; export def STDIN_FILENO: int = 0; export def STDOUT_FILENO: int = 1; export def STDERR_FILENO: int = 2; export def MFD_CLOEXEC: uint = 1; export def MFD_ALLOW_SEALING: uint = 2; export def MFD_HUGETLB: uint = 4; export def SPLICE_F_MOVE: uint = 1; export def SPLICE_F_NONBLOCK: uint = 2; export def SPLICE_F_MORE: uint = 4; export def SPLICE_F_GIFT: uint = 8; export def SEEK_SET: int = 0; export def SEEK_CUR: int = 1; export def SEEK_END: int = 2; // Flock operations export def LOCK_SH: int = 1; export def LOCK_EX: int = 2; export def LOCK_NB: int = 4; export def LOCK_UN: int = 8; // Inotify init1 flags export def IN_NONBLOCK: int = O_NONBLOCK; export def IN_CLOEXEC: int = O_CLOEXEC; // Inotify event masks export def INACCESS: u32 = 0x00000001; export def INMODIFY: u32 = 0x00000002; export def INATTRIB: u32 = 0x00000004; export def INCLOSEWRITE: u32 = 0x00000008; export def INCLOSENOWRITE: u32 = 0x00000010; export def INOPEN: u32 = 0x00000020; export def INMOVEDFROM: u32 = 0x00000040; export def INMOVEDTO: u32 = 0x00000080; export def INCREATE: u32 = 0x00000100; export def INDELETE: u32 = 0x00000200; export def INDELETESELF: u32 = 0x00000400; export def INMOVESELF: u32 = 0x00000800; export def INONLYDIR: u32 = 0x01000000; export def INDONTFOLLOW: u32 = 0x02000000; export def INEXCLUNLINK: u32 = 0x04000000; export def INMASKCREATE: u32 = 0x10000000; export def INMASKADD: u32 = 0x20000000; export def INISDIR: u32 = 0x40000000; export def INONESHOT: u32 = 0x80000000; export def INUNMOUNT: u32 = 0x00002000; export def INQOVERFLOW: u32 = 0x00004000; export def INIGNORED: u32 = 0x00008000; export def INMOVE: u32 = INMOVEDFROM | INMOVEDTO; export def INCLOSE: u32 = INCLOSEWRITE | INCLOSENOWRITE; export type rlimit = struct { rlim_cur: rlim_t, rlim_max: rlim_t, }; export def RLIM_INFINITY: rlim_t = -1; export def RLIMIT_CPU: int = 0; export def RLIMIT_FSIZE: int = 1; export def RLIMIT_DATA: int = 2; export def RLIMIT_STACK: int = 3; export def RLIMIT_CORE: int = 4; export def RLIMIT_RSS: int = 5; export def RLIMIT_NPROC: int = 6; export def RLIMIT_NOFILE: int = 7; export def RLIMIT_MEMLOCK: int = 8; export def RLIMIT_AS: int = 9; export def RLIMIT_LOCKS: int = 10; export def RLIMIT_SIGPENDING: int = 11; export def RLIMIT_MSGQUEUE: int = 12; export def RLIMIT_NICE: int = 13; export def RLIMIT_RTPRIO: int = 14; export def RLIMIT_RTTIME: int = 15; export def RLIMIT_NLIMITS: int = 16; export def SHUT_RD: int = 0; export def SHUT_WR: int = 1; export def SHUT_RDWR: int = 2; export type io_uring_sqe = struct { opcode: u8, flags: u8, ioprio: u16, fd: i32, union { off: u64, addr2: u64, struct { cmd_op: u32, __pad1: u32, }, }, union { addr: u64, splice_off_in: u64, }, length: u32, union { rw_flags: int, fsync_flags: u32, poll_events: u32, poll32_events: u32, sync_range_flags: u32, msg_flags: u32, timeout_flags: u32, accept_flags: u32, cancel_flags: u32, open_flags: u32, statx_flags: u32, fadvise_advice: u32, splice_flags: u32, rename_flags: u32, unlink_flags: u32, hardlink_flags: u32, xattr_flags: u32, msg_ring_flags: u32, uring_cmd_flags: u32, }, user_data: u64, // TODO: use @packed once size() stop returning different sizes union { buf_index: u16, buf_group: u16, }, personality: u16, union { splice_fd_in: i32, file_index: u32, struct { addr_len: u16, __pad3: [1]u16, }, }, union { struct { addr3: u64, __pad2: [1]u64, }, cmd: [*]u8, }, }; export def IORING_FILE_INDEX_ALLOC: u32 = ~0; export def IOSQE_FIXED_FILE: u8 = 1 << 0; export def IOSQE_IO_DRAIN: u8 = 1 << 1; export def IOSQE_IO_LINK: u8 = 1 << 2; export def IOSQE_IO_HARDLINK: u8 = 1 << 3; export def IOSQE_ASYNC: u8 = 1 << 4; export def IOSQE_BUFFER_SELECT: u8 = 1 << 5; export def IOSQE_CQE_SKIP_SUCCESS: u8 = 1 << 6; export def IORING_SETUP_IOPOLL: u32 = 1 << 0; export def IORING_SETUP_SQPOLL: u32 = 1 << 1; export def IORING_SETUP_SQ_AFF: u32 = 1 << 2; export def IORING_SETUP_CQSIZE: u32 = 1 << 3; export def IORING_SETUP_CLAMP: u32 = 1 << 4; export def IORING_SETUP_ATTACH_WQ: u32 = 1 << 5; export def IORING_SETUP_R_DISABLED: u32 = 1 << 6; export def IORING_SETUP_SUBMIT_ALL: u32 = 1 << 7; export def IORING_SETUP_COOP_TASKRUN: u32 = 1 << 8; export def IORING_SETUP_TASKRUN_FLAG: u32 = 1 << 9; export def IORING_SETUP_SQE128: u32 = 1 << 10; export def IORING_SETUP_CQE32: u32 = 1 << 11; export def IORING_SETUP_SINGLE_ISSUER: u32 = 1 << 12; export def IORING_SETUP_DEFER_TASKRUN: u32 = 1 << 13; export def IORING_SETUP_NO_MMAP: u32 = 1 << 14; export def IORING_SETUP_REGISTERED_FD_ONLY: u32 = 1 << 15; export def IORING_OP_NOP: u8 = 0; export def IORING_OP_READV: u8 = 1; export def IORING_OP_WRITEV: u8 = 2; export def IORING_OP_FSYNC: u8 = 3; export def IORING_OP_READ_FIXED: u8 = 4; export def IORING_OP_WRITE_FIXED: u8 = 5; export def IORING_OP_POLL_ADD: u8 = 6; export def IORING_OP_POLL_REMOVE: u8 = 7; export def IORING_OP_SYNC_FILE_RANGE: u8 = 8; export def IORING_OP_SENDMSG: u8 = 9; export def IORING_OP_RECVMSG: u8 = 10; export def IORING_OP_TIMEOUT: u8 = 11; export def IORING_OP_TIMEOUT_REMOVE: u8 = 12; export def IORING_OP_ACCEPT: u8 = 13; export def IORING_OP_ASYNC_CANCEL: u8 = 14; export def IORING_OP_LINK_TIMEOUT: u8 = 15; export def IORING_OP_CONNECT: u8 = 16; export def IORING_OP_FALLOCATE: u8 = 17; export def IORING_OP_OPENAT: u8 = 18; export def IORING_OP_CLOSE: u8 = 19; export def IORING_OP_FILES_UPDATE: u8 = 20; export def IORING_OP_STATX: u8 = 21; export def IORING_OP_READ: u8 = 22; export def IORING_OP_WRITE: u8 = 23; export def IORING_OP_FADVISE: u8 = 24; export def IORING_OP_MADVISE: u8 = 25; export def IORING_OP_SEND: u8 = 26; export def IORING_OP_RECV: u8 = 27; export def IORING_OP_OPENAT2: u8 = 28; export def IORING_OP_EPOLL_CTL: u8 = 29; export def IORING_OP_SPLICE: u8 = 30; export def IORING_OP_PROVIDE_BUFFERS: u8 = 31; export def IORING_OP_REMOVE_BUFFERS: u8 = 32; export def IORING_OP_TEE: u8 = 33; export def IORING_OP_SHUTDOWN: u8 = 34; export def IORING_OP_RENAMEAT: u8 = 35; export def IORING_OP_UNLINKAT: u8 = 36; export def IORING_OP_MKDIRAT: u8 = 37; export def IORING_OP_SYMLINKAT: u8 = 38; export def IORING_OP_LINKAT: u8 = 39; export def IORING_OP_MSG_RING: u8 = 40; export def IORING_OP_FSETXATTR: u8 = 41; export def IORING_OP_SETXATTR: u8 = 42; export def IORING_OP_FGETXATTR: u8 = 43; export def IORING_OP_GETXATTR: u8 = 44; export def IORING_OP_SOCKET: u8 = 45; export def IORING_OP_URING_CMD: u8 = 46; export def IORING_OP_SEND_ZC: u8 = 47; export def IORING_OP_SENDMSG_ZC: u8 = 48; export def IORING_URING_CMD_FIXED: u32 = 1 << 0; export def IORING_URING_CMD_POLLED: u32 = 1 << 31; export def IORING_FSYNC_DATASYNC: u32 = 1 << 0; export def IORING_TIMEOUT_ABS: u32 = 1 << 0; export def IORING_TIMEOUT_UPDATE: u32 = 1 << 1; export def IORING_TIMEOUT_BOOTTIME: u32 = 1 << 2; export def IORING_TIMEOUT_REALTIME: u32 = 1 << 3; export def IORING_LINK_TIMEOUT_UPDATE: u32 = 1 << 4; export def IORING_TIMEOUT_ETIME_SUCCESS: u32 = 1 << 5; export def IORING_TIMEOUT_MULTISHOT: u32 = 1 << 6; export def SPLICE_F_FD_IN_FIXED: u32 = 1 << 31; export def IORING_POLL_ADD_MULTI: u32 = 1 << 0; export def IORING_POLL_UPDATE_EVENTS: u32 = 1 << 1; export def IORING_POLL_UPDATE_USER_DATA: u32 = 1 << 2; export def IORING_POLL_ADD_LEVEL: u32 = 1 << 3; export def IORING_ASYNC_CANCEL_ALL: u32 = 1 << 0; export def IORING_ASYNC_CANCEL_FD: u32 = 1 << 1; export def IORING_ASYNC_CANCEL_ANY: u32 = 1 << 2; export def IORING_ASYNC_CANCEL_FD_FIXED: u32 = 1 << 3; export def IORING_RECVSEND_POLL_FIRST: u16 = 1 << 0; export def IORING_RECV_MULTISHOT: u16 = 1 << 1; export def IORING_RECVSEND_FIXED_BUF: u16 = 1 << 2; export def IORING_SEND_ZC_REPORT_USAGE: u16 = 1 << 3; // TODO: https://todo.sr.ht/~sircmpwn/hare/771 // export def IORING_NOTIF_USAGE_ZC_COPIED: i32 = 1 << 31; export def IORING_ACCEPT_MULTISHOT: u16 = 1 << 0; export def IORING_MSG_DATA: u64 = 0; export def IORING_MSG_SEND_FD: u64 = 1; export def IORING_MSG_RING_CQE_SKIP: u32 = 1 << 0; export def IORING_MSG_RING_FLAGS_PASS: u32 = 1 << 1; export type _io_uring_cqe = struct { user_data: u64, res: i32, flags: u32, }; export type io_uring_cqe = struct { _io_uring_cqe, big_cqe: [*]u64, }; export def IORING_CQE_F_BUFFER: u32 = 1 << 0; export def IORING_CQE_F_MORE: u32 = 1 << 1; export def IORING_CQE_F_SOCK_NONEMPTY: u32 = 1 << 2; export def IORING_CQE_F_NOTIF: u32 = 1 << 3; export def IORING_CQE_BUFFER_SHIFT: u32 = 16; export def IORING_OFF_SQ_RING: u64 = 0; export def IORING_OFF_CQ_RING: u64 = 0x8000000; export def IORING_OFF_SQES: u64 = 0x10000000; export def IORING_OFF_PBUF_RING: u64 = 0x80000000; export def IORING_OFF_PBUF_SHIFT: u64 = 16; export def IORING_OFF_MMAP_MASK: u64 = 0xf8000000; export type io_sqring_offsets = struct { head: u32, tail: u32, ring_mask: u32, ring_entries: u32, flags: u32, dropped: u32, array: u32, resv1: u32, user_addr: u64, }; export def IORING_SQ_NEED_WAKEUP: u32 = 1 << 0; export def IORING_SQ_CQ_OVERFLOW: u32 = 1 << 1; export def IORING_SQ_TASKRUN: u32 = 1 << 2; export type io_cqring_offsets = struct { head: u32, tail: u32, ring_mask: u32, ring_entries: u32, overflow: u32, cqes: u32, flags: u32, resv1: u32, user_addr: u64, }; export def IORING_CQ_EVENTFD_DISABLED: u32 = 1 << 0; export def IORING_ENTER_GETEVENTS: u32 = 1 << 0; export def IORING_ENTER_SQ_WAKEUP: u32 = 1 << 1; export def IORING_ENTER_SQ_WAIT: u32 = 1 << 2; export def IORING_ENTER_EXT_ARG: u32 = 1 << 3; export def IORING_ENTER_REGISTERED_RING: u32 = 1 << 4; export type io_uring_params = struct { sq_entries: u32, cq_entries: u32, flags: u32, sq_thread_cpu: u32, sq_thread_idle: u32, features: u32, wq_fd: u32, resv: [3]u32, sq_off: io_sqring_offsets, cq_off: io_cqring_offsets, }; export def IORING_FEAT_SINGLE_MMAP: u32 = 1 << 0; export def IORING_FEAT_NODROP: u32 = 1 << 1; export def IORING_FEAT_SUBMIT_STABLE: u32 = 1 << 2; export def IORING_FEAT_RW_CUR_POS: u32 = 1 << 3; export def IORING_FEAT_CUR_PERSONALITY: u32 = 1 << 4; export def IORING_FEAT_FAST_POLL: u32 = 1 << 5; export def IORING_FEAT_POLL_32BITS: u32 = 1 << 6; export def IORING_FEAT_SQPOLL_NONFIXED: u32 = 1 << 7; export def IORING_FEAT_EXT_ARG: u32 = 1 << 8; export def IORING_FEAT_NATIVE_WORKERS: u32 = 1 << 9; export def IORING_FEAT_RSRC_TAGS: u32 = 1 << 10; export def IORING_FEAT_CQE_SKIP: u32 = 1 << 11; export def IORING_FEAT_LINKED_FILE: u32 = 1 << 12; export def IORING_FEAT_REG_REG_RING: u32 = 1 << 13; export def IORING_REGISTER_BUFFERS: uint = 0; export def IORING_UNREGISTER_BUFFERS: uint = 1; export def IORING_REGISTER_FILES: uint = 2; export def IORING_UNREGISTER_FILES: uint = 3; export def IORING_REGISTER_EVENTFD: uint = 4; export def IORING_UNREGISTER_EVENTFD: uint = 5; export def IORING_REGISTER_FILES_UPDATE: uint = 6; export def IORING_REGISTER_EVENTFD_ASYNC: uint = 7; export def IORING_REGISTER_PROBE: uint = 8; export def IORING_REGISTER_PERSONALITY: uint = 9; export def IORING_UNREGISTER_PERSONALITY: uint = 10; export def IORING_REGISTER_RESTRICTIONS: uint = 11; export def IORING_REGISTER_ENABLE_RINGS: uint = 12; export def IORING_REGISTER_FILES2: uint = 13; export def IORING_REGISTER_FILES_UPDATE2: uint = 14; export def IORING_REGISTER_BUFFERS2: uint = 15; export def IORING_REGISTER_BUFFERS_UPDATE: uint = 16; export def IORING_REGISTER_IOWQ_AFF: uint = 17; export def IORING_UNREGISTER_IOWQ_AFF: uint = 18; export def IORING_REGISTER_IOWQ_MAX_WORKERS: uint = 19; export def IORING_REGISTER_RING_FDS: uint = 20; export def IORING_UNREGISTER_RING_FDS: uint = 21; export def IORING_REGISTER_PBUF_RING: uint = 22; export def IORING_UNREGISTER_PBUF_RING: uint = 23; export def IORING_REGISTER_SYNC_CANCEL: uint = 24; export def IORING_REGISTER_FILE_ALLOC_RANGE: uint = 25; export def IORING_REGISTER_USE_REGISTERED_RING: uint = 1 << 31; export type io_uring_files_update = struct { off: u32, resv: u32, fds: u64, }; export def IORING_RSRC_REGISTER_SPARSE: u32 = 1 << 0; export type io_uring_rsrc_register = struct { nr: u32, flags: u32, resv2: u64, data: u64, tags: u64, }; export type io_uring_rsrc_update = struct { off: u32, resv: u32, data: u64, }; export type io_uring_rsrc_update2 = struct { off: u32, resv: u32, data: u64, tags: u64, nr: u32, resv2: u32, }; export def IORING_REGISTER_FILES_SKIP: int = -2; export def IO_URING_OP_SUPPORTED: u16 = 1 << 0; export type io_uring_probe_op = struct { op: u8, resv: u8, flags: u16, resv2: u32, }; export type io_uring_probe = struct { last_op: u8, ops_len: u8, resv: u16, resv2: [3]u32, ops: [*]io_uring_probe_op, }; export type io_uring_restriction = struct { opcode: u16, union { register_op: u8, sqe_op: u8, sqe_flags: u8, }, resv: u8, resv2: [3]u32, }; export type io_uring_buf = struct { addr: u64, length: u32, bid: u16, resv: u16, }; export type io_uring_buf_ring = struct { union { struct { resv1: u64, resv2: u32, resv3: u16, tail: u16, }, bufs: [*]io_uring_buf, }, }; export def IOU_PBUF_RING_MMAP: u16 = 1; export type io_uring_buf_reg = struct { ring_addr: u64, ring_entries: u32, bgid: u16, flags: u16, resv: [3]u64, }; export def IORING_RESTRICTION_REGISTER_OP: u16 = 0; export def IORING_RESTRICTION_SQE_OP: u16 = 1; export def IORING_RESTRICTION_SQE_FLAGS_ALLOWED: u16 = 2; export def IORING_RESTRICTION_SQE_FLAGS_REQUIRED: u16 = 3; export type io_uring_getevents_arg = struct { sigmask: u64, sigmask_sz: u32, pad: u32, ts: u64, }; export type io_uring_sync_cancel_reg = struct { addr: u64, fd: i32, flags: u32, timeout: timespec, pad: [4]u64, }; export type io_uring_file_index_range = struct { off: u32, length: u32, resv: u64, }; export type io_uring_recvmsg_out = struct { namelen: u32, controllen: u32, payloadlen: u32, flags: u32, }; hare-0.24.2/rt/+netbsd/000077500000000000000000000000001464473310100145005ustar00rootroot00000000000000hare-0.24.2/rt/+netbsd/+x86_64.ha000066400000000000000000000021421464473310100160220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type siginfo = struct { si_signo: int, si_errno: int, si_code: int, si_pid: pid_t, si_uid: uid_t, si_status: int, si_addr: *opaque, si_value: sigval, _reason: union { _fault: struct { _trapno: int, }, _timer: struct { _timerid: int, _overrun: int, }, _mesgq: struct { _mqd: int, }, _poll: struct { _band: i64, }, __spare__: struct { __spare1__: i64, __spare2__: [7]int, }, }, }; export type ucontext = struct { uc_sigmask: sigset, uc_mcontext: mcontext, uc_link: *ucontext, uc_stack: stack_t, uc_flags: int, __spare__: [4]int, }; export type mcontext = struct { mc_onstack: u64, mc_rdi: u64, mc_rsi: u64, mc_rdx: u64, mc_rcx: u64, mc_r8: u64, mc_r9: u64, mc_rax: u64, mc_rbx: u64, mc_rbp: u64, mc_r10: u64, mc_r11: u64, mc_r12: u64, mc_r13: u64, mc_r14: u64, mc_r15: u64, mc_trapno: u32, mc_fs: u16, mc_gs: u16, mc_addr: u64, mc_flags: u32, mc_es: u16, mc_ds: u16, mc_err: u64, mc_rip: u64, mc_cs: u64, mc_rflags: u64, mc_rsp: u64, mc_ss: u64, }; hare-0.24.2/rt/+netbsd/env.ha000066400000000000000000000003211464473310100155760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export let argc: size = 0; export let argv: *[*]*u8 = null: *[*]*u8; export let envp: *[*]nullable *u8 = null: *[*]nullable *u8; hare-0.24.2/rt/+netbsd/errno.ha000066400000000000000000000312721464473310100161440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Represents an error returned from the NetBSD kernel. export type errno = !int; // Checks the return value from a NetBSD syscall and, if found to be in error, // returns the appropriate error. Otherwise, returns the original value. fn wrap_return(r: u64) (errno | u64) = { if (r > -4096: u64) { return (-(r: i64)): errno; }; return r; }; // Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not // permitted"). The return value may be statically allocated. export fn strerror(err: errno) str = { switch (err) { case EPERM => return "Operation not permitted"; case ENOENT => return "No such file or directory"; case ESRCH => return "No such process"; case EINTR => return "Interrupted system call"; case EIO => return "Input/output error"; case ENXIO => return "No such device or address"; case E2BIG => return "Argument list too long"; case ENOEXEC => return "Exec format error"; case EBADF => return "Bad file descriptor"; case ECHILD => return "No child processes"; case EAGAIN => return "Resource temporarily unavailable"; case ENOMEM => return "Cannot allocate memory"; case EACCES => return "Permission denied"; case EFAULT => return "Bad address"; case ENOTBLK => return "Block device required"; case EBUSY => return "Device or resource busy"; case EEXIST => return "File exists"; case EXDEV => return "Invalid cross-device link"; case ENODEV => return "No such device"; case ENOTDIR => return "Not a directory"; case EISDIR => return "Is a directory"; case EINVAL => return "Invalid argument"; case ENFILE => return "Too many open files in system"; case EMFILE => return "Too many open files"; case ENOTTY => return "Inappropriate ioctl for device"; case ETXTBSY => return "Text file busy"; case EFBIG => return "File too large"; case ENOSPC => return "No space left on device"; case ESPIPE => return "Illegal seek"; case EROFS => return "Read-only file system"; case EMLINK => return "Too many links"; case EPIPE => return "Broken pipe"; case EDOM => return "Numerical argument out of domain"; case ERANGE => return "Numerical result out of range"; case EDEADLK => return "Resource deadlock avoided"; case ENAMETOOLONG => return "File name too long"; case ENOLCK => return "No locks available"; case ENOSYS => return "Function not implemented"; case ENOTEMPTY => return "Directory not empty"; case ELOOP => return "Too many levels of symbolic links"; case ENOMSG => return "No message of desired type"; case EIDRM => return "Identifier removed"; case EREMOTE => return "Object is remote"; case ENOLINK => return "Link has been severed"; case EPROTO => return "Protocol error"; case EMULTIHOP => return "Multihop attempted"; case EBADMSG => return "Bad message"; case EOVERFLOW => return "Value too large for defined data type"; case EILSEQ => return "Invalid or incomplete multibyte or wide character"; case EUSERS => return "Too many users"; case ENOTSOCK => return "Socket operation on non-socket"; case EDESTADDRREQ => return "Destination address required"; case EMSGSIZE => return "Message too long"; case EPROTOTYPE => return "Protocol wrong type for socket"; case ENOPROTOOPT => return "Protocol not available"; case EPROTONOSUPPORT => return "Protocol not supported"; case ESOCKTNOSUPPORT => return "Socket type not supported"; case EOPNOTSUPP => return "Operation not supported"; case EPFNOSUPPORT => return "Protocol family not supported"; case EAFNOSUPPORT => return "Address family not supported by protocol"; case EADDRINUSE => return "Address already in use"; case EADDRNOTAVAIL => return "Cannot assign requested address"; case ENETDOWN => return "Network is down"; case ENETUNREACH => return "Network is unreachable"; case ENETRESET => return "Network dropped connection on reset"; case ECONNABORTED => return "Software caused connection abort"; case ECONNRESET => return "Connection reset by peer"; case ENOBUFS => return "No buffer space available"; case EISCONN => return "Transport endpoint is already connected"; case ENOTCONN => return "Transport endpoint is not connected"; case ESHUTDOWN => return "Cannot send after transport endpoint shutdown"; case ETOOMANYREFS => return "Too many references: cannot splice"; case ETIMEDOUT => return "Connection timed out"; case ECONNREFUSED => return "Connection refused"; case EHOSTDOWN => return "Host is down"; case EHOSTUNREACH => return "No route to host"; case EALREADY => return "Operation already in progress"; case EINPROGRESS => return "Operation now in progress"; case ESTALE => return "Stale file handle"; case EDQUOT => return "Disk quota exceeded"; case ECANCELED => return "Operation canceled"; case EOWNERDEAD => return "Owner died"; case ENOTRECOVERABLE => return "State not recoverable"; case EAUTH => return "Authentication error"; case EBADRPC => return "RPC struct is bad"; case ECAPMODE => return "Not permitted in capability mode"; case EDOOFUS => return "Programming error"; case EINTEGRITY => return "Integrity check failed"; case ENEEDAUTH => return "Need authenticator"; case ENOATTR => return "Attribute not found"; case ENOTCAPABLE => return "Capabilities insufficient"; case EPROCLIM => return "Too many processes"; case EPROCUNAVAIL => return "Bad procedure for program"; case EPROGMISMATCH => return "Program version wrong"; case EPROGUNAVAIL => return "RPC program not available"; case ERPCMISMATCH => return "RPC version wrong"; case => return unknown_errno(err); }; }; // Gets the programmer-friendly name for an [[errno]] (e.g. EPERM). The return // value may be statically allocated. export fn errname(err: errno) str = { switch (err) { case EPERM => return "EPERM"; case ENOENT => return "ENOENT"; case ESRCH => return "ESRCH"; case EINTR => return "EINTR"; case EIO => return "EIO"; case ENXIO => return "ENXIO"; case E2BIG => return "E2BIG"; case ENOEXEC => return "ENOEXEC"; case EBADF => return "EBADF"; case ECHILD => return "ECHILD"; case EAGAIN => return "EAGAIN"; case ENOMEM => return "ENOMEM"; case EACCES => return "EACCES"; case EFAULT => return "EFAULT"; case ENOTBLK => return "ENOTBLK"; case EBUSY => return "EBUSY"; case EEXIST => return "EEXIST"; case EXDEV => return "EXDEV"; case ENODEV => return "ENODEV"; case ENOTDIR => return "ENOTDIR"; case EISDIR => return "EISDIR"; case EINVAL => return "EINVAL"; case ENFILE => return "ENFILE"; case EMFILE => return "EMFILE"; case ENOTTY => return "ENOTTY"; case ETXTBSY => return "ETXTBSY"; case EFBIG => return "EFBIG"; case ENOSPC => return "ENOSPC"; case ESPIPE => return "ESPIPE"; case EROFS => return "EROFS"; case EMLINK => return "EMLINK"; case EPIPE => return "EPIPE"; case EDOM => return "EDOM"; case ERANGE => return "ERANGE"; case EDEADLK => return "EDEADLK"; case ENAMETOOLONG => return "ENAMETOOLONG"; case ENOLCK => return "ENOLCK"; case ENOSYS => return "ENOSYS"; case ENOTEMPTY => return "ENOTEMPTY"; case ELOOP => return "ELOOP"; case ENOMSG => return "ENOMSG"; case EIDRM => return "EIDRM"; case EREMOTE => return "EREMOTE"; case ENOLINK => return "ENOLINK"; case EPROTO => return "EPROTO"; case EMULTIHOP => return "EMULTIHOP"; case EBADMSG => return "EBADMSG"; case EOVERFLOW => return "EOVERFLOW"; case EILSEQ => return "EILSEQ"; case EUSERS => return "EUSERS"; case ENOTSOCK => return "ENOTSOCK"; case EDESTADDRREQ => return "EDESTADDRREQ"; case EMSGSIZE => return "EMSGSIZE"; case EPROTOTYPE => return "EPROTOTYPE"; case ENOPROTOOPT => return "ENOPROTOOPT"; case EPROTONOSUPPORT => return "EPROTONOSUPPORT"; case ESOCKTNOSUPPORT => return "ESOCKTNOSUPPORT"; case EOPNOTSUPP => return "EOPNOTSUPP"; case EPFNOSUPPORT => return "EPFNOSUPPORT"; case EAFNOSUPPORT => return "EAFNOSUPPORT"; case EADDRINUSE => return "EADDRINUSE"; case EADDRNOTAVAIL => return "EADDRNOTAVAIL"; case ENETDOWN => return "ENETDOWN"; case ENETUNREACH => return "ENETUNREACH"; case ENETRESET => return "ENETRESET"; case ECONNABORTED => return "ECONNABORTED"; case ECONNRESET => return "ECONNRESET"; case ENOBUFS => return "ENOBUFS"; case EISCONN => return "EISCONN"; case ENOTCONN => return "ENOTCONN"; case ESHUTDOWN => return "ESHUTDOWN"; case ETOOMANYREFS => return "ETOOMANYREFS"; case ETIMEDOUT => return "ETIMEDOUT"; case ECONNREFUSED => return "ECONNREFUSED"; case EHOSTDOWN => return "EHOSTDOWN"; case EHOSTUNREACH => return "EHOSTUNREACH"; case EALREADY => return "EALREADY"; case EINPROGRESS => return "EINPROGRESS"; case ESTALE => return "ESTALE"; case EDQUOT => return "EDQUOT"; case ECANCELED => return "ECANCELED"; case EOWNERDEAD => return "EOWNERDEAD"; case ENOTRECOVERABLE => return "ENOTRECOVERABLE"; case EAUTH => return "EAUTH"; case EBADRPC => return "EBADRPC"; case ECAPMODE => return "ECAPMODE"; case EDOOFUS => return "EDOOFUS"; case EINTEGRITY => return "EINTEGRITY"; case ENEEDAUTH => return "ENEEDAUTH"; case ENOATTR => return "ENOATTR"; case ENOTCAPABLE => return "ENOTCAPABLE"; case EPROCLIM => return "EPROCLIM"; case EPROCUNAVAIL => return "EPROCUNAVAIL"; case EPROGMISMATCH => return "EPROGMISMATCH"; case EPROGUNAVAIL => return "EPROGUNAVAIL"; case ERPCMISMATCH => return "ERPCMISMATCH"; case => return unknown_errno(err); }; }; export def EPERM: errno = 1; export def ENOENT: errno = 2; export def ESRCH: errno = 3; export def EINTR: errno = 4; export def EIO: errno = 5; export def ENXIO: errno = 6; export def E2BIG: errno = 7; export def ENOEXEC: errno = 8; export def EBADF: errno = 9; export def ECHILD: errno = 10; export def EDEADLK: errno = 11; export def ENOMEM: errno = 12; export def EACCES: errno = 13; export def EFAULT: errno = 14; export def ENOTBLK: errno = 15; export def EBUSY: errno = 16; export def EEXIST: errno = 17; export def EXDEV: errno = 18; export def ENODEV: errno = 19; export def ENOTDIR: errno = 20; export def EISDIR: errno = 21; export def EINVAL: errno = 22; export def ENFILE: errno = 23; export def EMFILE: errno = 24; export def ENOTTY: errno = 25; export def ETXTBSY: errno = 26; export def EFBIG: errno = 27; export def ENOSPC: errno = 28; export def ESPIPE: errno = 29; export def EROFS: errno = 30; export def EMLINK: errno = 31; export def EPIPE: errno = 32; export def EDOM: errno = 33; export def ERANGE: errno = 34; export def EAGAIN: errno = 35; export def EWOULDBLOCK: errno = EAGAIN; export def EINPROGRESS: errno = 36; export def EALREADY: errno = 37; export def ENOTSOCK: errno = 38; export def EDESTADDRREQ: errno = 39; export def EMSGSIZE: errno = 40; export def EPROTOTYPE: errno = 41; export def ENOPROTOOPT: errno = 42; export def EPROTONOSUPPORT: errno = 43; export def ESOCKTNOSUPPORT: errno = 44; export def EOPNOTSUPP: errno = 45; export def ENOTSUP: errno = EOPNOTSUPP; export def EPFNOSUPPORT: errno = 46; export def EAFNOSUPPORT: errno = 47; export def EADDRINUSE: errno = 48; export def EADDRNOTAVAIL: errno = 49; export def ENETDOWN: errno = 50; export def ENETUNREACH: errno = 51; export def ENETRESET: errno = 52; export def ECONNABORTED: errno = 53; export def ECONNRESET: errno = 54; export def ENOBUFS: errno = 55; export def EISCONN: errno = 56; export def ENOTCONN: errno = 57; export def ESHUTDOWN: errno = 58; export def ETOOMANYREFS: errno = 59; export def ETIMEDOUT: errno = 60; export def ECONNREFUSED: errno = 61; export def ELOOP: errno = 62; export def ENAMETOOLONG: errno = 63; export def EHOSTDOWN: errno = 64; export def EHOSTUNREACH: errno = 65; export def ENOTEMPTY: errno = 66; export def EPROCLIM: errno = 67; export def EUSERS: errno = 68; export def EDQUOT: errno = 69; export def ESTALE: errno = 70; export def EREMOTE: errno = 71; export def EBADRPC: errno = 72; export def ERPCMISMATCH: errno = 73; export def EPROGUNAVAIL: errno = 74; export def EPROGMISMATCH: errno = 75; export def EPROCUNAVAIL: errno = 76; export def ENOLCK: errno = 77; export def ENOSYS: errno = 78; export def EFTYPE: errno = 79; export def EAUTH: errno = 80; export def ENEEDAUTH: errno = 81; export def EIDRM: errno = 82; export def ENOMSG: errno = 83; export def EOVERFLOW: errno = 84; export def ECANCELED: errno = 85; export def EILSEQ: errno = 86; export def ENOATTR: errno = 87; export def EDOOFUS: errno = 88; export def EBADMSG: errno = 89; export def EMULTIHOP: errno = 90; export def ENOLINK: errno = 91; export def EPROTO: errno = 92; export def ENOTCAPABLE: errno = 93; export def ECAPMODE: errno = 94; export def ENOTRECOVERABLE: errno = 95; export def EOWNERDEAD: errno = 96; export def EINTEGRITY: errno = 97; hare-0.24.2/rt/+netbsd/hare.sc000066400000000000000000000014411464473310100157460ustar00rootroot00000000000000PHDRS { headers PT_PHDR PHDRS; text PT_LOAD FILEHDR PHDRS; data PT_LOAD; note PT_NOTE; } ENTRY(_start); SECTIONS { . = 0x8000000; .text : { KEEP (*(.text)) *(.text.*) } :text . = 0x80000000; .data : { KEEP (*(.data)) *(.data.*) } :data .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); } :data .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); } :data .test_array : { PROVIDE_HIDDEN (__test_array_start = .); KEEP (*(.test_array)) PROVIDE_HIDDEN (__test_array_end = .); } :data .note.netbsd.ident : { KEEP (*(.note.netbsd.ident)) *(.note.netbsd.*) } :data :note .bss : { KEEP (*(.bss)) *(.bss.*) } :data } hare-0.24.2/rt/+netbsd/initfini.ha000066400000000000000000000010161464473310100166210ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Run all global initialization functions. export fn init() void = { const ninit = (&init_end: uintptr - &init_start: uintptr): size / size(*fn() void); for (let i = 0z; i < ninit; i += 1) { init_start[i](); }; }; // Run all global finalization functions. export fn fini() void = { const nfini = (&fini_end: uintptr - &fini_start: uintptr): size / size(*fn() void); for (let i = nfini; i > 0; i -= 1) { fini_start[i - 1](); }; }; hare-0.24.2/rt/+netbsd/platform_abort.ha000066400000000000000000000011711464473310100200250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn strvec(s: str) iovec = { return iovec { iov_base = *(&s: **opaque), iov_len = len(s), }; }; fn platform_abort(path: *str, line: u64, col: u64, msg: str) never = { let linebuf: [U64_BUFSZ]u8 = [0...]; let colbuf: [U64_BUFSZ]u8 = [0...]; const iov = [ strvec("Abort: "), strvec(*path), strvec(":"), strvec(u64tos(linebuf, line)), strvec(":"), strvec(u64tos(colbuf, col)), strvec(": "), strvec(msg), strvec("\n"), ]; writev(STDERR_FILENO, &iov, len(iov): int): void; for (true) { kill(getpid(), SIGABRT): void; }; }; hare-0.24.2/rt/+netbsd/platformstart-libc.ha000066400000000000000000000004071464473310100206240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn start_netbsd(iv: *[*]uintptr) never = { // TODO: Find & parse auxv argc = iv[0]: size; argv = &iv[1]: *[*]*u8; envp = &argv[argc + 1]: *[*]nullable *u8; start_ha(); }; hare-0.24.2/rt/+netbsd/segmalloc.ha000066400000000000000000000010331464473310100167550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Allocates a segment. fn segmalloc(n: size) nullable *opaque = { return match (mmap(null, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) { case let err: errno => assert(err == ENOMEM: errno); yield null; case let p: *opaque => yield p; }; }; // Frees a segment allocated with segmalloc. fn segfree(p: *opaque, s: size) void = { match (munmap(p, s)) { case let err: errno => abort("munmap failed"); case void => void; }; }; hare-0.24.2/rt/+netbsd/signal.ha000066400000000000000000000075741464473310100163040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: work when _NSIG != 32 export fn alarm(sec: uint) uint = { let nval = itimerval { ... }; let oval = itimerval { ... }; nval.it_value.tv_sec = sec: time_t; setitimer(ITIMER_REAL, &nval, &oval)!; if (oval.it_value.tv_usec != 0) { oval.it_value.tv_sec += 1; }; return oval.it_value.tv_sec: uint; }; export def ITIMER_REAL: int = 0; export def ITIMER_VIRTUAL: int = 1; export def ITIMER_PROF: int = 2; export type itimerval = struct { it_interval: timeval, it_value: timeval, }; export fn getitimer( which: int, cur: *itimerval, ) (void | errno) = { wrap_return(syscall2(SYS_compat_50_getitimer, which: u64, cur: uintptr: u64))?; }; export fn setitimer( which: int, newval: *itimerval, oldval: nullable *itimerval, ) (void | errno) = { wrap_return(syscall3(SYS_compat_50_setitimer, which: u64, newval: uintptr: u64, oldval: uintptr: u64))?; }; export fn sigtimedwait( set: *sigset, info: nullable *siginfo, timeout: nullable *timespec, ) (int | errno) = { return wrap_return(syscall3(SYS_compat_50___sigtimedwait, set: uintptr: u64, info: uintptr: u64, timeout: uintptr: u64, ))?: int; }; export fn sigwait(set: *sigset, sig: *int) (void | errno) = { *sig = sigtimedwait(set, null, null)?; }; export fn sigwaitinfo(set: *sigset, info: nullable *siginfo) (void | errno) = { sigtimedwait(set, info, null)?; }; export fn sigemptyset(set: *sigset) void = { for (let i = 0z; i < len(set.__bits); i += 1) { set.__bits[i] = 0; }; }; export fn sigaddset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__bits[signum >> 5] |= (1 << signum): u32; }; export fn sigdelset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; set.__bits[signum >> 5] &= ~(1 << signum: u32); }; export fn sigismember(set: *sigset, signum: int) (bool | errno) = { if (signum < 1 || signum > NSIG) { return EINVAL; }; signum -= 1; return (set.__bits[signum >> 5] & (1 << signum: u32)) != 0; }; export fn sigfillset(set: *sigset) (void | errno) = { for (let i = 0z; i < len(set.__bits); i += 1) { set.__bits[i] = ~0u32; }; }; // Test sigset operations do not fail for valid signal numbers. @test fn sigset_valid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(!(sigismember(&set, 1) is errno), "Unexpected error"); assert(!(sigismember(&set, 15) is errno), "Unexpected error"); assert(!(sigismember(&set, NSIG) is errno), "Unexpected error"); assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigaddset(&set, 15) is errno), "Unexpected error"); assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error"); // It's ok to add a signal that is already present in the set. assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 15) is errno), "Unexpected error"); assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error"); // It's ok to delete a signal that is not present in the set. assert(!(sigdelset(&set, 10) is errno), "Unexpected error"); }; // Test sigset operations fail for invalid signal numbers. @test fn sigset_invalid_signum() void = { let set: sigset = sigset { ... }; sigemptyset(&set); assert(sigismember(&set, -1) is errno, "Expected error"); assert(sigismember(&set, 0) is errno, "Expected error"); assert(sigismember(&set, NSIG + 1) is errno, "Expected error"); assert(sigaddset(&set, -1) is errno, "Expected error"); assert(sigaddset(&set, 0) is errno, "Expected error"); assert(sigaddset(&set, NSIG + 1) is errno, "Expected error"); assert(sigdelset(&set, -1) is errno, "Expected error"); assert(sigdelset(&set, 0) is errno, "Expected error"); assert(sigdelset(&set, NSIG + 1) is errno, "Expected error"); }; hare-0.24.2/rt/+netbsd/socket.ha000066400000000000000000000267711464473310100163170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sa_family_t = u8; export type socklen_t = u32; export type in_addr = struct { s_addr: u32 }; export type sockaddr_in = struct { sin_len: u8, sin_family: sa_family_t, sin_port: u16, sin_addr: in_addr, __pad: [8]u8, }; export type in6_addr = struct { union { s6_addr: [16]u8, s6_addr16: [8]u16, s6_addr32: [4]u32, } }; export type sockaddr_in6 = struct { sin6_len: u8, sin6_family: sa_family_t, sin6_port: u16, sin6_flowinfo: u32, sin6_addr: in6_addr, sin6_scope_id: u32, }; export def UNIX_PATH_MAX: size = 104; export type sockaddr_un = struct { sun_len: u8, sun_family: sa_family_t, sun_path: [UNIX_PATH_MAX]u8, }; export type sockaddr = struct { union { in: sockaddr_in, in6: sockaddr_in6, un: sockaddr_un, }, }; export def SCM_RIGHTS: int = 0x01; export def SCM_CREDENTIALS: int = 0x02; export type msghdr = struct { msg_name: nullable *opaque, msg_namelen: socklen_t, msg_iov: nullable *[*]iovec, msg_iovlen: int, msg_control: nullable *opaque, msg_controllen: socklen_t, msg_flags: int }; export type cmsghdr = struct { cmsg_len: socklen_t, cmsg_level: int, cmsg_type: int, }; export type cmsg = struct { hdr: cmsghdr, cmsg_data: [*]u8, }; export def AF_UNSPEC: sa_family_t = 0; export def AF_UNIX: sa_family_t = 1; export def AF_LOCAL: sa_family_t = AF_UNIX; export def AF_INET: sa_family_t = 2; export def AF_IMPLINK: sa_family_t = 3; export def AF_PUP: sa_family_t = 4; export def AF_CHAOS: sa_family_t = 5; export def AF_NETBIOS: sa_family_t = 6; export def AF_ISO: sa_family_t = 7; export def AF_OSI: sa_family_t = AF_ISO; export def AF_ECMA: sa_family_t = 8; export def AF_DATAKIT: sa_family_t = 9; export def AF_CCITT: sa_family_t = 10; export def AF_SNA: sa_family_t = 11; export def AF_DECnet: sa_family_t = 12; export def AF_DLI: sa_family_t = 13; export def AF_LAT: sa_family_t = 14; export def AF_HYLINK: sa_family_t = 15; export def AF_APPLETALK: sa_family_t = 16; export def AF_ROUTE: sa_family_t = 17; export def AF_LINK: sa_family_t = 18; export def pseudo_AF_XTP: sa_family_t = 19; export def AF_COIP: sa_family_t = 20; export def AF_CNT: sa_family_t = 21; export def pseudo_AF_RTIP: sa_family_t = 22; export def AF_IPX: sa_family_t = 23; export def AF_SIP: sa_family_t = 24; export def pseudo_AF_PIP: sa_family_t = 25; export def AF_ISDN: sa_family_t = 26; export def AF_E164: sa_family_t = AF_ISDN; export def AF_INET6: sa_family_t = 28; export def AF_NATM: sa_family_t = 29; export def AF_ATM: sa_family_t = 30; export def AF_NETGRAPH: sa_family_t = 32; export def AF_SLOW: sa_family_t = 33; export def AF_SCLUSTER: sa_family_t = 34; export def AF_ARP: sa_family_t = 35; export def AF_BLUETOOTH: sa_family_t = 36; export def AF_IEEE80211: sa_family_t = 37; export def AF_INET_SDP: sa_family_t = 40; export def AF_INET6_SDP: sa_family_t = 42; export def AF_HYPERV: sa_family_t = 43; export def AF_MAX: sa_family_t = 43; export def AF_VENDOR00: sa_family_t = 39; export def AF_VENDOR01: sa_family_t = 41; export def AF_VENDOR03: sa_family_t = 45; export def AF_VENDOR04: sa_family_t = 47; export def AF_VENDOR05: sa_family_t = 49; export def AF_VENDOR06: sa_family_t = 51; export def AF_VENDOR07: sa_family_t = 53; export def AF_VENDOR08: sa_family_t = 55; export def AF_VENDOR09: sa_family_t = 57; export def AF_VENDOR10: sa_family_t = 59; export def AF_VENDOR11: sa_family_t = 61; export def AF_VENDOR12: sa_family_t = 63; export def AF_VENDOR13: sa_family_t = 65; export def AF_VENDOR14: sa_family_t = 67; export def AF_VENDOR15: sa_family_t = 69; export def AF_VENDOR16: sa_family_t = 71; export def AF_VENDOR17: sa_family_t = 73; export def AF_VENDOR18: sa_family_t = 75; export def AF_VENDOR19: sa_family_t = 77; export def AF_VENDOR20: sa_family_t = 79; export def AF_VENDOR21: sa_family_t = 81; export def AF_VENDOR22: sa_family_t = 83; export def AF_VENDOR23: sa_family_t = 85; export def AF_VENDOR24: sa_family_t = 87; export def AF_VENDOR25: sa_family_t = 89; export def AF_VENDOR26: sa_family_t = 91; export def AF_VENDOR27: sa_family_t = 93; export def AF_VENDOR28: sa_family_t = 95; export def AF_VENDOR29: sa_family_t = 97; export def AF_VENDOR30: sa_family_t = 99; export def AF_VENDOR31: sa_family_t = 101; export def AF_VENDOR32: sa_family_t = 103; export def AF_VENDOR33: sa_family_t = 105; export def AF_VENDOR34: sa_family_t = 107; export def AF_VENDOR35: sa_family_t = 109; export def AF_VENDOR36: sa_family_t = 111; export def AF_VENDOR37: sa_family_t = 113; export def AF_VENDOR38: sa_family_t = 115; export def AF_VENDOR39: sa_family_t = 117; export def AF_VENDOR40: sa_family_t = 119; export def AF_VENDOR41: sa_family_t = 121; export def AF_VENDOR42: sa_family_t = 123; export def AF_VENDOR43: sa_family_t = 125; export def AF_VENDOR44: sa_family_t = 127; export def AF_VENDOR45: sa_family_t = 129; export def AF_VENDOR46: sa_family_t = 131; export def AF_VENDOR47: sa_family_t = 133; export def SOCK_STREAM: int = 1; export def SOCK_DGRAM: int = 2; export def SOCK_RAW: int = 3; export def SOCK_RDM: int = 4; export def SOCK_SEQPACKET: int = 5; export def SOCK_CLOEXEC: int = 0x10000000; export def SOCK_NONBLOCK: int = 0x20000000; export def IPPROTO_IP: int = 0; export def IPPROTO_ICMP: int = 1; export def IPPROTO_TCP: int = 6; export def IPPROTO_UDP: int = 17; export def IPPROTO_IPV6: int = 41; export def IPPROTO_RAW: int = 255; export def IPPROTO_HOPOPTS: int = 0; export def IPPROTO_IGMP: int = 2; export def IPPROTO_GGP: int = 3; export def IPPROTO_IPV4: int = 4; export def IPPROTO_IPIP: int = IPPROTO_IPV4; export def IPPROTO_ST: int = 7; export def IPPROTO_EGP: int = 8; export def IPPROTO_PIGP: int = 9; export def IPPROTO_RCCMON: int = 10; export def IPPROTO_NVPII: int = 11; export def IPPROTO_PUP: int = 12; export def IPPROTO_ARGUS: int = 13; export def IPPROTO_EMCON: int = 14; export def IPPROTO_XNET: int = 15; export def IPPROTO_CHAOS: int = 16; export def IPPROTO_MUX: int = 18; export def IPPROTO_MEAS: int = 19; export def IPPROTO_HMP: int = 20; export def IPPROTO_PRM: int = 21; export def IPPROTO_IDP: int = 22; export def IPPROTO_TRUNK1: int = 23; export def IPPROTO_TRUNK2: int = 24; export def IPPROTO_LEAF1: int = 25; export def IPPROTO_LEAF2: int = 26; export def IPPROTO_RDP: int = 27; export def IPPROTO_IRTP: int = 28; export def IPPROTO_TP: int = 29; export def IPPROTO_BLT: int = 30; export def IPPROTO_NSP: int = 31; export def IPPROTO_INP: int = 32; export def IPPROTO_DCCP: int = 33; export def IPPROTO_3PC: int = 34; export def IPPROTO_IDPR: int = 35; export def IPPROTO_XTP: int = 36; export def IPPROTO_DDP: int = 37; export def IPPROTO_CMTP: int = 38; export def IPPROTO_TPXX: int = 39; export def IPPROTO_IL: int = 40; export def IPPROTO_SDRP: int = 42; export def IPPROTO_ROUTING: int = 43; export def IPPROTO_FRAGMENT: int = 44; export def IPPROTO_IDRP: int = 45; export def IPPROTO_RSVP: int = 46; export def IPPROTO_GRE: int = 47; export def IPPROTO_MHRP: int = 48; export def IPPROTO_BHA: int = 49; export def IPPROTO_ESP: int = 50; export def IPPROTO_AH: int = 51; export def IPPROTO_INLSP: int = 52; export def IPPROTO_SWIPE: int = 53; export def IPPROTO_NHRP: int = 54; export def IPPROTO_MOBILE: int = 55; export def IPPROTO_TLSP: int = 56; export def IPPROTO_SKIP: int = 57; export def IPPROTO_ICMPV6: int = 58; export def IPPROTO_NONE: int = 59; export def IPPROTO_DSTOPTS: int = 60; export def IPPROTO_AHIP: int = 61; export def IPPROTO_CFTP: int = 62; export def IPPROTO_HELLO: int = 63; export def IPPROTO_SATEXPAK: int = 64; export def IPPROTO_KRYPTOLAN: int = 65; export def IPPROTO_RVD: int = 66; export def IPPROTO_IPPC: int = 67; export def IPPROTO_ADFS: int = 68; export def IPPROTO_SATMON: int = 69; export def IPPROTO_VISA: int = 70; export def IPPROTO_IPCV: int = 71; export def IPPROTO_CPNX: int = 72; export def IPPROTO_CPHB: int = 73; export def IPPROTO_WSN: int = 74; export def IPPROTO_PVP: int = 75; export def IPPROTO_BRSATMON: int = 76; export def IPPROTO_ND: int = 77; export def IPPROTO_WBMON: int = 78; export def IPPROTO_WBEXPAK: int = 79; export def IPPROTO_EON: int = 80; export def IPPROTO_VMTP: int = 81; export def IPPROTO_SVMTP: int = 82; export def IPPROTO_VINES: int = 83; export def IPPROTO_TTP: int = 84; export def IPPROTO_IGP: int = 85; export def IPPROTO_DGP: int = 86; export def IPPROTO_TCF: int = 87; export def IPPROTO_IGRP: int = 88; export def IPPROTO_OSPFIGP: int = 89; export def IPPROTO_SRPC: int = 90; export def IPPROTO_LARP: int = 91; export def IPPROTO_MTP: int = 92; export def IPPROTO_AX25: int = 93; export def IPPROTO_IPEIP: int = 94; export def IPPROTO_MICP: int = 95; export def IPPROTO_SCCSP: int = 96; export def IPPROTO_ETHERIP: int = 97; export def IPPROTO_ENCAP: int = 98; export def IPPROTO_APES: int = 99; export def IPPROTO_GMTP: int = 100; export def IPPROTO_IPCOMP: int = 108; export def IPPROTO_SCTP: int = 132; export def IPPROTO_MH: int = 135; export def IPPROTO_UDPLITE: int = 136; export def IPPROTO_HIP: int = 139; export def IPPROTO_SHIM6: int = 140; export def IPPROTO_PIM: int = 103; export def IPPROTO_CARP: int = 112; export def IPPROTO_PGM: int = 113; export def IPPROTO_MPLS: int = 137; export def IPPROTO_PFSYNC: int = 240; export def IPPROTO_RESERVED_253: int = 253; export def IPPROTO_RESERVED_254: int = 254; export def MSG_OOB: int = 0x00000001; export def MSG_PEEK: int = 0x00000002; export def MSG_DONTROUTE: int = 0x00000004; export def MSG_EOR: int = 0x00000008; export def MSG_TRUNC: int = 0x00000010; export def MSG_CTRUNC: int = 0x00000020; export def MSG_WAITALL: int = 0x00000040; export def MSG_DONTWAIT: int = 0x00000080; export def MSG_EOF: int = 0x00000100; export def MSG_NOTIFICATION: int = 0x00002000; export def MSG_NBIO: int = 0x00004000; export def MSG_COMPAT: int = 0x00008000; export def MSG_NOSIGNAL: int = 0x00020000; export def MSG_CMSG_CLOEXEC: int = 0x00040000; export def MSG_WAITFORONE: int = 0x00080000; export def SO_DEBUG: int = 0x00000001; export def SO_ACCEPTCONN: int = 0x00000002; export def SO_REUSEADDR: int = 0x00000004; export def SO_KEEPALIVE: int = 0x00000008; export def SO_DONTROUTE: int = 0x00000010; export def SO_BROADCAST: int = 0x00000020; export def SO_USELOOPBACK: int = 0x00000040; export def SO_LINGER: int = 0x00000080; export def SO_OOBINLINE: int = 0x00000100; export def SO_REUSEPORT: int = 0x00000200; export def SO_TIMESTAMP: int = 0x00000400; export def SO_NOSIGPIPE: int = 0x00000800; export def SO_ACCEPTFILTER: int = 0x00001000; export def SO_BINTIME: int = 0x00002000; export def SO_NO_OFFLOAD: int = 0x00004000; export def SO_NO_DDP: int = 0x00008000; export def SO_REUSEPORT_LB: int = 0x00010000; export def SO_SNDBUF: int = 0x1001; export def SO_RCVBUF: int = 0x1002; export def SO_SNDLOWAT: int = 0x1003; export def SO_RCVLOWAT: int = 0x1004; export def SO_SNDTIMEO: int = 0x1005; export def SO_RCVTIMEO: int = 0x1006; export def SO_ERROR: int = 0x1007; export def SO_TYPE: int = 0x1008; export def SO_LABEL: int = 0x1009; export def SO_PEERLABEL: int = 0x1010; export def SO_LISTENQLIMIT: int = 0x1011; export def SO_LISTENQLEN: int = 0x1012; export def SO_LISTENINCQLEN: int = 0x1013; export def SO_SETFIB: int = 0x1014; export def SO_USER_COOKIE: int = 0x1015; export def SO_PROTOCOL: int = 0x1016; export def SO_PROTOTYPE: int = SO_PROTOCOL; export def SO_TS_CLOCK: int = 0x1017; export def SO_MAX_PACING_RATE: int = 0x1018; export def SO_DOMAIN: int = 0x1019; export def SO_TS_REALTIME_MICRO: int = 0; export def SO_TS_BINTIME: int = 1; export def SO_TS_REALTIME: int = 2; export def SO_TS_MONOTONIC: int = 3; export def SO_TS_DEFAULT: int = SO_TS_REALTIME_MICRO; export def SO_TS_CLOCK_MAX: int = SO_TS_MONOTONIC; export def SOL_SOCKET: int = 0xffff; hare-0.24.2/rt/+netbsd/start+test.ha000066400000000000000000000007421464473310100171250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("__test_main") fn test_main() size; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); const nfail = test_main(); fini(); exit(if (nfail > 0) 1 else 0); }; hare-0.24.2/rt/+netbsd/start+x86_64-libc.s000066400000000000000000000004061464473310100176620ustar00rootroot00000000000000.section ".note.netbsd.ident", "a" .long 2f-1f .long 4f-3f .long 1 1: .asciz "NetBSD" 2: .p2align 2 3: .long 199905 4: .p2align 2 .text .global _start _start: xor %rbp, %rbp movq %rsp, %rdi and $-16, %rsp call rt.start_netbsd hare-0.24.2/rt/+netbsd/start.ha000066400000000000000000000006551464473310100161550ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors @symbol("main") fn main() void; const @symbol("__init_array_start") init_start: [*]*fn() void; const @symbol("__init_array_end") init_end: [*]*fn() void; const @symbol("__fini_array_start") fini_start: [*]*fn() void; const @symbol("__fini_array_end") fini_end: [*]*fn() void; export fn start_ha() never = { init(); main(); fini(); exit(0); }; hare-0.24.2/rt/+netbsd/syscall+x86_64.s000066400000000000000000000021171464473310100172710ustar00rootroot00000000000000.section .text error: neg %rax ret .section .text.rt.syscall0 .global rt.syscall0 rt.syscall0: movq %rdi, %rax syscall jc error ret .section .text.rt.syscall1 .global rt.syscall1 rt.syscall1: movq %rdi, %rax movq %rsi, %rdi syscall jc error ret .section .text.rt.syscall2 .global rt.syscall2 rt.syscall2: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi syscall jc error ret .section .text.rt.syscall3 .global rt.syscall3 rt.syscall3: movq %rdi, %rax movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall4 .global rt.syscall4 rt.syscall4: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall5 .global rt.syscall5 rt.syscall5: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq %rcx, %rdx syscall jc error ret .section .text.rt.syscall6 .global rt.syscall6 rt.syscall6: movq %rdi, %rax movq %r8, %r10 movq %rsi, %rdi movq %r9, %r8 movq %rdx, %rsi movq 8(%rsp), %r9 movq %rcx, %rdx syscall jc error ret hare-0.24.2/rt/+netbsd/syscallno.ha000066400000000000000000000433361464473310100170320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export def SYS_syscall: u64 = 0; export def SYS_exit: u64 = 1; export def SYS_fork: u64 = 2; export def SYS_read: u64 = 3; export def SYS_write: u64 = 4; export def SYS_open: u64 = 5; export def SYS_close: u64 = 6; export def SYS_compat_50_wait4: u64 = 7; export def SYS_compat_43_ocreat: u64 = 8; export def SYS_link: u64 = 9; export def SYS_unlink: u64 = 10; export def SYS_chdir: u64 = 12; export def SYS_fchdir: u64 = 13; export def SYS_compat_50_mknod: u64 = 14; export def SYS_chmod: u64 = 15; export def SYS_chown: u64 = 16; export def SYS_break: u64 = 17; export def SYS_compat_20_getfsstat: u64 = 18; export def SYS_compat_43_olseek: u64 = 19; export def SYS_getpid: u64 = 20; export def SYS_compat_40_mount: u64 = 21; export def SYS_unmount: u64 = 22; export def SYS_setuid: u64 = 23; export def SYS_getuid: u64 = 24; export def SYS_geteuid: u64 = 25; export def SYS_ptrace: u64 = 26; export def SYS_recvmsg: u64 = 27; export def SYS_sendmsg: u64 = 28; export def SYS_recvfrom: u64 = 29; export def SYS_accept: u64 = 30; export def SYS_getpeername: u64 = 31; export def SYS_getsockname: u64 = 32; export def SYS_access: u64 = 33; export def SYS_chflags: u64 = 34; export def SYS_fchflags: u64 = 35; export def SYS_sync: u64 = 36; export def SYS_kill: u64 = 37; export def SYS_compat_43_stat43: u64 = 38; export def SYS_getppid: u64 = 39; export def SYS_compat_43_lstat43: u64 = 40; export def SYS_dup: u64 = 41; export def SYS_pipe: u64 = 42; export def SYS_getegid: u64 = 43; export def SYS_profil: u64 = 44; export def SYS_ktrace: u64 = 45; export def SYS_compat_13_sigaction13: u64 = 46; export def SYS_getgid: u64 = 47; export def SYS_compat_13_sigprocmask13: u64 = 48; export def SYS___getlogin: u64 = 49; export def SYS___setlogin: u64 = 50; export def SYS_acct: u64 = 51; export def SYS_compat_13_sigpending13: u64 = 52; export def SYS_compat_13_sigaltstack13: u64 = 53; export def SYS_ioctl: u64 = 54; export def SYS_compat_12_oreboot: u64 = 55; export def SYS_revoke: u64 = 56; export def SYS_symlink: u64 = 57; export def SYS_readlink: u64 = 58; export def SYS_execve: u64 = 59; export def SYS_umask: u64 = 60; export def SYS_chroot: u64 = 61; export def SYS_compat_43_fstat43: u64 = 62; export def SYS_compat_43_ogetkerninfo: u64 = 63; export def SYS_compat_43_ogetpagesize: u64 = 64; export def SYS_compat_12_msync: u64 = 65; export def SYS_vfork: u64 = 66; export def SYS_compat_43_ommap: u64 = 71; export def SYS_vadvise: u64 = 72; export def SYS_munmap: u64 = 73; export def SYS_mprotect: u64 = 74; export def SYS_madvise: u64 = 75; export def SYS_mincore: u64 = 78; export def SYS_getgroups: u64 = 79; export def SYS_setgroups: u64 = 80; export def SYS_getpgrp: u64 = 81; export def SYS_setpgid: u64 = 82; export def SYS_compat_50_setitimer: u64 = 83; export def SYS_compat_43_owait: u64 = 84; export def SYS_compat_12_oswapon: u64 = 85; export def SYS_compat_50_getitimer: u64 = 86; export def SYS_compat_43_ogethostname: u64 = 87; export def SYS_compat_43_osethostname: u64 = 88; export def SYS_compat_43_ogetdtablesize: u64 = 89; export def SYS_dup2: u64 = 90; export def SYS_getrandom: u64 = 91; export def SYS_fcntl: u64 = 92; export def SYS_compat_50_select: u64 = 93; export def SYS_fsync: u64 = 95; export def SYS_setpriority: u64 = 96; export def SYS_compat_30_socket: u64 = 97; export def SYS_connect: u64 = 98; export def SYS_compat_43_oaccept: u64 = 99; export def SYS_getpriority: u64 = 100; export def SYS_compat_43_osend: u64 = 101; export def SYS_compat_43_orecv: u64 = 102; export def SYS_compat_13_sigreturn13: u64 = 103; export def SYS_bind: u64 = 104; export def SYS_setsockopt: u64 = 105; export def SYS_listen: u64 = 106; export def SYS_compat_43_osigvec: u64 = 108; export def SYS_compat_43_osigblock: u64 = 109; export def SYS_compat_43_osigsetmask: u64 = 110; export def SYS_compat_13_sigsuspend13: u64 = 111; export def SYS_compat_43_osigstack: u64 = 112; export def SYS_compat_43_orecvmsg: u64 = 113; export def SYS_compat_43_osendmsg: u64 = 114; export def SYS_compat_50_gettimeofday: u64 = 116; export def SYS_compat_50_getrusage: u64 = 117; export def SYS_getsockopt: u64 = 118; export def SYS_readv: u64 = 120; export def SYS_writev: u64 = 121; export def SYS_compat_50_settimeofday: u64 = 122; export def SYS_fchown: u64 = 123; export def SYS_fchmod: u64 = 124; export def SYS_compat_43_orecvfrom: u64 = 125; export def SYS_setreuid: u64 = 126; export def SYS_setregid: u64 = 127; export def SYS_rename: u64 = 128; export def SYS_compat_43_otruncate: u64 = 129; export def SYS_compat_43_oftruncate: u64 = 130; export def SYS_flock: u64 = 131; export def SYS_mkfifo: u64 = 132; export def SYS_sendto: u64 = 133; export def SYS_shutdown: u64 = 134; export def SYS_socketpair: u64 = 135; export def SYS_mkdir: u64 = 136; export def SYS_rmdir: u64 = 137; export def SYS_compat_50_utimes: u64 = 138; export def SYS_compat_50_adjtime: u64 = 140; export def SYS_compat_43_ogetpeername: u64 = 141; export def SYS_compat_43_ogethostid: u64 = 142; export def SYS_compat_43_osethostid: u64 = 143; export def SYS_compat_43_ogetrlimit: u64 = 144; export def SYS_compat_43_osetrlimit: u64 = 145; export def SYS_compat_43_okillpg: u64 = 146; export def SYS_setsid: u64 = 147; export def SYS_compat_50_quotactl: u64 = 148; export def SYS_compat_43_oquota: u64 = 149; export def SYS_compat_43_ogetsockname: u64 = 150; export def SYS_nfssvc: u64 = 155; export def SYS_compat_43_ogetdirentries: u64 = 156; export def SYS_compat_20_statfs: u64 = 157; export def SYS_compat_20_fstatfs: u64 = 158; export def SYS_compat_30_getfh: u64 = 161; export def SYS_compat_09_ogetdomainname: u64 = 162; export def SYS_compat_09_osetdomainname: u64 = 163; export def SYS_compat_09_ouname: u64 = 164; export def SYS_sysarch: u64 = 165; export def SYS___futex: u64 = 166; export def SYS___futex_set_robust_list: u64 = 167; export def SYS___futex_get_robust_list: u64 = 168; export def SYS_compat_10_osemsys: u64 = 169; export def SYS_compat_10_omsgsys: u64 = 170; export def SYS_compat_10_oshmsys: u64 = 171; export def SYS_pread: u64 = 173; export def SYS_pwrite: u64 = 174; export def SYS_compat_30_ntp_gettime: u64 = 175; export def SYS_ntp_adjtime: u64 = 176; export def SYS_timerfd_create: u64 = 177; export def SYS_timerfd_settime: u64 = 178; export def SYS_timerfd_gettime: u64 = 179; export def SYS_setgid: u64 = 181; export def SYS_setegid: u64 = 182; export def SYS_seteuid: u64 = 183; export def SYS_lfs_bmapv: u64 = 184; export def SYS_lfs_markv: u64 = 185; export def SYS_lfs_segclean: u64 = 186; export def SYS_compat_50_lfs_segwait: u64 = 187; export def SYS_compat_12_stat12: u64 = 188; export def SYS_compat_12_fstat12: u64 = 189; export def SYS_compat_12_lstat12: u64 = 190; export def SYS_pathconf: u64 = 191; export def SYS_fpathconf: u64 = 192; export def SYS_getsockopt2: u64 = 193; export def SYS_getrlimit: u64 = 194; export def SYS_setrlimit: u64 = 195; export def SYS_compat_12_getdirentries: u64 = 196; export def SYS_mmap: u64 = 197; export def SYS___syscall: u64 = 198; export def SYS_lseek: u64 = 199; export def SYS_truncate: u64 = 200; export def SYS_ftruncate: u64 = 201; export def SYS___sysctl: u64 = 202; export def SYS_mlock: u64 = 203; export def SYS_munlock: u64 = 204; export def SYS_undelete: u64 = 205; export def SYS_compat_50_futimes: u64 = 206; export def SYS_getpgid: u64 = 207; export def SYS_reboot: u64 = 208; export def SYS_poll: u64 = 209; export def SYS_afssys: u64 = 210; export def SYS_compat_14___semctl: u64 = 220; export def SYS_semget: u64 = 221; export def SYS_semop: u64 = 222; export def SYS_semconfig: u64 = 223; export def SYS_compat_14_msgctl: u64 = 224; export def SYS_msgget: u64 = 225; export def SYS_msgsnd: u64 = 226; export def SYS_msgrcv: u64 = 227; export def SYS_shmat: u64 = 228; export def SYS_compat_14_shmctl: u64 = 229; export def SYS_shmdt: u64 = 230; export def SYS_shmget: u64 = 231; export def SYS_compat_50_clock_gettime: u64 = 232; export def SYS_compat_50_clock_settime: u64 = 233; export def SYS_compat_50_clock_getres: u64 = 234; export def SYS_timer_create: u64 = 235; export def SYS_timer_delete: u64 = 236; export def SYS_compat_50_timer_settime: u64 = 237; export def SYS_compat_50_timer_gettime: u64 = 238; export def SYS_timer_getoverrun: u64 = 239; export def SYS_compat_50_nanosleep: u64 = 240; export def SYS_fdatasync: u64 = 241; export def SYS_mlockall: u64 = 242; export def SYS_munlockall: u64 = 243; export def SYS_compat_50___sigtimedwait: u64 = 244; export def SYS_sigqueueinfo: u64 = 245; export def SYS_modctl: u64 = 246; export def SYS__ksem_init: u64 = 247; export def SYS__ksem_open: u64 = 248; export def SYS__ksem_unlink: u64 = 249; export def SYS__ksem_close: u64 = 250; export def SYS__ksem_post: u64 = 251; export def SYS__ksem_wait: u64 = 252; export def SYS__ksem_trywait: u64 = 253; export def SYS__ksem_getvalue: u64 = 254; export def SYS__ksem_destroy: u64 = 255; export def SYS__ksem_timedwait: u64 = 256; export def SYS_mq_open: u64 = 257; export def SYS_mq_close: u64 = 258; export def SYS_mq_unlink: u64 = 259; export def SYS_mq_getattr: u64 = 260; export def SYS_mq_setattr: u64 = 261; export def SYS_mq_notify: u64 = 262; export def SYS_mq_send: u64 = 263; export def SYS_mq_receive: u64 = 264; export def SYS_compat_50_mq_timedsend: u64 = 265; export def SYS_compat_50_mq_timedreceive: u64 = 266; export def SYS_eventfd: u64 = 267; export def SYS___posix_rename: u64 = 270; export def SYS_swapctl: u64 = 271; export def SYS_compat_30_getdents: u64 = 272; export def SYS_minherit: u64 = 273; export def SYS_lchmod: u64 = 274; export def SYS_lchown: u64 = 275; export def SYS_compat_50_lutimes: u64 = 276; export def SYS___msync13: u64 = 277; export def SYS_compat_30___stat13: u64 = 278; export def SYS_compat_30___fstat13: u64 = 279; export def SYS_compat_30___lstat13: u64 = 280; export def SYS___sigaltstack14: u64 = 281; export def SYS___vfork14: u64 = 282; export def SYS___posix_chown: u64 = 283; export def SYS___posix_fchown: u64 = 284; export def SYS___posix_lchown: u64 = 285; export def SYS_getsid: u64 = 286; export def SYS___clone: u64 = 287; export def SYS_fktrace: u64 = 288; export def SYS_preadv: u64 = 289; export def SYS_pwritev: u64 = 290; export def SYS_compat_16___sigaction14: u64 = 291; export def SYS___sigpending14: u64 = 292; export def SYS___sigprocmask14: u64 = 293; export def SYS___sigsuspend14: u64 = 294; export def SYS_compat_16___sigreturn14: u64 = 295; export def SYS___getcwd: u64 = 296; export def SYS_fchroot: u64 = 297; export def SYS_compat_30_fhopen: u64 = 298; export def SYS_compat_30_fhstat: u64 = 299; export def SYS_compat_20_fhstatfs: u64 = 300; export def SYS_compat_50_____semctl13: u64 = 301; export def SYS_compat_50___msgctl13: u64 = 302; export def SYS_compat_50___shmctl13: u64 = 303; export def SYS_lchflags: u64 = 304; export def SYS_issetugid: u64 = 305; export def SYS_utrace: u64 = 306; export def SYS_getcontext: u64 = 307; export def SYS_setcontext: u64 = 308; export def SYS__lwp_create: u64 = 309; export def SYS__lwp_exit: u64 = 310; export def SYS__lwp_self: u64 = 311; export def SYS__lwp_wait: u64 = 312; export def SYS__lwp_suspend: u64 = 313; export def SYS__lwp_continue: u64 = 314; export def SYS__lwp_wakeup: u64 = 315; export def SYS__lwp_getprivate: u64 = 316; export def SYS__lwp_setprivate: u64 = 317; export def SYS__lwp_kill: u64 = 318; export def SYS__lwp_detach: u64 = 319; export def SYS_compat_50__lwp_park: u64 = 320; export def SYS__lwp_unpark: u64 = 321; export def SYS__lwp_unpark_all: u64 = 322; export def SYS__lwp_setname: u64 = 323; export def SYS__lwp_getname: u64 = 324; export def SYS__lwp_ctl: u64 = 325; export def SYS_compat_60_sa_register: u64 = 330; export def SYS_compat_60_sa_stacks: u64 = 331; export def SYS_compat_60_sa_enable: u64 = 332; export def SYS_compat_60_sa_setconcurrency: u64 = 333; export def SYS_compat_60_sa_yield: u64 = 334; export def SYS_compat_60_sa_preempt: u64 = 335; export def SYS___sigaction_sigtramp: u64 = 340; export def SYS_rasctl: u64 = 343; export def SYS_kqueue: u64 = 344; export def SYS_compat_50_kevent: u64 = 345; export def SYS__sched_setparam: u64 = 346; export def SYS__sched_getparam: u64 = 347; export def SYS__sched_setaffinity: u64 = 348; export def SYS__sched_getaffinity: u64 = 349; export def SYS_sched_yield: u64 = 350; export def SYS__sched_protect: u64 = 351; export def SYS_fsync_range: u64 = 354; export def SYS_uuidgen: u64 = 355; export def SYS_compat_90_getvfsstat: u64 = 356; export def SYS_compat_90_statvfs1: u64 = 357; export def SYS_compat_90_fstatvfs1: u64 = 358; export def SYS_compat_30_fhstatvfs1: u64 = 359; export def SYS_extattrctl: u64 = 360; export def SYS_extattr_set_file: u64 = 361; export def SYS_extattr_get_file: u64 = 362; export def SYS_extattr_delete_file: u64 = 363; export def SYS_extattr_set_fd: u64 = 364; export def SYS_extattr_get_fd: u64 = 365; export def SYS_extattr_delete_fd: u64 = 366; export def SYS_extattr_set_link: u64 = 367; export def SYS_extattr_get_link: u64 = 368; export def SYS_extattr_delete_link: u64 = 369; export def SYS_extattr_list_fd: u64 = 370; export def SYS_extattr_list_file: u64 = 371; export def SYS_extattr_list_link: u64 = 372; export def SYS_compat_50_pselect: u64 = 373; export def SYS_compat_50_pollts: u64 = 374; export def SYS_setxattr: u64 = 375; export def SYS_lsetxattr: u64 = 376; export def SYS_fsetxattr: u64 = 377; export def SYS_getxattr: u64 = 378; export def SYS_lgetxattr: u64 = 379; export def SYS_fgetxattr: u64 = 380; export def SYS_listxattr: u64 = 381; export def SYS_llistxattr: u64 = 382; export def SYS_flistxattr: u64 = 383; export def SYS_removexattr: u64 = 384; export def SYS_lremovexattr: u64 = 385; export def SYS_fremovexattr: u64 = 386; export def SYS_compat_50___stat30: u64 = 387; export def SYS_compat_50___fstat30: u64 = 388; export def SYS_compat_50___lstat30: u64 = 389; export def SYS___getdents30: u64 = 390; export def SYS_compat_30___fhstat30: u64 = 392; export def SYS_compat_50___ntp_gettime30: u64 = 393; export def SYS___socket30: u64 = 394; export def SYS___getfh30: u64 = 395; export def SYS___fhopen40: u64 = 396; export def SYS_compat_90_fhstatvfs1: u64 = 397; export def SYS_compat_50___fhstat40: u64 = 398; export def SYS_aio_cancel: u64 = 399; export def SYS_aio_error: u64 = 400; export def SYS_aio_fsync: u64 = 401; export def SYS_aio_read: u64 = 402; export def SYS_aio_return: u64 = 403; export def SYS_compat_50_aio_suspend: u64 = 404; export def SYS_aio_write: u64 = 405; export def SYS_lio_listio: u64 = 406; export def SYS___mount50: u64 = 410; export def SYS_mremap: u64 = 411; export def SYS_pset_create: u64 = 412; export def SYS_pset_destroy: u64 = 413; export def SYS_pset_assign: u64 = 414; export def SYS__pset_bind: u64 = 415; export def SYS___posix_fadvise50: u64 = 416; export def SYS___select50: u64 = 417; export def SYS___gettimeofday50: u64 = 418; export def SYS___settimeofday50: u64 = 419; export def SYS___utimes50: u64 = 420; export def SYS___adjtime50: u64 = 421; export def SYS___lfs_segwait50: u64 = 422; export def SYS___futimes50: u64 = 423; export def SYS___lutimes50: u64 = 424; export def SYS___setitimer50: u64 = 425; export def SYS___getitimer50: u64 = 426; export def SYS___clock_gettime50: u64 = 427; export def SYS___clock_settime50: u64 = 428; export def SYS___clock_getres50: u64 = 429; export def SYS___nanosleep50: u64 = 430; export def SYS_____sigtimedwait50: u64 = 431; export def SYS___mq_timedsend50: u64 = 432; export def SYS___mq_timedreceive50: u64 = 433; export def SYS_compat_60__lwp_park: u64 = 434; export def SYS___kevent50: u64 = 435; export def SYS___pselect50: u64 = 436; export def SYS___pollts50: u64 = 437; export def SYS___aio_suspend50: u64 = 438; export def SYS___stat50: u64 = 439; export def SYS___fstat50: u64 = 440; export def SYS___lstat50: u64 = 441; export def SYS_____semctl50: u64 = 442; export def SYS___shmctl50: u64 = 443; export def SYS___msgctl50: u64 = 444; export def SYS___getrusage50: u64 = 445; export def SYS___timer_settime50: u64 = 446; export def SYS___timer_gettime50: u64 = 447; export def SYS___ntp_gettime50: u64 = 448; export def SYS___wait450: u64 = 449; export def SYS___mknod50: u64 = 450; export def SYS___fhstat50: u64 = 451; export def SYS_pipe2: u64 = 453; export def SYS_dup3: u64 = 454; export def SYS_kqueue1: u64 = 455; export def SYS_paccept: u64 = 456; export def SYS_linkat: u64 = 457; export def SYS_renameat: u64 = 458; export def SYS_mkfifoat: u64 = 459; export def SYS_mknodat: u64 = 460; export def SYS_mkdirat: u64 = 461; export def SYS_faccessat: u64 = 462; export def SYS_fchmodat: u64 = 463; export def SYS_fchownat: u64 = 464; export def SYS_fexecve: u64 = 465; export def SYS_fstatat: u64 = 466; export def SYS_utimensat: u64 = 467; export def SYS_openat: u64 = 468; export def SYS_readlinkat: u64 = 469; export def SYS_symlinkat: u64 = 470; export def SYS_unlinkat: u64 = 471; export def SYS_futimens: u64 = 472; export def SYS___quotactl: u64 = 473; export def SYS_posix_spawn: u64 = 474; export def SYS_recvmmsg: u64 = 475; export def SYS_sendmmsg: u64 = 476; export def SYS_clock_nanosleep: u64 = 477; export def SYS____lwp_park60: u64 = 478; export def SYS_posix_fallocate: u64 = 479; export def SYS_fdiscard: u64 = 480; export def SYS_wait6: u64 = 481; export def SYS_clock_getcpuclockid2: u64 = 482; export def SYS___getvfsstat90: u64 = 483; export def SYS___statvfs190: u64 = 484; export def SYS___fstatvfs190: u64 = 485; export def SYS___fhstatvfs190: u64 = 486; export def SYS___acl_get_link: u64 = 487; export def SYS___acl_set_link: u64 = 488; export def SYS___acl_delete_link: u64 = 489; export def SYS___acl_aclcheck_link: u64 = 490; export def SYS___acl_get_file: u64 = 491; export def SYS___acl_set_file: u64 = 492; export def SYS___acl_get_fd: u64 = 493; export def SYS___acl_set_fd: u64 = 494; export def SYS___acl_delete_file: u64 = 495; export def SYS___acl_delete_fd: u64 = 496; export def SYS___acl_aclcheck_file: u64 = 497; export def SYS___acl_aclcheck_fd: u64 = 498; export def SYS_lpathconf: u64 = 499; hare-0.24.2/rt/+netbsd/syscalls.ha000066400000000000000000000436111464473310100166540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn syscall0(u64) u64; fn syscall1(u64, u64) u64; fn syscall2(u64, u64, u64) u64; fn syscall3(u64, u64, u64, u64) u64; fn syscall4(u64, u64, u64, u64, u64) u64; fn syscall5(u64, u64, u64, u64, u64, u64) u64; fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64; let pathbuf: [PATH_MAX]u8 = [0...]; // The use of this function is discouraged, as it can create race conditions. // TOCTOU is preferred: attempt to simply use the resource you need and handle // any access errors which occur. export fn access(path: path, mode: int) (bool | errno) = faccessat(AT_FDCWD, path, mode, 0); export fn fchdir(fd: int) (void | errno) = { wrap_return(syscall1(SYS_fchdir, fd: u64))?; }; export fn chdir(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?; }; export fn chroot(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?; }; export fn fchmod(fd: int, mode: uint) (void | errno) = { wrap_return(syscall2(SYS_fchmod, fd: u64, mode: u64))?; }; export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_fchmodat, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?; }; export fn fchown(fd: int, uid: uint, gid: uint) (void | errno) = { wrap_return(syscall3(SYS_fchown, fd: u64, uid: u32, gid: u32))?; }; export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall5(SYS_fchownat, dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?; }; export fn fstatat(fd: int, path: path, _stat: *st, flag: int) (void | errno) = { let path = kpath(path)?; let sb = stat { ... }; wrap_return(syscall4(SYS_fstatat, fd: u64, path: uintptr: u64, &sb: uintptr: u64, flag: u64))?; _stat.dev = sb.st_dev; _stat.ino = sb.st_ino; _stat.mode = sb.st_mode; _stat.nlink = sb.st_nlink; _stat.uid = sb.st_uid; _stat.gid = sb.st_gid; _stat.rdev = sb.st_rdev; _stat.atime.tv_sec = sb.st_atim.tv_sec; _stat.atime.tv_nsec = sb.st_atim.tv_nsec: i64; _stat.mtime.tv_sec = sb.st_mtim.tv_sec; _stat.mtime.tv_nsec = sb.st_mtim.tv_nsec: i64; _stat.ctime.tv_sec = sb.st_ctim.tv_sec; _stat.ctime.tv_nsec = sb.st_ctim.tv_nsec: i64; _stat.btime.tv_sec = sb.st_birthtim.tv_sec; _stat.btime.tv_nsec = sb.st_birthtim.tv_nsec: i64; _stat.sz = sb.st_size; _stat.blocks = sb.st_blocks; _stat.blksz = sb.st_blksize; _stat.flags = sb.st_flags; }; export fn fstatvfs1(fd: int, _statvfs: *statvfs, flag: int) (void | errno) = { wrap_return(syscall3(SYS___fstatvfs190, fd: u64, _statvfs: uintptr: u64, flag: u64))?; }; export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = { wrap_return(syscall2(SYS_futimens, fd: u64, ts: uintptr: u64))?; }; export fn getdents(dirfd: int, buf: *opaque, nbytes: size) (size | errno) = { return wrap_return(syscall3(SYS___getdents30, dirfd: u64, buf: uintptr: u64, nbytes: u64))?: size; }; // The return value is statically allocated and must be duplicated before // calling getcwd again. export fn getcwd() (*const u8 | errno) = { static let pathbuf: [PATH_MAX]u8 = [0...]; wrap_return(syscall2(SYS___getcwd, &pathbuf: *[*]u8: uintptr: u64, PATH_MAX))?; return &pathbuf: *const u8; }; export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_mkdirat, dirfd: u64, path: uintptr: u64, mode: u64))?; }; export fn openat( dirfd: int, path: path, flags: int, mode: uint, ) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_openat, dirfd: u64, path: uintptr: u64, flags: u64, mode: u64))?: int; }; export fn readlinkat( dirfd: int, path: path, buf: []u8, ) (size | errno) = { let path = kpath(path)?; return wrap_return(syscall4(SYS_readlinkat, dirfd: u64, path: uintptr: u64, buf: *[*]u8: uintptr: u64, len(buf): u64))?: size; }; export fn renameat( olddirfd: int, oldpath: str, newdirfd: int, newpath: str, ) (void | errno) = { let oldpath = kpath(oldpath)?; static let newpathbuf: [PATH_MAX]u8 = [0...]; let newpath = copy_kpath(newpath, newpathbuf)?; wrap_return(syscall4(SYS_renameat, olddirfd: u64, oldpath: uintptr: u64, newdirfd: u64, newpath: uintptr: u64))?; }; export fn sysctl(name: []const u32, oldp: nullable *opaque, oldlenp: nullable *size, newp: nullable *const opaque, newlen: size) (void | errno) = { wrap_return(syscall6(SYS___sysctl, &name[0]: uintptr: u64, len(name): u64, oldp: uintptr: u64, oldlenp: uintptr: u64, newp: uintptr: u64, newlen: u64))?; }; export fn unlink(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall1(SYS_unlink, path: uintptr: u64))?; }; export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, dirfd: u64, path: uintptr: u64, flags: u64))?; }; export fn utimensat(dirfd: int, path: str, ts: *[2]timespec, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_utimensat, dirfd: u64, path: uintptr: u64, ts: uintptr: u64, flags: u64))?; }; export fn close(fd: int) (void | errno) = { wrap_return(syscall1(SYS_close, fd: u64))?; }; export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = { return wrap_return(syscall3(SYS_lseek, fd: u64, off: u64, whence: u64))?: i64; }; export fn dup2(old: int, new: int) (int | errno) = wrap_return(syscall2(SYS_dup2, old: u64, new: u64))?: int; export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; export def EXIT_SUCCESS: int = 0; export fn exit(status: int) never = { syscall1(SYS_exit, status: u64); abort(); }; export fn fork() (pid_t | void | errno) = { let n = wrap_return(syscall0(SYS_fork))?: pid_t; switch (n) { case 0 => return; case => return n; }; }; export fn execve( path: *const u8, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8, ) int = syscall3(SYS_execve, path: uintptr: u64, argv: uintptr: u64, envp: uintptr: u64): int; export fn wait4( pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, ) (int | errno) = { return wrap_return(syscall4(SYS___wait450, pid: u64, wstatus: uintptr: u64, options: u64, rusage: uintptr: u64))?: int; }; export fn wifexited(status: int) bool = wtermsig(status) == 0; export fn wexitstatus(status: int) int = (status & 0xff00) >> 8; export fn wtermsig(status: int) int = status & 0x7f; export fn wifsignaled(status: int) bool = wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13; export fn kill(pid: pid_t, signal: int) (void | errno) = { wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; }; export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = { wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?; }; export fn mmap( addr: nullable *opaque, length: size, prot: uint, flags: uint, fd: int, offs: size ) (errno | *opaque) = { return wrap_return(syscall6(SYS_mmap, addr: uintptr: u64, length: u64, prot: u64, flags: u64, fd: u64, offs: u64)): uintptr: *opaque; }; export fn munmap(addr: *opaque, length: size) (void | errno) = { wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?; }; export type fcntl_arg = (void | int | *st_flock | *u64); export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = { let _fd = fd: u64, _cmd = cmd: u64; return wrap_return(match (arg) { case void => yield syscall2(SYS_fcntl, _fd, _cmd); case let i: int => yield syscall3(SYS_fcntl, _fd, _cmd, i: u64); case let l: *st_flock => yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64); case let u: *u64 => yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64); })?: int; }; export fn read(fd: int, buf: *opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_read, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = { return wrap_return(syscall3(SYS_write, fd: u64, buf: uintptr: u64, count: u64))?: size; }; export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_readv, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { return wrap_return(syscall3(SYS_writev, fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; }; export fn flock(fd: int, op: int) (void | errno) = { wrap_return(syscall2(SYS_flock, fd: u64, op: u64))?; }; export fn ftruncate(fd: int, ln: off_t) (void | errno) = { wrap_return(syscall2(SYS_ftruncate, fd: u64, ln: u32))?; }; export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = { wrap_return(syscall2(SYS___nanosleep50, req: uintptr: u64, rem: uintptr: u64))?; }; export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = { wrap_return(syscall2(SYS___clock_gettime50, clock_id: u64, tp: uintptr: u64))?; }; export fn clock_settime(clock_id: int, tp: *const timespec) (void | errno) = { wrap_return(syscall2(SYS___clock_settime50, clock_id: u64, tp: uintptr: u64))?; }; export fn faccessat( dirfd: int, path: path, mode: int, flags: int, ) (bool | errno) = { let path = kpath(path)?; match (wrap_return(syscall4(SYS_faccessat, dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))) { case let err: errno => switch (err) { case EACCES => return false; case => return err; }; case let n: u64 => assert(n == 0); return true; }; }; // NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in // length. fn kpath(path: path) (*const u8 | errno) = { return copy_kpath(path, pathbuf); }; fn copy_kpath(path: path, buf: []u8) (*const u8 | errno) = { let path = match (path) { case let c: *const u8 => return c; case let s: str => let ptr = &s: *struct { buf: *[*]u8, length: size, capacity: size, }; yield ptr.buf[..ptr.length]; case let b: []u8 => yield b; }; if (len(path) + 1 >= len(pathbuf)) { return ENAMETOOLONG; }; memcpy(buf: *[*]u8, path: *[*]u8, len(path)); buf[len(path)] = 0; return buf: *[*]u8: *const u8; }; export fn getgroups(gids: []gid_t) (uint | errno) = { return wrap_return(syscall2(SYS_getgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; }; export fn setgroups(gids: []gid_t) (void | errno) = { wrap_return(syscall2(SYS_setgroups, len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; }; export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; export fn getpgrp() pid_t = syscall0(SYS_getpgrp): pid_t; export fn getsid(pid: pid_t) (pid_t | errno) = { return wrap_return(syscall1(SYS_getsid, pid))?: pid_t; }; export fn getpriority(which: int, who: id_t) (int | errno) = { return wrap_return(syscall2(SYS_getpriority, which: u64, who: u64))?: int; }; export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = { wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?; }; export fn umask(mode: mode_t) (mode_t | errno) = { return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t; }; export fn getuid() (uid_t | errno) = { return wrap_return(syscall0(SYS_getuid))?: uid_t; }; export fn geteuid() (uid_t | errno) = { return wrap_return(syscall0(SYS_geteuid))?: uid_t; }; export fn getgid() (gid_t | errno) = { return wrap_return(syscall0(SYS_getgid))?: gid_t; }; export fn getegid() (gid_t | errno) = { return wrap_return(syscall0(SYS_getegid))?: gid_t; }; export fn setuid(uid: *uid_t) (void | errno) = { wrap_return(syscall1(SYS_setuid, uid: uintptr: u64))?; }; export fn seteuid(euid: *uid_t) (void | errno) = { wrap_return(syscall1(SYS_seteuid, euid: uintptr: u64))?; }; export fn setgid(gid: *gid_t) (void | errno) = { wrap_return(syscall1(SYS_setgid, gid: uintptr: u64))?; }; export fn setegid(egid: *gid_t) (void | errno) = { wrap_return(syscall1(SYS_setegid, egid: uintptr: u64))?; }; export fn sigaction( signum: int, act: *const sigact, old: nullable *sigact, ) (int | errno) = { return wrap_return(syscall3(SYS___sigaction_sigtramp, signum: u64, act: uintptr: u64, old: uintptr: u64))?: int; }; export fn sigprocmask( how: int, set: nullable *const sigset, old: nullable *sigset, ) (int | errno) = { return wrap_return(syscall3(SYS___sigprocmask14, how: u64, set: uintptr: u64, old: uintptr: u64))?: int; }; export fn open( path: path, flags: int, mode: uint, ) (int | errno) = { let path = kpath(path)?; return wrap_return(syscall3(SYS_open, path: uintptr: u64, flags: u64, mode: u64))?: int; }; export fn fstat(fd: int, _stat: *st) (void | errno) = { let sb = stat { ... }; wrap_return(syscall2(SYS___fstat50, fd: u64, &sb: uintptr: u64))?; _stat.dev = sb.st_dev; _stat.ino = sb.st_ino; _stat.mode = sb.st_mode; _stat.nlink = sb.st_nlink; _stat.uid = sb.st_uid; _stat.gid = sb.st_gid; _stat.rdev = sb.st_rdev; _stat.atime.tv_sec = sb.st_atim.tv_sec; _stat.atime.tv_nsec = sb.st_atim.tv_nsec: i64; _stat.mtime.tv_sec = sb.st_mtim.tv_sec; _stat.mtime.tv_nsec = sb.st_mtim.tv_nsec: i64; _stat.ctime.tv_sec = sb.st_ctim.tv_sec; _stat.ctime.tv_nsec = sb.st_ctim.tv_nsec: i64; _stat.btime.tv_sec = sb.st_birthtim.tv_sec; _stat.btime.tv_nsec = sb.st_birthtim.tv_nsec: i64; _stat.sz = sb.st_size; _stat.blocks = sb.st_blocks; _stat.blksz = sb.st_blksize; _stat.flags = sb.st_flags; }; export fn fexecve(fd: int, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8) errno = { return match (wrap_return(syscall3(SYS_fexecve, fd: u64, argv: uintptr: u64, envp: uintptr: u64))) { case let err: errno => yield err; case u64 => abort("unreachable"); }; }; export type ioctl_arg = (nullable *opaque | u64); export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = { let fd = fd: u64, req = req: u64; return wrap_return(match (arg) { case let u: u64 => yield syscall3(SYS_ioctl, fd, req, u); case let v: nullable *opaque => yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64); })?: int; }; export fn posix_openpt(flags: int) (int | errno) = { return open("/dev/ptmx", flags, 0); }; export fn sigaltstack( ss: nullable *stack_t, old_ss: nullable *stack_t, ) (void | errno) = { wrap_return(syscall2(SYS___sigaltstack14, ss: uintptr: u64, old_ss: uintptr: u64))?; }; export fn ppoll( fds: *[*]pollfd, nfds: nfds_t, timeout: const nullable *timespec, sigmask: const nullable *sigset, ) (int | errno) = { return wrap_return(syscall4(SYS___pollts50, fds: uintptr: u64, nfds: u64, timeout: uintptr: u64, sigmask: uintptr: u64))?: int; }; export fn getrandom(buf: *opaque, bufln: size, flags: uint) (size | errno) = { return wrap_return(syscall3(SYS_getrandom, buf: uintptr: u64, bufln: u64, flags: u64))?: size; }; export fn paccept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, mask: nullable *int, flags: int) (int | errno) = { return wrap_return(syscall5(SYS_paccept, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, mask: uintptr: u64, flags: u64))?: int; }; export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { return paccept(sockfd, addr, addrlen, null, flags); }; export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_sendmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { return wrap_return(syscall3(SYS_recvmsg, fd: u64, msg: uintptr: u64, flags: u64))?: int; }; export fn shutdown(sockfd: int, how: int) (void | errno) = { wrap_return(syscall2(SYS_shutdown, sockfd: u64, how: u64))?; }; export fn socket(domain: int, type_: int, protocol: int) (int | errno) = { return wrap_return(syscall3(SYS___socket30, domain: u64, type_: u64, protocol: u64))?: int; }; export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_connect, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { return wrap_return(syscall3(SYS_bind, sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; }; export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getsockname, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return sendto(sockfd, buf, len_, flags, null, 0); }; export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int, dest_addr: nullable *sockaddr, addrlen: u32 ) (size | errno) = { return wrap_return(syscall6(SYS_sendto, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, dest_addr: uintptr: u64, addrlen: u64))?: size; }; export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { return recvfrom(sockfd, buf, len_, flags, null, null); }; export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = { return wrap_return(syscall5(SYS_setsockopt, sockfd: u64, level: u64, optname: u64, optval: uintptr: u64, optlen: u64))?: int; }; export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int, src_addr: nullable *sockaddr, addrlen: nullable *u32 ) (size | errno) = { return wrap_return(syscall6(SYS_recvfrom, sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, src_addr: uintptr: u64, addrlen: uintptr: u64))?: size; }; export fn listen(sockfd: int, backlog: u32) (int | errno) = { return wrap_return(syscall2(SYS_listen, sockfd: u64, backlog: u64))?: int; }; export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { return wrap_return(syscall3(SYS_getpeername, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; }; export fn socketpair( domain: int, type_: int, protocol: int, sv: *[*]int, ) (int | errno) = { return wrap_return(syscall4(SYS_socketpair, domain: u64, type_: u64, protocol: u64, sv: uintptr : u64))?: int; }; hare-0.24.2/rt/+netbsd/sysctl.ha000066400000000000000000000305061464473310100163370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Taken from NetBSD's sys/sysctl.h export def CTL_KERN: u32 = 1; // "high kernel": proc, limits export def CTL_VM: u32 = 2; // virtual memory export def CTL_VFS: u32 = 3; // file system, mount type is next export def CTL_NET: u32 = 4; // network, see socket.h export def CTL_DEBUG: u32 = 5; // debugging parameters export def CTL_HW: u32 = 6; // generic CPU/io export def CTL_MACHDEP: u32 = 7; // machine dependent export def CTL_USER: u32 = 8; // user-level export def CTL_DDB: u32 = 9; // in-kernel debugger export def CTL_PROC: u32 = 10; // per-proc attr export def CTL_VENDOR: u32 = 11; // vendor-specific data export def CTL_EMUL: u32 = 12; // emulation-specific data export def CTL_SECURITY: u32 = 13; // security export def KERN_OSTYPE: u32 = 1; // string: system version export def KERN_OSRELEASE: u32 = 2; // string: system release export def KERN_OSREV: u32 = 3; // int: system revision export def KERN_VERSION: u32 = 4; // string: compile time info export def KERN_MAXVNODES: u32 = 5; // int: max vnodes export def KERN_MAXPROC: u32 = 6; // int: max processes export def KERN_MAXFILES: u32 = 7; // int: max open files export def KERN_ARGMAX: u32 = 8; // int: max arguments to exec export def KERN_SECURELVL: u32 = 9; // int: system security level export def KERN_HOSTNAME: u32 = 10; // string: hostname export def KERN_HOSTID: u32 = 11; // int: host identifier export def KERN_CLOCKRATE: u32 = 12; // struct: struct clockinfo export def KERN_VNODE: u32 = 13; // struct: vnode structures export def KERN_PROC: u32 = 14; // struct: process entries export def KERN_FILE: u32 = 15; // struct: file entries export def KERN_PROF: u32 = 16; // node: kernel profiling info export def KERN_POSIX1: u32 = 17; // int: POSIX.1 version export def KERN_NGROUPS: u32 = 18; // int: # of supplemental group ids export def KERN_JOB_CONTROL: u32 = 19; // int: is job control available export def KERN_SAVED_IDS: u32 = 20; // int: saved set-user/group-ID export def KERN_OBOOTTIME: u32 = 21; // struct: time kernel was booted export def KERN_DOMAINNAME: u32 = 22; // string: (YP) domainname export def KERN_MAXPARTITIONS: u32 = 23; // int: number of partitions/disk export def KERN_RAWPARTITION: u32 = 24; // int: raw partition number export def KERN_NTPTIME: u32 = 25; // struct: extended-precision time export def KERN_TIMEX: u32 = 26; // struct: ntp timekeeping state export def KERN_AUTONICETIME: u32 = 27; // int: proc time before autonice export def KERN_AUTONICEVAL: u32 = 28; // int: auto nice value export def KERN_RTC_OFFSET: u32 = 29; // int: offset of rtc from gmt export def KERN_ROOT_DEVICE: u32 = 30; // string: root device export def KERN_MSGBUFSIZE: u32 = 31; // int: max # of chars in msg buffer export def KERN_FSYNC: u32 = 32; // int: file synchronization support export def KERN_OLDSYSVMSG: u32 = 33; // old: SysV message queue support export def KERN_OLDSYSVSEM: u32 = 34; // old: SysV semaphore support export def KERN_OLDSYSVSHM: u32 = 35; // old: SysV shared memory support export def KERN_OLDSHORTCORENAME: u32 = 36; // old, unimplemented export def KERN_SYNCHRONIZED_IO: u32 = 37; // int: POSIX synchronized I/O export def KERN_IOV_MAX: u32 = 38; // int: max iovec's for readv(2) etc. export def KERN_MBUF: u32 = 39; // node: mbuf parameters export def KERN_MAPPED_FILES: u32 = 40; // int: POSIX memory mapped files export def KERN_MEMLOCK: u32 = 41; // int: POSIX memory locking export def KERN_MEMLOCK_RANGE: u32 = 42; // int: POSIX memory range locking export def KERN_MEMORY_PROTECTION: u32 = 43; // int: POSIX memory protections export def KERN_LOGIN_NAME_MAX: u32 = 44; // int: max length login name + NUL export def KERN_DEFCORENAME: u32 = 45; // old: sort core name format export def KERN_LOGSIGEXIT: u32 = 46; // int: log signaled processes export def KERN_PROC2: u32 = 47; // struct: process entries export def KERN_PROC_ARGS: u32 = 48; // struct: process argv/env export def KERN_FSCALE: u32 = 49; // int: fixpt FSCALE export def KERN_CCPU: u32 = 50; // old: fixpt ccpu export def KERN_CP_TIME: u32 = 51; // struct: CPU time counters export def KERN_OLDSYSVIPC_INFO: u32 = 52; // old: number of valid kern ids export def KERN_MSGBUF: u32 = 53; // kernel message buffer export def KERN_CONSDEV: u32 = 54; // dev_t: console terminal device export def KERN_MAXPTYS: u32 = 55; // int: maximum number of ptys export def KERN_PIPE: u32 = 56; // node: pipe limits export def KERN_MAXPHYS: u32 = 57; // int: kernel value of MAXPHYS export def KERN_SBMAX: u32 = 58; // int: max socket buffer size export def KERN_TKSTAT: u32 = 59; // tty in/out counters export def KERN_MONOTONIC_CLOCK: u32 = 60; // int: POSIX monotonic clock export def KERN_URND: u32 = 61; // int: random integer from urandom export def KERN_LABELSECTOR: u32 = 62; // int: disklabel sector export def KERN_LABELOFFSET: u32 = 63; // int: offset of label within sector export def KERN_LWP: u32 = 64; // struct: lwp entries export def KERN_FORKFSLEEP: u32 = 65; // int: sleep length on failed fork export def KERN_POSIX_THREADS: u32 = 66; // int: POSIX Threads option export def KERN_POSIX_SEMAPHORES: u32 = 67; // int: POSIX Semaphores option export def KERN_POSIX_BARRIERS: u32 = 68; // int: POSIX Barriers option export def KERN_POSIX_TIMERS: u32 = 69; // int: POSIX Timers option export def KERN_POSIX_SPIN_LOCKS: u32 = 70; // int: POSIX Spin Locks option export def KERN_POSIX_READER_WRITER_LOCKS: u32 = 71; // int: POSIX R/W Locks option export def KERN_DUMP_ON_PANIC: u32 = 72; // int: dump on panic export def KERN_SOMAXKVA: u32 = 73; // int: max socket kernel virtual mem export def KERN_ROOT_PARTITION: u32 = 74; // int: root partition export def KERN_DRIVERS: u32 = 75; // struct: driver names and majors #s export def KERN_BUF: u32 = 76; // struct: buffers export def KERN_FILE2: u32 = 77; // struct: file entries export def KERN_VERIEXEC: u32 = 78; // node: verified exec export def KERN_CP_ID: u32 = 79; // struct: cpu id numbers export def KERN_HARDCLOCK_TICKS: u32 = 80; // int: number of hardclock ticks export def KERN_ARND: u32 = 81; // void *buf, size_t siz random export def KERN_SYSVIPC: u32 = 82; // node: SysV IPC parameters export def KERN_BOOTTIME: u32 = 83; // struct: time kernel was booted export def KERN_EVCNT: u32 = 84; // struct: evcnts export def KERN_SOFIXEDBUF: u32 = 85; // bool: fixed socket buffer sizes export def KERN_PROC_ALL: u32 = 0; // everything export def KERN_PROC_PID: u32 = 1; // by process id export def KERN_PROC_PGRP: u32 = 2; // by process group id export def KERN_PROC_SESSION: u32 = 3; // by session of pid export def KERN_PROC_TTY: u32 = 4; // by controlling tty export def KERN_PROC_UID: u32 = 5; // by effective uid export def KERN_PROC_RUID: u32 = 6; // by real uid export def KERN_PROC_GID: u32 = 7; // by effective gid export def KERN_PROC_RGID: u32 = 8; // by real gid export def KERN_PROC_TTY_NODEV: u32 = NODEV: u32; // no controlling tty export def KERN_PROC_TTY_REVOKE: u32 = -2; // revoked tty export def KERN_PROC_ARGV: u32 = 1; // argv export def KERN_PROC_NARGV: u32 = 2; // number of strings in above export def KERN_PROC_ENV: u32 = 3; // environ export def KERN_PROC_NENV: u32 = 4; // number of strings in above export def KERN_PROC_PATHNAME: u32 = 5; // path to executable export def KERN_PROC_CWD: u32 = 6; // current working dir export def KERN_SYSVIPC_INFO: u32 = 1; // struct: number of valid kern ids export def KERN_SYSVIPC_MSG: u32 = 2; // int: SysV message queue support export def KERN_SYSVIPC_SEM: u32 = 3; // int: SysV semaphore support export def KERN_SYSVIPC_SHM: u32 = 4; // int: SysV shared memory support export def KERN_SYSVIPC_SHMMAX: u32 = 5; // int: max shared memory segment size (bytes) export def KERN_SYSVIPC_SHMMNI: u32 = 6; // int: max number of shared memory identifiers export def KERN_SYSVIPC_SHMSEG: u32 = 7; // int: max shared memory segments per process export def KERN_SYSVIPC_SHMMAXPGS: u32 = 8; // int: max amount of shared memory (pages) export def KERN_SYSVIPC_SHMUSEPHYS: u32 = 9; // int: physical memory usage export def KERN_SYSVIPC_MSG_INFO: u32 = 4; // msginfo and msgid_ds export def KERN_SYSVIPC_SEM_INFO: u32 = 5; // seminfo and semid_ds export def KERN_SYSVIPC_SHM_INFO: u32 = 6; // shminfo and shmid_ds export def KERN_TKSTAT_NIN: u32 = 1; // total input character export def KERN_TKSTAT_NOUT: u32 = 2; // total output character export def KERN_TKSTAT_CANCC: u32 = 3; // canonical input character export def KERN_TKSTAT_RAWCC: u32 = 4; // raw input character export def KERN_BUF_ALL: u32 = 0; // all buffers export def KERN_BUFSLOP: u32 = 20; export def KERN_FILE_BYFILE: u32 = 1; export def KERN_FILE_BYPID: u32 = 2; export def KERN_FILESLOP: u32 = 10; export def KERN_EVCNT_COUNT_ANY: u32 = 0; export def KERN_EVCNT_COUNT_NONZERO: u32 = 1; export def HW_MACHINE: u32 = 1; // string: machine class export def HW_MODEL: u32 = 2; // string: specific machine model export def HW_NCPU: u32 = 3; // int: number of cpus export def HW_BYTEORDER: u32 = 4; // int: machine byte order export def HW_PHYSMEM: u32 = 5; // int: total memory (bytes) export def HW_USERMEM: u32 = 6; // int: non-kernel memory (bytes) export def HW_PAGESIZE: u32 = 7; // int: software page size export def HW_DISKNAMES: u32 = 8; // string: disk drive names export def HW_IOSTATS: u32 = 9; // struct: iostats[] export def HW_MACHINE_ARCH: u32 = 10; // string: machine architecture export def HW_ALIGNBYTES: u32 = 11; // int: ALIGNBYTES for the kernel export def HW_CNMAGIC: u32 = 12; // string: console magic sequence(s) export def HW_PHYSMEM64: u32 = 13; // quad: total memory (bytes) export def HW_USERMEM64: u32 = 14; // quad: non-kernel memory (bytes) export def HW_IOSTATNAMES: u32 = 15; // string: iostat names export def HW_NCPUONLINE: u32 = 16; // number CPUs online export def USER_CS_PATH: u32 = 1; // string: _CS_PATH export def USER_BC_BASE_MAX: u32 = 2; // int: BC_BASE_MAX export def USER_BC_DIM_MAX: u32 = 3; // int: BC_DIM_MAX export def USER_BC_SCALE_MAX: u32 = 4; // int: BC_SCALE_MAX export def USER_BC_STRING_MAX: u32 = 5; // int: BC_STRING_MAX export def USER_COLL_WEIGHTS_MAX: u32 = 6; // int: COLL_WEIGHTS_MAX export def USER_EXPR_NEST_MAX: u32 = 7; // int: EXPR_NEST_MAX export def USER_LINE_MAX: u32 = 8; // int: LINE_MAX export def USER_RE_DUP_MAX: u32 = 9; // int: RE_DUP_MAX export def USER_POSIX2_VERSION: u32 = 10; // int: POSIX2_VERSION export def USER_POSIX2_C_BIND: u32 = 11; // int: POSIX2_C_BIND export def USER_POSIX2_C_DEV: u32 = 12; // int: POSIX2_C_DEV export def USER_POSIX2_CHAR_TERM: u32 = 13; // int: POSIX2_CHAR_TERM export def USER_POSIX2_FORT_DEV: u32 = 14; // int: POSIX2_FORT_DEV export def USER_POSIX2_FORT_RUN: u32 = 15; // int: POSIX2_FORT_RUN export def USER_POSIX2_LOCALEDEF: u32 = 16; // int: POSIX2_LOCALEDEF export def USER_POSIX2_SW_DEV: u32 = 17; // int: POSIX2_SW_DEV export def USER_POSIX2_UPE: u32 = 18; // int: POSIX2_UPE export def USER_STREAM_MAX: u32 = 19; // int: POSIX2_STREAM_MAX export def USER_TZNAME_MAX: u32 = 20; // int: _POSIX_TZNAME_MAX export def USER_ATEXIT_MAX: u32 = 21; // int: {ATEXIT_MAX} export def PROC_CURPROC: u32 = ~(1 << 31); export def PROC_PID_CORENAME: u32 = 1; export def PROC_PID_LIMIT: u32 = 2; export def PROC_PID_STOPFORK: u32 = 3; export def PROC_PID_STOPEXEC: u32 = 4; export def PROC_PID_STOPEXIT: u32 = 5; export def PROC_PID_PAXFLAGS: u32 = 6; export def PROC_PID_LIMIT_CPU: u32 = (RLIMIT_CPU+1): u32; export def PROC_PID_LIMIT_FSIZE: u32 = (RLIMIT_FSIZE+1): u32; export def PROC_PID_LIMIT_DATA: u32 = (RLIMIT_DATA+1): u32; export def PROC_PID_LIMIT_STACK: u32 = (RLIMIT_STACK+1): u32; export def PROC_PID_LIMIT_CORE: u32 = (RLIMIT_CORE+1): u32; export def PROC_PID_LIMIT_RSS: u32 = (RLIMIT_RSS+1): u32; export def PROC_PID_LIMIT_MEMLOCK: u32 = (RLIMIT_MEMLOCK+1): u32; export def PROC_PID_LIMIT_NPROC: u32 = (RLIMIT_NPROC+1): u32; export def PROC_PID_LIMIT_NOFILE: u32 = (RLIMIT_NOFILE+1): u32; export def PROC_PID_LIMIT_SBSIZE: u32 = (RLIMIT_SBSIZE+1): u32; export def PROC_PID_LIMIT_AS: u32 = (RLIMIT_AS+1): u32; export def PROC_PID_LIMIT_NTHR: u32 = (RLIMIT_NTHR+1): u32; export def PROC_PID_LIMIT_TYPE_SOFT: u32 = 1; export def PROC_PID_LIMIT_TYPE_HARD: u32 = 2; export def EMUL_LINUX: u32 = 1; export def EMUL_LINUX32: u32 = 5; hare-0.24.2/rt/+netbsd/types.ha000066400000000000000000000366531464473310100161730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type time_t = i64; export type suseconds_t = i64; export type dev_t = u64; export type ino_t = u64; export type nlink_t = u64; export type id_t = uint; export type pid_t = u64; export type uid_t = u32; export type gid_t = u32; export type off_t = i64; export type blkcnt_t = i64; export type blksize_t = i32; export type fflags_t = u32; export type mode_t = u32; export type nfds_t = uint; export type rlim_t = u64; export type path = (str | []u8 | *const u8); // Maximum length of a file path including the NUL terminator. export def PATH_MAX = 1024z; // Max bytes in a file name export def NAME_MAX: int = 511; export def NGROUPS_MAX: size = 1023; export def NSIG: int = 32; export type sigset = struct { __bits: [4]u32, }; export def SA_ONSTACK: u64 = 0x0001; export def SA_RESTART: u64 = 0x0002; export def SA_RESETHAND: u64 = 0x0004; export def SA_NOCLDSTOP: u64 = 0x0008; export def SA_NODEFER: u64 = 0x0010; export def SA_NOCLDWAIT: u64 = 0x0020; export def SA_SIGINFO: u64 = 0x0040; export def SIG_ERR: uintptr = -1; export def SIG_DFL: uintptr = 0; export def SIG_IGN: uintptr = 1; export def SIG_CATCH: uintptr = 2; export def SIG_HOLD: uintptr = 3; export type sigact = struct { union { sa_handler: *fn (int) void, sa_sigaction: *fn (int, *siginfo, *opaque) void, }, sa_mask: sigset, sa_flags: int, }; export def SIG_BLOCK: int = 1; export def SIG_UNBLOCK: int = 2; export def SIG_SETMASK: int = 3; export type sigval = union { sival_t: int, sival_ptr: *opaque, }; export type stack_t = struct { ss_sp: *opaque, ss_size: size, ss_flags: int, }; export type pollfd = struct { fd: int, events: i16, revents: i16, }; export type timespec = struct { tv_sec: time_t, tv_nsec: i64, }; export def UTIME_OMIT = -0x2; export type timeval = struct { tv_sec: time_t, tv_usec: suseconds_t, }; export type st_flock = struct { l_start: off_t, l_len: off_t, l_pid: pid_t, l_type: i16, l_whence: i16, l_sysid: int, }; export type st = struct { dev: dev_t, ino: ino_t, nlink: nlink_t, mode: mode_t, uid: uid_t, gid: gid_t, rdev: dev_t, atime: timespec, mtime: timespec, ctime: timespec, btime: timespec, sz: off_t, blocks: blkcnt_t, blksz: blksize_t, flags: fflags_t, }; export type stat = struct { st_dev: u64, st_mode: mode_t, __pad0: u32, st_ino: u64, st_nlink: u32, st_uid: uid_t, st_gid: gid_t, __pad1: u32, st_rdev: u64, st_atim: timespec, st_mtim: timespec, st_ctim: timespec, st_birthtim: timespec, st_size: off_t, st_blocks: blkcnt_t, st_blksize: blksize_t, st_flags: fflags_t, st_gen: u32, st_spare: [2]u32, }; export type fsid_t = struct { __fsid_val: [2]u32, }; export def VFS_NAMELEN: int = 32; export def VFS_MNAMELEN: int = 1024; export type statvfs = struct { // copy of mount exported flags f_flag: u64, // file system block size f_bsize: u64, // fundamental file system block size f_frsize: u64, // optimal file system block size f_iosize: u64, // The following are in units of f_frsize // number of blocks in file system, f_blocks: u64, // free blocks avail in file system f_bfree: u64, // free blocks avail to non-root f_bavail: u64, // blocks reserved for root f_bresvd: u64, // total file nodes in file system f_files: u64, // free file nodes in file system f_ffree: u64, // free file nodes avail to non-root f_favail: u64, // file nodes reserved for root f_fresvd: u64, // count of sync reads since mount f_syncreads: u64, // count of sync writes since mount f_syncwrites: u64, // count of async reads since mount f_asyncreads: u64, // count of async writes since mount f_asyncwrites: u64, // NetBSD compatible fsid f_fsidx: fsid_t, // Posix compatible fsid f_fsid: u64, // maximum filename length f_namemax: u64, // user that mounted the file system f_owner: uid_t, __pad0: u32, // spare space f_spare: [4]u64, // fs type name f_fstypename: [VFS_NAMELEN]u8, // directory on which mounted f_mntonname: [VFS_MNAMELEN]u8, // mounted file system f_mntfromname: [VFS_MNAMELEN]u8, // disk label name if avail f_mntfromlabel: [VFS_MNAMELEN]u8, }; export type dirent = struct { // file number of entry d_fileno: ino_t, // length of this record d_reclen: u16, // length of d_name d_namlen: u16, // file type, see below d_type: u8, d_name: [NAME_MAX + 1]u8, }; export type iovec = struct { iov_base: *opaque, iov_len: size }; export type winsize = struct { ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, }; export type termios = struct { c_iflag: tcflag, c_oflag: tcflag, c_cflag: tcflag, c_lflag: tcflag, c_cc: [NCCS]cc, }; export def NCCS: size = 20; export type tcflag = enum uint { // c_iflag bits IGNBRK = 0x00000001, BRKINT = 0x00000002, IGNPAR = 0x00000004, PARMRK = 0x00000008, INPCK = 0x00000010, ISTRIP = 0x00000020, INLCR = 0x00000040, IGNCR = 0x00000080, ICRNL = 0x00000100, IXON = 0x00000200, IXOFF = 0x00000400, IXANY = 0x00000800, IMAXBEL = 0x00002000, // c_oflag bits OPOST = 0x00000001, ONLCR = 0x00000002, TABDLY = 0x00000004, TAB0 = 0x00000000, TAB3 = 0x00000004, ONOEOT = 0x00000008, OCRNL = 0x00000010, ONOCR = 0x00000020, ONLRET = 0x00000040, // c_cflag bits CIGNORE = 0x00000001, CSIZE = 0x00000300, CS5 = 0x00000000, CS6 = 0x00000100, CS7 = 0x00000200, CS8 = 0x00000300, CSTOPB = 0x00000400, CREAD = 0x00000800, PARENB = 0x00001000, PARODD = 0x00002000, HUPCL = 0x00004000, CLOCAL = 0x00008000, CCTS_OFLOW = 0x00010000, CRTS_IFLOW = 0x00020000, CRTSCTS = (CCTS_OFLOW | CRTS_IFLOW), CDTR_IFLOW = 0x00040000, CDSR_OFLOW = 0x00080000, CCAR_OFLOW = 0x00100000, CNO_RTSDTR = 0x00200000, // c_lflag bits ECHOKE = 0x00000001, ECHOE = 0x00000002, ECHOK = 0x00000004, ECHO = 0x00000008, ECHONL = 0x00000010, ECHOPRT = 0x00000020, ECHOCTL = 0x00000040, ISIG = 0x00000080, ICANON = 0x00000100, ALTWERASE = 0x00000200, IEXTEN = 0x00000400, EXTPROC = 0x00000800, TOSTOP = 0x00400000, FLUSHO = 0x00800000, NOKERNINFO = 0x02000000, PENDIN = 0x20000000, NOFLSH = 0x80000000, }; export type cc = enum u8 { VEOF = 0, VEOL = 1, VEOL2 = 2, VERASE = 3, VWERASE = 4, VKILL = 5, VREPRINT = 6, VERASE2 = 7, VINTR = 8, VQUIT = 9, VSUSP = 10, VDSUSP = 11, VSTART = 12, VSTOP = 13, VLNEXT = 14, VDISCARD = 15, VMIN = 16, VTIME = 17, VSTATUS = 18, }; export def TIOCGWINSZ: u64 = 0x40087468; export def TIOCSWINSZ: u64 = 0x80087467; export def TIOCGETA: u64 = 0x402c7413; export def TIOCSETA: u64 = 0x802c7414; export def TIOCPTSNAME: u64 = 0x48087448; export def TIOCSPGRP: u64 = 0x80047476; export def FIODGNAME: u64 = 0x80106678; export type ptmget = struct { cfd: int, sfd: int, cn: [PATH_MAX]u8, sn: [PATH_MAX]u8, }; export type rusage = struct { // user time used ru_utime: timeval, // system time used ru_stime: timeval, // max resident set size ru_maxrss: i64, // integral shared memory size ru_ixrss: i64, // integral unshared data " ru_idrss: i64, // integral unshared stack " ru_isrss: i64, // page reclaims ru_minflt: i64, // page faults ru_majflt: i64, // swaps ru_nswap: i64, // block input operations ru_inblock: i64, // block output operations ru_oublock: i64, // messages sent ru_msgsnd: i64, // messages received ru_msgrcv: i64, // signals received ru_nsignals: i64, // voluntary context switches ru_nvcsw: i64, // involuntary " ru_nivcsw: i64, }; export def DT_UNKNOWN: u8 = 0; export def DT_FIFO: u8 = 1; export def DT_CHR: u8 = 2; export def DT_DIR: u8 = 4; export def DT_BLK: u8 = 6; export def DT_REG: u8 = 8; export def DT_LNK: u8 = 10; export def DT_SOCK: u8 = 12; export def DT_WHT: u8 = 14; export def O_RDONLY: int = 0x0000; export def O_WRONLY: int = 0x0001; export def O_RDWR: int = 0x0002; export def O_ACCMODE: int = 0x0003; export def O_NONBLOCK: int = 0x0004; export def O_APPEND: int = 0x0008; export def O_SHLOCK: int = 0x0010; export def O_EXLOCK: int = 0x0020; export def O_ASYNC: int = 0x0040; export def O_FSYNC: int = 0x0080; export def O_SYNC: int = 0x0080; export def O_NOFOLLOW: int = 0x0100; export def O_CREAT: int = 0x0200; export def O_TRUNC: int = 0x0400; export def O_EXCL: int = 0x0800; export def O_NOCTTY: int = 0x8000; export def O_DIRECT: int = 0x00010000; export def O_DIRECTORY: int = 0x00020000; export def O_EXEC: int = 0x00040000; export def O_TTY_INIT: int = 0x00080000; export def O_CLOEXEC: int = 0x00400000; export def O_DSYNC: int = 0x01000000; export def O_RSYNC: int = 0x00020000; export def AT_FDCWD: int = -100; export def AT_EACCESS: int = 0x0100; export def AT_SYMLINK_NOFOLLOW: int = 0x0200; export def AT_SYMLINK_FOLLOW: int = 0x0400; export def AT_REMOVEDIR: int = 0x0800; export def AT_RESOLVE_BENEATH: int = 0x2000; // set user id on execution export def S_ISUID: u64 = 0o004000; // set group id on execution export def S_ISGID: u64 = 0o002000; // sticky bit export def S_ISTXT: u64 = 0o001000; // RWX mask for owner export def S_IRWXU: u64 = 0o000700; // R for owner export def S_IRUSR: u64 = 0o000400; // W for owner export def S_IWUSR: u64 = 0o000200; // X for owner export def S_IXUSR: u64 = 0o000100; export def S_IREAD: u64 = S_IRUSR; export def S_IWRITE: u64 = S_IWUSR; export def S_IEXEC: u64 = S_IXUSR; // RWX mask for group export def S_IRWXG: u64 = 0o000070; // R for group export def S_IRGRP: u64 = 0o000040; // W for group export def S_IWGRP: u64 = 0o000020; // X for group export def S_IXGRP: u64 = 0o000010; // RWX mask for other export def S_IRWXO: u64 = 0o000007; // R for other export def S_IROTH: u64 = 0o000004; // W for other export def S_IWOTH: u64 = 0o000002; // X for other export def S_IXOTH: u64 = 0o000001; // type of file mask export def S_IFMT: u64 = 0o170000; // named pipe (fifo) export def S_IFIFO: u64 = 0o010000; // character special export def S_IFCHR: u64 = 0o020000; // directory export def S_IFDIR: u64 = 0o040000; // block special export def S_IFBLK: u64 = 0o060000; // regular export def S_IFREG: u64 = 0o100000; // symbolic link export def S_IFLNK: u64 = 0o120000; // save swapped text even after use export def S_ISVTX: u64 = 0o001000; // socket export def S_IFSOCK: u64 = 0o140000; // whiteout export def S_IFWHT: u64 = 0o160000; // Archive state 1, ls -l shows 'a' export def S_ARCH1: u64 = 0o200000; // Archive state 2, ls -l shows 'A' export def S_ARCH2: u64 = 0o400000; export def MAP_SHARED: uint = 0x0001; export def MAP_PRIVATE: uint = 0x0002; export def MAP_FIXED: uint = 0x0010; export def MAP_HASSEMAPHORE: uint = 0x0200; export def MAP_STACK: uint = 0x0400; export def MAP_NOSYNC: uint = 0x0800; export def MAP_FILE: uint = 0x0000; export def MAP_ANON: uint = 0x1000; export def MAP_GUARD: uint = 0x00002000; export def MAP_EXCL: uint = 0x00004000; export def MAP_NOCORE: uint = 0x00020000; export def MAP_PREFAULT_READ: uint = 0x00040000; export def MAP_32BIT: uint = 0x00080000; export def PROT_NONE: uint = 0x00; export def PROT_READ: uint = 0x01; export def PROT_WRITE: uint = 0x02; export def PROT_EXEC: uint = 0x04; export def SIGHUP: int = 1; export def SIGINT: int = 2; export def SIGQUIT: int = 3; export def SIGILL: int = 4; export def SIGTRAP: int = 5; export def SIGABRT: int = 6; export def SIGIOT: int = SIGABRT; export def SIGEMT: int = 7; export def SIGFPE: int = 8; export def SIGKILL: int = 9; export def SIGBUS: int = 10; export def SIGSEGV: int = 11; export def SIGSYS: int = 12; export def SIGPIPE: int = 13; export def SIGALRM: int = 14; export def SIGTERM: int = 15; export def SIGURG: int = 16; export def SIGSTOP: int = 17; export def SIGTSTP: int = 18; export def SIGCONT: int = 19; export def SIGCHLD: int = 20; export def SIGTTIN: int = 21; export def SIGTTOU: int = 22; export def SIGIO: int = 23; export def SIGXCPU: int = 24; export def SIGXFSZ: int = 25; export def SIGVTALRM: int = 26; export def SIGPROF: int = 27; export def SIGWINCH: int = 28; export def SIGINFO: int = 29; export def SIGUSR1: int = 30; export def SIGUSR2: int = 31; export def SIGTHR: int = 32; export def SIGLWP: int = SIGTHR; export def SIGLIBRT: int = 33; export def F_DUPFD: int = 0; export def F_GETFD: int = 1; export def F_SETFD: int = 2; export def F_GETFL: int = 3; export def F_SETFL: int = 4; export def F_GETOWN: int = 5; export def F_SETOWN: int = 6; export def F_OGETLK: int = 7; export def F_OSETLK: int = 8; export def F_OSETLKW: int = 9; export def F_DUP2FD: int = 10; export def F_GETLK: int = 11; export def F_SETLK: int = 12; export def F_SETLKW: int = 13; export def F_SETLK_REMOTE: int = 14; export def F_READAHEAD: int = 15; export def F_RDAHEAD: int = 16; export def F_DUPFD_CLOEXEC: int = 12; export def F_DUP2FD_CLOEXEC: int = 18; export def F_ADD_SEALS: int = 16; export def F_GET_SEALS: int = 17; export def F_ISUNIONSTACK: int = 21; export def F_SEAL_SEAL: int = 0x0001; export def F_SEAL_SHRINK: int = 0x0002; export def F_SEAL_GROW: int = 0x0004; export def F_SEAL_WRITE: int = 0x0008; export def FD_CLOEXEC: int = 1; export def F_UNLCKSYS: int = 4; export def F_CANCEL: int = 5; export def F_RDLCK: i16 = 1; export def F_UNLCK: i16 = 2; export def F_WRLCK: i16 = 3; export def PRIO_PROCESS: int = 0; export def PRIO_PGRP: int = 1; export def PRIO_USER: int = 2; export def F_OK: int = 0; export def X_OK: int = 0x01; export def W_OK: int = 0x02; export def R_OK: int = 0x04; export def CLOCK_REALTIME: int = 0; export def CLOCK_VIRTUAL: int = 1; export def CLOCK_PROF: int = 2; export def CLOCK_MONOTONIC: int = 3; export def CLOCK_THREAD_CPUTIME_ID: int = 0x20000000; export def CLOCK_PROCESS_CPUTIME_ID: int = 0x40000000; export def WNOHANG: int = 1; export def WUNTRACED: int = 2; export def WSTOPPED: int = WUNTRACED; export def WCONTINUED: int = 4; export def WNOWAIT: int = 8; export def WEXITED: int = 16; export def WTRAPPED: int = 32; export def STDIN_FILENO: int = 0; export def STDOUT_FILENO: int = 1; export def STDERR_FILENO: int = 2; export def SEEK_SET: int = 0; export def SEEK_CUR: int = 1; export def SEEK_END: int = 2; // Flock operations export def LOCK_SH: int = 1; export def LOCK_EX: int = 2; export def LOCK_NB: int = 4; export def LOCK_UN: int = 8; export type rlimit = struct { rlim_cur: rlim_t, rlim_max: rlim_t, }; export def RLIM_INFINITY: rlim_t = -1; export def RLIMIT_CPU: int = 0; export def RLIMIT_FSIZE: int = 1; export def RLIMIT_DATA: int = 2; export def RLIMIT_STACK: int = 3; export def RLIMIT_CORE: int = 4; export def RLIMIT_RSS: int = 5; export def RLIMIT_MEMLOCK: int = 6; export def RLIMIT_NPROC: int = 7; export def RLIMIT_NOFILE: int = 8; export def RLIMIT_SBSIZE: int = 9; export def RLIMIT_VMEM: int = 10; export def RLIMIT_AS: int = RLIMIT_VMEM; export def RLIMIT_NPTS: int = 11; export def RLIMIT_SWAP: int = 12; export def RLIMIT_KQUEUES: int = 13; export def RLIMIT_UMTXP: int = 14; // number of threads export def RLIMIT_NTHR: int = 11; export def SHUT_RD: int = 0; export def SHUT_WR: int = 1; export def SHUT_RDWR: int = 2; // non-existent device export def NODEV: int = -1; // synchronously wait for I/O to complete export def MNT_WAIT: int = 1; // start all I/O, but do not wait for it export def MNT_NOWAIT: int = 2; // push data not written by filesystem syncer export def MNT_LAZY: int = 3; // Efficient memory file-system export def MOUNT_TMPFS = "tmpfs"; export def MOUNT_SHMFS = MOUNT_TMPFS; // Shared memory objects are supported using tmpfs. export def SHMFS_DIR_PATH = "/var/shm"; export def SHMFS_DIR_MODE = (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); export def SHMFS_OBJ_PREFIX = ".shmobj_"; hare-0.24.2/rt/+openbsd/000077500000000000000000000000001464473310100146535ustar00rootroot00000000000000hare-0.24.2/rt/+openbsd/+aarch64.ha000066400000000000000000000004231464473310100164670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sigcontext = struct { __sc_unused: int, sc_mask: int, sc_sp: u64, sc_lr: u64, sc_elr: u64, sc_spsr: u64, sc_x: [30]u64, sc_cookie: u64, }; export type ucontext = sigcontext; hare-0.24.2/rt/+openbsd/+riscv64.ha000066400000000000000000000005371464473310100165450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sigcontext = struct { __sc_unused: int, sc_mask: int, sc_ra: u64, sc_sp: u64, sc_gp: u64, sc_tp: u64, sc_t: [7]u64, sc_s: [12]u64, sc_a: [8]u64, sc_sepc: u64, sc_f: [32]u64, sc_fcsr: u64, sc_cookie: u64, }; export type ucontext = sigcontext; hare-0.24.2/rt/+openbsd/+x86_64.ha000066400000000000000000000014711464473310100162010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type sigcontext = struct { sc_rdi: u64, sc_rsi: u64, sc_rdx: u64, sc_rcx: u64, sc_r8: u64, sc_r9: u64, sc_r10: u64, sc_r11: u64, sc_r12: u64, sc_r13: u64, sc_r14: u64, sc_r15: u64, sc_rbp: u64, sc_rbx: u64, sc_rax: u64, sc_gs: u64, sc_fs: u64, sc_es: u64, sc_ds: u64, sc_trapno: u64, sc_err: u64, sc_rip: u64, sc_cs: u64, sc_rflags: u64, sc_rsp: u64, sc_ss: u64, sc_fpstate: *fxsave64, __sc_unused: int, sc_mask: int, sc_cookie: i64, }; export type fxsave64 = struct { fx_fcw: u16, fx_fsw: u16, fx_ftw: u8, fx_unused1: u8, fx_fop: u16, fx_rip: u64, fx_rdp: u64, fx_mxcsr: u32, fx_mxcsr_mask: u32, fx_st: [8][2]u64, fx_xmm: [16][2]u64, fx_unused3: [96]u8, }; export type ucontext = sigcontext; hare-0.24.2/rt/+openbsd/dynamic_linker.ha000066400000000000000000000007241464473310100201600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Functions and types for interacting with the dynamic linker. export type dl_info = struct { fname: nullable *u8, fbase: nullable *opaque, sname: nullable *u8, saddr: nullable *opaque, }; // dlopen // dlclose // dlsym // dladdr export @symbol("dladdr") fn dladdr(addr: *opaque, info: *dl_info) int; // dlctl // dlerror export @symbol("dlerror") fn dlerror() nullable *const u8; hare-0.24.2/rt/+openbsd/env.ha000066400000000000000000000003211464473310100157510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export let argc: size = 0; export let argv: *[*]*u8 = null: *[*]*u8; export let envp: *[*]nullable *u8 = null: *[*]nullable *u8; hare-0.24.2/rt/+openbsd/errno.ha000066400000000000000000000301771464473310100163220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // $OpenBSD: errno.h,v 1.25 2017/09/05 03:06:26 jsg Exp $ // Represents an error returned from the OpenBSD kernel. export type errno = !int; // Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not // permitted"). export fn strerror(err: errno) str = { switch (err) { case EPERM => return "Operation not permitted"; case ENOENT => return "No such file or directory"; case ESRCH => return "No such process"; case EINTR => return "Interrupted system call"; case EIO => return "Input/output error"; case ENXIO => return "Device not configured"; case E2BIG => return "Argument list too long"; case ENOEXEC => return "Exec format error"; case EBADF => return "Bad file descriptor"; case ECHILD => return "No child processes"; case EDEADLK => return "Resource deadlock avoided"; case ENOMEM => return "Cannot allocate memory"; case EACCES => return "Permission denied"; case EFAULT => return "Bad address"; case ENOTBLK => return "Block device required"; case EBUSY => return "Device busy"; case EEXIST => return "File exists"; case EXDEV => return "Cross-device link"; case ENODEV => return "Operation not supported by device"; case ENOTDIR => return "Not a directory"; case EISDIR => return "Is a directory"; case EINVAL => return "Invalid argument"; case ENFILE => return "Too many open files in system"; case EMFILE => return "Too many open files"; case ENOTTY => return "Inappropriate ioctl for device"; case ETXTBSY => return "Text file busy"; case EFBIG => return "File too large"; case ENOSPC => return "No space left on device"; case ESPIPE => return "Illegal seek"; case EROFS => return "Read-only file system"; case EMLINK => return "Too many links"; case EPIPE => return "Broken pipe"; case EDOM => return "Numerical argument out of domain"; case ERANGE => return "Result too large"; case EAGAIN => return "Resource temporarily unavailable"; case EINPROGRESS => return "Operation now in progress"; case EALREADY => return "Operation already in progress"; case ENOTSOCK => return "Socket operation on non-socket"; case EDESTADDRREQ => return "Destination address required"; case EMSGSIZE => return "Message too long"; case EPROTOTYPE => return "Protocol wrong type for socket"; case ENOPROTOOPT => return "Protocol not available"; case EPROTONOSUPPORT => return "Protocol not supported"; case ESOCKTNOSUPPORT => return "Socket type not supported"; case EOPNOTSUPP => return "Operation not supported"; case EPFNOSUPPORT => return "Protocol family not supported"; case EAFNOSUPPORT => return "Address family not supported by protocol family"; case EADDRINUSE => return "Address already in use"; case EADDRNOTAVAIL => return "Can't assign requested address"; case ENETDOWN => return "Network is down"; case ENETUNREACH => return "Network is unreachable"; case ENETRESET => return "Network dropped connection on reset"; case ECONNABORTED => return "Software caused connection abort"; case ECONNRESET => return "Connection reset by peer"; case ENOBUFS => return "No buffer space available"; case EISCONN => return "Socket is already connected"; case ENOTCONN => return "Socket is not connected"; case ESHUTDOWN => return "Can't send after socket shutdown"; case ETOOMANYREFS => return "Too many references: can't splice"; case ETIMEDOUT => return "Operation timed out"; case ECONNREFUSED => return "Connection refused"; case ELOOP => return "Too many levels of symbolic links"; case ENAMETOOLONG => return "File name too long"; case EHOSTDOWN => return "Host is down"; case EHOSTUNREACH => return "No route to host"; case ENOTEMPTY => return "Directory not empty"; case EPROCLIM => return "Too many processes"; case EUSERS => return "Too many users"; case EDQUOT => return "Disk quota exceeded"; case ESTALE => return "Stale NFS file handle"; case EREMOTE => return "Too many levels of remote in path"; case EBADRPC => return "RPC struct is bad"; case ERPCMISMATCH => return "RPC version wrong"; case EPROGUNAVAIL => return "RPC program not available"; case EPROGMISMATCH => return "Program version wrong"; case EPROCUNAVAIL => return "Bad procedure for program"; case ENOLCK => return "No locks available"; case ENOSYS => return "Function not implemented"; case EFTYPE => return "Inappropriate file type or format"; case EAUTH => return "Authentication error"; case ENEEDAUTH => return "Need authenticator"; case EIPSEC => return "IPsec processing failure"; case ENOATTR => return "Attribute not found"; case EILSEQ => return "Illegal byte sequence"; case ENOMEDIUM => return "No medium found"; case EMEDIUMTYPE => return "Wrong medium type"; case EOVERFLOW => return "Value too large to be stored in data type"; case ECANCELED => return "Operation canceled"; case EIDRM => return "Identifier removed"; case ENOMSG => return "No message of desired type"; case ENOTSUP => return "Not supported"; case EBADMSG => return "Bad message"; case ENOTRECOVERABLE => return "State not recoverable"; case EOWNERDEAD => return "Previous owner died"; case EPROTO => return "Protocol error"; case => return unknown_errno(err); }; }; // Gets the programmer-friendly name for an [[errno]] (e.g. EPERM). export fn errname(err: errno) str = { switch (err) { case EPERM => return "EPERM"; case ENOENT => return "ENOENT"; case ESRCH => return "ESRCH"; case EINTR => return "EINTR"; case EIO => return "EIO"; case ENXIO => return "ENXIO"; case E2BIG => return "E2BIG"; case ENOEXEC => return "ENOEXEC"; case EBADF => return "EBADF"; case ECHILD => return "ECHILD"; case EDEADLK => return "EDEADLK"; case ENOMEM => return "ENOMEM"; case EACCES => return "EACCES"; case EFAULT => return "EFAULT"; case ENOTBLK => return "ENOTBLK"; case EBUSY => return "EBUSY"; case EEXIST => return "EEXIST"; case EXDEV => return "EXDEV"; case ENODEV => return "ENODEV"; case ENOTDIR => return "ENOTDIR"; case EISDIR => return "EISDIR"; case EINVAL => return "EINVAL"; case ENFILE => return "ENFILE"; case EMFILE => return "EMFILE"; case ENOTTY => return "ENOTTY"; case ETXTBSY => return "ETXTBSY"; case EFBIG => return "EFBIG"; case ENOSPC => return "ENOSPC"; case ESPIPE => return "ESPIPE"; case EROFS => return "EROFS"; case EMLINK => return "EMLINK"; case EPIPE => return "EPIPE"; case EDOM => return "EDOM"; case ERANGE => return "ERANGE"; case EAGAIN => return "EAGAIN"; case EINPROGRESS => return "EINPROGRESS"; case EALREADY => return "EALREADY"; case ENOTSOCK => return "ENOTSOCK"; case EDESTADDRREQ => return "EDESTADDRREQ"; case EMSGSIZE => return "EMSGSIZE"; case EPROTOTYPE => return "EPROTOTYPE"; case ENOPROTOOPT => return "ENOPROTOOPT"; case EPROTONOSUPPORT => return "EPROTONOSUPPORT"; case ESOCKTNOSUPPORT => return "ESOCKTNOSUPPORT"; case EOPNOTSUPP => return "EOPNOTSUPP"; case EPFNOSUPPORT => return "EPFNOSUPPORT"; case EAFNOSUPPORT => return "EAFNOSUPPORT"; case EADDRINUSE => return "EADDRINUSE"; case EADDRNOTAVAIL => return "EADDRNOTAVAIL"; case ENETDOWN => return "ENETDOWN"; case ENETUNREACH => return "ENETUNREACH"; case ENETRESET => return "ENETRESET"; case ECONNABORTED => return "ECONNABORTED"; case ECONNRESET => return "ECONNRESET"; case ENOBUFS => return "ENOBUFS"; case EISCONN => return "EISCONN"; case ENOTCONN => return "ENOTCONN"; case ESHUTDOWN => return "ESHUTDOWN"; case ETOOMANYREFS => return "ETOOMANYREFS"; case ETIMEDOUT => return "ETIMEDOUT"; case ECONNREFUSED => return "ECONNREFUSED"; case ELOOP => return "ELOOP"; case ENAMETOOLONG => return "ENAMETOOLONG"; case EHOSTDOWN => return "EHOSTDOWN"; case EHOSTUNREACH => return "EHOSTUNREACH"; case ENOTEMPTY => return "ENOTEMPTY"; case EPROCLIM => return "EPROCLIM"; case EUSERS => return "EUSERS"; case EDQUOT => return "EDQUOT"; case ESTALE => return "ESTALE"; case EREMOTE => return "EREMOTE"; case EBADRPC => return "EBADRPC"; case ERPCMISMATCH => return "ERPCMISMATCH"; case EPROGUNAVAIL => return "EPROGUNAVAIL"; case EPROGMISMATCH => return "EPROGMISMATCH"; case EPROCUNAVAIL => return "EPROCUNAVAIL"; case ENOLCK => return "ENOLCK"; case ENOSYS => return "ENOSYS"; case EFTYPE => return "EFTYPE"; case EAUTH => return "EAUTH"; case ENEEDAUTH => return "ENEEDAUTH"; case EIPSEC => return "EIPSEC"; case ENOATTR => return "ENOATTR"; case EILSEQ => return "EILSEQ"; case ENOMEDIUM => return "ENOMEDIUM"; case EMEDIUMTYPE => return "EMEDIUMTYPE"; case EOVERFLOW => return "EOVERFLOW"; case ECANCELED => return "ECANCELED"; case EIDRM => return "EIDRM"; case ENOMSG => return "ENOMSG"; case ENOTSUP => return "ENOTSUP"; case EBADMSG => return "EBADMSG"; case ENOTRECOVERABLE => return "ENOTRECOVERABLE"; case EOWNERDEAD => return "EOWNERDEAD"; case EPROTO => return "EPROTO"; case => return unknown_errno(err); }; }; export def EPERM: errno = 1; export def ENOENT: errno = 2; export def ESRCH: errno = 3; export def EINTR: errno = 4; export def EIO: errno = 5; export def ENXIO: errno = 6; export def E2BIG: errno = 7; export def ENOEXEC: errno = 8; export def EBADF: errno = 9; export def ECHILD: errno = 10; export def EDEADLK: errno = 11; export def ENOMEM: errno = 12; export def EACCES: errno = 13; export def EFAULT: errno = 14; export def ENOTBLK: errno = 15; export def EBUSY: errno = 16; export def EEXIST: errno = 17; export def EXDEV: errno = 18; export def ENODEV: errno = 19; export def ENOTDIR: errno = 20; export def EISDIR: errno = 21; export def EINVAL: errno = 22; export def ENFILE: errno = 23; export def EMFILE: errno = 24; export def ENOTTY: errno = 25; export def ETXTBSY: errno = 26; export def EFBIG: errno = 27; export def ENOSPC: errno = 28; export def ESPIPE: errno = 29; export def EROFS: errno = 30; export def EMLINK: errno = 31; export def EPIPE: errno = 32; export def EDOM: errno = 33; export def ERANGE: errno = 34; export def EAGAIN: errno = 35; export def EWOULDBLOCK: errno = EAGAIN; export def EINPROGRESS: errno = 36; export def EALREADY: errno = 37; export def ENOTSOCK: errno = 38; export def EDESTADDRREQ: errno = 39; export def EMSGSIZE: errno = 40; export def EPROTOTYPE: errno = 41; export def ENOPROTOOPT: errno = 42; export def EPROTONOSUPPORT: errno = 43; export def ESOCKTNOSUPPORT: errno = 44; export def EOPNOTSUPP: errno = 45; export def EPFNOSUPPORT: errno = 46; export def EAFNOSUPPORT: errno = 47; export def EADDRINUSE: errno = 48; export def EADDRNOTAVAIL: errno = 49; export def ENETDOWN: errno = 50; export def ENETUNREACH: errno = 51; export def ENETRESET: errno = 52; export def ECONNABORTED: errno = 53; export def ECONNRESET: errno = 54; export def ENOBUFS: errno = 55; export def EISCONN: errno = 56; export def ENOTCONN: errno = 57; export def ESHUTDOWN: errno = 58; export def ETOOMANYREFS: errno = 59; export def ETIMEDOUT: errno = 60; export def ECONNREFUSED: errno = 61; export def ELOOP: errno = 62; export def ENAMETOOLONG: errno = 63; export def EHOSTDOWN: errno = 64; export def EHOSTUNREACH: errno = 65; export def ENOTEMPTY: errno = 66; export def EPROCLIM: errno = 67; export def EUSERS: errno = 68; export def EDQUOT: errno = 69; export def ESTALE: errno = 70; export def EREMOTE: errno = 71; export def EBADRPC: errno = 72; export def ERPCMISMATCH: errno = 73; export def EPROGUNAVAIL: errno = 74; export def EPROGMISMATCH: errno = 75; export def EPROCUNAVAIL: errno = 76; export def ENOLCK: errno = 77; export def ENOSYS: errno = 78; export def EFTYPE: errno = 79; export def EAUTH: errno = 80; export def ENEEDAUTH: errno = 81; export def EIPSEC: errno = 82; export def ENOATTR: errno = 83; export def EILSEQ: errno = 84; export def ENOMEDIUM: errno = 85; export def EMEDIUMTYPE: errno = 86; export def EOVERFLOW: errno = 87; export def ECANCELED: errno = 88; export def EIDRM: errno = 89; export def ENOMSG: errno = 90; export def ENOTSUP: errno = 91; export def EBADMSG: errno = 92; export def ENOTRECOVERABLE: errno = 93; export def EOWNERDEAD: errno = 94; export def EPROTO: errno = 95; hare-0.24.2/rt/+openbsd/hare+test.sc000066400000000000000000000002641464473310100170760ustar00rootroot00000000000000SECTIONS { .test_array : { PROVIDE(__test_array_start = .); KEEP(*(.test_array*)) PROVIDE(__test_array_end = .); } } INSERT AFTER .bss; /* .bss was choosen arbitrarily. */ hare-0.24.2/rt/+openbsd/hare.sc000066400000000000000000000000611464473310100161160ustar00rootroot00000000000000/* empty linker script; not needed for OpenBSD */hare-0.24.2/rt/+openbsd/libc.ha000066400000000000000000000006301464473310100160750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Miscellaneous libc functions export @symbol("arc4random_buf") fn arc4random_buf( buf: *opaque, nbytes: size ) void; @symbol("ptsname") fn libc_ptsname(flides: int) *u8; export fn ptsname(flides: int) (*u8 | errno) = { let res = libc_ptsname(flides); if (res == null) { return *__errno(): errno; }; return res; }; hare-0.24.2/rt/+openbsd/platform_abort.ha000066400000000000000000000011711464473310100202000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn strvec(s: str) iovec = { return iovec { iov_base = *(&s: **opaque), iov_len = len(s), }; }; fn platform_abort(path: *str, line: u64, col: u64, msg: str) never = { let linebuf: [U64_BUFSZ]u8 = [0...]; let colbuf: [U64_BUFSZ]u8 = [0...]; const iov = [ strvec("Abort: "), strvec(*path), strvec(":"), strvec(u64tos(linebuf, line)), strvec(":"), strvec(u64tos(colbuf, col)), strvec(": "), strvec(msg), strvec("\n"), ]; writev(STDERR_FILENO, &iov, len(iov): int): void; for (true) { kill(getpid(), SIGABRT): void; }; }; hare-0.24.2/rt/+openbsd/signal.ha000066400000000000000000000074321464473310100164500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // XXX: sigwaitinfo and sigtimedwait are not yet available in OpenBSD. Quoting // from OpenBSD's lib/libc/gen/sigwait.c: "need kernel to fill in more siginfo_t // bits first" // sigwait @symbol("sigwait") fn libc_sigwait(set: *sigset, sig: *int) int; export fn sigwait(set: *sigset, sig: *int) (void | errno) = { let res = libc_sigwait(set, sig); if (res != -1) { return *__errno(): errno; }; }; export fn alarm(sec: uint) uint = { let nval = itimerval { ... }; let oval = itimerval { ... }; nval.it_value.tv_sec = sec: time_t; setitimer(ITIMER_REAL, &nval, &oval)!; if (oval.it_value.tv_usec != 0) { oval.it_value.tv_sec += 1; }; return oval.it_value.tv_sec: uint; }; export def ITIMER_REAL: int = 0; export def ITIMER_VIRTUAL: int = 1; export def ITIMER_PROF: int = 2; export type itimerval = struct { it_interval: timeval, it_value: timeval, }; // setitimer @symbol("setitimer") fn libc_setitimer( which: int, newval: *itimerval, oldval: nullable *itimerval, ) int; export fn setitimer( which: int, newval: *itimerval, oldval: nullable *itimerval, ) (void | errno) = { let res = libc_setitimer(which, newval, oldval); if (res != -1) { return *__errno(): errno; }; }; // getitimer @symbol("getitimer") fn libc_getitimer( which: int, cur: *itimerval, ) int; export fn getitimer(which: int, cur: *itimerval) (void | errno) = { let res = libc_getitimer(which, cur); if (res != -1) { return *__errno(): errno; }; }; export fn sigemptyset(set: *sigset) void = { *set = 0; }; export fn sigaddset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return *__errno(): errno; }; *set |= 1u << (signum: uint - 1); }; export fn sigdelset(set: *sigset, signum: int) (void | errno) = { if (signum < 1 || signum > NSIG) { return *__errno(): errno; }; *set &= ~(1u << (signum: uint - 1)); }; export fn sigismember(set: *sigset, signum: int) (bool | errno) = { if (signum < 1 || signum > NSIG) { return *__errno(): errno; }; return (*set & (1u << (signum: uint - 1))) != 0; }; export fn sigfillset(set: *sigset) (void | errno) = { *set = ~0u; }; // Test sigset operations do not fail for valid signal numbers. @test fn sigset_valid_signum() void = { let set: sigset = 0; sigemptyset(&set); assert(!(sigismember(&set, 1) is errno), "Unexpected error"); assert(!(sigismember(&set, 15) is errno), "Unexpected error"); assert(!(sigismember(&set, NSIG) is errno), "Unexpected error"); assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigaddset(&set, 15) is errno), "Unexpected error"); assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error"); // It's ok to add a signal that is already present in the set. assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 1) is errno), "Unexpected error"); assert(!(sigdelset(&set, 15) is errno), "Unexpected error"); assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error"); // It's ok to delete a signal that is not present in the set. assert(!(sigdelset(&set, 10) is errno), "Unexpected error"); }; // Test sigset operations fail for invalid signal numbers. @test fn sigset_invalid_signum() void = { let set: sigset = 0; sigemptyset(&set); assert(sigismember(&set, -1) is errno, "Expected error"); assert(sigismember(&set, 0) is errno, "Expected error"); assert(sigismember(&set, NSIG + 1) is errno, "Expected error"); assert(sigaddset(&set, -1) is errno, "Expected error"); assert(sigaddset(&set, 0) is errno, "Expected error"); assert(sigaddset(&set, NSIG + 1) is errno, "Expected error"); assert(sigdelset(&set, -1) is errno, "Expected error"); assert(sigdelset(&set, 0) is errno, "Expected error"); assert(sigdelset(&set, NSIG + 1) is errno, "Expected error"); }; hare-0.24.2/rt/+openbsd/socket.ha000066400000000000000000000075711464473310100164670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type socklen_t = u32; export type sa_family_t = u8; export type in_addr = struct { s_addr: u32 }; export type sockaddr_in = struct { sin_len: u8, sin_family: sa_family_t, sin_port: u16, sin_addr: in_addr, __pad: [8]u8, }; export type in6_addr = struct { union { s6_addr: [16]u8, s6_addr16: [8]u16, s6_addr32: [4]u32, } }; export type sockaddr_in6 = struct { sin6_len: u8, sin6_family: sa_family_t, sin6_port: u16, sin6_flowinfo: u32, sin6_addr: in6_addr, sin6_scope_id: u32, }; export def UNIX_PATH_MAX: size = 104; export type sockaddr_un = struct { sun_len: u8, sun_family: sa_family_t, sun_path: [UNIX_PATH_MAX]u8, }; export type sockaddr = struct { union { in: sockaddr_in, in6: sockaddr_in6, un: sockaddr_un, }, }; export def SCM_RIGHTS: int = 0x01; export def SCM_TIMESTAMP: int = 0x04; export type msghdr = struct { msg_name: nullable *opaque, msg_namelen: socklen_t, msg_iov: nullable *[*]iovec, msg_iovlen: uint, msg_control: nullable *opaque, msg_controllen: socklen_t, msg_flags: int }; export type cmsghdr = struct { cmsg_len: socklen_t, cmsg_level: int, cmsg_type: int, }; export type cmsg = struct { hdr: cmsghdr, cmsg_data: [*]u8, }; export def SOCK_STREAM: int = 1; export def SOCK_DGRAM: int = 2; export def SOCK_RAW: int = 3; export def SOCK_RDM: int = 4; export def SOCK_SEQPACKET: int = 5; export def SOCK_CLOEXEC: int = 0x8000; export def SOCK_NONBLOCK: int = 0x4000; export def SOL_SOCKET: int = 0xffff; export def AF_UNSPEC: sa_family_t = 0; export def AF_UNIX: sa_family_t = 1; export def AF_LOCAL: sa_family_t = AF_UNIX; export def AF_INET: sa_family_t = 2; export def AF_IMPLINK: sa_family_t = 3; export def AF_PUP: sa_family_t = 4; export def AF_CHAOS: sa_family_t = 5; export def AF_NS: sa_family_t = 6; export def AF_ISO: sa_family_t = 7; export def AF_OSI: sa_family_t = AF_ISO; export def AF_ECMA: sa_family_t = 8; export def AF_DATAKIT: sa_family_t = 9; export def AF_CCITT: sa_family_t = 10; export def AF_SNA: sa_family_t = 11; export def AF_DECnet: sa_family_t = 12; export def AF_DLI: sa_family_t = 13; export def AF_LAT: sa_family_t = 14; export def AF_HYLINK: sa_family_t = 15; export def AF_APPLETALK: sa_family_t = 16; export def AF_ROUTE: sa_family_t = 17; export def AF_LINK: sa_family_t = 18; export def pseudo_AF_XTP: sa_family_t = 19; export def AF_COIP: sa_family_t = 20; export def AF_CNT: sa_family_t = 21; export def pseudo_AF_RTIP: sa_family_t = 22; export def AF_IPX: sa_family_t = 23; export def AF_INET6: sa_family_t = 24; export def pseudo_AF_PIP: sa_family_t = 25; export def AF_ISDN: sa_family_t = 26; export def AF_E164: sa_family_t = AF_ISDN; export def AF_NATM: sa_family_t = 27; export def AF_ENCAP: sa_family_t = 28; export def AF_SIP: sa_family_t = 29; export def AF_KEY: sa_family_t = 30; export def pseudo_AF_HDRCMPLT: sa_family_t = 31; export def SO_DEBUG: int = 0x0001; export def SO_ACCEPTCONN: int = 0x0002; export def SO_REUSEADDR: int = 0x0004; export def SO_KEEPALIVE: int = 0x0008; export def SO_DONTROUTE: int = 0x0010; export def SO_BROADCAST: int = 0x0020; export def SO_USELOOPBACK: int = 0x0040; export def SO_LINGER: int = 0x0080; export def SO_OOBINLINE: int = 0x0100; export def SO_REUSEPORT: int = 0x0200; export def SO_TIMESTAMP: int = 0x0800; export def SO_BINDANY: int = 0x1000; export def SO_ZEROIZE: int = 0x2000; export def SO_SNDBUF: int = 0x1001; export def SO_RCVBUF: int = 0x1002; export def SO_SNDLOWAT: int = 0x1003; export def SO_RCVLOWAT: int = 0x1004; export def SO_SNDTIMEO: int = 0x1005; export def SO_RCVTIMEO: int = 0x1006; export def SO_ERROR: int = 0x1007; export def SO_TYPE: int = 0x1008; export def SO_NETPROC: int = 0x1020; export def SO_RTABLE: int = 0x1021; export def SO_PEERCRED: int = 0x1022; export def SO_SPLICE: int = 0x1023; export def SO_DOMAIN: int = 0x1024; export def SO_PROTOCOL: int = 0x1025; hare-0.24.2/rt/+openbsd/start+test.ha000066400000000000000000000015021464473310100172730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The real main function. @symbol(".main") fn main() void; @symbol("__test_main") fn test_main() size; // The setup of envp and args is done here. This is called by crt0 before // normal init functions are called. export @symbol("preinit_hare") fn preinit_hare( c_argc: int, c_argv: *[*]*u8, c_envp: *[*]nullable *u8 ) void = { argc = c_argc: size; argv = c_argv; envp = c_envp; }; // The purpose of this "fake" main function is to make sure we exit with the // correct exit code in the case that rt::exit() is not called from within the // program. The intilization and finilization functions are not run from here, // they are ran by crt0. export @symbol("main") fn _main() void = { const ret = if (test_main() > 0) 1 else 0; exit(ret); }; hare-0.24.2/rt/+openbsd/start.ha000066400000000000000000000013601464473310100163220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // The real main function. @symbol(".main") fn main() void; // The setup of envp and args is done here. This is called by crt0 before // normal init functions are called. export @symbol("preinit_hare") fn preinit_hare( c_argc: int, c_argv: *[*]*u8, c_envp: *[*]nullable *u8 ) void = { argc = c_argc: size; argv = c_argv; envp = c_envp; }; // The purpose of this "fake" main function is to make sure we exit with the // correct exit code in the case that rt::exit() is not called from within the // program. The intilization and finilization functions are not run from here, // they are ran by crt0. export @symbol("main") fn _main() void = { main(); exit(0); }; hare-0.24.2/rt/+openbsd/start.s000066400000000000000000000001141464473310100161700ustar00rootroot00000000000000.section ".preinit_array" .balign 8 .init.initfunc.0: .quad preinit_hare+0 hare-0.24.2/rt/+openbsd/syscalls.ha000066400000000000000000000701041464473310100170240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors let pathbuf: [PATH_MAX]u8 = [0...]; // For functions that need more than one path, i.e. unveil, linkat, renameat, etc. let pathbuf1: [PATH_MAX]u8 = [0...]; export type path = (str | []u8 | *const u8); fn copy_cpath(path: path, buf: []u8) (*const u8 | errno) = { let path = match (path) { case let c: *const u8 => return c; case let s: str => let ptr = &s: *struct { buf: *[*]u8, length: size, capacity: size, }; yield ptr.buf[..ptr.length]; case let b: []u8 => yield b; }; if (len(path) + 1 >= len(buf)) { return ENAMETOOLONG; }; memcpy(buf: *[*]u8, path: *[*]u8, len(path)); buf[len(path)] = 0; return buf: *[*]u8: *const u8; }; // NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in // length. fn cpath(path: path) (*const u8 | errno) = { return copy_cpath(path, pathbuf); }; // /usr/include/errno.h: #define errno (*__errno()) @symbol("__errno") fn __errno() *int; // exit export @symbol("exit") fn exit(status: int) never; // fork @symbol("fork") fn libc_fork() int; export fn fork() (int | void | errno) = { let res = libc_fork(); if (res == -1) { return *__errno(): errno; }; if (res == 0) { return; }; return res; }; // read @symbol("read") fn libc_read(d: int, buf: *opaque, nbytes: size) size; export fn read(fd: int, buf: *opaque, count: size) (size | errno) = { let res: u64 = libc_read(fd, buf, count); if (res == -1) { return *__errno(): errno; }; return res; }; // write @symbol("write") fn libc_write(d: int, buf: *const opaque, nbytes: size) size; export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = { let res: u64 = libc_write(fd, buf, count); if (res == -1) { return *__errno(): errno; }; return res; }; // open @symbol("open") fn libc_open(path: *opaque, flags: int, mode: int) int; export fn open(path: path, flags: int, mode: int) (int | errno) = { let res = libc_open(cpath(path)?, flags, mode); if (res == -1) { return *__errno(): errno; }; return res; }; // posix_openpt (libc function not a syscall) @symbol("posix_openpt") fn libc_openpt(oflag: int) int; export fn posix_openpt(flags: int) (int | errno) = { let res = libc_openpt(flags); if (res == -1) { return *__errno(): errno; }; return res; }; // close @symbol("close") fn libc_close(d: int) int; export fn close(fd: int) (void | errno) = { let res = libc_close(fd); if (res == -1) { return *__errno(): errno; }; }; // getentropy // __tfork // link // unlink // wait4 @symbol("wait4") fn libc_wait4( wpid: pid_t, status: nullable *int, options: int, rusage: nullable *rusage ) pid_t; export fn wait4( pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, ) (pid_t | errno) = { let res = libc_wait4(pid, wstatus, options, rusage); if (res == -1) { return *__errno(): errno; }; return res; }; // chdir @symbol("chdir") fn libc_chdir(path: *const u8) int; export fn chdir(path: path) (void | errno) = { let res = libc_chdir(cpath(path)?); if (res == -1) { return *__errno(): errno; }; }; // fchdir @symbol("fchdir") fn libc_fchdir(fd: int) int; export fn fchdir(fd: int) (void | errno) = { let res = libc_fchdir(fd); if (res == -1) { return *__errno(): errno; }; }; // mknod // chmod // chown // obreak // getdtablecount // getrusage // getpid export @symbol("getpid") fn getpid() pid_t; // mount // unmount // setuid @symbol("setuid") fn libc_setuid(uid: uid_t) int; export fn setuid(uid: uid_t) (void | errno) = { let res = libc_setuid(uid); if (res == -1) { return *__errno(): errno; }; }; // getuid export @symbol("getuid") fn getuid() uid_t; // geteuid export @symbol("geteuid") fn geteuid() uid_t; // ptrace // recvmsg @symbol("recvmsg") fn libc_recvmsg(s: int, msg: *const msghdr, flags: int) i64; export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { let res = libc_recvmsg(fd, msg, flags); if (res == -1) { return *__errno(): errno; }; // TODO: could overflow return res: int; }; // sendmsg @symbol("sendmsg") fn libc_sendmsg(s: int, msg: *const msghdr, flags: int) i64; export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { let res = libc_sendmsg(fd, msg, flags); if (res == -1) { return *__errno(): errno; }; // TODO: could overflow return res: int; }; // recvfrom @symbol("recvfrom") fn libc_recvfrom( s: int, buf: *opaque, length: size, flags: int, from: nullable *sockaddr, fromlen: nullable *u32, ) i64; export fn recvfrom( sockfd: int, buf: *opaque, length: size, flags: int, from: nullable *sockaddr, fromlen: nullable *u32 ) (size | errno) = { let res = libc_recvfrom(sockfd, buf, length, flags, from, fromlen); if (res == -1) { return *__errno(): errno; }; return res: size; }; // accept // getpeername @symbol("getpeername") fn libc_getpeername( s: int, name: *sockaddr, namelen: *u32 ) int; export fn getpeername( sockfd: int, addr: *sockaddr, addrlen: *u32 ) (void | errno) = { let res = libc_getpeername(sockfd, addr, addrlen); if (res == -1) { return *__errno(): errno; }; }; // getsockname @symbol("getsockname") fn libc_getsockname( sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32 ) int; export fn getsockname( sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32 ) (void | errno) = { let res = libc_getsockname(sockfd, addr, addrlen); if (res == -1) { return *__errno(): errno; }; }; // access @symbol("access") fn libc_access(path: *const u8, amode: int) int; export fn access(path: path, amode: int) (bool | errno) = { let res = libc_access(cpath(path)?, amode); if (res == -1) { let err = *__errno(): errno; switch (res) { case EACCES => return false; case => return err; }; }; return true; }; // chflags // fchflags // sync // msyscall // stat // getppid export @symbol("getppid") fn getppid() pid_t; // lstat // dup // fstatat @symbol("fstatat") fn libc_fstatat(fd: int, path: *const u8, sb: *stat, flag: int) int; export fn fstatat( dirfd: int, path: path, stat: *stat, flag: int ) (void | errno) = { let res = libc_fstatat(dirfd, cpath(path)?, stat, flag); if (res == -1) { return *__errno(): errno; }; }; // getegid export @symbol("getegid") fn getegid() gid_t; // profil // ktrace // sigaction // sigaltstack export @symbol("sigaction") fn libc_sigaction( sig: int, act: *const sigact, oact: nullable *sigact ) int; export fn sigaction( signum: int, act: *const sigact, old: nullable *sigact, ) (void | errno) = { let res = libc_sigaction(signum, act, old); if (res == -1) { return *__errno(): errno; }; }; export @symbol("sigaltstack") fn libc_sigaltstack( ss: const nullable *stack_t, oss: nullable *stack_t, ) int; export fn sigaltstack( ss: const nullable *stack_t, oss: nullable *stack_t, ) (void | errno) = { let res = libc_sigaltstack(ss, oss); if (res == -1) { return *__errno(): errno; }; }; // getgid export @symbol("getgid") fn getgid() gid_t; // sigprocmask @symbol("sigprocmask") fn libc_sigprocmask( how: int, set: nullable *const sigset, old: nullable *sigset ) int; export fn sigprocmask( how: int, set: nullable *const sigset, old: nullable *sigset ) (void | errno) = { let res = libc_sigprocmask(how, set, old); if (res == -1) { return *__errno(): errno; }; }; // mmap @symbol("mmap") fn libc_mmap( addr: nullable *opaque, len_: size, prot: int, flags: int, fd: int, pos: i64 ) nullable *opaque; export fn mmap( addr: nullable *opaque, len_: size, prot: int, flags: int, fd: int, pos: i64 ) (*opaque | errno) = { let res = libc_mmap(addr, len_, prot, flags, fd, pos); if (res == null) { return *__errno(): errno; }; return res: *opaque; }; // setlogin // acct // sigpending // fstat // ioctl @symbol("ioctl") fn libc_ioctl(fd: int, req: u64, arg: u64) int; export type ioctl_arg = (nullable *opaque | u64); export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = { let res = match (arg) { case let u: u64 => yield libc_ioctl(fd, req, u); case let ptr: nullable *opaque => yield libc_ioctl(fd, req, ptr: uintptr: u64); }; if (res == -1) { return *__errno(): errno; }; return res; }; // reboot // revoke // symlink // readlink // execve @symbol("execve") fn libc_execve(path: *const u8, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8) int; export fn execve(path: path, argv: *[*]nullable *const u8, envp: *[*]nullable *const u8) errno = { let res = libc_execve(cpath(path)?, argv, envp); return *__errno(): errno; }; // umask @symbol("umask") fn libc_umask(numask: mode_t) mode_t; export fn umask(mode: mode_t) (mode_t | errno) = { // Always successful on OpenBSD. return libc_umask(mode); }; // chroot @symbol("chroot") fn libc_chroot(dirname: *const u8) int; export fn chroot(path: path) (void | errno) = { let res = libc_chroot(cpath(path)?); if (res == -1) { return *__errno(): errno; }; }; // getfsstat // statfs // fstatfs // fhstatfs // vfork // gettimeofday // settimeofday // select // kevent @symbol("kevent") fn libc_kevent( kq: int, changelist: nullable *const [*]kevent, nchanges: int, eventlist: nullable *[*]kevent, nevents: int, timeout: nullable *const timespec ) int; // kevent() wrapper. Renamed to not conflict with the struct "kevent" export fn kevent_poll( kq: int, changelist: nullable *const [*]kevent, nchanges: int, eventlist: nullable *[*]kevent, nevents: int, timeout: nullable *const timespec ) (int | errno) = { let res = libc_kevent(kq, changelist, nchanges, eventlist, nevents, timeout); if (res == -1) { return *__errno(): errno; }; return res; }; // munmap @symbol("munmap") fn libc_munmap(addr: *opaque, len_: size) int; export fn munmap(addr: *opaque, len_: size) (void | errno) = { let res = libc_munmap(addr, len_); if (res == -1) { return *__errno(): errno; }; }; // mprotect // madvise // utimes // futimes // mquery // getgroups @symbol("getgroups") fn libc_getgroups(gidsetlen: int, gidset: *[*]gid_t) int; export fn getgroups(gids: []gid_t) (uint | errno) = { let res = libc_getgroups(len(gids): int, gids: *[*]gid_t); if (res == -1) { return *__errno(): errno; }; return res: uint; }; // setgroups @symbol("setgroups") fn libc_setgroups( ngroups: int, gidset: *[*]gid_t, ) int; export fn setgroups(gids: []gid_t) (void | errno) = { let res = libc_setgroups(len(gids): int, gids: *[*]gid_t); if (res == -1) { return *__errno(): errno; }; }; // getpgrp export @symbol("getpgrp") fn getpgrp() pid_t; // setpgid @symbol("setpgid") fn libc_setpgid(pid: pid_t, pgrp: pid_t) int; export fn setpgid(pid: pid_t, pgrp: pid_t) (void | errno) = { let res = libc_setpgid(pid, pgrp); if (res == -1) { return *__errno(): errno; }; }; // futex // utimensat @symbol("utimensat") fn libc_utimensat( fd: int, path: *const u8, times: *const [2]timespec, flag: int ) int; export fn utimensat( dirfd: int, path: str, ts: *[2]timespec, flags: int ) (void | errno) = { let res = libc_utimensat(dirfd, cpath(path)?, ts, flags); if (res == -1) { return *__errno(): errno; }; }; // futimens @symbol("futimens") fn libc_futimens( fd: int, times: *const [2]timespec ) int; export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = { let res = libc_futimens(fd, ts); if (res == -1) { return *__errno(): errno; }; }; // kbind // clock_gettime // clock_settime @symbol("clock_gettime") fn libc_clock_gettime(clock: int, now: *timespec) int; export fn clock_gettime(clock: int, now: *timespec) (void | errno) = { let res = libc_clock_gettime(clock, now); if (res == -1) { return *__errno(): errno; }; }; @symbol("clock_settime") fn libc_clock_settime(clock: int, now: *const timespec) int; export fn clock_settime(clock: int, now: *const timespec) (void | errno) = { let res = libc_clock_settime(clock, now); if (res == -1) { return *__errno(): errno; }; }; // clock_getres // dup2 @symbol("dup2") fn libc_dup2(oldd: int, newd: int) int; export fn dup2(oldfd: int, newfd: int) (int | errno) = { let res = libc_dup2(oldfd, newfd); if (res == -1) { return *__errno(): errno; }; return res; }; // nanosleep @symbol("nanosleep") fn libc_nanosleep( timeout: *const timespec, remainder: *timespec ) int; export fn nanosleep( timeout: *const timespec, remainder: *timespec ) (void | errno) = { let res = libc_nanosleep(timeout, remainder); if (res == -1) { return *__errno(): errno; }; }; // fcntl @symbol("fcntl") fn libc_fcntl(fd: int, cmd: int, arg: u64) int; export type fcntl_arg = (void | int | *st_flock | *u64); export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = { let res = match (arg) { case void => yield libc_fcntl(fd, cmd, 0); case let i: int => yield libc_fcntl(fd, cmd, i: u64); case let l: *st_flock => yield libc_fcntl(fd, cmd, l: uintptr: u64); case let u: *u64 => yield libc_fcntl(fd, cmd, u: uintptr: u64); }; if (res == -1) { return *__errno(): errno; }; return res; }; // accept4 @symbol("accept4") fn libc_accept4( s: int, addr: nullable *sockaddr, adddrlen: nullable *u32, flags: int ) int; export fn accept4( sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int ) (int | errno) = { let res = libc_accept4(sockfd, addr, addrlen, flags); if (res == -1) { return *__errno(): errno; }; return res; }; // __thrsleep // fsync // setpriority @symbol("setpriority") fn libc_setpriority( which: int, who: id_t, prio: int ) int; export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = { let res = libc_setpriority(which, who, prio); if (res == -1) { return *__errno(): errno; }; }; // socket @symbol("socket") fn libc_socket(domain: int, t: int, protocol: int) int; export fn socket(domain: int, t: int, protocol: int) (int | errno) = { let res = libc_socket(domain, t, protocol); if (res == -1) { return *__errno(): errno; }; return res; }; // connect @symbol("connect") fn libc_connect( sockfd: int, addr: *const sockaddr, addrlen: u32 ) int; export fn connect( sockfd: int, addr: *const sockaddr, addrlen: u32 ) (void | errno) = { let res = libc_connect(sockfd, addr, addrlen); if (res == -1) { return *__errno(): errno; }; }; // getdents @symbol("getdents") fn libc_getdents(fd: int, buf: *opaque, nbytes: size) int; export fn getdents(dirfd: int, buf: *opaque, nbytes: size) (int | errno) = { let res = libc_getdents(dirfd, buf, nbytes); if (res == -1) { return *__errno(): errno; }; return res; }; // getpriority @symbol("getpriority") fn libc_getpriority(which: int, who: id_t) int; export fn getpriority(which: int, who: id_t) (int | errno) = { let res = libc_getpriority(which, who); if (res == -1) { return *__errno(): errno; }; return res; }; // pipe2 @symbol("pipe2") fn libc_pipe2(pipefd: *[2]int, flags: int) int; export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = { let res = libc_pipe2(pipefd, flags); if (res == -1) { return *__errno(): errno; }; }; // dup3 // sigreturn // bind @symbol("bind") fn libc_bind( sockfd: int, addr: *const sockaddr, addrlen: u32 ) int; export fn bind( sockfd: int, addr: *const sockaddr, addrlen: u32 ) (void | errno) = { let res = libc_bind(sockfd, addr, addrlen); if (res == -1) { return *__errno(): errno; }; }; // setsockopt @symbol("setsockopt") fn libc_setsockopt( s: int, level: int, optname: int, optval: *opaque, optlen: u32 ) int; export fn setsockopt( sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32 ) (void | errno) = { let res = libc_setsockopt(sockfd, level, optname, optval, optlen); if (res == -1) { return *__errno(): errno; }; }; // listen @symbol("listen") fn libc_listen(s: int, backlog: int) int; export fn listen(sockfd: int, backlog: u32) (void | errno) = { let res = libc_listen(sockfd, backlog: int); if (res == -1) { return *__errno(): errno; }; }; // chflagsat // pledge @symbol("pledge") fn libc_pledge( promises: nullable *const u8, execpromises: nullable *const u8 ) int; // The "stdio" pledge is always needed. Passing [[nullpromise]] to promises or // execpromises specifies to not change the current value. Check the pledge(2) // manual page for more information about the differrent promises. export fn pledge( promises: (const str | nullpromise), execpromises: (const str | nullpromise), ) (void | errno) = { let promises: nullable *u8 = match(promises) { case let p: const str => yield cpath(p)!; case nullpromise => yield null; }; let execpromises: nullable *u8 = match(execpromises) { case let ep: const str => yield copy_cpath(ep, pathbuf1)!; case nullpromise => yield null; }; let res = libc_pledge(promises, execpromises); if (res == -1) { return *__errno(): errno; }; }; // ppoll @symbol("ppoll") fn libc_ppoll( fds: *[*]pollfd, nfds: nfds_t, timeout: const nullable *timespec, mask: const nullable *sigset, ) int; export fn ppoll( fds: *[*]pollfd, nfds: nfds_t, timeout: const nullable *timespec, sigmask: const nullable *sigset, ) (int | errno) = { let ret = libc_ppoll(fds, nfds, timeout, sigmask); if (ret == -1) { return *__errno(): errno; }; return ret; }; // pselect // sigsuspend // sendsyslog // unveil @symbol("unveil") fn libc_unveil( path: nullable *const u8, permissions: nullable *const u8 ) int; // After establishing a collection of path and permissions rules, future // calls to [[unveil]] can be disabled by calling [[unveil_lock]]. // Alternatively, [[pledge]] may be used to remove the "unveil" promise. export fn unveil( path: path, permissions: const str, ) (void | errno) = { let res = libc_unveil(cpath(path)?, copy_cpath(permissions, pathbuf1)?); if (res == -1) { return *__errno(): errno; }; }; // Disable future calls to [[unveil]]. export fn unveil_lock() (void | errno) = { let res = libc_unveil(null, null); if (res == -1) { return *__errno(): errno; }; }; // __realpath // recvmmsg // sendmmsg // getsockopt @symbol("getsockopt") fn libc_getsockopt( s: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32 ) int; export fn getsockopt( sockfd: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32 ) (void | errno) = { let res = libc_getsockopt(sockfd, level, optname, optval, optlen); if (res == -1) { return *__errno(): errno; }; }; // thrkill // readv @symbol("readv") fn libc_readv(d: int, iov: const *[*]iovec, iovcnt: int) size; export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { let res: u64 = libc_readv(fd, iov, iovcnt); if (res == -1) { return *__errno(): errno; }; return res; }; // writev @symbol("writev") fn libc_writev(d: int, iov: const *[*]iovec, iovcnt: int) size; export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { let res: u64 = libc_writev(fd, iov, iovcnt); if (res == -1) { return *__errno(): errno; }; return res; }; // kill @symbol("kill") fn libc_kill(pid: int, signal: int) int; export fn kill(pid: int, signal: int) (void | errno) = { let res = libc_kill(pid, signal); if (res == -1) { return *__errno(): errno; }; }; // fchown @symbol("fchown") fn libc_fchown( fd: int, owner: uid_t, group: gid_t ) int; export fn fchown(fd: int, uid: uid_t, gid: gid_t) (void | errno) = { let res = libc_fchown(fd, uid, gid); if (res == -1) { return *__errno(): errno; }; }; // fchmod @symbol("fchmod") fn libc_fchmod( fd: int, mode: uint ) int; export fn fchmod(fd: int, mode: uint) (void | errno) = { let res = libc_fchmod(fd, mode); if (res == -1) { return *__errno(): errno; }; }; // setreuid // setregid // rename // flock @symbol("flock") fn libc_flock(fd: int, operation: int) int; export fn flock(fd: int, op: int) (void | errno) = { let res = libc_flock(fd, op); if (res == -1) { return *__errno(): errno; }; }; // mkfifo // sendto @symbol("sendto") fn libc_sendto( s: int, msg: *opaque, length: size, flags: int, to: nullable *sockaddr, tolen: socklen_t ) i64; export fn sendto( sockfd: int, buf: *opaque, length: size, flags: int, dest_addr: nullable *sockaddr, addrlen: u32 ) (size | errno) = { let res = libc_sendto(sockfd, buf, length, flags, dest_addr, addrlen); if (res == -1) { return *__errno(): errno; }; return res: size; }; // shutdown @symbol("shutdown") fn libc_shutdown(s: int, how: int) int; export fn shutdown(s: int, how: int) (void | errno) = { let res = libc_shutdown(s, how); if (res == -1) { return *__errno(): errno; }; }; // socketpair @symbol("socketpair") fn libc_socketpair( domain: int, type_: int, protocol: int, sv: *[*]int ) int; export fn socketpair( domain: int, type_: int, protocol: int, sv: *[*]int ) (void | errno) = { let res = libc_socketpair(domain, type_, protocol, sv); if (res == -1) { return *__errno(): errno; }; }; // mkdir // rmdir // adjtime // getlogin_r // getthrname // setthrname // pinsyscall // setsid @symbol("setsid") fn libc_setsid() pid_t; export fn setsid() (void | errno) = { let res = libc_setsid(); if (res == -1) { return *__errno(): errno; }; }; // quotactl // ypconnect // nfssvc // mimmutable // waitid // getfh // __tmpfd // sysarch // lseek @symbol("lseek") fn libc_lseek(fildes: int, pos: i64, whence: int) i64; export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = { let res = libc_lseek(fd, off, whence); if (res == -1) { return *__errno(): errno; }; return res; }; // truncate // ftruncate @symbol("ftruncate") fn libc_ftruncate(fd: int, length: i64) int; export fn ftruncate(fd: int, length: i64) (void | errno) = { let res = libc_ftruncate(fd, length); if (res == -1) { return *__errno(): errno; }; }; // pread // pwrite // preadv // pwritev // setgid @symbol("setgid") fn libc_setgid(gid: gid_t) int; export fn setgid(gid: gid_t) (void | errno) = { let res = libc_setgid(gid); if (res == -1) { return *__errno(): errno; }; }; // setegid @symbol("setegid") fn libc_setegid(gid: gid_t) int; export fn setegid(gid: gid_t) (void | errno) = { let res = libc_setegid(gid); if (res == -1) { return *__errno(): errno; }; }; // seteuid @symbol("seteuid") fn libc_seteuid(uid: uid_t) int; export fn seteuid(uid: uid_t) (void | errno) = { let res = libc_seteuid(uid); if (res == -1) { return *__errno(): errno; }; }; // pathconf // fpathconf // swapctl // getrlimit // setrlimit // sysctl @symbol("sysctl") fn libc_sysctl( name: *[*]int, namelen: uint, oldp: nullable *opaque, oldlenp: nullable *size, newp: nullable *opaque, newlen: size ) int; export fn sysctl( name: []int, namelen: uint, oldp: nullable *opaque, oldlenp: nullable *size, newp: nullable *opaque, newlen: size ) (void | errno) = { let res = libc_sysctl(name: *[*]int, namelen, oldp, oldlenp, newp, newlen); if (res == -1) { return *__errno(): errno; }; }; // mlock // munlock // getpgid @symbol("getpgid") fn libc_getpgid(pid: pid_t) pid_t; export fn getpgid(pid: pid_t) (pid_t | errno) = { let res = libc_getpgid(pid); if (res == -1) { return *__errno(): errno; }; return res; }; // utrace // semget // msgget // msgsnd // msgrcv // shmat // shmdt // minherit // poll // issetugid // lchown // shm_open @symbol("shm_open") fn libc_shm_open(path: *const u8, flags: int, mode: mode_t) int; export fn shm_open(path: path, flags: int, mode: mode_t) (int | errno) = { let res = libc_shm_open(cpath(path)?, flags, mode); if (res == -1) { return *__errno(): errno; }; return res; }; // shm_unlink @symbol("shm_unlink") fn libc_shm_unlink(path: *const u8) int; export fn shm_unlink(path: path) (void | errno) = { let res = libc_shm_unlink(cpath(path)?); if (res == -1) { return *__errno(): errno; }; }; // getsid @symbol("getsid") fn libc_getsid(pid: pid_t) pid_t; export fn getsid(pid: pid_t) (pid_t | errno) = { let res = libc_getsid(pid); if (res == -1) { return *__errno(): errno; }; return res; }; // msync // pipe // fhopen // kqueue @symbol("kqueue") fn libc_kqueue() int; export fn kqueue() (int | errno) = { let res = libc_kqueue(); if (res == -1) { return *__errno(): errno; }; return res; }; // kqueue1 @symbol("kqueue1") fn libc_kqueue1(flags: int) int; export fn kqueue1(flags: int) (int | errno) = { let res = libc_kqueue1(flags); if (res == -1) { return *__errno(): errno; }; return res; }; // mlockall // munlockall // getresuid // setresuid // getresgid // setresgid // closefrom // sigaltstack // shmget // semop // fhstat // __semctl // shmctl // msgctl // sched_yield // getthrid // __thrwakeup // __threxit // __thrsigdivert // getcwd @symbol("getcwd") fn libc_getcwd(buf: *u8, bufsz: size) *u8; // The return value is statically allocated and must be duplicated before // calling getcwd again. export fn getcwd() (*const u8 | errno) = { static let pathbuf: [PATH_MAX]u8 = [0...]; let res = libc_getcwd(&pathbuf: *u8, len(pathbuf)); if (res == null) { return *__errno(): errno; }; return res; }; // adjfreq // setrtable // getrtable // faccessat // fchmodat @symbol("fchmodat") fn libc_fchmodat( fd: int, path: *const u8, mode: mode_t, flag: int ) int; export fn fchmodat( dirfd: int, path: path, mode: mode_t, flag: int ) (void | errno) = { let res = libc_fchmodat(dirfd, cpath(path)?, mode, flag); if (res == -1) { return *__errno(): errno; }; }; // fchownat @symbol("fchownat") fn libc_fchownat( fd: int, path: *const u8, owner: uid_t, group: gid_t, flag: int ) int; export fn fchownat( dirfd: int, path: path, uid: uid_t, gid: gid_t, flag: int ) (void | errno) = { let res = libc_fchownat(dirfd, cpath(path)?, uid, gid, flag); if (res == -1) { return *__errno(): errno; }; }; // linkat @symbol("linkat") fn libc_linkat( fd1: int, name1: *const u8, fd2: int, name2: *const u8, flag: int ) int; export fn linkat( olddirfd: int, oldpath: path, newdirfd: int, newpath: path, flags: int, ) (void | errno) = { let oldpath = cpath(oldpath)?; let newpath = copy_cpath(newpath, pathbuf1)?; let res = libc_linkat(olddirfd, oldpath, newdirfd, newpath, flags); if (res == -1) { return *__errno(): errno; }; }; // mkdirat @symbol("mkdirat") fn libc_mkdirat(fd: int, path: *const u8, mode: mode_t) int; export fn mkdirat(dirfd: int, path: path, mode: mode_t) (void | errno) = { let res = libc_mkdirat(dirfd, cpath(path)?, mode); if (res == -1) { return *__errno(): errno; }; }; // mkfifoat // mknodat @symbol("mknodat") fn libc_mknodat( fd: int, path: *const u8, mode: mode_t, dev: dev_t ) int; // The OpenBSD implementation of mknodat *only* supports FIFO and // device special files. export fn mknodat( dirfd: int, path: path, mode: mode_t, dev: dev_t, ) (void | errno) = { let res = libc_mknodat(dirfd, cpath(path)?, mode, dev); if (res == -1) { return *__errno(): errno; }; }; // openat @symbol("openat") fn libc_openat( fd: int, path: *const u8, flags: int, mode: uint, ) int; export fn openat( dirfd: int, path: path, flags: int, mode: uint, ) (int | errno) = { let res = libc_openat(dirfd, cpath(path)?, flags, mode); if (res == -1) { return *__errno(): errno; }; return res; }; // readlinkat @symbol("readlinkat") fn libc_readlinkat( fd: int, path: *const u8, buf: *u8, bufsiz: size ) i64; export fn readlinkat( dirfd: int, path: path, buf: []u8, ) (size | errno) = { let res = libc_readlinkat(dirfd, cpath(path)?, buf: *[*]u8: *u8, len(buf)); if (res == -1) { return *__errno(): errno; }; return res: size; }; // renameat @symbol("renameat") fn libc_renameat( fromfd: int, from: *const u8, tofd: int, to: *const u8 ) int; export fn renameat( olddirfd: int, oldpath: str, newdirfd: int, newpath: str, ) (void | errno) = { let newpath = copy_cpath(newpath, pathbuf1)?; let res = libc_renameat(olddirfd, cpath(oldpath)?, newdirfd, newpath); if (res == -1) { return *__errno(): errno; }; }; // symlinkat @symbol("symlinkat") fn libc_symlinkat( name1: *const u8, fd: int, name2: *const u8 ) int; export fn symlinkat( target: path, newdirfd: int, linkpath: path, ) (void | errno) = { let target = cpath(target)?; let linkpath = copy_cpath(linkpath, pathbuf1)?; let res = libc_symlinkat(target, newdirfd, linkpath); if (res == -1) { return *__errno(): errno; }; }; // unlinkat @symbol("unlinkat") fn libc_unlinkat(fd: int, path: *const u8, flag: int) int; export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { let res = libc_unlinkat(dirfd, cpath(path)?, flags); if (res == -1) { return *__errno(): errno; }; }; // __set_tcb // __get_tcb hare-0.24.2/rt/+openbsd/types.ha000066400000000000000000000515101464473310100163330ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type time_t = i64; export type clock_t = i64; export type clockid_t = i32; export type suseconds_t = i64; export type dev_t = i32; export type ino_t = u64; export type nlink_t = u32; export type id_t = u32; export type pid_t = i32; export type uid_t = u32; export type gid_t = u32; export type off_t = i64; export type blkcnt_t = i64; export type blksize_t = i32; export type nfds_t = uint; export type mode_t = u32; export type sigset = uint; // Passing this to a pledge() promise specifies to not change the current value. export type nullpromise = void; // Maximum length of a file path including the NUL terminator. export def PATH_MAX: size = 1024; export def NAME_MAX: size = 255; export def PATH_PTMDEV: str = "/dev/ptm"; export def PTMGET: u64 = 0x40287401; export type ptmget = struct { cfd: int, sfd: int, cn: [16]u8, sn: [16]u8 }; export def S_ISUID: mode_t = 0o4000; export def S_ISGID: mode_t = 0o2000; export def S_ISTXT: mode_t = 0o1000; export def S_IRWXU: mode_t = 0o700; export def S_IRUSR: mode_t = 0o400; export def S_IWUSR: mode_t = 0o200; export def S_IXUSR: mode_t = 0o100; export def S_IRWXG: mode_t = 0o070; export def S_IRGRP: mode_t = 0o040; export def S_IWGRP: mode_t = 0o020; export def S_IXGRP: mode_t = 0o010; export def S_IRWXO: mode_t = 0o007; export def S_IROTH: mode_t = 0o004; export def S_IWOTH: mode_t = 0o002; export def S_IXOTH: mode_t = 0o001; export def S_IFMT: mode_t = 0o170000; export def S_IFIFO: mode_t = 0o010000; export def S_IFCHR: mode_t = 0o020000; export def S_IFDIR: mode_t = 0o040000; export def S_IFBLK: mode_t = 0o060000; export def S_IFREG: mode_t = 0o100000; export def S_IFLNK: mode_t = 0o120000; export def S_IFSOCK: mode_t = 0o140000; export def S_ISVTX: mode_t = 0o001000; export def O_RDONLY: int = 0x0; export def O_WRONLY: int = 0x1; export def O_RDWR: int = 0x2; export def O_ACCMODE: int = 0x3; export def O_NONBLOCK: int = 0x4; export def O_APPEND: int = 0x8; export def O_SHLOCK: int = 0x10; export def O_EXLOCK: int = 0x20; export def O_ASYNC: int = 0x40; export def O_FSYNC: int = 0x80; export def O_SYNC: int = 0x80; export def O_NOFOLLOW: int = 0x100; export def O_CREAT: int = 0x200; export def O_TRUNC: int = 0x400; export def O_EXCL: int = 0x800; export def O_DSYNC: int = O_SYNC; export def O_RSYNC: int = O_SYNC; export def O_NOCTTY: int = 0x8000; export def O_CLOEXEC: int = 0x10000; export def O_DIRECTORY: int = 0x20000; export def WAIT_ANY: pid_t = -1; export def WAIT_MYPGRP: pid_t = 0; export def WNOHANG: int = 0x1; export def WUNTRACED: int = 0x2; export def WSTOPPED: int = WUNTRACED; export def WEXITED: int = 0x4; export def WCONTINUED: int = 0x8; export def WNOWAIT: int = 0x10; export def WTRAPPED: int = 0x20; export fn wtermsig(status: int) int = status & 0o177; export fn wifexited(status: int) bool = wtermsig(status) == 0; export fn wexitstatus(status: int) int = (status >> 8) & 0xff; export fn wifsignaled(status: int) bool = wtermsig(status) != 0o177 && wtermsig(status) != 0; export type rusage = struct { ru_utime: timeval, ru_stime: timeval, ru_maxrss: i64, ru_ixrss: i64, ru_idrss: i64, ru_isrss: i64, ru_minflt: i64, ru_majflt: i64, ru_nswap: i64, ru_inblock: i64, ru_oublock: i64, ru_msgsnd: i64, ru_msgrcv: i64, ru_nsignals: i64, ru_nvcsw: i64, ru_nivcsw: i64, }; export def RUSAGE_SELF: int = 0; export def RUSAGE_CHILDREN: int = -1; export def RUSAGE_THREAD: int = 1; export def F_OK: int = 0; export def X_OK: int = 0x1; export def W_OK: int = 0x2; export def R_OK: int = 0x4; export def AT_FDCWD: int = -100; export def AT_EACCESS: int = 0x1; export def AT_SYMLINK_NOFOLLOW: int = 0x2; export def AT_SYMLINK_FOLLOW: int = 0x4; export def AT_REMOVEDIR: int = 0x8; export def PROT_NONE: int = 0x0; export def PROT_READ: int = 0x1; export def PROT_WRITE: int = 0x2; export def PROT_EXEC: int = 0x4; export def MAP_SHARED: int = 0x1; export def MAP_PRIVATE: int = 0x2; export def MAP_FIXED: int = 0x10; export def __MAP_NOREPLACE: int = 0x800; export def MAP_ANON: int = 0x1000; export def __MAP_NOFAULT: int = 0x2000; export def MAP_STACK: int = 0x4000; export def MAP_CONCEAL: int = 0x8000; export def MAP_FLAGMASK: int = 0xfff7; export def RB_AUTOBOOT: int = 0x0; export def RB_ASKNAME: int = 0x1; export def RB_SINGLE: int = 0x2; export def RB_NOSYNC: int = 0x4; export def RB_HALT: int = 0x8; export def RB_INITNAME: int = 0x10; export def RB_DFLTROOT: int = 0x20; export def RB_KDB: int = 0x40; export def RB_RDONLY: int = 0x80; export def RB_DUMP: int = 0x100; export def RB_MINIROOT: int = 0x200; export def RB_CONFIG: int = 0x400; export def RB_TIMEBAD: int = 0x800; export def RB_POWERDOWN: int = 0x1000; export def RB_SERCONS: int = 0x2000; export def RB_USERREQ: int = 0x4000; export def RB_RESET: int = 0x8000; export def RB_GOODRANDOM: int = 0x10000; export def RB_UNHIBERNATE: int = 0x20000; export def NGROUPS_MAX: size = 16; export type timespec = struct { tv_sec: time_t, tv_nsec: i64, }; export def UTIME_OMIT = -0x1; export def CLOCK_REALTIME: clockid_t = 0; export def CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; export def CLOCK_MONOTONIC: clockid_t = 3; export def CLOCK_THREAD_CPUTIME_ID: clockid_t = 4; export def CLOCK_UPTIME: clockid_t = 5; export def CLOCK_BOOTTIME: clockid_t = 6; export def F_DUPFD: int = 0; export def F_GETFD: int = 1; export def F_SETFD: int = 2; export def F_GETFL: int = 3; export def F_SETFL: int = 4; export def F_GETOWN: int = 5; export def F_SETOWN: int = 6; export def F_GETLK: int = 7; export def F_SETLK: int = 8; export def F_SETLKW: int = 9; export def F_DUPFD_CLOEXEC: int = 10; export def F_ISATTY: int = 11; export def FD_CLOEXEC: int = 1; export def F_RDLCK: i16 = 1; export def F_UNLCK: i16 = 2; export def F_WRLCK: i16 = 3; export type st_flock = struct { l_start: off_t, l_len: off_t, l_pid: pid_t, l_type: i16, l_whence: i16, }; export type dirent = struct { d_fileno: ino_t, d_off: off_t, d_reclen: u16, d_type: u8, d_namlen: u8, __d_padding: [4]u8, d_name: [*]u8, }; export def MAXNAMLEN: size = 255; export def MAXHOSTNAMELEN: size = 255; export def DT_UNKNOWN: u8 = 0; export def DT_FIFO: u8 = 1; export def DT_CHR: u8 = 2; export def DT_DIR: u8 = 4; export def DT_BLK: u8 = 6; export def DT_REG: u8 = 8; export def DT_LNK: u8 = 10; export def DT_SOCK: u8 = 12; export type pollfd = struct { fd: int, events: i16, revents: i16, }; export def POLLIN: i16 = 0x1; export def POLLPRI: i16 = 0x2; export def POLLOUT: i16 = 0x4; export def POLLERR: i16 = 0x8; export def POLLHUP: i16 = 0x10; export def POLLNVAL: i16 = 0x20; export def POLLRDNORM: i16 = 0x40; export def POLLNORM: i16 = POLLRDNORM; export def POLLWRNORM: i16 = POLLOUT; export def POLLRDBAND: i16 = 0x80; export def POLLWRBAND: i16 = 0x100; export type iovec = struct { iov_base: *opaque, iov_len: size, }; export def NSIG: int = 32; export type sigact = struct { union { sa_handler: *fn (int) void, sa_sigaction: *fn (int, *siginfo, *opaque) void, }, sa_mask: sigset, sa_flags: int, }; export type siginfo = struct { si_signo: int, si_code: int, si_errno: int, _data: union { _pad: [128/4 - 3]int, _proc: struct { _pid: pid_t, _uid: uid_t, _pdata: union { _kill: struct { _value: sigval, }, _cid: struct { _utime: clock_t, _stime: clock_t, _status: int }, }, }, _fault: struct { _addr: nullable *opaque, _trapno: int, }, }, }; export type sigval = union { sival_int: int, sival_ptr: *opaque, }; export type stack_t = struct { ss_sp: *opaque, ss_size: size, ss_flags: int, }; export type timeval = struct { tv_sec: time_t, tv_usec: suseconds_t, }; export type stat = struct { st_mode: mode_t, st_dev: dev_t, st_ino: ino_t, st_nlink: nlink_t, st_uid: uid_t, st_gid: gid_t, st_rdev: dev_t, st_atim: timespec, st_mtim: timespec, st_ctim: timespec, st_size: off_t, st_blocks: blkcnt_t, st_blksize: blksize_t, st_flags: u32, st_gen: u32, st_birthtim: timespec, }; export type winsize = struct { ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, }; export type termios = struct { c_iflag: tcflag, c_oflag: tcflag, c_cflag: tcflag, c_lflag: tcflag, c_cc: [NCCS]cc, c_ispeed: int, c_ospeed: int, }; export def NCCS: size = 20; export type tcflag = enum uint { // c_iflag bits IGNBRK = 0x1, BRKINT = 0x2, IGNPAR = 0x4, PARMRK = 0x8, INPCK = 0x10, ISTRIP = 0x20, INLCR = 0x40, IGNCR = 0x80, ICRNL = 0x100, IXON = 0x200, IXOFF = 0x400, IXANY = 0x800, IUCLC = 0x1000, IMAXBEL = 0x2000, // c_oflag bits OPOST = 0x1, ONLCR = 0x2, TABDLY = 0x4, TAB0 = 0x0, TAB3 = 0x4, OXTABS = TAB3, ONOEOT = 0x8, OCRNL = 0x10, OLCUC = 0x20, ONOCR = 0x40, ONLRET = 0x80, // c_cflag bits CIGNORE = 0x1, CSIZE = 0x300, CS5 = 0x0, CS6 = 0x100, CS7 = 0x200, CS8 = 0x300, CSTOPB = 0x400, CREAD = 0x800, PARENB = 0x1000, PARODD = 0x2000, HUPCL = 0x4000, CLOCAL = 0x8000, CRTSCTS = 0x10000, CRTS_IFLOW = CRTSCTS, CCTS_OFLOW = CRTSCTS, MDMBUF = 0x100000, CHWFLOW = (MDMBUF | CRTSCTS), // c_lflag bits ECHOKE = 0x1, ECHOE = 0x2, ECHOK = 0x4, ECHO = 0x8, ECHONL = 0x10, ECHOPRT = 0x20, ECHOCTL = 0x40, ISIG = 0x80, ICANON = 0x100, ALTWERASE = 0x200, IEXTEN = 0x400, EXTPROC = 0x800, TOSTOP = 0x400000, FLUSHO = 0x800000, XCASE = 0x1000000, NOKERNINFO = 0x2000000, PENDIN = 0x20000000, NOFLSH = 0x80000000, }; export type cc = enum u8 { VEOF = 0, VEOL = 1, VEOL2 = 2, VERASE = 3, VWERASE = 4, VKILL = 5, VREPRINT = 6, VERASE2 = 7, VINTR = 8, VQUIT = 9, VSUSP = 10, VDSUSP = 11, VSTART = 12, VSTOP = 13, VLNEXT = 14, VDISCARD = 15, VMIN = 16, VTIME = 17, VSTATUS = 18, }; export def TIOCSPGRP: u64 = 0x80047476; export def TIOCGWINSZ: u64 = 0x40087468; export def TIOCSWINSZ: u64 = 0x80087467; export def TIOCGETA: u64 = 0x402c7413; export def TIOCSETA: u64 = 0x802c7414; export def SIG_DFL: uintptr = 0; export def SIG_IGN: uintptr = 1; export def SIG_BLOCK: int = 1; export def SIG_UNBLOCK: int = 2; export def SIG_SETMASK: int = 3; export def SA_ONSTACK: int = 0x1; export def SA_RESTART: int = 0x2; export def SA_RESETHAND: int = 0x4; export def SA_NOCLDSTOP: int = 0x8; export def SA_NODEFER: int = 0x10; export def SA_NOCLDWAIT: int = 0x20; export def SA_SIGINFO: u64 = 0x40; export def SIGHUP: int = 1; export def SIGINT: int = 2; export def SIGQUIT: int = 3; export def SIGILL: int = 4; export def SIGTRAP: int = 5; export def SIGABRT: int = 6; export def SIGEMT: int = 7; export def SIGFPE: int = 8; export def SIGKILL: int = 9; export def SIGBUS: int = 10; export def SIGSEGV: int = 11; export def SIGSYS: int = 12; export def SIGPIPE: int = 13; export def SIGALRM: int = 14; export def SIGTERM: int = 15; export def SIGURG: int = 16; export def SIGSTOP: int = 17; export def SIGTSTP: int = 18; export def SIGCONT: int = 19; export def SIGCHLD: int = 20; export def SIGTTIN: int = 21; export def SIGTTOU: int = 22; export def SIGIO: int = 23; export def SIGXCPU: int = 24; export def SIGXFSZ: int = 25; export def SIGVTALRM: int = 26; export def SIGPROF: int = 27; export def SIGWINCH: int = 28; export def SIGINFO: int = 29; export def SIGUSR1: int = 30; export def SIGUSR2: int = 31; export def SIGTHR: int = 32; export def PRIO_PROCESS: int = 0; export def PRIO_PGRP: int = 1; export def PRIO_USER: int = 2; export def STDIN_FILENO: int = 0; export def STDOUT_FILENO: int = 1; export def STDERR_FILENO: int = 2; export def SEEK_SET: int = 0; export def SEEK_CUR: int = 1; export def SEEK_END: int = 2; export def LOCK_SH: int = 1; export def LOCK_EX: int = 2; export def LOCK_NB: int = 4; export def LOCK_UN: int = 8; // sysctl export def CTL_KERN: int = 1; export def CTL_VM: int = 2; export def CTL_FS: int = 3; export def CTL_NET: int = 4; export def CTL_DEBUG: int = 5; export def CTL_HW: int = 6; export def CTL_MACHDEP: int = 7; export def CTL_DDB: int = 9; export def CTL_VFS: int = 10; export def KERN_OSTYPE: int = 1; export def KERN_OSRELEASE: int = 2; export def KERN_OSREV: int = 3; export def KERN_VERSION: int = 4; export def KERN_MAXVNODES: int = 5; export def KERN_MAXPROC: int = 6; export def KERN_MAXFILES: int = 7; export def KERN_ARGMAX: int = 8; export def KERN_SECURELVL: int = 9; export def KERN_HOSTNAME: int = 10; export def KERN_HOSTID: int = 11; export def KERN_CLOCKRATE: int = 12; export def KERN_PROF: int = 16; export def KERN_POSIX1: int = 17; export def KERN_NGROUPS: int = 18; export def KERN_JOB_CONTROL: int = 19; export def KERN_SAVED_IDS: int = 20; export def KERN_BOOTTIME: int = 21; export def KERN_DOMAINNAME: int = 22; export def KERN_MAXPARTITIONS: int = 23; export def KERN_RAWPARTITION: int = 24; export def KERN_MAXTHREAD: int = 25; export def KERN_NTHREADS: int = 26; export def KERN_OSVERSION: int = 27; export def KERN_SOMAXCONN: int = 28; export def KERN_SOMINCONN: int = 29; export def KERN_NOSUIDCOREDUMP: int = 32; export def KERN_FSYNC: int = 33; export def KERN_SYSVMSG: int = 34; export def KERN_SYSVSEM: int = 35; export def KERN_SYSVSHM: int = 36; export def KERN_MSGBUFSIZE: int = 38; export def KERN_MALLOCSTATS: int = 39; export def KERN_CPTIME: int = 40; export def KERN_NCHSTATS: int = 41; export def KERN_FORKSTAT: int = 42; export def KERN_TTY: int = 44; export def KERN_CCPU: int = 45; export def KERN_FSCALE: int = 46; export def KERN_NPROCS: int = 47; export def KERN_MSGBUF: int = 48; export def KERN_POOL: int = 49; export def KERN_STACKGAPRANDOM: int = 50; export def KERN_SYSVIPC_INFO: int = 51; export def KERN_ALLOWKMEM: int = 52; export def KERN_WITNESSWATCH: int = 53; export def KERN_SPLASSERT: int = 54; export def KERN_PROC_ARGS: int = 55; export def KERN_NFILES: int = 56; export def KERN_TTYCOUNT: int = 57; export def KERN_NUMVNODES: int = 58; export def KERN_MBSTAT: int = 59; export def KERN_WITNESS: int = 60; export def KERN_SEMINFO: int = 61; export def KERN_SHMINFO: int = 62; export def KERN_INTRCNT: int = 63; export def KERN_WATCHDOG: int = 64; export def KERN_ALLOWDT: int = 65; export def KERN_PROC: int = 66; export def KERN_MAXCLUSTERS: int = 67; export def KERN_EVCOUNT: int = 68; export def KERN_TIMECOUNTER: int = 69; export def KERN_MAXLOCKSPERUID: int = 70; export def KERN_CPTIME2: int = 71; export def KERN_CACHEPCT: int = 72; export def KERN_FILE: int = 73; export def KERN_WXABORT: int = 74; export def KERN_CONSDEV: int = 75; export def KERN_NETLIVELOCKS: int = 76; export def KERN_POOL_DEBUG: int = 77; export def KERN_PROC_CWD: int = 78; export def KERN_PROC_NOBROADCASTKILL: int = 79; export def KERN_PROC_VMMAP: int = 80; export def KERN_GLOBAL_PTRACE: int = 81; export def KERN_CONSBUFSIZE: int = 82; export def KERN_CONSBUF: int = 83; export def KERN_AUDIO: int = 84; export def KERN_CPUSTATS: int = 85; export def KERN_PFSTATUS: int = 86; export def KERN_TIMEOUT_STATS: int = 87; export def KERN_UTC_OFFSET: int = 88; export def KERN_VIDEO: int = 89; export def KERN_CLOCKINTR: int = 90; export def KERN_AUTOCONF_SERIAL: int = 91; export def KERN_MAXID: int = 92; export def KERN_PROC_ALL: int = 0; export def KERN_PROC_PID: int = 1; export def KERN_PROC_PGRP: int = 2; export def KERN_PROC_SESSION: int = 3; export def KERN_PROC_TTY: int = 4; export def KERN_PROC_UID: int = 5; export def KERN_PROC_RUID: int = 6; export def KERN_PROC_KTHREAD: int = 7; export def KERN_PROC_SHOW_THREADS: int = 0x40000000; export def KERN_SYSVIPC_MSG_INFO: int = 1; export def KERN_SYSVIPC_SEM_INFO: int = 2; export def KERN_SYSVIPC_SHM_INFO: int = 3; export def KERN_PROC_ARGV: int = 1; export def KERN_PROC_NARGV: int = 2; export def KERN_PROC_ENV: int = 3; export def KERN_PROC_NENV: int = 4; export def KERN_AUDIO_RECORD: int = 1; export def KERN_AUDIO_MAXID: int = 2; export def KERN_VIDEO_RECORD: int = 1; export def KERN_VIDEO_MAXID: int = 2; export def KERN_FILE_BYFILE: int = 1; export def KERN_FILE_BYPID: int = 2; export def KERN_FILE_BYUID: int = 3; export def KERN_FILESLOP: int = 10; export def KERN_FILE_TEXT: int = -1; export def KERN_FILE_CDIR: int = -2; export def KERN_FILE_RDIR: int = -3; export def KERN_FILE_TRACE: int = -4; export def KI_MNAMELEN: int = 96; export def KI_UNPPATHLEN: int = 104; export def KERN_INTRCNT_NUM: int = 1; export def KERN_INTRCNT_CNT: int = 2; export def KERN_INTRCNT_NAME: int = 3; export def KERN_INTRCNT_VECTOR: int = 4; export def KERN_INTRCNT_MAXID: int = 5; export def KERN_WATCHDOG_PERIOD: int = 1; export def KERN_WATCHDOG_AUTO: int = 2; export def KERN_WATCHDOG_MAXID: int = 3; export def KERN_TIMECOUNTER_TICK: int = 1; export def KERN_TIMECOUNTER_TIMESTEPWARNINGS: int = 2; export def KERN_TIMECOUNTER_HARDWARE: int = 3; export def KERN_TIMECOUNTER_CHOICE: int = 4; export def KERN_TIMECOUNTER_MAXID: int = 5; export def KERN_CLOCKINTR_STATS: int = 1; export def KERN_CLOCKINTR_MAXID: int = 2; export def FS_POSIX: int = 1; export def FS_MAXID: int = 2; export def FS_POSIX_SETUID: int = 1; export def FS_POSIX_MAXID: int = 2; export def HW_MACHINE: int = 1; export def HW_MODEL: int = 2; export def HW_NCPU: int = 3; export def HW_BYTEORDER: int = 4; export def HW_PHYSMEM: int = 5; export def HW_USERMEM: int = 6; export def HW_PAGESIZE: int = 7; export def HW_DISKNAMES: int = 8; export def HW_DISKSTATS: int = 9; export def HW_DISKCOUNT: int = 10; export def HW_SENSORS: int = 11; export def HW_CPUSPEED: int = 12; export def HW_SETPERF: int = 13; export def HW_VENDOR: int = 14; export def HW_PRODUCT: int = 15; export def HW_VERSION: int = 16; export def HW_SERIALNO: int = 17; export def HW_UUID: int = 18; export def HW_PHYSMEM64: int = 19; export def HW_USERMEM64: int = 20; export def HW_NCPUFOUND: int = 21; export def HW_ALLOWPOWERDOWN: int = 22; export def HW_PERFPOLICY: int = 23; export def HW_SMT: int = 24; export def HW_NCPUONLINE: int = 25; export def HW_POWER: int = 26; export def HW_BATTERY: int = 27; export def HW_UCOMNAMES: int = 28; export def HW_MAXID: int = 30; export def HW_BATTERY_CHARGEMODE: int = 1; export def HW_BATTERY_CHARGESTART: int = 2; export def HW_BATTERY_CHARGESTOP: int = 3; export def HW_BATTERY_MAXID: int = 4; export def CTL_DEBUG_NAME: int = 0; export def CTL_DEBUG_VALUE: int = 1; export def CTL_DEBUG_MAXID: int = 20; export def SI_NOINFO: int = 32767; export def SI_USER: int = 0; export def SI_LWP: int = -1; export def SI_QUEUE: int = -2; export def SI_TIMER: int = -3; export def ILL_ILLOPC: int = 1; export def ILL_ILLOPN: int = 2; export def ILL_ILLADR: int = 3; export def ILL_ILLTRP: int = 4; export def ILL_PRVOPC: int = 5; export def ILL_PRVREG: int = 6; export def ILL_COPROC: int = 7; export def ILL_BADSTK: int = 8; export def FPE_INTDIV: int = 1; export def FPE_INTOVF: int = 2; export def FPE_FLTDIV: int = 3; export def FPE_FLTOVF: int = 4; export def FPE_FLTUND: int = 5; export def FPE_FLTRES: int = 6; export def FPE_FLTINV: int = 7; export def FPE_FLTSUB: int = 8; export def SEGV_MAPERR: int = 1; export def SEGV_ACCERR: int = 2; export def BUS_ADRALN: int = 1; export def BUS_ADRERR: int = 2; export def BUS_OBJERR: int = 3; export def TRAP_BRKPT: int = 1; export def TRAP_TRACE: int = 2; export def CLD_EXITED: int = 1; export def CLD_KILLED: int = 2; export def CLD_DUMPED: int = 3; export def CLD_TRAPPED: int = 4; export def CLD_STOPPED: int = 5; export def CLD_CONTINUED: int = 6; export def EVFILT_READ: i16 = -1; export def EVFILT_WRITE: i16 = -2; export def EVFILT_AIO: i16 = -3; export def EVFILT_VNODE: i16 = -4; export def EVFILT_PROC: i16 = -5; export def EVFILT_SIGNAL: i16 = -6; export def EVFILT_TIMER: i16 = -7; export def EVFILT_DEVICE: i16 = -8; export def EVFILT_EXCEPT: i16 = -9; export def EV_ADD: u16 = 0x0001; export def EV_DELETE: u16 = 0x0002; export def EV_ENABLE: u16 = 0x0004; export def EV_DISABLE: u16 = 0x0008; export def EV_ONESHOT: u16 = 0x0010; export def EV_CLEAR: u16 = 0x0020; export def EV_RECEIPT: u16 = 0x0040; export def EV_DISPATCH: u16 = 0x0080; export def EV_SYSFLAGS: u16 = 0xf800; export def EV_FLAG1: u16 = 0x2000; export def EV_EOF: u16 = 0x8000; export def EV_ERROR: u16 = 0x4000; export def NOTE_LOWAT: uint = 0x0001; export def NOTE_EOF: uint = 0x0002; export def NOTE_OOB: uint = 0x0004; export def NOTE_DELETE: uint = 0x0001; export def NOTE_WRITE: uint = 0x0002; export def NOTE_EXTEND: uint = 0x0004; export def NOTE_ATTRIB: uint = 0x0008; export def NOTE_LINK: uint = 0x0010; export def NOTE_RENAME: uint = 0x0020; export def NOTE_REVOKE: uint = 0x0040; export def NOTE_TRUNCATE: uint = 0x0080; export def NOTE_EXIT: uint = 0x80000000; export def NOTE_FORK: uint = 0x40000000; export def NOTE_EXEC: uint = 0x20000000; export def NOTE_PCTRLMASK: uint = 0xf0000000; export def NOTE_PDATAMASK: uint = 0x000fffff; export def NOTE_TRACK: uint = 0x00000001; export def NOTE_TRACKERR: uint = 0x00000002; export def NOTE_CHILD: uint = 0x00000004; export def NOTE_CHANGE: uint = 0x00000001; export def NOTE_MSECONDS: uint = 0x00000000; export def NOTE_SECONDS: uint = 0x00000001; export def NOTE_USECONDS: uint = 0x00000002; export def NOTE_NSECONDS: uint = 0x00000003; export def NOTE_ABSTIME: uint = 0x00000010; export type kevent = struct { ident: uintptr, filter: i16, flags: u16, fflags: uint, data: i64, udata: nullable *opaque, }; hare-0.24.2/rt/+riscv64/000077500000000000000000000000001464473310100145215ustar00rootroot00000000000000hare-0.24.2/rt/+riscv64/arch_jmp.ha000066400000000000000000000001631464473310100166160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type arch_jmpbuf = [26]u64; hare-0.24.2/rt/+riscv64/cpuid.ha000066400000000000000000000001301464473310100161310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO hare-0.24.2/rt/+riscv64/cpuid.s000066400000000000000000000000001464473310100157770ustar00rootroot00000000000000hare-0.24.2/rt/+riscv64/fenv.s000066400000000000000000000014461464473310100156500ustar00rootroot00000000000000.section ".text.rt.feclearexcept","ax" .global rt.feclearexcept .type rt.feclearexcept,@function rt.feclearexcept: and a0, a0, 0x1f # fflags = fflags & ~a0 frcsr t0 not a0, a0 and t0, t0, a0 fscsr t0 ret .section ".text.rt.feraiseexcept","ax" .global rt.feraiseexcept .type rt.feraiseexcept,@function rt.feraiseexcept: and a0, a0, 0x1f # fflags = fflags | a0 frcsr t0 or t0, t0, a0 fscsr t0 ret .section ".text.rt.fesetround","ax" .global rt.fesetround .type rt.fesetround,@function rt.fesetround: fsrm a0 ret .section ".text.rt.fegetround","ax" .global rt.fegetround .type rt.fegetround,@function rt.fegetround: frrm a0 ret .section ".text.rt.fetestexcept","ax" .global rt.fetestexcept .type rt.fetestexcept,@function rt.fetestexcept: and a0, a0, 0x1f frcsr t0 and a0, a0, t0 ret hare-0.24.2/rt/+riscv64/longjmp.s000066400000000000000000000011361464473310100163540ustar00rootroot00000000000000.section ".text.rt.longjmp","ax" .global rt.longjmp .type rt.longjmp, %function rt.longjmp: ld s0, 0(a0) ld s1, 8(a0) ld s2, 16(a0) ld s3, 24(a0) ld s4, 32(a0) ld s5, 40(a0) ld s6, 48(a0) ld s7, 56(a0) ld s8, 64(a0) ld s9, 72(a0) ld s10, 80(a0) ld s11, 88(a0) ld sp, 96(a0) ld ra, 104(a0) fld fs0, 112(a0) fld fs1, 120(a0) fld fs2, 128(a0) fld fs3, 136(a0) fld fs4, 144(a0) fld fs5, 152(a0) fld fs6, 160(a0) fld fs7, 168(a0) fld fs8, 176(a0) fld fs9, 184(a0) fld fs10, 192(a0) fld fs11, 200(a0) seqz a0, a1 add a0, a0, a1 ret hare-0.24.2/rt/+riscv64/setjmp.s000066400000000000000000000011061464473310100162050ustar00rootroot00000000000000.section ".text.rt.setjmp","ax" .global rt.setjmp .type rt.setjmp, %function rt.setjmp: sd s0, 0(a0) sd s1, 8(a0) sd s2, 16(a0) sd s3, 24(a0) sd s4, 32(a0) sd s5, 40(a0) sd s6, 48(a0) sd s7, 56(a0) sd s8, 64(a0) sd s9, 72(a0) sd s10, 80(a0) sd s11, 88(a0) sd sp, 96(a0) sd ra, 104(a0) fsd fs0, 112(a0) fsd fs1, 120(a0) fsd fs2, 128(a0) fsd fs3, 136(a0) fsd fs4, 144(a0) fsd fs5, 152(a0) fsd fs6, 160(a0) fsd fs7, 168(a0) fsd fs8, 176(a0) fsd fs9, 184(a0) fsd fs10, 192(a0) fsd fs11, 200(a0) li a0, 0 ret hare-0.24.2/rt/+x86_64/000077500000000000000000000000001464473310100141575ustar00rootroot00000000000000hare-0.24.2/rt/+x86_64/arch_jmp.ha000066400000000000000000000001621464473310100162530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type arch_jmpbuf = [8]u64; hare-0.24.2/rt/+x86_64/cpuid.ha000066400000000000000000000045731464473310100156060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type cpuid_vendor = enum { AMD, INTEL, WINCHIP, TRANSMETA, CYRIX, CENTAUR, NEXGEN, UMC, SIS, NSC, RISE, VORTEX, VIA, ZHAOXIN, HYGON, MCST_ELBRUS, // Virtual Machines. VMWARE, XENHVM, MICROSOFT_HV, PARALLELS, }; export type cpuid_unknownvendor = !void; // cpuid vendor list taken from https://wiki.osdev.org/CPUID and // https://en.wikipedia.org/wiki/CPUID // Order and len matches the entries in the cpuid_vendor enum. const vendors: [_]str = [ "AuthenticAMD", "GenuineIntel", "CentaurHauls", "GenuineTMx86", "CyrixInstead", "CentaurHauls", "NexGenDriven", "UMC UMC UMC ", "SiS SiS SiS ", "Geode by NSC", "RiseRiseRise", "Vortex86 SoC", "VIA VIA VIA ", " Shanghai ", "HygonGenuine", "E2K MACHINE", "VMwareVMware", "XenVMMXenVMM", "Microsoft Hv", " lrpepyh vr", ]; def VENDOR_OLDAMD: str = "AMDisbetter!"; def VENDOR_OLDTRANSMETA: str = "TransmetaCPU"; export type cpuid_edxflag = enum uint { SSE = 1 << 25, SSE2 = 1 << 26, }; export type cpuid_ecxflag = enum uint { SSE3 = 1 << 0, AES = 1 << 25, AVX = 1 << 28, }; fn cpuid_getvendorstr(v: *[12]u8) void; fn cpuid_getfeatureflags(flags: *[2]u32) void; // Figures out cpu vendor using cpuid export fn cpuid_getvendor() (cpuid_vendor | cpuid_unknownvendor) = { let vstr: [12]u8 = [0...]; cpuid_getvendorstr(&vstr); for (let i = 0z; i < len(vendors); i += 1) { if (bytes_equal(vstr, strings_toutf8(vendors[i]))) { return i: cpuid_vendor; }; }; // some vendors changed their strings in between cpu revisions if (bytes_equal(vstr, strings_toutf8(VENDOR_OLDAMD))) { return cpuid_vendor::AMD; }; if (bytes_equal(vstr, strings_toutf8(VENDOR_OLDTRANSMETA))) { return cpuid_vendor::TRANSMETA; }; return cpuid_unknownvendor; }; // Checks if cpu has given features. See [[cpuid_edxflag]] and // [[cpuid_ecxflag]] for available options. export fn cpuid_hasflags(edx: u32, ecx: u32) bool = { let flags: [2]u32 = [0...]; cpuid_getfeatureflags(&flags); return flags[0] & edx == edx && flags[1] & ecx == ecx; }; // we can't use strings in rt so we add a helper here fn strings_toutf8(s: str) []u8 = { return *(&s: *[]u8); }; fn bytes_equal(a: []u8, b: []u8) bool = { if (len(a) != len(b)) { return false; }; for (let i = 0z; i < len(a); i += 1) { if (a[i] != b[i]) { return false; }; }; return true; }; hare-0.24.2/rt/+x86_64/cpuid.s000066400000000000000000000012121464473310100154430ustar00rootroot00000000000000.section ".text.rt.cpuid_getvendorstr","ax" .global rt.cpuid_getvendorstr .type rt.cpuid_getvendorstr,@function rt.cpuid_getvendorstr: pushq %rdx pushq %rcx pushq %rbx cpuid movl %ebx, (%rdi) movl %edx, 4(%rdi) movl %ecx, 8(%rdi) popq %rbx popq %rcx popq %rdx ret .section ".text.rt.cpuid_getfeatureflags","ax" .global rt.cpuid_getfeatureflags .type rt.cpuid_getfeatureflags,@function rt.cpuid_getfeatureflags: pushq %rdx pushq %rcx pushq %rbx movl $1, %eax cpuid movq %rdi, -0x8(%rsp) movq -0x8(%rsp), %rax movl %edx, (%rax) movq -0x8(%rsp), %rax add $0x4, %rax movl %ecx, (%rax) popq %rbx popq %rcx popq %rdx ret hare-0.24.2/rt/+x86_64/fenv.s000066400000000000000000000051531464473310100153050ustar00rootroot00000000000000# This file is vendored from musl and is licensed under MIT license: # # ---------------------------------------------------------------------- # Copyright © 2005-2020 Rich Felker, et al. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ---------------------------------------------------------------------- .section ".text.rt.feclearexcept","ax" .global rt.feclearexcept .type rt.feclearexcept,@function rt.feclearexcept: # maintain exceptions in the sse mxcsr, clear x87 exceptions endbr64 mov %edi,%ecx and $0x3f,%ecx fnstsw %ax test %eax,%ecx jz 1f fnclex 1: stmxcsr -8(%rsp) and $0x3f,%eax or %eax,-8(%rsp) test %ecx,-8(%rsp) jz 1f not %ecx and %ecx,-8(%rsp) ldmxcsr -8(%rsp) 1: xor %eax,%eax ret .section ".text.rt.feraiseexcept","ax" .global rt.feraiseexcept .type rt.feraiseexcept,@function rt.feraiseexcept: endbr64 and $0x3f,%edi stmxcsr -8(%rsp) or %edi,-8(%rsp) ldmxcsr -8(%rsp) xor %eax,%eax ret .section ".text.rt.fesetround","ax" .global rt.fesetround .type rt.fesetround,@function rt.fesetround: endbr64 push %rax xor %eax,%eax mov %edi,%ecx fnstcw (%rsp) andb $0xf3,1(%rsp) or %ch,1(%rsp) fldcw (%rsp) stmxcsr (%rsp) shl $3,%ch andb $0x9f,1(%rsp) or %ch,1(%rsp) ldmxcsr (%rsp) pop %rcx ret .section ".text.rt.fegetround","ax" .global rt.fegetround .type rt.fegetround,@function rt.fegetround: endbr64 push %rax stmxcsr (%rsp) pop %rax shr $3,%eax and $0xc00,%eax ret .section ".text.rt.fetestexcept","ax" .global rt.fetestexcept .type rt.fetestexcept,@function rt.fetestexcept: endbr64 and $0x3f,%edi push %rax stmxcsr (%rsp) pop %rsi fnstsw %ax or %esi,%eax and %edi,%eax ret hare-0.24.2/rt/+x86_64/longjmp.s000066400000000000000000000016231464473310100160130ustar00rootroot00000000000000/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ .section ".text.rt.longjmp","ax" .global rt.longjmp .type rt.longjmp,@function rt.longjmp: /* no endbr64 here to avoid exploitation - this function cannot be the * result of an indirect branch. */ xor %eax,%eax cmp $1,%esi /* CF = val ? 0 : 1 */ adc %esi,%eax /* eax = val + !val */ mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */ mov 8(%rdi),%rbp mov 16(%rdi),%r12 mov 24(%rdi),%r13 mov 32(%rdi),%r14 mov 40(%rdi),%r15 mov 48(%rdi),%rsp /* IBT: we cannot directly jump to the saved adress since this might be * in the middle of the function where we are not going to have an * endbr64. instead, we push the address to the stack and return to it * in order to avoid an indirect branch. */ push 56(%rdi) /* goto saved address without altering rsp */ ret hare-0.24.2/rt/+x86_64/setjmp.s000066400000000000000000000012351464473310100156460ustar00rootroot00000000000000/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ .section ".text.rt.setjmp","ax" .global rt.setjmp .type rt.setjmp,@function rt.setjmp: /* no endbr64 here to avoid exploitation - this function cannot be the * result of an indirect branch. */ mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */ mov %rbp,8(%rdi) mov %r12,16(%rdi) mov %r13,24(%rdi) mov %r14,32(%rdi) mov %r15,40(%rdi) lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */ mov %rdx,48(%rdi) mov (%rsp),%rdx /* save return addr ptr for new rip */ mov %rdx,56(%rdi) xor %eax,%eax /* always return 0 */ ret hare-0.24.2/rt/README000066400000000000000000000007231464473310100140300ustar00rootroot00000000000000The rt (runtime) module provides low-level, non-portable access to the host, and support code for the Hare compiler and standard library. The use of this module is not recommended for most user programs, and any program which uses rt is unlikely to be portable. However, any program which needs to make syscalls directly will have to use rt to do so. Documentation for most interfaces is not provided; refer to the host documentation (e.g. Linux man pages) instead. hare-0.24.2/rt/abort+test.ha000066400000000000000000000025621464473310100155470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Signature for abort handler function. export type abort_handler = fn( path: *str, line: u64, col: u64, msg: str, ) never; // Sets a new global runtime abort handler. export fn onabort(handler: *abort_handler) void = { return; // no-op on +test (XXX: Do something here?) }; export type abort_reason = struct { path: nullable *str, line: u64, col: u64, msg: str, }; export let jmp: nullable *jmpbuf = null; export let reason: abort_reason = abort_reason { ... }; export @symbol("rt.abort") fn _abort( path: *str, line: u64, col: u64, msg: str, ) void = { match (jmp) { case let j: *jmpbuf => reason = abort_reason { path = path, line = line, col = col, msg = msg, }; longjmp(j, 1); // test::status::ABORT case null => platform_abort(path, line, col, msg); }; }; // See harec:include/gen.h const reasons: [_]str = [ "slice or array access out of bounds", // 0 "type assertion failed", // 1 "out of memory", // 2 "static insert/append exceeds slice capacity", // 3 "execution reached unreachable code (compiler bug)", // 4 "slice allocation capacity smaller than initializer", // 5 "assertion failed", // 6 "error occurred", // 7 ]; export fn abort_fixed(path: *str, line: u64, col: u64, i: u64) void = { _abort(path, line, col, reasons[i]); }; hare-0.24.2/rt/abort.ha000066400000000000000000000020211464473310100145620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Signature for abort handler function. export type abort_handler = fn( path: *str, line: u64, col: u64, msg: str, ) never; let handle_abort: *abort_handler = &platform_abort; // Sets a new global runtime abort handler. export fn onabort(handler: *abort_handler) void = { handle_abort = handler; }; export @symbol("rt.abort") fn _abort( path: *str, line: u64, col: u64, msg: str, ) never = { handle_abort(path, line, col, msg); }; // See harec:include/gen.h const reasons: [_]str = [ "slice or array access out of bounds", // 0 "type assertion failed", // 1 "out of memory", // 2 "static insert/append exceeds slice capacity", // 3 "execution reached unreachable code (compiler bug)", // 4 "slice allocation capacity smaller than initializer", // 5 "assertion failed", // 6 "error occurred", // 7 ]; export fn abort_fixed(path: *str, line: u64, col: u64, i: u64) void = { handle_abort(path, line, col, reasons[i]); }; hare-0.24.2/rt/ensure.ha000066400000000000000000000016221464473310100147620ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type slice = struct { data: nullable *opaque, length: size, capacity: size, }; export fn ensure(s: *slice, membsz: size) void = { let capacity = s.capacity; if (capacity >= s.length) { return; }; for (capacity < s.length) { assert(capacity >= s.capacity, "slice out of memory (overflow)"); if (capacity == 0) { capacity = s.length; } else { capacity *= 2; }; }; s.capacity = capacity; const data = realloc(s.data, s.capacity * membsz); assert(data != null || s.capacity * membsz == 0); s.data = data; }; export fn unensure(s: *slice, membsz: size) void = { let capacity = s.capacity; for (capacity > s.length) { capacity /= 2; }; capacity *= 2; s.capacity = capacity; const data = realloc(s.data, s.capacity * membsz); assert(data != null || s.capacity * membsz == 0); s.data = data; }; hare-0.24.2/rt/fenv_defs.ha000066400000000000000000000004501464473310100154160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn feclearexcept(ex: uint) void; export fn feraiseexcept(ex: uint) void; export fn fetestexcept(ex: uint) uint; export fn fegetround() uint; export fn fesetround(mode: uint) void; // TODO fesetenv/fegetenv? hare-0.24.2/rt/jmp.ha000066400000000000000000000004061464473310100142460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type jmpbuf = struct { __jb: arch_jmpbuf, __fl: size, __ss: [128 / size(size)]size, }; export fn setjmp(buf: *jmpbuf) int; export fn longjmp(buf: *jmpbuf, n: int) never; hare-0.24.2/rt/malloc+debug.ha000066400000000000000000000037231464473310100160160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // This is a very simple "debug" allocator which works by allocating only via // mmap and returning pointers to the end of the segment such that any writes // beyond the end will cause an immediate segfault to occur. // // Ultimately, this should be replaced with a much more sophisticated debugging // allocator. let pagesz: size = 4096; def AUXV_PAGESZ: u64 = 6; type auxv64 = struct { a_type: u64, union { a_val: u64, a_ptr: *opaque, a_fnc: *fn() void, } }; @init fn init() void = { let i = 0; for (envp[i] != null) { i += 1; }; let auxv = &envp[i + 1]: *[*]auxv64; for (let i = 0z; auxv[i].a_type != 0; i += 1) { if (auxv[i].a_type == AUXV_PAGESZ) { pagesz = auxv[i].a_val: size; break; }; }; }; export fn malloc(n: size) nullable *opaque = { if (n == 0) { return null; }; let z = n + size(*opaque) + size(size); if (z % pagesz != 0) { z += pagesz - z % pagesz; }; let seg = match (segmalloc(z)) { case null => return null; case let ptr: *opaque => yield ptr; }; let user = &(seg: *[*]u8)[z - n]; let segptr = &(user: *[*]*opaque)[-1]; let szptr = &(segptr: *[*]size)[-1]; *segptr = seg; *szptr = n; return user; }; export @symbol("rt.free") fn free_(_p: nullable *opaque) void = { if (_p != null) { let user = _p: *opaque; let segptr = &(user: *[*]*opaque)[-1]; let szptr = &(segptr: *[*]size)[-1]; let z = *szptr + size(*opaque) + size(size); if (z % pagesz != 0) { z += pagesz - z % pagesz; }; segfree(*segptr, z); }; }; export fn realloc(user: nullable *opaque, n: size) nullable *opaque = { if (n == 0) { free(user); return null; } else if (user == null) { return malloc(n); }; let user = user: *opaque; let segptr = &(user: *[*]*opaque)[-1]; let szptr = &(segptr: *[*]size)[-1]; let z = *szptr; let new = malloc(n); if (new != null) { memcpy(new: *opaque, user, if (z < n) z else n); free(user); }; return new; }; hare-0.24.2/rt/malloc+libc.ha000066400000000000000000000021321464473310100156320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Allocates n bytes of memory and returns a pointer to them, or null if there // is insufficient memory. export fn malloc(n: size) nullable *opaque = { return c_malloc(n); }; // Changes the allocation size of a pointer to n bytes. If n is smaller than // the prior allocation, it is truncated; otherwise the allocation is expanded // and the values of the new bytes are undefined. May return a different pointer // than the one given if there is insufficient space to expand the pointer // in-place. Returns null if there is insufficient memory to support the // request. export fn realloc(p: nullable *opaque, n: size) nullable *opaque = { if (n == 0) { free(p); return null; }; return c_realloc(p, n); }; // Frees a pointer previously allocated with [[malloc]]. export @symbol("rt.free") fn free_(p: nullable *opaque) void = { c_free(p); }; @symbol("malloc") fn c_malloc(size) nullable *opaque; @symbol("realloc") fn c_realloc(nullable *opaque, size) nullable *opaque; @symbol("free") fn c_free(nullable *opaque) void; hare-0.24.2/rt/malloc.ha000066400000000000000000000222441464473310100147330ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // This is a simple memory allocator, based on // Appel, Andrew W., and David A. Naumann. "Verified sequential malloc/free" // but with logarithmic bin sizing and additional safety checks. Not thread-safe // A group of blocks that were allocated together. export type chunk = union { padding: size, // TODO: track number of active allocations here data: [*]u8, }; // Metadata for a block. export type meta = struct { union { sz: size, next: uintptr, }, user: [*]u8, }; // Size of the header/footer for allocations. def META: size = size(size); // Alignment for pointers returned by malloc. // XXX: arch def ALIGN: size = 16; // Allocation granularity for large allocs. Only used to allow verifying large // heap pointers, doesn't necessarily need to match system page size. def PAGESZ: size = 4096; // Amount of memory to allocate at a time for chunks (2MiB). def CHUNKSZ: size = 1 << 21; // Byte to fill allocations with while they're not in use. def POISON: u8 = 0x69; export type memory_heap = struct { // Number of allocations currently in flight. cur_allocs: size, // Freelists for blocks up to 2048 bytes. bins: [9]nullable *meta, // The chunk to allocate from if there are no blocks available in the // right freelist. cur_chunk: (*chunk, size), }; let static_heap = memory_heap { cur_allocs = 0, bins = [null...], cur_chunk = (null: *chunk, CHUNKSZ), }; let heap = &static_heap; export fn newheap() memory_heap = { // Re-initializes the heap from scratch, abandoning all prior memory // allocations and returning the previous heap. // // This function is designed to be called by debug:: in a scenario where // the heap has been corrupted. It abandons the corrupt heap and // prepares a fresh heap which debug:: can use to allocate memory for // any operations it needs to perform during clean-up. const old = *heap; *heap = memory_heap { cur_allocs = 0, bins = [null...], cur_chunk = (null: *chunk, CHUNKSZ), }; return old; }; // Allocates n bytes of memory and returns a pointer to them, or null if there // is insufficient memory. export fn malloc(n: size) nullable *opaque = { if (n == 0) return null; if (size_islarge(n)) { // Round up to PAGESZ and just use mmap directly n = realsz(n); let m = match (segmalloc(n + ALIGN + META)) { case null => return null; case let p: *opaque => yield (p: uintptr + ALIGN - META): *meta; }; m.sz = n; *(&m.user[n]: *size) = n; // For out-of-bounds write detection heap.cur_allocs += 1; return &m.user; }; let bin = size_getbin(n), sz = bin_getsize(bin); let m = match (heap.bins[bin]) { case null => if (heap.cur_chunk.1 + META + sz + META > CHUNKSZ) { // No space left in this chunk, allocate a new one match (segmalloc(CHUNKSZ)) { case null => return null; case let p: *opaque => heap.cur_chunk = (p: *chunk, size(size)); }; }; // Allocate a new block from the currently-active chunk let m = &heap.cur_chunk.0.data[heap.cur_chunk.1]: *meta; heap.cur_chunk.1 += META + sz; m.sz = sz; *(&m.user[sz]: *size) = sz; yield m; case let m: *meta => // Pop a block off the freelist heap.bins[bin] = meta_next(m); checkpoison(m, sz); m.sz = sz; yield m; }; heap.cur_allocs += 1; return &m.user; }; // Frees an allocation returned by [[malloc]]. Freeing any other pointer, or // freeing a pointer that's already been freed, will cause an abort. export @symbol("rt.free") fn free_(p: nullable *opaque) void = { let m = match (p) { case null => return; case let p: *opaque => yield getmeta(p); }; heap.cur_allocs -= 1; if (size_islarge(m.sz)) { // Pass through to munmap segfree((p: uintptr - ALIGN): *opaque, m.sz + ALIGN + META); return; }; // Push onto freelist let bin = size_getbin(m.sz); m.user[..m.sz] = [POISON...]; m.next = heap.bins[bin]: uintptr | 0b1; heap.bins[bin] = m; }; // Changes the allocation size of a pointer to n bytes. If n is smaller than // the prior allocation, it is truncated; otherwise the allocation is expanded // and the values of the new bytes are undefined. May return a different pointer // than the one given if there is insufficient space to expand the pointer // in-place. Returns null if there is insufficient memory to support the // request. export fn realloc(p: nullable *opaque, n: size) nullable *opaque = { if (n == 0) { free(p); return null; }; let m = match (p) { case null => return malloc(n); case let p: *opaque => yield getmeta(p); }; if (realsz(n) == m.sz) return p; let new = match (malloc(n)) { case null => return null; case let new: *opaque => yield new; }; memcpy(new, &m.user, if (n < m.sz) n else m.sz); free(p); return new; }; // Gets the metadata for a given allocation. The provided pointer must have been // returned by [[malloc]] or [[realloc]] and must not have been freed. export fn getmeta(p: *opaque) *meta = { let m = (p: uintptr - META): *meta; validatemeta(m, false); assert(m.sz & 0b1 == 0, "tried to get metadata for already-freed pointer (double free?)"); return m; }; // Find the maximum allocation size for a given bin. fn bin_getsize(bin: size) size = { // Would need to have bin 0 be ALIGN rather than 0 in this case static assert(ALIGN != META); // Space bins logarithmically let sz = if (bin == 0) 0z else 1 << (bin - 1); // And make sure that (bin_getsize(n) + META) % ALIGN == 0, while erring on // the side of bin sizes slightly larger than powers of two return sz * ALIGN + ALIGN - META; }; // Find the bin for a given allocation size. fn size_getbin(sz: size) size = { // Undo alignment fudging. Equivalent to // ceil((sz - ALIGN + META) / ALIGN) sz = (sz + META - 1) / ALIGN; // Then undo exponentiation if (sz == 0) return 0; let ret = 0z; for (1 << ret < sz; ret += 1) void; return ret + 1; }; // Returns true if a given allocation size should use mmap directly. fn size_islarge(sz: size) bool = sz > bin_getsize(len(heap.bins) - 1); // Gets the next block on the freelist. fn meta_next(m: *meta) nullable *meta = { assert(m.next & 0b1 == 0b1, "expected metadata on freelist to be marked as free (heap corruption?)"); return (m.next & ~0b1): nullable *meta; }; // Round a user-requested allocation size up to the next-smallest size we can // allocate. fn realsz(sz: size) size = { if (size_islarge(sz)) { sz += ALIGN + META; if (sz % PAGESZ != 0) sz += PAGESZ - sz % PAGESZ; return sz - ALIGN - META; }; return bin_getsize(size_getbin(sz)); }; // Check for memory errors related to a given block of memory. fn validatemeta(m: *meta, shallow: bool) void = { assert(&m.user: uintptr % ALIGN == 0, "invalid alignment for metadata pointer (heap corruption?)"); // If we were recursively called to check a next pointer, the block // needs to be marked as free, abort in meta_next() if it's not if (m.sz & 0b1 == 0b1 || shallow == true) { // Block is currently free, verify that it points to a valid // next block match (meta_next(m)) { case null => void; case let next: *meta => assert(next: uintptr % ALIGN == META, "invalid metadata for small allocation on freelist (heap corruption?)"); if (!shallow) validatemeta(next, true); }; return; }; // Block is currently allocated, verify that its size is valid let second = &m.user[m.sz]: *meta; if (size_islarge(m.sz)) { assert((&m.user: uintptr - ALIGN) % PAGESZ == 0, "invalid large allocation address (non-heap pointer?)"); assert((m.sz + ALIGN + META) % PAGESZ == 0, "invalid metadata for large allocation (non-heap pointer?)"); assert(second.sz == m.sz, "invalid secondary metadata for large allocation (out-of-bounds write?)"); return; }; assert(bin_getsize(size_getbin(m.sz)) == m.sz, "invalid metadata for small allocation (non-heap pointer?)"); if (second.sz & 0b1 == 0b1) { // Next block after it in the chunk is free, recursively verify // that it's valid validatemeta(second, false); return; }; // Note that we can't recurse here because the "next block" might // actually be the extra metadata at the end of the chunk (which is // never marked as being on the freelist assert(!size_islarge(second.sz), "invalid secondary metadata for small allocation (out-of-bounds write?)"); assert(bin_getsize(size_getbin(second.sz)) == second.sz, "invalid secondary metadata for small allocation (out-of-bounds write?)"); }; // Verify that a pointer on a free list hasn't been touched since it was added. fn checkpoison(m: *meta, sz: size) void = { match (meta_next(m)) { case null => void; case let next: *meta => validatemeta(next, false); }; for (let i = 0z; i < sz; i += 1) { assert(m.user[i] == POISON, "invalid poison data on freelist (use after free?)"); }; }; @fini fn checkleaks() void = { for (let i = 0z; i < len(heap.bins); i += 1) { for (let m = heap.bins[i]; m != null; m = meta_next(m as *meta)) { checkpoison(m as *meta, bin_getsize(i)); }; }; // TODO: Need a debugging malloc that tracks backtraces for // currently-active allocations in order to help with finding leaks // before we enable this by default. Also need to make sure that this is // run after the rest of @fini in order to guarantee that we see all // frees //assert(heap.cur_allocs == 0, "memory leak"); }; hare-0.24.2/rt/memcpy.ha000066400000000000000000000052771464473310100147650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def MOD32 = size(u32) - 1; export fn memcpy(dest: *opaque, src: *const opaque, n: size) void = { // implementation adapted from musl libc let d = memfunc_ptr { byte = dest: *[*]u8 }; let s = memfunc_ptr { byte = src: *[*]u8 }; // copy bytes until src pointer is u32-aligned for (s.uptr & MOD32 != 0 && 0 < n; n -= 1) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; // if dest is u32-aligned with src, copy as batches of u32s if (d.uptr & MOD32 == 0) { for (16 <= n; n -= 16) { d.quad[0] = s.quad[0]; d.quad[1] = s.quad[1]; d.quad[2] = s.quad[2]; d.quad[3] = s.quad[3]; d.uptr += 16; s.uptr += 16; }; if (n & 8 != 0) { d.quad[0] = s.quad[0]; d.quad[1] = s.quad[1]; d.uptr += 8; s.uptr += 8; }; if (n & 4 != 0) { d.quad[0] = s.quad[0]; d.uptr += 4; s.uptr += 4; }; } else { // TODO: musl uses some byte-order-dependent code here // which could be incorporated at some point. for (16 <= n; n -= 16) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; if (n & 8 != 0) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; if (n & 4 != 0) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; }; if (n & 2 != 0) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; if (n & 1 != 0) { d.byte[0] = s.byte[0]; }; }; hare-0.24.2/rt/memfunc_ptr.ha000066400000000000000000000002741464473310100160020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors type memfunc_ptr = union { byte: *[*]u8, quad: *[*]u32, octs: *[*]u64, sz: *[*]size, uptr: uintptr, }; hare-0.24.2/rt/memmove.ha000066400000000000000000000031331464473310100151250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def SZSZ = size(size); def MODSZ = size(size) - 1; export fn memmove(dest: *opaque, src: *const opaque, n: size) void = { // implementation adapted from musl libc let d = memfunc_ptr { byte = dest: *[*]u8 }; let s = memfunc_ptr { byte = src: *[*]u8 }; if (d.uptr == s.uptr) return; // equivalent to n <= abs(src - dest) if (s.uptr - d.uptr - n <= -2*n) return memcpy(dest, src, n); if (d.uptr < s.uptr) { // if alignment matches, copy the majority as []size if (s.uptr & MODSZ == d.uptr & MODSZ) { // use u8 until we reach a word boundary for (0 < d.uptr & MODSZ) { if (n == 0) return else n -= 1; d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; for (SZSZ <= n; n -= SZSZ) { d.sz[0] = s.sz[0]; // TODO: should be +=, blocked on compiler bug d.uptr = d.uptr + SZSZ; s.uptr = s.uptr + SZSZ; }; }; for (0 < n; n -= 1) { d.byte[0] = s.byte[0]; d.uptr += 1; s.uptr += 1; }; } else { d.uptr = d.uptr + n; s.uptr = s.uptr + n; // if alignment matches, copy the majority as []size if (s.uptr & MODSZ == d.uptr & MODSZ) { // use u8 until we reach a word boundary for (0 < d.uptr & MODSZ) { if (n == 0) return else n -= 1; d.uptr -= 1; s.uptr -= 1; d.byte[0] = s.byte[0]; }; for (SZSZ <= n; n -= SZSZ) { // TODO: should be -=, blocked on compiler bug d.uptr = d.uptr - SZSZ; s.uptr = s.uptr - SZSZ; d.sz[0] = s.sz[0]; }; }; for (0 < n; n -= 1) { d.uptr -= 1; s.uptr -= 1; d.byte[0] = s.byte[0]; }; }; }; hare-0.24.2/rt/memset.ha000066400000000000000000000042031464473310100147510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export fn memset(dest: *opaque, val: u8, n: size) void = { // implementation adapted from musl libc let d = memfunc_ptr { byte = dest: *[*]u8 }; // fill 4 bytes of head and tail with minimal branching. the head/tail // regions may overlap, in which case we return early, and if not // then we infer that we can fill twice as much on the next round. if (n == 0) return; d.byte[0] = val; d.byte[n-1] = val; if (n <= 2) return; d.byte[1] = val; d.byte[2] = val; d.byte[n-2] = val; d.byte[n-3] = val; if (n <= 6) return; d.byte[3] = val; d.byte[n-4] = val; // NOTE: we could do more here but the work would be duplicated later if (n <= 8) return; // advance pointer to align it at a 4-byte boundary, // and truncate n to a multiple of 4. the previous code // already took care of any head/tail that get cut off // by the alignment let diff = -d.uptr & 0b11; d.uptr = d.uptr + diff; n -= diff; // convert length in u8 to u32, truncating it in the process n >>= 2; // 4-byte copy of val let val32 = 0x01010101u32 * val; // fill 7 u32s (28 bytes) of head and tail, using the same process // as before. we don't need to check for n == 0 because we advanced <4 // bytes out of more than 8, so there's at least one u32 left. d.quad[0] = val32; d.quad[n-1] = val32; if (n <= 2) return; d.quad[1] = val32; d.quad[2] = val32; d.quad[n-2] = val32; d.quad[n-3] = val32; if (n <= 6) return; d.quad[3] = val32; d.quad[4] = val32; d.quad[5] = val32; d.quad[6] = val32; d.quad[n-4] = val32; d.quad[n-5] = val32; d.quad[n-6] = val32; d.quad[n-7] = val32; // align to a multiple of 8 so we can copy as u64. // NOTE: the 24 here skips over most of the head we just filled, // while making sure that diff <= 28 diff = 24 + (d.uptr & 4); d.uptr = d.uptr + diff; n -= diff >> 2; // 28 tail bytes have already been filled, so any remainder // when n <= 7 (28 bytes) can be safely ignored const val64 = (val32: u64 << 32) | val32; for (8 <= n; n -= 8) { d.octs[0] = val64; d.octs[1] = val64; d.octs[2] = val64; d.octs[3] = val64; d.uptr += 32; }; }; hare-0.24.2/rt/strcmp.ha000066400000000000000000000006261464473310100147740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors type string = struct { data: *[*]u8, length: size, capacity: size, }; export fn strcmp(_a: str, _b: str) bool = { if (len(_a) != len(_b)) { return false; }; let a = (&_a: *string).data, b = (&_b: *string).data; for (let i = 0z; i < len(_a); i += 1) { if (a[i] != b[i]) { return false; }; }; return true; }; hare-0.24.2/rt/u64tos.ha000066400000000000000000000006421464473310100146260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def U64_BUFSZ = 20; fn u64tos(buf: []u8, u: u64) str = { let sl = buf[..0]; if (u == 0) { static append(sl, '0'); }; for (u > 0) { static append(sl, (u % 10): u8 + '0'); u /= 10; }; for (let s = 0z, e = len(sl) - 1; s < e) { let tmp = sl[s]; sl[s] = sl[e]; sl[e] = tmp; s += 1; e -= 1; }; return *(&sl: *str); }; hare-0.24.2/rt/unknown_errno.ha000066400000000000000000000014361464473310100163700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors fn unknown_errno(err: errno) str = { static let buf: [27]u8 = [0...]; let ubuf: [U64_BUFSZ]u8 = [0...]; let sl = buf[..0]; const s = *(&"[unknown errno ": *[]u8); static append(sl, s...); if (err < 0) { static append(sl, '-'); const s = u64tos(ubuf, -err: u64); static append(sl, *(&s: *[]u8)...); static append(sl, ']'); } else { const s = u64tos(ubuf, err: u64); static append(sl, *(&s: *[]u8)...); static append(sl, ']'); }; return *(&sl: *str); }; @test fn unknown_errno() void = { let err: errno = -1; assert(strerror(err) == "[unknown errno -1]"); err = 0; assert(strerror(err) == "[unknown errno 0]"); err = 2147483647; assert(strerror(err) == "[unknown errno 2147483647]"); }; hare-0.24.2/scripts/000077500000000000000000000000001464473310100142105ustar00rootroot00000000000000hare-0.24.2/scripts/genbootstrap000077500000000000000000000007001464473310100166420ustar00rootroot00000000000000#!/bin/sh -eu cd "$(dirname "$0")/.." mkdir -p "${BINOUT:-.bin}" makefiles/ hare build -o "${BINOUT:-.bin}"/genbootstrap cmd/genbootstrap for platform in linux freebsd openbsd netbsd; do platformtags= if [ $platform = "openbsd" ]; then platformtags=libc fi for arch in x86_64 aarch64 riscv64; do echo makefiles/$platform.$arch.mk "${BINOUT:-.bin}"/genbootstrap $platform $arch $platformtags \ >makefiles/$platform.$arch.mk done done hare-0.24.2/scripts/lint.sh000077500000000000000000000022611464473310100155160ustar00rootroot00000000000000#!/bin/sh -eu # XXX: technically doesn't work with paths that have newlines in them, but # find -exec doesn't propagate the exit status find . -name '*.ha' | while read -r f; do awk 'BEGIN { state = "start" } /./ { empty = 0 } /^$/ { empty = 1 } /[ \t]$/ { print "trailing whitespace in " FILENAME exit 1 } state == "start" { if ($0 !~ /^\/\/ SPDX-License-Identifier: /) { print "missing copyright header in " FILENAME exit 1 } state = "author" next } state == "author" { if ($0 != "// (c) Hare authors ") { print "invalid authorship information in " FILENAME exit 1 } state = "comment" next } state == "comment" && $0 !~ /^\/\// { if ($0 != "") { print "missing empty line after copyright header in " FILENAME exit 1 } state = "postheader" next } state == "postheader" { if ($0 == "") { print "extra empty line after copyright header in " FILENAME exit 1 } state = "body" } END { if (state != "body") { print "incomplete copyright header in " FILENAME exit 1 } if (empty) { print "trailing empty line in " FILENAME exit 1 } }' "$f" done hare-0.24.2/scripts/moddirs000077500000000000000000000002241464473310100155750ustar00rootroot00000000000000#!/bin/sh for i in *; do case "$i" in .* | cmd | configs | contrib | docs | makefiles | scripts) ;; *) find -- "$i" -prune -type d ;; esac done hare-0.24.2/scripts/version000077500000000000000000000006361464473310100156300ustar00rootroot00000000000000#!/bin/sh # Distro packagers may set the LOCALVER variable to add their distribution to # the version, e.g. 1.0-alpine. VERSION=${VERSION:0.24.2} ver=$(git describe 2>/dev/null) if [ $? -ne 0 ] then ver="dev+$(git log -1 --format='%h' 2>/dev/null)" if [ $? -ne 0 ] then # git presumed unavailable ver=$VERSION fi fi localver=${LOCALVER:-} if [ ${#localver} != 0 ] then ver="$ver-$localver" fi echo $ver hare-0.24.2/shlex/000077500000000000000000000000001464473310100136445ustar00rootroot00000000000000hare-0.24.2/shlex/+test.ha000066400000000000000000000040701464473310100152110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use memio; use strings; @test fn split() void = { const s = split(`hello\ world`)!; defer strings::freeall(s); assert(len(s) == 1); assert(s[0] == "hello world"); const s = split(`'hello\ world'`)!; defer strings::freeall(s); assert(len(s) == 1); assert(s[0] == `hello\ world`); const s = split(`"hello\\world"`)!; defer strings::freeall(s); assert(len(s) == 1); assert(s[0] == `hello\world`); const s = split(`"hello "'"'"world"'"'`)!; defer strings::freeall(s); assert(len(s) == 1); assert(s[0] == `hello "world"`); const s = split("hello '' world")!; defer strings::freeall(s); assert(len(s) == 3); assert(s[0] == "hello"); assert(s[1] == ""); assert(s[2] == "world"); const s = split("Empty ''")!; defer strings::freeall(s); assert(len(s) == 2); assert(s[0] == "Empty"); assert(s[1] == ""); const s = split(" Leading spaces")!; defer strings::freeall(s); assert(len(s) == 2); assert(s[0] == "Leading"); assert(s[1] == "spaces"); const s = split(`with\ backslashes 'single quoted' "double quoted"`)!; defer strings::freeall(s); assert(len(s) == 3); assert(s[0] == "with backslashes"); assert(s[1] == "single quoted"); assert(s[2] == "double quoted"); const s = split("'multiple spaces' 42")!; defer strings::freeall(s); assert(len(s) == 2); assert(s[0] == "multiple spaces"); assert(s[1] == "42"); // Invalid assert(split(`"dangling double quote`) is syntaxerr); assert(split("'dangling single quote") is syntaxerr); assert(split(`unterminated\ backslash \`) is syntaxerr); }; fn testquote(sink: *memio::stream, s: str, expected: str) void = { assert(quote(sink, s)! == len(expected)); assert(memio::string(sink)! == expected); memio::reset(sink); }; @test fn quote() void = { const sink = memio::dynamic(); defer io::close(&sink)!; testquote(&sink, `hello`, `hello`); testquote(&sink, `hello world`, `'hello world'`); testquote(&sink, `'hello' "world"`, `''"'"'hello'"'"' "world"'`); testquote(&sink, `hello\world`, `'hello\world'`); }; hare-0.24.2/shlex/README000066400000000000000000000001161464473310100145220ustar00rootroot00000000000000The shlex module provides lexical tools for working with POSIX shell grammar. hare-0.24.2/shlex/escape.ha000066400000000000000000000023301464473310100154140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use encoding::utf8; use io; use memio; use strings; fn is_safe(s: str) bool = { const iter = strings::iter(s); for (let rn => strings::next(&iter)) { switch (rn) { case '@', '%', '+', '=', ':', ',', '.', '/', '-' => void; case => if (!ascii::isalnum(rn) || ascii::isspace(rn)) { return false; }; }; }; return true; }; // Quotes a shell string and writes it to the provided I/O handle. export fn quote(sink: io::handle, s: str) (size | io::error) = { if (len(s) == 0) { return io::writeall(sink, strings::toutf8(`''`))?; }; if (is_safe(s)) { return io::writeall(sink, strings::toutf8(s))?; }; let z = io::writeall(sink, ['\''])?; const iter = strings::iter(s); for (let rn => strings::next(&iter)) { if (rn == '\'') { z += io::writeall(sink, strings::toutf8(`'"'"'`))?; } else { z += io::writeall(sink, utf8::encoderune(rn))?; }; }; z += io::writeall(sink, ['\''])?; return z; }; // Quotes a shell string and returns a new string. The caller must free the // return value. export fn quotestr(s: str) str = { const sink = memio::dynamic(); quote(&sink, s)!; return memio::string(&sink)!; }; hare-0.24.2/shlex/split.ha000066400000000000000000000046631464473310100153220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use memio; use strings; // Invalid shell syntax. export type syntaxerr = !void; // Converts an error into a human-friendly string. export fn strerror(err: syntaxerr) str = "Invalid shell syntax"; // Splits a string of arguments according to shell quoting. The result must be // freed using [[strings::freeall]] when the caller is done processing it. export fn split(in: const str) ([]str | syntaxerr) = { let iter = strings::iter(in); let s = memio::dynamic(); defer io::close(&s)!; let slice: []str = []; let first = true; let dirty = false; for (let r => strings::next(&iter)) { dirty = true; switch (r) { case ' ', '\t', '\n' => for (let r => strings::next(&iter)) { if (r != ' ' && r != '\t' && r != '\n') { strings::prev(&iter); // Unget break; }; }; if (!first) { const item = memio::string(&s)!; append(slice, strings::dup(item)); memio::reset(&s); }; dirty = false; case '\\' => scan_backslash(&s, &iter)?; case '"' => scan_double(&s, &iter)?; case '\'' => scan_single(&s, &iter)?; case => memio::appendrune(&s, r)!; }; if (first) { first = false; }; }; if (dirty) { const item = memio::string(&s)!; append(slice, strings::dup(item)); }; return slice; }; fn scan_backslash(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { const r = match (strings::next(in)) { case let r: rune => yield r; case done => return syntaxerr; }; // The and shall be removed before splitting the // input into tokens. Since the escaped is removed entirely // from the input and is not replaced by any white space, it cannot // serve as a token separator if (r == '\n') { return; }; memio::appendrune(out, r)!; }; fn scan_double(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { for (true) { const r = match (strings::next(in)) { case let r: rune => yield r; case done => return syntaxerr; }; switch (r) { case '"' => break; case '\\' => scan_backslash(out, in)?; case => memio::appendrune(out, r)!; }; }; }; fn scan_single(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { for (true) { const r = match (strings::next(in)) { case let r: rune => yield r; case done => return syntaxerr; }; if (r == '\'') { break; }; memio::appendrune(out, r)!; }; }; hare-0.24.2/sort/000077500000000000000000000000001464473310100135105ustar00rootroot00000000000000hare-0.24.2/sort/+test.ha000066400000000000000000000057151464473310100150640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math::random; use sort::cmp; use types; @test fn lbisect() void = { const nums = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; for (let i = 0z; i < len(nums); i += 1) { if (i != 0 && nums[i - 1] == nums[i]) continue; const key = nums[i]; assert(lbisect(nums, size(int), &key, &cmp::ints) == i); }; const n = 0; assert(lbisect(nums, size(int), &n, &cmp::ints) == 0); const n = 6; assert(lbisect(nums, size(int), &n, &cmp::ints) == 5); const n = 8; assert(lbisect(nums, size(int), &n, &cmp::ints) == 6); const n = 12; assert(lbisect(nums, size(int), &n, &cmp::ints) == len(nums)); }; @test fn rbisect() void = { const nums = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; for (let i = 0z; i < len(nums); i += 1) { if (i != len(nums) - 1 && nums[i + 1] == nums[i]) continue; const key = nums[i]; assert(rbisect(nums, size(int), &key, &cmp::ints) == i + 1); }; const n = 0; assert(rbisect(nums, size(int), &n, &cmp::ints) == 0); const n = 6; assert(rbisect(nums, size(int), &n, &cmp::ints) == 5); const n = 8; assert(rbisect(nums, size(int), &n, &cmp::ints) == 6); const n = 12; assert(rbisect(nums, size(int), &n, &cmp::ints) == len(nums)); }; @test fn search() void = { const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let i = 0z; i < len(nums); i += 1) { const key = nums[i]; const p = search(nums, size(int), &key, &cmp::ints) as size; assert(p == i); }; const key = 1337; assert(search(nums, size(int), &key, &cmp::ints) is void); }; @test fn sort() void = { let nums = [ 1, 6, 10, 7, 8, 10, 10, 3, 7, 5, 5, 8, 1, 1, 1, 9, 2, 3, 1, 4, 2, 1, 5, 3, 2, 5, 10, 1, 7, 6, 8, 10, 6, 5, 7, 4, 3, 9, 9, 4, 7, 10, 3, 4, 4, 8, 5, 6, 2, 1, 6, 2, 2, 2, 10, 8, 3, 4, 5, 6, 6, 2, 5, 2, 3, 7, 10, 7, 7, 5, 5, 2, 3, 4, 5, 3, 6, 2, 3, 6, 8, 8, 9, 7, 10, 4, 10, 3, 2, 7, 10, 8, 8, 2, 2, 5, 3, 7, 4, 1, ]; sort(nums, size(int), &cmp::ints); for (let i = 1z; i < len(nums); i += 1) { assert(nums[i] >= nums[i - 1]); }; }; @test fn big_equal() void = { let nums = alloc([42...], 1000000); defer free(nums); sort(nums, size(int), &cmp::ints); for (let i = 0z; i < len(nums); i += 1) { assert(nums[i] == 42); }; }; @test fn big_random() void = { let nums = alloc([0...], 100000); defer free(nums); let rand = random::init(0x424242); for (let i = 0z; i < len(nums); i += 1) { nums[i] = random::next(&rand): int; }; sort(nums, size(int), &cmp::ints); for (let i = 1z; i < len(nums); i += 1) { assert(nums[i] >= nums[i - 1]); }; }; @test fn sorted() void = { let nums = [1, 3, 2]; assert(!sorted(nums, size(int), &cmp::ints)); sort(nums, size(int), &cmp::ints); assert(sorted(nums, size(int), &cmp::ints)); assert(sorted(nums[..0], size(int), &cmp::ints)); }; @test fn cmp::ints() void = { assert(cmp::ints(&5, &0) == 1); assert(cmp::ints(&0, &5) == -1); assert(cmp::ints(&0, &0) == 0); assert(cmp::ints(&0, &types::INT_MIN) == 1); assert(cmp::ints(&types::INT_MIN, &0) == -1); }; hare-0.24.2/sort/README000066400000000000000000000007551464473310100143770ustar00rootroot00000000000000The sort module provides functions for sorting slices, as well as operations on sorted slices, such as binary search. The functions [[sort]] and [[search]] are provided for working with generic slices. In order to work with a user-supplied slice of an arbitrary type, the slice must be cast to []opaque and the size of the member type passed alongside it (e.g. size(int)). The functions also take in a [[cmpfunc]] argument, which is called to determine how the slice items should be ordered. hare-0.24.2/sort/bisect.ha000066400000000000000000000026571464473310100153050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Determines the index that 'elem' should be inserted into sorted slice 'in'. // If 'elem' already appears in the slice, inserting to the returned index will // insert immediately before the first occurance. export fn lbisect( in: []const opaque, sz: size, elem: const *opaque, cmp: *cmpfunc, ) size = { let min = 0z, max = len(in); const in = in: *[*]u8; for (min < max) { let i = (max - min) / 2 + min; const r = cmp(elem, &in[i * sz]); if (r < 0) { max = i; } else if (r > 0) { min = i + 1; } else { if (i == 0) return 0; for (i > 0; i -= 1) { if (cmp(elem, &in[(i - 1) * sz]) != 0) { break; }; }; return i; }; }; return max; }; // Determines the index that 'elem' should be inserted into sorted slice 'in'. // If 'elem' already appears in the slice, inserting to the returned index will // insert immediately after the last occurance. export fn rbisect( in: []const opaque, sz: size, elem: const *opaque, cmp: *cmpfunc, ) size = { const nmemb = len(in); let min = 0z, max = nmemb; const in = in: *[*]u8; for (min < max) { let i = (max - min) / 2 + min; const r = cmp(elem, &in[i * sz]); if (r < 0) { max = i; } else if (r > 0) { min = i + 1; } else { i += 1; for (i < nmemb; i += 1) { if (cmp(elem, &in[i * sz]) != 0) { break; }; }; return i; }; }; return max; }; hare-0.24.2/sort/cmp/000077500000000000000000000000001464473310100142675ustar00rootroot00000000000000hare-0.24.2/sort/cmp/cmp.ha000066400000000000000000000052361464473310100153660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // [[sort::cmpfunc]] for use with int. export fn ints(a: const *opaque, b: const *opaque) int = { const a = *(a: const *int), b = *(b: const *int); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with uint. export fn uints(a: const *opaque, b: const *opaque) int = { const a = *(a: const *uint), b = *(b: const *uint); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with i8. export fn i8s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *i8): int, b = *(b: const *i8): int; return a - b; }; // [[sort::cmpfunc]] for use with u8. export fn u8s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *u8): int, b = *(b: const *u8): int; return a - b; }; // [[sort::cmpfunc]] for use with i16. export fn i16s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *i16): int, b = *(b: const *i16): int; return a - b; }; // [[sort::cmpfunc]] for use with u16. export fn u16s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *u16): int, b = *(b: const *u16): int; return a - b; }; // [[sort::cmpfunc]] for use with i32. export fn i32s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *i32), b = *(b: const *i32); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with u32. export fn u32s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *u32), b = *(b: const *u32); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with i64. export fn i64s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *i64), b = *(b: const *i64); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with u64. export fn u64s(a: const *opaque, b: const *opaque) int = { const a = *(a: const *u64), b = *(b: const *u64); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with size. export fn sizes(a: const *opaque, b: const *opaque) int = { const a = *(a: const *size), b = *(b: const *size); return if (a < b) -1 else if (a > b) 1 else 0; }; // [[sort::cmpfunc]] for use with str. Sorting is done with respect to Unicode // codepoints; see [[strings::compare]]. export fn strs(a: const *opaque, b: const *opaque) int = { // Manual strings::toutf8() to avoid dependency on strings const a = *(a: *[]u8), b = *(b: *[]u8); let ln = if (len(a) < len(b)) (len(a), -1) else (len(b), 1); for (let i = 0z; i < ln.0; i += 1) { if (a[i] != b[i]) { return a[i]: int - b[i]: int; }; }; return if (len(a) == len(b)) 0 else ln.1; }; hare-0.24.2/sort/search.ha000066400000000000000000000013041464473310100152650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Performs a binary search over a sorted slice. If the key is found, index of // the matching item in the slice is returned. Otherwise, void is returned. export fn search( in: []const opaque, sz: size, key: const *opaque, cmp: *cmpfunc, ) (size | void) = { let ba = in: *[*]u8; for (let nmemb = len(in); nmemb > 0) { let v = &ba[nmemb / 2 * sz]; let r = cmp(key, v); if (r < 0) { nmemb /= 2; } else if (r > 0) { ba = (v: uintptr + sz: uintptr): *[*]u8; nmemb -= nmemb / 2 + 1; } else { const offs = (v: uintptr - in: *[*]u8: uintptr); return (offs / sz: uintptr): size; }; }; return void; }; hare-0.24.2/sort/sort.ha000066400000000000000000000136521464473310100150200ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math; use types; // Sorts a slice of items in place. This function provides a stable sort - // relative order of equal elements is preserved. // // Note that this function may (temporarily) allocate, and will abort on // allocation failure. export fn sort(items: []opaque, itemsz: size, cmp: *cmpfunc) void = { if (len(items) < 256) { insort(items, itemsz, cmp); return; }; powersort(items, itemsz, cmp); }; // Checks if all of the items in a slice are sorted. export fn sorted(items: []opaque, itemsz: size, cmp: *cmpfunc) bool = { let ba = items: *[*]u8; for (let i = 1z; i < len(items); i += 1) { if (cmp(&ba[(i - 1) * itemsz], &ba[i * itemsz]) > 0) { return false; }; }; return true; }; fn swap(a: *opaque, b: *opaque, sz: size) void = { let a = a: *[*]u8, b = b: *[*]u8; for (let i = 0z; i < sz; i += 1) { let c = a[i]; a[i] = b[i]; b[i] = c; }; }; // Finds the index of the rightmost value that is equal to key or, if such value // does not exist, less than key. fn search_rightmost( in: []opaque, sz: size, key: const *opaque, cmp: *cmpfunc, ) size = { let l = 0z; let r = len(in); let ba = in: *[*]u8; for (l < r) { let m = l + (r - l) / 2; if (cmp(key, &ba[m * sz]) < 0) { r = m; } else { l = m + 1; }; }; return r - 1; }; fn insort(items: []opaque, itemsz: size, cmp: *cmpfunc) void = { let ba = items: *[*]u8; for (let i = 0z; i < len(items); i += 1) { let bound = search_rightmost(items[0..i], itemsz, &ba[i * itemsz], cmp); for (let j = i; j > bound + 1; j -= 1) { let a = &ba[(j - 1) * itemsz]; let b = &ba[j * itemsz]; swap(a, b, itemsz); }; }; }; // Based on paper "Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods // That Optimally Adapt to Existing Runs"; J. Ian Munro, Sebastian Wild // // https://arxiv.org/pdf/1805.04154.pdf def MINRUN: size = 24; // FIXME: needs tuning def EMPTY: size = -1z; // A run of non-decreasing elements on the interval [start; end). type run = struct { start: size, // Set to EMPTY when a run is merged end: size, }; fn powersort(items: []opaque, itemsz: size, cmp: *cmpfunc) void = { // npowers = floor(log2(n)) + 1 const npowers = math::bit_size_u64(len(items)) + 1; const runs: []run = alloc([run { start = EMPTY, ... }...], npowers + 1); defer free(runs); let top = 0u8; const aux: []u8 = alloc([0...], len(items) * itemsz); defer free(aux); let a = run { start = 0z, end = extend(items, itemsz, cmp, 0), }; const length = a.end - a.start; if (length < MINRUN) { a.end = if (a.start + MINRUN < len(items)) a.start + MINRUN else len(items); insort(cut(items, itemsz, a.start, a.end), itemsz, cmp); }; for (a.end < len(items)) { let b = run { start = a.end, end = extend(items, itemsz, cmp, a.end), }; const length = b.end - b.start; if (length < MINRUN) { b.end = if (b.start + MINRUN < len(items)) b.start + MINRUN else len(items); insort(cut(items, itemsz, b.start, b.end), itemsz, cmp); }; const k = node_power(0, len(items), a.start, b.start, b.end); assert(k != top); for (let i = top; i > k; i -= 1) { if (runs[i].start == EMPTY) continue; merge(items, itemsz, cmp, aux, runs[i].start, runs[i].end, a.end); a.start = runs[i].start; runs[i].start = EMPTY; }; runs[k] = a; top = k; a = b; }; assert(a.end == len(items)); for (let i = top; i > 0; i -= 1) { if (runs[i].start == EMPTY) continue; merge(items, itemsz, cmp, aux, runs[i].start, runs[i].end, len(items)); }; }; // Returns 'end' such that [start; end) in 'items' is non-decreasing // // a[0] ≤ a[1] ≤ ... ≤ a[n - 1] - kept as-is // a[1] > a[1] > ... > a[n - 1] - reversed // // Note: reversing a sequence with equal elements will move their relative // locations, which is undesirable for a stable sort. fn extend(items: []opaque, itemsz: size, cmp: *cmpfunc, start: size) size = { const n = len(items); const items = (items: *[*]u8)[..len(items) * itemsz]; assert(n - start > 0, "Empty extension"); if (start + 1 == n) { return n; }; if (cmp(&items[start * itemsz], &items[(start + 1) * itemsz]) <= 0) { let end = start + 2; for (end < n && cmp(&items[(end - 1) * itemsz], &items[end * itemsz]) <= 0) { end += 1; }; return end; } else { let end = start + 2; for (end < n && cmp(&items[(end - 1) * itemsz], &items[end * itemsz]) > 0) { end += 1; }; reverse(cut(items, itemsz, start, end), itemsz); return end; }; }; fn reverse(items: []opaque, itemsz: size) void = { const n = len(items); const items = (items: *[*]u8)[..n * itemsz]; for (let i = 0z; i < n / 2; i += 1) { swap(&items[i * itemsz], &items[(n - i - 1) * itemsz], itemsz); }; }; fn merge( items: []opaque, itemsz: size, cmp: *cmpfunc, aux: []u8, l: size, m: size, r: size, ) void = { l *= itemsz; m *= itemsz; r *= itemsz; const items = items: *[*]u8; // Placing items at the beginning results in better cache performance // (probably) aux[..m - l] = items[l..m]; let i = 0z, j = m, out = l; for (i < m - l && j < r; out += itemsz) { if (cmp(&aux[i], &items[j]) < 0) { items[out..out + itemsz] = aux[i..i + itemsz]; i += itemsz; } else { items[out..out + itemsz] = items[j..j + itemsz]; j += itemsz; }; }; if (i < m - l) { const sz = (m - l) - i; items[out..out + sz] = aux[i..i + sz]; out += sz; }; if (j < r) { const sz = r - j; items[out..out + sz] = items[j..j + sz]; out += sz; }; }; fn cut(items: []opaque, itemsz: size, l: size, r: size) []opaque = { return *(&types::slice { data = &(items: *[*]u8)[l * itemsz], length = r - l, capacity = 0, }: *[]opaque); }; fn node_power(left: size, right: size, start_a: size, start_b: size, end_b: size) u8 = { const n: u64 = right - left; const l: u64 = start_a + start_b - 2 * left; const r: u64 = start_b + end_b - 2 * left; const a = ((l << 30) / n): u32; const b = ((r << 30) / n): u32; return math::leading_zeros_u32(a ^ b); }; hare-0.24.2/sort/types.ha000066400000000000000000000006601464473310100151700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // This function type is used when sorting and searching. Given two pointers to // values, a function of this type should return an integer less than, equal to, // or greater than zero if the first argument is, respectively, less than, equal // to, or greater than the second argument. export type cmpfunc = fn(a: const *opaque, b: const *opaque) int; hare-0.24.2/strconv/000077500000000000000000000000001464473310100142175ustar00rootroot00000000000000hare-0.24.2/strconv/+test/000077500000000000000000000000001464473310100152515ustar00rootroot00000000000000hare-0.24.2/strconv/+test/ftos_test.ha000066400000000000000000000224521464473310100176020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use math; use memio; @test fn ftosf() void = { // These tests should pass for both f32 and f64. const tcs: [](f64, ffmt, (void | uint), fflags, str) = [ // First test special values (1.0 / 0.0, ffmt::G, void, 0, "infinity"), (1.0 / 0.0, ffmt::G, void, fflags::SHOW_POS, "+infinity"), (-1.0 / 0.0, ffmt::F, void, 0, "-infinity"), (-1.0 / 0.0, ffmt::E, void, fflags::UPPERCASE, "-INFINITY"), (0.0 / 0.0, ffmt::G, void, 0, "nan"), (0.0 / 0.0, ffmt::E, void, fflags::UPPERCASE, "NAN"), // Then a million tests for zero. (0.0, ffmt::E, void, 0, "0e0"), (0.0, ffmt::E, void, fflags::SHOW_TWO_EXP_DIGITS, "0e00"), (0.0, ffmt::E, void, fflags::UPPER_EXP, "0E0"), (0.0, ffmt::E, void, fflags::SHOW_POS_EXP, "0e+0"), (0.0, ffmt::E, void, fflags::SHOW_POINT, "0.0e0"), (0.0, ffmt::F, void, 0, "0"), (0.0, ffmt::F, void, fflags::SHOW_POINT, "0.0"), (0.0, ffmt::G, void, 0, "0"), (-0.0, ffmt::G, void, fflags::SHOW_POS, "-0"), (0.0, ffmt::G, void, fflags::SHOW_POS, "+0"), (0.0, ffmt::G, void, fflags::SHOW_POINT, "0.0"), // ... e and f do not cut trailing zeros (0.0, ffmt::E, 0, 0, "0e0"), (0.0, ffmt::E, 1, 0, "0.0e0"), (0.0, ffmt::E, 2, 0, "0.00e0"), (0.0, ffmt::F, 0, 0, "0"), (0.0, ffmt::F, 1, 0, "0.0"), (0.0, ffmt::F, 2, 0, "0.00"), // ... g cuts trailing zeros (0.0, ffmt::G, 0, 0, "0"), (0.0, ffmt::G, 1, 0, "0"), (0.0, ffmt::G, 2, 0, "0"), // ... SHOW_POINT only changes precision 0 (0.0, ffmt::E, 0, fflags::SHOW_POINT, "0.0e0"), (0.0, ffmt::E, 1, fflags::SHOW_POINT, "0.0e0"), (0.0, ffmt::E, 2, fflags::SHOW_POINT, "0.00e0"), (0.0, ffmt::F, 0, fflags::SHOW_POINT, "0.0"), (0.0, ffmt::F, 1, fflags::SHOW_POINT, "0.0"), (0.0, ffmt::F, 2, fflags::SHOW_POINT, "0.00"), // ... g with SHOW_POINT only has the one extra 0 (0.0, ffmt::G, 0, fflags::SHOW_POINT, "0.0"), (0.0, ffmt::G, 1, fflags::SHOW_POINT, "0.0"), (0.0, ffmt::G, 2, fflags::SHOW_POINT, "0.0"), // Now we can test actual numbers. (10.0, ffmt::F, void, 0, "10"), (1.0, ffmt::F, void, 0, "1"), (1.1, ffmt::F, void, 0, "1.1"), (13.37, ffmt::G, void, 0, "13.37"), (0.3, ffmt::F, void, 0, "0.3"), (0.0031415, ffmt::F, void, 0, "0.0031415"), (-6345.972, ffmt::F, void, 0, "-6345.972"), (1.414, ffmt::F, void, 0, "1.414"), (1000000.0e9, ffmt::F, void, 0, "1000000000000000"), (10.0, ffmt::E, void, 0, "1e1"), (10.0, ffmt::E, void, fflags::SHOW_TWO_EXP_DIGITS, "1e01"), (10.0, ffmt::E, void, fflags::UPPER_EXP, "1E1"), (10.0, ffmt::E, void, fflags::SHOW_POS_EXP, "1e+1"), (0.1, ffmt::E, void, fflags::SHOW_POS_EXP, "1e-1"), (1.0, ffmt::E, void, 0, "1e0"), (0.3, ffmt::E, void, 0, "3e-1"), (0.0031415, ffmt::E, void, 0, "3.1415e-3"), (0.12345, ffmt::E, void, 0, "1.2345e-1"), // ... g is shortest (12345.0, ffmt::G, void, 0, "12345"), (10000.0, ffmt::G, void, 0, "1e4"), (11000.0, ffmt::G, void, 0, "1.1e4"), (1000.0, ffmt::G, void, 0, "1e3"), (1100.0, ffmt::G, void, 0, "1100"), (100.0, ffmt::G, void, 0, "100"), (10.0, ffmt::G, void, 0, "10"), (1.0, ffmt::G, void, 0, "1"), (0.1, ffmt::G, void, 0, "0.1"), (0.01, ffmt::G, void, 0, "0.01"), (0.011, ffmt::G, void, 0, "0.011"), (0.001, ffmt::G, void, 0, "1e-3"), // one shorter than f (0.0011, ffmt::G, void, 0, "1.1e-3"), // same length as f (0.0001, ffmt::G, void, 0, "1e-4"), // ... fixed precision stuff (0.5, ffmt::F, 0, 0, "0"), (1.0 / 3.0, ffmt::F, 2, 0, "0.33"), (1.0 / 3.0, ffmt::F, 1, 0, "0.3"), (1.0 / 3.0, ffmt::F, 0, 0, "0"), (1.0 / 3.0, ffmt::F, 0, fflags::SHOW_POINT, "0.3"), (2.0 / 3.0, ffmt::F, 2, 0, "0.67"), (2.0 / 3.0, ffmt::F, 1, 0, "0.7"), (2.0 / 3.0, ffmt::F, 0, 0, "1"), (2.0 / 3.0, ffmt::F, 0, fflags::SHOW_POINT, "0.7"), (2.0 / 30.0, ffmt::F, 5, 0, "0.06667"), (2.0 / 30.0, ffmt::F, 2, 0, "0.07"), (2.0 / 30.0, ffmt::F, 1, 0, "0.1"), (2.0 / 30.0, ffmt::F, 1, fflags::SHOW_POINT, "0.1"), (200.0 / 3.0, ffmt::F, 4, 0, "66.6667"), (100.0 / 3.0, ffmt::F, 4, 0, "33.3333"), (100.0 / 3.0, ffmt::F, 0, 0, "33"), (100.0 / 3.0, ffmt::F, 0, fflags::SHOW_POINT, "33.3"), (0.00001, ffmt::F, 1, 0, "0.0"), (0.001, ffmt::F, 2, 0, "0.00"), (0.006, ffmt::F, 2, 0, "0.01"), (0.001, ffmt::F, 6, 0, "0.001000"), (1.0, ffmt::F, 6, 0, "1.000000"), (100.0, ffmt::F, 6, 0, "100.000000"), // ... scientific notation stuff (460.0, ffmt::E, 2, 0, "4.60e2"), (1.0 / 3.0, ffmt::E, 2, 0, "3.33e-1"), (1.0 / 3.0, ffmt::E, 1, 0, "3.3e-1"), (1.0 / 3.0, ffmt::E, 0, 0, "3e-1"), (1.0 / 3.0, ffmt::E, 0, fflags::SHOW_POINT, "3.3e-1"), (2.0 / 3.0, ffmt::E, 2, 0, "6.67e-1"), (2.0 / 3.0, ffmt::E, 1, 0, "6.7e-1"), (2.0 / 3.0, ffmt::E, 0, 0, "7e-1"), (2.0 / 3.0, ffmt::E, 0, fflags::SHOW_POINT, "6.7e-1"), (2.0 / 30.0, ffmt::E, 5, 0, "6.66667e-2"), (2.0 / 30.0, ffmt::E, 2, 0, "6.67e-2"), (2.0 / 30.0, ffmt::E, 0, 0, "7e-2"), (2.0 / 30.0, ffmt::E, 0, fflags::SHOW_POINT, "6.7e-2"), (200.0 / 3.0, ffmt::E, 5, 0, "6.66667e1"), (100.0 / 3.0, ffmt::E, 5, 0, "3.33333e1"), (100.0 / 3.0, ffmt::E, 0, 0, "3e1"), (100.0 / 3.0, ffmt::E, 0, fflags::SHOW_POINT, "3.3e1"), (0.001, ffmt::E, 2, 0, "1.00e-3"), (1.0, ffmt::E, 6, 0, "1.000000e0"), (100.0, ffmt::E, 6, 0, "1.000000e2"), // ... and G. The behavior with SHOW_POINT is gnarly. (1.0 / 3.0, ffmt::G, 2, 0, "0.33"), (1.0 / 3.0, ffmt::G, 0, 0, "0.3"), (0.01, ffmt::G, void, fflags::SHOW_POINT, "0.01"), (1.0, ffmt::G, void, fflags::SHOW_POINT, "1.0"), (0.0001, ffmt::G, 0, 0, "1e-4"), (0.001, ffmt::G, 0, 0, "1e-3"), (0.00123, ffmt::G, 2, 0, "1.2e-3"), (0.01, ffmt::G, 5, 0, "0.01"), // trim trailing zeros (0.1, ffmt::G, 5, 0, "0.1"), (1.0, ffmt::G, 0, 0, "1"), (10.0, ffmt::G, 0, 0, "10"), (120.0, ffmt::G, 2, 0, "120"), (12000.0, ffmt::G, 2, 0, "1.2e4"), (0.0001, ffmt::G, 0, fflags::SHOW_POINT, "1.0e-4"), (0.001, ffmt::G, 0, fflags::SHOW_POINT, "1.0e-3"), (0.01, ffmt::G, 0, fflags::SHOW_POINT, "0.01"), (0.1, ffmt::G, 0, fflags::SHOW_POINT, "0.1"), (1.0, ffmt::G, 0, fflags::SHOW_POINT, "1.0"), (10.0, ffmt::G, 0, fflags::SHOW_POINT, "10.0"), (100.0, ffmt::G, 0, fflags::SHOW_POINT, "100.0"), (1000.0, ffmt::G, 0, fflags::SHOW_POINT, "1.0e3"), (0.0123, ffmt::G, 2, fflags::SHOW_POINT, "0.012"), (0.0123, ffmt::G, 5, fflags::SHOW_POINT, "0.0123"), ]; const stream = memio::dynamic(); defer io::close(&stream)!; for (let i = 0z; i < len(tcs); i += 1) { const z64 = fftosf(&stream, tcs[i].0, tcs[i].1, tcs[i].2, tcs[i].3)!; const res64 = memio::string(&stream)!; assert(len(res64) == z64); assert(res64 == tcs[i].4, res64); if (tcs[i].2 is void) { // void precision should guarantee that it parses back // to the original number. const back = stof64(res64)!; assert(math::isnan(back) == math::isnan(tcs[i].0)); if (!math::isnan(back)) assert(back == tcs[i].0); }; memio::reset(&stream); const z32 = fftosf(&stream, tcs[i].0: f32, tcs[i].1, tcs[i].2, tcs[i].3)!; const res32 = memio::string(&stream)!; assert(len(res32) == z32); assert(res32 == tcs[i].4); if (tcs[i].2 is void) { const back = stof32(res32)!; assert(math::isnan(back) == math::isnan(tcs[i].0)); if (!math::isnan(back)) assert(back == tcs[i].0: f32); }; memio::reset(&stream); }; // These tests will only pass for f64 const tcsf64: [](f64, ffmt, (void | uint), fflags, str) = [ (9007199254740991.0, ffmt::F, void, 0, "9007199254740991"), (90071992547409915.0, ffmt::F, void, 0, "90071992547409920"), (90071992547409925.0, ffmt::F, void, 0, "90071992547409920"), (math::F64_MIN, ffmt::E, void, 0, "5e-324"), (math::F64_MIN, ffmt::E, void, fflags::SHOW_TWO_EXP_DIGITS, "5e-324"), (-math::F64_MIN, ffmt::E, void, 0, "-5e-324"), (math::F64_MIN_NORMAL, ffmt::E, void, 0, "2.2250738585072014e-308"), (math::F64_MAX_NORMAL, ffmt::E, void, 0, "1.7976931348623157e308"), (math::F64_MIN, ffmt::E, 2, 0, "4.94e-324"), (math::F64_MIN_NORMAL, ffmt::E, 0, 0, "2e-308"), (math::F64_MAX_NORMAL, ffmt::E, 3, 0, "1.798e308"), ]; for (let i = 0z; i < len(tcsf64); i += 1) { const z64 = fftosf(&stream, tcsf64[i].0, tcsf64[i].1, tcsf64[i].2, tcsf64[i].3)!; const res64 = memio::string(&stream)!; assert(len(res64) == z64); assert(res64 == tcsf64[i].4); memio::reset(&stream); }; // These tests will only pass for f32 const tcsf32: [](f32, ffmt, (void | uint), fflags, str) = [ (math::F32_MIN, ffmt::G, void, 0, "1e-45"), (math::F32_MIN_NORMAL, ffmt::G, void, 0, "1.1754944e-38"), (math::F32_MAX_NORMAL, ffmt::G, void, 0, "3.4028235e38"), ]; for (let i = 0z; i < len(tcsf32); i += 1) { const z32 = fftosf(&stream, tcsf32[i].0, tcsf32[i].1, tcsf32[i].2, tcsf32[i].3)!; const res32 = memio::string(&stream)!; assert(len(res32) == z32); assert(res32 == tcsf32[i].4); memio::reset(&stream); }; // Just make sure we can generate big numbers without breaking anything. const tcslen: [](f64, ffmt, (void | uint), fflags, size) = [ (9007199254740991.0, ffmt::F, void, 0, 16), (-math::F64_MIN, ffmt::E, 100, 0, 108), (1.0, ffmt::F, 1000, 0, 1002), (2.22507385850720088902458687609E-308, ffmt::F, 1000, 0, 1002), ]; for (let i = 0z; i < len(tcslen); i += 1) { const z64 = fftosf(&stream, tcslen[i].0, tcslen[i].1, tcslen[i].2, tcslen[i].3)!; const res64 = memio::string(&stream)!; assert(len(res64) == z64); assert(len(res64) == tcslen[i].4); memio::reset(&stream); }; assert(f64tos(13.37) == "13.37"); }; hare-0.24.2/strconv/README000066400000000000000000000001661464473310100151020ustar00rootroot00000000000000The strconv module provides functions for parsing strings into numeric datatypes and formatting numbers into strings. hare-0.24.2/strconv/ftos.ha000066400000000000000000000242171464473310100155120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Uses Ryū for shortest, falls back to multiprecision for fixed precision. use io; use math; use memio; use strings; use types; // Format styles for the [[ftosf]] functions. export type ffmt = enum { // General format. Uses whichever of E and F is shortest, not accounting // for flags. G, // Scientific notation. Consists of a number in [1, 10), an 'e' (or 'E', // if UPPER_EXP flag is present), then an exponent. E, // Fixed-point notation. F, }; // Flags for the [[ftosf]] functions. export type fflags = enum uint { NONE = 0, // Use a sign for both positive and negative numbers. SHOW_POS = 1 << 0, // Include at least one decimal digit. SHOW_POINT = 1 << 1, // Uppercase INFINITY and NAN. UPPERCASE = 1 << 2, // Uppercase exponent symbols E and P rather than e and p. UPPER_EXP = 1 << 3, // Use a sign for both positive and negative exponents. SHOW_POS_EXP = 1 << 4, // Show at least two digits of the exponent. SHOW_TWO_EXP_DIGITS = 1 << 5, }; // Just for convenience... inline functions when? fn ffpos(f: fflags) bool = f & fflags::SHOW_POS != 0; fn ffpoint(f: fflags) bool = f & fflags::SHOW_POINT != 0; fn ffcaps(f: fflags) bool = f & fflags::UPPERCASE != 0; fn ffcaps_exp(f: fflags) bool = f & fflags::UPPER_EXP != 0; fn ffpos_exp(f: fflags) bool = f & fflags::SHOW_POS_EXP != 0; fn fftwodigs(f: fflags) bool = f & fflags::SHOW_TWO_EXP_DIGITS != 0; fn declen(n: u64) uint = { assert(n <= 1e17); return if (n >= 1e17) 18 else if (n >= 1e16) 17 else if (n >= 1e15) 16 else if (n >= 1e14) 15 else if (n >= 1e13) 14 else if (n >= 1e12) 13 else if (n >= 1e11) 12 else if (n >= 1e10) 11 else if (n >= 1e9) 10 else if (n >= 1e8) 9 else if (n >= 1e7) 8 else if (n >= 1e6) 7 else if (n >= 1e5) 6 else if (n >= 1e4) 5 else if (n >= 1e3) 4 else if (n >= 100) 3 else if (n >= 10) 2 else 1; }; fn writestr(h: io::handle, s: str) (size | io::error) = { return io::writeall(h, strings::toutf8(s))?; }; // XXX: this can likely be dedup'd with the other encode functions. fn encode_zero( h: io::handle, f: ffmt, prec: (void | uint), flag: fflags, ) (size | io::error) = { let z = 0z; z += memio::appendrune(h, '0')?; let hasdec = false; match (prec) { case void => void; case let u: uint => if (u > 0 && f != ffmt::G) { z += memio::appendrune(h, '.')?; for (let i = 0u; i < u; i += 1) { z += memio::appendrune(h, '0')?; }; hasdec = true; }; }; if (!hasdec && ffpoint(flag)) { z += memio::appendrune(h, '.')?; z += memio::appendrune(h, '0')?; }; if (f == ffmt::E) { z += memio::appendrune(h, if (ffcaps_exp(flag)) 'E' else 'e')?; if (ffpos_exp(flag)) z += memio::appendrune(h, '+')?; z += memio::appendrune(h, '0')?; if (fftwodigs(flag)) z += memio::appendrune(h, '0')?; }; return z; }; fn encode_f_mp( m: *mp, h: io::handle, f: ffmt, prec: (void | uint), flag: fflags, ) (size | io::error) = { // we will loop from lo <= i < hi, printing either zeros or a digit. // lo is simple, but hi depends intricately on f, prec, and the // SHOW_POINT flag. const lo = if (m.dp <= 0) m.dp - 1 else 0; let hi = match (prec) { case void => yield if (m.nd: int > m.dp) m.nd: int else m.dp; case let u: uint => yield if (m.dp <= 0) lo + u: int + 1 else m.dp + u: int; }; // ffmt::G: we need to remove trailing zeros if (f == ffmt::G) { // first, make sure we include at least prec digits if (prec is uint) { const p = prec as uint; if (m.dp <= 0 && hi < p: int) { hi = p: int; }; }; // then, cut back to the decimal point or nd if (hi > m.nd: int && m.dp <= 0) { hi = m.nd: int; } else if (hi > m.dp && m.dp > 0) { hi = if (m.nd: int > m.dp) m.nd: int else m.dp; }; }; // SHOW_POINT: we need to go at least one past the decimal if (ffpoint(flag) && hi <= m.dp) { hi = m.dp + 1; }; let z = 0z; for (let i = lo; i < hi; i += 1) { if (i == m.dp) { z += memio::appendrune(h, '.')?; }; if (0 <= i && i < m.nd: int) { z += memio::appendrune(h, (m.buf[i] + '0'): rune)?; } else { z += memio::appendrune(h, '0')?; }; }; return z; }; fn encode_e_mp( m: *mp, h: io::handle, f: ffmt, prec: (void | uint), flag: fflags, ) (size | io::error) = { let z = 0z; assert(m.nd > 0); z += memio::appendrune(h, (m.buf[0] + '0'): rune)?; const zeros: uint = match (prec) { case void => yield 0; case let u: uint => yield switch (f) { case ffmt::G => yield if (m.nd + 1 < u) u - m.nd + 1 else 0; case ffmt::E => yield if (m.nd < u + 1) u - m.nd + 1 else 0; case => abort(); }; }; if (m.nd <= 1 && ffpoint(flag) && zeros < 1) { zeros = 1; }; if (m.nd > 1 || zeros > 0) { z += memio::appendrune(h, '.')?; }; for (let i = 1z; i < m.nd; i += 1) { z += memio::appendrune(h, (m.buf[i] + '0'): rune)?; }; for (let i = 0u; i < zeros; i += 1) { z += memio::appendrune(h, '0')?; }; z += memio::appendrune(h, if (ffcaps_exp(flag)) 'E' else 'e')?; let e = m.dp - 1; if (e < 0) { e = -e; z += memio::appendrune(h, '-')?; } else if (ffpos_exp(flag)) { z += memio::appendrune(h, '+')?; }; let ebuf: [3]u8 = [0...]; // max and min exponents are 3 digits let l = declen(e: u64); for (let i = 0z; i < l; i += 1) { ebuf[2 - i] = (e % 10): u8; e /= 10; }; if (fftwodigs(flag) && l == 1) { l = 2; }; for (let i = 3 - l; i < 3; i += 1) { z += memio::appendrune(h, (ebuf[i] + '0'): rune)?; }; return z; }; // Converts a [[types::floating]] to a string in base 10 and writes the result // to the provided handle. Format parameters are as in [[ftosf]]. export fn fftosf( h: io::handle, n: types::floating, f: ffmt, prec: (void | uint), flag: fflags, ) (size | io::error) = { const (mantissa, exponent, sign, special) = match (n) { case let n: f64 => const bits = math::f64bits(n); const mantissa = bits & math::F64_MANTISSA_MASK; const exponent = ((bits >> math::F64_MANTISSA_BITS) & math::F64_EXPONENT_MASK): u32; const sign = bits >> (math::F64_EXPONENT_BITS + math::F64_MANTISSA_BITS) > 0; const special = exponent == math::F64_EXPONENT_MASK; yield (mantissa, exponent, sign, special); case let n: f32 => const bits = math::f32bits(n); const mantissa = bits & math::F32_MANTISSA_MASK; const exponent = ((bits >> math::F32_MANTISSA_BITS) & math::F32_EXPONENT_MASK): u32; const sign = bits >> (math::F32_EXPONENT_BITS + math::F32_MANTISSA_BITS) > 0; const special = exponent == math::F32_EXPONENT_MASK; yield (mantissa, exponent, sign, special); }; if (special && mantissa != 0) { return writestr(h, if (ffcaps(flag)) "NAN" else "nan"); }; let z = 0z; if (sign) { z += memio::appendrune(h, '-')?; } else if (ffpos(flag)) { z += memio::appendrune(h, '+')?; }; if (special) { return z + writestr(h, if (ffcaps(flag)) "INFINITY" else "infinity")?; } else if (exponent == 0 && mantissa == 0) { return z + encode_zero(h, f, prec, flag)?; }; let m = mp { ... }; let ok = false; if (prec is void) { // Shortest via Ryū. It is not correct to use f64todecf64 for // f32s, they must be handled separately. const (mdec, edec) = match (n) { case f64 => const d = f64todecf64(mantissa, exponent); yield (d.mantissa, d.exponent); case f32 => const d = f32todecf32(mantissa: u32, exponent); yield (d.mantissa: u64, d.exponent); }; init_mp_dec(&m, mdec, edec); // If SHOW_POINT and we have too few digits, then we need to // fall back to multiprecision. ok = !ffpoint(flag) || m.dp < m.nd: int; }; if (!ok) { // Fall back to multiprecision. match (n) { case f64 => init_mp(&m, mantissa, exponent, math::F64_EXPONENT_BIAS, math::F64_MANTISSA_BITS); case f32 => init_mp(&m, mantissa, exponent, math::F32_EXPONENT_BIAS, math::F32_MANTISSA_BITS); }; trim_mp(&m); const nd = compute_round_mp(&m, f, prec, flag); round_mp(&m, nd); }; if (f == ffmt::G) { trim_mp(&m); }; if (f == ffmt::G && prec is uint) { if (prec as uint == 0) prec = 1; }; if (m.nd == 0) { // rounded to zero return z + encode_zero(h, f, prec, flag)?; } else if (f == ffmt::E || (f == ffmt::G && (m.dp < -1 || m.dp - m.nd: int > 2))) { return z + encode_e_mp(&m, h, f, prec, flag)?; } else { return z + encode_f_mp(&m, h, f, prec, flag)?; }; }; // Converts any [[types::floating]] to a string in base 10. The return value // must be freed. // // A precision of void yields the smallest number of digits that can be parsed // into the exact same number. Otherwise, the meaning depends on f: // - ffmt::F, ffmt::E: Number of digits after the decimal point. // - ffmt::G: Number of significant digits. 0 is equivalent to 1 precision, and // trailing zeros are removed. export fn ftosf( n: types::floating, f: ffmt, prec: (void | uint), flag: fflags, ) str = { let m = memio::dynamic(); fftosf(&m, n, f, prec, flag)!; return memio::string(&m)!; }; // Converts a f64 to a string in base 10. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. The result is equivalent to [[ftosf]] with format G // and precision void. export fn f64tos(n: f64) const str = { // The biggest string produced by a f64 number in base 10 would have the // negative sign, followed by a digit and decimal point, and then // sixteen more decimal digits, followed by 'e' and another negative // sign and the maximum of three digits for exponent. // (1 + 1 + 1 + 16 + 1 + 1 + 3) = 24 static let buf: [24]u8 = [0...]; let m = memio::fixed(buf); fftosf(&m, n, ffmt::G, void, 0)!; return memio::string(&m)!; }; // Converts a f32 to a string in base 10. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. The result is equivalent to [[ftosf]] with format G // and precision void. export fn f32tos(n: f32) const str = { // The biggest string produced by a f32 number in base 10 would have the // negative sign, followed by a digit and decimal point, and then seven // more decimal digits, followed by 'e' and another negative sign and // the maximum of two digits for exponent. // (1 + 1 + 1 + 7 + 1 + 1 + 2) = 14 static let buf: [14]u8 = [0...]; let m = memio::fixed(buf); fftosf(&m, n, ffmt::G, void, 0)!; return memio::string(&m)!; }; hare-0.24.2/strconv/ftos_multiprecision.ha000066400000000000000000000160721464473310100206400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Multiprecision float to string based on golang's strconv/decimal.go. use strings; type mp = struct { // Numbers 0-9, not ascii. Length for small numbers is // log10(mantissa * 5^-exp). Subnormal doubles have min exp -1074 and // max mantissa 4e16, giving at most 767 digits. buf: [768]u8, // Number of valid digits in buf. May be 0 if the number rounds to 0. nd: uint, // Decimal point index, may be negative. // -1 means 0.0ddd... // 0 means 0.ddd... // 1 means d.dd... // and so on dp: int, }; // These come from golang. The index into the table is amount of shift, up to // 60. The number is the count of new digits that will be added by the shift, // but one fewer if the number's prefix is smaller than the string prefix. // // For example, leftcheats[2] is (1, "25"). Any number left shifted by 2 will // therefore be 1 digit longer, or zero digits longer if its first two digits // are smaller than 25. const leftcheats: [](size, str) = [ (0, ""), (1, "5"), (1, "25"), (1, "125"), (2, "625"), (2, "3125"), (2, "15625"), (3, "78125"), (3, "390625"), (3, "1953125"), (4, "9765625"), (4, "48828125"), (4, "244140625"), (4, "1220703125"), (5, "6103515625"), (5, "30517578125"), (5, "152587890625"), (6, "762939453125"), (6, "3814697265625"), (6, "19073486328125"), (7, "95367431640625"), (7, "476837158203125"), (7, "2384185791015625"), (7, "11920928955078125"), (8, "59604644775390625"), (8, "298023223876953125"), (8, "1490116119384765625"), (9, "7450580596923828125"), (9, "37252902984619140625"), (9, "186264514923095703125"), (10, "931322574615478515625"), (10, "4656612873077392578125"), (10, "23283064365386962890625"), (10, "116415321826934814453125"), (11, "582076609134674072265625"), (11, "2910383045673370361328125"), (11, "14551915228366851806640625"), (12, "72759576141834259033203125"), (12, "363797880709171295166015625"), (12, "1818989403545856475830078125"), (13, "9094947017729282379150390625"), (13, "45474735088646411895751953125"), (13, "227373675443232059478759765625"), (13, "1136868377216160297393798828125"), (14, "5684341886080801486968994140625"), (14, "28421709430404007434844970703125"), (14, "142108547152020037174224853515625"), (15, "710542735760100185871124267578125"), (15, "3552713678800500929355621337890625"), (15, "17763568394002504646778106689453125"), (16, "88817841970012523233890533447265625"), (16, "444089209850062616169452667236328125"), (16, "2220446049250313080847263336181640625"), (16, "11102230246251565404236316680908203125"), (17, "55511151231257827021181583404541015625"), (17, "277555756156289135105907917022705078125"), (17, "1387778780781445675529539585113525390625"), (18, "6938893903907228377647697925567626953125"), (18, "34694469519536141888238489627838134765625"), (18, "173472347597680709441192448139190673828125"), (19, "867361737988403547205962240695953369140625"), ]; fn prefix_less_than_mp(m: *mp, s: str) bool = { const u = strings::toutf8(s); for (let i = 0z; i < len(s); i += 1) { if (i >= m.nd) { return true; }; if (m.buf[i] + '0': u8 != u[i]) { return m.buf[i] + '0': u8 < u[i]; }; }; return false; }; // Shift left by k. fn shl_mp(m: *mp, k: u64) void = { let delta = leftcheats[k].0; if (prefix_less_than_mp(m, leftcheats[k].1)) delta -= 1; let r = (m.nd - 1): int; let w = m.nd + delta; let n = 0u64; for (r >= 0; r -= 1) { n += m.buf[r]: u64 << k; const quo = n / 10; const rem = n - 10 * quo; w -= 1; m.buf[w] = rem: u8; n = quo; }; for (n > 0) { const quo = n / 10; const rem = n - 10 * quo; w -= 1; m.buf[w] = rem: u8; n = quo; }; m.nd += delta: uint; m.dp += delta: int; }; // Shift right by k. fn shr_mp(m: *mp, k: u64) void = { let r = 0z; let w = 0z; let n = 0u64; const mask = (1 << k) - 1; for (n >> k == 0; r += 1) { if (r >= m.nd) { for (n >> k == 0) { n *= 10; r += 1; }; break; }; n = 10 * n + m.buf[r]; }; m.dp -= r: int - 1; for (r < m.nd; r += 1) { const c = m.buf[r]; const dig = n >> k; n &= mask; m.buf[w] = dig: u8; w += 1; n = n * 10 + c; }; for (n > 0; w += 1) { const dig = n >> k; n &= mask; m.buf[w] = dig: u8; n = n * 10; }; m.nd = w: uint; }; // Shift right (k < 0) or left (k > 0). We can only shift up to 60 at a time // without losing bits, so break up big shifts. fn shift_mp(m: *mp, k: int) void = { if (k < 0) { let nk = (-k): uint; for (nk > 60) { shr_mp(m, 60); nk -= 60; }; shr_mp(m, nk); } else if (k > 0) { for (k > 60) { shl_mp(m, 60); k -= 60; }; shl_mp(m, k: uint); }; }; fn init_mp(m: *mp, mantissa: u64, exponent: u32, eb: u64, mb: u64) void = { let e2 = (eb + mb): i32; let m2: u64 = 0; if (exponent == 0) { e2 = 1 - e2; m2 = mantissa; } else { e2 = (exponent: i32) - e2; m2 = (1u64 << mb) | mantissa; }; m.nd = declen(m2); m.dp = m.nd: int; for (let i = 0z; i < m.nd; i += 1) { m.buf[m.nd - i - 1] = (m2 % 10): u8; m2 /= 10; }; shift_mp(m, e2); }; fn init_mp_dec(m: *mp, mantissa: u64, exponent: i32) void = { const dl = declen(mantissa); for (let i = 0u; i < dl; i += 1) { m.buf[dl - i - 1] = (mantissa % 10): u8; mantissa /= 10; }; m.nd = dl; m.dp = dl: i32 + exponent; }; fn round_up_mp(m: *mp) void = { for (let i = 1z; i <= m.nd; i += 1) { if (m.buf[m.nd - i] < 9) { m.buf[m.nd - i] += 1; return; } else { m.buf[m.nd - i] = 0; }; }; // All high m.buf[0] = 1; m.nd = 1; m.dp += 1; }; // Compute the number of figs to round to for the given arguments. fn compute_round_mp(m: *mp, f: ffmt, prec: (void | uint), flag: fflags) uint = { // nd is the number of sig figs that we want to end up with let nd: int = match (prec) { case void => // we should only get here if Ryu did not extend past the // decimal point assert(ffpoint(flag)); yield m.nd: int + (if (m.dp > 0) m.dp else 0); case let u: uint => yield switch (f) { case ffmt::E => yield u: int + 1; case ffmt::F => yield u: int + m.dp; case ffmt::G => yield if (u == 0) 1 else u: int; }; }; const nde = if (nd < 2) 2 else nd; const ndf = if (m.dp >= 0 && nd < m.dp + 1) m.dp + 1 else nd; if (ffpoint(flag)) { nd = switch (f) { case ffmt::E => // need at least two digits, d.de0. yield nde; case ffmt::F => // need enough to clear the decimal point by one. yield ndf; case ffmt::G => // XXX: dup'd with the condition in ftosf_handle if (m.dp < -1 || m.dp - m.nd: int > 2) yield nde; yield ndf; }; }; if (nd <= 0) { nd = 0; }; return if (nd: uint > m.nd) m.nd else nd: uint; }; fn round_mp(m: *mp, nd: uint) void = { assert(nd <= m.nd); if (nd == m.nd) return; const oldnd = m.nd; m.nd = nd; if (m.buf[nd] > 5) { round_up_mp(m); } else if (m.buf[nd] == 5) { let gt = false; for (let i = m.nd + 1; i < oldnd; i += 1) { if (m.buf[i] > 0) { round_up_mp(m); gt = true; break; }; }; if (!gt && nd > 0 && m.buf[nd - 1] & 1 > 0) { round_up_mp(m); }; }; }; // Remove trailing zeros. fn trim_mp(m: *mp) void = { for (m.nd > 1 && m.buf[m.nd - 1] == 0) { m.nd -= 1; }; }; hare-0.24.2/strconv/ftos_ryu.ha000066400000000000000000000345011464473310100164060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Using Ryū: fast float-to-string conversion algorithm by Ulf Adams. // https://doi.org/10.1145/3192366.3192369 // This Hare implementation is translated from the original // C implementation here: https://github.com/ulfjack/ryu use math; use types; type r128 = struct { hi: u64, lo: u64, }; // TODO: use 128-bit integers when implemented fn u128mul(a: u64, b: u64) r128 = { const a0 = a: u32: u64, a1 = a >> 32; const b0 = b: u32: u64, b1 = b >> 32; const p00 = a0 * b0, p01 = a0 * b1, p10 = a1 * b0, p11 = a1 * b1; const p00_lo = p00: u32: u64, p00_hi = p00 >> 32; const mid1 = p10 + p00_hi; const mid1_lo = mid1: u32: u64, mid1_hi = mid1 >> 32; const mid2 = p01 + mid1_lo; const mid2_lo = mid2: u32: u64, mid2_hi = mid2 >> 32; const r_hi = p11 + mid1_hi + mid2_hi; const r_lo = (mid2_lo << 32) | p00_lo; return r128 { hi = r_hi, lo = r_lo }; }; // TODO: Same as above fn u128rshift(lo: u64, hi: u64, s: u32) u64 = { assert(0 <= s); assert(s <= 64); return (hi << (64 - s)) | (lo >> s); }; fn pow5fac(value: u64) u32 = { const m_inv_5: u64 = 14757395258967641293; // 5 * m_inv_5 = 1 (mod 2^64) const n_div_5: u64 = 3689348814741910323; let count: u32 = 0; for (true) { assert(value != 0); value *= m_inv_5; if (value > n_div_5) break; count += 1; }; return count; }; fn pow5fac32(value: u32) u32 = { let count: u32 = 0; for (true) { assert(value != 0); const q = value / 5, r = value % 5; if (r != 0) break; value = q; count += 1; }; return count; }; fn ibool(b: bool) u8 = if (b) 1 else 0; fn pow5multiple(v: u64, p: u32) bool = pow5fac(v) >= p; fn pow5multiple32(v: u32, p: u32) bool = pow5fac32(v) >= p; fn pow2multiple(v: u64, p: u32) bool = { assert(v > 0); assert(p < 64); return (v & ((1u64 << p) - 1)) == 0; }; fn pow2multiple32(v: u32, p: u32) bool = { assert(v > 0); assert(p < 32); return (v & ((1u32 << p) - 1)) == 0; }; fn mulshift64(m: u64, mul: (u64, u64), j: u32) u64 = { // m is maximum 55 bits let r0 = u128mul(m, mul.0), r1 = u128mul(m, mul.1); const sum = r1.lo + r0.hi; r1.hi += ibool(sum < r0.hi); return u128rshift(sum, r1.hi, j - 64); }; fn mulshiftall64( m: u64, mul: (u64, u64), j: i32, mm_shift: u32, ) (u64, u64, u64) = { m <<= 1; const r0 = u128mul(m, mul.0), r1 = u128mul(m, mul.1); const lo = r0.lo, tmp = r0.hi, mid = tmp + r1.lo; const hi = r1.hi + ibool(mid < tmp); const lo2 = lo + mul.0; const mid2 = mid + mul.1 + ibool(lo2 < lo); const hi2 = hi + ibool(mid2 < mid); const v_plus = u128rshift(mid2, hi2, (j - 64 - 1): u32); const v_minus = if (mm_shift == 1) { const lo3 = lo - mul.0; const mid3 = mid - mul.1 - ibool(lo3 > lo); const hi3 = hi - ibool(mid3 > mid); yield u128rshift(mid3, hi3, (j - 64 - 1): u32); } else { const lo3 = lo + lo; const mid3 = mid + mid + ibool(lo3 < lo); const hi3 = hi + hi + ibool(mid3 < mid); const lo4 = lo3 - mul.0; const mid4 = mid3 - mul.1 - ibool(lo4 > lo3); const hi4 = hi3 - ibool(mid4 > mid3); yield u128rshift(mid4, hi4, (j - 64): u32); }; const v_rounded = u128rshift(mid, hi, (j - 64 - 1): u32); return (v_plus, v_rounded, v_minus); }; fn mulshift32(m: u32, a: u64, s: u32) u32 = { assert(s > 32); const a_lo = a: u32: u64, a_hi = a >> 32; const b0 = m * a_lo, b1 = m * a_hi; const sum = (b0 >> 32) + b1, ss = sum >> (s - 32); assert(ss <= types::U32_MAX); return ss: u32; }; fn mulpow5inv_divpow2(m: u32, q: u32, j: i32) u32 = { const pow5 = f64computeinvpow5(q); return mulshift32(m, pow5.1 + 1, j: u32); }; fn mulpow5_divpow2(m: u32, i: u32, j: i32) u32 = { const pow5 = f64computepow5(i); return mulshift32(m, pow5.1, j: u32); }; fn log2pow5(e: u32) u32 = { assert(e <= 3528); return ((e * 1217359) >> 19); }; fn ceil_log2pow5(e: u32) u32 = log2pow5(e) + 1; fn pow5bits(e: u32) u32 = ceil_log2pow5(e); fn log10pow2(e: u32) u32 = { assert(e <= 1650); return ((e * 78913) >> 18); }; fn log10pow5(e: u32) u32 = { assert(e <= 2620); return ((e * 732923) >> 20); }; def F64_POW5_INV_BITCOUNT: u8 = 125; def F64_POW5_BITCOUNT: u8 = 125; def F32_POW5_INV_BITCOUNT: u8 = F64_POW5_INV_BITCOUNT - 64; def F32_POW5_BITCOUNT: u8 = F64_POW5_BITCOUNT - 64; const F64_POW5_INV_SPLIT2: [15][2]u64 = [ [1, 2305843009213693952], [5955668970331000884, 1784059615882449851], [8982663654677661702, 1380349269358112757], [7286864317269821294, 2135987035920910082], [7005857020398200553, 1652639921975621497], [17965325103354776697, 1278668206209430417], [8928596168509315048, 1978643211784836272], [10075671573058298858, 1530901034580419511], [597001226353042382, 1184477304306571148], [1527430471115325346, 1832889850782397517], [12533209867169019542, 1418129833677084982], [5577825024675947042, 2194449627517475473], [11006974540203867551, 1697873161311732311], [10313493231639821582, 1313665730009899186], [12701016819766672773, 2032799256770390445], ]; const POW5_INV_OFFSETS: [19]u32 = [ 0x54544554, 0x04055545, 0x10041000, 0x00400414, 0x40010000, 0x41155555, 0x00000454, 0x00010044, 0x40000000, 0x44000041, 0x50454450, 0x55550054, 0x51655554, 0x40004000, 0x01000001, 0x00010500, 0x51515411, 0x05555554, 0x00000000 ]; const F64_POW5_SPLIT2: [13][2]u64 = [ [0, 1152921504606846976], [0, 1490116119384765625], [1032610780636961552, 1925929944387235853], [7910200175544436838, 1244603055572228341], [16941905809032713930, 1608611746708759036], [13024893955298202172, 2079081953128979843], [6607496772837067824, 1343575221513417750], [17332926989895652603, 1736530273035216783], [13037379183483547984, 2244412773384604712], [1605989338741628675, 1450417759929778918], [9630225068416591280, 1874621017369538693], [665883850346957067, 1211445438634777304], [14931890668723713708, 1565756531257009982] ]; const POW5_OFFSETS: [21]u32 = [ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x59695995, 0x55545555, 0x56555515, 0x41150504, 0x40555410, 0x44555145, 0x44504540, 0x45555550, 0x40004000, 0x96440440, 0x55565565, 0x54454045, 0x40154151, 0x55559155, 0x51405555, 0x00000105 ]; def POW5_TABLE_SZ: u8 = 26; const POW5_TABLE: [POW5_TABLE_SZ]u64 = [ 1u64, 5u64, 25u64, 125u64, 625u64, 3125u64, 15625u64, 78125u64, 390625u64, 1953125u64, 9765625u64, 48828125u64, 244140625u64, 1220703125u64, 6103515625u64, 30517578125u64, 152587890625u64, 762939453125u64, 3814697265625u64, 19073486328125u64, 95367431640625u64, 476837158203125u64, 2384185791015625u64, 11920928955078125u64, 59604644775390625u64, 298023223876953125u64 //, 1490116119384765625u64 ]; fn f64computeinvpow5(i: u32) (u64, u64) = { const base = ((i + POW5_TABLE_SZ - 1) / POW5_TABLE_SZ): u32; const base2 = base * POW5_TABLE_SZ; const mul = F64_POW5_INV_SPLIT2[base]; const off = base2 - i; if (off == 0) { return (mul[0], mul[1]); }; const m = POW5_TABLE[off]; const r1 = u128mul(m, mul[1]), r0 = u128mul(m, mul[0] - 1); let high1 = r1.hi, low1 = r1.lo, high0 = r0.hi, low0 = r0.lo; const sum = high0 + low1; if (sum < high0) { high1 += 1; }; const delta = pow5bits(base2) - pow5bits(i); const res0 = u128rshift(low0, sum, delta) + 1 + ((POW5_INV_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3); const res1 = u128rshift(sum, high1, delta); return (res0, res1); }; fn f64computepow5(i: u32) (u64, u64) = { const base = i / POW5_TABLE_SZ, base2 = base * POW5_TABLE_SZ; const mul = F64_POW5_SPLIT2[base]; const off = i - base2; if (off == 0) { return (mul[0], mul[1]); }; const m = POW5_TABLE[off]; const r1 = u128mul(m, mul[1]), r0 = u128mul(m, mul[0]); let high1 = r1.hi, low1 = r1.lo, high0 = r0.hi, low0 = r0.lo; const sum = high0 + low1; if (sum < high0) { high1 += 1; }; const delta = pow5bits(i) - pow5bits(base2); const res0 = u128rshift(low0, sum, delta) + ((POW5_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3); const res1 = u128rshift(sum, high1, delta); return (res0, res1); }; type decf64 = struct { mantissa: u64, exponent: i32, }; fn f64todecf64(mantissa: u64, exponent: u32) decf64 = { let e2 = (math::F64_EXPONENT_BIAS + math::F64_MANTISSA_BITS + 2): i32; let m2: u64 = 0; if (exponent == 0) { e2 = 1 - e2; m2 = mantissa; } else { e2 = (exponent: i32) - e2; m2 = (1u64 << math::F64_MANTISSA_BITS) | mantissa; }; const accept_bounds = (m2 & 1) == 0; const mv = 4 * m2; const mm_shift = ibool(mantissa != 0 || exponent <= 1); let vp: u64 = 0, vr: u64 = 0, vm: u64 = 0; let e10: i32 = 0; let vm_trailing_zeros = false, vr_trailing_zeros = false; if (e2 >= 0) { const q = log10pow2(e2: u32) - ibool(e2 > 3); e10 = q: i32; const k = F64_POW5_INV_BITCOUNT + pow5bits(q) - 1; const i = -e2 + (q + k): i32; let pow5 = f64computeinvpow5(q); const res = mulshiftall64(m2, pow5, i, mm_shift); vp = res.0; vr = res.1; vm = res.2; if (q <= 21) { if ((mv - 5 * (mv / 5)) == 0) { vr_trailing_zeros = pow5multiple(mv, q); } else if (accept_bounds) { vm_trailing_zeros = pow5multiple(mv - 1 - mm_shift, q); } else { vp -= ibool(pow5multiple(mv + 2, q)); }; }; } else { const q = log10pow5((-e2): u32) - ibool(-e2 > 1); e10 = e2 + (q: i32); const i = -e2 - (q: i32); const k = pow5bits(i: u32): i32 - F64_POW5_BITCOUNT: i32; const j = (q: i32) - k; let pow5 = f64computepow5(i: u32); const res = mulshiftall64(m2, pow5, j, mm_shift); vp = res.0; vr = res.1; vm = res.2; if (q <= 1) { vr_trailing_zeros = true; if (accept_bounds) { vm_trailing_zeros = mm_shift == 1; } else { vp -= 1; }; } else if (q < 63) { vr_trailing_zeros = pow2multiple(mv, q); }; }; let removed: i32 = 0, last_removed_digit: u8 = 0; let output: u64 = 0; if (vm_trailing_zeros || vr_trailing_zeros) { for (true) { const vpby10 = vp / 10, vmby10 = vm / 10; if (vpby10 <= vmby10) break; const vmmod10 = (vm: u32) - 10 * (vmby10: u32); const vrby10 = vr / 10; const vrmod10 = (vr: u32) - 10 * (vrby10: u32); vm_trailing_zeros &&= vmmod10 == 0; vr_trailing_zeros &&= last_removed_digit == 0; last_removed_digit = vrmod10: u8; vr = vrby10; vp = vpby10; vm = vmby10; removed += 1; }; if (vm_trailing_zeros) { for (true) { const vmby10 = vm / 10; const vmmod10 = (vm: u32) - 10 * (vmby10: u32); if (vmmod10 != 0) break; const vpby10 = vp / 10, vrby10 = vr / 10; const vrmod10 = (vr: u32) - 10 * (vrby10: u32); vr_trailing_zeros &&= last_removed_digit == 0; last_removed_digit = vrmod10: u8; vr = vrby10; vp = vpby10; vm = vmby10; removed += 1; }; }; if (vr_trailing_zeros && last_removed_digit == 5 && (vr & 1 == 0)) { // round to even last_removed_digit = 4; }; output = vr + ibool((vr == vm && (!accept_bounds || !vm_trailing_zeros)) || last_removed_digit >= 5); } else { let round_up = false; const vpby100 = vp / 100, vmby100 = vm / 100; if (vpby100 > vmby100) { const vrby100 = vr / 100; const vrmod100 = (vr: u32) - 100 * (vrby100: u32); round_up = vrmod100 >= 50; vr = vrby100; vp = vpby100; vm = vmby100; removed += 2; }; for (true) { const vmby10 = vm / 10, vpby10 = vp / 10; if (vpby10 <= vmby10) break; const vrby10 = vr / 10; const vrmod10 = (vr: u32) - 10 * (vrby10: u32); round_up = vrmod10 >= 5; vr = vrby10; vp = vpby10; vm = vmby10; removed += 1; }; output = vr + ibool(vr == vm || round_up); }; const exp = e10 + removed; return decf64 { exponent = exp, mantissa = output }; }; type decf32 = struct { mantissa: u32, exponent: i32, }; fn f32todecf32(mantissa: u32, exponent: u32) decf32 = { let e2 = (math::F32_EXPONENT_BIAS + math::F32_MANTISSA_BITS + 2): i32; let m2: u32 = 0; if (exponent == 0) { e2 = 1 - e2; m2 = mantissa; } else { e2 = (exponent: i32) - e2; m2 = (1u32 << math::F32_MANTISSA_BITS: u32) | mantissa; }; const accept_bounds = (m2 & 1) == 0; const mv = 4 * m2, mp = mv + 2; const mm_shift = ibool(mantissa != 0 || exponent <= 1); const mm = mv - 1 - mm_shift; let vr: u32 = 0, vp: u32 = 0, vm: u32 = 0; let e10: i32 = 0; let vm_trailing_zeroes = false, vr_trailing_zeroes = false; let last_removed_digit: u8 = 0; if (e2 >= 0) { const q = log10pow2(e2: u32); e10 = q: i32; const k = F32_POW5_INV_BITCOUNT + pow5bits(q) - 1; const i = -e2 + (q + k): i32; vr = mulpow5inv_divpow2(mv, q, i); vp = mulpow5inv_divpow2(mp, q, i); vm = mulpow5inv_divpow2(mm, q, i); if (q != 0 && (vp - 1) / 10 <= vm / 10) { const l = F32_POW5_INV_BITCOUNT + pow5bits(q - 1) - 1; last_removed_digit = (mulpow5inv_divpow2(mv, q - 1, -e2 + ((q + l): i32) - 1) % 10): u8; }; if (q <= 9) { if (mv % 5 == 0) { vr_trailing_zeroes = pow5multiple32(mv, q); } else if (accept_bounds) { vm_trailing_zeroes = pow5multiple32(mm, q); } else { vp -= ibool(pow5multiple32(mp, q)); }; }; } else { const q = log10pow5((-e2): u32); e10 = (q: i32) + e2; const i = (-e2 - (q: i32)): u32; const k = pow5bits(i) - F32_POW5_BITCOUNT; let j = (q: i32) - k: i32; vr = mulpow5_divpow2(mv, i, j); vp = mulpow5_divpow2(mp, i, j); vm = mulpow5_divpow2(mm, i, j); if (q != 0 && (vp - 1) / 10 <= vm / 10) { j = (q: i32) - 1 - (pow5bits(i + 1): i32 - F32_POW5_BITCOUNT: i32); last_removed_digit = (mulpow5_divpow2(mv, (i + 1), j) % 10): u8; }; if (q <= 1) { vr_trailing_zeroes = true; if (accept_bounds) { vm_trailing_zeroes = mm_shift == 1; } else { vp -= 1; }; } else if (q < 31) { vr_trailing_zeroes = pow2multiple32(mv, q - 1); }; }; let removed: i32 = 0, output: u32 = 0; if (vm_trailing_zeroes || vr_trailing_zeroes) { for (vp / 10 > vm / 10) { vm_trailing_zeroes &&= (vm - (vm / 10) * 10) == 0; vr_trailing_zeroes &&= last_removed_digit == 0; last_removed_digit = (vr % 10): u8; vr /= 10; vp /= 10; vm /= 10; removed += 1; }; if (vm_trailing_zeroes) { for (vm % 10 == 0) { vr_trailing_zeroes &&= last_removed_digit == 0; last_removed_digit = (vr % 10): u8; vr /= 10; vp /= 10; vm /= 10; removed += 1; }; }; if (vr_trailing_zeroes && last_removed_digit == 5 && vr % 2 == 0) { // round to even last_removed_digit = 4; }; output = vr + ibool((vr == vm && (!accept_bounds || !vm_trailing_zeroes)) || last_removed_digit >= 5); } else { for (vp / 10 > vm / 10) { last_removed_digit = (vr % 10): u8; vr /= 10; vp /= 10; vm /= 10; removed += 1; }; output = vr + ibool(vr == vm || last_removed_digit >= 5); }; const exp = e10 + removed; return decf32 { mantissa = output, exponent = exp }; }; def F32_DECIMAL_DIGITS: i32 = 9; def F64_DECIMAL_DIGITS: i32 = 17; hare-0.24.2/strconv/itos.ha000066400000000000000000000050611464473310100155110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use strings; use types; // Converts an i64 to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn i64tos(i: i64, b: base = base::DEC) const str = { static assert(types::I64_MAX == 9223372036854775807); if (b == base::DEFAULT) { b = base::DEC; }; if (i >= 0) return u64tos(i: u64, b); static let buf: [65]u8 = [0...]; // 64 binary digits plus - let s = types::string { data = &buf, ... }; buf[0] = '-'; s.length = 1; let u = strings::toutf8(u64tos((-i): u64, b)); assert(len(u) < len(buf)); buf[1..len(u) + 1] = u[..]; s.length += len(u); return *(&s: *str); }; // Converts an i32 to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn i32tos(i: i32, b: base = base::DEC) const str = i64tos(i, b); // Converts an i16 to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn i16tos(i: i16, b: base = base::DEC) const str = i64tos(i, b); // Converts an i8 to a string. The return value is statically allocated and will // be overwritten on subsequent calls; see [[strings::dup]] to duplicate the // result. export fn i8tos(i: i8, b: base = base::DEC) const str = i64tos(i, b); // Converts an int to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn itos(i: int, b: base = base::DEC) const str = i64tos(i, b); @test fn itos_bases() void = { assert("11010" == i64tos(0b11010, base::BIN)); assert("1234567" == i64tos(0o1234567, base::OCT)); assert("123456789" == i64tos(123456789, base::DEC)); assert("123456789ABCDEF" == i64tos(0x123456789ABCDEF, base::HEX)); assert("123456789ABCDEF" == i64tos(0x123456789ABCDEF, base::HEX_UPPER)); assert("123456789abcdef" == i64tos(0x123456789ABCDEF, base::HEX_LOWER)); assert("-1000000000000000000000000000000000000000000000000000000000000000" == i64tos(types::I64_MIN, base::BIN)); }; @test fn itos() void = { const samples: [_]i64 = [ 1234, 4321, -1337, 0, types::I64_MAX, types::I64_MIN, ]; const expected = [ "1234", "4321", "-1337", "0", "9223372036854775807", "-9223372036854775808", ]; for (let i = 0z; i < len(samples); i += 1) { const s = i64tos(samples[i]); assert(s == expected[i]); }; }; hare-0.24.2/strconv/numeric.ha000066400000000000000000000057331464473310100162030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Converts any [[types::signed]] to a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. If base is not specified, base 10 is used. export fn signedtos(n: types::signed, b: base = base::DEC) const str = { match (n) { case let i: int => return itos(i, b); case let i: i8 => return i8tos(i, b); case let i: i16 => return i16tos(i, b); case let i: i32 => return i32tos(i, b); case let i: i64 => return i64tos(i, b); }; }; // Converts any [[types::unsigned]] to a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. If base is not specified, base 10 is used. export fn unsignedtos(n: types::unsigned, b: base = base::DEC) const str = { match (n) { case let u: size => return ztos(u, b); case let u: uint => return utos(u, b); case let u: u8 => return u8tos(u, b); case let u: u16 => return u16tos(u, b); case let u: u32 => return u32tos(u, b); case let u: u64 => return u64tos(u, b); }; }; // Converts any [[types::integer]] to a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. If base is not specified, base 10 is used. export fn integertos(n: types::integer, b: base = base::DEC) const str = { match (n) { case let s: types::signed => return signedtos(s, b); case let u: types::unsigned => return unsignedtos(u, b); }; }; // Converts any [[types::floating]] to a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. If base is not specified, base 10 is used. export fn floatingtos(n: types::floating, b: base = base::DEC) const str = { if (b == base::DEFAULT) { b = base::DEC; }; assert(b == base::DEC); match (n) { case let f: f32 => return f32tos(f); case let f: f64 => return f64tos(f); }; }; // Converts any [[types::numeric]] to a string. The return value is statically // allocated and will be overwritten on subsequent calls; see [[strings::dup]] // to duplicate the result. If base is not specified, base 10 is used. export fn numerictos(n: types::numeric, b: base = base::DEC) const str = { match (n) { case let i: types::integer => return integertos(i, b); case let f: types::floating => return floatingtos(f, b); }; }; @test fn numeric() void = { const cases: [_]types::numeric = [ 42u8, 1337u16, 1337u32, 1337u64, 42i8, -42i8, 1337i16, -1337i16, 1337i32, -1337i32, 1337i64, -1337i64, 1337i, -1337i, 1337u, -1337i, ]; const expected = [ "42", "1337", "1337", "1337", "42", "-42", "1337", "-1337", "1337", "-1337", "1337", "-1337", "1337", "-1337", "1337", "-1337", ]; for (let i = 0z; i < len(cases); i += 1) { assert(numerictos(cases[i]) == expected[i]); }; }; hare-0.24.2/strconv/stof.ha000066400000000000000000000506421464473310100155130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // (c) 2010 The Go Authors. All rights reserved. // Using the Eisel-Lemire algorithm [1] for fast parsing of floating-point // numbers, with Simple Decimal Conversion algorithm [2] as fallback. // [1]: https://nigeltao.github.io/blog/2020/eisel-lemire.html // [2]: https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html use ascii; use math; use strings; def maxshift: u8 = 60; def decimal_point_range: u16 = 2047; type decimal = struct { num_digits: size, decimal_point: i32, negative: bool, truncated: bool, digits: [800]u8, }; // remove trailing zeroes fn trim(d: *decimal) void = { for (d.num_digits > 0 && d.digits[d.num_digits - 1] == 0) { d.num_digits -= 1; }; }; fn leftshift_newdigits(d: *decimal, shift: u32) u32 = { shift &= 63; let x_a = left_shift_table[shift]: u32; let x_b = left_shift_table[shift + 1]: u32; let nn = x_a >> 11; let pow5_a = 0x7FF & x_a, pow5_b = 0x7FF & x_b; const p5 = pow5_table[pow5_a..]; let i = 0u32, n = pow5_b - pow5_a; for (i < n; i += 1) { if (i >= d.num_digits) { return nn - 1; } else if (d.digits[i] == p5[i]) { continue; } else if (d.digits[i] < p5[i]) { return nn - 1; } else { return nn; }; }; return nn; }; fn leftshift(d: *decimal, k: u32) void = { assert(k <= maxshift); if (d.num_digits == 0) return; let nn = leftshift_newdigits(d, k); let r = d.num_digits: int - 1, w = r: size + nn; let n = 0u64; for (r >= 0) { n += d.digits[r]: u64 << k; const quo = n / 10, rem = n - 10 * quo; if (w < len(d.digits)) { d.digits[w] = rem: u8; } else if (rem != 0) { d.truncated = true; }; n = quo; r -= 1; w -= 1; }; for (n > 0) { const quo = n / 10, rem = n - 10 * quo; if (w < len(d.digits)) { d.digits[w] = rem: u8; } else if (rem != 0) { d.truncated = true; }; n = quo; w -= 1; }; d.num_digits += nn; if (d.num_digits > len(d.digits)) { d.num_digits = len(d.digits); }; d.decimal_point += nn: i32; trim(d); }; fn rightshift(d: *decimal, k: u32) void = { let r = 0z, w = 0z, n = 0u64; for (n >> k == 0; r += 1) { if (r >= d.num_digits) { if (n == 0) { d.num_digits = 0; return; }; for (n >> k == 0; r += 1) { n *= 10; }; break; }; n = n * 10 + d.digits[r]; }; d.decimal_point -= r: i32 - 1; if (d.decimal_point < -(decimal_point_range: i32)) { *d = decimal { ... }; return; }; const mask = (1u64 << k) - 1; for (r < d.num_digits; r += 1) { const dig = n >> k; n &= mask; d.digits[w] = dig: u8; w += 1; n = n * 10 + d.digits[r]; }; for (n > 0) { const dig = n >> k; n &= mask; if (w < len(d.digits)) { d.digits[w] = dig: u8; w += 1; } else if (dig > 0) { d.truncated = true; }; n *= 10; }; d.num_digits = w; trim(d); }; fn decimal_shift(d: *decimal, k: int) void = { if (d.num_digits == 0) return; if (k > 0) { for (k > maxshift: int) { leftshift(d, maxshift); k -= maxshift: i32; }; leftshift(d, k: u32); } else if (k < 0) { for (k < -(maxshift: int)) { rightshift(d, maxshift); k += maxshift: i32; }; rightshift(d, (-k): u32); }; }; fn should_round_up(d: *decimal, nd: uint) bool = if (nd < d.num_digits) { if (d.digits[nd] == 5 && nd + 1 == d.num_digits) { return d.truncated || (nd > 0 && d.digits[nd - 1] & 1 != 0); } else return d.digits[nd] >= 5; } else false; fn round(d: *decimal, nd: uint) void = { if (nd >= d.num_digits) return; if (should_round_up(d, nd)) roundup(d, nd) else rounddown(d, nd); }; fn rounddown(d: *decimal, nd: uint) void = { if (nd >= d.num_digits) return; d.num_digits = nd; trim(d); }; fn roundup(d: *decimal, nd: uint) void = { if (nd >= d.num_digits) return; for (let i = nd: int - 1; i >= 0; i -= 1) { if (d.digits[i] < 9) { d.digits[i] += 1; d.num_digits = i: size + 1; return; }; }; d.digits[0] = 1; d.num_digits = 1; d.decimal_point += 1; }; fn decimal_round(d: *decimal) u64 = { if (d.num_digits == 0 || d.decimal_point < 0) return 0; if (d.decimal_point > 18) return ~0u64; let i = 0z, n: u64 = 0; for (i < d.decimal_point: uint && i < d.num_digits; i += 1) { n = n * 10 + d.digits[i]; }; for (i < d.decimal_point: uint; i += 1) { n *= 10; }; if (should_round_up(d, d.decimal_point: uint)) { n += 1; }; return n; }; fn todig(c: u8) u8 = { if ('0' <= c && c <= '9') { return c - '0'; } else if ('a' <= c && c <= 'f') { return c - 'a' + 10; } else if ('A' <= c && c <= 'F') { return c - 'A' + 10; }; abort("unreachable"); }; type fast_parsed_float = struct { mantissa: u64, exponent: i32, negative: bool, truncated: bool, }; fn fast_parse(s: str, b: base) (fast_parsed_float | invalid) = { let buf = strings::toutf8(s); let i = 0z, neg = false, trunc = false; if (buf[i] == '-') { neg = true; i += 1; } else if (buf[i] == '+') { i += 1; }; let (expchr, max_ndmant, isdigit) = switch (b) { case base::DEC => yield ('e', 19, &ascii::isdigit); case base::HEX => yield ('p', 16, &ascii::isxdigit); case => abort("unreachable"); }; let sawdot = false, sawdigits = false; let nd = 0, ndmant = 0, dp = 0; let mant = 0u64, exp = 0i32; for (i < len(s); i += 1) { if (buf[i] == '.') { if (sawdot) return i: invalid; sawdot = true; dp = nd; } else if (isdigit(buf[i]: rune)) { sawdigits = true; if (buf[i] == '0' && nd == 0) { dp -= 1; continue; }; nd += 1; if (ndmant < max_ndmant) { mant = mant * b + todig(buf[i]); ndmant += 1; } else if (buf[i] != '0') { trunc = true; }; } else break; }; if (!sawdigits) return i: invalid; if (!sawdot) { dp = nd; }; if (b == base::HEX) { dp *= 4; ndmant *= 4; }; if (i < len(s) && ascii::tolower(buf[i]: rune) == expchr) { i += 1; if (i >= len(s)) return i: invalid; let expsign: int = 1; if (buf[i] == '+') { i += 1; } else if (buf[i] == '-') { expsign = -1; i += 1; }; if (i >= len(s) || !ascii::isdigit(buf[i]: rune)) return i: invalid; let e: int = 0; for (i < len(s) && ascii::isdigit(buf[i]: rune); i += 1) { if (e < 10000) { e = e * 10 + (buf[i] - '0'): int; }; }; dp += e * expsign; } else if (b == base::HEX) { return i: invalid; // hex floats must have exponent }; if (i != len(s)) return i: invalid; if (mant != 0) { exp = dp - ndmant; }; return fast_parsed_float { mantissa = mant, exponent = exp, negative = neg, truncated = trunc, }; }; fn decimal_parse(d: *decimal, s: str) (void | invalid) = { let i = 0z; const buf = strings::toutf8(s); d.negative = false; d.truncated = false; if (buf[0] == '+') { i += 1; } else if (buf[0] == '-') { d.negative = true; i += 1; }; let sawdot = false, sawdigits = false; for (i < len(s); i += 1) { if (buf[i] == '.') { if (sawdot) return i: invalid; sawdot = true; d.decimal_point = d.num_digits: int; } else if (ascii::isdigit(buf[i]: rune)) { sawdigits = true; if (buf[i] == '0' && d.num_digits == 0) { d.decimal_point -= 1; continue; }; if (d.num_digits < len(d.digits)) { d.digits[d.num_digits] = buf[i] - '0'; d.num_digits += 1; } else if (buf[i] != '0') { d.truncated = true; }; } else break; }; if (!sawdigits) return i: invalid; if (!sawdot) { d.decimal_point = d.num_digits: int; }; if (i < len(s) && (buf[i] == 'e' || buf[i] == 'E')) { i += 1; if (i >= len(s)) return i: invalid; let expsign: int = 1; if (buf[i] == '+') { i += 1; } else if (buf[i] == '-') { expsign = -1; i += 1; }; if (i >= len(s) || !ascii::isdigit(buf[i]: rune)) return i: invalid; let e: int = 0; for (i < len(s) && ascii::isdigit(buf[i]: rune); i += 1) { if (e < 10000) { e = e * 10 + (buf[i] - '0'): int; }; }; d.decimal_point += e * expsign; }; if (i != len(s)) return i: invalid; }; fn leading_zeroes(n: u64) uint = { assert(n > 0); let b = 0u; if ((n & 0b1111111111111111111111111111111100000000000000000000000000000000u64) > 0) { n >>= 32; b |= 32; }; if ((n & 0b11111111111111110000000000000000u64) > 0) { n >>= 16; b |= 16; }; if ((n & 0b1111111100000000u64) > 0) { n >>= 8; b |= 8; }; if ((n & 0b11110000) > 0) { n >>= 4; b |= 4; }; if ((n & 0b1100) > 0) { n >>= 2; b |= 2; }; if ((n & 0b10) > 0) { n >>= 1; b |= 1; }; return 63 - b; }; fn eisel_lemire( mantissa: u64, exp10: i32, neg: bool, f: *math::floatinfo ) (u64 | void) = { if (mantissa == 0 || exp10 > 288 || exp10 < -307) return; const po10 = powers_of_ten[exp10 + 307]; const clz = leading_zeroes(mantissa); mantissa <<= clz; let shift = 64 - f.mantbits - 3, mask = (1 << shift) - 1; // log(10) / log(2) ≈ 217706 / 65536; x / 65536 = x >> 16 let exp = (217706 * exp10) >> 16; let e2 = (exp + f.expbias: i32 + 64): u64 - clz: u64; let x = u128mul(mantissa, po10[1]); if ((x.hi & mask) == mask && ((x.lo + mantissa) < mantissa)) { const y = u128mul(mantissa, po10[0]); let merged = r128 { hi = x.hi, lo = x.lo + y.hi }; if (merged.lo < x.lo) { merged.hi += 1; }; if (((merged.hi & mask) == mask) && ((merged.lo + 1) == 0) && (y.lo + mantissa < mantissa)) { return; }; x = merged; }; let msb = x.hi >> 63, mant = x.hi >> (msb + shift); e2 -= 1 ^ msb; if (x.lo == 0 && (x.hi & mask == 0) && (mant & 3 == 1)) { return; }; mant += mant & 1; mant >>= 1; if ((mant >> (f.mantbits + 1)) > 0) { mant >>= 1; e2 += 1; }; if (e2 <= 0 || e2 >= (1 << f.expbits) - 1) { return; }; return mkfloat(mant, e2: uint, neg, f); }; fn floatbits(d: *decimal, f: *math::floatinfo) (u64 | overflow) = { let e: int = 0, m: u64 = 0; const powtab: [19]i8 = [ 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59, ]; if (d.num_digits == 0 || d.decimal_point < -326) { return if (d.negative) mkfloat(0, 0, d.negative, f) else 0; } else if (d.decimal_point > 310) { return overflow; }; if (d.num_digits <= 19) { let mant = 0u64; for (let i = 0z; i < d.num_digits; i += 1) { mant = (10 * mant) + d.digits[i]; }; const exp10 = d.decimal_point - d.num_digits: i32; const r = eisel_lemire(mant, exp10, d.negative, f); if (r is u64) { return r: u64; }; }; for (d.decimal_point > 0) { const n: int = if (d.decimal_point: uint >= len(powtab)) maxshift: int else powtab[d.decimal_point]; decimal_shift(d, -n); e += n; }; for (d.decimal_point <= 0) { const n: int = if (d.decimal_point == 0) { if (d.digits[0] >= 5) break; yield if (d.digits[0] < 2) 2 else 1; } else if (-d.decimal_point >= len(powtab): i32) maxshift: int else powtab[-d.decimal_point]; decimal_shift(d, n); e -= n; }; e -= 1; if (e <= -f.expbias + 1) { const n = -f.expbias - e + 1; decimal_shift(d, -n); e += n; }; if (e + f.expbias >= (1 << f.expbits: int) - 1) { return overflow; }; decimal_shift(d, f.mantbits: int + 1); m = decimal_round(d); if (m == 2 << f.mantbits) { m >>= 1; e += 1; if (e + f.expbias >= (1 << f.expbits: int) - 1) { return overflow; }; }; if (m & (1 << f.mantbits) == 0) { e = -f.expbias; }; return mkfloat(m, (e + f.expbias): uint, d.negative, f); }; fn mkfloat(m: u64, e: uint, negative: bool, f: *math::floatinfo) u64 = { let n: u64 = m & ((1 << f.mantbits) - 1); n |= (e & ((1 << f.expbits) - 1)) << f.mantbits; if (negative) { n |= 1 << (f.mantbits + f.expbits); }; return n; }; const f64pow10: [_]f64 = [ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22 ]; fn stof64exact(mant: u64, exp: i32, neg: bool) (f64 | void) = { if (mant >> math::F64_MANTISSA_BITS != 0) return; let n = mant: i64: f64; // XXX: ARCH if (neg) { n = -n; }; if (exp == 0) { return n; }; if (-22 <= exp && exp <= 22) { if (exp >= 0) { n *= f64pow10[exp]; } else { n /= f64pow10[-exp]; }; } else return; return n; }; const f32pow10: [_]f32 = [ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10 ]; fn stof32exact(mant: u64, exp: i32, neg: bool) (f32 | void) = { if (mant >> math::F32_MANTISSA_BITS != 0) return; let n = mant: i32: f32; // XXX: ARCH if (neg) { n = -n; }; if (exp == 0) { return n; }; if (-10 <= exp && exp <= 10) { if (exp >= 0) { n *= f32pow10[exp]; } else { n /= f64pow10[-exp]: f32; }; } else return; return n; }; // Adapted from golang's atofHex. fn hex_to_bits( p: fast_parsed_float, info: *math::floatinfo, ) (u64 | overflow) = { const max_exp = (1 << info.expbits): int - info.expbias - 2; const min_exp = -info.expbias + 1; p.exponent += info.mantbits: i32; // Shift left until we have a leading 1 bit in the mantissa followed by // mantbits, plus two more for rounding. for (p.mantissa != 0 && p.mantissa >> (info.mantbits + 2) == 0) { p.mantissa <<= 1; p.exponent -= 1; }; // The lowest of the two rounding bits is set if we truncated. if (p.truncated) { p.mantissa |= 1; }; // If we have too many bits, shift right. for (p.mantissa >> (3 + info.mantbits) != 0) { p.mantissa = (p.mantissa >> 1) | (p.mantissa & 1); p.exponent += 1; }; // Denormalize if the exponent is small. for (p.mantissa > 1 && p.exponent < min_exp: i32 - 2) { p.mantissa = (p.mantissa >> 1) | (p.mantissa & 1); p.exponent += 1; }; // Round to even. let round = p.mantissa & 3; p.mantissa >>= 2; round |= p.mantissa & 1; p.exponent += 2; if (round == 3) { p.mantissa += 1; if (p.mantissa == 1 << (1 + info.mantbits)) { p.mantissa >>= 1; p.exponent += 1; }; }; // Denormal or zero. if (p.mantissa >> info.mantbits == 0) { p.exponent = -info.expbias; }; if (p.exponent > max_exp: i32) { return overflow; }; let bits = p.mantissa & info.mantmask; bits |= ((p.exponent + info.expbias: i32): u64 & info.expmask) << info.mantbits; if (p.negative) { bits |= 1 << (info.mantbits + info.expbits); }; return bits; }; fn special(s: str) (f32 | void) = { if (ascii::strcasecmp(s, "nan") == 0) { return math::NAN; } else if (ascii::strcasecmp(s, "infinity") == 0) { return math::INF; } else if (ascii::strcasecmp(s, "+infinity") == 0) { return math::INF; } else if (ascii::strcasecmp(s, "-infinity") == 0) { return -math::INF; }; }; // Converts a string to a f64 in [[base::DEC]] or [[base::HEX]]. If base is not // provided, [[base::DEC]] is used. If the string is not a syntactically // well-formed floating-point number, [[invalid]] is returned. If the string // represents a floating-point number that is larger than the largest finite // f64 number, [[overflow]] is returned. Zero is returned if the string // represents a floating-point number that is smaller than the f64 number // nearest to zero with respective sign. Recognizes "Infinity", "+Infinity", // "-Infinity", and "NaN", case insensitive. export fn stof64(s: str, b: base = base::DEC) (f64 | invalid | overflow) = { if (b == base::DEFAULT) { b = base::DEC; } else if (b == base::HEX_LOWER) { b = base::HEX; }; assert(b == base::DEC || b == base::HEX); if (len(s) == 0) { return 0z: invalid; }; match (special(s)) { case let f: f32 => return f; case void => void; }; const p = fast_parse(s, b)?; if (b == base::HEX) { return math::f64frombits(hex_to_bits(p, &math::f64info)?); } else if (!p.truncated) { let n = stof64exact(p.mantissa, p.exponent, p.negative); if (n is f64) { return n: f64; }; let n = eisel_lemire(p.mantissa, p.exponent, p.negative, &math::f64info); if (n is u64) { return math::f64frombits(n: u64); }; }; let d = decimal { ... }; decimal_parse(&d, s)?; const n = floatbits(&d, &math::f64info)?; return math::f64frombits(n); }; // Converts a string to a f32 in [[base::DEC]] or [[base::HEX]]. If base is not // provided, [[base::DEC]] is used. If the string is not a syntactically // well-formed floating-point number, [[invalid]] is returned. If the string // represents a floating-point number that is larger than the largest finite // f32 number, [[overflow]] is returned. Zero is returned if the string // represents a floating-point number that is smaller than the f32 number // nearest to zero with respective sign. Recognizes "Infinity", "+Infinity", // "-Infinity", and "NaN", case insensitive. export fn stof32(s: str, b: base = base::DEC) (f32 | invalid | overflow) = { if (b == base::DEFAULT) { b = base::DEC; } else if (b == base::HEX_LOWER) { b = base::HEX; }; assert(b == base::DEC || b == base::HEX); if (len(s) == 0) { return 0z: invalid; }; match (special(s)) { case let f: f32 => return f; case void => void; }; const p = fast_parse(s, b)?; if (b == base::HEX) { return math::f32frombits(hex_to_bits(p, &math::f32info)?: u32); } else if (!p.truncated) { let n = stof32exact(p.mantissa, p.exponent, p.negative); if (n is f32) { return n: f32; }; let n = eisel_lemire(p.mantissa, p.exponent, p.negative, &math::f32info); if (n is u64) { return math::f32frombits(n: u64: u32); }; }; let d = decimal { ... }; decimal_parse(&d, s)?; const n = floatbits(&d, &math::f32info)?: u32; return math::f32frombits(n); }; @test fn stof64() void = { assert(stof64("0"): f64 == 0.0); assert(stof64("200"): f64 == 200.0); assert(stof64("12345"): f64 == 12345.0); assert(stof64("+112233445566778899"): f64 == 1.122334455667789e17); assert(stof64("3.14"): f64 == 3.14); assert(stof64("2.99792458E+8"): f64 == 299792458.0); assert(stof64("6.022e23"): f64 == 6.022e23); assert(stof64("1e310") is overflow); assert(stof64("9007199254740991"): f64 == 9007199254740991.0); assert(stof64("90071992547409915"): f64 == 90071992547409920.0); assert(stof64("90071992547409925"): f64 == 90071992547409920.0); assert(stof64("2.2250738585072014e-308"): f64 == 2.2250738585072014e-308); assert(stof64("-1e-324"): f64 == -0.0); assert(stof64("5e-324"): f64 == 5.0e-324); assert(stof64(""): invalid: size == 0); assert(stof64("0ZO"): invalid: size == 1); assert(stof64("1.23ezz"): invalid: size == 5); assert(stof64("Infinity"): f64 == math::INF); assert(stof64("+Infinity"): f64 == math::INF); assert(stof64("-Infinity"): f64 == -math::INF); assert(stof64("infinity"): f64 == math::INF); assert(stof64("inFinIty"): f64 == math::INF); assert(stof64("-infinity"): f64 == -math::INF); assert(stof64("-infiNity"): f64 == -math::INF); assert(math::isnan(stof64("NaN"): f64)); assert(math::isnan(stof64("nan"): f64)); assert(math::isnan(stof64("naN"): f64)); }; @test fn stof32() void = { assert(stof32("0"): f32 == 0.0); assert(stof32("1e10"): f32 == 1.0e10); assert(stof32("299792458"): f32 == 299792458.0); assert(stof32("6.022e23"): f32 == 6.022e23); assert(stof32("1e40") is overflow); assert(stof32("16777215"): f32 == 16777215.0); assert(stof32("167772155"): f32 == 167772160.0); assert(stof32("167772145"): f32 == 167772140.0); assert(stof32("6.62607015e-34"): f32 == 6.62607015e-34); assert(stof32("1.1754944e-38"): f32 == 1.1754944e-38); assert(stof32("-1e-50"): f32 == -0.0); assert(stof32("1e-45"): f32 == 1.0e-45); assert(stof32(""): invalid: size == 0); assert(stof32("0ZO"): invalid: size == 1); assert(stof32("1.23e-zz"): invalid: size == 6); assert(stof32("Infinity"): f32 == math::INF); assert(stof32("+Infinity"): f32 == math::INF); assert(stof32("-Infinity"): f32 == -math::INF); assert(stof32("infinity"): f32 == math::INF); assert(stof32("inFinIty"): f32 == math::INF); assert(stof32("-infinity"): f32 == -math::INF); assert(stof32("-infiniTy"): f32 == -math::INF); assert(math::isnan(stof32("NaN"): f32)); assert(math::isnan(stof32("nan"): f32)); assert(math::isnan(stof32("naN"): f32)); assert(stof32("9.19100241453305036800e+20") == 9.19100241453305036800e+20); }; @test fn stofhex() void = { assert(stof64("0p0", base::HEX)! == 0x0.0p0); assert(stof64("1p0", base::HEX)! == 0x1.0p0); assert(stof64("-1p0", base::HEX_LOWER)! == -0x1.0p0); assert(stof64("1.fp-2", base::HEX)! == 0x1.fp-2); assert(stof64("1.fffffffffffffp+1023", base::HEX)! == math::F64_MAX_NORMAL); assert(stof64("1.0000000000000p-1022", base::HEX)! == math::F64_MIN_NORMAL); assert(stof64("0.0000000000001p-1022", base::HEX)! == math::F64_MIN); assert(stof64("1p+1024", base::HEX) is overflow); assert(stof64("0.00000000000001p-1022", base::HEX)! == 0.0); assert(stof32("0p0", base::HEX)! == 0x0.0p0); assert(stof32("1p0", base::HEX)! == 0x1.0p0); assert(stof32("-1p0", base::HEX)! == -0x1.0p0); assert(stof32("1.fp-2", base::HEX)! == 0x1.fp-2); assert(stof32("1.fffffd586b834p+127", base::HEX)! == math::F32_MAX_NORMAL); assert(stof32("1.0p-126", base::HEX)! == math::F32_MIN_NORMAL); assert(stof32("1.6p-150", base::HEX)! == math::F32_MIN); assert(stof32("1.0p+128", base::HEX) is overflow); assert(stof32("1.0p-151", base::HEX)! == 0.0); }; hare-0.24.2/strconv/stof_data.ha000066400000000000000000001070351464473310100165030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors const left_shift_table: [65]u16 = [ 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067, 0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF, 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0, 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA, 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC, 0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C, 0x051C, 0x051C, ]; const pow5_table: [0x051C]u8 = [ 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8, 7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, 9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1, 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, 4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0, 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7, 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5, 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3, 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8, 0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, 9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0, 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, 9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1, 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6, 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1, 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1, 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5, 9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5, ]; const powers_of_ten: [596][2]u64 = [ [0xA5D3B6D479F8E056, 0x8FD0C16206306BAB], // 1e-307 [0x8F48A4899877186C, 0xB3C4F1BA87BC8696], // 1e-306 [0x331ACDABFE94DE87, 0xE0B62E2929ABA83C], // 1e-305 [0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925], // 1e-304 [0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F], // 1e-303 [0xC9E82CD9F69D6150, 0xDB71E91432B1A24A], // 1e-302 [0xBE311C083A225CD2, 0x892731AC9FAF056E], // 1e-301 [0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA], // 1e-300 [0x092CBBCCDAD5B108, 0xD64D3D9DB981787D], // 1e-299 [0x25BBF56008C58EA5, 0x85F0468293F0EB4E], // 1e-298 [0xAF2AF2B80AF6F24E, 0xA76C582338ED2621], // 1e-297 [0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA], // 1e-296 [0x50D98D9FC890ED4D, 0x82CCA4DB847945CA], // 1e-295 [0xE50FF107BAB528A0, 0xA37FCE126597973C], // 1e-294 [0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C], // 1e-293 [0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F], // 1e-292 [0x77B191618C54E9AC, 0x9FAACF3DF73609B1], // 1e-291 [0xD59DF5B9EF6A2417, 0xC795830D75038C1D], // 1e-290 [0x4B0573286B44AD1D, 0xF97AE3D0D2446F25], // 1e-289 [0x4EE367F9430AEC32, 0x9BECCE62836AC577], // 1e-288 [0x229C41F793CDA73F, 0xC2E801FB244576D5], // 1e-287 [0x6B43527578C1110F, 0xF3A20279ED56D48A], // 1e-286 [0x830A13896B78AAA9, 0x9845418C345644D6], // 1e-285 [0x23CC986BC656D553, 0xBE5691EF416BD60C], // 1e-284 [0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F], // 1e-283 [0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39], // 1e-282 [0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07], // 1e-281 [0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9], // 1e-280 [0x23100809B9C21FA1, 0x91376C36D99995BE], // 1e-279 [0xABD40A0C2832A78A, 0xB58547448FFFFB2D], // 1e-278 [0x16C90C8F323F516C, 0xE2E69915B3FFF9F9], // 1e-277 [0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B], // 1e-276 [0x99CD11CFDF41779C, 0xB1442798F49FFB4A], // 1e-275 [0x40405643D711D583, 0xDD95317F31C7FA1D], // 1e-274 [0x482835EA666B2572, 0x8A7D3EEF7F1CFC52], // 1e-273 [0xDA3243650005EECF, 0xAD1C8EAB5EE43B66], // 1e-272 [0x90BED43E40076A82, 0xD863B256369D4A40], // 1e-271 [0x5A7744A6E804A291, 0x873E4F75E2224E68], // 1e-270 [0x711515D0A205CB36, 0xA90DE3535AAAE202], // 1e-269 [0x0D5A5B44CA873E03, 0xD3515C2831559A83], // 1e-268 [0xE858790AFE9486C2, 0x8412D9991ED58091], // 1e-267 [0x626E974DBE39A872, 0xA5178FFF668AE0B6], // 1e-266 [0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3], // 1e-265 [0x7CE66634BC9D0B99, 0x80FA687F881C7F8E], // 1e-264 [0x1C1FFFC1EBC44E80, 0xA139029F6A239F72], // 1e-263 [0xA327FFB266B56220, 0xC987434744AC874E], // 1e-262 [0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922], // 1e-261 [0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5], // 1e-260 [0xCB550FB4384D21D3, 0xC4CE17B399107C22], // 1e-259 [0x7E2A53A146606A48, 0xF6019DA07F549B2B], // 1e-258 [0x2EDA7444CBFC426D, 0x99C102844F94E0FB], // 1e-257 [0xFA911155FEFB5308, 0xC0314325637A1939], // 1e-256 [0x793555AB7EBA27CA, 0xF03D93EEBC589F88], // 1e-255 [0x4BC1558B2F3458DE, 0x96267C7535B763B5], // 1e-254 [0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2], // 1e-253 [0x465E15A979C1CADC, 0xEA9C227723EE8BCB], // 1e-252 [0x0BFACD89EC191EC9, 0x92A1958A7675175F], // 1e-251 [0xCEF980EC671F667B, 0xB749FAED14125D36], // 1e-250 [0x82B7E12780E7401A, 0xE51C79A85916F484], // 1e-249 [0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2], // 1e-248 [0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07], // 1e-247 [0x67A791E093E1D49A, 0xDFBDCECE67006AC9], // 1e-246 [0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD], // 1e-245 [0x58FAE9F773886E18, 0xAECC49914078536D], // 1e-244 [0xAF39A475506A899E, 0xDA7F5BF590966848], // 1e-243 [0x6D8406C952429603, 0x888F99797A5E012D], // 1e-242 [0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178], // 1e-241 [0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6], // 1e-240 [0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26], // 1e-239 [0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F], // 1e-238 [0xF13B94DAF124DA26, 0xD0601D8EFC57B08B], // 1e-237 [0x76C53D08D6B70858, 0x823C12795DB6CE57], // 1e-236 [0x54768C4B0C64CA6E, 0xA2CB1717B52481ED], // 1e-235 [0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268], // 1e-234 [0xD3F93B35435D7C4C, 0xFE5D54150B090B02], // 1e-233 [0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1], // 1e-232 [0x359AB6419CA1091B, 0xC6B8E9B0709F109A], // 1e-231 [0xC30163D203C94B62, 0xF867241C8CC6D4C0], // 1e-230 [0x79E0DE63425DCF1D, 0x9B407691D7FC44F8], // 1e-229 [0x985915FC12F542E4, 0xC21094364DFB5636], // 1e-228 [0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4], // 1e-227 [0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A], // 1e-226 [0x50C6FF782A838353, 0xBD8430BD08277231], // 1e-225 [0xA4F8BF5635246428, 0xECE53CEC4A314EBD], // 1e-224 [0x871B7795E136BE99, 0x940F4613AE5ED136], // 1e-223 [0x28E2557B59846E3F, 0xB913179899F68584], // 1e-222 [0x331AEADA2FE589CF, 0xE757DD7EC07426E5], // 1e-221 [0x3FF0D2C85DEF7621, 0x9096EA6F3848984F], // 1e-220 [0x0FED077A756B53A9, 0xB4BCA50B065ABE63], // 1e-219 [0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB], // 1e-218 [0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD], // 1e-217 [0xBD8D794D96AACFB3, 0xB080392CC4349DEC], // 1e-216 [0xECF0D7A0FC5583A0, 0xDCA04777F541C567], // 1e-215 [0xF41686C49DB57244, 0x89E42CAAF9491B60], // 1e-214 [0x311C2875C522CED5, 0xAC5D37D5B79B6239], // 1e-213 [0x7D633293366B828B, 0xD77485CB25823AC7], // 1e-212 [0xAE5DFF9C02033197, 0x86A8D39EF77164BC], // 1e-211 [0xD9F57F830283FDFC, 0xA8530886B54DBDEB], // 1e-210 [0xD072DF63C324FD7B, 0xD267CAA862A12D66], // 1e-209 [0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60], // 1e-208 [0x52D9BE85F074E608, 0xA46116538D0DEB78], // 1e-207 [0x67902E276C921F8B, 0xCD795BE870516656], // 1e-206 [0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6], // 1e-205 [0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3], // 1e-204 [0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0], // 1e-203 [0x796B805720085F81, 0xFAD2A4B13D1B5D6C], // 1e-202 [0xCBE3303674053BB0, 0x9CC3A6EEC6311A63], // 1e-201 [0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC], // 1e-200 [0xEE92FB5515482D44, 0xF4F1B4D515ACB93B], // 1e-199 [0x751BDD152D4D1C4A, 0x991711052D8BF3C5], // 1e-198 [0xD262D45A78A0635D, 0xBF5CD54678EEF0B6], // 1e-197 [0x86FB897116C87C34, 0xEF340A98172AACE4], // 1e-196 [0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E], // 1e-195 [0x8974836059CCA109, 0xBAE0A846D2195712], // 1e-194 [0x2BD1A438703FC94B, 0xE998D258869FACD7], // 1e-193 [0x7B6306A34627DDCF, 0x91FF83775423CC06], // 1e-192 [0x1A3BC84C17B1D542, 0xB67F6455292CBF08], // 1e-191 [0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA], // 1e-190 [0x547EB47B7282EE9C, 0x8E938662882AF53E], // 1e-189 [0xE99E619A4F23AA43, 0xB23867FB2A35B28D], // 1e-188 [0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31], // 1e-187 [0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E], // 1e-186 [0x9624AB50B148D445, 0xAE0B158B4738705E], // 1e-185 [0x3BADD624DD9B0957, 0xD98DDAEE19068C76], // 1e-184 [0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9], // 1e-183 [0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC], // 1e-182 [0x7647C3200069671F, 0xD47487CC8470652B], // 1e-181 [0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B], // 1e-180 [0xF468107100525890, 0xA5FB0A17C777CF09], // 1e-179 [0x7182148D4066EEB4, 0xCF79CC9DB955C2CC], // 1e-178 [0xC6F14CD848405530, 0x81AC1FE293D599BF], // 1e-177 [0xB8ADA00E5A506A7C, 0xA21727DB38CB002F], // 1e-176 [0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B], // 1e-175 [0x908F4A166D1DA663, 0xFD442E4688BD304A], // 1e-174 [0x9A598E4E043287FE, 0x9E4A9CEC15763E2E], // 1e-173 [0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA], // 1e-172 [0xD12BEE59E68EF47C, 0xF7549530E188C128], // 1e-171 [0x82BB74F8301958CE, 0x9A94DD3E8CF578B9], // 1e-170 [0xE36A52363C1FAF01, 0xC13A148E3032D6E7], // 1e-169 [0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1], // 1e-168 [0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5], // 1e-167 [0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE], // 1e-166 [0x111B495B3464AD21, 0xEBDF661791D60F56], // 1e-165 [0xCAB10DD900BEEC34, 0x936B9FCEBB25C995], // 1e-164 [0x3D5D514F40EEA742, 0xB84687C269EF3BFB], // 1e-163 [0x0CB4A5A3112A5112, 0xE65829B3046B0AFA], // 1e-162 [0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC], // 1e-161 [0x59ED216765690F56, 0xB3F4E093DB73A093], // 1e-160 [0x306869C13EC3532C, 0xE0F218B8D25088B8], // 1e-159 [0x1E414218C73A13FB, 0x8C974F7383725573], // 1e-158 [0xE5D1929EF90898FA, 0xAFBD2350644EEACF], // 1e-157 [0xDF45F746B74ABF39, 0xDBAC6C247D62A583], // 1e-156 [0x6B8BBA8C328EB783, 0x894BC396CE5DA772], // 1e-155 [0x066EA92F3F326564, 0xAB9EB47C81F5114F], // 1e-154 [0xC80A537B0EFEFEBD, 0xD686619BA27255A2], // 1e-153 [0xBD06742CE95F5F36, 0x8613FD0145877585], // 1e-152 [0x2C48113823B73704, 0xA798FC4196E952E7], // 1e-151 [0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0], // 1e-150 [0x9A984D73DBE722FB, 0x82EF85133DE648C4], // 1e-149 [0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5], // 1e-148 [0x318DF905079926A8, 0xCC963FEE10B7D1B3], // 1e-147 [0xFDF17746497F7052, 0xFFBBCFE994E5C61F], // 1e-146 [0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3], // 1e-145 [0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8], // 1e-144 [0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B], // 1e-143 [0x06BEA10CA65C084E, 0x9C1661A651213E2D], // 1e-142 [0x486E494FCFF30A62, 0xC31BFA0FE5698DB8], // 1e-141 [0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126], // 1e-140 [0xF89629465A75E01C, 0x986DDB5C6B3A76B7], // 1e-139 [0xF6BBB397F1135823, 0xBE89523386091465], // 1e-138 [0x746AA07DED582E2C, 0xEE2BA6C0678B597F], // 1e-137 [0xA8C2A44EB4571CDC, 0x94DB483840B717EF], // 1e-136 [0x92F34D62616CE413, 0xBA121A4650E4DDEB], // 1e-135 [0x77B020BAF9C81D17, 0xE896A0D7E51E1566], // 1e-134 [0x0ACE1474DC1D122E, 0x915E2486EF32CD60], // 1e-133 [0x0D819992132456BA, 0xB5B5ADA8AAFF80B8], // 1e-132 [0x10E1FFF697ED6C69, 0xE3231912D5BF60E6], // 1e-131 [0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F], // 1e-130 [0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3], // 1e-129 [0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0], // 1e-128 [0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4], // 1e-127 [0x86C16C98D2C953C6, 0xAD4AB7112EB3929D], // 1e-126 [0xE871C7BF077BA8B7, 0xD89D64D57A607744], // 1e-125 [0x11471CD764AD4972, 0x87625F056C7C4A8B], // 1e-124 [0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D], // 1e-123 [0x4AFF1D108D4EC2C3, 0xD389B47879823479], // 1e-122 [0xCEDF722A585139BA, 0x843610CB4BF160CB], // 1e-121 [0xC2974EB4EE658828, 0xA54394FE1EEDB8FE], // 1e-120 [0x733D226229FEEA32, 0xCE947A3DA6A9273E], // 1e-119 [0x0806357D5A3F525F, 0x811CCC668829B887], // 1e-118 [0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8], // 1e-117 [0xFC89B393DD02F0B5, 0xC9BCFF6034C13052], // 1e-116 [0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67], // 1e-115 [0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0], // 1e-114 [0x0A9E795E65D4DF11, 0xC5029163F384A931], // 1e-113 [0x4D4617B5FF4A16D5, 0xF64335BCF065D37D], // 1e-112 [0x504BCED1BF8E4E45, 0x99EA0196163FA42E], // 1e-111 [0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39], // 1e-110 [0x5D767327BB4E5A4C, 0xF07DA27A82C37088], // 1e-109 [0x3A6A07F8D510F86F, 0x964E858C91BA2655], // 1e-108 [0x890489F70A55368B, 0xBBE226EFB628AFEA], // 1e-107 [0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5], // 1e-106 [0x3B0B8BC90012929D, 0x92C8AE6B464FC96F], // 1e-105 [0x09CE6EBB40173744, 0xB77ADA0617E3BBCB], // 1e-104 [0xCC420A6A101D0515, 0xE55990879DDCAABD], // 1e-103 [0x9FA946824A12232D, 0x8F57FA54C2A9EAB6], // 1e-102 [0x47939822DC96ABF9, 0xB32DF8E9F3546564], // 1e-101 [0x59787E2B93BC56F7, 0xDFF9772470297EBD], // 1e-100 [0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36], // 1e-99 [0xEDE622920B6B23F1, 0xAEFAE51477A06B03], // 1e-98 [0xE95FAB368E45ECED, 0xDAB99E59958885C4], // 1e-97 [0x11DBCB0218EBB414, 0x88B402F7FD75539B], // 1e-96 [0xD652BDC29F26A119, 0xAAE103B5FCD2A881], // 1e-95 [0x4BE76D3346F0495F, 0xD59944A37C0752A2], // 1e-94 [0x6F70A4400C562DDB, 0x857FCAE62D8493A5], // 1e-93 [0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E], // 1e-92 [0x7E2000A41346A7A7, 0xD097AD07A71F26B2], // 1e-91 [0x8ED400668C0C28C8, 0x825ECC24C873782F], // 1e-90 [0x728900802F0F32FA, 0xA2F67F2DFA90563B], // 1e-89 [0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA], // 1e-88 [0xE2F610C84987BFA8, 0xFEA126B7D78186BC], // 1e-87 [0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436], // 1e-86 [0x91503D1C79720DBB, 0xC6EDE63FA05D3143], // 1e-85 [0x75A44C6397CE912A, 0xF8A95FCF88747D94], // 1e-84 [0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C], // 1e-83 [0xFBE85BADCE996168, 0xC24452DA229B021B], // 1e-82 [0xFAE27299423FB9C3, 0xF2D56790AB41C2A2], // 1e-81 [0xDCCD879FC967D41A, 0x97C560BA6B0919A5], // 1e-80 [0x5400E987BBC1C920, 0xBDB6B8E905CB600F], // 1e-79 [0x290123E9AAB23B68, 0xED246723473E3813], // 1e-78 [0xF9A0B6720AAF6521, 0x9436C0760C86E30B], // 1e-77 [0xF808E40E8D5B3E69, 0xB94470938FA89BCE], // 1e-76 [0xB60B1D1230B20E04, 0xE7958CB87392C2C2], // 1e-75 [0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9], // 1e-74 [0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828], // 1e-73 [0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232], // 1e-72 [0x579C487E5A38AD0E, 0x8D590723948A535F], // 1e-71 [0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837], // 1e-70 [0xF8E431456CF88E65, 0xDCDB1B2798182244], // 1e-69 [0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B], // 1e-68 [0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5], // 1e-67 [0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177], // 1e-66 [0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA], // 1e-65 [0x3F2398D747B36224, 0xA87FEA27A539E9A5], // 1e-64 [0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E], // 1e-63 [0x1953CF68300424AC, 0x83A3EEEEF9153E89], // 1e-62 [0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B], // 1e-61 [0x3792F412CB06794D, 0xCDB02555653131B6], // 1e-60 [0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11], // 1e-59 [0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6], // 1e-58 [0xF245825A5A445275, 0xC8DE047564D20A8B], // 1e-57 [0xEED6E2F0F0D56712, 0xFB158592BE068D2E], // 1e-56 [0x55464DD69685606B, 0x9CED737BB6C4183D], // 1e-55 [0xAA97E14C3C26B886, 0xC428D05AA4751E4C], // 1e-54 [0xD53DD99F4B3066A8, 0xF53304714D9265DF], // 1e-53 [0xE546A8038EFE4029, 0x993FE2C6D07B7FAB], // 1e-52 [0xDE98520472BDD033, 0xBF8FDB78849A5F96], // 1e-51 [0x963E66858F6D4440, 0xEF73D256A5C0F77C], // 1e-50 [0xDDE7001379A44AA8, 0x95A8637627989AAD], // 1e-49 [0x5560C018580D5D52, 0xBB127C53B17EC159], // 1e-48 [0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF], // 1e-47 [0xCAB3961304CA70E8, 0x9226712162AB070D], // 1e-46 [0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1], // 1e-45 [0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05], // 1e-44 [0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3], // 1e-43 [0x55F038B237591ED3, 0xB267ED1940F1C61C], // 1e-42 [0x6B6C46DEC52F6688, 0xDF01E85F912E37A3], // 1e-41 [0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6], // 1e-40 [0xABEC975E0A0D081A, 0xAE397D8AA96C1B77], // 1e-39 [0x96E7BD358C904A21, 0xD9C7DCED53C72255], // 1e-38 [0x7E50D64177DA2E54, 0x881CEA14545C7575], // 1e-37 [0xDDE50BD1D5D0B9E9, 0xAA242499697392D2], // 1e-36 [0x955E4EC64B44E864, 0xD4AD2DBFC3D07787], // 1e-35 [0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4], // 1e-34 [0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61], // 1e-33 [0x67DE18EDA5814AF2, 0xCFB11EAD453994BA], // 1e-32 [0x80EACF948770CED7, 0x81CEB32C4B43FCF4], // 1e-31 [0xA1258379A94D028D, 0xA2425FF75E14FC31], // 1e-30 [0x096EE45813A04330, 0xCAD2F7F5359A3B3E], // 1e-29 [0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D], // 1e-28 [0x775EA264CF55347D, 0x9E74D1B791E07E48], // 1e-27 [0x95364AFE032A819D, 0xC612062576589DDA], // 1e-26 [0x3A83DDBD83F52204, 0xF79687AED3EEC551], // 1e-25 [0xC4926A9672793542, 0x9ABE14CD44753B52], // 1e-24 [0x75B7053C0F178293, 0xC16D9A0095928A27], // 1e-23 [0x5324C68B12DD6338, 0xF1C90080BAF72CB1], // 1e-22 [0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE], // 1e-21 [0x88F4BB1CA6BCF584, 0xBCE5086492111AEA], // 1e-20 [0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5], // 1e-19 [0x3AFF322E62439FCF, 0x9392EE8E921D5D07], // 1e-18 [0x09BEFEB9FAD487C2, 0xB877AA3236A4B449], // 1e-17 [0x4C2EBE687989A9B3, 0xE69594BEC44DE15B], // 1e-16 [0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9], // 1e-15 [0x538484C19EF38C94, 0xB424DC35095CD80F], // 1e-14 [0x2865A5F206B06FB9, 0xE12E13424BB40E13], // 1e-13 [0xF93F87B7442E45D3, 0x8CBCCC096F5088CB], // 1e-12 [0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE], // 1e-11 [0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE], // 1e-10 [0x31680A88F8953030, 0x89705F4136B4A597], // 1e-9 [0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC], // 1e-8 [0x3D32907604691B4C, 0xD6BF94D5E57A42BC], // 1e-7 [0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5], // 1e-6 [0x0FCF80DC33721D53, 0xA7C5AC471B478423], // 1e-5 [0xD3C36113404EA4A8, 0xD1B71758E219652B], // 1e-4 [0x645A1CAC083126E9, 0x83126E978D4FDF3B], // 1e-3 [0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A], // 1e-2 [0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC], // 1e-1 [0x0000000000000000, 0x8000000000000000], // 1e0 [0x0000000000000000, 0xA000000000000000], // 1e1 [0x0000000000000000, 0xC800000000000000], // 1e2 [0x0000000000000000, 0xFA00000000000000], // 1e3 [0x0000000000000000, 0x9C40000000000000], // 1e4 [0x0000000000000000, 0xC350000000000000], // 1e5 [0x0000000000000000, 0xF424000000000000], // 1e6 [0x0000000000000000, 0x9896800000000000], // 1e7 [0x0000000000000000, 0xBEBC200000000000], // 1e8 [0x0000000000000000, 0xEE6B280000000000], // 1e9 [0x0000000000000000, 0x9502F90000000000], // 1e10 [0x0000000000000000, 0xBA43B74000000000], // 1e11 [0x0000000000000000, 0xE8D4A51000000000], // 1e12 [0x0000000000000000, 0x9184E72A00000000], // 1e13 [0x0000000000000000, 0xB5E620F480000000], // 1e14 [0x0000000000000000, 0xE35FA931A0000000], // 1e15 [0x0000000000000000, 0x8E1BC9BF04000000], // 1e16 [0x0000000000000000, 0xB1A2BC2EC5000000], // 1e17 [0x0000000000000000, 0xDE0B6B3A76400000], // 1e18 [0x0000000000000000, 0x8AC7230489E80000], // 1e19 [0x0000000000000000, 0xAD78EBC5AC620000], // 1e20 [0x0000000000000000, 0xD8D726B7177A8000], // 1e21 [0x0000000000000000, 0x878678326EAC9000], // 1e22 [0x0000000000000000, 0xA968163F0A57B400], // 1e23 [0x0000000000000000, 0xD3C21BCECCEDA100], // 1e24 [0x0000000000000000, 0x84595161401484A0], // 1e25 [0x0000000000000000, 0xA56FA5B99019A5C8], // 1e26 [0x0000000000000000, 0xCECB8F27F4200F3A], // 1e27 [0x4000000000000000, 0x813F3978F8940984], // 1e28 [0x5000000000000000, 0xA18F07D736B90BE5], // 1e29 [0xA400000000000000, 0xC9F2C9CD04674EDE], // 1e30 [0x4D00000000000000, 0xFC6F7C4045812296], // 1e31 [0xF020000000000000, 0x9DC5ADA82B70B59D], // 1e32 [0x6C28000000000000, 0xC5371912364CE305], // 1e33 [0xC732000000000000, 0xF684DF56C3E01BC6], // 1e34 [0x3C7F400000000000, 0x9A130B963A6C115C], // 1e35 [0x4B9F100000000000, 0xC097CE7BC90715B3], // 1e36 [0x1E86D40000000000, 0xF0BDC21ABB48DB20], // 1e37 [0x1314448000000000, 0x96769950B50D88F4], // 1e38 [0x17D955A000000000, 0xBC143FA4E250EB31], // 1e39 [0x5DCFAB0800000000, 0xEB194F8E1AE525FD], // 1e40 [0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE], // 1e41 [0xF14A3D9E40000000, 0xB7ABC627050305AD], // 1e42 [0x6D9CCD05D0000000, 0xE596B7B0C643C719], // 1e43 [0xE4820023A2000000, 0x8F7E32CE7BEA5C6F], // 1e44 [0xDDA2802C8A800000, 0xB35DBF821AE4F38B], // 1e45 [0xD50B2037AD200000, 0xE0352F62A19E306E], // 1e46 [0x4526F422CC340000, 0x8C213D9DA502DE45], // 1e47 [0x9670B12B7F410000, 0xAF298D050E4395D6], // 1e48 [0x3C0CDD765F114000, 0xDAF3F04651D47B4C], // 1e49 [0xA5880A69FB6AC800, 0x88D8762BF324CD0F], // 1e50 [0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053], // 1e51 [0x72A4904598D6D880, 0xD5D238A4ABE98068], // 1e52 [0x47A6DA2B7F864750, 0x85A36366EB71F041], // 1e53 [0x999090B65F67D924, 0xA70C3C40A64E6C51], // 1e54 [0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765], // 1e55 [0xBFF8F10E7A8921A4, 0x82818F1281ED449F], // 1e56 [0xAFF72D52192B6A0D, 0xA321F2D7226895C7], // 1e57 [0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39], // 1e58 [0x02F236D04753D5B4, 0xFEE50B7025C36A08], // 1e59 [0x01D762422C946590, 0x9F4F2726179A2245], // 1e60 [0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6], // 1e61 [0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B], // 1e62 [0x63CC55F49F88EB2F, 0x9B934C3B330C8577], // 1e63 [0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5], // 1e64 [0x8BEF464E3945EF7A, 0xF316271C7FC3908A], // 1e65 [0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56], // 1e66 [0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC], // 1e67 [0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27], // 1e68 [0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8], // 1e69 [0xB3E2FD538E122B44, 0xB975D6B6EE39E436], // 1e70 [0x60DBBCA87196B616, 0xE7D34C64A9C85D44], // 1e71 [0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A], // 1e72 [0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD], // 1e73 [0xC696963C7EED2DD1, 0xE264589A4DCDAB14], // 1e74 [0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC], // 1e75 [0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8], // 1e76 [0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912], // 1e77 [0x6E3569326C784337, 0x8A2DBF142DFCC7AB], // 1e78 [0x49C2C37F07965404, 0xACB92ED9397BF996], // 1e79 [0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB], // 1e80 [0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD], // 1e81 [0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC], // 1e82 [0xF50A3FA490C30190, 0xD2D80DB02AABD62B], // 1e83 [0x792667C6DA79E0FA, 0x83C7088E1AAB65DB], // 1e84 [0x577001B891185938, 0xA4B8CAB1A1563F52], // 1e85 [0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26], // 1e86 [0x544F8158315B05B4, 0x80B05E5AC60B6178], // 1e87 [0x696361AE3DB1C721, 0xA0DC75F1778E39D6], // 1e88 [0x03BC3A19CD1E38E9, 0xC913936DD571C84C], // 1e89 [0x04AB48A04065C723, 0xFB5878494ACE3A5F], // 1e90 [0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B], // 1e91 [0x3BA5D0BD324F8394, 0xC45D1DF942711D9A], // 1e92 [0xCA8F44EC7EE36479, 0xF5746577930D6500], // 1e93 [0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20], // 1e94 [0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8], // 1e95 [0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2], // 1e96 [0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5], // 1e97 [0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F], // 1e98 [0xF52D09D71A3293BD, 0xEA1575143CF97226], // 1e99 [0x593C2626705F9C56, 0x924D692CA61BE758], // 1e100 [0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E], // 1e101 [0x0B6DFB9C0F956447, 0xE498F455C38B997A], // 1e102 [0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC], // 1e103 [0x58EDEC91EC2CB657, 0xB2977EE300C50FE7], // 1e104 [0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1], // 1e105 [0xBD79E0D20082EE74, 0x8B865B215899F46C], // 1e106 [0xECD8590680A3AA11, 0xAE67F1E9AEC07187], // 1e107 [0xE80E6F4820CC9495, 0xDA01EE641A708DE9], // 1e108 [0x3109058D147FDCDD, 0x884134FE908658B2], // 1e109 [0xBD4B46F0599FD415, 0xAA51823E34A7EEDE], // 1e110 [0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96], // 1e111 [0x03E2CF6BC604DDB0, 0x850FADC09923329E], // 1e112 [0x84DB8346B786151C, 0xA6539930BF6BFF45], // 1e113 [0xE612641865679A63, 0xCFE87F7CEF46FF16], // 1e114 [0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E], // 1e115 [0xE3BE5E330F38F09D, 0xA26DA3999AEF7749], // 1e116 [0x5CADF5BFD3072CC5, 0xCB090C8001AB551C], // 1e117 [0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63], // 1e118 [0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E], // 1e119 [0xB281E1FD541501B8, 0xC646D63501A1511D], // 1e120 [0x1F225A7CA91A4226, 0xF7D88BC24209A565], // 1e121 [0x3375788DE9B06958, 0x9AE757596946075F], // 1e122 [0x0052D6B1641C83AE, 0xC1A12D2FC3978937], // 1e123 [0xC0678C5DBD23A49A, 0xF209787BB47D6B84], // 1e124 [0xF840B7BA963646E0, 0x9745EB4D50CE6332], // 1e125 [0xB650E5A93BC3D898, 0xBD176620A501FBFF], // 1e126 [0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF], // 1e127 [0xC66F336C36B10137, 0x93BA47C980E98CDF], // 1e128 [0xB80B0047445D4184, 0xB8A8D9BBE123F017], // 1e129 [0xA60DC059157491E5, 0xE6D3102AD96CEC1D], // 1e130 [0x87C89837AD68DB2F, 0x9043EA1AC7E41392], // 1e131 [0x29BABE4598C311FB, 0xB454E4A179DD1877], // 1e132 [0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94], // 1e133 [0x1899E4A65F58660C, 0x8CE2529E2734BB1D], // 1e134 [0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4], // 1e135 [0x76707543F4FA1F73, 0xDC21A1171D42645D], // 1e136 [0x6A06494A791C53A8, 0x899504AE72497EBA], // 1e137 [0x0487DB9D17636892, 0xABFA45DA0EDBDE69], // 1e138 [0x45A9D2845D3C42B6, 0xD6F8D7509292D603], // 1e139 [0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2], // 1e140 [0x8E6CAC7768D7141E, 0xA7F26836F282B732], // 1e141 [0x3207D795430CD926, 0xD1EF0244AF2364FF], // 1e142 [0x7F44E6BD49E807B8, 0x8335616AED761F1F], // 1e143 [0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7], // 1e144 [0x36DBA887C37A8C0F, 0xCD036837130890A1], // 1e145 [0xC2494954DA2C9789, 0x802221226BE55A64], // 1e146 [0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD], // 1e147 [0x6F92829494E5ACC7, 0xC83553C5C8965D3D], // 1e148 [0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C], // 1e149 [0xFF2A760414536EFB, 0x9C69A97284B578D7], // 1e150 [0xFEF5138519684ABA, 0xC38413CF25E2D70D], // 1e151 [0x7EB258665FC25D69, 0xF46518C2EF5B8CD1], // 1e152 [0xEF2F773FFBD97A61, 0x98BF2F79D5993802], // 1e153 [0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603], // 1e154 [0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784], // 1e155 [0xDD945A747BF26183, 0x952AB45CFA97A0B2], // 1e156 [0x94F971119AEEF9E4, 0xBA756174393D88DF], // 1e157 [0x7A37CD5601AAB85D, 0xE912B9D1478CEB17], // 1e158 [0xAC62E055C10AB33A, 0x91ABB422CCB812EE], // 1e159 [0x577B986B314D6009, 0xB616A12B7FE617AA], // 1e160 [0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94], // 1e161 [0x14588F13BE847307, 0x8E41ADE9FBEBC27D], // 1e162 [0x596EB2D8AE258FC8, 0xB1D219647AE6B31C], // 1e163 [0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3], // 1e164 [0x25DE7BB9480D5854, 0x8AEC23D680043BEE], // 1e165 [0xAF561AA79A10AE6A, 0xADA72CCC20054AE9], // 1e166 [0x1B2BA1518094DA04, 0xD910F7FF28069DA4], // 1e167 [0x90FB44D2F05D0842, 0x87AA9AFF79042286], // 1e168 [0x353A1607AC744A53, 0xA99541BF57452B28], // 1e169 [0x42889B8997915CE8, 0xD3FA922F2D1675F2], // 1e170 [0x69956135FEBADA11, 0x847C9B5D7C2E09B7], // 1e171 [0x43FAB9837E699095, 0xA59BC234DB398C25], // 1e172 [0x94F967E45E03F4BB, 0xCF02B2C21207EF2E], // 1e173 [0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D], // 1e174 [0x6462D92A69731732, 0xA1BA1BA79E1632DC], // 1e175 [0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93], // 1e176 [0x5CDA735244C3D43E, 0xFCB2CB35E702AF78], // 1e177 [0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB], // 1e178 [0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916], // 1e179 [0x8AAD549E57273D45, 0xF6C69A72A3989F5B], // 1e180 [0x36AC54E2F678864B, 0x9A3C2087A63F6399], // 1e181 [0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F], // 1e182 [0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F], // 1e183 [0x9F644AE5A4B1B325, 0x969EB7C47859E743], // 1e184 [0x873D5D9F0DDE1FEE, 0xBC4665B596706114], // 1e185 [0xA90CB506D155A7EA, 0xEB57FF22FC0C7959], // 1e186 [0x09A7F12442D588F2, 0x9316FF75DD87CBD8], // 1e187 [0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE], // 1e188 [0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81], // 1e189 [0xF96E017D694487BC, 0x8FA475791A569D10], // 1e190 [0x37C981DCC395A9AC, 0xB38D92D760EC4455], // 1e191 [0x85BBE253F47B1417, 0xE070F78D3927556A], // 1e192 [0x93956D7478CCEC8E, 0x8C469AB843B89562], // 1e193 [0x387AC8D1970027B2, 0xAF58416654A6BABB], // 1e194 [0x06997B05FCC0319E, 0xDB2E51BFE9D0696A], // 1e195 [0x441FECE3BDF81F03, 0x88FCF317F22241E2], // 1e196 [0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A], // 1e197 [0x8A71E223D8D3B074, 0xD60B3BD56A5586F1], // 1e198 [0xF6872D5667844E49, 0x85C7056562757456], // 1e199 [0xB428F8AC016561DB, 0xA738C6BEBB12D16C], // 1e200 [0xE13336D701BEBA52, 0xD106F86E69D785C7], // 1e201 [0xECC0024661173473, 0x82A45B450226B39C], // 1e202 [0x27F002D7F95D0190, 0xA34D721642B06084], // 1e203 [0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5], // 1e204 [0x7E67047175A15271, 0xFF290242C83396CE], // 1e205 [0x0F0062C6E984D386, 0x9F79A169BD203E41], // 1e206 [0x52C07B78A3E60868, 0xC75809C42C684DD1], // 1e207 [0xA7709A56CCDF8A82, 0xF92E0C3537826145], // 1e208 [0x88A66076400BB691, 0x9BBCC7A142B17CCB], // 1e209 [0x6ACFF893D00EA435, 0xC2ABF989935DDBFE], // 1e210 [0x0583F6B8C4124D43, 0xF356F7EBF83552FE], // 1e211 [0xC3727A337A8B704A, 0x98165AF37B2153DE], // 1e212 [0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6], // 1e213 [0x1162DEF06F79DF73, 0xEDA2EE1C7064130C], // 1e214 [0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7], // 1e215 [0x6D953E2BD7173692, 0xB9A74A0637CE2EE1], // 1e216 [0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99], // 1e217 [0x1D9C9892400A22A2, 0x910AB1D4DB9914A0], // 1e218 [0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8], // 1e219 [0x2E44AE64840FD61D, 0xE2A0B5DC971F303A], // 1e220 [0x5CEAECFED289E5D2, 0x8DA471A9DE737E24], // 1e221 [0x7425A83E872C5F47, 0xB10D8E1456105DAD], // 1e222 [0xD12F124E28F77719, 0xDD50F1996B947518], // 1e223 [0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F], // 1e224 [0x636CC64D1001550B, 0xACE73CBFDC0BFB7B], // 1e225 [0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A], // 1e226 [0x65ACFAEC34810A71, 0x8714A775E3E95C78], // 1e227 [0x7F1839A741A14D0D, 0xA8D9D1535CE3B396], // 1e228 [0x1EDE48111209A050, 0xD31045A8341CA07C], // 1e229 [0x934AED0AAB460432, 0x83EA2B892091E44D], // 1e230 [0xF81DA84D5617853F, 0xA4E4B66B68B65D60], // 1e231 [0x36251260AB9D668E, 0xCE1DE40642E3F4B9], // 1e232 [0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3], // 1e233 [0xB24CF65B8612F81F, 0xA1075A24E4421730], // 1e234 [0xDEE033F26797B627, 0xC94930AE1D529CFC], // 1e235 [0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C], // 1e236 [0x8E1F289560EE864E, 0x9D412E0806E88AA5], // 1e237 [0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E], // 1e238 [0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2], // 1e239 [0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765], // 1e240 [0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F], // 1e241 [0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E], // 1e242 [0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9], // 1e243 [0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F], // 1e244 [0x84C86189216DC5ED, 0xEA53DF5FD18D5513], // 1e245 [0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C], // 1e246 [0x3FBC8C33221DC2A1, 0xB7118682DBB66A77], // 1e247 [0x0FABAF3FEAA5334A, 0xE4D5E82392A40515], // 1e248 [0x29CB4D87F2A7400E, 0x8F05B1163BA6832D], // 1e249 [0x743E20E9EF511012, 0xB2C71D5BCA9023F8], // 1e250 [0x914DA9246B255416, 0xDF78E4B2BD342CF6], // 1e251 [0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A], // 1e252 [0xA184AC2473B529B1, 0xAE9672ABA3D0C320], // 1e253 [0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8], // 1e254 [0x7E2FA67C7A658892, 0x8865899617FB1871], // 1e255 [0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D], // 1e256 [0x552A74227F3EA565, 0xD51EA6FA85785631], // 1e257 [0xD53A88958F87275F, 0x8533285C936B35DE], // 1e258 [0x8A892ABAF368F137, 0xA67FF273B8460356], // 1e259 [0x2D2B7569B0432D85, 0xD01FEF10A657842C], // 1e260 [0x9C3B29620E29FC73, 0x8213F56A67F6B29B], // 1e261 [0x8349F3BA91B47B8F, 0xA298F2C501F45F42], // 1e262 [0x241C70A936219A73, 0xCB3F2F7642717713], // 1e263 [0xED238CD383AA0110, 0xFE0EFB53D30DD4D7], // 1e264 [0xF4363804324A40AA, 0x9EC95D1463E8A506], // 1e265 [0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48], // 1e266 [0xDD94B7868E94050A, 0xF81AA16FDC1B81DA], // 1e267 [0xCA7CF2B4191C8326, 0x9B10A4E5E9913128], // 1e268 [0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72], // 1e269 [0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF], // 1e270 [0xD5BE0503E085D813, 0x976E41088617CA01], // 1e271 [0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82], // 1e272 [0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2], // 1e273 [0xCABB90E5C942B503, 0x93E1AB8252F33B45], // 1e274 [0x3D6A751F3B936243, 0xB8DA1662E7B00A17], // 1e275 [0x0CC512670A783AD4, 0xE7109BFBA19C0C9D], // 1e276 [0x27FB2B80668B24C5, 0x906A617D450187E2], // 1e277 [0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA], // 1e278 [0x5E7873F8A0396973, 0xE1A63853BBD26451], // 1e279 [0xDB0B487B6423E1E8, 0x8D07E33455637EB2], // 1e280 [0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F], // 1e281 [0x7641A140CC7810FB, 0xDC5C5301C56B75F7], // 1e282 [0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA], // 1e283 [0x546345FA9FBDCD44, 0xAC2820D9623BF429], // 1e284 [0xA97C177947AD4095, 0xD732290FBACAF133], // 1e285 [0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0], // 1e286 [0x5C68F256BFFF5A74, 0xA81F301449EE8C70], // 1e287 [0x73832EEC6FFF3111, 0xD226FC195C6A2F8C], // 1e288 ]; hare-0.24.2/strconv/stoi.ha000066400000000000000000000061001464473310100155040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Converts a string to an i64. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by an i64. export fn stoi64(s: str, base: base = base::DEC) (i64 | invalid | overflow) = { let (sign, u) = parseint(s, base)?; // Two's complement: I64_MIN = -I64_MAX - 1 let max = if (sign) types::I64_MAX: u64 + 1 else types::I64_MAX: u64; if (u > max) { return overflow; }; return u: i64 * (if (sign) -1 else 1); }; fn stoiminmax( s: str, base: base, min: i64, max: i64, ) (i64 | invalid | overflow) = { const n = stoi64(s, base)?; if (n < min || n > max) { return overflow; }; return n; }; // Converts a string to an i32. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by an i32. export fn stoi32(s: str, base: base = base::DEC) (i32 | invalid | overflow) = stoiminmax(s, base, types::I32_MIN, types::I32_MAX)?: i32; // Converts a string to an i16. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by an i16. export fn stoi16(s: str, base: base = base::DEC) (i16 | invalid | overflow) = stoiminmax(s, base, types::I16_MIN, types::I16_MAX)?: i16; // Converts a string to an i8. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by an i8. export fn stoi8(s: str, base: base = base::DEC) (i8 | invalid | overflow) = stoiminmax(s, base, types::I8_MIN, types::I8_MAX)?: i8; // Converts a string to an int. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by an int. export fn stoi(s: str, base: base = base::DEC) (int | invalid | overflow) = stoiminmax(s, base, types::INT_MIN, types::INT_MAX)?: int; @test fn stoi() void = { assert(stoi64("") as invalid == 0); assert(stoi64("abc") as invalid == 0); assert(stoi64("1a") as invalid == 1); assert(stoi64("+") as invalid == 1); assert(stoi64("-+") as invalid == 1); assert(stoi64("-z") as invalid == 1); assert(stoi64("9223372036854775808") is overflow); assert(stoi64("-9223372036854775809") is overflow); assert(stoi64("0") as i64 == 0); assert(stoi64("1") as i64 == 1); assert(stoi64("+1") as i64 == 1); assert(stoi64("-1") as i64 == -1); assert(stoi64("9223372036854775807") as i64 == types::I64_MAX); assert(stoi64("-9223372036854775808") as i64 == types::I64_MIN); assert(stoi32("2147483648") is overflow); assert(stoi32("-2147483649") is overflow); assert(stoi32("2147483647") as i32 == 2147483647); assert(stoi32("-2147483648") as i32 == -2147483648); }; @test fn stoi_bases() void = { assert(stoi64("-7f", 16) as i64 == -0x7f); assert(stoi64("7F", 16) as i64 == 0x7f); assert(stoi64("37", 8) as i64 == 0o37); assert(stoi64("-110101", 2) as i64 == -0b110101); }; hare-0.24.2/strconv/stou.ha000066400000000000000000000077271464473310100155400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use strings; use types; fn rune_to_integer(r: rune) (u64 | void) = { if (ascii::isdigit(r)) return (r: u32 - '0'): u64 else if (ascii::isalpha(r) && ascii::islower(r)) return (r: u32 - 'a'): u64 + 10 else if (ascii::isalpha(r) && ascii::isupper(r)) return (r: u32 - 'A'): u64 + 10; }; fn parseint(s: str, base: base) ((bool, u64) | invalid | overflow) = { if (base == base::DEFAULT) { base = base::DEC; } else if (base == base::HEX_LOWER) { base = base::HEX; }; assert(base == 2 || base == 8 || base == 10 || base == 16); if (len(s) == 0) { return 0: invalid; }; let buf = strings::toutf8(s); let i = 0z; let sign = buf[i] == '-'; if (sign || buf[i] == '+') { i += 1; }; // Require at least one digit. if (i == len(buf)) { return i: invalid; }; let n = 0u64; for (i < len(buf); i += 1) { const digit = match (rune_to_integer(buf[i]: rune)) { case void => return i: invalid; case let d: u64 => yield d; }; if (digit >= base) { return i: invalid; }; const old = n; n *= base; n += digit; if (n < old) { return overflow; }; }; return (sign, n); }; // Converts a string to a u64. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by a u64. export fn stou64(s: str, base: base = base::DEC) (u64 | invalid | overflow) = { let (sign, u) = parseint(s, base)?; if (sign) { return overflow; }; return u; }; fn stoumax(s: str, base: base, max: u64) (u64 | invalid | overflow) = { const n = stou64(s, base)?; if (n > max) { return overflow; }; return n; }; // Converts a string to a u32. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by a u32. export fn stou32(s: str, base: base = base::DEC) (u32 | invalid | overflow) = stoumax(s, base, types::U32_MAX)?: u32; // Converts a string to a u16. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by a u16. export fn stou16(s: str, base: base = base::DEC) (u16 | invalid | overflow) = stoumax(s, base, types::U16_MAX)?: u16; // Converts a string to a u8. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by a u8. export fn stou8(s: str, base: base = base::DEC) (u8 | invalid | overflow) = stoumax(s, base, types::U8_MAX)?: u8; // Converts a string to a uint in the given base. Returns [[invalid]] if the // string is empty or contains invalid characters. Returns [[overflow]] if the // number is too large to be represented by a uint. export fn stou(s: str, base: base = base::DEC) (uint | invalid | overflow) = stoumax(s, base, types::UINT_MAX)?: uint; // Converts a string to a size. Returns [[invalid]] if the string is empty or // contains invalid characters. Returns [[overflow]] if the number is too large // to be represented by a size. export fn stoz(s: str, base: base = base::DEC) (size | invalid | overflow) = stoumax(s, base, types::SIZE_MAX)?: size; @test fn stou() void = { assert(stou64("") as invalid == 0); assert(stou64("+") as invalid == 1); assert(stou64("+a") as invalid == 1); assert(stou64("abc") as invalid == 0); assert(stou64("1a") as invalid == 1); assert(stou64("18446744073709551616") is overflow); assert(stou64("184467440737095516150") is overflow); assert(stou64("-1") is overflow); assert(stou64("0") as u64 == 0); assert(stou64("1") as u64 == 1); assert(stou64("18446744073709551615") as u64 == 18446744073709551615); }; @test fn stou_bases() void = { assert(stou64("f", base::HEX_LOWER) as u64 == 0xf); assert(stou64("7f", 16) as u64 == 0x7f); assert(stou64("7F", 16) as u64 == 0x7f); assert(stou64("37", 8) as u64 == 0o37); assert(stou64("110101", 2) as u64 == 0b110101); }; hare-0.24.2/strconv/types.ha000066400000000000000000000021331464473310100156740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Indicates that the input string doesn't have the requested number format // (integer or float). Contains the index of the first invalid rune. export type invalid = !size; // Indicates that the input member can't be represented by the requested data // type. export type overflow = !void; // Any error which may be returned from a strconv function. export type error = !(invalid | overflow); // The valid numeric bases for numeric conversions. export type base = enum uint { // Default base - decimal DEFAULT = 0, // Base 2, binary BIN = 2, // Base 8, octal OCT = 8, // Base 10, decimal DEC = 10, // Base 16, UPPERCASE hexadecimal HEX_UPPER = 16, // Alias for HEX_UPPER HEX = 16, // Base 16, lowercase hexadecimal HEX_LOWER = 17, }; // Converts an strconv [[error]] into a user-friendly string. export fn strerror(err: error) str = { match (err) { case invalid => return "Input string doesn't have the requested number format"; case overflow => return "Input number doesn't fit into requested type"; }; }; hare-0.24.2/strconv/utos.ha000066400000000000000000000064511464473310100155310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use types; // Converts a u64 to a string. The return value is statically allocated and will // be overwritten on subsequent calls; see [[strings::dup]] to duplicate the // result. export fn u64tos(u: u64, b: base = base::DEC) const str = { static assert(types::U64_MAX == 18446744073709551615); static let buf: [64]u8 = [0...]; // 64 binary digits static const lut_upper = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', ], lut_lower = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', ]; const lut = if (b != base::HEX_LOWER) &lut_upper else { b = base::HEX_UPPER; yield &lut_lower; }; const b: uint = if (b == base::DEFAULT) base::DEC else b; let s = types::string { data = &buf, ... }; if (u == 0) { buf[s.length] = '0'; s.length += 1z; }; for (u > 0u64) { buf[s.length] = lut[u % b: u64]: u8; s.length += 1; u /= b; }; bytes::reverse(buf[..s.length]); return *(&s: *str); }; // Converts a u32 to a string. The return value is statically allocated and will // be overwritten on subsequent calls; see [[strings::dup]] to duplicate the // result. export fn u32tos(u: u32, b: base = base::DEC) const str = u64tos(u, b); // Converts a u16 to a string. The return value is statically allocated and will // be overwritten on subsequent calls; see [[strings::dup]] to duplicate the // result. export fn u16tos(u: u16, b: base = base::DEC) const str = u64tos(u, b); // Converts a u8 to a string. The return value is statically allocated and will // be overwritten on subsequent calls; see [[strings::dup]] to duplicate the // result. export fn u8tos(u: u8, b: base = base::DEC) const str = u64tos(u, b); // Converts a uint to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn utos(u: uint, b: base = base::DEC) const str = u64tos(u, b); // Converts a size to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn ztos(u: size, b: base = base::DEC) const str = u64tos(u, b); // Converts a uintptr to a string. The return value is statically allocated and // will be overwritten on subsequent calls; see [[strings::dup]] to duplicate // the result. export fn uptrtos(uptr: uintptr, b: base = base::DEC) const str = u64tos(uptr: u64, b); @test fn utos_bases() void = { assert("11010" == u64tos(0b11010, base::BIN)); assert("1234567" == u64tos(0o1234567, base::OCT)); assert("123456789" == u64tos(123456789, base::DEC)); assert("123456789ABCDEF" == u64tos(0x123456789ABCDEF, base::HEX)); assert("123456789ABCDEF" == u64tos(0x123456789ABCDEF, base::HEX_UPPER)); assert("123456789abcdef" == u64tos(0x123456789ABCDEF, base::HEX_LOWER)); assert("1111111111111111111111111111111111111111111111111111111111111111" == u64tos(types::U64_MAX, base::BIN)); }; @test fn utos() void = { const samples: [_]u64 = [ 1234, 4321, types::U64_MIN, types::U64_MAX, ]; const expected = [ "1234", "4321", "0", "18446744073709551615", ]; for (let i = 0z; i < len(samples); i += 1) { const s = u64tos(samples[i]); assert(s == expected[i]); }; }; hare-0.24.2/strings/000077500000000000000000000000001464473310100142125ustar00rootroot00000000000000hare-0.24.2/strings/README000066400000000000000000000001151464473310100150670ustar00rootroot00000000000000The strings module provides support functions for working with Hare strings. hare-0.24.2/strings/compare.ha000066400000000000000000000013741464473310100161570ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use sort::cmp; // Compares two strings by their Unicode codepoint sort order. Zero is returned // if the strings are equal, a negative value if a is less than b, or a positive // value if a is greater than b. // // If you only want to check two strings for equality, then this function isn't // necessary; you can compare the strings directly with ==. export fn compare(a: str, b: str) int = { return cmp::strs(&a, &b); }; @test fn compare() void = { assert(compare("ABC", "ABC") == 0); assert(compare("ABC", "AB") > 0); assert(compare("AB", "ABC") < 0); assert(compare("BCD", "ABC") > 0); assert(compare("ABC", "こんにちは") < 0); assert(compare("ABC", "abc") < 0); }; hare-0.24.2/strings/concat.ha000066400000000000000000000031621464473310100157750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Concatenates multiple strings. The caller must free the return value. export fn concat(strs: str...) str = { let z = 0z; for (let s .. strs) { z += len(s); }; let new: []u8 = alloc([], z); for (let s .. strs) { static append(new, toutf8(s)...); }; return fromutf8_unsafe(new); }; @test fn concat() void = { let s = concat("hello ", "world"); defer free(s); assert(s == "hello world"); let s = concat("hello", " ", "world"); defer free(s); assert(s == "hello world"); let s = concat("hello", "", "world"); defer free(s); assert(s == "helloworld"); let s = concat("", ""); defer free(s); assert(s == ""); let s = concat(); defer free(s); assert(s == ""); let s = concat("hello"); defer free(s); assert(s == "hello"); }; // Joins several strings together by placing a delimiter between them. The // caller must free the return value. export fn join(delim: str, strs: str...) str = { let z = 0z; for (let i = 0z; i < len(strs); i += 1) { z += len(strs[i]); if (i + 1 < len(strs)) { z += len(delim); }; }; let new: []u8 = alloc([], z); for (let i = 0z; i < len(strs); i += 1) { static append(new, toutf8(strs[i])...); if (i + 1 < len(strs)) { static append(new, toutf8(delim)...); }; }; return fromutf8_unsafe(new); }; @test fn join() void = { let s = join(".", "a", "b", "c"); defer free(s); assert(s == "a.b.c"); let s = join("", "a", "b", "c"); defer free(s); assert(s == "abc"); let s = join("."); defer free(s); assert(s == ""); let s = join(".", "a"); defer free(s); assert(s == "a"); }; hare-0.24.2/strings/contains.ha000066400000000000000000000021411464473310100163400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; // Returns true if a string contains a rune or a sub-string, multiple of which // can be given. export fn contains(haystack: str, needles: (str | rune)...) bool = { for (let needle .. needles) { const matched = match (needle) { case let s: str => yield bytes::contains(toutf8(haystack), toutf8(s)); case let r: rune => yield bytes::contains(toutf8(haystack), utf8::encoderune(r)); }; if (matched) { return true; }; }; return false; }; @test fn contains() void = { assert(contains("hello world", "hello")); assert(contains("hello world", 'h')); assert(!contains("hello world", 'x')); assert(contains("hello world", "world")); assert(contains("hello world", "")); assert(!contains("hello world", "foobar")); assert(contains("hello world", "foobar", "hello", "bar")); assert(!contains("hello world", "foobar", "foo", "bar")); assert(contains("hello world", 'h', "foo", "bar")); assert(!contains("hello world", 'x', "foo", "bar")); assert(!contains("hello world")); }; hare-0.24.2/strings/dup.ha000066400000000000000000000027521464473310100153220ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Duplicates a string. Aborts on allocation failure. export fn dup(s: const str) str = { const in = &s: *types::string; const id = match (in.data) { case null => return ""; // Empty string case let b: *[*]u8 => yield b; }; let buf: []u8 = alloc(id[..in.length], in.length); let out = types::string { data = buf: *[*]u8, length = in.length, capacity = in.length, }; return *(&out: *str); }; // Creates a copy of a []str slice with all the strings duplicated. The result // must be freed using [[freeall]]. export fn dupall(strs: []str) []str = { let newsl: []str = alloc([], len(strs)); for (let s .. strs) { static append(newsl, dup(s)); }; return newsl; }; // Frees all the strings in a slice and the slice itself. Inverse of [[dupall]]. export fn freeall(s: []str) void = { for (let i = 0z; i < len(s); i += 1) { free(s[i]); }; free(s); }; @test fn dup() void = { let s = dup(""); defer free(s); assert(s == ""); let s = dup("hello"); defer free(s); assert(s == "hello"); }; @test fn dupall() void = { const payload: []str = []; let s = dupall(payload); defer freeall(s); assert(len(s) == len(payload)); for (let i = 0z; i < len(s); i += 1) { assert(s[i] == payload[i]); }; const payload: []str = ["a", "aaa"]; let s = dupall(payload); defer freeall(s); assert(len(s) == len(payload)); for (let i = 0z; i < len(s); i += 1) { assert(s[i] == payload[i]); }; }; hare-0.24.2/strings/index.ha000066400000000000000000000106631464473310100156410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; // Returns the index of the first occurance of 'needle' in the 'haystack', or // void if not present. The index returned is the rune-wise index, not the // byte-wise index. export fn index(haystack: str, needle: (str | rune)) (size | void) = { match (needle) { case let r: rune => return index_rune(haystack, r); case let s: str => return index_string(haystack, s); }; }; // Returns the index of the last occurance of 'needle' in the 'haystack', or // void if not present. The index returned is the rune-wise index, not the // byte-wise index. export fn rindex(haystack: str, needle: (str | rune)) (size | void) = { match (needle) { case let r: rune => return rindex_rune(haystack, r); case let s: str => return rindex_string(haystack, s); }; }; fn index_rune(s: str, r: rune) (size | void) = { let iter = iter(s); for (let i = 0z; true; i += 1) { match (next(&iter)) { case let n: rune => if (r == n) { return i; }; case done => break; }; }; }; fn rindex_rune(s: str, r: rune) (size | void) = { let iter = riter(s); for (let i = len(s) - 1; true; i -= 1) { match (next(&iter)) { case let n: rune => if (r == n) { return i; }; case done => break; }; }; }; fn index_string(s: str, needle: str) (size | void) = { let s_iter = iter(s); for (let i = 0z; true; i += 1) { let rest_iter = s_iter; let needle_iter = iter(needle); for (true) { const rest_rune = next(&rest_iter); const needle_rune = next(&needle_iter); if (rest_rune is done && !(needle_rune is done)) { break; }; if (needle_rune is done) { return i; }; if ((rest_rune as rune) != (needle_rune as rune)) { break; }; }; if (next(&s_iter) is done) { break; }; }; }; fn rindex_string(s: str, needle: str) (size | void) = { let s_iter = riter(s); for (let i = len(s); true; i -= 1) { let rest_iter = s_iter; let needle_iter = riter(needle); for (true) { const rest_rune = next(&rest_iter); const needle_rune = next(&needle_iter); if (rest_rune is done && !(needle_rune is done)) { break; }; if (needle_rune is done) { return i - len(needle); }; if ((rest_rune as rune) != (needle_rune as rune)) { break; }; }; if (next(&s_iter) is done) { break; }; }; }; @test fn index() void = { assert(index("hello world", 'w') as size == 6); assert(index("こんにちは", 'ち') as size == 3); assert(index("こんにちは", 'q') is void); assert(index("hello", "hello") as size == 0); assert(index("hello world!", "hello") as size == 0); assert(index("hello world!", "world") as size == 6); assert(index("hello world!", "orld!") as size == 7); assert(index("hello world!", "word") is void); assert(index("こんにちは", "ちは") as size == 3); assert(index("こんにちは", "きょうは") is void); assert(index("hello world!", "o") as size == 4); assert(rindex("hello world!", "o") as size == 7); }; // Returns the byte-wise index of the first occurance of 'needle' in the // 'haystack', or void if not present. export fn byteindex(haystack: str, needle: (str | rune)) (size | void) = { return bytes::index(toutf8(haystack), match (needle) { case let s: str => yield toutf8(s); case let r: rune => yield if (r: u32 <= 0x7f) r: u8 else utf8::encoderune(r); }); }; // Returns the byte-wise index of the last occurance of 'needle' in the // 'haystack', or void if not present. export fn rbyteindex(haystack: str, needle: (str | rune)) (size | void) = { return bytes::rindex(toutf8(haystack), match (needle) { case let s: str => yield toutf8(s); case let r: rune => yield if (r: u32 <= 0x7f) r: u8 else utf8::encoderune(r); }); }; @test fn byteindex() void = { assert(byteindex("hello world", 'w') as size == 6); assert(byteindex("こんにちは", 'ち') as size == 9); assert(byteindex("こんにちは", 'q') is void); assert(byteindex("hello", "hello") as size == 0); assert(byteindex("hello world!", "hello") as size == 0); assert(byteindex("hello world!", "world") as size == 6); assert(byteindex("hello world!", "orld!") as size == 7); assert(byteindex("hello world!", "word") is void); assert(byteindex("こんにちは", "ちは") as size == 9); assert(byteindex("こんにちは", "きょうは") is void); assert(byteindex("またあったね", "た") as size == 3); assert(rbyteindex("またあったね", "た") as size == 12); }; hare-0.24.2/strings/iter.ha000066400000000000000000000075761464473310100155060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; export type iterator = struct { dec: utf8::decoder, reverse: bool, }; // Initializes a string iterator, starting at the beginning of the string. You // may copy the iterator to save its state. // // let iter = strings::iter("hi!"); // strings::next(&iter); // 'h' // strings::next(&iter); // 'i' // // // Copying the iterator copies its state: // let dup = iter; // strings::next(&iter); // '!' // strings::next(&iter); // void // strings::next(&dup); // '!' // strings::next(&dup); // void export fn iter(src: str) iterator = iterator { dec = utf8::decode(toutf8(src)), reverse = false, }; // Initializes a string iterator, starting at the end of the string and moving // backwards with each call to [[next]]. export fn riter(src: str) iterator = { let ret = iterator { dec = utf8::decode(toutf8(src)), reverse = true, }; ret.dec.offs = len(src); return ret; }; // Get the next rune from an iterator, or done if there are none left. // // Be aware that a rune is not the minimum lexographical unit of language in // Unicode strings. If you use these runes to construct a new string, // reordering, editing, or omitting any of the runes without careful discretion // may cause linguistic errors to arise. To avoid this, you may need to use a // third-party Unicode module instead. export fn next(iter: *iterator) (rune | done) = move(!iter.reverse, iter); // Get the previous rune from an iterator, or done when at the start of the // string. export fn prev(iter: *iterator) (rune | done) = move(iter.reverse, iter); fn move(forward: bool, iter: *iterator) (rune | done) = { let fun = if (forward) &utf8::next else &utf8::prev; match (fun(&iter.dec)) { case (utf8::more | utf8::invalid) => abort("Invalid UTF-8 string (this should not happen)"); case let r: (rune | done) => return r; }; }; // Return a substring from the next rune to the end of the string if initialized // with [[iter]], or the beginning of the string if initialized with [[riter]]. export fn iterstr(iter: *iterator) str = { if (iter.reverse) { return fromutf8_unsafe(iter.dec.src[..iter.dec.offs]); } else { return fromutf8_unsafe(iter.dec.src[iter.dec.offs..]); }; }; // Return a substring from the position of the first iterator to the position of // the second iterator. The iterators must originate from the same string and // the position of the second iterator must not be before the position of the // first one. export fn slice(begin: *iterator, end: *iterator) str = { assert(begin.dec.src: *[*]u8 == end.dec.src: *[*]u8 && begin.dec.offs <= end.dec.offs); return fromutf8_unsafe(begin.dec.src[begin.dec.offs..end.dec.offs]); }; @test fn iter() void = { let s = iter("こんにちは"); assert(prev(&s) is done); const expected1 = ['こ', 'ん']; for (let i = 0z; i < len(expected1); i += 1) { assert(next(&s) as rune == expected1[i]); }; assert(iterstr(&s) == "にちは"); assert(prev(&s) as rune == 'ん'); const expected2 = ['ん', 'に', 'ち', 'は']; for (let i = 0z; i < len(expected2); i += 1) { assert(next(&s) as rune == expected2[i]); }; assert(next(&s) is done); assert(next(&s) is done); assert(prev(&s) as rune == 'は'); s = riter("にちは"); const expected3 = ['は', 'ち', 'に']; for (let i = 0z; i < len(expected3); i += 1) { assert(next(&s) as rune == expected3[i]); }; assert(next(&s) is done); assert(prev(&s) as rune == 'に'); }; @test fn slice() void = { let s = iter("こんにちは"); let t = s; assert(len(slice(&s, &t)) == 0 && len(slice(&t, &s)) == 0); for (let i = 0; i < 2; i += 1) { next(&s); next(&t); }; assert(len(slice(&s, &t)) == 0 && len(slice(&t, &s)) == 0); for (let i = 0; i < 3; i += 1) { next(&t); }; assert(slice(&s, &t) == "にちは"); for (let i = 0; i < 3; i += 1) { next(&s); }; assert(len(slice(&s, &t)) == 0 && len(slice(&t, &s)) == 0); }; hare-0.24.2/strings/pad.ha000066400000000000000000000025641464473310100152770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; // Pads the start of a string 's' with rune 'p' until the string reaches length // 'maxlen'. The caller must free the return value. export fn lpad(s: str, p: rune, maxlen: size) str = { if (len(s) >= maxlen) { return dup(s); }; let res: []u8 = alloc([], maxlen); for (let i = 0z; i < maxlen - len(s); i += 1) { append(res, utf8::encoderune(p)...); }; append(res, toutf8(s)...); return fromutf8_unsafe(res[..maxlen]); }; @test fn lpad() void = { let s = lpad("2", '0', 5); assert(s == "00002"); free(s); let s = lpad("12345", '0', 5); assert(s == "12345"); free(s); let s = lpad("", '0', 5); assert(s == "00000"); free(s); }; // Pads the end of a string 's' with rune 'p' until the string reaches length // 'maxlen'. The caller must free the return value. export fn rpad(s: str, p: rune, maxlen: size) str = { if (len(s) >= maxlen) { return dup(s); }; let res: []u8 = alloc([], maxlen); append(res, toutf8(s)...); for (let i = 0z; i < maxlen - len(s); i += 1) { append(res, utf8::encoderune(p)...); }; return fromutf8_unsafe(res[..maxlen]); }; @test fn rpad() void = { let s = rpad("2", '0', 5); assert(s == "20000"); free(s); let s = rpad("12345", '0', 5); assert(s == "12345"); free(s); let s = rpad("", '0', 5); assert(s == "00000"); free(s); }; hare-0.24.2/strings/replace.ha000066400000000000000000000046121464473310100161420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; // Returns a new string duplicated from 's', but with all instances of 'needle' // replaced with 'target'. The caller must free the return value. export fn replace(s: str, needle: str, target: str) str = { return multireplace(s, (needle, target)); }; // Performs a replacement in 's' of each tuple given by 'repls'. Replacement // occurs in a single pass of 's', and works like in [[replace]], except that // replacement pairs found earlier in 'repls' will take precedence over later // ones. For example: // // assert(multireplace("hello there", ("e", "a"), ("a", "x"), ("ell", "eww")) == "hallo thara"); // assert(multireplace("hello there", ("ell", "eww"), ("e", "a")) == "hewwo thara"); // // The caller must free the return value. export fn multireplace(s: str, repls: (str, str)...) str = { let b = toutf8(s); let res: []u8 = []; let i = 0z; let prev = 0z; // end of previous match, so we can append in chunks for :step (i < len(b)) { for (let (replace, with) .. repls) { const replb = (toutf8(replace), toutf8(with)); if (bytes::hasprefix(b[i..], replb.0)) { append(res, b[prev..i]...); append(res, replb.1...); i += len(replb.0); prev = i; continue :step; }; }; i += 1; }; append(res, b[prev..i]...); return fromutf8_unsafe(res); }; @test fn replace() void = { const s = replace("Hello world!", "world", "there"); defer free(s); assert(s == "Hello there!"); const s = replace("I like dogs, dogs, birds, dogs", "dogs", "cats"); defer free(s); assert(s == "I like cats, cats, birds, cats"); const s = replace("aaaaaa", "aa", "a"); defer free(s); assert(s == "aaa"); const s = replace("aaa", "a", "aa"); defer free(s); assert(s == "aaaaaa"); const s = replace("こんにちは", "にち", "ばん"); defer free(s); assert(s == "こんばんは"); }; @test fn multireplace() void = { const s = multireplace("Hello world", ("Hello", "Greetings"), ("world", "globe")); defer free(s); assert(s == "Greetings globe"); const s = multireplace("ababa", ("a", "ba"), ("b", "a"), ("a", "c")); defer free(s); assert(s == "baabaaba"); const s = multireplace("hello there", ("e", "a"), ("a", "x"), ("ell", "eww")); defer free(s); assert(s == "hallo thara"); const s = multireplace("hello there", ("ell", "eww"), ("e", "a")); defer free(s); assert(s == "hewwo thara"); }; hare-0.24.2/strings/runes.ha000066400000000000000000000030561464473310100156640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; // Returns a slice of runes for a string in O(n). The caller must free the // return value. export fn torunes(s: str) []rune = { let sl: []rune = []; let iter = iter(s); for (let r => next(&iter)) { append(sl, r); }; return sl; }; // Returns a string from a slice of runes. The caller must free the return value. export fn fromrunes(runes: []rune) str = { let bytes: []u8 = []; for (let r .. runes) { const bs = utf8::encoderune(r); append(bytes, bs...); }; return fromutf8_unsafe(bytes); }; @test fn fromrunes() void = { const tests: [_](str, []rune) = [ ("Harriet", ['H', 'a', 'r', 'r', 'i', 'e', 't']), ("", []), (".", ['.']), ("\a\b\f\n\r\t\v", ['\a', '\b', '\f', '\n', '\r', '\t', '\v']), ("Hello, world!", ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']), ("¡Hola Mundo!", ['¡', 'H', 'o', 'l', 'a', ' ', 'M', 'u', 'n', 'd', 'o', '!']), ("Γειά σου Κόσμε!", ['Γ', 'ε', 'ι', 'ά', ' ', 'σ', 'ο', 'υ', ' ', 'Κ', 'ό', 'σ', 'μ', 'ε', '!']), ("Привет, мир!", ['П', 'р', 'и', 'в', 'е', 'т', ',', ' ', 'м', 'и', 'р', '!']), ("こんにちは世界!", ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']), ]; for (let (string, runes) .. tests) { const s = fromrunes(runes); defer free(s); assert(s == string); const rs = torunes(s); defer free(rs); assert(len(rs) == len(runes)); for (let j = 0z; j < len(rs); j += 1) { assert(rs[j] == runes[j]); }; }; }; hare-0.24.2/strings/sub.ha000066400000000000000000000027431464473310100153230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors export type end = void; fn utf8_byte_len_bounded(iter: *iterator, end: size) size = { for (let i = 0z; i < end; i += 1) { match (next(iter)) { case let r: rune => continue; case done => abort("index exceeds string length"); }; }; return iter.dec.offs; }; // Returns a substring in the range [start, end - 1], where each argument is the // index of the Nth rune. If the end argument is given as [[end]], the end of // the substring is the end of the original string. The lifetime of the // substring is the same as that of the original string. // // Note that substringing runewise is not always the correct thing to do, and it // may cause unexpected linguistic errors to arise. You may want to use a // third-party Unicode module instead. export fn sub(s: str, start: size, end: (size | end) = end) str = { let iter = iter(s); let starti = utf8_byte_len_bounded(&iter, start); let endi = match (end) { case let sz: size => assert(start <= sz, "start is higher than end"); yield utf8_byte_len_bounded(&iter, sz - start); case => yield len(s); }; let bytes = toutf8(s); return fromutf8_unsafe(bytes[starti..endi]); }; @test fn sub() void = { assert(sub("a string", 2) == "string"); assert(sub("a string", 2, end) == "string"); assert(sub("a string", 0, 1) == "a"); assert(sub("a string", 0, 3) == "a s"); assert(sub("a string", 2, 8) == "string"); assert(sub("a string", 4, 4) == ""); }; hare-0.24.2/strings/suffix.ha000066400000000000000000000020571464473310100160340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use encoding::utf8; // Returns true if 'in' has the given prefix. export fn hasprefix(in: str, prefix: (str | rune)) bool = { let prefix = match (prefix) { case let r: rune => yield utf8::encoderune(r); case let s: str => yield toutf8(s); }; return bytes::hasprefix(toutf8(in), prefix); }; @test fn hasprefix() void = { assert(hasprefix("hello world", "hello")); assert(hasprefix("hello world", 'h')); assert(!hasprefix("hello world", "world")); assert(!hasprefix("hello world", 'q')); }; // Returns true if 'in' has the given suffix. export fn hassuffix(in: str, suff: (str | rune)) bool = { let suff = match (suff) { case let r: rune => yield utf8::encoderune(r); case let s: str => yield toutf8(s); }; return bytes::hassuffix(toutf8(in), suff); }; @test fn hassuffix() void = { assert(hassuffix("hello world", "world")); assert(hassuffix("hello world", 'd')); assert(!hassuffix("hello world", "hello")); assert(!hassuffix("hello world", 'h')); }; hare-0.24.2/strings/template/000077500000000000000000000000001464473310100160255ustar00rootroot00000000000000hare-0.24.2/strings/template/README000066400000000000000000000016471464473310100167150ustar00rootroot00000000000000This module provides support for formatting of large or complex strings beyond the scope of [[fmt::]]. A template is compiled using [[compile]], then executed with [[execute]] to print formatted text to an [[io::handle]]. The template format is a string with variables substituted using "$". Variable names must be alphanumeric ASCII characters (i.e. for which [[ascii::isalnum]] returns true). A literal "$" may be printed by using it twice: "$$". Variables may also be used with braces, i.e. ${variable}, so that they can be placed immediately next to alphanumeric characters; such variables may include non-alphanumeric characters other than '{' and '}'. const src = "Hello, $user! Your balance is $$$balance.\n"; const template = template::compile(src)!; defer template::finish(&template); template::execute(&template, os::stdout, ("user", "ddevault"), ("balance", 1000), )!; // "Hello, ddevault! Your balance is $1000. hare-0.24.2/strings/template/template.ha000066400000000000000000000101751464473310100201560ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use fmt; use io; use memio; use strings; export type literal = str; export type variable = str; export type instruction = (literal | variable); export type template = []instruction; // Parameters to execute with a template, a tuple of a variable name and a // formattable object. export type param = (str, fmt::formattable); // The template string has an invalid format. export type invalid = !void; // Converts an error into a human-friendly string. export fn strerror(err: invalid) str = "Template string has invalid format"; // Compiles a template string. The return value must be freed with [[finish]] // after use. export fn compile(input: str) (template | invalid) = { let buf = memio::dynamic(); defer io::close(&buf)!; let instrs: []instruction = []; const iter = strings::iter(input); for (let rn => strings::next(&iter)) { if (rn == '$') { match (strings::next(&iter)) { case let next_rn: rune => if (next_rn == '$') { memio::appendrune(&buf, rn)!; } else { strings::prev(&iter); const lit = memio::string(&buf)!; append(instrs, strings::dup(lit): literal); memio::reset(&buf); parse_variable(&instrs, &iter, &buf)?; }; case => return invalid; }; } else { memio::appendrune(&buf, rn)!; }; }; if (len(memio::string(&buf)!) != 0) { const lit = memio::string(&buf)!; append(instrs, strings::dup(lit): literal); }; return instrs; }; // Frees resources associated with a [[template]]. export fn finish(tmpl: *template) void = { for (let instr .. *tmpl) { match (instr) { case let lit: literal => free(lit); case let var: variable => free(var); }; }; free(*tmpl); }; // Executes a template, writing the output to the given [[io::handle]]. If the // template calls for a parameter which is not provided, an assertion will be // fired. export fn execute( tmpl: *template, out: io::handle, params: param... ) (size | io::error) = { let z = 0z; for (let instr .. *tmpl) { match (instr) { case let lit: literal => z += fmt::fprint(out, lit)?; case let var: variable => const value = get_param(var, params...); z += fmt::fprint(out, value)?; }; }; return z; }; fn get_param(name: str, params: param...) fmt::formattable = { // TODO: Consider preparing a parameter map or something for (let (var_name, obj) .. params) { if (var_name == name) { return obj; }; }; fmt::errorfln("strings::template: required parameter ${} was not provided", name)!; abort(); }; fn parse_variable( instrs: *[]instruction, iter: *strings::iterator, buf: *memio::stream, ) (void | invalid) = { let brace = false; match (strings::next(iter)) { case let rn: rune => if (rn == '{') { brace = true; } else { strings::prev(iter); }; case => return invalid; }; for (true) { const rn = match (strings::next(iter)) { case let rn: rune => yield rn; case => return invalid; }; if (brace) { if (rn == '{') { return invalid; } else if (rn != '}') { memio::appendrune(buf, rn)!; } else { break; }; } else { if (ascii::isalnum(rn)) { memio::appendrune(buf, rn)!; } else { strings::prev(iter); break; }; }; }; const var = memio::string(buf)!; append(instrs, strings::dup(var): variable); memio::reset(buf); }; def test_input: str = `Dear ${recipient}, I am the crown prince of $country. Your brother, $brother, has recently passed away in my country. I am writing to you to facilitate the transfer of his foreign bank account balance of $$1,000,000 to you.`; def test_output: str = `Dear Mrs. Johnson, I am the crown prince of South Africa. Your brother, Elon Musk, has recently passed away in my country. I am writing to you to facilitate the transfer of his foreign bank account balance of $1,000,000 to you.`; @test fn template() void = { const tmpl = compile(test_input)!; defer finish(&tmpl); let buf = memio::dynamic(); defer io::close(&buf)!; execute(&tmpl, &buf, ("recipient", "Mrs. Johnson"), ("country", "South Africa"), ("brother", "Elon Musk"), )!; assert(memio::string(&buf)! == test_output); }; hare-0.24.2/strings/tokenize.ha000066400000000000000000000205411464473310100163560ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use types; export type tokenizer = bytes::tokenizer; // Tokenizes a string, returning an iterator that yields substrings separated by // one or more delimiters, such that the string will be split along any of the // characters found in "delim". If the string begins with or ends with a // delimiter, an empty string is returned respectively as the first and last // call to [[next_token]]. // // Each character of the delimiter string must be an ASCII character (see // [[ascii::valid]]). // // The input string and delimiter string are borrowed from the caller for the // lifetime of the tokenizer. // // The caller must ensure that at least one delimiter is provided and that the // length of the input string is less than [[types::I64_MAX]]. // // const tok = strings::tokenize("Hello world!\tMy name is Harriet.", " \t"); // assert(next_token(&tok) as str == "Hello"); // assert(next_token(&tok) as str == "world!"); // assert(next_token(&tok) as str == "My"); // assert(next_token(&tok) as str == "name"); // assert(next_token(&tok) as str == "is"); // assert(next_token(&tok) as str == "Harriet"); // assert(next_token(&tok) is done); export fn tokenize(s: str, delim: str) tokenizer = { const in = toutf8(s); const delim = toutf8(delim); for (let ch .. delim) { assert(ch & 0x80 == 0, "strings::tokenize cannot tokenize on non-ASCII delimiters"); }; return bytes::tokenize(in, delim...); }; // Like [[tokenize]], but tokenizes the string in reverse, such that the first // call to [[next_token]] returns the last token and the last call returns the // first token. export fn rtokenize(s: str, delim: str) tokenizer = { const in = toutf8(s); const delim = toutf8(delim); for (let ch .. delim) { assert(ch & 0x80 == 0, "strings::tokenize cannot tokenize on non-ASCII delimiters"); }; return bytes::rtokenize(in, delim...); }; // Returns the next token from a [[tokenizer]] and advances the cursor. export fn next_token(s: *tokenizer) (str | done) = { let s = s: *bytes::tokenizer; match (bytes::next_token(s)) { case let b: []u8 => return fromutf8_unsafe(b); case done => return done; }; }; // Returns the next token from a [[tokenizer]] without advancing the cursor. export fn peek_token(s: *tokenizer) (str | done) = { let s = s: *bytes::tokenizer; return match (bytes::peek_token(s)) { case let b: []u8 => yield fromutf8_unsafe(b); case done => return done; }; }; // Returns the remainder of the input string from a [[tokenizer]] ahead of the // token cursor. export fn remaining_tokens(s: *tokenizer) str = { let s = s: *bytes::tokenizer; return fromutf8_unsafe(bytes::remaining_tokens(s)); }; fn tokenize_test( testcase: str, in: str, delim: str, tokens: []str, iters: size = types::SIZE_MAX, ) tokenizer = { const tok = tokenize(in, delim); let n = 0z; for (const want .. tokens) { if (n >= iters) { return tok; }; n += 1; const p = peek_token(&tok) as str; const n = next_token(&tok) as str; assert(p == n, testcase); assert(n == want, testcase); }; if (n >= iters) { return tok; }; assert(peek_token(&tok) is done, testcase); assert(next_token(&tok) is done, testcase); return tok; }; @test fn tokenize() void = { tokenize_test("simple case", "Hello world! My name is Harriet.", " ", [ "Hello", "world!", "My", "name", "is", "Harriet.", ]); tokenize_test("multiple delimiters", "/dev/sda1\t/ ext4 rw,relatime\t0 0", " \t", [ "/dev/sda1", "/", "ext4", "rw,relatime", "0", "0", ]); tokenize_test("consecutive delimiters", "hello world", " ", [ "hello", "", "", "", "world", ]); tokenize_test("leading delimiters", " hello world ", " ", [ "", "hello", "world", "", ]); const tok = tokenize_test("remaining_tokens", "Hello world! My name is Harriet.", " ", [ "Hello", "world!", ], 2); assert(remaining_tokens(&tok) == "My name is Harriet."); }; // Splits a string into tokens delimited by 'delim', starting at the beginning // of the string, and returning a slice of up to N tokens. The caller must free // this slice. The strings within the slice are borrowed from 'in'. // // The caller must ensure that 'delim' is not an empty string. export fn splitn(in: str, delim: str, n: size) []str = { let toks: []str = []; let tok = tokenize(in, delim); for (let i = 0z; i < n - 1z; i += 1) { match (next_token(&tok)) { case let s: str => append(toks, s); case done => return toks; }; }; match(peek_token(&tok)) { case done => void; case let s: str => append(toks, remaining_tokens(&tok)); }; return toks; }; // Splits a string into tokens delimited by 'delim', starting at the end // of the string, and returning a slice of up to N tokens. The caller must free // this slice. The strings within the slice are borrowed from 'in'. // // The caller must ensure that 'delim' is not an empty string. export fn rsplitn(in: str, delim: str, n: size) []str = { let toks: []str = []; let tok = rtokenize(in, delim); for (let i = 0z; i < n - 1z; i += 1) { match (next_token(&tok)) { case let s: str => append(toks, s); case done => return toks; }; }; match(peek_token(&tok)) { case done => void; case let s: str => append(toks, remaining_tokens(&tok)); }; for (let i = 0z; i < len(toks) / 2; i += 1) { const tmp = toks[i]; toks[i] = toks[len(toks) - i - 1]; toks[len(toks) - i - 1] = tmp; }; return toks; }; // Splits a string into tokens delimited by 'delim'. The caller must free the // returned slice. The strings within the slice are borrowed from 'in'. // // The caller must ensure that 'delim' is not an empty string. export fn split(in: str, delim: str) []str = splitn(in, delim, types::SIZE_MAX); @test fn split() void = { const expected = ["Hello,", "my", "name", "is Drew"]; const actual = splitn("Hello, my name is Drew", " ", 4z); assert(len(expected) == len(actual)); for (let i = 0z; i < len(expected); i += 1) { assert(expected[i] == actual[i]); }; free(actual); const expected2 = ["Hello,", "my", "name", "is", "Drew"]; const actual2 = split("Hello, my name is Drew", " "); assert(len(expected2) == len(actual2)); for (let i = 0z; i < len(expected2); i += 1) { assert(expected2[i] == actual2[i]); }; free(actual2); const expected3 = ["one"]; const actual3 = splitn("one", "=", 2z); assert(len(expected3) == len(actual3)); for (let i = 0z; i < len(expected3); i += 1) { assert(expected3[i] == actual3[i]); }; free(actual3); const expected4 = ["Hello, my", "name", "is", "Drew"]; const actual4 = rsplitn("Hello, my name is Drew", " ", 4z); assert(len(expected4) == len(actual4)); for (let i = 0z; i < len(expected4); i += 1) { assert(expected4[i] == actual4[i]); }; free(actual4); }; // Returns a string "cut" along the first instance of a delimiter, returning // everything up to the delimiter, and everything after the delimiter, in a // tuple. // // strings::cut("hello=world=foobar", "=") // ("hello", "world=foobar") // strings::cut("hello world", "=") // ("hello world", "") // // The return value is borrowed from the 'in' parameter. The caller must ensure // that 'delim' is not an empty string. export fn cut(in: str, delim: str) (str, str) = { let c = bytes::cut(toutf8(in), toutf8(delim)); return (fromutf8_unsafe(c.0), fromutf8_unsafe(c.1)); }; // Returns a string "cut" along the last instance of a delimiter, returning // everything up to the delimiter, and everything after the delimiter, in a // tuple. // // strings::rcut("hello=world=foobar", "=") // ("hello=world", "foobar") // strings::rcut("hello world", "=") // ("hello world", "") // // The return value is borrowed from the 'in' parameter. The caller must ensure // that 'delim' is not an empty string. export fn rcut(in: str, delim: str) (str, str) = { let c = bytes::rcut(toutf8(in), toutf8(delim)); return (fromutf8_unsafe(c.0), fromutf8_unsafe(c.1)); }; @test fn cut() void = { const sample = cut("hello=world", "="); assert(sample.0 == "hello" && sample.1 == "world"); const sample = cut("hello=world=foobar", "="); assert(sample.0 == "hello" && sample.1 == "world=foobar"); const sample = cut("hello world", "="); assert(sample.0 == "hello world" && sample.1 == ""); const sample = cut("", "="); assert(sample.0 == "" && sample.1 == ""); const sample = rcut("hello=world=foobar", "="); assert(sample.0 == "hello=world" && sample.1 == "foobar"); }; hare-0.24.2/strings/trim.ha000066400000000000000000000101421464473310100154750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; const whitespace: [_]u8 = [' ', '\n', '\t', '\r']; // Returns a string (borrowed from given input string) after trimming off of // the start of the input string the characters in the given list of runes. If // no runes are given, returns the string with leading whitespace stripped off. export fn ltrim(input: str, trim: rune...) str = { if (len(trim) == 0) { let input = toutf8(input); return fromutf8_unsafe(bytes::ltrim(input, whitespace...)); }; let it = iter(input); for :outer (let r => next(&it)) { for (let tr .. trim) { if (r == tr) { continue :outer; }; }; prev(&it); break; }; return fromutf8_unsafe(it.dec.src[it.dec.offs..]); }; // Returns a string (borrowed from given input string) after trimming off of // the end of the input string the characters in the given list of runes. If no // runes are given, returns the string with trailing whitespace stripped off. export fn rtrim(input: str, trim: rune...) str = { if (len(trim) == 0) { let input = toutf8(input); return fromutf8_unsafe(bytes::rtrim(input, whitespace...)); }; let it = riter(input); for :outer (let r => next(&it)) { for (let tr .. trim) { if (r == tr) { continue :outer; }; }; prev(&it); break; }; return fromutf8_unsafe(it.dec.src[..it.dec.offs]); }; // Returns a string (borrowed from given input string) after trimming off of // the both ends of the input string the characters in the given list of runes. // If no runes are given, returns the string with both leading and trailing // whitespace stripped off. export fn trim(input: str, exclude: rune...) str = ltrim(rtrim(input, exclude...), exclude...); // Returns a string (borrowed from given input string) after trimming off the // given prefix. If the input string doesn't have the given prefix, it is // returned unmodified. export fn trimprefix(input: str, trim: str) str = { if (!hasprefix(input, trim)) return input; const slice = toutf8(input); return fromutf8_unsafe(slice[len(trim)..]); }; // Returns a string (borrowed from given input string) after trimming off the // given suffix. If the input string doesn't have the given suffix, it is // returned unmodified. export fn trimsuffix(input: str, trim: str) str = { if (!hassuffix(input, trim)) return input; const slice = toutf8(input); return fromutf8_unsafe(slice[..len(input) - len(trim)]); }; @test fn trim() void = { assert(ltrim("") == ""); assert(ltrim(" hi") == "hi"); assert(ltrim("\t\r\n hello") == "hello"); assert(ltrim("((()(())))())", '(', ')') == ""); assert(ltrim("abacadabra", 'a', 'b', 'c', 'd') == "ra"); assert(ltrim("𝚊𝚋𝚊𝚌𝚊𝚍𝚊𝚋𝚛𝚊", '𝚊', '𝚋', '𝚌', '𝚍') == "𝚛𝚊"); // '𝚊' = U+1D68A assert(rtrim("") == ""); assert(rtrim("hello ") == "hello"); assert(rtrim("hello, world\r\n\r\n") == "hello, world"); assert(rtrim("Sentimentalized sensationalism sensationalized sentimentalisms", ' ', 's', 'i', 'l', 'z', 't', 'm', 'n', 'o', 'e', 'a', 'd') == "S"); assert(rtrim("\\/\\/\\\\//\\//\\////\\/\\", '/', '\\') == ""); assert(rtrim("yellowwooddoor", 'w', 'd', 'o', 'r') == "yell"); assert(trim("") == ""); assert(trim(" ​ ") == "​"); assert(trim("mississippi", 'm', 'i', 'p', 's') == ""); assert(trim("[[][[[]]][][].[[]][]]][]]]", '[', ']') == "."); assert(trim("AAAΑА𝖠AAAA", 'A') == "ΑА𝖠"); assert(trim(" চিত্ত যেথা ভয়শূন্য, উচ্চ যেথা শির ") == "চিত্ত যেথা ভয়শূন্য, উচ্চ যেথা শির"); assert(trim("𝖺𝖻𝖺𝖼𝖺𝖽𝖺𝖻‌𝗋‌𝖺𝖼𝖺𝖽𝖺𝖻𝖼𝖺", '𝖺', '𝖻', '𝖼', '𝖽') == "‌𝗋‌"); assert(trimprefix("", "") == ""); assert(trimprefix("", "blablabla") == ""); assert(trimprefix("hello, world", "hello") == ", world"); assert(trimprefix("blablabla", "bla") == "blabla"); assert(trimsuffix("", "") == ""); assert(trimsuffix("", "blablabla") == ""); assert(trimsuffix("hello, world", "world") == "hello, "); assert(trimsuffix("blablabla", "bla") == "blabla"); }; hare-0.24.2/strings/utf8.ha000066400000000000000000000021601464473310100154110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use types; // Converts a byte slice into a string, but does not test if it is valid UTF-8. // This is faster than the safe equivalent, but if the string is not valid UTF-8 // it may cause undefined behavior. The return value is borrowed from the input. export fn fromutf8_unsafe(in: []u8) str = { const s = types::string { data = in: *[*]u8, length = len(in), capacity = len(in), }; return *(&s: *const str); }; // Converts a byte slice into a string. The return value is borrowed from the // input. If the slice contains invalid UTF-8 sequences, // [[encoding::utf8::invalid]] is returned instead. export fn fromutf8(in: []u8) (str | utf8::invalid) = { utf8::validate(in)?; return fromutf8_unsafe(in); }; // Converts a string to a UTF-8 byte slice. The return value is borrowed from // the input. export fn toutf8(in: str) []u8 = *(&in: *[]u8); @test fn utf8() void = { assert(fromutf8([ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, ])! == "hello world"); assert(fromutf8([])! == ""); }; hare-0.24.2/temp/000077500000000000000000000000001464473310100134665ustar00rootroot00000000000000hare-0.24.2/temp/+freebsd.ha000066400000000000000000000054261464473310100154740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::random; use encoding::hex; use errors; use fmt; use fs; use io; use memio; use os; use path; fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp"); // Creates an unnamed temporary file. The file may or may not have a name; not // all systems support the creation of temporary inodes which are not linked to // any directory. If it is necessary to create a real file, it will be removed // when the stream is closed. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn file(iomode: io::mode, mode: fs::mode) (io::file | fs::error) = { // TODO: Add a custom "close" function which removes the named file let file = named(os::cwd, get_tmpdir(), iomode, mode)?; free(file.1); return file.0; }; // Creates a named temporary file in the given directory of the given // filesystem. The caller is responsible for closing and removing the file when // they're done with it. The name is statically allocated, and will be // overwritten on subsequent calls. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn named( fs: *fs::fs, path: str, iomode: io::mode, mode: fs::mode, ) ((io::file, str) | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); let oflags = fs::flag::EXCL; if (iomode == io::mode::RDWR) { oflags |= fs::flag::RDWR; } else { oflags |= fs::flag::WRONLY; }; static let pathbuf = path::buffer { ... }; static let namebuf: [32]u8 = [0...]; for (true) { let rand: [size(u64)]u8 = [0...]; random::buffer(rand); const id = *(&rand[0]: *u64); const name = fmt::bsprintf(namebuf, "temp.{}", id); const path = path::set(&pathbuf, path, name)!; match (fs::create_file(fs, path, mode, oflags)) { case errors::exists => continue; case let err: fs::error => return err; case let f: io::file => return (f, path); }; }; }; // Creates a temporary directory. This function only guarantees that the // directory will have a unique name and be placed in the system temp directory, // but not that it will be removed automatically; the caller must remove it when // they're done using it via [[os::rmdir]] or [[os::rmdirall]]. // // The return value is statically allocated and will be overwritten on // subsequent calls. export fn dir() str = { let buf: [8]u8 = [0...], name: [16]u8 = [0...]; random::buffer(buf[..]); let sink = memio::fixed(name); const enc = hex::newencoder(&sink); io::write(&enc, buf)!; let name = memio::string(&sink)!; static let buf = path::buffer { ... }; path::set(&buf, get_tmpdir(), name)!; const path = path::string(&buf); match (os::mkdir(path,0o755)) { case let err: fs::error => abort("Could not create temp directory"); case void => void; }; return path; }; hare-0.24.2/temp/+linux.ha000066400000000000000000000061241464473310100152150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::random; use encoding::hex; use errors; use fmt; use fs; use io; use memio; use os; use path; fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp"); // Creates an unnamed temporary file. The file may or may not have a name; not // all systems support the creation of temporary inodes which are not linked to // any directory. If it is necessary to create a real file, it will be removed // when the stream is closed. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn file(iomode: io::mode, mode: fs::mode) (io::file | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); let oflags = fs::flag::TMPFILE | fs::flag::EXCL; if (iomode == io::mode::RDWR) { oflags |= fs::flag::RDWR; } else { oflags |= fs::flag::WRONLY; }; // TODO: Add a custom "close" function which removes the named file match (os::create(get_tmpdir(), mode, oflags)) { case let err: fs::error => return named(os::cwd, get_tmpdir(), iomode, mode)?.0; case let f: io::file => return f; }; }; // Creates a named temporary file in the given directory of the given // filesystem. The caller is responsible for closing and removing the file when // they're done with it. The name is statically allocated, and will be // overwritten on subsequent calls. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn named( fs: *fs::fs, path: str, iomode: io::mode, mode: fs::mode, ) ((io::file, str) | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); let oflags = fs::flag::EXCL; if (iomode == io::mode::RDWR) { oflags |= fs::flag::RDWR; } else { oflags |= fs::flag::WRONLY; }; static let pathbuf = path::buffer { ... }; static let namebuf: [32]u8 = [0...]; for (true) { let rand: [size(u64)]u8 = [0...]; random::buffer(rand); const id = *(&rand[0]: *u64); const name = fmt::bsprintf(namebuf, "temp.{}", id); const path = path::set(&pathbuf, path, name)!; match (fs::create_file(fs, path, mode, oflags)) { case errors::exists => continue; case let err: fs::error => return err; case let f: io::file => return (f, path); }; }; }; // Creates a temporary directory. This function only guarantees that the // directory will have a unique name and be placed in the system temp directory, // but not that it will be removed automatically; the caller must remove it when // they're done using it via [[os::rmdir]] or [[os::rmdirall]]. // // The return value is statically allocated and will be overwritten on // subsequent calls. export fn dir() str = { const buf: [8]u8 = [0...], name: [16]u8 = [0...]; random::buffer(buf[..]); const sink = memio::fixed(name); let enc = hex::newencoder(&sink); io::write(&enc, buf) as size; const name = memio::string(&sink)!; static let buf = path::buffer { ... }; path::set(&buf, get_tmpdir(), name)!; const path = path::string(&buf); match (os::mkdir(path, 0o755)) { case let err: fs::error => abort("Could not create temp directory"); case void => void; }; return path; }; hare-0.24.2/temp/+netbsd.ha000066400000000000000000000054261464473310100153410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use crypto::random; use encoding::hex; use errors; use fmt; use fs; use io; use memio; use os; use path; fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp"); // Creates an unnamed temporary file. The file may or may not have a name; not // all systems support the creation of temporary inodes which are not linked to // any directory. If it is necessary to create a real file, it will be removed // when the stream is closed. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn file(iomode: io::mode, mode: fs::mode) (io::file | fs::error) = { // TODO: Add a custom "close" function which removes the named file let file = named(os::cwd, get_tmpdir(), iomode, mode)?; free(file.1); return file.0; }; // Creates a named temporary file in the given directory of the given // filesystem. The caller is responsible for closing and removing the file when // they're done with it. The name is statically allocated, and will be // overwritten on subsequent calls. // // The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. export fn named( fs: *fs::fs, path: str, iomode: io::mode, mode: fs::mode, ) ((io::file, str) | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); let oflags = fs::flag::EXCL; if (iomode == io::mode::RDWR) { oflags |= fs::flag::RDWR; } else { oflags |= fs::flag::WRONLY; }; static let pathbuf = path::buffer { ... }; static let namebuf: [32]u8 = [0...]; for (true) { let rand: [size(u64)]u8 = [0...]; random::buffer(rand); const id = *(&rand[0]: *u64); const name = fmt::bsprintf(namebuf, "temp.{}", id); const path = path::set(&pathbuf, path, name)!; match (fs::create_file(fs, path, mode, oflags)) { case errors::exists => continue; case let err: fs::error => return err; case let f: io::file => return (f, path); }; }; }; // Creates a temporary directory. This function only guarantees that the // directory will have a unique name and be placed in the system temp directory, // but not that it will be removed automatically; the caller must remove it when // they're done using it via [[os::rmdir]] or [[os::rmdirall]]. // // The return value is statically allocated and will be overwritten on // subsequent calls. export fn dir() str = { let buf: [8]u8 = [0...], name: [16]u8 = [0...]; random::buffer(buf[..]); let sink = memio::fixed(name); const enc = hex::newencoder(&sink); io::write(&enc, buf)!; let name = memio::string(&sink)!; static let buf = path::buffer { ... }; path::set(&buf, get_tmpdir(), name)!; const path = path::string(&buf); match (os::mkdir(path,0o755)) { case let err: fs::error => abort("Could not create temp directory"); case void => void; }; return path; }; hare-0.24.2/temp/README000066400000000000000000000001171464473310100143450ustar00rootroot00000000000000The temp module provides support for creating temporary directories and files. hare-0.24.2/test/000077500000000000000000000000001464473310100135005ustar00rootroot00000000000000hare-0.24.2/test/+test.ha000066400000000000000000000212721464473310100150500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use bufio; use encoding::hex; use encoding::utf8; use fmt; use fnmatch; use io; use memio; use os; use rt; use strings; use time; use unix::signal; use unix::tty; type test = struct { name: str, func: *fn() void, }; // RETURN and ABORT must be 0 and 1 respectively type status = enum { RETURN = 0, ABORT = 1, SKIP, SEGV, }; type failure = struct { test: str, reason: rt::abort_reason, }; type skipped = struct { test: str, reason: str, }; type output = struct { test: str, stdout: str, stderr: str, }; fn finish_output(output: *output) void = { free(output.stdout); free(output.stderr); }; type context = struct { stdout: memio::stream, stderr: memio::stream, failures: []failure, skipped: []skipped, output: []output, maxname: size, total_time: time::duration, default_round: uint, cwd: str, }; fn finish_context(ctx: *context) void = { io::close(&ctx.stdout)!; io::close(&ctx.stderr)!; free(ctx.failures); free(ctx.skipped); for (let out &.. ctx.output) { finish_output(out); }; free(ctx.output); free(ctx.cwd); }; fn colored() bool = { return len(os::tryenv("NO_COLOR", "")) == 0 && tty::isatty(os::stdout_file); }; let jmpbuf = rt::jmpbuf { ... }; const @symbol("__test_array_start") test_start: [*]test; const @symbol("__test_array_end") test_end: [*]test; export @symbol("__test_main") fn main() size = { const ntest = (&test_end: uintptr - &test_start: uintptr): size / size(test); const tests = test_start[..ntest]; let enabled_tests: []test = []; defer free(enabled_tests); if (len(os::args) == 1) { append(enabled_tests, tests...); } else for (let i = 0z; i < ntest; i += 1) { for (let arg .. os::args) { if (fnmatch::fnmatch(arg, tests[i].name)) { append(enabled_tests, tests[i]); break; }; }; }; if (len(enabled_tests) == 0) { fmt::println("No tests run")!; return 0; }; let maxname = 0z; for (let test .. enabled_tests) { if (len(test.name) > maxname) { maxname = len(test.name); }; }; let ctx = context { stdout = memio::dynamic(), stderr = memio::dynamic(), maxname = maxname, default_round = rt::fegetround(), cwd = strings::dup(os::getcwd()), ... }; defer finish_context(&ctx); fmt::printfln("Running {}/{} tests:\n", len(enabled_tests), ntest)!; reset(&ctx); for (let test .. enabled_tests) { do_test(&ctx, test); }; fmt::println()!; if (len(ctx.skipped) > 0 && colored()) { fmt::print("\x1b[37m")!; }; for (let skipped .. ctx.skipped) { fmt::printfln("Skipped {}: {}", skipped.test, skipped.reason)!; }; if (len(ctx.skipped) > 0) { fmt::println(if (colored()) "\x1b[m" else "")!; }; if (len(ctx.failures) > 0) { fmt::println("Failures:")!; for (let failure .. ctx.failures) { match (failure.reason.path) { case null => fmt::printfln("{}: {}", failure.test, failure.reason.msg)!; case let path: *str => fmt::printfln("{}: {}:{}:{}: {}", failure.test, *path, failure.reason.line, failure.reason.col, failure.reason.msg)!; }; }; fmt::println()!; }; for (let i = 0z; i < len(ctx.output); i += 1) { if (ctx.output[i].stdout != "") { fmt::println(ctx.output[i].test, "stdout:")!; fmt::println(ctx.output[i].stdout)!; }; if (ctx.output[i].stderr != "") { fmt::println(ctx.output[i].test, "stderr:")!; fmt::println(ctx.output[i].stderr)!; }; if (i == len(ctx.output) - 1) { fmt::println()!; }; }; // XXX: revisit once time::format_duration is implemented const total_cnt = len(enabled_tests); const failed_cnt = len(ctx.failures); const skipped_cnt = len(ctx.skipped); const passed_cnt = total_cnt - failed_cnt - skipped_cnt; const elapsed_whole = ctx.total_time / time::SECOND; const elapsed_fraction = ctx.total_time % time::SECOND; styled_print(if (passed_cnt > 0) 92 else 37, passed_cnt); fmt::print(" passed; ")!; styled_print(if (len(ctx.failures) > 0) 91 else 37, failed_cnt); fmt::print(" failed; ")!; if (len(ctx.skipped) > 0) { fmt::print(len(ctx.skipped), "skipped; ")!; }; fmt::printfln("{} completed in {}.{:.9}s", total_cnt, elapsed_whole, elapsed_fraction)!; easter_egg(ctx.failures, enabled_tests); return len(ctx.failures); }; fn reset(ctx: *context) void = { rt::fesetround(ctx.default_round); rt::feclearexcept(~0u); signal::resetall(); os::chdir(ctx.cwd)!; want_abort = false; }; fn do_test(ctx: *context, test: test) void = { signal::handle(signal::sig::SEGV, &handle_segv, signal::flag::NODEFER, signal::flag::ONSTACK); memio::reset(&ctx.stdout); memio::reset(&ctx.stderr); const start_time = time::now(time::clock::MONOTONIC); const status = run_test(ctx, test); const end_time = time::now(time::clock::MONOTONIC); const failed = interpret_status(ctx, test.name, status); const time_diff = time::diff(start_time, end_time); assert(time_diff >= 0); ctx.total_time += time_diff; fmt::printfln(" in {}.{:.9}s", time_diff / 1000000000, time_diff % 1000000000)!; const stdout = printable(memio::buffer(&ctx.stdout)); const stderr = printable(memio::buffer(&ctx.stderr)); if (failed && (stdout != "" || stderr != "")) { append(ctx.output, output { test = test.name, stdout = stdout, stderr = stderr, }); }; reset(ctx); }; fn run_test(ctx: *context, test: test) status = { fmt::print(test.name)!; dots(ctx.maxname - len(test.name) + 3); bufio::flush(os::stdout)!; // write test name before test runs let orig_stdout = os::stdout; let orig_stderr = os::stderr; os::stdout = &ctx.stdout; os::stderr = &ctx.stderr; defer rt::jmp = null; const n = rt::setjmp(&jmpbuf): status; if (n == status::RETURN) { rt::jmp = &jmpbuf; test.func(); }; os::stdout = orig_stdout; os::stderr = orig_stderr; return n; }; fn printable(buf: []u8) str = { match (strings::fromutf8(buf)) { case let s: str => let it = strings::iter(s); for (true) match (strings::next(&it)) { case done => return strings::dup(s); case let r: rune => if (ascii::valid(r) && !ascii::isprint(r) && r != '\t' && r != '\n') { break; }; }; case utf8::invalid => void; }; let s = memio::dynamic(); hex::dump(&s, buf)!; return memio::string(&s)!; }; fn dots(n: size) void = { for (let i = 0z; i < n; i += 1) { fmt::print(".")!; }; }; // returns true if test failed, false if it passed or was skipped fn interpret_status(ctx: *context, test: str, status: status) bool = { switch (status) { case status::RETURN => if (want_abort) { styled_print(91, "FAIL"); append(ctx.failures, failure { test = test, reason = rt::abort_reason { msg = "Expected test to abort", ... }, }); return true; } else { styled_print(92, "PASS"); return false; }; case status::ABORT => if (want_abort) { styled_print(92, "PASS"); return false; } else { styled_print(91, "FAIL"); append(ctx.failures, failure { test = test, reason = rt::reason, }); return true; }; case status::SKIP => styled_print(37, "SKIP"); append(ctx.skipped, skipped { test = test, reason = rt::reason.msg, }); return false; case status::SEGV => styled_print(91, "FAIL"); append(ctx.failures, failure { test = test, reason = rt::abort_reason { msg = "Segmentation fault", ... }, }); return true; }; }; fn styled_print(color: int, result: fmt::formattable) void = { if (colored()) { fmt::printf("\x1b[{}m" "{}" "\x1b[m", color, result)!; } else { fmt::print(result)!; }; }; fn handle_segv( sig: signal::sig, info: *signal::siginfo, ucontext: *opaque, ) void = { rt::longjmp(&jmpbuf, status::SEGV); }; fn easter_egg(fails: []failure, tests: []test) void = { // norwegian deadbeef let blob: [_]u8 = [ 0xe1, 0x41, 0xf2, 0x21, 0x3f, 0x9e, 0x2d, 0xfe, 0x3f, 0x9e, 0x22, 0xfc, 0x43, 0xc2, 0x2f, 0x82, 0x15, 0xd1, 0x62, 0xae, 0x6c, 0x9e, 0x71, 0xfe, 0x33, 0xc2, 0x71, 0xfe, 0x63, 0xb4, 0x2d, 0xfe, 0x3f, 0xe1, 0x52, 0xf2, 0x43, 0xc6, 0x2d, 0xf9, 0x3d, 0x90, 0x07, 0xfe, 0x33, 0x9c, 0x2d, 0xfe, 0x3f, 0x96, 0x2d, 0x8f, 0x3f, 0x9e, 0x64, 0xd4, 0x33, 0x9c, 0x21, 0xfe, 0x3f, 0x9e, 0x2d, 0x82, 0x40, 0x9e, 0x54, 0xf9, 0x15, 0x99, 0x30, 0xfe, 0x3f, 0x92, 0x2d, 0xfe, 0x31, 0x9e, 0x2d, 0xfe, 0x38, 0xb4, 0x2d, 0xf9, 0x22, 0x83, 0x52, 0xf9, 0x40, 0xe1, 0x30, 0xe3, 0x38, 0x9e, 0x2d, 0xd4, ]; let words = &blob: *[24]u32; // doesn't currently work on big-endian, would need to re-find the // constants and use a different blob there if (words[0]: u8 != 0xe1) return; words[0] ^= len(tests): u32; let hash = 2166136261u32; for (let i = 0z; i < size(u32); i += 1) { hash = (hash ^ blob[i]) * 16777619; }; for (let i = 0z; i < len(words); i += 1) { words[i] ^= hash; }; if (-len(fails): u32 == words[0]) { io::write(os::stdout, blob[size(u32)..])!; }; }; hare-0.24.2/test/fail+test.ha000066400000000000000000000003631464473310100157020ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use os; @test fn _abort() void = { expectabort(); abort("Intentional failure"); }; @test fn exit() void = { expectabort(); os::exit(os::status::FAILURE); }; hare-0.24.2/test/util+test.ha000066400000000000000000000024011464473310100157370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use os; use rt; use strings; let want_abort = false; // Expect the currently running test to abort. The test will fail if it doesn't // abort. export fn expectabort() void = { if (rt::jmp == null) { abort("Attempted to call test::expectabort outside of @test function"); }; want_abort = true; }; // Skip the currently running test. export fn skip(reason: str) never = { if (rt::jmp == null) { abort("Attempted to call test::skip outside of @test function"); }; rt::reason = rt::abort_reason { msg = reason, ... }; rt::longjmp(&jmpbuf, status::SKIP); }; // Check the $HARETEST_INCLUDE space-delimited environment variable for // keywords. If all the keywords are present, return void. Otherwise, skip the // currently running test. export fn require(keywords: str...) void = { for :keywords (let keyword .. keywords) { let tokr = strings::tokenize(os::tryenv("HARETEST_INCLUDE", ""), " "); for (true) { match (strings::next_token(&tokr)) { case let tok: str => if (tok == keyword) { continue :keywords; }; case done => skip(fmt::asprintf( "Requires HARETEST_INCLUDE='{}'", strings::join(" ", keywords...), )); }; }; }; }; hare-0.24.2/test/util.ha000066400000000000000000000013171464473310100147710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Expect the currently running test to abort. The test will fail if it doesn't // abort. export fn expectabort() void = { abort("Attempted to call test::expectabort outside of @test function"); }; // Skip the currently running test. export fn skip(reason: str) never = { abort("Attempted to call test::skip outside of @test function"); }; // Check the $HARETEST_INCLUDE space-delimited environment variable for // keywords. If all the keywords are present, return void. Otherwise, skip the // currently running test. export fn require(keywords: str...) void = { abort("Attempted to call test::require outside of @test function"); }; hare-0.24.2/time/000077500000000000000000000000001464473310100134575ustar00rootroot00000000000000hare-0.24.2/time/+freebsd/000077500000000000000000000000001464473310100151445ustar00rootroot00000000000000hare-0.24.2/time/+freebsd/functions.ha000066400000000000000000000056701464473310100174760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Converts a [[duration]] to an [[rt::timespec]]. This function is // non-portable. export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec { tv_sec = n / SECOND, tv_nsec = n % SECOND, }; // Converts a [[duration]] to an [[rt::timeval]]. This function is // non-portable. export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval { tv_sec = d / SECOND, tv_usec = d % SECOND / 1000, }; // Converts an [[instant]] to an [[rt::timespec]]. This function is // non-portable. export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec { tv_sec = t.sec, tv_nsec = t.nsec, }; // Converts a [[rt::timespec]] to an [[instant]]. This function is // non-portable. export fn timespec_to_instant(ts: rt::timespec) instant = instant { sec = ts.tv_sec, nsec = ts.tv_nsec, }; // Yields the process to the kernel and returns after the requested duration. export fn sleep(d: duration) void = { let req = duration_to_timespec(d); for (true) { let res = rt::timespec { ... }; match (rt::nanosleep(&req, &res)) { case void => return; case let err: rt::errno => switch (err) { case rt::EINTR => req = res; case => abort("Unexpected error from nanosleep"); }; }; }; }; // An enumeration of clocks available on this system. Different clocks represent // times from different epochs, and have different characteristics with regards // to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME // and MONOTONIC clocks at least; use of other clocks is not guaranteed to be // portable. export type clock = enum { // The current wall-clock time. This may jump forwards or backwards in // time to account for leap seconds, NTP adjustments, etc. REALTIME = 0, // The current monotonic time. This clock measures from some undefined // epoch and is not affected by leap seconds, NTP adjustments, and // changes to the system time: it always increases by one second per // second. MONOTONIC = 4, // TODO: Document these VIRTUAL = 1, PROF = 2, UPTIME = 5, UPTIME_PRECISE = 7, UPTIME_FAST = 8, REALTIME_PRECISE = 9, REALTIME_FAST = 10, MONOTONIC_PRECISE = 11, MONOTONIC_FAST = 12, SECOND = 13, THREAD_CPUTIME_ID = 14, PROCESS_CPUTIME_ID = 15, }; // Returns the current time for a given clock. export fn now(clock: clock) instant = { let tp = rt::timespec { ... }; match (rt::clock_gettime(clock, &tp)) { case void => return timespec_to_instant(tp); case let err: rt::errno => abort("Unexpected error from clock_gettime"); }; }; // Sets system clock to given time. export fn set(clock: clock, t: instant) (void | errors::noaccess) = { let tp = instant_to_timespec(t); let err = match (rt::clock_settime(clock, &tp)) { case void => return; case let err: rt::errno => yield err; }; if (err == rt::EPERM) { return errors::noaccess; }; abort("Unexpected error from clock_settime"); }; hare-0.24.2/time/+linux/000077500000000000000000000000001464473310100146715ustar00rootroot00000000000000hare-0.24.2/time/+linux/+aarch64.ha000066400000000000000000000002521464473310100165050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def VDSO_CGT_SYM: str = "__kernel_clock_gettime"; def VDSO_CGT_VER: str = "LINUX_2.6.39"; hare-0.24.2/time/+linux/+riscv64.ha000066400000000000000000000002501464473310100165530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def VDSO_CGT_SYM: str = "__kernel_clock_gettime"; def VDSO_CGT_VER: str = "LINUX_4.15"; hare-0.24.2/time/+linux/+x86_64.ha000066400000000000000000000002451464473310100162150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def VDSO_CGT_SYM: str = "__vdso_clock_gettime"; def VDSO_CGT_VER: str = "LINUX_2.6"; hare-0.24.2/time/+linux/functions.ha000066400000000000000000000100141464473310100172070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use linux::vdso; use rt; // Converts a [[duration]] to an [[rt::timespec]]. This function is // non-portable. export fn duration_to_timespec(d: duration) rt::timespec = rt::timespec { tv_sec = d / SECOND, tv_nsec = d % SECOND, }; // Converts a [[duration]] to an [[rt::timeval]]. This function is // non-portable. export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval { tv_sec = d / SECOND, tv_usec = d % SECOND / 1000, }; // Converts an [[instant]] to an [[rt::timespec]]. This function is // non-portable. export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec { tv_sec = t.sec, tv_nsec = t.nsec, }; // Converts a [[rt::timespec]] to an [[instant]]. This function is non-portable. export fn timespec_to_instant(ts: rt::timespec) instant = instant { sec = ts.tv_sec, nsec = ts.tv_nsec, }; // Yields the process to the kernel and returns after the requested duration. export fn sleep(d: duration) void = { let req = duration_to_timespec(d); for (true) { let res = rt::timespec { ... }; match (rt::nanosleep(&req, &res)) { case void => return; case let err: rt::errno => switch (err) { case rt::EINTR => req = res; case => abort("Unexpected error from nanosleep"); }; }; }; }; // An enumeration of clocks available on this system. Different clocks represent // times from different epochs, and have different characteristics with regards // to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME // and MONOTONIC clocks at least; use of other clocks is not guaranteed to be // portable. export type clock = enum { // The current wall-clock time. This may jump forwards or backwards in // time to account for leap seconds, NTP adjustments, etc. REALTIME = 0, // The current monotonic time. This clock measures from some undefined // epoch and is not affected by leap seconds, NTP adjustments, and // changes to the system time: it always increases by one second per // second. MONOTONIC = 1, // Measures CPU time consumed by the calling process. PROCESS_CPU = 2, // Time since the system was booted. Increases monotonically and, unlike // [[MONOTONIC]], continues to tick while the system is suspended. BOOT = 7, // This clock is like [[REALTIME]], but will wake the system if it is suspended. REALTIME_ALARM = 8, // This clock is like [[BOOT]], but will wake the system if it is suspended. BOOT_ALARM = 9, // A system-wide clock derived from wall-clock time but ignoring leap seconds. TAI = 11, }; fn cgt_vdso() nullable *fn(int, *rt::timespec) int = { static let vdso_checked: bool = false; static let cgt_vdso: nullable *fn(int, *rt::timespec) int = null; if (vdso_checked) { return cgt_vdso; }; vdso_checked = true; cgt_vdso = vdso::getsym(VDSO_CGT_SYM, VDSO_CGT_VER): nullable *fn(int, *rt::timespec) int; return cgt_vdso; }; fn now_vdso(clock: clock, tp: *rt::timespec) (void | rt::errno) = { const vfn = match (cgt_vdso()) { case null => return rt::ENOSYS; case let vfn: *fn(int, *rt::timespec) int => yield vfn; }; const ret = vfn(clock, tp); if (ret == 0) { return; }; return ret; }; // Returns the current time for a given clock. export fn now(clock: clock) instant = { let tp = rt::timespec { ... }; let err = match (now_vdso(clock, &tp)) { case void => return timespec_to_instant(tp); case let err: rt::errno => yield err; }; if (err != rt::ENOSYS) { abort("Unexpected error from clock_gettime"); }; match (rt::clock_gettime(clock, &tp)) { case void => return timespec_to_instant(tp); case let err: rt::errno => abort("Unexpected error from clock_gettime"); }; }; // Sets system clock to given time. export fn set(clock: clock, t: instant) (void | errors::noaccess) = { let tp = instant_to_timespec(t); let err = match (rt::clock_settime(clock, &tp)) { case void => return; case let err: rt::errno => yield err; }; if (err == rt::EPERM) { return errors::noaccess; }; abort("Unexpected error from clock_settime"); }; hare-0.24.2/time/+netbsd/000077500000000000000000000000001464473310100150115ustar00rootroot00000000000000hare-0.24.2/time/+netbsd/functions.ha000066400000000000000000000064201464473310100173350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Converts a [[duration]] to an [[rt::timespec]]. This function is // non-portable. export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec { tv_sec = n / SECOND, tv_nsec = n % SECOND, }; // Converts a [[duration]] to an [[rt::timeval]]. This function is // non-portable. export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval { tv_sec = d / SECOND, tv_usec = d % SECOND / 1000, }; // Converts an [[instant]] to an [[rt::timespec]]. This function is // non-portable. export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec { tv_sec = t.sec, tv_nsec = t.nsec, }; // Converts a [[rt::timespec]] to an [[instant]]. This function is // non-portable. export fn timespec_to_instant(ts: rt::timespec) instant = instant { sec = ts.tv_sec, nsec = ts.tv_nsec, }; // Yields the process to the kernel and returns after the requested duration. export fn sleep(d: duration) void = { let req = duration_to_timespec(d); for (true) { let res = rt::timespec { ... }; match (rt::nanosleep(&req, &res)) { case void => return; case let err: rt::errno => switch (err) { case rt::EINTR => req = res; case => abort("Unexpected error from nanosleep"); }; }; }; }; // An enumeration of clocks available on this system. Different clocks represent // times from different epochs, and have different characteristics with regards // to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME // and MONOTONIC clocks at least; use of other clocks is not guaranteed to be // portable. export type clock = enum { // The current wall-clock time. This may jump forwards or backwards in // time to account for leap seconds, NTP adjustments, etc. REALTIME = rt::CLOCK_REALTIME, // The current monotonic time. This clock measures from some undefined // epoch and is not affected by leap seconds, NTP adjustments, and // changes to the system time: it always increases by one second per // second. MONOTONIC = rt::CLOCK_MONOTONIC, // Increments only when the CPU is running in user mode on behalf of the // calling process. VIRTUAL = rt::CLOCK_VIRTUAL, // Increments when the CPU is running in user or kernel mode. PROF = rt::CLOCK_PROF, // The thread CPU clock. It begins at zero and is advanced while the // calling thread is running in user or kernel mode. THREAD_CPUTIME_ID = rt::CLOCK_THREAD_CPUTIME_ID, // The process CPU clock. It begins at zero and is advanced while the // calling process is running in user or kernel mode. PROCESS_CPUTIME_ID = rt::CLOCK_PROCESS_CPUTIME_ID, }; // Returns the current time for a given clock. export fn now(clock: clock) instant = { let tp = rt::timespec { ... }; match (rt::clock_gettime(clock, &tp)) { case void => return timespec_to_instant(tp); case let err: rt::errno => abort("Unexpected error from clock_gettime"); }; }; // Sets system clock to given time. export fn set(clock: clock, t: instant) (void | errors::noaccess) = { let tp = instant_to_timespec(t); let err = match (rt::clock_settime(clock, &tp)) { case void => return; case let err: rt::errno => yield err; }; if (err == rt::EPERM) { return errors::noaccess; }; abort("Unexpected error from clock_settime"); }; hare-0.24.2/time/+openbsd/000077500000000000000000000000001464473310100151645ustar00rootroot00000000000000hare-0.24.2/time/+openbsd/functions.ha000066400000000000000000000065151464473310100175150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Converts a [[duration]] to an [[rt::timespec]]. This function is // non-portable. export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec { tv_sec = n / SECOND, tv_nsec = n % SECOND, }; // Converts a [[duration]] to an [[rt::timeval]]. This function is // non-portable. export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval { tv_sec = d / SECOND, tv_usec = d % SECOND / 1000, }; // Converts an [[instant]] to an [[rt::timespec]]. This function is // non-portable. export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec { tv_sec = t.sec, tv_nsec = t.nsec, }; // Converts a [[rt::timespec]] to an [[instant]]. This function is // non-portable. export fn timespec_to_instant(ts: rt::timespec) instant = instant { sec = ts.tv_sec, nsec = ts.tv_nsec, }; // Yields the process to the kernel and returns after the requested duration. export fn sleep(d: duration) void = { let req = duration_to_timespec(d); for (true) { let res = rt::timespec { ... }; match (rt::nanosleep(&req, &res)) { case void => return; case let err: rt::errno => switch (err) { case rt::EINTR => req = res; case => abort("Unexpected error from nanosleep"); }; }; }; }; // An enumeration of clocks available on this system. Different clocks represent // times from different epochs, and have different characteristics with regards // to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME // and MONOTONIC clocks at least; use of other clocks is not guaranteed to be // portable. export type clock = enum { // The current wall-clock time. This may jump forwards or backwards in // time to account for leap seconds, NTP adjustments, etc. REALTIME = rt::CLOCK_REALTIME, // The current monotonic time. This clock measures from some undefined // epoch and is not affected by leap seconds, NTP adjustments, and // changes to the system time: it always increases by one second per // second. MONOTONIC = rt::CLOCK_MONOTONIC, // The uptime clock. It is the time that has elapsed since the system // booted. Begins at zero. BOOT = rt::CLOCK_BOOTTIME, // The runtime clock. It only advances while the system is not suspended // and begins when the system is booted. Begins at zero. UPTIME = rt::CLOCK_UPTIME, // The process CPU clock. It begins at zero and is advanced while the // calling process is running in user or kernel mode. PROCESS_CPU = rt::CLOCK_PROCESS_CPUTIME_ID, // The thread CPU clock. It begins at zero and is advanced while the // calling thread is running in user or kernel mode. THREAD_CPU = rt::CLOCK_THREAD_CPUTIME_ID, }; // Returns the current time for a given clock. export fn now(clock: clock) instant = { let ts = rt::timespec { ... }; match (rt::clock_gettime(clock, &ts)) { case void => return timespec_to_instant(ts); case let err: rt::errno => abort("Unexpected error from clock_gettime"); }; }; // Sets system clock to given time. export fn set(clock: clock, t: instant) (void | errors::noaccess) = { let tp = instant_to_timespec(t); let err = match (rt::clock_settime(clock, &tp)) { case void => return; case let err: rt::errno => yield err; }; if (err == rt::EPERM) { return errors::noaccess; }; abort("Unexpected error from clock_settime"); }; hare-0.24.2/time/README000066400000000000000000000003251464473310100143370ustar00rootroot00000000000000The time module provides basic timekeeping primitives and system clock access. See [[time::chrono::]] for timescales, timezones, and other chronology primitives. See [[time::date::]] for the Gregorian chronology. hare-0.24.2/time/arithm.ha000066400000000000000000000176621464473310100152710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use math; // Adds a [[duration]] to an [[instant]], returning an instant further in the // future (given a positive duration), or further in the past (given a negative // duration). export fn add(i: instant, x: duration) instant = { if (x == 0) { return i; } else if (x > 0) { return instant { sec = i.sec + (i.nsec + x) / SECOND, nsec = (i.nsec + x) % SECOND, }; } else { return instant { sec = i.sec + (i.nsec + x - SECOND + NANOSECOND) / SECOND, nsec = (i.nsec + (x % SECOND) + SECOND) % SECOND, }; }; }; // Returns the [[duration]] from [[instant]] "a" to [[instant]] "b". export fn diff(a: instant, b: instant) duration = { return ((b.sec - a.sec) * SECOND) + (b.nsec - a.nsec); }; // Returns -1 if a precedes b, 0 if a and b are simultaneous, or +1 if b // precedes a. export fn compare(a: instant, b: instant) i8 = { return if (a.sec < b.sec) -1 else if (a.sec > b.sec) 1 else if (a.nsec < b.nsec) -1 else if (a.nsec > b.nsec) 1 else 0; }; // Scales the given [[instant]]'s scalar value by a factor 'f'. Make sure to // know what epoch you're dealing with. export fn mult(i: instant, f: f64) instant = { // use positive numbers for convenience const positive = if (i.sec < 0 ^^ f < 0.0) false else true; const f = if (f < 0.0) -f else f; const asec: i64 = if (i.sec < 0) -i.sec - 1 else i.sec; const ansec: i64 = if (i.sec < 0) SECOND - i.nsec else i.nsec; // initial multiply const fsec = (asec: f64 * f); const bsec = fsec: i64; const fnsec = (ansec: f64 * f); const bnsec = fnsec: i64; // get seconds overflow (nsec remainder) const secrem = math::modf64(fsec, 1.0); const addnsec = (secrem * SECOND: f64): i64; // add overflows const b = instant { sec = bsec, nsec = ansec, }; const b = add(b, bnsec - ansec); // add nsec overflow const b = add(b, addnsec); // add sec overflow // switch back to original sign const b = if (positive) { yield b; } else { yield instant { sec = -b.sec - 1, nsec = SECOND - b.nsec, }; }; return b; }; @test fn add() void = { const cases = [ // instant a duration x instant b ( 0, 0, -2000000001, -3, 999999999), ( 0, 0, -2000000000, -2, 0), ( 0, 0, -1999999999, -2, 1), ( 0, 0, -1000000001, -2, 999999999), ( 0, 0, -1000000000, -1, 0), ( 0, 0, -999999999, -1, 1), ( 0, 0, -1, -1, 999999999), ( 0, 0, 0, 0, 0), ( 0, 0, 1, 0, 1), ( 0, 0, 999999999, 0, 999999999), ( 0, 0, 1000000000, 1, 0), ( 0, 0, 1000000001, 1, 1), ( 0, 0, 1999999999, 1, 999999999), ( 0, 0, 2000000000, 2, 0), ( 0, 0, 2000000001, 2, 1), ( 0, 1, -2000000001, -2, 0), ( 0, 1, -2000000000, -2, 1), ( 0, 1, -1999999999, -2, 2), ( 0, 1, -1000000001, -1, 0), ( 0, 1, -1000000000, -1, 1), ( 0, 1, -999999999, -1, 2), ( 0, 1, -1, 0, 0), ( 0, 1, 0, 0, 1), ( 0, 1, 1, 0, 2), ( 0, 1, 999999999, 1, 0), ( 0, 1, 1000000000, 1, 1), ( 0, 1, 1000000001, 1, 2), ( 0, 1, 1999999999, 2, 0), ( 0, 1, 2000000000, 2, 1), ( 0, 1, 2000000001, 2, 2), (-1, 999999999, -2000000001, -3, 999999998), (-1, 999999999, -2000000000, -3, 999999999), (-1, 999999999, -1999999999, -2, 0), (-1, 999999999, -1000000001, -2, 999999998), (-1, 999999999, -1000000000, -2, 999999999), (-1, 999999999, - 999999999, -1, 0), (-1, 999999999, -1, -1, 999999998), (-1, 999999999, 0, -1, 999999999), (-1, 999999999, 1, 0, 0), (-1, 999999999, 999999999, 0, 999999998), (-1, 999999999, 1000000000, 0, 999999999), (-1, 999999999, 1000000001, 1, 0), (-1, 999999999, 1999999999, 1, 999999998), (-1, 999999999, 2000000000, 1, 999999999), (-1, 999999999, 2000000001, 2, 0), ( 0, 999999999, -2000000001, -2, 999999998), ( 0, 999999999, -2000000000, -2, 999999999), ( 0, 999999999, -1999999999, -1, 0), ( 0, 999999999, -1000000001, -1, 999999998), ( 0, 999999999, -1000000000, -1, 999999999), ( 0, 999999999, -999999999, 0, 0), ( 0, 999999999, -1, 0, 999999998), ( 0, 999999999, 0, 0, 999999999), ( 0, 999999999, 1, 1, 0), ( 0, 999999999, 999999999, 1, 999999998), ( 0, 999999999, 1000000000, 1, 999999999), ( 0, 999999999, 1000000001, 2, 0), ( 0, 999999999, 1999999999, 2, 999999998), ( 0, 999999999, 2000000000, 2, 999999999), ( 0, 999999999, 2000000001, 3, 0), ]; for (let i = 0z; i < len(cases); i += 1) { const C = cases[i]; const a = instant { sec = C.0, nsec = C.1 }; const x = C.2; const b = instant { sec = C.3, nsec = C.4 }; const B = add(a, x); assert(B.sec == b.sec, "time::add() .sec error"); assert(B.nsec == b.nsec, "time::add() .nsec error"); }; }; @test fn compare() void = { let a = now(clock::MONOTONIC); sleep(1 * MILLISECOND); let b = now(clock::MONOTONIC); assert(compare(a, b) < 0); assert(compare(b, a) > 0); assert(compare(a, a) == 0); }; @test fn mult() void = { const cases = [ // instant a factor f instant b interpretations ( 0, 0, 0.000, 0, 0), // 0.000000000 ( 9, 0, 0.000, 0, 0), // 0.000000000 ( 0, 999999999, 0.000, 0, 0), // 0.000000000 ( 9, 999999999, 0.000, 0, 0), // 0.000000000 ( 1, 0, 1.000, 1, 0), // 1.000000000 ( 9, 0, 1.000, 9, 0), // 9.000000000 ( 1, 999999999, 1.000, 1, 999999999), // 1.999999999 ( 9, 999999999, 1.000, 9, 999999999), // 9.999999999 ( 1, 0, 0.001, 0, 1000000), // 0.001000000 ( 1, 0, 0.010, 0, 10000000), // 0.010000000 ( 1, 0, 0.100, 0, 100000000), // 0.100000000 (-1, 0, 0.001, -1, 999000000), // -0.001000000 (-1, 0, 0.010, -1, 990000000), // -0.010000000 (-1, 0, 0.100, -1, 900000000), // -0.100000000 (-1, 0, 1.000, -1, 0), // -1.000000000 ( 0, 500000000, 0.001, 0, 500000), // 0.005000000 ( 0, 500000000, 0.010, 0, 5000000), // 0.050000000 ( 0, 500000000, 0.100, 0, 50000000), // 0.500000000 ( 2, 0, 0.001, 0, 2000000), // 0.002000000 ( 2, 0, 0.010, 0, 20000000), // 0.020000000 ( 2, 0, 0.100, 0, 200000000), // 0.200000000 ( 3, 141592653, 3.141, 9, 867742523), // 9.867742523073 ( 2, 718281828, 2.718, 7, 388290007), // 7.388290008504 (rounds down?) ( 1, 414213562, 1.414, 1, 999697975), // 1.999697976668 (rounds down?) ( 3, 141592653, -3.141, -10, 132257477), // -9.867742523073 ( 2, 718281828, -2.718, -8, 611709993), // -7.388290008504 ( 1, 414213562, -1.414, -2, 302025), // -1.999697976668 (-4, 858407347, 3.141, -10, 132257477), // -9.867742523073 (-3, 281718172, 2.718, -8, 611709993), // -7.388290008504 (-2, 585786438, 1.414, -2, 302025), // -1.999697976668 (-4, 858407347, -3.141, 9, 867742523), // 9.867742523073 (-3, 281718172, -2.718, 7, 388290007), // 7.388290008504 (-2, 585786438, -1.414, 1, 999697975), // 1.999697976668 ]; for (let i = 0z; i < len(cases); i += 1) { const C = cases[i]; const a = instant { sec = C.0, nsec = C.1 }; const f = C.2; const b = instant { sec = C.3, nsec = C.4 }; const B = mult(a, f); assert(B.sec == b.sec, "time::mult() .sec error"); assert(B.nsec == b.nsec, "time::mult() .nsec error"); }; }; hare-0.24.2/time/chrono/000077500000000000000000000000001464473310100147475ustar00rootroot00000000000000hare-0.24.2/time/chrono/+freebsd.ha000066400000000000000000000005261464473310100167510ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def LOCALTIME_PATH: str = "/etc/localtime"; def TZDB_PATH: str = "/usr/share/zoneinfo/"; // The filepath of the system's "leap-seconds.list" file, which contains UTC/TAI // leap second data. export def UTC_LEAPSECS_PATH: str = "/var/db/ntpd.leap-seconds.list"; hare-0.24.2/time/chrono/+linux.ha000066400000000000000000000005351464473310100164760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def LOCALTIME_PATH: str = "/etc/localtime"; def TZDB_PATH: str = "/usr/share/zoneinfo/"; // The filepath of the system's "leap-seconds.list" file, which contains UTC/TAI // leap second data. export def UTC_LEAPSECS_PATH: str = "/usr/share/zoneinfo/leap-seconds.list"; hare-0.24.2/time/chrono/+netbsd.ha000066400000000000000000000005351464473310100166160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def LOCALTIME_PATH: str = "/etc/localtime"; def TZDB_PATH: str = "/usr/share/zoneinfo/"; // The filepath of the system's "leap-seconds.list" file, which contains UTC/TAI // leap second data. export def UTC_LEAPSECS_PATH: str = "/usr/share/zoneinfo/leap-seconds.list"; hare-0.24.2/time/chrono/+openbsd.ha000066400000000000000000000005351464473310100167710ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def LOCALTIME_PATH: str = "/etc/localtime"; def TZDB_PATH: str = "/usr/share/zoneinfo/"; // The filepath of the system's "leap-seconds.list" file, which contains UTC/TAI // leap second data. export def UTC_LEAPSECS_PATH: str = "/usr/share/zoneinfo/leap-seconds.list"; hare-0.24.2/time/chrono/README000066400000000000000000000014731464473310100156340ustar00rootroot00000000000000The time::chrono module provides timescale utilities, and the foundations for chronology with the [[moment]] type, an abstract, extendable date/time object. For the Gregorian chronology, see the [[time::date::]] module. Hare defines a chronology as a system for naming and ordering moments in time. In practice, it is the combination of a calendar and wall clock. This module implements a simple date & time chronology with [[moment]], which observes certain chronological values according to its [[locality]]. The observer functions [[daydate]], [[daytime]], and [[mzone]] obtain these values. Use [[in]] to localize a moment to another [[locality]]; consult [[tz]]. The [[timescale]] interface facilitates leap-second aware [[convert]]ion of [[time::instant]]s. The [[tai]] timescale is the default intermediary timescale. hare-0.24.2/time/chrono/arithmetic.ha000066400000000000000000000062301464473310100174130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; // Returns true if two [[moment]]s represent the same time in the same locality, // which is to say that their [[locality]] and [[time::instant]] are both equal. // Their observed values and representations in a chronology should be the same // in all cases. // // See [[simultaneous]] to determine if two moments represent the same moment in // time regardless of locality. export fn coincident(a: *moment, b: *moment) bool = { return a.loc == b.loc && a.sec == b.sec && a.nsec == b.nsec; }; // Returns true if two [[moment]]s represent the same moment in time, regardless // of locality. // // The moments are compared as [[time::instant]]s; their observed chronological // values and representations are ignored. // // If the moments' associated [[timescale]]s are different, they will be // converted to [[tai]] instants first. Any [[discontinuity]] occurence will be // returned. If a discontinuity against TAI amongst the two timescales exist, // consider converting such instants manually. // // See [[coincident]] to determine if two [[moment]]s are equal with respect to // both time and locality. export fn simultaneous(a: *moment, b: *moment) (bool | discontinuity) = { return 0 == compare(a, b)?; }; // Compares two [[moment]]s. Returns -1 if a precedes b, 0 if a and b are // simultaneous, or +1 if b precedes a. // // The moments are compared as [[time::instant]]s; their observed chronological // values are ignored. // // If the moments' associated [[timescale]]s are different, they will be // converted to [[tai]] instants first. Any [[discontinuity]] occurence will be // returned. If a discontinuity against TAI amongst the two timescales exist, // consider converting such instants manually. export fn compare(a: *moment, b: *moment) (i8 | discontinuity) = { const (ia, ib) = convertpair(a, b)?; return time::compare(ia, ib); }; // Returns the [[time::duration]] between two [[moment]]s, from a to b. // // The moments are compared as [[time::instant]]s; their observed chronological // values are ignored. // // If the moments' associated [[timescale]]s are different, they will be // converted to [[tai]] instants first. Any [[discontinuity]] occurence will be // returned. If a discontinuity against TAI amongst the two timescales exist, // consider converting such instants manually. export fn diff(a: *moment, b: *moment) (time::duration | discontinuity) = { const (ia, ib) = convertpair(a, b)?; return time::diff(ia, ib); }; // Adds a [[time::duration]] to a [[moment]] with [[time::add]]. export fn add(m: *moment, x: time::duration) moment = { return new(m.loc, time::add(*(m: *time::instant), x)); }; fn convertpair( a: *moment, b: *moment, ) ((time::instant, time::instant) | discontinuity) = { let ia = *(a: *time::instant); let ib = *(b: *time::instant); if (a.loc.timescale != b.loc.timescale) { match (convert(ia, a.loc.timescale, &tai)) { case let i: time::instant => ia = i; case => return discontinuity; }; match (convert(ib, b.loc.timescale, &tai)) { case let i: time::instant => ib = i; case => return discontinuity; }; }; return (ia, ib); }; hare-0.24.2/time/chrono/chronology.ha000066400000000000000000000107021464473310100174440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; // Invalid [[moment]]. export type invalid = !void; // A moment in time within a [[locality]]. Create one with [[new]]. This type // extends the [[time::instant]] type and couples it with a [[timescale]] via // its [[locality]] field. // // This object should be treated as private and immutable. Directly mutating its // fields causes undefined behavour when used with module functions. Likewise, // interrogating the fields' type and value (e.g. using match statements) is // also improper. // // Moments observe a daydate, time-of-day, and [[zone]], which are evaluated, // cached and obtained with the observer functions [[daydate]], [[daytime]], and // [[ozone]]. These values are derived from the embedded instant and locality // information, and thus are guaranteed to be valid. export type moment = struct { // The embedded [[time::instant]]. time::instant, // The [[locality]] with which to interpret this moment. loc: locality, // The observed [[zone]]. zone: nullable *zone, // The observed daydate (scalar day number) // since an abitrary epoch (e.g. the Unix epoch 1970-01-01). daydate: (void | i64), // The observed time-of-day (amount of daytime progressed in a day) // as nanoseconds. daytime: (void | i64), }; // Creates a new [[moment]]. Uses a given [[time::instant]] with a [[timescale]] // associated with a given [[locality]]. export fn new(loc: locality, i: time::instant) moment = { return moment { sec = i.sec, nsec = i.nsec, loc = loc, zone = null, daydate = void, daytime = void, }; }; // Observes a [[moment]]'s observed [[zone]]. export fn ozone(m: *moment) zone = { match (m.zone) { case let z: *zone => return *z; case null => const z = lookupzone(m.loc, *(m: *time::instant)); m.zone = z; return *z; }; }; // Observes a [[moment]]'s observed daydate (day number since epoch). // // For moments with [[locality]]s based on the [[utc]], [[tai]], [[gps]], and // similar timescales, their epoch date should be interpreted as the Unix epoch // (1970 Janurary 1st). Other timescales may suggest their own interpretations // applicable to other chronologies. export fn daydate(m: *moment) i64 = { match (m.daydate) { case let dd: i64 => return dd; case void => const (dd, dt) = calc_datetime( m.loc, *(m: *time::instant), ozone(m).zoff, ); m.daytime = dt; m.daydate = dd; return dd; }; }; // Observes a [[moment]]'s observed time-of-day (amount of daytime progressed in // a day) as nanoseconds. export fn daytime(m: *moment) i64 = { match (m.daytime) { case let dt: i64 => return dt; case void => const (dd, dt) = calc_datetime( m.loc, *(m: *time::instant), ozone(m).zoff, ); m.daytime = dt; m.daydate = dd; return dt; }; }; // Calculates the observed daydate and time-of-day of a [[time::instant]] in a // [[locality]] at a particular zone offset. fn calc_datetime( loc: locality, inst: time::instant, zoff: time::duration, ) (i64, time::duration) = { const i = time::add(inst, zoff); const day = loc.daylength; const daysec = day / time::SECOND; const dd = if (i.sec >= 0) i.sec / daysec else (i.sec + 1) / daysec - 1; const dt = ((i.sec % daysec + daysec) * time::SECOND + i.nsec) % day; return (dd, dt); }; // Creates a [[moment]] from a given [[locality]], zone offset, daydate, and // time-of-day. export fn from_datetime( loc: locality, zo: time::duration, dd: i64, dt: i64, ) moment = { const inst = calc_instant(loc.daylength, zo, dd, dt); return moment { sec = inst.sec, nsec = inst.nsec, loc = loc, zone = null, daydate = dd, daytime = dt, }; }; fn calc_instant( day: time::duration, // length of a day zo: time::duration, // zone offset dd: i64, // date since epoch dt: i64, // time since start of day (ns) ) time::instant = { const daysec = (day / time::SECOND): i64; const dayrem = day % time::SECOND; let i = time::instant { sec = dd * daysec, nsec = 0, }; i = time::add(i, dd * dayrem); i = time::add(i, dt); i = time::add(i, -zo); return i; }; // The duration of a day on Earth, in terrestrial (SI) seconds. export def EARTH_DAY: time::duration = 86400 * time::SECOND; // The duration of a solar day on Mars, in Martian seconds. export def MARS_SOL_MARTIAN: time::duration = 86400 * time::SECOND; // The duration of a solar day on Mars, in terrestrial (SI) seconds. export def MARS_SOL_TERRESTRIAL: time::duration = 88775244147000 * time::NANOSECOND; hare-0.24.2/time/chrono/error.ha000066400000000000000000000021151464473310100164110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use fs; use io; // All possible errors returned from this module. export type error = !( invalid | invalidtzif | tzdberror | discontinuity | analytical ); // Converts an [[error]] into a human-friendly string. The result may be // statically allocated. export fn strerror(err: error) const str = { match (err) { case invalid => return "Invalid moment"; case invalidtzif => return "Invalid TZif data"; case let err: tzdberror => static let buf: [1024]u8 = [0...]; match (err) { case let err: fs::error => return fmt::bsprintf(buf, "Timezone database error: {}", fs::strerror(err), ); case let err: io::error => return fmt::bsprintf(buf, "Timezone database error: {}", io::strerror(err), ); case invalidtzif => return "Timezone database error: Invalid TZif data"; }; case discontinuity => return "A timescale discontinuity caused a misconversion"; case analytical => return "The analyical result of a conversion at a timescale discontinuity"; }; }; hare-0.24.2/time/chrono/leapsec.ha000066400000000000000000000060341464473310100167000ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use encoding::utf8; use fs; use io; use os; use strconv; use strings; // Hare uses raw leap second information when dealing with the UTC and TAI // timescales. This information is source from a standard file installed at // /usr/share/zoneinfo/leap-seconds.list, which itself is fetched from and // periodically maintained at various observatories. // // https://data.iana.org/time-zones/code/leap-seconds.list // https://www.ietf.org/timezones/data/leap-seconds.list // ftp://ftp.nist.gov/pub/time/leap-seconds.list // ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list // // This is in contrast to previous systems which rely on TZif files, which are // installed typically at /usr/share/zoneinfo, as part of the "Olson" IANA // Timezone database. These files couple timezone and leap second data. // // Depending on a system's installation, leap second information may be // deliberately left out of the TZif files, or duplicated throughout. This // design also inhibits our ambitions for dealing with multiple, dynamic // timescales. Therefore, we have decided to take an alternative approach. // Error initializing the [[utc]] [[timescale]]. type utciniterror = !(fs::error | io::error | utf8::invalid); // The number of seconds between the years 1900 and 1970. // // This number is hypothetical since timekeeping before atomic clocks was not // accurate enough to account for small changes in time. export def SECS_1900_1970: i64 = 2208988800; // UTC/TAI leap second data; UTC timestamps and their offsets from TAI. // Sourced from [[UTC_LEAPSECS_PATH]]. let utc_leapsecs: [](i64, i64) = []; let utc_isinitialized: bool = false; @fini fn free_utc() void = { free(utc_leapsecs); }; fn init_utc_leapsecs() (void | utciniterror) = { const file = os::open(UTC_LEAPSECS_PATH)?; defer io::close(file)!; parse_utc_leapsecs(file)?; }; // Parse UTC/TAI leap second data from [[UTC_LEAPSECS_PATH]]. // See file for format details. fn parse_utc_leapsecs(h: io::handle) (void | utf8::invalid | io::error) = { const scan = bufio::newscanner(h); defer bufio::finish(&scan); for (let line => bufio::scan_line(&scan)?) { if (strings::hasprefix(line, '#')) { continue; }; const iter = strings::iter(line); const secs = scan_number(&iter); scan_whitespace(&iter); const diff = scan_number(&iter); if (secs is void || diff is void) { continue; }; let secs = secs as i64 - SECS_1900_1970; let diff = diff as i64; append(utc_leapsecs, (secs, diff)); }; }; fn scan_number(iter: *strings::iterator) (i64 | void) = { let begin = *iter; for (let rn => strings::next(iter)) { switch (rn) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => continue; case => strings::prev(iter); break; }; }; return strconv::stoi64(strings::slice(&begin, iter))!; }; fn scan_whitespace(iter: *strings::iterator) void = { for (let rn => strings::next(iter)) { switch (rn) { case ' ', '\t' => continue; case => strings::prev(iter); return; }; }; }; hare-0.24.2/time/chrono/timescale.ha000066400000000000000000000454571464473310100172460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; // Represents a scale of time; a time standard. See [[convert]]. export type timescale = struct { name: str, abbr: str, convto: *tsconverter, convfrom: *tsconverter, }; export type tsconverter = fn(ts: *timescale, i: time::instant) ([]time::instant | void); // A discontinuity between two [[timescale]]s caused a one-to-one // [[time::instant]] conversion to fail. export type discontinuity = !void; // The analytical result of a [[time::instant]] conversion between two // [[timescale]]s at a point of [[discontinuity]]. // // An empty slice represents a nonexistent conversion result. // A populated (>1) slice represents an ambiguous conversion result. export type analytical = ![]time::instant; // Converts a [[time::instant]] from one [[timescale]] to the next exhaustively. // The final conversion result is returned. For each active pair of timescales, // if neither implements conversion from the first to the second, a two-step // intermediary TAI conversion will occur. If given zero or one timescales, the // given instant is returned. export fn convert(i: time::instant, tscs: *timescale...) (time::instant | analytical) = { let ts: []time::instant = [i]; let tmps: []time::instant = []; for (let j = 1z; j < len(tscs); j += 1) { let a = tscs[j - 1]; let b = tscs[j]; for (let k = 0z; k < len(ts); k += 1) { const t = ts[k]; // try .convto match (a.convto(b, t)) { case let convs: []time::instant => append(tmps, convs...); continue; case void => void; }; // try .convfrom match (b.convfrom(a, t)) { case let convs: []time::instant => append(tmps, convs...); continue; case void => void; }; // default to TAI intermediary const convs = a.convto(&tai, t) as []time::instant; for (let conv .. convs) { append(tmps, ( b.convfrom(&tai, conv) as []time::instant )...); }; }; // TODO: sort and deduplicate 'ts' here ts = tmps; tmps = []; }; return if (len(ts) == 1) ts[0] else ts; }; // International Atomic Time // // The realisation of proper time on Earth's geoid. // Continuous (no leap seconds). export const tai: timescale = timescale { name = "International Atomic Time", abbr = "TAI", convto = &tai_conv, convfrom = &tai_conv, }; fn tai_conv(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &tai => append(ret, i); return ret; case => return void; }; }; // Coordinated Universal Time // // Used as the basis of civil timekeeping. // Based on TAI; time-dependent offset. // Discontinuous (has leap seconds). // // During a program's initialization, this timescale initializes by loading its // UTC/TAI leap second data from [[UTC_LEAPSECS_PATH]]; otherwise, fails // silently. If failed, any attempt to consult UTC leapsec data (e.g. calling // [[convert]] on UTC) causes an abort. This includes [[in]]. export const utc: timescale = timescale { name = "Coordinated Universal Time", abbr = "UTC", convto = &utc_convto, convfrom = &utc_convfrom, }; fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &utc => append(ret, i); return ret; case &tai => if (!utc_isinitialized) { match (init_utc_leapsecs()) { case void => utc_isinitialized = true; case => abort("Failed to initialize UTC timescale"); }; }; const firstleap = utc_leapsecs[0]; // TODO: no leapsecs loaded if (time::compare(i, time::from_unix(firstleap.0)) < 0) { append(ret, time::instant { sec = i.sec + firstleap.1, nsec = i.nsec, }); return ret; }; for (let idx = len(utc_leapsecs) - 1; idx >= 0 ; idx -= 1) { const leap = utc_leapsecs[idx]; const leapsecond = time::from_unix(leap.0); const leapoffset = leap.1; const diff = time::diff(leapsecond, i); const prevleapoffset = if (idx == 0) 0i64 else utc_leapsecs[idx - 1].1; const offsetdiff = (leapoffset - prevleapoffset) * time::SECOND; // case of positive leap second (UTC repeats a second) if (offsetdiff >= 0) { if (diff >= 0) { append(ret, time::instant { sec = i.sec + leapoffset, nsec = i.nsec, }); return ret; }; if (diff >= -offsetdiff && diff < 0) { append(ret, [ time::instant { sec = i.sec + prevleapoffset, nsec = i.nsec, }, time::instant { sec = i.sec + leapoffset, nsec = i.nsec, }, ]...); return ret; }; continue; }; // case of negative leap second (UTC skips a second) if (offsetdiff < 0) { if (diff >= 0) { append(ret, time::instant { sec = i.sec + leapoffset, nsec = i.nsec, }); return ret; }; if (diff >= offsetdiff && diff < 0) { return ret; }; continue; }; }; case => return void; }; }; fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &utc => append(ret, i); return ret; case &tai => if (!utc_isinitialized) { match (init_utc_leapsecs()) { case void => utc_isinitialized = true; case => abort("Failed to initialize UTC timescale"); }; }; const firstleap = utc_leapsecs[0]; // TODO: no leapsecs loaded if (time::compare(i, time::from_unix(firstleap.0 + firstleap.1)) < 0) { append(ret, time::instant { sec = i.sec - firstleap.1, nsec = i.nsec, }); return ret; }; for (let idx = len(utc_leapsecs) - 1; idx >= 0 ; idx -= 1) { const leap = utc_leapsecs[idx]; const leapsecond = time::from_unix(leap.0 + leap.1); const leapoffset = leap.1; const diff = time::diff(leapsecond, i); const prevleapoffset = if (idx == 0) 10i64 else utc_leapsecs[idx - 1].1; const offsetdiff = (leapoffset - prevleapoffset) * time::SECOND; // case of positive leap second (UTC repeats a second) if (offsetdiff >= 0) { if (diff >= -offsetdiff) { append(ret, time::instant { sec = i.sec - leapoffset, nsec = i.nsec, }); return ret; }; continue; }; // case of negative leap second (UTC skips a second) if (offsetdiff < 0) { if (diff >= 0) { append(ret, time::instant { sec = i.sec - leapoffset, nsec = i.nsec, }); return ret; }; continue; }; }; case => return void; }; }; // Global Positioning System Time // // Used for GPS coordination. // Based on TAI; constant -19 second offset. // Continuous (no leap seconds). export const gps: timescale = timescale { name = "Global Positioning System Time", abbr = "GPS", convto = &gps_convto, convfrom = &gps_convfrom, }; // The constant offset between GPS-Time (Global Positioning System Time) and TAI // (International Atomic Time). Used by [[gps]]. def GPS_OFFSET: time::duration = -19 * time::SECOND; fn gps_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &gps => append(ret, i); return ret; case &tai => append(ret, time::add(i, -GPS_OFFSET)); return ret; case => return void; }; }; fn gps_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &gps => append(ret, i); return ret; case &tai => append(ret, time::add(i, GPS_OFFSET)); return ret; case => return void; }; }; // Terrestrial Time // // Used for astronomical timekeeping. // Based on TAI; constant +32.184 offset. // Continuous (no leap seconds). export const tt: timescale = timescale { name = "Terrestrial Time", abbr = "TT", convto = &tt_convto, convfrom = &tt_convfrom, }; // The constant offset between TT (Terrestrial Time) and TAI (International // Atomic Time). Used by [[tt]]. def TT_OFFSET: time::duration = 32184 * time::MILLISECOND; // 32.184 seconds fn tt_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &tt => append(ret, i); return ret; case &tai => append(ret, time::add(i, -TT_OFFSET)); return ret; case => return void; }; }; fn tt_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &tt => append(ret, i); return ret; case &tai => append(ret, time::add(i, TT_OFFSET)); return ret; case => return void; }; }; // Arthur David Olson had expressed support for Martian time in his timezone // database project : // // > The tz database does not currently support Mars time, but it is documented // > here in the hopes that support will be added eventually. // Coordinated Mars Time // // Used for timekeeping on Mars. // Based on TT; constant factor. // Continuous (no leap seconds). export const mtc: timescale = timescale { name = "Coordinated Mars Time", abbr = "MTC", convto = &mtc_convto, convfrom = &mtc_convfrom, }; // Factor f, where Martian-time * f == Earth-time. def FACTOR_TERRESTRIAL_MARTIAN: f64 = 1.0274912517; // [[time::duration]] in Earth-time between the Unix epoch of 1970 Jan 1st // midnight, and the Earth-Mars convergence date of 2000 Jan 6th midnight. def DELTA_UNIXEPOCH_JANSIX: time::duration = 10962 * 24 * time::HOUR; // [[time::duration]] in Mars-time between the Mars Sol Date epoch corresponding // to the Gregorian Earth date 1873 Dec 29th, and the Earth-Mars convergence // date of 2000 Jan 6. def DELTA_MARSEPOCH_JANSIX: time::duration = 44796 * 24 * time::HOUR; // [[time::duration]] in Mars-time between the midnights of 2000 Jan 6th on // Earth and Mars. Earth's midnight occurred first. def DELTA_JANSIX_ADJUSTMENT: time::duration = 82944 * time::MILLISECOND; fn mtc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &mtc => append(ret, i); return ret; case &tai => // Change epoch from that of the Mars Sol Date // to the Earth-Mars convergence date 2000 Jan 6th. let i = time::add(i, -DELTA_MARSEPOCH_JANSIX); // Slightly adjust epoch for the actual Martian midnight. // Earth's midnight occurred before Mars'. i = time::add(i, DELTA_JANSIX_ADJUSTMENT); // Scale from Mars-time to Earth-time. i = time::mult(i, FACTOR_TERRESTRIAL_MARTIAN); // Change epoch to the Unix epoch 1970 Jan 1st (Terrestrial Time). i = time::add(i, DELTA_UNIXEPOCH_JANSIX); // Get the TAI time. // assertion since TT and TAI are continuous. append(ret, (tt.convto(&tai, i) as []time::instant)[0]); return ret; case => return void; }; }; fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; switch (ts) { case &mtc => append(ret, i); return ret; case &tai => // Get the "Terrestrial Time". // assertion since TT and TAI are continuous. let i = (tt.convfrom(&tai, i) as []time::instant)[0]; // Change epoch from the Unix epoch 1970 Jan 1st (Terrestrial Time) // to the Earth-Mars convergence date 2000 Jan 6th midnight. i = time::add(i, -DELTA_UNIXEPOCH_JANSIX); // Scale from Earth-time to Mars-time. i = time::mult(i, 1.0 / FACTOR_TERRESTRIAL_MARTIAN); // Slightly adjust epoch for the actual Martian midnight. // Earth's midnight occurred before Mars'. i = time::add(i, -DELTA_JANSIX_ADJUSTMENT); // Change epoch to that of the Mars Sol Date. append(ret, time::add(i, DELTA_MARSEPOCH_JANSIX)); return ret; case => return void; }; }; @test fn utc_convto_tai() void = { // TODO: skip test if no leapsec data available (!utc_isinitialized) // TODO: test negative leapsecs somehow let testcases: []( (i64, i64), // give (void | [0](i64, i64) | [1](i64, i64) | [2](i64, i64)) // expect ) = [ ((- 1000i64, 0i64), [(- 990i64, 0i64)]), (( 0i64, 0i64), [( 10i64, 0i64)]), (( 1000i64, 0i64), [( 1010i64, 0i64)]), // 1970 Jan 01 (( 63071998i64, 0i64), [( 63072008i64, 0i64)]), (( 63071998i64, 500000000i64), [( 63072008i64, 500000000i64)]), (( 63071999i64, 0i64), [( 63072009i64, 0i64)]), (( 63071999i64, 500000000i64), [( 63072009i64, 500000000i64)]), (( 63072000i64, 0i64), [( 63072010i64, 0i64)]), (( 63072000i64, 500000000i64), [( 63072010i64, 500000000i64)]), (( 63072001i64, 0i64), [( 63072011i64, 0i64)]), (( 63072001i64, 500000000i64), [( 63072011i64, 500000000i64)]), (( 63072002i64, 0i64), [( 63072012i64, 0i64)]), // 1981 Jul 01 (( 362793598i64, 0i64), [( 362793617i64, 0i64)]), (( 362793598i64, 500000000i64), [( 362793617i64, 500000000i64)]), (( 362793599i64, 0i64), [ ( 362793618i64, 0i64), ( 362793619i64, 0i64), ]), (( 362793599i64, 500000000i64), [ ( 362793618i64, 500000000i64), ( 362793619i64, 500000000i64), ]), (( 362793600i64, 0i64), [( 362793620i64, 0i64)]), (( 362793600i64, 500000000i64), [( 362793620i64, 500000000i64)]), (( 362793601i64, 0i64), [( 362793621i64, 0i64)]), (( 362793601i64, 500000000i64), [( 362793621i64, 500000000i64)]), (( 362793602i64, 0i64), [( 362793622i64, 0i64)]), // 2017 Jan 01 (( 1483228798i64, 0i64), [( 1483228834i64, 0i64)]), (( 1483228798i64, 500000000i64), [( 1483228834i64, 500000000i64)]), (( 1483228799i64, 0i64), [ ( 1483228835i64, 0i64), ( 1483228836i64, 0i64), ]), (( 1483228799i64, 500000000i64), [ ( 1483228835i64, 500000000i64), ( 1483228836i64, 500000000i64), ]), (( 1483228800i64, 0i64), [( 1483228837i64, 0i64)]), (( 1483228800i64, 500000000i64), [( 1483228837i64, 500000000i64)]), (( 1483228801i64, 0i64), [( 1483228838i64, 0i64)]), (( 1483228801i64, 500000000i64), [( 1483228838i64, 500000000i64)]), (( 1483228802i64, 0i64), [( 1483228839i64, 0i64)]), ]; for (let testcase .. testcases) { let params = testcase.0; let param = time::instant{ sec = params.0, nsec = params.1 }; let expect = testcase.1; let actual = utc_convto(&tai, param); match (expect) { case void => assert(actual is void); case [0](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 0); case let insts: [1](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 1); assert(0 == time::compare( actual[0], time::instant{ sec = insts[0].0, nsec = insts[0].1, }, )); case let insts: [2](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 2); assert(0 == time::compare( actual[0], time::instant{ sec = insts[0].0, nsec = insts[0].1, }, )); assert(0 == time::compare( actual[1], time::instant{ sec = insts[1].0, nsec = insts[1].1, }, )); }; if (actual is []time::instant) { free(actual as []time::instant); }; }; }; @test fn utc_convfrom_tai() void = { // TODO: skip test if no leapsec data available (!utc_isinitialized) // TODO: test negative leapsecs somehow let testcases: []( (i64, i64), // give (void | [0](i64, i64) | [1](i64, i64) | [2](i64, i64)) // expect ) = [ ((- 990i64, 0i64), [(- 1000i64, 0i64)]), (( 10i64, 0i64), [( 0i64, 0i64)]), (( 1010i64, 0i64), [( 1000i64, 0i64)]), // 1970 Jan 01 (( 63072008i64, 0i64), [( 63071998i64, 0i64)]), (( 63072008i64, 500000000i64), [( 63071998i64, 500000000i64)]), (( 63072009i64, 0i64), [( 63071999i64, 0i64)]), (( 63072009i64, 500000000i64), [( 63071999i64, 500000000i64)]), (( 63072010i64, 0i64), [( 63072000i64, 0i64)]), (( 63072010i64, 500000000i64), [( 63072000i64, 500000000i64)]), (( 63072011i64, 0i64), [( 63072001i64, 0i64)]), (( 63072011i64, 500000000i64), [( 63072001i64, 500000000i64)]), (( 63072012i64, 0i64), [( 63072002i64, 0i64)]), // 1981 Jul 01 (( 362793617i64, 0i64), [( 362793598i64, 0i64)]), (( 362793617i64, 500000000i64), [( 362793598i64, 500000000i64)]), (( 362793618i64, 0i64), [( 362793599i64, 0i64)]), (( 362793618i64, 500000000i64), [( 362793599i64, 500000000i64)]), (( 362793619i64, 0i64), [( 362793599i64, 0i64)]), (( 362793619i64, 500000000i64), [( 362793599i64, 500000000i64)]), (( 362793620i64, 0i64), [( 362793600i64, 0i64)]), (( 362793620i64, 500000000i64), [( 362793600i64, 500000000i64)]), (( 362793621i64, 0i64), [( 362793601i64, 0i64)]), (( 362793621i64, 500000000i64), [( 362793601i64, 500000000i64)]), (( 362793622i64, 0i64), [( 362793602i64, 0i64)]), // 2017 Jan 01 (( 1483228834i64, 0i64), [( 1483228798i64, 0i64)]), (( 1483228834i64, 500000000i64), [( 1483228798i64, 500000000i64)]), (( 1483228835i64, 0i64), [( 1483228799i64, 0i64)]), (( 1483228835i64, 500000000i64), [( 1483228799i64, 500000000i64)]), (( 1483228836i64, 0i64), [( 1483228799i64, 0i64)]), (( 1483228836i64, 500000000i64), [( 1483228799i64, 500000000i64)]), (( 1483228837i64, 0i64), [( 1483228800i64, 0i64)]), (( 1483228837i64, 500000000i64), [( 1483228800i64, 500000000i64)]), (( 1483228838i64, 0i64), [( 1483228801i64, 0i64)]), (( 1483228838i64, 500000000i64), [( 1483228801i64, 500000000i64)]), (( 1483228839i64, 0i64), [( 1483228802i64, 0i64)]), ]; for (let testcase .. testcases) { let params = testcase.0; let param = time::instant{ sec = params.0, nsec = params.1 }; let expect = testcase.1; let actual = utc_convfrom(&tai, param); match (expect) { case void => assert(actual is void); case [0](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 0); case let insts: [1](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 1); assert(0 == time::compare( actual[0], time::instant{ sec = insts[0].0, nsec = insts[0].1, }, )); case let insts: [2](i64, i64) => assert(actual is []time::instant); const actual = actual as []time::instant; assert(len(actual) == 2); assert(0 == time::compare( actual[0], time::instant{ sec = insts[0].0, nsec = insts[0].1, }, )); assert(0 == time::compare( actual[1], time::instant{ sec = insts[1].0, nsec = insts[1].1, }, )); }; if (actual is []time::instant) { free(actual as []time::instant); }; }; }; hare-0.24.2/time/chrono/timezone.ha000066400000000000000000000163401464473310100171170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use os; use sort; use strings; use time; // The locality of a [[moment]]. Contains information about how to calculate a // moment's observed chronological values. export type locality = *timezone; // A timezone; a political or otherwise theoretical region with a ruleset // regarding offsets for calculating localized date/time. export type timezone = struct { // The textual identifier ("Europe/Amsterdam") name: str, // The base timescale (time::chrono::utc) timescale: *timescale, // The duration of a day in this timezone (24 * time::HOUR) daylength: time::duration, // The possible temporal zones a locality with this timezone can observe // (CET, CEST, ...) zones: []zone, // The transitions between this timezone's zones transitions: []transition, // A timezone specifier in the POSIX "expanded" TZ format. // See https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html // // Used for extending calculations beyond the last known transition. posix_extend: str, }; // A [[timezone]] state, with an offset for calculating localized date/time. export type zone = struct { // The offset from the normal timezone (2 * time::HOUR) zoff: time::duration, // The full descriptive name ("Central European Summer Time") name: str, // The abbreviated name ("CEST") abbr: str, // Indicator of Daylight Saving Time dst: bool, // true }; // A [[timezone]] transition between two [[zone]]s. export type transition = struct { when: time::instant, zoneindex: size, }; // A destructured dual std/dst POSIX timezone. See tzset(3). type tzname = struct { std_name: str, std_offset: time::duration, dst_name: str, dst_offset: time::duration, dst_start: str, dst_starttime: str, dst_end: str, dst_endtime: str, }; // Frees a [[timezone]]. A [[locality]] argument can be passed. export fn timezone_free(tz: *timezone) void = { free(tz.name); for (let zone &.. tz.zones) { zone_finish(zone); }; free(tz.zones); free(tz.transitions); free(tz.posix_extend); free(tz); }; // Frees resources associated with a [[zone]]. export fn zone_finish(z: *zone) void = { free(z.name); free(z.abbr); }; // Creates an equivalent [[moment]] with a different [[locality]]. // // If the moment's associated [[timescale]] and the target locality's timescale // are different, a conversion from one to the other via the TAI timescale will // be attempted. Any [[discontinuity]] occurrence will be returned. If a // discontinuity against TAI amongst the two timescales exist, consider // converting such instants manually. export fn in(loc: locality, m: moment) (moment | discontinuity) = { let i = *(&m: *time::instant); if (m.loc.timescale != loc.timescale) { match (convert(i, m.loc.timescale, loc.timescale)) { case analytical => return discontinuity; case let i: time::instant => return new(loc, i); }; }; return new(loc, i); }; // Finds and returns a [[moment]]'s currently observed [[zone]]. fn lookupzone(loc: locality, inst: time::instant) *zone = { // TODO: https://todo.sr.ht/~sircmpwn/hare/643 if (len(loc.zones) == 0) { abort("time::chrono: Timezone has no zones"); }; if (len(loc.zones) == 1) { return &loc.zones[0]; }; let trs = loc.transitions[..]; if (len(trs) == 0 || time::compare(inst, trs[0].when) == -1) { // TODO: special case abort("lookupzone(): time is before known transitions"); }; // index of transition which inst is equal to or greater than. const idx = -1 + sort::rbisect( trs, size(transition), &inst, &cmpinstants, ); const z = &loc.zones[trs[idx].zoneindex]; // if we've reached the end of the locality's transitions, try its // posix_extend string // // TODO: Unfinished; complete. if (idx == len(trs) - 1 && loc.posix_extend != "") { void; }; return z; }; fn cmpinstants(a: const *opaque, b: const *opaque) int = { let a = a: *transition; let b = b: *time::instant; return time::compare(a.when, *b): int; }; // Creates a [[timezone]] with a single [[zone]]. Useful for fixed offsets. // For example, replicate the civil time Hawaii timezone on Earth: // // let hawaii = chrono::fixedzone(&chrono::utc, chrono::EARTH_DAY, // chrono::zone { // zoff = -10 * time::HOUR, // name = "Hawaiian Reef", // abbr = "HARE", // dst = false, // }, // ); // export fn fixedzone(ts: *timescale, daylen: time::duration, z: zone) timezone = { return timezone { name = z.name, timescale = ts, daylength = daylen, zones = alloc([z]), transitions = [], posix_extend = "", }; }; // The local [[locality]]; the system or environment configured [[timezone]]. // // This is set during the program's initialization. In order of preference, the // TZ environment variable is used, if set; the file at [[LOCALTIME_PATH]], if // present; or, as a last resort, [[UTC]] is used as a default. export const LOCAL: locality = &TZ_UTC; @init fn init_tz_local() void = { let path = match (os::getenv("TZ")) { case let path: str => // remove POSIX prefix ':' yield if (strings::hasprefix(path, ':')) { yield strings::sub(path, 1, strings::end); } else { yield path; }; case void => yield match (os::realpath(LOCALTIME_PATH)) { case let path: str => yield path; case => return; }; }; match (tz(path)) { case => void; case let loc: locality => LOCAL = loc; }; }; @fini fn free_tz_local() void = { if (LOCAL != UTC) { timezone_free(LOCAL); }; }; // The UTC (Coordinated Universal Time) "Zulu" [[timezone]] as a [[locality]]. export const UTC: locality = &TZ_UTC; const TZ_UTC: timezone = timezone { name = "UTC", timescale = &utc, daylength = EARTH_DAY, zones = [ zone { zoff = 0 * time::SECOND, name = "Universal Coordinated Time", abbr = "UTC", dst = false, }, ], transitions = [], posix_extend = "", }; // The TAI (International Atomic Time) "Zulu" [[timezone]] as a [[locality]]. export const TAI: locality = &TZ_TAI; const TZ_TAI: timezone = timezone { name = "TAI", timescale = &tai, daylength = EARTH_DAY, zones = [ zone { zoff = 0 * time::SECOND, name = "International Atomic Time", abbr = "TAI", dst = false, }, ], transitions = [], posix_extend = "", }; // The GPS (Global Positioning System) "Zulu" [[timezone]] as a [[locality]]. export const GPS: locality = &TZ_GPS; const TZ_GPS: timezone = timezone { name = "GPS", timescale = &gps, daylength = EARTH_DAY, zones = [ zone { zoff = 0 * time::SECOND, name = "Global Positioning System", abbr = "GPS", dst = false, }, ], transitions = [], posix_extend = "", }; // The TT (Terrestrial Time) "Zulu" [[timezone]] as a [[locality]]. export const TT: locality = &TZ_TT; const TZ_TT: timezone = timezone { name = "TT", timescale = &tt, daylength = EARTH_DAY, zones = [ zone { zoff = 0 * time::SECOND, name = "Terrestrial Time", abbr = "TT", dst = false, }, ], transitions = [], posix_extend = "", }; // The MTC (Coordinated Mars Time) "Zulu" [[timezone]] as a [[locality]]. export const MTC: locality = &TZ_MTC; const TZ_MTC: timezone = timezone { name = "MTC", timescale = &mtc, daylength = MARS_SOL_MARTIAN, zones = [ zone { zoff = 0 * time::SECOND, name = "Coordinated Mars Time", abbr = "MTC", dst = false, }, ], transitions = [], posix_extend = "", }; hare-0.24.2/time/chrono/tzdb.ha000066400000000000000000000167221464473310100162340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use bytes; use encoding::utf8; use endian; use fs; use io; use os; use path; use strings; use time; // Error concerning the Timezone database. export type tzdberror = !(invalidtzif | fs::error | io::error); // Invalid TZif data. export type invalidtzif = !void; // Finds, loads, and allocates a [[timezone]] from the system's Timezone // database (TZDB), and returns it as a [[locality]]. Each call returns a new // instance. The caller must free the return value; see [[timezone_free]]. // // The system TZDB is normally located at [[TZDB_PATH]]. The timezone // filepath is resolved by appending the name argument to this prefix path. // If [name] is a full filepath (begins with '/'), it is used directly instead. // // All localities returned default to the [[utc]] [[timescale]] and // [[EARTH_DAY]] day-length. export fn tz(name: str) (locality | tzdberror) = { const filepath = if (!strings::hasprefix(name, TZDB_PATH)) path::init(TZDB_PATH, name)! else path::init(name)!; const file = os::open(path::string(&filepath))?; static let buf: [os::BUFSZ]u8 = [0...]; const bufstrm = bufio::init(file, buf, []); let loc = alloc(timezone { name = strings::dup(name), timescale = &utc, daylength = EARTH_DAY, ... }); match (load_tzif(&bufstrm, loc)) { case void => io::close(&bufstrm)?; io::close(file)?; return loc; case invalidtzif => io::close(&bufstrm): void; io::close(file): void; return invalidtzif; case let err: io::error => io::close(&bufstrm): void; io::close(file): void; return err; }; }; // Loads data of the TZif "Time Zone Information Format", and initialises the // fields "zones", "transitions", and "posix_extend" of the given [[timezone]]. // // See: https://datatracker.ietf.org/doc/html/rfc8536 fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error) = { const buf1: [1]u8 = [0...]; const buf4: [4]u8 = [0...]; const buf8: [8]u8 = [0...]; const buf15: [15]u8 = [0...]; // test for magic "TZif" mustread(h, buf4)?; if (!bytes::equal(buf4, ['T', 'Z', 'i', 'f'])) { return invalidtzif; }; // read version mustread(h, buf1)?; const version = switch (buf1[0]) { case 0 => yield 1; case '2' => yield 2; case '3' => yield 3; case => return invalidtzif; }; // skip padding mustread(h, buf15)?; // read counts mustread(h, buf4)?; let isutcnt = endian::begetu32(buf4); mustread(h, buf4)?; let isstdcnt = endian::begetu32(buf4); mustread(h, buf4)?; let leapcnt = endian::begetu32(buf4); mustread(h, buf4)?; let timecnt = endian::begetu32(buf4); mustread(h, buf4)?; let typecnt = endian::begetu32(buf4); mustread(h, buf4)?; let charcnt = endian::begetu32(buf4); let is64 = false; if (version > 1) { is64 = true; // skip to the version 2 data const skip = ( // size of version 1 data block timecnt * 4 + timecnt + typecnt * 6 + charcnt + leapcnt * 8 + isstdcnt + isutcnt // size of version 2 header + 20 ); for (let i = 0z; i < skip; i += 1) { mustread(h, buf1)?; }; // read version 2 counts mustread(h, buf4)?; isutcnt = endian::begetu32(buf4); mustread(h, buf4)?; isstdcnt = endian::begetu32(buf4); mustread(h, buf4)?; leapcnt = endian::begetu32(buf4); mustread(h, buf4)?; timecnt = endian::begetu32(buf4); mustread(h, buf4)?; typecnt = endian::begetu32(buf4); mustread(h, buf4)?; charcnt = endian::begetu32(buf4); }; if (typecnt == 0 || charcnt == 0) { return invalidtzif; }; if (!(isutcnt == 0 || isutcnt == typecnt) && (isstdcnt == 0 && isstdcnt == typecnt)) { return invalidtzif; }; const timesz = if (is64) 8 else 4; // read data const transition_times: []i64 = []; if (is64) { readitems8(h, &transition_times, timecnt)?; } else { readitems4(h, &transition_times, timecnt)?; }; defer free(transition_times); const zone_indicies: []u8 = []; readbytes(h, &zone_indicies, timecnt)?; defer free(zone_indicies); const zonedata: []u8 = []; readbytes(h, &zonedata, typecnt * 6)?; defer free(zonedata); const abbrdata: []u8 = []; readbytes(h, &abbrdata, charcnt)?; defer free(abbrdata); const leapdata: []u8 = []; readbytes(h, &leapdata, leapcnt * (timesz: u32 + 4))?; defer free(leapdata); const stdwalldata: []u8 = []; readbytes(h, &stdwalldata, isstdcnt)?; defer free(stdwalldata); const normlocaldata: []u8 = []; readbytes(h, &normlocaldata, isutcnt)?; defer free(normlocaldata); // read footer let footerdata: []u8 = []; defer free(footerdata); mustread(h, buf1)?; if (buf1[0] != 0x0A) { // '\n' newline return invalidtzif; }; for (true) { mustread(h, buf1)?; if (buf1[0] == 0x0A) { // '\n' newline break; }; if (buf1[0] == 0x0) { // cannot contain NUL return invalidtzif; }; append(footerdata, buf1...); }; const posix_extend = strings::dup(match (strings::fromutf8(footerdata)) { case let s: str => yield s; case utf8::invalid => return invalidtzif; }); // assemble structured data // assemble zones let zones: []zone = []; for (let i = 0z; i < typecnt; i += 1) { const idx = i * 6; const zone = zone { ... }; // offset const zoff = endian::begetu32(zonedata[idx..idx + 4]): i32; if (zoff == -2147483648) { // -2^31 return invalidtzif; }; zone.zoff = zoff * time::SECOND; // daylight saving time indicator zone.dst = switch (zonedata[idx + 4]) { case 1u8 => yield true; case 0u8 => yield false; case => return invalidtzif; }; // abbreviation const abbridx = zonedata[idx + 5]; if (abbridx < 0 || abbridx > (charcnt - 1)) { return invalidtzif; }; let bytes: []u8 = []; for (let j = abbridx; j < len(abbrdata); j += 1) { if (abbrdata[j] == 0x0) { bytes = abbrdata[abbridx..j]; break; }; }; if (len(bytes) == 0) { // no NUL encountered return invalidtzif; }; const abbr = match (strings::fromutf8(bytes)) { case let s: str => yield s; case utf8::invalid => return invalidtzif; }; zone.abbr = strings::dup(abbr); append(zones, zone); }; // assemble transitions let transitions: []transition = []; for (let i = 0z; i < timecnt; i += 1) { const zoneindex = zone_indicies[i]; if (zoneindex < 0 || zoneindex > (typecnt - 1)) { return invalidtzif; }; const tx = transition { when = time::instant { sec = transition_times[i], ... }, zoneindex = zoneindex, }; // stdwalldata and normlocaldata have been omitted, // until they show their utility. append(transitions, tx); }; // commit and return data tz.zones = zones; tz.transitions = transitions; tz.posix_extend = posix_extend; }; fn mustread(h: io::handle, buf: []u8) (void | invalidtzif | io::error) = { match (io::readall(h, buf)) { case let err: io::error => return err; case io::EOF => return invalidtzif; case size => return; }; }; fn readbytes( h: io::handle, items: *[]u8, n: size, ) (void | invalidtzif | io::error) = { const buf: [1]u8 = [0]; for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = buf[0]; append(items, it); }; }; fn readitems8( h: io::handle, items: *[]i64, n: size, ) (void | invalidtzif | io::error) = { const buf: [8]u8 = [0...]; for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = endian::begetu64(buf): i64; append(items, it); }; }; fn readitems4( h: io::handle, items: *[]i64, n: size, ) (void | invalidtzif | io::error) = { const buf: [4]u8 = [0...]; for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = endian::begetu32(buf): i64; append(items, it); }; }; hare-0.24.2/time/conv.ha000066400000000000000000000005471464473310100147440ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Converts a given [[instant]] to a Unix timestamp. // Note, nanosecond information is lost during conversion. export fn unix(i: instant) i64 = i.sec; // Converts a given Unix timestamp to an [[instant]]. export fn from_unix(u: i64) instant = instant { sec = u, nsec = 0, }; hare-0.24.2/time/date/000077500000000000000000000000001464473310100143745ustar00rootroot00000000000000hare-0.24.2/time/date/README000066400000000000000000000026541464473310100152630ustar00rootroot00000000000000The time::date module implements the common international Gregorian chronology, based on the astronomically numbered proleptic Gregorian calendar and the ISO week-numbering calendar, as per the ISO 8601 standard, and the common 24 hour clock. It provides [[date]], a representation of civil date/time and a optimized extension of the [[time::chrono::moment]] type. The [[time::chrono::]] module has many useful functions which interoperate with dates. Any [[time::chrono::]] function which accepts *moment also accepts *date. Dates are created using [[new]], [[now]], [[localnow]], or a "from_" function. Alternatively, the [[virtual]]/[[realize]] interface can handle uncertain or invalid date/time information, and construct new dates incrementally and safely. The observer functions ([[year]], [[hour]], etc.) evaluate a date's observed chronological values, adjusted for its associated [[time::chrono::locality]]. Use [[in]] to localize a date to another locality; consult [[time::chrono::tz]]. See [[parse]] and [[format]] for working with date/time strings. Date arithmetic operations are categorized into "timescalar" or "chronological". Timescalar uses [[time::duration]]; see [[add]], [[time::chrono::diff]]. Chronological uses [[period]]; see [[reckon]], [[pdiff]], [[unitdiff]], [[truncate]]. Note that calendrical arithmetic is highly irregular due to field overflows and timezone discontinuities, so think carefully about what you want. hare-0.24.2/time/date/constants.ha000066400000000000000000000024621464473310100167260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Ordinal for the month of January. export def JANUARY: int = 1; // Ordinal for the month of February. export def FEBRUARY: int = 2; // Ordinal for the month of March. export def MARCH: int = 3; // Ordinal for the month of April. export def APRIL: int = 4; // Ordinal for the month of May. export def MAY: int = 5; // Ordinal for the month of June. export def JUNE: int = 6; // Ordinal for the month of July. export def JULY: int = 7; // Ordinal for the month of August. export def AUGUST: int = 8; // Ordinal for the month of September. export def SEPTEMBER: int = 9; // Ordinal for the month of October. export def OCTOBER: int = 10; // Ordinal for the month of November. export def NOVEMBER: int = 11; // Ordinal for the month of December. export def DECEMBER: int = 12; // Ordinal for the weekday Monday. export def MONDAY: int = 0; // Ordinal for the weekday Tuesday. export def TUESDAY: int = 1; // Ordinal for the weekday Wednesday. export def WEDNESDAY: int = 2; // Ordinal for the weekday Thursday. export def THURSDAY: int = 3; // Ordinal for the weekday Friday. export def FRIDAY: int = 4; // Ordinal for the weekday Saturday. export def SATURDAY: int = 5; // Ordinal for the weekday Sunday. export def SUNDAY: int = 6; hare-0.24.2/time/date/date.ha000066400000000000000000000227201464473310100156260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; use time::chrono; // Invalid [[date]]. export type invalid = !chrono::invalid; // A date/time object; a [[time::chrono::moment]] wrapper optimized for the // Gregorian chronology, and by extension a [[time::instant]] wrapper. // // This object should be treated as private and immutable. Directly mutating its // fields causes undefined behaviour when used with module functions. Likewise, // interrogating the fields' type and value (e.g. using match statements) is // also improper. // // A date observes various chronological values, cached in its fields. To // evaluate and obtain these values, use the various observer functions // ([[year]], [[hour]], etc.). These values are derived from the embedded moment // information, and thus are guaranteed to be valid. // // See [[virtual]] for an public, mutable, intermediary representation of a // date, which waives guarantees of validity. export type date = struct { chrono::moment, era: (void | int), year: (void | int), month: (void | int), day: (void | int), yearday: (void | int), isoweekyear: (void | int), isoweek: (void | int), week: (void | int), sundayweek: (void | int), weekday: (void | int), hour: (void | int), minute: (void | int), second: (void | int), nanosecond: (void | int), }; fn init() date = date { sec = 0, nsec = 0, loc = chrono::UTC, zone = null, daydate = void, daytime = void, era = void, year = void, month = void, day = void, yearday = void, isoweekyear = void, isoweek = void, week = void, sundayweek = void, weekday = void, hour = void, minute = void, second = void, nanosecond = void, }; // Evaluates and populates all of a [[date]]'s fields. fn all(d: *date) *date = { _era(d); _year(d); _month(d); _day(d); _yearday(d); _isoweekyear(d); _isoweek(d); _week(d); _sundayweek(d); _weekday(d); _hour(d); _minute(d); _second(d); _nanosecond(d); return d; }; // Creates a new [[date]]. Accepts a [[time::chrono::locality]], a zone-offset, // and up to seven nominal fields applied in the following order: // // - year // - month // - day // - hour // - minute // - second // - nanosecond // // 8 or more fields causes an abort. If omitted, the month and day default to 1, // and the rest default to 0. // // If the desired zone-offset is known, it can be given as a [[time::duration]]. // Otherwise, use a zflag. See [[zflag]] on its effects to the result. // // An invalid combination of provided date/time/zoff values returns [[invalid]]. // // Examples: // // // 0000-01-01 00:00:00.000000000 +0000 UTC UTC // date::new(time::chrono::UTC, date::zflag::CONTIG); // // // 2000-01-02 15:04:05.600000000 +0000 UTC UTC // date::new(time::chrono::UTC, 0, // 2000, 1, 2, 15, 4, 5, 600000000); // // // 2000-01-02 15:00:00.000000000 +0100 CET Europe/Amsterdam // date::new(time::chrono::tz("Europe/Amsterdam")!, // 1 * time::HOUR, // standard time in January // 2000, 1, 2, 15); // // // Could return [[zfunresolved]] by encountering a timezone transition. // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::CONTIG, // fields...); // // // Will never return [[zfunresolved]]. // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::LAP_EARLY | date::zflag::GAP_END, // fields...); // // // On this day in Amsterdam, the clock jumped +1 hour at 02:00. // // 02:30 is never observed. Note the difference in zone-offset. // // // // 2000-03-26 01:59:59.999999999 +0100 CET Europe/Amsterdam // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::GAP_START, // 2000, 3, 26, 2, 30); // // // // 2000-03-26 03:00:00.000000000 +0200 CET Europe/Amsterdam // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::GAP_END, // 2000, 3, 26, 2, 30); // // // On this day in Amsterdam, the clock jumped -1 hour at 03:00. // // 02:30 is observed twice. Note the difference in zone-offset. // // // // 2000-10-29 02:30:00.000000000 +0200 CET Europe/Amsterdam // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::LAP_EARLY, // 2000, 10, 29, 2, 30); // // // // 2000-10-29 02:30:00.000000000 +0100 CET Europe/Amsterdam // date::new(time::chrono::tz("Europe/Amsterdam")!, // date::zflag::LAP_LATE, // 2000, 10, 29, 2, 30); // export fn new( loc: chrono::locality, zoff: (time::duration | zflag), fields: int... ) (date | invalid | zfunresolved) = { let _fields: [_]int = [ 0, 1, 1, // year month day 0, 0, 0, 0, // hour min sec nsec ]; assert(len(fields) <= len(_fields), "time::date::new(): Too many field arguments"); _fields[..len(fields)] = fields; let v = newvirtual(); v.vloc = loc; v.zoff = zoff; v.year = _fields[0]; v.month = _fields[1]; v.day = _fields[2]; v.hour = _fields[3]; v.minute = _fields[4]; v.second = _fields[5]; v.nanosecond = _fields[6]; let d = (realize(v, loc) as (date | invalid | zfunresolved))?; // if zflag::GAP_START or zflag::GAP_END was not specified, // check if input values are actually observed if ( // TODO: check observe values outside of gap? zoff is zflag && zoff as zflag & (zflag::GAP_START | zflag::GAP_END) == 0 ) { if ( _fields[0] != _year(&d) || _fields[1] != _month(&d) || _fields[2] != _day(&d) || _fields[3] != _hour(&d) || _fields[4] != _minute(&d) || _fields[5] != _second(&d) || _fields[6] != _nanosecond(&d) ) { return invalid; }; }; return d; }; // Returns a [[date]] of the current system time using // [[time::clock::REALTIME]], in the [[time::chrono::UTC]] locality. export fn now() date = { return from_instant(chrono::UTC, time::now(time::clock::REALTIME)); }; // Returns a [[date]] of the current system time using // [[time::clock::REALTIME]], in the [[time::chrono::LOCAL]] locality. export fn localnow() date = { return from_instant(chrono::LOCAL, time::now(time::clock::REALTIME)); }; // Creates a [[date]] from a [[time::chrono::moment]]. export fn from_moment(m: chrono::moment) date = { const d = init(); d.loc = m.loc; d.sec = m.sec; d.nsec = m.nsec; d.daydate = m.daydate; d.daytime = m.daytime; d.zone = m.zone; return d; }; // Creates a [[date]] from a [[time::instant]] in a [[time::chrono::locality]]. export fn from_instant(loc: chrono::locality, i: time::instant) date = { return from_moment(chrono::new(loc, i)); }; // Creates a [[date]] from a string, parsed according to a layout format. // See [[parse]] and [[format]]. Example: // // let new = date::from_str( // date::STAMPLOC, // "2000-01-02 15:04:05.600000000 +0100 CET Europe/Amsterdam", // chrono::tz("Europe/Amsterdam")! // )!; // // At least a complete calendar date has to be provided. If the hour, minute, // second, or nanosecond values are not provided, they default to 0. // If the zone-offset or zone-abbreviation are not provided, the [[zflags]]s // LAP_EARLY and GAP_END are used. // // The date's [[time::chrono::locality]] will be selected from the provided // locality arguments. The 'name' field of these localities will be matched // against the parsed result of the %L specifier. If %L is not specified, // or if no locality is provided, [[time::chrono::UTC]] is used. export fn from_str( layout: str, s: str, locs: chrono::locality... ) (date | parsefail | insufficient | invalid) = { const v = newvirtual(); v.zoff = zflag::LAP_EARLY | zflag::GAP_END; v.hour = 0; v.minute = 0; v.second = 0; v.nanosecond = 0; parse(&v, layout, s)?; if (v.locname is void || len(locs) == 0) { v.vloc = chrono::UTC; }; return realize(v, locs...) as (date | insufficient | invalid); }; @test fn from_str() void = { let testcases: [_](str, str, []chrono::locality, (date | error)) = [ (STAMPLOC, "2001-02-03 15:16:17.123456789 +0000 UTC UTC", [], new(chrono::UTC, 0, 2001, 2, 3, 15, 16, 17, 123456789)!), (STAMP, "2001-02-03 15:16:17", [], new(chrono::UTC, 0, 2001, 2, 3, 15, 16, 17)!), (RFC3339, "2001-02-03T15:16:17+0000", [], new(chrono::UTC, 0, 2001, 2, 3, 15, 16, 17)!), ("%F", "2009-06-30", [], new(chrono::UTC, 0, 2009, 6, 30)!), ("%F %L", "2009-06-30 GPS", [chrono::TAI, chrono::GPS], new(chrono::GPS, 0, 2009, 6, 30)!), ("%F %T", "2009-06-30 01:02:03", [], new(chrono::UTC, 0, 2009, 6, 30, 1, 2, 3)!), ("%FT%T%z", "2009-06-30T18:30:00Z", [], new(chrono::UTC, 0, 2009, 6, 30, 18, 30)!), ("%FT%T.%N%z", "2009-06-30T18:30:00.987654321Z", [], new(chrono::UTC, 0, 2009, 6, 30, 18, 30, 0, 987654321)!), // TODO: for the tests overhaul, when internal test timezones // are available, check for %L //("%FT%T%z %L", "2009-06-30T18:30:00+0200 Europe/Amsterdam", [amst], // new(amst, 2 * time::HOUR, 2009, 6, 30, 18, 30)!), ("%Y", "a", [], (0z, 'a'): parsefail), ("%X", "2008", [], (0z, '2'): parsefail), ]; let buf: [64]u8 = [0...]; for (let tc .. testcases) { const expect = tc.3; const actual = from_str(tc.0, tc.1, tc.2...); match (expect) { case let e: date => assert(actual is date, "wanted 'date', got 'error'"); assert(chrono::simultaneous(&(actual as date), &e)!, "incorrect 'date' value"); case let e: parsefail => assert(actual is parsefail, "wanted 'parsefail', got other"); case insufficient => assert(actual is insufficient, "wanted 'insufficient', got other"); case invalid => assert(actual is invalid, "wanted 'invalid', got other"); }; }; }; hare-0.24.2/time/date/daydate.ha000066400000000000000000000347111464473310100163270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Hare internally uses the Unix epoch (1970-01-01) for calendrical logic. Here // we provide useful constant for working with the astronomically numbered // proleptic Gregorian calendar, as offsets from the Hare epoch. // The Hare epochal day of the Julian Day Number. export def EPOCHDAY_JULIAN: i64 = -2440588; // The Hare epochal day of the Gregorian Common Era. export def EPOCHDAY_GREGORIAN: i64 = -719164; // Number of days in the Gregorian 400 year cycle def GREGORIAN_CYCLE_DAYS: i64 = 146097; fn has(item: int, list: int...) bool = { for (let member .. list) { if (member == item) { return true; }; }; return false; }; // Calculates whether a year is a leap year. export fn isleapyear(y: int) bool = { return if (y % 4 != 0) false else if (y % 100 != 0) true else if (y % 400 != 0) false else true; }; // Calculates whether a given year, month, and day-of-month, is a valid date. fn is_valid_ymd(y: int, m: int, d: int) bool = { return m >= 1 && m <= 12 && d >= 1 && d <= calc_days_in_month(y, m); }; // Calculates whether a given year, and day-of-year, is a valid date. fn is_valid_yd(y: int, yd: int) bool = { return yd >= 1 && yd <= calc_days_in_year(y); }; // Calculates the number of days in the given month of the given year. fn calc_days_in_month(y: int, m: int) int = { const days_per_month: [_]int = [ 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; if (m == 2) { return if (isleapyear(y)) 29 else 28; } else { return days_per_month[m - 1]; }; }; // Calculates the number of days in a given year. fn calc_days_in_year(y: int) int = { return if (isleapyear(y)) 366 else 365; }; // Calculates the day-of-week of January 1st, given a year. fn calc_janfirstweekday(y: int) int = { const y = (y % 400) + 400; // keep year > 0 (using Gregorian cycle) // Gauss' algorithm const wd = (5 * ((y - 1) % 4) + 4 * ((y - 1) % 100) + 6 * ((y - 1) % 400) ) % 7; return wd; }; // Calculates whether an ISO week-numbering year has // 53 weeks (long) or 52 weeks (short). fn islongisoyear(y: int) bool = { const jan1 = calc_janfirstweekday(y); return jan1 == THURSDAY || (isleapyear(y) && jan1 == WEDNESDAY); }; // Calculates the era, given a year. fn calc_era(y: int) int = { return if (y >= 0) { yield 1; // CE "Common Era" } else { yield 0; // BCE "Before Common Era" }; }; // Calculates the year, month, and day-of-month, given an epochal day. fn calc_ymd(e: i64) (int, int, int) = { // Algorithm adapted from: // https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number // // TODO: Review, cite, verify, annotate. // workaround for dates before -4716 March 1st let E = e; let cycles = 0; for (E < -2441951) { E += GREGORIAN_CYCLE_DAYS; cycles += 1; }; const J = E - EPOCHDAY_JULIAN; const b = 274277; const c = -38; const j = 1401; const m = 2; const n = 12; const p = 1461; const r = 4; const s = 153; const u = 5; const v = 3; const w = 2; const y = 4716; const f = J + j + (((4 * J + b) / GREGORIAN_CYCLE_DAYS) * 3) / 4 + c; const a = r * f + v; const g = (a % p) / r; const h = u * g + w; const D = (h % s) / u + 1; const M = ((h / s + m) % n) + 1; const Y = (a / p) - y + (n + m - M) / n; const Y = Y - (400 * cycles); return (Y: int, M: int, D: int); }; // Calculates the day-of-year, given a year, month, and day-of-month. fn calc_yearday(y: int, m: int, d: int) int = { const months_firsts: [_]int = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, ]; if (m > FEBRUARY && isleapyear(y)) { return months_firsts[m - 1] + d + 1; } else { return months_firsts[m - 1] + d; }; }; // Calculates the ISO week-numbering year, // given a year, month, day-of-month, and day-of-week. fn calc_isoweekyear(y: int, m: int, d: int, wd: int) int = { if ( // if the date is within a week whose Thursday // belongs to the previous Gregorian year m == JANUARY && ( (d == 1 && has(wd, FRIDAY, SATURDAY, SUNDAY)) || (d == 2 && has(wd, SATURDAY, SUNDAY)) || (d == 3 && has(wd, SUNDAY)) ) ) { return y - 1; } else if ( // if the date is within a week whose Thursday // belongs to the next Gregorian year m == DECEMBER && ( (d == 29 && has(wd, MONDAY)) || (d == 30 && has(wd, MONDAY, TUESDAY)) || (d == 31 && has(wd, MONDAY, TUESDAY, WEDNESDAY)) ) ) { return y + 1; } else { return y; }; }; // Calculates the ISO week, // given a year, and week. fn calc_isoweek(y: int, w: int) int = { switch (w) { case 0 => return if (islongisoyear(y - 1)) 53 else 52; case 53 => return if (islongisoyear(y)) 53 else 1; case => return w; }; }; // Calculates the week within a Gregorian year [0..53], // given a day-of-year and day-of-week. // All days in a year before the year's first Monday belong to week 0. fn calc_week(yd: int, wd: int) int = { return (yd - wd + 9) / 7; }; // Calculates the week within a Gregorian year [0..53], // given a day-of-year and day-of-week. // All days in a year before the year's first Sunday belong to week 0. fn calc_sundayweek(yd: int, wd: int) int = { return (yd + 6 - ((wd + 1) % 7)) / 7; }; // Calculates the day-of-week, given a epochal day, // from Monday=0 to Sunday=6. fn calc_weekday(e: i64) int = { const wd = ((e + 3) % 7): int; return (wd + 7) % 7; }; // Calculates the daydate, // given a year, month, and day-of-month. fn calc_daydate__ymd(y: int, m: int, d: int) (i64 | invalid) = { if (!is_valid_ymd(y, m, d)) { return invalid; }; // Algorithm adapted from: // https://en.wikipedia.org/wiki/Julian_day // // TODO: Review, cite, verify, annotate. // workaround for dates before -4800 March 1st let Y = y; let cycles = 0; for (Y <= -4800) { Y += 400; // Gregorian 400 year cycle cycles += 1; }; const jdn = ( // Julian Date Number (1461 * (Y + 4800 + (m - 14) / 12)) / 4 + (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - (3 * ((Y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075 ); const e = jdn + EPOCHDAY_JULIAN - (GREGORIAN_CYCLE_DAYS * cycles); return e; }; // Calculates the daydate, // given a year, week, and day-of-week. fn calc_daydate__ywd(y: int, w: int, wd: int) (i64 | invalid) = { const jan1wd = calc_janfirstweekday(y); const yd = wd - jan1wd + 7 * w; return calc_daydate__yd(y, yd)?; }; // Calculates the daydate, // given a year and day-of-year. fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = { if (yd < 1 || yd > calc_days_in_year(y)) { return invalid; }; return calc_daydate__ymd(y, 1, 1)? + yd - 1; }; @test fn calc_daydate__ymd() void = { const cases = [ (( -768, 2, 5), -999999, false), (( -1, 12, 31), -719529, false), (( 0, 1, 1), -719528, false), (( 0, 1, 2), -719527, false), (( 0, 12, 31), -719163, false), (( 1, 1, 1), -719162, false), (( 1, 1, 2), -719161, false), (( 1965, 3, 23), -1745, false), (( 1969, 12, 31), -1, false), (( 1970, 1, 1), 0, false), (( 1970, 1, 2), 1, false), (( 1999, 12, 31), 10956, false), (( 2000, 1, 1), 10957, false), (( 2000, 1, 2), 10958, false), (( 2038, 1, 18), 24854, false), (( 2038, 1, 19), 24855, false), (( 2038, 1, 20), 24856, false), (( 2243, 10, 17), 100000, false), (( 4707, 11, 28), 999999, false), (( 4707, 11, 29), 1000000, false), ((29349, 1, 25), 9999999, false), (( 1970,-99,-99), 0, true), (( 1970, -9, -9), 0, true), (( 1970, -1, -1), 0, true), (( 1970, 0, 0), 0, true), (( 1970, 0, 1), 0, true), (( 1970, 1, 99), 0, true), (( 1970, 99, 99), 0, true), ]; for (let (params, expect, should_error) .. cases) { const actual = calc_daydate__ymd( params.0, params.1, params.2, ); if (should_error) { assert(actual is invalid, "invalid date accepted"); } else { assert(actual is i64, "valid date not accepted"); assert(actual as i64 == expect, "date miscalculation"); }; }; }; @test fn calc_daydate__ywd() void = { const cases = [ (( -768, 0, 4), -1000034), (( -768, 5, 4), -999999), (( -1, 52, 5), -719529), (( 0, 0, 6), -719528), (( 0, 0, 7), -719527), (( 0, 52, 7), -719163), (( 1, 0, 1), -719162), (( 1, 0, 2), -719161), (( 1965, 12, 2), -1745), (( 1969, 52, 3), -1), (( 1970, 0, 4), 0), (( 1970, 0, 5), 1), (( 1999, 52, 5), 10956), (( 2000, 0, 6), 10957), (( 2000, 0, 7), 10958), (( 2020, 0, 3), 18262), (( 2022, 9, 1), 19051), (( 2022, 9, 2), 19052), (( 2023, 51, 7), 19715), (( 2024, 8, 3), 19781), (( 2024, 8, 4), 19782), (( 2024, 8, 5), 19783), (( 2024, 49, 4), 20069), (( 2024, 52, 2), 20088), (( 2038, 3, 1), 24854), (( 2038, 3, 2), 24855), (( 2038, 3, 3), 24856), (( 2243, 41, 2), 99993), (( 4707, 47, 4), 999999), (( 4707, 47, 5), 1000000), ((29349, 3, 6), 9999999), ]; for (let (ywd, expected) .. cases) { const actual = calc_daydate__ywd(ywd.0, ywd.1, ywd.2)!; assert(actual == expected, "incorrect calc_daydate__ywd() result"); }; }; @test fn calc_daydate__yd() void = { const cases = [ ( -768, 36, -999999), ( -1, 365, -719529), ( 0, 1, -719528), ( 0, 2, -719527), ( 0, 366, -719163), ( 1, 1, -719162), ( 1, 2, -719161), ( 1965, 82, -1745 ), ( 1969, 365, -1 ), ( 1970, 1, 0 ), ( 1970, 2, 1 ), ( 1999, 365, 10956 ), ( 2000, 1, 10957 ), ( 2000, 2, 10958 ), ( 2038, 18, 24854 ), ( 2038, 19, 24855 ), ( 2038, 20, 24856 ), ( 2243, 290, 100000 ), ( 4707, 332, 999999 ), ( 4707, 333, 1000000), (29349, 25, 9999999), ]; for (let (y, yd, expected) .. cases) { const actual = calc_daydate__yd(y, yd)!; assert(expected == actual, "error in date calculation from yd"); }; assert(calc_daydate__yd(2020, 0) is invalid, "calc_daydate__yd() did not reject invalid yearday"); assert(calc_daydate__yd(2020, 400) is invalid, "calc_daydate__yd() did not reject invalid yearday"); }; @test fn calc_ymd() void = { const cases = [ (-999999, ( -768, 2, 5)), (-719529, ( -1, 12, 31)), (-719528, ( 0, 1, 1)), (-719527, ( 0, 1, 2)), (-719163, ( 0, 12, 31)), (-719162, ( 1, 1, 1)), (-719161, ( 1, 1, 2)), ( -1745, ( 1965, 3, 23)), ( -1, ( 1969, 12, 31)), ( 0, ( 1970, 1, 1)), ( 1, ( 1970, 1, 2)), ( 10956, ( 1999, 12, 31)), ( 10957, ( 2000, 1, 1)), ( 10958, ( 2000, 1, 2)), ( 24854, ( 2038, 1, 18)), ( 24855, ( 2038, 1, 19)), ( 24856, ( 2038, 1, 20)), ( 100000, ( 2243, 10, 17)), ( 999999, ( 4707, 11, 28)), (1000000, ( 4707, 11, 29)), (9999999, (29349, 1, 25)), ]; for (let (paramt, expect) .. cases) { const actual = calc_ymd(paramt); assert(expect.0 == actual.0, "year mismatch"); assert(expect.1 == actual.1, "month mismatch"); assert(expect.2 == actual.2, "day mismatch"); }; }; @test fn calc_yearday() void = { const cases = [ (( -768, 2, 5), 36), (( -1, 12, 31), 365), (( 0, 1, 1), 1), (( 0, 1, 2), 2), (( 0, 12, 31), 366), (( 1, 1, 1), 1), (( 1, 1, 2), 2), (( 1965, 3, 23), 82), (( 1969, 12, 31), 365), (( 1970, 1, 1), 1), (( 1970, 1, 2), 2), (( 1999, 12, 31), 365), (( 2000, 1, 1), 1), (( 2000, 1, 2), 2), (( 2020, 2, 12), 43), (( 2038, 1, 18), 18), (( 2038, 1, 19), 19), (( 2038, 1, 20), 20), (( 2243, 10, 17), 290), (( 4707, 11, 28), 332), (( 4707, 11, 29), 333), ((29349, 1, 25), 25), ]; for (let (params, expect) .. cases) { const actual = calc_yearday(params.0, params.1, params.2); assert(expect == actual, "yearday miscalculation"); }; }; @test fn calc_week() void = { const cases = [ (( 1, 0), 1), (( 1, 1), 1), (( 1, 2), 1), (( 1, 3), 1), (( 1, 4), 0), (( 1, 5), 0), (( 1, 6), 0), (( 21, 1), 4), (( 61, 6), 9), ((193, 5), 28), ((229, 6), 33), ((286, 0), 42), ((341, 6), 49), ((365, 2), 53), ((366, 3), 53), ]; for (let (params, expect) .. cases) { const actual = calc_week(params.0, params.1); assert(expect == actual, "week miscalculation"); }; }; @test fn calc_sundayweek() void = { const cases = [ (( 1, 0), 0), (( 1, 1), 0), (( 1, 2), 0), (( 1, 3), 0), (( 1, 4), 0), (( 1, 5), 0), (( 1, 6), 1), (( 21, 1), 3), (( 61, 2), 9), ((193, 4), 27), ((229, 0), 33), ((286, 3), 41), ((341, 6), 49), ((365, 5), 52), ((366, 0), 53), ]; for (let (params, expect) .. cases) { const actual = calc_sundayweek(params.0, params.1); assert(expect == actual, "week miscalculation"); }; }; @test fn calc_weekday() void = { const cases = [ (-999999, 3), // -0768-02-05 (-719529, 4), // -0001-12-31 (-719528, 5), // 0000-01-01 (-719527, 6), // 0000-01-02 (-719163, 6), // 0000-12-31 (-719162, 0), // 0001-01-01 (-719161, 1), // 0001-01-02 ( -1745, 1), // 1965-03-23 ( -1, 2), // 1969-12-31 ( 0, 3), // 1970-01-01 ( 1, 4), // 1970-01-02 ( 10956, 4), // 1999-12-31 ( 10957, 5), // 2000-01-01 ( 10958, 6), // 2000-01-02 ( 24854, 0), // 2038-01-18 ( 24855, 1), // 2038-01-19 ( 24856, 2), // 2038-01-20 ( 100000, 1), // 2243-10-17 ( 999999, 3), // 4707-11-28 (1000000, 4), // 4707-11-29 (9999999, 5), // 29349-01-25 ]; for (let (paramt, expect) .. cases) { const actual = calc_weekday(paramt); assert(expect == actual, "weekday miscalculation"); }; }; @test fn calc_janfirstweekday() void = { const cases = [ // year weekday (1969, 2), (1970, 3), (1971, 4), (1972, 5), (1973, 0), (1974, 1), (1975, 2), (1976, 3), (1977, 5), (1978, 6), (1979, 0), (1980, 1), (1981, 3), (1982, 4), (1983, 5), (1984, 6), (1985, 1), (1986, 2), (1987, 3), (1988, 4), (1989, 6), (1990, 0), (1991, 1), (1992, 2), (1993, 4), (1994, 5), (1995, 6), (1996, 0), (1997, 2), (1998, 3), (1999, 4), (2000, 5), (2001, 0), (2002, 1), (2003, 2), (2004, 3), (2005, 5), (2006, 6), (2007, 0), (2008, 1), (2009, 3), (2010, 4), (2011, 5), (2012, 6), (2013, 1), (2014, 2), (2015, 3), (2016, 4), (2017, 6), (2018, 0), (2019, 1), (2020, 2), (2021, 4), (2022, 5), (2023, 6), (2024, 0), (2025, 2), (2026, 3), (2027, 4), (2028, 5), (2029, 0), (2030, 1), (2031, 2), (2032, 3), (2033, 5), (2034, 6), (2035, 0), (2036, 1), (2037, 3), (2038, 4), (2039, 5), ]; for (let (paramt, expect) .. cases) { const actual = calc_janfirstweekday(paramt); assert(expect == actual, "calc_janfirstweekday() miscalculation"); }; }; hare-0.24.2/time/date/daytime.ha000066400000000000000000000015531464473310100163460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; // Calculates the wall clock (hour, minute, second, nanosecond), // given a time-of-day (amount of daytime progressed in a day). fn calc_hmsn(t: i64) (int, int, int, int) = { // TODO: Special case for leap seconds, 61st second? const hour = (t / time::HOUR): int; const min = ((t / time::MINUTE) % 60): int; const sec = ((t / time::SECOND) % 60): int; const nsec = (t % time::SECOND): int; return (hour, min, sec, nsec); }; // Calculates the time-of-day (amount of daytime progressed in a day), // given a wall clock (hour, minute, second, nanosecond). fn calc_daytime__hmsn( hour: int, min: int, sec: int, nsec: int, ) (i64 | invalid) = { const t = ( (hour * time::HOUR) + (min * time::MINUTE) + (sec * time::SECOND) + (nsec * time::NANOSECOND) ); return t; }; hare-0.24.2/time/date/error.ha000066400000000000000000000024571464473310100160470ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use strings; // All possible errors returned from [[date]]. export type error = !(insufficient | invalid | zfunresolved | parsefail); // Converts an [[error]] into a human-friendly string. The result may be // statically allocated. export fn strerror(err: error) const str = { match (err) { case let lack: insufficient => static let buf: [92]u8 = [0...]; return strings::rtrim(fmt::bsprint(buf, "Insufficient date information, could not calculate:", if (lack & insufficient::LOCALITY: u8 == 0) "" else "locality", if (lack & insufficient::DAYDATE: u8 == 0) "" else "daydate", if (lack & insufficient::DAYTIME: u8 == 0) "" else "time-of-day", if (lack & insufficient::ZOFF: u8 == 0) "" else "zone-offset", )); case invalid => return "Invalid date information"; case let lap: zfunresolved => if (lap) { return "Failed to resolve zone-offset in a timezone transition overlap"; } else { return "Failed to resolve zone-offset in a timezone transition gap"; }; case let pf: parsefail => const (bi, rn) = pf; def FMTMSG = "Date parsing failure for layout rune '{}' at byteindex {}"; static let buf: [len(FMTMSG) + 3]u8 = [0...]; return fmt::bsprintf(buf, FMTMSG, rn, bi); }; }; hare-0.24.2/time/date/format.ha000066400000000000000000000230531464473310100162010ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fmt; use io; use memio; use strings; use time::chrono; // [[format]] layout for the email date format. export def EMAIL: str = "%a, %d %b %Y %H:%M:%S %z"; // [[format]] layout for the email date format, with zone offset and // zone abbreviation. export def EMAILZONE: str = "%a, %d %b %Y %H:%M:%S %z %Z"; // [[format]] layout for the POSIX locale's default date & time representation. export def POSIX: str = "%a %b %e %H:%M:%S %Y"; // [[format]] layout compatible with RFC 3339. export def RFC3339: str = "%Y-%m-%dT%H:%M:%S%z"; // [[format]] layout for a standard, collatable timestamp. export def STAMP: str = "%Y-%m-%d %H:%M:%S"; // [[format]] layout for a standard, collatable timestamp with nanoseconds. export def STAMPNANO: str = "%Y-%m-%d %H:%M:%S.%N"; // [[format]] layout for a standard, collatable timestamp with nanoseconds // and zone offset. export def STAMPZOFF: str = "%Y-%m-%d %H:%M:%S.%N %z"; // [[format]] layout for a standard, collatable timestamp with nanoseconds, // zone offset, and zone abbreviation. export def STAMPZONE: str = "%Y-%m-%d %H:%M:%S.%N %z %Z"; // [[format]] layout for a standard, collatable timestamp with nanoseconds, // zone offset, zone abbreviation, and locality. export def STAMPLOC: str = "%Y-%m-%d %H:%M:%S.%N %z %Z %L"; // [[format]] layout for an ISO week-numbering timestamp. export def ISOWKSTAMP: str = "%G-W%V-%u %H:%M:%S"; // [[format]] layout for a friendly, comprehensive datetime. export def JOURNAL: str = "%Y %b %d, %a %H:%M:%S %z %Z %L"; // [[format]] layout for a friendly, terse datetime. export def WRIST: str = "%b-%d %a %H:%M %Z"; // [[format]] layout for a precise timescalar second and nanosecond. export def QUARTZ: str = "%s.%N"; // [[format]] layout for a precise timescalar second, nanosecond, // and zone offset. export def QUARTZZOFF: str = "%s.%N%z"; // [[format]] layout for a precise timescalar second, nanosecond, // and locality. export def QUARTZLOC: str = "%s.%N:%L"; def WEEKDAYS: [_]str = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", ]; def WEEKDAYS_SHORT: [_]str = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; def MONTHS: [_]str = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; def MONTHS_SHORT: [_]str = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; // TODO: Make format() accept parameters of type (date | period), using the // "intervals" standard representation provided by ISO 8601? // // See https://en.wikipedia.org/wiki/ISO_8601#Time_intervals // // Ticket: https://todo.sr.ht/~sircmpwn/hare/650 // Formats a [[date]] and writes it into a caller supplied buffer. // The returned string is borrowed from this buffer. export fn bsformat( buf: []u8, layout: str, d: *date, ) (str | io::error) = { let sink = memio::fixed(buf); format(&sink, layout, d)?; return memio::string(&sink)!; }; // Formats a [[date]] and writes it into a heap-allocated string. // The caller must free the return value. export fn asformat(layout: str, d: *date) (str | io::error) = { let sink = memio::dynamic(); format(&sink, layout, d)?; return memio::string(&sink)!; }; // Formats a [[date]] according to a layout and writes to an [[io::handle]]. // // The layout may contain any of the following format specifiers listed below. // These specifiers emit 2 digit zero-padded decimals unless stated otherwise. // Use of unimplemented specifiers or an invalid layout will cause an abort. // // - %% : A single literal '%' character. // - %a : The day of the week, abbreviated name. ("Sun"). // - %A : The day of the week, full name. ("Sunday"). // - %b : The month, abbreviated name. ("Jan"). // - %B : The month, full name. ("January"). // - %C : The century (the year without the last 2 digits). ("20"). // - %d : The day of the month. Range 01 to 31. ("02"). // - %e : The day of the month. Range 1 to 31, // right-aligned, space-padded. (" 2"). // - %F : The full Gregorian calendar date. // Alias for "%Y-%m-%d". ("2000-01-02"). // - %G : The ISO week-numbering year. At least 4 digits. // ISO-years before the Common Era have a minus sign prefix. ("1999"). // - %H : The hour of the day of a 24-hour clock. Range 00 to 23. ("15"). // - %I : The hour of the day of a 12-hour clock. Range 01 to 12. ("03"). // - %j : The ordinal day of the year. 3 digits, range 001 to 366. ("002"). // - %L : The locality's name (the timezone identifier). ("Europe/Amsterdam"). // - %m : The month of the year. Range 01 to 12. ("01"). // - %M : The minute of the hour. Range 00 to 59. ("04"). // - %N : The nanosecond of the second. 9 digits, // range 000000000 to 999999999. ("600000000"). // - %p : The meridian indicator, either "AM" or "PM". // "AM" includes midnight, and "PM" includes noon. // - %s : The number of seconds since the locality's epoch. ("946821845"). // - %S : The second of the minute. Range 00 to 59. ("05"). // - %T : The wall-time of a 24-hour clock without nanoseconds. // Alias for "%H:%M:%S". ("15:04:05"). // - %u : The day of the week. 1 digit, range 1 to 7, Monday to Sunday. ("7"). // - %U : The sunday-week of the year. Range 00 to 53. // The year's first Sunday is the first day of week 01. ("01"). // - %V : The week of the ISO week-numbering year. Range 01 to 53. ("52"). // - %w : The day of the sunday-week. // 1 digit, range 0 to 6, Sunday to Saturday. ("0"). // - %W : The week of the year. Range 00 to 53. // The year's first Monday is the first day of week 01. ("00"). // - %y : The year's last 2 digits, no century digits. Range 00 to 99. ("00"). // - %Y : The year. At least 4 digits. // Years before the Common Era have a minus sign prefix. ("2000"). // - %z : The observed zone offset. ("+0100"). // - %Z : The observed zone abbreviation. ("CET"). export fn format( h: io::handle, layout: str, d: *date ) (size | io::error) = { let iter = strings::iter(layout); let z = 0z; for (let r => strings::next(&iter)) { if (r == '%') { match (strings::next(&iter)) { case let spec: rune => z += fmtspec(h, spec, d)?; case done => abort("layout has dangling '%'"); }; } else { z += memio::appendrune(h, r)?; }; }; return z; }; fn fmtspec(out: io::handle, r: rune, d: *date) (size | io::error) = { switch (r) { case 'a' => return fmt::fprint(out, WEEKDAYS_SHORT[_weekday(d)]); case 'A' => return fmt::fprint(out, WEEKDAYS[_weekday(d)]); case 'b' => return fmt::fprint(out, MONTHS_SHORT[_month(d) - 1]); case 'B' => return fmt::fprint(out, MONTHS[_month(d) - 1]); case 'C' => return fmt::fprintf(out, "{:.2}", _year(d) / 100); case 'd' => return fmt::fprintf(out, "{:.2}", _day(d)); case 'e' => return fmt::fprintf(out, "{: 2}", _day(d)); case 'F' => return fmt::fprintf(out, "{:.4}-{:.2}-{:.2}", _year(d), _month(d), _day(d)); case 'G' => return fmt::fprintf(out, "{:.4}", _isoweekyear(d)); case 'H' => return fmt::fprintf(out, "{:.2}", _hour(d)); case 'I' => return fmt::fprintf(out, "{:.2}", (_hour(d) + 11) % 12 + 1); case 'j' => return fmt::fprintf(out, "{:.3}", _yearday(d)); case 'L' => return fmt::fprint(out, d.loc.name); case 'm' => return fmt::fprintf(out, "{:.2}", _month(d)); case 'M' => return fmt::fprintf(out, "{:.2}", _minute(d)); case 'N' => return fmt::fprintf(out, "{:.9}", _nanosecond(d)); case 'p' => return fmt::fprint(out, if (_hour(d) < 12) "AM" else "PM"); case 's' => return fmt::fprintf(out, "{:.2}", d.sec); case 'S' => return fmt::fprintf(out, "{:.2}", _second(d)); case 'T' => return fmt::fprintf(out, "{:.2}:{:.2}:{:.2}", _hour(d), _minute(d), _second(d)); case 'u' => return fmt::fprintf(out, "{}", _weekday(d) + 1); case 'U' => return fmt::fprintf(out, "{:.2}", _sundayweek(d)); case 'V' => return fmt::fprintf(out, "{:.2}", _isoweek(d)); case 'w' => return fmt::fprintf(out, "{}", (_weekday(d) + 1) % 7); case 'W' => return fmt::fprintf(out, "{:.2}", _week(d)); case 'y' => return fmt::fprintf(out, "{:.2}", _year(d) % 100); case 'Y' => return fmt::fprintf(out, "{:.4}", _year(d)); case 'z' => const (sign, zo) = if (chrono::ozone(d).zoff >= 0) { yield ('+', calc_hmsn(chrono::ozone(d).zoff)); } else { yield ('-', calc_hmsn(-chrono::ozone(d).zoff)); }; const (hr, mi) = (zo.0, zo.1); return fmt::fprintf(out, "{}{:.2}{:.2}", sign, hr, mi); case 'Z' => return fmt::fprint(out, chrono::ozone(d).abbr); case '%' => return fmt::fprint(out, "%"); case => abort("layout has unrecognised specifier"); }; }; @test fn format() void = { const d = new(chrono::UTC, 0, 1994, 1, 1, 2, 17, 5, 24)!; const cases = [ // special characters ("%%", "%"), // hour ("%H", "02"), ("%I", "02"), // minute ("%M", "17"), // second ("%S", "05"), // nanosecond ("%N", "000000024"), // am/pm ("%p", "AM"), // day ("%d", "01"), // day ("%e", " 1"), // month ("%m", "01"), // year ("%Y", "1994"), ("%y", "94"), ("%C", "19"), // month name ("%b", "Jan"), ("%B", "January"), // weekday ("%u", "6"), ("%w", "6"), ("%a", "Sat"), ("%A", "Saturday"), // yearday ("%j", "001"), // week ("%W", "00"), // full date ("%F", "1994-01-01"), // full time ("%T", "02:17:05"), // Unix timestamp ("%s", "757390625"), ]; for (let (layout, expected) .. cases) { const actual = asformat(layout, &d)!; defer free(actual); if (actual != expected) { fmt::printfln( "expected format({}, &d) to be {} but was {}", layout, expected, actual )!; abort(); }; }; }; hare-0.24.2/time/date/locality.ha000066400000000000000000000006351464473310100165320ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time::chrono; // Creates an equivalent [[date]] with a different // [[time::chrono::locality]]. // // The [[time::chrono::discontinuity]] rules from [[time::chrono::in]] apply here. export fn in(loc: chrono::locality, d: date) (date | chrono::discontinuity) = { return from_moment(chrono::in(loc, *(&d: *chrono::moment))?); }; hare-0.24.2/time/date/observe.ha000066400000000000000000000114461464473310100163610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time::chrono; // These functions are renamed to avoid namespace conflicts, like in the // parameters of the [[new]] function. // Observes a [[date]]'s era. export fn era(d: *date) int = _era(d); // Observes a [[date]]'s year. export fn year(d: *date) int = _year(d); // Observes a [[date]]'s month of the year. Range January=1 to December=12. export fn month(d: *date) int = _month(d); // Observes a [[date]]'s day of the month. Range 1 to 31. export fn day(d: *date) int = _day(d); // Observes a [[date]]'s day of the week. Range Monday=0 to Sunday=6. export fn weekday(d: *date) int = _weekday(d); // Observes a [[date]]'s ordinal day of the year. Range 1 to 366. export fn yearday(d: *date) int = _yearday(d); // Observes a [[date]]'s ISO week-numbering year. export fn isoweekyear(d: *date) int = _isoweekyear(d); // Observes a [[date]]'s Gregorian week starting Monday. Range 0 to 53. // All days in a year before the year's first Monday belong to week 0. export fn week(d: *date) int = _week(d); // Observes a [[date]]'s Gregorian week starting Sunday. Range 0 to 53. // All days in a year before the year's first Sunday belong to week 0. export fn sundayweek(d: *date) int = _sundayweek(d); // Observes a [[date]]'s ISO week-numbering week. Range 0 to 53. export fn isoweek(d: *date) int = _isoweek(d); // Observes a [[date]]'s hour of the day. export fn hour(d: *date) int = _hour(d); // Observes a [[date]]'s minute of the hour. export fn minute(d: *date) int = _minute(d); // Observes a [[date]]'s second of the minute. export fn second(d: *date) int = _second(d); // Observes a [[date]]'s nanosecond of the second. export fn nanosecond(d: *date) int = _nanosecond(d); fn _era(d: *date) int = { match (d.era) { case void => d.era = calc_era( _year(d), ); return d.era: int; case let a: int => return a; }; }; fn _year(d: *date) int = { match (d.year) { case void => const ymd = calc_ymd( chrono::daydate(d), ); d.year = ymd.0; d.month = ymd.1; d.day = ymd.2; return d.year: int; case let y: int => return y; }; }; fn _month(d: *date) int = { match (d.month) { case void => const ymd = calc_ymd( chrono::daydate(d), ); d.year = ymd.0; d.month = ymd.1; d.day = ymd.2; return d.month: int; case let y: int => return y; }; }; fn _day(d: *date) int = { match (d.day) { case void => const ymd = calc_ymd( chrono::daydate(d), ); d.year = ymd.0; d.month = ymd.1; d.day = ymd.2; return d.day: int; case let y: int => return y; }; }; fn _weekday(d: *date) int = { match (d.weekday) { case void => d.weekday = calc_weekday( chrono::daydate(d), ); return d.weekday: int; case let y: int => return y; }; }; fn _yearday(d: *date) int = { match (d.yearday) { case void => d.yearday = calc_yearday( _year(d), _month(d), _day(d), ); return d.yearday: int; case let yd: int => return yd; }; }; fn _isoweekyear(d: *date) int = { match (d.isoweekyear) { case void => d.isoweekyear = calc_isoweekyear( _year(d), _month(d), _day(d), _weekday(d), ); return d.isoweekyear: int; case let iwy: int => return iwy; }; }; fn _week(d: *date) int = { match (d.week) { case void => d.week = calc_week( _yearday(d), _weekday(d), ); return d.week: int; case let w: int => return w; }; }; fn _sundayweek(d: *date) int = { match (d.sundayweek) { case void => d.sundayweek = calc_sundayweek( _yearday(d), _weekday(d), ); return d.sundayweek: int; case let w: int => return w; }; }; fn _isoweek(d: *date) int = { match (d.isoweek) { case void => d.isoweek = calc_isoweek( _year(d), _week(d), ); return d.isoweek: int; case let iw: int => return iw; }; }; fn _hour(d: *date) int = { match (d.hour) { case void => const hmsn = calc_hmsn( chrono::daytime(d), ); d.hour = hmsn.0; d.minute = hmsn.1; d.second = hmsn.2; d.nanosecond = hmsn.3; return d.hour: int; case let h: int => return h; }; }; fn _minute(d: *date) int = { match (d.minute) { case void => const hmsn = calc_hmsn( chrono::daytime(d), ); d.hour = hmsn.0; d.minute = hmsn.1; d.second = hmsn.2; d.nanosecond = hmsn.3; return d.minute: int; case let m: int => return m; }; }; fn _second(d: *date) int = { match (d.second) { case void => const hmsn = calc_hmsn( chrono::daytime(d), ); d.hour = hmsn.0; d.minute = hmsn.1; d.second = hmsn.2; d.nanosecond = hmsn.3; return d.second: int; case let s: int => return s; }; }; fn _nanosecond(d: *date) int = { match (d.nanosecond) { case void => const hmsn = calc_hmsn( chrono::daytime(d), ); d.hour = hmsn.0; d.minute = hmsn.1; d.second = hmsn.2; d.nanosecond = hmsn.3; return d.nanosecond: int; case let n: int => return n; }; }; hare-0.24.2/time/date/parithm.ha000066400000000000000000000227051464473310100163600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; use time::chrono; // The nominal units of the Gregorian chronology. Used for chronological // arithmetic. export type unit = enum int { ERA, YEAR, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, NANOSECOND, }; // Calculates the [[period]] between two [[date]]s, from A to B. // The returned period, provided to [[reckon]] along with A, will produce B, // regardless of the [[calculus]] used. All the period's non-zero fields will // have the same sign. export fn pdiff(a: date, b: date) period = { let p = period { ... }; if (chrono::compare(&a, &b) == 0) { return p; }; let reverse = if (chrono::compare(&a, &b) > 0) true else false; if (reverse) { let tmp = a; a = b; b = tmp; }; p.years = _year(&b) - _year(&a); p.months = _month(&b) - _month(&a); if (p.months < 0) { p.years -= 1; p.months += 12; }; p.days = _day(&b) - _day(&a); let year = _year(&b); let month = _month(&b); let monthdays = calc_days_in_month(year, month); for (_day(&a) > monthdays || p.days < 0) { month -= 1; if (month == 0) { year -= 1; month = 12; }; monthdays = calc_days_in_month(year, month); p.months -= 1; if (p.months < 0) { p.years -= 1; p.months += 12; }; p.days += monthdays; }; p.hours = _hour(&b) - _hour(&a); if (p.hours < 0) { p.days -= 1; p.hours += 24; }; p.minutes = _minute(&b) - _minute(&a); if (p.minutes < 0) { p.hours -= 1; p.minutes += 60; }; p.seconds = _second(&b) - _second(&a); if (p.seconds < 0) { p.minutes -= 1; p.seconds += 60; }; p.nanoseconds = _nanosecond(&b) - _nanosecond(&a); if (p.nanoseconds < 0) { p.seconds -= 1; p.nanoseconds += 1000000000; // 10E9 }; return if (reverse) neg(p) else p; }; // Calculates the nominal [[unit]] difference between two [[date]]s. export fn unitdiff(a: date, b: date, u: unit) i64 = { switch (u) { case unit::ERA => return era(&b) - era(&a); case unit::YEAR => return pdiff(a, b).years; case unit::MONTH => const d = pdiff(a, b); return d.years * 12 + d.months; case unit::WEEK => return unitdiff(a, b, unit::DAY) / 7; case unit::DAY => return chrono::daydate(&b) - chrono::daydate(&a); case unit::HOUR => return unitdiff(a, b, unit::DAY) * 24 + pdiff(a, b).hours; case unit::MINUTE => return unitdiff(a, b, unit::HOUR) * 60 + pdiff(a, b).minutes; case unit::SECOND => return unitdiff(a, b, unit::MINUTE) * 60 + pdiff(a, b).seconds; case unit::NANOSECOND => return unitdiff(a, b, unit::SECOND) * 1000000000 + pdiff(a, b).nanoseconds; }; }; // Truncates the given [[date]] at the provided nominal [[unit]]. // The [[zflag]] parameter affects the final result. Example: // // // On this day in Sao Paulo, a +1 hour jump occurs at 00:00. // // The time range 00:00..00:59 is never observed. // // // // 2000-10-08 12:00:00.000000000 -0200 -02 America/Sao_Paulo // let a = date::new(chrono::tz("America/Sao_Paulo")!, -2 * time::HOUR, // 2000, 10, 8, 12)! // // // // 2000-10-08 01:00:00.000000000 -0200 -02 America/Sao_Paulo // let b = date::truncate(a, date::zflag::GAP_END, date::unit::DAY)!; // export fn truncate(d: date, zf: zflag, u: unit) (date | invalid | zfunresolved) = { switch (u) { case unit::ERA => return new(d.loc, zf, 1, 1, 1, 0, 0, 0, 0, ); case unit::YEAR => return new(d.loc, zf, _year(&d), 1, 1, 0, 0, 0, 0, ); case unit::MONTH => return new(d.loc, zf, _year(&d), _month(&d), 1, 0, 0, 0, 0, ); case unit::WEEK => const dd = chrono::daydate(&d) - _weekday(&d); const ymd = calc_ymd(dd); return new(d.loc, zf, ymd.0, ymd.1, ymd.2, 0, 0, 0, 0, ); case unit::DAY => return new(d.loc, zf, _year(&d), _month(&d), _day(&d), 0, 0, 0, 0, ); case unit::HOUR => return new(d.loc, zf, _year(&d), _month(&d), _day(&d), _hour(&d), 0, 0, 0, ); case unit::MINUTE => return new(d.loc, zf, _year(&d), _month(&d), _day(&d), _hour(&d), _minute(&d), 0, 0, ); case unit::SECOND => return new(d.loc, zf, _year(&d), _month(&d), _day(&d), _hour(&d), _minute(&d), _second(&d), 0, ); case unit::NANOSECOND => return d; }; }; @test fn pdiff() void = { const cases = [ ( new(chrono::UTC, 0, 2021, 1, 15, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2022, 2, 16, 0, 0, 0, 0)!, period { years = 1, months = 1, days = 1, ... }, ), ( new(chrono::UTC, 0, 2021, 1, 15, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2022, 3, 27, 0, 0, 0, 0)!, period { years = 1, months = 2, days = 12, ... }, ), ( new(chrono::UTC, 0, 2021, 1, 15, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2022, 3, 14, 0, 0, 0, 0)!, period { years = 1, months = 1, days = 27, ... }, ), ( new(chrono::UTC, 0, 2021, 1, 15, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2021, 1, 16, 0, 0, 0, 0)!, period { days = 1, ... }, ), ( new(chrono::UTC, 0, 2021, 1, 15, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2021, 1, 16, 1, 3, 2, 4)!, period { days = 1, hours = 1, minutes = 3, seconds = 2, nanoseconds = 4, ... }, ), ( new(chrono::UTC, 0, 2021, 1, 15, 2, 3, 2, 2)!, new(chrono::UTC, 0, 2021, 1, 16, 1, 1, 2, 4)!, period { hours = 22, minutes = 58, nanoseconds = 2, ... }, ), ( new(chrono::UTC, 0, 500, 1, 1, 0, 0, 0, 0)!, new(chrono::UTC, 0, 3500, 1, 1, 0, 6, 0, 0)!, period { years = 3000, minutes = 6, ... }, ), ( new(chrono::UTC, 0, -500, 1, 1, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2500, 1, 1, 0, 6, 0, 0)!, period { years = 3000, minutes = 6, ... }, ), ( new(chrono::UTC, 0, 2000, 1, 1, 0, 0, 0, 0)!, new(chrono::UTC, 0, 2000, 1, 1, 0, 6, 0, 999999999)!, period { minutes = 6, nanoseconds = 999999999, ... }, ), ( new(chrono::UTC, 0, 2000, 1, 1, 0, 6, 0, 999999999)!, new(chrono::UTC, 0, 2000, 1, 1, 0, 6, 1, 0)!, period { nanoseconds = 1, ... }, ), ( new(chrono::UTC, 0, -4000, 1, 1, 0, 6, 0, 999999999)!, new(chrono::UTC, 0, 4000, 1, 1, 0, 6, 1, 0)!, period { years = 8000, nanoseconds = 1, ... }, ), ]; for (let (da, db, expected) .. cases) { const actual = pdiff(da, db); assert(peq(actual, expected), "pdiff miscalculation"); }; }; @test fn unitdiff() void = { const cases = [ ( new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 2)!, new(chrono::UTC, 0, 2022, 1, 5, 13, 53, 30, 20)!, (27, 328, 1427, 9993, 239834, 14390073, 863404409i64, (863404409i64 * time::SECOND) + 18), ), ( new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 0)!, new(chrono::UTC, 0, 1994, 8, 28, 11, 20, 1, 2)!, (0, 0, 0, 1, 24, 1440, 86400i64, (86400i64 * time::SECOND) + 2), ), ( new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 0)!, new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 0)!, (0, 0, 0, 0, 0, 0, 0i64, 0i64), ), ( new(chrono::UTC, 0, -500, 1, 1, 0, 59, 1, 0)!, new(chrono::UTC, 0, 2000, 1, 1, 23, 1, 1, 0)!, (2500, 30000, 130443, 913106, 913106 * 24 + 22, (913106 * 24 + 22) * 60 + 2, ((913106 * 24 + 22) * 60 + 2) * 60i64, (((913106 * 24 + 22) * 60 + 2) * 60i64 * time::SECOND)), ), ]; for (let (da, db, expected) .. cases) { assert(unitdiff(da, db, unit::YEAR) == expected.0, "invalid diff_in_years() result"); assert(unitdiff(da, db, unit::MONTH) == expected.1, "invalid diff_in_months() result"); assert(unitdiff(da, db, unit::WEEK) == expected.2, "invalid diff_in_weeks() result"); assert(unitdiff(da, db, unit::DAY) == expected.3, "invalid diff_in_days() result"); assert(unitdiff(da, db, unit::HOUR) == expected.4, "invalid diff_in_hours() result"); assert(unitdiff(da, db, unit::MINUTE) == expected.5, "invalid diff_in_minutes() result"); assert(unitdiff(da, db, unit::SECOND) == expected.6, "invalid diff_in_seconds() result"); assert(unitdiff(da, db, unit::NANOSECOND) == expected.7, "invalid diff_in_nanoseconds() result"); }; }; @test fn truncate() void = { const d = new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 2)!; assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::ERA)!, &new(chrono::UTC, 0, 1, 1, 1, 0, 0, 0, 0)!)!, "invalid truncate() result 01"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::YEAR)!, &new(chrono::UTC, 0, 1994, 1, 1, 0, 0, 0, 0)!)!, "invalid truncate() result 02"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::MONTH)!, &new(chrono::UTC, 0, 1994, 8, 1, 0, 0, 0, 0)!)!, "invalid truncate() result 03"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::WEEK)!, &new(chrono::UTC, 0, 1994, 8, 22, 0, 0, 0, 0)!)!, "invalid truncate() result 04"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::DAY)!, &new(chrono::UTC, 0, 1994, 8, 27, 0, 0, 0, 0)!)!, "invalid truncate() result 05"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::HOUR)!, &new(chrono::UTC, 0, 1994, 8, 27, 11, 0, 0, 0)!)!, "invalid truncate() result 06"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::MINUTE)!, &new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 0, 0)!)!, "invalid truncate() result 07"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::SECOND)!, &new(chrono::UTC, 0, 1994, 8, 27, 11, 20, 1, 0)!)!, "invalid truncate() result 08"); assert(chrono::simultaneous( &truncate(d, zflag::CONTIG, unit::NANOSECOND)!, &d)!, "invalid truncate() result 09"); }; hare-0.24.2/time/date/parse.ha000066400000000000000000000415301464473310100160230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use ascii; use strconv; use strings; use time; type failure = !void; // A parsing error occurred. This shall contain a byteindex of and rune from the // layout at the position where the parsing failure occured. export type parsefail = !(size, rune); // Parses a datetime string into a [[virtual]] date, according to a layout // format string with specifiers as documented under [[format]]. Partial, // sequential, aggregative parsing is possible. // // date::parse(&v, "%Y-%m-%d", "2019-12-27"); // date::parse(&v, "%H:%M:%S.%N", "22:07:08.000000000"); // date::parse(&v, "%z %Z %L", "+0100 CET Europe/Amsterdam"); // // Parse will return [[parsefail]] if an invalid format specifier is encountered // or if given string 's' does not match the layout. export fn parse(v: *virtual, layout: str, s: str) (void | parsefail) = { const liter = strings::iter(layout); const siter = strings::iter(s); let escaped = false; for (let lr => strings::next(&liter)) { if (!escaped && lr == '%') { escaped = true; continue; }; if (!escaped) { const sr = match (strings::next(&siter)) { case done => return (liter.dec.offs, lr); case let sr: rune => yield sr; }; if (sr != lr) { return (liter.dec.offs, lr); }; continue; }; escaped = false; match (parse_specifier(v, &siter, lr)) { case void => void; case failure => return (liter.dec.offs, lr); }; }; return void; }; fn parse_specifier( v: *virtual, iter: *strings::iterator, lr: rune, ) (void | failure) = { switch (lr) { case 'a' => v.weekday = scan_for(iter, WEEKDAYS_SHORT...)?; case 'A' => v.weekday = scan_for(iter, WEEKDAYS...)?; case 'b' => v.month = scan_for(iter, MONTHS_SHORT...)? + 1; case 'B' => v.month = scan_for(iter, MONTHS...)? + 1; case 'C' => v.century = scan_int(iter, 2)?; case 'd', 'e' => v.day = scan_int(iter, 2)?; case 'F' => v.year = scan_int(iter, 4)?; eat_rune(iter, '-')?; v.month = scan_int(iter, 2)?; eat_rune(iter, '-')?; v.day = scan_int(iter, 2)?; case 'H' => v.hour = scan_int(iter, 2)?; case 'I' => v.hour12 = scan_int(iter, 2)?; case 'j' => v.yearday = scan_int(iter, 3)?; case 'L' => v.locname = scan_str(iter)?; case 'm' => v.month = scan_int(iter, 2)?; case 'M' => v.minute = scan_int(iter, 2)?; case 'N' => let nsec = scan_decimal(iter, 9)?; v.nanosecond = nsec: int; v.vnsec = nsec; case 'p' => // AM=false PM=true v.ampm = scan_for(iter, "AM", "PM", "am", "pm")? % 2 == 1; case 's' => v.vsec = scan_num(iter, 20)?; case 'S' => v.second = scan_int(iter, 2)?; case 'T' => v.hour = scan_int(iter, 2)?; eat_rune(iter, ':')?; v.minute = scan_int(iter, 2)?; eat_rune(iter, ':')?; v.second = scan_int(iter, 2)?; case 'u' => v.weekday = scan_int(iter, 1)? - 1; case 'U' => v.week = scan_int(iter, 2)?; case 'w' => v.weekday = scan_int(iter, 1)? - 1; case 'W' => v.week = scan_int(iter, 2)?; case 'y' => v.year100 = scan_int(iter, 2)?; case 'Y' => v.year = scan_int(iter, 4)?; case 'z' => v.zoff = scan_zo(iter)?; case 'Z' => v.zabbr = scan_str(iter)?; case '%' => eat_rune(iter, '%')?; case => return failure; }; }; fn eat_rune(iter: *strings::iterator, needle: rune) (uint | failure) = { const rn = match (strings::next(iter)) { case done => return failure; case let rn: rune => yield rn; }; if (rn == needle) { return 1; } else { strings::prev(iter); return 0; }; }; // Scans the iterator for a given list of strings. // Returns the list index of the matched string. fn scan_for(iter: *strings::iterator, list: str...) (int | failure) = { const name = strings::iterstr(iter); if (len(name) == 0) { return failure; }; for(let i = 0z; i < len(list); i += 1) { if (strings::hasprefix(name, list[i])) { // Consume name for (let j = 0z; j < len(list[i]); j += 1) { strings::next(iter); }; return i: int; }; }; return failure; }; // Scans the iterator for consecutive numeric digits. // Left-padded whitespace and zeros are permitted. // Returns the resulting int. fn scan_int(iter: *strings::iterator, maxrunes: size) (int | failure) = { let start = *iter; let startfixed = false; for (let i = 0z; i < maxrunes; i += 1) { let rn: rune = match (strings::next(iter)) { case done => break; case let rn: rune => yield rn; }; if (!ascii::isdigit(rn) && rn != ' ') { return failure; }; if (!startfixed) { if (ascii::isdigit(rn)) { startfixed = true; } else { strings::next(&start); }; }; }; match (strconv::stoi(strings::slice(&start, iter))) { case let num: int => return num; case => return failure; }; }; // Scans the iterator for consecutive numeric digits. // Left-padded whitespace and zeros are permitted. // Returns the resulting i64. fn scan_num(iter: *strings::iterator, maxrunes: size) (i64 | failure) = { let start = *iter; for (let i = 0z; i < maxrunes; i += 1) { match (strings::next(iter)) { case done => return failure; case let rn: rune => if (!ascii::isdigit(rn)) { strings::prev(iter); break; }; }; }; match (strconv::stoi64(strings::slice(&start, iter))) { case let num: i64 => return num; case => return failure; }; }; // Scans the iterator for consecutive numeric digits. // Left-padded whitespace and zeros are NOT permitted. // The resulting decimal is right-padded with zeros. fn scan_decimal(iter: *strings::iterator, maxrunes: size) (i64 | failure) = { let start = *iter; for (let i = 0z; i < maxrunes; i += 1) { let rn: rune = match (strings::next(iter)) { case done => break; case let rn: rune => yield rn; }; if (!ascii::isdigit(rn)) { strings::prev(iter); break; }; }; const s = strings::slice(&start, iter); match (strconv::stoi64(s)) { case let num: i64 => for (let i = 0z; i < maxrunes - len(s); i += 1) { num *= 10; }; return num; case => return failure; }; }; // Scans and parses zone offsets of the form: // // Z // z // +nn:nn // +nnnn // -nn:nn // -nnnn // fn scan_zo(iter: *strings::iterator) (time::duration | failure) = { const first = match (strings::next(iter)) { case done => return failure; case let first: rune => yield first; }; if (first == 'Z' || first == 'z') { return 0; }; let zo = scan_int(iter, 2)? * time::HOUR; match (strings::next(iter)) { case done => return failure; case let sep: rune => if (sep != ':') { strings::prev(iter); }; }; zo += scan_int(iter, 2)? * time::MINUTE; if (first == '-') { zo *= -1; }; return zo; }; // Scans and parses locality names, made of printable characters. fn scan_str(iter: *strings::iterator) (str | failure) = { let start = *iter; for (let rn => strings::next(iter)) { if (!ascii::isgraph(rn)) { strings::prev(iter); break; }; }; return strings::slice(&start, iter); }; @test fn parse() void = { let v = newvirtual(); assert(parse(&v, "foo", "foo") is void, "none: parsefail"); assert(v.zone == null, "none: non-null zone"); assert(v.daydate is void, "none: non-void daydate"); assert(v.daytime is void, "none: non-void daytime"); assert(v.era is void, "none: non-void era"); assert(v.year is void, "none: non-void year"); assert(v.month is void, "none: non-void month"); assert(v.day is void, "none: non-void day"); assert(v.yearday is void, "none: non-void yearday"); assert(v.isoweekyear is void, "none: non-void isoweekyear"); assert(v.isoweek is void, "none: non-void isoweek"); assert(v.week is void, "none: non-void week"); assert(v.sundayweek is void, "none: non-void sundayweek"); assert(v.weekday is void, "none: non-void weekday"); assert(v.hour is void, "none: non-void hour"); assert(v.minute is void, "none: non-void minute"); assert(v.second is void, "none: non-void second"); assert(v.nanosecond is void, "none: non-void nanosecond"); assert(v.vloc is void, "none: non-void vloc"); assert(v.locname is void, "none: non-void locname"); assert(v.zoff is void, "none: non-void zoff"); assert(v.zabbr is void, "none: non-void zabbr"); assert(v.hour12 is void, "none: non-void hour12"); assert(v.ampm is void, "none: non-void ampm"); let v = newvirtual(); assert(parse(&v, "%a", "Fri") is void , "%a: parsefail"); assert(v.weekday is int , "%a: void"); assert(v.weekday as int == 4 , "%a: incorrect"); let v = newvirtual(); assert(parse(&v, "%A", "Friday") is void , "%A: parsefail"); assert(v.weekday is int , "%A: void"); assert(v.weekday as int == 4 , "%A: incorrect"); let v = newvirtual(); assert(parse(&v, "%b", "Jan") is void , "%b: parsefail"); assert(v.month is int , "%b: void"); assert(v.month as int == 1 , "%b: incorrect"); let v = newvirtual(); assert(parse(&v, "%B", "January") is void , "%B: parsefail"); assert(v.month is int , "%B: void"); assert(v.month as int == 1 , "%B: incorrect"); let v = newvirtual(); assert(parse(&v, "%d", "27") is void , "%d: parsefail"); assert(v.day is int , "%d: void"); assert(v.day as int == 27 , "%d: incorrect"); let v = newvirtual(); assert(parse(&v, "%d", " 1") is void , "%d: parsefail"); assert(v.day is int , "%d: void"); assert(v.day as int == 1 , "%d: incorrect"); let v = newvirtual(); assert(parse(&v, "%d", "x1") is parsefail , "%d: not parsefail"); let v = newvirtual(); assert(parse(&v, "%e", " 7") is void , "%d: parsefail"); assert(v.day is int , "%d: void"); assert(v.day as int == 7 , "%d: incorrect"); let v = newvirtual(); assert(parse(&v, "%F", "2012-10-01") is void , "%d: parsefail"); assert(v.year is int , "%d: void"); assert(v.year as int == 2012 , "%d: incorrect"); assert(v.month is int , "%d: void"); assert(v.month as int == 10 , "%d: incorrect"); assert(v.day is int , "%d: void"); assert(v.day as int == 1 , "%d: incorrect"); let v = newvirtual(); assert(parse(&v, "%H", "22") is void , "%H: parsefail"); assert(v.hour is int , "%H: void"); assert(v.hour as int == 22 , "%H: incorrect"); let v = newvirtual(); assert(parse(&v, "%I", "10") is void , "%I: parsefail"); assert(v.hour12 is int , "%I: void"); assert(v.hour12 as int == 10 , "%I: incorrect"); let v = newvirtual(); assert(parse(&v, "%j", "361") is void , "%j: parsefail"); assert(v.yearday is int , "%j: void"); assert(v.yearday as int == 361 , "%j: incorrect"); let v = newvirtual(); assert(parse(&v, "%j", " 9") is void , "%j: parsefail"); assert(v.yearday is int , "%j: void"); assert(v.yearday as int == 9 , "%j: incorrect"); let v = newvirtual(); assert(parse(&v, "%L", "Europe/Amsterdam") is void , "%L: parsefail"); assert(v.locname is str , "%L: void"); assert(v.locname as str == "Europe/Amsterdam" , "%L: incorrect"); let v = newvirtual(); assert(parse(&v, "%m", "12") is void , "%m: parsefail"); assert(v.month is int , "%m: void"); assert(v.month as int == 12 , "%m: incorrect"); let v = newvirtual(); assert(parse(&v, "%M", "07") is void , "%M: parsefail"); assert(v.minute is int , "%M: void"); assert(v.minute as int == 7 , "%M: incorrect"); let v = newvirtual(); assert(parse(&v, "%N", "123456789") is void , "%N: parsefail"); assert(v.nanosecond is int , "%N: void"); assert(v.nanosecond as int == 123456789 , "%N: incorrect"); let v = newvirtual(); assert(parse(&v, "%N", "123") is void , "%N: parsefail"); assert(v.nanosecond is int , "%N: void"); assert(v.nanosecond as int == 123000000 , "%N: incorrect"); let v = newvirtual(); assert(parse(&v, "%p", "PM") is void , "%p: parsefail"); assert(v.ampm is bool , "%p: void"); assert(v.ampm as bool == true , "%p: incorrect"); let v = newvirtual(); assert(parse(&v, "%S", "08") is void , "%S: parsefail"); assert(v.second is int , "%S: void"); assert(v.second as int == 8 , "%S: incorrect"); let v = newvirtual(); assert(parse(&v, "%T", "18:42:05") is void , "%d: parsefail"); assert(v.hour is int , "%d: void"); assert(v.hour as int == 18 , "%d: incorrect"); assert(v.minute is int , "%d: void"); assert(v.minute as int == 42 , "%d: incorrect"); assert(v.second is int , "%d: void"); assert(v.second as int == 5 , "%d: incorrect"); let v = newvirtual(); assert(parse(&v, "%u", "5") is void , "%u: parsefail"); assert(v.weekday is int , "%u: void"); assert(v.weekday as int == 4 , "%u: incorrect"); let v = newvirtual(); assert(parse(&v, "%U", "51") is void , "%U: parsefail"); assert(v.week is int , "%U: void"); assert(v.week as int == 51 , "%U: incorrect"); let v = newvirtual(); assert(parse(&v, "%w", "5") is void , "%w: parsefail"); assert(v.weekday is int , "%w: void"); assert(v.weekday as int == 4 , "%w: incorrect"); let v = newvirtual(); assert(parse(&v, "%W", "51") is void , "%W: parsefail"); assert(v.week is int , "%W: void"); assert(v.week as int == 51 , "%W: incorrect"); let v = newvirtual(); assert(parse(&v, "%Y", "2019") is void , "%Y: parsefail"); assert(v.year is int , "%Y: void"); assert(v.year as int == 2019 , "%Y: incorrect"); let v = newvirtual(); assert(parse(&v, "%z", "+0100") is void , "%z: parsefail"); assert(v.zoff is i64 , "%z: void"); assert(v.zoff as i64 == 1 * time::HOUR , "%z: incorrect"); let v = newvirtual(); assert(parse(&v, "%z", "+01:00") is void , "%z: parsefail"); assert(v.zoff is i64 , "%z: void"); assert(v.zoff as i64 == 1 * time::HOUR , "%z: incorrect"); let v = newvirtual(); assert(parse(&v, "%Z", "CET") is void , "%Z: parsefail"); assert(v.zabbr is str , "%Z: void"); assert(v.zabbr as str == "CET" , "%Z: incorrect"); let v = newvirtual(); assert(( parse(&v, "%Y-%m-%d %H:%M:%S.%N %z %Z %L", "2038-01-19 03:14:07.000000000 +0000 UTC UTC", ) is void ), "test 1: parsefail" ); assert(v.year is int , "test 1: year void"); assert(v.year as int == 2038, "test 1: year incorrect"); assert(v.month is int , "test 1: month void"); assert(v.month as int == 1, "test 1: month incorrect"); assert(v.day is int , "test 1: day void"); assert(v.day as int == 19, "test 1: day incorrect"); assert(v.hour is int , "test 1: hour void"); assert(v.hour as int == 3, "test 1: hour incorrect"); assert(v.minute is int , "test 1: minute void"); assert(v.minute as int == 14, "test 1: minute incorrect"); assert(v.second is int , "test 1: second void"); assert(v.second as int == 7, "test 1: second incorrect"); assert(v.nanosecond is int , "test 1: nanosecond void"); assert(v.nanosecond as int == 0, "test 1: nanosecond incorrect"); assert(v.zoff is i64 , "test 1: zoff void"); assert(v.zoff as i64 == 0, "test 1: zoff incorrect"); assert(v.zabbr is str , "test 1: zabbr void"); assert(v.zabbr as str == "UTC", "test 1: zabbr incorrect"); assert(v.locname is str , "test 1: locname void"); assert(v.locname as str == "UTC", "test 1: locname incorrect"); }; hare-0.24.2/time/date/period.ha000066400000000000000000000041301464473310100161660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Represents a span of time in the Gregorian chronology, using nominal units of // time. Used for chronological arithmetic. export type period = struct { years: i64, months: i64, weeks: i64, days: i64, hours: i64, minutes: i64, seconds: i64, nanoseconds: i64, }; // Returns true if two [[period]]s are numerically equal, false otherwise. export fn peq(pa: period, pb: period) bool = { return ( pa.years == pb.years && pa.months == pb.months && pa.weeks == pb.weeks && pa.days == pb.days && pa.hours == pb.hours && pa.minutes == pb.minutes && pa.seconds == pb.seconds && pa.nanoseconds == pb.nanoseconds ); }; // Returns the sum [[period]] of a set of periods. export fn sum(ps: period...) period = { let out = period { ... }; for (let p &.. ps) { out.years += p.years; out.months += p.months; out.weeks += p.weeks; out.days += p.days; out.hours += p.hours; out.minutes += p.minutes; out.seconds += p.seconds; out.nanoseconds += p.nanoseconds; }; return out; }; // Returns a [[period]] with its fields negated. export fn neg(p: period) period = period { years = -p.years, months = -p.months, weeks = -p.weeks, days = -p.days, hours = -p.hours, minutes = -p.minutes, seconds = -p.seconds, nanoseconds = -p.nanoseconds, }; // Returns a [[period]] with its fields made absolute and positive. export fn abs(p: period) period = period { years = if (p.years < 0) -p.years else p.years, months = if (p.months < 0) -p.months else p.months, weeks = if (p.weeks < 0) -p.weeks else p.weeks, days = if (p.days < 0) -p.days else p.days, hours = if (p.hours < 0) -p.hours else p.hours, minutes = if (p.minutes < 0) -p.minutes else p.minutes, seconds = if (p.seconds < 0) -p.seconds else p.seconds, nanoseconds = if (p.nanoseconds < 0) -p.nanoseconds else p.nanoseconds, }; hare-0.24.2/time/date/reckon.ha000066400000000000000000000347101464473310100161740ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; use time::chrono; // Specifies the behaviour of [[reckon]] when doing chronological arithmetic. // // The FLOOR, CEIL, HOP, and FOLD specifies how to resolve sub-significant // overflows -- when a field's change in value causes any sub-significant // field's range to shrink below its current value and become invalid. For // example, adding 1 month to January 31st results in February 31st, a date with // an unresolved day field, since February permits only 28 or 29 days. export type rflag = enum uint { // The default behaviour. Equivalent to CEIL. DEFAULT = 0, // Apply units in reverse order, from least to most significant. REVSIG = 1 << 0, // When a sub-significant overflow occurs, the unresolved field is set // to its minimum valid value. // // Feb 31 -> Feb 01 // Aug 64 -> Aug 01 FLOOR = 1 << 1, // When a sub-significant overflow occurs, the unresolved field is set // to its maximum valid value. // // Feb 31 -> Feb 28 / Feb 29 (leap year dependent) // Aug 64 -> Aug 31 CEIL = 1 << 2, // When a sub-significant overflow occurs, the unresolved field is set // to its new minimum valid value after the next super-significant field // increments by one. // // Feb 31 -> Mar 01 // Aug 64 -> Sep 01 HOP = 1 << 3, // When a sub-significant overflow occurs, the unresolved field's // maximum valid value is subtracted from its current value, and the // next super-significant field increments by one. This process repeats // until the unresolved field's value becomes valid (falls in range). // // Feb 31 -> Mar 03 / Mar 02 (leap year dependent) // Aug 64 -> Sep 33 -> Oct 03 FOLD = 1 << 4, }; // Reckons from a given [[date]] to a new one, via a given set of [[period]]s. // This is a chronological arithmetic operation. Each period is reckoned // independently in succession, applying (adding) their units from most to least // significant. // // The [[rflag]] parameter handles field overflows and other behaviours. // The [[zflag]] parameter affects the final result. Example: // // // 2000-02-29 00:00:00.000000000 -1100 -11 Pacific/Apia // let a = date::new(chrono::tz("Pacific/Apia")!, -11 * time::HOUR, // 2000, 2, 29)!; // // let b = date::reckon(a, // starts as: 2000-Feb-29 00:00 -1100 // date::zflag::GAP_END, // date::rflag::DEFAULT, // date::period { // years = 11, // becomes: 2011-Feb-28 00:00 -1100 // months = 10, // becomes: 2011-Dec-28 00:00 -1100 // days = 1, // becomes: 2011-Dec-29 00:00 -1100 // hours = 36, // becomes: 2011-Dec-30 12:00 -1100 // }, // // In Samoa, Apia, the day 2011-Dec-30 was skipped entirely. // // Thus, after applying date::zflag::GAP_END for adjustment, // // we arrive at the final date, time, and zone-offset: // // 2011-12-31 00:00:00.000000000 +1400 +14 Pacific/Apia // ); // // See [[add]]. export fn reckon( d: date, zoff: (time::duration | zflag), rf: rflag, ps: period... ) (date | invalid | zfunresolved) = { let r = newvirtual(); // our reckoner r.vloc = d.loc; r.zoff = zoff; r.year = _year(&d); r.month = _month(&d); r.day = _day(&d); r.hour = _hour(&d); r.minute = _minute(&d); r.second = _second(&d); r.nanosecond = _nanosecond(&d); if (rf == rflag::DEFAULT) { rf |= rflag::CEIL; }; for (let p .. ps) if (rf & rflag::REVSIG == 0) { const fold = rflag::FOLD; r.year = r.year as int + p.years: int; reckon_days(&r, 0, rf); // bubble up potential Feb 29 overflow reckon_months(&r, p.months); reckon_days(&r, 0, rf); // bubble up potential overflows reckon_days(&r, p.weeks * 7, fold); reckon_days(&r, p.days, fold); // TODO: These functions aren't aware of top-down overflows. // Handle overflows (e.g. [[zone]] changes). reckon_hours(&r, p.hours, fold); reckon_minutes(&r, p.minutes, fold); reckon_seconds(&r, p.seconds, fold); reckon_nanoseconds(&r, p.nanoseconds, fold); } else { const fold = rflag::FOLD | rflag::REVSIG; reckon_nanoseconds(&r, p.nanoseconds, fold); reckon_seconds(&r, p.seconds, fold); reckon_minutes(&r, p.minutes, fold); reckon_hours(&r, p.hours, fold); reckon_days(&r, p.days, fold); reckon_days(&r, p.weeks * 7, fold); reckon_months(&r, p.months); reckon_days(&r, 0, rf); // bubble up potential overflows r.year = r.year as int + p.years: int; reckon_days(&r, 0, rf); // bubble up potential Feb 29 overflow }; return realize(r) as (date | invalid | zfunresolved); }; fn reckon_months(r: *virtual, months: i64) void = { let year = r.year as int; let month = r.month as int; month += months: int; // month overflow for (month > 12) { month -= 12; year += 1; }; for (month < 1) { month += 12; year -= 1; }; r.year = year; r.month = month; }; fn reckon_days(r: *virtual, days: i64, rf: rflag) void = { let year = r.year as int; let month = r.month as int; let day = r.day as int; day += days: int; // day overflow let monthdays = calc_days_in_month(year, month); for (day > monthdays) { if (rf & rflag::FLOOR != 0) { day = 1; } else if (rf & rflag::CEIL != 0) { day = monthdays; } else if (rf & rflag::HOP != 0) { r.year = year; r.month = month; reckon_months(r, 1); year = r.year as int; month = r.month as int; day = 1; } else if (rf & rflag::FOLD != 0) { r.year = year; r.month = month; reckon_months(r, 1); year = r.year as int; month = r.month as int; day -= monthdays; }; monthdays = calc_days_in_month(year, month); }; for (day < 1) { r.year = year; r.month = month; reckon_months(r, -1); year = r.year as int; month = r.month as int; day += calc_days_in_month(year, month); }; r.year = year; r.month = month; r.day = day; }; fn reckon_hours(r: *virtual, hours: i64, rf: rflag) void = { let hour = r.hour as int; hour += hours: int; // hour overflow for (hour >= 24) { reckon_days(r, 1, rf); hour -= 24; }; for (hour < 0) { reckon_days(r, -1, rf); hour += 24; }; r.hour = hour; }; fn reckon_minutes(r: *virtual, mins: i64, rf: rflag) void = { let min = r.minute as int; min += mins: int; // minute overflow for (min >= 60) { reckon_hours(r, 1, rf); min -= 60; }; for (min < 0) { reckon_hours(r, -1, rf); min += 60; }; r.minute = min; }; fn reckon_seconds(r: *virtual, secs: i64, rf: rflag) void = { let s = r.second as int; s += secs: int; // second overflow for (s >= 60) { reckon_minutes(r, 1, rf); s -= 60; }; for (s < 0) { reckon_minutes(r, -1, rf); s += 60; }; r.second = s; }; fn reckon_nanoseconds(r: *virtual, nsecs: i64, rf: rflag) void = { let ns = r.nanosecond as int; ns += nsecs: int; // nanosecond overflow for (ns >= 1000000000) { // 1E9 nanoseconds (1 second) reckon_seconds(r, 1, rf); ns -= 1000000000; }; for (ns < 0) { reckon_seconds(r, -1, rf); ns += 1000000000; }; r.nanosecond = ns; }; @test fn reckon() void = { // no-op period, rflag::CEIL let p = period { ... }; let a = new(chrono::UTC, 0)!; let r = reckon(a, zflag::CONTIG, 0, p)!; assert(chrono::simultaneous(&a, &r)!, "01. incorrect result"); let a = new(chrono::UTC, 0, 2019, 12, 27, 21, 7, 8, 0)!; let r = reckon(a, zflag::CONTIG, 0, p)!; assert(chrono::simultaneous(&a, &r)!, "02. incorrect result"); let a = new(chrono::UTC, 0, 1970, 1, 1, 0, 0, 0, 0)!; let r = reckon(a, zflag::CONTIG, 0, p)!; assert(chrono::simultaneous(&a, &r)!, "03. incorrect result"); // generic periods, rflag::CEIL let a = new(chrono::UTC, 0, 2019, 12, 27, 21, 7, 8, 0)!; let r = reckon(a, zflag::CONTIG, 0, period { years = 1, months = 1, days = 1, hours = 1, minutes = 1, seconds = 1, nanoseconds = 1, ... })!; let b = new(chrono::UTC, 0, 2021, 1, 28, 22, 8, 9, 1)!; assert(chrono::simultaneous(&b, &r)!, "04. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, period { years = -1, months = -1, days = -1, hours = -1, minutes = -1, seconds = -1, nanoseconds = -1, ... })!; let b = new(chrono::UTC, 0, 2018, 11, 26, 20, 6, 6, 999999999)!; assert(chrono::simultaneous(&b, &r)!, "05. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, period { years = 100, months = 100, days = 100, hours = 100, minutes = 100, seconds = 100, nanoseconds = 100, ... })!; let b = new(chrono::UTC, 0, 2128, 8, 10, 2, 48, 48, 100)!; assert(chrono::simultaneous(&b, &r)!, "06. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, period { years = -100, months = -100, days = -100, hours = -100, minutes = -100, seconds = -100, nanoseconds = -100, ... })!; let b = new(chrono::UTC, 0, 1911, 5, 15, 15, 25, 27, 999999900)!; assert(chrono::simultaneous(&b, &r)!, "07. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, period { weeks = 100, ... })!; let b = new(chrono::UTC, 0, 2021, 11, 26, 21, 7, 8, 0)!; assert(chrono::simultaneous(&b, &r)!, "08. incorrect result"); // rflag, February 29 overflows let a = new(chrono::UTC, 0, 2000, 1, 31)!; // leap year let p = period { months = 1, ... }; let r = reckon(a, zflag::CONTIG, rflag::FLOOR, p)!; let b = new(chrono::UTC, 0, 2000, 2, 1)!; assert(chrono::simultaneous(&b, &r)!, "09. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::CEIL, p)!; let b = new(chrono::UTC, 0, 2000, 2, 29)!; assert(chrono::simultaneous(&b, &r)!, "10. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::HOP, p)!; let b = new(chrono::UTC, 0, 2000, 3, 1)!; assert(chrono::simultaneous(&b, &r)!, "11. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::FOLD, p)!; let b = new(chrono::UTC, 0, 2000, 3, 2)!; assert(chrono::simultaneous(&b, &r)!, "12. incorrect result"); // rflag, February 28 overflows let a = new(chrono::UTC, 0, 2000, 1, 31)!; // leap year let p = period { years = 1, months = 1, ... }; let r = reckon(a, zflag::CONTIG, rflag::FLOOR, p)!; let b = new(chrono::UTC, 0, 2001, 2, 1)!; assert(chrono::simultaneous(&b, &r)!, "13. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::CEIL, p)!; let b = new(chrono::UTC, 0, 2001, 2, 28)!; assert(chrono::simultaneous(&b, &r)!, "14. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::HOP, p)!; let b = new(chrono::UTC, 0, 2001, 3, 1)!; assert(chrono::simultaneous(&b, &r)!, "15. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::FOLD, p)!; let b = new(chrono::UTC, 0, 2001, 3, 3)!; assert(chrono::simultaneous(&b, &r)!, "16. incorrect result"); // multiple periods let a = new(chrono::UTC, 0, 2000, 12, 31)!; let ps = [ period { years = 1, months = 1, days = 1, ... }, period { years = -1, months = -1, days = -1, ... }, period { years = -1, months = -1, days = -1, ... }, period { years = 1, months = 1, days = 1, ... }, period { hours = 1, minutes = 1, seconds = 1, ... }, period { hours = -1, minutes = -1, seconds = -1, ... }, period { hours = -1, minutes = -1, seconds = -1, ... }, period { hours = 1, minutes = 1, seconds = 1, ... }, ]; let r = reckon(a, zflag::CONTIG, 0, ps[..1]...)!; let b = new(chrono::UTC, 0, 2002, 2, 1)!; assert(chrono::simultaneous(&b, &r)!, "17. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..2]...)!; let b = new(chrono::UTC, 0, 2000, 12, 31)!; assert(chrono::simultaneous(&b, &r)!, "18. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..3]...)!; let b = new(chrono::UTC, 0, 1999, 11, 29)!; assert(chrono::simultaneous(&b, &r)!, "19. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..4]...)!; let b = new(chrono::UTC, 0, 2000, 12, 30)!; assert(chrono::simultaneous(&b, &r)!, "20. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..5]...)!; let b = new(chrono::UTC, 0, 2000, 12, 30, 1, 1, 1)!; assert(chrono::simultaneous(&b, &r)!, "21. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..6]...)!; let b = new(chrono::UTC, 0, 2000, 12, 30)!; assert(chrono::simultaneous(&b, &r)!, "22. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..7]...)!; let b = new(chrono::UTC, 0, 2000, 12, 29, 22, 58, 59)!; assert(chrono::simultaneous(&b, &r)!, "23. incorrect result"); let r = reckon(a, zflag::CONTIG, 0, ps[..8]...)!; let b = new(chrono::UTC, 0, 2000, 12, 30)!; assert(chrono::simultaneous(&b, &r)!, "24. incorrect result"); // multiple periods, rflag::REVSIG let a = new(chrono::UTC, 0, 2000, 12, 31)!; let ps = [ period { years = 1, months = 1, days = 1, ... }, period { years = -1, months = -1, days = -1, ... }, period { years = -1, months = -1, days = -1, ... }, period { years = 1, months = 1, days = 1, ... }, period { hours = 1, minutes = 1, seconds = 1, ... }, period { hours = -1, minutes = -1, seconds = -1, ... }, period { hours = -1, minutes = -1, seconds = -1, ... }, period { hours = 1, minutes = 1, seconds = 1, ... }, ]; let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..1]...)!; let b = new(chrono::UTC, 0, 2002, 2, 1)!; assert(chrono::simultaneous(&b, &r)!, "25. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..2]...)!; let b = new(chrono::UTC, 0, 2000, 12, 31)!; assert(chrono::simultaneous(&b, &r)!, "26. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..3]...)!; let b = new(chrono::UTC, 0, 1999, 11, 30)!; assert(chrono::simultaneous(&b, &r)!, "27. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..4]...)!; let b = new(chrono::UTC, 0, 2001, 1, 1)!; assert(chrono::simultaneous(&b, &r)!, "28. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..5]...)!; let b = new(chrono::UTC, 0, 2001, 1, 1, 1, 1, 1)!; assert(chrono::simultaneous(&b, &r)!, "29. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..6]...)!; let b = new(chrono::UTC, 0, 2001, 1, 1)!; assert(chrono::simultaneous(&b, &r)!, "30. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..7]...)!; let b = new(chrono::UTC, 0, 2000, 12, 31, 22, 58, 59)!; assert(chrono::simultaneous(&b, &r)!, "31. incorrect result"); let r = reckon(a, zflag::CONTIG, rflag::REVSIG, ps[..8]...)!; let b = new(chrono::UTC, 0, 2001, 1, 1)!; assert(chrono::simultaneous(&b, &r)!, "32. incorrect result"); return; }; hare-0.24.2/time/date/tarithm.ha000066400000000000000000000005251464473310100163600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use time; // Adds a [[time::duration]] to a [[date]] with [[time::add]]. This is a // timescalar aritmetic operation. // // See [[reckon]]. export fn add(d: date, x: time::duration) date = { return from_instant(d.loc, time::add(*(&d: *time::instant), x)); }; hare-0.24.2/time/date/virtual.ha000066400000000000000000000400221464473310100163720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use sort; use time; use time::chrono; // Flags for resolving an absent zone-offset. Handles timezone transitions. // // The [[realize]] function, as well as other date creation functions (like // [[new]], [[truncate]], [[reckon]]...) accept zflags. If zflags are provided, // these functions normally calculate an intermediate date with a best-guess // numerical zone-offset. This intermediate date can be [[invalid]] if it falls // within the observed overlap or gap of a timezone transition, where such dates // are ambiguous or nonexistent. In this case, the provided zflags are // consulted, and a final calculation takes place before the final resultant // date (or [[zfunresolved]]) is returned. // // Timezone transitions create gaps and overlaps, the two causes of [[invalid]] // intermediate dates. Passing one "GAP_" and one "LAP_" flag covers both cases. // // let zf = date::zflag::LAP_EARLY | date::zflag::GAP_END; // date::new(loc, zf, fields...)!; // will never return [[zfunresolved]] // // Note that usage of "GAP_" flags will cause the resultant date to be different // to what is originally specified if the intermediate date falls within a gap. // Flags with greater value take precedent. // // The following figures exist to help understand the effect of these flags. // // Fig A 2000 October 29th // -1 hour // // f=02:30+0200 // g=02:30+0100 // lp | lq // +0200 | | | +0100 // Observed time: 00 01 02 | 03 04 05 // Amsterdam: |-----|-----|==*==|-----|-----| // . . .\ :: |. . // . . . \: :| . . // . . . : : . . // . . . :\ |: . . // . . . : \| : . . // UTC: |-----|-----|--*--|--*--|-----| // Contiguous time: 22 23 00 | 01 | 02 03 // | | | // a tx b // // Fig A -- A backjump timezone transition in the Europe/Amsterdam locality. // The transition is marked by "tx". There is an overlap in the chronology, // marked by "lp" and "lq". The specified local time 02:30 falls within the // observed overlap, and so has two valid zone-offsets and can be observed // twice, as dates "f" and "g". When localized to UTC, these two observations // correspond to UTC dates "a" and "b" respectively. // // Fig B 2000 March 26th // +1 hour // // f~02:30+!!!! // gp | gq // +0100 | | | +0200 // Observed time: 00 01 02 | 03 04 05 // Amsterdam: |-----|-----| * |-----|-----| // . . | / . . // . . | / . . // . . | / . . // . . | / . . // . . |/ . . // UTC: |-----|-----|-----|-----|-----| // Contiguous time: 23 00 01 02 03 04 // | // tx // // Fig B -- A forejump timezone transition in the Europe/Amsterdam locality. // The transition is marked by "tx". There is a gap in the chronology, marked by // "gp" and "gq". The specified local time 02:30 falls within the observed gap, // and so cannot be observed and is [[invalid]]. export type zflag = enum u8 { // Assume a contiguous chronology with no observed gaps or overlaps. // Upon encountering an observed gap or overlap, fail with [[invalid]]. // In other words, accept one and only one zone-offset. CONTIG = 0b00000000, // Upon encountering an observed overlap, select the earliest possible // date (Fig A "f") using the most positive (eastmost) zone-offset. LAP_EARLY = 0b00000001, // Upon encountering an observed overlap, select the latest possible // date (Fig A "g") using the most negative (westmost) zone-offset. LAP_LATE = 0b00000010, // Upon encountering an observed gap, disregard the specified date and // select the date at the start boundary of the observed gap (Fig B // "gp"), corresponding to the contiguous time just before the // transition (Fig B "tx"). GAP_START = 0b00000100, // Upon encountering an observed gap, disregard the specified date and // select the date at the end boundary of the observed gap (Fig B "gq"), // corresponding to the contiguous time at the transition (Fig B "tx"). GAP_END = 0b00001000, }; // Failed to resolve an absent zone-offset. The provided [[zflag]]s failed to // account for some timezone effect and could not produce a valid zone-offset. // A false value signifies the occurence of a timezone transition gap. // A true value signifies the occurence of a timezone transition overlap. export type zfunresolved = !bool; // A [[virtual]] date does not have enough information from which to create a // valid [[date]]. export type insufficient = !lack; // TODO: drop alias workaround export type lack = enum u8 { LOCALITY = 1 << 0, // could not deduce locality DAYDATE = 1 << 1, // could not deduce daydate DAYTIME = 1 << 2, // could not deduce time-of-day ZOFF = 1 << 3, // could not deduce zone offset }; // A virtual date; a [[date]] wrapper interface, which represents a date of // uncertain validity. Its fields need not be valid observed chronological // values. It is meant as an intermediary container for date information to be // resolved with the [[realize]] function. // // Unlike [[date]], a virtual date's fields are meant to be treated as public // and mutable. The embedded [[time::instant]] and [[time::chrono::locality]] // fields (.sec .nsec .loc) are considered meaningless. Behaviour with the // observer functions is undefined. // // This can be used to safely construct a new [[date]] piece-by-piece. Start // with [[newvirtual]], then collect enough date/time information incrementally // by direct field assignments and/or with [[parse]]. Finish with [[realize]]. // // let v = date::newvirtual(); // v.vloc = chrono::tz("Europe/Amsterdam")!; // v.zoff = date::zflag::LAP_EARLY | date::zflag::GAP_END; // date::parse(&v, "Date: %Y-%m-%d", "Date: 2000-01-02")!; // v.hour = 15; // v.minute = 4; // v.second = 5; // v.nanosecond = 600000000; // let d = date::realize(v)!; // export type virtual = struct { date, // virtual's timescalar second vsec: (void | i64), // virtual's nanosecond of timescalar second vnsec: (void | i64), // virtual's locality vloc: (void | chrono::locality), // locality name locname: (void | str), // zone offset zoff: (void | time::duration | zflag), // zone abbreviation zabbr: (void | str), // all but the last two digits of the year century: (void | int), // the last two digits of the year year100: (void | int), // hour of 12 hour clock hour12: (void | int), // AM/PM (false/true) ampm: (void | bool), }; // Creates a new [[virtual]] date. All its fields are voided or nulled. export fn newvirtual() virtual = virtual { sec = 0, nsec = 0, loc = chrono::UTC, zone = null, daydate = void, daytime = void, era = void, year = void, month = void, day = void, yearday = void, isoweekyear = void, isoweek = void, week = void, sundayweek = void, weekday = void, hour = void, minute = void, second = void, nanosecond = void, vsec = void, vnsec = void, vloc = void, locname = void, zoff = void, zabbr = void, century = void, year100 = void, hour12 = void, ampm = void, }; // Realizes a valid [[date]] from a [[virtual]] date, or fails appropriately. // // The virtual date must hold enough valid date information to be able to // calculate values for the resulting date. A valid combination of its fields // must be "filled-in" (hold numerical, non-void values). For example: // // let v = date::newvirtual(); // v.locname = "Europe/Amsterdam"; // v.zoff = date::zflag::LAP_EARLY | date::zflag::GAP_END; // date::parse(&v, // fills-in .year .month .day // "Date: %Y-%m-%d", "Date: 2038-01-19")!; // v.hour = 4; // v.minute = 14; // v.second = 7; // v.nanosecond = 0; // let d = date::realize(v, time::chrono::tz("Europe/Amsterdam")!)!; // // This function consults the fields of the given virtual date using a // predictable procedure, attempting the simplest and most common field // combinations first. Fields marked below with an asterisk (*), when empty, // depend on other filled-in field-sets to calculate a new value for itself. The // order in which these "dependency" field-sets are tried is described below. // // The resultant date depends on a locality value and instant value. // // The locality ([[time::chrono::locality]]) value depends on: // // - .vloc // - .locname : This is compared to the .name field of each locality // provided via the locs parameter, or "UTC" if none are provided. // The first matching locality is used. // // The instant ([[time::instant]]) value depends on: // // - .vsec, .vnsec // - .daydate*, .daytime*, .zoff // // An empty .daydate depends on: // // - .year*, .month, .day // - .year*, .yearday // - .year*, .week, .weekday // - .isoweekyear, .isoweek, .weekday // // An empty .daytime depends on: // // - .hour*, .minute, .second, .nanosecond // // An empty .year depends on: // // - .century, .year100 // // An empty .hour depends on: // // - .hour12, .ampm // // If not enough information was provided, [[insufficient]] is returned. // If invalid information was provided, [[invalid]] is returned. // Any [[zflag]]s assigned to the .zoff field affect the final result. export fn realize( v: virtual, locs: chrono::locality... ) (date | insufficient | invalid | zfunresolved) = { match (v.zoff) { case void => return lack::ZOFF; case time::duration => return realize_validzoff(v, locs...); case let zf: zflag => let valid_dates = realize_validzoffs(v, locs...)?; defer free(valid_dates); switch (len(valid_dates)) { case 0 => if (0 != zf & zflag::GAP_END) { return realize_gapbounds(v).1; } else if (0 != zf & zflag::GAP_START) { return realize_gapbounds(v).0; } else { return false: zfunresolved; }; case 1 => return valid_dates[0]; case => if (0 != zf & zflag::LAP_LATE) { return valid_dates[len(valid_dates) - 1]; } else if (0 != zf & zflag::LAP_EARLY) { return valid_dates[0]; } else { return true: zfunresolved; }; }; }; }; fn realize_validzoff( v: virtual, locs: chrono::locality... ) (date | insufficient | invalid) = { let d = realize_datetimezoff(v, locs...)?; // verify zone offset if (chrono::ozone(&d).zoff != v.zoff as time::duration) { return invalid; }; return d; }; fn realize_datetimezoff( v: virtual, locs: chrono::locality... ) (date | insufficient | invalid) = { let lacking = 0u8; // determine .loc if (v.vloc is chrono::locality) { v.loc = v.vloc as chrono::locality; } else if (v.locname is str) { for (let loc .. locs) { if (loc.name == v.locname as str) { v.loc = loc; break; }; }; } else { lacking |= insufficient::LOCALITY; }; // try using .vsec .vnsec if (v.vsec is i64 && v.vnsec is i64) { return from_instant( v.loc, time::instant{ sec = v.vsec as i64, nsec = v.vnsec as i64, }, ); }; // try using .daydate, .daytime, .zoff // determine zone offset if (v.zoff is i64) { void; } else { lacking |= insufficient::ZOFF; }; // determine .daydate if (v.daydate is i64) { void; } else :daydate { const year = if (v.year is int) { yield v.year as int; } else if (v.century is int && v.year100 is int) { let cc = v.century as int; let yy = v.year100 as int; if (yy < 0 || yy > 99) { return invalid; }; yield cc * 100 + yy; } else { lacking |= lack::DAYDATE; yield :daydate; }; if ( v.month is int && v.day is int ) { v.daydate = calc_daydate__ymd( year, v.month as int, v.day as int, )?; } else if ( v.yearday is int ) { v.daydate = calc_daydate__yd( year, v.yearday as int, )?; } else if ( v.week is int && v.weekday is int ) { v.daydate = calc_daydate__ywd( year, v.week as int, v.weekday as int, )?; } else if (false) { // TODO: calendar.ha: calc_daydate__isoywd() void; } else { // cannot deduce daydate lacking |= insufficient::DAYDATE; }; }; // determine .daytime if (v.daytime is i64) { void; } else :daytime { const hour = if (v.hour is int) { yield v.hour as int; } else if (v.hour12 is int && v.ampm is bool) { const hr = v.hour12 as int; const pm = v.ampm as bool; yield if (pm) hr * 2 else hr; } else { lacking |= insufficient::DAYTIME; yield :daytime; }; if ( v.minute is int && v.second is int && v.nanosecond is int ) { v.daytime = calc_daytime__hmsn( hour, v.minute as int, v.second as int, v.nanosecond as int, )?; } else { lacking |= insufficient::DAYTIME; }; }; if (lacking != 0u8) { return lacking: insufficient; }; // determine .sec, .nsec const d = from_moment(chrono::from_datetime( v.loc, v.zoff as time::duration, v.daydate as i64, v.daytime as i64, )); return d; }; fn realize_validzoffs( v: virtual, locs: chrono::locality... ) ([]date | insufficient | invalid) = { // check if only zoff is missing v.zoff = 0o0; match (realize_validzoff(v, locs...)) { case (date | invalid) => void; case let ins: insufficient => return ins; }; v.zoff = void; let dates: []date = []; // determine .loc if (v.vloc is chrono::locality) { v.loc = v.vloc as chrono::locality; } else if (v.locname is str) { for (let loc .. locs) { if (loc.name == v.locname as str) { v.loc = loc; v.vloc = loc; break; }; }; } else { return insufficient::LOCALITY; }; // try matching zone abbreviation if (v.zabbr is str) { for (let zone .. v.loc.zones) { if (v.zabbr as str == zone.abbr) { v.zoff = zone.zoff; match (realize_validzoff(v, locs...)) { case let d: date => match (sort::search( dates, size(date), &d, &cmpdates, )) { case size => void; case void => append(dates, d); sort::sort(dates, size(date), &cmpdates); }; case invalid => continue; case => abort(); }; }; }; return invalid; }; // try zone offsets from locality for (let zone .. v.loc.zones) { v.zoff = zone.zoff; match (realize_validzoff(v, locs...)) { case let d: date => match (sort::search(dates, size(date), &d, &cmpdates)) { case size => void; case void => append(dates, d); sort::sort(dates, size(date), &cmpdates); }; case invalid => continue; case => abort(); }; }; return dates; }; fn cmpdates(a: const *opaque, b: const *opaque) int = { let a = a: *date; let b = b: *date; return chrono::compare(a, b)!: int; }; fn realize_gapbounds(v: virtual) (date, date) = { let loc = v.vloc as chrono::locality; let zlo: time::duration = 48 * time::HOUR; let zhi: time::duration = -48 * time::HOUR; for (let zone .. loc.zones) { if (zone.zoff > zhi) { zhi = zone.zoff; }; if (zone.zoff < zlo) { zlo = zone.zoff; }; }; v.zoff = zhi; let earliest = realize_datetimezoff(v)!; let earliest = *(&earliest: *time::instant); v.zoff = zlo; let latest = realize_datetimezoff(v)!; let latest = *(&latest: *time::instant); let t = time::instant{ ... }; for (let tr .. loc.transitions) { let is_within_bounds = ( time::compare(earliest, tr.when) < 0 && time::compare(latest, tr.when) > 0 ); if (is_within_bounds) { t = tr.when; break; }; }; let gapstart = from_instant(loc, time::add(t, -time::NANOSECOND)); let gapend = from_instant(loc, t); // TODO: check if original v falls within gapstart & gapend? return (gapstart, gapend); }; hare-0.24.2/time/types.ha000066400000000000000000000026461464473310100151450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // The elapsed time between two instants, in nanoseconds. The largest // representable duration is about 290 years. export type duration = i64; // [[duration]] representing a single nanosecond. export def NANOSECOND: duration = 1; // [[duration]] representing a single microsecond. export def MICROSECOND: duration = 1000 * NANOSECOND; // [[duration]] representing a single millisecond. export def MILLISECOND: duration = 1000 * MICROSECOND; // [[duration]] representing a second. export def SECOND: duration = 1000 * MILLISECOND; // [[duration]] representing a minute. export def MINUTE: duration = 60 * SECOND; // [[duration]] representing an hour. export def HOUR: duration = 60 * MINUTE; // The earliest representable [[instant]]. export def INSTANT_MIN = instant { sec = types::I64_MIN, nsec = 0, }; // The latest representable [[instant]]. export def INSTANT_MAX = instant { sec = types::I64_MAX, nsec = SECOND - 1, }; // Represents a specific instant in time as seconds (+nanoseconds) since an // arbitrary epoch. Instants may only be meaningfully compared with other // instants sourced from the same [[clock]], or handled by the same // [[time::chrono::timescale]] export type instant = struct { sec: i64, nsec: i64, }; // Represents a unique interval of time between two [[instant]]s. export type interval = (instant, instant); hare-0.24.2/types/000077500000000000000000000000001464473310100136655ustar00rootroot00000000000000hare-0.24.2/types/README000066400000000000000000000004751464473310100145530ustar00rootroot00000000000000The types module provides access to some information about the Hare type system. It provides constants like [[INT_MAX]], which defines the useful range for integer types (see [[math::]] for f32 and f64 limits), as well as types like [[slice]], which describe the internal structure of data types like slices and str. hare-0.24.2/types/arch+aarch64.ha000066400000000000000000000015041464473310100163400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Minimum value which can be stored in an int type. export def INT_MIN: int = I32_MIN; // Maximum value which can be stored in an int type. export def INT_MAX: int = I32_MAX; // Minimum value which can be stored in a uint type export def UINT_MIN: uint = U32_MIN; // Maximum value which can be stored in a uint type. export def UINT_MAX: uint = U32_MAX; // Minimum value which can be stored in a size type export def SIZE_MIN: size = U64_MIN; // Maximum value which can be stored in a size type. export def SIZE_MAX: size = U64_MAX; // Minimum value which can be stored in a uintptr type export def UINTPTR_MIN: uintptr = U64_MIN: uintptr; // Maximum value which can be stored in a uintptr type. export def UINTPTR_MAX: uintptr = U64_MAX: uintptr; hare-0.24.2/types/arch+riscv64.ha000066400000000000000000000015041464473310100164100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Minimum value which can be stored in an int type. export def INT_MIN: int = I32_MIN; // Maximum value which can be stored in an int type. export def INT_MAX: int = I32_MAX; // Minimum value which can be stored in a uint type export def UINT_MIN: uint = U32_MIN; // Maximum value which can be stored in a uint type. export def UINT_MAX: uint = U32_MAX; // Minimum value which can be stored in a size type export def SIZE_MIN: size = U64_MIN; // Maximum value which can be stored in a size type. export def SIZE_MAX: size = U64_MAX; // Minimum value which can be stored in a uintptr type export def UINTPTR_MIN: uintptr = U64_MIN: uintptr; // Maximum value which can be stored in a uintptr type. export def UINTPTR_MAX: uintptr = U64_MAX: uintptr; hare-0.24.2/types/arch+x86_64.ha000066400000000000000000000015041464473310100160460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Minimum value which can be stored in an int type. export def INT_MIN: int = I32_MIN; // Maximum value which can be stored in an int type. export def INT_MAX: int = I32_MAX; // Minimum value which can be stored in a uint type export def UINT_MIN: uint = U32_MIN; // Maximum value which can be stored in a uint type. export def UINT_MAX: uint = U32_MAX; // Minimum value which can be stored in a size type export def SIZE_MIN: size = U64_MIN; // Maximum value which can be stored in a size type. export def SIZE_MAX: size = U64_MAX; // Minimum value which can be stored in a uintptr type export def UINTPTR_MIN: uintptr = U64_MIN: uintptr; // Maximum value which can be stored in a uintptr type. export def UINTPTR_MAX: uintptr = U64_MAX: uintptr; hare-0.24.2/types/c/000077500000000000000000000000001464473310100141075ustar00rootroot00000000000000hare-0.24.2/types/c/+test.ha000066400000000000000000000032771464473310100154640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors static assert(size(char) == size(schar)); static assert(size(char) == size(uchar)); static assert(size(char) == 1); static assert(size(short) == size(ushort)); static assert(size(long) == size(ulong)); static assert(size(longlong) == size(ulonglong)); static assert(size(intmax) == size(uintmax)); static assert(size(intptr) == size(uintptr)); static assert(size(ssize) == size(size)); static assert(size(short) <= size(int)); static assert(size(long) >= 4); static assert(size(longlong) >= 8); static assert(size(short) >= size(char)); static assert(size(int) >= size(short)); static assert(size(long) >= size(int)); static assert(size(longlong) >= size(long)); static assert(align(char) == align(schar)); static assert(align(char) == align(uchar)); static assert(align(char) == 1); static assert(align(short) == align(ushort)); static assert(align(long) == align(ulong)); static assert(align(longlong) == align(ulonglong)); static assert(align(intmax) == align(uintmax)); static assert(align(intptr) == align(uintptr)); static assert(align(ssize) == align(size)); @test fn strings() void = { let s = fromstr("hello!"); defer free(s); assert(tostr(s)! == "hello!"); let s = nulstr("hello!\0"); assert(tostr(s)! == "hello!"); }; @test fn strlen() void = { assert(strlen(nulstr("hello!\0")) == 6); assert(strlen(nulstr("\0")) == 0); }; @test fn strnlen() void = { assert(strnlen(nulstr("hello!\0"), 10) == 6); assert(strnlen(nulstr("hello!\0"), 6) == 6); assert(strnlen(nulstr("hello!\0"), 4) == 4); assert(strnlen(nulstr("hello!\0"), 0) == 0); assert(strnlen(nulstr("\0"), 1) == 0); assert(strnlen(null: *const char, 0) == 0); }; hare-0.24.2/types/c/README000066400000000000000000000027661464473310100150020ustar00rootroot00000000000000types::c provides type aliases that are compatible with standard C builtin types and typedefs, as specified ISO/IEC 9899 and POSIX, as well as convenience functions for working with C types. This module is useful for C interop, for instance if an external function returns a [[long]] or a [[ssize]], or if you need to convert between a C string and a Hare string. The types provided here shouldn't be used for most Hare code. Some C types aren't provided by this module, since they are provided by the Hare language itself: - _Bool, bool -> bool - nullptr_t -> null - (signed) int -> int - size_t -> size - unsigned int -> uint - uintptr_t -> uintptr - va_list -> valist Some C types are mostly compatible with Hare types, with minor differences: - C's void is an incomplete opaque type, which is also used to indicate the absence of a value. Hare provides void as a zero-size type, and opaque as an undefined-size opaque type. - Hare doesn't have builtin imaginary or complex types, though complex types with equivalent represention to their C counterparts are declared in [[math::complex::]]. Hare doesn't allow casting between real and complex types like C does. Hare doesn't support bit-precise integer types (_BitInt) or decimal floating point types (_Decimal32, _Decimal64, _Decimal128). Hare also doesn't provide any floating point type larger than 8 bytes, implicating `long double` on some platforms. Additional low-level or implementation-specific types may be defined in [[rt::]]. hare-0.24.2/types/c/arch+aarch64.ha000066400000000000000000000064471464473310100165750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Integer type compatible with `char`, as specified by ISO/IEC 9899. export type char = uchar; // Minimum value which can be stored in a [[char]] type. export def CHAR_MIN: char = UCHAR_MIN; // Maximum value which can be stored in a [[char]] type. export def CHAR_MAX: char = UCHAR_MAX; // Integer type compatible with `signed short`, as specified by ISO/IEC 9899. export type short = i16; // Minimum value which can be stored in a [[short]] type. export def SHORT_MIN: short = types::I16_MIN; // Maximum value which can be stored in a [[short]] type. export def SHORT_MAX: short = types::I16_MAX; // Integer type compatible with `unsigned short`, as specified by ISO/IEC 9899. export type ushort = u16; // Minimum value which can be stored in a [[ushort]] type. export def USHRT_MIN: ushort = types::U16_MIN; // Maximum value which can be stored in a [[ushort]] type. export def USHRT_MAX: ushort = types::U16_MAX; // Integer type compatible with `signed long`, as specified by ISO/IEC 9899. export type long = i64; // Minimum value which can be stored in a [[long]] type. export def LONG_MIN: long = types::I64_MIN; // Maximum value which can be stored in a [[long]] type. export def LONG_MAX: long = types::I64_MAX; // Integer type compatible with `unsigned long`, as specified by ISO/IEC 9899. export type ulong = u64; // Minimum value which can be stored in a [[ulong]] type. export def ULONG_MIN: ulong = types::U64_MIN; // Maximum value which can be stored in a [[ulong]] type. export def ULONG_MAX: ulong = types::U64_MAX; // Integer type compatible with `signed long long`, as specified by ISO/IEC // 9899:1999. export type longlong = i64; // Minimum value which can be stored in a [[longlong]] type. export def LLONG_MIN: longlong = types::I64_MIN; // Maximum value which can be stored in a [[longlong]] type. export def LLONG_MAX: longlong = types::I64_MAX; // Integer type compatible with `unsigned long long`, as specified by ISO/IEC // 9899:1999. export type ulonglong = u64; // Minimum value which can be stored in a [[ulonglong]] type. export def ULLONG_MIN: ulonglong = types::U64_MIN; // Maximum value which can be stored in a [[ulonglong]] type. export def ULLONG_MAX: ulonglong = types::U64_MAX; // Integer type compatible with `intptr_t`, as defined in and // specified by ISO/IEC 9899. export type intptr = i64; // Minimum value which can be stored in an [[intptr]] type. export def INTPTR_MIN: intptr = types::I64_MIN; // Maximum value which can be stored in an [[intptr]] type. export def INTPTR_MAX: intptr = types::I64_MAX; // Integer type compatible with `ptrdiff_t`, as defined in and // specified by ISO/IEC 9899. export type ptrdiff = i64; // Minimum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MIN: ptrdiff = types::I64_MIN; // Maximum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MAX: ptrdiff = types::I64_MAX; // Integer type compatible with `ssize_t`, as defined in and // specified by POSIX. export type ssize = i64; // Minimum value which can be stored in an [[ssize]] type. export def SSIZE_MIN: ssize = types::I64_MIN; // Maximum value which can be stored in an [[ssize]] type. export def SSIZE_MAX: ssize = types::I64_MAX; hare-0.24.2/types/c/arch+riscv64.ha000066400000000000000000000064471464473310100166450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Integer type compatible with `char`, as specified by ISO/IEC 9899. export type char = uchar; // Minimum value which can be stored in a [[char]] type. export def CHAR_MIN: char = UCHAR_MIN; // Maximum value which can be stored in a [[char]] type. export def CHAR_MAX: char = UCHAR_MAX; // Integer type compatible with `signed short`, as specified by ISO/IEC 9899. export type short = i16; // Minimum value which can be stored in a [[short]] type. export def SHORT_MIN: short = types::I16_MIN; // Maximum value which can be stored in a [[short]] type. export def SHORT_MAX: short = types::I16_MAX; // Integer type compatible with `unsigned short`, as specified by ISO/IEC 9899. export type ushort = u16; // Minimum value which can be stored in a [[ushort]] type. export def USHRT_MIN: ushort = types::U16_MIN; // Maximum value which can be stored in a [[ushort]] type. export def USHRT_MAX: ushort = types::U16_MAX; // Integer type compatible with `signed long`, as specified by ISO/IEC 9899. export type long = i64; // Minimum value which can be stored in a [[long]] type. export def LONG_MIN: long = types::I64_MIN; // Maximum value which can be stored in a [[long]] type. export def LONG_MAX: long = types::I64_MAX; // Integer type compatible with `unsigned long`, as specified by ISO/IEC 9899. export type ulong = u64; // Minimum value which can be stored in a [[ulong]] type. export def ULONG_MIN: ulong = types::U64_MIN; // Maximum value which can be stored in a [[ulong]] type. export def ULONG_MAX: ulong = types::U64_MAX; // Integer type compatible with `signed long long`, as specified by ISO/IEC // 9899:1999. export type longlong = i64; // Minimum value which can be stored in a [[longlong]] type. export def LLONG_MIN: longlong = types::I64_MIN; // Maximum value which can be stored in a [[longlong]] type. export def LLONG_MAX: longlong = types::I64_MAX; // Integer type compatible with `unsigned long long`, as specified by ISO/IEC // 9899:1999. export type ulonglong = u64; // Minimum value which can be stored in a [[ulonglong]] type. export def ULLONG_MIN: ulonglong = types::U64_MIN; // Maximum value which can be stored in a [[ulonglong]] type. export def ULLONG_MAX: ulonglong = types::U64_MAX; // Integer type compatible with `intptr_t`, as defined in and // specified by ISO/IEC 9899. export type intptr = i64; // Minimum value which can be stored in an [[intptr]] type. export def INTPTR_MIN: intptr = types::I64_MIN; // Maximum value which can be stored in an [[intptr]] type. export def INTPTR_MAX: intptr = types::I64_MAX; // Integer type compatible with `ptrdiff_t`, as defined in and // specified by ISO/IEC 9899. export type ptrdiff = i64; // Minimum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MIN: ptrdiff = types::I64_MIN; // Maximum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MAX: ptrdiff = types::I64_MAX; // Integer type compatible with `ssize_t`, as defined in and // specified by POSIX. export type ssize = i64; // Minimum value which can be stored in an [[ssize]] type. export def SSIZE_MIN: ssize = types::I64_MIN; // Maximum value which can be stored in an [[ssize]] type. export def SSIZE_MAX: ssize = types::I64_MAX; hare-0.24.2/types/c/arch+x86_64.ha000066400000000000000000000064471464473310100163030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Integer type compatible with `char`, as specified by ISO/IEC 9899. export type char = schar; // Minimum value which can be stored in a [[char]] type. export def CHAR_MIN: char = SCHAR_MIN; // Maximum value which can be stored in a [[char]] type. export def CHAR_MAX: char = SCHAR_MAX; // Integer type compatible with `signed short`, as specified by ISO/IEC 9899. export type short = i16; // Minimum value which can be stored in a [[short]] type. export def SHORT_MIN: short = types::I16_MIN; // Maximum value which can be stored in a [[short]] type. export def SHORT_MAX: short = types::I16_MAX; // Integer type compatible with `unsigned short`, as specified by ISO/IEC 9899. export type ushort = u16; // Minimum value which can be stored in a [[ushort]] type. export def USHRT_MIN: ushort = types::U16_MIN; // Maximum value which can be stored in a [[ushort]] type. export def USHRT_MAX: ushort = types::U16_MAX; // Integer type compatible with `signed long`, as specified by ISO/IEC 9899. export type long = i64; // Minimum value which can be stored in a [[long]] type. export def LONG_MIN: long = types::I64_MIN; // Maximum value which can be stored in a [[long]] type. export def LONG_MAX: long = types::I64_MAX; // Integer type compatible with `unsigned long`, as specified by ISO/IEC 9899. export type ulong = u64; // Minimum value which can be stored in a [[ulong]] type. export def ULONG_MIN: ulong = types::U64_MIN; // Maximum value which can be stored in a [[ulong]] type. export def ULONG_MAX: ulong = types::U64_MAX; // Integer type compatible with `signed long long`, as specified by ISO/IEC // 9899:1999. export type longlong = i64; // Minimum value which can be stored in a [[longlong]] type. export def LLONG_MIN: longlong = types::I64_MIN; // Maximum value which can be stored in a [[longlong]] type. export def LLONG_MAX: longlong = types::I64_MAX; // Integer type compatible with `unsigned long long`, as specified by ISO/IEC // 9899:1999. export type ulonglong = u64; // Minimum value which can be stored in a [[ulonglong]] type. export def ULLONG_MIN: ulonglong = types::U64_MIN; // Maximum value which can be stored in a [[ulonglong]] type. export def ULLONG_MAX: ulonglong = types::U64_MAX; // Integer type compatible with `intptr_t`, as defined in and // specified by ISO/IEC 9899. export type intptr = i64; // Minimum value which can be stored in an [[intptr]] type. export def INTPTR_MIN: intptr = types::I64_MIN; // Maximum value which can be stored in an [[intptr]] type. export def INTPTR_MAX: intptr = types::I64_MAX; // Integer type compatible with `ptrdiff_t`, as defined in and // specified by ISO/IEC 9899. export type ptrdiff = i64; // Minimum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MIN: ptrdiff = types::I64_MIN; // Maximum value which can be stored in a [[ptrdiff]] type. export def PTRDIFF_MAX: ptrdiff = types::I64_MAX; // Integer type compatible with `ssize_t`, as defined in and // specified by POSIX. export type ssize = i64; // Minimum value which can be stored in an [[ssize]] type. export def SSIZE_MIN: ssize = types::I64_MIN; // Maximum value which can be stored in an [[ssize]] type. export def SSIZE_MAX: ssize = types::I64_MAX; hare-0.24.2/types/c/strings.ha000066400000000000000000000063051464473310100161160ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use types; let empty: [_]u8 = [0]; // An empty NUL-terminated C string. export let empty_string: *const char = &empty[0]: *const char; // Computes the length of a NUL-terminated C string, in octets, in O(n). The // computed length does not include the NUL terminator. export fn strlen(cstr: *const char) size = { const ptr = cstr: *[*]u8; let ln = 0z; for (ptr[ln] != 0; ln += 1) void; return ln; }; // Computes the length of a NUL-terminated C string, only looking at the first // maxlen bytes. The computed length does not include the NUL terminator. export fn strnlen(cstr: *const char, maxlen: size) size = { const ptr = cstr: *[*]u8; let ln = 0z; for (ln < maxlen && ptr[ln] != 0; ln += 1) void; return ln; }; // Converts a C string to a Hare string in O(n), and does not check if it's // valid UTF-8. export fn tostr_unsafe(cstr: *const char) const str = { return tostrn_unsafe(cstr, strlen(cstr)); }; // Converts a C string with a given length to a Hare string, and does not check // if it's valid UTF-8. export fn tostrn_unsafe(cstr: *const char, length: size) const str = { const s = types::string { data = cstr: *[*]u8, length = length, capacity = length + 1, }; return *(&s: *const str); }; // Converts a C string to a Hare string in O(n). If the string is not valid // UTF-8, return [[encoding::utf8::invalid]]. export fn tostr(cstr: *const char) (const str | utf8::invalid) = { return tostrn(cstr, strlen(cstr)); }; // Converts a C string with a given length to a Hare string. If the string is // not valid UTF-8, return [[encoding::utf8::invalid]]. export fn tostrn(cstr: *const char, length: size) (const str | utf8::invalid) = { utf8::validate((cstr: *[*]u8)[..length])?; return tostrn_unsafe(cstr, length); }; // Converts a Hare string to a C string. The result is allocated; the caller // must free it when they're done. export fn fromstr(s: const str) *char = { let slice: []char = alloc([0...], len(s) + 1); return fromstr_buf(s, slice); }; // Converts a Hare string to a C string. The result is stored into a // user-supplied buffer. export fn fromstr_buf(s: const str, sl: []char) *char = { if (len(sl) < len(s) + 1) { abort("types::c::fromstr_buf: buffer has insufficient space for string plus NUL"); }; const s = &s: *[]char; sl[..len(s)] = s[..]; sl[len(s)] = 0; return (*(&sl: *types::slice)).data: *char; }; // Converts a NUL-terminated Hare string to a C string. Aborts if the input // string isn't NUL-terminated. The result is borrowed from the input. export fn nulstr(s: const str) *const char = { let s = &s: *types::string; let data = s.data as *[*]u8; assert(data[s.length - 1] == '\0', "types::c::nulstr input must be NUL-terminated"); return s.data: *const char; }; // Converts a non-NUL-terminated Hare string to a *const [[char]]. The return // value is borrowed from the input, except in the case of an empty string, in // which case it is statically allocated. // // Use with caution! export fn unterminatedstr(s: const str) *const char = { let s = &s: *types::string; if (s.data == null) { return empty_string; }; let data = s.data as *[*]u8; return data: *const char; }; hare-0.24.2/types/c/types.ha000066400000000000000000000227021464473310100155700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use types; // Integer type compatible with `signed char`, as specified by ISO/IEC 9899. export type schar = i8; // Minimum value which can be stored in an [[schar]] type. export def SCHAR_MIN: schar = types::I8_MIN; // Maximum value which can be stored in an [[schar]] type. export def SCHAR_MAX: schar = types::I8_MAX; // Integer type compatible with `unsigned char`, as specified by ISO/IEC 9899. export type uchar = u8; // Minimum value which can be stored in a [[uchar]] type. export def UCHAR_MIN: uchar = types::U8_MIN; // Maximum value which can be stored in a [[uchar]] type. export def UCHAR_MAX: uchar = types::U8_MAX; // Integer type compatible with `char8_t`, as defined in and specified // by ISO/IEC 9899:2023. export type char8 = uchar; // Minimum value which can be stored in a [[char8]] type. export def CHAR8_MIN: char8 = UCHAR_MIN; // Maximum value which can be stored in a [[char8]] type. export def CHAR8_MAX: char8 = UCHAR_MAX; // Integer type compatible with `char16_t`, as defined in and // specified by ISO/IEC 9899:2011. export type char16 = uint_least16; // Minimum value which can be stored in a [[char16]] type. export def CHAR16_MIN: char16 = UINT_LEAST16_MIN; // Maximum value which can be stored in a [[char16]] type. export def CHAR16_MAX: char16 = UINT_LEAST16_MAX; // Integer type compatible with `char32_t`, as defined in and // specified by ISO/IEC 9899:2011. export type char32 = uint_least32; // Minimum value which can be stored in a [[char32]] type. export def CHAR32_MIN: char32 = UINT_LEAST32_MIN; // Maximum value which can be stored in a [[char32]] type. export def CHAR32_MAX: char32 = UINT_LEAST32_MAX; // Integer type compatible with `intmax_t`, as defined in and // specified by ISO/IEC 9899:1999. // // Note that this type isn't necessarily the actual maximum integer type. This // type should only be used when required for C interop. export type intmax = i64; // Minimum value which can be stored in an [[intmax]] type. export def INTMAX_MIN: intmax = types::I64_MIN; // Maximum value which can be stored in an [[intmax]] type. export def INTMAX_MAX: intmax = types::I64_MAX; // Integer type compatible with `uintmax_t`, as defined in and // specified by ISO/IEC 9899:1999. // // Note that this type isn't necessarily the actual maximum integer type. This // type should only be used when required for C interop. export type uintmax = u64; // Minimum value which can be stored in a [[uintmax]] type. export def UINTMAX_MIN: uintmax = types::U64_MIN; // Maximum value which can be stored in a [[uintmax]] type. export def UINTMAX_MAX: uintmax = types::U64_MAX; // Integer type compatible with `int_least8_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_least8 = i8; // Minimum value which can be stored in an [[int_least8]] type. export def INT_LEAST8_MIN: int_least8 = types::I8_MIN; // Maximum value which can be stored in an [[int_least8]] type. export def INT_LEAST8_MAX: int_least8 = types::I8_MAX; // Integer type compatible with `int_least16_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_least16 = i16; // Minimum value which can be stored in an [[int_least16]] type. export def INT_LEAST16_MIN: int_least16 = types::I16_MIN; // Maximum value which can be stored in an [[int_least16]] type. export def INT_LEAST16_MAX: int_least16 = types::I16_MAX; // Integer type compatible with `int_least32_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_least32 = i32; // Minimum value which can be stored in an [[int_least32]] type. export def INT_LEAST32_MIN: int_least32 = types::I32_MIN; // Maximum value which can be stored in an [[int_least32]] type. export def INT_LEAST32_MAX: int_least32 = types::I32_MAX; // Integer type compatible with `int_least64_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_least64 = i64; // Minimum value which can be stored in an [[int_least64]] type. export def INT_LEAST64_MIN: int_least64 = types::I64_MIN; // Maximum value which can be stored in an [[int_least64]] type. export def INT_LEAST64_MAX: int_least64 = types::I64_MAX; // Integer type compatible with `uint_least8_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_least8 = u8; // Minimum value which can be stored in a [[uint_least8]] type. export def UINT_LEAST8_MIN: uint_least8 = types::U8_MIN; // Maximum value which can be stored in a [[uint_least8]] type. export def UINT_LEAST8_MAX: uint_least8 = types::U8_MAX; // Integer type compatible with `uint_least16_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_least16 = u16; // Minimum value which can be stored in a [[uint_least16]] type. export def UINT_LEAST16_MIN: uint_least16 = types::U16_MIN; // Maximum value which can be stored in a [[uint_least16]] type. export def UINT_LEAST16_MAX: uint_least16 = types::U16_MAX; // Integer type compatible with `uint_least32_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_least32 = u32; // Minimum value which can be stored in a [[uint_least32]] type. export def UINT_LEAST32_MIN: uint_least32 = types::U32_MIN; // Maximum value which can be stored in a [[uint_least32]] type. export def UINT_LEAST32_MAX: uint_least32 = types::U32_MAX; // Integer type compatible with `uint_least64_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_least64 = u64; // Minimum value which can be stored in a [[uint_least64]] type. export def UINT_LEAST64_MIN: uint_least64 = types::U64_MIN; // Maximum value which can be stored in a [[uint_least64]] type. export def UINT_LEAST64_MAX: uint_least64 = types::U64_MAX; // Integer type compatible with `int_fast8_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_fast8 = i8; // Minimum value which can be stored in an [[int_fast8]] type. export def INT_FAST8_MIN: int_fast8 = types::I8_MIN; // Maximum value which can be stored in an [[int_fast8]] type. export def INT_FAST8_MAX: int_fast8 = types::I8_MAX; // Integer type compatible with `int_fast16_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_fast16 = i16; // Minimum value which can be stored in an [[int_fast16]] type. export def INT_FAST16_MIN: int_fast16 = types::I16_MIN; // Maximum value which can be stored in an [[int_fast16]] type. export def INT_FAST16_MAX: int_fast16 = types::I16_MAX; // Integer type compatible with `int_fast32_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_fast32 = i32; // Minimum value which can be stored in an [[int_fast32]] type. export def INT_FAST32_MIN: int_fast32 = types::I32_MIN; // Maximum value which can be stored in an [[int_fast32]] type. export def INT_FAST32_MAX: int_fast32 = types::I32_MAX; // Integer type compatible with `int_fast64_t`, as defined in and // specified by ISO/IEC 9899:1999. export type int_fast64 = i64; // Minimum value which can be stored in an [[int_fast64]] type. export def INT_FAST64_MIN: int_fast64 = types::I64_MIN; // Maximum value which can be stored in an [[int_fast64]] type. export def INT_FAST64_MAX: int_fast64 = types::I64_MAX; // Integer type compatible with `uint_fast8_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_fast8 = u8; // Minimum value which can be stored in a [[uint_fast8]] type. export def UINT_FAST8_MIN: uint_fast8 = types::U8_MIN; // Maximum value which can be stored in a [[uint_fast8]] type. export def UINT_FAST8_MAX: uint_fast8 = types::U8_MAX; // Integer type compatible with `uint_fast16_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_fast16 = u16; // Minimum value which can be stored in a [[uint_fast16]] type. export def UINT_FAST16_MIN: uint_fast16 = types::U16_MIN; // Maximum value which can be stored in a [[uint_fast16]] type. export def UINT_FAST16_MAX: uint_fast16 = types::U16_MAX; // Integer type compatible with `uint_fast32_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_fast32 = u32; // Minimum value which can be stored in a [[uint_fast32]] type. export def UINT_FAST32_MIN: uint_fast32 = types::U32_MIN; // Maximum value which can be stored in a [[uint_fast32]] type. export def UINT_FAST32_MAX: uint_fast32 = types::U32_MAX; // Integer type compatible with `uint_fast64_t`, as defined in and // specified by ISO/IEC 9899:1999. export type uint_fast64 = u64; // Minimum value which can be stored in a [[uint_fast64]] type. export def UINT_FAST64_MIN: uint_fast64 = types::U64_MIN; // Maximum value which can be stored in a [[uint_fast64]] type. export def UINT_FAST64_MAX: uint_fast64 = types::U64_MAX; // Integer type compatible with `wchar_t`, as defined in and // specified by ISO/IEC 9899. export type wchar = i32; // Minimum value which can be stored in a [[wchar]] type. export def WCHAR_MIN: wchar = types::I32_MIN; // Maximum value which can be stored in a [[wchar]] type. export def WCHAR_MAX: wchar = types::I32_MAX; // Integer type compatible with `wint_t`, as defined in and specified // by ISO/IEC 9899:1994. export type wint = u32; // Minimum value which can be stored in a [[wint]] type. export def WINT_MIN: wint = types::U32_MIN; // Maximum value which can be stored in a [[wint]] type. export def WINT_MAX: wint = types::U32_MAX; hare-0.24.2/types/classes.ha000066400000000000000000000023411464473310100156340ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A tagged union of all signed integer types. export type signed = (i8 | i16 | i32 | i64 | int); // A tagged union of all unsigned integer types, excluding uintptr. export type unsigned = (u8 | u16 | u32 | u64 | uint | size); // A tagged union of all integer types, excluding uintptr. export type integer = (...signed | ...unsigned); // A tagged union of all floating point numeric types. export type floating = (f32 | f64); // A tagged union of all numeric types, excluding uintptr. export type numeric = (...integer | ...floating); // A type representing the internal structure of strings, useful for low-level // string manipulation. export type string = struct { // UTF-8 encoded octets. data: nullable *[*]u8, // The length capacity, in octets of UTF-8 data. length: size, // The allocated capacity, in octets of UTF-8 data. capacity: size, }; // A type representing the internal structure of slices, useful for low-level // slice manipulation. export type slice = struct { // The slice contents. data: nullable *opaque, // The number of members of the slice. length: size, // The allocated capacity (in members) of data. capacity: size, }; hare-0.24.2/types/limits.ha000066400000000000000000000032311464473310100154770ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Minimum value which can be stored in an i8 type. export def I8_MIN: i8 = -128; // Maximum value which can be stored in an i8 type. export def I8_MAX: i8 = 127; // Minimum value which can be stored in an i16 type. export def I16_MIN: i16 = -32768; // Maximum value which can be stored in an i16 type. export def I16_MAX: i16 = 32767; // Minimum value which can be stored in an i32 type. export def I32_MIN: i32 = -2147483648; // Maximum value which can be stored in an i32 type. export def I32_MAX: i32 = 2147483647; // Minimum value which can be stored in an i64 type export def I64_MIN: i64 = -9223372036854775808i64; // Maximum value which can be stored in an i64 type. export def I64_MAX: i64 = 9223372036854775807; // Minimum value which can be stored in a u8 type. export def U8_MIN: u8 = 0; // Maximum value which can be stored in a u8 type. export def U8_MAX: u8 = 255; // Minimum value which can be stored in a u16 type export def U16_MIN: u16 = 0; // Maximum value which can be stored in a u16 type. export def U16_MAX: u16 = 65535; // Minimum value which can be stored in a u32 type export def U32_MIN: u32 = 0; // Maximum value which can be stored in a u32 type. export def U32_MAX: u32 = 4294967295; // Minimum value which can be stored in a u64 type export def U64_MIN: u64 = 0; // Maximum value which can be stored in a u64 type. export def U64_MAX: u64 = 18446744073709551615; // Minimum Unicode codepoint which can be stored in a rune. export def RUNE_MIN: rune = '\0'; // Maximum Unicode codepoint which can be stored in a rune. export def RUNE_MAX: rune = '\U0010ffff'; hare-0.24.2/unix/000077500000000000000000000000001464473310100135045ustar00rootroot00000000000000hare-0.24.2/unix/+freebsd/000077500000000000000000000000001464473310100151715ustar00rootroot00000000000000hare-0.24.2/unix/+freebsd/creds.ha000066400000000000000000000112741464473310100166100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Unix credentials types & functions; ref credentials(7) use errors; use rt; // Process ID. export type pid = rt::pid_t; // User ID. export type uid = rt::uid_t; // Group ID. export type gid = rt::gid_t; // Returns the current process user ID. export fn getuid() uid = { let uid = 0u, euid = 0u, suid = 0u; rt::getresuid(&uid, &euid, &suid) as void; return uid; }; // Returns the current process effective user ID. export fn geteuid() uid = { let uid = 0u, euid = 0u, suid = 0u; rt::getresuid(&uid, &euid, &suid) as void; return euid; }; // Returns the current process group ID. export fn getgid() gid = { let gid = 0u, egid = 0u, sgid = 0u; rt::getresgid(&gid, &egid, &sgid) as void; return gid; }; // Returns the current process effective group ID. export fn getegid() gid = { let gid = 0u, egid = 0u, sgid = 0u; rt::getresgid(&gid, &egid, &sgid) as void; return egid; }; // Sets the caller's user ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setuid(uid: uid) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; // Sets the caller's effective user ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from seteuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn seteuid(uid: uid) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; // Sets the caller's group ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgid(gid: gid) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; // Sets the caller's effective group ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setegid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setegid(gid: gid) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; // Returns a list of supplementary group IDs for the current process. The // returned slice is statically allocated. export fn getgroups() []gid = { static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; const n = rt::getgroups(gids)!; return gids[..n]: []gid; }; // Sets the list of supplementary group IDs which apply to the current process. // This generally requires elevated permissions. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setgroups is a grave security issue in your program, // and therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; // Returns the current process ID. export fn getpid() pid = rt::getpid(); // Returns the parent process ID. export fn getppid() pid = rt::getppid(); // Returns the current process group ID. export fn getpgrp() pid = rt::getpgrp(); // Returns the current process's session ID. export fn getsid() pid = rt::getsid(0)!; // Returns the session ID associated with the given process. export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { match (rt::getsid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH); return errors::noentry; }; }; hare-0.24.2/unix/+freebsd/nice.ha000066400000000000000000000013321464473310100164200ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Adds the argument to the niceness of the current process. The input should be // between -20 and 19 (inclusive); lower numbers represent a higher priority. // Generally, you must have elevated permissions to reduce your niceness, but // not to increase it. export fn nice(inc: int) (void | errors::error) = { let prio = inc; if (inc > -40 && inc <= 40) { prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int; }; if (prio > 19) { prio = 19; }; if (prio < -20) { prio = -20; }; match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/+freebsd/pipe.ha000066400000000000000000000014071464473310100164420ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags to use for the [[io::file]]s returned by [[pipe]]. // Only NOCLOEXEC and NONBLOCK are guaranteed to be available. export type pipe_flag = enum { NOCLOEXEC = rt::O_CLOEXEC, DIRECT = rt::O_DIRECT, NONBLOCK = rt::O_NONBLOCK, }; // Create a pair of two linked [[io::file]]s, such that any data written to the // second [[io::file]] may be read from the first. export fn pipe(flags: pipe_flag = 0) ((io::file, io::file) | errors::error) = { let fds: [2]int = [0...]; flags ^= pipe_flag::NOCLOEXEC; // invert CLOEXEC match (rt::pipe2(&fds, flags)) { case void => void; case let e: rt::errno => return errors::errno(e); }; return (fds[0], fds[1]); }; hare-0.24.2/unix/+freebsd/umask.ha000066400000000000000000000004361464473310100166260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; // Sets the file mode creation mask for the current process and return the // previous value of the mask. export fn umask(mode: fs::mode) fs::mode = rt::umask(mode: rt::mode_t)!: fs::mode; hare-0.24.2/unix/+linux/000077500000000000000000000000001464473310100147165ustar00rootroot00000000000000hare-0.24.2/unix/+linux/creds.ha000066400000000000000000000140571464473310100163370ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Unix credentials types & functions; ref credentials(7) use errors; use rt; // Process ID. export type pid = rt::pid_t; // User ID. export type uid = rt::uid_t; // Group ID. export type gid = rt::gid_t; // Returns the current process user ID. export fn getuid() uid = { let uid = 0u, euid = 0u, suid = 0u; rt::getresuid(&uid, &euid, &suid) as void; return uid; }; // Returns the current process effective user ID. export fn geteuid() uid = { let uid = 0u, euid = 0u, suid = 0u; rt::getresuid(&uid, &euid, &suid) as void; return euid; }; // Returns the current process group ID. export fn getgid() gid = { let gid = 0u, egid = 0u, sgid = 0u; rt::getresgid(&gid, &egid, &sgid) as void; return gid; }; // Returns the current process effective group ID. export fn getegid() gid = { let gid = 0u, egid = 0u, sgid = 0u; rt::getresgid(&gid, &egid, &sgid) as void; return egid; }; // Sets the caller's user ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setuid(uid: uid) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; // Sets the caller's effective user ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from seteuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn seteuid(uid: uid) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; // Sets the caller's group ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgid(gid: gid) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; // Sets the caller's effective group ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setegid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setegid(gid: gid) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; // Returns a list of supplementary group IDs for the current process. The // returned slice is statically allocated. export fn getgroups() []gid = { static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; const n = rt::getgroups(gids)!; return gids[..n]: []gid; }; // Sets the list of supplementary group IDs which apply to the current process. // This generally requires elevated permissions. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setgroups is a grave security issue in your program, // and therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; // Returns the current process ID. export fn getpid() pid = rt::getpid(); // Returns the parent process ID. export fn getppid() pid = rt::getppid(); // Returns the current process group ID. export fn getpgrp() pid = rt::getpgrp(); // Returns the process group associated with the given pid. export fn getpgid(pid: pid) (pid | errors::noentry) = { match (rt::getpgid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH, "Unexpected getpgid return value"); return errors::noentry; }; }; // Sets the process group ID of the specified process. This function is // error-prone; see the notes in the POSIX specification for its many caveats. export fn setpgid(targ: pid, pgid: pid) (void | errors::error) = { match (rt::setpgid(targ, pgid)) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; // Returns the current process's session ID. export fn getsid() pid = rt::getsid(0)!; // Returns the session ID associated with the given process. export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { match (rt::getsid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH, "Unexpected getsid return value"); return errors::noentry; }; }; // Creates a new session and sets the current process to the session leader. // A new process group is also created with its process group ID equal to the // pid of the current process, and the current process is made the process group // leader. // // Upon return, the new session will have no controlling terminal. To establish // one, the caller must open a terminal file with [[fs::flag::CTTY]]; this // opt-in approach differs from the Unix norm where O_NOCTTY is required to // opt-out of establishing a controlling terminal. // // The current process cannot be a process group leader; this is a programmer // error and will cause a runtime assertion failure. export fn setsid() void = rt::setsid()!; hare-0.24.2/unix/+linux/nice.ha000066400000000000000000000013321464473310100161450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Adds the argument to the niceness of the current process. The input should be // between -20 and 19 (inclusive); lower numbers represent a higher priority. // Generally, you must have elevated permissions to reduce your niceness, but // not to increase it. export fn nice(inc: int) (void | errors::error) = { let prio = inc; if (inc > -40 && inc <= 40) { prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int; }; if (prio > 19) { prio = 19; }; if (prio < -20) { prio = -20; }; match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/+linux/pipe.ha000066400000000000000000000014071464473310100161670ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags to use for the [[io::file]]s returned by [[pipe]]. // Only NOCLOEXEC and NONBLOCK are guaranteed to be available. export type pipe_flag = enum { NOCLOEXEC = rt::O_CLOEXEC, DIRECT = rt::O_DIRECT, NONBLOCK = rt::O_NONBLOCK, }; // Create a pair of two linked [[io::file]]s, such that any data written to the // second [[io::file]] may be read from the first. export fn pipe(flags: pipe_flag = 0) ((io::file, io::file) | errors::error) = { let fds: [2]int = [0...]; flags ^= pipe_flag::NOCLOEXEC; // invert CLOEXEC match (rt::pipe2(&fds, flags)) { case void => void; case let e: rt::errno => return errors::errno(e); }; return (fds[0], fds[1]); }; hare-0.24.2/unix/+linux/umask.ha000066400000000000000000000004221464473310100163460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; // Sets the file mode creation mask for the current process and return the // previous value of the mask. export fn umask(mode: fs::mode) fs::mode = rt::umask(mode)!: fs::mode; hare-0.24.2/unix/+netbsd/000077500000000000000000000000001464473310100150365ustar00rootroot00000000000000hare-0.24.2/unix/+netbsd/creds.ha000066400000000000000000000105261464473310100164540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Unix credentials types & functions; ref credentials(7) use errors; use rt; // Process ID. export type pid = rt::pid_t; // User ID. export type uid = rt::uid_t; // Group ID. export type gid = rt::gid_t; // Returns the current process user ID. export fn getuid() uid = rt::getuid() as rt::uid_t: uid; // Returns the current process effective user ID. export fn geteuid() uid = rt::geteuid() as rt::uid_t: uid; // Returns the current process group ID. export fn getgid() gid = rt::getgid() as rt::gid_t: gid; // Returns the current process effective group ID. export fn getegid() gid = rt::getegid() as rt::gid_t: gid; // Sets the caller's user ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setuid(uid: uid) void = rt::setuid(&uid)!; // Sets the caller's effective user ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from seteuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn seteuid(euid: uid) void = rt::seteuid(&euid)!; // Sets the caller's group ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgid(gid: gid) void = rt::setgid(&gid)!; // Sets the caller's effective group ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setegid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setegid(egid: gid) void = rt::setegid(&egid)!; // Returns a list of supplementary group IDs for the current process. The // returned slice is statically allocated. export fn getgroups() []gid = { static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; const n = rt::getgroups(gids)!; return gids[..n]: []gid; }; // Sets the list of supplementary group IDs which apply to the current process. // This generally requires elevated permissions. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setgroups is a grave security issue in your program, // and therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; // Returns the current process ID. export fn getpid() pid = rt::getpid(); // Returns the parent process ID. export fn getppid() pid = rt::getppid(); // Returns the current process group ID. export fn getpgrp() pid = rt::getpgrp(); // Returns the current process's session ID. export fn getsid() pid = rt::getsid(0)!; // Returns the session ID associated with the given process. export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { match (rt::getsid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH); return errors::noentry; }; }; hare-0.24.2/unix/+netbsd/nice.ha000066400000000000000000000013321464473310100162650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Adds the argument to the niceness of the current process. The input should be // between -20 and 19 (inclusive); lower numbers represent a higher priority. // Generally, you must have elevated permissions to reduce your niceness, but // not to increase it. export fn nice(inc: int) (void | errors::error) = { let prio = inc; if (inc > -40 && inc <= 40) { prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int; }; if (prio > 19) { prio = 19; }; if (prio < -20) { prio = -20; }; match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/+netbsd/pipe.ha000066400000000000000000000013571464473310100163130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags to use for the [[io::file]]s returned by [[pipe]]. // Only NOCLOEXEC and NONBLOCK are guaranteed to be available. export type pipe_flag = enum { NOCLOEXEC = rt::O_CLOEXEC, NONBLOCK = rt::O_NONBLOCK, }; // Create a pair of two linked [[io::file]]s, such that any data written to the // second [[io::file]] may be read from the first. export fn pipe(flags: pipe_flag = 0) ((io::file, io::file) | errors::error) = { let fds: [2]int = [0...]; flags ^= pipe_flag::NOCLOEXEC; // invert CLOEXEC match (rt::pipe2(&fds, flags)) { case void => void; case let e: rt::errno => return errors::errno(e); }; return (fds[0], fds[1]); }; hare-0.24.2/unix/+netbsd/umask.ha000066400000000000000000000004361464473310100164730ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; // Sets the file mode creation mask for the current process and return the // previous value of the mask. export fn umask(mode: fs::mode) fs::mode = rt::umask(mode: rt::mode_t)!: fs::mode; hare-0.24.2/unix/+openbsd/000077500000000000000000000000001464473310100152115ustar00rootroot00000000000000hare-0.24.2/unix/+openbsd/creds.ha000066400000000000000000000131711464473310100166260ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // Unix credentials types & functions; ref credentials(7) use errors; use rt; // Process ID. export type pid = rt::pid_t; // User ID. export type uid = rt::uid_t; // Group ID. export type gid = rt::gid_t; // Returns the current process user ID. export fn getuid() uid = rt::getuid(); // Returns the current process effective user ID. export fn geteuid() uid = rt::geteuid(); // Returns the current process group ID. export fn getgid() uid = rt::getgid(); // Returns the current process effective group ID. export fn getegid() uid = rt::getegid(); // Sets the caller's user ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, // and take extreme care to handle errors correctly. export fn setuid(uid: uid) void = rt::setuid(uid)!; // Sets the caller's effective user ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from seteuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, // and take extreme care to handle errors correctly. export fn seteuid(uid: uid) void = rt::seteuid(uid)!; // Sets the caller's group ID to the specified value. This generally requires // elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setuid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, // and take extreme care to handle errors correctly. export fn setgid(gid: gid) void = rt::setgid(gid)!; // Sets the caller's effective group ID to the specified value. This generally // requires elevated permissions from the calling process. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setegid is a grave security issue in your program, and // therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, // and take extreme care to handle errors correctly. export fn setegid(gid: gid) void = rt::setegid(gid)!; // Returns a list of supplementary group IDs for the current process. The // returned slice is statically allocated. export fn getgroups() []gid = { static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; const n = rt::getgroups(gids)!; return gids[..n]: []gid; }; // Sets the list of supplementary group IDs which apply to the current process. // This generally requires elevated permissions. // // If the system returns an error, this function will abort the program. Failing // to handle errors from setgroups is a grave security issue in your program, // and therefore we require this function to succeed. If you need to handle the // error case gracefully, call the appropriate syscall wrapper in [[rt::]] // yourself, and take extreme care to handle errors correctly. export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; // Returns the current process ID. export fn getpid() pid = rt::getpid(); // Returns the parent process ID. export fn getppid() pid = rt::getppid(); // Returns the current process group ID. export fn getpgrp() pid = rt::getpgrp(); // Returns the process group associated with the given pid. export fn getpgid(pid: pid) (pid | errors::noentry) = { match (rt::getpgid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH, "Unexpected getpgid return value"); return errors::noentry; }; }; // Sets the process group ID of the specified process. This function is // error-prone; see the notes in the POSIX specification for its many caveats. export fn setpgid(targ: pid, pgid: pid) (void | errors::error) = { match (rt::setpgid(targ, pgid)) { case let err: rt::errno => return errors::errno(err); case void => return; }; }; // Returns the current process's session ID. export fn getsid() pid = rt::getsid(0)!; // Returns the session ID associated with the given process. export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { match (rt::getsid(pid)) { case let pid: rt::pid_t => return pid; case let err: rt::errno => assert(err == rt::ESRCH, "Unexpected getsid return value"); return errors::noentry; }; }; // Creates a new session and sets the current process to the session leader. // A new process group is also created with its process group ID equal to the // pid of the current process, and the current process is made the process group // leader. // // Upon return, the new session will have no controlling terminal. To establish // one, the caller must open a terminal file with [[fs::flag::CTTY]]; this // opt-in approach differs from the Unix norm where O_NOCTTY is required to // opt-out of establishing a controlling terminal. // // The current process cannot be a process group leader; this is a programmer // error and will cause a runtime assertion failure. export fn setsid() void = rt::setsid()!; hare-0.24.2/unix/+openbsd/nice.ha000066400000000000000000000013321464473310100164400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; // Adds the argument to the niceness of the current process. The input should be // between -20 and 19 (inclusive); lower numbers represent a higher priority. // Generally, you must have elevated permissions to reduce your niceness, but // not to increase it. export fn nice(inc: int) (void | errors::error) = { let prio = inc; if (inc > -40 && inc <= 40) { prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int; }; if (prio > 19) { prio = 19; }; if (prio < -20) { prio = -20; }; match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) { case void => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/+openbsd/pipe.ha000066400000000000000000000013571464473310100164660ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Flags to use for the [[io::file]]s returned by [[pipe]]. // Only NOCLOEXEC and NONBLOCK are guaranteed to be available. export type pipe_flag = enum { NOCLOEXEC = rt::O_CLOEXEC, NONBLOCK = rt::O_NONBLOCK, }; // Create a pair of two linked [[io::file]]s, such that any data written to the // second [[io::file]] may be read from the first. export fn pipe(flags: pipe_flag = 0) ((io::file, io::file) | errors::error) = { let fds: [2]int = [0...]; flags ^= pipe_flag::NOCLOEXEC; // invert CLOEXEC match (rt::pipe2(&fds, flags)) { case void => void; case let e: rt::errno => return errors::errno(e); }; return (fds[0], fds[1]); }; hare-0.24.2/unix/+openbsd/umask.ha000066400000000000000000000004361464473310100166460ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use fs; use rt; // Sets the file mode creation mask for the current process and return the // previous value of the mask. export fn umask(mode: fs::mode) fs::mode = rt::umask(mode: rt::mode_t)!: fs::mode; hare-0.24.2/unix/README000066400000000000000000000001431464473310100143620ustar00rootroot00000000000000The unix module and its submodules provides support for functionality common to Unix-like systems. hare-0.24.2/unix/hosts/000077500000000000000000000000001464473310100146445ustar00rootroot00000000000000hare-0.24.2/unix/hosts/+freebsd.ha000066400000000000000000000001561464473310100166450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/hosts"; hare-0.24.2/unix/hosts/+linux.ha000066400000000000000000000001561464473310100163720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/hosts"; hare-0.24.2/unix/hosts/+netbsd.ha000066400000000000000000000001561464473310100165120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/hosts"; hare-0.24.2/unix/hosts/+openbsd.ha000066400000000000000000000001561464473310100166650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/hosts"; hare-0.24.2/unix/hosts/errors.ha000066400000000000000000000013641464473310100164760ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use encoding::utf8; use fs; use io; use net::ip; // Returned when an invalid host line was found. export type invalid = !void; // All possible errors returned from this module. export type error = !(io::error | invalid | utf8::invalid | ip::invalid | fs::error); // Converts an [[error]] to a human-friendly representation. export fn strerror(err: error) const str = { match (err) { case invalid => return "Host file format is invalid"; case utf8::invalid => return "File is invalid UTF-8"; case ip::invalid => return "IP address is invalid"; case let err: io::error => return io::strerror(err); case let err: fs::error => return fs::strerror(err); }; }; hare-0.24.2/unix/hosts/hosts.ha000066400000000000000000000045621464473310100163250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use errors; use encoding::utf8; use fs; use io; use net::ip; use os; use strings; // Represents a host line in /etc/hosts, guaranteed to have at least a single // name. The first name is the canonical one. export type host = struct { addr: ip::addr, names: []str, }; export type reader = struct { scan: bufio::scanner, names: []str, }; // Read from an /etc/hosts-formatted file. Call [[next]] to enumerate entries // and [[finish]] to free state associated with the [[reader]]. export fn read(in: io::handle) reader = { return reader { scan = bufio::newscanner(in), names = [], }; }; // Frees resources associated with a [[reader]]. export fn finish(rd: *reader) void = { bufio::finish(&rd.scan); free(rd.names); }; // Returns the next host line as a [[host]] type. The host value is borrowed // from the [[reader]]; see [[host_dup]] to extend its lifetime. export fn next(rd: *reader) (host | done | error) = { for (const line => bufio::scan_line(&rd.scan)?) { if (len(line) == 0 || strings::hasprefix(line, "#")) { continue; }; const tok = strings::tokenize(line, " \t"); const addr = strings::next_token(&tok) as str; const addr = ip::parse(addr)?; rd.names = rd.names[..0]; for (const tok => strings::next_token(&tok)) { if (len(tok) == 0) { continue; }; append(rd.names, tok); }; if (len(rd.names) == 0) { return invalid; }; return host { addr = addr, names = rd.names, }; }; return done; }; // Looks up a slice of addresses from /etc/hosts. The caller must free the // return value. export fn lookup(name: const str) ([]ip::addr | error) = { const file = os::open(PATH)?; defer io::close(file)!; const rd = read(file); defer finish(&rd); return _lookup(&rd, name); }; fn _lookup(rd: *reader, name: const str) ([]ip::addr | error) = { let addrs: []ip::addr = []; for (const host => next(rd)?) { for (const cand .. host.names) { if (cand == name) { append(addrs, host.addr); }; }; }; if (len(addrs) != 0) { return addrs; }; return []; }; // Duplicates a [[host]] value. export fn host_dup(src: *host) host = { return host { addr = src.addr, names = strings::dupall(src.names), }; }; // Frees resources associated with a [[host]]. export fn host_finish(host: *host) void = { strings::freeall(host.names); }; hare-0.24.2/unix/hosts/test+test.ha000066400000000000000000000033151464473310100171120ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use memio; use net::ip; use strings; def HOSTS_FILE = ` 127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback 10.10.10.10 other.localdomain 10.10.20.20 other.localdomain `; @test fn next() void = { const buf = memio::fixed(strings::toutf8(HOSTS_FILE)); const rd = read(&buf); defer finish(&rd); const h = next(&rd) as host; assert(ip::equal(h.addr, ip::LOCAL_V4)); assert(len(h.names) == 1); assert(h.names[0] == "localhost"); const h = next(&rd) as host; assert(ip::equal(h.addr, ip::LOCAL_V6)); assert(len(h.names) == 2); assert(h.names[0] == "ip6-localhost"); assert(h.names[1] == "ip6-loopback"); const h = next(&rd) as host; assert(ip::equal(h.addr, [10, 10, 10, 10]: ip::addr4)); assert(len(h.names) == 1); assert(h.names[0] == "other.localdomain"); const h = next(&rd) as host; assert(ip::equal(h.addr, [10, 10, 20, 20]: ip::addr4)); assert(len(h.names) == 1); assert(h.names[0] == "other.localdomain"); const h = next(&rd); assert(h is done); const h = next(&rd); assert(h is done); }; @test fn errors() void = { const s = "127"; assert(next(&read(&memio::fixed(strings::toutf8(s)))) is ip::invalid); const s = "127.0.0.1"; assert(next(&read(&memio::fixed(strings::toutf8(s)))) is invalid); }; @test fn lookup() void = { const buf = memio::fixed(strings::toutf8(HOSTS_FILE)); const rd = read(&buf); defer finish(&rd); const addrs = _lookup(&rd, "other.localdomain") as []ip::addr; defer free(addrs); assert(len(addrs) == 2); assert(ip::equal(addrs[0], [10, 10, 10, 10]: ip::addr4)); assert(ip::equal(addrs[1], [10, 10, 20, 20]: ip::addr4)); }; hare-0.24.2/unix/passwd/000077500000000000000000000000001464473310100150055ustar00rootroot00000000000000hare-0.24.2/unix/passwd/group.ha000066400000000000000000000121141464473310100164520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use encoding::utf8; use io; use memio; use os; use strconv; use strings; use unix; // A Unix-like group file entry. export type grent = struct { // Name of the group name: str, // Optional encrypted password password: str, // Numerical group ID gid: unix::gid, // List of usernames that are members of this group, separated by commas userlist: str, }; export type groupreader = struct { scan: bufio::scanner, }; // Creates a parser for an /etc/groups-formatted file. Use [[nextgr]] to // enumerate the groups, and [[groups_finish]] to free resources associated with // the reader. export fn groups_read(in: io::handle) groupreader = { return groupreader { scan = bufio::newscanner(in), }; }; // Frees resources associated with a [[groupreader]]. export fn groups_finish(rd: *groupreader) void = { bufio::finish(&rd.scan); }; // Reads a Unix-like group entry from a [[grreader]]. The return value is // borrowed from the scanner. export fn nextgr(rd: *groupreader) (grent | io::EOF | io::error | invalid) = { const line = match (bufio::scan_line(&rd.scan)) { case let ln: const str => yield ln; case let err: io::error => return err; case utf8::invalid => return invalid; case io::EOF => return io::EOF; }; const tok = strings::tokenize(line, ":"); let i = 0z; let fields: [4]str = [""...]; for (const f => strings::next_token(&tok)) { defer i += 1; if (i >= len(fields)) { return invalid; }; fields[i] = f; }; let gid = match (strconv::stou64(fields[2])) { case let u: u64 => yield u: unix::gid; case => return invalid; }; return grent { name = fields[0], password = fields[1], gid = gid, userlist = fields[3], }; }; // Frees resources associated with a [[grent]]. export fn grent_finish(ent: *grent) void = { free(ent.name); free(ent.password); free(ent.userlist); }; // Frees resources associated with a slice of [[grent]]s. export fn grents_free(ents: []grent) void = { for (let ent &.. ents) { grent_finish(ent); }; free(ents); }; fn grent_dup(ent: *grent) void = { ent.name = strings::dup(ent.name); ent.password = strings::dup(ent.password); ent.userlist = strings::dup(ent.userlist); }; // Looks up a group by name in a Unix-like group file. It expects a such file at // /etc/group. Aborts if that file doesn't exist or is not properly formatted. // // The user must pass the return value to [[grent_finish]] to free resources // associated with the group. // // See [[nextgr]] for low-level parsing API. export fn getgroup(name: str) (grent | void) = { const file = match (os::open("/etc/group")) { case let f: io::file => yield f; case => abort("Unable to open /etc/group"); }; defer io::close(file)!; const rd = groups_read(file); defer groups_finish(&rd); for (const ent => nextgr(&rd)!) { if (ent.name == name) { grent_dup(&ent); return ent; }; }; }; // Looks up a group by ID in a Unix-like group file. It expects a such file at // /etc/group. Aborts if that file doesn't exist or is not properly formatted. // // The user must pass the return value to [[grent_finish]] to free resources // associated with the group. // // See [[nextgr]] for low-level parsing API. export fn getgid(gid: unix::gid) (grent | void) = { const file = match (os::open("/etc/group")) { case let f: io::file => yield f; case => abort("Unable to open /etc/group"); }; defer io::close(file)!; const rd = groups_read(file); defer groups_finish(&rd); for (const ent => nextgr(&rd)!) { if (ent.gid == gid) { grent_dup(&ent); return ent; }; }; }; // Looks up groups by user name in a Unix-like group file. It expects a such // file at /etc/group. Aborts if that file doesn't exist or is not properly // formatted. The caller must pass the return value to [[grents_finish]]. // // See [[nextgr]] for low-level parsing API. export fn getgroups(name: str) []grent = { const file = match (os::open("/etc/group")) { case let f: io::file => yield f; case => abort("Unable to open /etc/group"); }; defer io::close(file)!; const rd = groups_read(file); defer groups_finish(&rd); let groups: []grent = []; for (const ent => nextgr(&rd)!) { const tok = strings::tokenize(ent.userlist, ","); for (const tok => strings::next_token(&tok)) { if (tok == name) { grent_dup(&ent); append(groups, ent); }; }; }; return groups; }; @test fn nextgr() void = { const buf = memio::fixed(strings::toutf8( "root:x:0:root\n" "mail:x:12:\n" "video:x:986:alex,wmuser")); const rd = groups_read(&buf); defer groups_finish(&rd); const expect = [ grent { name = "root", password = "x", gid = 0, userlist = "root", }, grent { name = "mail", password = "x", gid = 12, userlist = "", }, grent { name = "video", password = "x", gid = 986, userlist = "alex,wmuser", }, ]; let i = 0z; for (const ent => nextgr(&rd)!) { defer i += 1; assert(ent.name == expect[i].name); assert(ent.password == expect[i].password); assert(ent.gid == expect[i].gid); assert(ent.userlist == expect[i].userlist); }; }; hare-0.24.2/unix/passwd/passwd.ha000066400000000000000000000112651464473310100166250ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use encoding::utf8; use io; use memio; use os; use strconv; use strings; use unix; // A Unix-like password database entry. export type pwent = struct { // Login name username: str, // Optional encrypted password password: str, // Numerical user ID uid: unix::uid, // Numerical group ID gid: unix::gid, // User name or comment field comment: str, // User home directory homedir: str, // Optional user command interpreter shell: str, }; export type userreader = struct { scan: bufio::scanner, }; // Creates a parser for an /etc/passwd-formatted file. Use [[nextpw]] to // enumerate the users, and [[users_finish]] to free resources associated with // the reader. export fn users_read(in: io::handle) userreader = { return groupreader { scan = bufio::newscanner(in), }; }; // Frees resources associated with a [[groupreader]]. export fn users_finish(rd: *userreader) void = { bufio::finish(&rd.scan); }; // Reads a Unix-like password entry from an [[io::handle]]. The return value is // borrowed from the reader. export fn nextpw(rd: *userreader) (pwent | io::EOF | io::error | invalid) = { const line = match (bufio::scan_line(&rd.scan)) { case io::EOF => return io::EOF; case let ln: const str => yield ln; case utf8::invalid => return invalid; case let err: io::error => return err; }; const tok = strings::tokenize(line, ":"); let i = 0z; let fields: [7]str = [""...]; for (const f => strings::next_token(&tok)) { defer i += 1; if (i >= len(fields)) { return invalid; }; fields[i] = f; }; const uid = match (strconv::stou64(fields[2])) { case let u: u64 => yield u: unix::uid; case => return invalid; }; const gid = match (strconv::stou64(fields[3])) { case let u: u64 => yield u: unix::gid; case => return invalid; }; return pwent { username = fields[0], password = fields[1], uid = uid, gid = gid, comment = fields[4], homedir = fields[5], shell = fields[6], }; }; // Frees resources associated with a [[pwent]]. export fn pwent_finish(ent: *pwent) void = { free(ent.username); free(ent.password); free(ent.comment); free(ent.homedir); free(ent.shell); }; fn pwent_dup(ent: *pwent) void = { ent.username = strings::dup(ent.username); ent.password = strings::dup(ent.password); ent.comment = strings::dup(ent.comment); ent.homedir = strings::dup(ent.homedir); ent.shell = strings::dup(ent.shell); }; // Looks up a user by name in a Unix-like password file. It expects a password // database file at /etc/passwd. Aborts if that file doesn't exist or is not // properly formatted. The return value must be freed with [[pwent_finish]]. // // See [[nextpw]] for low-level parsing API. export fn getuser(username: str) (pwent | void) = { const file = match (os::open("/etc/passwd")) { case let f: io::file => yield f; case => abort("Can't open /etc/passwd"); }; defer io::close(file)!; const rd = users_read(file); defer users_finish(&rd); for (const ent => nextpw(&rd)!) { if (ent.username == username) { pwent_dup(&ent); return ent; }; }; }; // Looks up a user by ID in a Unix-like password file. It expects a password // database file at /etc/passwd. Aborts if that file doesn't exist or is not // properly formatted. The return value must be freed with [[pwent_finish]]. // // See [[nextpw]] for low-level parsing API. export fn getuid(uid: unix::uid) (pwent | void) = { const file = match (os::open("/etc/passwd")) { case let f: io::file => yield f; case => abort("Can't open /etc/passwd"); }; defer io::close(file)!; const rd = users_read(file); defer users_finish(&rd); for (const ent => nextpw(&rd)!) { if (ent.uid == uid) { pwent_dup(&ent); return ent; }; }; }; @test fn nextpw() void = { const buf = memio::fixed(strings::toutf8( "sircmpwn:x:1000:1000:sircmpwn's comment:/home/sircmpwn:/bin/rc\n" "alex:x:1001:1001::/home/alex:/bin/zsh")); const rd = users_read(&buf); defer users_finish(&rd); const expect = [ pwent { username = "sircmpwn", password = "x", uid = 1000, gid = 1000, comment = "sircmpwn's comment", homedir = "/home/sircmpwn", shell = "/bin/rc", }, pwent { username = "alex", password = "x", uid = 1001, gid = 1001, comment = "", homedir = "/home/alex", shell = "/bin/zsh", }, ]; let i = 0z; for (const ent => nextpw(&rd)!) { defer i += 1; assert(ent.username == expect[i].username); assert(ent.password == expect[i].password); assert(ent.uid == expect[i].uid); assert(ent.gid == expect[i].gid); assert(ent.comment == expect[i].comment); assert(ent.homedir == expect[i].homedir); assert(ent.shell == expect[i].shell); }; }; hare-0.24.2/unix/passwd/types.ha000066400000000000000000000002411464473310100164600ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // An invalid entry was encountered during parsing. export type invalid = !void; hare-0.24.2/unix/poll/000077500000000000000000000000001464473310100144525ustar00rootroot00000000000000hare-0.24.2/unix/poll/+freebsd.ha000066400000000000000000000026121464473310100164520ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; use time; // Events bitfield for the events and revents field of [[pollfd]]. export type event = enum i16 { POLLIN = 1, POLLPRI = 2, POLLOUT = 4, POLLERR = 8, POLLHUP = 16, }; // A single file descriptor to be polled. export type pollfd = struct { fd: io::file, events: i16, revents: i16, }; // Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for // the next event. export def INDEF: time::duration = -1; // Pass this [[time::duration]] to [[poll]] to cause it to return immediately if // no events are available. export def NONBLOCK: time::duration = 0; // Polls for the desired events on a slice of [[pollfd]]s, blocking until an // event is available, or the timeout expires. Set the timeout to [[INDEF]] to // block forever, or [[NONBLOCK]] to return immediately if no events are // available. Returns the number of [[pollfd]] items which have events, i.e. // those which have revents set to a nonzero value. export fn poll( fds: []pollfd, timeout: time::duration, ) (uint | error) = { let ts = time::duration_to_timespec(timeout); let ts = if (timeout == INDEF) null else &ts; match (rt::ppoll(fds: *[*]pollfd: *[*]rt::pollfd, len(fds): rt::nfds_t, ts, null)) { case let err: rt::errno => return errors::errno(err); case let n: int => return n: uint; }; }; hare-0.24.2/unix/poll/+linux.ha000066400000000000000000000025761464473310100162100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; use time; // Events bitfield for the events and revents field of [[pollfd]]. export type event = enum i16 { POLLIN = 1, POLLPRI = 2, POLLOUT = 4, POLLERR = 8, POLLHUP = 16, }; // A single file descriptor to be polled. export type pollfd = struct { fd: io::file, events: i16, revents: i16, }; // Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for // the next event. export def INDEF: time::duration = -1; // Pass this [[time::duration]] to [[poll]] to cause it to return immediately if // no events are available. export def NONBLOCK: time::duration = 0; // Polls for the desired events on a slice of [[pollfd]]s, blocking until an // event is available, or the timeout expires. Set the timeout to [[INDEF]] to // block forever, or [[NONBLOCK]] to return immediately if no events are // available. Returns the number of [[pollfd]] items which have events, i.e. // those which have revents set to a nonzero value. export fn poll( fds: []pollfd, timeout: time::duration, ) (uint | error) = { let ts = time::duration_to_timespec(timeout); let ts = if (timeout == INDEF) null else &ts; match (rt::ppoll(fds: *[*]pollfd: *[*]rt::pollfd, len(fds), ts, null)) { case let err: rt::errno => return errors::errno(err); case let n: int => return n: uint; }; }; hare-0.24.2/unix/poll/+netbsd.ha000066400000000000000000000026121464473310100163170ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; use time; // Events bitfield for the events and revents field of [[pollfd]]. export type event = enum i16 { POLLIN = 1, POLLPRI = 2, POLLOUT = 4, POLLERR = 8, POLLHUP = 16, }; // A single file descriptor to be polled. export type pollfd = struct { fd: io::file, events: i16, revents: i16, }; // Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for // the next event. export def INDEF: time::duration = -1; // Pass this [[time::duration]] to [[poll]] to cause it to return immediately if // no events are available. export def NONBLOCK: time::duration = 0; // Polls for the desired events on a slice of [[pollfd]]s, blocking until an // event is available, or the timeout expires. Set the timeout to [[INDEF]] to // block forever, or [[NONBLOCK]] to return immediately if no events are // available. Returns the number of [[pollfd]] items which have events, i.e. // those which have revents set to a nonzero value. export fn poll( fds: []pollfd, timeout: time::duration, ) (uint | error) = { let ts = time::duration_to_timespec(timeout); let ts = if (timeout == INDEF) null else &ts; match (rt::ppoll(fds: *[*]pollfd: *[*]rt::pollfd, len(fds): rt::nfds_t, ts, null)) { case let err: rt::errno => return errors::errno(err); case let n: int => return n: uint; }; }; hare-0.24.2/unix/poll/+openbsd.ha000066400000000000000000000026121464473310100164720ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; use time; // Events bitfield for the events and revents field of [[pollfd]]. export type event = enum i16 { POLLIN = 1, POLLPRI = 2, POLLOUT = 4, POLLERR = 8, POLLHUP = 16, }; // A single file descriptor to be polled. export type pollfd = struct { fd: io::file, events: i16, revents: i16, }; // Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for // the next event. export def INDEF: time::duration = -1; // Pass this [[time::duration]] to [[poll]] to cause it to return immediately if // no events are available. export def NONBLOCK: time::duration = 0; // Polls for the desired events on a slice of [[pollfd]]s, blocking until an // event is available, or the timeout expires. Set the timeout to [[INDEF]] to // block forever, or [[NONBLOCK]] to return immediately if no events are // available. Returns the number of [[pollfd]] items which have events, i.e. // those which have revents set to a nonzero value. export fn poll( fds: []pollfd, timeout: time::duration, ) (uint | error) = { let ts = time::duration_to_timespec(timeout); let ts = if (timeout == INDEF) null else &ts; match (rt::ppoll(fds: *[*]pollfd: *[*]rt::pollfd, len(fds): rt::nfds_t, ts, null)) { case let err: rt::errno => return errors::errno(err); case let n: int => return n: uint; }; }; hare-0.24.2/unix/poll/README000066400000000000000000000003001464473310100153230ustar00rootroot00000000000000unix::poll provides an interface for polling activity on file descriptors, compatible with the behavior defined by POSIX. https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html hare-0.24.2/unix/poll/types.ha000066400000000000000000000005011464473310100161240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // All error types that can be returned from [[poll]]. export type error = !errors::error; // Converts an [[error]] into a human-friendly string representation. export fn strerror(err: error) const str = errors::strerror(err); hare-0.24.2/unix/resolvconf/000077500000000000000000000000001464473310100156645ustar00rootroot00000000000000hare-0.24.2/unix/resolvconf/+freebsd.ha000066400000000000000000000001641464473310100176640ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/resolv.conf"; hare-0.24.2/unix/resolvconf/+linux.ha000066400000000000000000000001641464473310100174110ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/resolv.conf"; hare-0.24.2/unix/resolvconf/+netbsd.ha000066400000000000000000000001641464473310100175310ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/resolv.conf"; hare-0.24.2/unix/resolvconf/+openbsd.ha000066400000000000000000000001641464473310100177040ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors def PATH: str = "/etc/resolv.conf"; hare-0.24.2/unix/resolvconf/README000066400000000000000000000007631464473310100165520ustar00rootroot00000000000000[[unix::resolvconf]] implements a parser for /etc/resolv.conf files which has feature parity with the resolv.conf format supported by glibc 2.36. However, most options are not supported by Hare internally, i.e. via [[net::dns]]. The user may parse a resolv.conf file manually via the [[read]] and [[next]] functions. Additionally, this module maintains a global copy of the local resolv.conf file, parsed once at runtime and cached for the lifetime of the process, which is available via [[load]]. hare-0.24.2/unix/resolvconf/errors.ha000066400000000000000000000014771464473310100175230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use encoding::utf8; use io; use net::ip; // The resolv.conf file is not well-formatted. export type invalid = !void; // Any error which can be raised by the resolv.conf parser. export type error = !(errors::error | io::error | utf8::invalid | ip::invalid | invalid); // Converts an [[error]] into a human-friendly representation. export fn strerror(err: error) const str = { match (err) { case invalid => return "resolv.conf is not well-formatted"; case let err: errors::error => return errors::strerror(err); case let err: io::error => return io::strerror(err); case let err: ip::invalid => return "Invalid IP address in /etc/resolv.conf"; case utf8::invalid => return "resolv.conf contains invalid UTF-8 data"; }; }; hare-0.24.2/unix/resolvconf/load.ha000066400000000000000000000031751464473310100171230ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use io; use memio; use net::ip; use os; use strings; let cache_valid = false; let cache: config = config { options = DEFAULT_OPTIONS, ... }; @fini fn fini() void = { if (!cache_valid) { return; }; strings::freeall(cache.search); free(cache.nameservers); free(cache.sortlist); }; // Reads /etc/resolv.conf (or the platform-specific equivalent path) and returns // the configuration therein. If the file does not exist, or is poorly // formatted, returns the default resolver configuration. export fn load() *config = { if (cache_valid) { return &cache; }; const file = match (os::open("/etc/resolv.conf")) { case let file: io::file => yield file; case => cache_valid = true; return &cache; }; defer io::close(file)!; match (parse(&cache, file)) { case let err: error => fmt::errorfln("Error parsing /etc/resolv.conf: {}", strerror(err)): void; return &cache; case void => cache_valid = true; return &cache; }; }; // Parses a resolv.conf-formatted file and populates the given config object. fn parse(conf: *config, in: io::handle) (void | error) = { const rd = read(in); for (const param => next(&rd)!) { switch (param.name) { case "nameserver" => append(conf.nameservers, param.value as ip::addr); case "search" => strings::freeall(conf.search); conf.search = strings::dupall(param.value as []str); case "sortlist" => free(conf.sortlist); conf.sortlist = alloc((param.value as []ip::subnet)...); case "options" => conf.options = *(param.value as *options); case => void; }; }; }; hare-0.24.2/unix/resolvconf/reader.ha000066400000000000000000000073321464473310100174450ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use io; use net::ip; use strconv; use strings; export type reader = struct { scan: bufio::scanner, // Only one of these is valid at a time (return values from [[next]] are // borrowed from this). union { addr_list: []ip::addr, subnet_list: []ip::subnet, str_list: []str, }, options: options, }; // Reads an /etc/resolv.conf-formatted file from the provided I/O handle. Use // [[next]] to enumerate directives from the file and pass the return value to // [[finish]] to free resources associated with the reader. export fn read(in: io::handle) reader = { return reader { scan = bufio::newscanner(in), ... }; }; // Frees resources associated with a [[reader]]. export fn finish(rd: *reader) void = { bufio::finish(&rd.scan); free(rd.addr_list); }; // Reads the next [[parameter]] from a resolv.conf [[reader]]. The return value // is borrowed from the [[reader]]. export fn next(rd: *reader) (parameter | io::EOF | error) = { for (const line => bufio::scan_line(&rd.scan)?) { if (strings::hasprefix(line, '#') || strings::hasprefix(line, ';')) { continue; }; if (len(line) == 0) { continue; }; const tok = strings::tokenize(line, " \t"); const name = match (strings::next_token(&tok)) { case let name: str => yield name; case done => continue; }; const val = switch (name) { case "nameserver" => yield parse_addr(rd, &tok)?; case "search" => yield parse_str_list(rd, &tok)?; case "sortlist" => yield parse_subnet_list(rd, &tok)?; case "options" => yield parse_options(rd, &tok)?; case => continue; }; return parameter { name = name, value = val, }; }; return io::EOF; }; fn parse_addr(rd: *reader, tok: *strings::tokenizer) (value | error) = { const addr = match (strings::next_token(tok)) { case let addr: str => yield addr; case done => return invalid; }; return ip::parse(addr)?; }; fn parse_subnet_list(rd: *reader, tok: *strings::tokenizer) (value | error) = { rd.subnet_list = rd.subnet_list[..0]; for (const tok => strings::next_token(tok)) { if (len(tok) == 0) { continue; }; const subnet = ip::parsecidr(tok)?; append(rd.subnet_list, subnet); }; return rd.subnet_list; }; fn parse_str_list(rd: *reader, tok: *strings::tokenizer) (value | error) = { rd.str_list = rd.str_list[..0]; for (const tok => strings::next_token(tok)) { if (len(tok) == 0) { continue; }; append(rd.str_list, tok); }; return rd.str_list; }; fn parse_options(rd: *reader, tok: *strings::tokenizer) (value | error) = { rd.options = DEFAULT_OPTIONS; let opts = &rd.options; for (const tok => strings::next_token(tok)) { if (len(tok) == 0) { continue; }; const (name, val) = strings::cut(tok, ":"); switch (name) { case "debug" => opts.debug = true; case "ndots" => match (strconv::stou(val)) { case let u: uint => opts.ndots = u; case => return invalid; }; case "timeout" => match (strconv::stou(val)) { case let u: uint => opts.timeout = u; case => return invalid; }; case "attempts" => match (strconv::stou(val)) { case let u: uint => opts.attempts = u; case => return invalid; }; case "rotate" => opts.rotate = true; case "no-aaaa" => opts.no_aaaa = true; case "no-check-names" => opts.no_check_names = true; case "inet6" => opts.inet6 = true; case "edns0" => opts.edns0 = true; case "single-request" => opts.single_request = true; case "no-tld-query" => opts.no_tld_query = true; case "use-vc" => opts.use_vc = true; case "no-reload" => opts.no_reload = true; case "trust-ad" => opts.trust_ad = true; case => void; }; }; return opts; }; hare-0.24.2/unix/resolvconf/types.ha000066400000000000000000000017561464473310100173530ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use net::ip; // A list of [[net::ip::subnet]]s. export type subnet_list = []ip::subnet; // Values set in an "options" directive. export type options = struct { debug: bool, ndots: uint, timeout: uint, attempts: uint, rotate: bool, no_aaaa: bool, no_check_names: bool, inet6: bool, edns0: bool, single_request: bool, single_request_reopen: bool, no_tld_query: bool, use_vc: bool, no_reload: bool, trust_ad: bool, }; def DEFAULT_OPTIONS = options { ndots = 1, timeout = 5, attempts = 2, ... }; // The value associated with a configuration parameter. export type value = (ip::addr | subnet_list | *options | []str); // A configuration parameter from resolv.conf. export type parameter = struct { name: const str, value: value, }; // A complete configuration parsed from resolv.conf. export type config = struct { nameservers: []ip::addr, search: []str, sortlist: []ip::subnet, options: options, }; hare-0.24.2/unix/signal/000077500000000000000000000000001464473310100147615ustar00rootroot00000000000000hare-0.24.2/unix/signal/+freebsd.ha000066400000000000000000000363301464473310100167650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use time; use unix; // Requests that [[sig::ALRM]] is delivered to the calling process in (about) // "sec" seconds. Returns the number of seconds until the previously scheduled // alarm, or zero if none was scheduled. export fn alarm(sec: uint) uint = { return rt::alarm(sec); }; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). // // The variadic parameters specify either [[flag]]s to enable or a signal mask // to use via [[sigset]]; if the latter is provided no more than one may be // used. export fn handle( signum: sig, handler: *handler, opt: (flag | sigset)... ) sigaction = { let sa_mask = newsigset(); let sa_flags = rt::SA_SIGINFO: int, nmask = 0; for (let i = 0z; i < len(opt); i += 1) { match (opt[i]) { case let flag: flag => sa_flags |= flag: int; case let mask: sigset => assert(nmask == 0, "Multiple signal masks provided to signal::handle"); nmask += 1; sa_mask = mask; }; }; let new = rt::sigact { sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, sa_mask = sa_mask, sa_flags = sa_flags, }; let old = rt::sigact { sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, ... }; match (rt::sigaction(signum, &new, &old)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; return old; }; // Restores previous signal behavior following [[handle]]. export fn restore(signum: sig, action: *sigaction) void = { match (rt::sigaction(signum, action: *rt::sigact, null)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; }; // Unregisters signal handlers for the specified signal. export fn reset(signum: sig) void = { handle(signum, rt::SIG_DFL: *handler); }; // Unregisters all signal handlers. export fn resetall() void = { // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) reset(sig::HUP); reset(sig::INT); reset(sig::QUIT); reset(sig::ILL); reset(sig::TRAP); reset(sig::ABRT); reset(sig::EMT); reset(sig::FPE); reset(sig::BUS); reset(sig::SEGV); reset(sig::SYS); reset(sig::PIPE); reset(sig::ALRM); reset(sig::TERM); reset(sig::URG); reset(sig::TSTP); reset(sig::CONT); reset(sig::CHLD); reset(sig::TTIN); reset(sig::TTOU); reset(sig::IO); reset(sig::XCPU); reset(sig::XFSZ); reset(sig::VTALRM); reset(sig::PROF); reset(sig::WINCH); reset(sig::INFO); reset(sig::USR1); reset(sig::USR2); reset(sig::THR); reset(sig::LIBRT); }; // Prevents given signal from arriving to the current process. // One common use case is to ignore SIGCHLD to avoid zombie child processes. export fn ignore(signum: sig) void = { handle(signum, rt::SIG_IGN: *handler); }; // Adds the given list of signals to the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn block(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::BLOCK, &new); }; // Removes the given list of signals from the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn unblock(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::UNBLOCK, &new); }; // Sets the process's signal mask, returning the previous mask. export fn setprocmask(how: how, mask: *sigset) sigset = { let old = sigset { ... }; rt::sigprocmask(how, mask: *rt::sigset, &old)!; return old; }; // Gets the current process's signal mask. export fn getprocmask() sigset = { let old = sigset { ... }; rt::sigprocmask(how::SETMASK, null, &old)!; return old; }; // Defines the modes of operation for [[setprocmask]]. export type how = enum int { // Adds the given set of signals to the current mask. BLOCK = rt::SIG_BLOCK, // Removes the given set of signals from the current mask. UNBLOCK = rt::SIG_UNBLOCK, // Sets the process mask to the given set. SETMASK = rt::SIG_SETMASK, }; export type sigaction = rt::sigact; export type sigset = rt::sigset; // Creates a new signal set filled in with the provided signals (or empty if // none are provided). export fn newsigset(items: sig...) sigset = { let set = sigset { ... }; rt::sigemptyset(&set); sigset_add(&set, items...); return set; }; // Sets a [[sigset]] to empty. export fn sigset_empty(set: *sigset) void = { rt::sigemptyset(set: *rt::sigset); }; // Adds signals to a [[sigset]]. export fn sigset_add(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigaddset(set: *rt::sigset, items[i])!; }; }; // Removes signals from a [[sigset]]. export fn sigset_del(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigdelset(set: *rt::sigset, items[i])!; }; }; // Adds all platform-defined signals to a [[sigset]]. export fn sigset_fill(set: *sigset) void = { rt::sigfillset(set: *rt::sigset)!; }; // Returns true if the given signal is a member of this [[sigset]]. export fn sigset_member(set: *sigset, item: sig) bool = { return rt::sigismember(set: *rt::sigset, item)!; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the signal number. // // If a signal is received while waiting, [[errors::interrupted]] is returned. // Most consumers of this function will likely wish to block all signals and // handle them exclusively through [[wait]] et al, in which case this error // cannot occur. // // See also [[waitinfo]] and [[timedwait]]. export fn wait(set: *sigset) (sig | errors::interrupted) = { let signal = 0i; match (rt::sigwait(set: *rt::sigset, &signal)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case void => return signal: sig; }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // See notes on [[wait]] regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigwaitinfo(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigwaitinfo]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on OpenBSD. export fn waitinfo(set: *sigset) (siginfo | errors::interrupted) = { let info = rt::siginfo { si_addr = null: *opaque, si_value = rt::sigval { ... }, ... }; match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case int => return *(&info: *siginfo); }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // Returns a [[siginfo]] if a signal is successfully processed through this // function, or [[errors::again]] if the timeout expired. See notes on [[wait]] // regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigtimedwait(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigtimedwait]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on OpenBSD. export fn timedwait( set: *sigset, timeout: time::duration, ) (siginfo | errors::interrupted | errors::again) = { let info = rt::siginfo { si_addr = null: *opaque, si_value = rt::sigval { ... }, ... }; let to = time::duration_to_timeval(timeout); match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => switch (err) { case rt::EINTR => return errors::interrupted; case rt::EAGAIN => return errors::again; case => abort(); }; case int => return *(&info: *siginfo); }; }; // Provides additional information about signal deliveries. Only the members // defined by POSIX are available here; cast to [[rt::siginfo]] to access // non-portable members. export type siginfo = union { struct { // The signal number being delivered. signo: sig, // The errno, if any, associated with this signal. See // [[errors::errno]] to convert to a Hare-native error. errno: rt::errno, // The signal code, if any. code: code, // Process ID of the sender. pid: unix::pid, // Real user ID of the sending process. uid: unix::uid, // Exit value or signal. status: int, // Address of the faulting instruction. addr: *opaque, }, // Pads the structure out to the length used by the kernel; do not use. _si_pad: [128 - 3 * size(int)]u8, }; // A code indicating why a signal was sent. export type code = enum int { USER = 0, // sent by userspace program (kill) KERNEL = 128, // sent by kernel QUEUE = -1, // sent by sigqueue TIMER = -2, // generated by expiration of a timer MESQ = -3, // generated by arrival of a message on an empty queue ASYNCIO = -4, // generated by completion of an asynchronous I/O request SIGIO = -5, TKILL = -6, // sent by userspace program (tkill, tgkill) ASYNCNL = -60, ILLOPC = 1, // sig::ILL: illegal opcode ILLOPN = 2, // sig::ILL: illegal operand ILLADR = 3, // sig::ILL: illegal addressing mode ILLTRP = 4, // sig::ILL: illegal trap PRVOPC = 5, // sig::ILL: privileged opcode PRVREG = 6, // sig::ILL: privileged register COPROC = 7, // sig::ILL: coprocessor error BADSTK = 8, // sig::ILL: internal stack error INTOVF = 1, // sig::FPE: integer overflow INTDIV = 2, // sig::FPE: integer divide by zero FLTDIV = 3, // sig::FPE: floating-point divide by zero FLTOVF = 4, // sig::FPE: floating-point overflow FLTUND = 5, // sig::FPE: floating-point underflow FLTRES = 6, // sig::FPE: floating-point inexact result FLTINV = 7, // sig::FPE: invalid floating-point operation FLTSUB = 8, // sig::FPE: subscript out of range MAPERR = 1, // sig::SEGV: address not mapped to object ACCERR = 2, // sig::SEGV: invalid permissions for mapped object PKUERR = 100, // sig::SEGV: access was denied by memory protection keys (x86_64) ADRALN = 1, // sig::BUS: invalid address alignment ADRERR = 2, // sig::BUS: nonexistent physical address OBJERR = 3, // sig::BUS: object-specific hardware error OOMERR = 100, // sig::BUS: out of memory BRKPT = 1, // sig::TRAP: process breakpoint TRACE = 2, // sig::TRAP: process trace trap DTRACE = 3, // sig::TRAP: DTrace induced trap CAP = 4, // sig::TRAP: capabilities protection trap EXITED = 1, // sig::CHLD: child exited KILLED = 2, // sig::CHLD: child terminated abnormally without a core file DUMPED = 3, // sig::CHLD: child terminated abnormally with a core file TRAPPED = 4, // sig::CHLD: traced child has trapped STOPPED = 5, // sig::CHLD: child has stopped CONTINUED = 6, // sig::CHLD: stopped child has continued IN = 1, // sig::IO: data input available OUT = 2, // sig::IO: output buffers available MSG = 3, // sig::IO: input message available ERR = 4, // sig::IO: I/O error PRI = 5, // sig::IO: high priority input available HUP = 6, // sig::IO: device disconnected }; // Flags used to configure the behavior of a signal handler. export type flag = enum int { // For use with sig::CHLD. Prevents notifications when child processes // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). NOCLDSTOP = rt::SA_NOCLDSTOP: int, // For use with sig::CHLD. Do not transform children into zombies when // they terminate. Note that POSIX leaves the delivery of sig::CHLD // unspecified when this flag is present; some systems will still // deliver a signal and others may not. NOCLDWAIT = rt::SA_NOCLDWAIT: int, // Uses an alternate stack when handling this signal. See // [[setaltstack]] and [[getaltstack]] for details. ONSTACK = rt::SA_ONSTACK: int, // Do not add the signal to the signal mask while executing the signal // handler. This can cause the same signal to be delivered again during // the execution of the signal handler. NODEFER = rt::SA_NODEFER: int, // Restore the signal handler to the default behavior upon entering the // signal handler. RESETHAND = rt::SA_RESETHAND: int, // Makes certain system calls restartable across signals. See signal(7) // or similar documentation for your local system for details. RESTART = rt::SA_RESTART: int, }; // All possible signals. export type sig = enum int { HUP = rt::SIGHUP, // Hangup. INT = rt::SIGINT, // Terminal interrupt. QUIT = rt::SIGQUIT, // Terminal quit. ILL = rt::SIGILL, // Illegal instruction. TRAP = rt::SIGTRAP, // Trace/breakpoint trap. ABRT = rt::SIGABRT, // Process abort. IOT = rt::SIGIOT, // Synonym for ABRT, provided for compatibility. EMT = rt::SIGEMT, // Emulate instruction executed. FPE = rt::SIGFPE, // Erroneous arithmetic operation. KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. SEGV = rt::SIGSEGV, // Invalid memory reference. SYS = rt::SIGSYS, // Bad system call. PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. ALRM = rt::SIGALRM, // Alarm clock. TERM = rt::SIGTERM, // Termination. URG = rt::SIGURG, // High bandwidth data is available at a socket. STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). TSTP = rt::SIGTSTP, // Terminal stop. CONT = rt::SIGCONT, // Continue executing, if stopped. CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. TTIN = rt::SIGTTIN, // Background process attempting read. TTOU = rt::SIGTTOU, // Background process attempting write. IO = rt::SIGIO, // I/O now possible. XCPU = rt::SIGXCPU, // CPU time limit exceeded. XFSZ = rt::SIGXFSZ, // File size limit exceeded. VTALRM = rt::SIGVTALRM, // Virtual timer expired. PROF = rt::SIGPROF, // Profiling timer expired. WINCH = rt::SIGWINCH, // Window resize. INFO = rt::SIGINFO, // Status request from keyboard. USR1 = rt::SIGUSR1, // User-defined signal 1. USR2 = rt::SIGUSR2, // User-defined signal 2. THR = rt::SIGTHR, // Thread interrupt. LIBRT = rt::SIGLIBRT, // Real-time library interrupt. }; // Returns the human friendly name of a given signal. export fn signame(sig: sig) const str = { switch (sig) { case sig::HUP => return "SIGHUP"; case sig::INT => return "SIGINT"; case sig::QUIT => return "SIGQUIT"; case sig::ILL => return "SIGILL"; case sig::TRAP => return "SIGTRAP"; case sig::ABRT => return "SIGABRT"; case sig::EMT => return "SIGEMT"; case sig::FPE => return "SIGFPE"; case sig::KILL => return "SIGKILL"; case sig::BUS => return "SIGBUS"; case sig::SEGV => return "SIGSEGV"; case sig::SYS => return "SIGSYS"; case sig::PIPE => return "SIGPIPE"; case sig::ALRM => return "SIGALRM"; case sig::TERM => return "SIGTERM"; case sig::URG => return "SIGURG"; case sig::STOP => return "SIGSTOP"; case sig::TSTP => return "SIGTSTP"; case sig::CONT => return "SIGCONT"; case sig::CHLD => return "SIGCHLD"; case sig::TTIN => return "SIGTTIN"; case sig::TTOU => return "SIGTTOU"; case sig::IO => return "SIGIO"; case sig::XCPU => return "SIGXCPU"; case sig::XFSZ => return "SIGXFSZ"; case sig::VTALRM => return "SIGVTALRM"; case sig::PROF => return "SIGPROF"; case sig::WINCH => return "SIGWINCH"; case sig::INFO => return "SIGINFO"; case sig::USR1 => return "SIGUSR1"; case sig::USR2 => return "SIGUSR2"; case sig::THR => return "SIGTHR"; case sig::LIBRT => return "SIGLIBRT"; }; }; hare-0.24.2/unix/signal/+linux.ha000066400000000000000000000406171464473310100165150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; use time; use unix; // Requests that [[sig::ALRM]] is delivered to the calling process in (about) // "sec" seconds. Returns the number of seconds until the previously scheduled // alarm, or zero if none was scheduled. export fn alarm(sec: uint) uint = { return rt::alarm(sec); }; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). // // The variadic parameters specify either [[flag]]s to enable or a signal mask // to use via [[sigset]]; if the latter is provided no more than one may be // used. export fn handle( signum: sig, handler: *handler, opt: (flag | sigset)... ) sigaction = { let sa_mask = newsigset(); let sa_flags = rt::SA_SIGINFO, nmask = 0; for (let i = 0z; i < len(opt); i += 1) { match (opt[i]) { case let flag: flag => sa_flags |= flag: u64; case let mask: sigset => assert(nmask == 0, "Multiple signal masks provided to signal::handle"); nmask += 1; sa_mask = mask; }; }; let new = rt::sigact { sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, sa_mask = sa_mask, sa_flags = sa_flags, // Filled in by rt: sa_restorer = null: *fn () void, }; let old = rt::sigact { // Filled in by rt: sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, sa_restorer = null: *fn() void, ... }; match (rt::sigaction(signum, &new, &old)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; return old; }; // Restores previous signal behavior following [[handle]]. export fn restore(signum: sig, action: *sigaction) void = { match (rt::sigaction(signum, action: *rt::sigact, null)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; }; // Unregisters signal handlers for the specified signal. export fn reset(signum: sig) void = { handle(signum, rt::SIG_DFL: *handler); }; // Unregisters all signal handlers. export fn resetall() void = { // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) reset(sig::HUP); reset(sig::INT); reset(sig::QUIT); reset(sig::ILL); reset(sig::TRAP); reset(sig::ABRT); reset(sig::BUS); reset(sig::FPE); reset(sig::USR1); reset(sig::SEGV); reset(sig::USR2); reset(sig::PIPE); reset(sig::ALRM); reset(sig::TERM); reset(sig::CHLD); reset(sig::CONT); reset(sig::TSTP); reset(sig::TTIN); reset(sig::TTOU); reset(sig::URG); reset(sig::XCPU); reset(sig::XFSZ); reset(sig::VTALRM); reset(sig::PROF); reset(sig::WINCH); reset(sig::POLL); reset(sig::PWR); reset(sig::SYS); }; // Prevents given signal from arriving to the current process. // One common use case is to ignore SIGCHLD to avoid zombie child processes. export fn ignore(signum: sig) void = { handle(signum, rt::SIG_IGN: *handler); }; // Adds the given list of signals to the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn block(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::BLOCK, &new); }; // Removes the given list of signals from the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn unblock(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::UNBLOCK, &new); }; // Sets the process's signal mask, returning the previous mask. export fn setprocmask(how: how, mask: *sigset) sigset = { let old = sigset { ... }; rt::sigprocmask(how, mask: *rt::sigset, &old)!; return old; }; // Gets the current process's signal mask. export fn getprocmask() sigset = { let old = sigset { ... }; rt::sigprocmask(how::SETMASK, null, &old)!; return old; }; // Defines the modes of operation for [[setprocmask]]. export type how = enum int { // Adds the given set of signals to the current mask. BLOCK = rt::SIG_BLOCK, // Removes the given set of signals from the current mask. UNBLOCK = rt::SIG_UNBLOCK, // Sets the process mask to the given set. SETMASK = rt::SIG_SETMASK, }; export type sigaction = rt::sigact; export type sigset = rt::sigset; // Creates a new signal set filled in with the provided signals (or empty if // none are provided). export fn newsigset(items: sig...) sigset = { let set = sigset { ... }; rt::sigemptyset(&set); sigset_add(&set, items...); return set; }; // Sets a [[sigset]] to empty. export fn sigset_empty(set: *sigset) void = { rt::sigemptyset(set: *rt::sigset); }; // Adds signals to a [[sigset]]. export fn sigset_add(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigaddset(set: *rt::sigset, items[i])!; }; }; // Removes signals from a [[sigset]]. export fn sigset_del(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigdelset(set: *rt::sigset, items[i])!; }; }; // Adds all platform-defined signals to a [[sigset]]. export fn sigset_fill(set: *sigset) void = { rt::sigfillset(set: *rt::sigset); }; // Returns true if the given signal is a member of this [[sigset]]. export fn sigset_member(set: *sigset, item: sig) bool = { return rt::sigismember(set: *rt::sigset, item)!; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the signal number. // // If a signal is received while waiting, [[errors::interrupted]] is returned. // Most consumers of this function will likely wish to block all signals and // handle them exclusively through [[wait]] et al, in which case this error // cannot occur. // // See also [[waitinfo]] and [[timedwait]]. export fn wait(set: *sigset) (sig | errors::interrupted) = { let signal = 0i; match (rt::sigwait(set: *rt::sigset, &signal)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case void => return signal: sig; }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // See notes on [[wait]] regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigwaitinfo(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigwaitinfo]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on OpenBSD. export fn waitinfo(set: *sigset) (siginfo | errors::interrupted) = { let info = rt::siginfo { ... }; match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case int => return *(&info: *siginfo); }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // Returns a [[siginfo]] if a signal is successfully processed through this // function, or [[errors::again]] if the timeout expired. See notes on [[wait]] // regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigtimedwait(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigtimedwait]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on OpenBSD. export fn timedwait( set: *sigset, timeout: time::duration, ) (siginfo | errors::interrupted | errors::again) = { let info = rt::siginfo { ... }; let to = time::duration_to_timeval(timeout); match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => switch (err) { case rt::EINTR => return errors::interrupted; case rt::EAGAIN => return errors::again; case => abort(); }; case int => return *(&info: *siginfo); }; }; // Provides additional information about signal deliveries. Only the members // defined by POSIX are available here; cast to [[rt::siginfo]] to access // non-portable members. export type siginfo = union { struct { // The signal number being delivered. signo: sig, // The errno, if any, associated with this signal. See // [[errors::errno]] to convert to a Hare-native error. errno: rt::errno, // The signal code, if any. code: code, union { struct { // Process ID of the sender. pid: unix::pid, // Real user ID of the sending process. uid: unix::uid, // Exit value or signal. status: int, }, struct { // Address of the faulting instruction. addr: *opaque, }, }, }, // Pads the structure out to the length used by the kernel; do not use. _si_pad: [128 - 3 * size(int)]u8, }; // A code indicating why a signal was sent. export type code = enum int { USER = 0, // sent by userspace program (kill) KERNEL = 128, // sent by kernel QUEUE = -1, // sent by sigqueue TIMER = -2, // generated by expiration of a timer MESQ = -3, // generated by arrival of a message on an empty queue ASYNCIO = -4, // generated by completion of an asynchronous I/O request SIGIO = -5, TKILL = -6, // sent by userspace program (tkill, tgkill) ASYNCNL = -60, ILLOPC = 1, // sig::ILL: illegal opcode ILLOPN = 2, // sig::ILL: illegal operand ILLADR = 3, // sig::ILL: illegal addressing mode ILLTRP = 4, // sig::ILL: illegal trap PRVOPC = 5, // sig::ILL: privileged opcode PRVREG = 6, // sig::ILL: privileged register COPROC = 7, // sig::ILL: coprocessor error BADSTK = 8, // sig::ILL: internal stack error INTDIV = 1, // sig::FPE: integer divide by zero INTOVF = 2, // sig::FPE: integer overflow FLTDIV = 3, // sig::FPE: floating-point divide by zero FLTOVF = 4, // sig::FPE: floating-point overflow FLTUND = 5, // sig::FPE: floating-point underflow FLTRES = 6, // sig::FPE: floating-point inexact result FLTINV = 7, // sig::FPE: invalid floating-point operation FLTSUB = 8, // sig::FPE: subscript out of range MAPERR = 1, // sig::SEGV: address not mapped to object ACCERR = 2, // sig::SEGV: invalid permissions for mapped object BNDERR = 3, // sig::SEGV: failed address bound checks PKUERR = 4, // sig::SEGV: access was denied by memory protection keys MTEAERR = 8, // sig::SEGV MTESERR = 9, // sig::SEGV ADRALN = 1, // sig::BUS: invalid address alignment ADRERR = 2, // sig::BUS: nonexistent physical address OBJERR = 3, // sig::BUS: object-specific hardware error MCEERR_AR = 4, // sig::BUS: hardware memory error consumed on a machine check; action required MCEERR_AO = 5, // sig::BUS: hardware memory error detected in process but not consumed; action optional BRKPT = 1, // sig::TRAP: process breakpoint TRACE = 2, // sig::TRAP: process trace trap BRANCH = 3, // sig::TRAP: process taken branch trap HWBKPT = 4, // sig::TRAP: hardware breakpoint/watchpoint UNK = 5, // sig::TRAP EXITED = 1, // sig::CHLD: child exited KILLED = 2, // sig::CHLD: child terminated abnormally without a core file DUMPED = 3, // sig::CHLD: child terminated abnormally with a core file TRAPPED = 4, // sig::CHLD: traced child has trapped STOPPED = 5, // sig::CHLD: child has stopped CONTINUED = 6, // sig::CHLD: stopped child has continued IN = 1, // sig::POLL: data input available OUT = 2, // sig::POLL: output buffers available MSG = 3, // sig::POLL: input message available ERR = 4, // sig::POLL: I/O error PRI = 5, // sig::POLL: high priority input available HUP = 6, // sig::POLL: device disconnected }; // Flags used to configure the behavior of a signal handler. export type flag = enum int { // For use with sig::CHLD. Prevents notifications when child processes // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). NOCLDSTOP = rt::SA_NOCLDSTOP: int, // For use with sig::CHLD. Do not transform children into zombies when // they terminate. Note that POSIX leaves the delivery of sig::CHLD // unspecified when this flag is present; some systems will still // deliver a signal and others may not. NOCLDWAIT = rt::SA_NOCLDWAIT: int, // Uses an alternate stack when handling this signal. See // [[setaltstack]] and [[getaltstack]] for details. ONSTACK = rt::SA_ONSTACK: int, // Makes certain system calls restartable across signals. See signal(7) // or similar documentation for your local system for details. RESTART = rt::SA_RESTART: int, // Do not add the signal to the signal mask while executing the signal // handler. This can cause the same signal to be delivered again during // the execution of the signal handler. NODEFER = rt::SA_NODEFER: int, // Restore the signal handler to the default behavior upon entering the // signal handler. RESETHAND = rt::SA_RESETHAND: int, }; // All possible signals. export type sig = enum int { HUP = rt::SIGHUP, // Hangup. INT = rt::SIGINT, // Terminal interrupt. QUIT = rt::SIGQUIT, // Terminal quit. ILL = rt::SIGILL, // Illegal instruction. TRAP = rt::SIGTRAP, // Trace/breakpoint trap. ABRT = rt::SIGABRT, // Process abort. BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. FPE = rt::SIGFPE, // Erroneous arithmetic operation. KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). USR1 = rt::SIGUSR1, // User-defined signal 1. SEGV = rt::SIGSEGV, // Invalid memory reference. USR2 = rt::SIGUSR2, // User-defined signal 2. PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. ALRM = rt::SIGALRM, // Alarm clock. TERM = rt::SIGTERM, // Termination. CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. CONT = rt::SIGCONT, // Continue executing if stopped. STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). TSTP = rt::SIGTSTP, // Terminal stop. TTIN = rt::SIGTTIN, // Background process attempting read. TTOU = rt::SIGTTOU, // Background process attempting write. URG = rt::SIGURG, // High bandwidth data is available at a socket. XCPU = rt::SIGXCPU, // CPU time limit exceeded. XFSZ = rt::SIGXFSZ, // File size limit exceeded. VTALRM = rt::SIGVTALRM, // Virtual timer expired. PROF = rt::SIGPROF, // Profiling timer expired. WINCH = rt::SIGWINCH, // Window resize signal. IO = rt::SIGIO, // I/O now possible (synonymous with sig::POLL). POLL = rt::SIGPOLL, // Pollable event. PWR = rt::SIGPWR, // Power failure. SYS = rt::SIGSYS, // Bad system call. }; // Creates a signal file that handles the given set of signals. export fn signalfd(signals: sig...) (io::file | errors::error) = { let sa_mask = newsigset(signals...); match (rt::signalfd(-1, &sa_mask, rt::SFD_CLOEXEC)) { case let fd: int => return fd; case let err: rt::errno => return errors::errno(err); }; }; // Updates a signalfd with a new set of signals. The signal set is overwritten, // rather than appended to, with the provided set of signals. export fn update(fd: io::file, signals: sig...) (void | errors::error) = { let sa_mask = newsigset(signals...); match (rt::signalfd(fd, &sa_mask, rt::SFD_CLOEXEC)) { case int => return; case let err: rt::errno => return errors::errno(err); }; }; // Reads pending signal info from a signalfd. export fn read(fd: io::file) (siginfo | errors::error) = { let si = rt::signalfd_siginfo { ... }; match (rt::read(fd, &si, size(rt::signalfd_siginfo))) { case let err: rt::errno => return errors::errno(err); case let z: size => assert(z == size(rt::signalfd_siginfo)); }; return siginfo { signo = si.ssi_signo: sig, errno = si.ssi_errno: rt::errno, code = si.ssi_code: code, ... }; }; // Returns the human friendly name of a given signal. export fn signame(sig: sig) const str = { switch (sig) { case sig::HUP => return "SIGHUP"; case sig::INT => return "SIGINT"; case sig::QUIT => return "SIGQUIT"; case sig::ILL => return "SIGILL"; case sig::TRAP => return "SIGTRAP"; case sig::ABRT => return "SIGABRT"; case sig::BUS => return "SIGBUS"; case sig::FPE => return "SIGFPE"; case sig::KILL => return "SIGKILL"; case sig::USR1 => return "SIGUSR1"; case sig::SEGV => return "SIGSEGV"; case sig::USR2 => return "SIGUSR2"; case sig::PIPE => return "SIGPIPE"; case sig::ALRM => return "SIGALRM"; case sig::TERM => return "SIGTERM"; case sig::CHLD => return "SIGCHLD"; case sig::CONT => return "SIGCONT"; case sig::STOP => return "SIGSTOP"; case sig::TSTP => return "SIGTSTP"; case sig::TTIN => return "SIGTTIN"; case sig::TTOU => return "SIGTTOU"; case sig::URG => return "SIGURG"; case sig::XCPU => return "SIGXCPU"; case sig::XFSZ => return "SIGXFSZ"; case sig::VTALRM => return "SIGVTALRM"; case sig::PROF => return "SIGPROF"; case sig::WINCH => return "SIGWINCH"; case sig::POLL => return "SIGPOLL"; case sig::PWR => return "SIGPWR"; case sig::SYS => return "SIGSYS"; }; }; hare-0.24.2/unix/signal/+netbsd.ha000066400000000000000000000363271464473310100166400ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use time; use unix; // Requests that [[sig::ALRM]] is delivered to the calling process in (about) // "sec" seconds. Returns the number of seconds until the previously scheduled // alarm, or zero if none was scheduled. export fn alarm(sec: uint) uint = { return rt::alarm(sec); }; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). // // The variadic parameters specify either [[flag]]s to enable or a signal mask // to use via [[sigset]]; if the latter is provided no more than one may be // used. export fn handle( signum: sig, handler: *handler, opt: (flag | sigset)... ) sigaction = { let sa_mask = newsigset(); let sa_flags = rt::SA_SIGINFO: int, nmask = 0; for (let i = 0z; i < len(opt); i += 1) { match (opt[i]) { case let flag: flag => sa_flags |= flag: int; case let mask: sigset => assert(nmask == 0, "Multiple signal masks provided to signal::handle"); nmask += 1; sa_mask = mask; }; }; let new = rt::sigact { sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, sa_mask = sa_mask, sa_flags = sa_flags, }; let old = rt::sigact { sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, ... }; match (rt::sigaction(signum, &new, &old)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; return old; }; // Restores previous signal behavior following [[handle]]. export fn restore(signum: sig, action: *sigaction) void = { match (rt::sigaction(signum, action: *rt::sigact, null)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case int => void; }; }; // Unregisters signal handlers for the specified signal. export fn reset(signum: sig) void = { handle(signum, rt::SIG_DFL: *handler); }; // Unregisters all signal handlers. export fn resetall() void = { // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) reset(sig::HUP); reset(sig::INT); reset(sig::QUIT); reset(sig::ILL); reset(sig::TRAP); reset(sig::ABRT); reset(sig::EMT); reset(sig::FPE); reset(sig::BUS); reset(sig::SEGV); reset(sig::SYS); reset(sig::PIPE); reset(sig::ALRM); reset(sig::TERM); reset(sig::URG); reset(sig::TSTP); reset(sig::CONT); reset(sig::CHLD); reset(sig::TTIN); reset(sig::TTOU); reset(sig::IO); reset(sig::XCPU); reset(sig::XFSZ); reset(sig::VTALRM); reset(sig::PROF); reset(sig::WINCH); reset(sig::INFO); reset(sig::USR1); reset(sig::USR2); reset(sig::THR); reset(sig::LIBRT); }; // Prevents given signal from arriving to the current process. // One common use case is to ignore SIGCHLD to avoid zombie child processes. export fn ignore(signum: sig) void = { handle(signum, rt::SIG_IGN: *handler); }; // Adds the given list of signals to the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn block(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::BLOCK, &new); }; // Removes the given list of signals from the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn unblock(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::UNBLOCK, &new); }; // Sets the process's signal mask, returning the previous mask. export fn setprocmask(how: how, mask: *sigset) sigset = { let old = sigset { ... }; rt::sigprocmask(how, mask: *rt::sigset, &old)!; return old; }; // Gets the current process's signal mask. export fn getprocmask() sigset = { let old = sigset { ... }; rt::sigprocmask(how::SETMASK, null, &old)!; return old; }; // Defines the modes of operation for [[setprocmask]]. export type how = enum int { // Adds the given set of signals to the current mask. BLOCK = rt::SIG_BLOCK, // Removes the given set of signals from the current mask. UNBLOCK = rt::SIG_UNBLOCK, // Sets the process mask to the given set. SETMASK = rt::SIG_SETMASK, }; export type sigaction = rt::sigact; export type sigset = rt::sigset; // Creates a new signal set filled in with the provided signals (or empty if // none are provided). export fn newsigset(items: sig...) sigset = { let set = sigset { ... }; rt::sigemptyset(&set); sigset_add(&set, items...); return set; }; // Sets a [[sigset]] to empty. export fn sigset_empty(set: *sigset) void = { rt::sigemptyset(set: *rt::sigset); }; // Adds signals to a [[sigset]]. export fn sigset_add(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigaddset(set: *rt::sigset, items[i])!; }; }; // Removes signals from a [[sigset]]. export fn sigset_del(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigdelset(set: *rt::sigset, items[i])!; }; }; // Adds all platform-defined signals to a [[sigset]]. export fn sigset_fill(set: *sigset) void = { rt::sigfillset(set: *rt::sigset)!; }; // Returns true if the given signal is a member of this [[sigset]]. export fn sigset_member(set: *sigset, item: sig) bool = { return rt::sigismember(set: *rt::sigset, item)!; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the signal number. // // If a signal is received while waiting, [[errors::interrupted]] is returned. // Most consumers of this function will likely wish to block all signals and // handle them exclusively through [[wait]] et al, in which case this error // cannot occur. // // See also [[waitinfo]] and [[timedwait]]. export fn wait(set: *sigset) (sig | errors::interrupted) = { let signal = 0i; match (rt::sigwait(set: *rt::sigset, &signal)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case void => return signal: sig; }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // See notes on [[wait]] regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigwaitinfo(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigwaitinfo]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on NetBSD. export fn waitinfo(set: *sigset) (siginfo | errors::interrupted) = { let info = rt::siginfo { si_addr = null: *opaque, si_value = rt::sigval { ... }, ... }; match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case int => return *(&info: *siginfo); }; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the corresponding [[siginfo]] data. // // Returns a [[siginfo]] if a signal is successfully processed through this // function, or [[errors::again]] if the timeout expired. See notes on [[wait]] // regarding the [[errors::interrupted]] case. // // This function is designed to provide the portable subset of the semantics of // sigtimedwait(3) as defined by POSIX.1-2008. To access the complete siginfo_t // structure provided by the underlying platform, use [[rt::sigtimedwait]] and // [[rt::siginfo_t]] directly. // // Note that this function is not supported on OpenBSD. export fn timedwait( set: *sigset, timeout: time::duration, ) (siginfo | errors::interrupted | errors::again) = { let info = rt::siginfo { si_addr = null: *opaque, si_value = rt::sigval { ... }, ... }; let to = time::duration_to_timeval(timeout); match (rt::sigwaitinfo(set: *rt::sigset, &info)) { case let err: rt::errno => switch (err) { case rt::EINTR => return errors::interrupted; case rt::EAGAIN => return errors::again; case => abort(); }; case int => return *(&info: *siginfo); }; }; // Provides additional information about signal deliveries. Only the members // defined by POSIX are available here; cast to [[rt::siginfo]] to access // non-portable members. export type siginfo = union { struct { // The signal number being delivered. signo: sig, // The errno, if any, associated with this signal. See // [[errors::errno]] to convert to a Hare-native error. errno: rt::errno, // The signal code, if any. code: code, // Process ID of the sender. pid: unix::pid, // Real user ID of the sending process. uid: unix::uid, // Exit value or signal. status: int, // Address of the faulting instruction. addr: *opaque, }, // Pads the structure out to the length used by the kernel; do not use. _si_pad: [128 - 3 * size(int)]u8, }; // A code indicating why a signal was sent. export type code = enum int { USER = 0, // sent by userspace program (kill) KERNEL = 128, // sent by kernel QUEUE = -1, // sent by sigqueue TIMER = -2, // generated by expiration of a timer MESQ = -3, // generated by arrival of a message on an empty queue ASYNCIO = -4, // generated by completion of an asynchronous I/O request SIGIO = -5, TKILL = -6, // sent by userspace program (tkill, tgkill) ASYNCNL = -60, ILLOPC = 1, // sig::ILL: illegal opcode ILLOPN = 2, // sig::ILL: illegal operand ILLADR = 3, // sig::ILL: illegal addressing mode ILLTRP = 4, // sig::ILL: illegal trap PRVOPC = 5, // sig::ILL: privileged opcode PRVREG = 6, // sig::ILL: privileged register COPROC = 7, // sig::ILL: coprocessor error BADSTK = 8, // sig::ILL: internal stack error INTOVF = 1, // sig::FPE: integer overflow INTDIV = 2, // sig::FPE: integer divide by zero FLTDIV = 3, // sig::FPE: floating-point divide by zero FLTOVF = 4, // sig::FPE: floating-point overflow FLTUND = 5, // sig::FPE: floating-point underflow FLTRES = 6, // sig::FPE: floating-point inexact result FLTINV = 7, // sig::FPE: invalid floating-point operation FLTSUB = 8, // sig::FPE: subscript out of range MAPERR = 1, // sig::SEGV: address not mapped to object ACCERR = 2, // sig::SEGV: invalid permissions for mapped object PKUERR = 100, // sig::SEGV: access was denied by memory protection keys (x86_64) ADRALN = 1, // sig::BUS: invalid address alignment ADRERR = 2, // sig::BUS: nonexistent physical address OBJERR = 3, // sig::BUS: object-specific hardware error OOMERR = 100, // sig::BUS: out of memory BRKPT = 1, // sig::TRAP: process breakpoint TRACE = 2, // sig::TRAP: process trace trap DTRACE = 3, // sig::TRAP: DTrace induced trap CAP = 4, // sig::TRAP: capabilities protection trap EXITED = 1, // sig::CHLD: child exited KILLED = 2, // sig::CHLD: child terminated abnormally without a core file DUMPED = 3, // sig::CHLD: child terminated abnormally with a core file TRAPPED = 4, // sig::CHLD: traced child has trapped STOPPED = 5, // sig::CHLD: child has stopped CONTINUED = 6, // sig::CHLD: stopped child has continued IN = 1, // sig::IO: data input available OUT = 2, // sig::IO: output buffers available MSG = 3, // sig::IO: input message available ERR = 4, // sig::IO: I/O error PRI = 5, // sig::IO: high priority input available HUP = 6, // sig::IO: device disconnected }; // Flags used to configure the behavior of a signal handler. export type flag = enum int { // For use with sig::CHLD. Prevents notifications when child processes // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). NOCLDSTOP = rt::SA_NOCLDSTOP: int, // For use with sig::CHLD. Do not transform children into zombies when // they terminate. Note that POSIX leaves the delivery of sig::CHLD // unspecified when this flag is present; some systems will still // deliver a signal and others may not. NOCLDWAIT = rt::SA_NOCLDWAIT: int, // Uses an alternate stack when handling this signal. See // [[setaltstack]] and [[getaltstack]] for details. ONSTACK = rt::SA_ONSTACK: int, // Do not add the signal to the signal mask while executing the signal // handler. This can cause the same signal to be delivered again during // the execution of the signal handler. NODEFER = rt::SA_NODEFER: int, // Restore the signal handler to the default behavior upon entering the // signal handler. RESETHAND = rt::SA_RESETHAND: int, // Makes certain system calls restartable across signals. See signal(7) // or similar documentation for your local system for details. RESTART = rt::SA_RESTART: int, }; // All possible signals. export type sig = enum int { HUP = rt::SIGHUP, // Hangup. INT = rt::SIGINT, // Terminal interrupt. QUIT = rt::SIGQUIT, // Terminal quit. ILL = rt::SIGILL, // Illegal instruction. TRAP = rt::SIGTRAP, // Trace/breakpoint trap. ABRT = rt::SIGABRT, // Process abort. IOT = rt::SIGIOT, // Synonym for ABRT, provided for compatibility. EMT = rt::SIGEMT, // Emulate instruction executed. FPE = rt::SIGFPE, // Erroneous arithmetic operation. KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. SEGV = rt::SIGSEGV, // Invalid memory reference. SYS = rt::SIGSYS, // Bad system call. PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. ALRM = rt::SIGALRM, // Alarm clock. TERM = rt::SIGTERM, // Termination. URG = rt::SIGURG, // High bandwidth data is available at a socket. STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). TSTP = rt::SIGTSTP, // Terminal stop. CONT = rt::SIGCONT, // Continue executing, if stopped. CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. TTIN = rt::SIGTTIN, // Background process attempting read. TTOU = rt::SIGTTOU, // Background process attempting write. IO = rt::SIGIO, // I/O now possible. XCPU = rt::SIGXCPU, // CPU time limit exceeded. XFSZ = rt::SIGXFSZ, // File size limit exceeded. VTALRM = rt::SIGVTALRM, // Virtual timer expired. PROF = rt::SIGPROF, // Profiling timer expired. WINCH = rt::SIGWINCH, // Window resize. INFO = rt::SIGINFO, // Status request from keyboard. USR1 = rt::SIGUSR1, // User-defined signal 1. USR2 = rt::SIGUSR2, // User-defined signal 2. THR = rt::SIGTHR, // Thread interrupt. LIBRT = rt::SIGLIBRT, // Real-time library interrupt. }; // Returns the human friendly name of a given signal. export fn signame(sig: sig) const str = { switch (sig) { case sig::HUP => return "SIGHUP"; case sig::INT => return "SIGINT"; case sig::QUIT => return "SIGQUIT"; case sig::ILL => return "SIGILL"; case sig::TRAP => return "SIGTRAP"; case sig::ABRT => return "SIGABRT"; case sig::EMT => return "SIGEMT"; case sig::FPE => return "SIGFPE"; case sig::KILL => return "SIGKILL"; case sig::BUS => return "SIGBUS"; case sig::SEGV => return "SIGSEGV"; case sig::SYS => return "SIGSYS"; case sig::PIPE => return "SIGPIPE"; case sig::ALRM => return "SIGALRM"; case sig::TERM => return "SIGTERM"; case sig::URG => return "SIGURG"; case sig::STOP => return "SIGSTOP"; case sig::TSTP => return "SIGTSTP"; case sig::CONT => return "SIGCONT"; case sig::CHLD => return "SIGCHLD"; case sig::TTIN => return "SIGTTIN"; case sig::TTOU => return "SIGTTOU"; case sig::IO => return "SIGIO"; case sig::XCPU => return "SIGXCPU"; case sig::XFSZ => return "SIGXFSZ"; case sig::VTALRM => return "SIGVTALRM"; case sig::PROF => return "SIGPROF"; case sig::WINCH => return "SIGWINCH"; case sig::INFO => return "SIGINFO"; case sig::USR1 => return "SIGUSR1"; case sig::USR2 => return "SIGUSR2"; case sig::THR => return "SIGTHR"; case sig::LIBRT => return "SIGLIBRT"; }; }; hare-0.24.2/unix/signal/+openbsd.ha000066400000000000000000000307501464473310100170050ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use rt; use unix; // Requests that [[sig::ALRM]] is delivered to the calling process in (about) // "sec" seconds. Returns the number of seconds until the previously scheduled // alarm, or zero if none was scheduled. export fn alarm(sec: uint) uint = { return rt::alarm(sec); }; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). // // The variadic parameters specify either [[flag]]s to enable or a signal mask // to use via [[sigset]]; if the latter is provided no more than one may be // used. export fn handle( signum: sig, handler: *handler, opt: (flag | sigset)... ) sigaction = { let sa_mask = newsigset(); let sa_flags = rt::SA_SIGINFO: int, nmask = 0; for (let i = 0z; i < len(opt); i += 1) { match (opt[i]) { case let flag: flag => sa_flags |= flag: int; case let mask: sigset => assert(nmask == 0, "Multiple signal masks provided to signal::handle"); nmask += 1; sa_mask = mask; }; }; let new = rt::sigact { sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, sa_mask = sa_mask, sa_flags = sa_flags, }; let old = rt::sigact { sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, ... }; match (rt::sigaction(signum, &new, &old)) { case let err: rt::errno => abort("sigaction failed (invalid signal?)"); case void => void; }; return old; }; // Restores previous signal behavior following [[handle]]. export fn restore(signum: sig, action: *sigaction) void = { match (rt::sigaction(signum, action: *rt::sigact, null)) { case rt::errno => abort("sigaction failed (invalid signal?)"); case void => void; }; }; // Unregisters signal handlers for the specified signal. export fn reset(signum: sig) void = { handle(signum, rt::SIG_DFL: *handler); }; // Unregisters all signal handlers. export fn resetall() void = { // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) reset(sig::HUP); reset(sig::INT); reset(sig::QUIT); reset(sig::ILL); reset(sig::TRAP); reset(sig::ABRT); reset(sig::EMT); reset(sig::FPE); reset(sig::BUS); reset(sig::SEGV); reset(sig::SYS); reset(sig::PIPE); reset(sig::ALRM); reset(sig::TERM); reset(sig::URG); reset(sig::TSTP); reset(sig::CONT); reset(sig::CHLD); reset(sig::TTIN); reset(sig::TTOU); reset(sig::IO); reset(sig::XCPU); reset(sig::XFSZ); reset(sig::VTALRM); reset(sig::PROF); reset(sig::WINCH); reset(sig::INFO); reset(sig::USR1); reset(sig::USR2); }; // Prevents given signal from arriving to the current process. // One common use case is to ignore SIGCHLD to avoid zombie child processes. export fn ignore(signum: sig) void = { handle(signum, rt::SIG_IGN: *handler); }; // Adds the given list of signals to the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn block(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::BLOCK, &new); }; // Removes the given list of signals from the process's current signal mask, // returning the old signal mask. This is a convenience function around // [[setprocmask]]. export fn unblock(signals: sig...) sigset = { let new = newsigset(signals...); return setprocmask(how::UNBLOCK, &new); }; // Sets the process's signal mask, returning the previous mask. export fn setprocmask(how: how, mask: *sigset) sigset = { let old: sigset = 0; rt::sigprocmask(how, mask: *rt::sigset, &old)!; return old; }; // Gets the current process's signal mask. export fn getprocmask() sigset = { let old: sigset = 0; rt::sigprocmask(how::SETMASK, null, &old)!; return old; }; // Defines the modes of operation for [[setprocmask]]. export type how = enum int { // Adds the given set of signals to the current mask. BLOCK = rt::SIG_BLOCK, // Removes the given set of signals from the current mask. UNBLOCK = rt::SIG_UNBLOCK, // Sets the process mask to the given set. SETMASK = rt::SIG_SETMASK, }; export type sigaction = rt::sigact; export type sigset = rt::sigset; // Creates a new signal set filled in with the provided signals (or empty if // none are provided). export fn newsigset(items: sig...) sigset = { let set: sigset = 0; rt::sigemptyset(&set); sigset_add(&set, items...); return set; }; // Sets a [[sigset]] to empty. export fn sigset_empty(set: *sigset) void = { rt::sigemptyset(set: *rt::sigset); }; // Adds signals to a [[sigset]]. export fn sigset_add(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigaddset(set: *rt::sigset, items[i])!; }; }; // Removes signals from a [[sigset]]. export fn sigset_del(set: *sigset, items: sig...) void = { for (let i = 0z; i < len(items); i += 1) { rt::sigdelset(set: *rt::sigset, items[i])!; }; }; // Adds all platform-defined signals to a [[sigset]]. export fn sigset_fill(set: *sigset) void = { rt::sigfillset(set: *rt::sigset)!; }; // Returns true if the given signal is a member of this [[sigset]]. export fn sigset_member(set: *sigset, item: sig) bool = { return rt::sigismember(set: *rt::sigset, item)!; }; // Waits for a signal among the given [[sigset]] to be delivered, then returns // the signal number. // // If a signal is received while waiting, [[errors::interrupted]] is returned. // Most consumers of this function will likely wish to block all signals and // handle them exclusively through [[wait]] et al, in which case this error // cannot occur. export fn wait(set: *sigset) (sig | errors::interrupted) = { let signal = 0i; match (rt::sigwait(set: *rt::sigset, &signal)) { case let err: rt::errno => assert(err == rt::EINTR); return errors::interrupted; case void => return signal: sig; }; }; // Provides additional information about signal deliveries. Only the members // defined by POSIX are available here; cast to [[rt::siginfo]] to access // non-portable members. export type siginfo = struct { // The signal number being delivered. signo: sig, // The signal code, if any. code: code, // The errno, if any, associated with this signal. See // [[errors::errno]] to convert to a Hare-native error. errno: rt::errno, union { union { struct { // Process ID of the sender. pid: unix::pid, // Real user ID of the sending process. uid: unix::uid, }, struct { // Address of the faulting instruction. addr: *opaque, }, }, // Pads the structure out to the length used by the kernel; do not use. _si_pad: [29]int, }, }; export type code = enum int { NOINFO = rt::SI_NOINFO, // no signal information USER = rt::SI_USER, // user generated signal via kill() LWP = rt::SI_LWP, // user generated signal via lwp_kill() QUEUE = rt::SI_QUEUE, // user generated signal via sigqueue() TIMER = rt::SI_TIMER, // from timer expiration ILLOPC = rt::ILL_ILLOPC, // sig::ILL: illegal opcode ILLOPN = rt::ILL_ILLOPN, // sig::ILL: illegal operand ILLADR = rt::ILL_ILLADR, // sig::ILL: illegal addressing mode ILLTRP = rt::ILL_ILLTRP, // sig::ILL: illegal trap PRVOPC = rt::ILL_PRVOPC, // sig::ILL: privileged opcode PRVREG = rt::ILL_PRVREG, // sig::ILL: privileged register COPROC = rt::ILL_COPROC, // sig::ILL: co-processor BADSTK = rt::ILL_BADSTK, // sig::ILL: bad stack INTDIV = rt::FPE_INTDIV, // sig::FPE: integer divide by zero INTOVF = rt::FPE_INTOVF, // sig::FPE: integer overflow FLTDIV = rt::FPE_FLTDIV, // sig::FPE: floating point divide by zero FLTOVF = rt::FPE_FLTOVF, // sig::FPE: floating point overflow FLTUND = rt::FPE_FLTUND, // sig::FPE: floating point underflow FLTRES = rt::FPE_FLTRES, // sig::FPE: floating point inexact result FLTINV = rt::FPE_FLTINV, // sig::FPE: invalid floating point operation FLTSUB = rt::FPE_FLTSUB, // sig::FPE: subscript out of range MAPERR = rt::SEGV_MAPERR, // sig::SEGV: address not mapped to object ACCERR = rt::SEGV_ACCERR, // sig::SEGV: invalid permissions ADRALN = rt::BUS_ADRALN, // sig::BUS: invalid address alignment ADRERR = rt::BUS_ADRERR, // sig::BUS: non-existent physical address OBJERR = rt::BUS_OBJERR, // sig::BUS: object specific hardware error BRKPT = rt::TRAP_BRKPT, // sig::TRAP: breakpoint trap TRACE = rt::TRAP_TRACE, // sig::TRAP: trace trap EXITED = rt::CLD_EXITED, // sig::CHLD: child has exited KILLED = rt::CLD_KILLED, // sig::CHLD: child was killed DUMPED = rt::CLD_DUMPED, // sig::CHLD: child has coredumped TRAPPED = rt::CLD_TRAPPED, // sig::CHLD: traced child has stopped STOPPED = rt::CLD_STOPPED, // sig::CHLD: child has stopped on signal CONTINUED = rt::CLD_CONTINUED, // sig::CHLD: stopped child has continued }; export type flag = enum int { // For use with sig::CHLD. Prevents notifications when child processes // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). NOCLDSTOP = rt::SA_NOCLDSTOP: int, // For use with sig::CHLD. Do not transform children into zombies when // they terminate. Note that POSIX leaves the delivery of sig::CHLD // unspecified when this flag is present; some systems will still // deliver a signal and others may not. NOCLDWAIT = rt::SA_NOCLDWAIT: int, // Uses an alternate stack when handling this signal. See // [[setaltstack]] and [[getaltstack]] for details. ONSTACK = rt::SA_ONSTACK: int, // Do not add the signal to the signal mask while executing the signal // handler. This can cause the same signal to be delivered again during // the execution of the signal handler. NODEFER = rt::SA_NODEFER: int, // Restore the signal handler to the default behavior upon entering the // signal handler. RESETHAND = rt::SA_RESETHAND: int, // Makes certain system calls restartable across signals. See signal(7) // or similar documentation for your local system for details. RESTART = rt::SA_RESTART: int, }; // All possible signals. export type sig = enum int { HUP = rt::SIGHUP, // Hangup. INT = rt::SIGINT, // Terminal interrupt. QUIT = rt::SIGQUIT, // Terminal quit. ILL = rt::SIGILL, // Illegal instruction. TRAP = rt::SIGTRAP, // Trace/breakpoint trap. ABRT = rt::SIGABRT, // Process abort. EMT = rt::SIGEMT, // Emulate instruction executed. FPE = rt::SIGFPE, // Erroneous arithmetic operation. KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. SEGV = rt::SIGSEGV, // Invalid memory reference. SYS = rt::SIGSYS, // Bad system call. PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. ALRM = rt::SIGALRM, // Alarm clock. TERM = rt::SIGTERM, // Termination. URG = rt::SIGURG, // High bandwidth data is available at a socket. STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). TSTP = rt::SIGTSTP, // Terminal stop. CONT = rt::SIGCONT, // Continue executing, if stopped. CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. TTIN = rt::SIGTTIN, // Background process attempting read. TTOU = rt::SIGTTOU, // Background process attempting write. IO = rt::SIGIO, // I/O now possible. XCPU = rt::SIGXCPU, // CPU time limit exceeded. XFSZ = rt::SIGXFSZ, // File size limit exceeded. VTALRM = rt::SIGVTALRM, // Virtual timer expired. PROF = rt::SIGPROF, // Profiling timer expired. WINCH = rt::SIGWINCH, // Window resize. INFO = rt::SIGINFO, // Status request from keyboard. USR1 = rt::SIGUSR1, // User-defined signal 1. USR2 = rt::SIGUSR2, // User-defined signal 2. }; // Returns the human friendly name of a given signal. export fn signame(sig: sig) const str = { switch (sig) { case sig::HUP => return "SIGHUP"; case sig::INT => return "SIGINT"; case sig::QUIT => return "SIGQUIT"; case sig::ILL => return "SIGILL"; case sig::TRAP => return "SIGTRAP"; case sig::ABRT => return "SIGABRT"; case sig::EMT => return "SIGEMT"; case sig::FPE => return "SIGFPE"; case sig::KILL => return "SIGKILL"; case sig::BUS => return "SIGBUS"; case sig::SEGV => return "SIGSEGV"; case sig::SYS => return "SIGSYS"; case sig::PIPE => return "SIGPIPE"; case sig::ALRM => return "SIGALRM"; case sig::TERM => return "SIGTERM"; case sig::URG => return "SIGURG"; case sig::STOP => return "SIGSTOP"; case sig::TSTP => return "SIGTSTP"; case sig::CONT => return "SIGCONT"; case sig::CHLD => return "SIGCHLD"; case sig::TTIN => return "SIGTTIN"; case sig::TTOU => return "SIGTTOU"; case sig::IO => return "SIGIO"; case sig::XCPU => return "SIGXCPU"; case sig::XFSZ => return "SIGXFSZ"; case sig::VTALRM => return "SIGVTALRM"; case sig::PROF => return "SIGPROF"; case sig::WINCH => return "SIGWINCH"; case sig::INFO => return "SIGINFO"; case sig::USR1 => return "SIGUSR1"; case sig::USR2 => return "SIGUSR2"; }; }; hare-0.24.2/unix/signal/README000066400000000000000000000014161464473310100156430ustar00rootroot00000000000000The signal module provides support for Unix signal handlers. Typical applications will provide a signal handler to [[handle]] to configure it for the desired signal, possibly along with flags and a signal mask. This function returns the previous signal handler, which can be passed to [[restore]] to restore the previous behavior. Signal handling is stupidly complicated and easy to get wrong. The standard library makes little effort to help you deal with this. Consult your local man pages, particularly signal-safety(7) on Linux, and perhaps a local priest as well. We advise you to get out of the signal handler as soon as possible, for example via the "self-pipe trick". Note that the necessary sa_restorer functionality is implemented (and imposed) by the standard library. hare-0.24.2/unix/signal/types.ha000066400000000000000000000006211464473310100164360ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // A function which handles a signal. The first argument is the signal number // which was caught, the second provides information about the signal, and the // third argument is the ucontext, which is usually ignored by most signal // handlers. export type handler = fn(sig: sig, info: *siginfo, ucontext: *opaque) void; hare-0.24.2/unix/tty/000077500000000000000000000000001464473310100143245ustar00rootroot00000000000000hare-0.24.2/unix/tty/+freebsd/000077500000000000000000000000001464473310100160115ustar00rootroot00000000000000hare-0.24.2/unix/tty/+freebsd/isatty.ha000066400000000000000000000005671464473310100176500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use rt; // Returns whether the given stream is connected to a terminal. export fn isatty(fd: io::file) bool = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => return false; case let r: int => return r == 0; }; }; hare-0.24.2/unix/tty/+freebsd/open.ha000066400000000000000000000006301464473310100172630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; // Returns a stream connected to the TTY of the current process. The caller must // close it using [[io::close]]. export fn open() (io::file | error) = { match (os::open("/dev/tty", fs::flag::RDWR)) { case let f: io::file => return f; case fs::error => return errors::noentry; }; }; hare-0.24.2/unix/tty/+freebsd/pgid.ha000066400000000000000000000006151464473310100172500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use os::exec; use rt; // Sets the process group on the foreground of this terminal. export fn tcsetpgrp(fd: io::file, pg: exec::process) (void | errors::error) = { match (rt::ioctl(fd, rt::TIOCSPGRP, pg: u64)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/tty/+freebsd/pty.ha000066400000000000000000000043571464473310100171500ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use fs; use io; use os; use rt; use types::c; // Opens an available pseudoterminal and returns the file descriptors of the // master and slave. export fn openpty() ((io::file, io::file) | fs::error) = { let master = open_master()?; let slave = match (get_slave(master)) { case let e: fs::error => io::close(master)!; return e; case let s: io::file => yield s; }; return (master, slave); }; // Opens an available pseudoterminal master. fn open_master() (io::file | fs::error) = { match (rt::posix_openpt(rt::O_RDWR | rt::O_NOCTTY)) { case let e: rt::errno => return errors::errno(e); case let i: int => return io::fdopen(i); }; }; // Returns a file descriptor referring to the pseudoterminal slave for a // pseudoterminal master. fn get_slave(master: io::file) (io::file | fs::error) = os::open(ptsname(master)?, fs::flag::RDWR); // Returns the filename of the pseudoterminal slave. export fn ptsname(master: io::file) (str | error) = { // Ensure that the file descriptor refers to a master match (rt::ioctl(master, rt::TIOCPTMASTER, null)) { case let e: rt::errno => if (e == rt::EBADF) return errors::invalid else return errors::unsupported; case => void; }; let name: [rt::PATH_MAX]u8 = [0...]; let fiodgname_arg = (len(name), &name); match (rt::ioctl(master, rt::FIODGNAME, &fiodgname_arg)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::EINVAL, rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => static let path_buf: [rt::PATH_MAX]u8 = [0...]; return fmt::bsprintf(path_buf, "/dev/{}", c::tostr(&name: *const c::char)!); }; }; // Sets the dimensions of the underlying pseudoterminal for an [[io::file]]. export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = { let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... }; match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) { case let e: rt::errno => switch (e) { case rt::EBADF, rt::EINVAL => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => void; }; }; hare-0.24.2/unix/tty/+freebsd/termios.ha000066400000000000000000000045441464473310100200140ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; export type termios = struct { file: io::file, saved: rt::termios, current: rt::termios, }; // Retrieves serial port settings of the given terminal. export fn termios_query(file: io::file) (termios | errors::error) = { let settings = rt::termios { ... }; match (rt::ioctl(file, rt::TIOCGETA, &settings)) { case int => void; case let err: rt::errno => return errors::errno(err); }; return termios { file = file, saved = settings, current = settings, }; }; // Restores original serial port settings. export fn termios_restore(termios: *const termios) void = { rt::ioctl(termios.file, rt::TIOCSETA, &termios.saved): void; }; // Sets serial port settings. export fn termios_set(termios: *const termios) (void | errors::error) = { match (rt::ioctl(termios.file, rt::TIOCSETA, &termios.current)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; // Enables "raw" mode for this terminal, disabling echoing, line // editing, and signal handling. Users should call [[termios_query]] // prior to this to save the previous terminal settings, and // [[termios_restore]] to restore them before exiting. export fn makeraw(termios: *termios) (void | errors::error) = { // Disable break signal and CR<->LF processing termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT | rt::tcflag::INLCR | rt::tcflag::IGNCR | rt::tcflag::ICRNL); // Disable output post-processing termios.current.c_oflag &= ~rt::tcflag::OPOST; // Disable character echo, canonical mode, implementation defined // extensions and INTR/QUIT/SUSP characters termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL | rt::tcflag::ICANON | rt::tcflag::IEXTEN | rt::tcflag::ISIG); termios_set(termios)?; }; // Disables "echo" on this terminal. Users should call [[termios_restore]] to // restore settings. export fn noecho(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ECHO; termios_set(termios)?; }; // Enables "noncanonical" mode for this terminal, disabling line buffering and // line editing. Users should call [[termios_restore]] to restore settings. export fn noncanonical(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ICANON; termios_set(termios)?; }; hare-0.24.2/unix/tty/+freebsd/winsize.ha000066400000000000000000000011401464473310100200070ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Returns the dimensions of underlying terminal for an [[io::file]]. export fn winsize(fd: io::file) (ttysize | error) = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case int => return ttysize { rows = wsz.ws_row, columns = wsz.ws_col, }; }; }; hare-0.24.2/unix/tty/+linux/000077500000000000000000000000001464473310100155365ustar00rootroot00000000000000hare-0.24.2/unix/tty/+linux/isatty.ha000066400000000000000000000005671464473310100173750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use rt; // Returns whether the given stream is connected to a terminal. export fn isatty(fd: io::file) bool = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => return false; case let r: int => return r == 0; }; }; hare-0.24.2/unix/tty/+linux/open.ha000066400000000000000000000006301464473310100170100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; // Returns a stream connected to the TTY of the current process. The caller must // close it using [[io::close]]. export fn open() (io::file | error) = { match (os::open("/dev/tty", fs::flag::RDWR)) { case let f: io::file => return f; case fs::error => return errors::noentry; }; }; hare-0.24.2/unix/tty/+linux/pgid.ha000066400000000000000000000006151464473310100167750ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use os::exec; use rt; // Sets the process group on the foreground of this terminal. export fn tcsetpgrp(fd: io::file, pg: exec::process) (void | errors::error) = { match (rt::ioctl(fd, rt::TIOCSPGRP, pg: u64)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/tty/+linux/pty.ha000066400000000000000000000041041464473310100166630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fmt; use fs; use io; use os; use rt; // Opens an available pseudoterminal and returns the file descriptors of the // master and slave. export fn openpty() ((io::file, io::file) | fs::error) = { let master = open_master()?; let slave = match (get_slave(master)) { case let e: fs::error => io::close(master)!; return e; case let s: io::file => yield s; }; return (master, slave); }; // Opens an available pseudoterminal master. fn open_master() (io::file | fs::error) = { return os::open("/dev/ptmx", fs::flag::RDWR); }; // Returns a file descriptor referring to the pseudoterminal slave for a // pseudoterminal master. fn get_slave(master: io::file) (io::file | fs::error) = { // Unlock the pseudoterminal slave match (rt::ioctl(master, rt::TIOCSPTLCK, &0)) { case rt::errno => return errors::invalid; case => void; }; let ioctl = rt::ioctl( master, rt::TIOCGPTPEER, (rt::O_RDWR | rt::O_NOCTTY): u64); match (ioctl) { case let e: rt::errno => return errors::errno(e); case let fd: int => return io::fdopen(fd); }; }; // Returns the filename of the pseudoterminal slave. export fn ptsname(master: io::file) (str | error) = { let pty = 0; match (rt::ioctl(master, rt::TIOCGPTN, &pty)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => static let buf: [9 + 20]u8 = [0...]; return fmt::bsprintf(buf[..len(buf)], "/dev/pts/{}", pty); }; }; // Sets the dimensions of the underlying pseudoterminal for an [[io::file]]. export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = { let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... }; match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => void; }; }; hare-0.24.2/unix/tty/+linux/termios.ha000066400000000000000000000046071464473310100175410ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: Not in love with this interface use errors; use io; use rt; export type termios = struct { file: io::file, saved: rt::termios, current: rt::termios, }; // Retrieves serial port settings of the given terminal. export fn termios_query(file: io::file) (termios | errors::error) = { let settings = rt::termios { ... }; match (rt::ioctl(file, rt::TCGETS, &settings)) { case int => void; case let err: rt::errno => return errors::errno(err); }; return termios { file = file, saved = settings, current = settings, }; }; // Restores original serial port settings. export fn termios_restore(termios: *const termios) void = { rt::ioctl(termios.file, rt::TCSETS, &termios.saved): void; }; // Sets serial port settings. export fn termios_set(termios: *const termios) (void | errors::error) = { match (rt::ioctl(termios.file, rt::TCSETS, &termios.current)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; // Enables "raw" mode for this terminal, disabling echoing, line // editing, and signal handling. Users should call [[termios_query]] // prior to this to save the previous terminal settings, and // [[termios_restore]] to restore them before exiting. export fn makeraw(termios: *termios) (void | errors::error) = { // Disable break signal and CR<->LF processing termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT | rt::tcflag::INLCR | rt::tcflag::IGNCR | rt::tcflag::ICRNL); // Disable output post-processing termios.current.c_oflag &= ~rt::tcflag::OPOST; // Disable character echo, canonical mode, implementation defined // extensions and INTR/QUIT/SUSP characters termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL | rt::tcflag::ICANON | rt::tcflag::IEXTEN | rt::tcflag::ISIG); termios_set(termios)?; }; // Disables "echo" on this terminal. Users should call [[termios_restore]] to // restore settings. export fn noecho(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ECHO; termios_set(termios)?; }; // Enables "noncanonical" mode for this terminal, disabling line buffering and // line editing. Users should call [[termios_restore]] to restore settings. export fn noncanonical(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ICANON; termios_set(termios)?; }; hare-0.24.2/unix/tty/+linux/winsize.ha000066400000000000000000000011411464473310100175350ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Returns the dimensions of underlying terminal for an [[io::file]]. export fn winsize(fd: io::file) (ttysize | error) = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => switch (e) { case rt::EBADFD => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case int => return ttysize { rows = wsz.ws_row, columns = wsz.ws_col, }; }; }; hare-0.24.2/unix/tty/+netbsd/000077500000000000000000000000001464473310100156565ustar00rootroot00000000000000hare-0.24.2/unix/tty/+netbsd/isatty.ha000066400000000000000000000005671464473310100175150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use io; use rt; // Returns whether the given stream is connected to a terminal. export fn isatty(fd: io::file) bool = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => return false; case let r: int => return r == 0; }; }; hare-0.24.2/unix/tty/+netbsd/open.ha000066400000000000000000000006301464473310100171300ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; // Returns a stream connected to the TTY of the current process. The caller must // close it using [[io::close]]. export fn open() (io::file | error) = { match (os::open("/dev/tty", fs::flag::RDWR)) { case let f: io::file => return f; case fs::error => return errors::noentry; }; }; hare-0.24.2/unix/tty/+netbsd/pgid.ha000066400000000000000000000006151464473310100171150ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use os::exec; use rt; // Sets the process group on the foreground of this terminal. export fn tcsetpgrp(fd: io::file, pg: exec::process) (void | errors::error) = { match (rt::ioctl(fd, rt::TIOCSPGRP, pg: u64)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/tty/+netbsd/pty.ha000066400000000000000000000036121464473310100170060ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; use rt; use types::c; use strings; // Opens an available pseudoterminal and returns the file descriptors of the // master and slave. export fn openpty() ((io::file, io::file) | fs::error) = { let master = open_master()?; let slave = match (get_slave(master)) { case let e: fs::error => io::close(master)!; return e; case let s: io::file => yield s; }; return (master, slave); }; // Opens an available pseudoterminal master. fn open_master() (io::file | fs::error) = { match (rt::posix_openpt(rt::O_RDWR | rt::O_NOCTTY)) { case let e: rt::errno => return errors::errno(e); case let i: int => return io::fdopen(i); }; }; // Returns a file descriptor referring to the pseudoterminal slave for a // pseudoterminal master. fn get_slave(master: io::file) (io::file | fs::error) = os::open(ptsname(master)?, fs::flag::RDWR); // Returns the filename of the pseudoterminal slave. export fn ptsname(master: io::file) (str | error) = { let pm = rt::ptmget { ... }; match (rt::ioctl(master, rt::TIOCPTSNAME, &pm)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::EINVAL, rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => void; }; return strings::dup(c::tostr(&pm.sn: *const c::char)!); }; // Sets the dimensions of the underlying pseudoterminal for an [[io::file]]. export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = { let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... }; match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) { case let e: rt::errno => switch (e) { case rt::EBADF, rt::EINVAL => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => void; }; }; hare-0.24.2/unix/tty/+netbsd/termios.ha000066400000000000000000000045441464473310100176610ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; export type termios = struct { file: io::file, saved: rt::termios, current: rt::termios, }; // Retrieves serial port settings of the given terminal. export fn termios_query(file: io::file) (termios | errors::error) = { let settings = rt::termios { ... }; match (rt::ioctl(file, rt::TIOCGETA, &settings)) { case int => void; case let err: rt::errno => return errors::errno(err); }; return termios { file = file, saved = settings, current = settings, }; }; // Restores original serial port settings. export fn termios_restore(termios: *const termios) void = { rt::ioctl(termios.file, rt::TIOCSETA, &termios.saved): void; }; // Sets serial port settings. export fn termios_set(termios: *const termios) (void | errors::error) = { match (rt::ioctl(termios.file, rt::TIOCSETA, &termios.current)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; // Enables "raw" mode for this terminal, disabling echoing, line // editing, and signal handling. Users should call [[termios_query]] // prior to this to save the previous terminal settings, and // [[termios_restore]] to restore them before exiting. export fn makeraw(termios: *termios) (void | errors::error) = { // Disable break signal and CR<->LF processing termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT | rt::tcflag::INLCR | rt::tcflag::IGNCR | rt::tcflag::ICRNL); // Disable output post-processing termios.current.c_oflag &= ~rt::tcflag::OPOST; // Disable character echo, canonical mode, implementation defined // extensions and INTR/QUIT/SUSP characters termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL | rt::tcflag::ICANON | rt::tcflag::IEXTEN | rt::tcflag::ISIG); termios_set(termios)?; }; // Disables "echo" on this terminal. Users should call [[termios_restore]] to // restore settings. export fn noecho(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ECHO; termios_set(termios)?; }; // Enables "noncanonical" mode for this terminal, disabling line buffering and // line editing. Users should call [[termios_restore]] to restore settings. export fn noncanonical(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ICANON; termios_set(termios)?; }; hare-0.24.2/unix/tty/+netbsd/winsize.ha000066400000000000000000000011401464473310100176540ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Returns the dimensions of underlying terminal for an [[io::file]]. export fn winsize(fd: io::file) (ttysize | error) = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case int => return ttysize { rows = wsz.ws_row, columns = wsz.ws_col, }; }; }; hare-0.24.2/unix/tty/+openbsd/000077500000000000000000000000001464473310100160315ustar00rootroot00000000000000hare-0.24.2/unix/tty/+openbsd/isatty.ha000066400000000000000000000003731464473310100176630ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use rt; use io; // Returns whether the given stream is connected to a terminal. export fn isatty(fd: io::file) bool = { return rt::fcntl(fd, rt::F_ISATTY, 0) is int; }; hare-0.24.2/unix/tty/+openbsd/open.ha000066400000000000000000000006301464473310100173030ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use os; // Returns a stream connected to the TTY of the current process. The caller must // close it using [[io::close]]. export fn open() (io::file | error) = { match (os::open("/dev/tty", fs::flag::RDWR)) { case let f: io::file => return f; case fs::error => return errors::noentry; }; }; hare-0.24.2/unix/tty/+openbsd/pgid.ha000066400000000000000000000006151464473310100172700ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use os::exec; use rt; // Sets the process group on the foreground of this terminal. export fn tcsetpgrp(fd: io::file, pg: exec::process) (void | errors::error) = { match (rt::ioctl(fd, rt::TIOCSPGRP, pg: u64)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; hare-0.24.2/unix/tty/+openbsd/pty.ha000066400000000000000000000036521464473310100171650ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use fs; use io; use rt; use types::c; // Opens an available pseudoterminal and returns the file descriptors of the // master and slave. export fn openpty() ((io::file, io::file) | fs::error) = { let master = open_master()?; defer io::close(master)!; let ptm = rt::ptmget { ... }; match (rt::ioctl(master, rt::PTMGET, &ptm)) { case let e: rt::errno => return errors::errno(e); case => void; }; return (ptm.cfd, ptm.sfd); }; // Opens an available pseudoterminal master. fn open_master() (io::file | fs::error) = { match (rt::open(rt::PATH_PTMDEV, rt::O_RDWR, 0)) { case let e: rt::errno => return errors::errno(e); case let i: int => return io::fdopen(i); }; }; // Returns the filename of the pseudoterminal slave. export fn ptsname(master: io::file) (str | error) = { static let path_buf: [rt::PATH_MAX]u8 = [0...]; let name = match (rt::ptsname(master)) { case let name: *u8 => yield name: *[*]u8; case let err: rt::errno => switch (err) { // master is not a pseudo-terminal device case rt::EINVAL => return errors::unsupported; // master is not an open valid file descriptor case rt::EBADF => return errors::invalid; case => abort("Unexpected error from ptsname"); }; }; let namelen = c::strlen(name: *const c::char); path_buf[..namelen] = name[..namelen]; return c::tostrn(&path_buf: *const c::char, namelen)!; }; // Sets the dimensions of the underlying pseudoterminal for an [[io::file]]. export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = { let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... }; match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) { case let e: rt::errno => switch (e) { case rt::EBADF, rt::EINVAL => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case => void; }; }; hare-0.24.2/unix/tty/+openbsd/termios.ha000066400000000000000000000041401464473310100200240ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors // TODO: Not in love with this interface use io; use rt; use errors; export type termios = struct { file: io::file, saved: rt::termios, current: rt::termios, }; // Retrieves serial port settings of the given terminal. export fn termios_query(file: io::file) (termios | errors::error) = { let settings = rt::termios { ... }; match (rt::ioctl(file, rt::TIOCGETA, &settings)) { case int => void; case let err: rt::errno => return errors::errno(err); }; return termios { file = file, saved = settings, current = settings, }; }; // Restores original serial port settings. export fn termios_restore(termios: *const termios) void = { rt::ioctl(termios.file, rt::TIOCSETA, &termios.saved): void; }; // Sets serial port settings. export fn termios_set(termios: *const termios) (void | errors::error) = { match (rt::ioctl(termios.file, rt::TIOCSETA, &termios.current)) { case int => void; case let err: rt::errno => return errors::errno(err); }; }; // Enables "raw" mode for this terminal, disabling echoing, line // editing, and signal handling. Users should call [[termios_query]] // prior to this to save the previous terminal settings, and // [[termios_restore]] to restore them before exiting. export fn makeraw(termios: *termios) (void | errors::error) = { // Disable break signal and CR<->LF processing termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT | rt::tcflag::INLCR | rt::tcflag::IGNCR | rt::tcflag::ICRNL); // Disable output post-processing termios.current.c_oflag &= ~rt::tcflag::OPOST; // Disable character echo, canonical mode, implementation defined // extensions and INTR/QUIT/SUSP characters termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL | rt::tcflag::ICANON | rt::tcflag::IEXTEN | rt::tcflag::ISIG); termios_set(termios)?; }; // Disables "echo" on this terminal. Users should call [[termios_restore]] to // restore settings. export fn noecho(termios: *termios) (void | errors::error) = { termios.current.c_lflag &= ~rt::tcflag::ECHO; termios_set(termios)?; }; hare-0.24.2/unix/tty/+openbsd/winsize.ha000066400000000000000000000011401464473310100200270ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; use io; use rt; // Returns the dimensions of underlying terminal for an [[io::file]]. export fn winsize(fd: io::file) (ttysize | error) = { let wsz = rt::winsize { ... }; match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { case let e: rt::errno => switch (e) { case rt::EBADF => return errors::invalid; case rt::ENOTTY => return errors::unsupported; case => abort("Unexpected error from ioctl"); }; case int => return ttysize { rows = wsz.ws_row, columns = wsz.ws_col, }; }; }; hare-0.24.2/unix/tty/README000066400000000000000000000003311464473310100152010ustar00rootroot00000000000000unix::tty provides an interface for interacting with and manipulating a terminal environment, based on the termios interface defined by POSIX. https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html hare-0.24.2/unix/tty/pty_test.ha000066400000000000000000000012721464473310100165130ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bufio; use fmt; use fs; use io; use os; use strings; @test fn pty() void = { let pty = openpty()!; defer io::close(pty.1)!; defer io::close(pty.0)!; assert(fs::exists(os::cwd, ptsname(pty.0)!)); for (let i: u16 = 5; i < 100; i += 1) { let sz1 = ttysize { rows = i, columns = i }; set_winsize(pty.1, sz1)!; let sz2 = winsize(pty.1)!; assert(sz2.rows == sz1.rows); assert(sz2.columns == sz1.columns); }; fmt::fprintln(pty.0, "hello, world")!; const scan = bufio::newscanner(pty.1); defer bufio::finish(&scan); const s = bufio::scan_line(&scan) as const str; assert(s == "hello, world"); }; hare-0.24.2/unix/tty/types.ha000066400000000000000000000007271464473310100160100ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use errors; // Any error that may occur during TTY-related tasks. export type error = !(errors::invalid | errors::unsupported | errors::noentry); // Converts an [[error]] to a human-friendly string. export fn strerror(err: error) str = { return errors::strerror(err); }; // Structure representing dimensions of a terminal. export type ttysize = struct { rows: u16, columns: u16, }; hare-0.24.2/uuid/000077500000000000000000000000001464473310100134675ustar00rootroot00000000000000hare-0.24.2/uuid/README000066400000000000000000000002441464473310100143470ustar00rootroot00000000000000The uuid module implements RFC 4122-compatible Univerally Unique IDentifiers. This module only generates UUID4, aka "truly random" UUIDs, due to privacy concerns. hare-0.24.2/uuid/uuid.ha000066400000000000000000000110401464473310100147430ustar00rootroot00000000000000// SPDX-License-Identifier: MPL-2.0 // (c) Hare authors use bytes; use crypto::random; use endian; use fmt; use io; use memio; use strconv; use strings; // A UUID. export type uuid = [16]u8; // The length of a UUID in bytes. export def UUID_LEN: size = 16; // The length of a UUID in runes when encoded as a string. export def UUID_STRLEN: size = 36; // The length of the return value of [[uri]] in runes. export def UUID_URILEN: size = 45; // The "nil" UUID, with all bits set to zero. export const nil: uuid = [0...]; // Returned from [[decode]] if an invalid UUID is observed. export type invalid = !void; // Octet offsets of various fields as defined by the RFC. def TIME_LOW: size = 0; def TIME_MID: size = 4; def TIME_HI_AND_VERSION: size = 6; def CLOCK_SEQ_HI_AND_RESERVED: size = 8; def CLOCK_SEQ_LOW: size = 9; def NODE: size = 10; // Generates a new version 4 UUID. export fn generate() uuid = { let id: uuid = [0...]; random::buffer(id[..]); let buf = id[CLOCK_SEQ_HI_AND_RESERVED..CLOCK_SEQ_HI_AND_RESERVED + 2]; let clock = (endian::begetu16(buf) & 0x3FFF) | 0x8000; endian::beputu16(buf, clock); let buf = id[TIME_HI_AND_VERSION..TIME_HI_AND_VERSION + 2]; let version = (endian::begetu16(buf) & 0x0FFF) | 0x4000; endian::beputu16(buf, version); return id; }; // Returns true if two UUIDs are equal. export fn compare(a: uuid, b: uuid) bool = bytes::equal(a, b); // Encodes a UUID as a string and writes it to an I/O handle. export fn encode(out: io::handle, in: uuid) (size | io::error) = { let z = 0z; for (let i = TIME_LOW; i < TIME_LOW + 4; i += 1) { z += fmt::fprintf(out, "{:.2x}", in[i])?; }; z += fmt::fprintf(out, "-")?; for (let i = TIME_MID; i < TIME_MID + 2; i += 1) { z += fmt::fprintf(out, "{:.2x}", in[i])?; }; z += fmt::fprintf(out, "-")?; for (let i = TIME_HI_AND_VERSION; i < TIME_HI_AND_VERSION + 2; i += 1) { z += fmt::fprintf(out, "{:.2x}", in[i])?; }; z += fmt::fprintf(out, "-{:.2x}{:.2x}-", in[CLOCK_SEQ_HI_AND_RESERVED], in[CLOCK_SEQ_LOW])?; for (let i = NODE; i < NODE + 6; i += 1) { z += fmt::fprintf(out, "{:.2x}", in[i])?; }; return z; }; // Encodes a UUID as a URI and writes it to an I/O handle. export fn uri(out: io::handle, in: uuid) (size | io::error) = { return fmt::fprintf(out, "urn:uuid:")? + encode(out, in)?; }; // Encodes a UUID as a string. The return value is statically allocated, the // caller must use [[strings::dup]] to extend its lifetime. export fn encodestr(in: uuid) str = { static let buf: [UUID_STRLEN]u8 = [0...]; let sink = memio::fixed(buf); encode(&sink, in) as size; return memio::string(&sink)!; }; // Encodes a UUID as a string. The return value is statically allocated, the // caller must use [[strings::dup]] to extend its lifetime. export fn encodeuri(in: uuid) str = { static let buf: [UUID_URILEN]u8 = [0...]; let sink = memio::fixed(buf); uri(&sink, in) as size; return memio::string(&sink)!; }; @test fn encode() void = { let in: uuid = [ 0x3d, 0xed, 0x91, 0x0c, 0x80, 0x80, 0x4b, 0xc8, 0xaf, 0x39, 0xb6, 0xcc, 0xce, 0xe3, 0x67, 0x41, ]; assert(encodestr(in) == "3ded910c-8080-4bc8-af39-b6cccee36741"); }; // Decodes a UUID as a string from an [[io::handle]]. export fn decode(in: io::handle) (uuid | invalid | io::error) = { let u: uuid = [0...]; for (let i = 0z; i < len(u); i += 1) { let buf: [2]u8 = [0...]; match (io::readall(in, buf)?) { case io::EOF => return invalid; case let z: size => void; }; u[i] = match (strconv::stou8( strings::fromutf8_unsafe(buf), strconv::base::HEX)) { case strconv::overflow => abort(); case strconv::invalid => return invalid; case let u: u8 => yield u; }; if (i + 1 == TIME_MID || i + 1 == TIME_HI_AND_VERSION || i + 1 == CLOCK_SEQ_HI_AND_RESERVED || i + 1 == NODE) { match (io::readall(in, buf[..1])?) { case io::EOF => return invalid; case let z: size => void; }; if (buf[0] != '-') { return invalid; }; }; }; return u; }; // Decodes a UUID from a string. export fn decodestr(in: str) (uuid | invalid) = { let buf = memio::fixed(strings::toutf8(in)); match (decode(&buf)) { case let err: io::error => abort(); case invalid => return invalid; case let u: uuid => return u; }; }; @test fn decode() void = { let in = "3ded910c-8080-4bc8-af39-b6cccee36741"; let id = match (decodestr(in)) { case invalid => abort(); case let u: uuid => yield u; }; assert(compare(id, [ 0x3d, 0xed, 0x91, 0x0c, 0x80, 0x80, 0x4b, 0xc8, 0xaf, 0x39, 0xb6, 0xcc, 0xce, 0xe3, 0x67, 0x41, ])); assert(decodestr("hello world") is invalid); }; hare-0.24.2/wordexp/000077500000000000000000000000001464473310100142115ustar00rootroot00000000000000hare-0.24.2/wordexp/+test.ha000066400000000000000000000022421464473310100155550ustar00rootroot00000000000000// SPDX-License-Identifier: MIT // (c) Hare authors use os; use strings; fn streq(a: []str, b: []str) bool = { if (len(a) != len(b)) { return false; }; for (let i = 0z; i < len(a); i += 1) { if (a[i] != b[i]) { return false; }; }; return true; }; @test fn wordexp() void = { os::setenv("TESTVAR", "test value")!; os::unsetenv("UNSET")!; static const cases: [_](str, []str) = [ (``, []), (" \t\n", []), (`hello world`, ["hello", "world"]), (`hello $TESTVAR`, ["hello", "test", "value"]), (`hello "$TESTVAR"`, ["hello", "test value"]), (`hello $(echo world)`, ["hello", "world"]), (`hello $((2+2))`, ["hello", "4"]), (`hello $UNSET`, ["hello"]), ]; for (let i = 0z; i < len(cases); i += 1) { const (in, out) = cases[i]; const words = wordexp(in)!; defer strings::freeall(words); assert(streq(words, out)); }; }; @test fn wordexp_error() void = { os::unsetenv("UNSET")!; static const cases: [_](str, flag) = [ (`hello $UNSET`, flag::UNDEF), (`hello $(`, 0), ]; for (let i = 0z; i < len(cases); i += 1) { const (in, flag) = cases[i]; const result = wordexp(in, flag); assert(result is sh_error); }; }; hare-0.24.2/wordexp/README000066400000000000000000000010101464473310100150610ustar00rootroot00000000000000The wordexp module implements word expansion using shell semantics, similar to POSIX wordexp(3). Word expansion is performed with the platform-specific system shell, which is generally POSIX sh(1) compatible on Unix-like systems. When used with a POSIX shell, the IFS variable is unconditionally unset in the environment, causing the shell to assume the default value of " \t\n". Note that, by design, this module runs arbitrary shell commands from user-supplied inputs. It must only be used in a trusted environment. hare-0.24.2/wordexp/error.ha000066400000000000000000000013041464473310100156520ustar00rootroot00000000000000// SPDX-License-Identifier: MIT // (c) Hare authors use encoding::utf8; use io; use os::exec; // Tagged union of possible wordexp error conditions. export type error = !(io::error | exec::error | utf8::invalid | sh_error); // An error occured during shell expansion. export type sh_error = !void; // Converts an [[error]] to a human-friendly string. export fn strerror(err: error) const str = { match (err) { case let err: io::error => return io::strerror(err); case let err: exec::error => return exec::strerror(err); case utf8::invalid => return "Word expansion returned invalid UTF-8 data"; case sh_error => return "An error occured during shell expansion"; }; }; hare-0.24.2/wordexp/wordexp.ha000066400000000000000000000036021464473310100162140ustar00rootroot00000000000000// SPDX-License-Identifier: MIT // (c) Hare authors // (c) 2005-2020 Rich Felker, et al // Based on the musl libc implementation use bufio; use io; use os; use os::exec; use strings; // Flags applicable to a [[wordexp]] operation. export type flag = enum uint { NONE = 0, // DOOFFS = (1 << 0), // not implemented // APPEND = (1 << 1), // not implemented // REUSE = (1 << 3), // not implemented // NOCMD = (1 << 2), // not implemented SHOWERR = (1 << 4), UNDEF = (1 << 5), }; // Performs shell expansion and word splitting on the provided string, returning // a list of expanded words, similar to POSIX wordexp(3). Note that this // function, by design, will execute arbitrary commands from the input string. // // Pass the return value to [[strings::freeall]] to free resources associated // with the return value. export fn wordexp(s: str, flags: flag = flag::NONE) ([]str | error) = { const (rd, wr) = exec::pipe(); // "x" is added to handle the list of expanded words being empty const cmd = exec::cmd("/bin/sh", if (flags & flag::UNDEF != 0) "-uc" else "-c", `eval "printf %s\\\\0 x $1"`, "sh", s)!; exec::unsetenv(&cmd, "IFS")!; exec::addfile(&cmd, os::stdout_file, wr); if (flags & flag::SHOWERR == 0) { exec::addfile(&cmd, os::stderr_file, exec::nullfd); }; const child = exec::start(&cmd)!; io::close(wr)!; const scan = bufio::newscanner(rd); defer bufio::finish(&scan); match (bufio::scan_string(&scan, "\0")?) { case io::EOF => return sh_error; case => void; // Discard the first "x" argument }; let words: []str = []; for (true) { match (bufio::scan_string(&scan, "\0")?) { case io::EOF => break; case let word: const str => append(words, strings::dup(word)); }; }; io::close(rd)!; const st = exec::wait(&child)!; match (exec::check(&st)) { case !exec::exit_status => return sh_error; case void => return words; }; };