From 6929baf0de36ca4f46da0ad56d847f5ec984008a Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 10:33:57 +0000 Subject: [PATCH 01/18] README.md: expand overview --- README.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 221b337..a868b49 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://api.travis-ci.org/JehanneOS/jehanne.svg?branch=master)](https://travis-ci.org/JehanneOS/jehanne) + # Jehanne Jehanne is a [simple][simplicity] operating system. @@ -7,10 +9,72 @@ It is a fork of [Harvey][harvey] (which in turn is a fork of diverges from the design and conventions of its ancestors whenever they are at odds with its goals. -For this reason project is named after the famous Franch heretic [Joan of Arc][arc]. +For this reason the project is named after the famous Franch heretic [Joan of Arc][arc]. + +## Overview + +This is the main repository, used to build the system as a whole: + +- [arch](./arch/) contains one folder for each + supported architecture, with specific C headers and binaries +- [sys](./sys) is the system folder + * [include](./sys/include) contains portable C headers + * [lib](./sys/lib) contains data and scripts used by the + running system + * [man](./sys/man) contains manual pages + * [src](./sys/src) contains the sources of the system +- [doc](./doc/) contains useful documentation for Jehanne + development + * [license](./doc/license/) contains detailed info + about Jehanne [licenses][lic] + * [hacking](./doc/hacking/) contains details about how + to build and modify Jehanne +- [hacking](./hacking) contains the utilities used to + develop Jehanne +- [qa](./qa) contains the regression tests +- [mnt](./mnt) contains default mount targets +- [usr](./usr) contains the users' folders +- [pkgs](./pkgs) will contains the installed packages + +The running system also includes supplemental folders like `/lib`, +`/bin` and `/dev` that are bound during the boot as required. + +## Build + +To build Jehanne and play with it, you need to have git, golang, qemu, +gcc, binutils and bison installed. +For example on Debian GNU/Linux you should be able to get going with + + sudo aptitude install git golang build-essential bison qemu-system + +After the repository clone, you can give a look with + + git submodule init # we have a lot of submodules + git submodule update --init --recursive + ./hacking/devshell.sh # start a shell with appropriate environment + ./hacking/continuous-build.sh # to build everything + ./hacking/runOver9P.sh # to start the system in QEMU + ./hacking/drawterm.sh # to connect Jehanne with drawterm + +## Hacking + +Jehanne is a work in progress. +Forks and pull requests are welcome. + +In [doc/hacking](./doc/hacking/) you will find all you +need to know about its principles, design and weirdness. + +There's a lot of work to do, in every area of the system. + +To coordinate our efforts, we use the github issues. +To discuss (and even debate) about the design and development of Jehanne +we use the [JehanneOS mailing list][mailinglist]: please join and present +yourself and your attitudes. [simplicity]: http://plato.stanford.edu/entries/simplicity/ "What is simplicity?" [harvey]: http://harvey-os.org "Harvey OS" [plan9]: https://github.com/brho/plan9 "UC Berkeley release of Plan 9 under the GPLv2" [nix]: https://github.com/rminnich/nix-os [arc]: https://en.wikipedia.org/wiki/Joan_of_Arc "Jeanne d'Arc" +[lic]: ./LICENSE.md "A summary of Jehanne licensing" +[mailinglist]: https://groups.google.com/forum/#!forum/jehanneos From b5fcad4e29bf04eb767c2c47f5d21eef27ef69a8 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 10:38:12 +0000 Subject: [PATCH 02/18] Add devtools (as submodule) in hacking/ --- .gitmodules | 4 ++++ hacking | 1 + 2 files changed, 5 insertions(+) create mode 100644 .gitmodules create mode 160000 hacking diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9b69754 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "hacking"] + path = hacking + url = https://github.com/JehanneOS/devtools.git + branch = master diff --git a/hacking b/hacking new file mode 160000 index 0000000..0f95361 --- /dev/null +++ b/hacking @@ -0,0 +1 @@ +Subproject commit 0f953617d1713d922233b5fcfedd84bfe65a06e2 From 1a83ae4cc53173e3060ddc66b840cfea97f58949 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 10:49:17 +0000 Subject: [PATCH 03/18] devtools: update ref --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index 0f95361..ab6ec66 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit 0f953617d1713d922233b5fcfedd84bfe65a06e2 +Subproject commit ab6ec669ba565aa1e5d53cd4a64964884db36fb3 From a634ef3b34d0b2b4233815355824f4c433525f24 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 10:52:39 +0000 Subject: [PATCH 04/18] README.md: fix submodule initialization --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a868b49..3f15fae 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,12 @@ For example on Debian GNU/Linux you should be able to get going with After the repository clone, you can give a look with - git submodule init # we have a lot of submodules - git submodule update --init --recursive - ./hacking/devshell.sh # start a shell with appropriate environment - ./hacking/continuous-build.sh # to build everything - ./hacking/runOver9P.sh # to start the system in QEMU - ./hacking/drawterm.sh # to connect Jehanne with drawterm + git submodule init # we have a lot of submodules + git submodule update --init --recursive --remote + ./hacking/devshell.sh # start a shell with appropriate environment + ./hacking/continuous-build.sh # to build everything + ./hacking/runOver9P.sh # to start the system in QEMU + ./hacking/drawterm.sh # to connect Jehanne with drawterm ## Hacking From fc42b02a283154d0c4684085b7bcc02540f17f52 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 11:40:34 +0000 Subject: [PATCH 05/18] Add arch/amd64 PRO MEMORIA: in arch/amd64/include/ureg.h the commented registers are preserved. They were removed at https://github.com/Harvey-OS/harvey/commit/6ab2e16c9f1058aab427f79d4516d281c8e6039b but apparently the es register is used by vesavga (386 version) in both Plan9, 9front and 9atom. --- arch/amd64/bin/auth/disable | 5 ++ arch/amd64/bin/auth/enable | 5 ++ arch/amd64/bin/auth/status | 36 +++++++++++++ arch/amd64/include/cflags.json | 28 ++++++++++ arch/amd64/include/u.h | 97 ++++++++++++++++++++++++++++++++++ arch/amd64/include/ureg.h | 42 +++++++++++++++ 6 files changed, 213 insertions(+) create mode 100755 arch/amd64/bin/auth/disable create mode 100755 arch/amd64/bin/auth/enable create mode 100755 arch/amd64/bin/auth/status create mode 100644 arch/amd64/include/cflags.json create mode 100644 arch/amd64/include/u.h create mode 100644 arch/amd64/include/ureg.h diff --git a/arch/amd64/bin/auth/disable b/arch/amd64/bin/auth/disable new file mode 100755 index 0000000..7ef7149 --- /dev/null +++ b/arch/amd64/bin/auth/disable @@ -0,0 +1,5 @@ +#!/bin/rc +if(test -e /mnt/keys/$1) + echo -n disabled > /mnt/keys/$1/status +if(test -e /mnt/netkeys/$1) + echo -n disabled > /mnt/netkeys/$1/status diff --git a/arch/amd64/bin/auth/enable b/arch/amd64/bin/auth/enable new file mode 100755 index 0000000..f7a9118 --- /dev/null +++ b/arch/amd64/bin/auth/enable @@ -0,0 +1,5 @@ +#!/bin/rc +if(test -e /mnt/keys/$1) + echo -n ok > /mnt/keys/$1/status +if(test -e /mnt/netkeys/$1) + echo -n ok > /mnt/netkeys/$1/status diff --git a/arch/amd64/bin/auth/status b/arch/amd64/bin/auth/status new file mode 100755 index 0000000..4dc0323 --- /dev/null +++ b/arch/amd64/bin/auth/status @@ -0,0 +1,36 @@ +#!/bin/rc +cd /mnt/keys/$1 > /dev/null >[2=1] && { + stat=`{cat status} + exp=`{cat expire} + switch($exp){ + case never 0 + exp='never expires' + case * + exp=(expires on `{date $exp}) + } + switch($stat){ + case expired + echo user $1: plan 9 key has expired + case * + echo user $1: plan 9 key status is $stat and $exp + } + grep '^'$1'[ ]' /adm/keys.who | tail -1 +} +cd /mnt/netkeys/$1 > /dev/null >[2=1] && { + stat=`{cat status} + exp=`{cat expire} + switch($exp){ + case never 0 + exp='never expires' + case * + exp=(expires on `{date $exp}) + } + switch($stat){ + case expired + echo user $1: network key has expired + case * + echo user $1: network key status is $stat and $exp + auth/printnetkey $1 + } + grep '^'$1'[ ]' /adm/netkeys.who | tail -1 +} diff --git a/arch/amd64/include/cflags.json b/arch/amd64/include/cflags.json new file mode 100644 index 0000000..c824bda --- /dev/null +++ b/arch/amd64/include/cflags.json @@ -0,0 +1,28 @@ +{ + "buildflags": { + "Cflags": [ + "-std=c11", + "-c", + "-I/$JEHANNE/arch/$ARCH/include", + "-I/$JEHANNE/sys/include", + "-I.", + "-ffreestanding", + "-fno-builtin", + "-fno-omit-frame-pointer", + "-fplan9-extensions", + "-fvar-tracking", + "-fvar-tracking-assignments", + "-g", + "-gdwarf-2", + "-ggdb", + "-mcmodel=small", + "-mno-red-zone", + "-O0", + "-static", + "-Wall", + "-Wno-missing-braces", + "-Wno-parentheses", + "-Wno-unknown-pragmas" + ] + } +} diff --git a/arch/amd64/include/u.h b/arch/amd64/include/u.h new file mode 100644 index 0000000..43a05ac --- /dev/null +++ b/arch/amd64/include/u.h @@ -0,0 +1,97 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#define nil ((void*)0) +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef unsigned int uint; +typedef signed int int32_t; +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef uint64_t uintptr; +typedef uint64_t uintptr_t; +typedef uint32_t usize; +typedef int64_t size_t; +typedef uint32_t Rune; +typedef union FPdbleword FPdbleword; +typedef uintptr jmp_buf[10]; // for registers. + +#define JMPBUFSP 6 +#define JMPBUFPC 7 +#define JMPBUFARG1 8 +#define JMPBUFARG2 9 + +#define JMPBUFDPC 0 +typedef unsigned int mpdigit; /* for /sys/include/mp.h */ + +/* MXCSR */ +/* fcr */ +#define FPFTZ (1<<15) /* amd64 */ +#define FPINEX (1<<12) +#define FPUNFL (1<<11) +#define FPOVFL (1<<10) +#define FPZDIV (1<<9) +#define FPDNRM (1<<8) /* amd64 */ +#define FPINVAL (1<<7) +#define FPDAZ (1<<6) /* amd64 */ +#define FPRNR (0<<13) +#define FPRZ (3<<13) +#define FPRPINF (2<<13) +#define FPRNINF (1<<13) +#define FPRMASK (3<<13) +#define FPPEXT 0 +#define FPPSGL 0 +#define FPPDBL 0 +#define FPPMASK 0 +/* fsr */ +#define FPAINEX (1<<5) +#define FPAUNFL (1<<4) +#define FPAOVFL (1<<3) +#define FPAZDIV (1<<2) +#define FPADNRM (1<<1) /* not in plan 9 */ +#define FPAINVAL (1<<0) +union FPdbleword +{ + double x; + struct { /* little endian */ + uint lo; + uint hi; + }; +}; + +/* +#if 0 +typedef char* va_list; +#define va_start(list, start) list =\ + (sizeof(start) < 8?\ + (char*)((int64_t*)&(start)+1):\ + (char*)(&(start)+1)) +#define va_end(list)\ + USED(list) +#define va_arg(list, mode)\ + ((sizeof(mode) == 1)?\ + ((list += 8), (mode*)list)[-8]:\ + (sizeof(mode) == 2)?\ + ((list += 8), (mode*)list)[-4]:\ + (sizeof(mode) == 4)?\ + ((list += 8), (mode*)list)[-2]:\ + ((list += sizeof(mode)), (mode*)list)[-1]) +#endif +*/ + +typedef __builtin_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(v,l) __builtin_va_copy(v,l) + diff --git a/arch/amd64/include/ureg.h b/arch/amd64/include/ureg.h new file mode 100644 index 0000000..d1b17bd --- /dev/null +++ b/arch/amd64/include/ureg.h @@ -0,0 +1,42 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +struct Ureg { + uint64_t ax; + uint64_t bx; + uint64_t cx; + uint64_t dx; + uint64_t si; + uint64_t di; + uint64_t bp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + // these are pointless and I don't want to waste a second on them. + // I'm sure it will break something but let's see. + // Not pushing them simplifies the interrupt handler a lot. + // uint16_t ds; + // uint16_t es; + // uint16_t fs; + // uint16_t gs; + + uint64_t type; + uint64_t error; /* error code (or zero) */ + uint64_t ip; /* pc */ + uint64_t cs; /* old context */ + uint64_t flags; /* old flags */ + uint64_t sp; /* sp */ + uint64_t ss; /* old stack segment */ +}; From bbf498c38e334fb3652f1b7e5afbea49f46cdd5b Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 11:46:42 +0000 Subject: [PATCH 06/18] Added root folders mnt/ pkgs/ and tmp/ --- mnt/acme/.gitignore | 2 ++ mnt/temp/.gitignore | 2 ++ mnt/term/.gitignore | 2 ++ mnt/wsys/.gitignore | 2 ++ pkgs/.gitignore | 3 +++ pkgs/README.md | 6 ++++++ tmp/.gitignore | 2 ++ 7 files changed, 19 insertions(+) create mode 100644 mnt/acme/.gitignore create mode 100644 mnt/temp/.gitignore create mode 100644 mnt/term/.gitignore create mode 100644 mnt/wsys/.gitignore create mode 100644 pkgs/.gitignore create mode 100644 pkgs/README.md create mode 100644 tmp/.gitignore diff --git a/mnt/acme/.gitignore b/mnt/acme/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/mnt/acme/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/mnt/temp/.gitignore b/mnt/temp/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/mnt/temp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/mnt/term/.gitignore b/mnt/term/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/mnt/term/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/mnt/wsys/.gitignore b/mnt/wsys/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/mnt/wsys/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/pkgs/.gitignore b/pkgs/.gitignore new file mode 100644 index 0000000..7c9d611 --- /dev/null +++ b/pkgs/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!README.md diff --git a/pkgs/README.md b/pkgs/README.md new file mode 100644 index 0000000..2ecac01 --- /dev/null +++ b/pkgs/README.md @@ -0,0 +1,6 @@ +# Jehanne packages + +In this folder you find the packages installed in your system. + +For each installed package you find a folder named after the package. +Inside such folder you find one folder for each version installed. diff --git a/tmp/.gitignore b/tmp/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/tmp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From e4ebd7eace5837d0917b8c7d21d7ff845b859407 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 11:49:55 +0000 Subject: [PATCH 07/18] travis-ci: add first .travis.yml --- .travis.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c905938 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,31 @@ +language: c +install: + - git submodule init + - git submodule update --init --recursive --remote +script: + - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./hacking/continuous-build.sh; fi +compiler: + - gcc-4.8 + +env: + global: + - ARCH=amd64 + - JEHANNE=$TRAVIS_BUILD_DIR + - PATH=$PATH:$JEHANNE/hacking/bin + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - rc + - gcc-4.8 + coverity_scan: + project: + name: "JehanneOS/jehanne" + description: "Build submitted via Travis CI" + notification_email: jehanneos@googlegroups.com + build_command_prepend: "git submodule init && git submodule update --init --recursive" + build_command: "./hacking/coverity-scan.sh" + branch_pattern: coverity_scan + From 3925b61fa655d510c9281083b312b9e8b6b9b4f7 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 11:55:44 +0000 Subject: [PATCH 08/18] libc: initial import from Harvey Note that libc is what distinguish "native" software from "non-native" in Jehanne: further C libraries can be ported to Jehanne, but this libc will remain the main building block of the system. Also note that a few files have not been ported from Harvey: - 9sys/pushtls.c - port/rijndael.c - port/rijndael.tbl - port/sha2.c Pushtls.c depends on libmp and libsec so libc is not the appropriate place for it. The other three will be moved to libsec. --- sys/include/ctype.h | 38 + sys/include/fcall.h | 149 ++ sys/include/libc.h | 763 +++++++++ sys/include/pool.h | 64 + sys/include/tos.h | 29 + sys/src/klib.json | 32 + sys/src/klibs.json | 7 + sys/src/lib.json | 16 + sys/src/libc/9sys/access.c | 42 + sys/src/libc/9sys/announce.c | 284 ++++ sys/src/libc/9sys/awakened.c | 50 + sys/src/libc/9sys/convD2M.c | 104 ++ sys/src/libc/9sys/convM2D.c | 103 ++ sys/src/libc/9sys/convM2S.c | 324 ++++ sys/src/libc/9sys/convS2M.c | 398 +++++ sys/src/libc/9sys/cputime.c | 25 + sys/src/libc/9sys/ctime.c | 316 ++++ sys/src/libc/9sys/dial.c | 560 +++++++ sys/src/libc/9sys/dirfstat.c | 46 + sys/src/libc/9sys/dirfwstat.c | 28 + sys/src/libc/9sys/dirmodefmt.c | 57 + sys/src/libc/9sys/dirread.c | 106 ++ sys/src/libc/9sys/dirstat.c | 46 + sys/src/libc/9sys/dirwstat.c | 28 + sys/src/libc/9sys/fcallfmt.c | 244 +++ sys/src/libc/9sys/fork.c | 17 + sys/src/libc/9sys/getenv.c | 45 + sys/src/libc/9sys/getnetconninfo.c | 142 ++ sys/src/libc/9sys/getpid.c | 26 + sys/src/libc/9sys/getppid.c | 26 + sys/src/libc/9sys/getwd.c | 26 + sys/src/libc/9sys/iounit.c | 36 + sys/src/libc/9sys/nulldir.c | 18 + sys/src/libc/9sys/postnote.c | 41 + sys/src/libc/9sys/privalloc.c | 54 + sys/src/libc/9sys/pushssl.c | 53 + sys/src/libc/9sys/putenv.c | 35 + sys/src/libc/9sys/qlock.c | 633 ++++++++ sys/src/libc/9sys/read.c | 26 + sys/src/libc/9sys/read9pmsg.c | 40 + sys/src/libc/9sys/readv.c | 58 + sys/src/libc/9sys/rerrstr.c | 22 + sys/src/libc/9sys/sbrk.c | 44 + sys/src/libc/9sys/setnetmtpt.c | 25 + sys/src/libc/9sys/sleep.c | 31 + sys/src/libc/9sys/sysfatal.c | 37 + sys/src/libc/9sys/syslog.c | 125 ++ sys/src/libc/9sys/sysname.c | 30 + sys/src/libc/9sys/time.c | 22 + sys/src/libc/9sys/times.c | 69 + sys/src/libc/9sys/tm2sec.c | 203 +++ sys/src/libc/9sys/truerand.c | 26 + sys/src/libc/9sys/wait.c | 41 + sys/src/libc/9sys/waitpid.c | 30 + sys/src/libc/9sys/werrstr.c | 23 + sys/src/libc/9sys/write.c | 26 + sys/src/libc/9sys/writev.c | 51 + sys/src/libc/9syscall/.gitignore | 3 + sys/src/libc/9syscall/9syscall.json | 8 + sys/src/libc/amd64/argv0.c | 9 + sys/src/libc/amd64/atom.S | 86 ++ sys/src/libc/amd64/cycles.c | 11 + sys/src/libc/amd64/main9.S | 32 + sys/src/libc/amd64/notejmp.c | 16 + sys/src/libc/amd64/rdpmc.c | 9 + sys/src/libc/amd64/setjmp.s | 39 + sys/src/libc/amd64/sqrt.s | 5 + sys/src/libc/amd64/tas.s | 10 + sys/src/libc/build.json | 255 +++ sys/src/libc/fmt/dofmt.c | 539 +++++++ sys/src/libc/fmt/dorfmt.c | 54 + sys/src/libc/fmt/errfmt.c | 21 + sys/src/libc/fmt/fltfmt.c | 327 ++++ sys/src/libc/fmt/fmt.c | 227 +++ sys/src/libc/fmt/fmtdef.h | 94 ++ sys/src/libc/fmt/fmtfd.c | 40 + sys/src/libc/fmt/fmtlock.c | 25 + sys/src/libc/fmt/fmtprint.c | 30 + sys/src/libc/fmt/fmtquote.c | 259 ++++ sys/src/libc/fmt/fmtrune.c | 34 + sys/src/libc/fmt/fmtstr.c | 20 + sys/src/libc/fmt/fmtvprint.c | 39 + sys/src/libc/fmt/fprint.c | 23 + sys/src/libc/fmt/print.c | 23 + sys/src/libc/fmt/runefmtstr.c | 20 + sys/src/libc/fmt/runeseprint.c | 23 + sys/src/libc/fmt/runesmprint.c | 23 + sys/src/libc/fmt/runesnprint.c | 24 + sys/src/libc/fmt/runesprint.c | 23 + sys/src/libc/fmt/runevseprint.c | 34 + sys/src/libc/fmt/runevsmprint.c | 83 + sys/src/libc/fmt/runevsnprint.c | 33 + sys/src/libc/fmt/seprint.c | 23 + sys/src/libc/fmt/smprint.c | 24 + sys/src/libc/fmt/snprint.c | 24 + sys/src/libc/fmt/sprint.c | 23 + sys/src/libc/fmt/vfprint.c | 45 + sys/src/libc/fmt/vseprint.c | 34 + sys/src/libc/fmt/vsmprint.c | 85 + sys/src/libc/fmt/vsnprint.c | 33 + sys/src/libc/klibc.json | 255 +++ sys/src/libc/port/_assert.c | 22 + sys/src/libc/port/abs.c | 27 + sys/src/libc/port/asin.c | 49 + sys/src/libc/port/atan.c | 87 ++ sys/src/libc/port/atan2.c | 33 + sys/src/libc/port/atexit.c | 69 + sys/src/libc/port/atnotify.c | 67 + sys/src/libc/port/atof.c | 17 + sys/src/libc/port/atol.c | 62 + sys/src/libc/port/atoll.c | 17 + sys/src/libc/port/charstod.c | 90 ++ sys/src/libc/port/cistrcmp.c | 35 + sys/src/libc/port/cistrncmp.c | 37 + sys/src/libc/port/cistrstr.c | 32 + sys/src/libc/port/cleanname.c | 106 ++ sys/src/libc/port/crypt.c | 77 + sys/src/libc/port/ctype.c | 34 + sys/src/libc/port/encodefmt.c | 86 ++ sys/src/libc/port/execl.c | 39 + sys/src/libc/port/exp.c | 49 + sys/src/libc/port/fabs.c | 20 + sys/src/libc/port/floor.c | 36 + sys/src/libc/port/fmod.c | 40 + sys/src/libc/port/frand.c | 26 + sys/src/libc/port/frexp.c | 129 ++ sys/src/libc/port/getcallerpc.c | 17 + sys/src/libc/port/getfields.c | 46 + sys/src/libc/port/getuser.c | 30 + sys/src/libc/port/hangup.c | 21 + sys/src/libc/port/hypot.c | 50 + sys/src/libc/port/lnrand.c | 27 + sys/src/libc/port/lock.c | 67 + sys/src/libc/port/log.c | 67 + sys/src/libc/port/lrand.c | 92 ++ sys/src/libc/port/malloc.c | 337 ++++ sys/src/libc/port/memccpy.c | 28 + sys/src/libc/port/memchr.c | 26 + sys/src/libc/port/memcmp.c | 32 + sys/src/libc/port/memmove.c | 45 + sys/src/libc/port/memset.c | 24 + sys/src/libc/port/mktemp.c | 40 + sys/src/libc/port/muldiv.c | 47 + sys/src/libc/port/nan.c | 63 + sys/src/libc/port/needsrcquote.c | 21 + sys/src/libc/port/netmkaddr.c | 61 + sys/src/libc/port/nrand.c | 30 + sys/src/libc/port/ntruerand.c | 32 + sys/src/libc/port/perror.c | 24 + sys/src/libc/port/pool.c | 1471 ++++++++++++++++++ sys/src/libc/port/pow.c | 78 + sys/src/libc/port/pow10.c | 58 + sys/src/libc/port/qsort.c | 133 ++ sys/src/libc/port/quote.c | 146 ++ sys/src/libc/port/rand.c | 17 + sys/src/libc/port/readn.c | 31 + sys/src/libc/port/reduce | 16 + sys/src/libc/port/rune.c | 173 +++ sys/src/libc/port/runebase.c | 1967 ++++++++++++++++++++++++ sys/src/libc/port/runebsearch.c | 31 + sys/src/libc/port/runestrcat.c | 19 + sys/src/libc/port/runestrchr.c | 29 + sys/src/libc/port/runestrcmp.c | 29 + sys/src/libc/port/runestrcpy.c | 22 + sys/src/libc/port/runestrdup.c | 24 + sys/src/libc/port/runestrecpy.c | 26 + sys/src/libc/port/runestrlen.c | 18 + sys/src/libc/port/runestrncat.c | 26 + sys/src/libc/port/runestrncmp.c | 31 + sys/src/libc/port/runestrncpy.c | 27 + sys/src/libc/port/runestrrchr.c | 24 + sys/src/libc/port/runestrstr.c | 38 + sys/src/libc/port/runetype.c | 15 + sys/src/libc/port/runetypebody-6.2.0.h | 1650 ++++++++++++++++++++ sys/src/libc/port/sin.c | 77 + sys/src/libc/port/sinh.c | 71 + sys/src/libc/port/strcat.c | 19 + sys/src/libc/port/strchr.c | 29 + sys/src/libc/port/strcmp.c | 29 + sys/src/libc/port/strcpy.c | 25 + sys/src/libc/port/strcspn.c | 31 + sys/src/libc/port/strdup.c | 24 + sys/src/libc/port/strecpy.c | 26 + sys/src/libc/port/strlen.c | 18 + sys/src/libc/port/strncat.c | 28 + sys/src/libc/port/strncmp.c | 31 + sys/src/libc/port/strncpy.c | 27 + sys/src/libc/port/strpbrk.c | 31 + sys/src/libc/port/strrchr.c | 24 + sys/src/libc/port/strspn.c | 28 + sys/src/libc/port/strstr.c | 38 + sys/src/libc/port/strtod.c | 530 +++++++ sys/src/libc/port/strtok.c | 39 + sys/src/libc/port/strtol.c | 110 ++ sys/src/libc/port/strtoll.c | 110 ++ sys/src/libc/port/strtoul.c | 106 ++ sys/src/libc/port/strtoull.c | 106 ++ sys/src/libc/port/tan.c | 76 + sys/src/libc/port/tanh.c | 34 + sys/src/libc/port/tokenize.c | 116 ++ sys/src/libc/port/toupper.c | 28 + sys/src/libc/port/u16.c | 62 + sys/src/libc/port/u32.c | 119 ++ sys/src/libc/port/u64.c | 136 ++ sys/src/libc/port/utfecpy.c | 30 + sys/src/libc/port/utflen.c | 31 + sys/src/libc/port/utfnlen.c | 35 + sys/src/libc/port/utfrrune.c | 39 + sys/src/libc/port/utfrune.c | 38 + sys/src/libc/port/utfutf.c | 35 + sys/src/libs.json | 7 + sys/src/sysconf.json | 702 +++++++++ 212 files changed, 20644 insertions(+) create mode 100644 sys/include/ctype.h create mode 100644 sys/include/fcall.h create mode 100644 sys/include/libc.h create mode 100644 sys/include/pool.h create mode 100644 sys/include/tos.h create mode 100644 sys/src/klib.json create mode 100644 sys/src/klibs.json create mode 100644 sys/src/lib.json create mode 100644 sys/src/libc/9sys/access.c create mode 100644 sys/src/libc/9sys/announce.c create mode 100644 sys/src/libc/9sys/awakened.c create mode 100644 sys/src/libc/9sys/convD2M.c create mode 100644 sys/src/libc/9sys/convM2D.c create mode 100644 sys/src/libc/9sys/convM2S.c create mode 100644 sys/src/libc/9sys/convS2M.c create mode 100644 sys/src/libc/9sys/cputime.c create mode 100644 sys/src/libc/9sys/ctime.c create mode 100644 sys/src/libc/9sys/dial.c create mode 100644 sys/src/libc/9sys/dirfstat.c create mode 100644 sys/src/libc/9sys/dirfwstat.c create mode 100644 sys/src/libc/9sys/dirmodefmt.c create mode 100644 sys/src/libc/9sys/dirread.c create mode 100644 sys/src/libc/9sys/dirstat.c create mode 100644 sys/src/libc/9sys/dirwstat.c create mode 100644 sys/src/libc/9sys/fcallfmt.c create mode 100644 sys/src/libc/9sys/fork.c create mode 100644 sys/src/libc/9sys/getenv.c create mode 100644 sys/src/libc/9sys/getnetconninfo.c create mode 100644 sys/src/libc/9sys/getpid.c create mode 100644 sys/src/libc/9sys/getppid.c create mode 100644 sys/src/libc/9sys/getwd.c create mode 100644 sys/src/libc/9sys/iounit.c create mode 100644 sys/src/libc/9sys/nulldir.c create mode 100644 sys/src/libc/9sys/postnote.c create mode 100644 sys/src/libc/9sys/privalloc.c create mode 100644 sys/src/libc/9sys/pushssl.c create mode 100644 sys/src/libc/9sys/putenv.c create mode 100644 sys/src/libc/9sys/qlock.c create mode 100644 sys/src/libc/9sys/read.c create mode 100644 sys/src/libc/9sys/read9pmsg.c create mode 100644 sys/src/libc/9sys/readv.c create mode 100644 sys/src/libc/9sys/rerrstr.c create mode 100644 sys/src/libc/9sys/sbrk.c create mode 100644 sys/src/libc/9sys/setnetmtpt.c create mode 100644 sys/src/libc/9sys/sleep.c create mode 100644 sys/src/libc/9sys/sysfatal.c create mode 100644 sys/src/libc/9sys/syslog.c create mode 100644 sys/src/libc/9sys/sysname.c create mode 100644 sys/src/libc/9sys/time.c create mode 100644 sys/src/libc/9sys/times.c create mode 100644 sys/src/libc/9sys/tm2sec.c create mode 100644 sys/src/libc/9sys/truerand.c create mode 100644 sys/src/libc/9sys/wait.c create mode 100644 sys/src/libc/9sys/waitpid.c create mode 100644 sys/src/libc/9sys/werrstr.c create mode 100644 sys/src/libc/9sys/write.c create mode 100644 sys/src/libc/9sys/writev.c create mode 100644 sys/src/libc/9syscall/.gitignore create mode 100644 sys/src/libc/9syscall/9syscall.json create mode 100644 sys/src/libc/amd64/argv0.c create mode 100644 sys/src/libc/amd64/atom.S create mode 100644 sys/src/libc/amd64/cycles.c create mode 100644 sys/src/libc/amd64/main9.S create mode 100644 sys/src/libc/amd64/notejmp.c create mode 100644 sys/src/libc/amd64/rdpmc.c create mode 100644 sys/src/libc/amd64/setjmp.s create mode 100644 sys/src/libc/amd64/sqrt.s create mode 100644 sys/src/libc/amd64/tas.s create mode 100644 sys/src/libc/build.json create mode 100644 sys/src/libc/fmt/dofmt.c create mode 100644 sys/src/libc/fmt/dorfmt.c create mode 100644 sys/src/libc/fmt/errfmt.c create mode 100644 sys/src/libc/fmt/fltfmt.c create mode 100644 sys/src/libc/fmt/fmt.c create mode 100644 sys/src/libc/fmt/fmtdef.h create mode 100644 sys/src/libc/fmt/fmtfd.c create mode 100644 sys/src/libc/fmt/fmtlock.c create mode 100644 sys/src/libc/fmt/fmtprint.c create mode 100644 sys/src/libc/fmt/fmtquote.c create mode 100644 sys/src/libc/fmt/fmtrune.c create mode 100644 sys/src/libc/fmt/fmtstr.c create mode 100644 sys/src/libc/fmt/fmtvprint.c create mode 100644 sys/src/libc/fmt/fprint.c create mode 100644 sys/src/libc/fmt/print.c create mode 100644 sys/src/libc/fmt/runefmtstr.c create mode 100644 sys/src/libc/fmt/runeseprint.c create mode 100644 sys/src/libc/fmt/runesmprint.c create mode 100644 sys/src/libc/fmt/runesnprint.c create mode 100644 sys/src/libc/fmt/runesprint.c create mode 100644 sys/src/libc/fmt/runevseprint.c create mode 100644 sys/src/libc/fmt/runevsmprint.c create mode 100644 sys/src/libc/fmt/runevsnprint.c create mode 100644 sys/src/libc/fmt/seprint.c create mode 100644 sys/src/libc/fmt/smprint.c create mode 100644 sys/src/libc/fmt/snprint.c create mode 100644 sys/src/libc/fmt/sprint.c create mode 100644 sys/src/libc/fmt/vfprint.c create mode 100644 sys/src/libc/fmt/vseprint.c create mode 100644 sys/src/libc/fmt/vsmprint.c create mode 100644 sys/src/libc/fmt/vsnprint.c create mode 100644 sys/src/libc/klibc.json create mode 100644 sys/src/libc/port/_assert.c create mode 100644 sys/src/libc/port/abs.c create mode 100644 sys/src/libc/port/asin.c create mode 100644 sys/src/libc/port/atan.c create mode 100644 sys/src/libc/port/atan2.c create mode 100644 sys/src/libc/port/atexit.c create mode 100644 sys/src/libc/port/atnotify.c create mode 100644 sys/src/libc/port/atof.c create mode 100644 sys/src/libc/port/atol.c create mode 100644 sys/src/libc/port/atoll.c create mode 100644 sys/src/libc/port/charstod.c create mode 100644 sys/src/libc/port/cistrcmp.c create mode 100644 sys/src/libc/port/cistrncmp.c create mode 100644 sys/src/libc/port/cistrstr.c create mode 100644 sys/src/libc/port/cleanname.c create mode 100644 sys/src/libc/port/crypt.c create mode 100644 sys/src/libc/port/ctype.c create mode 100644 sys/src/libc/port/encodefmt.c create mode 100644 sys/src/libc/port/execl.c create mode 100644 sys/src/libc/port/exp.c create mode 100644 sys/src/libc/port/fabs.c create mode 100644 sys/src/libc/port/floor.c create mode 100644 sys/src/libc/port/fmod.c create mode 100644 sys/src/libc/port/frand.c create mode 100644 sys/src/libc/port/frexp.c create mode 100644 sys/src/libc/port/getcallerpc.c create mode 100644 sys/src/libc/port/getfields.c create mode 100644 sys/src/libc/port/getuser.c create mode 100644 sys/src/libc/port/hangup.c create mode 100644 sys/src/libc/port/hypot.c create mode 100644 sys/src/libc/port/lnrand.c create mode 100644 sys/src/libc/port/lock.c create mode 100644 sys/src/libc/port/log.c create mode 100644 sys/src/libc/port/lrand.c create mode 100644 sys/src/libc/port/malloc.c create mode 100644 sys/src/libc/port/memccpy.c create mode 100644 sys/src/libc/port/memchr.c create mode 100644 sys/src/libc/port/memcmp.c create mode 100644 sys/src/libc/port/memmove.c create mode 100644 sys/src/libc/port/memset.c create mode 100644 sys/src/libc/port/mktemp.c create mode 100644 sys/src/libc/port/muldiv.c create mode 100644 sys/src/libc/port/nan.c create mode 100644 sys/src/libc/port/needsrcquote.c create mode 100644 sys/src/libc/port/netmkaddr.c create mode 100644 sys/src/libc/port/nrand.c create mode 100644 sys/src/libc/port/ntruerand.c create mode 100644 sys/src/libc/port/perror.c create mode 100644 sys/src/libc/port/pool.c create mode 100644 sys/src/libc/port/pow.c create mode 100644 sys/src/libc/port/pow10.c create mode 100644 sys/src/libc/port/qsort.c create mode 100644 sys/src/libc/port/quote.c create mode 100644 sys/src/libc/port/rand.c create mode 100644 sys/src/libc/port/readn.c create mode 100644 sys/src/libc/port/reduce create mode 100644 sys/src/libc/port/rune.c create mode 100644 sys/src/libc/port/runebase.c create mode 100644 sys/src/libc/port/runebsearch.c create mode 100644 sys/src/libc/port/runestrcat.c create mode 100644 sys/src/libc/port/runestrchr.c create mode 100644 sys/src/libc/port/runestrcmp.c create mode 100644 sys/src/libc/port/runestrcpy.c create mode 100644 sys/src/libc/port/runestrdup.c create mode 100644 sys/src/libc/port/runestrecpy.c create mode 100644 sys/src/libc/port/runestrlen.c create mode 100644 sys/src/libc/port/runestrncat.c create mode 100644 sys/src/libc/port/runestrncmp.c create mode 100644 sys/src/libc/port/runestrncpy.c create mode 100644 sys/src/libc/port/runestrrchr.c create mode 100644 sys/src/libc/port/runestrstr.c create mode 100644 sys/src/libc/port/runetype.c create mode 100755 sys/src/libc/port/runetypebody-6.2.0.h create mode 100644 sys/src/libc/port/sin.c create mode 100644 sys/src/libc/port/sinh.c create mode 100644 sys/src/libc/port/strcat.c create mode 100644 sys/src/libc/port/strchr.c create mode 100644 sys/src/libc/port/strcmp.c create mode 100644 sys/src/libc/port/strcpy.c create mode 100644 sys/src/libc/port/strcspn.c create mode 100644 sys/src/libc/port/strdup.c create mode 100644 sys/src/libc/port/strecpy.c create mode 100644 sys/src/libc/port/strlen.c create mode 100644 sys/src/libc/port/strncat.c create mode 100644 sys/src/libc/port/strncmp.c create mode 100644 sys/src/libc/port/strncpy.c create mode 100644 sys/src/libc/port/strpbrk.c create mode 100644 sys/src/libc/port/strrchr.c create mode 100644 sys/src/libc/port/strspn.c create mode 100644 sys/src/libc/port/strstr.c create mode 100644 sys/src/libc/port/strtod.c create mode 100644 sys/src/libc/port/strtok.c create mode 100644 sys/src/libc/port/strtol.c create mode 100644 sys/src/libc/port/strtoll.c create mode 100644 sys/src/libc/port/strtoul.c create mode 100644 sys/src/libc/port/strtoull.c create mode 100644 sys/src/libc/port/tan.c create mode 100644 sys/src/libc/port/tanh.c create mode 100644 sys/src/libc/port/tokenize.c create mode 100644 sys/src/libc/port/toupper.c create mode 100644 sys/src/libc/port/u16.c create mode 100644 sys/src/libc/port/u32.c create mode 100644 sys/src/libc/port/u64.c create mode 100644 sys/src/libc/port/utfecpy.c create mode 100644 sys/src/libc/port/utflen.c create mode 100644 sys/src/libc/port/utfnlen.c create mode 100644 sys/src/libc/port/utfrrune.c create mode 100644 sys/src/libc/port/utfrune.c create mode 100644 sys/src/libc/port/utfutf.c create mode 100644 sys/src/libs.json create mode 100644 sys/src/sysconf.json diff --git a/sys/include/ctype.h b/sys/include/ctype.h new file mode 100644 index 0000000..e840e34 --- /dev/null +++ b/sys/include/ctype.h @@ -0,0 +1,38 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#pragma src "/sys/src/libc/port" +#pragma lib "libc.a" + +#define _U 01 +#define _L 02 +#define _N 04 +#define _S 010 +#define _P 020 +#define _C 040 +#define _B 0100 +#define _X 0200 + +extern unsigned char _ctype[]; + +#define isalpha(c) (_ctype[(unsigned char)(c)]&(_U|_L)) +#define isupper(c) (_ctype[(unsigned char)(c)]&_U) +#define islower(c) (_ctype[(unsigned char)(c)]&_L) +#define isdigit(c) (_ctype[(unsigned char)(c)]&_N) +#define isxdigit(c) (_ctype[(unsigned char)(c)]&_X) +#define isspace(c) (_ctype[(unsigned char)(c)]&_S) +#define ispunct(c) (_ctype[(unsigned char)(c)]&_P) +#define isalnum(c) (_ctype[(unsigned char)(c)]&(_U|_L|_N)) +#define isprint(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N|_B)) +#define isgraph(c) (_ctype[(unsigned char)(c)]&(_P|_U|_L|_N)) +#define iscntrl(c) (_ctype[(unsigned char)(c)]&_C) +#define isascii(c) ((unsigned char)(c)<=0177) +#define _toupper(c) ((c)-'a'+'A') +#define _tolower(c) ((c)-'A'+'a') +#define toascii(c) ((c)&0177) diff --git a/sys/include/fcall.h b/sys/include/fcall.h new file mode 100644 index 0000000..085a707 --- /dev/null +++ b/sys/include/fcall.h @@ -0,0 +1,149 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#pragma src "/sys/src/libc/9sys" +#pragma lib "libc.a" + +#define VERSION9P "9P2000" + +#define MAXWELEM 16 + +typedef +struct Fcall +{ + uint8_t type; + uint32_t fid; + uint16_t tag; + union { + struct { + uint32_t msize; /* Tversion, Rversion */ + char *version; /* Tversion, Rversion */ + }; + struct { + uint16_t oldtag; /* Tflush */ + }; + struct { + char *ename; /* Rerror */ + }; + struct { + Qid qid; /* Rattach, Ropen, Rcreate */ + uint32_t iounit; /* Ropen, Rcreate */ + }; + struct { + Qid aqid; /* Rauth */ + }; + struct { + uint32_t afid; /* Tauth, Tattach */ + char *uname; /* Tauth, Tattach */ + char *aname; /* Tauth, Tattach */ + }; + struct { + uint32_t perm; /* Tcreate */ + char *name; /* Tcreate */ + uint8_t mode; /* Tcreate, Topen */ + }; + struct { + uint32_t newfid; /* Twalk */ + uint16_t nwname; /* Twalk */ + char *wname[MAXWELEM]; /* Twalk */ + }; + struct { + uint16_t nwqid; /* Rwalk */ + Qid wqid[MAXWELEM]; /* Rwalk */ + }; + struct { + int64_t offset; /* Tread, Twrite */ + uint32_t count; /* Tread, Twrite, Rread */ + char *data; /* Twrite, Rread */ + }; + struct { + uint16_t nstat; /* Twstat, Rstat */ + uint8_t *stat; /* Twstat, Rstat */ + }; + }; +} Fcall; + + +#define GBIT8(p) ((p)[0]) +#define GBIT16(p) ((p)[0]|((p)[1]<<8)) +#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) +#define GBIT64(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ + ((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) + +#define PBIT8(p,v) (p)[0]=(v) +#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 +#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 +#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ + (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 + +#define BIT8SZ 1 +#define BIT16SZ 2 +#define BIT32SZ 4 +#define BIT64SZ 8 +#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ) + +/* STATFIXLEN includes leading 16-bit count */ +/* The count, however, excludes itself; total size is BIT16SZ+count */ +#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */ + +#define NOTAG (uint16_t)~0U /* Dummy tag */ +#define NOFID (uint32_t)~0U /* Dummy fid */ +#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */ + +enum +{ + Tversion = 100, + Rversion, + Tauth = 102, + Rauth, + Tattach = 104, + Rattach, + Terror = 106, /* illegal */ + Rerror, + Tflush = 108, + Rflush, + Twalk = 110, + Rwalk, + Topen = 112, + Ropen, + Tcreate = 114, + Rcreate, + Tread = 116, + Rread, + Twrite = 118, + Rwrite, + Tclunk = 120, + Rclunk, + Tremove = 122, + Rremove, + Tstat = 124, + Rstat, + Twstat = 126, + Rwstat, + Tmax, +}; + +uint convM2S(uint8_t*, uint, Fcall*); +uint convS2M(Fcall*, uint8_t*, uint); +uint sizeS2M(Fcall*); + +int statcheck(uint8_t *abuf, uint nbuf); +uint convM2D(uint8_t*, uint, Dir*, char*); +uint convD2M(Dir*, uint8_t*, uint); +uint sizeD2M(Dir*); + +int fcallfmt(Fmt*); +int dirfmt(Fmt*); +int dirmodefmt(Fmt*); + +int read9pmsg(int, void*, uint); + +#pragma varargck type "F" Fcall* +#pragma varargck type "M" ulong +#pragma varargck type "D" Dir* diff --git a/sys/include/libc.h b/sys/include/libc.h new file mode 100644 index 0000000..170654b --- /dev/null +++ b/sys/include/libc.h @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2015 Giacomo Tesio + * + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#pragma lib "libc.a" +#pragma src "/sys/src/libc" + +#define nelem(x) (sizeof(x)/sizeof((x)[0])) +#define offsetof(s, m) (uintptr_t)(&(((s*)0)->m)) +#define assert(x) if(x){}else _assert(#x) + +extern void (*_abort)(void); +#define abort() if(_abort){_abort();}else{while(*(int*)0);} + +/* + * mem routines + */ +extern void* memccpy(void*, const void*, int, uint32_t); +extern void* memset(void*, int, uint32_t); +extern int memcmp(const void*, const void*, uint32_t); +extern void* memcpy(void*, const void*, size_t); +extern void* memmove(void*, const void*, size_t); +extern void* memchr(const void*, int, uint32_t); + +/* + * string routines + */ +extern char* strcat(char*, const char*); +extern char* strchr(const char*, int); +extern int strcmp(const char*, const char*); +extern char* strcpy(char*, const char*); +extern char* strecpy(char*, char *, const char*); +extern char* strdup(const char*); +extern char* strncat(char*, const char*, int32_t); +extern char* strncpy(char*, const char*, uint32_t); +extern int strncmp(const char*, const char*, int32_t); +extern char* strpbrk(const char*, const char*); +extern char* strrchr(const char*, int); +extern char* strtok(char*, char*); +extern int32_t strlen(const char*); +extern int32_t strspn(const char*, const char*); +extern int32_t strcspn(const char*, const char*); +extern char* strstr(const char*, const char*); +extern int cistrncmp(const char*, const char*, int); +extern int cistrcmp(const char*, const char*); +extern char* cistrstr(const char*, const char*); +extern int tokenize(char*, char**, int); + +enum +{ + UTFmax = 4, /* maximum bytes per rune */ + Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ + Runeerror = 0xFFFD, /* decoding error in UTF */ + Runemax = 0x10FFFF, /* 21-bit rune */ + Runemask = 0x1FFFFF, /* bits used by runes (see grep) */ +}; + +/* + * rune routines + */ +extern int runetochar(char*, const Rune*); +extern int chartorune(Rune*, const char*); +extern int runelen(Rune); +extern int runenlen(const Rune*, int); +extern int fullrune(const char*, int); +extern int utflen(const char*); +extern int utfnlen(const char*, int32_t); +extern char* utfrune(const char*, Rune); +extern char* utfrrune(const char*, Rune); +extern char* utfutf(const char*, const char*); +extern char* utfecpy(char*, char *, const char*); + +extern Rune* runestrcat(Rune*, const Rune*); +extern Rune* runestrchr(const Rune*, Rune); +extern int runestrcmp(const Rune*, const Rune*); +extern Rune* runestrcpy(Rune*, const Rune*); +extern Rune* runestrncpy(Rune*, const Rune*, int32_t); +extern Rune* runestrecpy(Rune*, Rune*, const Rune*); +extern Rune* runestrdup(const Rune*); +extern Rune* runestrncat(Rune*, const Rune*, int32_t); +extern int runestrncmp(const Rune*, const Rune*, int32_t); +extern Rune* runestrrchr(const Rune*, Rune); +extern int32_t runestrlen(const Rune*); +extern Rune* runestrstr(const Rune*, const Rune*); + +extern Rune tolowerrune(Rune); +extern Rune totitlerune(Rune); +extern Rune toupperrune(Rune); +extern Rune tobaserune(Rune); +extern int isalpharune(Rune); +extern int isbaserune(Rune); +extern int isdigitrune(Rune); +extern int islowerrune(Rune); +extern int isspacerune(Rune); +extern int istitlerune(Rune); +extern int isupperrune(Rune); + +/* + * malloc + */ +extern void* malloc(size_t); +extern void* mallocz(uint32_t, int); +extern void free(void*); +extern uint32_t msize(void*); +extern void* mallocalign(uint32_t, uint32_t, int32_t, uint32_t); +extern void* calloc(uint32_t, size_t); +extern void* realloc(void*, size_t); +void setmalloctag(void*, uintptr_t); +void setrealloctag(void*, uintptr_t); +uintptr_t getmalloctag(void*); +uintptr_t getrealloctag(void*); +void* malloctopoolblock(void*); + +/* + * print routines + */ +typedef struct Fmt Fmt; +struct Fmt{ + uint8_t runes; /* output buffer is runes or chars? */ + void *start; /* of buffer */ + void *to; /* current place in the buffer */ + void *stop; /* end of the buffer; overwritten if flush fails */ + int (*flush)(Fmt *); /* called when to == stop */ + void *farg; /* to make flush a closure */ + int nfmt; /* num chars formatted so far */ + va_list args; /* args passed to dofmt */ + int r; /* % format Rune */ + int width; + int prec; + uint32_t flags; +}; + +enum{ + FmtWidth = 1, + FmtLeft = FmtWidth << 1, + FmtPrec = FmtLeft << 1, + FmtSharp = FmtPrec << 1, + FmtSpace = FmtSharp << 1, + FmtSign = FmtSpace << 1, + FmtZero = FmtSign << 1, + FmtUnsigned = FmtZero << 1, + FmtShort = FmtUnsigned << 1, + FmtLong = FmtShort << 1, + FmtVLong = FmtLong << 1, + FmtComma = FmtVLong << 1, + FmtByte = FmtComma << 1, + + FmtFlag = FmtByte << 1 +}; + +extern int print(const char*, ...); +extern char* seprint(char*, char*, const char*, ...); +extern char* vseprint(char*, char*, const char*, va_list); +extern int snprint(char*, int, const char*, ...); +extern int vsnprint(char*, int, const char*, va_list); +extern char* smprint(const char*, ...); +extern char* vsmprint(const char*, va_list); +extern int sprint(char*, const char*, ...); +extern int fprint(int, const char*, ...); +extern int vfprint(int, const char*, va_list); + +extern int runesprint(Rune*, const char*, ...); +extern int runesnprint(Rune*, int, const char*, ...); +extern int runevsnprint(Rune*, int, const char*, va_list); +extern Rune* runeseprint(Rune*, Rune*, const char*, ...); +extern Rune* runevseprint(Rune*, Rune*, const char*, va_list); +extern Rune* runesmprint(const char*, ...); +extern Rune* runevsmprint(const char*, va_list); + +extern int fmtfdinit(Fmt*, int, char*, int); +extern int fmtfdflush(Fmt*); +extern int fmtstrinit(Fmt*); +extern char* fmtstrflush(Fmt*); +extern int runefmtstrinit(Fmt*); +extern Rune* runefmtstrflush(Fmt*); + +#pragma varargck argpos fmtprint 2 +#pragma varargck argpos fprint 2 +#pragma varargck argpos print 1 +#pragma varargck argpos runeseprint 3 +#pragma varargck argpos runesmprint 1 +#pragma varargck argpos runesnprint 3 +#pragma varargck argpos runesprint 2 +#pragma varargck argpos seprint 3 +#pragma varargck argpos smprint 1 +#pragma varargck argpos snprint 3 +#pragma varargck argpos sprint 2 + +#pragma varargck type "lld" vlong +#pragma varargck type "llo" vlong +#pragma varargck type "llx" vlong +#pragma varargck type "llb" vlong +#pragma varargck type "lld" uvlong +#pragma varargck type "llo" uvlong +#pragma varargck type "llx" uvlong +#pragma varargck type "llb" uvlong +#pragma varargck type "ld" long +#pragma varargck type "lo" long +#pragma varargck type "lx" long +#pragma varargck type "lb" long +#pragma varargck type "ld" ulong +#pragma varargck type "lo" ulong +#pragma varargck type "lx" ulong +#pragma varargck type "lb" ulong +#pragma varargck type "d" int +#pragma varargck type "o" int +#pragma varargck type "x" int +#pragma varargck type "c" int +#pragma varargck type "C" int +#pragma varargck type "b" int +#pragma varargck type "d" uint +#pragma varargck type "x" uint +#pragma varargck type "c" uint +#pragma varargck type "C" uint +#pragma varargck type "b" uint +#pragma varargck type "f" double +#pragma varargck type "e" double +#pragma varargck type "g" double +#pragma varargck type "s" char* +#pragma varargck type "q" char* +#pragma varargck type "S" Rune* +#pragma varargck type "Q" Rune* +#pragma varargck type "r" void +#pragma varargck type "%" void +#pragma varargck type "n" int* +#pragma varargck type "p" uintptr +#pragma varargck type "p" void* +#pragma varargck flag ',' +#pragma varargck flag ' ' +#pragma varargck flag 'h' +#pragma varargck type "<" void* +#pragma varargck type "[" void* +#pragma varargck type "H" void* +#pragma varargck type "lH" void* + +extern int fmtinstall(int, int (*)(Fmt*)); +extern int dofmt(Fmt*, const char*); +extern int dorfmt(Fmt*, const Rune*); +extern int fmtprint(Fmt*, const char*, ...); +extern int fmtvprint(Fmt*, const char*, va_list); +extern int fmtrune(Fmt*, int); +extern int fmtstrcpy(Fmt*, const char*); +extern int fmtrunestrcpy(Fmt*, const Rune*); +/* + * error string for %r + * supplied on per os basis, not part of fmt library + */ +extern int errfmt(Fmt *f); + +/* + * quoted strings + */ +extern char *unquotestrdup(const char*); +extern Rune *unquoterunestrdup(const Rune*); +extern char *quotestrdup(const char*); +extern Rune *quoterunestrdup(const Rune*); +extern int quotestrfmt(Fmt*); +extern int quoterunestrfmt(Fmt*); +extern void quotefmtinstall(void); +extern int (*doquote)(int); +extern int needsrcquote(int); + +/* + * random number + */ +extern void srand(int32_t); +extern int rand(void); +extern int nrand(int); +extern int32_t lrand(void); +extern int32_t lnrand(int32_t); +extern double frand(void); +extern uint32_t truerand(void); /* uses /dev/random */ +extern uint32_t ntruerand(uint32_t); /* uses /dev/random */ + +/* + * math + */ +extern uint32_t getfcr(void); +extern void setfsr(uint32_t); +extern uint32_t getfsr(void); +extern void setfcr(uint32_t); +extern double NaN(void); +extern double Inf(int); +extern int isNaN(double); +extern int isInf(double, int); +extern uint32_t umuldiv(uint32_t, uint32_t, uint32_t); +extern int32_t muldiv(int32_t, int32_t, int32_t); + +extern double pow(double, double); +extern double atan2(double, double); +extern double fabs(double); +extern double atan(double); +extern double log(double); +extern double log10(double); +extern double exp(double); +extern double floor(double); +extern double ceil(double); +extern double hypot(double, double); +extern double sin(double); +extern double cos(double); +extern double tan(double); +extern double asin(double); +extern double acos(double); +extern double sinh(double); +extern double cosh(double); +extern double tanh(double); +extern double sqrt(double); +extern double fmod(double, double); + +#define HUGE 3.4028234e38 +#define PIO2 1.570796326794896619231e0 +#define PI (PIO2+PIO2) + +/* + * Time-of-day + */ + +typedef +struct Tm +{ + int sec; + int min; + int hour; + int mday; + int mon; + int year; + int wday; + int yday; + char zone[4]; + int tzoff; +} Tm; + +extern Tm* gmtime(int32_t); +extern Tm* localtime(int32_t); +extern char* asctime(Tm*); +extern char* ctime(int32_t); +extern double cputime(void); +extern int32_t times(int32_t*); +extern int32_t tm2sec(Tm*); +extern int64_t nsec(void); + +extern void cycles(uint64_t*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */ + +/* + * one-of-a-kind + */ +enum +{ + PNPROC = 1, + PNGROUP = 2, +}; + +extern void _assert(const char*); +extern int abs(int); +extern int atexit(void(*)(void)); +extern void atexitdont(void(*)(void)); +extern int atnotify(int(*)(void*, char*), int); +extern double atof(const char*); +extern int atoi(const char*); +extern int32_t atol(const char*); +extern int64_t atoll(const char*); +extern double charstod(int(*)(void*), void*); +extern char* cleanname(char*); +extern int decrypt(void*, void*, int); +extern int encrypt(void*, void*, int); +extern int dec64(uint8_t*, int, const char*, int); +extern int enc64(char*, int, const uint8_t*, int); +extern int dec32(uint8_t*, int, const char*, int); +extern int enc32(char*, int, const uint8_t*, int); +extern int dec16(uint8_t*, int, const char*, int); +extern int enc16(char*, int, const uint8_t*, int); +extern int encodefmt(Fmt*); +extern void exits(const char*); +extern double frexp(double, int*); +extern uintptr getcallerpc(void); +extern char* getenv(const char*); +extern int getfields(char*, char**, int, int, const char*); +extern int gettokens(char *, char **, int, const char *); +extern char* getuser(void); +extern char* getwd(char*, int); +extern int iounit(int); +extern int32_t labs(int32_t); +extern double ldexp(double, int); +extern void longjmp(jmp_buf, int); +extern char* mktemp(char*); +extern double modf(double, double*); +extern void notejmp(void*, jmp_buf, int); +extern void perror(const char*); +extern int postnote(int, int, const char *); +extern double pow10(int); +extern int putenv(const char*, const char*); +extern void qsort(void*, int32_t, int32_t, + int (*)(const void*, const void*)); +extern int setjmp(jmp_buf); +extern double strtod(const char*, const char**); +extern int32_t strtol(const char*, char**, int); +extern uint32_t strtoul(const char*, char**, int); +extern int64_t strtoll(const char*, char**, int); +extern uint64_t strtoull(const char*, char**, int); +extern void sysfatal(const char*, ...); +#pragma varargck argpos sysfatal 1 +extern void syslog(int, const char*, const char*, ...); +#pragma varargck argpos syslog 3 +extern int32_t time(int32_t*); +extern int tolower(int); +extern int toupper(int); + +/* + * atomic + */ +int32_t ainc(int32_t*); +int32_t adec(int32_t*); +int cas32(uint32_t*, uint32_t, uint32_t); +int casp(void**, void*, void*); +int casl(uint32_t*, uint32_t, uint32_t); + +/* + * synchronization + */ +typedef +struct Lock { + int32_t key; + int32_t sem; +} Lock; + +extern int _tas(int*); + +extern void lock(Lock*); +extern int lockt(Lock*, uint32_t); +extern void unlock(Lock*); +extern int canlock(Lock*); + +typedef struct QLp QLp; +struct QLp +{ + int inuse; + QLp *next; + char state; +}; + +typedef +struct QLock +{ + Lock lock; + int locked; + QLp *head; + QLp *tail; +} QLock; + +extern void qlock(QLock*); +extern int qlockt(QLock*, uint32_t); +extern void qunlock(QLock*); +extern int canqlock(QLock*); +extern void _qlockinit(void* (*)(void*, void*)); /* called only by the thread library */ + +typedef +struct RWLock +{ + Lock lock; + int _readers; /* number of readers */ + int writer; /* number of writers */ + QLp *head; /* list of waiting processes */ + QLp *tail; +} RWLock; + +extern void rlock(RWLock*); +extern int rlockt(RWLock*, uint32_t); +extern void runlock(RWLock*); +extern int canrlock(RWLock*); +extern void wlock(RWLock*); +extern int wlockt(RWLock*, uint32_t); +extern void wunlock(RWLock*); +extern int canwlock(RWLock*); + +typedef +struct Rendez +{ + QLock *l; + QLp *head; + QLp *tail; +} Rendez; + +extern void rsleep(Rendez*); /* unlocks r->l, sleeps, locks r->l again */ +extern int rsleept(Rendez*, uint32_t); /* unlocks r->l, sleeps (up to ms), locks r->l again (if not timedout) */ +extern int rwakeup(Rendez*); +extern int rwakeupall(Rendez*); +extern void** privalloc(void); +extern void privfree(void**); + +/* + * network dialing + */ +#define NETPATHLEN 40 +extern int accept(int, const char*); +extern int announce(const char*, char*); +extern int dial(const char*, const char*, char*, int*); +extern void setnetmtpt(char*, int, const char*); +extern int hangup(int); +extern int listen(const char*, char*); +extern char* netmkaddr(const char*, const char*, const char*); +extern int reject(int, const char*, const char*); + +/* + * encryption + */ +extern int pushssl(int, const char*, const char*, const char*, int*); +extern int pushtls(int, const char*, const char*, int, const char*, + char*); + +/* + * network services + */ +typedef struct NetConnInfo NetConnInfo; +struct NetConnInfo +{ + char *dir; /* connection directory */ + char *root; /* network root */ + char *spec; /* binding spec */ + char *lsys; /* local system */ + char *lserv; /* local service */ + char *rsys; /* remote system */ + char *rserv; /* remote service */ + char *laddr; /* local address */ + char *raddr; /* remote address */ +}; +extern NetConnInfo* getnetconninfo(const char*, int); +extern void freenetconninfo(NetConnInfo*); + +/* + * system calls + * + */ +#define STATMAX 65535U /* max length of machine-independent stat structure */ +#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */ +#define ERRMAX 128 /* max length of error string */ + +#define MORDER 0x0003 /* mask for bits defining order of mounting */ +#define MREPL 0x0000 /* mount replaces object */ +#define MBEFORE 0x0001 /* mount goes before others in union directory */ +#define MAFTER 0x0002 /* mount goes after others in union directory */ +#define MCREATE 0x0004 /* permit creation in mounted directory */ +#define MCACHE 0x0010 /* cache some data */ +#define MMASK 0x0017 /* all bits on */ + +#define OREAD 0 /* open for read */ +#define OWRITE 1 /* write */ +#define ORDWR 2 /* read and write */ +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ +#define OCEXEC 32 /* or'ed in, close on exec */ +#define ORCLOSE 64 /* or'ed in, remove on close */ +#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */ +// #define OBEHIND 0x2000 /* use write behind for writes [for 9n] */ + +#define AEXIST 0 /* accessible: exists */ +#define AEXEC 1 /* execute access */ +#define AWRITE 2 /* write access */ +#define AREAD 4 /* read access */ + +/* Segattch */ +#define SG_RONLY 0040 /* read only */ +#define SG_CEXEC 0100 /* detach on exec */ + +#define NCONT 0 /* continue after note */ +#define NDFLT 1 /* terminate after note */ +#define NSAVE 2 /* clear note but hold state */ +#define NRSTR 3 /* restore saved state */ + +/* bits in Qid.type */ +#define QTDIR 0x80 /* type bit for directories */ +#define QTAPPEND 0x40 /* type bit for append only files */ +#define QTEXCL 0x20 /* type bit for exclusive use files */ +#define QTMOUNT 0x10 /* type bit for mounted channel */ +#define QTAUTH 0x08 /* type bit for authentication file */ +#define QTTMP 0x04 /* type bit for not-backed-up file */ +#define QTFILE 0x00 /* plain file */ + +/* bits in Dir.mode */ +#define DMDIR 0x80000000 /* mode bit for directories */ +#define DMAPPEND 0x40000000 /* mode bit for append only files */ +#define DMEXCL 0x20000000 /* mode bit for exclusive use files */ +#define DMMOUNT 0x10000000 /* mode bit for mounted channel */ +#define DMAUTH 0x08000000 /* mode bit for authentication file */ +#define DMTMP 0x04000000 /* mode bit for non-backed-up files */ +#define DMREAD 0x4 /* mode bit for read permission */ +#define DMWRITE 0x2 /* mode bit for write permission */ +#define DMEXEC 0x1 /* mode bit for execute permission */ + +/* rfork */ +enum +{ + RFNAMEG = (1<<0), + RFENVG = (1<<1), + RFFDG = (1<<2), + RFNOTEG = (1<<3), + RFPROC = (1<<4), + RFMEM = (1<<5), + RFNOWAIT = (1<<6), + RFCNAMEG = (1<<10), + RFCENVG = (1<<11), + RFCFDG = (1<<12), + RFREND = (1<<13), + RFNOMNT = (1<<14) +}; + +typedef +struct Qid +{ + uint64_t path; + uint32_t vers; + uint8_t type; +} Qid; + +typedef +struct Dir { + /* system-modified data */ + uint16_t type; /* server type */ + uint dev; /* server subtype */ + /* file data */ + Qid qid; /* unique id from server */ + uint32_t mode; /* permissions */ + uint32_t atime; /* last read time */ + uint32_t mtime; /* last write time */ + int64_t length; /* file length */ + char *name; /* last element of path */ + char *uid; /* owner name */ + char *gid; /* group name */ + char *muid; /* last modifier name */ +} Dir; + +/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */ +typedef +struct Waitmsg +{ + int pid; /* of loved one */ + uint32_t time[3]; /* of loved one & descendants */ + char *msg; +} Waitmsg; + +typedef +struct IOchunk +{ + void *addr; + uint32_t len; +} IOchunk; + +extern void _exits(const char*); + +extern int access(const char*, int); +extern int64_t alarm(uint64_t); +extern int await(char*, int); +extern int64_t awake(int64_t); +extern int awakened(int64_t); +extern int bind(const char*, const char*, int); +extern int brk(void*); +extern int chdir(const char*); +extern int close(int); +extern int create(const char*, int, uint32_t); +extern int dup(int, int); +extern int errstr(char*, uint); +extern int exec(const char*, char* const[]); +extern int execl(const char*, ...); +extern int forgivewkp(int64_t); +extern int fork(void); +extern int rfork(int); +extern int fauth(int, const char*); +extern int fstat(int, uint8_t*, int); +extern int fwstat(int, uint8_t*, int); +extern int fversion(int, int, char*, int); +extern int mount(int, int, const char*, int, const char*, int); +extern int unmount(const char*, const char*); +extern int noted(int); +extern int notify(void(*)(void*, char*)); +extern int open(const char*, int); +extern int fd2path(int, char*, int); +// extern int fdflush(int); +extern int pipe(int*); +extern int32_t pread(int, void*, int32_t, int64_t); +extern int32_t preadv(int, IOchunk*, int, int64_t); +extern int32_t pwrite(int, const void*, int32_t, int64_t); +extern int32_t pwritev(int, IOchunk*, int, int64_t); +extern int32_t read(int, void*, int32_t); +extern int32_t readn(int, void*, int32_t); +extern int32_t readv(int, IOchunk*, int); +extern int remove(const char*); +extern void* sbrk(uint32_t); +extern int32_t oseek(int, int32_t, int); +extern int64_t seek(int, int64_t, int); +extern void* segattach(int, const char*, void*, uint32_t); +extern void* segbrk(void*, void*); +extern int segdetach(void*); +extern int segflush(void*, uint32_t); +extern int segfree(void*, uint32_t); +extern int semacquire(int32_t*, int); +extern int32_t semrelease(int32_t*, int32_t); +extern void sleep(int32_t); +extern int stat(const char*, uint8_t*, int); +extern int tsemacquire(int32_t*, uint64_t); +extern Waitmsg* wait(void); +extern int waitpid(void); +extern int32_t write(int, const void*, int32_t); +extern int32_t writev(int, IOchunk*, int); +extern int wstat(const char*, uint8_t*, int); +extern void* rendezvous(void*, void*); + +extern Dir* dirstat(const char*); +extern Dir* dirfstat(int); +extern int dirwstat(const char*, Dir*); +extern int dirfwstat(int, Dir*); +extern int32_t dirread(int, Dir**); +extern void nulldir(Dir*); +extern int32_t dirreadall(int, Dir**); +extern int getpid(void); +extern int getppid(void); +extern void rerrstr(char*, uint); +extern char* sysname(void); +extern void werrstr(const char*, ...); +#pragma varargck argpos werrstr 1 + +/* compiler directives on plan 9 */ +#define SET(x) ((x)=0) +#define USED(x) if(x){}else{} +#ifdef __GNUC__ +# if __GNUC__ >= 3 +# undef USED +# define USED(x) ((void)(x)) +# endif +#endif + +extern char *argv0; +/* #define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\ */ +#define ARGBEGIN for((argv0?0:(argv0=*argv)),argv++,argc--;\ + argv[0] && argv[0][0]=='-' && argv[0][1];\ + argc--, argv++) {\ + char *_args, *_argt;\ + Rune _argc;\ + _args = &argv[0][1];\ + if(_args[0]=='-' && _args[1]==0){\ + argc--; argv++; break;\ + }\ + _argc = 0;\ + while(*_args && (_args += chartorune(&_argc, _args)))\ + switch(_argc) +/* #define ARGEND SET(_argt);USED(_argt,_argc,_args);}USED(argv, argc); */ +#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc); +#define ARGF() (_argt=_args, _args="",\ + (*_argt? _argt: argv[1]? (argc--, *++argv): 0)) +#define EARGF(x) (_argt=_args, _args="",\ + (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), argc = *(int*)0, (char*)0))) + +#define ARGC() _argc + +/* this is used by sbrk and brk, it's a really bad idea to redefine it */ +extern char end[]; + diff --git a/sys/include/pool.h b/sys/include/pool.h new file mode 100644 index 0000000..dea0088 --- /dev/null +++ b/sys/include/pool.h @@ -0,0 +1,64 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +typedef struct Pool Pool; +struct Pool { + char* name; + uint32_t maxsize; + + uint32_t cursize; + uint32_t curfree; + uint32_t curalloc; + + uint32_t minarena; /* smallest size of new arena */ + uint32_t quantum; /* allocated blocks should be multiple of */ + uint32_t minblock; /* smallest newly allocated block */ + + void* freeroot; /* actually Free* */ + void* arenalist; /* actually Arena* */ + + void* (*alloc)(uint32_t); + int (*merge)(void*, void*); + void (*move)(void* from, void* to); + + int flags; + int nfree; + int lastcompact; + + void (*lock)(Pool*); + void (*unlock)(Pool*); + void (*print)(Pool*, char*, ...); + void (*panic)(Pool*, char*, ...); + void (*logstack)(Pool*); + + void* private; +}; + +extern void* poolalloc(Pool*, uint32_t); +extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t, + uint32_t); +extern void poolfree(Pool*, void*); +extern uint32_t poolmsize(Pool*, void*); +extern void* poolrealloc(Pool*, void*, uint32_t); +extern void poolcheck(Pool*); +extern int poolcompact(Pool*); +extern void poolblockcheck(Pool*, void*); + +extern Pool* mainmem; +extern Pool* imagmem; + +enum { /* flags */ + POOL_ANTAGONISM = 1<<0, + POOL_PARANOIA = 1<<1, + POOL_VERBOSITY = 1<<2, + POOL_DEBUGGING = 1<<3, + POOL_LOGGING = 1<<4, + POOL_TOLERANCE = 1<<5, + POOL_NOREUSE = 1<<6, +}; diff --git a/sys/include/tos.h b/sys/include/tos.h new file mode 100644 index 0000000..b6c4429 --- /dev/null +++ b/sys/include/tos.h @@ -0,0 +1,29 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +typedef struct Tos Tos; + +struct Tos { + uint64_t cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */ + int64_t kcycles; /* cycles spent in kernel */ + int64_t pcycles; /* cycles spent in process (kernel + user) */ + uint32_t pid; /* might as well put the pid here */ + uint32_t clock; + /* scratch space for kernel use (e.g., mips fp delay-slot execution) */ + uint32_t kscr[4]; + + /* + * Fields below are not available on Plan 9 kernels. + */ + int nixtype; /* role of the core we are running at */ + int core; /* core we are running at */ + /* top of stack is here */ +}; + +extern Tos *_tos; diff --git a/sys/src/klib.json b/sys/src/klib.json new file mode 100644 index 0000000..9c0b53b --- /dev/null +++ b/sys/src/klib.json @@ -0,0 +1,32 @@ +{ + "KernelLibs": { + "Cflags": [ + "-std=c11", + "-c", + "-I/$JEHANNE/arch/$ARCH/include", + "-I/$JEHANNE/sys/include", + "-I.", + "-mcmodel=kernel", + "-O0", + "-fplan9-extensions", + "-mno-red-zone", + "-ffreestanding", + "-fno-builtin", + "-Wall", + "-Wno-missing-braces", + "-Wno-parentheses", + "-Wno-unknown-pragmas", + "-Wuninitialized", + "-g" + ], + "Oflags": [ + "-static" + ], + "Post": [ + "rm *.o" + ], + "Pre": [ + "rm -f *.o *.tag.*" + ] + } +} diff --git a/sys/src/klibs.json b/sys/src/klibs.json new file mode 100644 index 0000000..327c1f1 --- /dev/null +++ b/sys/src/klibs.json @@ -0,0 +1,7 @@ +{ + "klibs": { + "Projects": [ + "/sys/src/libc/klibc.json" + ] + } +} diff --git a/sys/src/lib.json b/sys/src/lib.json new file mode 100644 index 0000000..e7df642 --- /dev/null +++ b/sys/src/lib.json @@ -0,0 +1,16 @@ +{ + "Libs": { + "Include": [ + "/arch/$ARCH/include/cflags.json" + ], + "Oflags": [ + "-static" + ], + "Post": [ + "rm *.o" + ], + "Pre": [ + "rm -f *.o *.tag.*" + ] + } +} diff --git a/sys/src/libc/9sys/access.c b/sys/src/libc/9sys/access.c new file mode 100644 index 0000000..92723df --- /dev/null +++ b/sys/src/libc/9sys/access.c @@ -0,0 +1,42 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +access(const char *name, int mode) +{ + int fd; + Dir *db; + static char omode[] = { + 0, + OEXEC, + OWRITE, + ORDWR, + OREAD, + OEXEC, /* only approximate */ + ORDWR, + ORDWR /* only approximate */ + }; + + if(mode == AEXIST){ + db = dirstat(name); + free(db); + if(db != nil) + return 0; + return -1; + } + fd = open(name, omode[mode&7]); + if(fd >= 0){ + close(fd); + return 0; + } + return -1; +} diff --git a/sys/src/libc/9sys/announce.c b/sys/src/libc/9sys/announce.c new file mode 100644 index 0000000..18424cb --- /dev/null +++ b/sys/src/libc/9sys/announce.c @@ -0,0 +1,284 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static int nettrans(const char*, char*, int na, char*, int); + +enum +{ + Maxpath= 256, +}; + +/* + * announce a network service. + */ +int +announce(const char *addr, char *dir) +{ + int ctl, n, m; + char buf[Maxpath]; + char buf2[Maxpath]; + char netdir[Maxpath]; + char naddr[Maxpath]; + char *cp; + + /* + * translate the address + */ + if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0) + return -1; + + /* + * get a control channel + */ + ctl = open(netdir, ORDWR); + if(ctl<0){ + werrstr("announce opening %s: %r", netdir); + return -1; + } + cp = strrchr(netdir, '/'); + if(cp == nil){ + werrstr("announce arg format %s", netdir); + close(ctl); + return -1; + } + *cp = 0; + + /* + * find out which line we have + */ + n = snprint(buf, sizeof(buf), "%s/", netdir); + m = read(ctl, &buf[n], sizeof(buf)-n-1); + if(m <= 0){ + werrstr("announce reading %s: %r", netdir); + close(ctl); + return -1; + } + buf[n+m] = 0; + + /* + * make the call + */ + n = snprint(buf2, sizeof(buf2), "announce %s", naddr); + if(write(ctl, buf2, n)!=n){ + werrstr("announce writing %s: %r", netdir); + close(ctl); + return -1; + } + + /* + * return directory etc. + */ + if(dir){ + strncpy(dir, buf, NETPATHLEN); + dir[NETPATHLEN-1] = 0; + } + return ctl; +} + +/* + * listen for an incoming call + */ +int +listen(const char *dir, char *newdir) +{ + int ctl, n, m; + char buf[Maxpath]; + char *cp; + + /* + * open listen, wait for a call + */ + snprint(buf, sizeof(buf), "%s/listen", dir); + ctl = open(buf, ORDWR); + if(ctl < 0){ + werrstr("listen opening %s: %r", buf); + return -1; + } + + /* + * find out which line we have + */ + strncpy(buf, dir, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + cp = strrchr(buf, '/'); + if(cp == nil){ + close(ctl); + werrstr("listen arg format %s", dir); + return -1; + } + *++cp = 0; + n = cp-buf; + m = read(ctl, cp, sizeof(buf) - n - 1); + if(m <= 0){ + close(ctl); + werrstr("listen reading %s/listen: %r", dir); + return -1; + } + buf[n+m] = 0; + + /* + * return directory etc. + */ + if(newdir){ + strncpy(newdir, buf, NETPATHLEN); + newdir[NETPATHLEN-1] = 0; + } + return ctl; + +} + +/* + * accept a call, return an fd to the open data file + */ +int +accept(int ctl, const char *dir) +{ + char buf[Maxpath]; + const char *num; + int32_t n; + + num = strrchr(dir, '/'); + if(num == nil) + num = dir; + else + num++; + + n = snprint(buf, sizeof(buf), "accept %s", num); + write(ctl, buf, n); /* ignore return value, network might not need accepts */ + + snprint(buf, sizeof(buf), "%s/data", dir); + return open(buf, ORDWR); +} + +/* + * reject a call, tell device the reason for the rejection + */ +int +reject(int ctl, const char *dir, const char *cause) +{ + char buf[Maxpath]; + const char *num; + int32_t n; + + num = strrchr(dir, '/'); + if(num == 0) + num = dir; + else + num++; + snprint(buf, sizeof(buf), "reject %s %s", num, cause); + n = strlen(buf); + if(write(ctl, buf, n) != n) + return -1; + return 0; +} + +/* + * perform the identity translation (in case we can't reach cs) + */ +static int +identtrans(char *netdir, const char *addr, char *naddr, int na, + char *file, int nf) +{ + char proto[Maxpath]; + char *p; + + USED(nf); + + /* parse the protocol */ + strncpy(proto, addr, sizeof(proto)); + proto[sizeof(proto)-1] = 0; + p = strchr(proto, '!'); + if(p) + *p++ = 0; + + snprint(file, nf, "%s/%s/clone", netdir, proto); + strncpy(naddr, p, na); + naddr[na-1] = 0; + + return 1; +} + +/* + * call up the connection server and get a translation + */ +static int +nettrans(const char *addr, char *naddr, int na, char *file, int nf) +{ + int i, fd; + char buf[Maxpath]; + char netdir[Maxpath]; + char *p, *p2; + int32_t n; + + /* + * parse, get network directory + */ + p = strchr(addr, '!'); + if(p == 0){ + werrstr("bad dial string: %s", addr); + return -1; + } + if(*addr != '/'){ + strncpy(netdir, "/net", sizeof(netdir)); + netdir[sizeof(netdir) - 1] = 0; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + i = p2 - addr; + if(i == 0 || i >= sizeof(netdir)){ + werrstr("bad dial string: %s", addr); + return -1; + } + strncpy(netdir, addr, i); + netdir[i] = 0; + addr = p2 + 1; + } + + /* + * ask the connection server + */ + snprint(buf, sizeof(buf), "%s/cs", netdir); + fd = open(buf, ORDWR); + if(fd < 0) + return identtrans(netdir, addr, naddr, na, file, nf); + if(write(fd, addr, strlen(addr)) < 0){ + close(fd); + return -1; + } + seek(fd, 0, 0); + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if(n <= 0) + return -1; + buf[n] = 0; + + /* + * parse the reply + */ + p = strchr(buf, ' '); + if(p == 0) + return -1; + *p++ = 0; + strncpy(naddr, p, na); + naddr[na-1] = 0; + + if(buf[0] == '/'){ + p = strchr(buf+1, '/'); + if(p == nil) + p = buf; + else + p++; + } + snprint(file, nf, "%s/%s", netdir, p); + return 0; +} diff --git a/sys/src/libc/9sys/awakened.c b/sys/src/libc/9sys/awakened.c new file mode 100644 index 0000000..ccd3826 --- /dev/null +++ b/sys/src/libc/9sys/awakened.c @@ -0,0 +1,50 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2015 Giacomo Tesio + * + * Jehanne 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, version 2 of the License. + * + * Jehanne 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 Jehanne. If not, see . + */ + +#include +#include + +int +awakened(int64_t wakeup) +{ + /* awake returns the ticks of the scheduled wakeup in negative, + * thus a wakeup is in the past iff (-awake(0)) >= (-wakeup) + * + * NOTE: this is not a macro so that we can change the awake() + * implementation in the future, without affecting the client code. + */ + assert(wakeup < 0); + return wakeup >= awake(0); +} + +int +forgivewkp(int64_t wakeup) +{ + /* awake returns the ticks of the scheduled wakeup in negative, + * and is able to remove a wakeup provided such value. + * + * forgivewkp() is just a wrapper to hide awake()'s details that + * could change in the future and make client code easier to + * read. + * + * NOTE: this is not a macro so that we can change the awake() + * implementation in the future, without affecting the client code. + */ + assert(wakeup < 0); + return awake(wakeup); +} diff --git a/sys/src/libc/9sys/convD2M.c b/sys/src/libc/9sys/convD2M.c new file mode 100644 index 0000000..3a2d845 --- /dev/null +++ b/sys/src/libc/9sys/convD2M.c @@ -0,0 +1,104 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +uint +sizeD2M(Dir *d) +{ + char *sv[4]; + int i, ns; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++) + if(sv[i]) + ns += strlen(sv[i]); + + return STATFIXLEN + ns; +} + +uint +convD2M(Dir *d, uint8_t *buf, uint nbuf) +{ + uint8_t *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4], ss; + + if(nbuf < BIT16SZ) + return 0; + + p = buf; + ebuf = buf + nbuf; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++){ + if(sv[i]) + nsv[i] = strlen(sv[i]); + else + nsv[i] = 0; + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size before erroring, so user can know how much is needed */ + /* note that length excludes count field itself */ + PBIT16(p, ss-BIT16SZ); + p += BIT16SZ; + + if(ss > nbuf) + return BIT16SZ; + + PBIT16(p, d->type); + p += BIT16SZ; + PBIT32(p, d->dev); + p += BIT32SZ; + PBIT8(p, d->qid.type); + p += BIT8SZ; + PBIT32(p, d->qid.vers); + p += BIT32SZ; + PBIT64(p, d->qid.path); + p += BIT64SZ; + PBIT32(p, d->mode); + p += BIT32SZ; + PBIT32(p, d->atime); + p += BIT32SZ; + PBIT32(p, d->mtime); + p += BIT32SZ; + PBIT64(p, d->length); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + ns = nsv[i]; + if(p + ns + BIT16SZ > ebuf) + return 0; + PBIT16(p, ns); + p += BIT16SZ; + if(ns) + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} diff --git a/sys/src/libc/9sys/convM2D.c b/sys/src/libc/9sys/convM2D.c new file mode 100644 index 0000000..23a81c3 --- /dev/null +++ b/sys/src/libc/9sys/convM2D.c @@ -0,0 +1,103 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +statcheck(uint8_t *buf, uint nbuf) +{ + uint8_t *ebuf; + int i; + + ebuf = buf + nbuf; + + if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) + return -1; + + buf += STATFIXLEN - 4 * BIT16SZ; + + for(i = 0; i < 4; i++){ + if(buf + BIT16SZ > ebuf) + return -1; + buf += BIT16SZ + GBIT16(buf); + } + + if(buf != ebuf) + return -1; + + return 0; +} + +static char nullstring[] = ""; + +uint +convM2D(uint8_t *buf, uint nbuf, Dir *d, char *strs) +{ + uint8_t *p, *ebuf; + char *sv[4]; + int i, ns; + + if(nbuf < STATFIXLEN) + return 0; + + p = buf; + ebuf = buf + nbuf; + + p += BIT16SZ; /* ignore size */ + d->type = GBIT16(p); + p += BIT16SZ; + d->dev = GBIT32(p); + p += BIT32SZ; + d->qid.type = GBIT8(p); + p += BIT8SZ; + d->qid.vers = GBIT32(p); + p += BIT32SZ; + d->qid.path = GBIT64(p); + p += BIT64SZ; + d->mode = GBIT32(p); + p += BIT32SZ; + d->atime = GBIT32(p); + p += BIT32SZ; + d->mtime = GBIT32(p); + p += BIT32SZ; + d->length = GBIT64(p); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + if(p + BIT16SZ > ebuf) + return 0; + ns = GBIT16(p); + p += BIT16SZ; + if(p + ns > ebuf) + return 0; + if(strs){ + sv[i] = strs; + memmove(strs, p, ns); + strs += ns; + *strs++ = '\0'; + } + p += ns; + } + + if(strs){ + d->name = sv[0]; + d->uid = sv[1]; + d->gid = sv[2]; + d->muid = sv[3]; + }else{ + d->name = nullstring; + d->uid = nullstring; + d->gid = nullstring; + d->muid = nullstring; + } + + return p - buf; +} diff --git a/sys/src/libc/9sys/convM2S.c b/sys/src/libc/9sys/convM2S.c new file mode 100644 index 0000000..77dd743 --- /dev/null +++ b/sys/src/libc/9sys/convM2S.c @@ -0,0 +1,324 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static +uint8_t* +gstring(uint8_t *p, uint8_t *ep, char **s) +{ + uint n; + + if(p+BIT16SZ > ep) + return nil; + n = GBIT16(p); + p += BIT16SZ - 1; + if(p+n+1 > ep) + return nil; + /* move it down, on top of count, to make room for '\0' */ + memmove(p, p + 1, n); + p[n] = '\0'; + *s = (char*)p; + p += n+1; + return p; +} + +static +uint8_t* +gqid(uint8_t *p, uint8_t *ep, Qid *q) +{ + if(p+QIDSZ > ep) + return nil; + q->type = GBIT8(p); + p += BIT8SZ; + q->vers = GBIT32(p); + p += BIT32SZ; + q->path = GBIT64(p); + p += BIT64SZ; + return p; +} + +/* + * no syntactic checks. + * three causes for error: + * 1. message size field is incorrect + * 2. input buffer too short for its own data (counts too long, etc.) + * 3. too many names or qids + * gqid() and gstring() return nil if they would reach beyond buffer. + * main switch statement checks range and also can fall through + * to test at end of routine. + */ +uint +convM2S(uint8_t *ap, uint nap, Fcall *f) +{ + uint8_t *p, *ep; + uint i, size; + + p = ap; + ep = p + nap; + + if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) + return 0; + size = GBIT32(p); + p += BIT32SZ; + + if(size < BIT32SZ+BIT8SZ+BIT16SZ) + return 0; + + f->type = GBIT8(p); + p += BIT8SZ; + f->tag = GBIT16(p); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Tflush: + if(p+BIT16SZ > ep) + return 0; + f->oldtag = GBIT16(p); + p += BIT16SZ; + break; + + case Tauth: + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Tattach: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Twalk: + if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->newfid = GBIT32(p); + p += BIT32SZ; + f->nwname = GBIT16(p); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; inwname; i++){ + p = gstring(p, ep, &f->wname[i]); + if(p == nil) + break; + } + break; + + case Topen: + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tcreate: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->name); + if(p == nil) + break; + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->perm = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tread: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Twrite: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Tclunk: + case Tremove: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Tstat: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Twstat: + if(p+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + +/* + */ + case Rversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Rerror: + p = gstring(p, ep, &f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = gqid(p, ep, &f->aqid); + if(p == nil) + break; + break; + + case Rattach: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + break; + + case Rwalk: + if(p+BIT16SZ > ep) + return 0; + f->nwqid = GBIT16(p); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; inwqid; i++){ + p = gqid(p, ep, &f->wqid[i]); + if(p == nil) + break; + } + break; + + case Ropen: + case Rcreate: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + if(p+BIT32SZ > ep) + return 0; + f->iounit = GBIT32(p); + p += BIT32SZ; + break; + + case Rread: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Rwrite: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Rclunk: + case Rremove: + break; + + case Rstat: + if(p+BIT16SZ > ep) + return 0; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + + case Rwstat: + break; + } + + if(p==nil || p>ep) + return 0; + if(ap+size == p) + return size; + return 0; +} diff --git a/sys/src/libc/9sys/convS2M.c b/sys/src/libc/9sys/convS2M.c new file mode 100644 index 0000000..18cd1ec --- /dev/null +++ b/sys/src/libc/9sys/convS2M.c @@ -0,0 +1,398 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static +uint8_t* +pstring(uint8_t *p, char *s) +{ + uint n; + + if(s == nil){ + PBIT16(p, 0); + p += BIT16SZ; + return p; + } + + n = strlen(s); + /* + * We are moving the string before the length, + * so you can S2M a struct into an existing message + */ + memmove(p + BIT16SZ, s, n); + PBIT16(p, n); + p += n + BIT16SZ; + return p; +} + +static +uint8_t* +pqid(uint8_t *p, Qid *q) +{ + PBIT8(p, q->type); + p += BIT8SZ; + PBIT32(p, q->vers); + p += BIT32SZ; + PBIT64(p, q->path); + p += BIT64SZ; + return p; +} + +static +uint +stringsz(char *s) +{ + if(s == nil) + return BIT16SZ; + + return BIT16SZ+strlen(s); +} + +uint +sizeS2M(Fcall *f) +{ + uint n; + int i; + + n = 0; + n += BIT32SZ; /* size */ + n += BIT8SZ; /* type */ + n += BIT16SZ; /* tag */ + + switch(f->type) + { + default: + return 0; + + case Tversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Tflush: + n += BIT16SZ; + break; + + case Tauth: + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Tattach: + n += BIT32SZ; + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Twalk: + n += BIT32SZ; + n += BIT32SZ; + n += BIT16SZ; + for(i=0; inwname; i++) + n += stringsz(f->wname[i]); + break; + + case Topen: + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tcreate: + n += BIT32SZ; + n += stringsz(f->name); + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tread: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + break; + + case Twrite: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + n += f->count; + break; + + case Tclunk: + case Tremove: + n += BIT32SZ; + break; + + case Tstat: + n += BIT32SZ; + break; + + case Twstat: + n += BIT32SZ; + n += BIT16SZ; + n += f->nstat; + break; +/* + */ + + case Rversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Rerror: + n += stringsz(f->ename); + break; + + case Rflush: + break; + + case Rauth: + n += QIDSZ; + break; + + case Rattach: + n += QIDSZ; + break; + + case Rwalk: + n += BIT16SZ; + n += f->nwqid*QIDSZ; + break; + + case Ropen: + case Rcreate: + n += QIDSZ; + n += BIT32SZ; + break; + + case Rread: + n += BIT32SZ; + n += f->count; + break; + + case Rwrite: + n += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + n += BIT16SZ; + n += f->nstat; + break; + + case Rwstat: + break; + } + return n; +} + +uint +convS2M(Fcall *f, uint8_t *ap, uint nap) +{ + uint8_t *p; + uint i, size; + + size = sizeS2M(f); + if(size == 0) + return 0; + if(size > nap) + return 0; + + p = (uint8_t*)ap; + + PBIT32(p, size); + p += BIT32SZ; + PBIT8(p, f->type); + p += BIT8SZ; + PBIT16(p, f->tag); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Tflush: + PBIT16(p, f->oldtag); + p += BIT16SZ; + break; + + case Tauth: + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Tattach: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Twalk: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->newfid); + p += BIT32SZ; + PBIT16(p, f->nwname); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; inwname; i++) + p = pstring(p, f->wname[i]); + break; + + case Topen: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tcreate: + PBIT32(p, f->fid); + p += BIT32SZ; + p = pstring(p, f->name); + PBIT32(p, f->perm); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tread: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Twrite: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Tclunk: + case Tremove: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Tstat: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Twstat: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; +/* + */ + + case Rversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Rerror: + p = pstring(p, f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = pqid(p, &f->aqid); + break; + + case Rattach: + p = pqid(p, &f->qid); + break; + + case Rwalk: + PBIT16(p, f->nwqid); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; inwqid; i++) + p = pqid(p, &f->wqid[i]); + break; + + case Ropen: + case Rcreate: + p = pqid(p, &f->qid); + PBIT32(p, f->iounit); + p += BIT32SZ; + break; + + case Rread: + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Rwrite: + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; + + case Rwstat: + break; + } + if(size != p-ap) + return 0; + return size; +} diff --git a/sys/src/libc/9sys/cputime.c b/sys/src/libc/9sys/cputime.c new file mode 100644 index 0000000..fb0d92a --- /dev/null +++ b/sys/src/libc/9sys/cputime.c @@ -0,0 +1,25 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define HZ 1000 + +double +cputime(void) +{ + int32_t t[4]; + int i; + + times(t); + for(i=1; i<4; i++) + t[0] += t[i]; + return t[0] / (double)HZ; +} diff --git a/sys/src/libc/9sys/ctime.c b/sys/src/libc/9sys/ctime.c new file mode 100644 index 0000000..a907e18 --- /dev/null +++ b/sys/src/libc/9sys/ctime.c @@ -0,0 +1,316 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * This routine converts time as follows. + * The epoch is 0000 Jan 1 1970 GMT. + * The argument time is in seconds since then. + * The localtime(t) entry returns a pointer to an array + * containing + * + * seconds (0-59) + * minutes (0-59) + * hours (0-23) + * day of month (1-31) + * month (0-11) + * year-1970 + * weekday (0-6, Sun is 0) + * day of the year + * daylight savings flag + * + * The routine gets the daylight savings time from the environment. + * + * asctime(tvec)) + * where tvec is produced by localtime + * returns a ptr to a character string + * that has the ascii time in the form + * + * \\ + * Thu Jan 01 00:00:00 GMT 1970n0 + * 012345678901234567890123456789 + * 0 1 2 + * + * ctime(t) just calls localtime, then asctime. + */ + +#include +#include + +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * The following table is used for 1974 and 1975 and + * gives the day number of the first day after the Sunday of the + * change. + */ + +static int dysize(int); +static void ct_numb(char*, int); + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, int32_t*); +static +struct +{ + char stname[4]; + char dlname[4]; + int32_t stdiff; + int32_t dldiff; + int32_t dlpairs[TZSIZE]; +} timezone; + +char* +ctime(int32_t t) +{ + return asctime(localtime(t)); +} + +Tm* +localtime(int32_t tim) +{ + Tm *ct; + int32_t t, *p; + int dlflag; + + if(timezone.stname[0] == 0) + readtimezone(); + t = tim + timezone.stdiff; + dlflag = 0; + for(p = timezone.dlpairs; *p; p += 2) + if(t >= p[0]) + if(t < p[1]) { + t = tim + timezone.dldiff; + dlflag++; + break; + } + ct = gmtime(t); + if(dlflag){ + strcpy(ct->zone, timezone.dlname); + ct->tzoff = timezone.dldiff; + } else { + strcpy(ct->zone, timezone.stname); + ct->tzoff = timezone.stdiff; + } + return ct; +} + +Tm* +gmtime(int32_t tim) +{ + int d0, d1; + int32_t hms, day; + static Tm xtime; + + /* + * break initial number into days + */ + hms = (uint32_t)tim % 86400L; + day = (uint32_t)tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + xtime.sec = hms % 60; + d1 = hms / 60; + xtime.min = d1 % 60; + d1 /= 60; + xtime.hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + xtime.wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 1970; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 1970; day < 0; d1--) + day += dysize(d1-1); + xtime.year = d1-1900; + xtime.yday = d0 = day; + + /* + * generate month + */ + + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + xtime.mday = d0 + 1; + xtime.mon = d1; + strcpy(xtime.zone, "GMT"); + return &xtime; +} + +char* +asctime(Tm *t) +{ + char *ncp; + static char cbuf[30]; + + strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n"); + ncp = &"SunMonTueWedThuFriSat"[t->wday*3]; + cbuf[0] = *ncp++; + cbuf[1] = *ncp++; + cbuf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3]; + cbuf[4] = *ncp++; + cbuf[5] = *ncp++; + cbuf[6] = *ncp; + ct_numb(cbuf+8, t->mday); + ct_numb(cbuf+11, t->hour+100); + ct_numb(cbuf+14, t->min+100); + ct_numb(cbuf+17, t->sec+100); + ncp = t->zone; + cbuf[20] = *ncp++; + cbuf[21] = *ncp++; + cbuf[22] = *ncp; + if(t->year >= 100) { + cbuf[24] = '2'; + cbuf[25] = '0'; + } + ct_numb(cbuf+26, t->year+100); + return cbuf; +} + +static +int +dysize(int y) +{ + + if(y%4 == 0 && (y%100 != 0 || y%400 == 0)) + return 366; + return 365; +} + +static +void +ct_numb(char *cp, int n) +{ + + cp[0] = ' '; + if(n >= 10) + cp[0] = (n/10)%10 + '0'; + cp[1] = n%10 + '0'; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)){ + close(i); + goto error; + } + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; +} diff --git a/sys/src/libc/9sys/dial.c b/sys/src/libc/9sys/dial.c new file mode 100644 index 0000000..43f4b89 --- /dev/null +++ b/sys/src/libc/9sys/dial.c @@ -0,0 +1,560 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * dial - connect to a service (parallel version) + */ +#include +#include + +typedef struct Conn Conn; +typedef struct Dest Dest; +typedef struct DS DS; + +enum +{ + Maxstring = 128, + Maxpath = 256, + + Maxcsreply = 64*80, /* this is probably overly generous */ + /* + * this should be a plausible slight overestimate for non-interactive + * use even if it's ridiculously long for interactive use. + */ + Maxconnms = 2*60*1000, /* 2 minutes */ +}; + +struct DS { + /* dist string */ + char buf[Maxstring]; + char *netdir; + char *proto; + char *rem; + + /* other args */ + const char *local; + char *dir; + int *cfdp; +}; + +/* + * malloc these; they need to be writable by this proc & all children. + * the stack is private to each proc, and static allocation in the data + * segment would not permit concurrent dials within a multi-process program. + */ +struct Conn { + int pid; + int dead; + + int dfd; + int cfd; + char dir[NETPATHLEN+1]; + char err[ERRMAX]; +}; +struct Dest { + Conn *conn; /* allocated array */ + Conn *connend; + int nkid; + + int32_t oalarm; + int naddrs; + + QLock winlck; + int winner; /* index into conn[] */ + + char *nextaddr; + char addrlist[Maxcsreply]; +}; + +static int call(char*, char*, DS*, Dest*, Conn*); +static int csdial(DS*); +static void _dial_string_parse(const char*, DS*); + + +/* + * the dialstring is of the form '[/net/]proto!dest' + */ +static int +dialimpl(const char *dest, const char *local, char *dir, int *cfdp) +{ + DS ds; + int rv; + char err[ERRMAX], alterr[ERRMAX]; + + ds.local = local; + ds.dir = dir; + ds.cfdp = cfdp; + + _dial_string_parse(dest, &ds); + if(ds.netdir) + return csdial(&ds); + + ds.netdir = "/net"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + err[0] = '\0'; + errstr(err, sizeof err); + if(strstr(err, "refused") != 0){ + werrstr("%s", err); + return rv; + } + ds.netdir = "/net.alt"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + + alterr[0] = 0; + errstr(alterr, sizeof alterr); + if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) + werrstr("%s", err); + else + werrstr("%s", alterr); + return rv; +} + +/* + * the thread library can't cope with rfork(RFMEM|RFPROC), + * so it must override this with a private version of dial. + */ +int (*_dial)(const char *, const char *, char *, int *) = dialimpl; + +int +dial(const char *dest, const char *local, char *dir, int *cfdp) +{ + return (*_dial)(dest, local, dir, cfdp); +} + +static int +connsalloc(Dest *dp, int addrs) +{ + Conn *conn; + + free(dp->conn); + dp->connend = nil; + assert(addrs > 0); + + dp->conn = mallocz(addrs * sizeof *dp->conn, 1); + if(dp->conn == nil) + return -1; + dp->connend = dp->conn + addrs; + for(conn = dp->conn; conn < dp->connend; conn++) + conn->cfd = conn->dfd = -1; + return 0; +} + +static void +freedest(Dest *dp) +{ + int32_t oalarm; + + if (dp == nil) + return; + oalarm = dp->oalarm; + free(dp->conn); + free(dp); + if (oalarm >= 0) + alarm(oalarm); +} + +static void +closeopenfd(int *fdp) +{ + if (*fdp >= 0) { + close(*fdp); + *fdp = -1; + } +} + +static void +notedeath(Dest *dp, char *exitsts) +{ + int i, n, pid; + char *fields[5]; /* pid + 3 times + error */ + Conn *conn; + + for (i = 0; i < nelem(fields); i++) + fields[i] = ""; + n = tokenize(exitsts, fields, nelem(fields)); + if (n < 4) + return; + pid = atoi(fields[0]); + if (pid <= 0) + return; + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn->pid == pid && !conn->dead) { /* it's one we know? */ + if (conn - dp->conn != dp->winner) { + closeopenfd(&conn->dfd); + closeopenfd(&conn->cfd); + } + strncpy(conn->err, fields[4], sizeof conn->err - 1); + conn->err[sizeof conn->err - 1] = '\0'; + conn->dead = 1; + return; + } + /* not a proc that we forked */ +} + +static int +outstandingprocs(Dest *dp) +{ + Conn *conn; + + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + return 1; + return 0; +} + +static int +reap(Dest *dp) +{ + char exitsts[2*ERRMAX]; + + if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) { + notedeath(dp, exitsts); + return 0; + } + return -1; +} + +static int +fillinds(DS *ds, Dest *dp) +{ + Conn *conn; + + if (dp->winner < 0) + return -1; + conn = &dp->conn[dp->winner]; + if (ds->cfdp) + *ds->cfdp = conn->cfd; + if (ds->dir) { + strncpy(ds->dir, conn->dir, NETPATHLEN); + ds->dir[NETPATHLEN-1] = '\0'; + } + return conn->dfd; +} + +static int +connectwait(Dest *dp, char *besterr) +{ + Conn *conn; + + /* wait for a winner or all attempts to time out */ + while (dp->winner < 0 && reap(dp) >= 0) + ; + + /* kill all of our still-live kids & reap them */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + postnote(PNPROC, conn->pid, "alarm"); + while (reap(dp) >= 0) + ; + + /* rummage about and report some error string */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn - dp->conn != dp->winner && conn->dead && + conn->err[0]) { + strncpy(besterr, conn->err, ERRMAX-1); + besterr[ERRMAX-1] = '\0'; + break; + } + return dp->winner; +} + +static int +parsecs(Dest *dp, char **clonep, char **destp) +{ + char *dest, *p; + + dest = strchr(dp->nextaddr, ' '); + if(dest == nil) { + p = strchr(dp->nextaddr, '\n'); + if(p) + *p = '\0'; + werrstr("malformed clone cmd from cs `%s'", dp->nextaddr); + if(p) + *p = '\n'; + return -1; + } + *dest++ = '\0'; + p = strchr(dest, '\n'); + if(p == nil) + return -1; + *p++ = '\0'; + *clonep = dp->nextaddr; + *destp = dest; + dp->nextaddr = p; /* advance to next line */ + return 0; +} + +static void +pickuperr(char *besterr, char *err) +{ + err[0] = '\0'; + errstr(err, ERRMAX); + if(strstr(err, "does not exist") == 0) + strcpy(besterr, err); +} + +static int +catcher(void *v, char *s) +{ + return strstr(s, "alarm") != nil; +} + +/* + * try all addresses in parallel and take the first one that answers; + * this helps when systems have ip v4 and v6 addresses but are + * only reachable from here on one (or some) of them. + */ +static int +dialmulti(DS *ds, Dest *dp) +{ + int rv, kid, kidme; + char *clone, *dest; + char besterr[ERRMAX]; + + dp->winner = -1; + dp->nkid = 0; + while(dp->winner < 0 && *dp->nextaddr != '\0' && + parsecs(dp, &clone, &dest) >= 0) { + kidme = dp->nkid++; /* make private copy on stack */ + kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */ + if (kid < 0) + --dp->nkid; + else if (kid == 0) { + char err[ERRMAX]; + + /* only in kid, to avoid atnotify callbacks in parent */ + atnotify(catcher, 1); + + *besterr = '\0'; + rv = call(clone, dest, ds, dp, &dp->conn[kidme]); + if(rv < 0) + pickuperr(besterr, err); + _exits(besterr); /* avoid atexit callbacks */ + } + } + *besterr = '\0'; + rv = connectwait(dp, besterr); + if(rv < 0) + werrstr("%s", (*besterr? besterr: "unknown error")); + return rv; +} + +static int +csdial(DS *ds) +{ + int n, fd, rv, addrs, bleft; + char c; + char *addrp, *clone2, *dest; + char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX]; + Dest *dp; + + werrstr(""); + dp = mallocz(sizeof *dp, 1); + if(dp == nil) + return -1; + dp->winner = -1; + dp->oalarm = alarm(0); + if (connsalloc(dp, 1) < 0) { /* room for a single conn. */ + freedest(dp); + return -1; + } + + /* + * open connection server + */ + snprint(buf, sizeof(buf), "%s/cs", ds->netdir); + fd = open(buf, ORDWR); + if(fd < 0){ + /* no connection server, don't translate */ + snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); + rv = call(clone, ds->rem, ds, dp, &dp->conn[0]); + fillinds(ds, dp); + freedest(dp); + return rv; + } + + /* + * ask connection server to translate + * e.g., net!cs.bell-labs.com!smtp + */ + snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem); + if(write(fd, buf, strlen(buf)) < 0){ + close(fd); + freedest(dp); + return -1; + } + + /* + * read all addresses from the connection server: + * /net/tcp/clone 135.104.9.78!25 + * /net/tcp/clone 2620:0:dc0:1805::29!25 + * + * assumes that we'll get one record per read. + */ + seek(fd, 0, 0); + addrs = 0; + addrp = dp->nextaddr = dp->addrlist; + bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */ + while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) { + if (addrp[n-1] != '\n') + addrp[n++] = '\n'; + addrs++; + addrp += n; + bleft -= n; + } + *addrp = '\0'; + + /* + * if we haven't read all of cs's output, assume the last line might + * have been truncated and ignore it. we really don't expect this + * to happen. + */ + if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1) + addrs--; + close(fd); + + *besterr = 0; + rv = -1; /* pessimistic default */ + dp->naddrs = addrs; + if (addrs == 0) + werrstr("no address to dial"); + else if (addrs == 1) { + /* common case: dial one address without forking */ + if (parsecs(dp, &clone2, &dest) >= 0 && + (rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) { + pickuperr(besterr, err); + werrstr("%s", besterr); + } + } else if (connsalloc(dp, addrs) >= 0) + rv = dialmulti(ds, dp); + + /* fill in results */ + if (rv >= 0 && dp->winner >= 0) + rv = fillinds(ds, dp); + + freedest(dp); + return rv; +} + +static int +call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn) +{ + int fd, cfd, n, calleralarm, oalarm; + char cname[Maxpath], name[Maxpath], data[Maxpath], *p; + + /* because cs is in a different name space, replace the mount point */ + if(*clone == '/'){ + p = strchr(clone+1, '/'); + if(p == nil) + p = clone; + else + p++; + } else + p = clone; + snprint(cname, sizeof cname, "%s/%s", ds->netdir, p); + + conn->pid = getpid(); + conn->cfd = cfd = open(cname, ORDWR); + if(cfd < 0) + return -1; + + /* get directory name */ + n = read(cfd, name, sizeof(name)-1); + if(n < 0){ + closeopenfd(&conn->cfd); + return -1; + } + name[n] = 0; + for(p = name; *p == ' '; p++) + ; + snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0)); + p = strrchr(cname, '/'); + *p = 0; + if(ds->dir) + snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name); + snprint(data, sizeof(data), "%s/%s/data", cname, name); + + /* should be no alarm pending now; re-instate caller's alarm, if any */ + calleralarm = dp->oalarm > 0; + if (calleralarm) + alarm(dp->oalarm); + else if (dp->naddrs > 1) /* in a sub-process? */ + alarm(Maxconnms); + + /* connect */ + if(ds->local) + snprint(name, sizeof(name), "connect %s %s", dest, ds->local); + else + snprint(name, sizeof(name), "connect %s", dest); + if(write(cfd, name, strlen(name)) < 0){ + closeopenfd(&conn->cfd); + return -1; + } + + oalarm = alarm(0); /* don't let alarm interrupt critical section */ + if (calleralarm) + dp->oalarm = oalarm; /* time has passed, so update user's */ + + /* open data connection */ + conn->dfd = fd = open(data, ORDWR); + if(fd < 0){ + closeopenfd(&conn->cfd); + alarm(dp->oalarm); + return -1; + } + if(ds->cfdp == nil) + closeopenfd(&conn->cfd); + + n = conn - dp->conn; + if (dp->winner < 0) { + qlock(&dp->winlck); + if (dp->winner < 0 && conn < dp->connend) + dp->winner = n; + qunlock(&dp->winlck); + } + alarm(calleralarm? dp->oalarm: 0); + return fd; +} + +/* + * parse a dial string + */ +static void +_dial_string_parse(const char *str, DS *ds) +{ + char *p, *p2; + + strncpy(ds->buf, str, Maxstring); + ds->buf[Maxstring-1] = 0; + + p = strchr(ds->buf, '!'); + if(p == 0) { + ds->netdir = 0; + ds->proto = "net"; + ds->rem = ds->buf; + } else { + if(*ds->buf != '/' && *ds->buf != '#'){ + ds->netdir = 0; + ds->proto = ds->buf; + } else { + /* expecting /net.alt/tcp!foo or #I1/tcp!foo */ + for(p2 = p; p2 > ds->buf && *p2 != '/'; p2--) + ; + *p2++ = 0; + ds->netdir = ds->buf; + ds->proto = p2; + } + *p = 0; + ds->rem = p + 1; + } +} diff --git a/sys/src/libc/9sys/dirfstat.c b/sys/src/libc/9sys/dirfstat.c new file mode 100644 index 0000000..2f3eee4 --- /dev/null +++ b/sys/src/libc/9sys/dirfstat.c @@ -0,0 +1,46 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +Dir* +dirfstat(int fd) +{ + Dir *d; + uint8_t *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + BIT16SZ + nd); + if(d == nil) + return nil; + buf = (uint8_t*)&d[1]; + n = fstat(fd, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16(buf); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirfwstat.c b/sys/src/libc/9sys/dirfwstat.c new file mode 100644 index 0000000..193a0d9 --- /dev/null +++ b/sys/src/libc/9sys/dirfwstat.c @@ -0,0 +1,28 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +dirfwstat(int fd, Dir *d) +{ + uint8_t *buf; + int r; + + r = sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + convD2M(d, buf, r); + r = fwstat(fd, buf, r); + free(buf); + return r; +} diff --git a/sys/src/libc/9sys/dirmodefmt.c b/sys/src/libc/9sys/dirmodefmt.c new file mode 100644 index 0000000..3d25d69 --- /dev/null +++ b/sys/src/libc/9sys/dirmodefmt.c @@ -0,0 +1,57 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static char *modes[] = +{ + "---", + "--x", + "-w-", + "-wx", + "r--", + "r-x", + "rw-", + "rwx", +}; + +static void +rwx(int32_t m, char *s) +{ + strncpy(s, modes[m], 3); +} + +int +dirmodefmt(Fmt *f) +{ + static char buf[16]; + uint32_t m; + + m = va_arg(f->args, uint32_t); + + if(m & DMDIR) + buf[0]='d'; + else if(m & DMAPPEND) + buf[0]='a'; + else if(m & DMAUTH) + buf[0]='A'; + else + buf[0]='-'; + if(m & DMEXCL) + buf[1]='l'; + else + buf[1]='-'; + rwx((m>>6)&7, buf+2); + rwx((m>>3)&7, buf+5); + rwx((m>>0)&7, buf+8); + buf[11] = 0; + return fmtstrcpy(f, buf); +} diff --git a/sys/src/libc/9sys/dirread.c b/sys/src/libc/9sys/dirread.c new file mode 100644 index 0000000..1cafee3 --- /dev/null +++ b/sys/src/libc/9sys/dirread.c @@ -0,0 +1,106 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static +int32_t +dirpackage(uint8_t *buf, int32_t ts, Dir **d) +{ + char *s; + int32_t ss, i, n, nn, m; + + *d = nil; + if(ts <= 0) + return 0; + + /* + * first find number of all stats, check they look like stats, & size all associated strings + */ + ss = 0; + n = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16(&buf[i]); + if(statcheck(&buf[i], m) < 0) + break; + ss += m; + n++; + } + + if(i != ts) + return -1; + + *d = malloc(n * sizeof(Dir) + ss); + if(*d == nil) + return -1; + + /* + * then convert all buffers + */ + s = (char*)*d + n * sizeof(Dir); + nn = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16((uint8_t*)&buf[i]); + if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ + free(*d); + *d = nil; + return -1; + } + nn++; + s += m; + } + + return nn; +} + +int32_t +dirread(int fd, Dir **d) +{ + uint8_t *buf; + int32_t ts; + + buf = malloc(DIRMAX); + if(buf == nil) + return -1; + ts = read(fd, buf, DIRMAX); + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + return ts; +} + +int32_t +dirreadall(int fd, Dir **d) +{ + uint8_t *buf, *nbuf; + int32_t n, ts; + + buf = nil; + ts = 0; + for(;;){ + nbuf = realloc(buf, ts+DIRMAX); + if(nbuf == nil){ + free(buf); + return -1; + } + buf = nbuf; + n = read(fd, buf+ts, DIRMAX); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + if(ts == 0 && n < 0) + return -1; + return ts; +} diff --git a/sys/src/libc/9sys/dirstat.c b/sys/src/libc/9sys/dirstat.c new file mode 100644 index 0000000..75116b7 --- /dev/null +++ b/sys/src/libc/9sys/dirstat.c @@ -0,0 +1,46 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +Dir* +dirstat(const char *name) +{ + Dir *d; + uint8_t *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + BIT16SZ + nd); + if(d == nil) + return nil; + buf = (uint8_t*)&d[1]; + n = stat(name, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16((uint8_t*)buf); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirwstat.c b/sys/src/libc/9sys/dirwstat.c new file mode 100644 index 0000000..f6c19eb --- /dev/null +++ b/sys/src/libc/9sys/dirwstat.c @@ -0,0 +1,28 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +dirwstat(const char *name, Dir *d) +{ + uint8_t *buf; + int r; + + r = sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + convD2M(d, buf, r); + r = wstat(name, buf, r); + free(buf); + return r; +} diff --git a/sys/src/libc/9sys/fcallfmt.c b/sys/src/libc/9sys/fcallfmt.c new file mode 100644 index 0000000..6c1f21b --- /dev/null +++ b/sys/src/libc/9sys/fcallfmt.c @@ -0,0 +1,244 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +static uint dumpsome(char*, char*, char*, int32_t); +static void fdirconv(char*, char*, Dir*); +static char *qidtype(char*, uint8_t); + +#define QIDFMT "(%.16llux %lud %s)" + +int +fcallfmt(Fmt *fmt) +{ + Fcall *f; + int fid, type, tag, i; + char buf[512], tmp[200]; + char *p, *e; + Dir *d; + Qid *q; + + e = buf+sizeof(buf); + f = va_arg(fmt->args, Fcall*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tversion: /* 100 */ + seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Rversion: + seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Tauth: /* 102 */ + seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, + f->afid, f->uname, f->aname); + break; + case Rauth: + seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, + f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); + break; + case Tattach: /* 104 */ + seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, + fid, f->afid, f->uname, f->aname); + break; + case Rattach: + seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); + break; + case Rerror: /* 107; 106 (Terror) illegal */ + seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); + break; + case Tflush: /* 108 */ + seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); + break; + case Rflush: + seprint(buf, e, "Rflush tag %ud", tag); + break; + case Twalk: /* 110 */ + p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); + if(f->nwname <= MAXWELEM) + for(i=0; inwname; i++) + p = seprint(p, e, "%d:%s ", i, f->wname[i]); + break; + case Rwalk: + p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); + if(f->nwqid <= MAXWELEM) + for(i=0; inwqid; i++){ + q = &f->wqid[i]; + p = seprint(p, e, "%d:" QIDFMT " ", i, + q->path, q->vers, qidtype(tmp, q->type)); + } + break; + case Topen: /* 112 */ + seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); + break; + case Ropen: + seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tcreate: /* 114 */ + seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, + (uint32_t)f->perm, f->mode); + break; + case Rcreate: + seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tread: /* 116 */ + seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", + tag, fid, f->offset, f->count); + break; + case Rread: + p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Twrite: /* 118 */ + p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", + tag, fid, f->offset, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Rwrite: + seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); + break; + case Tclunk: /* 120 */ + seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); + break; + case Rclunk: + seprint(buf, e, "Rclunk tag %ud", tag); + break; + case Tremove: /* 122 */ + seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); + break; + case Rremove: + seprint(buf, e, "Rremove tag %ud", tag); + break; + case Tstat: /* 124 */ + seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); + break; + case Rstat: + p = seprint(buf, e, "Rstat tag %ud ", tag); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Twstat: /* 126 */ + p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Rwstat: + seprint(buf, e, "Rwstat tag %ud", tag); + break; + default: + seprint(buf, e, "unknown type %d", type); + } + return fmtstrcpy(fmt, buf); +} + +static char* +qidtype(char *s, uint8_t t) +{ + char *p; + + p = s; + if(t & QTDIR) + *p++ = 'd'; + if(t & QTAPPEND) + *p++ = 'a'; + if(t & QTEXCL) + *p++ = 'l'; + if(t & QTAUTH) + *p++ = 'A'; + *p = '\0'; + return s; +} + +int +dirfmt(Fmt *fmt) +{ + char buf[160]; + + fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); + return fmtstrcpy(fmt, buf); +} + +static void +fdirconv(char *buf, char *e, Dir *d) +{ + char tmp[16]; + + seprint(buf, e, "'%s' '%s' '%s' '%s' " + "q " QIDFMT " m %#luo " + "at %ld mt %ld l %lld " + "t %d d %d", + d->name, d->uid, d->gid, d->muid, + d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, + d->atime, d->mtime, d->length, + d->type, d->dev); +} + +/* + * dump out count (or DUMPL, if count is bigger) bytes from + * buf to ans, as a string if they are all printable, + * else as a series of hex bytes + */ +#define DUMPL 64 + +static uint +dumpsome(char *ans, char *e, char *buf, int32_t count) +{ + int i, printable; + char *p; + + if(buf == nil){ + seprint(ans, e, ""); + return strlen(ans); + } + printable = 1; + if(count > DUMPL) + count = DUMPL; + for(i=0; i127) + printable = 0; + p = ans; + *p++ = '\''; + if(printable){ + if(count > e-p-2) + count = e-p-2; + memmove(p, buf, count); + p += count; + }else{ + if(2*count > e-p-2) + count = (e-p-2)/2; + for(i=0; i0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", (uint8_t)buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; + return p - ans; +} diff --git a/sys/src/libc/9sys/fork.c b/sys/src/libc/9sys/fork.c new file mode 100644 index 0000000..bc086d0 --- /dev/null +++ b/sys/src/libc/9sys/fork.c @@ -0,0 +1,17 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +fork(void) +{ + return rfork(RFPROC|RFFDG|RFREND); +} diff --git a/sys/src/libc/9sys/getenv.c b/sys/src/libc/9sys/getenv.c new file mode 100644 index 0000000..f0cdd09 --- /dev/null +++ b/sys/src/libc/9sys/getenv.c @@ -0,0 +1,45 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +getenv(const char *name) +{ + int r, f; + int32_t s; + char *ans; + char *p, *ep, ename[100]; + + if(strchr(name, '/') != nil) + return nil; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return nil; + f = open(ename, OREAD); + if(f < 0) + return 0; + s = seek(f, 0, 2); + ans = malloc(s+1); + if(ans) { + setmalloctag(ans, getcallerpc()); + seek(f, 0, 0); + r = read(f, ans, s); + if(r >= 0) { + ep = ans + s - 1; + for(p = ans; p < ep; p++) + if(*p == '\0') + *p = ' '; + ans[s] = '\0'; + } + } + close(f); + return ans; +} diff --git a/sys/src/libc/9sys/getnetconninfo.c b/sys/src/libc/9sys/getnetconninfo.c new file mode 100644 index 0000000..1348b4e --- /dev/null +++ b/sys/src/libc/9sys/getnetconninfo.c @@ -0,0 +1,142 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static char *unknown = "???"; + +static void +getendpoint(char *dir, char *file, char **sysp, char **servp) +{ + int fd, n; + char buf[128]; + char *sys, *serv; + + sys = serv = 0; + + snprint(buf, sizeof buf, "%s/%s", dir, file); + fd = open(buf, OREAD); + if(fd >= 0){ + n = read(fd, buf, sizeof(buf)-1); + if(n>0){ + buf[n-1] = 0; + serv = strchr(buf, '!'); + if(serv){ + *serv++ = 0; + serv = strdup(serv); + } + sys = strdup(buf); + } + close(fd); + } + if(serv == 0) + serv = unknown; + if(sys == 0) + sys = unknown; + *servp = serv; + *sysp = sys; +} + +NetConnInfo* +getnetconninfo(const char *dir, int fd) +{ + NetConnInfo *nci; + char *cp; + Dir *d; + char spec[10]; + char path[128]; + char netname[128], *p; + + /* get a directory address via fd */ + if(dir == nil || *dir == 0){ + if(fd2path(fd, path, sizeof(path)) < 0) + return nil; + cp = strrchr(path, '/'); + if(cp == nil) + return nil; + *cp = 0; + dir = path; + } + + nci = mallocz(sizeof *nci, 1); + if(nci == nil) + return nil; + + /* copy connection directory */ + nci->dir = strdup(dir); + if(nci->dir == nil) + goto err; + + /* get netroot */ + nci->root = strdup(dir); + if(nci->root == nil) + goto err; + cp = strchr(nci->root+1, '/'); + if(cp == nil) + goto err; + *cp = 0; + + /* figure out bind spec */ + d = dirstat(nci->dir); + if(d != nil){ + sprint(spec, "#%C%d", d->type, d->dev); + nci->spec = strdup(spec); + } + if(nci->spec == nil) + nci->spec = unknown; + free(d); + + /* get the two end points */ + getendpoint(nci->dir, "local", &nci->lsys, &nci->lserv); + if(nci->lsys == nil || nci->lserv == nil) + goto err; + getendpoint(nci->dir, "remote", &nci->rsys, &nci->rserv); + if(nci->rsys == nil || nci->rserv == nil) + goto err; + + strecpy(netname, netname+sizeof netname, nci->dir); + if((p = strrchr(netname, '/')) != nil) + *p = 0; + if(strncmp(netname, "/net/", 5) == 0) + memmove(netname, netname+5, strlen(netname+5)+1); + nci->laddr = smprint("%s!%s!%s", netname, nci->lsys, nci->lserv); + nci->raddr = smprint("%s!%s!%s", netname, nci->rsys, nci->rserv); + if(nci->laddr == nil || nci->raddr == nil) + goto err; + return nci; +err: + freenetconninfo(nci); + return nil; +} + +static void +xfree(char *x) +{ + if(x == nil || x == unknown) + return; + free(x); +} + +void +freenetconninfo(NetConnInfo *nci) +{ + if(nci == nil) + return; + xfree(nci->root); + xfree(nci->dir); + xfree(nci->spec); + xfree(nci->lsys); + xfree(nci->lserv); + xfree(nci->rsys); + xfree(nci->rserv); + xfree(nci->laddr); + xfree(nci->raddr); + free(nci); +} diff --git a/sys/src/libc/9sys/getpid.c b/sys/src/libc/9sys/getpid.c new file mode 100644 index 0000000..5bf24d5 --- /dev/null +++ b/sys/src/libc/9sys/getpid.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +getpid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("#c/pid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getppid.c b/sys/src/libc/9sys/getppid.c new file mode 100644 index 0000000..f0ebf03 --- /dev/null +++ b/sys/src/libc/9sys/getppid.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +getppid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("/dev/ppid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getwd.c b/sys/src/libc/9sys/getwd.c new file mode 100644 index 0000000..4834c1e --- /dev/null +++ b/sys/src/libc/9sys/getwd.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +getwd(char *buf, int nbuf) +{ + int n, fd; + + fd = open(".", OREAD); + if(fd < 0) + return nil; + n = fd2path(fd, buf, nbuf); + close(fd); + if(n < 0) + return nil; + return buf; +} diff --git a/sys/src/libc/9sys/iounit.c b/sys/src/libc/9sys/iounit.c new file mode 100644 index 0000000..834dec2 --- /dev/null +++ b/sys/src/libc/9sys/iounit.c @@ -0,0 +1,36 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * Format: + 3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain + */ + +int +iounit(int fd) +{ + int i, cfd; + char buf[128], *args[10]; + + snprint(buf, sizeof buf, "#d/%dctl", fd); + cfd = open(buf, OREAD); + if(cfd < 0) + return 0; + i = read(cfd, buf, sizeof buf-1); + close(cfd); + if(i <= 0) + return 0; + buf[i] = '\0'; + if(tokenize(buf, args, nelem(args)) != nelem(args)) + return 0; + return atoi(args[7]); +} diff --git a/sys/src/libc/9sys/nulldir.c b/sys/src/libc/9sys/nulldir.c new file mode 100644 index 0000000..0d3a17e --- /dev/null +++ b/sys/src/libc/9sys/nulldir.c @@ -0,0 +1,18 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +nulldir(Dir *d) +{ + memset(d, ~0, sizeof(Dir)); + d->name = d->uid = d->gid = d->muid = ""; +} diff --git a/sys/src/libc/9sys/postnote.c b/sys/src/libc/9sys/postnote.c new file mode 100644 index 0000000..e5c9eb3 --- /dev/null +++ b/sys/src/libc/9sys/postnote.c @@ -0,0 +1,41 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +postnote(int group, int pid, const char *note) +{ + char file[128]; + int f, r; + + switch(group) { + case PNPROC: + sprint(file, "/proc/%d/note", pid); + break; + case PNGROUP: + sprint(file, "/proc/%d/notepg", pid); + break; + default: + return -1; + } + + f = open(file, OWRITE); + if(f < 0) + return -1; + + r = strlen(note); + if(write(f, note, r) != r) { + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/privalloc.c b/sys/src/libc/9sys/privalloc.c new file mode 100644 index 0000000..c64137e --- /dev/null +++ b/sys/src/libc/9sys/privalloc.c @@ -0,0 +1,54 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static Lock privlock; +static int privinit = 0; +static void **privs; + +extern void **_privates; +extern int _nprivates; + +void ** +privalloc(void) +{ + void **p; + int i; + lock(&privlock); + if(!privinit){ + privinit = 1; + if(_nprivates){ + _privates[0] = 0; + for(i = 1; i < _nprivates; i++) + _privates[i] = &_privates[i - 1]; + privs = &_privates[i - 1]; + } + } + p = privs; + if(p != nil){ + privs = *p; + *p = nil; + } + unlock(&privlock); + + return p; +} + +void +privfree(void **p) +{ + lock(&privlock); + if(p != nil && privinit){ + *p = privs; + privs = p; + } + unlock(&privlock); +} diff --git a/sys/src/libc/9sys/pushssl.c b/sys/src/libc/9sys/pushssl.c new file mode 100644 index 0000000..3f2b2c8 --- /dev/null +++ b/sys/src/libc/9sys/pushssl.c @@ -0,0 +1,53 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * Since the SSL device uses decimal file descriptors to name channels, + * it is impossible for a user-level file server to stand in for the kernel device. + * Thus we hard-code #D rather than use /net/ssl. + */ + +int +pushssl(int fd, const char *alg, const char *secin, const char *secout, int *cfd) +{ + char buf[8]; + char dname[64]; + int n, data, ctl; + + ctl = open("#D/ssl/clone", ORDWR); + if(ctl < 0) + return -1; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0) + goto error; + buf[n] = 0; + sprint(dname, "#D/ssl/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0) + goto error; + if(fprint(ctl, "fd %d", fd) < 0 || + fprint(ctl, "secretin %s", secin) < 0 || + fprint(ctl, "secretout %s", secout) < 0 || + fprint(ctl, "alg %s", alg) < 0){ + close(data); + goto error; + } + close(fd); + if(cfd != 0) + *cfd = ctl; + else + close(ctl); + return data; +error: + close(ctl); + return -1; +} diff --git a/sys/src/libc/9sys/putenv.c b/sys/src/libc/9sys/putenv.c new file mode 100644 index 0000000..0276303 --- /dev/null +++ b/sys/src/libc/9sys/putenv.c @@ -0,0 +1,35 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +putenv(const char *name, const char *val) +{ + int f; + char ename[100]; + int32_t s; + + if(strchr(name, '/') != nil) + return -1; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return -1; + f = create(ename, OWRITE, 0664); + if(f < 0) + return -1; + s = strlen(val); + if(write(f, val, s) != s){ + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/qlock.c b/sys/src/libc/9sys/qlock.c new file mode 100644 index 0000000..9f75ebf --- /dev/null +++ b/sys/src/libc/9sys/qlock.c @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2015 Giacomo Tesio + * + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static struct { + QLp *p; + QLp x[1024]; +} ql = { + ql.x +}; + +enum +{ + Queuing, + QueuingR, + QueuingW, + Sleeping, +}; + +static void* (*_rendezvousp)(void*, void*) = rendezvous; + +/* this gets called by the thread library ONLY to get us to use its rendezvous */ +void +_qlockinit(void* (*r)(void*, void*)) +{ + _rendezvousp = r; +} + +/* find a free shared memory location to queue ourselves in */ +static QLp* +getqlp(void) +{ + QLp *p, *op; + + op = ql.p; + for(p = op+1; ; p++){ + if(p == &ql.x[nelem(ql.x)]) + p = ql.x; + if(p == op) + abort(); + if(_tas(&(p->inuse)) == 0){ + ql.p = p; + p->next = nil; + break; + } + } + return p; +} +static void +releaseqlp(QLp **head, QLp **tail, QLp *mp) +{ + /* NOTE: we assume a lock is held during the execution to prevent + * modifications to the chain + */ + QLp *p; + + p = *head; + while(p != nil && p != mp && p->next != mp && p != *tail) + p = p->next; + if(p == nil) + abort(); /* mp must be somewhere */ + + if(p == mp){ + /* mp was head */ + *head = mp->next; + } else { + p->next = mp->next; + } + if(*head == nil) + *tail = nil; + mp->inuse = 0; +} + +void +qlock(QLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return; + } + + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->state = Queuing; + unlock(&q->lock); + + /* wait */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +void +qunlock(QLock *q) +{ + QLp *p; + + lock(&q->lock); + if (q->locked == 0) + fprint(2, "qunlock called with qlock not held, from %#p\n", + getcallerpc()); + p = q->head; + if(p != nil){ + /* wakeup head waiting process */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0) + ; + return; + } + q->locked = 0; + unlock(&q->lock); +} + +int +qlockt(QLock *q, uint32_t ms) +{ + QLp *p, *mp; + int64_t wkup; + + /* set up awake to interrupt rendezvous */ + wkup = awake(ms); + + if(!lockt(&q->lock, ms)){ + forgivewkp(wkup); + return 0; + } + + if(!q->locked){ + forgivewkp(wkup); + q->locked = 1; + unlock(&q->lock); + return 1; + } + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->state = Queuing; + + if (awakened(wkup)) { /* do not miss already occurred wakeups */ + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + + unlock(&q->lock); + + /* wait */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + if (awakened(wkup)){ + /* interrupted by awake */ + lock(&q->lock); + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + + forgivewkp(wkup); + mp->inuse = 0; + + return 1; +} + +int +canqlock(QLock *q) +{ + if(!canlock(&q->lock)) + return 0; + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +rlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->writer == 0 && q->head == nil){ + /* no writer, go for it */ + q->_readers++; + unlock(&q->lock); + return; + } + + mp = getqlp(); + p = q->tail; + if(p == 0) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingR; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +int +rlockt(RWLock *q, uint32_t ms) +{ + QLp *p, *mp; + int64_t wkup; + + /* set up awake to interrupt rendezvous */ + wkup = awake(ms); + + if(!lockt(&q->lock, ms)) { + forgivewkp(wkup); + return 0; + } + + if(q->writer == 0 && q->head == nil){ + /* no writer, go for it */ + forgivewkp(wkup); + q->_readers++; + unlock(&q->lock); + return 1; + } + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == 0) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingR; + + if (awakened(wkup)) { /* do not miss already occurred wakeups */ + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + if (awakened(wkup)){ + /* interrupted by awake */ + lock(&q->lock); + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + + forgivewkp(wkup); + mp->inuse = 0; + + return 1; +} + +int +canrlock(RWLock *q) +{ + lock(&q->lock); + if (q->writer == 0 && q->head == nil) { + /* no writer; go for it */ + q->_readers++; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +runlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->_readers <= 0) + abort(); + p = q->head; + if(--(q->_readers) > 0 || p == nil){ + unlock(&q->lock); + return; + } + + /* start waiting writer */ + if(p->state != QueuingW) + abort(); + q->head = p->next; + if(q->head == 0) + q->tail = 0; + q->writer = 1; + unlock(&q->lock); + + /* wakeup waiter */ + while((*_rendezvousp)(p, 0) == (void*)~0) + ; +} + +void +wlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->_readers == 0 && q->writer == 0){ + /* noone waiting, go for it */ + q->writer = 1; + unlock(&q->lock); + return; + } + + /* chain into waiting list */ + p = q->tail; + mp = getqlp(); + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingW; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + + mp->inuse = 0; +} + + +int +wlockt(RWLock *q, uint32_t ms) +{ + QLp *p, *mp; + int64_t wkup; + + /* set up awake to interrupt rendezvous */ + wkup = awake(ms); + + if(!lockt(&q->lock, ms)) { + forgivewkp(wkup); + return 0; + } + + if(q->_readers == 0 && q->writer == 0){ + /* noone waiting, go for it */ + forgivewkp(wkup); + q->writer = 1; + unlock(&q->lock); + return 1; + } + + /* chain into waiting list */ + p = q->tail; + mp = getqlp(); + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingW; + + if (awakened(wkup)) { /* do not miss already occurred wakeups */ + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + if (awakened(wkup)){ + /* interrupted by awake */ + lock(&q->lock); + releaseqlp(&q->head, &q->tail, mp); + unlock(&q->lock); + return 0; + } + forgivewkp(wkup); + mp->inuse = 0; + + return 1; +} + +int +canwlock(RWLock *q) +{ + lock(&q->lock); + if (q->_readers == 0 && q->writer == 0) { + /* no one waiting; go for it */ + q->writer = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +wunlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->writer == 0) + abort(); + p = q->head; + if(p == nil){ + q->writer = 0; + unlock(&q->lock); + return; + } + if(p->state == QueuingW){ + /* start waiting writer */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)(p, 0) == (void*)~0) + ; + return; + } + + if(p->state != QueuingR) + abort(); + + /* wake waiting readers */ + while(q->head != nil && q->head->state == QueuingR){ + p = q->head; + q->head = p->next; + q->_readers++; + while((*_rendezvousp)(p, 0) == (void*)~0) + ; + } + if(q->head == nil) + q->tail = nil; + q->writer = 0; + unlock(&q->lock); +} + +void +rsleep(Rendez *r) +{ + QLp *t, *me; + + if(!r->l) + abort(); + lock(&r->l->lock); + /* we should hold the qlock */ + if(!r->l->locked) + abort(); + + /* add ourselves to the wait list */ + me = getqlp(); + me->state = Sleeping; + if(r->head == nil) + r->head = me; + else + r->tail->next = me; + me->next = nil; + r->tail = me; + + /* pass the qlock to the next guy */ + t = r->l->head; + if(t){ + r->l->head = t->next; + if(r->l->head == nil) + r->l->tail = nil; + unlock(&r->l->lock); + while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a wakeup */ + while((*_rendezvousp)(me, (void*)1) == (void*)~0) + ; + me->inuse = 0; +} + +int +rsleept(Rendez *r, uint32_t ms) +{ + QLp *t, *me; + int64_t wkup; + + if(!r->l) + abort(); + + /* set up awake to interrupt rendezvous */ + wkup = awake(ms); + + if(!lockt(&r->l->lock, ms)){ + forgivewkp(wkup); + return 0; + } + + /* we should hold the qlock */ + if(!r->l->locked) + abort(); + + /* add ourselves to the wait list */ + me = getqlp(); + me->state = Sleeping; + if(r->head == nil) + r->head = me; + else + r->tail->next = me; + me->next = nil; + r->tail = me; + + /* pass the qlock to the next guy */ + t = r->l->head; + if(t){ + r->l->head = t->next; + if(r->l->head == nil) + r->l->tail = nil; + unlock(&r->l->lock); + + while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a rwakeup (or a timeout) */ + do + { + if (awakened(wkup)){ + /* interrupted by awake */ + lock(&r->l->lock); + releaseqlp(&r->head, &r->tail, me); + unlock(&r->l->lock); + return 0; + } + } + while((*_rendezvousp)(me, (void*)1) == (void*)~0); + + forgivewkp(wkup); + me->inuse = 0; + + return 1; +} + +int +rwakeup(Rendez *r) +{ + QLp *t; + + /* + * take off wait and put on front of queue + * put on front so guys that have been waiting will not get starved + */ + + if(!r->l) + abort(); + lock(&r->l->lock); + if(!r->l->locked) + abort(); + + t = r->head; + if(t == nil){ + unlock(&r->l->lock); + return 0; + } + + r->head = t->next; + if(r->head == nil) + r->tail = nil; + + t->next = r->l->head; + r->l->head = t; + if(r->l->tail == nil) + r->l->tail = t; + + t->state = Queuing; + unlock(&r->l->lock); + return 1; +} + +int +rwakeupall(Rendez *r) +{ + int i; + + for(i=0; rwakeup(r); i++) + ; + return i; +} + diff --git a/sys/src/libc/9sys/read.c b/sys/src/libc/9sys/read.c new file mode 100644 index 0000000..5e579b4 --- /dev/null +++ b/sys/src/libc/9sys/read.c @@ -0,0 +1,26 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2015 Giacomo Tesio + * + * Jehanne 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, version 2 of the License. + * + * Jehanne 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 Jehanne. If not, see . + */ + +#include +#include + +int32_t +read(int fd, void* buf, int32_t nbytes) +{ + return pread(fd, buf, nbytes, ~0LL); +} diff --git a/sys/src/libc/9sys/read9pmsg.c b/sys/src/libc/9sys/read9pmsg.c new file mode 100644 index 0000000..4d521f1 --- /dev/null +++ b/sys/src/libc/9sys/read9pmsg.c @@ -0,0 +1,40 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +read9pmsg(int fd, void *abuf, uint n) +{ + int m, len; + uint8_t *buf; + + buf = abuf; + + /* read count */ + m = readn(fd, buf, BIT32SZ); + if(m != BIT32SZ){ + if(m < 0) + return -1; + return 0; + } + + len = GBIT32(buf); + if(len <= BIT32SZ || len > n){ + werrstr("bad length in 9P2000 message header"); + return -1; + } + len -= BIT32SZ; + m = readn(fd, buf+BIT32SZ, len); + if(m < len) + return 0; + return BIT32SZ+m; +} diff --git a/sys/src/libc/9sys/readv.c b/sys/src/libc/9sys/readv.c new file mode 100644 index 0000000..7280e69 --- /dev/null +++ b/sys/src/libc/9sys/readv.c @@ -0,0 +1,58 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static +int32_t +ioreadv(int fd, IOchunk *io, int nio, int64_t offset) +{ + int i; + int32_t m, n, tot; + char *buf, *p; + + tot = 0; + for(i=0; ilen; + if(m > n) + m = n; + memmove(io->addr, p, m); + n -= m; + p += m; + io++; + } + + free(buf); + return tot; +} + +int32_t +readv(int fd, IOchunk *io, int nio) +{ + return ioreadv(fd, io, nio, -1LL); +} + +int32_t +preadv(int fd, IOchunk *io, int nio, int64_t off) +{ + return ioreadv(fd, io, nio, off); +} diff --git a/sys/src/libc/9sys/rerrstr.c b/sys/src/libc/9sys/rerrstr.c new file mode 100644 index 0000000..fd7d95c --- /dev/null +++ b/sys/src/libc/9sys/rerrstr.c @@ -0,0 +1,22 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +rerrstr(char *buf, uint nbuf) +{ + char tmp[ERRMAX]; + + tmp[0] = 0; + errstr(tmp, sizeof tmp); + utfecpy(buf, buf+nbuf, tmp); + errstr(tmp, sizeof tmp); +} diff --git a/sys/src/libc/9sys/sbrk.c b/sys/src/libc/9sys/sbrk.c new file mode 100644 index 0000000..95c565a --- /dev/null +++ b/sys/src/libc/9sys/sbrk.c @@ -0,0 +1,44 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +extern char end[]; +static char *bloc = { end }; +extern int brk_(void*); + +enum +{ + Round = 7 +}; + +int +brk(void *p) +{ + uintptr bl; + + bl = ((uintptr)p + Round) & ~Round; + if(brk_((void*)bl) < 0) + return -1; + bloc = (char*)bl; + return 0; +} + +void* +sbrk(uint32_t n) +{ + uintptr bl; + + bl = ((uintptr)bloc + Round) & ~Round; + if(brk_((void*)(bl+n)) < 0) + return (void*)-1; + bloc = (char*)bl + n; + return (void*)bl; +} diff --git a/sys/src/libc/9sys/setnetmtpt.c b/sys/src/libc/9sys/setnetmtpt.c new file mode 100644 index 0000000..48f2cd2 --- /dev/null +++ b/sys/src/libc/9sys/setnetmtpt.c @@ -0,0 +1,25 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +setnetmtpt(char *net, int n, const char *x) +{ + if(x == nil) + x = "/net"; + + if(*x == '/'){ + strncpy(net, x, n); + net[n-1] = 0; + } else { + snprint(net, n, "/net%s", x); + } +} diff --git a/sys/src/libc/9sys/sleep.c b/sys/src/libc/9sys/sleep.c new file mode 100644 index 0000000..04390c3 --- /dev/null +++ b/sys/src/libc/9sys/sleep.c @@ -0,0 +1,31 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2015 Giacomo Tesio + * + * Jehanne 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, version 2 of the License. + * + * Jehanne 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 Jehanne. If not, see . + */ + +#include +#include + +void +sleep(int32_t millisecs) +{ + int64_t wakeup; + + wakeup = awake(millisecs); + + while(!awakened(wakeup) && rendezvous(&wakeup, (void*)1) == (void*)~0) + ; +} diff --git a/sys/src/libc/9sys/sysfatal.c b/sys/src/libc/9sys/sysfatal.c new file mode 100644 index 0000000..f297f29 --- /dev/null +++ b/sys/src/libc/9sys/sysfatal.c @@ -0,0 +1,37 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + + +static void +_sysfatalimpl(const char *fmt, va_list arg) +{ + char buf[1024]; + + vseprint(buf, buf+sizeof(buf), fmt, arg); + if(argv0) + fprint(2, "%s: %s\n", argv0, buf); + else + fprint(2, "%s\n", buf); + exits(buf); +} + +void (*_sysfatal)(const char *fmt, va_list arg) = _sysfatalimpl; + +void +sysfatal(const char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + (*_sysfatal)(fmt, arg); + va_end(arg); +} diff --git a/sys/src/libc/9sys/syslog.c b/sys/src/libc/9sys/syslog.c new file mode 100644 index 0000000..196f479 --- /dev/null +++ b/sys/src/libc/9sys/syslog.c @@ -0,0 +1,125 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static struct +{ + int fd; + int consfd; + char *name; + Dir *d; + Dir *consd; + Lock; +} sl = +{ + -1, -1, +}; + +static void +_syslogopen(void) +{ + char buf[1024]; + + if(sl.fd >= 0) + close(sl.fd); + snprint(buf, sizeof(buf), "/sys/log/%s", sl.name); + sl.fd = open(buf, OWRITE|OCEXEC); +} + +static int +eqdirdev(Dir *a, Dir *b) +{ + return a != nil && b != nil && + a->dev == b->dev && a->type == b->type && + a->qid.path == b->qid.path; +} + +/* + * Print + * sysname: time: mesg + * on /sys/log/logname. + * If cons or log file can't be opened, print on the system console, too. + */ +void +syslog(int cons, const char *logname, const char *fmt, ...) +{ + char buf[1024]; + char *ctim, *p; + va_list arg; + int n; + Dir *d; + char err[ERRMAX]; + + err[0] = '\0'; + errstr(err, sizeof err); + lock(&sl); + + /* + * paranoia makes us stat to make sure a fork+close + * hasn't broken our fd's + */ + d = dirfstat(sl.fd); + if(sl.fd < 0 || sl.name == nil || strcmp(sl.name, logname) != 0 || + !eqdirdev(d, sl.d)){ + free(sl.name); + sl.name = strdup(logname); + if(sl.name == nil) + cons = 1; + else{ + free(sl.d); + sl.d = nil; + _syslogopen(); + if(sl.fd < 0) + cons = 1; + else + sl.d = dirfstat(sl.fd); + } + } + free(d); + if(cons){ + d = dirfstat(sl.consfd); + if(sl.consfd < 0 || !eqdirdev(d, sl.consd)){ + free(sl.consd); + sl.consd = nil; + sl.consfd = open("#c/cons", OWRITE|OCEXEC); + if(sl.consfd >= 0) + sl.consd = dirfstat(sl.consfd); + } + free(d); + } + + if(fmt == nil){ + unlock(&sl); + return; + } + + ctim = ctime(time(0)); + p = buf + snprint(buf, sizeof(buf)-1, "%s ", sysname()); + strncpy(p, ctim+4, 15); + p += 15; + *p++ = ' '; + errstr(err, sizeof err); + va_start(arg, fmt); + p = vseprint(p, buf+sizeof(buf)-1, fmt, arg); + va_end(arg); + *p++ = '\n'; + n = p - buf; + + if(sl.fd >= 0){ + seek(sl.fd, 0, 2); + write(sl.fd, buf, n); + } + + if(cons && sl.consfd >=0) + write(sl.consfd, buf, n); + + unlock(&sl); +} diff --git a/sys/src/libc/9sys/sysname.c b/sys/src/libc/9sys/sysname.c new file mode 100644 index 0000000..08aefe1 --- /dev/null +++ b/sys/src/libc/9sys/sysname.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +sysname(void) +{ + int f, n; + static char b[128]; + + if(b[0]) + return b; + + f = open("#c/sysname", 0); + if(f >= 0) { + n = read(f, b, sizeof(b)-1); + if(n > 0) + b[n] = 0; + close(f); + } + return b; +} diff --git a/sys/src/libc/9sys/time.c b/sys/src/libc/9sys/time.c new file mode 100644 index 0000000..4730581 --- /dev/null +++ b/sys/src/libc/9sys/time.c @@ -0,0 +1,22 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int32_t +time(int32_t *tp) +{ + int64_t t; + + t = nsec()/1000000000LL; + if(tp != nil) + *tp = t; + return t; +} diff --git a/sys/src/libc/9sys/times.c b/sys/src/libc/9sys/times.c new file mode 100644 index 0000000..8bc4e75 --- /dev/null +++ b/sys/src/libc/9sys/times.c @@ -0,0 +1,69 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static +char* +skip(char *p) +{ + + while(*p == ' ') + p++; + while(*p != ' ' && *p != 0) + p++; + return p; +} + +/* + * after a fork with fd's copied, both fd's are pointing to + * the same Chan structure. Since the offset is kept in the Chan + * structure, the seek's and read's in the two processes can be + * are competing moving the offset around. Hence the unusual loop + * in the middle of this routine. + */ +int32_t +times(int32_t *t) +{ + char b[200], *p; + static int f = -1; + int i, retries; + uint32_t r; + + memset(b, 0, sizeof(b)); + for(retries = 0; retries < 100; retries++){ + if(f < 0) + f = open("/dev/cputime", OREAD|OCEXEC); + if(f < 0) + break; + if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ + close(f); + f = -1; + } else { + if(i != 0) + break; + } + } + p = b; + if(t) + t[0] = atol(p); + p = skip(p); + if(t) + t[1] = atol(p); + p = skip(p); + r = atol(p); + if(t){ + p = skip(p); + t[2] = atol(p); + p = skip(p); + t[3] = atol(p); + } + return r; +} diff --git a/sys/src/libc/9sys/tm2sec.c b/sys/src/libc/9sys/tm2sec.c new file mode 100644 index 0000000..6bad4df --- /dev/null +++ b/sys/src/libc/9sys/tm2sec.c @@ -0,0 +1,203 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, int32_t*); +static +struct +{ + char stname[4]; + char dlname[4]; + int32_t stdiff; + int32_t dldiff; + int32_t dlpairs[TZSIZE]; +} timezone; + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ +int32_t +tm2sec(Tm *tm) +{ + int32_t secs; + int i, yday, year, *d2m; + + if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0) + readtimezone(); + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; imon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Only handles zones mentioned in /env/timezone, + * but things get too ambiguous otherwise. + */ + if(strcmp(tm->zone, timezone.stname) == 0) + secs -= timezone.stdiff; + else if(strcmp(tm->zone, timezone.dlname) == 0) + secs -= timezone.dldiff; + if(secs < 0) + secs = 0; + return secs; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)) + goto error; + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; +} diff --git a/sys/src/libc/9sys/truerand.c b/sys/src/libc/9sys/truerand.c new file mode 100644 index 0000000..f3c0e88 --- /dev/null +++ b/sys/src/libc/9sys/truerand.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +uint32_t +truerand(void) +{ + uint32_t x; + static int randfd = -1; + + if(randfd < 0) + randfd = open("/dev/random", OREAD|OCEXEC); + if(randfd < 0) + sysfatal("can't open /dev/random"); + if(read(randfd, &x, sizeof(x)) != sizeof(x)) + sysfatal("can't read /dev/random"); + return x; +} diff --git a/sys/src/libc/9sys/wait.c b/sys/src/libc/9sys/wait.c new file mode 100644 index 0000000..3694901 --- /dev/null +++ b/sys/src/libc/9sys/wait.c @@ -0,0 +1,41 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +Waitmsg* +wait(void) +{ + int n, l; + char buf[512], *fld[5]; + Waitmsg *w; + + n = await(buf, sizeof buf-1); + if(n < 0) + return nil; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return nil; + } + l = strlen(fld[4])+1; + w = malloc(sizeof(Waitmsg)+l); + if(w == nil) + return nil; + w->pid = atoi(fld[0]); + w->time[0] = atoi(fld[1]); + w->time[1] = atoi(fld[2]); + w->time[2] = atoi(fld[3]); + w->msg = (char*)&w[1]; + memmove(w->msg, fld[4], l); + return w; +} + diff --git a/sys/src/libc/9sys/waitpid.c b/sys/src/libc/9sys/waitpid.c new file mode 100644 index 0000000..c96384a --- /dev/null +++ b/sys/src/libc/9sys/waitpid.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +waitpid(void) +{ + int n; + char buf[512], *fld[5]; + + n = await(buf, sizeof buf-1); + if(n <= 0) + return -1; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return -1; + } + return atoi(fld[0]); +} + diff --git a/sys/src/libc/9sys/werrstr.c b/sys/src/libc/9sys/werrstr.c new file mode 100644 index 0000000..f62b28a --- /dev/null +++ b/sys/src/libc/9sys/werrstr.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +werrstr(const char *fmt, ...) +{ + va_list arg; + char buf[ERRMAX]; + + va_start(arg, fmt); + vseprint(buf, buf+ERRMAX, fmt, arg); + va_end(arg); + errstr(buf, ERRMAX); +} diff --git a/sys/src/libc/9sys/write.c b/sys/src/libc/9sys/write.c new file mode 100644 index 0000000..1de769e --- /dev/null +++ b/sys/src/libc/9sys/write.c @@ -0,0 +1,26 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2015 Giacomo Tesio + * + * Jehanne 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, version 2 of the License. + * + * Jehanne 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 Jehanne. If not, see . + */ + +#include +#include + +int32_t +write(int fd, const void* buf, int32_t nbytes) +{ + return pwrite(fd, buf, nbytes, ~0LL); +} diff --git a/sys/src/libc/9sys/writev.c b/sys/src/libc/9sys/writev.c new file mode 100644 index 0000000..fa73590 --- /dev/null +++ b/sys/src/libc/9sys/writev.c @@ -0,0 +1,51 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static +int32_t +iowritev(int fd, IOchunk *io, int nio, int64_t offset) +{ + int i; + int32_t tot; + char *buf, *p; + + tot = 0; + for(i=0; iaddr, io->len); + p += io->len; + io++; + } + + tot = pwrite(fd, buf, tot, offset); + + free(buf); + return tot; +} + +int32_t +writev(int fd, IOchunk *io, int nio) +{ + return iowritev(fd, io, nio, -1LL); +} + +int32_t +pwritev(int fd, IOchunk *io, int nio, int64_t off) +{ + return iowritev(fd, io, nio, off); +} diff --git a/sys/src/libc/9syscall/.gitignore b/sys/src/libc/9syscall/.gitignore new file mode 100644 index 0000000..9b6971c --- /dev/null +++ b/sys/src/libc/9syscall/.gitignore @@ -0,0 +1,3 @@ +/*.s +/*.o +/sys.h diff --git a/sys/src/libc/9syscall/9syscall.json b/sys/src/libc/9syscall/9syscall.json new file mode 100644 index 0000000..9b797ee --- /dev/null +++ b/sys/src/libc/9syscall/9syscall.json @@ -0,0 +1,8 @@ +{ + "KernelLibc": { + "Pre": [ + "mksys -o sys.h '-mode=sys.h' $JEHANNE/sys/src/sysconf.json", + "mksys -o . '-mode=syscallfiles' $JEHANNE/sys/src/sysconf.json" + ] + } +} diff --git a/sys/src/libc/amd64/argv0.c b/sys/src/libc/amd64/argv0.c new file mode 100644 index 0000000..13de30f --- /dev/null +++ b/sys/src/libc/amd64/argv0.c @@ -0,0 +1,9 @@ +#include +#include + +void (*_abort)(void); +char *argv0; +char *_tos; +char *_privates; +char *_nprivates; + diff --git a/sys/src/libc/amd64/atom.S b/sys/src/libc/amd64/atom.S new file mode 100644 index 0000000..42bfee6 --- /dev/null +++ b/sys/src/libc/amd64/atom.S @@ -0,0 +1,86 @@ +.text + +.globl ainc /* long ainc(long *); */ + /* N.B.: long in Plan 9 is 32 BITS! */ +ainc: + + pushq %rcx +ainclp: + movl (%rdi), %eax + movl %eax, %ecx + incl %ecx /* new */ + lock; cmpxchgl %ecx, (%rdi) + jnz ainclp + movl %ecx, %eax + popq %rcx + ret + +.globl adec /* long adec(long*); */ +adec: + pushq %rcx +adeclp: + movl (%rdi), %eax + movl %eax, %ecx + decl %ecx /* new */ + lock; cmpxchgl %ecx, (%rdi) + jnz adeclp + movl %ecx, %eax + popq %rcx + ret + +/* + * int cas32(u32int *p, u32int ov, u32int nv); + * int cas(uint *p, int ov, int nv); + * int casul(ulong *p, ulong ov, ulong nv); + */ + +.globl cas32 +cas32: +.globl cas +cas: +.globl casul +casul: +.globl casl +casl: + pushq %rcx + movl 16(%rdi), %eax + movl 24(%rdi), %ebx + lock; cmpxchgl %ecx, (%rdi) + movl $1, %eax + jnz _cas32r0 +_cas32r1: + ret +_cas32r0: + decl %eax + popq %rcx + ret + +/* + * int cas64(u64int *p, u64int ov, u64int nv); + * int casp(void **p, void *ov, void *nv); + */ + +.globl cas64 +cas64: +.globl casp +casp: + pushq %rcx + movq 16(%rdi), %rax + movq 24(%rdi), %rbx + lock; cmpxchgq %rbx, (%rdi) + movl $1, %eax + jnz _cas64r0 +_cas64r1: + ret +_cas64r0: + decq %rax + popq %rcx + ret +/* + * void mfence(void); + */ +.globl mfence +mfence: + mfence + ret + diff --git a/sys/src/libc/amd64/cycles.c b/sys/src/libc/amd64/cycles.c new file mode 100644 index 0000000..fca3ab5 --- /dev/null +++ b/sys/src/libc/amd64/cycles.c @@ -0,0 +1,11 @@ +#include +#include + +void _cycles(uint64_t *x) +{ + uint32_t a, d; + + asm __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); + +} + diff --git a/sys/src/libc/amd64/main9.S b/sys/src/libc/amd64/main9.S new file mode 100644 index 0000000..3253f20 --- /dev/null +++ b/sys/src/libc/amd64/main9.S @@ -0,0 +1,32 @@ +#define NPRIVATES 16 + +.text + +// %rdi and %rsi are set up as argc, argv for main. +// %rdx points to top of stack +.globl _main +_main: + + movq 0(%rsp), %rdi + leaq 8(%rsp), %rsi + movq %rdx, _tos + movq $-128, _privates + addq %rsp, _privates + movl $NPRIVATES, _nprivates + leaq -160(%rsp), %rsp + call main + +loop: + movq $_exits, %rdi + call exits + jmp loop + +.data +_exits: + .ascii "main" + + +.globl gettls0 +gettls0: + movq %fs:0, %rax + ret diff --git a/sys/src/libc/amd64/notejmp.c b/sys/src/libc/amd64/notejmp.c new file mode 100644 index 0000000..05b7a0e --- /dev/null +++ b/sys/src/libc/amd64/notejmp.c @@ -0,0 +1,16 @@ +#include +#include +#include + +void +notejmp(void *vr, jmp_buf j, int ret) +{ + struct Ureg *r = vr; + + r->ax = ret; + if(ret == 0) + r->ax = 1; + r->ip = j[JMPBUFPC]; + r->sp = j[JMPBUFSP] + 8; + noted(NCONT); +} diff --git a/sys/src/libc/amd64/rdpmc.c b/sys/src/libc/amd64/rdpmc.c new file mode 100644 index 0000000..af9f70b --- /dev/null +++ b/sys/src/libc/amd64/rdpmc.c @@ -0,0 +1,9 @@ +#include +#include + +void +rdpmc (int counter, int low, int high) +{ + asm __volatile__("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)) ; +} + diff --git a/sys/src/libc/amd64/setjmp.s b/sys/src/libc/amd64/setjmp.s new file mode 100644 index 0000000..a8b5d8c --- /dev/null +++ b/sys/src/libc/amd64/setjmp.s @@ -0,0 +1,39 @@ +.text + +.globl longjmp +longjmp: + movq %rdi, %r9 + movq 0(%r9), %rbx + movq 8(%r9), %r12 + movq 16(%r9), %r13 + movq 24(%r9), %r14 + movq 32(%r9), %r15 + movq 40(%r9), %rbp + movq 48(%r9), %rsp + movl %esi, %eax + test %eax, %eax /* if val != 0 */ + jnz 1f /* return val */ + incl %eax /* else return 1 */ +1: + movq 56(%r9), %r8 /* return to caller of setjmp */ + + movq 64(%r9), %rdi /* 1st function argument */ + movq 72(%r9), %rsi /* 2nd function argument */ + + jmp *%r8 + +.globl setjmp +setjmp: + movq %rbx, 0(%rdi) + movq %r12, 8(%rdi) + movq %r13, 16(%rdi) + movq %r14, 24(%rdi) + movq %r15, 32(%rdi) + movq %rbp, 40(%rdi) + popq %rdx /* return address */ + movq %rsp, 48(%rdi) + movq %rdx, 56(%rdi) + + + xorl %eax, %eax /* return 0 */ + jmp *%rdx diff --git a/sys/src/libc/amd64/sqrt.s b/sys/src/libc/amd64/sqrt.s new file mode 100644 index 0000000..ab520b8 --- /dev/null +++ b/sys/src/libc/amd64/sqrt.s @@ -0,0 +1,5 @@ +.globl sqrt +sqrt: + sqrtsd %xmm0, %xmm0 + ret + diff --git a/sys/src/libc/amd64/tas.s b/sys/src/libc/amd64/tas.s new file mode 100644 index 0000000..7c9d388 --- /dev/null +++ b/sys/src/libc/amd64/tas.s @@ -0,0 +1,10 @@ +/* + * The kernel and the libc use the same constant for TAS + */ +.text +.globl _tas +_tas: + movl $0xdeaddead, %eax + xchgl %eax, 0(%rdi) /* lock->key */ + ret + diff --git a/sys/src/libc/build.json b/sys/src/libc/build.json new file mode 100644 index 0000000..1de9144 --- /dev/null +++ b/sys/src/libc/build.json @@ -0,0 +1,255 @@ +{ + "Libc": { + "Cflags": [ + "-fasm", + "-Werror" + ], + "Include": [ + "../lib.json" + ], + "Install": "/arch/$ARCH/lib/", + "Library": "libc.a", + "Post": [ + "rm 9syscall/*.s" + ], + "Projects": [ + "9syscall/9syscall.json" + ], + "SourceFiles": [ + "9sys/access.c", + "9sys/announce.c", + "9sys/awakened.c", + "9sys/convD2M.c", + "9sys/convM2D.c", + "9sys/convM2S.c", + "9sys/convS2M.c", + "9sys/cputime.c", + "9sys/ctime.c", + "9sys/dial.c", + "9sys/dirfstat.c", + "9sys/dirfwstat.c", + "9sys/dirmodefmt.c", + "9sys/dirread.c", + "9sys/dirstat.c", + "9sys/dirwstat.c", + "9sys/fcallfmt.c", + "9sys/fork.c", + "9sys/getnetconninfo.c", + "9sys/getenv.c", + "9sys/getpid.c", + "9sys/getppid.c", + "9sys/getwd.c", + "9sys/iounit.c", + "9sys/nulldir.c", + "9sys/postnote.c", + "9sys/privalloc.c", + "9sys/pushssl.c", + "9sys/putenv.c", + "9sys/qlock.c", + "9sys/read9pmsg.c", + "9sys/read.c", + "9sys/readv.c", + "9sys/rerrstr.c", + "9sys/sbrk.c", + "9sys/setnetmtpt.c", + "9sys/sleep.c", + "9sys/sysfatal.c", + "9sys/syslog.c", + "9sys/sysname.c", + "9sys/time.c", + "9sys/times.c", + "9sys/tm2sec.c", + "9sys/truerand.c", + "9sys/wait.c", + "9sys/waitpid.c", + "9sys/werrstr.c", + "9sys/write.c", + "9sys/writev.c", + "9syscall/alarm.s", + "9syscall/await.s", + "9syscall/awake.s", + "9syscall/bind.s", + "9syscall/brk_.s", + "9syscall/chdir.s", + "9syscall/close.s", + "9syscall/create.s", + "9syscall/dup.s", + "9syscall/errstr.s", + "9syscall/exec.s", + "9syscall/_exits.s", + "9syscall/fauth.s", + "9syscall/fd2path.s", + "9syscall/fstat.s", + "9syscall/fversion.s", + "9syscall/fwstat.s", + "9syscall/mount.s", + "9syscall/noted.s", + "9syscall/notify.s", + "9syscall/nsec.s", + "9syscall/open.s", + "9syscall/pipe.s", + "9syscall/pread.s", + "9syscall/pwrite.s", + "9syscall/remove.s", + "9syscall/rendezvous.s", + "9syscall/rfork.s", + "9syscall/seek.s", + "9syscall/segattach.s", + "9syscall/segbrk.s", + "9syscall/segdetach.s", + "9syscall/segflush.s", + "9syscall/segfree.s", + "9syscall/semacquire.s", + "9syscall/semrelease.s", + "9syscall/stat.s", + "9syscall/tsemacquire.s", + "9syscall/unmount.s", + "9syscall/wstat.s", + "fmt/dofmt.c", + "fmt/dorfmt.c", + "fmt/errfmt.c", + "fmt/fltfmt.c", + "fmt/fmt.c", + "fmt/fmtfd.c", + "fmt/fmtlock.c", + "fmt/fmtprint.c", + "fmt/fmtquote.c", + "fmt/fmtrune.c", + "fmt/fmtstr.c", + "fmt/fmtvprint.c", + "fmt/fprint.c", + "fmt/print.c", + "fmt/runefmtstr.c", + "fmt/runeseprint.c", + "fmt/runesmprint.c", + "fmt/runesnprint.c", + "fmt/runesprint.c", + "fmt/runevseprint.c", + "fmt/runevsmprint.c", + "fmt/runevsnprint.c", + "fmt/seprint.c", + "fmt/smprint.c", + "fmt/snprint.c", + "fmt/sprint.c", + "fmt/vfprint.c", + "fmt/vseprint.c", + "fmt/vsmprint.c", + "fmt/vsnprint.c", + "port/_assert.c", + "port/abs.c", + "port/asin.c", + "port/atan.c", + "port/atan2.c", + "port/atexit.c", + "port/atnotify.c", + "port/atof.c", + "port/atol.c", + "port/atoll.c", + "port/cistrcmp.c", + "port/cistrncmp.c", + "port/cistrstr.c", + "port/charstod.c", + "port/cleanname.c", + "port/ctype.c", + "port/encodefmt.c", + "port/execl.c", + "port/exp.c", + "port/fabs.c", + "port/floor.c", + "port/fmod.c", + "port/frand.c", + "port/frexp.c", + "port/getcallerpc.c", + "port/getfields.c", + "port/getuser.c", + "port/hangup.c", + "port/hypot.c", + "port/lnrand.c", + "port/lock.c", + "port/log.c", + "port/lrand.c", + "port/malloc.c", + "port/memccpy.c", + "port/memchr.c", + "port/memcmp.c", + "port/memmove.c", + "port/memset.c", + "port/mktemp.c", + "port/muldiv.c", + "port/nan.c", + "port/needsrcquote.c", + "port/netmkaddr.c", + "port/nrand.c", + "port/ntruerand.c", + "port/perror.c", + "port/pool.c", + "port/pow.c", + "port/pow10.c", + "port/qsort.c", + "port/quote.c", + "port/rand.c", + "port/readn.c", + "port/rune.c", + "port/runebase.c", + "port/runebsearch.c", + "port/runestrcat.c", + "port/runestrchr.c", + "port/runestrcmp.c", + "port/runestrcpy.c", + "port/runestrecpy.c", + "port/runestrdup.c", + "port/runestrncat.c", + "port/runestrncmp.c", + "port/runestrncpy.c", + "port/runestrrchr.c", + "port/runestrlen.c", + "port/runestrstr.c", + "port/runetype.c", + "port/sin.c", + "port/sinh.c", + "port/strcat.c", + "port/strchr.c", + "port/strcmp.c", + "port/strcpy.c", + "port/strecpy.c", + "port/strcspn.c", + "port/strdup.c", + "port/strlen.c", + "port/strncat.c", + "port/strncmp.c", + "port/strncpy.c", + "port/strpbrk.c", + "port/strrchr.c", + "port/strspn.c", + "port/strstr.c", + "port/strtod.c", + "port/strtok.c", + "port/strtol.c", + "port/strtoll.c", + "port/strtoul.c", + "port/strtoull.c", + "port/tan.c", + "port/tanh.c", + "port/tokenize.c", + "port/toupper.c", + "port/utfecpy.c", + "port/utflen.c", + "port/utfnlen.c", + "port/utfrune.c", + "port/utfrrune.c", + "port/utfutf.c", + "port/u16.c", + "port/u32.c", + "port/u64.c", + "$ARCH/notejmp.c", + "$ARCH/cycles.c", + "$ARCH/argv0.c", + "$ARCH/rdpmc.c", + "$ARCH/setjmp.s", + "$ARCH/sqrt.s", + "$ARCH/tas.s", + "$ARCH/atom.S", + "$ARCH/main9.S" + ] + } +} diff --git a/sys/src/libc/fmt/dofmt.c b/sys/src/libc/fmt/dofmt.c new file mode 100644 index 0000000..f6a8f46 --- /dev/null +++ b/sys/src/libc/fmt/dofmt.c @@ -0,0 +1,539 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +/* format the output into f->to and return the number of characters fmted */ +int +dofmt(Fmt *f, const char *fmt) +{ + Rune rune, *rt, *rs; + int r; + char *t, *s; + int n, nfmt; + + nfmt = f->nfmt; + for(;;){ + if(f->runes){ + rt = f->to; + rs = f->stop; + while((r = *(uint8_t*)fmt) && r != '%'){ + if(r < Runeself) + fmt++; + else{ + fmt += chartorune(&rune, fmt); + r = rune; + } + FMTRCHAR(f, rt, rs, r); + } + fmt++; + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(!r) + return f->nfmt - nfmt; + f->stop = rs; + }else{ + t = f->to; + s = f->stop; + while((r = *(uint8_t*)fmt) && r != '%'){ + if(r < Runeself){ + FMTCHAR(f, t, s, r); + fmt++; + }else{ + n = chartorune(&rune, fmt); + if(t + n > s){ + t = _fmtflush(f, t, n); + if(t != nil) + s = f->stop; + else + return -1; + } + while(n--) + *t++ = *fmt++; + } + } + fmt++; + f->nfmt += t - (char *)f->to; + f->to = t; + if(!r) + return f->nfmt - nfmt; + f->stop = s; + } + + fmt = _fmtdispatch(f, fmt, 0); + if(fmt == nil) + return -1; + } +} + +void * +_fmtflush(Fmt *f, void *t, int len) +{ + if(f->runes) + f->nfmt += (Rune*)t - (Rune*)f->to; + else + f->nfmt += (char*)t - (char *)f->to; + f->to = t; + if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ + f->stop = f->to; + return nil; + } + return f->to; +} + +/* + * put a formatted block of memory sz bytes long of n runes into the output buffer, + * left/right justified in a field of at least f->width charactes + */ +int +_fmtpad(Fmt *f, int n) +{ + char *t, *s; + int i; + + t = f->to; + s = f->stop; + for(i = 0; i < n; i++) + FMTCHAR(f, t, s, ' '); + f->nfmt += t - (char *)f->to; + f->to = t; + return 0; +} + +int +_rfmtpad(Fmt *f, int n) +{ + Rune *t, *s; + int i; + + t = f->to; + s = f->stop; + for(i = 0; i < n; i++) + FMTRCHAR(f, t, s, ' '); + f->nfmt += t - (Rune *)f->to; + f->to = t; + return 0; +} + +int +_fmtcpy(Fmt *f, const void *vm, int n, int sz) +{ + Rune *rt, *rs, r; + char *t, *s; + const char *m, *me; + uint32_t fl; + int nc, w; + + m = vm; + me = m + sz; + w = f->width; + fl = f->flags; + if((fl & FmtPrec) && n > f->prec) + n = f->prec; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) + return -1; + rt = f->to; + rs = f->stop; + for(nc = n; nc > 0; nc--){ + r = *(uint8_t*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + FMTRCHAR(f, rt, rs, r); + } + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) + return -1; + t = f->to; + s = f->stop; + for(nc = n; nc > 0; nc--){ + r = *(uint8_t*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + FMTRUNE(f, t, s, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - n) < 0) + return -1; + } + return 0; +} + +int +_fmtrcpy(Fmt *f, const void *vm, int n) +{ + Rune r, *rt, *rs; + const Rune *m, *me; + char *t, *s; + uint32_t fl; + int w; + + m = vm; + w = f->width; + fl = f->flags; + if((fl & FmtPrec) && n > f->prec) + n = f->prec; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) + return -1; + rt = f->to; + rs = f->stop; + for(me = m + n; m < me; m++) + FMTRCHAR(f, rt, rs, *m); + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) + return -1; + t = f->to; + s = f->stop; + for(me = m + n; m < me; m++){ + r = *m; + FMTRUNE(f, t, s, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - n) < 0) + return -1; + } + return 0; +} + +/* fmt out one character */ +int +_charfmt(Fmt *f) +{ + char x[1]; + + x[0] = va_arg(f->args, int); + f->prec = 1; + return _fmtcpy(f, x, 1, 1); +} + +/* fmt out one rune */ +int +_runefmt(Fmt *f) +{ + Rune x[1]; + + x[0] = va_arg(f->args, int); + return _fmtrcpy(f, x, 1); +} + +/* public helper routine: fmt out a null terminated string already in hand */ +int +fmtstrcpy(Fmt *f, const char *s) +{ + int i, j; + Rune r; + + if(!s) + return _fmtcpy(f, "", 5, 5); + /* if precision is specified, make sure we don't wander off the end */ + if(f->flags & FmtPrec){ + i = 0; + for(j=0; jprec && s[i]; j++) + i += chartorune(&r, s+i); + return _fmtcpy(f, s, j, i); + } + return _fmtcpy(f, s, utflen(s), strlen(s)); +} + +/* fmt out a null terminated utf string */ +int +_strfmt(Fmt *f) +{ + char *s; + + s = va_arg(f->args, char *); + return fmtstrcpy(f, s); +} + +/* public helper routine: fmt out a null terminated rune string already in hand */ +int +fmtrunestrcpy(Fmt *f, const Rune *s) +{ + const Rune *e; + int n, p; + + if(!s) + return _fmtcpy(f, "", 5, 5); + /* if precision is specified, make sure we don't wander off the end */ + if(f->flags & FmtPrec){ + p = f->prec; + for(n = 0; n < p; n++) + if(s[n] == 0) + break; + }else{ + for(e = s; *e; e++) + ; + n = e - s; + } + return _fmtrcpy(f, s, n); +} + +/* fmt out a null terminated rune string */ +int +_runesfmt(Fmt *f) +{ + Rune *s; + + s = va_arg(f->args, Rune *); + return fmtrunestrcpy(f, s); +} + +/* fmt a % */ +int +_percentfmt(Fmt *f) +{ + Rune x[1]; + + x[0] = f->r; + f->prec = 1; + return _fmtrcpy(f, x, 1); +} + +enum { + /* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */ + Maxintwidth = 1 + 2 + 64 + 64/3, +}; + +/* fmt an integer */ +int +_ifmt(Fmt *f) +{ + char buf[Maxintwidth + 1], *p, *conv; + uint64_t vu; + uint32_t u; + uintptr pu; + int neg, base, i, n, fl, w, isv; + + neg = 0; + fl = f->flags; + isv = 0; + vu = 0; + u = 0; + if(f->r == 'p'){ + pu = va_arg(f->args, uintptr); + if(sizeof(uintptr) == sizeof(uint64_t)){ + vu = pu; + isv = 1; + }else + u = pu; + f->r = 'x'; + fl |= FmtUnsigned; + }else if(fl & FmtVLong){ + isv = 1; + if(fl & FmtUnsigned) + vu = va_arg(f->args, uint64_t); + else + vu = va_arg(f->args, int64_t); + }else if(fl & FmtLong){ + if(fl & FmtUnsigned) + u = va_arg(f->args, uint32_t); + else + u = va_arg(f->args, int32_t); + }else if(fl & FmtByte){ + if(fl & FmtUnsigned) + u = (uint8_t)va_arg(f->args, int); + else + u = (char)va_arg(f->args, int); + }else if(fl & FmtShort){ + if(fl & FmtUnsigned) + u = (uint16_t)va_arg(f->args, int); + else + u = (int16_t)va_arg(f->args, int); + }else{ + if(fl & FmtUnsigned) + u = va_arg(f->args, uint); + else + u = va_arg(f->args, int); + } + conv = "0123456789abcdef"; + switch(f->r){ + case 'd': + base = 10; + break; + case 'x': + base = 16; + break; + case 'X': + base = 16; + conv = "0123456789ABCDEF"; + break; + case 'b': + base = 2; + break; + case 'o': + base = 8; + break; + default: + return -1; + } + if(!(fl & FmtUnsigned)){ + if(isv && (int64_t)vu < 0){ + vu = -(int64_t)vu; + neg = 1; + }else if(!isv && (int32_t)u < 0){ + u = -(int32_t)u; + neg = 1; + } + } + p = buf + sizeof buf - 1; + n = 0; + if(isv){ + while(vu){ + i = vu % base; + vu /= base; + if((fl & FmtComma) && n % 4 == 3){ + *p-- = ','; + n++; + } + *p-- = conv[i]; + n++; + } + }else{ + while(u){ + i = u % base; + u /= base; + if((fl & FmtComma) && n % 4 == 3){ + *p-- = ','; + n++; + } + *p-- = conv[i]; + n++; + } + } + if(n == 0){ + *p-- = '0'; + n = 1; + } + for(w = f->prec; n < w && p > buf+3; n++) + *p-- = '0'; + if(neg || (fl & (FmtSign|FmtSpace))) + n++; + if(fl & FmtSharp){ + if(base == 16) + n += 2; + else if(base == 8){ + if(p[1] == '0') + fl &= ~FmtSharp; + else + n++; + } + } + if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ + for(w = f->width; n < w && p > buf+3; n++) + *p-- = '0'; + f->width = 0; + } + if(fl & FmtSharp){ + if(base == 16) + *p-- = f->r; + if(base == 16 || base == 8) + *p-- = '0'; + } + if(neg) + *p-- = '-'; + else if(fl & FmtSign) + *p-- = '+'; + else if(fl & FmtSpace) + *p-- = ' '; + f->flags &= ~FmtPrec; + return _fmtcpy(f, p + 1, n, n); +} + +int +_countfmt(Fmt *f) +{ + void *p; + uint32_t fl; + + fl = f->flags; + p = va_arg(f->args, void*); + if(fl & FmtVLong){ + *(int64_t*)p = f->nfmt; + }else if(fl & FmtLong){ + *(int32_t*)p = f->nfmt; + }else if(fl & FmtByte){ + *(char*)p = f->nfmt; + }else if(fl & FmtShort){ + *(int16_t*)p = f->nfmt; + }else{ + *(int*)p = f->nfmt; + } + return 0; +} + +int +_flagfmt(Fmt *f) +{ + switch(f->r){ + case ',': + f->flags |= FmtComma; + break; + case '-': + f->flags |= FmtLeft; + break; + case '+': + f->flags |= FmtSign; + break; + case '#': + f->flags |= FmtSharp; + break; + case ' ': + f->flags |= FmtSpace; + break; + case 'u': + f->flags |= FmtUnsigned; + break; + case 'h': + if(f->flags & FmtShort) + f->flags |= FmtByte; + f->flags |= FmtShort; + break; + case 'l': + if(f->flags & FmtLong) + f->flags |= FmtVLong; + f->flags |= FmtLong; + break; + } + return 1; +} + +/* default error format */ +int +_badfmt(Fmt *f) +{ + Rune x[3]; + + x[0] = '%'; + x[1] = f->r; + x[2] = '%'; + f->prec = 3; + _fmtrcpy(f, x, 3); + return 0; +} diff --git a/sys/src/libc/fmt/dorfmt.c b/sys/src/libc/fmt/dorfmt.c new file mode 100644 index 0000000..2d96c22 --- /dev/null +++ b/sys/src/libc/fmt/dorfmt.c @@ -0,0 +1,54 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +/* format the output into f->to and return the number of characters fmted */ + +int +dorfmt(Fmt *f, const Rune *fmt) +{ + Rune *rt, *rs; + int r; + char *t, *s; + int nfmt; + + nfmt = f->nfmt; + for(;;){ + if(f->runes){ + rt = f->to; + rs = f->stop; + while((r = *fmt++) && r != '%'){ + FMTRCHAR(f, rt, rs, r); + } + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(!r) + return f->nfmt - nfmt; + f->stop = rs; + }else{ + t = f->to; + s = f->stop; + while((r = *fmt++) && r != '%'){ + FMTRUNE(f, t, f->stop, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(!r) + return f->nfmt - nfmt; + f->stop = s; + } + + fmt = _fmtdispatch(f, fmt, 1); + if(fmt == nil) + return -1; + } +} diff --git a/sys/src/libc/fmt/errfmt.c b/sys/src/libc/fmt/errfmt.c new file mode 100644 index 0000000..cb7656b --- /dev/null +++ b/sys/src/libc/fmt/errfmt.c @@ -0,0 +1,21 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +int +errfmt(Fmt *f) +{ + char buf[ERRMAX]; + + rerrstr(buf, sizeof buf); + return _fmtcpy(f, buf, utflen(buf), strlen(buf)); +} diff --git a/sys/src/libc/fmt/fltfmt.c b/sys/src/libc/fmt/fltfmt.c new file mode 100644 index 0000000..bc320a1 --- /dev/null +++ b/sys/src/libc/fmt/fltfmt.c @@ -0,0 +1,327 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include +#include "fmtdef.h" + +enum +{ + FDIGIT = 30, + FDEFLT = 6, + NSIGNIF = 17, + NEXP10 = 308, +}; + +static int +xadd(char *a, int n, int v) +{ + char *b; + int c; + + if(n < 0 || n >= NSIGNIF) + return 0; + for(b = a+n; b >= a; b--) { + c = *b + v; + if(c <= '9') { + *b = c; + return 0; + } + *b = '0'; + v = 1; + } + *a = '1'; // overflow adding + return 1; +} + +static int +xsub(char *a, int n, int v) +{ + char *b; + int c; + + for(b = a+n; b >= a; b--) { + c = *b - v; + if(c >= '0') { + *b = c; + return 0; + } + *b = '9'; + v = 1; + } + *a = '9'; // underflow subtracting + return 1; +} + +static void +xdtoa(Fmt *fmt, char *s2, double f) +{ + char s1[NSIGNIF+10]; + double g, h; + int e, d, i, n; + int c1, c2, c3, c4, ucase, sign, chr, prec; + + prec = FDEFLT; + if(fmt->flags & FmtPrec) + prec = fmt->prec; + if(prec > FDIGIT) + prec = FDIGIT; + if(isNaN(f)) { + strcpy(s2, "NaN"); + return; + } + if(isInf(f, 1)) { + strcpy(s2, "+Inf"); + return; + } + if(isInf(f, -1)) { + strcpy(s2, "-Inf"); + return; + } + sign = 0; + if(f < 0) { + f = -f; + sign++; + } + ucase = 0; + chr = fmt->r; + if(isupper(chr)) { + ucase = 1; + chr = tolower(chr); + } + + e = 0; + g = f; + if(g != 0) { + frexp(f, &e); + e = e * .301029995664; + if(e >= -150 && e <= +150) { + d = 0; + h = f; + } else { + d = e/2; + h = f * pow10(-d); + } + g = h * pow10(d-e); + while(g < 1) { + e--; + g = h * pow10(d-e); + } + while(g >= 10) { + e++; + g = h * pow10(d-e); + } + } + + /* + * convert NSIGNIF digits and convert + * back to get accuracy. + */ + for(i=0; i= NSIGNIF-2) { + strcpy(s2, s1); + d = e; + s1[NSIGNIF-2] = '0'; + s1[NSIGNIF-1] = '0'; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(s1, nil); + if(g == f) + goto found; + if(xadd(s1, NSIGNIF-3, 1)) { + e++; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + } + g = strtod(s1, nil); + if(g == f) + goto found; + strcpy(s1, s2); + e = d; + } + + /* + * convert back so s1 gets exact answer + */ + for(;;) { + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(s1, nil); + if(f > g) { + if(xadd(s1, NSIGNIF-1, 1)) + e--; + continue; + } + if(f < g) { + if(xsub(s1, NSIGNIF-1, 1)) + e++; + continue; + } + break; + } + +found: + /* + * sign + */ + d = 0; + i = 0; + if(sign) + s2[d++] = '-'; + else if(fmt->flags & FmtSign) + s2[d++] = '+'; + else if(fmt->flags & FmtSpace) + s2[d++] = ' '; + + /* + * copy into final place + * c1 digits of leading '0' + * c2 digits from conversion + * c3 digits of trailing '0' + * c4 digits after '.' + */ + c1 = 0; + c2 = prec + 1; + c3 = 0; + c4 = prec; + switch(chr) { + default: + if(xadd(s1, c2, 5)) + e++; + break; + case 'g': + /* + * decide on 'e' of 'f' style convers + */ + if(xadd(s1, c2, 5)) + e++; + if(e >= -5 && e <= prec) { + c1 = -e - 1; + c4 = prec - e; + chr = 'h'; // flag for 'f' style + } + break; + case 'f': + if(xadd(s1, c2+e, 5)) + e++; + c1 = -e; + if(c1 > prec) + c1 = c2; + c2 += e; + break; + } + + /* + * clean up c1 c2 and c3 + */ + if(c1 < 0) + c1 = 0; + if(c2 < 0) + c2 = 0; + if(c2 > NSIGNIF) { + c3 = c2-NSIGNIF; + c2 = NSIGNIF; + } + + /* + * copy digits + */ + while(c1 > 0) { + if(c1+c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c1--; + } + while(c2 > 0) { + if(c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = s1[i++]; + c2--; + } + while(c3 > 0) { + if(c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c3--; + } + + /* + * strip trailing '0' on g conv + */ + if(fmt->flags & FmtSharp) { + if(0 == c4) + s2[d++] = '.'; + } else + if(chr == 'g' || chr == 'h') { + for(n=d-1; n>=0; n--) + if(s2[n] != '0') + break; + for(i=n; i>=0; i--) + if(s2[i] == '.') { + d = n; + if(i != n) + d++; + break; + } + } + if(chr == 'e' || chr == 'g') { + if(ucase) + s2[d++] = 'E'; + else + s2[d++] = 'e'; + c1 = e; + if(c1 < 0) { + s2[d++] = '-'; + c1 = -c1; + } else + s2[d++] = '+'; + if(c1 >= 100) { + s2[d++] = c1/100 + '0'; + c1 = c1%100; + } + s2[d++] = c1/10 + '0'; + s2[d++] = c1%10 + '0'; + } + s2[d] = 0; +} + +int +_floatfmt(Fmt *fmt, double f) +{ + char s[1+NEXP10+1+FDIGIT+1]; + + /* + * The max length of a %f string is + * '[+-]'+"max exponent"+'.'+"max precision"+'\0' + * which is 341 currently. + */ + xdtoa(fmt, s, f); + fmt->flags &= FmtWidth|FmtLeft; + _fmtcpy(fmt, s, strlen(s), strlen(s)); + return 0; +} + +int +_efgfmt(Fmt *f) +{ + double d; + + d = va_arg(f->args, double); + return _floatfmt(f, d); +} diff --git a/sys/src/libc/fmt/fmt.c b/sys/src/libc/fmt/fmt.c new file mode 100644 index 0000000..afeb3a9 --- /dev/null +++ b/sys/src/libc/fmt/fmt.c @@ -0,0 +1,227 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +enum +{ + Maxfmt = 64 +}; + +typedef struct Convfmt Convfmt; +struct Convfmt +{ + int c; + volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ +}; + +struct +{ + /* lock by calling _fmtlock, _fmtunlock */ + int nfmt; + Convfmt fmt[Maxfmt]; +} fmtalloc; + +static Convfmt knownfmt[] = { + ' ', _flagfmt, + '#', _flagfmt, + '%', _percentfmt, + '+', _flagfmt, + ',', _flagfmt, + '-', _flagfmt, + 'C', _runefmt, + 'E', _efgfmt, + 'G', _efgfmt, + 'S', _runesfmt, + 'X', _ifmt, + 'b', _ifmt, + 'c', _charfmt, + 'd', _ifmt, + 'e', _efgfmt, + 'f', _efgfmt, + 'g', _efgfmt, + 'h', _flagfmt, + 'l', _flagfmt, + 'n', _countfmt, + 'o', _ifmt, + 'p', _ifmt, + 'r', errfmt, + 's', _strfmt, + 'u', _flagfmt, + 'x', _ifmt, + 0, nil, +}; + +int (*doquote)(int); + +/* + * _fmtlock() must be set + */ +static int +_fmtinstall(int c, Fmts f) +{ + Convfmt *p, *ep; + + if(c<=0 || c>=65536) + return -1; + if(!f) + f = _badfmt; + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; pc == c) + break; + + if(p == &fmtalloc.fmt[Maxfmt]) + return -1; + + p->fmt = f; + if(p == ep){ /* installing a new format character */ + fmtalloc.nfmt++; + p->c = c; + } + + return 0; +} + +int +fmtinstall(int c, Fmts f) +{ + int ret; + + _fmtlock(); + ret = _fmtinstall(c, f); + _fmtunlock(); + return ret; +} + +static Fmts +fmtfmt(int c) +{ + Convfmt *p, *ep; + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; pc == c){ + while(p->fmt == nil) /* loop until value is updated */ + ; + return p->fmt; + } + + /* is this a predefined format char? */ + _fmtlock(); + for(p=knownfmt; p->c; p++) + if(p->c == c){ + _fmtinstall(p->c, p->fmt); + _fmtunlock(); + return p->fmt; + } + _fmtunlock(); + + return _badfmt; +} + +void* +_fmtdispatch(Fmt *f, const void *fmt, int isrunes) +{ + Rune rune, r; + int i, n, w, p; + uint32_t fl; + const void *ret; + + w = f->width; + p = f->prec; + fl = f->flags; + + f->flags = 0; + f->width = f->prec = 0; + + for(;;){ + if(isrunes){ + r = *(Rune*)fmt; + fmt = (Rune*)fmt + 1; + }else{ + fmt = (char*)fmt + chartorune(&rune, fmt); + r = rune; + } + f->r = r; + switch(r){ + case '\0': + ret = nil; + goto end; + case '.': + f->flags |= FmtWidth|FmtPrec; + continue; + case '0': + if(!(f->flags & FmtWidth)){ + f->flags |= FmtZero; + continue; + } + /* fall through */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + i = 0; + while(r >= '0' && r <= '9'){ + i = i * 10 + r - '0'; + if(isrunes){ + r = *(Rune*)fmt; + fmt = (Rune*)fmt + 1; + }else{ + r = *(char*)fmt; + fmt = (char*)fmt + 1; + } + } + if(isrunes) + fmt = (Rune*)fmt - 1; + else + fmt = (char*)fmt - 1; + numflag: + if(f->flags & FmtWidth){ + f->flags |= FmtPrec; + f->prec = i; + }else{ + f->flags |= FmtWidth; + f->width = i; + } + continue; + case '*': + i = va_arg(f->args, int); + if(i < 0){ + /* + * negative precision => + * ignore the precision. + */ + if(f->flags & FmtPrec){ + f->flags &= ~FmtPrec; + f->prec = 0; + continue; + } + i = -i; + f->flags |= FmtLeft; + } + goto numflag; + } + n = (*fmtfmt(r))(f); + if(n < 0){ + ret = nil; + break; + } + if(n == 0){ + ret = fmt; + break; + } + } +end: + f->width = w; + f->prec = p; + f->flags = fl; + return (void*)ret; +} diff --git a/sys/src/libc/fmt/fmtdef.h b/sys/src/libc/fmt/fmtdef.h new file mode 100644 index 0000000..928101f --- /dev/null +++ b/sys/src/libc/fmt/fmtdef.h @@ -0,0 +1,94 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * dofmt -- format to a buffer + * the number of characters formatted is returned, + * or -1 if there was an error. + * if the buffer is ever filled, flush is called. + * it should reset the buffer and return whether formatting should continue. + */ + +typedef int (*Fmts)(Fmt*); + +typedef struct Quoteinfo Quoteinfo; +struct Quoteinfo +{ + int quoted; /* if set, string must be quoted */ + int nrunesin; /* number of input runes that can be accepted */ + int nbytesin; /* number of input bytes that can be accepted */ + int nrunesout; /* number of runes that will be generated */ + int nbytesout; /* number of bytes that will be generated */ +}; + +void *_fmtflush(Fmt*, void*, int); +void *_fmtdispatch(Fmt*, const void*, int); +int _floatfmt(Fmt*, double); +int _fmtpad(Fmt*, int); +int _rfmtpad(Fmt*, int); +int _fmtFdFlush(Fmt*); + +int _efgfmt(Fmt*); +int _charfmt(Fmt*); +int _countfmt(Fmt*); +int _flagfmt(Fmt*); +int _percentfmt(Fmt*); +int _ifmt(Fmt*); +int _runefmt(Fmt*); +int _runesfmt(Fmt*); +int _strfmt(Fmt*); +int _badfmt(Fmt*); +int _fmtcpy(Fmt*, const void*, int, int); +int _fmtrcpy(Fmt*, const void*, int n); + +void _fmtlock(void); +void _fmtunlock(void); + +#define FMTCHAR(f, t, s, c)\ + do{\ + if(t + 1 > (char*)s){\ + t = _fmtflush(f, t, 1);\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + *t++ = c;\ + }while(0) + +#define FMTRCHAR(f, t, s, c)\ + do{\ + if(t + 1 > (Rune*)s){\ + t = _fmtflush(f, t, sizeof(Rune));\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + *t++ = c;\ + }while(0) + +#define FMTRUNE(f, t, s, r)\ + do{\ + Rune _rune;\ + int _runelen;\ + if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\ + t = _fmtflush(f, t, _runelen);\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + if(r < Runeself)\ + *t++ = r;\ + else{\ + _rune = r;\ + t += runetochar(t, &_rune);\ + }\ + }while(0) diff --git a/sys/src/libc/fmt/fmtfd.c b/sys/src/libc/fmt/fmtfd.c new file mode 100644 index 0000000..4938c15 --- /dev/null +++ b/sys/src/libc/fmt/fmtfd.c @@ -0,0 +1,40 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +/* + * public routine for final flush of a formatting buffer + * to a file descriptor; returns total char count. + */ +int +fmtfdflush(Fmt *f) +{ + if(_fmtFdFlush(f) <= 0) + return -1; + return f->nfmt; +} + +/* + * initialize an output buffer for buffered printing + */ +int +fmtfdinit(Fmt *f, int fd, char *buf, int size) +{ + f->runes = 0; + f->start = buf; + f->to = buf; + f->stop = buf + size; + f->flush = _fmtFdFlush; + f->farg = (void*)(uintptr_t)fd; + f->nfmt = 0; + return 0; +} diff --git a/sys/src/libc/fmt/fmtlock.c b/sys/src/libc/fmt/fmtlock.c new file mode 100644 index 0000000..5583a72 --- /dev/null +++ b/sys/src/libc/fmt/fmtlock.c @@ -0,0 +1,25 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static Lock fmtl; + +void +_fmtlock(void) +{ + lock(&fmtl); +} + +void +_fmtunlock(void) +{ + unlock(&fmtl); +} diff --git a/sys/src/libc/fmt/fmtprint.c b/sys/src/libc/fmt/fmtprint.c new file mode 100644 index 0000000..8c2e149 --- /dev/null +++ b/sys/src/libc/fmt/fmtprint.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + + +/* + * format a string into the output buffer + * designed for formats which themselves call fmt + */ +int +fmtprint(Fmt *f, const char *fmt, ...) +{ + va_list va; + int n; + + va_start(va, fmt); + n = fmtvprint(f, fmt, va); + va_end(va); + return n; +} + diff --git a/sys/src/libc/fmt/fmtquote.c b/sys/src/libc/fmt/fmtquote.c new file mode 100644 index 0000000..589bef7 --- /dev/null +++ b/sys/src/libc/fmt/fmtquote.c @@ -0,0 +1,259 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +/* + * How many bytes of output UTF will be produced by quoting (if necessary) this string? + * How many runes? How much of the input will be consumed? + * The parameter q is filled in by _quotesetup. + * The string may be UTF or Runes (s or r). + * Return count does not include NUL. + * Terminate the scan at the first of: + * NUL in input + * count exceeded in input + * count exceeded on output + * *ninp is set to number of input bytes accepted. + * nin may be <0 initially, to avoid checking input by count. + */ +void +_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, + int sharp, int runesout) +{ + int w; + Rune c; + + q->quoted = 0; + q->nbytesout = 0; + q->nrunesout = 0; + q->nbytesin = 0; + q->nrunesin = 0; + if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ + if(nout < 2) + return; + q->quoted = 1; + q->nbytesout = 2; + q->nrunesout = 2; + } + for(; nin!=0; nin--){ + if(s) + w = chartorune(&c, s); + else{ + c = *r; + w = runelen(c); + } + + if(c == '\0') + break; + if(runesout){ + if(q->nrunesout+1 > nout) + break; + }else{ + if(q->nbytesout+w > nout) + break; + } + + if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ + if(!q->quoted){ + if(runesout){ + if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ + break; + }else{ + if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ + break; + } + q->nrunesout += 2; /* include quotes */ + q->nbytesout += 2; /* include quotes */ + q->quoted = 1; + } + if(c == '\'') { + if(runesout){ + if(1+q->nrunesout+1 > nout) /* no room for quotes */ + break; + }else{ + if(1+q->nbytesout+w > nout) /* no room for quotes */ + break; + } + q->nbytesout++; + q->nrunesout++; /* quotes reproduce as two characters */ + } + } + + /* advance input */ + if(s) + s += w; + else + r++; + q->nbytesin += w; + q->nrunesin++; + + /* advance output */ + q->nbytesout += w; + q->nrunesout++; + } +} + +static int +qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) +{ + Rune r, *rm, *rme; + char *t, *s, *m, *me; + Rune *rt, *rs; + uint32_t fl; + int nc, w; + + m = sin; + me = m + q->nbytesin; + rm = rin; + rme = rm + q->nrunesin; + + w = f->width; + fl = f->flags; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0) + return -1; + } + t = f->to; + s = f->stop; + rt = f->to; + rs = f->stop; + if(f->runes) + FMTRCHAR(f, rt, rs, '\''); + else + FMTRUNE(f, t, s, '\''); + for(nc = q->nrunesin; nc > 0; nc--){ + if(sin){ + r = *(uint8_t*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + }else{ + if(rm >= rme) + break; + r = *(uint8_t*)rm++; + } + if(f->runes){ + FMTRCHAR(f, rt, rs, r); + if(r == '\'') + FMTRCHAR(f, rt, rs, r); + }else{ + FMTRUNE(f, t, s, r); + if(r == '\'') + FMTRUNE(f, t, s, r); + } + } + + if(f->runes){ + FMTRCHAR(f, rt, rs, '\''); + USED(rs); + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0) + return -1; + }else{ + FMTRUNE(f, t, s, '\''); + USED(s); + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0) + return -1; + } + return 0; +} + +int +_quotestrfmt(int runesin, Fmt *f) +{ + int nin, outlen; + Rune *r; + char *s; + Quoteinfo q; + + nin = -1; + if(f->flags&FmtPrec) + nin = f->prec; + if(runesin){ + r = va_arg(f->args, Rune *); + s = nil; + }else{ + s = va_arg(f->args, char *); + r = nil; + } + if(!s && !r) + return _fmtcpy(f, "", 5, 5); + + if(f->flush) + outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ + else if(f->runes) + outlen = (Rune*)f->stop - (Rune*)f->to; + else + outlen = (char*)f->stop - (char*)f->to; + + _quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); +//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); + + if(runesin){ + if(!q.quoted) + return _fmtrcpy(f, r, q.nrunesin); + return qstrfmt(nil, r, &q, f); + } + + if(!q.quoted) + return _fmtcpy(f, s, q.nrunesin, q.nbytesin); + return qstrfmt(s, nil, &q, f); +} + +int +quotestrfmt(Fmt *f) +{ + return _quotestrfmt(0, f); +} + +int +quoterunestrfmt(Fmt *f) +{ + return _quotestrfmt(1, f); +} + +void +quotefmtinstall(void) +{ + fmtinstall('q', quotestrfmt); + fmtinstall('Q', quoterunestrfmt); +} + +int +_needsquotes(char *s, int *quotelenp) +{ + Quoteinfo q; + + _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0); + *quotelenp = q.nbytesout; + + return q.quoted; +} + +int +_runeneedsquotes(Rune *r, int *quotelenp) +{ + Quoteinfo q; + + _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0); + *quotelenp = q.nrunesout; + + return q.quoted; +} diff --git a/sys/src/libc/fmt/fmtrune.c b/sys/src/libc/fmt/fmtrune.c new file mode 100644 index 0000000..7286fa6 --- /dev/null +++ b/sys/src/libc/fmt/fmtrune.c @@ -0,0 +1,34 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +int +fmtrune(Fmt *f, int r) +{ + Rune *rt; + char *t; + int n; + + if(f->runes){ + rt = f->to; + FMTRCHAR(f, rt, f->stop, r); + f->to = rt; + n = 1; + }else{ + t = f->to; + FMTRUNE(f, t, f->stop, r); + n = t - (char*)f->to; + f->to = t; + } + f->nfmt += n; + return 0; +} diff --git a/sys/src/libc/fmt/fmtstr.c b/sys/src/libc/fmt/fmtstr.c new file mode 100644 index 0000000..b746f7e --- /dev/null +++ b/sys/src/libc/fmt/fmtstr.c @@ -0,0 +1,20 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +fmtstrflush(Fmt *f) +{ + if(f->start == nil) + return nil; + *(char*)f->to = '\0'; + return f->start; +} diff --git a/sys/src/libc/fmt/fmtvprint.c b/sys/src/libc/fmt/fmtvprint.c new file mode 100644 index 0000000..5dde86b --- /dev/null +++ b/sys/src/libc/fmt/fmtvprint.c @@ -0,0 +1,39 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + + +/* + * format a string into the output buffer + * designed for formats which themselves call fmt + */ +int +fmtvprint(Fmt *f, const char *fmt, va_list args) +{ + va_list va; + int n; + + //va = f->args; + //f->args = args; + va_copy(va,f->args); + va_end(f->args); + va_copy(f->args,args); + n = dofmt(f, fmt); + va_end(f->args); + va_copy(f->args,va); + va_end(va); + //f->args = va; + if(n >= 0) + return 0; + return n; +} + diff --git a/sys/src/libc/fmt/fprint.c b/sys/src/libc/fmt/fprint.c new file mode 100644 index 0000000..6ee18c1 --- /dev/null +++ b/sys/src/libc/fmt/fprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +fprint(int fd, const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(fd, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/print.c b/sys/src/libc/fmt/print.c new file mode 100644 index 0000000..2187747 --- /dev/null +++ b/sys/src/libc/fmt/print.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +print(const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(1, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/runefmtstr.c b/sys/src/libc/fmt/runefmtstr.c new file mode 100644 index 0000000..aa0d003 --- /dev/null +++ b/sys/src/libc/fmt/runefmtstr.c @@ -0,0 +1,20 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runefmtstrflush(Fmt *f) +{ + if(f->start == nil) + return nil; + *(Rune*)f->to = '\0'; + return f->start; +} diff --git a/sys/src/libc/fmt/runeseprint.c b/sys/src/libc/fmt/runeseprint.c new file mode 100644 index 0000000..ff0d51c --- /dev/null +++ b/sys/src/libc/fmt/runeseprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runeseprint(Rune *buf, Rune *e, const char *fmt, ...) +{ + Rune *p; + va_list args; + + va_start(args, fmt); + p = runevseprint(buf, e, fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/runesmprint.c b/sys/src/libc/fmt/runesmprint.c new file mode 100644 index 0000000..337d0d3 --- /dev/null +++ b/sys/src/libc/fmt/runesmprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runesmprint(const char *fmt, ...) +{ + va_list args; + Rune *p; + + va_start(args, fmt); + p = runevsmprint(fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/runesnprint.c b/sys/src/libc/fmt/runesnprint.c new file mode 100644 index 0000000..6478727 --- /dev/null +++ b/sys/src/libc/fmt/runesnprint.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +runesnprint(Rune *buf, int len, const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = runevsnprint(buf, len, fmt, args); + va_end(args); + return n; +} + diff --git a/sys/src/libc/fmt/runesprint.c b/sys/src/libc/fmt/runesprint.c new file mode 100644 index 0000000..c7128fd --- /dev/null +++ b/sys/src/libc/fmt/runesprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +runesprint(Rune *buf, const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = runevsnprint(buf, 256, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/runevseprint.c b/sys/src/libc/fmt/runevseprint.c new file mode 100644 index 0000000..de6eebc --- /dev/null +++ b/sys/src/libc/fmt/runevseprint.c @@ -0,0 +1,34 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runevseprint(Rune *buf, Rune *e, const char *fmt, va_list args) +{ + Fmt f; + + if(e <= buf) + return nil; + f.runes = 1; + f.start = buf; + f.to = buf; + f.stop = e - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + //f.args = args; + va_copy(f.args,args); + dofmt(&f, fmt); + va_end(f.args); + *(Rune*)f.to = '\0'; + return f.to; +} + diff --git a/sys/src/libc/fmt/runevsmprint.c b/sys/src/libc/fmt/runevsmprint.c new file mode 100644 index 0000000..ad43410 --- /dev/null +++ b/sys/src/libc/fmt/runevsmprint.c @@ -0,0 +1,83 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +static int +runeFmtStrFlush(Fmt *f) +{ + Rune *s; + int n; + + if(f->start == nil) + return 0; + n = (int)(uintptr)f->farg; + n *= 2; + s = f->start; + f->start = realloc(s, sizeof(Rune)*n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)(uintptr_t)n; + f->to = (Rune*)f->start + ((Rune*)f->to - s); + f->stop = (Rune*)f->start + n - 1; + return 1; +} + +int +runefmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 1; + n = 32; + f->start = malloc(sizeof(Rune)*n); + if(f->start == nil) + return -1; + setmalloctag(f->start, getcallerpc()); + f->to = f->start; + f->stop = (Rune*)f->start + n - 1; + f->flush = runeFmtStrFlush; + f->farg = (void*)(uintptr_t)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +Rune* +runevsmprint(const char *fmt, va_list args) +{ + Fmt f; + int n; + + if(runefmtstrinit(&f) < 0) + return nil; + //f.args = args; + va_copy(f.args,args); + n = dofmt(&f, fmt); + va_end(f.args); + if(f.start == nil) /* realloc failed? */ + return nil; + if(n < 0){ + free(f.start); + return nil; + } + setmalloctag(f.start, getcallerpc()); + *(Rune*)f.to = '\0'; + return f.start; +} diff --git a/sys/src/libc/fmt/runevsnprint.c b/sys/src/libc/fmt/runevsnprint.c new file mode 100644 index 0000000..c7cec2d --- /dev/null +++ b/sys/src/libc/fmt/runevsnprint.c @@ -0,0 +1,33 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +runevsnprint(Rune *buf, int len, const char *fmt, va_list args) +{ + Fmt f; + + if(len <= 0) + return -1; + f.runes = 1; + f.start = buf; + f.to = buf; + f.stop = buf + len - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + //f.args = args; + va_copy(f.args,args); + dofmt(&f, fmt); + va_end(f.args); + *(Rune*)f.to = '\0'; + return (Rune*)f.to - buf; +} diff --git a/sys/src/libc/fmt/seprint.c b/sys/src/libc/fmt/seprint.c new file mode 100644 index 0000000..614be35 --- /dev/null +++ b/sys/src/libc/fmt/seprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +seprint(char *buf, char *e, const char *fmt, ...) +{ + char *p; + va_list args; + + va_start(args, fmt); + p = vseprint(buf, e, fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/smprint.c b/sys/src/libc/fmt/smprint.c new file mode 100644 index 0000000..2dc9c7c --- /dev/null +++ b/sys/src/libc/fmt/smprint.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +smprint(const char *fmt, ...) +{ + va_list args; + char *p; + + va_start(args, fmt); + p = vsmprint(fmt, args); + va_end(args); + setmalloctag(p, getcallerpc()); + return p; +} diff --git a/sys/src/libc/fmt/snprint.c b/sys/src/libc/fmt/snprint.c new file mode 100644 index 0000000..528fedc --- /dev/null +++ b/sys/src/libc/fmt/snprint.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +snprint(char *buf, int len, const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprint(buf, len, fmt, args); + va_end(args); + return n; +} + diff --git a/sys/src/libc/fmt/sprint.c b/sys/src/libc/fmt/sprint.c new file mode 100644 index 0000000..7cb4915 --- /dev/null +++ b/sys/src/libc/fmt/sprint.c @@ -0,0 +1,23 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +sprint(char *buf, const char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */ + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/vfprint.c b/sys/src/libc/fmt/vfprint.c new file mode 100644 index 0000000..a6445ba --- /dev/null +++ b/sys/src/libc/fmt/vfprint.c @@ -0,0 +1,45 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +/* + * generic routine for flushing a formatting buffer + * to a file descriptor + */ +int +_fmtFdFlush(Fmt *f) +{ + int n; + + n = (char*)f->to - (char*)f->start; + if(n && write((int)(uintptr)f->farg, f->start, n) != n) + return 0; + f->to = f->start; + return 1; +} + +int +vfprint(int fd, const char *fmt, va_list args) +{ + Fmt f; + char buf[256]; + int n; + + fmtfdinit(&f, fd, buf, sizeof(buf)); + //f.args = args; + va_copy(f.args,args); + n = dofmt(&f, fmt); + va_end(f.args); + if(n > 0 && _fmtFdFlush(&f) == 0) + return -1; + return n; +} diff --git a/sys/src/libc/fmt/vseprint.c b/sys/src/libc/fmt/vseprint.c new file mode 100644 index 0000000..3f69275 --- /dev/null +++ b/sys/src/libc/fmt/vseprint.c @@ -0,0 +1,34 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +vseprint(char *buf, char *e, const char *fmt, va_list args) +{ + Fmt f; + + if(e <= buf) + return nil; + f.runes = 0; + f.start = buf; + f.to = buf; + f.stop = e - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + //f.args = args; + va_copy(f.args,args); + dofmt(&f, fmt); + va_end(f.args); + *(char*)f.to = '\0'; + return f.to; +} + diff --git a/sys/src/libc/fmt/vsmprint.c b/sys/src/libc/fmt/vsmprint.c new file mode 100644 index 0000000..346017c --- /dev/null +++ b/sys/src/libc/fmt/vsmprint.c @@ -0,0 +1,85 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include "fmtdef.h" + +static int +fmtStrFlush(Fmt *f) +{ + char *s; + int n; + + if(f->start == nil) + return 0; + n = (int)(uintptr)f->farg; + n *= 2; + s = f->start; + f->start = realloc(s, n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)(uintptr_t)n; + f->to = (char*)f->start + ((char*)f->to - s); + f->stop = (char*)f->start + n - 1; + return 1; +} + +int +fmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 0; + n = 32; + /* this should not be necessary */ + n = 4096; + f->start = malloc(n); + if(f->start == nil) + return -1; + setmalloctag(f->start, getcallerpc()); + f->to = f->start; + f->stop = (char*)f->start + n - 1; + f->flush = fmtStrFlush; + f->farg = (void*)(uintptr_t)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +char* +vsmprint(const char *fmt, va_list args) +{ + Fmt f; + int n; + + if(fmtstrinit(&f) < 0) + return nil; + //f.args = args; + va_copy(f.args,args); + n = dofmt(&f, fmt); + va_end(f.args); + if(f.start == nil) /* realloc failed? */ + return nil; + if(n < 0){ + free(f.start); + return nil; + } + setmalloctag(f.start, getcallerpc()); + *(char*)f.to = '\0'; + return f.start; +} diff --git a/sys/src/libc/fmt/vsnprint.c b/sys/src/libc/fmt/vsnprint.c new file mode 100644 index 0000000..f22c1dc --- /dev/null +++ b/sys/src/libc/fmt/vsnprint.c @@ -0,0 +1,33 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +vsnprint(char *buf, int len, const char *fmt, va_list args) +{ + Fmt f; + + if(len <= 0) + return -1; + f.runes = 0; + f.start = buf; + f.to = buf; + f.stop = buf + len - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + //f.args = args; + va_copy(f.args,args); + dofmt(&f, fmt); + va_end(f.args); + *(char*)f.to = '\0'; + return (char*)f.to - buf; +} diff --git a/sys/src/libc/klibc.json b/sys/src/libc/klibc.json new file mode 100644 index 0000000..2d852be --- /dev/null +++ b/sys/src/libc/klibc.json @@ -0,0 +1,255 @@ +{ + "KernelLibc": { + "Cflags": [ + "-fasm", + "-Werror" + ], + "Include": [ + "../klib.json" + ], + "Install": "/arch/$ARCH/lib/", + "Library": "klibc.a", + "Post": [ + "rm 9syscall/*.s" + ], + "Projects": [ + "9syscall/9syscall.json" + ], + "SourceFiles": [ + "9sys/access.c", + "9sys/announce.c", + "9sys/awakened.c", + "9sys/convD2M.c", + "9sys/convM2D.c", + "9sys/convM2S.c", + "9sys/convS2M.c", + "9sys/cputime.c", + "9sys/ctime.c", + "9sys/dial.c", + "9sys/dirfstat.c", + "9sys/dirfwstat.c", + "9sys/dirmodefmt.c", + "9sys/dirread.c", + "9sys/dirstat.c", + "9sys/dirwstat.c", + "9sys/fcallfmt.c", + "9sys/fork.c", + "9sys/getnetconninfo.c", + "9sys/getenv.c", + "9sys/getpid.c", + "9sys/getppid.c", + "9sys/getwd.c", + "9sys/iounit.c", + "9sys/nulldir.c", + "9sys/postnote.c", + "9sys/privalloc.c", + "9sys/pushssl.c", + "9sys/putenv.c", + "9sys/qlock.c", + "9sys/read9pmsg.c", + "9sys/read.c", + "9sys/readv.c", + "9sys/rerrstr.c", + "9sys/sbrk.c", + "9sys/setnetmtpt.c", + "9sys/sleep.c", + "9sys/sysfatal.c", + "9sys/syslog.c", + "9sys/sysname.c", + "9sys/time.c", + "9sys/times.c", + "9sys/tm2sec.c", + "9sys/truerand.c", + "9sys/wait.c", + "9sys/waitpid.c", + "9sys/werrstr.c", + "9sys/write.c", + "9sys/writev.c", + "9syscall/alarm.s", + "9syscall/await.s", + "9syscall/awake.s", + "9syscall/bind.s", + "9syscall/brk_.s", + "9syscall/chdir.s", + "9syscall/close.s", + "9syscall/create.s", + "9syscall/dup.s", + "9syscall/errstr.s", + "9syscall/exec.s", + "9syscall/_exits.s", + "9syscall/fauth.s", + "9syscall/fd2path.s", + "9syscall/fstat.s", + "9syscall/fversion.s", + "9syscall/fwstat.s", + "9syscall/mount.s", + "9syscall/noted.s", + "9syscall/notify.s", + "9syscall/nsec.s", + "9syscall/open.s", + "9syscall/pipe.s", + "9syscall/pread.s", + "9syscall/pwrite.s", + "9syscall/remove.s", + "9syscall/rendezvous.s", + "9syscall/rfork.s", + "9syscall/seek.s", + "9syscall/segattach.s", + "9syscall/segbrk.s", + "9syscall/segdetach.s", + "9syscall/segflush.s", + "9syscall/segfree.s", + "9syscall/semacquire.s", + "9syscall/semrelease.s", + "9syscall/stat.s", + "9syscall/tsemacquire.s", + "9syscall/unmount.s", + "9syscall/wstat.s", + "fmt/dofmt.c", + "fmt/dorfmt.c", + "fmt/errfmt.c", + "fmt/fltfmt.c", + "fmt/fmt.c", + "fmt/fmtfd.c", + "fmt/fmtlock.c", + "fmt/fmtprint.c", + "fmt/fmtquote.c", + "fmt/fmtrune.c", + "fmt/fmtstr.c", + "fmt/fmtvprint.c", + "fmt/fprint.c", + "fmt/print.c", + "fmt/runefmtstr.c", + "fmt/runeseprint.c", + "fmt/runesmprint.c", + "fmt/runesnprint.c", + "fmt/runesprint.c", + "fmt/runevseprint.c", + "fmt/runevsmprint.c", + "fmt/runevsnprint.c", + "fmt/seprint.c", + "fmt/smprint.c", + "fmt/snprint.c", + "fmt/sprint.c", + "fmt/vfprint.c", + "fmt/vseprint.c", + "fmt/vsmprint.c", + "fmt/vsnprint.c", + "port/_assert.c", + "port/abs.c", + "port/asin.c", + "port/atan.c", + "port/atan2.c", + "port/atexit.c", + "port/atnotify.c", + "port/atof.c", + "port/atol.c", + "port/atoll.c", + "port/cistrcmp.c", + "port/cistrncmp.c", + "port/cistrstr.c", + "port/charstod.c", + "port/cleanname.c", + "port/ctype.c", + "port/encodefmt.c", + "port/execl.c", + "port/exp.c", + "port/fabs.c", + "port/floor.c", + "port/fmod.c", + "port/frand.c", + "port/frexp.c", + "port/getcallerpc.c", + "port/getfields.c", + "port/getuser.c", + "port/hangup.c", + "port/hypot.c", + "port/lnrand.c", + "port/lock.c", + "port/log.c", + "port/lrand.c", + "port/malloc.c", + "port/memccpy.c", + "port/memchr.c", + "port/memcmp.c", + "port/memmove.c", + "port/memset.c", + "port/mktemp.c", + "port/muldiv.c", + "port/nan.c", + "port/needsrcquote.c", + "port/netmkaddr.c", + "port/nrand.c", + "port/ntruerand.c", + "port/perror.c", + "port/pool.c", + "port/pow.c", + "port/pow10.c", + "port/qsort.c", + "port/quote.c", + "port/rand.c", + "port/readn.c", + "port/rune.c", + "port/runebase.c", + "port/runebsearch.c", + "port/runestrcat.c", + "port/runestrchr.c", + "port/runestrcmp.c", + "port/runestrcpy.c", + "port/runestrecpy.c", + "port/runestrdup.c", + "port/runestrncat.c", + "port/runestrncmp.c", + "port/runestrncpy.c", + "port/runestrrchr.c", + "port/runestrlen.c", + "port/runestrstr.c", + "port/runetype.c", + "port/sin.c", + "port/sinh.c", + "port/strcat.c", + "port/strchr.c", + "port/strcmp.c", + "port/strcpy.c", + "port/strecpy.c", + "port/strcspn.c", + "port/strdup.c", + "port/strlen.c", + "port/strncat.c", + "port/strncmp.c", + "port/strncpy.c", + "port/strpbrk.c", + "port/strrchr.c", + "port/strspn.c", + "port/strstr.c", + "port/strtod.c", + "port/strtok.c", + "port/strtol.c", + "port/strtoll.c", + "port/strtoul.c", + "port/strtoull.c", + "port/tan.c", + "port/tanh.c", + "port/tokenize.c", + "port/toupper.c", + "port/utfecpy.c", + "port/utflen.c", + "port/utfnlen.c", + "port/utfrune.c", + "port/utfrrune.c", + "port/utfutf.c", + "port/u16.c", + "port/u32.c", + "port/u64.c", + "$ARCH/notejmp.c", + "$ARCH/cycles.c", + "$ARCH/argv0.c", + "$ARCH/rdpmc.c", + "$ARCH/setjmp.s", + "$ARCH/sqrt.s", + "$ARCH/tas.s", + "$ARCH/atom.S", + "$ARCH/main9.S" + ] + } +} diff --git a/sys/src/libc/port/_assert.c b/sys/src/libc/port/_assert.c new file mode 100644 index 0000000..34d15c2 --- /dev/null +++ b/sys/src/libc/port/_assert.c @@ -0,0 +1,22 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void (*__assert)(char*); + +void +_assert(const char *s) +{ + if(__assert) + (*__assert)((char*)s); + fprint(2, "assert failed: %s\n", s); + abort(); +} diff --git a/sys/src/libc/port/abs.c b/sys/src/libc/port/abs.c new file mode 100644 index 0000000..5fba73e --- /dev/null +++ b/sys/src/libc/port/abs.c @@ -0,0 +1,27 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +abs(int a) +{ + if(a < 0) + return -a; + return a; +} + +int32_t +labs(int32_t a) +{ + if(a < 0) + return -a; + return a; +} diff --git a/sys/src/libc/port/asin.c b/sys/src/libc/port/asin.c new file mode 100644 index 0000000..3be7660 --- /dev/null +++ b/sys/src/libc/port/asin.c @@ -0,0 +1,49 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * asin(arg) and acos(arg) return the arcsin, arccos, + * respectively of their arguments. + * + * Arctan is called after appropriate range reduction. + */ + +#include +#include + +double +asin(double arg) +{ + double temp; + int sign; + + sign = 0; + if(arg < 0) { + arg = -arg; + sign++; + } + if(arg > 1) + return NaN(); + temp = sqrt(1 - arg*arg); + if(arg > 0.7) + temp = PIO2 - atan(temp/arg); + else + temp = atan(arg/temp); + if(sign) + temp = -temp; + return temp; +} + +double +acos(double arg) +{ + if(arg > 1 || arg < -1) + return NaN(); + return PIO2 - asin(arg); +} diff --git a/sys/src/libc/port/atan.c b/sys/src/libc/port/atan.c new file mode 100644 index 0000000..864d534 --- /dev/null +++ b/sys/src/libc/port/atan.c @@ -0,0 +1,87 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + floating-point arctangent + + atan returns the value of the arctangent of its + argument in the range [-pi/2,pi/2]. + + atan2 returns the arctangent of arg1/arg2 + in the range [-pi,pi]. + + there are no error returns. + + coefficients are #5077 from Hart & Cheney. (19.56D) +*/ + +#include +#include + +#define sq2p1 2.414213562373095048802e0 +#define sq2m1 .414213562373095048802e0 +#define p4 .161536412982230228262e2 +#define p3 .26842548195503973794141e3 +#define p2 .11530293515404850115428136e4 +#define p1 .178040631643319697105464587e4 +#define p0 .89678597403663861959987488e3 +#define q4 .5895697050844462222791e2 +#define q3 .536265374031215315104235e3 +#define q2 .16667838148816337184521798e4 +#define q1 .207933497444540981287275926e4 +#define q0 .89678597403663861962481162e3 + + +/* + xatan evaluates a series valid in the + range [-0.414...,+0.414...]. (tan(pi/8)) + */ + +static +double +xatan(double arg) +{ + double argsq, value; + + argsq = arg*arg; + value = ((((p4*argsq + p3)*argsq + p2)*argsq + p1)*argsq + p0); + value = value/(((((argsq + q4)*argsq + q3)*argsq + q2)*argsq + q1)*argsq + q0); + return value*arg; +} + +/* + satan reduces its argument (known to be positive) + to the range [0,0.414...] and calls xatan. + */ + +static +double +satan(double arg) +{ + + if(arg < sq2m1) + return xatan(arg); + if(arg > sq2p1) + return PIO2 - xatan(1/arg); + return PIO2/2 + xatan((arg-1)/(arg+1)); +} + +/* + atan makes its argument positive and + calls the inner routine satan. + */ + +double +atan(double arg) +{ + + if(arg > 0) + return satan(arg); + return -satan(-arg); +} diff --git a/sys/src/libc/port/atan2.c b/sys/src/libc/port/atan2.c new file mode 100644 index 0000000..14874e8 --- /dev/null +++ b/sys/src/libc/port/atan2.c @@ -0,0 +1,33 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +/* + atan2 discovers what quadrant the angle + is in and calls atan. +*/ + +double +atan2(double arg1, double arg2) +{ + + if(arg1+arg2 == arg1) { + if(arg1 >= 0) + return PIO2; + return -PIO2; + } + arg1 = atan(arg1/arg2); + if(arg2 < 0) { + if(arg1 <= 0) + return arg1 + PI; + return arg1 - PI; + } + return arg1; +} diff --git a/sys/src/libc/port/atexit.c b/sys/src/libc/port/atexit.c new file mode 100644 index 0000000..c52d896 --- /dev/null +++ b/sys/src/libc/port/atexit.c @@ -0,0 +1,69 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define NEXIT 33 + +typedef struct Onex Onex; +struct Onex{ + void (*f)(void); + int pid; +}; + +static Lock onexlock; +Onex onex[NEXIT]; + +int +atexit(void (*f)(void)) +{ + int i; + + lock(&onexlock); + for(i=0; i= 0; i--) + if((f = onex[i].f) && pid == onex[i].pid) { + onex[i].f = 0; + (*f)(); + } + _exits(s); +} + +#pragma profile on diff --git a/sys/src/libc/port/atnotify.c b/sys/src/libc/port/atnotify.c new file mode 100644 index 0000000..e7bec33 --- /dev/null +++ b/sys/src/libc/port/atnotify.c @@ -0,0 +1,67 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define NFN 33 +static int (*onnot[NFN])(void*, char*); +static Lock onnotlock; + +static +void +notifier(void *v, char *s) +{ + int i; + + for(i=0; i +#include + +double +atof(const char *cp) +{ + return strtod(cp, 0); +} diff --git a/sys/src/libc/port/atol.c b/sys/src/libc/port/atol.c new file mode 100644 index 0000000..a72a2be --- /dev/null +++ b/sys/src/libc/port/atol.c @@ -0,0 +1,62 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int32_t +atol(const char *s) +{ + int32_t n; + int f, c; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]) { + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;) { + c = *s; + if(c >= '0' && c <= '9') + n = n*16 + c - '0'; + else + if(c >= 'a' && c <= 'f') + n = n*16 + c - 'a' + 10; + else + if(c >= 'A' && c <= 'F') + n = n*16 + c - 'A' + 10; + else + break; + s++; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +int +atoi(const char *s) +{ + + return atol(s); +} diff --git a/sys/src/libc/port/atoll.c b/sys/src/libc/port/atoll.c new file mode 100644 index 0000000..ae52759 --- /dev/null +++ b/sys/src/libc/port/atoll.c @@ -0,0 +1,17 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int64_t +atoll(const char *s) +{ + return strtoll(s, nil, 0); +} diff --git a/sys/src/libc/port/charstod.c b/sys/src/libc/port/charstod.c new file mode 100644 index 0000000..af169ad --- /dev/null +++ b/sys/src/libc/port/charstod.c @@ -0,0 +1,90 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * Reads a floating-point number by interpreting successive characters + * returned by (*f)(vp). The last call it makes to f terminates the + * scan, so is not a character in the number. It may therefore be + * necessary to back up the input stream up one byte after calling charstod. + */ + +#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp) + +double +charstod(int(*f)(void*), void *vp) +{ + char str[400], *s, *e, *start; + int c; + + s = str; + e = str + sizeof str - 1; + c = (*f)(vp); + while(c == ' ' || c == '\t') + c = (*f)(vp); + if(c == '-' || c == '+'){ + ADVANCE; + } + start = s; + while(c >= '0' && c <= '9'){ + ADVANCE; + } + if(c == '.'){ + ADVANCE; + while(c >= '0' && c <= '9'){ + ADVANCE; + } + } + if(s > start && (c == 'e' || c == 'E')){ + ADVANCE; + if(c == '-' || c == '+'){ + ADVANCE; + } + while(c >= '0' && c <= '9'){ + ADVANCE; + } + }else if(s == start && (c == 'i' || c == 'I')){ + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; + if(c != 'f' && c != 'F') + return NaN(); + ADVANCE; + if(c != 'i' && c != 'I') + return NaN(); + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; + if(c != 'i' && c != 'I') + return NaN(); + ADVANCE; + if(c != 't' && c != 'T') + return NaN(); + ADVANCE; + if(c != 'y' && c != 'Y') + return NaN(); + ADVANCE; /* so caller can back up uniformly */ + USED(c); + }else if(s == str && (c == 'n' || c == 'N')){ + ADVANCE; + if(c != 'a' && c != 'A') + return NaN(); + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; /* so caller can back up uniformly */ + USED(c); + } + *s = 0; + return strtod(str, (const char **)&s); +} diff --git a/sys/src/libc/port/cistrcmp.c b/sys/src/libc/port/cistrcmp.c new file mode 100644 index 0000000..e664109 --- /dev/null +++ b/sys/src/libc/port/cistrcmp.c @@ -0,0 +1,35 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +cistrcmp(const char *s1, const char *s2) +{ + int c1, c2; + + while(*s1){ + c1 = *(uint8_t*)s1++; + c2 = *(uint8_t*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + return -*s2; +} diff --git a/sys/src/libc/port/cistrncmp.c b/sys/src/libc/port/cistrncmp.c new file mode 100644 index 0000000..c1d0760 --- /dev/null +++ b/sys/src/libc/port/cistrncmp.c @@ -0,0 +1,37 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +cistrncmp(const char *s1, const char *s2, int n) +{ + int c1, c2; + + while(*s1 && n-- > 0){ + c1 = *(uint8_t*)s1++; + c2 = *(uint8_t*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + if(n <= 0) + return 0; + return -*s2; +} diff --git a/sys/src/libc/port/cistrstr.c b/sys/src/libc/port/cistrstr.c new file mode 100644 index 0000000..fc41b6f --- /dev/null +++ b/sys/src/libc/port/cistrstr.c @@ -0,0 +1,32 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +cistrstr(const char *s, const char *sub) +{ + int c, csub, n; + + csub = *sub; + if(csub == '\0') + return (char*)s; + if(csub >= 'A' && csub <= 'Z') + csub -= 'A' - 'a'; + sub++; + n = strlen(sub); + for(; c = *s; s++){ + if(c >= 'A' && c <= 'Z') + c -= 'A' - 'a'; + if(c == csub && cistrncmp(s+1, sub, n) == 0) + return (char*)s; + } + return nil; +} diff --git a/sys/src/libc/port/cleanname.c b/sys/src/libc/port/cleanname.c new file mode 100644 index 0000000..d7e8556 --- /dev/null +++ b/sys/src/libc/port/cleanname.c @@ -0,0 +1,106 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * In place, rewrite name to compress multiple /, eliminate ., and process .. + */ +#define SEP(x) ((x)=='/' || (x) == 0) +char* +cleanname(char *name) +{ + char *s; /* source of copy */ + char *d; /* destination of copy */ + char *d0; /* start of path afer the root name */ + Rune r; + int rooted; + + if(name[0] == 0) + return strcpy(name, "."); + rooted = 0; + d0 = name; + if(d0[0] == '#'){ + if(d0[1] == 0) + return d0; + d0 += 1 + chartorune(&r, d0+1); /* ignore slash: #/ */ + while(!SEP(*d0)) + d0 += chartorune(&r, d0); + if(d0 == 0) + return name; + d0++; /* keep / after # */ + rooted = 1; + }else if(d0[0] == '/'){ + rooted = 1; + d0++; + } + + s = d0; + if(rooted){ + /* skip extra '/' at root name */ + for(; *s == '/'; s++) + ; + } + /* remove dup slashes */ + for(d = d0; *s != 0; s++){ + *d++ = *s; + if(*s == '/') + while(s[1] == '/') + s++; + } + *d = 0; + + d = d0; + s = d0; + while(*s != 0){ + if(s[0] == '.' && SEP(s[1])){ + if(s[1] == 0) + break; + s+= 2; + continue; + } + if(s[0] == '.' && s[1] == '.' && SEP(s[2])){ + if(d == d0){ + if(rooted){ + /* /../x -> /x */ + if(s[2] == 0) + break; + s += 3; + continue; + }else{ + /* ../x -> ../x; and never collect ../ */ + d0 += 3; + } + } + if(d > d0){ + /* a/../x -> x */ + assert(d-2 >= d0 && d[-1] == '/'); + for(d -= 2; d > d0 && d[-1] != '/'; d--) + ; + if(s[2] == 0) + break; + s += 3; + continue; + } + } + while(!SEP(*s)) + *d++ = *s++; + if(*s == 0) + break; + + *d++ = *s++; + } + *d = 0; + if(d-1 > name && d[-1] == '/') /* thanks to #/ */ + *--d = 0; + if(name[0] == 0) + strcpy(name, "."); + return name; +} diff --git a/sys/src/libc/port/crypt.c b/sys/src/libc/port/crypt.c new file mode 100644 index 0000000..1aada9f --- /dev/null +++ b/sys/src/libc/port/crypt.c @@ -0,0 +1,77 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * Data Encryption Standard + * D.P.Mitchell 83/06/08. + * + * block_cipher(key, block, decrypting) + * + * these routines use the non-standard 7 byte format + * for DES keys. + */ +#include +#include +#include +#include + +/* + * destructively encrypt the buffer, which + * must be at least 8 characters long. + */ +int +encrypt(void *key, void *vbuf, int n) +{ + uint32_t ekey[32]; + uint8_t *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + for(i = 0; i < n; i++){ + block_cipher(ekey, buf, 0); + buf += 7; + } + if(r) + block_cipher(ekey, buf - 7 + r, 0); + return 1; +} + +/* + * destructively decrypt the buffer, which + * must be at least 8 characters long. + */ +int +decrypt(void *key, void *vbuf, int n) +{ + uint32_t ekey[128]; + uint8_t *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + buf += n * 7; + if(r) + block_cipher(ekey, buf - 7 + r, 1); + for(i = 0; i < n; i++){ + buf -= 7; + block_cipher(ekey, buf, 1); + } + return 1; +} diff --git a/sys/src/libc/port/ctype.c b/sys/src/libc/port/ctype.c new file mode 100644 index 0000000..5e3b843 --- /dev/null +++ b/sys/src/libc/port/ctype.c @@ -0,0 +1,34 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +uint8_t _ctype[256] = +{ +/* 0 1 2 3 4 5 6 7 */ + +/* 0*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 10*/ _C, _S|_C, _S|_C, _S|_C, _S|_C, _S|_C, _C, _C, +/* 20*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 30*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 40*/ _S|_B, _P, _P, _P, _P, _P, _P, _P, +/* 50*/ _P, _P, _P, _P, _P, _P, _P, _P, +/* 60*/ _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, +/* 70*/ _N|_X, _N|_X, _P, _P, _P, _P, _P, _P, +/*100*/ _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, +/*110*/ _U, _U, _U, _U, _U, _U, _U, _U, +/*120*/ _U, _U, _U, _U, _U, _U, _U, _U, +/*130*/ _U, _U, _U, _P, _P, _P, _P, _P, +/*140*/ _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, +/*150*/ _L, _L, _L, _L, _L, _L, _L, _L, +/*160*/ _L, _L, _L, _L, _L, _L, _L, _L, +/*170*/ _L, _L, _L, _P, _P, _P, _P, _C, +}; diff --git a/sys/src/libc/port/encodefmt.c b/sys/src/libc/port/encodefmt.c new file mode 100644 index 0000000..7fd710c --- /dev/null +++ b/sys/src/libc/port/encodefmt.c @@ -0,0 +1,86 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +int +encodefmt(Fmt *f) +{ + char *out; + char *buf; + int len; + int ilen; + int rv; + uint8_t *b; + char *p; + char obuf[64]; // rsc optimization + + if(!(f->flags&FmtPrec) || f->prec < 1) + goto error; + + b = va_arg(f->args, uint8_t*); + if(b == 0) + return fmtstrcpy(f, ""); + + ilen = f->prec; + f->prec = 0; + f->flags &= ~FmtPrec; + switch(f->r){ + case '<': + len = (8*ilen+4)/5 + 3; + break; + case '[': + len = (8*ilen+5)/6 + 4; + break; + case 'H': + len = 2*ilen + 1; + break; + default: + goto error; + } + + if(len > sizeof(obuf)){ + buf = malloc(len); + if(buf == nil) + goto error; + } else + buf = obuf; + + // convert + out = buf; + switch(f->r){ + case '<': + rv = enc32(out, len, b, ilen); + break; + case '[': + rv = enc64(out, len, b, ilen); + break; + case 'H': + rv = enc16(out, len, b, ilen); + if(rv >= 0 && (f->flags & FmtLong)) + for(p = buf; *p; p++) + *p = tolower(*p); + break; + default: + rv = -1; + break; + } + if(rv < 0) + goto error; + + fmtstrcpy(f, buf); + if(buf != obuf) + free(buf); + return 0; + +error: + return fmtstrcpy(f, ""); +} diff --git a/sys/src/libc/port/execl.c b/sys/src/libc/port/execl.c new file mode 100644 index 0000000..effced1 --- /dev/null +++ b/sys/src/libc/port/execl.c @@ -0,0 +1,39 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + + +int +execl(const char *f, ...) +{ + va_list va, va2; + char *arg; + int n; + + va_start(va, f); + va_copy(va2, va); + + n = 0; + while((arg = va_arg(va, char *)) != nil) + n++; + + char *args[n+1]; + + n = 0; + while((arg = va_arg(va2, char *)) != nil) + args[n++] = arg; + args[n] = nil; + + va_end(va); + va_end(va2); + + return exec(f, args); +} diff --git a/sys/src/libc/port/exp.c b/sys/src/libc/port/exp.c new file mode 100644 index 0000000..49cf0fb --- /dev/null +++ b/sys/src/libc/port/exp.c @@ -0,0 +1,49 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + exp returns the exponential function of its + floating-point argument. + + The coefficients are #1069 from Hart and Cheney. (22.35D) +*/ + +#include +#include + +#define p0 .2080384346694663001443843411e7 +#define p1 .3028697169744036299076048876e5 +#define p2 .6061485330061080841615584556e2 +#define q0 .6002720360238832528230907598e7 +#define q1 .3277251518082914423057964422e6 +#define q2 .1749287689093076403844945335e4 +#define log2e 1.4426950408889634073599247 +#define sqrt2 1.4142135623730950488016887 +#define maxf 10000 + +double +exp(double arg) +{ + double fract, temp1, temp2, xsq; + int ent; + + if(arg == 0) + return 1; + if(arg < -maxf) + return 0; + if(arg > maxf) + return Inf(1); + arg *= log2e; + ent = floor(arg); + fract = (arg-ent) - 0.5; + xsq = fract*fract; + temp1 = ((p2*xsq+p1)*xsq+p0)*fract; + temp2 = ((xsq+q2)*xsq+q1)*xsq + q0; + return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent); +} diff --git a/sys/src/libc/port/fabs.c b/sys/src/libc/port/fabs.c new file mode 100644 index 0000000..27eef4e --- /dev/null +++ b/sys/src/libc/port/fabs.c @@ -0,0 +1,20 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +double +fabs(double arg) +{ + + if(arg < 0) + return -arg; + return arg; +} diff --git a/sys/src/libc/port/floor.c b/sys/src/libc/port/floor.c new file mode 100644 index 0000000..3e6761b --- /dev/null +++ b/sys/src/libc/port/floor.c @@ -0,0 +1,36 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +/* + * floor and ceil-- greatest integer <= arg + * (resp least >=) + */ + +double +floor(double d) +{ + double fract; + + if(d < 0) { + fract = modf(-d, &d); + if(fract != 0.0) + d += 1; + d = -d; + } else + modf(d, &d); + return d; +} + +double +ceil(double d) +{ + return -floor(-d); +} diff --git a/sys/src/libc/port/fmod.c b/sys/src/libc/port/fmod.c new file mode 100644 index 0000000..90669cc --- /dev/null +++ b/sys/src/libc/port/fmod.c @@ -0,0 +1,40 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * floating-point mod function without infinity or NaN checking + */ +double +fmod (double x, double y) +{ + int sign, yexp, rexp; + double r, yfr, rfr; + + if (y == 0) + return x; + if (y < 0) + y = -y; + yfr = frexp(y, &yexp); + sign = 0; + if(x < 0) { + r = -x; + sign++; + } else + r = x; + while(r >= y) { + rfr = frexp(r, &rexp); + r -= ldexp(y, rexp - yexp - (rfr < yfr)); + } + if(sign) + r = -r; + return r; +} diff --git a/sys/src/libc/port/frand.c b/sys/src/libc/port/frand.c new file mode 100644 index 0000000..ac14ab2 --- /dev/null +++ b/sys/src/libc/port/frand.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define MASK 0x7fffffffL +#define NORM (1.0/(1.0+MASK)) + +double +frand(void) +{ + double x; + + do { + x = lrand() * NORM; + x = (x + lrand()) * NORM; + } while(x >= 1); + return x; +} diff --git a/sys/src/libc/port/frexp.c b/sys/src/libc/port/frexp.c new file mode 100644 index 0000000..bc1a403 --- /dev/null +++ b/sys/src/libc/port/frexp.c @@ -0,0 +1,129 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * this is big/little endian non-portable + * it gets the endian from the FPdbleword + * union in u.h. + */ +#define MASK 0x7ffL +#define SHIFT 20 +#define BIAS 1022L +#define SIG 52 + +double +frexp(double d, int *ep) +{ + FPdbleword x, a; + + *ep = 0; + /* order matters: only isNaN can operate on NaN */ + if(isNaN(d) || isInf(d, 0) || d == 0) + return d; + x.x = d; + a.x = fabs(d); + if((a.hi >> SHIFT) == 0){ /* normalize subnormal numbers */ + x.x = (double)(1ULL<> SHIFT) & MASK) - BIAS; + x.hi &= ~(MASK << SHIFT); + x.hi |= BIAS << SHIFT; + return x.x; +} + +double +ldexp(double d, int deltae) +{ + int e, bits; + FPdbleword x; + uint32_t z; + + if(d == 0) + return 0; + x.x = d; + e = (x.hi >> SHIFT) & MASK; + if(deltae >= 0 || e+deltae >= 1){ /* no underflow */ + e += deltae; + if(e >= MASK){ /* overflow */ + if(d < 0) + return Inf(-1); + return Inf(1); + } + }else{ /* underflow gracefully */ + deltae = -deltae; + /* need to shift d right deltae */ + if(e > 1){ /* shift e-1 by exponent manipulation */ + deltae -= e-1; + e = 1; + } + if(deltae > 0 && e==1){ /* shift 1 by switch from 1.fff to 0.1ff */ + deltae--; + e = 0; + x.lo >>= 1; + x.lo |= (x.hi&1)<<31; + z = x.hi & ((1<>1); + } + while(deltae > 0){ /* shift bits down */ + bits = deltae; + if(bits > SHIFT) + bits = SHIFT; + x.lo >>= bits; + x.lo |= (x.hi&((1<>bits; + deltae -= bits; + } + } + x.hi &= ~(MASK << SHIFT); + x.hi |= (int32_t)e << SHIFT; + return x.x; +} + +double +modf(double d, double *ip) +{ + FPdbleword x; + int e; + + x.x = d; + e = (x.hi >> SHIFT) & MASK; + if(e == MASK){ + *ip = d; + if(x.lo != 0 || (x.hi & 0xfffffL) != 0) /* NaN */ + return d; + /* ±Inf */ + x.hi &= 0x80000000L; + return x.x; + } + if(d < 1) { + if(d < 0) { + x.x = modf(-d, ip); + *ip = -*ip; + return -x.x; + } + *ip = 0; + return d; + } + e -= BIAS; + if(e <= SHIFT+1) { + x.hi &= ~(0x1fffffL >> e); + x.lo = 0; + } else + if(e <= SHIFT+33) + x.lo &= ~(0x7fffffffL >> (e-SHIFT-2)); + *ip = x.x; + return d - x.x; +} diff --git a/sys/src/libc/port/getcallerpc.c b/sys/src/libc/port/getcallerpc.c new file mode 100644 index 0000000..bf0f588 --- /dev/null +++ b/sys/src/libc/port/getcallerpc.c @@ -0,0 +1,17 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +uintptr_t +getcallerpc(void) +{ + return (uintptr_t)__builtin_return_address(2); +} diff --git a/sys/src/libc/port/getfields.c b/sys/src/libc/port/getfields.c new file mode 100644 index 0000000..983c169 --- /dev/null +++ b/sys/src/libc/port/getfields.c @@ -0,0 +1,46 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +getfields(char *str, char **args, int max, int mflag, const char *set) +{ + Rune r; + int nr, intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;; str += nr) { + nr = chartorune(&r, str); + if(r == 0) + break; + if(utfrune(set, r)) { + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + nr; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} diff --git a/sys/src/libc/port/getuser.c b/sys/src/libc/port/getuser.c new file mode 100644 index 0000000..d7b1d3d --- /dev/null +++ b/sys/src/libc/port/getuser.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char * +getuser(void) +{ + static char user[64]; + int fd; + int n; + + fd = open("/dev/user", OREAD); + if(fd < 0) + return "none"; + n = read(fd, user, (sizeof user)-1); + close(fd); + if(n <= 0) + strcpy(user, "none"); + else + user[n] = 0; + return user; +} diff --git a/sys/src/libc/port/hangup.c b/sys/src/libc/port/hangup.c new file mode 100644 index 0000000..5b3a2ec --- /dev/null +++ b/sys/src/libc/port/hangup.c @@ -0,0 +1,21 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +/* + * force a connection to hangup + */ +int +hangup(int ctl) +{ + return write(ctl, "hangup", sizeof("hangup")-1) != sizeof("hangup")-1; +} diff --git a/sys/src/libc/port/hypot.c b/sys/src/libc/port/hypot.c new file mode 100644 index 0000000..1bcf033 --- /dev/null +++ b/sys/src/libc/port/hypot.c @@ -0,0 +1,50 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * hypot -- sqrt(p*p+q*q), but overflows only if the result does. + * See Cleve Moler and Donald Morrison, + * ``Replacing Square Roots by Pythagorean Sums,'' + * IBM Journal of Research and Development, + * Vol. 27, Number 6, pp. 577-581, Nov. 1983 + */ + +#include +#include + +double +hypot(double p, double q) +{ + double r, s, pfac; + + if(p < 0) + p = -p; + if(q < 0) + q = -q; + if(p < q) { + r = p; + p = q; + q = r; + } + if(p == 0) + return 0; + pfac = p; + r = q = q/p; + p = 1; + for(;;) { + r *= r; + s = r+4; + if(s == 4) + return p*pfac; + r /= s; + p += 2*r*p; + q *= r; + r = q/p; + } +} diff --git a/sys/src/libc/port/lnrand.c b/sys/src/libc/port/lnrand.c new file mode 100644 index 0000000..7a96228 --- /dev/null +++ b/sys/src/libc/port/lnrand.c @@ -0,0 +1,27 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define MASK 0x7fffffffL + +int32_t +lnrand(int32_t n) +{ + int32_t slop, v; + + if(n < 0) + return n; + slop = MASK % n; + do + v = lrand(); + while(v <= slop); + return v % n; +} diff --git a/sys/src/libc/port/lock.c b/sys/src/libc/port/lock.c new file mode 100644 index 0000000..4e7afde --- /dev/null +++ b/sys/src/libc/port/lock.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Giacomo Tesio + * + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +lock(Lock *l) +{ + if(ainc(&l->key) == 1) + return; /* changed from 0 -> 1: we hold lock */ + /* otherwise wait in kernel */ + while(semacquire(&l->sem, 1) < 0){ + /* interrupted; try again */ + } +} + +void +unlock(Lock *l) +{ + if(adec(&l->key) == 0) + return; /* changed from 1 -> 0: no contention */ + semrelease(&l->sem, 1); +} + +int +canlock(Lock *l) +{ + if(ainc(&l->key) == 1) + return 1; /* changed from 0 -> 1: success */ + /* Undo increment (but don't miss wakeup) */ + if(adec(&l->key) == 0) + return 0; /* changed from 1 -> 0: no contention */ + semrelease(&l->sem, 1); + return 0; +} + +int +lockt(Lock *l, uint32_t ms) +{ + int semr; + int64_t start, end; + + if(ainc(&l->key) == 1) + return 1; /* changed from 0 -> 1: we hold lock */ + /* otherwise wait in kernel */ + semr = 0; + start = nsec() / (1000 * 1000); + end = start + ms; + while(start < end && (semr = tsemacquire(&l->sem, ms)) < 0){ + /* interrupted; try again */ + start = nsec() / (1000 * 1000); + ms = end - start; + } + /* copy canlock semantic for return values */ + if(semr == 1) + return 1; /* success, lock acquired */ + return 0; /* timed out or interrupt at timeout */ +} diff --git a/sys/src/libc/port/log.c b/sys/src/libc/port/log.c new file mode 100644 index 0000000..7499552 --- /dev/null +++ b/sys/src/libc/port/log.c @@ -0,0 +1,67 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + log returns the natural logarithm of its floating + point argument. + + The coefficients are #2705 from Hart & Cheney. (19.38D) + + It calls frexp. +*/ + +#include +#include + +#define log2 0.693147180559945309e0 +#define ln10o1 .4342944819032518276511 +#define sqrto2 0.707106781186547524e0 +#define p0 -.240139179559210510e2 +#define p1 0.309572928215376501e2 +#define p2 -.963769093377840513e1 +#define p3 0.421087371217979714e0 +#define q0 -.120069589779605255e2 +#define q1 0.194809660700889731e2 +#define q2 -.891110902798312337e1 + +double +log(double arg) +{ + double x, z, zsq, temp; + int exp; + + if(arg <= 0) + return NaN(); + x = frexp(arg, &exp); + while(x < 0.5) { + x *= 2; + exp--; + } + if(x < sqrto2) { + x *= 2; + exp--; + } + + z = (x-1) / (x+1); + zsq = z*z; + + temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0; + temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0); + temp = temp*z + exp*log2; + return temp; +} + +double +log10(double arg) +{ + + if(arg <= 0) + return NaN(); + return log(arg) * ln10o1; +} diff --git a/sys/src/libc/port/lrand.c b/sys/src/libc/port/lrand.c new file mode 100644 index 0000000..a2d4693 --- /dev/null +++ b/sys/src/libc/port/lrand.c @@ -0,0 +1,92 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * algorithm by + * D. P. Mitchell & J. A. Reeds + */ + +#define LEN 607 +#define TAP 273 +#define MASK 0x7fffffffL +#define A 48271 +#define M 2147483647 +#define Q 44488 +#define R 3399 +#define NORM (1.0/(1.0+MASK)) + +static uint32_t rng_vec[LEN]; +static uint32_t* rng_tap = rng_vec; +static uint32_t* rng_feed = 0; +static Lock lk; + +static void +isrand(int32_t seed) +{ + int32_t lo, hi, x; + int i; + + rng_tap = rng_vec; + rng_feed = rng_vec+LEN-TAP; + seed = seed%M; + if(seed < 0) + seed += M; + if(seed == 0) + seed = 89482311; + x = seed; + /* + * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1) + */ + for(i = -20; i < LEN; i++) { + hi = x / Q; + lo = x % Q; + x = A*lo - R*hi; + if(x < 0) + x += M; + if(i >= 0) + rng_vec[i] = x; + } +} + +void +srand(int32_t seed) +{ + lock(&lk); + isrand(seed); + unlock(&lk); +} + +int32_t +lrand(void) +{ + uint32_t x; + + lock(&lk); + + rng_tap--; + if(rng_tap < rng_vec) { + if(rng_feed == 0) { + isrand(1); + rng_tap--; + } + rng_tap += LEN; + } + rng_feed--; + if(rng_feed < rng_vec) + rng_feed += LEN; + x = (*rng_feed + *rng_tap) & MASK; + *rng_feed = x; + + unlock(&lk); + + return x; +} diff --git a/sys/src/libc/port/malloc.c b/sys/src/libc/port/malloc.c new file mode 100644 index 0000000..6a12f25 --- /dev/null +++ b/sys/src/libc/port/malloc.c @@ -0,0 +1,337 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include +#include + +static void* sbrkalloc(uint32_t); +static int sbrkmerge(void*, void*); +static void plock(Pool*); +static void punlock(Pool*); +static void pprint(Pool*, char*, ...); +static void ppanic(Pool*, char*, ...); + +typedef struct Private Private; +struct Private { + Lock lk; + int pid; + int printfd; /* gets debugging output if set */ +}; + +Private sbrkmempriv; + +static Pool sbrkmem = { + .name= "sbrkmem", + .maxsize= (3840UL-1)*1024*1024, /* up to ~0xf0000000 */ + .minarena= 4*1024, + .quantum= 32, + .alloc= sbrkalloc, + .merge= sbrkmerge, + .flags= 0, + + .lock= plock, + .unlock= punlock, + .print= pprint, + .panic= ppanic, + .private= &sbrkmempriv, +}; +Pool *mainmem = &sbrkmem; +Pool *imagmem = &sbrkmem; + +/* + * we do minimal bookkeeping so we can tell pool + * whether two blocks are adjacent and thus mergeable. + */ +static void* +sbrkalloc(uint32_t n) +{ + uint32_t *x; + + n += 2*sizeof(uint32_t); /* two longs for us */ + x = sbrk(n); + if(x == (void*)-1) + return nil; + x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */ + x[1] = 0xDeadBeef; + return x+2; +} + +static int +sbrkmerge(void *x, void *y) +{ + uint32_t *lx, *ly; + + lx = x; + if(lx[-1] != 0xDeadBeef) + abort(); + + if((uint8_t*)lx+lx[-2] == (uint8_t*)y) { + ly = y; + lx[-2] += ly[-2]; + return 1; + } + return 0; +} + +static void +plock(Pool *p) +{ + Private *pv; + pv = p->private; + lock(&pv->lk); + if(pv->pid != 0) + abort(); + pv->pid = _tos->pid; +} + +static void +punlock(Pool *p) +{ + Private *pv; + pv = p->private; + if(pv->pid != _tos->pid) + abort(); + pv->pid = 0; + unlock(&pv->lk); +} + +static int +checkenv(void) +{ + int n, fd; + char buf[20]; + fd = open("/env/MALLOCFD", OREAD); + if(fd < 0) + return -1; + if((n = read(fd, buf, sizeof buf)) < 0) { + close(fd); + return -1; + } + if(n >= sizeof buf) + n = sizeof(buf)-1; + buf[n] = 0; + n = atoi(buf); + if(n == 0) + n = -1; + return n; +} + +static void +pprint(Pool *p, char *fmt, ...) +{ + va_list v; + Private *pv; + + pv = p->private; + if(pv->printfd == 0) + pv->printfd = checkenv(); + + if(pv->printfd <= 0) + pv->printfd = 2; + + va_start(v, fmt); + vfprint(pv->printfd, fmt, v); + va_end(v); +} + +static char panicbuf[256]; +static void +ppanic(Pool *p, char *fmt, ...) +{ + va_list v; + int n; + char *msg; + Private *pv; + + pv = p->private; + assert(canlock(&pv->lk)==0); + + if(pv->printfd == 0) + pv->printfd = checkenv(); + if(pv->printfd <= 0) + pv->printfd = 2; + + msg = panicbuf; + va_start(v, fmt); + n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg; + write(2, "panic: ", 7); + write(2, msg, n); + write(2, "\n", 1); + if(pv->printfd != 2){ + write(pv->printfd, "panic: ", 7); + write(pv->printfd, msg, n); + write(pv->printfd, "\n", 1); + } + va_end(v); +// unlock(&pv->lk); + abort(); +} + +/* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */ +/* - except the code for malloc(), which alternately doesn't clear or does. - */ + +/* + * Npadlong is the number of 32-bit longs to leave at the beginning of + * each allocated buffer for our own bookkeeping. We return to the callers + * a pointer that points immediately after our bookkeeping area. Incoming pointers + * must be decremented by that much, and outgoing pointers incremented. + * The malloc tag is stored at MallocOffset from the beginning of the block, + * and the realloc tag at ReallocOffset. The offsets are from the true beginning + * of the block, not the beginning the caller sees. + * + * The extra if(Npadlong != 0) in various places is a hint for the compiler to + * compile out function calls that would otherwise be no-ops. + */ + +/* tracing */ +enum { + Npadlong = 2, + MallocOffset = 0, + ReallocOffset = 1 +}; + +void* +malloc(size_t size) +{ + void *v; + + v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr_t)); + if(Npadlong && v != nil) { + v = (uintptr_t*)v+Npadlong; + setmalloctag(v, getcallerpc()); + setrealloctag(v, 0); + } + return v; +} + +void* +mallocz(uint32_t size, int clr) +{ + void *v; + + v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr_t)); + if(Npadlong && v != nil){ + v = (uintptr_t*)v+Npadlong; + setmalloctag(v, getcallerpc()); + setrealloctag(v, 0); + } + if(clr && v != nil) + memset(v, 0, size); + return v; +} + +void* +mallocalign(uint32_t size, uint32_t align, int32_t offset, uint32_t span) +{ + void *v; + + v = poolallocalign(mainmem, size+Npadlong*sizeof(uintptr_t), align, + offset-Npadlong*sizeof(uintptr_t), span); + if(Npadlong && v != nil){ + v = (uintptr_t*)v+Npadlong; + setmalloctag(v, getcallerpc()); + setrealloctag(v, 0); + } + return v; +} + +void +free(void *v) +{ + if(v != nil) + poolfree(mainmem, (uintptr_t*)v-Npadlong); +} + +void* +realloc(void *v, size_t size) +{ + void *nv; + + if(size == 0){ + free(v); + return nil; + } + + if(v) + v = (uintptr_t*)v-Npadlong; + size += Npadlong*sizeof(uintptr_t); + + if((nv = poolrealloc(mainmem, v, size))){ + nv = (uintptr_t*)nv+Npadlong; + setrealloctag(nv, getcallerpc()); + if(v == nil) + setmalloctag(nv, getcallerpc()); + } + return nv; +} + +uint32_t +msize(void *v) +{ + return poolmsize(mainmem, (uintptr_t*)v-Npadlong)-Npadlong*sizeof(uintptr_t); +} + +void* +calloc(uint32_t n, size_t szelem) +{ + void *v; + if((v = mallocz(n*szelem, 1))) + setmalloctag(v, getcallerpc()); + return v; +} + +void +setmalloctag(void *v, uintptr_t pc) +{ + uintptr_t *u; + if(Npadlong <= MallocOffset || v == nil) + return; + u = v; + u[-Npadlong+MallocOffset] = pc; +} + +void +setrealloctag(void *v, uintptr_t pc) +{ + uintptr_t *u; + //USED(v, pc); + if(Npadlong <= ReallocOffset || v == nil) + return; + u = v; + u[-Npadlong+ReallocOffset] = pc; +} + +uintptr_t +getmalloctag(void *v) +{ + USED(v); + if(Npadlong <= MallocOffset) + return ~0; + return ((uintptr_t*)v)[-Npadlong+MallocOffset]; +} + +uintptr_t +getrealloctag(void *v) +{ + USED(v); + if(Npadlong <= ReallocOffset) + return ((uintptr_t*)v)[-Npadlong+ReallocOffset]; + return ~0; +} + +void* +malloctopoolblock(void *v) +{ + if(v == nil) + return nil; + + return &((uintptr_t*)v)[-Npadlong]; +} diff --git a/sys/src/libc/port/memccpy.c b/sys/src/libc/port/memccpy.c new file mode 100644 index 0000000..d257185 --- /dev/null +++ b/sys/src/libc/port/memccpy.c @@ -0,0 +1,28 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void* +memccpy(void *a1, const void *a2, int c, uint32_t n) +{ + uint8_t *s1; + const uint8_t *s2; + + s1 = a1; + s2 = a2; + c &= 0xFF; + while(n > 0) { + if((*s1++ = *s2++) == c) + return s1; + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memchr.c b/sys/src/libc/port/memchr.c new file mode 100644 index 0000000..18fddb6 --- /dev/null +++ b/sys/src/libc/port/memchr.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void* +memchr(const void *ap, int c, uint32_t n) +{ + const char *sp; + + sp = ap; + c &= 0xFF; + while(n > 0) { + if(*sp++ == c) + return (char *)sp-1; + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memcmp.c b/sys/src/libc/port/memcmp.c new file mode 100644 index 0000000..8223fc6 --- /dev/null +++ b/sys/src/libc/port/memcmp.c @@ -0,0 +1,32 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +memcmp(const void *a1, const void *a2, uint32_t n) +{ + const char *s1, *s2; + uint c1, c2; + + s1 = a1; + s2 = a2; + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memmove.c b/sys/src/libc/port/memmove.c new file mode 100644 index 0000000..b1cbdb9 --- /dev/null +++ b/sys/src/libc/port/memmove.c @@ -0,0 +1,45 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void* +memmove(void *a1, const void *a2, size_t n) +{ + char *s1; + const char *s2; + + if((int32_t)n < 0) + abort(); + s1 = a1; + s2 = a2; + if((s2 < s1) && (s2+n > s1)) + goto back; + while(n > 0) { + *s1++ = *s2++; + n--; + } + return a1; + +back: + s1 += n; + s2 += n; + while(n > 0) { + *--s1 = *--s2; + n--; + } + return a1; +} + +void* +memcpy(void *a1, const void *a2, size_t n) +{ + return memmove(a1, a2, n); +} diff --git a/sys/src/libc/port/memset.c b/sys/src/libc/port/memset.c new file mode 100644 index 0000000..68fb415 --- /dev/null +++ b/sys/src/libc/port/memset.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void* +memset(void *ap, int c, uint32_t n) +{ + char *p; + + p = ap; + while(n > 0) { + *p++ = c; + n--; + } + return ap; +} diff --git a/sys/src/libc/port/mktemp.c b/sys/src/libc/port/mktemp.c new file mode 100644 index 0000000..4aec614 --- /dev/null +++ b/sys/src/libc/port/mktemp.c @@ -0,0 +1,40 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +mktemp(char *as) +{ + char *s; + unsigned pid; + int i; + char err[ERRMAX]; + + pid = getpid(); + s = as; + while(*s++) + ; + s--; + while(*--s == 'X') { + *s = pid % 10 + '0'; + pid = pid/10; + } + s++; + i = 'a'; + while(access(as, 0) != -1) { + if (i == 'z') + return "/"; + *s = i++; + } + err[0] = '\0'; + errstr(err, sizeof err); /* clear the error */ + return as; +} diff --git a/sys/src/libc/port/muldiv.c b/sys/src/libc/port/muldiv.c new file mode 100644 index 0000000..81723ac --- /dev/null +++ b/sys/src/libc/port/muldiv.c @@ -0,0 +1,47 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +uint32_t +umuldiv(uint32_t a, uint32_t b, uint32_t c) +{ + double d; + + d = ((double)a * (double)b) / (double)c; + if(d >= 4294967296.) + abort(); + return d; +} + +int32_t +muldiv(int32_t a, int32_t b, int32_t c) +{ + int s; + int32_t v; + + s = 0; + if(a < 0) { + s = !s; + a = -a; + } + if(b < 0) { + s = !s; + b = -b; + } + if(c < 0) { + s = !s; + c = -c; + } + v = umuldiv(a, b, c); + if(s) + v = -v; + return v; +} diff --git a/sys/src/libc/port/nan.c b/sys/src/libc/port/nan.c new file mode 100644 index 0000000..ef75391 --- /dev/null +++ b/sys/src/libc/port/nan.c @@ -0,0 +1,63 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define NANEXP (2047<<20) +#define NANMASK (2047<<20) +#define NANSIGN (1<<31) + +double +NaN(void) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 1; + return a.x; +} + +int +isNaN(double d) +{ + FPdbleword a; + + a.x = d; + if((a.hi & NANMASK) != NANEXP) + return 0; + return !isInf(d, 0); +} + +double +Inf(int sign) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 0; + if(sign < 0) + a.hi |= NANSIGN; + return a.x; +} + +int +isInf(double d, int sign) +{ + FPdbleword a; + + a.x = d; + if(a.lo != 0) + return 0; + if(a.hi == NANEXP) + return sign >= 0; + if(a.hi == (NANEXP|NANSIGN)) + return sign <= 0; + return 0; +} diff --git a/sys/src/libc/port/needsrcquote.c b/sys/src/libc/port/needsrcquote.c new file mode 100644 index 0000000..a0c3130 --- /dev/null +++ b/sys/src/libc/port/needsrcquote.c @@ -0,0 +1,21 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +needsrcquote(int c) +{ + if(c <= ' ') + return 1; + if(utfrune("`^#*[]=|\\?${}()'<>&;", c)) + return 1; + return 0; +} diff --git a/sys/src/libc/port/netmkaddr.c b/sys/src/libc/port/netmkaddr.c new file mode 100644 index 0000000..ce18fcb --- /dev/null +++ b/sys/src/libc/port/netmkaddr.c @@ -0,0 +1,61 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +/* + * make an address, add the defaults + */ +char * +netmkaddr(const char *linear, const char *defnet, const char *defsrv) +{ + static char addr[256]; + char *cp; + + /* + * dump network name + */ + cp = strchr(linear, '!'); + if(cp == 0){ + if(defnet==0){ + if(defsrv) + snprint(addr, sizeof(addr), "net!%s!%s", + linear, defsrv); + else + snprint(addr, sizeof(addr), "net!%s", linear); + } + else { + if(defsrv) + snprint(addr, sizeof(addr), "%s!%s!%s", defnet, + linear, defsrv); + else + snprint(addr, sizeof(addr), "%s!%s", defnet, + linear); + } + return addr; + } + + /* + * if there is already a service, use it + */ + cp = strchr(cp+1, '!'); + if(cp) + return (char *)linear; + + /* + * add default service + */ + if(defsrv == 0) + return (char *)linear; + snprint(addr, sizeof(addr), "%s!%s", linear, defsrv); + + return addr; +} diff --git a/sys/src/libc/port/nrand.c b/sys/src/libc/port/nrand.c new file mode 100644 index 0000000..6e005a4 --- /dev/null +++ b/sys/src/libc/port/nrand.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define MASK 0x7fffffffL + +int +nrand(int n) +{ + int32_t slop, v; + + if(n < 0) + return n; + if(n == 1) + return 0; + /* and if n == 0, you deserve what you get */ + slop = MASK % n; + do + v = lrand(); + while(v <= slop); + return v % n; +} diff --git a/sys/src/libc/port/ntruerand.c b/sys/src/libc/port/ntruerand.c new file mode 100644 index 0000000..8bdfdb3 --- /dev/null +++ b/sys/src/libc/port/ntruerand.c @@ -0,0 +1,32 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +uint32_t +ntruerand(uint32_t n) +{ + uint32_t m, r; + + /* + * set m to the one less than the maximum multiple of n <= 2^32, + * so we want a random number <= m. + */ + if(n > (1UL<<31)) + m = n-1; + else + /* 2^32 - 2^32%n - 1 = (2^32 - 1) - (2*(2^31%n))%n */ + m = 0xFFFFFFFFUL - (2*((1UL<<31)%n))%n; + + while((r = truerand()) > m) + ; + + return r%n; +} diff --git a/sys/src/libc/port/perror.c b/sys/src/libc/port/perror.c new file mode 100644 index 0000000..76ae90f --- /dev/null +++ b/sys/src/libc/port/perror.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +void +perror(const char *s) +{ + char buf[ERRMAX]; + + buf[0] = '\0'; + errstr(buf, sizeof buf); + if(s && *s) + fprint(2, "%s: %s\n", s, buf); + else + fprint(2, "%s\n", buf); +} diff --git a/sys/src/libc/port/pool.c b/sys/src/libc/port/pool.c new file mode 100644 index 0000000..dd29b38 --- /dev/null +++ b/sys/src/libc/port/pool.c @@ -0,0 +1,1471 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * This allocator takes blocks from a coarser allocator (p->alloc) and + * uses them as arenas. + * + * An arena is split into a sequence of blocks of variable size. The + * blocks begin with a Bhdr that denotes the length (including the Bhdr) + * of the block. An arena begins with an Arena header block (Arena, + * ARENA_MAGIC) and ends with a Bhdr block with magic ARENATAIL_MAGIC and + * size 0. Intermediate blocks are either allocated or free. At the end + * of each intermediate block is a Btail, which contains information + * about where the block starts. This is useful for walking backwards. + * + * Free blocks (Free*) have a magic value of FREE_MAGIC in their Bhdr + * headers. They are kept in a binary tree (p->freeroot) traversible by + * walking ->left and ->right. Each node of the binary tree is a pointer + * to a circular doubly-linked list (next, prev) of blocks of identical + * size. Blocks are added to this ``tree of lists'' by pooladd(), and + * removed by pooldel(). + * + * When freed, adjacent blocks are coalesced to create larger blocks when + * possible. + * + * Allocated blocks (Alloc*) have one of two magic values: ALLOC_MAGIC or + * UNALLOC_MAGIC. When blocks are released from the pool, they have + * magic value UNALLOC_MAGIC. Once the block has been trimmed by trim() + * and the amount of user-requested data has been recorded in the + * datasize field of the tail, the magic value is changed to ALLOC_MAGIC. + * All blocks returned to callers should be of type ALLOC_MAGIC, as + * should all blocks passed to us by callers. The amount of data the user + * asked us for can be found by subtracting the short in tail->datasize + * from header->size. Further, the up to at most four bytes between the + * end of the user-requested data block and the actual Btail structure are + * marked with a magic value, which is checked to detect user overflow. + * + * The arenas returned by p->alloc are kept in a doubly-linked list + * (p->arenalist) running through the arena headers, sorted by descending + * base address (prev, next). When a new arena is allocated, we attempt + * to merge it with its two neighbors via p->merge. + */ + +#include +#include +#include + +typedef struct Alloc Alloc; +typedef struct Arena Arena; +typedef struct Bhdr Bhdr; +typedef struct Btail Btail; +typedef struct Free Free; + +struct Bhdr { + uint32_t magic; + uint32_t size; +}; +enum { + NOT_MAGIC = 0xdeadfa11, + DEAD_MAGIC = 0xdeaddead, +}; +#define B2NB(b) ((Bhdr*)((uint8_t*)(b)+(b)->size)) + +#define SHORT(x) (((x)[0] << 8) | (x)[1]) +#define PSHORT(p, x) \ + (((uint8_t*)(p))[0] = ((x)>>8)&0xFF, \ + ((uint8_t*)(p))[1] = (x)&0xFF) + +enum { + TAIL_MAGIC0 = 0xBE, + TAIL_MAGIC1 = 0xEF +}; +struct Btail { + uint8_t magic0; + uint8_t datasize[2]; + uint8_t magic1; + uint32_t size; /* same as Bhdr->size */ +}; +#define B2T(b) ((Btail*)((uint8_t*)(b)+(b)->size-sizeof(Btail))) +#define B2PT(b) ((Btail*)((uint8_t*)(b)-sizeof(Btail))) +#define T2HDR(t) ((Bhdr*)((uint8_t*)(t)+sizeof(Btail)-(t)->size)) +struct Free { + Bhdr; + Free* left; + Free* right; + Free* next; + Free* prev; +}; +enum { + FREE_MAGIC = 0xBA5EBA11, +}; + +/* + * the point of the notused fields is to make 8c differentiate + * between Bhdr and Allocblk, and between Kempt and Unkempt. + */ +struct Alloc { + Bhdr; +}; +enum { + ALLOC_MAGIC = 0x0A110C09, + UNALLOC_MAGIC = 0xCAB00D1E + 1, +}; + +struct Arena { + Bhdr; + Arena* aup; + Arena* down; + uint32_t asize; + uint32_t pad; /* to a multiple of 8 bytes */ +}; +enum { + ARENA_MAGIC = 0xC0A1E5CE + 1, + ARENATAIL_MAGIC = 0xEC5E1A0C + 1, +}; +#define A2TB(a) ((Bhdr*)((uint8_t*)(a)+(a)->asize-sizeof(Bhdr))) +#define A2B(a) B2NB(a) + +enum { + ALIGN_MAGIC = 0xA1F1D1C1, +}; + +enum { + MINBLOCKSIZE = sizeof(Free)+sizeof(Btail) +}; + +static uint8_t datamagic[] = { 0xFE, 0xF1, 0xF0, 0xFA }; + +#define IntPoison 0xCafeBabe +#define Poison (void*)IntPoison + +#define _B2D(a) ((void*)((uint8_t*)a+sizeof(Bhdr))) +#define _D2B(v) ((Alloc*)((uint8_t*)v-sizeof(Bhdr))) + +// static void* _B2D(void*); +// static void* _D2B(void*); +static void* B2D(Pool*, Alloc*); +static Alloc* D2B(Pool*, void*); +static Arena* arenamerge(Pool*, Arena*, Arena*); +static void blockcheck(Pool*, Bhdr*); +static Alloc* blockmerge(Pool*, Bhdr*, Bhdr*); +static Alloc* blocksetdsize(Pool*, Alloc*, uint32_t); +static Bhdr* blocksetsize(Bhdr*, uint32_t); +static uint32_t bsize2asize(Pool*, uint32_t); +static uint32_t dsize2bsize(Pool*, uint32_t); +static uint32_t getdsize(Alloc*); +static Alloc* trim(Pool*, Alloc*, uint32_t); +static Free* listadd(Free*, Free*); +static Free** ltreewalk(Free**, uint32_t); +static void memmark(void*, int, uint32_t); +static Free* pooladd(Pool*, Alloc*); +static void* poolallocl(Pool*, uint32_t); +static void poolcheckl(Pool*); +static void poolcheckarena(Pool*, Arena*); +static int poolcompactl(Pool*); +static Alloc* pooldel(Pool*, Free*); +static void pooldumpl(Pool*); +static void pooldumparena(Pool*, Arena*); +static void poolfreel(Pool*, void*); +static void poolnewarena(Pool*, uint32_t); +static void* poolreallocl(Pool*, void*, uint32_t); +static Free* treedelete(Free*, Free*); +static Free* treeinsert(Free*, Free*); +static Free* treelookupgt(Free*, uint32_t); + +/* + * Debugging + * + * Antagonism causes blocks to always be filled with garbage if their + * contents are undefined. This tickles both programs and the library. + * It's a linear time hit but not so noticeable during nondegenerate use. + * It would be worth leaving in except that it negates the benefits of the + * kernel's demand-paging. The tail magic and end-of-data magic + * provide most of the user-visible benefit that antagonism does anyway. + * + * Paranoia causes the library to recheck the entire pool on each lock + * or unlock. A failed check on unlock means we tripped over ourselves, + * while a failed check on lock tends to implicate the user. Paranoia has + * the potential to slow things down a fair amount for pools with large + * numbers of allocated blocks. It completely negates all benefits won + * by the binary tree. Turning on paranoia in the kernel makes it painfully + * slow. + * + * Verbosity induces the dumping of the pool via p->print at each lock operation. + * By default, only one line is logged for each alloc, free, and realloc. + */ + +/* the if(!x);else avoids ``dangling else'' problems */ +#define antagonism if(!(p->flags & POOL_ANTAGONISM)){}else +#define paranoia if(!(p->flags & POOL_PARANOIA)){}else +#define verbosity if(!(p->flags & POOL_VERBOSITY)){}else + +#define DPRINT if(!(p->flags & POOL_DEBUGGING)){}else p->print +#define LOG if(!(p->flags & POOL_LOGGING)){}else p->print + +/* + * Tree walking + */ + +static void +checklist(Free *t) +{ + Free *q; + + for(q=t->next; q!=t; q=q->next){ + assert(q->size == t->size); + assert(q->next==nil || q->next->prev==q); + assert(q->prev==nil || q->prev->next==q); + assert(q->magic==FREE_MAGIC); + } +} + +static void +checktree(Free *t, int a, int b) +{ + assert(t->magic==FREE_MAGIC); + assert(a < t->size && t->size < b); + assert(t->next==nil || t->next->prev==t); + assert(t->prev==nil || t->prev->next==t); + checklist(t); + if(t->left) + checktree(t->left, a, t->size); + if(t->right) + checktree(t->right, t->size, b); + +} + +/* ltreewalk: return address of pointer to node of size == size */ +static Free** +ltreewalk(Free **t, uint32_t size) +{ + assert(t != nil /* ltreewalk */); + + for(;;) { + if(*t == nil) + return t; + + assert((*t)->magic == FREE_MAGIC); + + if(size == (*t)->size) + return t; + if(size < (*t)->size) + t = &(*t)->left; + else + t = &(*t)->right; + } +} + +/* treeinsert: insert node into tree */ +static Free* +treeinsert(Free *tree, Free *node) +{ + Free **loc, *repl; + + assert(node != nil /* treeinsert */); + + loc = ltreewalk(&tree, node->size); + if(*loc == nil) { + node->left = nil; + node->right = nil; + } else { /* replace existing node */ + repl = *loc; + node->left = repl->left; + node->right = repl->right; + } + *loc = node; + return tree; +} + +/* treedelete: remove node from tree */ +static Free* +treedelete(Free *tree, Free *node) +{ + Free **loc, **lsucc, *succ; + + assert(node != nil /* treedelete */); + + loc = ltreewalk(&tree, node->size); + assert(*loc == node); + + if(node->left == nil) + *loc = node->right; + else if(node->right == nil) + *loc = node->left; + else { + /* have two children, use inorder successor as replacement */ + for(lsucc = &node->right; (*lsucc)->left; lsucc = &(*lsucc)->left) + ; + succ = *lsucc; + *lsucc = succ->right; + succ->left = node->left; + succ->right = node->right; + *loc = succ; + } + + node->left = node->right = Poison; + return tree; +} + +/* treelookupgt: find smallest node in tree with size >= size */ +static Free* +treelookupgt(Free *t, uint32_t size) +{ + Free *lastgood; /* last node we saw that was big enough */ + + lastgood = nil; + for(;;) { + if(t == nil) + return lastgood; + if(size == t->size) + return t; + if(size < t->size) { + lastgood = t; + t = t->left; + } else + t = t->right; + } +} + +/* + * List maintenance + */ + +/* listadd: add a node to a doubly linked list */ +static Free* +listadd(Free *list, Free *node) +{ + if(list == nil) { + node->next = node; + node->prev = node; + return node; + } + + node->prev = list->prev; + node->next = list; + + node->prev->next = node; + node->next->prev = node; + + return list; +} + +/* listdelete: remove node from a doubly linked list */ +static Free* +listdelete(Pool *p, Free *list, Free *node) +{ + if(node->next == node) { /* singular list */ + node->prev = node->next = Poison; + return nil; + } + if(node->next == nil) + p->panic(p, "pool->next"); + if(node->prev == nil) + p->panic(p, "pool->prev"); + node->next->prev = node->prev; + node->prev->next = node->next; + + if(list == node) + list = node->next; + + node->prev = node->next = Poison; + return list; +} + +/* + * Pool maintenance + */ + +/* pooladd: add anode to the free pool */ +static Free* +pooladd(Pool *p, Alloc *anode) +{ + Free *lst, *olst; + Free *node; + Free **parent; + + antagonism { + memmark(_B2D(anode), 0xF7, anode->size-sizeof(Bhdr)-sizeof(Btail)); + } + + node = (Free*)anode; + node->magic = FREE_MAGIC; + parent = ltreewalk((Free **)&p->freeroot, node->size); + olst = *parent; + lst = listadd(olst, node); + if(olst != lst) /* need to update tree */ + *parent = treeinsert(*parent, lst); + p->curfree += node->size; + return node; +} + +/* pooldel: remove node from the free pool */ +static Alloc* +pooldel(Pool *p, Free *node) +{ + Free *lst, *olst; + Free **parent; + + parent = ltreewalk((Free **)&p->freeroot, node->size); + olst = *parent; + assert(olst != nil /* pooldel */); + + lst = listdelete(p, olst, node); + if(lst == nil) + *parent = treedelete(*parent, olst); + else if(lst != olst) + *parent = treeinsert(*parent, lst); + + node->left = node->right = Poison; + p->curfree -= node->size; + + antagonism { + memmark(_B2D(node), 0xF9, node->size-sizeof(Bhdr)-sizeof(Btail)); + } + + node->magic = UNALLOC_MAGIC; + return (Alloc*)node; +} + +/* + * Block maintenance + */ +/* block allocation */ +static uint32_t +dsize2bsize(Pool *p, uint32_t sz) +{ + sz += sizeof(Bhdr)+sizeof(Btail); + if(sz < p->minblock) + sz = p->minblock; + if(sz < MINBLOCKSIZE) + sz = MINBLOCKSIZE; + sz = (sz+p->quantum-1)&~(p->quantum-1); + return sz; +} + +static uint32_t +bsize2asize(Pool *p, uint32_t sz) +{ + sz += sizeof(Arena)+sizeof(Btail); + if(sz < p->minarena) + sz = p->minarena; + sz = (sz+p->quantum)&~(p->quantum-1); + return sz; +} + +/* blockmerge: merge a and b, known to be adjacent */ +/* both are removed from pool if necessary. */ +static Alloc* +blockmerge(Pool *pool, Bhdr *a, Bhdr *b) +{ + Btail *t; + + assert(B2NB(a) == b); + + if(a->magic == FREE_MAGIC) + pooldel(pool, (Free*)a); + if(b->magic == FREE_MAGIC) + pooldel(pool, (Free*)b); + + t = B2T(a); + t->size = IntPoison; + t->magic0 = (uint8_t)NOT_MAGIC; + t->magic1 = (uint8_t)NOT_MAGIC; + PSHORT(t->datasize, NOT_MAGIC); + + a->size += b->size; + t = B2T(a); + t->size = a->size; + PSHORT(t->datasize, 0xFFFF); + + b->size = NOT_MAGIC; + b->magic = NOT_MAGIC; + + a->magic = UNALLOC_MAGIC; + return (Alloc*)a; +} + +/* blocksetsize: set the total size of a block, fixing tail pointers */ +static Bhdr* +blocksetsize(Bhdr *b, uint32_t bsize) +{ + Btail *t; + + assert(b->magic != FREE_MAGIC /* blocksetsize */); + + b->size = bsize; + t = B2T(b); + t->size = b->size; + t->magic0 = TAIL_MAGIC0; + t->magic1 = TAIL_MAGIC1; + return b; +} + +/* getdsize: return the requested data size for an allocated block */ +static uint32_t +getdsize(Alloc *b) +{ + Btail *t; + t = B2T(b); + return b->size - SHORT(t->datasize); +} + +/* blocksetdsize: set the user data size of a block */ +static Alloc* +blocksetdsize(Pool *p, Alloc *b, uint32_t dsize) +{ + Btail *t; + uint8_t *q, *eq; + + assert(b->size >= dsize2bsize(p, dsize)); + assert(b->size - dsize < 0x10000); + + t = B2T(b); + PSHORT(t->datasize, b->size - dsize); + + q=(uint8_t*)_B2D(b)+dsize; + eq = (uint8_t*)t; + if(eq > q+4) + eq = q+4; + for(; qsize - bsize; + if(b->size - dsize >= 0x10000 || + (extra >= bsize>>2 && extra >= MINBLOCKSIZE && extra >= p->minblock)) { + blocksetsize(b, bsize); + frag = (Alloc*) B2NB(b); + + antagonism { + memmark(frag, 0xF1, extra); + } + + frag->magic = UNALLOC_MAGIC; + blocksetsize(frag, extra); + pooladd(p, frag); + } + + b->magic = ALLOC_MAGIC; + blocksetdsize(p, b, dsize); + return b; +} + +static Alloc* +freefromfront(Pool *p, Alloc *b, uint32_t skip) +{ + Alloc *bb; + + skip = skip&~(p->quantum-1); + if(skip >= 0x1000 || (skip >= b->size>>2 && skip >= MINBLOCKSIZE && skip >= p->minblock)){ + bb = (Alloc*)((uint8_t*)b+skip); + blocksetsize(bb, b->size-skip); + bb->magic = UNALLOC_MAGIC; + blocksetsize(b, skip); + b->magic = UNALLOC_MAGIC; + pooladd(p, b); + return bb; + } + return b; +} + +/* + * Arena maintenance + */ + +/* arenasetsize: set arena size, updating tail */ +static void +arenasetsize(Arena *a, uint32_t asize) +{ + Bhdr *atail; + + a->asize = asize; + atail = A2TB(a); + atail->magic = ARENATAIL_MAGIC; + atail->size = 0; +} + +/* poolnewarena: allocate new arena */ +static void +poolnewarena(Pool *p, uint32_t asize) +{ + Arena *a; + Arena *ap, *lastap; + Alloc *b; + + LOG(p, "newarena %lud\n", asize); + if(p->cursize+asize > p->maxsize) { + if(poolcompactl(p) == 0){ + LOG(p, "pool too big: %lud+%lud > %lud\n", + p->cursize, asize, p->maxsize); + werrstr("memory pool too large"); + } + return; + } + + if((a = p->alloc(asize)) == nil) { + /* assume errstr set by p->alloc */ + return; + } + + p->cursize += asize; + + /* arena hdr */ + a->magic = ARENA_MAGIC; + blocksetsize(a, sizeof(Arena)); + arenasetsize(a, asize); + blockcheck(p, a); + + /* create one large block in arena */ + b = (Alloc*)A2B(a); + b->magic = UNALLOC_MAGIC; + blocksetsize(b, (uint8_t*)A2TB(a)-(uint8_t*)b); + blockcheck(p, b); + pooladd(p, b); + blockcheck(p, b); + + /* sort arena into descending sorted arena list */ + for(lastap=nil, ap=p->arenalist; ap > a; lastap=ap, ap=ap->down) + ; + + if(a->down = ap) /* assign = */ + a->down->aup = a; + + if(a->aup = lastap) /* assign = */ + a->aup->down = a; + else + p->arenalist = a; + + /* merge with surrounding arenas if possible */ + /* must do a with up before down with a (think about it) */ + if(a->aup) + arenamerge(p, a, a->aup); + if(a->down) + arenamerge(p, a->down, a); +} + +/* blockresize: grow a block to encompass space past its end, possibly by */ +/* trimming it into two different blocks. */ +static void +blockgrow(Pool *p, Bhdr *b, uint32_t nsize) +{ + if(b->magic == FREE_MAGIC) { + Alloc *a; + Bhdr *bnxt; + a = pooldel(p, (Free*)b); + blockcheck(p, a); + blocksetsize(a, nsize); + blockcheck(p, a); + bnxt = B2NB(a); + if(bnxt->magic == FREE_MAGIC) + a = blockmerge(p, a, bnxt); + blockcheck(p, a); + pooladd(p, a); + } else { + Alloc *a; + uint32_t dsize; + + a = (Alloc*)b; + dsize = getdsize(a); + blocksetsize(a, nsize); + trim(p, a, dsize); + } +} + +/* arenamerge: attempt to coalesce to arenas that might be adjacent */ +static Arena* +arenamerge(Pool *p, Arena *bot, Arena *top) +{ + Bhdr *bbot, *btop; + Btail *t; + + blockcheck(p, bot); + blockcheck(p, top); + assert(bot->aup == top && top > bot); + + if(p->merge == nil || p->merge(bot, top) == 0) + return nil; + + /* remove top from list */ + if(bot->aup = top->aup) /* assign = */ + bot->aup->down = bot; + else + p->arenalist = bot; + + /* save ptrs to last block in bot, first block in top */ + t = B2PT(A2TB(bot)); + bbot = T2HDR(t); + btop = A2B(top); + blockcheck(p, bbot); + blockcheck(p, btop); + + /* grow bottom arena to encompass top */ + arenasetsize(bot, top->asize + ((uint8_t*)top - (uint8_t*)bot)); + + /* grow bottom block to encompass space between arenas */ + blockgrow(p, bbot, (uint8_t*)btop-(uint8_t*)bbot); + blockcheck(p, bbot); + return bot; +} + +/* dumpblock: print block's vital stats */ +static void +dumpblock(Pool *p, Bhdr *b) +{ + uint32_t *dp; + uint32_t dsize; + uint8_t *cp; + + dp = (uint32_t*)b; + p->print(p, "pool %s block %p\nhdr %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\n", + p->name, b, dp[0], dp[1], dp[2], dp[3], dp[4], dp[5], dp[6]); + + dp = (uint32_t*)B2T(b); + p->print(p, "tail %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux | %.8lux %.8lux\n", + dp[-6], dp[-5], dp[-4], dp[-3], dp[-2], dp[-1], dp[0], dp[1]); + + if(b->magic == ALLOC_MAGIC){ + dsize = getdsize((Alloc*)b); + if(dsize >= b->size) /* user data size corrupt */ + return; + + cp = (uint8_t*)_B2D(b)+dsize; + p->print(p, "user data "); + p->print(p, "%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux", + cp[-8], cp[-7], cp[-6], cp[-5], cp[-4], cp[-3], cp[-2], cp[-1]); + p->print(p, " | %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } +} + +static void +printblock(Pool *p, Bhdr *b, char *msg) +{ + p->print(p, "%s\n", msg); + dumpblock(p, b); +} + +static void +panicblock(Pool *p, Bhdr *b, char *msg) +{ + p->print(p, "%s\n", msg); + dumpblock(p, b); + p->panic(p, "pool panic"); +} + +/* blockcheck: ensure a block consistent with our expectations */ +/* should only be called when holding pool lock */ +static void +blockcheck(Pool *p, Bhdr *b) +{ + Alloc *a; + Btail *t; + int i, n; + uint8_t *q, *bq, *eq; + uint32_t dsize; + + switch(b->magic) { + default: + panicblock(p, b, "bad magic"); + case FREE_MAGIC: + case UNALLOC_MAGIC: + t = B2T(b); + if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + break; + case DEAD_MAGIC: + t = B2T(b); + if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + n = getdsize((Alloc*)b); + q = _B2D(b); + q += 8; + for(i=8; imagic != ARENATAIL_MAGIC) + panicblock(p, b, "bad arena size"); + /* fall through */ + case ARENATAIL_MAGIC: + if(b->size != 0) + panicblock(p, b, "bad arena tail size"); + break; + case ALLOC_MAGIC: + a = (Alloc*)b; + t = B2T(b); + dsize = getdsize(a); + bq = (uint8_t*)_B2D(a)+dsize; + eq = (uint8_t*)t; + + if(t->magic0 != TAIL_MAGIC0){ + /* if someone wrote exactly one byte over and it was a NUL, we sometimes only complain. */ + if((p->flags & POOL_TOLERANCE) && bq == eq && t->magic0 == 0) + printblock(p, b, "mem user overflow (magic0)"); + else + panicblock(p, b, "corrupt tail magic0"); + } + + if(t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic1"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + + if(dsize2bsize(p, dsize) > a->size) + panicblock(p, b, "too much block data"); + + if(eq > bq+4) + eq = bq+4; + for(q=bq; qflags & POOL_TOLERANCE)){ + printblock(p, b, "mem user overflow"); + continue; + } + panicblock(p, b, "mem user overflow"); + } + } + break; + } +} + +/* + * compact an arena by shifting all the free blocks to the end. + * assumes pool lock is held. + */ +enum { + FLOATING_MAGIC = 0xCBCBCBCB, /* temporarily neither allocated nor in the free tree */ +}; + +static int +arenacompact(Pool *p, Arena *a) +{ + Bhdr *b, *wb, *eb, *nxt; + int compacted; + + if(p->move == nil) + p->panic(p, "don't call me when pool->move is nil\n"); + + poolcheckarena(p, a); + eb = A2TB(a); + compacted = 0; + for(b=wb=A2B(a); b && b < eb; b=nxt) { + nxt = B2NB(b); + switch(b->magic) { + case FREE_MAGIC: + pooldel(p, (Free*)b); + b->magic = FLOATING_MAGIC; + break; + case ALLOC_MAGIC: + if(wb != b) { + memmove(wb, b, b->size); + p->move(_B2D(b), _B2D(wb)); + compacted = 1; + } + wb = B2NB(wb); + break; + } + } + + /* + * the only free data is now at the end of the arena, pointed + * at by wb. all we need to do is set its size and get out. + */ + if(wb < eb) { + wb->magic = UNALLOC_MAGIC; + blocksetsize(wb, (uint8_t*)eb-(uint8_t*)wb); + pooladd(p, (Alloc*)wb); + } + + return compacted; +} + +/* + * compact a pool by compacting each individual arena. + * 'twould be nice to shift blocks from one arena to the + * next but it's a pain to code. + */ +static int +poolcompactl(Pool *pool) +{ + Arena *a; + int compacted; + + if(pool->move == nil || pool->lastcompact == pool->nfree) + return 0; + + pool->lastcompact = pool->nfree; + compacted = 0; + for(a=pool->arenalist; a; a=a->down) + compacted |= arenacompact(pool, a); + return compacted; +} + +/* +static int +poolcompactl(Pool*) +{ + return 0; +} +*/ + +/* + * Actual allocators + */ + +/* +static void* +_B2D(void *a) +{ + return (uint8_t*)a+sizeof(Bhdr); +} +*/ + +static void* +B2D(Pool *p, Alloc *a) +{ + if(a->magic != ALLOC_MAGIC) + p->panic(p, "B2D called on unworthy block"); + return _B2D(a); +} + +/* +static void* +_D2B(void *v) +{ + Alloc *a; + a = (Alloc*)((uint8_t*)v-sizeof(Bhdr)); + return a; +} +*/ + +static Alloc* +D2B(Pool *p, void *v) +{ + Alloc *a; + uint32_t *u; + + if((uintptr)v&(sizeof(uint32_t)-1)) + v = (char*)v - ((uintptr)v&(sizeof(uint32_t)-1)); + u = v; + while(u[-1] == ALIGN_MAGIC) + u--; + a = _D2B(u); + if(a->magic != ALLOC_MAGIC) + p->panic(p, "D2B called on non-block %p (double-free?)", v); + return a; +} + +/* poolallocl: attempt to allocate block to hold dsize user bytes; assumes lock held */ +static void* +poolallocl(Pool *p, uint32_t dsize) +{ + uint32_t bsize; + Free *fb; + Alloc *ab; + + if(dsize >= 0x80000000UL){ /* for sanity, overflow */ + werrstr("invalid allocation size"); + return nil; + } + + bsize = dsize2bsize(p, dsize); + + fb = treelookupgt(p->freeroot, bsize); + if(fb == nil) { + poolnewarena(p, bsize2asize(p, bsize)); + if((fb = treelookupgt(p->freeroot, bsize)) == nil) { + /* assume poolnewarena failed and set %r */ + return nil; + } + } + + ab = trim(p, pooldel(p, fb), dsize); + p->curalloc += ab->size; + antagonism { + memset(B2D(p, ab), 0xDF, dsize); + } + return B2D(p, ab); +} + +/* poolreallocl: attempt to grow v to ndsize bytes; assumes lock held */ +static void* +poolreallocl(Pool *p, void *v, uint32_t ndsize) +{ + Alloc *a; + Bhdr *left, *right, *newb; + Btail *t; + uint32_t nbsize; + uint32_t odsize; + uint32_t obsize; + void *nv; + + if(v == nil) /* for ANSI */ + return poolallocl(p, ndsize); + if(ndsize == 0) { + poolfreel(p, v); + return nil; + } + a = D2B(p, v); + blockcheck(p, a); + odsize = getdsize(a); + obsize = a->size; + + /* can reuse the same block? */ + nbsize = dsize2bsize(p, ndsize); + if(nbsize <= a->size) { + Returnblock: + if(v != _B2D(a)) + memmove(_B2D(a), v, odsize); + a = trim(p, a, ndsize); + p->curalloc -= obsize; + p->curalloc += a->size; + v = B2D(p, a); + return v; + } + + /* can merge with surrounding blocks? */ + right = B2NB(a); + if(right->magic == FREE_MAGIC && a->size+right->size >= nbsize) { + a = blockmerge(p, a, right); + goto Returnblock; + } + + t = B2PT(a); + left = T2HDR(t); + if(left->magic == FREE_MAGIC && left->size+a->size >= nbsize) { + a = blockmerge(p, left, a); + goto Returnblock; + } + + if(left->magic == FREE_MAGIC && right->magic == FREE_MAGIC + && left->size+a->size+right->size >= nbsize) { + a = blockmerge(p, blockmerge(p, left, a), right); + goto Returnblock; + } + + if((nv = poolallocl(p, ndsize)) == nil) + return nil; + + /* maybe the new block is next to us; if so, merge */ + left = T2HDR(B2PT(a)); + right = B2NB(a); + newb = D2B(p, nv); + if(left == newb || right == newb) { + if(left == newb || left->magic == FREE_MAGIC) + a = blockmerge(p, left, a); + if(right == newb || right->magic == FREE_MAGIC) + a = blockmerge(p, a, right); + assert(a->size >= nbsize); + goto Returnblock; + } + + /* enough cleverness */ + memmove(nv, v, odsize); + antagonism { + memset((char*)nv+odsize, 0xDE, ndsize-odsize); + } + poolfreel(p, v); + return nv; +} + +static void* +alignptr(void *v, uint32_t align, long offset) +{ + char *c; + uint32_t off; + + c = v; + if(align){ + off = (uintptr)c%align; + if(off != offset){ + c += offset - off; + if(off > offset) + c += align; + } + } + return c; +} + +/* poolallocalignl: allocate as described below; assumes pool locked */ +static void* +poolallocalignl(Pool *p, uint32_t dsize, uint32_t align, long offset, + uint32_t span) +{ + uint32_t asize; + void *v; + char *c; + uint32_t *u; + int skip; + Alloc *b; + + /* + * allocate block + * dsize bytes + * addr == offset (modulo align) + * does not cross span-byte block boundary + * + * to satisfy alignment, just allocate an extra + * align bytes and then shift appropriately. + * + * to satisfy span, try once and see if we're + * lucky. the second time, allocate 2x asize + * so that we definitely get one not crossing + * the boundary. + */ + if(align){ + if(offset < 0) + offset = align - ((-offset)%align); + else + offset %= align; + } + asize = dsize+align; + v = poolallocl(p, asize); + if(v == nil) + return nil; + if(span && (uintptr)v/span != ((uintptr)v+asize)/span){ + /* try again */ + poolfreel(p, v); + v = poolallocl(p, 2*asize); + if(v == nil) + return nil; + } + + /* + * figure out what pointer we want to return + */ + c = alignptr(v, align, offset); + if(span && (uintptr)c/span != (uintptr)(c+dsize-1)/span){ + c += span - (uintptr)c%span; + c = alignptr(c, align, offset); + if((uintptr)c/span != (uintptr)(c+dsize-1)/span){ + poolfreel(p, v); + werrstr("cannot satisfy dsize %lud span %lud with align %lud+%ld", dsize, span, align, offset); + return nil; + } + } + skip = c - (char*)v; + + /* + * free up the skip bytes before that pointer + * or mark it as unavailable. + */ + b = _D2B(v); + b = freefromfront(p, b, skip); + v = _B2D(b); + skip = c - (char*)v; + if(c > (char*)v){ + u = v; + while(c >= (char*)u+sizeof(uint32_t)) + *u++ = ALIGN_MAGIC; + } + trim(p, b, skip+dsize); + assert(D2B(p, c) == b); + antagonism { + memset(c, 0xDD, dsize); + } + return c; +} + +/* poolfree: free block obtained from poolalloc; assumes lock held */ +static void +poolfreel(Pool *p, void *v) +{ + Alloc *ab; + Bhdr *back, *fwd; + + if(v == nil) /* for ANSI */ + return; + + ab = D2B(p, v); + blockcheck(p, ab); + + if(p->flags&POOL_NOREUSE){ + int n; + + ab->magic = DEAD_MAGIC; + n = getdsize(ab)-8; + if(n > 0) + memset((uint8_t*)v+8, 0xDA, n); + return; + } + + p->nfree++; + p->curalloc -= ab->size; + back = T2HDR(B2PT(ab)); + if(back->magic == FREE_MAGIC) + ab = blockmerge(p, back, ab); + + fwd = B2NB(ab); + if(fwd->magic == FREE_MAGIC) + ab = blockmerge(p, ab, fwd); + + pooladd(p, ab); +} + +void* +poolalloc(Pool *p, uint32_t n) +{ + void *v; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + v = poolallocl(p, n); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolalloc %p %lud = %p\n", p, n, v); + p->unlock(p); + return v; +} + +void* +poolallocalign(Pool *p, uint32_t n, uint32_t align, int32_t offset, + uint32_t span) +{ + void *v; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + v = poolallocalignl(p, n, align, offset, span); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolalignspanalloc %p %lud %lud %lud %ld = %p\n", p, n, align, span, offset, v); + p->unlock(p); + return v; +} + +int +poolcompact(Pool *p) +{ + int rv; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + rv = poolcompactl(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + LOG(p, "poolcompact %p\n", p); + p->unlock(p); + return rv; +} + +void* +poolrealloc(Pool *p, void *v, uint32_t n) +{ + void *nv; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + nv = poolreallocl(p, v, n); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolrealloc %p %p %ld = %p\n", p, v, n, nv); + p->unlock(p); + return nv; +} + +void +poolfree(Pool *p, void *v) +{ + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + poolfreel(p, v); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolfree %p %p\n", p, v); + p->unlock(p); +} + +/* + * Return the real size of a block, and let the user use it. + */ +uint32_t +poolmsize(Pool *p, void *v) +{ + Alloc *b; + uint32_t dsize; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(v == nil) /* consistency with other braindead ANSI-ness */ + dsize = 0; + else { + b = D2B(p, v); + dsize = (b->size&~(p->quantum-1)) - sizeof(Bhdr) - sizeof(Btail); + assert(dsize >= getdsize(b)); + blocksetdsize(p, b, dsize); + } + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolmsize %p %p = %ld\n", p, v, dsize); + p->unlock(p); + return dsize; +} + +/* + * Debugging + */ + +static void +poolcheckarena(Pool *p, Arena *a) +{ + Bhdr *b; + Bhdr *atail; + + atail = A2TB(a); + for(b=a; b->magic != ARENATAIL_MAGIC && bpanic(p, "found wrong tail"); +} + +static void +poolcheckl(Pool *p) +{ + Arena *a; + + for(a=p->arenalist; a; a=a->down) + poolcheckarena(p, a); + if(p->freeroot) + checktree(p->freeroot, 0, 1<<30); +} + +void +poolcheck(Pool *p) +{ + p->lock(p); + poolcheckl(p); + p->unlock(p); +} + +void +poolblockcheck(Pool *p, void *v) +{ + if(v == nil) + return; + + p->lock(p); + blockcheck(p, D2B(p, v)); + p->unlock(p); +} + +static void +pooldumpl(Pool *p) +{ + Arena *a; + + p->print(p, "pool %p %s\n", p, p->name); + for(a=p->arenalist; a; a=a->down) + pooldumparena(p, a); +} + +void +pooldump(Pool *p) +{ + p->lock(p); + pooldumpl(p); + p->unlock(p); +} + +static void +pooldumparena(Pool *p, Arena *a) +{ + Bhdr *b; + + for(b=a; b->magic != ARENATAIL_MAGIC; b=B2NB(b)) + p->print(p, "(%p %.8lux %lud)", b, b->magic, b->size); + p->print(p, "\n"); +} + +/* + * mark the memory in such a way that we know who marked it + * (via the signature) and we know where the marking started. + */ +static void +memmark(void *v, int sig, uint32_t size) +{ + uint8_t *p, *ep; + uint32_t *lp, *elp; + lp = v; + elp = lp+size/4; + while(lp < elp) { + *lp = (sig<<24) ^ ((uintptr)lp-(uintptr)v); + lp++; + } + p = (uint8_t*)lp; + ep = (uint8_t*)v+size; + while(p +#include + +double +pow(double x, double y) /* return x ^ y (exponentiation) */ +{ + double xy, y1, ye; + int32_t i; + int ex, ey, flip; + + if(y == 0.0) + return 1.0; + + flip = 0; + if(y < 0.){ + y = -y; + flip = 1; + } + y1 = modf(y, &ye); + if(y1 != 0.0){ + if(x <= 0.) + goto zreturn; + if(y1 > 0.5) { + y1 -= 1.; + ye += 1.; + } + xy = exp(y1 * log(x)); + }else + xy = 1.0; + if(ye > 0x7FFFFFFF){ /* should be ~0UL but compiler can't convert double to ulong */ + if(x <= 0.){ + zreturn: + if(x==0. && !flip) + return 0.; + return NaN(); + } + if(flip){ + if(y == .5) + return 1./sqrt(x); + y = -y; + }else if(y == .5) + return sqrt(x); + return exp(y * log(x)); + } + x = frexp(x, &ex); + ey = 0; + i = ye; + if(i) + for(;;){ + if(i & 1){ + xy *= x; + ey += ex; + } + i >>= 1; + if(i == 0) + break; + x *= x; + ex <<= 1; + if(x < .5){ + x += x; + ex -= 1; + } + } + if(flip){ + xy = 1. / xy; + ey = -ey; + } + return ldexp(xy, ey); +} diff --git a/sys/src/libc/port/pow10.c b/sys/src/libc/port/pow10.c new file mode 100644 index 0000000..59bb975 --- /dev/null +++ b/sys/src/libc/port/pow10.c @@ -0,0 +1,58 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * this table might overflow 127-bit exponent representations. + * in that case, truncate it after 1.0e38. + * it is important to get all one can from this + * routine since it is used in atof to scale numbers. + * the presumption is that C converts fp numbers better + * than multipication of lower powers of 10. + */ +static +double tab[] = +{ + 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, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, + 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, + 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, + 1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, + 1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, + 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, + 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, + 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, + 1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109, + 1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119, + 1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129, + 1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139, + 1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149, + 1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159, +}; + +double +pow10(int n) +{ + int m; + + if(n < 0) { + n = -n; + if(n < sizeof(tab)/sizeof(tab[0])) + return 1/tab[n]; + m = n/2; + return 1/(pow10(m) * pow10(n-m)); + } + if(n < sizeof(tab)/sizeof(tab[0])) + return tab[n]; + m = n/2; + return pow10(m) * pow10(n-m); +} diff --git a/sys/src/libc/port/qsort.c b/sys/src/libc/port/qsort.c new file mode 100644 index 0000000..a7e359a --- /dev/null +++ b/sys/src/libc/port/qsort.c @@ -0,0 +1,133 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + * qsort -- simple quicksort + */ + +#include + +typedef +struct +{ + int (*cmp)(const void*, const void*); + void (*swap)(char*, char*, int32_t); + int32_t es; +} Sort; + +static void +swapb(char *i, char *j, int32_t es) +{ + char c; + + do { + c = *i; + *i++ = *j; + *j++ = c; + es--; + } while(es != 0); + +} + +static void +swapi(char *ii, char *ij, int32_t es) +{ + int32_t *i, *j, c; + + i = (int32_t*)ii; + j = (int32_t*)ij; + do { + c = *i; + *i++ = *j; + *j++ = c; + es -= sizeof(int32_t); + } while(es != 0); +} + +static char* +pivot(char *a, int32_t n, Sort *p) +{ + int32_t j; + char *pi, *pj, *pk; + + j = n/6 * p->es; + pi = a + j; /* 1/6 */ + j += j; + pj = pi + j; /* 1/2 */ + pk = pj + j; /* 5/6 */ + if(p->cmp(pi, pj) < 0) { + if(p->cmp(pi, pk) < 0) { + if(p->cmp(pj, pk) < 0) + return pj; + return pk; + } + return pi; + } + if(p->cmp(pj, pk) < 0) { + if(p->cmp(pi, pk) < 0) + return pi; + return pk; + } + return pj; +} + +static void +qsorts(char *a, int32_t n, Sort *p) +{ + int32_t j, es; + char *pi, *pj, *pn; + + es = p->es; + while(n > 1) { + if(n > 10) { + pi = pivot(a, n, p); + } else + pi = a + (n>>1)*es; + + p->swap(a, pi, es); + pi = a; + pn = a + n*es; + pj = pn; + for(;;) { + do + pi += es; + while(pi < pn && p->cmp(pi, a) < 0); + do + pj -= es; + while(pj > a && p->cmp(pj, a) > 0); + if(pj < pi) + break; + p->swap(pi, pj, es); + } + p->swap(a, pj, es); + j = (pj - a) / es; + + n = n-j-1; + if(j >= n) { + qsorts(a, j, p); + a += (j+1)*es; + } else { + qsorts(a + (j+1)*es, n, p); + n = j; + } + } +} + +void +qsort(void *va, int32_t n, int32_t es, int (*cmp)(const void*, const void*)) +{ + Sort s; + + s.cmp = cmp; + s.es = es; + s.swap = swapi; + if(((uintptr)va | es) % sizeof(int32_t)) + s.swap = swapb; + qsorts((char*)va, n, &s); +} diff --git a/sys/src/libc/port/quote.c b/sys/src/libc/port/quote.c new file mode 100644 index 0000000..42b2f61 --- /dev/null +++ b/sys/src/libc/port/quote.c @@ -0,0 +1,146 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int (*doquote)(int); + +extern int _needsquotes(const char*, int*); +extern int _runeneedsquotes(const Rune*, int*); + +char* +unquotestrdup(const char *s) +{ + char *s1, *t, *ret; + int quoting; + + ret = s1 = strdup(s); /* return unquoted copy */ + if(ret == nil) + return ret; + quoting = 0; + t = s1; /* s1 is output string, t is input string */ + while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){ + if(*t != '\''){ + *s1++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s1++ = *t++; + } + if(t != s1) + memmove(s1, t, strlen(t)+1); + return ret; +} + +Rune* +unquoterunestrdup(const Rune *s) +{ + Rune *s1, *t, *ret; + int quoting; + + ret = s1 = runestrdup(s); /* return unquoted copy */ + if(ret == nil) + return ret; + quoting = 0; + t = s1; /* s1 is output string, t is input string */ + while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){ + if(*t != '\''){ + *s1++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s1++ = *t++; + } + if(t != s1) + memmove(s1, t, (runestrlen(t)+1)*sizeof(Rune)); + return ret; +} + +char* +quotestrdup(const char *s) +{ + const char *t; + char *u, *ret; + int quotelen; + Rune r; + + if(_needsquotes(s, "elen) == 0) + return strdup(s); + + ret = malloc(quotelen+1); + if(ret == nil) + return nil; + u = ret; + *u++ = '\''; + for(t=s; *t; t++){ + r = *t; + if(r == L'\'') + *u++ = r; /* double the quote */ + *u++ = r; + } + *u++ = '\''; + *u = '\0'; + return ret; +} + +Rune* +quoterunestrdup(const Rune *s) +{ + const Rune *t; + Rune *u, *ret; + int quotelen; + Rune r; + + if(_runeneedsquotes(s, "elen) == 0) + return runestrdup(s); + + ret = malloc((quotelen+1)*sizeof(Rune)); + if(ret == nil) + return nil; + u = ret; + *u++ = '\''; + for(t=s; *t; t++){ + r = *t; + if(r == L'\'') + *u++ = r; /* double the quote */ + *u++ = r; + } + *u++ = '\''; + *u = '\0'; + return ret; +} diff --git a/sys/src/libc/port/rand.c b/sys/src/libc/port/rand.c new file mode 100644 index 0000000..78184f5 --- /dev/null +++ b/sys/src/libc/port/rand.c @@ -0,0 +1,17 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +rand(void) +{ + return lrand() & 0x7fff; +} diff --git a/sys/src/libc/port/readn.c b/sys/src/libc/port/readn.c new file mode 100644 index 0000000..d826cb5 --- /dev/null +++ b/sys/src/libc/port/readn.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int32_t +readn(int f, void *av, int32_t n) +{ + char *a; + int32_t m, t; + + a = av; + t = 0; + while(t < n){ + m = read(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/sys/src/libc/port/reduce b/sys/src/libc/port/reduce new file mode 100644 index 0000000..584f8b9 --- /dev/null +++ b/sys/src/libc/port/reduce @@ -0,0 +1,16 @@ +O=$1 +shift +objtype=$1 +shift + +ls -p ../$objtype/*.[cs] >[2]/dev/null | sed 's/..$//;s/^/^/' > /tmp/reduce.$pid +# +# if empty directory, just return the input files +# +if (! ~ $status '|') { + echo $* + rm /tmp/reduce.$pid + exit 0 +} +echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' ' +rm /tmp/reduce.$pid diff --git a/sys/src/libc/port/rune.c b/sys/src/libc/port/rune.c new file mode 100644 index 0000000..10fae11 --- /dev/null +++ b/sys/src/libc/port/rune.c @@ -0,0 +1,173 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define Bit(i) (7-(i)) +/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */ +#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF) +/* 0000 0000 0000 0111 1111 1111 */ +#define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1) + +enum +{ + Bitx = Bit(1), + + Tx = T(1), /* 1000 0000 */ + Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ + + Maskx = (1< T1 + * 00080-007FF => T2 Tx + * 00800-0FFFF => T3 Tx Tx + * 10000-10FFFF => T4 Tx Tx Tx + */ + + c[0] = *(uint8_t*)(str); + if(c[0] < Tx){ + *rune = c[0]; + return 1; + } + l = c[0]; + + for(i = 1; i < UTFmax; i++) { + c[i] = *(uint8_t*)(str+i); + c[i] ^= Tx; + if(c[i] & Testx) + goto bad; + l = (l << Bitx) | c[i]; + if(c[0] < T(i + 2)) { + l &= RuneX(i + 1); + if(i == 1) { + if(c[0] < T(2) || l <= Rune1) + goto bad; + } else if(l <= RuneX(i) || l > Runemax) + goto bad; + if (i == 2 && SurrogateMin <= l && l <= SurrogateMax) + goto bad; + *rune = l; + return i + 1; + } + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, const Rune *rune) +{ + int i, j; + Rune c; + + c = *rune; + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * one character sequence + * 00000-0007F => 00-7F + * two character sequence + * 0080-07FF => T2 Tx + * three character sequence + * 0800-FFFF => T3 Tx Tx + * four character sequence (21-bit value) + * 10000-1FFFFF => T4 Tx Tx Tx + * If the Rune is out of range or a surrogate half, + * convert it to the error rune. + * Do this test when i==3 because the error rune encodes to three bytes. + * Doing it earlier would duplicate work, since an out of range + * Rune wouldn't have fit in one or two bytes. + */ + for(i = 2; i < UTFmax + 1; i++){ + if(i == 3){ + if(c > Runemax) + c = Runeerror; + if(SurrogateMin <= c && c <= SurrogateMax) + c = Runeerror; + } + if (c <= RuneX(i) || i == UTFmax ) { + str[0] = T(i) | (c >> (i - 1)*Bitx); + for(j = 1; j < i; j++) + str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx); + return i; + } + } + return UTFmax; +} + +int +runelen(Rune c) +{ + char str[10]; + + return runetochar(str, &c); +} + +int +runenlen(const Rune *r, int nrune) +{ + int nb, i; + Rune c; + + nb = 0; + while(nrune--) { + c = *r++; + if(c <= Rune1){ + nb++; + } else { + for(i = 2; i < UTFmax + 1; i++) + if(c <= RuneX(i) || i == UTFmax){ + nb += i; + break; + } + } + } + return nb; +} + +int +fullrune(const char *str, int n) +{ + int i; + Rune c; + + if(n <= 0) + return 0; + c = *(uint8_t*)str; + if(c < Tx) + return 1; + for(i = 3; i < UTFmax + 1; i++) + if(c < T(i)) + return n >= i - 1; + return n >= UTFmax; +} diff --git a/sys/src/libc/port/runebase.c b/sys/src/libc/port/runebase.c new file mode 100644 index 0000000..7c970fb --- /dev/null +++ b/sys/src/libc/port/runebase.c @@ -0,0 +1,1967 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune*_runebsearch(Rune c, Rune *t, int n, int ne); + +static Rune _base2[] = +{ + 0x00c0, 0x0041, /* À A */ + 0x00c1, 0x0041, /* Á A */ + 0x00c2, 0x0041, /* Â A */ + 0x00c3, 0x0041, /* Ã A */ + 0x00c4, 0x0041, /* Ä A */ + 0x00c5, 0x0041, /* Å A */ + 0x00c7, 0x0043, /* Ç C */ + 0x00c8, 0x0045, /* È E */ + 0x00c9, 0x0045, /* É E */ + 0x00ca, 0x0045, /* Ê E */ + 0x00cb, 0x0045, /* Ë E */ + 0x00cc, 0x0049, /* Ì I */ + 0x00cd, 0x0049, /* Í I */ + 0x00ce, 0x0049, /* Î I */ + 0x00cf, 0x0049, /* Ï I */ + 0x00d1, 0x004e, /* Ñ N */ + 0x00d2, 0x004f, /* Ò O */ + 0x00d3, 0x004f, /* Ó O */ + 0x00d4, 0x004f, /* Ô O */ + 0x00d5, 0x004f, /* Õ O */ + 0x00d6, 0x004f, /* Ö O */ + 0x00d9, 0x0055, /* Ù U */ + 0x00da, 0x0055, /* Ú U */ + 0x00db, 0x0055, /* Û U */ + 0x00dc, 0x0055, /* Ü U */ + 0x00dd, 0x0059, /* Ý Y */ + 0x00e0, 0x0061, /* à a */ + 0x00e1, 0x0061, /* á a */ + 0x00e2, 0x0061, /* â a */ + 0x00e3, 0x0061, /* ã a */ + 0x00e4, 0x0061, /* ä a */ + 0x00e5, 0x0061, /* å a */ + 0x00e7, 0x0063, /* ç c */ + 0x00e8, 0x0065, /* è e */ + 0x00e9, 0x0065, /* é e */ + 0x00ea, 0x0065, /* ê e */ + 0x00eb, 0x0065, /* ë e */ + 0x00ec, 0x0069, /* ì i */ + 0x00ed, 0x0069, /* í i */ + 0x00ee, 0x0069, /* î i */ + 0x00ef, 0x0069, /* ï i */ + 0x00f1, 0x006e, /* ñ n */ + 0x00f2, 0x006f, /* ò o */ + 0x00f3, 0x006f, /* ó o */ + 0x00f4, 0x006f, /* ô o */ + 0x00f5, 0x006f, /* õ o */ + 0x00f6, 0x006f, /* ö o */ + 0x00f9, 0x0075, /* ù u */ + 0x00fa, 0x0075, /* ú u */ + 0x00fb, 0x0075, /* û u */ + 0x00fc, 0x0075, /* ü u */ + 0x00fd, 0x0079, /* ý y */ + 0x00ff, 0x0079, /* ÿ y */ + 0x0100, 0x0041, /* Ā A */ + 0x0101, 0x0061, /* ā a */ + 0x0102, 0x0041, /* Ă A */ + 0x0103, 0x0061, /* ă a */ + 0x0104, 0x0041, /* Ą A */ + 0x0105, 0x0061, /* ą a */ + 0x0106, 0x0043, /* Ć C */ + 0x0107, 0x0063, /* ć c */ + 0x0108, 0x0043, /* Ĉ C */ + 0x0109, 0x0063, /* ĉ c */ + 0x010a, 0x0043, /* Ċ C */ + 0x010b, 0x0063, /* ċ c */ + 0x010c, 0x0043, /* Č C */ + 0x010d, 0x0063, /* č c */ + 0x010e, 0x0044, /* Ď D */ + 0x010f, 0x0064, /* ď d */ + 0x0112, 0x0045, /* Ē E */ + 0x0113, 0x0065, /* ē e */ + 0x0114, 0x0045, /* Ĕ E */ + 0x0115, 0x0065, /* ĕ e */ + 0x0116, 0x0045, /* Ė E */ + 0x0117, 0x0065, /* ė e */ + 0x0118, 0x0045, /* Ę E */ + 0x0119, 0x0065, /* ę e */ + 0x011a, 0x0045, /* Ě E */ + 0x011b, 0x0065, /* ě e */ + 0x011c, 0x0047, /* Ĝ G */ + 0x011d, 0x0067, /* ĝ g */ + 0x011e, 0x0047, /* Ğ G */ + 0x011f, 0x0067, /* ğ g */ + 0x0120, 0x0047, /* Ġ G */ + 0x0121, 0x0067, /* ġ g */ + 0x0122, 0x0047, /* Ģ G */ + 0x0123, 0x0067, /* ģ g */ + 0x0124, 0x0048, /* Ĥ H */ + 0x0125, 0x0068, /* ĥ h */ + 0x0128, 0x0049, /* Ĩ I */ + 0x0129, 0x0069, /* ĩ i */ + 0x012a, 0x0049, /* Ī I */ + 0x012b, 0x0069, /* ī i */ + 0x012c, 0x0049, /* Ĭ I */ + 0x012d, 0x0069, /* ĭ i */ + 0x012e, 0x0049, /* Į I */ + 0x012f, 0x0069, /* į i */ + 0x0130, 0x0049, /* İ I */ + 0x0134, 0x004a, /* Ĵ J */ + 0x0135, 0x006a, /* ĵ j */ + 0x0136, 0x004b, /* Ķ K */ + 0x0137, 0x006b, /* ķ k */ + 0x0139, 0x004c, /* Ĺ L */ + 0x013a, 0x006c, /* ĺ l */ + 0x013b, 0x004c, /* Ļ L */ + 0x013c, 0x006c, /* ļ l */ + 0x013d, 0x004c, /* Ľ L */ + 0x013e, 0x006c, /* ľ l */ + 0x0143, 0x004e, /* Ń N */ + 0x0144, 0x006e, /* ń n */ + 0x0145, 0x004e, /* Ņ N */ + 0x0146, 0x006e, /* ņ n */ + 0x0147, 0x004e, /* Ň N */ + 0x0148, 0x006e, /* ň n */ + 0x014c, 0x004f, /* Ō O */ + 0x014d, 0x006f, /* ō o */ + 0x014e, 0x004f, /* Ŏ O */ + 0x014f, 0x006f, /* ŏ o */ + 0x0150, 0x004f, /* Ő O */ + 0x0151, 0x006f, /* ő o */ + 0x0154, 0x0052, /* Ŕ R */ + 0x0155, 0x0072, /* ŕ r */ + 0x0156, 0x0052, /* Ŗ R */ + 0x0157, 0x0072, /* ŗ r */ + 0x0158, 0x0052, /* Ř R */ + 0x0159, 0x0072, /* ř r */ + 0x015a, 0x0053, /* Ś S */ + 0x015b, 0x0073, /* ś s */ + 0x015c, 0x0053, /* Ŝ S */ + 0x015d, 0x0073, /* ŝ s */ + 0x015e, 0x0053, /* Ş S */ + 0x015f, 0x0073, /* ş s */ + 0x0160, 0x0053, /* Š S */ + 0x0161, 0x0073, /* š s */ + 0x0162, 0x0054, /* Ţ T */ + 0x0163, 0x0074, /* ţ t */ + 0x0164, 0x0054, /* Ť T */ + 0x0165, 0x0074, /* ť t */ + 0x0168, 0x0055, /* Ũ U */ + 0x0169, 0x0075, /* ũ u */ + 0x016a, 0x0055, /* Ū U */ + 0x016b, 0x0075, /* ū u */ + 0x016c, 0x0055, /* Ŭ U */ + 0x016d, 0x0075, /* ŭ u */ + 0x016e, 0x0055, /* Ů U */ + 0x016f, 0x0075, /* ů u */ + 0x0170, 0x0055, /* Ű U */ + 0x0171, 0x0075, /* ű u */ + 0x0172, 0x0055, /* Ų U */ + 0x0173, 0x0075, /* ų u */ + 0x0174, 0x0057, /* Ŵ W */ + 0x0175, 0x0077, /* ŵ w */ + 0x0176, 0x0059, /* Ŷ Y */ + 0x0177, 0x0079, /* ŷ y */ + 0x0178, 0x0059, /* Ÿ Y */ + 0x0179, 0x005a, /* Ź Z */ + 0x017a, 0x007a, /* ź z */ + 0x017b, 0x005a, /* Ż Z */ + 0x017c, 0x007a, /* ż z */ + 0x017d, 0x005a, /* Ž Z */ + 0x017e, 0x007a, /* ž z */ + 0x01a0, 0x004f, /* Ơ O */ + 0x01a1, 0x006f, /* ơ o */ + 0x01af, 0x0055, /* Ư U */ + 0x01b0, 0x0075, /* ư u */ + 0x01cd, 0x0041, /* Ǎ A */ + 0x01ce, 0x0061, /* ǎ a */ + 0x01cf, 0x0049, /* Ǐ I */ + 0x01d0, 0x0069, /* ǐ i */ + 0x01d1, 0x004f, /* Ǒ O */ + 0x01d2, 0x006f, /* ǒ o */ + 0x01d3, 0x0055, /* Ǔ U */ + 0x01d4, 0x0075, /* ǔ u */ + 0x01d5, 0x0055, /* Ǖ U */ + 0x01d6, 0x0075, /* ǖ u */ + 0x01d7, 0x0055, /* Ǘ U */ + 0x01d8, 0x0075, /* ǘ u */ + 0x01d9, 0x0055, /* Ǚ U */ + 0x01da, 0x0075, /* ǚ u */ + 0x01db, 0x0055, /* Ǜ U */ + 0x01dc, 0x0075, /* ǜ u */ + 0x01de, 0x0041, /* Ǟ A */ + 0x01df, 0x0061, /* ǟ a */ + 0x01e0, 0x0041, /* Ǡ A */ + 0x01e1, 0x0061, /* ǡ a */ + 0x01e2, 0x00c6, /* Ǣ Æ */ + 0x01e3, 0x00e6, /* ǣ æ */ + 0x01e6, 0x0047, /* Ǧ G */ + 0x01e7, 0x0067, /* ǧ g */ + 0x01e8, 0x004b, /* Ǩ K */ + 0x01e9, 0x006b, /* ǩ k */ + 0x01ea, 0x004f, /* Ǫ O */ + 0x01eb, 0x006f, /* ǫ o */ + 0x01ec, 0x004f, /* Ǭ O */ + 0x01ed, 0x006f, /* ǭ o */ + 0x01ee, 0x01b7, /* Ǯ Ʒ */ + 0x01ef, 0x0292, /* ǯ ʒ */ + 0x01f0, 0x006a, /* ǰ j */ + 0x01f4, 0x0047, /* Ǵ G */ + 0x01f5, 0x0067, /* ǵ g */ + 0x01f8, 0x004e, /* Ǹ N */ + 0x01f9, 0x006e, /* ǹ n */ + 0x01fa, 0x0041, /* Ǻ A */ + 0x01fb, 0x0061, /* ǻ a */ + 0x01fc, 0x00c6, /* Ǽ Æ */ + 0x01fd, 0x00e6, /* ǽ æ */ + 0x01fe, 0x00d8, /* Ǿ Ø */ + 0x01ff, 0x00f8, /* ǿ ø */ + 0x0200, 0x0041, /* Ȁ A */ + 0x0201, 0x0061, /* ȁ a */ + 0x0202, 0x0041, /* Ȃ A */ + 0x0203, 0x0061, /* ȃ a */ + 0x0204, 0x0045, /* Ȅ E */ + 0x0205, 0x0065, /* ȅ e */ + 0x0206, 0x0045, /* Ȇ E */ + 0x0207, 0x0065, /* ȇ e */ + 0x0208, 0x0049, /* Ȉ I */ + 0x0209, 0x0069, /* ȉ i */ + 0x020a, 0x0049, /* Ȋ I */ + 0x020b, 0x0069, /* ȋ i */ + 0x020c, 0x004f, /* Ȍ O */ + 0x020d, 0x006f, /* ȍ o */ + 0x020e, 0x004f, /* Ȏ O */ + 0x020f, 0x006f, /* ȏ o */ + 0x0210, 0x0052, /* Ȑ R */ + 0x0211, 0x0072, /* ȑ r */ + 0x0212, 0x0052, /* Ȓ R */ + 0x0213, 0x0072, /* ȓ r */ + 0x0214, 0x0055, /* Ȕ U */ + 0x0215, 0x0075, /* ȕ u */ + 0x0216, 0x0055, /* Ȗ U */ + 0x0217, 0x0075, /* ȗ u */ + 0x0218, 0x0053, /* Ș S */ + 0x0219, 0x0073, /* ș s */ + 0x021a, 0x0054, /* Ț T */ + 0x021b, 0x0074, /* ț t */ + 0x021e, 0x0048, /* Ȟ H */ + 0x021f, 0x0068, /* ȟ h */ + 0x0226, 0x0041, /* Ȧ A */ + 0x0227, 0x0061, /* ȧ a */ + 0x0228, 0x0045, /* Ȩ E */ + 0x0229, 0x0065, /* ȩ e */ + 0x022a, 0x004f, /* Ȫ O */ + 0x022b, 0x006f, /* ȫ o */ + 0x022c, 0x004f, /* Ȭ O */ + 0x022d, 0x006f, /* ȭ o */ + 0x022e, 0x004f, /* Ȯ O */ + 0x022f, 0x006f, /* ȯ o */ + 0x0230, 0x004f, /* Ȱ O */ + 0x0231, 0x006f, /* ȱ o */ + 0x0232, 0x0059, /* Ȳ Y */ + 0x0233, 0x0079, /* ȳ y */ + 0x0374, 0x02b9, /* ʹ ʹ */ + 0x0386, 0x0391, /* Ά Α */ + 0x0388, 0x0395, /* Έ Ε */ + 0x0389, 0x0397, /* Ή Η */ + 0x038a, 0x0399, /* Ί Ι */ + 0x038c, 0x039f, /* Ό Ο */ + 0x038e, 0x03a5, /* Ύ Υ */ + 0x038f, 0x03a9, /* Ώ Ω */ + 0x0390, 0x03b9, /* ΐ ι */ + 0x03aa, 0x0399, /* Ϊ Ι */ + 0x03ab, 0x03a5, /* Ϋ Υ */ + 0x03ac, 0x03b1, /* ά α */ + 0x03ad, 0x03b5, /* έ ε */ + 0x03ae, 0x03b7, /* ή η */ + 0x03af, 0x03b9, /* ί ι */ + 0x03b0, 0x03c5, /* ΰ υ */ + 0x03ca, 0x03b9, /* ϊ ι */ + 0x03cb, 0x03c5, /* ϋ υ */ + 0x03cc, 0x03bf, /* ό ο */ + 0x03cd, 0x03c5, /* ύ υ */ + 0x03ce, 0x03c9, /* ώ ω */ + 0x03d3, 0x03d2, /* ϓ ϒ */ + 0x03d4, 0x03d2, /* ϔ ϒ */ + 0x0400, 0x0415, /* Ѐ Е */ + 0x0401, 0x0415, /* Ё Е */ + 0x0403, 0x0413, /* Ѓ Г */ + 0x0407, 0x0406, /* Ї І */ + 0x040c, 0x041a, /* Ќ К */ + 0x040d, 0x0418, /* Ѝ И */ + 0x040e, 0x0423, /* Ў У */ + 0x0419, 0x0418, /* Й И */ + 0x0439, 0x0438, /* й и */ + 0x0450, 0x0435, /* ѐ е */ + 0x0451, 0x0435, /* ё е */ + 0x0453, 0x0433, /* ѓ г */ + 0x0457, 0x0456, /* ї і */ + 0x045c, 0x043a, /* ќ к */ + 0x045d, 0x0438, /* ѝ и */ + 0x045e, 0x0443, /* ў у */ + 0x0476, 0x0474, /* Ѷ Ѵ */ + 0x0477, 0x0475, /* ѷ ѵ */ + 0x04c1, 0x0416, /* Ӂ Ж */ + 0x04c2, 0x0436, /* ӂ ж */ + 0x04d0, 0x0410, /* Ӑ А */ + 0x04d1, 0x0430, /* ӑ а */ + 0x04d2, 0x0410, /* Ӓ А */ + 0x04d3, 0x0430, /* ӓ а */ + 0x04d6, 0x0415, /* Ӗ Е */ + 0x04d7, 0x0435, /* ӗ е */ + 0x04da, 0x04d8, /* Ӛ Ә */ + 0x04db, 0x04d9, /* ӛ ә */ + 0x04dc, 0x0416, /* Ӝ Ж */ + 0x04dd, 0x0436, /* ӝ ж */ + 0x04de, 0x0417, /* Ӟ З */ + 0x04df, 0x0437, /* ӟ з */ + 0x04e2, 0x0418, /* Ӣ И */ + 0x04e3, 0x0438, /* ӣ и */ + 0x04e4, 0x0418, /* Ӥ И */ + 0x04e5, 0x0438, /* ӥ и */ + 0x04e6, 0x041e, /* Ӧ О */ + 0x04e7, 0x043e, /* ӧ о */ + 0x04ea, 0x04e8, /* Ӫ Ө */ + 0x04eb, 0x04e9, /* ӫ ө */ + 0x04ec, 0x042d, /* Ӭ Э */ + 0x04ed, 0x044d, /* ӭ э */ + 0x04ee, 0x0423, /* Ӯ У */ + 0x04ef, 0x0443, /* ӯ у */ + 0x04f0, 0x0423, /* Ӱ У */ + 0x04f1, 0x0443, /* ӱ у */ + 0x04f2, 0x0423, /* Ӳ У */ + 0x04f3, 0x0443, /* ӳ у */ + 0x04f4, 0x0427, /* Ӵ Ч */ + 0x04f5, 0x0447, /* ӵ ч */ + 0x04f8, 0x042b, /* Ӹ Ы */ + 0x04f9, 0x044b, /* ӹ ы */ + 0x0622, 0x0627, /* آ ا */ + 0x0623, 0x0627, /* أ ا */ + 0x0624, 0x0648, /* ؤ و */ + 0x0625, 0x0627, /* إ ا */ + 0x0626, 0x064a, /* ئ ي */ + 0x06c0, 0x06d5, /* ۀ ە */ + 0x06c2, 0x06c1, /* ۂ ہ */ + 0x06d3, 0x06d2, /* ۓ ے */ + 0x0929, 0x0928, /* ऩ न */ + 0x0931, 0x0930, /* ऱ र */ + 0x0934, 0x0933, /* ऴ ळ */ + 0x0958, 0x0915, /* क़ क */ + 0x0959, 0x0916, /* ख़ ख */ + 0x095a, 0x0917, /* ग़ ग */ + 0x095b, 0x091c, /* ज़ ज */ + 0x095c, 0x0921, /* ड़ ड */ + 0x095d, 0x0922, /* ढ़ ढ */ + 0x095e, 0x092b, /* फ़ फ */ + 0x095f, 0x092f, /* य़ य */ + 0x09dc, 0x09a1, /* ড় ড */ + 0x09dd, 0x09a2, /* ঢ় ঢ */ + 0x09df, 0x09af, /* য় য */ + 0x0a33, 0x0a32, /* ਲ਼ ਲ */ + 0x0a36, 0x0a38, /* ਸ਼ ਸ */ + 0x0a59, 0x0a16, /* ਖ਼ ਖ */ + 0x0a5a, 0x0a17, /* ਗ਼ ਗ */ + 0x0a5b, 0x0a1c, /* ਜ਼ ਜ */ + 0x0a5e, 0x0a2b, /* ਫ਼ ਫ */ + 0x0b5c, 0x0b21, /* ଡ଼ ଡ */ + 0x0b5d, 0x0b22, /* ଢ଼ ଢ */ + 0x0b94, 0x0b92, /* ஔ ஒ */ + 0x0f43, 0x0f42, /* གྷ ག */ + 0x0f4d, 0x0f4c, /* ཌྷ ཌ */ + 0x0f52, 0x0f51, /* དྷ ད */ + 0x0f57, 0x0f56, /* བྷ བ */ + 0x0f5c, 0x0f5b, /* ཛྷ ཛ */ + 0x0f69, 0x0f40, /* ཀྵ ཀ */ + 0x1026, 0x1025, /* ဦ ဥ */ + 0x1b06, 0x1b05, /* ᬆ ᬅ */ + 0x1b08, 0x1b07, /* ᬈ ᬇ */ + 0x1b0a, 0x1b09, /* ᬊ ᬉ */ + 0x1b0c, 0x1b0b, /* ᬌ ᬋ */ + 0x1b0e, 0x1b0d, /* ᬎ ᬍ */ + 0x1b12, 0x1b11, /* ᬒ ᬑ */ + 0x1e00, 0x0041, /* Ḁ A */ + 0x1e01, 0x0061, /* ḁ a */ + 0x1e02, 0x0042, /* Ḃ B */ + 0x1e03, 0x0062, /* ḃ b */ + 0x1e04, 0x0042, /* Ḅ B */ + 0x1e05, 0x0062, /* ḅ b */ + 0x1e06, 0x0042, /* Ḇ B */ + 0x1e07, 0x0062, /* ḇ b */ + 0x1e08, 0x0043, /* Ḉ C */ + 0x1e09, 0x0063, /* ḉ c */ + 0x1e0a, 0x0044, /* Ḋ D */ + 0x1e0b, 0x0064, /* ḋ d */ + 0x1e0c, 0x0044, /* Ḍ D */ + 0x1e0d, 0x0064, /* ḍ d */ + 0x1e0e, 0x0044, /* Ḏ D */ + 0x1e0f, 0x0064, /* ḏ d */ + 0x1e10, 0x0044, /* Ḑ D */ + 0x1e11, 0x0064, /* ḑ d */ + 0x1e12, 0x0044, /* Ḓ D */ + 0x1e13, 0x0064, /* ḓ d */ + 0x1e14, 0x0045, /* Ḕ E */ + 0x1e15, 0x0065, /* ḕ e */ + 0x1e16, 0x0045, /* Ḗ E */ + 0x1e17, 0x0065, /* ḗ e */ + 0x1e18, 0x0045, /* Ḙ E */ + 0x1e19, 0x0065, /* ḙ e */ + 0x1e1a, 0x0045, /* Ḛ E */ + 0x1e1b, 0x0065, /* ḛ e */ + 0x1e1c, 0x0045, /* Ḝ E */ + 0x1e1d, 0x0065, /* ḝ e */ + 0x1e1e, 0x0046, /* Ḟ F */ + 0x1e1f, 0x0066, /* ḟ f */ + 0x1e20, 0x0047, /* Ḡ G */ + 0x1e21, 0x0067, /* ḡ g */ + 0x1e22, 0x0048, /* Ḣ H */ + 0x1e23, 0x0068, /* ḣ h */ + 0x1e24, 0x0048, /* Ḥ H */ + 0x1e25, 0x0068, /* ḥ h */ + 0x1e26, 0x0048, /* Ḧ H */ + 0x1e27, 0x0068, /* ḧ h */ + 0x1e28, 0x0048, /* Ḩ H */ + 0x1e29, 0x0068, /* ḩ h */ + 0x1e2a, 0x0048, /* Ḫ H */ + 0x1e2b, 0x0068, /* ḫ h */ + 0x1e2c, 0x0049, /* Ḭ I */ + 0x1e2d, 0x0069, /* ḭ i */ + 0x1e2e, 0x0049, /* Ḯ I */ + 0x1e2f, 0x0069, /* ḯ i */ + 0x1e30, 0x004b, /* Ḱ K */ + 0x1e31, 0x006b, /* ḱ k */ + 0x1e32, 0x004b, /* Ḳ K */ + 0x1e33, 0x006b, /* ḳ k */ + 0x1e34, 0x004b, /* Ḵ K */ + 0x1e35, 0x006b, /* ḵ k */ + 0x1e36, 0x004c, /* Ḷ L */ + 0x1e37, 0x006c, /* ḷ l */ + 0x1e38, 0x004c, /* Ḹ L */ + 0x1e39, 0x006c, /* ḹ l */ + 0x1e3a, 0x004c, /* Ḻ L */ + 0x1e3b, 0x006c, /* ḻ l */ + 0x1e3c, 0x004c, /* Ḽ L */ + 0x1e3d, 0x006c, /* ḽ l */ + 0x1e3e, 0x004d, /* Ḿ M */ + 0x1e3f, 0x006d, /* ḿ m */ + 0x1e40, 0x004d, /* Ṁ M */ + 0x1e41, 0x006d, /* ṁ m */ + 0x1e42, 0x004d, /* Ṃ M */ + 0x1e43, 0x006d, /* ṃ m */ + 0x1e44, 0x004e, /* Ṅ N */ + 0x1e45, 0x006e, /* ṅ n */ + 0x1e46, 0x004e, /* Ṇ N */ + 0x1e47, 0x006e, /* ṇ n */ + 0x1e48, 0x004e, /* Ṉ N */ + 0x1e49, 0x006e, /* ṉ n */ + 0x1e4a, 0x004e, /* Ṋ N */ + 0x1e4b, 0x006e, /* ṋ n */ + 0x1e4c, 0x004f, /* Ṍ O */ + 0x1e4d, 0x006f, /* ṍ o */ + 0x1e4e, 0x004f, /* Ṏ O */ + 0x1e4f, 0x006f, /* ṏ o */ + 0x1e50, 0x004f, /* Ṑ O */ + 0x1e51, 0x006f, /* ṑ o */ + 0x1e52, 0x004f, /* Ṓ O */ + 0x1e53, 0x006f, /* ṓ o */ + 0x1e54, 0x0050, /* Ṕ P */ + 0x1e55, 0x0070, /* ṕ p */ + 0x1e56, 0x0050, /* Ṗ P */ + 0x1e57, 0x0070, /* ṗ p */ + 0x1e58, 0x0052, /* Ṙ R */ + 0x1e59, 0x0072, /* ṙ r */ + 0x1e5a, 0x0052, /* Ṛ R */ + 0x1e5b, 0x0072, /* ṛ r */ + 0x1e5c, 0x0052, /* Ṝ R */ + 0x1e5d, 0x0072, /* ṝ r */ + 0x1e5e, 0x0052, /* Ṟ R */ + 0x1e5f, 0x0072, /* ṟ r */ + 0x1e60, 0x0053, /* Ṡ S */ + 0x1e61, 0x0073, /* ṡ s */ + 0x1e62, 0x0053, /* Ṣ S */ + 0x1e63, 0x0073, /* ṣ s */ + 0x1e64, 0x0053, /* Ṥ S */ + 0x1e65, 0x0073, /* ṥ s */ + 0x1e66, 0x0053, /* Ṧ S */ + 0x1e67, 0x0073, /* ṧ s */ + 0x1e68, 0x0053, /* Ṩ S */ + 0x1e69, 0x0073, /* ṩ s */ + 0x1e6a, 0x0054, /* Ṫ T */ + 0x1e6b, 0x0074, /* ṫ t */ + 0x1e6c, 0x0054, /* Ṭ T */ + 0x1e6d, 0x0074, /* ṭ t */ + 0x1e6e, 0x0054, /* Ṯ T */ + 0x1e6f, 0x0074, /* ṯ t */ + 0x1e70, 0x0054, /* Ṱ T */ + 0x1e71, 0x0074, /* ṱ t */ + 0x1e72, 0x0055, /* Ṳ U */ + 0x1e73, 0x0075, /* ṳ u */ + 0x1e74, 0x0055, /* Ṵ U */ + 0x1e75, 0x0075, /* ṵ u */ + 0x1e76, 0x0055, /* Ṷ U */ + 0x1e77, 0x0075, /* ṷ u */ + 0x1e78, 0x0055, /* Ṹ U */ + 0x1e79, 0x0075, /* ṹ u */ + 0x1e7a, 0x0055, /* Ṻ U */ + 0x1e7b, 0x0075, /* ṻ u */ + 0x1e7c, 0x0056, /* Ṽ V */ + 0x1e7d, 0x0076, /* ṽ v */ + 0x1e7e, 0x0056, /* Ṿ V */ + 0x1e7f, 0x0076, /* ṿ v */ + 0x1e80, 0x0057, /* Ẁ W */ + 0x1e81, 0x0077, /* ẁ w */ + 0x1e82, 0x0057, /* Ẃ W */ + 0x1e83, 0x0077, /* ẃ w */ + 0x1e84, 0x0057, /* Ẅ W */ + 0x1e85, 0x0077, /* ẅ w */ + 0x1e86, 0x0057, /* Ẇ W */ + 0x1e87, 0x0077, /* ẇ w */ + 0x1e88, 0x0057, /* Ẉ W */ + 0x1e89, 0x0077, /* ẉ w */ + 0x1e8a, 0x0058, /* Ẋ X */ + 0x1e8b, 0x0078, /* ẋ x */ + 0x1e8c, 0x0058, /* Ẍ X */ + 0x1e8d, 0x0078, /* ẍ x */ + 0x1e8e, 0x0059, /* Ẏ Y */ + 0x1e8f, 0x0079, /* ẏ y */ + 0x1e90, 0x005a, /* Ẑ Z */ + 0x1e91, 0x007a, /* ẑ z */ + 0x1e92, 0x005a, /* Ẓ Z */ + 0x1e93, 0x007a, /* ẓ z */ + 0x1e94, 0x005a, /* Ẕ Z */ + 0x1e95, 0x007a, /* ẕ z */ + 0x1e96, 0x0068, /* ẖ h */ + 0x1e97, 0x0074, /* ẗ t */ + 0x1e98, 0x0077, /* ẘ w */ + 0x1e99, 0x0079, /* ẙ y */ + 0x1e9b, 0x017f, /* ẛ ſ */ + 0x1ea0, 0x0041, /* Ạ A */ + 0x1ea1, 0x0061, /* ạ a */ + 0x1ea2, 0x0041, /* Ả A */ + 0x1ea3, 0x0061, /* ả a */ + 0x1ea4, 0x0041, /* Ấ A */ + 0x1ea5, 0x0061, /* ấ a */ + 0x1ea6, 0x0041, /* Ầ A */ + 0x1ea7, 0x0061, /* ầ a */ + 0x1ea8, 0x0041, /* Ẩ A */ + 0x1ea9, 0x0061, /* ẩ a */ + 0x1eaa, 0x0041, /* Ẫ A */ + 0x1eab, 0x0061, /* ẫ a */ + 0x1eac, 0x0041, /* Ậ A */ + 0x1ead, 0x0061, /* ậ a */ + 0x1eae, 0x0041, /* Ắ A */ + 0x1eaf, 0x0061, /* ắ a */ + 0x1eb0, 0x0041, /* Ằ A */ + 0x1eb1, 0x0061, /* ằ a */ + 0x1eb2, 0x0041, /* Ẳ A */ + 0x1eb3, 0x0061, /* ẳ a */ + 0x1eb4, 0x0041, /* Ẵ A */ + 0x1eb5, 0x0061, /* ẵ a */ + 0x1eb6, 0x0041, /* Ặ A */ + 0x1eb7, 0x0061, /* ặ a */ + 0x1eb8, 0x0045, /* Ẹ E */ + 0x1eb9, 0x0065, /* ẹ e */ + 0x1eba, 0x0045, /* Ẻ E */ + 0x1ebb, 0x0065, /* ẻ e */ + 0x1ebc, 0x0045, /* Ẽ E */ + 0x1ebd, 0x0065, /* ẽ e */ + 0x1ebe, 0x0045, /* Ế E */ + 0x1ebf, 0x0065, /* ế e */ + 0x1ec0, 0x0045, /* Ề E */ + 0x1ec1, 0x0065, /* ề e */ + 0x1ec2, 0x0045, /* Ể E */ + 0x1ec3, 0x0065, /* ể e */ + 0x1ec4, 0x0045, /* Ễ E */ + 0x1ec5, 0x0065, /* ễ e */ + 0x1ec6, 0x0045, /* Ệ E */ + 0x1ec7, 0x0065, /* ệ e */ + 0x1ec8, 0x0049, /* Ỉ I */ + 0x1ec9, 0x0069, /* ỉ i */ + 0x1eca, 0x0049, /* Ị I */ + 0x1ecb, 0x0069, /* ị i */ + 0x1ecc, 0x004f, /* Ọ O */ + 0x1ecd, 0x006f, /* ọ o */ + 0x1ece, 0x004f, /* Ỏ O */ + 0x1ecf, 0x006f, /* ỏ o */ + 0x1ed0, 0x004f, /* Ố O */ + 0x1ed1, 0x006f, /* ố o */ + 0x1ed2, 0x004f, /* Ồ O */ + 0x1ed3, 0x006f, /* ồ o */ + 0x1ed4, 0x004f, /* Ổ O */ + 0x1ed5, 0x006f, /* ổ o */ + 0x1ed6, 0x004f, /* Ỗ O */ + 0x1ed7, 0x006f, /* ỗ o */ + 0x1ed8, 0x004f, /* Ộ O */ + 0x1ed9, 0x006f, /* ộ o */ + 0x1eda, 0x004f, /* Ớ O */ + 0x1edb, 0x006f, /* ớ o */ + 0x1edc, 0x004f, /* Ờ O */ + 0x1edd, 0x006f, /* ờ o */ + 0x1ede, 0x004f, /* Ở O */ + 0x1edf, 0x006f, /* ở o */ + 0x1ee0, 0x004f, /* Ỡ O */ + 0x1ee1, 0x006f, /* ỡ o */ + 0x1ee2, 0x004f, /* Ợ O */ + 0x1ee3, 0x006f, /* ợ o */ + 0x1ee4, 0x0055, /* Ụ U */ + 0x1ee5, 0x0075, /* ụ u */ + 0x1ee6, 0x0055, /* Ủ U */ + 0x1ee7, 0x0075, /* ủ u */ + 0x1ee8, 0x0055, /* Ứ U */ + 0x1ee9, 0x0075, /* ứ u */ + 0x1eea, 0x0055, /* Ừ U */ + 0x1eeb, 0x0075, /* ừ u */ + 0x1eec, 0x0055, /* Ử U */ + 0x1eed, 0x0075, /* ử u */ + 0x1eee, 0x0055, /* Ữ U */ + 0x1eef, 0x0075, /* ữ u */ + 0x1ef0, 0x0055, /* Ự U */ + 0x1ef1, 0x0075, /* ự u */ + 0x1ef2, 0x0059, /* Ỳ Y */ + 0x1ef3, 0x0079, /* ỳ y */ + 0x1ef4, 0x0059, /* Ỵ Y */ + 0x1ef5, 0x0079, /* ỵ y */ + 0x1ef6, 0x0059, /* Ỷ Y */ + 0x1ef7, 0x0079, /* ỷ y */ + 0x1ef8, 0x0059, /* Ỹ Y */ + 0x1ef9, 0x0079, /* ỹ y */ + 0x1f00, 0x03b1, /* ἀ α */ + 0x1f01, 0x03b1, /* ἁ α */ + 0x1f02, 0x03b1, /* ἂ α */ + 0x1f03, 0x03b1, /* ἃ α */ + 0x1f04, 0x03b1, /* ἄ α */ + 0x1f05, 0x03b1, /* ἅ α */ + 0x1f06, 0x03b1, /* ἆ α */ + 0x1f07, 0x03b1, /* ἇ α */ + 0x1f08, 0x0391, /* Ἀ Α */ + 0x1f09, 0x0391, /* Ἁ Α */ + 0x1f0a, 0x0391, /* Ἂ Α */ + 0x1f0b, 0x0391, /* Ἃ Α */ + 0x1f0c, 0x0391, /* Ἄ Α */ + 0x1f0d, 0x0391, /* Ἅ Α */ + 0x1f0e, 0x0391, /* Ἆ Α */ + 0x1f0f, 0x0391, /* Ἇ Α */ + 0x1f10, 0x03b5, /* ἐ ε */ + 0x1f11, 0x03b5, /* ἑ ε */ + 0x1f12, 0x03b5, /* ἒ ε */ + 0x1f13, 0x03b5, /* ἓ ε */ + 0x1f14, 0x03b5, /* ἔ ε */ + 0x1f15, 0x03b5, /* ἕ ε */ + 0x1f18, 0x0395, /* Ἐ Ε */ + 0x1f19, 0x0395, /* Ἑ Ε */ + 0x1f1a, 0x0395, /* Ἒ Ε */ + 0x1f1b, 0x0395, /* Ἓ Ε */ + 0x1f1c, 0x0395, /* Ἔ Ε */ + 0x1f1d, 0x0395, /* Ἕ Ε */ + 0x1f20, 0x03b7, /* ἠ η */ + 0x1f21, 0x03b7, /* ἡ η */ + 0x1f22, 0x03b7, /* ἢ η */ + 0x1f23, 0x03b7, /* ἣ η */ + 0x1f24, 0x03b7, /* ἤ η */ + 0x1f25, 0x03b7, /* ἥ η */ + 0x1f26, 0x03b7, /* ἦ η */ + 0x1f27, 0x03b7, /* ἧ η */ + 0x1f28, 0x0397, /* Ἠ Η */ + 0x1f29, 0x0397, /* Ἡ Η */ + 0x1f2a, 0x0397, /* Ἢ Η */ + 0x1f2b, 0x0397, /* Ἣ Η */ + 0x1f2c, 0x0397, /* Ἤ Η */ + 0x1f2d, 0x0397, /* Ἥ Η */ + 0x1f2e, 0x0397, /* Ἦ Η */ + 0x1f2f, 0x0397, /* Ἧ Η */ + 0x1f30, 0x03b9, /* ἰ ι */ + 0x1f31, 0x03b9, /* ἱ ι */ + 0x1f32, 0x03b9, /* ἲ ι */ + 0x1f33, 0x03b9, /* ἳ ι */ + 0x1f34, 0x03b9, /* ἴ ι */ + 0x1f35, 0x03b9, /* ἵ ι */ + 0x1f36, 0x03b9, /* ἶ ι */ + 0x1f37, 0x03b9, /* ἷ ι */ + 0x1f38, 0x0399, /* Ἰ Ι */ + 0x1f39, 0x0399, /* Ἱ Ι */ + 0x1f3a, 0x0399, /* Ἲ Ι */ + 0x1f3b, 0x0399, /* Ἳ Ι */ + 0x1f3c, 0x0399, /* Ἴ Ι */ + 0x1f3d, 0x0399, /* Ἵ Ι */ + 0x1f3e, 0x0399, /* Ἶ Ι */ + 0x1f3f, 0x0399, /* Ἷ Ι */ + 0x1f40, 0x03bf, /* ὀ ο */ + 0x1f41, 0x03bf, /* ὁ ο */ + 0x1f42, 0x03bf, /* ὂ ο */ + 0x1f43, 0x03bf, /* ὃ ο */ + 0x1f44, 0x03bf, /* ὄ ο */ + 0x1f45, 0x03bf, /* ὅ ο */ + 0x1f48, 0x039f, /* Ὀ Ο */ + 0x1f49, 0x039f, /* Ὁ Ο */ + 0x1f4a, 0x039f, /* Ὂ Ο */ + 0x1f4b, 0x039f, /* Ὃ Ο */ + 0x1f4c, 0x039f, /* Ὄ Ο */ + 0x1f4d, 0x039f, /* Ὅ Ο */ + 0x1f50, 0x03c5, /* ὐ υ */ + 0x1f51, 0x03c5, /* ὑ υ */ + 0x1f52, 0x03c5, /* ὒ υ */ + 0x1f53, 0x03c5, /* ὓ υ */ + 0x1f54, 0x03c5, /* ὔ υ */ + 0x1f55, 0x03c5, /* ὕ υ */ + 0x1f56, 0x03c5, /* ὖ υ */ + 0x1f57, 0x03c5, /* ὗ υ */ + 0x1f59, 0x03a5, /* Ὑ Υ */ + 0x1f5b, 0x03a5, /* Ὓ Υ */ + 0x1f5d, 0x03a5, /* Ὕ Υ */ + 0x1f5f, 0x03a5, /* Ὗ Υ */ + 0x1f60, 0x03c9, /* ὠ ω */ + 0x1f61, 0x03c9, /* ὡ ω */ + 0x1f62, 0x03c9, /* ὢ ω */ + 0x1f63, 0x03c9, /* ὣ ω */ + 0x1f64, 0x03c9, /* ὤ ω */ + 0x1f65, 0x03c9, /* ὥ ω */ + 0x1f66, 0x03c9, /* ὦ ω */ + 0x1f67, 0x03c9, /* ὧ ω */ + 0x1f68, 0x03a9, /* Ὠ Ω */ + 0x1f69, 0x03a9, /* Ὡ Ω */ + 0x1f6a, 0x03a9, /* Ὢ Ω */ + 0x1f6b, 0x03a9, /* Ὣ Ω */ + 0x1f6c, 0x03a9, /* Ὤ Ω */ + 0x1f6d, 0x03a9, /* Ὥ Ω */ + 0x1f6e, 0x03a9, /* Ὦ Ω */ + 0x1f6f, 0x03a9, /* Ὧ Ω */ + 0x1f70, 0x03b1, /* ὰ α */ + 0x1f71, 0x03b1, /* ά α */ + 0x1f72, 0x03b5, /* ὲ ε */ + 0x1f73, 0x03b5, /* έ ε */ + 0x1f74, 0x03b7, /* ὴ η */ + 0x1f75, 0x03b7, /* ή η */ + 0x1f76, 0x03b9, /* ὶ ι */ + 0x1f77, 0x03b9, /* ί ι */ + 0x1f78, 0x03bf, /* ὸ ο */ + 0x1f79, 0x03bf, /* ό ο */ + 0x1f7a, 0x03c5, /* ὺ υ */ + 0x1f7b, 0x03c5, /* ύ υ */ + 0x1f7c, 0x03c9, /* ὼ ω */ + 0x1f7d, 0x03c9, /* ώ ω */ + 0x1f80, 0x03b1, /* ᾀ α */ + 0x1f81, 0x03b1, /* ᾁ α */ + 0x1f82, 0x03b1, /* ᾂ α */ + 0x1f83, 0x03b1, /* ᾃ α */ + 0x1f84, 0x03b1, /* ᾄ α */ + 0x1f85, 0x03b1, /* ᾅ α */ + 0x1f86, 0x03b1, /* ᾆ α */ + 0x1f87, 0x03b1, /* ᾇ α */ + 0x1f88, 0x0391, /* ᾈ Α */ + 0x1f89, 0x0391, /* ᾉ Α */ + 0x1f8a, 0x0391, /* ᾊ Α */ + 0x1f8b, 0x0391, /* ᾋ Α */ + 0x1f8c, 0x0391, /* ᾌ Α */ + 0x1f8d, 0x0391, /* ᾍ Α */ + 0x1f8e, 0x0391, /* ᾎ Α */ + 0x1f8f, 0x0391, /* ᾏ Α */ + 0x1f90, 0x03b7, /* ᾐ η */ + 0x1f91, 0x03b7, /* ᾑ η */ + 0x1f92, 0x03b7, /* ᾒ η */ + 0x1f93, 0x03b7, /* ᾓ η */ + 0x1f94, 0x03b7, /* ᾔ η */ + 0x1f95, 0x03b7, /* ᾕ η */ + 0x1f96, 0x03b7, /* ᾖ η */ + 0x1f97, 0x03b7, /* ᾗ η */ + 0x1f98, 0x0397, /* ᾘ Η */ + 0x1f99, 0x0397, /* ᾙ Η */ + 0x1f9a, 0x0397, /* ᾚ Η */ + 0x1f9b, 0x0397, /* ᾛ Η */ + 0x1f9c, 0x0397, /* ᾜ Η */ + 0x1f9d, 0x0397, /* ᾝ Η */ + 0x1f9e, 0x0397, /* ᾞ Η */ + 0x1f9f, 0x0397, /* ᾟ Η */ + 0x1fa0, 0x03c9, /* ᾠ ω */ + 0x1fa1, 0x03c9, /* ᾡ ω */ + 0x1fa2, 0x03c9, /* ᾢ ω */ + 0x1fa3, 0x03c9, /* ᾣ ω */ + 0x1fa4, 0x03c9, /* ᾤ ω */ + 0x1fa5, 0x03c9, /* ᾥ ω */ + 0x1fa6, 0x03c9, /* ᾦ ω */ + 0x1fa7, 0x03c9, /* ᾧ ω */ + 0x1fa8, 0x03a9, /* ᾨ Ω */ + 0x1fa9, 0x03a9, /* ᾩ Ω */ + 0x1faa, 0x03a9, /* ᾪ Ω */ + 0x1fab, 0x03a9, /* ᾫ Ω */ + 0x1fac, 0x03a9, /* ᾬ Ω */ + 0x1fad, 0x03a9, /* ᾭ Ω */ + 0x1fae, 0x03a9, /* ᾮ Ω */ + 0x1faf, 0x03a9, /* ᾯ Ω */ + 0x1fb0, 0x03b1, /* ᾰ α */ + 0x1fb1, 0x03b1, /* ᾱ α */ + 0x1fb2, 0x03b1, /* ᾲ α */ + 0x1fb3, 0x03b1, /* ᾳ α */ + 0x1fb4, 0x03b1, /* ᾴ α */ + 0x1fb6, 0x03b1, /* ᾶ α */ + 0x1fb7, 0x03b1, /* ᾷ α */ + 0x1fb8, 0x0391, /* Ᾰ Α */ + 0x1fb9, 0x0391, /* Ᾱ Α */ + 0x1fba, 0x0391, /* Ὰ Α */ + 0x1fbb, 0x0391, /* Ά Α */ + 0x1fbc, 0x0391, /* ᾼ Α */ + 0x1fbe, 0x03b9, /* ι ι */ + 0x1fc2, 0x03b7, /* ῂ η */ + 0x1fc3, 0x03b7, /* ῃ η */ + 0x1fc4, 0x03b7, /* ῄ η */ + 0x1fc6, 0x03b7, /* ῆ η */ + 0x1fc7, 0x03b7, /* ῇ η */ + 0x1fc8, 0x0395, /* Ὲ Ε */ + 0x1fc9, 0x0395, /* Έ Ε */ + 0x1fca, 0x0397, /* Ὴ Η */ + 0x1fcb, 0x0397, /* Ή Η */ + 0x1fcc, 0x0397, /* ῌ Η */ + 0x1fd0, 0x03b9, /* ῐ ι */ + 0x1fd1, 0x03b9, /* ῑ ι */ + 0x1fd2, 0x03b9, /* ῒ ι */ + 0x1fd3, 0x03b9, /* ΐ ι */ + 0x1fd6, 0x03b9, /* ῖ ι */ + 0x1fd7, 0x03b9, /* ῗ ι */ + 0x1fd8, 0x0399, /* Ῐ Ι */ + 0x1fd9, 0x0399, /* Ῑ Ι */ + 0x1fda, 0x0399, /* Ὶ Ι */ + 0x1fdb, 0x0399, /* Ί Ι */ + 0x1fe0, 0x03c5, /* ῠ υ */ + 0x1fe1, 0x03c5, /* ῡ υ */ + 0x1fe2, 0x03c5, /* ῢ υ */ + 0x1fe3, 0x03c5, /* ΰ υ */ + 0x1fe4, 0x03c1, /* ῤ ρ */ + 0x1fe5, 0x03c1, /* ῥ ρ */ + 0x1fe6, 0x03c5, /* ῦ υ */ + 0x1fe7, 0x03c5, /* ῧ υ */ + 0x1fe8, 0x03a5, /* Ῠ Υ */ + 0x1fe9, 0x03a5, /* Ῡ Υ */ + 0x1fea, 0x03a5, /* Ὺ Υ */ + 0x1feb, 0x03a5, /* Ύ Υ */ + 0x1fec, 0x03a1, /* Ῥ Ρ */ + 0x1ff2, 0x03c9, /* ῲ ω */ + 0x1ff3, 0x03c9, /* ῳ ω */ + 0x1ff4, 0x03c9, /* ῴ ω */ + 0x1ff6, 0x03c9, /* ῶ ω */ + 0x1ff7, 0x03c9, /* ῷ ω */ + 0x1ff8, 0x039f, /* Ὸ Ο */ + 0x1ff9, 0x039f, /* Ό Ο */ + 0x1ffa, 0x03a9, /* Ὼ Ω */ + 0x1ffb, 0x03a9, /* Ώ Ω */ + 0x1ffc, 0x03a9, /* ῼ Ω */ + 0x2126, 0x03a9, /* Ω Ω */ + 0x212a, 0x004b, /* K K */ + 0x212b, 0x0041, /* Å A */ + 0x304c, 0x304b, /* が か */ + 0x304e, 0x304d, /* ぎ き */ + 0x3050, 0x304f, /* ぐ く */ + 0x3052, 0x3051, /* げ け */ + 0x3054, 0x3053, /* ご こ */ + 0x3056, 0x3055, /* ざ さ */ + 0x3058, 0x3057, /* じ し */ + 0x305a, 0x3059, /* ず す */ + 0x305c, 0x305b, /* ぜ せ */ + 0x305e, 0x305d, /* ぞ そ */ + 0x3060, 0x305f, /* だ た */ + 0x3062, 0x3061, /* ぢ ち */ + 0x3065, 0x3064, /* づ つ */ + 0x3067, 0x3066, /* で て */ + 0x3069, 0x3068, /* ど と */ + 0x3070, 0x306f, /* ば は */ + 0x3071, 0x306f, /* ぱ は */ + 0x3073, 0x3072, /* び ひ */ + 0x3074, 0x3072, /* ぴ ひ */ + 0x3076, 0x3075, /* ぶ ふ */ + 0x3077, 0x3075, /* ぷ ふ */ + 0x3079, 0x3078, /* べ へ */ + 0x307a, 0x3078, /* ぺ へ */ + 0x307c, 0x307b, /* ぼ ほ */ + 0x307d, 0x307b, /* ぽ ほ */ + 0x3094, 0x3046, /* ゔ う */ + 0x309e, 0x309d, /* ゞ ゝ */ + 0x30ac, 0x30ab, /* ガ カ */ + 0x30ae, 0x30ad, /* ギ キ */ + 0x30b0, 0x30af, /* グ ク */ + 0x30b2, 0x30b1, /* ゲ ケ */ + 0x30b4, 0x30b3, /* ゴ コ */ + 0x30b6, 0x30b5, /* ザ サ */ + 0x30b8, 0x30b7, /* ジ シ */ + 0x30ba, 0x30b9, /* ズ ス */ + 0x30bc, 0x30bb, /* ゼ セ */ + 0x30be, 0x30bd, /* ゾ ソ */ + 0x30c0, 0x30bf, /* ダ タ */ + 0x30c2, 0x30c1, /* ヂ チ */ + 0x30c5, 0x30c4, /* ヅ ツ */ + 0x30c7, 0x30c6, /* デ テ */ + 0x30c9, 0x30c8, /* ド ト */ + 0x30d0, 0x30cf, /* バ ハ */ + 0x30d1, 0x30cf, /* パ ハ */ + 0x30d3, 0x30d2, /* ビ ヒ */ + 0x30d4, 0x30d2, /* ピ ヒ */ + 0x30d6, 0x30d5, /* ブ フ */ + 0x30d7, 0x30d5, /* プ フ */ + 0x30d9, 0x30d8, /* ベ ヘ */ + 0x30da, 0x30d8, /* ペ ヘ */ + 0x30dc, 0x30db, /* ボ ホ */ + 0x30dd, 0x30db, /* ポ ホ */ + 0x30f4, 0x30a6, /* ヴ ウ */ + 0x30f7, 0x30ef, /* ヷ ワ */ + 0x30f8, 0x30f0, /* ヸ ヰ */ + 0x30f9, 0x30f1, /* ヹ ヱ */ + 0x30fa, 0x30f2, /* ヺ ヲ */ + 0x30fe, 0x30fd, /* ヾ ヽ */ + 0xf900, 0x8c48, /* 豈 豈 */ + 0xf901, 0x66f4, /* 更 更 */ + 0xf902, 0x8eca, /* 車 車 */ + 0xf903, 0x8cc8, /* 賈 賈 */ + 0xf904, 0x6ed1, /* 滑 滑 */ + 0xf905, 0x4e32, /* 串 串 */ + 0xf906, 0x53e5, /* 句 句 */ + 0xf907, 0x9f9c, /* 龜 龜 */ + 0xf908, 0x9f9c, /* 龜 龜 */ + 0xf909, 0x5951, /* 契 契 */ + 0xf90a, 0x91d1, /* 金 金 */ + 0xf90b, 0x5587, /* 喇 喇 */ + 0xf90c, 0x5948, /* 奈 奈 */ + 0xf90d, 0x61f6, /* 懶 懶 */ + 0xf90e, 0x7669, /* 癩 癩 */ + 0xf90f, 0x7f85, /* 羅 羅 */ + 0xf910, 0x863f, /* 蘿 蘿 */ + 0xf911, 0x87ba, /* 螺 螺 */ + 0xf912, 0x88f8, /* 裸 裸 */ + 0xf913, 0x908f, /* 邏 邏 */ + 0xf914, 0x6a02, /* 樂 樂 */ + 0xf915, 0x6d1b, /* 洛 洛 */ + 0xf916, 0x70d9, /* 烙 烙 */ + 0xf917, 0x73de, /* 珞 珞 */ + 0xf918, 0x843d, /* 落 落 */ + 0xf919, 0x916a, /* 酪 酪 */ + 0xf91a, 0x99f1, /* 駱 駱 */ + 0xf91b, 0x4e82, /* 亂 亂 */ + 0xf91c, 0x5375, /* 卵 卵 */ + 0xf91d, 0x6b04, /* 欄 欄 */ + 0xf91e, 0x721b, /* 爛 爛 */ + 0xf91f, 0x862d, /* 蘭 蘭 */ + 0xf920, 0x9e1e, /* 鸞 鸞 */ + 0xf921, 0x5d50, /* 嵐 嵐 */ + 0xf922, 0x6feb, /* 濫 濫 */ + 0xf923, 0x85cd, /* 藍 藍 */ + 0xf924, 0x8964, /* 襤 襤 */ + 0xf925, 0x62c9, /* 拉 拉 */ + 0xf926, 0x81d8, /* 臘 臘 */ + 0xf927, 0x881f, /* 蠟 蠟 */ + 0xf928, 0x5eca, /* 廊 廊 */ + 0xf929, 0x6717, /* 朗 朗 */ + 0xf92a, 0x6d6a, /* 浪 浪 */ + 0xf92b, 0x72fc, /* 狼 狼 */ + 0xf92c, 0x90ce, /* 郎 郎 */ + 0xf92d, 0x4f86, /* 來 來 */ + 0xf92e, 0x51b7, /* 冷 冷 */ + 0xf92f, 0x52de, /* 勞 勞 */ + 0xf930, 0x64c4, /* 擄 擄 */ + 0xf931, 0x6ad3, /* 櫓 櫓 */ + 0xf932, 0x7210, /* 爐 爐 */ + 0xf933, 0x76e7, /* 盧 盧 */ + 0xf934, 0x8001, /* 老 老 */ + 0xf935, 0x8606, /* 蘆 蘆 */ + 0xf936, 0x865c, /* 虜 虜 */ + 0xf937, 0x8def, /* 路 路 */ + 0xf938, 0x9732, /* 露 露 */ + 0xf939, 0x9b6f, /* 魯 魯 */ + 0xf93a, 0x9dfa, /* 鷺 鷺 */ + 0xf93b, 0x788c, /* 碌 碌 */ + 0xf93c, 0x797f, /* 祿 祿 */ + 0xf93d, 0x7da0, /* 綠 綠 */ + 0xf93e, 0x83c9, /* 菉 菉 */ + 0xf93f, 0x9304, /* 錄 錄 */ + 0xf940, 0x9e7f, /* 鹿 鹿 */ + 0xf941, 0x8ad6, /* 論 論 */ + 0xf942, 0x58df, /* 壟 壟 */ + 0xf943, 0x5f04, /* 弄 弄 */ + 0xf944, 0x7c60, /* 籠 籠 */ + 0xf945, 0x807e, /* 聾 聾 */ + 0xf946, 0x7262, /* 牢 牢 */ + 0xf947, 0x78ca, /* 磊 磊 */ + 0xf948, 0x8cc2, /* 賂 賂 */ + 0xf949, 0x96f7, /* 雷 雷 */ + 0xf94a, 0x58d8, /* 壘 壘 */ + 0xf94b, 0x5c62, /* 屢 屢 */ + 0xf94c, 0x6a13, /* 樓 樓 */ + 0xf94d, 0x6dda, /* 淚 淚 */ + 0xf94e, 0x6f0f, /* 漏 漏 */ + 0xf94f, 0x7d2f, /* 累 累 */ + 0xf950, 0x7e37, /* 縷 縷 */ + 0xf951, 0x964b, /* 陋 陋 */ + 0xf952, 0x52d2, /* 勒 勒 */ + 0xf953, 0x808b, /* 肋 肋 */ + 0xf954, 0x51dc, /* 凜 凜 */ + 0xf955, 0x51cc, /* 凌 凌 */ + 0xf956, 0x7a1c, /* 稜 稜 */ + 0xf957, 0x7dbe, /* 綾 綾 */ + 0xf958, 0x83f1, /* 菱 菱 */ + 0xf959, 0x9675, /* 陵 陵 */ + 0xf95a, 0x8b80, /* 讀 讀 */ + 0xf95b, 0x62cf, /* 拏 拏 */ + 0xf95c, 0x6a02, /* 樂 樂 */ + 0xf95d, 0x8afe, /* 諾 諾 */ + 0xf95e, 0x4e39, /* 丹 丹 */ + 0xf95f, 0x5be7, /* 寧 寧 */ + 0xf960, 0x6012, /* 怒 怒 */ + 0xf961, 0x7387, /* 率 率 */ + 0xf962, 0x7570, /* 異 異 */ + 0xf963, 0x5317, /* 北 北 */ + 0xf964, 0x78fb, /* 磻 磻 */ + 0xf965, 0x4fbf, /* 便 便 */ + 0xf966, 0x5fa9, /* 復 復 */ + 0xf967, 0x4e0d, /* 不 不 */ + 0xf968, 0x6ccc, /* 泌 泌 */ + 0xf969, 0x6578, /* 數 數 */ + 0xf96a, 0x7d22, /* 索 索 */ + 0xf96b, 0x53c3, /* 參 參 */ + 0xf96c, 0x585e, /* 塞 塞 */ + 0xf96d, 0x7701, /* 省 省 */ + 0xf96e, 0x8449, /* 葉 葉 */ + 0xf96f, 0x8aaa, /* 說 說 */ + 0xf970, 0x6bba, /* 殺 殺 */ + 0xf971, 0x8fb0, /* 辰 辰 */ + 0xf972, 0x6c88, /* 沈 沈 */ + 0xf973, 0x62fe, /* 拾 拾 */ + 0xf974, 0x82e5, /* 若 若 */ + 0xf975, 0x63a0, /* 掠 掠 */ + 0xf976, 0x7565, /* 略 略 */ + 0xf977, 0x4eae, /* 亮 亮 */ + 0xf978, 0x5169, /* 兩 兩 */ + 0xf979, 0x51c9, /* 凉 凉 */ + 0xf97a, 0x6881, /* 梁 梁 */ + 0xf97b, 0x7ce7, /* 糧 糧 */ + 0xf97c, 0x826f, /* 良 良 */ + 0xf97d, 0x8ad2, /* 諒 諒 */ + 0xf97e, 0x91cf, /* 量 量 */ + 0xf97f, 0x52f5, /* 勵 勵 */ + 0xf980, 0x5442, /* 呂 呂 */ + 0xf981, 0x5973, /* 女 女 */ + 0xf982, 0x5eec, /* 廬 廬 */ + 0xf983, 0x65c5, /* 旅 旅 */ + 0xf984, 0x6ffe, /* 濾 濾 */ + 0xf985, 0x792a, /* 礪 礪 */ + 0xf986, 0x95ad, /* 閭 閭 */ + 0xf987, 0x9a6a, /* 驪 驪 */ + 0xf988, 0x9e97, /* 麗 麗 */ + 0xf989, 0x9ece, /* 黎 黎 */ + 0xf98a, 0x529b, /* 力 力 */ + 0xf98b, 0x66c6, /* 曆 曆 */ + 0xf98c, 0x6b77, /* 歷 歷 */ + 0xf98d, 0x8f62, /* 轢 轢 */ + 0xf98e, 0x5e74, /* 年 年 */ + 0xf98f, 0x6190, /* 憐 憐 */ + 0xf990, 0x6200, /* 戀 戀 */ + 0xf991, 0x649a, /* 撚 撚 */ + 0xf992, 0x6f23, /* 漣 漣 */ + 0xf993, 0x7149, /* 煉 煉 */ + 0xf994, 0x7489, /* 璉 璉 */ + 0xf995, 0x79ca, /* 秊 秊 */ + 0xf996, 0x7df4, /* 練 練 */ + 0xf997, 0x806f, /* 聯 聯 */ + 0xf998, 0x8f26, /* 輦 輦 */ + 0xf999, 0x84ee, /* 蓮 蓮 */ + 0xf99a, 0x9023, /* 連 連 */ + 0xf99b, 0x934a, /* 鍊 鍊 */ + 0xf99c, 0x5217, /* 列 列 */ + 0xf99d, 0x52a3, /* 劣 劣 */ + 0xf99e, 0x54bd, /* 咽 咽 */ + 0xf99f, 0x70c8, /* 烈 烈 */ + 0xf9a0, 0x88c2, /* 裂 裂 */ + 0xf9a1, 0x8aaa, /* 說 說 */ + 0xf9a2, 0x5ec9, /* 廉 廉 */ + 0xf9a3, 0x5ff5, /* 念 念 */ + 0xf9a4, 0x637b, /* 捻 捻 */ + 0xf9a5, 0x6bae, /* 殮 殮 */ + 0xf9a6, 0x7c3e, /* 簾 簾 */ + 0xf9a7, 0x7375, /* 獵 獵 */ + 0xf9a8, 0x4ee4, /* 令 令 */ + 0xf9a9, 0x56f9, /* 囹 囹 */ + 0xf9aa, 0x5be7, /* 寧 寧 */ + 0xf9ab, 0x5dba, /* 嶺 嶺 */ + 0xf9ac, 0x601c, /* 怜 怜 */ + 0xf9ad, 0x73b2, /* 玲 玲 */ + 0xf9ae, 0x7469, /* 瑩 瑩 */ + 0xf9af, 0x7f9a, /* 羚 羚 */ + 0xf9b0, 0x8046, /* 聆 聆 */ + 0xf9b1, 0x9234, /* 鈴 鈴 */ + 0xf9b2, 0x96f6, /* 零 零 */ + 0xf9b3, 0x9748, /* 靈 靈 */ + 0xf9b4, 0x9818, /* 領 領 */ + 0xf9b5, 0x4f8b, /* 例 例 */ + 0xf9b6, 0x79ae, /* 禮 禮 */ + 0xf9b7, 0x91b4, /* 醴 醴 */ + 0xf9b8, 0x96b8, /* 隸 隸 */ + 0xf9b9, 0x60e1, /* 惡 惡 */ + 0xf9ba, 0x4e86, /* 了 了 */ + 0xf9bb, 0x50da, /* 僚 僚 */ + 0xf9bc, 0x5bee, /* 寮 寮 */ + 0xf9bd, 0x5c3f, /* 尿 尿 */ + 0xf9be, 0x6599, /* 料 料 */ + 0xf9bf, 0x6a02, /* 樂 樂 */ + 0xf9c0, 0x71ce, /* 燎 燎 */ + 0xf9c1, 0x7642, /* 療 療 */ + 0xf9c2, 0x84fc, /* 蓼 蓼 */ + 0xf9c3, 0x907c, /* 遼 遼 */ + 0xf9c4, 0x9f8d, /* 龍 龍 */ + 0xf9c5, 0x6688, /* 暈 暈 */ + 0xf9c6, 0x962e, /* 阮 阮 */ + 0xf9c7, 0x5289, /* 劉 劉 */ + 0xf9c8, 0x677b, /* 杻 杻 */ + 0xf9c9, 0x67f3, /* 柳 柳 */ + 0xf9ca, 0x6d41, /* 流 流 */ + 0xf9cb, 0x6e9c, /* 溜 溜 */ + 0xf9cc, 0x7409, /* 琉 琉 */ + 0xf9cd, 0x7559, /* 留 留 */ + 0xf9ce, 0x786b, /* 硫 硫 */ + 0xf9cf, 0x7d10, /* 紐 紐 */ + 0xf9d0, 0x985e, /* 類 類 */ + 0xf9d1, 0x516d, /* 六 六 */ + 0xf9d2, 0x622e, /* 戮 戮 */ + 0xf9d3, 0x9678, /* 陸 陸 */ + 0xf9d4, 0x502b, /* 倫 倫 */ + 0xf9d5, 0x5d19, /* 崙 崙 */ + 0xf9d6, 0x6dea, /* 淪 淪 */ + 0xf9d7, 0x8f2a, /* 輪 輪 */ + 0xf9d8, 0x5f8b, /* 律 律 */ + 0xf9d9, 0x6144, /* 慄 慄 */ + 0xf9da, 0x6817, /* 栗 栗 */ + 0xf9db, 0x7387, /* 率 率 */ + 0xf9dc, 0x9686, /* 隆 隆 */ + 0xf9dd, 0x5229, /* 利 利 */ + 0xf9de, 0x540f, /* 吏 吏 */ + 0xf9df, 0x5c65, /* 履 履 */ + 0xf9e0, 0x6613, /* 易 易 */ + 0xf9e1, 0x674e, /* 李 李 */ + 0xf9e2, 0x68a8, /* 梨 梨 */ + 0xf9e3, 0x6ce5, /* 泥 泥 */ + 0xf9e4, 0x7406, /* 理 理 */ + 0xf9e5, 0x75e2, /* 痢 痢 */ + 0xf9e6, 0x7f79, /* 罹 罹 */ + 0xf9e7, 0x88cf, /* 裏 裏 */ + 0xf9e8, 0x88e1, /* 裡 裡 */ + 0xf9e9, 0x91cc, /* 里 里 */ + 0xf9ea, 0x96e2, /* 離 離 */ + 0xf9eb, 0x533f, /* 匿 匿 */ + 0xf9ec, 0x6eba, /* 溺 溺 */ + 0xf9ed, 0x541d, /* 吝 吝 */ + 0xf9ee, 0x71d0, /* 燐 燐 */ + 0xf9ef, 0x7498, /* 璘 璘 */ + 0xf9f0, 0x85fa, /* 藺 藺 */ + 0xf9f1, 0x96a3, /* 隣 隣 */ + 0xf9f2, 0x9c57, /* 鱗 鱗 */ + 0xf9f3, 0x9e9f, /* 麟 麟 */ + 0xf9f4, 0x6797, /* 林 林 */ + 0xf9f5, 0x6dcb, /* 淋 淋 */ + 0xf9f6, 0x81e8, /* 臨 臨 */ + 0xf9f7, 0x7acb, /* 立 立 */ + 0xf9f8, 0x7b20, /* 笠 笠 */ + 0xf9f9, 0x7c92, /* 粒 粒 */ + 0xf9fa, 0x72c0, /* 狀 狀 */ + 0xf9fb, 0x7099, /* 炙 炙 */ + 0xf9fc, 0x8b58, /* 識 識 */ + 0xf9fd, 0x4ec0, /* 什 什 */ + 0xf9fe, 0x8336, /* 茶 茶 */ + 0xf9ff, 0x523a, /* 刺 刺 */ + 0xfa00, 0x5207, /* 切 切 */ + 0xfa01, 0x5ea6, /* 度 度 */ + 0xfa02, 0x62d3, /* 拓 拓 */ + 0xfa03, 0x7cd6, /* 糖 糖 */ + 0xfa04, 0x5b85, /* 宅 宅 */ + 0xfa05, 0x6d1e, /* 洞 洞 */ + 0xfa06, 0x66b4, /* 暴 暴 */ + 0xfa07, 0x8f3b, /* 輻 輻 */ + 0xfa08, 0x884c, /* 行 行 */ + 0xfa09, 0x964d, /* 降 降 */ + 0xfa0a, 0x898b, /* 見 見 */ + 0xfa0b, 0x5ed3, /* 廓 廓 */ + 0xfa0c, 0x5140, /* 兀 兀 */ + 0xfa0d, 0x55c0, /* 嗀 嗀 */ + 0xfa10, 0x585a, /* 塚 塚 */ + 0xfa12, 0x6674, /* 晴 晴 */ + 0xfa15, 0x51de, /* 凞 凞 */ + 0xfa16, 0x732a, /* 猪 猪 */ + 0xfa17, 0x76ca, /* 益 益 */ + 0xfa18, 0x793c, /* 礼 礼 */ + 0xfa19, 0x795e, /* 神 神 */ + 0xfa1a, 0x7965, /* 祥 祥 */ + 0xfa1b, 0x798f, /* 福 福 */ + 0xfa1c, 0x9756, /* 靖 靖 */ + 0xfa1d, 0x7cbe, /* 精 精 */ + 0xfa1e, 0x7fbd, /* 羽 羽 */ + 0xfa20, 0x8612, /* 蘒 蘒 */ + 0xfa22, 0x8af8, /* 諸 諸 */ + 0xfa25, 0x9038, /* 逸 逸 */ + 0xfa26, 0x90fd, /* 都 都 */ + 0xfa2a, 0x98ef, /* 飯 飯 */ + 0xfa2b, 0x98fc, /* 飼 飼 */ + 0xfa2c, 0x9928, /* 館 館 */ + 0xfa2d, 0x9db4, /* 鶴 鶴 */ + 0xfa2e, 0x90de, /* 郞 郞 */ + 0xfa2f, 0x96b7, /* 隷 隷 */ + 0xfa30, 0x4fae, /* 侮 侮 */ + 0xfa31, 0x50e7, /* 僧 僧 */ + 0xfa32, 0x514d, /* 免 免 */ + 0xfa33, 0x52c9, /* 勉 勉 */ + 0xfa34, 0x52e4, /* 勤 勤 */ + 0xfa35, 0x5351, /* 卑 卑 */ + 0xfa36, 0x559d, /* 喝 喝 */ + 0xfa37, 0x5606, /* 嘆 嘆 */ + 0xfa38, 0x5668, /* 器 器 */ + 0xfa39, 0x5840, /* 塀 塀 */ + 0xfa3a, 0x58a8, /* 墨 墨 */ + 0xfa3b, 0x5c64, /* 層 層 */ + 0xfa3c, 0x5c6e, /* 屮 屮 */ + 0xfa3d, 0x6094, /* 悔 悔 */ + 0xfa3e, 0x6168, /* 慨 慨 */ + 0xfa3f, 0x618e, /* 憎 憎 */ + 0xfa40, 0x61f2, /* 懲 懲 */ + 0xfa41, 0x654f, /* 敏 敏 */ + 0xfa42, 0x65e2, /* 既 既 */ + 0xfa43, 0x6691, /* 暑 暑 */ + 0xfa44, 0x6885, /* 梅 梅 */ + 0xfa45, 0x6d77, /* 海 海 */ + 0xfa46, 0x6e1a, /* 渚 渚 */ + 0xfa47, 0x6f22, /* 漢 漢 */ + 0xfa48, 0x716e, /* 煮 煮 */ + 0xfa49, 0x722b, /* 爫 爫 */ + 0xfa4a, 0x7422, /* 琢 琢 */ + 0xfa4b, 0x7891, /* 碑 碑 */ + 0xfa4c, 0x793e, /* 社 社 */ + 0xfa4d, 0x7949, /* 祉 祉 */ + 0xfa4e, 0x7948, /* 祈 祈 */ + 0xfa4f, 0x7950, /* 祐 祐 */ + 0xfa50, 0x7956, /* 祖 祖 */ + 0xfa51, 0x795d, /* 祝 祝 */ + 0xfa52, 0x798d, /* 禍 禍 */ + 0xfa53, 0x798e, /* 禎 禎 */ + 0xfa54, 0x7a40, /* 穀 穀 */ + 0xfa55, 0x7a81, /* 突 突 */ + 0xfa56, 0x7bc0, /* 節 節 */ + 0xfa57, 0x7df4, /* 練 練 */ + 0xfa58, 0x7e09, /* 縉 縉 */ + 0xfa59, 0x7e41, /* 繁 繁 */ + 0xfa5a, 0x7f72, /* 署 署 */ + 0xfa5b, 0x8005, /* 者 者 */ + 0xfa5c, 0x81ed, /* 臭 臭 */ + 0xfa5d, 0x8279, /* 艹 艹 */ + 0xfa5e, 0x8279, /* 艹 艹 */ + 0xfa5f, 0x8457, /* 著 著 */ + 0xfa60, 0x8910, /* 褐 褐 */ + 0xfa61, 0x8996, /* 視 視 */ + 0xfa62, 0x8b01, /* 謁 謁 */ + 0xfa63, 0x8b39, /* 謹 謹 */ + 0xfa64, 0x8cd3, /* 賓 賓 */ + 0xfa65, 0x8d08, /* 贈 贈 */ + 0xfa66, 0x8fb6, /* 辶 辶 */ + 0xfa67, 0x9038, /* 逸 逸 */ + 0xfa68, 0x96e3, /* 難 難 */ + 0xfa69, 0x97ff, /* 響 響 */ + 0xfa6a, 0x983b, /* 頻 頻 */ + 0xfa6b, 0x6075, /* 恵 恵 */ + 0xfa6c, 0x242ee, /* 𤋮 𤋮 */ + 0xfa6d, 0x8218, /* 舘 舘 */ + 0xfa70, 0x4e26, /* 並 並 */ + 0xfa71, 0x51b5, /* 况 况 */ + 0xfa72, 0x5168, /* 全 全 */ + 0xfa73, 0x4f80, /* 侀 侀 */ + 0xfa74, 0x5145, /* 充 充 */ + 0xfa75, 0x5180, /* 冀 冀 */ + 0xfa76, 0x52c7, /* 勇 勇 */ + 0xfa77, 0x52fa, /* 勺 勺 */ + 0xfa78, 0x559d, /* 喝 喝 */ + 0xfa79, 0x5555, /* 啕 啕 */ + 0xfa7a, 0x5599, /* 喙 喙 */ + 0xfa7b, 0x55e2, /* 嗢 嗢 */ + 0xfa7c, 0x585a, /* 塚 塚 */ + 0xfa7d, 0x58b3, /* 墳 墳 */ + 0xfa7e, 0x5944, /* 奄 奄 */ + 0xfa7f, 0x5954, /* 奔 奔 */ + 0xfa80, 0x5a62, /* 婢 婢 */ + 0xfa81, 0x5b28, /* 嬨 嬨 */ + 0xfa82, 0x5ed2, /* 廒 廒 */ + 0xfa83, 0x5ed9, /* 廙 廙 */ + 0xfa84, 0x5f69, /* 彩 彩 */ + 0xfa85, 0x5fad, /* 徭 徭 */ + 0xfa86, 0x60d8, /* 惘 惘 */ + 0xfa87, 0x614e, /* 慎 慎 */ + 0xfa88, 0x6108, /* 愈 愈 */ + 0xfa89, 0x618e, /* 憎 憎 */ + 0xfa8a, 0x6160, /* 慠 慠 */ + 0xfa8b, 0x61f2, /* 懲 懲 */ + 0xfa8c, 0x6234, /* 戴 戴 */ + 0xfa8d, 0x63c4, /* 揄 揄 */ + 0xfa8e, 0x641c, /* 搜 搜 */ + 0xfa8f, 0x6452, /* 摒 摒 */ + 0xfa90, 0x6556, /* 敖 敖 */ + 0xfa91, 0x6674, /* 晴 晴 */ + 0xfa92, 0x6717, /* 朗 朗 */ + 0xfa93, 0x671b, /* 望 望 */ + 0xfa94, 0x6756, /* 杖 杖 */ + 0xfa95, 0x6b79, /* 歹 歹 */ + 0xfa96, 0x6bba, /* 殺 殺 */ + 0xfa97, 0x6d41, /* 流 流 */ + 0xfa98, 0x6edb, /* 滛 滛 */ + 0xfa99, 0x6ecb, /* 滋 滋 */ + 0xfa9a, 0x6f22, /* 漢 漢 */ + 0xfa9b, 0x701e, /* 瀞 瀞 */ + 0xfa9c, 0x716e, /* 煮 煮 */ + 0xfa9d, 0x77a7, /* 瞧 瞧 */ + 0xfa9e, 0x7235, /* 爵 爵 */ + 0xfa9f, 0x72af, /* 犯 犯 */ + 0xfaa0, 0x732a, /* 猪 猪 */ + 0xfaa1, 0x7471, /* 瑱 瑱 */ + 0xfaa2, 0x7506, /* 甆 甆 */ + 0xfaa3, 0x753b, /* 画 画 */ + 0xfaa4, 0x761d, /* 瘝 瘝 */ + 0xfaa5, 0x761f, /* 瘟 瘟 */ + 0xfaa6, 0x76ca, /* 益 益 */ + 0xfaa7, 0x76db, /* 盛 盛 */ + 0xfaa8, 0x76f4, /* 直 直 */ + 0xfaa9, 0x774a, /* 睊 睊 */ + 0xfaaa, 0x7740, /* 着 着 */ + 0xfaab, 0x78cc, /* 磌 磌 */ + 0xfaac, 0x7ab1, /* 窱 窱 */ + 0xfaad, 0x7bc0, /* 節 節 */ + 0xfaae, 0x7c7b, /* 类 类 */ + 0xfaaf, 0x7d5b, /* 絛 絛 */ + 0xfab0, 0x7df4, /* 練 練 */ + 0xfab1, 0x7f3e, /* 缾 缾 */ + 0xfab2, 0x8005, /* 者 者 */ + 0xfab3, 0x8352, /* 荒 荒 */ + 0xfab4, 0x83ef, /* 華 華 */ + 0xfab5, 0x8779, /* 蝹 蝹 */ + 0xfab6, 0x8941, /* 襁 襁 */ + 0xfab7, 0x8986, /* 覆 覆 */ + 0xfab8, 0x8996, /* 視 視 */ + 0xfab9, 0x8abf, /* 調 調 */ + 0xfaba, 0x8af8, /* 諸 諸 */ + 0xfabb, 0x8acb, /* 請 請 */ + 0xfabc, 0x8b01, /* 謁 謁 */ + 0xfabd, 0x8afe, /* 諾 諾 */ + 0xfabe, 0x8aed, /* 諭 諭 */ + 0xfabf, 0x8b39, /* 謹 謹 */ + 0xfac0, 0x8b8a, /* 變 變 */ + 0xfac1, 0x8d08, /* 贈 贈 */ + 0xfac2, 0x8f38, /* 輸 輸 */ + 0xfac3, 0x9072, /* 遲 遲 */ + 0xfac4, 0x9199, /* 醙 醙 */ + 0xfac5, 0x9276, /* 鉶 鉶 */ + 0xfac6, 0x967c, /* 陼 陼 */ + 0xfac7, 0x96e3, /* 難 難 */ + 0xfac8, 0x9756, /* 靖 靖 */ + 0xfac9, 0x97db, /* 韛 韛 */ + 0xfaca, 0x97ff, /* 響 響 */ + 0xfacb, 0x980b, /* 頋 頋 */ + 0xfacc, 0x983b, /* 頻 頻 */ + 0xfacd, 0x9b12, /* 鬒 鬒 */ + 0xface, 0x9f9c, /* 龜 龜 */ + 0xfacf, 0x2284a, /* 𢡊 𢡊 */ + 0xfad0, 0x22844, /* 𢡄 𢡄 */ + 0xfad1, 0x233d5, /* 𣏕 𣏕 */ + 0xfad2, 0x3b9d, /* 㮝 㮝 */ + 0xfad3, 0x4018, /* 䀘 䀘 */ + 0xfad4, 0x4039, /* 䀹 䀹 */ + 0xfad5, 0x25249, /* 𥉉 𥉉 */ + 0xfad6, 0x25cd0, /* 𥳐 𥳐 */ + 0xfad7, 0x27ed3, /* 𧻓 𧻓 */ + 0xfad8, 0x9f43, /* 齃 齃 */ + 0xfad9, 0x9f8e, /* 龎 龎 */ + 0xfb1d, 0x05d9, /* יִ י */ + 0xfb1f, 0x05f2, /* ײַ ײ */ + 0xfb2a, 0x05e9, /* שׁ ש */ + 0xfb2b, 0x05e9, /* שׂ ש */ + 0xfb2c, 0x05e9, /* שּׁ ש */ + 0xfb2d, 0x05e9, /* שּׂ ש */ + 0xfb2e, 0x05d0, /* אַ א */ + 0xfb2f, 0x05d0, /* אָ א */ + 0xfb30, 0x05d0, /* אּ א */ + 0xfb31, 0x05d1, /* בּ ב */ + 0xfb32, 0x05d2, /* גּ ג */ + 0xfb33, 0x05d3, /* דּ ד */ + 0xfb34, 0x05d4, /* הּ ה */ + 0xfb35, 0x05d5, /* וּ ו */ + 0xfb36, 0x05d6, /* זּ ז */ + 0xfb38, 0x05d8, /* טּ ט */ + 0xfb39, 0x05d9, /* יּ י */ + 0xfb3a, 0x05da, /* ךּ ך */ + 0xfb3b, 0x05db, /* כּ כ */ + 0xfb3c, 0x05dc, /* לּ ל */ + 0xfb3e, 0x05de, /* מּ מ */ + 0xfb40, 0x05e0, /* נּ נ */ + 0xfb41, 0x05e1, /* סּ ס */ + 0xfb43, 0x05e3, /* ףּ ף */ + 0xfb44, 0x05e4, /* פּ פ */ + 0xfb46, 0x05e6, /* צּ צ */ + 0xfb47, 0x05e7, /* קּ ק */ + 0xfb48, 0x05e8, /* רּ ר */ + 0xfb49, 0x05e9, /* שּ ש */ + 0xfb4a, 0x05ea, /* תּ ת */ + 0xfb4b, 0x05d5, /* וֹ ו */ + 0xfb4c, 0x05d1, /* בֿ ב */ + 0xfb4d, 0x05db, /* כֿ כ */ + 0xfb4e, 0x05e4, /* פֿ פ */ + 0x1109a, 0x11099, /* 𑂚 𑂙 */ + 0x1109c, 0x1109b, /* 𑂜 𑂛 */ + 0x110ab, 0x110a5, /* 𑂫 𑂥 */ + 0x2f800, 0x4e3d, /* 丽 丽 */ + 0x2f801, 0x4e38, /* 丸 丸 */ + 0x2f802, 0x4e41, /* 乁 乁 */ + 0x2f803, 0x20122, /* 𠄢 𠄢 */ + 0x2f804, 0x4f60, /* 你 你 */ + 0x2f805, 0x4fae, /* 侮 侮 */ + 0x2f806, 0x4fbb, /* 侻 侻 */ + 0x2f807, 0x5002, /* 倂 倂 */ + 0x2f808, 0x507a, /* 偺 偺 */ + 0x2f809, 0x5099, /* 備 備 */ + 0x2f80a, 0x50e7, /* 僧 僧 */ + 0x2f80b, 0x50cf, /* 像 像 */ + 0x2f80c, 0x349e, /* 㒞 㒞 */ + 0x2f80d, 0x2063a, /* 𠘺 𠘺 */ + 0x2f80e, 0x514d, /* 免 免 */ + 0x2f80f, 0x5154, /* 兔 兔 */ + 0x2f810, 0x5164, /* 兤 兤 */ + 0x2f811, 0x5177, /* 具 具 */ + 0x2f812, 0x2051c, /* 𠔜 𠔜 */ + 0x2f813, 0x34b9, /* 㒹 㒹 */ + 0x2f814, 0x5167, /* 內 內 */ + 0x2f815, 0x518d, /* 再 再 */ + 0x2f816, 0x2054b, /* 𠕋 𠕋 */ + 0x2f817, 0x5197, /* 冗 冗 */ + 0x2f818, 0x51a4, /* 冤 冤 */ + 0x2f819, 0x4ecc, /* 仌 仌 */ + 0x2f81a, 0x51ac, /* 冬 冬 */ + 0x2f81b, 0x51b5, /* 况 况 */ + 0x2f81c, 0x291df, /* 𩇟 𩇟 */ + 0x2f81d, 0x51f5, /* 凵 凵 */ + 0x2f81e, 0x5203, /* 刃 刃 */ + 0x2f81f, 0x34df, /* 㓟 㓟 */ + 0x2f820, 0x523b, /* 刻 刻 */ + 0x2f821, 0x5246, /* 剆 剆 */ + 0x2f822, 0x5272, /* 割 割 */ + 0x2f823, 0x5277, /* 剷 剷 */ + 0x2f824, 0x3515, /* 㔕 㔕 */ + 0x2f825, 0x52c7, /* 勇 勇 */ + 0x2f826, 0x52c9, /* 勉 勉 */ + 0x2f827, 0x52e4, /* 勤 勤 */ + 0x2f828, 0x52fa, /* 勺 勺 */ + 0x2f829, 0x5305, /* 包 包 */ + 0x2f82a, 0x5306, /* 匆 匆 */ + 0x2f82b, 0x5317, /* 北 北 */ + 0x2f82c, 0x5349, /* 卉 卉 */ + 0x2f82d, 0x5351, /* 卑 卑 */ + 0x2f82e, 0x535a, /* 博 博 */ + 0x2f82f, 0x5373, /* 即 即 */ + 0x2f830, 0x537d, /* 卽 卽 */ + 0x2f831, 0x537f, /* 卿 卿 */ + 0x2f832, 0x537f, /* 卿 卿 */ + 0x2f833, 0x537f, /* 卿 卿 */ + 0x2f834, 0x20a2c, /* 𠨬 𠨬 */ + 0x2f835, 0x7070, /* 灰 灰 */ + 0x2f836, 0x53ca, /* 及 及 */ + 0x2f837, 0x53df, /* 叟 叟 */ + 0x2f838, 0x20b63, /* 𠭣 𠭣 */ + 0x2f839, 0x53eb, /* 叫 叫 */ + 0x2f83a, 0x53f1, /* 叱 叱 */ + 0x2f83b, 0x5406, /* 吆 吆 */ + 0x2f83c, 0x549e, /* 咞 咞 */ + 0x2f83d, 0x5438, /* 吸 吸 */ + 0x2f83e, 0x5448, /* 呈 呈 */ + 0x2f83f, 0x5468, /* 周 周 */ + 0x2f840, 0x54a2, /* 咢 咢 */ + 0x2f841, 0x54f6, /* 哶 哶 */ + 0x2f842, 0x5510, /* 唐 唐 */ + 0x2f843, 0x5553, /* 啓 啓 */ + 0x2f844, 0x5563, /* 啣 啣 */ + 0x2f845, 0x5584, /* 善 善 */ + 0x2f846, 0x5584, /* 善 善 */ + 0x2f847, 0x5599, /* 喙 喙 */ + 0x2f848, 0x55ab, /* 喫 喫 */ + 0x2f849, 0x55b3, /* 喳 喳 */ + 0x2f84a, 0x55c2, /* 嗂 嗂 */ + 0x2f84b, 0x5716, /* 圖 圖 */ + 0x2f84c, 0x5606, /* 嘆 嘆 */ + 0x2f84d, 0x5717, /* 圗 圗 */ + 0x2f84e, 0x5651, /* 噑 噑 */ + 0x2f84f, 0x5674, /* 噴 噴 */ + 0x2f850, 0x5207, /* 切 切 */ + 0x2f851, 0x58ee, /* 壮 壮 */ + 0x2f852, 0x57ce, /* 城 城 */ + 0x2f853, 0x57f4, /* 埴 埴 */ + 0x2f854, 0x580d, /* 堍 堍 */ + 0x2f855, 0x578b, /* 型 型 */ + 0x2f856, 0x5832, /* 堲 堲 */ + 0x2f857, 0x5831, /* 報 報 */ + 0x2f858, 0x58ac, /* 墬 墬 */ + 0x2f859, 0x214e4, /* 𡓤 𡓤 */ + 0x2f85a, 0x58f2, /* 売 売 */ + 0x2f85b, 0x58f7, /* 壷 壷 */ + 0x2f85c, 0x5906, /* 夆 夆 */ + 0x2f85d, 0x591a, /* 多 多 */ + 0x2f85e, 0x5922, /* 夢 夢 */ + 0x2f85f, 0x5962, /* 奢 奢 */ + 0x2f860, 0x216a8, /* 𡚨 𡚨 */ + 0x2f861, 0x216ea, /* 𡛪 𡛪 */ + 0x2f862, 0x59ec, /* 姬 姬 */ + 0x2f863, 0x5a1b, /* 娛 娛 */ + 0x2f864, 0x5a27, /* 娧 娧 */ + 0x2f865, 0x59d8, /* 姘 姘 */ + 0x2f866, 0x5a66, /* 婦 婦 */ + 0x2f867, 0x36ee, /* 㛮 㛮 */ + 0x2f868, 0x36fc, /* 㛼 㛼 */ + 0x2f869, 0x5b08, /* 嬈 嬈 */ + 0x2f86a, 0x5b3e, /* 嬾 嬾 */ + 0x2f86b, 0x5b3e, /* 嬾 嬾 */ + 0x2f86c, 0x219c8, /* 𡧈 𡧈 */ + 0x2f86d, 0x5bc3, /* 寃 寃 */ + 0x2f86e, 0x5bd8, /* 寘 寘 */ + 0x2f86f, 0x5be7, /* 寧 寧 */ + 0x2f870, 0x5bf3, /* 寳 寳 */ + 0x2f871, 0x21b18, /* 𡬘 𡬘 */ + 0x2f872, 0x5bff, /* 寿 寿 */ + 0x2f873, 0x5c06, /* 将 将 */ + 0x2f874, 0x5f53, /* 当 当 */ + 0x2f875, 0x5c22, /* 尢 尢 */ + 0x2f876, 0x3781, /* 㞁 㞁 */ + 0x2f877, 0x5c60, /* 屠 屠 */ + 0x2f878, 0x5c6e, /* 屮 屮 */ + 0x2f879, 0x5cc0, /* 峀 峀 */ + 0x2f87a, 0x5c8d, /* 岍 岍 */ + 0x2f87b, 0x21de4, /* 𡷤 𡷤 */ + 0x2f87c, 0x5d43, /* 嵃 嵃 */ + 0x2f87d, 0x21de6, /* 𡷦 𡷦 */ + 0x2f87e, 0x5d6e, /* 嵮 嵮 */ + 0x2f87f, 0x5d6b, /* 嵫 嵫 */ + 0x2f880, 0x5d7c, /* 嵼 嵼 */ + 0x2f881, 0x5de1, /* 巡 巡 */ + 0x2f882, 0x5de2, /* 巢 巢 */ + 0x2f883, 0x382f, /* 㠯 㠯 */ + 0x2f884, 0x5dfd, /* 巽 巽 */ + 0x2f885, 0x5e28, /* 帨 帨 */ + 0x2f886, 0x5e3d, /* 帽 帽 */ + 0x2f887, 0x5e69, /* 幩 幩 */ + 0x2f888, 0x3862, /* 㡢 㡢 */ + 0x2f889, 0x22183, /* 𢆃 𢆃 */ + 0x2f88a, 0x387c, /* 㡼 㡼 */ + 0x2f88b, 0x5eb0, /* 庰 庰 */ + 0x2f88c, 0x5eb3, /* 庳 庳 */ + 0x2f88d, 0x5eb6, /* 庶 庶 */ + 0x2f88e, 0x5eca, /* 廊 廊 */ + 0x2f88f, 0x2a392, /* 𪎒 𪎒 */ + 0x2f890, 0x5efe, /* 廾 廾 */ + 0x2f891, 0x22331, /* 𢌱 𢌱 */ + 0x2f892, 0x22331, /* 𢌱 𢌱 */ + 0x2f893, 0x8201, /* 舁 舁 */ + 0x2f894, 0x5f22, /* 弢 弢 */ + 0x2f895, 0x5f22, /* 弢 弢 */ + 0x2f896, 0x38c7, /* 㣇 㣇 */ + 0x2f897, 0x232b8, /* 𣊸 𣊸 */ + 0x2f898, 0x261da, /* 𦇚 𦇚 */ + 0x2f899, 0x5f62, /* 形 形 */ + 0x2f89a, 0x5f6b, /* 彫 彫 */ + 0x2f89b, 0x38e3, /* 㣣 㣣 */ + 0x2f89c, 0x5f9a, /* 徚 徚 */ + 0x2f89d, 0x5fcd, /* 忍 忍 */ + 0x2f89e, 0x5fd7, /* 志 志 */ + 0x2f89f, 0x5ff9, /* 忹 忹 */ + 0x2f8a0, 0x6081, /* 悁 悁 */ + 0x2f8a1, 0x393a, /* 㤺 㤺 */ + 0x2f8a2, 0x391c, /* 㤜 㤜 */ + 0x2f8a3, 0x6094, /* 悔 悔 */ + 0x2f8a4, 0x226d4, /* 𢛔 𢛔 */ + 0x2f8a5, 0x60c7, /* 惇 惇 */ + 0x2f8a6, 0x6148, /* 慈 慈 */ + 0x2f8a7, 0x614c, /* 慌 慌 */ + 0x2f8a8, 0x614e, /* 慎 慎 */ + 0x2f8a9, 0x614c, /* 慌 慌 */ + 0x2f8aa, 0x617a, /* 慺 慺 */ + 0x2f8ab, 0x618e, /* 憎 憎 */ + 0x2f8ac, 0x61b2, /* 憲 憲 */ + 0x2f8ad, 0x61a4, /* 憤 憤 */ + 0x2f8ae, 0x61af, /* 憯 憯 */ + 0x2f8af, 0x61de, /* 懞 懞 */ + 0x2f8b0, 0x61f2, /* 懲 懲 */ + 0x2f8b1, 0x61f6, /* 懶 懶 */ + 0x2f8b2, 0x6210, /* 成 成 */ + 0x2f8b3, 0x621b, /* 戛 戛 */ + 0x2f8b4, 0x625d, /* 扝 扝 */ + 0x2f8b5, 0x62b1, /* 抱 抱 */ + 0x2f8b6, 0x62d4, /* 拔 拔 */ + 0x2f8b7, 0x6350, /* 捐 捐 */ + 0x2f8b8, 0x22b0c, /* 𢬌 𢬌 */ + 0x2f8b9, 0x633d, /* 挽 挽 */ + 0x2f8ba, 0x62fc, /* 拼 拼 */ + 0x2f8bb, 0x6368, /* 捨 捨 */ + 0x2f8bc, 0x6383, /* 掃 掃 */ + 0x2f8bd, 0x63e4, /* 揤 揤 */ + 0x2f8be, 0x22bf1, /* 𢯱 𢯱 */ + 0x2f8bf, 0x6422, /* 搢 搢 */ + 0x2f8c0, 0x63c5, /* 揅 揅 */ + 0x2f8c1, 0x63a9, /* 掩 掩 */ + 0x2f8c2, 0x3a2e, /* 㨮 㨮 */ + 0x2f8c3, 0x6469, /* 摩 摩 */ + 0x2f8c4, 0x647e, /* 摾 摾 */ + 0x2f8c5, 0x649d, /* 撝 撝 */ + 0x2f8c6, 0x6477, /* 摷 摷 */ + 0x2f8c7, 0x3a6c, /* 㩬 㩬 */ + 0x2f8c8, 0x654f, /* 敏 敏 */ + 0x2f8c9, 0x656c, /* 敬 敬 */ + 0x2f8ca, 0x2300a, /* 𣀊 𣀊 */ + 0x2f8cb, 0x65e3, /* 旣 旣 */ + 0x2f8cc, 0x66f8, /* 書 書 */ + 0x2f8cd, 0x6649, /* 晉 晉 */ + 0x2f8ce, 0x3b19, /* 㬙 㬙 */ + 0x2f8cf, 0x6691, /* 暑 暑 */ + 0x2f8d0, 0x3b08, /* 㬈 㬈 */ + 0x2f8d1, 0x3ae4, /* 㫤 㫤 */ + 0x2f8d2, 0x5192, /* 冒 冒 */ + 0x2f8d3, 0x5195, /* 冕 冕 */ + 0x2f8d4, 0x6700, /* 最 最 */ + 0x2f8d5, 0x669c, /* 暜 暜 */ + 0x2f8d6, 0x80ad, /* 肭 肭 */ + 0x2f8d7, 0x43d9, /* 䏙 䏙 */ + 0x2f8d8, 0x6717, /* 朗 朗 */ + 0x2f8d9, 0x671b, /* 望 望 */ + 0x2f8da, 0x6721, /* 朡 朡 */ + 0x2f8db, 0x675e, /* 杞 杞 */ + 0x2f8dc, 0x6753, /* 杓 杓 */ + 0x2f8dd, 0x233c3, /* 𣏃 𣏃 */ + 0x2f8de, 0x3b49, /* 㭉 㭉 */ + 0x2f8df, 0x67fa, /* 柺 柺 */ + 0x2f8e0, 0x6785, /* 枅 枅 */ + 0x2f8e1, 0x6852, /* 桒 桒 */ + 0x2f8e2, 0x6885, /* 梅 梅 */ + 0x2f8e3, 0x2346d, /* 𣑭 𣑭 */ + 0x2f8e4, 0x688e, /* 梎 梎 */ + 0x2f8e5, 0x681f, /* 栟 栟 */ + 0x2f8e6, 0x6914, /* 椔 椔 */ + 0x2f8e7, 0x3b9d, /* 㮝 㮝 */ + 0x2f8e8, 0x6942, /* 楂 楂 */ + 0x2f8e9, 0x69a3, /* 榣 榣 */ + 0x2f8ea, 0x69ea, /* 槪 槪 */ + 0x2f8eb, 0x6aa8, /* 檨 檨 */ + 0x2f8ec, 0x236a3, /* 𣚣 𣚣 */ + 0x2f8ed, 0x6adb, /* 櫛 櫛 */ + 0x2f8ee, 0x3c18, /* 㰘 㰘 */ + 0x2f8ef, 0x6b21, /* 次 次 */ + 0x2f8f0, 0x238a7, /* 𣢧 𣢧 */ + 0x2f8f1, 0x6b54, /* 歔 歔 */ + 0x2f8f2, 0x3c4e, /* 㱎 㱎 */ + 0x2f8f3, 0x6b72, /* 歲 歲 */ + 0x2f8f4, 0x6b9f, /* 殟 殟 */ + 0x2f8f5, 0x6bba, /* 殺 殺 */ + 0x2f8f6, 0x6bbb, /* 殻 殻 */ + 0x2f8f7, 0x23a8d, /* 𣪍 𣪍 */ + 0x2f8f8, 0x21d0b, /* 𡴋 𡴋 */ + 0x2f8f9, 0x23afa, /* 𣫺 𣫺 */ + 0x2f8fa, 0x6c4e, /* 汎 汎 */ + 0x2f8fb, 0x23cbc, /* 𣲼 𣲼 */ + 0x2f8fc, 0x6cbf, /* 沿 沿 */ + 0x2f8fd, 0x6ccd, /* 泍 泍 */ + 0x2f8fe, 0x6c67, /* 汧 汧 */ + 0x2f8ff, 0x6d16, /* 洖 洖 */ + 0x2f900, 0x6d3e, /* 派 派 */ + 0x2f901, 0x6d77, /* 海 海 */ + 0x2f902, 0x6d41, /* 流 流 */ + 0x2f903, 0x6d69, /* 浩 浩 */ + 0x2f904, 0x6d78, /* 浸 浸 */ + 0x2f905, 0x6d85, /* 涅 涅 */ + 0x2f906, 0x23d1e, /* 𣴞 𣴞 */ + 0x2f907, 0x6d34, /* 洴 洴 */ + 0x2f908, 0x6e2f, /* 港 港 */ + 0x2f909, 0x6e6e, /* 湮 湮 */ + 0x2f90a, 0x3d33, /* 㴳 㴳 */ + 0x2f90b, 0x6ecb, /* 滋 滋 */ + 0x2f90c, 0x6ec7, /* 滇 滇 */ + 0x2f90d, 0x23ed1, /* 𣻑 𣻑 */ + 0x2f90e, 0x6df9, /* 淹 淹 */ + 0x2f90f, 0x6f6e, /* 潮 潮 */ + 0x2f910, 0x23f5e, /* 𣽞 𣽞 */ + 0x2f911, 0x23f8e, /* 𣾎 𣾎 */ + 0x2f912, 0x6fc6, /* 濆 濆 */ + 0x2f913, 0x7039, /* 瀹 瀹 */ + 0x2f914, 0x701e, /* 瀞 瀞 */ + 0x2f915, 0x701b, /* 瀛 瀛 */ + 0x2f916, 0x3d96, /* 㶖 㶖 */ + 0x2f917, 0x704a, /* 灊 灊 */ + 0x2f918, 0x707d, /* 災 災 */ + 0x2f919, 0x7077, /* 灷 灷 */ + 0x2f91a, 0x70ad, /* 炭 炭 */ + 0x2f91b, 0x20525, /* 𠔥 𠔥 */ + 0x2f91c, 0x7145, /* 煅 煅 */ + 0x2f91d, 0x24263, /* 𤉣 𤉣 */ + 0x2f91e, 0x719c, /* 熜 熜 */ + 0x2f91f, 0x243ab, /* 𤎫 𤎫 */ + 0x2f920, 0x7228, /* 爨 爨 */ + 0x2f921, 0x7235, /* 爵 爵 */ + 0x2f922, 0x7250, /* 牐 牐 */ + 0x2f923, 0x24608, /* 𤘈 𤘈 */ + 0x2f924, 0x7280, /* 犀 犀 */ + 0x2f925, 0x7295, /* 犕 犕 */ + 0x2f926, 0x24735, /* 𤜵 𤜵 */ + 0x2f927, 0x24814, /* 𤠔 𤠔 */ + 0x2f928, 0x737a, /* 獺 獺 */ + 0x2f929, 0x738b, /* 王 王 */ + 0x2f92a, 0x3eac, /* 㺬 㺬 */ + 0x2f92b, 0x73a5, /* 玥 玥 */ + 0x2f92c, 0x3eb8, /* 㺸 㺸 */ + 0x2f92d, 0x3eb8, /* 㺸 㺸 */ + 0x2f92e, 0x7447, /* 瑇 瑇 */ + 0x2f92f, 0x745c, /* 瑜 瑜 */ + 0x2f930, 0x7471, /* 瑱 瑱 */ + 0x2f931, 0x7485, /* 璅 璅 */ + 0x2f932, 0x74ca, /* 瓊 瓊 */ + 0x2f933, 0x3f1b, /* 㼛 㼛 */ + 0x2f934, 0x7524, /* 甤 甤 */ + 0x2f935, 0x24c36, /* 𤰶 𤰶 */ + 0x2f936, 0x753e, /* 甾 甾 */ + 0x2f937, 0x24c92, /* 𤲒 𤲒 */ + 0x2f938, 0x7570, /* 異 異 */ + 0x2f939, 0x2219f, /* 𢆟 𢆟 */ + 0x2f93a, 0x7610, /* 瘐 瘐 */ + 0x2f93b, 0x24fa1, /* 𤾡 𤾡 */ + 0x2f93c, 0x24fb8, /* 𤾸 𤾸 */ + 0x2f93d, 0x25044, /* 𥁄 𥁄 */ + 0x2f93e, 0x3ffc, /* 㿼 㿼 */ + 0x2f93f, 0x4008, /* 䀈 䀈 */ + 0x2f940, 0x76f4, /* 直 直 */ + 0x2f941, 0x250f3, /* 𥃳 𥃳 */ + 0x2f942, 0x250f2, /* 𥃲 𥃲 */ + 0x2f943, 0x25119, /* 𥄙 𥄙 */ + 0x2f944, 0x25133, /* 𥄳 𥄳 */ + 0x2f945, 0x771e, /* 眞 眞 */ + 0x2f946, 0x771f, /* 真 真 */ + 0x2f947, 0x771f, /* 真 真 */ + 0x2f948, 0x774a, /* 睊 睊 */ + 0x2f949, 0x4039, /* 䀹 䀹 */ + 0x2f94a, 0x778b, /* 瞋 瞋 */ + 0x2f94b, 0x4046, /* 䁆 䁆 */ + 0x2f94c, 0x4096, /* 䂖 䂖 */ + 0x2f94d, 0x2541d, /* 𥐝 𥐝 */ + 0x2f94e, 0x784e, /* 硎 硎 */ + 0x2f94f, 0x788c, /* 碌 碌 */ + 0x2f950, 0x78cc, /* 磌 磌 */ + 0x2f951, 0x40e3, /* 䃣 䃣 */ + 0x2f952, 0x25626, /* 𥘦 𥘦 */ + 0x2f953, 0x7956, /* 祖 祖 */ + 0x2f954, 0x2569a, /* 𥚚 𥚚 */ + 0x2f955, 0x256c5, /* 𥛅 𥛅 */ + 0x2f956, 0x798f, /* 福 福 */ + 0x2f957, 0x79eb, /* 秫 秫 */ + 0x2f958, 0x412f, /* 䄯 䄯 */ + 0x2f959, 0x7a40, /* 穀 穀 */ + 0x2f95a, 0x7a4a, /* 穊 穊 */ + 0x2f95b, 0x7a4f, /* 穏 穏 */ + 0x2f95c, 0x2597c, /* 𥥼 𥥼 */ + 0x2f95d, 0x25aa7, /* 𥪧 𥪧 */ + 0x2f95e, 0x25aa7, /* 𥪧 𥪧 */ + 0x2f95f, 0x7aee, /* 竮 竮 */ + 0x2f960, 0x4202, /* 䈂 䈂 */ + 0x2f961, 0x25bab, /* 𥮫 𥮫 */ + 0x2f962, 0x7bc6, /* 篆 篆 */ + 0x2f963, 0x7bc9, /* 築 築 */ + 0x2f964, 0x4227, /* 䈧 䈧 */ + 0x2f965, 0x25c80, /* 𥲀 𥲀 */ + 0x2f966, 0x7cd2, /* 糒 糒 */ + 0x2f967, 0x42a0, /* 䊠 䊠 */ + 0x2f968, 0x7ce8, /* 糨 糨 */ + 0x2f969, 0x7ce3, /* 糣 糣 */ + 0x2f96a, 0x7d00, /* 紀 紀 */ + 0x2f96b, 0x25f86, /* 𥾆 𥾆 */ + 0x2f96c, 0x7d63, /* 絣 絣 */ + 0x2f96d, 0x4301, /* 䌁 䌁 */ + 0x2f96e, 0x7dc7, /* 緇 緇 */ + 0x2f96f, 0x7e02, /* 縂 縂 */ + 0x2f970, 0x7e45, /* 繅 繅 */ + 0x2f971, 0x4334, /* 䌴 䌴 */ + 0x2f972, 0x26228, /* 𦈨 𦈨 */ + 0x2f973, 0x26247, /* 𦉇 𦉇 */ + 0x2f974, 0x4359, /* 䍙 䍙 */ + 0x2f975, 0x262d9, /* 𦋙 𦋙 */ + 0x2f976, 0x7f7a, /* 罺 罺 */ + 0x2f977, 0x2633e, /* 𦌾 𦌾 */ + 0x2f978, 0x7f95, /* 羕 羕 */ + 0x2f979, 0x7ffa, /* 翺 翺 */ + 0x2f97a, 0x8005, /* 者 者 */ + 0x2f97b, 0x264da, /* 𦓚 𦓚 */ + 0x2f97c, 0x26523, /* 𦔣 𦔣 */ + 0x2f97d, 0x8060, /* 聠 聠 */ + 0x2f97e, 0x265a8, /* 𦖨 𦖨 */ + 0x2f97f, 0x8070, /* 聰 聰 */ + 0x2f980, 0x2335f, /* 𣍟 𣍟 */ + 0x2f981, 0x43d5, /* 䏕 䏕 */ + 0x2f982, 0x80b2, /* 育 育 */ + 0x2f983, 0x8103, /* 脃 脃 */ + 0x2f984, 0x440b, /* 䐋 䐋 */ + 0x2f985, 0x813e, /* 脾 脾 */ + 0x2f986, 0x5ab5, /* 媵 媵 */ + 0x2f987, 0x267a7, /* 𦞧 𦞧 */ + 0x2f988, 0x267b5, /* 𦞵 𦞵 */ + 0x2f989, 0x23393, /* 𣎓 𣎓 */ + 0x2f98a, 0x2339c, /* 𣎜 𣎜 */ + 0x2f98b, 0x8201, /* 舁 舁 */ + 0x2f98c, 0x8204, /* 舄 舄 */ + 0x2f98d, 0x8f9e, /* 辞 辞 */ + 0x2f98e, 0x446b, /* 䑫 䑫 */ + 0x2f98f, 0x8291, /* 芑 芑 */ + 0x2f990, 0x828b, /* 芋 芋 */ + 0x2f991, 0x829d, /* 芝 芝 */ + 0x2f992, 0x52b3, /* 劳 劳 */ + 0x2f993, 0x82b1, /* 花 花 */ + 0x2f994, 0x82b3, /* 芳 芳 */ + 0x2f995, 0x82bd, /* 芽 芽 */ + 0x2f996, 0x82e6, /* 苦 苦 */ + 0x2f997, 0x26b3c, /* 𦬼 𦬼 */ + 0x2f998, 0x82e5, /* 若 若 */ + 0x2f999, 0x831d, /* 茝 茝 */ + 0x2f99a, 0x8363, /* 荣 荣 */ + 0x2f99b, 0x83ad, /* 莭 莭 */ + 0x2f99c, 0x8323, /* 茣 茣 */ + 0x2f99d, 0x83bd, /* 莽 莽 */ + 0x2f99e, 0x83e7, /* 菧 菧 */ + 0x2f99f, 0x8457, /* 著 著 */ + 0x2f9a0, 0x8353, /* 荓 荓 */ + 0x2f9a1, 0x83ca, /* 菊 菊 */ + 0x2f9a2, 0x83cc, /* 菌 菌 */ + 0x2f9a3, 0x83dc, /* 菜 菜 */ + 0x2f9a4, 0x26c36, /* 𦰶 𦰶 */ + 0x2f9a5, 0x26d6b, /* 𦵫 𦵫 */ + 0x2f9a6, 0x26cd5, /* 𦳕 𦳕 */ + 0x2f9a7, 0x452b, /* 䔫 䔫 */ + 0x2f9a8, 0x84f1, /* 蓱 蓱 */ + 0x2f9a9, 0x84f3, /* 蓳 蓳 */ + 0x2f9aa, 0x8516, /* 蔖 蔖 */ + 0x2f9ab, 0x273ca, /* 𧏊 𧏊 */ + 0x2f9ac, 0x8564, /* 蕤 蕤 */ + 0x2f9ad, 0x26f2c, /* 𦼬 𦼬 */ + 0x2f9ae, 0x455d, /* 䕝 䕝 */ + 0x2f9af, 0x4561, /* 䕡 䕡 */ + 0x2f9b0, 0x26fb1, /* 𦾱 𦾱 */ + 0x2f9b1, 0x270d2, /* 𧃒 𧃒 */ + 0x2f9b2, 0x456b, /* 䕫 䕫 */ + 0x2f9b3, 0x8650, /* 虐 虐 */ + 0x2f9b4, 0x865c, /* 虜 虜 */ + 0x2f9b5, 0x8667, /* 虧 虧 */ + 0x2f9b6, 0x8669, /* 虩 虩 */ + 0x2f9b7, 0x86a9, /* 蚩 蚩 */ + 0x2f9b8, 0x8688, /* 蚈 蚈 */ + 0x2f9b9, 0x870e, /* 蜎 蜎 */ + 0x2f9ba, 0x86e2, /* 蛢 蛢 */ + 0x2f9bb, 0x8779, /* 蝹 蝹 */ + 0x2f9bc, 0x8728, /* 蜨 蜨 */ + 0x2f9bd, 0x876b, /* 蝫 蝫 */ + 0x2f9be, 0x8786, /* 螆 螆 */ + 0x2f9bf, 0x45d7, /* 䗗 䗗 */ + 0x2f9c0, 0x87e1, /* 蟡 蟡 */ + 0x2f9c1, 0x8801, /* 蠁 蠁 */ + 0x2f9c2, 0x45f9, /* 䗹 䗹 */ + 0x2f9c3, 0x8860, /* 衠 衠 */ + 0x2f9c4, 0x8863, /* 衣 衣 */ + 0x2f9c5, 0x27667, /* 𧙧 𧙧 */ + 0x2f9c6, 0x88d7, /* 裗 裗 */ + 0x2f9c7, 0x88de, /* 裞 裞 */ + 0x2f9c8, 0x4635, /* 䘵 䘵 */ + 0x2f9c9, 0x88fa, /* 裺 裺 */ + 0x2f9ca, 0x34bb, /* 㒻 㒻 */ + 0x2f9cb, 0x278ae, /* 𧢮 𧢮 */ + 0x2f9cc, 0x27966, /* 𧥦 𧥦 */ + 0x2f9cd, 0x46be, /* 䚾 䚾 */ + 0x2f9ce, 0x46c7, /* 䛇 䛇 */ + 0x2f9cf, 0x8aa0, /* 誠 誠 */ + 0x2f9d0, 0x8aed, /* 諭 諭 */ + 0x2f9d1, 0x8b8a, /* 變 變 */ + 0x2f9d2, 0x8c55, /* 豕 豕 */ + 0x2f9d3, 0x27ca8, /* 𧲨 𧲨 */ + 0x2f9d4, 0x8cab, /* 貫 貫 */ + 0x2f9d5, 0x8cc1, /* 賁 賁 */ + 0x2f9d6, 0x8d1b, /* 贛 贛 */ + 0x2f9d7, 0x8d77, /* 起 起 */ + 0x2f9d8, 0x27f2f, /* 𧼯 𧼯 */ + 0x2f9d9, 0x20804, /* 𠠄 𠠄 */ + 0x2f9da, 0x8dcb, /* 跋 跋 */ + 0x2f9db, 0x8dbc, /* 趼 趼 */ + 0x2f9dc, 0x8df0, /* 跰 跰 */ + 0x2f9dd, 0x208de, /* 𠣞 𠣞 */ + 0x2f9de, 0x8ed4, /* 軔 軔 */ + 0x2f9df, 0x8f38, /* 輸 輸 */ + 0x2f9e0, 0x285d2, /* 𨗒 𨗒 */ + 0x2f9e1, 0x285ed, /* 𨗭 𨗭 */ + 0x2f9e2, 0x9094, /* 邔 邔 */ + 0x2f9e3, 0x90f1, /* 郱 郱 */ + 0x2f9e4, 0x9111, /* 鄑 鄑 */ + 0x2f9e5, 0x2872e, /* 𨜮 𨜮 */ + 0x2f9e6, 0x911b, /* 鄛 鄛 */ + 0x2f9e7, 0x9238, /* 鈸 鈸 */ + 0x2f9e8, 0x92d7, /* 鋗 鋗 */ + 0x2f9e9, 0x92d8, /* 鋘 鋘 */ + 0x2f9ea, 0x927c, /* 鉼 鉼 */ + 0x2f9eb, 0x93f9, /* 鏹 鏹 */ + 0x2f9ec, 0x9415, /* 鐕 鐕 */ + 0x2f9ed, 0x28bfa, /* 𨯺 𨯺 */ + 0x2f9ee, 0x958b, /* 開 開 */ + 0x2f9ef, 0x4995, /* 䦕 䦕 */ + 0x2f9f0, 0x95b7, /* 閷 閷 */ + 0x2f9f1, 0x28d77, /* 𨵷 𨵷 */ + 0x2f9f2, 0x49e6, /* 䧦 䧦 */ + 0x2f9f3, 0x96c3, /* 雃 雃 */ + 0x2f9f4, 0x5db2, /* 嶲 嶲 */ + 0x2f9f5, 0x9723, /* 霣 霣 */ + 0x2f9f6, 0x29145, /* 𩅅 𩅅 */ + 0x2f9f7, 0x2921a, /* 𩈚 𩈚 */ + 0x2f9f8, 0x4a6e, /* 䩮 䩮 */ + 0x2f9f9, 0x4a76, /* 䩶 䩶 */ + 0x2f9fa, 0x97e0, /* 韠 韠 */ + 0x2f9fb, 0x2940a, /* 𩐊 𩐊 */ + 0x2f9fc, 0x4ab2, /* 䪲 䪲 */ + 0x2f9fd, 0x29496, /* 𩒖 𩒖 */ + 0x2f9fe, 0x980b, /* 頋 頋 */ + 0x2f9ff, 0x980b, /* 頋 頋 */ + 0x2fa00, 0x9829, /* 頩 頩 */ + 0x2fa01, 0x295b6, /* 𩖶 𩖶 */ + 0x2fa02, 0x98e2, /* 飢 飢 */ + 0x2fa03, 0x4b33, /* 䬳 䬳 */ + 0x2fa04, 0x9929, /* 餩 餩 */ + 0x2fa05, 0x99a7, /* 馧 馧 */ + 0x2fa06, 0x99c2, /* 駂 駂 */ + 0x2fa07, 0x99fe, /* 駾 駾 */ + 0x2fa08, 0x4bce, /* 䯎 䯎 */ + 0x2fa09, 0x29b30, /* 𩬰 𩬰 */ + 0x2fa0a, 0x9b12, /* 鬒 鬒 */ + 0x2fa0b, 0x9c40, /* 鱀 鱀 */ + 0x2fa0c, 0x9cfd, /* 鳽 鳽 */ + 0x2fa0d, 0x4cce, /* 䳎 䳎 */ + 0x2fa0e, 0x4ced, /* 䳭 䳭 */ + 0x2fa0f, 0x9d67, /* 鵧 鵧 */ + 0x2fa10, 0x2a0ce, /* 𪃎 𪃎 */ + 0x2fa11, 0x4cf8, /* 䳸 䳸 */ + 0x2fa12, 0x2a105, /* 𪄅 𪄅 */ + 0x2fa13, 0x2a20e, /* 𪈎 𪈎 */ + 0x2fa14, 0x2a291, /* 𪊑 𪊑 */ + 0x2fa15, 0x9ebb, /* 麻 麻 */ + 0x2fa16, 0x4d56, /* 䵖 䵖 */ + 0x2fa17, 0x9ef9, /* 黹 黹 */ + 0x2fa18, 0x9efe, /* 黾 黾 */ + 0x2fa19, 0x9f05, /* 鼅 鼅 */ + 0x2fa1a, 0x9f0f, /* 鼏 鼏 */ + 0x2fa1b, 0x9f16, /* 鼖 鼖 */ + 0x2fa1c, 0x9f3b, /* 鼻 鼻 */ +}; + +Rune +tobaserune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, _base2, nelem(_base2)/2, 2); + if(p && c == p[0]) + c = p[1]; + return c; +} + +int +isbaserune(Rune c) +{ + return tobaserune(c) == c; +} diff --git a/sys/src/libc/port/runebsearch.c b/sys/src/libc/port/runebsearch.c new file mode 100644 index 0000000..e9b6d7a --- /dev/null +++ b/sys/src/libc/port/runebsearch.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +_runebsearch(Rune c, Rune *t, int n, int ne) +{ + Rune *p; + int m; + + while(n > 1) { + m = n/2; + p = t + m*ne; + if(c >= p[0]) { + t = p; + n = n-m; + } else + n = m; + } + if(n && c >= t[0]) + return t; + return 0; +} diff --git a/sys/src/libc/port/runestrcat.c b/sys/src/libc/port/runestrcat.c new file mode 100644 index 0000000..72d6945 --- /dev/null +++ b/sys/src/libc/port/runestrcat.c @@ -0,0 +1,19 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrcat(Rune *s1, const Rune *s2) +{ + + runestrcpy(runestrchr(s1, 0), s2); + return s1; +} diff --git a/sys/src/libc/port/runestrchr.c b/sys/src/libc/port/runestrchr.c new file mode 100644 index 0000000..0d7d43f --- /dev/null +++ b/sys/src/libc/port/runestrchr.c @@ -0,0 +1,29 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrchr(const Rune *s, Rune c) +{ + Rune c0 = c; + Rune c1; + + if(c == 0) { + while(*s++) + ; + return (Rune*)s-1; + } + + while(c1 = *s++) + if(c1 == c0) + return (Rune*)s-1; + return 0; +} diff --git a/sys/src/libc/port/runestrcmp.c b/sys/src/libc/port/runestrcmp.c new file mode 100644 index 0000000..a2138b6 --- /dev/null +++ b/sys/src/libc/port/runestrcmp.c @@ -0,0 +1,29 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +runestrcmp(const Rune *s1, const Rune *s2) +{ + Rune c1, c2; + + for(;;) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + return 0; + } +} diff --git a/sys/src/libc/port/runestrcpy.c b/sys/src/libc/port/runestrcpy.c new file mode 100644 index 0000000..73ef8af --- /dev/null +++ b/sys/src/libc/port/runestrcpy.c @@ -0,0 +1,22 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrcpy(Rune *s1, const Rune *s2) +{ + Rune *os1; + + os1 = s1; + while(*s1++ = *s2++) + ; + return os1; +} diff --git a/sys/src/libc/port/runestrdup.c b/sys/src/libc/port/runestrdup.c new file mode 100644 index 0000000..e4d3aed --- /dev/null +++ b/sys/src/libc/port/runestrdup.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrdup(const Rune *s) +{ + Rune *ns; + + ns = malloc(sizeof(Rune)*(runestrlen(s) + 1)); + if(ns == 0) + return 0; + setmalloctag(ns, getcallerpc()); + + return runestrcpy(ns, s); +} diff --git a/sys/src/libc/port/runestrecpy.c b/sys/src/libc/port/runestrecpy.c new file mode 100644 index 0000000..32bb9b0 --- /dev/null +++ b/sys/src/libc/port/runestrecpy.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrecpy(Rune *s1, Rune *es1, const Rune *s2) +{ + if(s1 >= es1) + return s1; + + while(*s1++ = *s2++){ + if(s1 == es1){ + *--s1 = '\0'; + break; + } + } + return s1; +} diff --git a/sys/src/libc/port/runestrlen.c b/sys/src/libc/port/runestrlen.c new file mode 100644 index 0000000..fe25e2c --- /dev/null +++ b/sys/src/libc/port/runestrlen.c @@ -0,0 +1,18 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int32_t +runestrlen(const Rune *s) +{ + + return runestrchr(s, 0) - s; +} diff --git a/sys/src/libc/port/runestrncat.c b/sys/src/libc/port/runestrncat.c new file mode 100644 index 0000000..74b18dd --- /dev/null +++ b/sys/src/libc/port/runestrncat.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrncat(Rune *s1, const Rune *s2, int32_t n) +{ + Rune *os1; + + os1 = s1; + s1 = runestrchr(s1, 0); + while(*s1++ = *s2++) + if(--n < 0) { + s1[-1] = 0; + break; + } + return os1; +} diff --git a/sys/src/libc/port/runestrncmp.c b/sys/src/libc/port/runestrncmp.c new file mode 100644 index 0000000..dade20c --- /dev/null +++ b/sys/src/libc/port/runestrncmp.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +runestrncmp(const Rune *s1, const Rune *s2, int32_t n) +{ + Rune c1, c2; + + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + n--; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + break; + } + return 0; +} diff --git a/sys/src/libc/port/runestrncpy.c b/sys/src/libc/port/runestrncpy.c new file mode 100644 index 0000000..5ceb341 --- /dev/null +++ b/sys/src/libc/port/runestrncpy.c @@ -0,0 +1,27 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrncpy(Rune *s1, const Rune *s2, int32_t n) +{ + int i; + Rune *os1; + + os1 = s1; + for(i = 0; i < n; i++) + if((*s1++ = *s2++) == 0) { + while(++i < n) + *s1++ = 0; + return os1; + } + return os1; +} diff --git a/sys/src/libc/port/runestrrchr.c b/sys/src/libc/port/runestrrchr.c new file mode 100644 index 0000000..65c85f2 --- /dev/null +++ b/sys/src/libc/port/runestrrchr.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune* +runestrrchr(const Rune *s, Rune c) +{ + const Rune *r; + + if(c == 0) + return runestrchr(s, 0); + r = 0; + while(s = runestrchr(s, c)) + r = s++; + return (Rune *)r; +} diff --git a/sys/src/libc/port/runestrstr.c b/sys/src/libc/port/runestrstr.c new file mode 100644 index 0000000..53cc4fa --- /dev/null +++ b/sys/src/libc/port/runestrstr.c @@ -0,0 +1,38 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +Rune* +runestrstr(const Rune *s1, const Rune *s2) +{ + const Rune *p, *pa, *pb; + int c0, c; + + c0 = *s2; + if(c0 == 0) + return (Rune*)s1; + s2++; + for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) { + pa = p; + for(pb=s2;; pb++) { + c = *pb; + if(c == 0) + return (Rune*)p; + if(c != *++pa) + break; + } + } + return 0; +} diff --git a/sys/src/libc/port/runetype.c b/sys/src/libc/port/runetype.c new file mode 100644 index 0000000..a9ac324 --- /dev/null +++ b/sys/src/libc/port/runetype.c @@ -0,0 +1,15 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +Rune*_runebsearch(Rune c, Rune *t, int n, int ne); + +#include "runetypebody-6.2.0.h" diff --git a/sys/src/libc/port/runetypebody-6.2.0.h b/sys/src/libc/port/runetypebody-6.2.0.h new file mode 100755 index 0000000..21d6a36 --- /dev/null +++ b/sys/src/libc/port/runetypebody-6.2.0.h @@ -0,0 +1,1650 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* generated automatically by mkrunetype.c in Go from UnicodeData-6.2.0.txt + * with s/rbsearch/_runebsearch/g + */ + +static Rune __isspacer[] = { + 0x0009, 0x000d, + 0x0020, 0x0020, + 0x0085, 0x0085, + 0x00a0, 0x00a0, + 0x1680, 0x1680, + 0x180e, 0x180e, + 0x2000, 0x200a, + 0x2028, 0x2029, + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, + 0xfeff, 0xfeff, +}; + +int +isspacerune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __isspacer, nelem(__isspacer)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} + +static Rune __isdigitr[] = { + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06f0, 0x06f9, + 0x07c0, 0x07c9, + 0x0966, 0x096f, + 0x09e6, 0x09ef, + 0x0a66, 0x0a6f, + 0x0ae6, 0x0aef, + 0x0b66, 0x0b6f, + 0x0be6, 0x0bef, + 0x0c66, 0x0c6f, + 0x0ce6, 0x0cef, + 0x0d66, 0x0d6f, + 0x0e50, 0x0e59, + 0x0ed0, 0x0ed9, + 0x0f20, 0x0f29, + 0x1040, 0x1049, + 0x1090, 0x1099, + 0x17e0, 0x17e9, + 0x1810, 0x1819, + 0x1946, 0x194f, + 0x19d0, 0x19d9, + 0x1a80, 0x1a89, + 0x1a90, 0x1a99, + 0x1b50, 0x1b59, + 0x1bb0, 0x1bb9, + 0x1c40, 0x1c49, + 0x1c50, 0x1c59, + 0xa620, 0xa629, + 0xa8d0, 0xa8d9, + 0xa900, 0xa909, + 0xa9d0, 0xa9d9, + 0xaa50, 0xaa59, + 0xabf0, 0xabf9, + 0xff10, 0xff19, + 0x104a0, 0x104a9, + 0x11066, 0x1106f, + 0x110f0, 0x110f9, + 0x11136, 0x1113f, + 0x111d0, 0x111d9, + 0x116c0, 0x116c9, + 0x1d7ce, 0x1d7ff, +}; + +int +isdigitrune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __isdigitr, nelem(__isdigitr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} + +static Rune __isalphar[] = { + 0x0041, 0x005a, + 0x0061, 0x007a, + 0x00c0, 0x00d6, + 0x00d8, 0x00f6, + 0x00f8, 0x02c1, + 0x02c6, 0x02d1, + 0x02e0, 0x02e4, + 0x0370, 0x0374, + 0x0376, 0x0377, + 0x037a, 0x037d, + 0x0388, 0x038a, + 0x038e, 0x03a1, + 0x03a3, 0x03f5, + 0x03f7, 0x0481, + 0x048a, 0x0527, + 0x0531, 0x0556, + 0x0561, 0x0587, + 0x05d0, 0x05ea, + 0x05f0, 0x05f2, + 0x0620, 0x064a, + 0x066e, 0x066f, + 0x0671, 0x06d3, + 0x06e5, 0x06e6, + 0x06ee, 0x06ef, + 0x06fa, 0x06fc, + 0x0712, 0x072f, + 0x074d, 0x07a5, + 0x07ca, 0x07ea, + 0x07f4, 0x07f5, + 0x0800, 0x0815, + 0x0840, 0x0858, + 0x08a2, 0x08ac, + 0x0904, 0x0939, + 0x0958, 0x0961, + 0x0971, 0x0977, + 0x0979, 0x097f, + 0x0985, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09a8, + 0x09aa, 0x09b0, + 0x09b6, 0x09b9, + 0x09dc, 0x09dd, + 0x09df, 0x09e1, + 0x09f0, 0x09f1, + 0x0a05, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a28, + 0x0a2a, 0x0a30, + 0x0a32, 0x0a33, + 0x0a35, 0x0a36, + 0x0a38, 0x0a39, + 0x0a59, 0x0a5c, + 0x0a72, 0x0a74, + 0x0a85, 0x0a8d, + 0x0a8f, 0x0a91, + 0x0a93, 0x0aa8, + 0x0aaa, 0x0ab0, + 0x0ab2, 0x0ab3, + 0x0ab5, 0x0ab9, + 0x0ae0, 0x0ae1, + 0x0b05, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b28, + 0x0b2a, 0x0b30, + 0x0b32, 0x0b33, + 0x0b35, 0x0b39, + 0x0b5c, 0x0b5d, + 0x0b5f, 0x0b61, + 0x0b85, 0x0b8a, + 0x0b8e, 0x0b90, + 0x0b92, 0x0b95, + 0x0b99, 0x0b9a, + 0x0b9e, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0c05, 0x0c0c, + 0x0c0e, 0x0c10, + 0x0c12, 0x0c28, + 0x0c2a, 0x0c33, + 0x0c35, 0x0c39, + 0x0c58, 0x0c59, + 0x0c60, 0x0c61, + 0x0c85, 0x0c8c, + 0x0c8e, 0x0c90, + 0x0c92, 0x0ca8, + 0x0caa, 0x0cb3, + 0x0cb5, 0x0cb9, + 0x0ce0, 0x0ce1, + 0x0cf1, 0x0cf2, + 0x0d05, 0x0d0c, + 0x0d0e, 0x0d10, + 0x0d12, 0x0d3a, + 0x0d60, 0x0d61, + 0x0d7a, 0x0d7f, + 0x0d85, 0x0d96, + 0x0d9a, 0x0db1, + 0x0db3, 0x0dbb, + 0x0dc0, 0x0dc6, + 0x0e01, 0x0e30, + 0x0e32, 0x0e33, + 0x0e40, 0x0e46, + 0x0e81, 0x0e82, + 0x0e87, 0x0e88, + 0x0e94, 0x0e97, + 0x0e99, 0x0e9f, + 0x0ea1, 0x0ea3, + 0x0eaa, 0x0eab, + 0x0ead, 0x0eb0, + 0x0eb2, 0x0eb3, + 0x0ec0, 0x0ec4, + 0x0edc, 0x0edf, + 0x0f40, 0x0f47, + 0x0f49, 0x0f6c, + 0x0f88, 0x0f8c, + 0x1000, 0x102a, + 0x1050, 0x1055, + 0x105a, 0x105d, + 0x1065, 0x1066, + 0x106e, 0x1070, + 0x1075, 0x1081, + 0x10a0, 0x10c5, + 0x10d0, 0x10fa, + 0x10fc, 0x1248, + 0x124a, 0x124d, + 0x1250, 0x1256, + 0x125a, 0x125d, + 0x1260, 0x1288, + 0x128a, 0x128d, + 0x1290, 0x12b0, + 0x12b2, 0x12b5, + 0x12b8, 0x12be, + 0x12c2, 0x12c5, + 0x12c8, 0x12d6, + 0x12d8, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x135a, + 0x1380, 0x138f, + 0x13a0, 0x13f4, + 0x1401, 0x166c, + 0x166f, 0x167f, + 0x1681, 0x169a, + 0x16a0, 0x16ea, + 0x1700, 0x170c, + 0x170e, 0x1711, + 0x1720, 0x1731, + 0x1740, 0x1751, + 0x1760, 0x176c, + 0x176e, 0x1770, + 0x1780, 0x17b3, + 0x1820, 0x1877, + 0x1880, 0x18a8, + 0x18b0, 0x18f5, + 0x1900, 0x191c, + 0x1950, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19c1, 0x19c7, + 0x1a00, 0x1a16, + 0x1a20, 0x1a54, + 0x1b05, 0x1b33, + 0x1b45, 0x1b4b, + 0x1b83, 0x1ba0, + 0x1bae, 0x1baf, + 0x1bba, 0x1be5, + 0x1c00, 0x1c23, + 0x1c4d, 0x1c4f, + 0x1c5a, 0x1c7d, + 0x1ce9, 0x1cec, + 0x1cee, 0x1cf1, + 0x1cf5, 0x1cf6, + 0x1d00, 0x1dbf, + 0x1e00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f57, + 0x1f5f, 0x1f7d, + 0x1f80, 0x1fb4, + 0x1fb6, 0x1fbc, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fcc, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fdb, + 0x1fe0, 0x1fec, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ffc, + 0x2090, 0x209c, + 0x210a, 0x2113, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x212f, 0x2139, + 0x213c, 0x213f, + 0x2145, 0x2149, + 0x2183, 0x2184, + 0x2c00, 0x2c2e, + 0x2c30, 0x2c5e, + 0x2c60, 0x2ce4, + 0x2ceb, 0x2cee, + 0x2cf2, 0x2cf3, + 0x2d00, 0x2d25, + 0x2d30, 0x2d67, + 0x2d80, 0x2d96, + 0x2da0, 0x2da6, + 0x2da8, 0x2dae, + 0x2db0, 0x2db6, + 0x2db8, 0x2dbe, + 0x2dc0, 0x2dc6, + 0x2dc8, 0x2dce, + 0x2dd0, 0x2dd6, + 0x2dd8, 0x2dde, + 0x3005, 0x3006, + 0x3031, 0x3035, + 0x303b, 0x303c, + 0x3041, 0x3096, + 0x309d, 0x309f, + 0x30a1, 0x30fa, + 0x30fc, 0x30ff, + 0x3105, 0x312d, + 0x3131, 0x318e, + 0x31a0, 0x31ba, + 0x31f0, 0x31ff, + 0x3400, 0x4db5, + 0x4e00, 0x9fcc, + 0xa000, 0xa48c, + 0xa4d0, 0xa4fd, + 0xa500, 0xa60c, + 0xa610, 0xa61f, + 0xa62a, 0xa62b, + 0xa640, 0xa66e, + 0xa67f, 0xa697, + 0xa6a0, 0xa6e5, + 0xa717, 0xa71f, + 0xa722, 0xa788, + 0xa78b, 0xa78e, + 0xa790, 0xa793, + 0xa7a0, 0xa7aa, + 0xa7f8, 0xa801, + 0xa803, 0xa805, + 0xa807, 0xa80a, + 0xa80c, 0xa822, + 0xa840, 0xa873, + 0xa882, 0xa8b3, + 0xa8f2, 0xa8f7, + 0xa90a, 0xa925, + 0xa930, 0xa946, + 0xa960, 0xa97c, + 0xa984, 0xa9b2, + 0xaa00, 0xaa28, + 0xaa40, 0xaa42, + 0xaa44, 0xaa4b, + 0xaa60, 0xaa76, + 0xaa80, 0xaaaf, + 0xaab5, 0xaab6, + 0xaab9, 0xaabd, + 0xaadb, 0xaadd, + 0xaae0, 0xaaea, + 0xaaf2, 0xaaf4, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab26, + 0xab28, 0xab2e, + 0xabc0, 0xabe2, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1f, 0xfb28, + 0xfb2a, 0xfb36, + 0xfb38, 0xfb3c, + 0xfb40, 0xfb41, + 0xfb43, 0xfb44, + 0xfb46, 0xfbb1, + 0xfbd3, 0xfd3d, + 0xfd50, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdf0, 0xfdfb, + 0xfe70, 0xfe74, + 0xfe76, 0xfefc, + 0xff21, 0xff3a, + 0xff41, 0xff5a, + 0xff66, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0x10000, 0x1000b, + 0x1000d, 0x10026, + 0x10028, 0x1003a, + 0x1003c, 0x1003d, + 0x1003f, 0x1004d, + 0x10050, 0x1005d, + 0x10080, 0x100fa, + 0x10280, 0x1029c, + 0x102a0, 0x102d0, + 0x10300, 0x1031e, + 0x10330, 0x10340, + 0x10342, 0x10349, + 0x10380, 0x1039d, + 0x103a0, 0x103c3, + 0x103c8, 0x103cf, + 0x10400, 0x1049d, + 0x10800, 0x10805, + 0x1080a, 0x10835, + 0x10837, 0x10838, + 0x1083f, 0x10855, + 0x10900, 0x10915, + 0x10920, 0x10939, + 0x10980, 0x109b7, + 0x109be, 0x109bf, + 0x10a10, 0x10a13, + 0x10a15, 0x10a17, + 0x10a19, 0x10a33, + 0x10a60, 0x10a7c, + 0x10b00, 0x10b35, + 0x10b40, 0x10b55, + 0x10b60, 0x10b72, + 0x10c00, 0x10c48, + 0x11003, 0x11037, + 0x11083, 0x110af, + 0x110d0, 0x110e8, + 0x11103, 0x11126, + 0x11183, 0x111b2, + 0x111c1, 0x111c4, + 0x11680, 0x116aa, + 0x12000, 0x1236e, + 0x13000, 0x1342e, + 0x16800, 0x16a38, + 0x16f00, 0x16f44, + 0x16f93, 0x16f9f, + 0x1b000, 0x1b001, + 0x1d400, 0x1d454, + 0x1d456, 0x1d49c, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d51e, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d552, 0x1d6a5, + 0x1d6a8, 0x1d6c0, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6fa, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d734, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d76e, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d7a8, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7cb, + 0x1ee00, 0x1ee03, + 0x1ee05, 0x1ee1f, + 0x1ee21, 0x1ee22, + 0x1ee29, 0x1ee32, + 0x1ee34, 0x1ee37, + 0x1ee4d, 0x1ee4f, + 0x1ee51, 0x1ee52, + 0x1ee61, 0x1ee62, + 0x1ee67, 0x1ee6a, + 0x1ee6c, 0x1ee72, + 0x1ee74, 0x1ee77, + 0x1ee79, 0x1ee7c, + 0x1ee80, 0x1ee89, + 0x1ee8b, 0x1ee9b, + 0x1eea1, 0x1eea3, + 0x1eea5, 0x1eea9, + 0x1eeab, 0x1eebb, + 0x20000, 0x2a6d6, + 0x2a700, 0x2b734, + 0x2b740, 0x2b81d, + 0x2f800, 0x2fa1d, +}; + +static Rune __isalphas[] = { + 0x00aa, + 0x00b5, + 0x00ba, + 0x02ec, + 0x02ee, + 0x0386, + 0x038c, + 0x0559, + 0x06d5, + 0x06ff, + 0x0710, + 0x07b1, + 0x07fa, + 0x081a, + 0x0824, + 0x0828, + 0x08a0, + 0x093d, + 0x0950, + 0x09b2, + 0x09bd, + 0x09ce, + 0x0a5e, + 0x0abd, + 0x0ad0, + 0x0b3d, + 0x0b71, + 0x0b83, + 0x0b9c, + 0x0bd0, + 0x0c3d, + 0x0cbd, + 0x0cde, + 0x0d3d, + 0x0d4e, + 0x0dbd, + 0x0e84, + 0x0e8a, + 0x0e8d, + 0x0ea5, + 0x0ea7, + 0x0ebd, + 0x0ec6, + 0x0f00, + 0x103f, + 0x1061, + 0x108e, + 0x10c7, + 0x10cd, + 0x1258, + 0x12c0, + 0x17d7, + 0x17dc, + 0x18aa, + 0x1aa7, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1fbe, + 0x2071, + 0x207f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x214e, + 0x2d27, + 0x2d2d, + 0x2d6f, + 0x2e2f, + 0xa8fb, + 0xa9cf, + 0xaa7a, + 0xaab1, + 0xaac0, + 0xaac2, + 0xfb1d, + 0xfb3e, + 0x10808, + 0x1083c, + 0x10a00, + 0x16f50, + 0x1d4a2, + 0x1d4bb, + 0x1d546, + 0x1ee24, + 0x1ee27, + 0x1ee39, + 0x1ee3b, + 0x1ee42, + 0x1ee47, + 0x1ee49, + 0x1ee4b, + 0x1ee54, + 0x1ee57, + 0x1ee59, + 0x1ee5b, + 0x1ee5d, + 0x1ee5f, + 0x1ee64, + 0x1ee7e, +}; + +int +isalpharune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __isalphar, nelem(__isalphar)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = _runebsearch(c, __isalphas, nelem(__isalphas), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __isupperr[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03d2, 0x03d4, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x210b, 0x210d, + 0x2110, 0x2112, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x2130, 0x2133, + 0x213e, 0x213f, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x1d400, 0x1d419, + 0x1d434, 0x1d44d, + 0x1d468, 0x1d481, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b5, + 0x1d4d0, 0x1d4e9, + 0x1d504, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d538, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d56c, 0x1d585, + 0x1d5a0, 0x1d5b9, + 0x1d5d4, 0x1d5ed, + 0x1d608, 0x1d621, + 0x1d63c, 0x1d655, + 0x1d670, 0x1d689, + 0x1d6a8, 0x1d6c0, + 0x1d6e2, 0x1d6fa, + 0x1d71c, 0x1d734, + 0x1d756, 0x1d76e, + 0x1d790, 0x1d7a8, +}; + +static Rune __isupperp[] = { + 0x0100, 0x0136, + 0x0139, 0x0147, + 0x014a, 0x0176, + 0x017b, 0x017d, + 0x01a2, 0x01a4, + 0x01cd, 0x01db, + 0x01de, 0x01ee, + 0x01fa, 0x0232, + 0x0248, 0x024e, + 0x0370, 0x0372, + 0x03d8, 0x03ee, + 0x0460, 0x0480, + 0x048a, 0x04be, + 0x04c3, 0x04cd, + 0x04d0, 0x0526, + 0x1e00, 0x1e94, + 0x1e9e, 0x1efe, + 0x1f59, 0x1f5f, + 0x2124, 0x2128, + 0x2c67, 0x2c6b, + 0x2c82, 0x2ce2, + 0x2ceb, 0x2ced, + 0xa640, 0xa66c, + 0xa680, 0xa696, + 0xa722, 0xa72e, + 0xa732, 0xa76e, + 0xa779, 0xa77b, + 0xa780, 0xa786, + 0xa78b, 0xa78d, + 0xa790, 0xa792, + 0xa7a0, 0xa7aa, +}; + +static Rune __isuppers[] = { + 0x0184, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c4, + 0x01c7, + 0x01ca, + 0x01f1, + 0x01f4, + 0x0241, + 0x0376, + 0x0386, + 0x038c, + 0x03cf, + 0x03f4, + 0x03f7, + 0x10c7, + 0x10cd, + 0x2102, + 0x2107, + 0x2115, + 0x2145, + 0x2183, + 0x2c60, + 0x2c72, + 0x2c75, + 0x2cf2, + 0x1d49c, + 0x1d4a2, + 0x1d546, + 0x1d7ca, +}; + +int +isupperrune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __isupperr, nelem(__isupperr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = _runebsearch(c, __isupperp, nelem(__isupperp)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = _runebsearch(c, __isuppers, nelem(__isuppers), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __islowerr[] = { + 0x0061, 0x007a, + 0x00df, 0x00f6, + 0x00f8, 0x00ff, + 0x0137, 0x0138, + 0x0148, 0x0149, + 0x017e, 0x0180, + 0x018c, 0x018d, + 0x0199, 0x019b, + 0x01aa, 0x01ab, + 0x01b9, 0x01ba, + 0x01bd, 0x01bf, + 0x01dc, 0x01dd, + 0x01ef, 0x01f0, + 0x0233, 0x0239, + 0x023f, 0x0240, + 0x024f, 0x0293, + 0x0295, 0x02af, + 0x037b, 0x037d, + 0x03ac, 0x03ce, + 0x03d0, 0x03d1, + 0x03d5, 0x03d7, + 0x03ef, 0x03f3, + 0x03fb, 0x03fc, + 0x0430, 0x045f, + 0x04ce, 0x04cf, + 0x0561, 0x0587, + 0x1d00, 0x1d2b, + 0x1d6b, 0x1d77, + 0x1d79, 0x1d9a, + 0x1e95, 0x1e9d, + 0x1eff, 0x1f07, + 0x1f10, 0x1f15, + 0x1f20, 0x1f27, + 0x1f30, 0x1f37, + 0x1f40, 0x1f45, + 0x1f50, 0x1f57, + 0x1f60, 0x1f67, + 0x1f70, 0x1f7d, + 0x1f80, 0x1f87, + 0x1f90, 0x1f97, + 0x1fa0, 0x1fa7, + 0x1fb0, 0x1fb4, + 0x1fb6, 0x1fb7, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fc7, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fd7, + 0x1fe0, 0x1fe7, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ff7, + 0x210e, 0x210f, + 0x213c, 0x213d, + 0x2146, 0x2149, + 0x2170, 0x217f, + 0x24d0, 0x24e9, + 0x2c30, 0x2c5e, + 0x2c65, 0x2c66, + 0x2c73, 0x2c74, + 0x2c76, 0x2c7b, + 0x2ce3, 0x2ce4, + 0x2d00, 0x2d25, + 0xa72f, 0xa731, + 0xa771, 0xa778, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xff41, 0xff5a, + 0x10428, 0x1044f, + 0x1d41a, 0x1d433, + 0x1d44e, 0x1d454, + 0x1d456, 0x1d467, + 0x1d482, 0x1d49b, + 0x1d4b6, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d4cf, + 0x1d4ea, 0x1d503, + 0x1d51e, 0x1d537, + 0x1d552, 0x1d56b, + 0x1d586, 0x1d59f, + 0x1d5ba, 0x1d5d3, + 0x1d5ee, 0x1d607, + 0x1d622, 0x1d63b, + 0x1d656, 0x1d66f, + 0x1d68a, 0x1d6a5, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6e1, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d71b, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d755, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d78f, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7c9, +}; + +static Rune __islowerp[] = { + 0x0101, 0x0135, + 0x013a, 0x0146, + 0x014b, 0x0177, + 0x017a, 0x017c, + 0x0183, 0x0185, + 0x01a1, 0x01a5, + 0x01b4, 0x01b6, + 0x01cc, 0x01da, + 0x01df, 0x01ed, + 0x01f3, 0x01f5, + 0x01f9, 0x0231, + 0x0247, 0x024d, + 0x0371, 0x0373, + 0x03d9, 0x03ed, + 0x0461, 0x0481, + 0x048b, 0x04bf, + 0x04c2, 0x04cc, + 0x04d1, 0x0527, + 0x1e01, 0x1e93, + 0x1e9f, 0x1efd, + 0x2c68, 0x2c6c, + 0x2c81, 0x2ce1, + 0x2cec, 0x2cee, + 0xa641, 0xa66d, + 0xa681, 0xa697, + 0xa723, 0xa72d, + 0xa733, 0xa76f, + 0xa77a, 0xa77c, + 0xa77f, 0xa787, + 0xa78c, 0xa78e, + 0xa791, 0xa793, + 0xa7a1, 0xa7a9, +}; + +static Rune __islowers[] = { + 0x00b5, + 0x0188, + 0x0192, + 0x0195, + 0x019e, + 0x01a8, + 0x01ad, + 0x01b0, + 0x01c6, + 0x01c9, + 0x023c, + 0x0242, + 0x0377, + 0x0390, + 0x03f5, + 0x03f8, + 0x1fbe, + 0x210a, + 0x2113, + 0x212f, + 0x2134, + 0x2139, + 0x214e, + 0x2184, + 0x2c61, + 0x2c71, + 0x2cf3, + 0x2d27, + 0x2d2d, + 0xa7fa, + 0x1d4bb, + 0x1d7cb, +}; + +int +islowerrune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __islowerr, nelem(__islowerr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = _runebsearch(c, __islowerp, nelem(__islowerp)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = _runebsearch(c, __islowers, nelem(__islowers), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __istitler[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xff21, 0xff3a, + 0x10400, 0x10427, +}; + +static Rune __istitlep[] = { + 0x0100, 0x012e, + 0x0132, 0x0136, + 0x0139, 0x0147, + 0x014a, 0x0176, + 0x017b, 0x017d, + 0x01a2, 0x01a4, + 0x01cb, 0x01db, + 0x01de, 0x01ee, + 0x01f2, 0x01f4, + 0x01fa, 0x0232, + 0x0248, 0x024e, + 0x0370, 0x0372, + 0x03d8, 0x03ee, + 0x0460, 0x0480, + 0x048a, 0x04be, + 0x04c3, 0x04cd, + 0x04d0, 0x0526, + 0x1e00, 0x1e94, + 0x1ea0, 0x1efe, + 0x1f59, 0x1f5f, + 0x2c67, 0x2c6b, + 0x2c82, 0x2ce2, + 0x2ceb, 0x2ced, + 0xa640, 0xa66c, + 0xa680, 0xa696, + 0xa722, 0xa72e, + 0xa732, 0xa76e, + 0xa779, 0xa77b, + 0xa780, 0xa786, + 0xa78b, 0xa78d, + 0xa790, 0xa792, + 0xa7a0, 0xa7aa, +}; + +static Rune __istitles[] = { + 0x0184, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c5, + 0x01c8, + 0x0241, + 0x0376, + 0x0386, + 0x038c, + 0x03cf, + 0x03f7, + 0x10c7, + 0x10cd, + 0x2132, + 0x2183, + 0x2c60, + 0x2c72, + 0x2c75, + 0x2cf2, +}; + +int +istitlerune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __istitler, nelem(__istitler)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = _runebsearch(c, __istitlep, nelem(__istitlep)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = _runebsearch(c, __istitles, nelem(__istitles), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __toupperr[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, +}; + +static Rune __toupperp[] = { + 0x0101, 0x012f, 1048575, + 0x0133, 0x0137, 1048575, + 0x013a, 0x0148, 1048575, + 0x014b, 0x0177, 1048575, + 0x017a, 0x017e, 1048575, + 0x0183, 0x0185, 1048575, + 0x01a1, 0x01a5, 1048575, + 0x01b4, 0x01b6, 1048575, + 0x01ce, 0x01dc, 1048575, + 0x01df, 0x01ef, 1048575, + 0x01f9, 0x021f, 1048575, + 0x0223, 0x0233, 1048575, + 0x0247, 0x024f, 1048575, + 0x0371, 0x0373, 1048575, + 0x03d9, 0x03ef, 1048575, + 0x0461, 0x0481, 1048575, + 0x048b, 0x04bf, 1048575, + 0x04c2, 0x04ce, 1048575, + 0x04d1, 0x0527, 1048575, + 0x1e01, 0x1e95, 1048575, + 0x1ea1, 0x1eff, 1048575, + 0x1f51, 0x1f57, 1048584, + 0x2c68, 0x2c6c, 1048575, + 0x2c81, 0x2ce3, 1048575, + 0x2cec, 0x2cee, 1048575, + 0xa641, 0xa66d, 1048575, + 0xa681, 0xa697, 1048575, + 0xa723, 0xa72f, 1048575, + 0xa733, 0xa76f, 1048575, + 0xa77a, 0xa77c, 1048575, + 0xa77f, 0xa787, 1048575, + 0xa791, 0xa793, 1048575, + 0xa7a1, 0xa7a9, 1048575, +}; + +static Rune __touppers[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0131, 1048344, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c5, 1048575, + 0x01c6, 1048574, + 0x01c8, 1048575, + 0x01c9, 1048574, + 0x01cb, 1048575, + 0x01cc, 1048574, + 0x01dd, 1048497, + 0x01f2, 1048575, + 0x01f3, 1048574, + 0x01f5, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x0260, 1048371, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x0345, 1048660, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x04cf, 1048561, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e9b, 1048517, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa78c, 1048575, +}; + +Rune +toupperrune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __toupperr, nelem(__toupperr)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = _runebsearch(c, __toupperp, nelem(__toupperp)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = _runebsearch(c, __touppers, nelem(__touppers)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + +static Rune __tolowerr[] = { + 0x0041, 0x005a, 1048608, + 0x00c0, 0x00d6, 1048608, + 0x00d8, 0x00de, 1048608, + 0x0189, 0x018a, 1048781, + 0x01b1, 0x01b2, 1048793, + 0x0388, 0x038a, 1048613, + 0x038e, 0x038f, 1048639, + 0x0391, 0x03a1, 1048608, + 0x03a3, 0x03ab, 1048608, + 0x03fd, 0x03ff, 1048446, + 0x0400, 0x040f, 1048656, + 0x0410, 0x042f, 1048608, + 0x0531, 0x0556, 1048624, + 0x10a0, 0x10c5, 1055840, + 0x1f08, 0x1f0f, 1048568, + 0x1f18, 0x1f1d, 1048568, + 0x1f28, 0x1f2f, 1048568, + 0x1f38, 0x1f3f, 1048568, + 0x1f48, 0x1f4d, 1048568, + 0x1f68, 0x1f6f, 1048568, + 0x1f88, 0x1f8f, 1048568, + 0x1f98, 0x1f9f, 1048568, + 0x1fa8, 0x1faf, 1048568, + 0x1fb8, 0x1fb9, 1048568, + 0x1fba, 0x1fbb, 1048502, + 0x1fc8, 0x1fcb, 1048490, + 0x1fd8, 0x1fd9, 1048568, + 0x1fda, 0x1fdb, 1048476, + 0x1fe8, 0x1fe9, 1048568, + 0x1fea, 0x1feb, 1048464, + 0x1ff8, 0x1ff9, 1048448, + 0x1ffa, 0x1ffb, 1048450, + 0x2160, 0x216f, 1048592, + 0x24b6, 0x24cf, 1048602, + 0x2c00, 0x2c2e, 1048624, + 0x2c7e, 0x2c7f, 1037761, + 0xff21, 0xff3a, 1048608, + 0x10400, 0x10427, 1048616, +}; + +static Rune __tolowerp[] = { + 0x0100, 0x012e, 1048577, + 0x0132, 0x0136, 1048577, + 0x0139, 0x0147, 1048577, + 0x014a, 0x0176, 1048577, + 0x017b, 0x017d, 1048577, + 0x01a2, 0x01a4, 1048577, + 0x01b3, 0x01b5, 1048577, + 0x01cd, 0x01db, 1048577, + 0x01de, 0x01ee, 1048577, + 0x01f8, 0x021e, 1048577, + 0x0222, 0x0232, 1048577, + 0x0248, 0x024e, 1048577, + 0x0370, 0x0372, 1048577, + 0x03d8, 0x03ee, 1048577, + 0x0460, 0x0480, 1048577, + 0x048a, 0x04be, 1048577, + 0x04c3, 0x04cd, 1048577, + 0x04d0, 0x0526, 1048577, + 0x1e00, 0x1e94, 1048577, + 0x1ea0, 0x1efe, 1048577, + 0x1f59, 0x1f5f, 1048568, + 0x2c67, 0x2c6b, 1048577, + 0x2c80, 0x2ce2, 1048577, + 0x2ceb, 0x2ced, 1048577, + 0xa640, 0xa66c, 1048577, + 0xa680, 0xa696, 1048577, + 0xa722, 0xa72e, 1048577, + 0xa732, 0xa76e, 1048577, + 0xa779, 0xa77b, 1048577, + 0xa780, 0xa786, 1048577, + 0xa790, 0xa792, 1048577, + 0xa7a0, 0xa7a8, 1048577, +}; + +static Rune __tolowers[] = { + 0x0130, 1048377, + 0x0178, 1048455, + 0x0179, 1048577, + 0x0181, 1048786, + 0x0182, 1048577, + 0x0184, 1048577, + 0x0186, 1048782, + 0x0187, 1048577, + 0x018b, 1048577, + 0x018e, 1048655, + 0x018f, 1048778, + 0x0190, 1048779, + 0x0191, 1048577, + 0x0193, 1048781, + 0x0194, 1048783, + 0x0196, 1048787, + 0x0197, 1048785, + 0x0198, 1048577, + 0x019c, 1048787, + 0x019d, 1048789, + 0x019f, 1048790, + 0x01a0, 1048577, + 0x01a6, 1048794, + 0x01a7, 1048577, + 0x01a9, 1048794, + 0x01ac, 1048577, + 0x01ae, 1048794, + 0x01af, 1048577, + 0x01b7, 1048795, + 0x01b8, 1048577, + 0x01bc, 1048577, + 0x01c4, 1048578, + 0x01c5, 1048577, + 0x01c7, 1048578, + 0x01c8, 1048577, + 0x01ca, 1048578, + 0x01cb, 1048577, + 0x01f1, 1048578, + 0x01f2, 1048577, + 0x01f4, 1048577, + 0x01f6, 1048479, + 0x01f7, 1048520, + 0x0220, 1048446, + 0x023a, 1059371, + 0x023b, 1048577, + 0x023d, 1048413, + 0x023e, 1059368, + 0x0241, 1048577, + 0x0243, 1048381, + 0x0244, 1048645, + 0x0245, 1048647, + 0x0246, 1048577, + 0x0376, 1048577, + 0x0386, 1048614, + 0x038c, 1048640, + 0x03cf, 1048584, + 0x03f4, 1048516, + 0x03f7, 1048577, + 0x03f9, 1048569, + 0x03fa, 1048577, + 0x04c0, 1048591, + 0x04c1, 1048577, + 0x10c7, 1055840, + 0x10cd, 1055840, + 0x1e9e, 1040961, + 0x1fbc, 1048567, + 0x1fcc, 1048567, + 0x1fec, 1048569, + 0x1ffc, 1048567, + 0x2126, 1041059, + 0x212a, 1040193, + 0x212b, 1040314, + 0x2132, 1048604, + 0x2183, 1048577, + 0x2c60, 1048577, + 0x2c62, 1037833, + 0x2c63, 1044762, + 0x2c64, 1037849, + 0x2c6d, 1037796, + 0x2c6e, 1037827, + 0x2c6f, 1037793, + 0x2c70, 1037794, + 0x2c72, 1048577, + 0x2c75, 1048577, + 0x2cf2, 1048577, + 0xa77d, 1013244, + 0xa77e, 1048577, + 0xa78b, 1048577, + 0xa78d, 1006296, + 0xa7aa, 1006268, +}; + +Rune +tolowerrune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __tolowerr, nelem(__tolowerr)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = _runebsearch(c, __tolowerp, nelem(__tolowerp)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = _runebsearch(c, __tolowers, nelem(__tolowers)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + +static Rune __totitler[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, +}; + +static Rune __totitlep[] = { + 0x0101, 0x012f, 1048575, + 0x0133, 0x0137, 1048575, + 0x013a, 0x0148, 1048575, + 0x014b, 0x0177, 1048575, + 0x017a, 0x017e, 1048575, + 0x0183, 0x0185, 1048575, + 0x01a1, 0x01a5, 1048575, + 0x01b4, 0x01b6, 1048575, + 0x01cc, 0x01dc, 1048575, + 0x01df, 0x01ef, 1048575, + 0x01f3, 0x01f5, 1048575, + 0x01f9, 0x021f, 1048575, + 0x0223, 0x0233, 1048575, + 0x0247, 0x024f, 1048575, + 0x0371, 0x0373, 1048575, + 0x03d9, 0x03ef, 1048575, + 0x0461, 0x0481, 1048575, + 0x048b, 0x04bf, 1048575, + 0x04c2, 0x04ce, 1048575, + 0x04d1, 0x0527, 1048575, + 0x1e01, 0x1e95, 1048575, + 0x1ea1, 0x1eff, 1048575, + 0x1f51, 0x1f57, 1048584, + 0x2c68, 0x2c6c, 1048575, + 0x2c81, 0x2ce3, 1048575, + 0x2cec, 0x2cee, 1048575, + 0xa641, 0xa66d, 1048575, + 0xa681, 0xa697, 1048575, + 0xa723, 0xa72f, 1048575, + 0xa733, 0xa76f, 1048575, + 0xa77a, 0xa77c, 1048575, + 0xa77f, 0xa787, 1048575, + 0xa791, 0xa793, 1048575, + 0xa7a1, 0xa7a9, 1048575, +}; + +static Rune __totitles[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0131, 1048344, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c4, 1048577, + 0x01c6, 1048575, + 0x01c7, 1048577, + 0x01c9, 1048575, + 0x01ca, 1048577, + 0x01dd, 1048497, + 0x01f1, 1048577, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x0260, 1048371, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x0345, 1048660, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x04cf, 1048561, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e9b, 1048517, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa78c, 1048575, +}; + +Rune +totitlerune(Rune c) +{ + Rune *p; + + p = _runebsearch(c, __totitler, nelem(__totitler)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = _runebsearch(c, __totitlep, nelem(__totitlep)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = _runebsearch(c, __totitles, nelem(__totitles)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + diff --git a/sys/src/libc/port/sin.c b/sys/src/libc/port/sin.c new file mode 100644 index 0000000..7e1688f --- /dev/null +++ b/sys/src/libc/port/sin.c @@ -0,0 +1,77 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + C program for floating point sin/cos. + Calls modf. + There are no error exits. + Coefficients are #3370 from Hart & Cheney (18.80D). +*/ + +#include +#include + +#define p0 .1357884097877375669092680e8 +#define p1 -.4942908100902844161158627e7 +#define p2 .4401030535375266501944918e6 +#define p3 -.1384727249982452873054457e5 +#define p4 .1459688406665768722226959e3 +#define q0 .8644558652922534429915149e7 +#define q1 .4081792252343299749395779e6 +#define q2 .9463096101538208180571257e4 +#define q3 .1326534908786136358911494e3 + +static +double +sinus(double arg, int quad) +{ + double e, f, ysq, x, y, temp1, temp2; + int k; + + x = arg; + if(x < 0) { + x = -x; + quad += 2; + } + x *= 1/PIO2; /* underflow? */ + if(x > 32764) { + y = modf(x, &e); + e += quad; + modf(0.25*e, &f); + quad = e - 4*f; + } else { + k = x; + y = x - k; + quad += k; + quad &= 3; + } + if(quad & 1) + y = 1-y; + if(quad > 1) + y = -y; + + ysq = y*y; + temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y; + temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0); + return temp1/temp2; +} + +double +cos(double arg) +{ + if(arg < 0) + arg = -arg; + return sinus(arg, 1); +} + +double +sin(double arg) +{ + return sinus(arg, 0); +} diff --git a/sys/src/libc/port/sinh.c b/sys/src/libc/port/sinh.c new file mode 100644 index 0000000..85a8893 --- /dev/null +++ b/sys/src/libc/port/sinh.c @@ -0,0 +1,71 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * sinh(arg) returns the hyperbolic sine of its floating- + * point argument. + * + * The exponential function is called for arguments + * greater in magnitude than 0.5. + * + * A series is used for arguments smaller in magnitude than 0.5. + * The coefficients are #2029 from Hart & Cheney. (20.36D) + * + * cosh(arg) is computed from the exponential function for + * all arguments. + */ + +static double p0 = -0.6307673640497716991184787251e+6; +static double p1 = -0.8991272022039509355398013511e+5; +static double p2 = -0.2894211355989563807284660366e+4; +static double p3 = -0.2630563213397497062819489e+2; +static double q0 = -0.6307673640497716991212077277e+6; +static double q1 = 0.1521517378790019070696485176e+5; +static double q2 = -0.173678953558233699533450911e+3; + +double +sinh(double arg) +{ + double temp, argsq; + int sign; + + sign = 0; + if(arg < 0) { + arg = -arg; + sign++; + } + if(arg > 21) { + temp = exp(arg)/2; + goto out; + } + if(arg > 0.5) { + temp = (exp(arg) - exp(-arg))/2; + goto out; + } + argsq = arg*arg; + temp = (((p3*argsq+p2)*argsq+p1)*argsq+p0)*arg; + temp /= (((argsq+q2)*argsq+q1)*argsq+q0); +out: + if(sign) + temp = -temp; + return temp; +} + +double +cosh(double arg) +{ + if(arg < 0) + arg = - arg; + if(arg > 21) + return exp(arg)/2; + return (exp(arg) + exp(-arg))/2; +} diff --git a/sys/src/libc/port/strcat.c b/sys/src/libc/port/strcat.c new file mode 100644 index 0000000..ec2b6f0 --- /dev/null +++ b/sys/src/libc/port/strcat.c @@ -0,0 +1,19 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strcat(char *s1, const char *s2) +{ + + strcpy(strchr(s1, 0), s2); + return s1; +} diff --git a/sys/src/libc/port/strchr.c b/sys/src/libc/port/strchr.c new file mode 100644 index 0000000..5261ec7 --- /dev/null +++ b/sys/src/libc/port/strchr.c @@ -0,0 +1,29 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strchr(const char *s, int c) +{ + char c0 = c; + char c1; + + if(c == 0) { + while(*s++) + ; + return (char*)s-1; + } + + while(c1 = *s++) + if(c1 == c0) + return (char*)s-1; + return 0; +} diff --git a/sys/src/libc/port/strcmp.c b/sys/src/libc/port/strcmp.c new file mode 100644 index 0000000..b2f5199 --- /dev/null +++ b/sys/src/libc/port/strcmp.c @@ -0,0 +1,29 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +strcmp(const char *s1, const char *s2) +{ + unsigned c1, c2; + + for(;;) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + return 0; + } +} diff --git a/sys/src/libc/port/strcpy.c b/sys/src/libc/port/strcpy.c new file mode 100644 index 0000000..bfa21c4 --- /dev/null +++ b/sys/src/libc/port/strcpy.c @@ -0,0 +1,25 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#define N 10000 + +char* +strcpy(char *s1, const char *s2) +{ + char *os1; + + os1 = s1; + while(!memccpy(s1, s2, 0, N)) { + s1 += N; + s2 += N; + } + return os1; +} diff --git a/sys/src/libc/port/strcspn.c b/sys/src/libc/port/strcspn.c new file mode 100644 index 0000000..dfb1f73 --- /dev/null +++ b/sys/src/libc/port/strcspn.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define N 256 + +int32_t +strcspn(const char *s, const char *b) +{ + const char *os; + char map[N]; + + memset(map, 0, N); + for(;;) { + map[*(uint8_t*)b] = 1; + if(*b++ == 0) + break; + } + os = s; + while(map[*(uint8_t*)s++] == 0) + ; + return s - os - 1; +} diff --git a/sys/src/libc/port/strdup.c b/sys/src/libc/port/strdup.c new file mode 100644 index 0000000..8a8aa69 --- /dev/null +++ b/sys/src/libc/port/strdup.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strdup(const char *s) +{ + char *ns; + + ns = malloc(strlen(s) + 1); + if(ns == 0) + return 0; + setmalloctag(ns, getcallerpc()); + + return strcpy(ns, s); +} diff --git a/sys/src/libc/port/strecpy.c b/sys/src/libc/port/strecpy.c new file mode 100644 index 0000000..3c5f42d --- /dev/null +++ b/sys/src/libc/port/strecpy.c @@ -0,0 +1,26 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strecpy(char *to, char *e, const char *from) +{ + if(to >= e) + return to; + to = memccpy(to, from, '\0', e - to); + if(to == nil){ + to = e - 1; + *to = '\0'; + }else{ + to--; + } + return to; +} diff --git a/sys/src/libc/port/strlen.c b/sys/src/libc/port/strlen.c new file mode 100644 index 0000000..e115683 --- /dev/null +++ b/sys/src/libc/port/strlen.c @@ -0,0 +1,18 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int32_t +strlen(const char *s) +{ + + return strchr(s, 0) - s; +} diff --git a/sys/src/libc/port/strncat.c b/sys/src/libc/port/strncat.c new file mode 100644 index 0000000..8f858f4 --- /dev/null +++ b/sys/src/libc/port/strncat.c @@ -0,0 +1,28 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strncat(char *s1, const char *s2, int32_t n) +{ + char *os1; + + os1 = s1; + while(*s1++) + ; + s1--; + while(*s1++ = *s2++) + if(--n < 0) { + s1[-1] = 0; + break; + } + return os1; +} diff --git a/sys/src/libc/port/strncmp.c b/sys/src/libc/port/strncmp.c new file mode 100644 index 0000000..595e706 --- /dev/null +++ b/sys/src/libc/port/strncmp.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +strncmp(const char *s1, const char *s2, int32_t n) +{ + unsigned c1, c2; + + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + n--; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + break; + } + return 0; +} diff --git a/sys/src/libc/port/strncpy.c b/sys/src/libc/port/strncpy.c new file mode 100644 index 0000000..553f015 --- /dev/null +++ b/sys/src/libc/port/strncpy.c @@ -0,0 +1,27 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strncpy(char *s1, const char *s2, uint32_t n) +{ + int i; + char *os1; + + os1 = s1; + for(i = 0; i < n; i++) + if((*s1++ = *s2++) == 0) { + while(++i < n) + *s1++ = 0; + return os1; + } + return os1; +} diff --git a/sys/src/libc/port/strpbrk.c b/sys/src/libc/port/strpbrk.c new file mode 100644 index 0000000..7c78dd3 --- /dev/null +++ b/sys/src/libc/port/strpbrk.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#define N 256 + +char* +strpbrk(const char *cs, const char *cb) +{ + char map[N]; + uint8_t *s=(uint8_t*)cs, *b=(uint8_t*)cb; + + memset(map, 0, N); + for(;;) { + map[*b] = 1; + if(*b++ == 0) + break; + } + while(map[*s++] == 0) + ; + if(*--s) + return (char*)s; + return 0; +} diff --git a/sys/src/libc/port/strrchr.c b/sys/src/libc/port/strrchr.c new file mode 100644 index 0000000..d5847cf --- /dev/null +++ b/sys/src/libc/port/strrchr.c @@ -0,0 +1,24 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +strrchr(const char *s, int c) +{ + const char *r; + + if(c == 0) + return strchr(s, 0); + r = 0; + while(s = strchr(s, c)) + r = s++; + return (char *)r; +} diff --git a/sys/src/libc/port/strspn.c b/sys/src/libc/port/strspn.c new file mode 100644 index 0000000..7c17d92 --- /dev/null +++ b/sys/src/libc/port/strspn.c @@ -0,0 +1,28 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define N 256 + +int32_t +strspn(const char *s, const char *b) +{ + const char *os; + char map[N]; + + memset(map, 0, N); + while(*b) + map[*(uint8_t *)b++] = 1; + os = s; + while(map[*(uint8_t *)s++]) + ; + return s - os - 1; +} diff --git a/sys/src/libc/port/strstr.c b/sys/src/libc/port/strstr.c new file mode 100644 index 0000000..f7d0089 --- /dev/null +++ b/sys/src/libc/port/strstr.c @@ -0,0 +1,38 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +char* +strstr(const char *s1, const char *s2) +{ + const char *p, *pa, *pb; + int c0, c; + + c0 = *s2; + if(c0 == 0) + return (char*)s1; + s2++; + for(p=strchr(s1, c0); p; p=strchr(p+1, c0)) { + pa = p; + for(pb=s2;; pb++) { + c = *pb; + if(c == 0) + return (char*)p; + if(c != *++pa) + break; + } + } + return 0; +} diff --git a/sys/src/libc/port/strtod.c b/sys/src/libc/port/strtod.c new file mode 100644 index 0000000..87a3884 --- /dev/null +++ b/sys/src/libc/port/strtod.c @@ -0,0 +1,530 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +#include + +/* + * This routine will convert to arbitrary precision + * floating point entirely in multi-precision fixed. + * The answer is the closest floating point number to + * the given decimal number. Exactly half way are + * rounded ala ieee rules. + * Method is to scale input decimal between .500 and .999... + * with external power of 2, then binary search for the + * closest mantissa to this decimal number. + * Nmant is is the required precision. (53 for ieee dp) + * Nbits is the max number of bits/word. (must be <= 28) + * Prec is calculated - the number of words of fixed mantissa. + */ +enum +{ + Nbits = 28, // bits safely represented in a ulong + Nmant = 53, // bits of precision required + Bias = 1022, + Prec = (Nmant+Nbits+1)/Nbits, // words of Nbits each to represent mantissa + Sigbit = 1<<(Prec*Nbits-Nmant), // first significant bit of Prec-th word + Ndig = 1500, + One = (uint32_t)(1<>1), + Maxe = 310, + Fsign = 1<<0, // found - + Fesign = 1<<1, // found e- + Fdpoint = 1<<2, // found . + + S0 = 0, // _ _S0 +S1 #S2 .S3 + S1, // _+ #S2 .S3 + S2, // _+# #S2 .S4 eS5 + S3, // _+. #S4 + S4, // _+#.# #S4 eS5 + S5, // _+#.#e +S6 #S7 + S6, // _+#.#e+ #S7 + S7, // _+#.#e+# #S7 +}; + +static int xcmp(const char*, char*); +static int fpcmp(char*, uint32_t*); +static void frnorm(uint32_t*); +static void divascii(char*, int*, int*, int*); +static void mulascii(char*, int*, int*, int*); +static void divby(char*, int*, int); + +typedef struct Tab Tab; +struct Tab +{ + int bp; + int siz; + char* cmp; +}; + +double +strtod(const char *as, const char **aas) +{ + int na, ona, ex, dp, bp, c, i, flag, state; + uint32_t low[Prec], hig[Prec], mid[Prec], num, den; + double d; + const char *s; + char a[Ndig]; + + flag = 0; // Fsign, Fesign, Fdpoint + na = 0; // number of digits of a[] + dp = 0; // na of decimal point + ex = 0; // exonent + + state = S0; + for(s=as;; s++) { + c = *s; + if(c >= '0' && c <= '9') { + switch(state) { + case S0: + case S1: + case S2: + state = S2; + break; + case S3: + case S4: + state = S4; + break; + + case S5: + case S6: + case S7: + state = S7; + ex = ex*10 + (c-'0'); + continue; + } + if(na == 0 && c == '0') { + dp--; + continue; + } + if(na < Ndig-50) + a[na++] = c; + continue; + } + switch(c) { + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + if(state == S0) + continue; + break; + case '-': + if(state == S0) + flag |= Fsign; + else + flag |= Fesign; + case '+': + if(state == S0) + state = S1; + else + if(state == S5) + state = S6; + else + break; // syntax + continue; + case '.': + flag |= Fdpoint; + dp = na; + if(state == S0 || state == S1) { + state = S3; + continue; + } + if(state == S2) { + state = S4; + continue; + } + break; + case 'e': + case 'E': + if(state == S2 || state == S4) { + state = S5; + continue; + } + break; + } + break; + } + + /* + * clean up return char-pointer + */ + switch(state) { + case S0: + if(xcmp(s, "nan") == 0) { + if(aas != nil) + *aas = s+3; + goto retnan; + } + case S1: + if(xcmp(s, "infinity") == 0) { + if(aas != nil) + *aas = s+8; + goto retinf; + } + if(xcmp(s, "inf") == 0) { + if(aas != nil) + *aas = s+3; + goto retinf; + } + case S3: + if(aas != nil) + *aas = as; + goto ret0; // no digits found + case S6: + s--; // back over +- + case S5: + s--; // back over e + break; + } + if(aas != nil) + *aas = s; + + if(flag & Fdpoint) + while(na > 0 && a[na-1] == '0') + na--; + if(na == 0) + goto ret0; // zero + a[na] = 0; + if(!(flag & Fdpoint)) + dp = na; + if(flag & Fesign) + ex = -ex; + dp += ex; + if(dp < -Maxe-Nmant/3) /* actually -Nmant*log(2)/log(10), but Nmant/3 close enough */ + goto ret0; // underflow by exp + else + if(dp > +Maxe) + goto retinf; // overflow by exp + + /* + * normalize the decimal ascii number + * to range .[5-9][0-9]* e0 + */ + bp = 0; // binary exponent + while(dp > 0) + divascii(a, &na, &dp, &bp); + while(dp < 0 || a[0] < '5') + mulascii(a, &na, &dp, &bp); + a[na] = 0; + + /* + * very small numbers are represented using + * bp = -Bias+1. adjust accordingly. + */ + if(bp < -Bias+1){ + ona = na; + divby(a, &na, -bp-Bias+1); + if(na < ona){ + memmove(a+ona-na, a, na); + memset(a, '0', ona-na); + na = ona; + } + a[na] = 0; + bp = -Bias+1; + } + + /* close approx by naive conversion */ + num = 0; + den = 1; + for(i=0; i<9 && (c=a[i]); i++) { + num = num*10 + (c-'0'); + den *= 10; + } + low[0] = umuldiv(num, One, den); + hig[0] = umuldiv(num+1, One, den); + for(i=1; i>= 1; + } + frnorm(mid); + + /* compare */ + c = fpcmp(a, mid); + if(c > 0) { + c = 1; + for(i=0; i= Sigbit/2) { + mid[Prec-1] += Sigbit; + frnorm(mid); + } + d = 0; + for(i=0; i0; i--) { + f[i] += c; + c = f[i] >> Nbits; + f[i] &= One-1; + } + f[0] += c; +} + +static int +fpcmp(char *a, uint32_t* f) +{ + uint32_t tf[Prec]; + int i, d, c; + + for(i=0; i> Nbits) + '0'; + tf[0] &= One-1; + + /* compare next digit */ + c = *a; + if(c == 0) { + if('0' < d) + return -1; + if(tf[0] != 0) + goto cont; + for(i=1; i d) + return +1; + if(c < d) + return -1; + a++; + cont:; + } +} + +static void +_divby(char *a, int *na, int b) +{ + int n, c; + char *p; + + p = a; + n = 0; + while(n>>b == 0) { + c = *a++; + if(c == 0) { + while(n) { + c = n*10; + if(c>>b) + break; + n = c; + } + goto xx; + } + n = n*10 + c-'0'; + (*na)--; + } + for(;;) { + c = n>>b; + n -= c<>b; + n -= c< 9){ + _divby(a, na, 9); + a[*na] = 0; + b -= 9; + } + if(b > 0) + _divby(a, na, b); +} + +static Tab tab1[] = +{ + 1, 0, "", + 3, 1, "7", + 6, 2, "63", + 9, 3, "511", + 13, 4, "8191", + 16, 5, "65535", + 19, 6, "524287", + 23, 7, "8388607", + 26, 8, "67108863", + 27, 9, "134217727", +}; + +static void +divascii(char *a, int *na, int *dp, int *bp) +{ + int b, d; + Tab *t; + + d = *dp; + if(d >= nelem(tab1)) + d = nelem(tab1)-1; + t = tab1 + d; + b = t->bp; + if(memcmp(a, t->cmp, t->siz) > 0) + d--; + *dp -= d; + *bp += b; + divby(a, na, b); +} + +static void +mulby(char *a, char *p, char *q, int b) +{ + int n, c; + + n = 0; + *p = 0; + for(;;) { + q--; + if(q < a) + break; + c = *q - '0'; + c = (c<= nelem(tab2)) + d = nelem(tab2)-1; + t = tab2 + d; + b = t->bp; + if(memcmp(a, t->cmp, t->siz) < 0) + d--; + p = a + *na; + *bp -= b; + *dp += d; + *na += d; + mulby(a, p+d, p, b); +} + +static int +xcmp(const char *a, char *b) +{ + int c1, c2; + + while(c1 = *b++) { + c2 = *a++; + if(isupper(c2)) + c2 = tolower(c2); + if(c1 != c2) + return 1; + } + return 0; +} diff --git a/sys/src/libc/port/strtok.c b/sys/src/libc/port/strtok.c new file mode 100644 index 0000000..4957e01 --- /dev/null +++ b/sys/src/libc/port/strtok.c @@ -0,0 +1,39 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define N 256 + +char* +strtok(char *s, char *b) +{ + static char *under_rock; + char map[N], *os; + + memset(map, 0, N); + while(*b) + map[*(uint8_t*)b++] = 1; + if(s == 0) + s = under_rock; + while(map[*(uint8_t*)s++]) + ; + if(*--s == 0) + return 0; + os = s; + while(map[*(uint8_t*)s] == 0) + if(*s++ == 0) { + under_rock = s-1; + return os; + } + *s++ = 0; + under_rock = s; + return os; +} diff --git a/sys/src/libc/port/strtol.c b/sys/src/libc/port/strtol.c new file mode 100644 index 0000000..fc5aae5 --- /dev/null +++ b/sys/src/libc/port/strtol.c @@ -0,0 +1,110 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define LONG_MAX 2147483647L +#define LONG_MIN -2147483648L + +int32_t +strtol(const char *nptr, char **endptr, int base) +{ + const char *p; + int32_t n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0) { + base = 10; + if(*p == '0') { + base = 8; + if(p[1]=='x' || p[1]=='X') { + p += 2; + base = 16; + } + } + } else + if(base==16 && *p=='0'){ + if(p[1]=='x' || p[1]=='X') + p += 2; + } else + if(base<0 || 36= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = (char*)p; + if(ovfl){ + if(neg) + return LONG_MIN; + return LONG_MAX; + } + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoll.c b/sys/src/libc/port/strtoll.c new file mode 100644 index 0000000..16f8fa6 --- /dev/null +++ b/sys/src/libc/port/strtoll.c @@ -0,0 +1,110 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define VLONG_MAX ~(1LL<<63) +#define VLONG_MIN (1LL<<63) + +int64_t +strtoll(const char *nptr, char **endptr, int base) +{ + const char *p; + int64_t n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0){ + base = 10; + if(*p == '0') { + base = 8; + if(p[1]=='x' || p[1]=='X') { + p += 2; + base = 16; + } + } + } else + if(base==16 && *p=='0') { + if(p[1]=='x' || p[1]=='X') + p += 2; + } else + if(base<0 || 36= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = (char *)p; + if(ovfl){ + if(neg) + return VLONG_MIN; + return VLONG_MAX; + } + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoul.c b/sys/src/libc/port/strtoul.c new file mode 100644 index 0000000..b06c654 --- /dev/null +++ b/sys/src/libc/port/strtoul.c @@ -0,0 +1,106 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define ULONG_MAX 4294967295UL + +uint32_t +strtoul(const char *nptr, char **endptr, int base) +{ + const char *p; + uint32_t n, nn, m; + int c, ovfl, neg, v, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;;p++){ + switch(*p){ + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0){ + if(*p != '0') + base = 10; + else{ + base = 8; + if(p[1]=='x' || p[1]=='X') + base = 16; + } + } + if(base<2 || 36= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + + Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = (char*)p; + if(ovfl) + return ULONG_MAX; + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoull.c b/sys/src/libc/port/strtoull.c new file mode 100644 index 0000000..0f06b1f --- /dev/null +++ b/sys/src/libc/port/strtoull.c @@ -0,0 +1,106 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +#define UVLONG_MAX (1LL<<63) + +uint64_t +strtoull(const char *nptr, char **endptr, int base) +{ + const char *p; + uint64_t n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p == '-' || *p == '+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base == 0) { + base = 10; + if(*p == '0') { + base = 8; + if(p[1] == 'x' || p[1] == 'X'){ + p += 2; + base = 16; + } + } + } else + if(base == 16 && *p == '0') { + if(p[1] == 'x' || p[1] == 'X') + p += 2; + } else + if(base < 0 || 36 < base) + goto Return; + + /* + * Non-empty sequence of digits + */ + m = UVLONG_MAX/base; + for(;; p++,ndig++) { + c = *p; + v = base; + if('0' <= c && c <= '9') + v = c - '0'; + else + if('a' <= c && c <= 'z') + v = c - 'a' + 10; + else + if('A' <= c && c <= 'Z') + v = c - 'A' + 10; + if(v >= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = (char *)p; + if(ovfl) + return UVLONG_MAX; + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/tan.c b/sys/src/libc/port/tan.c new file mode 100644 index 0000000..06178ca --- /dev/null +++ b/sys/src/libc/port/tan.c @@ -0,0 +1,76 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +/* + floating point tangent + + A series is used after range reduction. + Coefficients are #4285 from Hart & Cheney. (19.74D) + */ + +#include +#include + +static double p0 = -0.1306820264754825668269611177e+5; +static double p1 = 0.1055970901714953193602353981e+4; +static double p2 = -0.1550685653483266376941705728e+2; +static double p3 = 0.3422554387241003435328470489e-1; +static double p4 = 0.3386638642677172096076369e-4; +static double q0 = -0.1663895238947119001851464661e+5; +static double q1 = 0.4765751362916483698926655581e+4; +static double q2 = -0.1555033164031709966900124574e+3; + +double +tan(double arg) +{ + double temp, e, x, xsq; + int flag, sign, i; + + flag = 0; + sign = 0; + if(arg < 0){ + arg = -arg; + sign++; + } + arg = 2*arg/PIO2; /* overflow? */ + x = modf(arg, &e); + i = e; + switch(i%4) { + case 1: + x = 1 - x; + flag = 1; + break; + + case 2: + sign = !sign; + flag = 1; + break; + + case 3: + x = 1 - x; + sign = !sign; + break; + + case 0: + break; + } + + xsq = x*x; + temp = ((((p4*xsq+p3)*xsq+p2)*xsq+p1)*xsq+p0)*x; + temp = temp/(((xsq+q2)*xsq+q1)*xsq+q0); + + if(flag) { + if(temp == 0) + return NaN(); + temp = 1/temp; + } + if(sign) + temp = -temp; + return temp; +} diff --git a/sys/src/libc/port/tanh.c b/sys/src/libc/port/tanh.c new file mode 100644 index 0000000..7397966 --- /dev/null +++ b/sys/src/libc/port/tanh.c @@ -0,0 +1,34 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +/* + tanh(arg) computes the hyperbolic tangent of its floating + point argument. + + sinh and cosh are called except for large arguments, which + would cause overflow improperly. + */ + +double +tanh(double arg) +{ + + if(arg < 0) { + arg = -arg; + if(arg > 21) + return -1; + return -sinh(arg)/cosh(arg); + } + if(arg > 21) + return 1; + return sinh(arg)/cosh(arg); +} diff --git a/sys/src/libc/port/tokenize.c b/sys/src/libc/port/tokenize.c new file mode 100644 index 0000000..9b40c3c --- /dev/null +++ b/sys/src/libc/port/tokenize.c @@ -0,0 +1,116 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +static char qsep[] = " \t\r\n"; + +static char* +qtoken(char *s, char *sep) +{ + int quoting; + char *t; + + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(*s != '\0'){ + *s = '\0'; + if(t == s) + t++; + } + return t; +} + +static char* +etoken(char *t, const char *sep) +{ + int quoting; + + /* move to end of next token */ + quoting = 0; + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t += 2; + } + return (char*)t; +} + +int +gettokens(char *s, char **args, int maxargs, const char *sep) +{ + int nargs; + + for(nargs=0; nargs + +int +toupper(int c) +{ + + if(c < 'a' || c > 'z') + return c; + return _toupper(c); +} + +int +tolower(int c) +{ + + if(c < 'A' || c > 'Z') + return c; + return _tolower(c); +} diff --git a/sys/src/libc/port/u16.c b/sys/src/libc/port/u16.c new file mode 100644 index 0000000..c8069c5 --- /dev/null +++ b/sys/src/libc/port/u16.c @@ -0,0 +1,62 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include +static char t16e[] = "0123456789ABCDEF"; + +int +dec16(uint8_t *out, int lim, const char *in, int n) +{ + int c, w = 0, i = 0; + uint8_t *start = out; + uint8_t *eout = out + lim; + + while(n-- > 0){ + c = *in++; + if('0' <= c && c <= '9') + c = c - '0'; + else if('a' <= c && c <= 'z') + c = c - 'a' + 10; + else if('A' <= c && c <= 'Z') + c = c - 'A' + 10; + else + continue; + w = (w<<4) + c; + i++; + if(i == 2){ + if(out + 1 > eout) + goto exhausted; + *out++ = w; + w = 0; + i = 0; + } + } +exhausted: + return out - start; +} + +int +enc16(char *out, int lim, const uint8_t *in, int n) +{ + uint c; + char *eout = out + lim; + char *start = out; + + while(n-- > 0){ + c = *in++; + if(out + 2 >= eout) + goto exhausted; + *out++ = t16e[c>>4]; + *out++ = t16e[c&0xf]; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/sys/src/libc/port/u32.c b/sys/src/libc/port/u32.c new file mode 100644 index 0000000..2f3c900 --- /dev/null +++ b/sys/src/libc/port/u32.c @@ -0,0 +1,119 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +dec32(uint8_t *dest, int ndest, const char *src, int nsrc) +{ + char *s, *tab; + uint8_t *start; + int i, u[8]; + + if(ndest+1 < (5*nsrc+7)/8) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=8){ + for(i=0; i<8; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + *dest++ = ((0x7 & u[6])<<5) | u[7]; + src += 8; + nsrc -= 8; + } + if(nsrc > 0){ + if(nsrc == 1 || nsrc == 3 || nsrc == 6) + return -1; + for(i=0; i>2)); + if(nsrc == 2) + goto out; + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + if(nsrc == 4) + goto out; + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + if(nsrc == 5) + goto out; + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + } +out: + return dest-start; +} + +int +enc32(char *dest, int ndest, const uint8_t *src, int nsrc) +{ + char *tab, *start; + int j; + + if(ndest <= (8*nsrc+4)/5 ) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=5){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); + *dest++ = tab[j]; + j = (0x1f & (src[4])); + *dest++ = tab[j]; + src += 5; + nsrc -= 5; + } + if(nsrc){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)); + if(nsrc == 1) + goto out; + j |= (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + if(nsrc == 2) + goto out; + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)); + if(nsrc == 3) + goto out; + j |= (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)); + if(nsrc == 4) + goto out; + j |= (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)); +out: + *dest++ = tab[j]; + } + *dest = 0; + return dest-start; +} diff --git a/sys/src/libc/port/u64.c b/sys/src/libc/port/u64.c new file mode 100644 index 0000000..cd2a0dd --- /dev/null +++ b/sys/src/libc/port/u64.c @@ -0,0 +1,136 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +enum { + INVAL= 255 +}; + +static uint8_t t64d[256] = { + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL +}; +static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +int +dec64(uint8_t *out, int lim, const char *in, int n) +{ + uint32_t b24; + uint8_t *start = out; + uint8_t *e = out + lim; + int i, c; + + b24 = 0; + i = 0; + while(n-- > 0){ + + c = t64d[*(uint8_t*)in++]; + if(c == INVAL) + continue; + switch(i){ + case 0: + b24 = c<<18; + break; + case 1: + b24 |= c<<12; + break; + case 2: + b24 |= c<<6; + break; + case 3: + if(out + 3 > e) + goto exhausted; + + b24 |= c; + *out++ = b24>>16; + *out++ = b24>>8; + *out++ = b24; + i = -1; + break; + } + i++; + } + switch(i){ + case 2: + if(out + 1 > e) + goto exhausted; + *out++ = b24>>16; + break; + case 3: + if(out + 2 > e) + goto exhausted; + *out++ = b24>>16; + *out++ = b24>>8; + break; + } +exhausted: + return out - start; +} + +int +enc64(char *out, int lim, const uint8_t *in, int n) +{ + int i; + uint32_t b24; + char *start = out; + char *e = out + lim; + + for(i = n/3; i > 0; i--){ + b24 = (*in++)<<16; + b24 |= (*in++)<<8; + b24 |= *in++; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = t64e[(b24)&0x3f]; + } + + switch(n%3){ + case 2: + b24 = (*in++)<<16; + b24 |= (*in)<<8; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = '='; + break; + case 1: + b24 = (*in)<<16; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = '='; + *out++ = '='; + break; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/sys/src/libc/port/utfecpy.c b/sys/src/libc/port/utfecpy.c new file mode 100644 index 0000000..0871ab7 --- /dev/null +++ b/sys/src/libc/port/utfecpy.c @@ -0,0 +1,30 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +utfecpy(char *to, char *e, const char *from) +{ + char *end; + + if(to >= e) + return to; + end = memccpy(to, from, '\0', e - to); + if(end == nil){ + end = e; + while(end>to && (*--end&0xC0)==0x80) + ; + *end = '\0'; + }else{ + end--; + } + return end; +} diff --git a/sys/src/libc/port/utflen.c b/sys/src/libc/port/utflen.c new file mode 100644 index 0000000..95d63cf --- /dev/null +++ b/sys/src/libc/port/utflen.c @@ -0,0 +1,31 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +utflen(const char *s) +{ + int c; + int32_t n; + Rune rune; + + n = 0; + for(;;) { + c = *(uint8_t*)s; + if(c < Runeself) { + if(c == 0) + return n; + s++; + } else + s += chartorune(&rune, s); + n++; + } +} diff --git a/sys/src/libc/port/utfnlen.c b/sys/src/libc/port/utfnlen.c new file mode 100644 index 0000000..16f1f15 --- /dev/null +++ b/sys/src/libc/port/utfnlen.c @@ -0,0 +1,35 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +int +utfnlen(const char *s, int32_t m) +{ + int c; + int32_t n; + Rune rune; + const char *es; + + es = s + m; + for(n = 0; s < es; n++) { + c = *(uint8_t*)s; + if(c < Runeself){ + if(c == '\0') + break; + s++; + continue; + } + if(!fullrune(s, es-s)) + break; + s += chartorune(&rune, s); + } + return n; +} diff --git a/sys/src/libc/port/utfrrune.c b/sys/src/libc/port/utfrrune.c new file mode 100644 index 0000000..af769bf --- /dev/null +++ b/sys/src/libc/port/utfrrune.c @@ -0,0 +1,39 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +utfrrune(const char *s, Rune c) +{ + int32_t c1; + Rune r; + const char *s1; + + if(c < Runesync) /* not part of utf sequence */ + return strrchr(s, c); + + s1 = 0; + for(;;) { + c1 = *(uint8_t*)s; + if(c1 < Runeself) { /* one byte rune */ + if(c1 == 0) + return (char *)s1; + if(c1 == c) + s1 = s; + s++; + continue; + } + c1 = chartorune(&r, s); + if(r == c) + s1 = s; + s += c1; + } +} diff --git a/sys/src/libc/port/utfrune.c b/sys/src/libc/port/utfrune.c new file mode 100644 index 0000000..6d5a2b1 --- /dev/null +++ b/sys/src/libc/port/utfrune.c @@ -0,0 +1,38 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + +char* +utfrune(const char *s, Rune c) +{ + int32_t c1; + Rune r; + int n; + + if(c < Runesync) /* not part of utf sequence */ + return strchr(s, c); + + for(;;) { + c1 = *(uint8_t*)s; + if(c1 < Runeself) { /* one byte rune */ + if(c1 == 0) + return 0; + if(c1 == c) + return (char*)s; + s++; + continue; + } + n = chartorune(&r, s); + if(r == c) + return (char*)s; + s += n; + } +} diff --git a/sys/src/libc/port/utfutf.c b/sys/src/libc/port/utfutf.c new file mode 100644 index 0000000..3c0ba2d --- /dev/null +++ b/sys/src/libc/port/utfutf.c @@ -0,0 +1,35 @@ +/* + * This file is part of the UCB release of Plan 9. It is subject to the license + * terms in the LICENSE file found in the top-level directory of this + * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No + * part of the UCB release of Plan 9, including this file, may be copied, + * modified, propagated, or distributed except according to the terms contained + * in the LICENSE file. + */ + +#include +#include + + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +char* +utfutf(const char *s1, const char *s2) +{ + const char *p; + int32_t f, n1, n2; + Rune r; + + n1 = chartorune(&r, s2); + f = r; + if(f <= Runesync) /* represents self */ + return strstr(s1, s2); + + n2 = strlen(s2); + for(p=s1; p=utfrune(p, f); p+=n1) + if(strncmp(p, s2, n2) == 0) + return (char*)p; + return 0; +} diff --git a/sys/src/libs.json b/sys/src/libs.json new file mode 100644 index 0000000..a79b675 --- /dev/null +++ b/sys/src/libs.json @@ -0,0 +1,7 @@ +{ + "libs.json": { + "Projects": [ + "/sys/src/libc/" + ] + } +} diff --git a/sys/src/sysconf.json b/sys/src/sysconf.json new file mode 100644 index 0000000..b94f7c4 --- /dev/null +++ b/sys/src/sysconf.json @@ -0,0 +1,702 @@ +{ + "Bootmethods": [ + { + "Arg": "", + "Config": "configtcp", + "Connect": "connecttcp", + "Name": "tcp" + }, + { + "Arg": "", + "Config": "configrc", + "Connect": "connectrc", + "Name": "rc" + }, + { + "Arg": "", + "Config": "configlocal", + "Connect": "connectlocal", + "Name": "local" + } + ], + "Syscalls": [ + { + "Args": [ + "char*", + "int32_t" + ], + "Id": 0, + "Name": "await", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int64_t" + ], + "Id": 1, + "Name": "awake", + "Ret": [ + "int64_t" + ] + }, + { + "Args": [ + "char*", + "char*", + "int32_t" + ], + "Id": 2, + "Name": "bind", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*" + ], + "Id": 3, + "Name": "chdir", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t" + ], + "Id": 4, + "Name": "close", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*", + "int32_t", + "int32_t" + ], + "Id": 5, + "Name": "create", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "int32_t" + ], + "Id": 6, + "Name": "dup", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*", + "uint32_t" + ], + "Id": 7, + "Name": "errstr", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*", + "char**" + ], + "Id": 8, + "Name": "exec", + "Ret": [ + "void*" + ] + }, + { + "Args": [ + "char*" + ], + "Id": 9, + "Libname": "_exits", + "Name": "exits", + "Ret": [ + "int32_t" + ] + }, + { + "Id": 10, + "Name": "fauth", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "char*", + "uint32_t" + ], + "Id": 11, + "Name": "fd2path", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "uint8_t*", + "uint32_t" + ], + "Id": 12, + "Name": "fstat", + "Ret": [ + "int32_t" + ] + }, + { + "Id": 13, + "Name": "fversion", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "uint8_t*", + "uint32_t" + ], + "Id": 14, + "Name": "fwstat", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "char*", + "int32_t", + "char*" + ], + "Id": 15, + "Name": "mount", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t" + ], + "Id": 16, + "Name": "noted", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "void*" + ], + "Id": 17, + "Name": "notify", + "Ret": [ + "int32_t" + ] + }, + { + "Id": 18, + "Name": "nsec", + "Ret": [ + "int64_t" + ] + }, + { + "Args": [ + "char*", + "int32_t" + ], + "Id": 19, + "Name": "open", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t*" + ], + "Id": 20, + "Name": "pipe", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "void*", + "int32_t", + "int64_t" + ], + "Id": 21, + "Name": "pread", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "void*", + "int32_t", + "int64_t" + ], + "Id": 22, + "Name": "pwrite", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*" + ], + "Id": 23, + "Name": "remove", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "void*" + ], + "Id": 24, + "Name": "rendezvous", + "Ret": [ + "void*" + ] + }, + { + "Args": [ + "int32_t" + ], + "Id": 25, + "Name": "rfork", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t", + "int64_t", + "int32_t" + ], + "Id": 26, + "Name": "seek", + "Ret": [ + "int64_t" + ] + }, + { + "Id": 27, + "Name": "segattach", + "Ret": [ + "void*" + ] + }, + { + "Id": 28, + "Name": "segbrk", + "Ret": [ + "void*" + ] + }, + { + "Id": 29, + "Name": "segdetach", + "Ret": [ + "int32_t" + ] + }, + { + "Id": 30, + "Name": "segflush", + "Ret": [ + "int32_t" + ] + }, + { + "Id": 31, + "Name": "segfree", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t*", + "int32_t" + ], + "Id": 32, + "Name": "semacquire", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t*", + "int32_t" + ], + "Id": 33, + "Name": "semrelease", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "int32_t*", + "uint64_t" + ], + "Id": 34, + "Name": "tsemacquire", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*", + "char*" + ], + "Id": 35, + "Name": "unmount", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "void*" + ], + "Id": 36, + "Name": "brk_", + "Ret": [ + "void*" + ] + }, + { + "Args": [ + "char*", + "uint8_t*", + "uint32_t" + ], + "Id": 37, + "Name": "stat", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "char*", + "uint8_t*", + "uint32_t" + ], + "Id": 38, + "Name": "wstat", + "Ret": [ + "int32_t" + ] + }, + { + "Args": [ + "uint64_t" + ], + "Id": 39, + "Name": "alarm", + "Ret": [ + "int64_t" + ] + } + ], + "Syserrors": [ + { + "Id": 0, + "Name": "Ebadarg", + "String": "bad arg in system call" + }, + { + "Id": 1, + "Name": "Ebadchar", + "String": "bad character in file name" + }, + { + "Id": 2, + "Name": "Ebadctl", + "String": "bad process or channel control request" + }, + { + "Id": 3, + "Name": "Ebadexec", + "String": "exec header invalid" + }, + { + "Id": 4, + "Name": "Ebadfd", + "String": "fd out of range or not open" + }, + { + "Id": 5, + "Name": "Ebadip", + "String": "bad ip address syntax" + }, + { + "Id": 6, + "Name": "Ebadsharp", + "String": "unknown device in # filename" + }, + { + "Id": 7, + "Name": "Ebadspec", + "String": "bad attach specifier" + }, + { + "Id": 8, + "Name": "Ebadstat", + "String": "malformed stat buffer" + }, + { + "Id": 9, + "Name": "Ebadusefd", + "String": "inappropriate use of fd" + }, + { + "Id": 10, + "Name": "Ecmdargs", + "String": "wrong #args in control message" + }, + { + "Id": 11, + "Name": "Econinuse", + "String": "connection in use" + }, + { + "Id": 12, + "Name": "Econrefused", + "String": "connection refused" + }, + { + "Id": 13, + "Name": "Edirseek", + "String": "seek in directory" + }, + { + "Id": 14, + "Name": "Eexist", + "String": "file already exists" + }, + { + "Id": 15, + "Name": "Efilename", + "String": "file name syntax" + }, + { + "Id": 16, + "Name": "Egreg", + "String": "ken has left the building" + }, + { + "Id": 17, + "Name": "Ehungup", + "String": "i/o on hungup channel" + }, + { + "Id": 18, + "Name": "Eintr", + "String": "interrupted" + }, + { + "Id": 19, + "Name": "Einuse", + "String": "device or object already in use" + }, + { + "Id": 20, + "Name": "Eio", + "String": "i/o error" + }, + { + "Id": 21, + "Name": "Eioload", + "String": "i/o error in demand load" + }, + { + "Id": 22, + "Name": "Eisdir", + "String": "file is a directory" + }, + { + "Id": 23, + "Name": "Eismtpt", + "String": "is a mount point" + }, + { + "Id": 24, + "Name": "Eisstream", + "String": "seek on a stream" + }, + { + "Id": 25, + "Name": "Emount", + "String": "inconsistent mount" + }, + { + "Id": 26, + "Name": "Emountrpc", + "String": "mount rpc error" + }, + { + "Id": 27, + "Name": "Emouseset", + "String": "mount rpc error" + }, + { + "Id": 28, + "Name": "Enegoff", + "String": "negative i/o offset" + }, + { + "Id": 29, + "Name": "Enoattach", + "String": "mount/attach disallowed" + }, + { + "Id": 30, + "Name": "Enochild", + "String": "no living children" + }, + { + "Id": 31, + "Name": "Enocreate", + "String": "mounted directory forbids creation" + }, + { + "Id": 32, + "Name": "Enodev", + "String": "no free devices" + }, + { + "Id": 33, + "Name": "Enoerror", + "String": "no error" + }, + { + "Id": 34, + "Name": "Enofd", + "String": "no free file descriptors" + }, + { + "Id": 35, + "Name": "Enomem", + "String": "kernel allocate failed" + }, + { + "Id": 36, + "Name": "Enonexist", + "String": "file does not exist" + }, + { + "Id": 37, + "Name": "Enoport", + "String": "network port not available" + }, + { + "Id": 38, + "Name": "Enoreg", + "String": "process has no saved registers" + }, + { + "Id": 39, + "Name": "Enoswap", + "String": "swap space full" + }, + { + "Id": 40, + "Name": "Enotdir", + "String": "not a directory" + }, + { + "Id": 41, + "Name": "Enovmem", + "String": "virtual memory allocation failed" + }, + { + "Id": 42, + "Name": "Eperm", + "String": "permission denied" + }, + { + "Id": 43, + "Name": "Eprocdied", + "String": "process exited" + }, + { + "Id": 44, + "Name": "Eshort", + "String": "i/o count too small" + }, + { + "Id": 45, + "Name": "Eshortstat", + "String": "stat buffer too small" + }, + { + "Id": 46, + "Name": "Eshutdown", + "String": "device shut down" + }, + { + "Id": 47, + "Name": "Esoverlap", + "String": "segments overlap" + }, + { + "Id": 48, + "Name": "Etimedout", + "String": "connection timed out" + }, + { + "Id": 49, + "Name": "Etoobig", + "String": "read or write too large" + }, + { + "Id": 50, + "Name": "Etoosmall", + "String": "read or write too small" + }, + { + "Id": 51, + "Name": "Eunion", + "String": "not in union" + }, + { + "Id": 52, + "Name": "Eunmount", + "String": "not mounted" + } + ] +} From a59e9035ba98a8a7fe614902b6cf63eeea91efbc Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 17:21:13 +0100 Subject: [PATCH 09/18] add build.json --- build.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 build.json diff --git a/build.json b/build.json new file mode 100644 index 0000000..c30e79d --- /dev/null +++ b/build.json @@ -0,0 +1,8 @@ +{ + "all": { + "Projects": [ + "/sys/src/klibs.json", + "/sys/src/libs.json" + ] + } +} From 16c5baeb7845d4fa252130437bbf9b5111414fc3 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 17:21:27 +0100 Subject: [PATCH 10/18] add .gitignore --- .gitignore | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73da436 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +arch/amd64/bin +arch/amd64/kern +arch/amd64/lib + +sys/log + +sys/src/9/port/error.h +sys/src/9/root/nvram + +*.orig +*_orig +*.rej +*~ +*.o +o.* +*.a +*.ao +*.out +9pccpuf + +cfg/pxe/tftpboot From ee4eab6b320d30c913e96c57dbd0f85746eb1417 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Tue, 22 Dec 2015 21:44:07 +0100 Subject: [PATCH 11/18] README.md: add coverity badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3f15fae..073dd9e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://api.travis-ci.org/JehanneOS/jehanne.svg?branch=master)](https://travis-ci.org/JehanneOS/jehanne) +[![Coverity Badge](https://scan.coverity.com/projects/7364/badge.svg)](https://scan.coverity.com/projects/jehanne) # Jehanne From 817858bedc21cf5b496e61cf0a4d7d2264b9fa69 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 00:32:12 +0100 Subject: [PATCH 12/18] update devtools --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index ab6ec66..f62c23d 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit ab6ec669ba565aa1e5d53cd4a64964884db36fb3 +Subproject commit f62c23db188e65f6552baf6dfbcc418734810e5b From b029ce94b92dbd9d239c23a1bcf984025d671a9a Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 01:02:08 +0100 Subject: [PATCH 13/18] update devtools --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index f62c23d..0d8e5b4 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit f62c23db188e65f6552baf6dfbcc418734810e5b +Subproject commit 0d8e5b4df98c7d41f2961b26a3d0fd8c9b7dfe14 From 97fbabc93ff28e040cdb622508873d4009f0a19c Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 01:03:41 +0100 Subject: [PATCH 14/18] travis-ci: integrate coverity --- .travis.yml | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index c905938..dd3fc24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,17 @@ language: c install: - - git submodule init - - git submodule update --init --recursive --remote +- git submodule init +- git submodule update --init --recursive --remote script: - - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./hacking/continuous-build.sh; fi -compiler: - - gcc-4.8 - +- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./hacking/continuous-build.sh; fi +compiler: +- gcc-4.8 env: global: - - ARCH=amd64 - - JEHANNE=$TRAVIS_BUILD_DIR - - PATH=$PATH:$JEHANNE/hacking/bin - + - ARCH=amd64 + - JEHANNE=$TRAVIS_BUILD_DIR + - PATH=$PATH:$JEHANNE/hacking/bin + - secure: eu81pAD2iXg3b/rm9VYf+8bnlg09IpXdw/WMNeiXqxULCoNZI/1N7oEmLSBvqI068x+mzr6eT0P1C8zVm3wxhTSWs2JKzF0klIe4Tj0S2CjSGDx1GenO2zDdH9mSCvnx8a6xvNzms8O3xOGbV4jzolmckJYi2mLqZwtIxmShMijj8Ou046IMXhchEGFd5bx6rwN01OhFcTUVIHS73CMzZJQxXpT5zjuVDXKSnuX3BnTGHCTNNyoVmnomuvwNZmUch0q/SI8tlYzhsQrz77aZXMBkVqpFM5aTE/fOwgmwEf0Gc8kwa3YtQboxPxlXafn4ygVczMUI9mIXS2ql7ek1Mptxsx3IJUiou9iG31IhN7Pi7DyTIwGTcG6FvDw73oOL3zUY+DTfipNVDaN1GTM8ZPWJ0A/s7V9M+7sUqRyJ4sTpjPtPEmCBtDSDfFIXpq54LcjHAGyTjqveCcm/Wn2kTpxrABrQxPGVLbrGgT7dsZx6eD/vIfgbhKLj6NZUyWoDhErv0NFX7ZIG6brsvHAcY7YLu/NlW398VzwTgu38Fy180TRT/zrhxfTvsnhnrN0Jn/kr60CSXi8Fh1yaMl1vY6tcf662mGoX+pwvobGEJzDJYfMWkLjjq02jbV+nd7VkB3B9vgJtV1xfroGH2gN94iFZxg6FLwBpONWHbmh/JjY= addons: apt: sources: @@ -22,10 +21,9 @@ addons: - gcc-4.8 coverity_scan: project: - name: "JehanneOS/jehanne" - description: "Build submitted via Travis CI" + name: JehanneOS/jehanne + description: Build submitted via Travis CI notification_email: jehanneos@googlegroups.com - build_command_prepend: "git submodule init && git submodule update --init --recursive" + build_command_prepend: git submodule init && git submodule update --init --recursive --remote build_command: "./hacking/coverity-scan.sh" branch_pattern: coverity_scan - From 83993a6d0a76f6a109cae5c26e173457fcca9fa8 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 01:24:56 +0100 Subject: [PATCH 15/18] update devtools --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index 0d8e5b4..26847c6 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit 0d8e5b4df98c7d41f2961b26a3d0fd8c9b7dfe14 +Subproject commit 26847c64866646b5715cbcdd612cdc6694f913cb From 8f6b365eb0f9c3147e89ec59d9980bd47f786fd0 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 10:07:01 +0000 Subject: [PATCH 16/18] travis-ci: improved coverity integration --- .travis.yml | 6 +++--- hacking | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd3fc24..9bd540f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,9 @@ language: c install: - git submodule init - git submodule update --init --recursive --remote +- ./hacking/buildtools.sh script: -- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./hacking/continuous-build.sh; fi +- ./hacking/continuous-build.sh compiler: - gcc-4.8 env: @@ -24,6 +25,5 @@ addons: name: JehanneOS/jehanne description: Build submitted via Travis CI notification_email: jehanneos@googlegroups.com - build_command_prepend: git submodule init && git submodule update --init --recursive --remote - build_command: "./hacking/coverity-scan.sh" + build_command: "build" branch_pattern: coverity_scan diff --git a/hacking b/hacking index 26847c6..ed86291 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit 26847c64866646b5715cbcdd612cdc6694f913cb +Subproject commit ed8629197fb53e629fa59f277b006e3625a0a360 From d07a6b1e39c6c8cafdcbcc5be210efcf0376f793 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 10:45:29 +0000 Subject: [PATCH 17/18] update devtools --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index ed86291..93c44d0 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit ed8629197fb53e629fa59f277b006e3625a0a360 +Subproject commit 93c44d0a8e8ffe83029774b2d509d05c8fb2a2eb From 51b7a95bb7cd8559225d112383a9b0d9427dc5b4 Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Wed, 23 Dec 2015 21:51:57 +0100 Subject: [PATCH 18/18] devtools: update ufs (quick hack that works) --- hacking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking b/hacking index 93c44d0..6cc262b 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit 93c44d0a8e8ffe83029774b2d509d05c8fb2a2eb +Subproject commit 6cc262b43b1d5630c73f079872a260c8d0cd5e0e