Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc584aa56e | ||
|
|
ec95d06f6c | ||
|
|
c5d18d9046 | ||
|
|
af06983c60 | ||
|
|
e027872f50 | ||
|
|
e98e4fde8d | ||
|
|
2daf9de890 | ||
|
|
ae50511135 | ||
|
|
2227f83b1d | ||
|
|
e764a2298d | ||
|
|
ed4a8c2a36 | ||
|
|
8cc3e571e3 | ||
|
|
66a89a7d54 | ||
|
|
666be94a71 | ||
|
|
49fabf23a8 | ||
|
|
a3b23e348a | ||
|
|
384e887fdb | ||
|
|
d3e84cbc4c | ||
|
|
1b06948fb0 | ||
|
|
98d075728f | ||
|
|
1a7ecda67c | ||
|
|
067078db86 | ||
|
|
37650fae75 | ||
|
|
13be3e3216 | ||
|
|
87a7809104 | ||
|
|
e82c33716a | ||
|
|
9ebdddad1f | ||
|
|
90f85bb9c3 | ||
|
|
002d04a3a1 | ||
|
|
88a0b12e73 | ||
|
|
5828e7f576 | ||
|
|
a11da90d10 | ||
|
|
d8026833dc | ||
|
|
8029bb6142 | ||
|
|
baaddd395c | ||
|
|
8bcbe7b3c6 | ||
|
|
4297320886 | ||
|
|
614994d8c7 | ||
|
|
65e1f261c0 | ||
|
|
aa4caa6938 | ||
|
|
9741574516 | ||
|
|
c27c654180 | ||
|
|
c63580ee38 | ||
|
|
e9d4328fad | ||
|
|
545f9f2cca | ||
|
|
db6930d9e4 | ||
|
|
9379a41b37 | ||
|
|
c0eeedc71a | ||
|
|
400197def8 | ||
|
|
0f8b202531 | ||
|
|
1eb9775f34 | ||
|
|
89bdb315d5 | ||
|
|
ab1afd68b7 | ||
|
|
e1109e9e51 | ||
|
|
7230e19166 | ||
|
|
eb7a94bb55 | ||
|
|
18de4e57eb | ||
|
|
74cc12133e | ||
|
|
7583354f44 | ||
|
|
14c49dd681 | ||
|
|
e060208417 | ||
|
|
635eea7acb | ||
|
|
2c47f4a23d | ||
|
|
2223577302 | ||
|
|
f42d235dec | ||
|
|
06a3e278ff | ||
|
|
17c30b5fdc | ||
|
|
024b30d0b7 | ||
|
|
a108610a67 | ||
|
|
12b6abe6a3 | ||
|
|
6f82b36962 | ||
|
|
ea6b397526 | ||
|
|
118bb3f3ba | ||
|
|
bd68075f4d | ||
|
|
5fa68f8cdd | ||
|
|
199aaf2d05 | ||
|
|
892efcc166 | ||
|
|
bc90c6b82f | ||
|
|
82d3d1f0f3 | ||
|
|
576b3198f1 | ||
|
|
f55cad8f1c | ||
|
|
d98654b50d | ||
|
|
675d9d8c09 | ||
|
|
bab0bb349f | ||
|
|
65d3ed8ce8 | ||
|
|
8fc4000b63 | ||
|
|
5b35f781cb | ||
|
|
2cd11b7da7 | ||
|
|
cf30d2923c | ||
|
|
8fc97794e8 | ||
|
|
df2ba37687 | ||
|
|
85b16b2a54 | ||
|
|
eeabc6b61a | ||
|
|
2b3dafed61 | ||
|
|
7232fc36ab | ||
|
|
a8e1fd1054 | ||
|
|
c248a50338 | ||
|
|
fa0ca23798 | ||
|
|
ed224cf912 | ||
|
|
b51df25371 | ||
|
|
db8cc8eb7b | ||
|
|
a027e9fe14 | ||
|
|
b882ca809a | ||
|
|
daf0a9dc9a | ||
|
|
f2dafa7544 | ||
|
|
7fe22875a6 | ||
|
|
3da3c8ecd8 | ||
|
|
254acbbbe2 | ||
|
|
519c850f17 | ||
|
|
1cf57508b0 | ||
|
|
f8bacfcc67 | ||
|
|
9daa77c1a4 | ||
|
|
c4775dd313 | ||
|
|
ae87cb031e | ||
|
|
3c049f25ee | ||
|
|
85a90b62b7 | ||
|
|
10b0124951 | ||
|
|
c0d7ff9543 | ||
|
|
74012d4869 | ||
|
|
830c40440f | ||
|
|
21a2f71ad9 | ||
|
|
cf75e3e664 | ||
|
|
ffc307323a | ||
|
|
ff0aec28c5 | ||
|
|
31394b03ae | ||
|
|
2ab93cb385 | ||
|
|
172b396dc9 | ||
|
|
9b82d08087 | ||
|
|
410617f73b | ||
|
|
ade0d38a7c | ||
|
|
3ce55a2ac4 | ||
|
|
cc6e4dbec0 | ||
|
|
2935ae7bf1 | ||
|
|
96e418e63b | ||
|
|
e4a84dcfe9 | ||
|
|
9ea91cfce3 | ||
|
|
8c7f0cf988 | ||
|
|
afa9a00259 | ||
|
|
a0ee11c300 | ||
|
|
6e02dace18 | ||
|
|
93bac6f26f | ||
|
|
8657fbd810 | ||
|
|
68203be004 | ||
|
|
b2323ef2e7 | ||
|
|
70b017fb72 | ||
|
|
607e3bbc11 | ||
|
|
315c9285de | ||
|
|
c22427b8fd | ||
|
|
2fcfac9e84 | ||
|
|
7cc857233f | ||
|
|
f85aa09784 | ||
|
|
0b0cecc2a9 | ||
|
|
3b5b9c9587 | ||
|
|
cbe190fa70 | ||
|
|
9156466351 | ||
|
|
f79caf095d | ||
|
|
d31dcd13fc | ||
|
|
552224bbfe | ||
|
|
5ba01674fb | ||
|
|
7390afc5e1 | ||
|
|
85ec23d552 | ||
|
|
007064c0ac | ||
|
|
fd53756170 | ||
|
|
9e6dd9f23d | ||
|
|
ef8be6c7c2 | ||
|
|
de4b5b70da | ||
|
|
9edeee4b3f | ||
|
|
767a0cc1fd | ||
|
|
ae09247e34 | ||
|
|
a3ea4798bc | ||
|
|
af54a22d16 | ||
|
|
b026bfc71b | ||
|
|
80d80ad8aa | ||
|
|
dbecf33924 | ||
|
|
2b08e3604d | ||
|
|
7d3a672c2b | ||
|
|
022e46ae38 | ||
|
|
3f930d228e | ||
|
|
5eba370f7b | ||
|
|
e138951e9e | ||
|
|
5cd18d7275 | ||
|
|
d7ff5a53a7 | ||
|
|
aa14bb6fdf | ||
|
|
c275f682a9 | ||
|
|
08894025bc | ||
|
|
b063a48520 | ||
|
|
858d38d314 | ||
|
|
f5875d09e9 | ||
|
|
34db181686 | ||
|
|
be55ea2b0b | ||
|
|
aa0dd4d10d | ||
|
|
39533e4209 | ||
|
|
4bba3bf1d2 | ||
|
|
2d29d1549a | ||
|
|
c7a078f17f | ||
|
|
2cf92037e9 | ||
|
|
452ee7a103 | ||
|
|
68f70af2f3 | ||
|
|
11682e487e | ||
|
|
4d006230f9 | ||
|
|
a32f4bb05c | ||
|
|
6d4e260127 | ||
|
|
45404b5bcf | ||
|
|
861551b2ba | ||
|
|
aac820a8d5 | ||
|
|
a5ff25b0fe | ||
|
|
b81638794f | ||
|
|
88cfeb2791 | ||
|
|
d0b57535ed | ||
|
|
528add4702 | ||
|
|
dd47971877 | ||
|
|
d51a99c8e2 | ||
|
|
e192f01dc3 | ||
|
|
aedaf57249 | ||
|
|
222e58e76e | ||
|
|
c8fc80f4a0 | ||
|
|
1ed180887d | ||
|
|
d6a38a567f | ||
|
|
ae9c3276bc | ||
|
|
35d34cd4e8 | ||
|
|
4f45824632 | ||
|
|
532da174dd | ||
|
|
dbe13feba2 | ||
|
|
1c93061a7f | ||
|
|
0e371930e6 | ||
|
|
06bd748bd6 | ||
|
|
b64775772b | ||
|
|
5f76314085 | ||
|
|
57588ea936 | ||
|
|
3f344b55bb | ||
|
|
e4ae0980b4 | ||
|
|
e41da0d697 | ||
|
|
ce3955d393 | ||
|
|
22a2cc564f | ||
|
|
2b19513a05 | ||
|
|
60f8fe6f41 | ||
|
|
a2fd010521 | ||
|
|
a36d5b6302 | ||
|
|
2c14dc16dd | ||
|
|
4c7f3f7972 | ||
|
|
794df59265 | ||
|
|
3dd71713c2 | ||
|
|
c0777d1a0a | ||
|
|
55392cb047 | ||
|
|
070eedda18 | ||
|
|
ae6ec78dc3 | ||
|
|
9fe1b2a565 | ||
|
|
f374419be3 | ||
|
|
0ff25cb116 | ||
|
|
d7e50f352a | ||
|
|
aa9254eeb0 | ||
|
|
c1eba336a8 | ||
|
|
a5d7fc484a | ||
|
|
7a294e6d4e | ||
|
|
2f79417d0d | ||
|
|
73b42f924d | ||
|
|
ccf915e798 | ||
|
|
62ffa14f10 | ||
|
|
5d7840a34c | ||
|
|
fd14f6ff73 | ||
|
|
88962f9358 | ||
|
|
5bec1729f1 | ||
|
|
f3662fc152 | ||
|
|
c5047186dd | ||
|
|
1e39bd8336 | ||
|
|
e58de234ac | ||
|
|
903cc181c4 | ||
|
|
2183a098c3 | ||
|
|
1d4cba9180 | ||
|
|
ed724c5280 | ||
|
|
fbd13ac42c | ||
|
|
ea6eab557b | ||
|
|
a1cb2a0589 | ||
|
|
5de5a8ca94 | ||
|
|
274026d338 | ||
|
|
3875bc34bd |
5
.github/workflows/go.yml
vendored
5
.github/workflows/go.yml
vendored
@@ -5,9 +5,9 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: [ "*" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
branches: [ "*" ]
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -15,6 +15,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
# os: [macos-latest]
|
||||
llvm: [18]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
40
.github/workflows/populate_darwin_sysroot.sh
vendored
Executable file
40
.github/workflows/populate_darwin_sysroot.sh
vendored
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
export TMPDIR
|
||||
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||
|
||||
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@18
|
||||
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@18
|
||||
mkdir -p "${DARWIN_AMD64_LLVM_PREFIX}" "${DARWIN_ARM64_LLVM_PREFIX}"
|
||||
|
||||
BREW_LLVM_FORMULA_JSON="$(mktemp)"
|
||||
curl -fsSL https://formulae.brew.sh/api/formula/llvm.json > "${BREW_LLVM_FORMULA_JSON}"
|
||||
BREW_LLVM_AMD64_BOTTLE_URL=$(jq -r '.bottle.stable.files.sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||
BREW_LLVM_ARM64_BOTTLE_URL=$(jq -r '.bottle.stable.files.arm64_sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_AMD64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_AMD64_LLVM_PREFIX}"
|
||||
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_ARM64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_ARM64_LLVM_PREFIX}"
|
||||
|
||||
patch_homebrew_lib_dir() {
|
||||
local LIB_DIR="$1"
|
||||
local HOMEBREW_PREFIX="$2"
|
||||
for DYLIB_FILE in "${LIB_DIR}"/*.dylib; do
|
||||
if [[ -f "${DYLIB_FILE}" ]]; then
|
||||
ID=$(otool -D "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
|
||||
if [[ -n "${ID}" ]]; then
|
||||
NEW_ID=${ID/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
|
||||
install_name_tool -id "${NEW_ID}" "${DYLIB_FILE}"
|
||||
fi
|
||||
|
||||
DEPS=$(otool -L "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
|
||||
for DEP in ${DEPS}; do
|
||||
NEW_DEP=${DEP/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
|
||||
install_name_tool -change "${DEP}" "${NEW_DEP}" "${DYLIB_FILE}"
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
patch_homebrew_lib_dir "${DARWIN_AMD64_LLVM_PREFIX}/lib" /usr/lib
|
||||
patch_homebrew_lib_dir "${DARWIN_ARM64_LLVM_PREFIX}/lib" /opt/homebrew
|
||||
143
.github/workflows/populate_linux_sysroot.sh
vendored
Executable file
143
.github/workflows/populate_linux_sysroot.sh
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
export TMPDIR
|
||||
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||
|
||||
LINUX_AMD64_PREFIX=.sysroot/linux/amd64
|
||||
LINUX_ARM64_PREFIX=.sysroot/linux/arm64
|
||||
mkdir -p "${LINUX_AMD64_PREFIX}" "${LINUX_ARM64_PREFIX}"
|
||||
|
||||
POPULATE_LINUX_SYSROOT_SCRIPT="$(mktemp)"
|
||||
cat > "${POPULATE_LINUX_SYSROOT_SCRIPT}" << EOF
|
||||
#!/bin/bash
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
apt-get update
|
||||
apt-get install -y lsb-release gnupg2 wget rsync
|
||||
|
||||
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-18 main" | tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
apt-get update
|
||||
apt-get install -y llvm-18-dev
|
||||
|
||||
error() {
|
||||
echo -e "\$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
exclude_list=()
|
||||
include_list=()
|
||||
|
||||
exclude_list+=(--exclude "/bin")
|
||||
exclude_list+=(--exclude "/boot")
|
||||
exclude_list+=(--exclude "/boot*")
|
||||
exclude_list+=(--exclude "/dev")
|
||||
exclude_list+=(--exclude "/etc")
|
||||
exclude_list+=(--exclude "/home")
|
||||
exclude_list+=(--exclude "/lib/dhcpd")
|
||||
exclude_list+=(--exclude "/lib/firmware")
|
||||
exclude_list+=(--exclude "/lib/hdparm")
|
||||
exclude_list+=(--exclude "/lib/ifupdown")
|
||||
exclude_list+=(--exclude "/lib/modules")
|
||||
exclude_list+=(--exclude "/lib/modprobe.d")
|
||||
exclude_list+=(--exclude "/lib/modules-load.d")
|
||||
exclude_list+=(--exclude "/lib/resolvconf")
|
||||
exclude_list+=(--exclude "/lib/startpar")
|
||||
exclude_list+=(--exclude "/lib/systemd")
|
||||
exclude_list+=(--exclude "/lib/terminfo")
|
||||
exclude_list+=(--exclude "/lib/udev")
|
||||
exclude_list+=(--exclude "/lib/xtables")
|
||||
exclude_list+=(--exclude "/lib/ssl/private")
|
||||
exclude_list+=(--exclude "/lost+found")
|
||||
exclude_list+=(--exclude "/media")
|
||||
exclude_list+=(--exclude "/mnt")
|
||||
exclude_list+=(--exclude "/proc")
|
||||
exclude_list+=(--exclude "/root")
|
||||
exclude_list+=(--exclude "/run")
|
||||
exclude_list+=(--exclude "/sbin")
|
||||
exclude_list+=(--exclude "/srv")
|
||||
exclude_list+=(--exclude "/sys")
|
||||
exclude_list+=(--exclude "/tmp")
|
||||
exclude_list+=(--exclude "/usr/bin")
|
||||
exclude_list+=(--exclude "/usr/games")
|
||||
exclude_list+=(--exclude "/usr/sbin")
|
||||
exclude_list+=(--exclude "/usr/share")
|
||||
exclude_list+=(--exclude "/usr/src")
|
||||
exclude_list+=(--exclude "/usr/local/bin")
|
||||
exclude_list+=(--exclude "/usr/local/etc")
|
||||
exclude_list+=(--exclude "/usr/local/games")
|
||||
exclude_list+=(--exclude "/usr/local/man")
|
||||
exclude_list+=(--exclude "/usr/local/sbin")
|
||||
exclude_list+=(--exclude "/usr/local/share")
|
||||
exclude_list+=(--exclude "/usr/local/src")
|
||||
exclude_list+=(--exclude "/usr/lib/ssl/private")
|
||||
exclude_list+=(--exclude "/var")
|
||||
exclude_list+=(--exclude "/snap")
|
||||
exclude_list+=(--exclude "*python*")
|
||||
|
||||
include_list+=(--include "*.a")
|
||||
include_list+=(--include "*.so")
|
||||
include_list+=(--include "*.so.*")
|
||||
include_list+=(--include "*.h")
|
||||
include_list+=(--include "*.hh")
|
||||
include_list+=(--include "*.hpp")
|
||||
include_list+=(--include "*.hxx")
|
||||
include_list+=(--include "*.pc")
|
||||
include_list+=(--include "*.def")
|
||||
include_list+=(--include "*.inc")
|
||||
include_list+=(--include "/lib")
|
||||
include_list+=(--include "/lib32")
|
||||
include_list+=(--include "/lib64")
|
||||
include_list+=(--include "/libx32")
|
||||
include_list+=(--include "*/")
|
||||
|
||||
do-sync() {
|
||||
from=\$1
|
||||
to=\$2
|
||||
|
||||
args=()
|
||||
args+=(-a)
|
||||
args+=(-z)
|
||||
args+=(-m)
|
||||
args+=(-d)
|
||||
args+=(-h)
|
||||
args+=(--keep-dirlinks)
|
||||
args+=("--info=progress2")
|
||||
args+=(--delete)
|
||||
args+=(--prune-empty-dirs)
|
||||
args+=(--sparse)
|
||||
args+=(--links)
|
||||
args+=(--copy-unsafe-links)
|
||||
args+=("\${exclude_list[@]}")
|
||||
args+=("\${include_list[@]}")
|
||||
args+=(--exclude "*")
|
||||
args+=("\${from}")
|
||||
args+=("\${to}")
|
||||
|
||||
echo "\${args[@]}"
|
||||
rsync "\${args[@]}"
|
||||
|
||||
exit \$?
|
||||
}
|
||||
|
||||
do-sync / /sysroot/
|
||||
EOF
|
||||
chmod +x "${POPULATE_LINUX_SYSROOT_SCRIPT}"
|
||||
|
||||
populate_linux_sysroot() {
|
||||
local ARCH="$1"
|
||||
local PREFIX="$2"
|
||||
docker run \
|
||||
--rm \
|
||||
--platform "linux/${ARCH}" \
|
||||
-v "$(pwd)/${PREFIX}":/sysroot \
|
||||
-v "${POPULATE_LINUX_SYSROOT_SCRIPT}":/populate_linux_sysroot.sh \
|
||||
debian:bullseye \
|
||||
/populate_linux_sysroot.sh
|
||||
}
|
||||
populate_linux_sysroot amd64 "${LINUX_AMD64_PREFIX}"
|
||||
populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}"
|
||||
58
.github/workflows/release-build.yml
vendored
Normal file
58
.github/workflows/release-build.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
populate-darwin-sysroot:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Populate Darwin sysroot
|
||||
run: bash .github/workflows/populate_darwin_sysroot.sh
|
||||
- name: Create Darwin sysroot tarball
|
||||
run: tar -czvf .sysroot/darwin.tar.gz -C .sysroot darwin
|
||||
- name: Upload Darwin sysroot tarball
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: darwin-sysroot-tarball
|
||||
path: .sysroot/darwin.tar.gz
|
||||
compression-level: 0
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: populate-darwin-sysroot
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Download Darwin sysroot tarball
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: darwin-sysroot-tarball
|
||||
path: .sysroot
|
||||
- name: Populate Darwin sysroot
|
||||
run: tar -xzvf .sysroot/darwin.tar.gz -C .sysroot
|
||||
- name: Populate Linux sysroot
|
||||
run: bash .github/workflows/populate_linux_sysroot.sh
|
||||
- name: Run GoReleaser
|
||||
env:
|
||||
GITHUB_TOKEN: ${{github.token}}
|
||||
run: |
|
||||
docker run \
|
||||
--rm \
|
||||
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $(pwd):/go/src/llgo \
|
||||
-w /go/src/llgo \
|
||||
ghcr.io/goreleaser/goreleaser-cross:v1.22 \
|
||||
release --clean --skip nfpm,snapcraft
|
||||
2
.github/workflows/test_demo.sh
vendored
2
.github/workflows/test_demo.sh
vendored
@@ -8,7 +8,7 @@ for d in ./_demo/* ./_pydemo/*; do
|
||||
total=$((total+1))
|
||||
if [ -d "$d" ]; then
|
||||
echo "Testing $d"
|
||||
if ! llgo run -v "$d"; then
|
||||
if ! llgo run "$d"; then
|
||||
echo "FAIL"
|
||||
failed=$((failed+1))
|
||||
failed_cases="$failed_cases\n* :x: $d"
|
||||
|
||||
2
.github/workflows/test_llgo.sh
vendored
2
.github/workflows/test_llgo.sh
vendored
@@ -4,7 +4,7 @@ set -e
|
||||
export LLGOROOT=$PWD
|
||||
|
||||
testcmd=/tmp/test
|
||||
llgo build -o $testcmd ./_test
|
||||
llgo build -o $testcmd ./c/bdwgc/_test
|
||||
cases=$($testcmd)
|
||||
total=$(echo "$cases" | wc -l | tr -d ' ')
|
||||
failed=0
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -35,3 +35,7 @@ build.dir/
|
||||
|
||||
# Go workspace file
|
||||
go.work*
|
||||
|
||||
# GoReleaser
|
||||
.dist/
|
||||
.sysroot/
|
||||
|
||||
145
.goreleaser.yaml
Normal file
145
.goreleaser.yaml
Normal file
@@ -0,0 +1,145 @@
|
||||
version: 2
|
||||
|
||||
dist: .dist
|
||||
|
||||
env:
|
||||
- SYSROOT_DARWIN_AMD64={{.Env.PWD}}/.sysroot/darwin/amd64
|
||||
- SYSROOT_DARWIN_ARM64={{.Env.PWD}}/.sysroot/darwin/arm64
|
||||
- SYSROOT_LINUX_AMD64={{.Env.PWD}}/.sysroot/linux/amd64
|
||||
- SYSROOT_LINUX_ARM64={{.Env.PWD}}/.sysroot/linux/arm64
|
||||
- CGO_ENABLED=1
|
||||
- CGO_CXXFLAGS=-std=c++17
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod download
|
||||
|
||||
builds:
|
||||
- id: llgo-darwin-amd64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=darwin,amd64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@18/bin/llvm-config
|
||||
env:
|
||||
- CC=o64-clang
|
||||
- CXX=o64-clang++
|
||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
||||
targets:
|
||||
- darwin_amd64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-darwin-arm64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=darwin,arm64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@18/bin/llvm-config
|
||||
env:
|
||||
- CC=oa64-clang
|
||||
- CXX=oa64-clang++
|
||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
||||
targets:
|
||||
- darwin_arm64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-linux-amd64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=linux,amd64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
||||
env:
|
||||
- CC=x86_64-linux-gnu-gcc
|
||||
- CXX=x86_64-linux-gnu-g++
|
||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||
targets:
|
||||
- linux_amd64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-linux-arm64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=linux,arm64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
||||
env:
|
||||
- CC=aarch64-linux-gnu-gcc
|
||||
- CXX=aarch64-linux-gnu-g++
|
||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||
targets:
|
||||
- linux_arm64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
files:
|
||||
- LICENSE
|
||||
- README.md
|
||||
|
||||
checksum:
|
||||
name_template: "{{.ProjectName}}{{.Version}}.checksums.txt"
|
||||
|
||||
nfpms:
|
||||
- package_name: llgo
|
||||
vendor: goplus
|
||||
homepage: https://github.com/goplus/llgo
|
||||
maintainer: Aofei Sheng <aofei@aofeisheng.com>
|
||||
description: |
|
||||
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
|
||||
subproject of the Go+ project.
|
||||
|
||||
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
|
||||
|
||||
- Game development
|
||||
- AI and data science
|
||||
- WebAssembly
|
||||
- Embedded development
|
||||
- ...
|
||||
license: Apache-2.0
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
file_name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
bindir: /usr/local/bin
|
||||
|
||||
snapcrafts:
|
||||
- name: llgo
|
||||
title: A Go compiler based on LLVM
|
||||
summary: A Go compiler based on LLVM
|
||||
description: |
|
||||
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
|
||||
subproject of the Go+ project.
|
||||
|
||||
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
|
||||
|
||||
- Game development
|
||||
- AI and data science
|
||||
- WebAssembly
|
||||
- Embedded development
|
||||
- ...
|
||||
license: Apache-2.0
|
||||
confinement: classic
|
||||
name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
|
||||
snapshot:
|
||||
name_template: '{{trimprefix .Summary "v"}}'
|
||||
|
||||
release:
|
||||
prerelease: auto
|
||||
81
README.md
81
README.md
@@ -27,11 +27,13 @@ LLGo := Go + C + Python
|
||||
LLGo is compatible with C and Python through the language's **Application Binary Interface (ABI)**, while LLGo is compatible with Go through its **syntax (source code)**.
|
||||
|
||||
|
||||
## C standard libary support
|
||||
## C/C++ standard libary support
|
||||
|
||||
You can import a C standard library in LLGo!
|
||||
You can import a C/C++ standard library in LLGo!
|
||||
|
||||
* [c](https://pkg.go.dev/github.com/goplus/llgo/c)
|
||||
* [c/syscall](https://pkg.go.dev/github.com/goplus/llgo/c/syscall)
|
||||
* [c/sys](https://pkg.go.dev/github.com/goplus/llgo/c/sys)
|
||||
* [c/os](https://pkg.go.dev/github.com/goplus/llgo/c/os)
|
||||
* [c/math](https://pkg.go.dev/github.com/goplus/llgo/c/math)
|
||||
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/llgo/c/math/cmplx)
|
||||
@@ -40,6 +42,8 @@ You can import a C standard library in LLGo!
|
||||
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/llgo/c/pthread/sync)
|
||||
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/llgo/c/sync/atomic)
|
||||
* [c/time](https://pkg.go.dev/github.com/goplus/llgo/c/time)
|
||||
* [c/net](https://pkg.go.dev/github.com/goplus/llgo/c/net)
|
||||
* [cpp/std](https://pkg.go.dev/github.com/goplus/llgo/cpp/std)
|
||||
|
||||
Here is a simple example:
|
||||
|
||||
@@ -69,6 +73,45 @@ llgo run .
|
||||
```
|
||||
|
||||
|
||||
## How support C/C++ and Python
|
||||
|
||||
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
||||
|
||||
```go
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
```
|
||||
|
||||
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
Or put it into a package (see [c/math](c/math/math.go)):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/goplus/llgo/c/math"
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", math.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Python support
|
||||
|
||||
You can import a Python library in LLGo!
|
||||
@@ -171,10 +214,15 @@ The currently supported libraries include:
|
||||
* [c/bdwgc](https://pkg.go.dev/github.com/goplus/llgo/c/bdwgc)
|
||||
* [c/cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
||||
* [c/clang](https://pkg.go.dev/github.com/goplus/llgo/c/clang)
|
||||
* [c/libuv](https://pkg.go.dev/github.com/goplus/llgo/c/libuv)
|
||||
* [c/llama2](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
|
||||
* [c/lua](https://pkg.go.dev/github.com/goplus/llgo/c/lua)
|
||||
* [c/neco](https://pkg.go.dev/github.com/goplus/llgo/c/neco)
|
||||
* [c/raylib](https://pkg.go.dev/github.com/goplus/llgo/c/raylib)
|
||||
* [c/sqlite](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite)
|
||||
* [c/zlib](https://pkg.go.dev/github.com/goplus/llgo/c/zlib)
|
||||
* [cpp/inih](https://pkg.go.dev/github.com/goplus/llgo/cpp/inih)
|
||||
* [cpp/llvm](https://pkg.go.dev/github.com/goplus/llgo/cpp/llvm)
|
||||
|
||||
Here are some examples related to them:
|
||||
|
||||
@@ -186,7 +234,7 @@ Here are some examples related to them:
|
||||
|
||||
## Go syntax support
|
||||
|
||||
All Go syntax is already supported. Here are some examples:
|
||||
All Go syntax (not including `cgo`) is already supported. Here are some examples:
|
||||
|
||||
* [concat](_demo/concat/concat.go): define a variadic function
|
||||
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
|
||||
@@ -222,15 +270,21 @@ Here are the Go packages that can be imported correctly:
|
||||
* [math](https://pkg.go.dev/math)
|
||||
* [math/bits](https://pkg.go.dev/math/bits)
|
||||
* [math/cmplx](https://pkg.go.dev/math/cmplx)
|
||||
* [errors](https://pkg.go.dev/errors)
|
||||
* [context](https://pkg.go.dev/context)
|
||||
* [io](https://pkg.go.dev/io)
|
||||
* [io/fs](https://pkg.go.dev/io/fs)
|
||||
* [log](https://pkg.go.dev/log)
|
||||
* [flag](https://pkg.go.dev/flag)
|
||||
* [sort](https://pkg.go.dev/sort)
|
||||
* [strconv](https://pkg.go.dev/strconv)
|
||||
* [strings](https://pkg.go.dev/strings)
|
||||
* [sync/atomic](https://pkg.go.dev/sync/atomic)
|
||||
* [sync](https://pkg.go.dev/sync) (partially)
|
||||
* [syscall](https://pkg.go.dev/syscall) (partially)
|
||||
* [errors](https://pkg.go.dev/errors) (partially)
|
||||
* [io](https://pkg.go.dev/io) (partially)
|
||||
* [io/fs](https://pkg.go.dev/io/fs) (partially)
|
||||
* [runtime](https://pkg.go.dev/runtime) (partially)
|
||||
* [os](https://pkg.go.dev/os) (partially)
|
||||
* [os/exec](https://pkg.go.dev/os/exec) (partially)
|
||||
* [fmt](https://pkg.go.dev/fmt) (partially)
|
||||
* [reflect](https://pkg.go.dev/reflect) (partially)
|
||||
* [time](https://pkg.go.dev/time) (partially)
|
||||
@@ -259,10 +313,7 @@ brew update # execute if needed
|
||||
brew install llvm@18 pkg-config libgc
|
||||
brew install cjson sqlite python@3.12 # optional
|
||||
export PATH=$(brew --prefix llvm@18)/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.zshrc
|
||||
git clone https://github.com/goplus/llgo.git
|
||||
cd llgo
|
||||
export LLGOROOT="/path/to/llgo" # Replace this with the root directory of the llgo project
|
||||
go install -v ./...
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
@@ -274,10 +325,7 @@ sudo apt-get update # execute if needed
|
||||
sudo apt-get install -y llvm-18-dev clang-18 lld-18 pkg-config libgc-dev
|
||||
sudo apt-get install -y libcjson-dev libsqlite3-dev python3.12-dev # optional
|
||||
export PATH=/usr/lib/llvm-18/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.bashrc
|
||||
git clone https://github.com/goplus/llgo.git
|
||||
cd llgo
|
||||
export LLGOROOT="/path/to/llgo" # Replace this with the root directory of the llgo project
|
||||
go install -v ./...
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
```
|
||||
|
||||
### on Windows
|
||||
@@ -296,8 +344,9 @@ TODO
|
||||
How do I generate these tools?
|
||||
|
||||
```sh
|
||||
export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers
|
||||
go install -v ./... # compile all tools except pydump
|
||||
git clone https://github.com/goplus/llgo.git
|
||||
cd llgo
|
||||
go install -v ./chore/... # compile all tools except pydump
|
||||
cd chore/_xtool
|
||||
llgo install ./... # compile pydump
|
||||
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
|
||||
|
||||
18
_cmptest/_osexec/exec.go
Normal file
18
_cmptest/_osexec/exec.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
}
|
||||
cmd := exec.Command(ls)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Run()
|
||||
}
|
||||
26
_cmptest/_pipedemo/pipe.go
Normal file
26
_cmptest/_pipedemo/pipe.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("This is some data that needs to be stored in Body.")
|
||||
pr, pw := io.Pipe()
|
||||
go func() {
|
||||
defer pw.Close()
|
||||
if _, err := pw.Write(data); err != nil {
|
||||
fmt.Println("Error writing to pipe:", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
defer pr.Close()
|
||||
|
||||
readData, err := io.ReadAll(pr)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading from Body:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Body:", string(readData))
|
||||
}
|
||||
19
_cmptest/_timeout/timer.go
Normal file
19
_cmptest/_timeout/timer.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var c chan int
|
||||
|
||||
func handle(int) {}
|
||||
|
||||
func main() {
|
||||
select {
|
||||
case m := <-c:
|
||||
handle(m)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timed out")
|
||||
}
|
||||
}
|
||||
39
_cmptest/ctxcancel/ctx.go
Normal file
39
_cmptest/ctxcancel/ctx.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// gen generates integers in a separate goroutine and
|
||||
// sends them to the returned channel.
|
||||
// The callers of gen need to cancel the context once
|
||||
// they are done consuming generated integers not to leak
|
||||
// the internal goroutine started by gen.
|
||||
gen := func(ctx context.Context) <-chan int {
|
||||
dst := make(chan int)
|
||||
n := 1
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return // returning not to leak the goroutine
|
||||
case dst <- n:
|
||||
n++
|
||||
}
|
||||
}
|
||||
}()
|
||||
return dst
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel() // cancel when we are finished consuming integers
|
||||
|
||||
for n := range gen(ctx) {
|
||||
fmt.Println(n)
|
||||
if n == 5 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
21
_cmptest/flagdemo/flagdemo.go
Normal file
21
_cmptest/flagdemo/flagdemo.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("args:", os.Args[1:])
|
||||
if len(os.Args) == 1 {
|
||||
os.Args = []string{"flagdemo", "-cpu", "100"}
|
||||
}
|
||||
|
||||
verbose := flag.Bool("v", false, "verbose")
|
||||
cpu := flag.Int("cpu", 1, "cpu number")
|
||||
host := flag.String("host", ":8888", "host")
|
||||
flag.Parse()
|
||||
|
||||
fmt.Println("host:", *host, "cpu:", *cpu, "verbose:", *verbose)
|
||||
}
|
||||
30
_cmptest/osproc/exec.go
Normal file
30
_cmptest/osproc/exec.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
args := []string{ls, "-l"}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
args = []string{ls}
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
proc, err := os.StartProcess(ls, args, &os.ProcAttr{
|
||||
Files: []*os.File{nil, os.Stdout, os.Stderr},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("os.StartProcess error:", err)
|
||||
return
|
||||
}
|
||||
proc.Wait()
|
||||
fmt.Println("proc.Wait done")
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package main
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(strconv.Itoa(-123))
|
||||
fmt.Println(strconv.Itoa(-123))
|
||||
fmt.Println(strings.Split("abc,def,123", ","))
|
||||
}
|
||||
|
||||
11
_demo/cexec/exec.go
Normal file
11
_demo/cexec/exec.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := c.Str("ls")
|
||||
os.Execlp(ls, ls, c.Str("-l"), nil)
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
77
_demo/fcntl/fcntl.go
Normal file
77
_demo/fcntl/fcntl.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
filename := c.Str("testfile.txt")
|
||||
data := c.Str("Hello, os!")
|
||||
var buffer [20]c.Char
|
||||
|
||||
// Open a file, O_CREAT|O_WRONLY|O_TRUNC means create, write only, or clear the file
|
||||
fd := os.Open(filename, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if fd == -1 {
|
||||
c.Printf(c.Str("open error\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Writing data to a file
|
||||
bytesWritten := os.Write(fd, c.Pointer(data), c.Strlen(data))
|
||||
if bytesWritten == -1 {
|
||||
c.Printf(c.Str("write error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("Written %ld bytes to %s\n"), bytesWritten, filename)
|
||||
|
||||
// Get file status flags
|
||||
flags := os.Fcntl(fd, os.F_GETFL)
|
||||
if flags == -1 {
|
||||
c.Printf(c.Str("os error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("File flags: %d\n"), flags)
|
||||
|
||||
// Set the file status flag to non-blocking mode
|
||||
if os.Fcntl(fd, os.F_SETFL, flags|os.O_NONBLOCK) == -1 {
|
||||
c.Printf(c.Str("os error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("set file status successfully\n"))
|
||||
|
||||
|
||||
|
||||
c.Printf(c.Str("111"))
|
||||
// Close file
|
||||
os.Close(fd)
|
||||
|
||||
// Reopen the file, O_RDONLY means read-only
|
||||
fd = os.Open(filename, os.O_RDONLY)
|
||||
if fd == -1 {
|
||||
c.Printf(c.Str("open error\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Reading data from a file
|
||||
// &buffer[:][0]
|
||||
// unsafe.SliceData(buffer[:])
|
||||
bytesRead := os.Read(fd, c.Pointer(unsafe.SliceData(buffer[:])), unsafe.Sizeof(buffer)-1)
|
||||
if bytesRead == -1 {
|
||||
c.Printf(c.Str("read error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure that the buffer is null-terminated
|
||||
buffer[bytesRead] = c.Char(0)
|
||||
c.Printf(c.Str("Read %ld bytes: %s\n"), bytesRead, &buffer[0])
|
||||
|
||||
// Close file
|
||||
os.Close(fd)
|
||||
}
|
||||
@@ -9,5 +9,5 @@ func main() {
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Hello World
|
||||
Hello world
|
||||
*/
|
||||
|
||||
10
_demo/linkname/linkname.go
Normal file
10
_demo/linkname/linkname.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", Sqrt(2))
|
||||
}
|
||||
9
_demo/logdemo/log.go
Normal file
9
_demo/logdemo/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Hello")
|
||||
}
|
||||
20
_demo/netdbdemo/netdb.go
Normal file
20
_demo/netdbdemo/netdb.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var hints net.AddrInfo
|
||||
hints.Family = net.AF_UNSPEC
|
||||
hints.SockType = net.SOCK_STREAM
|
||||
|
||||
host := "httpbin.org"
|
||||
port := "80"
|
||||
|
||||
var result *net.AddrInfo
|
||||
c.Printf(c.Str("%d\n"), net.Getaddrinfo(c.Str(host), c.Str(port), &hints, &result))
|
||||
|
||||
c.Printf(c.Str("%d\n"), net.Freeaddrinfo(result))
|
||||
}
|
||||
19
_demo/oslookpath/lookpath.go
Normal file
19
_demo/oslookpath/lookpath.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
fmt.Println(ls)
|
||||
}
|
||||
32
_demo/socket/client/client.go
Normal file
32
_demo/socket/client/client.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sockfd := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
|
||||
msg := c.Str("Hello, World!")
|
||||
defer os.Close(sockfd)
|
||||
|
||||
server := net.GetHostByName(c.Str("localhost"))
|
||||
if server == nil {
|
||||
c.Perror(c.Str("hostname get error"))
|
||||
return
|
||||
}
|
||||
|
||||
servAddr := &net.SockaddrIn{}
|
||||
servAddr.Family = net.AF_INET
|
||||
servAddr.Port = net.Htons(uint16(1234))
|
||||
c.Memcpy(unsafe.Pointer(&servAddr.Addr.Addr), unsafe.Pointer(*server.AddrList), uintptr(server.Length))
|
||||
|
||||
if res := net.Connect(sockfd, (*net.SockAddr)(unsafe.Pointer(servAddr)), c.Uint(16)); res < 0 {
|
||||
c.Perror(c.Str("connect error"))
|
||||
return
|
||||
}
|
||||
os.Write(sockfd, unsafe.Pointer(msg), c.Strlen(msg))
|
||||
}
|
||||
43
_demo/socket/server/server.go
Normal file
43
_demo/socket/server/server.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var buffer [256]c.Char
|
||||
|
||||
sockfd := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
|
||||
defer os.Close(sockfd)
|
||||
|
||||
servAddr := &net.SockaddrIn{
|
||||
Family: net.AF_INET,
|
||||
Port: net.Htons(uint16(1234)),
|
||||
Addr: net.InAddr{Addr: 0x00000000},
|
||||
Zero: [8]c.Char{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
if res := net.Bind(sockfd, servAddr, c.Uint(unsafe.Sizeof(*servAddr))); res < 0 {
|
||||
c.Perror(c.Str("bind error"))
|
||||
return
|
||||
}
|
||||
|
||||
if net.Listen(sockfd, 5) < 0 {
|
||||
c.Printf(c.Str("listen error"))
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("Listening on port 1234...\n"))
|
||||
|
||||
cliAddr, clilen := &net.SockaddrIn{}, c.Uint(unsafe.Sizeof(servAddr))
|
||||
|
||||
newsockfd := net.Accept(sockfd, cliAddr, &clilen)
|
||||
defer os.Close(newsockfd)
|
||||
c.Printf(c.Str("Connection accepted."))
|
||||
|
||||
os.Read(newsockfd, unsafe.Pointer(unsafe.SliceData(buffer[:])), 256)
|
||||
c.Printf(c.Str("Received: %s"), &buffer[0])
|
||||
|
||||
}
|
||||
26
_demo/sysexec/exec.go
Normal file
26
_demo/sysexec/exec.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
args := []string{ls, "-l"}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
args = []string{ls}
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
err := syscall.Exec(ls, args, nil)
|
||||
if err != nil {
|
||||
fmt.Println("syscall.Exec error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
11
_demo/timedur/timedur.go
Normal file
11
_demo/timedur/timedur.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Now().Add(time.Second * 5)
|
||||
fmt.Println(time.Until(t))
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package main
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/_test/testing"
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/bdwgc"
|
||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||
)
|
||||
|
||||
// ------ Test malloc ------
|
||||
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/_test/testing"
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
Binary file not shown.
Binary file not shown.
13
c/c.go
13
c/c.go
@@ -28,6 +28,7 @@ const (
|
||||
)
|
||||
|
||||
type (
|
||||
Void = [0]byte
|
||||
Char = int8
|
||||
Float = float32
|
||||
Double = float64
|
||||
@@ -68,6 +69,9 @@ func Alloca(size uintptr) Pointer
|
||||
//go:linkname AllocaCStr llgo.allocaCStr
|
||||
func AllocaCStr(s string) *Char
|
||||
|
||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
||||
|
||||
// TODO(xsw):
|
||||
// llgo:link AllocaNew llgo.allocaNew
|
||||
func AllocaNew[T any]() *T { return nil }
|
||||
@@ -212,6 +216,15 @@ func Fputs(s *Char, fp FilePtr) Int
|
||||
//go:linkname Fflush C.fflush
|
||||
func Fflush(fp FilePtr) Int
|
||||
|
||||
//go:linkname Fopen C.fopen
|
||||
func Fopen(c *Char, mod *Char) FilePtr
|
||||
|
||||
//go:linkname Fclose C.fclose
|
||||
func Fclose(fp FilePtr) Int
|
||||
|
||||
//go:linkname Perror C.perror
|
||||
func Perror(s *Char)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Time C.time
|
||||
|
||||
@@ -22,6 +22,22 @@ func main() {
|
||||
|
||||
mod.SetItem(c.Str("items"), syms)
|
||||
|
||||
c.Printf(c.Str("%s\n"), mod.CStr())
|
||||
cstr := mod.CStr()
|
||||
str := c.GoString(cstr)
|
||||
c.Printf(c.Str("%s\n"), cstr)
|
||||
cjson.FreeCStr(cstr)
|
||||
|
||||
mod.Delete()
|
||||
|
||||
cjsonLoad(str)
|
||||
}
|
||||
|
||||
func cjsonLoad(str string) {
|
||||
mod := cjson.ParseString(str)
|
||||
|
||||
cstr := mod.Print()
|
||||
c.Printf(c.Str("%s\n"), cstr)
|
||||
cjson.FreeCStr(cstr)
|
||||
|
||||
mod.Delete()
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package cjson
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
@@ -31,6 +31,20 @@ type JSON struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
//go:linkname Parse C.cJSON_Parse
|
||||
func Parse(value *c.Char) *JSON
|
||||
|
||||
//go:linkname ParseWithLength C.cJSON_ParseWithLength
|
||||
func ParseWithLength(value *byte, valueLength uintptr) *JSON
|
||||
|
||||
func ParseBytes(value []byte) *JSON {
|
||||
return ParseWithLength(unsafe.SliceData(value), uintptr(len(value)))
|
||||
}
|
||||
|
||||
func ParseString(value string) *JSON {
|
||||
return ParseWithLength(unsafe.StringData(value), uintptr(len(value)))
|
||||
}
|
||||
|
||||
//go:linkname Null C.cJSON_CreateNull
|
||||
func Null() *JSON
|
||||
|
||||
@@ -119,3 +133,9 @@ func (o *JSON) PrintUnformatted() *c.Char { return nil }
|
||||
//
|
||||
// llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered
|
||||
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil }
|
||||
|
||||
//go:linkname Free C.cJSON_free
|
||||
func Free(ptr unsafe.Pointer)
|
||||
|
||||
//go:linkname FreeCStr C.cJSON_free
|
||||
func FreeCStr(*c.Char)
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
@@ -13,6 +16,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe
|
||||
|
||||
func printAST(cursor clang.Cursor, depth c.Uint) {
|
||||
cursorKind := cursor.Kind.String()
|
||||
|
||||
cursorSpelling := cursor.String()
|
||||
|
||||
for i := c.Uint(0); i < depth; i++ {
|
||||
@@ -28,9 +32,16 @@ func printAST(cursor clang.Cursor, depth c.Uint) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
if c.Argc != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
|
||||
return
|
||||
}
|
||||
sourceFile := *c.Advance(c.Argv, 1)
|
||||
|
||||
index := clang.CreateIndex(0, 0)
|
||||
|
||||
unit := index.ParseTranslationUnit(
|
||||
c.Str("todo"),
|
||||
sourceFile,
|
||||
nil, 0,
|
||||
nil, 0,
|
||||
clang.TranslationUnit_None,
|
||||
@@ -42,6 +53,7 @@ func main() {
|
||||
}
|
||||
|
||||
cursor := unit.Cursor()
|
||||
|
||||
printAST(cursor, 0)
|
||||
|
||||
unit.Dispose()
|
||||
|
||||
131
c/clang/_demo/symboldump/symboldump.go
Normal file
131
c/clang/_demo/symboldump/symboldump.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
namespaceName string
|
||||
className string
|
||||
}
|
||||
|
||||
func newContext() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
||||
func (c *Context) setNamespaceName(name string) {
|
||||
c.namespaceName = name
|
||||
}
|
||||
|
||||
func (c *Context) setClassName(name string) {
|
||||
c.className = name
|
||||
}
|
||||
|
||||
var context = newContext()
|
||||
|
||||
func print_cursor_info(cursor clang.Cursor) {
|
||||
loc := cursor.Location()
|
||||
var file clang.File
|
||||
var line, column c.Uint
|
||||
|
||||
loc.SpellingLocation(&file, &line, &column, nil)
|
||||
filename := file.FileName()
|
||||
|
||||
c.Printf(c.Str("%s:%d:%d\n"), filename.CStr(), line, column)
|
||||
|
||||
cursorStr := cursor.String()
|
||||
symbol := cursor.Mangling()
|
||||
defer symbol.Dispose()
|
||||
defer cursorStr.Dispose()
|
||||
defer filename.Dispose()
|
||||
|
||||
if context.namespaceName != "" && context.className != "" {
|
||||
fmt.Printf("%s:%s:", context.namespaceName, context.className)
|
||||
} else if context.namespaceName != "" {
|
||||
fmt.Printf("%s:", context.namespaceName)
|
||||
}
|
||||
c.Printf(c.Str("%s\n"), cursorStr.CStr())
|
||||
|
||||
if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl {
|
||||
c.Printf(c.Str("symbol:%s\n"), symbol.CStr())
|
||||
|
||||
typeStr := cursor.ResultType().String()
|
||||
defer typeStr.Dispose()
|
||||
c.Printf(c.Str("Return Type: %s\n"), typeStr.CStr())
|
||||
c.Printf(c.Str("Parameters(%d): ( "), cursor.NumArguments())
|
||||
|
||||
for i := 0; i < int(cursor.NumArguments()); i++ {
|
||||
argCurSor := cursor.Argument(c.Uint(i))
|
||||
argType := argCurSor.Type().String()
|
||||
argName := argCurSor.String()
|
||||
c.Printf(c.Str("%s %s"), argType.CStr(), argName.CStr())
|
||||
if i < int(cursor.NumArguments())-1 {
|
||||
c.Printf(c.Str(", "))
|
||||
}
|
||||
|
||||
argType.Dispose()
|
||||
argName.Dispose()
|
||||
}
|
||||
|
||||
c.Printf(c.Str(" )\n"))
|
||||
println("--------------------------------")
|
||||
}
|
||||
}
|
||||
|
||||
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
||||
if cursor.Kind == clang.Namespace {
|
||||
nameStr := cursor.String()
|
||||
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
context.setNamespaceName("")
|
||||
} else if cursor.Kind == clang.ClassDecl {
|
||||
nameStr := cursor.String()
|
||||
context.setClassName(c.GoString(nameStr.CStr()))
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
context.setClassName("")
|
||||
} else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl {
|
||||
print_cursor_info(cursor)
|
||||
}
|
||||
|
||||
return clang.ChildVisit_Continue
|
||||
}
|
||||
|
||||
func parse(filename *c.Char) {
|
||||
index := clang.CreateIndex(0, 0)
|
||||
args := make([]*c.Char, 3)
|
||||
args[0] = c.Str("-x")
|
||||
args[1] = c.Str("c++")
|
||||
args[2] = c.Str("-std=c++11")
|
||||
unit := index.ParseTranslationUnit(
|
||||
filename,
|
||||
unsafe.SliceData(args), 3,
|
||||
nil, 0,
|
||||
clang.TranslationUnit_None,
|
||||
)
|
||||
|
||||
if unit == nil {
|
||||
println("Unable to parse translation unit. Quitting.")
|
||||
c.Exit(1)
|
||||
}
|
||||
|
||||
cursor := unit.Cursor()
|
||||
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
unit.Dispose()
|
||||
index.Dispose()
|
||||
}
|
||||
|
||||
func main() {
|
||||
if c.Argc != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: <C++ header file>\n")
|
||||
return
|
||||
} else {
|
||||
sourceFile := *c.Advance(c.Argv, 1)
|
||||
parse(sourceFile)
|
||||
}
|
||||
}
|
||||
50
c/clang/_wrap/cursor.cpp
Normal file
50
c/clang/_wrap/cursor.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <clang-c/Index.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum CXChildVisitResult (*wrap_CXCursorVisitor)(CXCursor *cursor, CXCursor *parent, CXClientData client_data);
|
||||
|
||||
typedef struct {
|
||||
CXClientData data;
|
||||
wrap_CXCursorVisitor visitor;
|
||||
} wrap_data;
|
||||
|
||||
CXChildVisitResult wrap_visitor(CXCursor cursor, CXCursor parent, CXClientData data) {
|
||||
wrap_data *d = (wrap_data *)(data);
|
||||
return d->visitor(&cursor, &parent, d->data);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
CXString wrap_clang_getCursorSpelling(CXCursor *cur) { return clang_getCursorSpelling(*cur); }
|
||||
|
||||
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*cur); }
|
||||
|
||||
int wrap_clang_Cursor_getNumArguments(CXCursor *cur) { return clang_Cursor_getNumArguments(*cur); }
|
||||
|
||||
void wrap_clang_Cursor_getArgument(CXCursor *C, unsigned i, CXCursor *argCur) {
|
||||
*argCur = clang_Cursor_getArgument(*C, i);
|
||||
}
|
||||
|
||||
void wrap_clang_getTranslationUnitCursor(CXTranslationUnit uint, CXCursor *cur) {
|
||||
*cur = clang_getTranslationUnitCursor(uint);
|
||||
}
|
||||
|
||||
void wrap_clang_getCursorType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorType(*cur); }
|
||||
|
||||
void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorResultType(*cur); }
|
||||
|
||||
CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); }
|
||||
|
||||
void wrap_clang_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); }
|
||||
|
||||
void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column,
|
||||
unsigned *offset) {
|
||||
clang_getSpellingLocation(*loc, file, line, column, offset);
|
||||
}
|
||||
|
||||
unsigned wrap_clang_visitChildren(CXCursor *parent, wrap_CXCursorVisitor visitor, CXClientData client_data) {
|
||||
wrap_data data = {client_data, visitor};
|
||||
return clang_visitChildren(*parent, wrap_visitor, CXClientData(&data));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
7
c/clang/_wrap/llgo_check.cpp
Normal file
7
c/clang/_wrap/llgo_check.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
int main() {
|
||||
printf("sizeof(clang.Cursor) = %lu\n", sizeof(CXCursor));
|
||||
return 0;
|
||||
}
|
||||
16
c/clang/_wrap/llgo_check.go
Normal file
16
c/clang/_wrap/llgo_check.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoCFlags = "-I$(llvm-config --includedir)"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("sizeof(clang.Cursor) = %lu\n"), unsafe.Sizeof(clang.Cursor{}))
|
||||
}
|
||||
@@ -38,13 +38,13 @@ type String struct {
|
||||
/**
|
||||
* Retrieve the character data associated with the given string.
|
||||
*/
|
||||
// llgo:link C.clang_getCString
|
||||
// llgo:link String.CStr C.clang_getCString
|
||||
func (String) CStr() *c.Char { return nil }
|
||||
|
||||
/**
|
||||
* Free the given string.
|
||||
*/
|
||||
// llgo:link C.clang_disposeString
|
||||
// llgo:link String.Dispose C.clang_disposeString
|
||||
func (String) Dispose() {}
|
||||
|
||||
type StringSet struct {
|
||||
@@ -55,5 +55,5 @@ type StringSet struct {
|
||||
/**
|
||||
* Free the given string set.
|
||||
*/
|
||||
// llgo:link C.clang_disposeStringSet
|
||||
// llgo:link (*StringSet).Dispose C.clang_disposeStringSet
|
||||
func (*StringSet) Dispose() {}
|
||||
|
||||
1280
c/clang/clang.go
1280
c/clang/clang.go
File diff suppressed because it is too large
Load Diff
Binary file not shown.
44
c/libuv/README.md
Normal file
44
c/libuv/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
LLGo wrapper of libuv
|
||||
=====
|
||||
|
||||
## How to install
|
||||
|
||||
### on macOS (Homebrew)
|
||||
|
||||
```sh
|
||||
brew install libuv
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
|
||||
```sh
|
||||
apt-get install -y libuv1-dev
|
||||
```
|
||||
|
||||
### on Linux (CentOS/RHEL)
|
||||
|
||||
```sh
|
||||
yum install -y libuv-devel
|
||||
```
|
||||
|
||||
### on Linux (Arch Linux)
|
||||
|
||||
```sh
|
||||
pacman -S libuv
|
||||
```
|
||||
|
||||
## Demos
|
||||
|
||||
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
|
||||
|
||||
* [async_fs](_demo/async_fs/async_fs.go): a simple async file read demo
|
||||
* [echo_server](_demo/echo_server/echo_server.go): a basic async tcp echo server
|
||||
|
||||
### How to run demos
|
||||
|
||||
To run the demos in directory `_demo`:
|
||||
|
||||
```sh
|
||||
cd <demo-directory> # eg. cd _demo/sqlitedemo
|
||||
llgo run .
|
||||
```
|
||||
97
c/libuv/_demo/async_fs/async_fs.go
Normal file
97
c/libuv/_demo/async_fs/async_fs.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/libuv"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
const BUFFER_SIZE = 1024
|
||||
|
||||
var (
|
||||
loop *libuv.Loop
|
||||
openReq libuv.Fs
|
||||
readReq libuv.Fs
|
||||
closeReq libuv.Fs
|
||||
|
||||
buffer [BUFFER_SIZE]c.Char
|
||||
iov libuv.Buf
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print the libuv version
|
||||
c.Printf(c.Str("libuv version: %d\n"), libuv.Version())
|
||||
|
||||
// Initialize the loop
|
||||
loop = libuv.DefaultLoop()
|
||||
|
||||
// Open the file
|
||||
libuv.FsOpen(loop, &openReq, c.Str("example.txt"), os.O_RDONLY, 0, onOpen)
|
||||
|
||||
// Run the loop
|
||||
libuv.Run(loop, libuv.RUN_DEFAULT)
|
||||
|
||||
// Cleanup
|
||||
defer cleanup()
|
||||
}
|
||||
|
||||
func onOpen(req *libuv.Fs) {
|
||||
// Check for errors
|
||||
if libuv.FsGetResult(req) < 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(libuv.Errno(libuv.LoopClose(loop))))
|
||||
libuv.LoopClose(loop)
|
||||
return
|
||||
}
|
||||
// Init buffer
|
||||
iov = libuv.InitBuf((*c.Char)(unsafe.Pointer(&buffer[0])), c.Uint(unsafe.Sizeof(buffer)))
|
||||
// Read the file
|
||||
readRes := libuv.FsRead(loop, &readReq, libuv.UvFile(libuv.FsGetResult(req)), &iov, 1, -1, onRead)
|
||||
if readRes != 0 {
|
||||
c.Printf(c.Str("Error in FsRead: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(readRes)), readRes)
|
||||
libuv.LoopClose(loop)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func onRead(req *libuv.Fs) {
|
||||
// Check for errors
|
||||
if libuv.FsGetResult(req) < 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req))))
|
||||
libuv.LoopClose(loop)
|
||||
} else if libuv.FsGetResult(req) == 0 {
|
||||
c.Printf(c.Str("EOF\n"))
|
||||
// Close the file
|
||||
closeRes := libuv.FsClose(loop, &closeReq, libuv.UvFile(libuv.FsGetResult(&openReq)), onClose)
|
||||
if closeRes != 0 {
|
||||
// Print the content
|
||||
c.Printf(c.Str("Error in FsClose: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(closeRes)), closeRes)
|
||||
libuv.LoopClose(loop)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.Printf(c.Str("Read %d bytes\n"), libuv.FsGetResult(req))
|
||||
c.Printf(c.Str("Read content: %.*s\n"), libuv.FsGetResult(req), (*c.Char)(unsafe.Pointer(&buffer[0])))
|
||||
libuv.LoopClose(loop)
|
||||
}
|
||||
}
|
||||
|
||||
func onClose(req *libuv.Fs) {
|
||||
// Check for errors
|
||||
if libuv.FsGetResult(req) < 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Error closing file: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req))))
|
||||
} else {
|
||||
c.Printf(c.Str("\nFile closed successfully.\n"))
|
||||
}
|
||||
libuv.LoopClose(loop)
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
// Cleanup the requests
|
||||
libuv.FsReqCleanup(&openReq)
|
||||
libuv.FsReqCleanup(&readReq)
|
||||
libuv.FsReqCleanup(&closeReq)
|
||||
// Close the loop
|
||||
libuv.LoopClose(loop)
|
||||
}
|
||||
1
c/libuv/_demo/async_fs/example.txt
Executable file
1
c/libuv/_demo/async_fs/example.txt
Executable file
@@ -0,0 +1 @@
|
||||
123
|
||||
120
c/libuv/_demo/echo_server/echo_server.go
Normal file
120
c/libuv/_demo/echo_server/echo_server.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/libuv"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
)
|
||||
|
||||
var DEFAULT_PORT c.Int = 8080
|
||||
var DEFAULT_BACKLOG c.Int = 128
|
||||
|
||||
var loop *libuv.Loop
|
||||
|
||||
type WriteReq struct {
|
||||
Req libuv.Write
|
||||
Buf libuv.Buf
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize the default event loop
|
||||
loop = libuv.DefaultLoop()
|
||||
|
||||
// Initialize a TCP server
|
||||
var server libuv.Tcp
|
||||
libuv.InitTcp(loop, &server)
|
||||
|
||||
// Set up the address to bind the server to
|
||||
var addr net.SockaddrIn
|
||||
libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr)
|
||||
c.Printf(c.Str("Listening on %s:%d\n"), c.Str("0.0.0.0"), DEFAULT_PORT)
|
||||
|
||||
// Bind the server to the specified address and port
|
||||
(&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0)
|
||||
res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection)
|
||||
if res != 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror((libuv.Errno(res))))
|
||||
return
|
||||
}
|
||||
|
||||
// Start listening for incoming connections
|
||||
libuv.Run(loop, libuv.RUN_DEFAULT)
|
||||
}
|
||||
|
||||
func FreeWriteReq(req *libuv.Write) {
|
||||
wr := (*WriteReq)(c.Pointer(req))
|
||||
// Free the buffer base and the WriteReq itself.
|
||||
c.Free(c.Pointer(wr.Buf.Base))
|
||||
c.Free(c.Pointer(wr))
|
||||
}
|
||||
|
||||
func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
|
||||
// Allocate memory for the buffer based on the suggested size.
|
||||
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
|
||||
buf.Len = suggestedSize
|
||||
}
|
||||
|
||||
func EchoWrite(req *libuv.Write, status c.Int) {
|
||||
if status != 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror((libuv.Errno(status))))
|
||||
}
|
||||
FreeWriteReq(req)
|
||||
}
|
||||
|
||||
func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
|
||||
if nread > 0 {
|
||||
req := (*WriteReq)(c.Malloc(unsafe.Sizeof(WriteReq{})))
|
||||
if req == nil {
|
||||
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for write request\n"))
|
||||
c.Free(c.Pointer(buf.Base))
|
||||
return
|
||||
}
|
||||
// Initialize the buffer with the data read.
|
||||
req.Buf = libuv.InitBuf(buf.Base, c.Uint(nread))
|
||||
// Write the data back to the client.
|
||||
(&req.Req).Write(client, &req.Buf, 1, EchoWrite)
|
||||
return
|
||||
}
|
||||
if nread < 0 {
|
||||
// Handle read errors and EOF.
|
||||
if (libuv.Errno)(nread) != libuv.EOF {
|
||||
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror((libuv.Errno)(nread)))
|
||||
}
|
||||
(*libuv.Handle)(c.Pointer(client)).Close(nil)
|
||||
}
|
||||
// Free the buffer if it's no longer needed.
|
||||
if buf.Base != nil {
|
||||
c.Free(c.Pointer(buf.Base))
|
||||
}
|
||||
}
|
||||
|
||||
func OnNewConnection(server *libuv.Stream, status c.Int) {
|
||||
if status < 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(libuv.Errno(status)))
|
||||
return
|
||||
}
|
||||
|
||||
// Allocate memory for a new client.
|
||||
client := (*libuv.Tcp)(c.Malloc(unsafe.Sizeof(libuv.Tcp{})))
|
||||
|
||||
if client == nil {
|
||||
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for client\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize the client TCP handle.
|
||||
if libuv.InitTcp(loop, client) < 0 {
|
||||
c.Fprintf(c.Stderr, c.Str("Failed to initialize client\n"))
|
||||
c.Free(c.Pointer(client))
|
||||
return
|
||||
}
|
||||
|
||||
// Accept the new connection and start reading data.
|
||||
if server.Accept((*libuv.Stream)(client)) == 0 {
|
||||
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead)
|
||||
} else {
|
||||
(*libuv.Handle)(c.Pointer(client)).Close(nil)
|
||||
}
|
||||
}
|
||||
118
c/libuv/error.go
Normal file
118
c/libuv/error.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
"github.com/goplus/llgo/c/syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
E2BIG = Errno(syscall.E2BIG)
|
||||
EACCES = Errno(syscall.EACCES)
|
||||
EADDRINUSE = Errno(syscall.EADDRINUSE)
|
||||
EADDRNOTAVAIL = Errno(syscall.EADDRNOTAVAIL)
|
||||
EAFNOSUPPORT = Errno(syscall.EAFNOSUPPORT)
|
||||
EAGAIN = Errno(syscall.EAGAIN)
|
||||
EALREADY = Errno(syscall.EALREADY)
|
||||
EBADF = Errno(syscall.EBADF)
|
||||
EBUSY = Errno(syscall.EBUSY)
|
||||
ECANCELED = Errno(syscall.ECANCELED)
|
||||
ECONNABORTED = Errno(syscall.ECONNABORTED)
|
||||
ECONNREFUSED = Errno(syscall.ECONNREFUSED)
|
||||
ECONNRESET = Errno(syscall.ECONNRESET)
|
||||
EDESTADDRREQ = Errno(syscall.EDESTADDRREQ)
|
||||
EEXIST = Errno(syscall.EEXIST)
|
||||
EFAULT = Errno(syscall.EFAULT)
|
||||
EFBIG = Errno(syscall.EFBIG)
|
||||
EHOSTUNREACH = Errno(syscall.EHOSTUNREACH)
|
||||
EINTR = Errno(syscall.EINTR)
|
||||
EINVAL = Errno(syscall.EINVAL)
|
||||
EIO = Errno(syscall.EIO)
|
||||
EISCONN = Errno(syscall.EISCONN)
|
||||
EISDIR = Errno(syscall.EISDIR)
|
||||
ELOOP = Errno(syscall.ELOOP)
|
||||
EMFILE = Errno(syscall.EMFILE)
|
||||
EMSGSIZE = Errno(syscall.EMSGSIZE)
|
||||
ENAMETOOLONG = Errno(syscall.ENAMETOOLONG)
|
||||
ENETDOWN = Errno(syscall.ENETDOWN)
|
||||
ENETUNREACH = Errno(syscall.ENETUNREACH)
|
||||
ENFILE = Errno(syscall.ENFILE)
|
||||
ENOBUFS = Errno(syscall.ENOBUFS)
|
||||
ENODEV = Errno(syscall.ENODEV)
|
||||
ENOENT = Errno(syscall.ENOENT)
|
||||
ENOMEM = Errno(syscall.ENOMEM)
|
||||
ENOPROTOOPT = Errno(syscall.ENOPROTOOPT)
|
||||
ENOSPC = Errno(syscall.ENOSPC)
|
||||
ENOSYS = Errno(syscall.ENOSYS)
|
||||
ENOTCONN = Errno(syscall.ENOTCONN)
|
||||
ENOTDIR = Errno(syscall.ENOTDIR)
|
||||
ENOTEMPTY = Errno(syscall.ENOTEMPTY)
|
||||
ENOTSOCK = Errno(syscall.ENOTSOCK)
|
||||
ENOTSUP = Errno(syscall.ENOTSUP)
|
||||
EOVERFLOW = Errno(syscall.EOVERFLOW)
|
||||
EPERM = Errno(syscall.EPERM)
|
||||
EPIPE = Errno(syscall.EPIPE)
|
||||
EPROTO = Errno(syscall.EPROTO)
|
||||
EPROTONOSUPPORT = Errno(syscall.EPROTONOSUPPORT)
|
||||
EPROTOTYPE = Errno(syscall.EPROTOTYPE)
|
||||
ERANGE = Errno(syscall.ERANGE)
|
||||
EROFS = Errno(syscall.EROFS)
|
||||
ESHUTDOWN = Errno(syscall.ESHUTDOWN)
|
||||
ESPIPE = Errno(syscall.ESPIPE)
|
||||
ESRCH = Errno(syscall.ESRCH)
|
||||
ETIMEDOUT = Errno(syscall.ETIMEDOUT)
|
||||
ETXTBSY = Errno(syscall.ETXTBSY)
|
||||
EXDEV = Errno(syscall.EXDEV)
|
||||
ENXIO = Errno(syscall.ENXIO)
|
||||
EMLINK = Errno(syscall.EMLINK)
|
||||
EHOSTDOWN = Errno(syscall.EHOSTDOWN)
|
||||
ENOTTY = Errno(syscall.ENOTTY)
|
||||
//EFTYPE = Errno(syscall.EFTYPE)
|
||||
EILSEQ = Errno(syscall.EILSEQ)
|
||||
ESOCKTNOSUPPORT = Errno(syscall.ESOCKTNOSUPPORT)
|
||||
)
|
||||
|
||||
const (
|
||||
EAI_ADDRFAMILY = Errno(net.EAI_ADDRFAMILY)
|
||||
EAI_AGAIN = Errno(net.EAI_AGAIN)
|
||||
EAI_BADFLAGS = Errno(net.EAI_BADFLAGS)
|
||||
EAI_BADHINTS = Errno(net.EAI_BADHINTS)
|
||||
EAI_FAIL = Errno(net.EAI_FAIL)
|
||||
EAI_FAMILY = Errno(net.EAI_FAMILY)
|
||||
EAI_MEMORY = Errno(net.EAI_MEMORY)
|
||||
EAI_NODATA = Errno(net.EAI_NODATA)
|
||||
EAI_NONAME = Errno(net.EAI_NONAME)
|
||||
EAI_OVERFLOW = Errno(net.EAI_OVERFLOW)
|
||||
EAI_PROTOCOL = Errno(net.EAI_PROTOCOL)
|
||||
EAI_SERVICE = Errno(net.EAI_SERVICE)
|
||||
EAI_SOCKTYPE = Errno(net.EAI_SOCKTYPE)
|
||||
)
|
||||
|
||||
const (
|
||||
EAI_CANCELED Errno = -3003
|
||||
ECHARSET Errno = -4080
|
||||
ENONET Errno = -4056
|
||||
UNKNOWN Errno = -4094
|
||||
EOF Errno = -1
|
||||
EREMOTEIO Errno = -4030
|
||||
ERRNO_MAX Errno = EOF - 1
|
||||
)
|
||||
|
||||
type Errno c.Int
|
||||
|
||||
//go:linkname TranslateSysError C.uv_translate_sys_error
|
||||
func TranslateSysError(sysErrno c.Int) Errno
|
||||
|
||||
//go:linkname Strerror C.uv_strerror
|
||||
func Strerror(err Errno) *c.Char
|
||||
|
||||
//go:linkname StrerrorR C.uv_strerror_r
|
||||
func StrerrorR(err Errno, buf *c.Char, bufLen uintptr) *c.Char
|
||||
|
||||
//go:linkname ErrName C.uv_err_name
|
||||
func ErrName(err Errno) *c.Char
|
||||
|
||||
//go:linkname ErrNameR C.uv_err_name_r
|
||||
func ErrNameR(err Errno, buf *c.Char, bufLen uintptr) *c.Char
|
||||
277
c/libuv/fs.go
Normal file
277
c/libuv/fs.go
Normal file
@@ -0,0 +1,277 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
FS_UNKNOWN FsType = -1
|
||||
FS_CUSTOM FsType = 0
|
||||
FS_OPEN FsType = 1
|
||||
FS_CLOSE FsType = 2
|
||||
FS_READ FsType = 3
|
||||
FS_WRITE FsType = 4
|
||||
FS_SENDFILE FsType = 5
|
||||
FS_STAT FsType = 6
|
||||
FS_LSTAT FsType = 7
|
||||
FS_FSTAT FsType = 8
|
||||
FS_FTRUNCATE FsType = 9
|
||||
FS_UTIME FsType = 10
|
||||
FS_FUTIME FsType = 11
|
||||
FS_ACCESS FsType = 12
|
||||
FS_CHMOD FsType = 13
|
||||
FS_FCHMOD FsType = 14
|
||||
FS_FSYNC FsType = 15
|
||||
FS_FDATASYNC FsType = 16
|
||||
FS_UNLINK FsType = 17
|
||||
FS_RMDIR FsType = 18
|
||||
FS_MKDIR FsType = 19
|
||||
FS_MKDTEMP FsType = 20
|
||||
FS_RENAME FsType = 21
|
||||
FS_SCANDIR FsType = 22
|
||||
FS_LINK FsType = 23
|
||||
FS_SYMLINK FsType = 24
|
||||
FS_READLINK FsType = 25
|
||||
FS_CHOWN FsType = 26
|
||||
FS_FCHOWN FsType = 27
|
||||
FS_REALPATH FsType = 28
|
||||
FS_COPYFILE FsType = 29
|
||||
FS_LCHOWN FsType = 30
|
||||
FS_OPENDIR FsType = 31
|
||||
FS_READDIR FsType = 32
|
||||
FS_CLOSEDIR FsType = 33
|
||||
FS_STATFS FsType = 34
|
||||
FS_MKSTEMP FsType = 35
|
||||
FS_LUTIME FsType = 36
|
||||
)
|
||||
|
||||
const (
|
||||
DirentUnknown DirentType = iota
|
||||
DirentFile
|
||||
DirentDir
|
||||
DirentLink
|
||||
DirentFifo
|
||||
DirentSocket
|
||||
DirentChar
|
||||
DirentBlock
|
||||
)
|
||||
|
||||
type FsType c.Int
|
||||
|
||||
type DirentType c.Int
|
||||
|
||||
type UvFile c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Handle types. */
|
||||
|
||||
type Fs struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type FsEvent struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type FsPoll struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Dirent struct {
|
||||
Name *c.Char
|
||||
Type DirentType
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Loop *Loop
|
||||
Req *Fs
|
||||
}
|
||||
|
||||
type Stat struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Function type */
|
||||
|
||||
// llgo:type C
|
||||
type FsCb func(req *Fs)
|
||||
|
||||
// llgo:type C
|
||||
type FsEventCb func(handle *FsEvent, filename *c.Char, events c.Int, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type FsPollCb func(handle *FsPoll, status c.Int, events c.Int)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Fs related function and method */
|
||||
|
||||
//go:linkname FsGetType C.uv_fs_get_type
|
||||
func FsGetType(req *Fs) *FsType
|
||||
|
||||
//go:linkname FsGetPath C.uv_fs_get_path
|
||||
func FsGetPath(req *Fs) *c.Char
|
||||
|
||||
//go:linkname FsGetResult C.uv_fs_get_result
|
||||
func FsGetResult(req *Fs) c.Int
|
||||
|
||||
//go:linkname FsGetPtr C.uv_fs_get_ptr
|
||||
func FsGetPtr(req *Fs) c.Pointer
|
||||
|
||||
//go:linkname FsGetSystemError C.uv_fs_get_system_error
|
||||
func FsGetSystemError(req *Fs) c.Int
|
||||
|
||||
//go:linkname FsGetStatBuf C.uv_fs_get_statbuf
|
||||
func FsGetStatBuf(req *Fs) *Stat
|
||||
|
||||
//go:linkname FsReqCleanup C.uv_fs_req_cleanup
|
||||
func FsReqCleanup(req *Fs)
|
||||
|
||||
//go:linkname DefaultLoop C.uv_default_loop
|
||||
func DefaultLoop() *Loop
|
||||
|
||||
//go:linkname FsOpen C.uv_fs_open
|
||||
func FsOpen(loop *Loop, req *Fs, path *c.Char, flags c.Int, mode c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsClose C.uv_fs_close
|
||||
func FsClose(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsRead C.uv_fs_read
|
||||
func FsRead(loop *Loop, req *Fs, file UvFile, bufs *Buf, nbufs c.Uint, offset c.LongLong, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsWrite C.uv_fs_write
|
||||
func FsWrite(loop *Loop, req *Fs, file UvFile, bufs *Buf, nbufs c.Uint, offset c.LongLong, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsUnlink C.uv_fs_unlink
|
||||
func FsUnlink(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsMkdir C.uv_fs_mkdir
|
||||
func FsMkdir(loop *Loop, req *Fs, path *c.Char, mode c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsMkdtemp C.uv_fs_mkdtemp
|
||||
func FsMkdtemp(loop *Loop, req *Fs, tpl *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsMkStemp C.uv_fs_mkstemp
|
||||
func FsMkStemp(loop *Loop, req *Fs, tpl *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsRmdir C.uv_fs_rmdir
|
||||
func FsRmdir(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsStat C.uv_fs_stat
|
||||
func FsStat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFstat C.uv_fs_fstat
|
||||
func FsFstat(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsRename C.uv_fs_rename
|
||||
func FsRename(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFsync C.uv_fs_fsync
|
||||
func FsFsync(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFdatasync C.uv_fs_fdatasync
|
||||
func FsFdatasync(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFtruncate C.uv_fs_ftruncate
|
||||
func FsFtruncate(loop *Loop, req *Fs, file UvFile, offset c.LongLong, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsSendfile C.uv_fs_sendfile
|
||||
func FsSendfile(loop *Loop, req *Fs, outFd c.Int, inFd c.Int, inOffset c.LongLong, length c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsAccess C.uv_fs_access
|
||||
func FsAccess(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsChmod C.uv_fs_chmod
|
||||
func FsChmod(loop *Loop, req *Fs, path *c.Char, mode c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFchmod C.uv_fs_fchmod
|
||||
func FsFchmod(loop *Loop, req *Fs, file UvFile, mode c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsUtime C.uv_fs_utime
|
||||
func FsUtime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFutime C.uv_fs_futime
|
||||
func FsFutime(loop *Loop, req *Fs, file UvFile, atime c.Int, mtime c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsLutime C.uv_fs_lutime
|
||||
func FsLutime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsLink C.uv_fs_link
|
||||
func FsLink(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsSymlink C.uv_fs_symlink
|
||||
func FsSymlink(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, flags c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsReadlink C.uv_fs_read
|
||||
func FsReadlink(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsRealpath C.uv_fs_realpath
|
||||
func FsRealpath(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsCopyfile C.uv_fs_copyfile
|
||||
func FsCopyfile(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, flags c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsScandir C.uv_fs_scandir
|
||||
func FsScandir(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsScandirNext C.uv_fs_scandir_next
|
||||
func FsScandirNext(req *Fs, ent *Dirent) c.Int
|
||||
|
||||
//go:linkname FsOpenDir C.uv_fs_opendir
|
||||
func FsOpenDir(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsReaddir C.uv_fs_readdir
|
||||
func FsReaddir(loop *Loop, req *Fs, dir c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsCloseDir C.uv_fs_closedir
|
||||
func FsCloseDir(loop *Loop, req *Fs) c.Int
|
||||
|
||||
//go:linkname FsStatfs C.uv_fs_statfs
|
||||
func FsStatfs(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsChown C.uv_fs_chown
|
||||
func FsChown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsFchown C.uv_fs_fchown
|
||||
func FsFchown(loop *Loop, req *Fs, file UvFile, uid c.Int, gid c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsLchown C.uv_fs_lchown
|
||||
func FsLchown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsLstat C.uv_fs_lstat
|
||||
func FsLstat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
|
||||
|
||||
//go:linkname FsEventInit C.uv_fs_event_init
|
||||
func FsEventInit(loop *Loop, handle *FsEvent) c.Int
|
||||
|
||||
//go:linkname FsEventStart C.uv_fs_event_start
|
||||
func FsEventStart(handle *FsEvent, cb FsEventCb, path *c.Char, flags c.Int) c.Int
|
||||
|
||||
//go:linkname FsEventStop C.uv_fs_event_stop
|
||||
func FsEventStop(handle *FsEvent) c.Int
|
||||
|
||||
//go:linkname FsEventClose C.uv_fs_event_close
|
||||
func FsEventClose(handle *FsEvent) c.Int
|
||||
|
||||
//go:linkname FsEventGetpath C.uv_fs_event_getpath
|
||||
func FsEventGetpath(handle *FsEvent) *c.Char
|
||||
|
||||
//go:linkname FsPollInit C.uv_fs_poll_init
|
||||
func FsPollInit(loop *Loop, handle *FsPoll) c.Int
|
||||
|
||||
//go:linkname FsPollStart C.uv_fs_poll_start
|
||||
func FsPollStart(handle *FsPoll, cb FsPollCb, path *c.Char, interval uint) c.Int
|
||||
|
||||
//go:linkname FsPollStop C.uv_fs_poll_stop
|
||||
func FsPollStop(handle *FsPoll) c.Int
|
||||
|
||||
//go:linkname FsPollClose C.uv_fs_poll_close
|
||||
func FsPollClose(handle *FsPoll) c.Int
|
||||
|
||||
//go:linkname FsPollGetPath C.uv_fs_poll_getpath
|
||||
func FsPollGetPath(handle *FsPoll) *c.Char
|
||||
488
c/libuv/libuv.go
Normal file
488
c/libuv/libuv.go
Normal file
@@ -0,0 +1,488 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libuv); -luv"
|
||||
)
|
||||
|
||||
// ----------------------------------------------
|
||||
const (
|
||||
RUN_DEFAULT RunMode = iota
|
||||
RUN_ONCE
|
||||
RUN_NOWAIT
|
||||
)
|
||||
|
||||
const (
|
||||
LOOP_BLOCK_SIGNAL LoopOption = iota
|
||||
METRICS_IDLE_TIME
|
||||
)
|
||||
|
||||
const (
|
||||
UV_LEAVE_GROUP Membership = iota
|
||||
UV_JOIN_GROUP
|
||||
)
|
||||
|
||||
const (
|
||||
UNKNOWN_HANDLE HandleType = iota
|
||||
ASYNC
|
||||
CHECK
|
||||
FS_EVENT
|
||||
FS_POLL
|
||||
HANDLE
|
||||
IDLE
|
||||
NAMED_PIPE
|
||||
POLL
|
||||
PREPARE
|
||||
PROCESS
|
||||
STREAM
|
||||
TCP
|
||||
TIMER
|
||||
TTY
|
||||
UDP
|
||||
SIGNAL
|
||||
FILE
|
||||
HANDLE_TYPE_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
UNKNOWN_REQ ReqType = iota
|
||||
REQ
|
||||
CONNECT
|
||||
WRITE
|
||||
SHUTDOWN
|
||||
UDP_SEND
|
||||
FS
|
||||
WORK
|
||||
GETADDRINFO
|
||||
GETNAMEINFO
|
||||
RANDOM
|
||||
REQ_TYPE_PRIVATE
|
||||
REQ_TYPE_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
READABLE PollEvent = 1 << iota
|
||||
WRITABLE
|
||||
DISCONNECT
|
||||
PRIPRIORITIZED
|
||||
)
|
||||
|
||||
type RunMode c.Int
|
||||
|
||||
type LoopOption c.Int
|
||||
|
||||
type Membership c.Int
|
||||
|
||||
type HandleType c.Int
|
||||
|
||||
type ReqType c.Int
|
||||
|
||||
type OsSock c.Int
|
||||
|
||||
type OsFd c.Int
|
||||
|
||||
type PollEvent c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Handle types. */
|
||||
|
||||
type Loop struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Handle struct {
|
||||
Unused [96]byte
|
||||
}
|
||||
|
||||
type Dir struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Stream struct {
|
||||
Unused [264]byte
|
||||
}
|
||||
|
||||
type Pipe struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Tty struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Poll struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Prepare struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Check struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Idle struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Async struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Process struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
/* Request types. */
|
||||
|
||||
type Req struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type GetAddrInfo struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type GetNameInfo struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Shutdown struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Write struct {
|
||||
Unused [192]byte
|
||||
}
|
||||
|
||||
type Connect struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
type Buf struct {
|
||||
Base *c.Char
|
||||
Len uintptr
|
||||
} // ----------------------------------------------
|
||||
|
||||
/* Function type */
|
||||
|
||||
// llgo:type C
|
||||
type MallocFunc func(size uintptr) c.Pointer
|
||||
|
||||
// llgo:type C
|
||||
type ReallocFunc func(ptr c.Pointer, size uintptr) c.Pointer
|
||||
|
||||
// llgo:type C
|
||||
type CallocFunc func(count uintptr, size uintptr) c.Pointer
|
||||
|
||||
// llgo:type C
|
||||
type FreeFunc func(ptr c.Pointer)
|
||||
|
||||
// llgo:type C
|
||||
type AllocCb func(handle *Handle, suggestedSize uintptr, buf *Buf)
|
||||
|
||||
// llgo:type C
|
||||
type ReadCb func(stream *Stream, nread c.Long, buf *Buf)
|
||||
|
||||
// llgo:type C
|
||||
type WriteCb func(req *Write, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type GetaddrinfoCb func(req *GetAddrInfo, status c.Int, res *net.AddrInfo)
|
||||
|
||||
// llgo:type C
|
||||
type GetnameinfoCb func(req *GetNameInfo, status c.Int, hostname *c.Char, service *c.Char)
|
||||
|
||||
// llgo:type C
|
||||
type ConnectionCb func(server *Stream, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type ShutdownCb func(req *Shutdown, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type WalkCb func(handle *Handle, arg c.Pointer)
|
||||
|
||||
// llgo:type C
|
||||
type PollCb func(handle *Poll, status c.Int, events c.Int)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
//go:linkname Version C.uv_version
|
||||
func Version() c.Uint
|
||||
|
||||
//go:linkname VersionString C.uv_version_string
|
||||
func VersionString() *c.Char
|
||||
|
||||
//go:linkname LibraryShutdown C.uv_library_shutdown
|
||||
func LibraryShutdown()
|
||||
|
||||
//go:linkname ReplaceAllocator C.uv_replace_allocator
|
||||
func ReplaceAllocator(mallocFunc MallocFunc, reallocFunc ReallocFunc, callocFunc CallocFunc, freeFunc FreeFunc) c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
// llgo:link (*Shutdown).Shutdown C.uv_shutdown
|
||||
func (shutdown *Shutdown) Shutdown(stream *Stream, shutdownCb ShutdownCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Handle related function and method */
|
||||
|
||||
// llgo:link (*Handle).Ref C.uv_ref
|
||||
func (handle *Handle) Ref() {}
|
||||
|
||||
// llgo:link (*Handle).Unref C.uv_unref
|
||||
func (handle *Handle) Unref() {}
|
||||
|
||||
// llgo:link (*Handle).HasRef C.uv_has_ref
|
||||
func (handle *Handle) HasRef() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname HandleSize C.uv_handle_size
|
||||
func HandleSize(handleType HandleType) uintptr
|
||||
|
||||
// llgo:link (*Handle).GetType C.uv_handle_get_type
|
||||
func (handle *Handle) GetType() HandleType {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname HandleTypeName C.uv_handle_type_name
|
||||
func HandleTypeName(handleType HandleType) *c.Char
|
||||
|
||||
// llgo:link (*Handle).GetData C.uv_handle_get_data
|
||||
func (handle *Handle) GetData() c.Pointer {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).GetLoop C.uv_handle_get_loop
|
||||
func (handle *Handle) GetLoop() *Loop {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).SetData C.uv_handle_set_data
|
||||
func (handle *Handle) SetData(data c.Pointer) {}
|
||||
|
||||
// llgo:link (*Handle).IsActive C.uv_is_active
|
||||
func (handle *Handle) IsActive() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).Close C.uv_close
|
||||
func (handle *Handle) Close(closeCb CloseCb) {}
|
||||
|
||||
// llgo:link (*Handle).SendBufferSize C.uv_send_buffer_size
|
||||
func (handle *Handle) SendBufferSize(value *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).RecvBufferSize C.uv_recv_buffer_size
|
||||
func (handle *Handle) RecvBufferSize(value *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).Fileno C.uv_fileno
|
||||
func (handle *Handle) Fileno(fd *OsFd) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname UvPipe C.uv_pipe
|
||||
func UvPipe(fds [2]UvFile, readFlags c.Int, writeFlags c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname Socketpair C.uv_socketpair
|
||||
func Socketpair(_type c.Int, protocol c.Int, socketVector [2]OsSock, flag0 c.Int, flag1 c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Handle).IsClosing C.uv_is_closing
|
||||
func (handle *Handle) IsClosing() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Req related function and method */
|
||||
|
||||
//go:linkname ReqSize C.uv_req_size
|
||||
func ReqSize(reqType ReqType) uintptr
|
||||
|
||||
// llgo:link (*Req).GetData C.uv_req_get_data
|
||||
func (req *Req) GetData() c.Pointer {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*Req).SetData C.uv_handle_set_data
|
||||
func (req *Req) SetData(data c.Pointer) {}
|
||||
|
||||
// llgo:link (*Req).GetType C.uv_req_get_type
|
||||
func (req *Req) GetType() ReqType {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname TypeName C.uv_req_type_name
|
||||
func TypeName(reqType ReqType) *c.Char
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Stream related function and method */
|
||||
|
||||
// llgo:link (*Stream).GetWriteQueueSize C.uv_stream_get_write_queue_size
|
||||
func (stream *Stream) GetWriteQueueSize() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).Listen C.uv_listen
|
||||
func (stream *Stream) Listen(backlog c.Int, connectionCb ConnectionCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).Accept C.uv_accept
|
||||
func (server *Stream) Accept(client *Stream) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).StartRead C.uv_read_start
|
||||
func (stream *Stream) StartRead(allocCb AllocCb, readCb ReadCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).StopRead C.uv_read_stop
|
||||
func (stream *Stream) StopRead() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Write).Write C.uv_write
|
||||
func (req *Write) Write(stream *Stream, bufs *Buf, nbufs c.Uint, writeCb WriteCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Write).Write2 C.uv_write2
|
||||
func (req *Write) Write2(stream *Stream, bufs *Buf, nbufs c.Uint, sendStream *Stream, writeCb WriteCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).TryWrite C.uv_try_write
|
||||
func (stream *Stream) TryWrite(bufs *Buf, nbufs c.Uint) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).TryWrite2 C.uv_try_write2
|
||||
func (stream *Stream) TryWrite2(bufs *Buf, nbufs c.Uint, sendStream *Stream) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).IsReadable C.uv_is_readable
|
||||
func (stream *Stream) IsReadable() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).IsWritable C.uv_is_writable
|
||||
func (stream *Stream) IsWritable() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Stream).SetBlocking C.uv_stream_set_blocking
|
||||
func (stream *Stream) SetBlocking(blocking c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Loop related functions and method. */
|
||||
|
||||
//go:linkname LoopSize C.uv_loop_size
|
||||
func LoopSize() uintptr
|
||||
|
||||
//go:linkname Run C.uv_run
|
||||
func Run(loop *Loop, mode RunMode) c.Int
|
||||
|
||||
//go:linkname LoopAlive C.uv_loop_alive
|
||||
func LoopAlive(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopClose C.uv_loop_close
|
||||
func LoopClose(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopConfigure C.uv_loop_configure
|
||||
func LoopConfigure(loop *Loop, option LoopOption, arg c.Int) c.Int
|
||||
|
||||
//go:linkname LoopDefault C.uv_default_loop
|
||||
func LoopDefault() *Loop
|
||||
|
||||
//go:linkname LoopDelete C.uv_loop_delete
|
||||
func LoopDelete(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopFork C.uv_loop_fork
|
||||
func LoopFork(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopInit C.uv_loop_init
|
||||
func LoopInit(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopNew C.uv_loop_new
|
||||
func LoopNew() *Loop
|
||||
|
||||
//go:linkname LoopNow C.uv_now
|
||||
func LoopNow(loop *Loop) c.UlongLong
|
||||
|
||||
//go:linkname LoopUpdateTime C.uv_update_time
|
||||
func LoopUpdateTime(loop *Loop)
|
||||
|
||||
//go:linkname LoopBackendFd C.uv_backend_fd
|
||||
func LoopBackendFd(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopBackendTimeout C.uv_backend_timeout
|
||||
func LoopBackendTimeout(loop *Loop) c.Int
|
||||
|
||||
//go:linkname LoopWalk C.uv_walk
|
||||
func LoopWalk(loop *Loop, walkCb WalkCb, arg c.Pointer)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Buf related functions and method. */
|
||||
|
||||
//go:linkname InitBuf C.uv_buf_init
|
||||
func InitBuf(base *c.Char, len c.Uint) Buf
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Poll related function and method */
|
||||
|
||||
//go:linkname PollInit C.uv_poll_init
|
||||
func PollInit(loop *Loop, handle *Poll, fd OsFd) c.Int
|
||||
|
||||
//go:linkname PollStart C.uv_poll_start
|
||||
func PollStart(handle *Poll, events c.Int, cb PollCb) c.Int
|
||||
|
||||
//go:linkname PollStop C.uv_poll_stop
|
||||
func PollStop(handle *Poll) c.Int
|
||||
|
||||
//go:linkname PollInitSocket C.uv_poll_init_socket
|
||||
func PollInitSocket(loop *Loop, handle *Poll, socket c.Int) c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Getaddrinfo related function and method */
|
||||
|
||||
//go:linkname Getaddrinfo C.uv_getaddrinfo
|
||||
func Getaddrinfo(loop *Loop, req *GetAddrInfo, getaddrinfoCb GetaddrinfoCb, node *c.Char, service *c.Char, hints *net.AddrInfo) c.Int
|
||||
|
||||
//go:linkname Freeaddrinfo C.uv_freeaddrinfo
|
||||
func Freeaddrinfo(addrInfo *net.AddrInfo)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Getnameinfo related function and method */
|
||||
|
||||
//go:linkname Getnameinfo C.uv_getnameinfo
|
||||
func Getnameinfo(loop *Loop, req *GetNameInfo, getnameinfoCb GetnameinfoCb, addr *net.SockAddr, flags c.Int) c.Int
|
||||
275
c/libuv/net.go
Normal file
275
c/libuv/net.go
Normal file
@@ -0,0 +1,275 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
)
|
||||
|
||||
const (
|
||||
/* Used with uv_tcp_bind, when an IPv6 address is used. */
|
||||
TCP_IPV6ONLY TcpFlags = 1
|
||||
)
|
||||
|
||||
/*
|
||||
* UDP support.
|
||||
*/
|
||||
const (
|
||||
/* Disables dual stack mode. */
|
||||
UDP_IPV6ONLY UdpFlags = 1
|
||||
/*
|
||||
* Indicates message was truncated because read buffer was too small. The
|
||||
* remainder was discarded by the OS. Used in uv_udp_recv_cb.
|
||||
*/
|
||||
UDP_PARTIAL UdpFlags = 2
|
||||
/*
|
||||
* Indicates if SO_REUSEADDR will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
|
||||
* Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
|
||||
* multiple threads or processes can bind to the same address without error
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
UDP_REUSEADDR UdpFlags = 4
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||
* must not be freed by the recv_cb callback.
|
||||
*/
|
||||
UDP_MMSG_CHUNK UdpFlags = 8
|
||||
/*
|
||||
* Indicates that the buffer provided has been fully utilized by recvmmsg and
|
||||
* that it should now be freed by the recv_cb callback. When this flag is set
|
||||
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
||||
*/
|
||||
UDP_MMSG_FREE UdpFlags = 16
|
||||
/*
|
||||
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
|
||||
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
|
||||
* Linux. This stops the Linux kernel from suppressing some ICMP error
|
||||
* messages and enables full ICMP error reporting for faster failover.
|
||||
* This flag is no-op on platforms other than Linux.
|
||||
*/
|
||||
UDP_LINUX_RECVERR UdpFlags = 32
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
UDP_RECVMMSG UdpFlags = 256
|
||||
)
|
||||
|
||||
type TcpFlags c.Int
|
||||
|
||||
type UdpFlags c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Handle types. */
|
||||
|
||||
type Tcp struct {
|
||||
Unused [264]byte
|
||||
}
|
||||
|
||||
type Udp struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
/* Request types. */
|
||||
|
||||
type UdpSend struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Function type */
|
||||
|
||||
// llgo:type C
|
||||
type CloseCb func(handle *Handle)
|
||||
|
||||
// llgo:type C
|
||||
type ConnectCb func(req *Connect, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type UdpSendCb func(req *UdpSend, status c.Int)
|
||||
|
||||
// llgo:type C
|
||||
type UdpRecvCb func(handle *Udp, nread c.Long, buf *Buf, addr *net.SockAddr, flags c.Uint)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Tcp related function and method */
|
||||
|
||||
//go:linkname InitTcp C.uv_tcp_init
|
||||
func InitTcp(loop *Loop, tcp *Tcp) c.Int
|
||||
|
||||
//go:linkname InitTcpEx C.uv_tcp_init_ex
|
||||
func InitTcpEx(loop *Loop, tcp *Tcp, flags c.Uint) c.Int
|
||||
|
||||
// llgo:link (*Tcp).Open C.uv_tcp_open
|
||||
func (tcp *Tcp) Open(sock OsSock) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).Nodelay C.uv_tcp_nodelay
|
||||
func (tcp *Tcp) Nodelay(enable c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).KeepAlive C.uv_tcp_keepalive
|
||||
func (tcp *Tcp) KeepAlive(enable c.Int, delay c.Uint) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).SimultaneousAccepts C.uv_tcp_simultaneous_accepts
|
||||
func (tcp *Tcp) SimultaneousAccepts(enable c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).Bind C.uv_tcp_bind
|
||||
func (tcp *Tcp) Bind(addr *net.SockAddr, flags c.Uint) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).Getsockname C.uv_tcp_getsockname
|
||||
func (tcp *Tcp) Getsockname(name *net.SockAddr, nameLen *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).Getpeername C.uv_tcp_getpeername
|
||||
func (tcp *Tcp) Getpeername(name *net.SockAddr, nameLen *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Tcp).CloseReset C.uv_tcp_close_reset
|
||||
func (tcp *Tcp) CloseReset(closeCb CloseCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname TcpConnect C.uv_tcp_connect
|
||||
func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb) c.Int
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Udp related function and method */
|
||||
|
||||
//go:linkname InitUdp C.uv_udp_init
|
||||
func InitUdp(loop *Loop, udp *Udp) c.Int
|
||||
|
||||
//go:linkname InitUdpEx C.uv_udp_init_ex
|
||||
func InitUdpEx(loop *Loop, udp *Udp, flags c.Uint) c.Int
|
||||
|
||||
// llgo:link (*Udp).Open C.uv_udp_open
|
||||
func (udp *Udp) Open(sock OsSock) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).Bind C.uv_udp_bind
|
||||
func (udp *Udp) Bind(addr *net.SockAddr, flags c.Uint) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).Connect C.uv_udp_connect
|
||||
func (udp *Udp) Connect(addr *net.SockAddr) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).Getpeername C.uv_udp_getpeername
|
||||
func (udp *Udp) Getpeername(name *net.SockAddr, nameLen *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).Getsockname C.uv_udp_getsockname
|
||||
func (udp *Udp) Getsockname(name *net.SockAddr, nameLen *c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetMembership C.uv_udp_set_membership
|
||||
func (udp *Udp) SetMembership(multicastAddr *c.Char, interfaceAddr *c.Char, membership Membership) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SourceMembership C.uv_udp_set_source_membership
|
||||
func (udp *Udp) SourceMembership(multicastAddr *c.Char, interfaceAddr *c.Char, sourceAddr *c.Char, membership Membership) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetMulticastLoop C.uv_udp_set_multicast_loop
|
||||
func (udp *Udp) SetMulticastLoop(on c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetMulticastTTL C.uv_udp_set_multicast_ttl
|
||||
func (udp *Udp) SetMulticastTTL(ttl c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetMulticastInterface C.uv_udp_set_multicast_interface
|
||||
func (udp *Udp) SetMulticastInterface(interfaceAddr *c.Char) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetBroadcast C.uv_udp_set_broadcast
|
||||
func (udp *Udp) SetBroadcast(on c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).SetTTL C.uv_udp_set_ttl
|
||||
func (udp *Udp) SetTTL(ttl c.Int) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:linkname Send C.uv_udp_send
|
||||
func Send(req *UdpSend, udp *Udp, bufs *Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int
|
||||
|
||||
// llgo:link (*Udp).TrySend C.uv_udp_try_send
|
||||
func (udp *Udp) TrySend(bufs *Buf, nbufs c.Uint, addr *net.SockAddr) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).StartRecv C.uv_udp_recv_start
|
||||
func (udp *Udp) StartRecv(allocCb AllocCb, recvCb UdpRecvCb) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).UsingRecvmmsg C.uv_udp_using_recvmmsg
|
||||
func (udp *Udp) UsingRecvmmsg() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).StopRecv C.uv_udp_recv_stop
|
||||
func (udp *Udp) StopRecv() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).GetSendQueueSize C.uv_udp_get_send_queue_size
|
||||
func (udp *Udp) GetSendQueueSize() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Udp).GetSendQueueCount C.uv_udp_get_send_queue_count
|
||||
func (udp *Udp) GetSendQueueCount() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
//go:linkname Ip4Addr C.uv_ip4_addr
|
||||
func Ip4Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn) c.Int
|
||||
|
||||
//go:linkname Ip6Addr C.uv_ip6_addr
|
||||
func Ip6Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn6) c.Int
|
||||
|
||||
//go:linkname Ip4Name C.uv_ip4_name
|
||||
func Ip4Name(src *net.SockaddrIn, dst *c.Char, size uintptr) c.Int
|
||||
|
||||
//go:linkname Ip6Name C.uv_ip6_name
|
||||
func Ip6Name(src *net.SockaddrIn6, dst *c.Char, size uintptr) c.Int
|
||||
|
||||
//go:linkname IpName C.uv_ip_name
|
||||
func IpName(src *net.SockAddr, dst *c.Char, size uintptr) c.Int
|
||||
|
||||
//go:linkname InetNtop C.uv_inet_ntop
|
||||
func InetNtop(af c.Int, src c.Pointer, dst *c.Char, size uintptr) c.Int
|
||||
|
||||
//go:linkname InetPton C.uv_inet_pton
|
||||
func InetPton(af c.Int, src *c.Char, dst c.Pointer) c.Int
|
||||
33
c/libuv/signal.go
Normal file
33
c/libuv/signal.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
/* Handle types. */
|
||||
|
||||
type Signal struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Function type */
|
||||
|
||||
// llgo:type C
|
||||
type SignalCb func(handle *Signal, sigNum c.Int)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Signal related functions and method. */
|
||||
|
||||
//go:linkname SignalInit C.uv_signal_init
|
||||
func SignalInit(loop *Loop, handle *Signal) c.Int
|
||||
|
||||
//go:linkname SignalStart C.uv_signal_start
|
||||
func SignalStart(handle *Signal, cb SignalCb, signum c.Int) c.Int
|
||||
|
||||
//go:linkname SignalStartOneshot C.uv_signal_start_oneshot
|
||||
func SignalStartOneshot(handle *Signal, cb SignalCb, signum c.Int) c.Int
|
||||
55
c/libuv/timer.go
Normal file
55
c/libuv/timer.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Handle types. */
|
||||
|
||||
type Timer struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
// llgo:type Cgit
|
||||
type TimerCb func(timer *Timer)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Timer related function and method */
|
||||
|
||||
//go:linkname InitTimer C.uv_timer_init
|
||||
func InitTimer(loop *Loop, timer *Timer) c.Int
|
||||
|
||||
// llgo:link (*Timer).Start C.uv_timer_start
|
||||
func (timer *Timer) Start(cb TimerCb, timeout uint64, repeat uint64) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Timer).Stop C.uv_timer_stop
|
||||
func (timer *Timer) Stop() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Timer).Again C.uv_timer_again
|
||||
func (timer *Timer) Again() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Timer).SetRepeat C.uv_timer_set_repeat
|
||||
func (timer *Timer) SetRepeat(repeat uint64) {}
|
||||
|
||||
// llgo:link (*Timer).GetRepeat C.uv_timer_get_repeat
|
||||
func (timer *Timer) GetRepeat() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Timer).GetDueIn C.uv_timer_get_due_in
|
||||
func (timer *Timer) GetDueIn() uint64 {
|
||||
return 0
|
||||
}
|
||||
Binary file not shown.
60
c/lua/_demo/coroutine/coroutine.go
Normal file
60
c/lua/_demo/coroutine/coroutine.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func coroutineFunc(L *lua.State) {
|
||||
L.Loadstring(c.Str(`
|
||||
function coro_func()
|
||||
for i = 1, 5 do
|
||||
coroutine.yield(i)
|
||||
end
|
||||
end
|
||||
`))
|
||||
L.Pcall(0, 0, 0)
|
||||
L.Getglobal(c.Str("coro_func"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
coroutineFunc(L) // Load and get the coroutine function
|
||||
|
||||
co := L.Newthread() // Create a new coroutine/thread
|
||||
L.Pushvalue(-2) // Move the function to the top of the stack
|
||||
L.Xmove(co, 1) // Move the function to the new coroutine
|
||||
|
||||
var nres c.Int
|
||||
var status c.Int
|
||||
|
||||
c.Printf(c.Str("Resuming coroutine...\n"))
|
||||
// Resume coroutine and handle yields
|
||||
for {
|
||||
status = co.Resume(nil, 0, &nres)
|
||||
c.Printf(c.Str("Resuming coroutine %d...\n"), status)
|
||||
if status == lua.YIELD {
|
||||
yieldValue := co.Tointeger(-1)
|
||||
c.Printf(c.Str("Yield value: %d\n"), yieldValue)
|
||||
co.Pop(1) // Clean up the stack
|
||||
|
||||
// Check if the coroutine is yieldable
|
||||
if co.Isyieldable() != 0 {
|
||||
c.Printf(c.Str("Coroutine is yieldable.\n"))
|
||||
} else {
|
||||
c.Printf(c.Str("Coroutine is not yieldable.\n"))
|
||||
}
|
||||
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Check the final status of the coroutine
|
||||
finalStatus := co.Status()
|
||||
c.Printf(c.Str("Final status of coroutine: %d\n"), finalStatus)
|
||||
}
|
||||
21
c/lua/_demo/error/error.go
Normal file
21
c/lua/_demo/error/error.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Loadstring(c.Str("function doubleNumber(x) ! return x * 2 end")); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
error: [string "function doubleNumber(x) ! return x * 2 end"]:1: unexpected symbol near '!'
|
||||
*/
|
||||
32
c/lua/_demo/funccall-concat/funccall.go
Normal file
32
c/lua/_demo/funccall-concat/funccall.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
if res := L.Dostring(c.Str("function combineParams(num, str) return 'Result: ' .. str .. ' ' .. num end")); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
L.Getglobal(c.Str("combineParams"))
|
||||
L.Pushnumber(3.14159)
|
||||
L.Pushstring(c.Str("Hello, World!"))
|
||||
if res := L.Pcall(2, 1, 0); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
if res := L.Isstring(-1); res != 0 {
|
||||
result := L.Tostring(-1)
|
||||
c.Printf(result)
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Result: Hello, World! 3.14159
|
||||
*/
|
||||
39
c/lua/_demo/funccall-number/funccall.go
Normal file
39
c/lua/_demo/funccall-number/funccall.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
if res := L.Loadstring(c.Str("function doubleNumber(x) return x * 2 end")); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
if res := L.Pcall(0, 0, 0); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
|
||||
L.Getglobal(c.Str("doubleNumber"))
|
||||
L.Pushnumber(10)
|
||||
|
||||
if res := L.Pcall(1, 1, 0); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
|
||||
if res := L.Isnumber(-1); res != 0 {
|
||||
result := L.Tointeger(-1)
|
||||
c.Printf(c.Str("result: %lld\n"), result)
|
||||
} else {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
result: 20
|
||||
*/
|
||||
48
c/lua/_demo/funccall-string/funccall.go
Normal file
48
c/lua/_demo/funccall-string/funccall.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
code := c.Str(
|
||||
`function processStrings(a, b, c)
|
||||
print('Received string a: ' .. a)
|
||||
print('Received string b: ', b)
|
||||
print('Received string c (formatted): ' .. c)
|
||||
return a .. b .. c
|
||||
end`)
|
||||
|
||||
if res := L.Dostring(code); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
|
||||
L.Getglobal(c.Str("processStrings"))
|
||||
|
||||
L.Pushstring(c.Str("Hello, World!"))
|
||||
L.Pushlstring(c.Str(`Hello Lua In LLGO`), 17)
|
||||
L.Pushfstring(c.Str(`Hello %s In %d`), c.Str("LLGO"), 2024)
|
||||
|
||||
if res := L.Pcall(3, 1, 0); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
|
||||
if res := L.Isstring(-1); res != 0 {
|
||||
result := L.Tostring(-1)
|
||||
c.Printf(c.Str("result: %s\n"), result)
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Received string a: Hello, World!
|
||||
Received string b: Hello Lua In LLGO
|
||||
Received string c (formatted): Hello LLGO In 2024
|
||||
result: Hello, World!Hello Lua In LLGOHello LLGO In 2024
|
||||
*/
|
||||
21
c/lua/_demo/hello/hello.go
Normal file
21
c/lua/_demo/hello/hello.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Dostring(c.Str("print('hello world')")); res != lua.OK {
|
||||
println("error")
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
hello world
|
||||
*/
|
||||
26
c/lua/_demo/loadcall/loadcall.go
Normal file
26
c/lua/_demo/loadcall/loadcall.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
if res := L.Loadstring(c.Str("print('hello world')")); res != lua.OK {
|
||||
println("error")
|
||||
}
|
||||
if res := L.Pcall(0, 0, 0); res != lua.OK {
|
||||
println("error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
hello world
|
||||
*/
|
||||
104
c/lua/_demo/stack/stack.go
Normal file
104
c/lua/_demo/stack/stack.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
// printStack prints the current stack of the given Lua state.
|
||||
func printStack(L *lua.State, stateName *c.Char) {
|
||||
top := L.Gettop()
|
||||
c.Printf(c.Str("%s stack (top=%d):"), stateName, top)
|
||||
for i := 1; i <= int(top); i++ {
|
||||
c.Printf(c.Str("%s "), L.Tostring(c.Int(i)))
|
||||
}
|
||||
c.Printf(c.Str("\n"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create a new Lua state and open libraries
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
// Push initial values onto the stack
|
||||
L.Pushstring(c.Str("Hello"))
|
||||
L.Pushstring(c.Str("LLGO"))
|
||||
L.Pushnumber(2024)
|
||||
|
||||
// Print initial stack
|
||||
c.Printf(c.Str("Initial stack:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Use absindex to ensure the index is positive
|
||||
idx := -2
|
||||
absIdx := L.Absindex(c.Int(idx))
|
||||
c.Printf(c.Str("Absolute index of 'LLGO': %d\n"), absIdx)
|
||||
|
||||
// Copy 'LLGO' to the top of the stack
|
||||
L.Pushvalue(absIdx)
|
||||
c.Printf(c.Str("\nAfter pushing 'LLGO' to the top:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Rotate stack elements
|
||||
L.Rotate(c.Int(1), c.Int(-1))
|
||||
c.Printf(c.Str("\nAfter rotating the stack:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Copy the top element to index 2
|
||||
L.Copy(c.Int(-1), c.Int(2))
|
||||
c.Printf(c.Str("\nAfter copying the top element to index 2:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Check if we can grow the stack
|
||||
if L.Checkstack(c.Int(2)) == 0 {
|
||||
c.Printf(c.Str("Cannot grow stack\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Push additional elements
|
||||
L.Pushnumber(3.14)
|
||||
L.Pushstring(c.Str("Lua"))
|
||||
c.Printf(c.Str("\nAfter pushing more elements:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Set the top of the stack, clearing extra elements
|
||||
L.Settop(c.Int(5))
|
||||
c.Printf(c.Str("\nAfter setting top to 5:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Create a second Lua state
|
||||
L1 := lua.Newstate()
|
||||
defer L1.Close()
|
||||
|
||||
// Move two elements to the new state
|
||||
L.Xmove(L1, c.Int(2))
|
||||
c.Printf(c.Str("\nAfter moving two elements to L1:\n"))
|
||||
printStack(L, c.Str("L1"))
|
||||
printStack(L1, c.Str("L2"))
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Initial stack:
|
||||
L1 stack (top=3):Hello LLGO 2024.0
|
||||
Absolute index of 'LLGO': 2
|
||||
|
||||
After pushing 'LLGO' to the top:
|
||||
L1 stack (top=4):Hello LLGO 2024.0 LLGO
|
||||
|
||||
After rotating the stack:
|
||||
L1 stack (top=4):LLGO 2024.0 LLGO Hello
|
||||
|
||||
After copying the top element to index 2:
|
||||
L1 stack (top=4):LLGO Hello LLGO Hello
|
||||
|
||||
After pushing more elements:
|
||||
L1 stack (top=6):LLGO Hello LLGO Hello 3.14 Lua
|
||||
|
||||
After setting top to 5:
|
||||
L1 stack (top=5):LLGO Hello LLGO Hello 3.14
|
||||
|
||||
After moving two elements to L1:
|
||||
L1 stack (top=3):LLGO Hello LLGO
|
||||
L2 stack (top=2):Hello 3.14
|
||||
*/
|
||||
60
c/lua/_demo/table/table.go
Normal file
60
c/lua/_demo/table/table.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func printTable(L *lua.State) {
|
||||
L.Pushnil()
|
||||
for L.Next(-2) != 0 {
|
||||
key := L.Tostring(-2)
|
||||
value := L.Tostring(-1)
|
||||
c.Printf(c.Str("%s - %s\n"), key, value)
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
L.Newtable()
|
||||
|
||||
L.Pushstring(c.Str("name"))
|
||||
L.Pushstring(c.Str("John"))
|
||||
L.Settable(-3)
|
||||
|
||||
L.Pushstring(c.Str("age"))
|
||||
L.Pushnumber(30)
|
||||
L.Settable(-3)
|
||||
|
||||
L.Pushstring(c.Str("John Doe"))
|
||||
L.Setfield(-2, c.Str("fullname"))
|
||||
|
||||
L.Getfield(-1, c.Str("name"))
|
||||
c.Printf(c.Str("%s\n"), L.Tostring(-1))
|
||||
L.Pop(1)
|
||||
|
||||
L.Pushstring(c.Str("age"))
|
||||
L.Gettable(-2)
|
||||
age := int(L.Tonumber(-1))
|
||||
c.Printf(c.Str("Age: %d\n"), age)
|
||||
L.Pop(1)
|
||||
|
||||
c.Printf(c.Str("All entries in the table:\n"))
|
||||
printTable(L)
|
||||
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
John
|
||||
Age: 30
|
||||
All entries in the table:
|
||||
age - 30.0
|
||||
fullname - John Doe
|
||||
name - John
|
||||
*/
|
||||
101
c/lua/lauxlib.go
Normal file
101
c/lua/lauxlib.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package lua
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
// /* global table */
|
||||
|
||||
// /* extra error code for 'luaL_loadfilex' */
|
||||
|
||||
// /* key, in the registry, for table of loaded modules */
|
||||
|
||||
// /* key, in the registry, for table of preloaded loaders */
|
||||
|
||||
// /* predefined references */
|
||||
|
||||
// llgo:link (*State).Loadfilex C.luaL_loadfilex
|
||||
func (L *State) Loadfilex(filename *c.Char, mode *c.Char) c.Int { return 0 }
|
||||
|
||||
func (L *State) Loadfile(filename *c.Char) c.Int { return L.Loadfilex(filename, nil) }
|
||||
|
||||
// llgo:link (*State).Loadstring C.luaL_loadstring
|
||||
func (L *State) Loadstring(s *c.Char) c.Int { return 0 }
|
||||
|
||||
//go:linkname Newstate C.luaL_newstate
|
||||
func Newstate() *State
|
||||
|
||||
// /*
|
||||
// ** ===============================================================
|
||||
// ** some useful macros
|
||||
// ** ===============================================================
|
||||
// */
|
||||
|
||||
func (L *State) Dofile(filename *c.Char) c.Int {
|
||||
if loadResult := L.Loadfile(filename); loadResult != 0 {
|
||||
return loadResult
|
||||
}
|
||||
return L.Pcall(c.Int(0), c.Int(MULTRET), c.Int(0))
|
||||
}
|
||||
|
||||
func (L *State) Dostring(str *c.Char) c.Int {
|
||||
if loadResult := L.Loadstring(str); loadResult != 0 {
|
||||
return loadResult
|
||||
}
|
||||
return L.Pcall(c.Int(0), c.Int(MULTRET), c.Int(0))
|
||||
}
|
||||
|
||||
// /*
|
||||
// ** Perform arithmetic operations on lua_Integer values with wrap-around
|
||||
// ** semantics, as the Lua core does.
|
||||
// */
|
||||
|
||||
// /* push the value used to represent failure/error */
|
||||
|
||||
// /*
|
||||
// ** {======================================================
|
||||
// ** Generic Buffer manipulation
|
||||
// ** =======================================================
|
||||
// */
|
||||
|
||||
// /* }====================================================== */
|
||||
|
||||
// /*
|
||||
// ** {======================================================
|
||||
// ** File handles for IO library
|
||||
// ** =======================================================
|
||||
// */
|
||||
|
||||
// /*
|
||||
// ** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
|
||||
// ** initial structure 'luaL_Stream' (it may contain other fields
|
||||
// ** after that initial structure).
|
||||
// */
|
||||
|
||||
// #define LUA_FILEHANDLE "FILE*"
|
||||
|
||||
// /* }====================================================== */
|
||||
|
||||
// /*
|
||||
// ** {==================================================================
|
||||
// ** "Abstraction Layer" for basic report of messages and errors
|
||||
// ** ===================================================================
|
||||
// */
|
||||
|
||||
// /* print a string */
|
||||
|
||||
// /* print a newline and flush the output */
|
||||
|
||||
// /* print an error message */
|
||||
|
||||
// /* }================================================================== */
|
||||
|
||||
// /*
|
||||
// ** {============================================================
|
||||
// ** Compatibility with deprecated conversions
|
||||
// ** =============================================================
|
||||
// */
|
||||
|
||||
// /* }============================================================ */
|
||||
495
c/lua/lua.go
Normal file
495
c/lua/lua.go
Normal file
@@ -0,0 +1,495 @@
|
||||
package lua
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs lua); -llua -lm"
|
||||
)
|
||||
|
||||
// /* mark for precompiled code ('<esc>Lua') */
|
||||
|
||||
// /* option for multiple returns in 'lua_pcall' and 'lua_call' */
|
||||
const (
|
||||
MULTRET = -1
|
||||
)
|
||||
|
||||
// /*
|
||||
// ** Pseudo-indices
|
||||
// ** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
||||
// ** space after that to help overflow detection)
|
||||
// */
|
||||
|
||||
// /* thread status */
|
||||
const (
|
||||
OK = 0
|
||||
YIELD = 1
|
||||
ERRRUN = 2
|
||||
ERRSYNTAX = 3
|
||||
ERRMEM = 4
|
||||
ERRERR = 5
|
||||
)
|
||||
|
||||
type State struct {
|
||||
Unused [8]byte
|
||||
}
|
||||
|
||||
// /*
|
||||
// ** basic types
|
||||
// */
|
||||
const (
|
||||
NONE = int(-1)
|
||||
NIL = int(0)
|
||||
BOOLEAN = int(1)
|
||||
LIGHTUSERDATA = int(2)
|
||||
NUMBER = int(3)
|
||||
STRING = int(4)
|
||||
TABLE = int(5)
|
||||
FUNCTION = int(6)
|
||||
USERDATA = int(7)
|
||||
THREAD = int(8)
|
||||
UMTYPES = int(9)
|
||||
)
|
||||
|
||||
// /* minimum Lua stack available to a C function */
|
||||
const (
|
||||
MINSTACK = 20
|
||||
)
|
||||
|
||||
// /* predefined values in the registry */
|
||||
const (
|
||||
RIDX_MAINTHREAD = 1
|
||||
RIDX_GLOBALS = 2
|
||||
RIDX_LAST = RIDX_GLOBALS
|
||||
)
|
||||
|
||||
// /* type of numbers in Lua */
|
||||
type Number = c.Double
|
||||
|
||||
// /* type for integer functions */
|
||||
// TODO(zzy):consider dynamic size
|
||||
|
||||
type Integer = c.Int
|
||||
|
||||
// /* unsigned integer type */
|
||||
type Unsigned = c.Uint
|
||||
|
||||
// /* type for continuation-function contexts */
|
||||
// TODO(zzy): Context may not be c.Int
|
||||
type KContext c.Int
|
||||
|
||||
// /*
|
||||
// ** Type for C functions registered with Lua
|
||||
// */
|
||||
|
||||
// /*
|
||||
// ** Type for continuation functions
|
||||
// */
|
||||
|
||||
// TODO(zzy): KFunction does not currently support
|
||||
type KFunction func(L *State, status c.Int, ctx KContext) c.Int
|
||||
|
||||
// /*
|
||||
// ** Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
// */
|
||||
|
||||
// typedef const char * (*lua_Reader) (State *L, void *ud, size_t *sz);
|
||||
// typedef int (*lua_Writer) (State *L, const void *p, size_t sz, void *ud);
|
||||
|
||||
// /*
|
||||
// ** Type for memory-allocation functions
|
||||
// */
|
||||
|
||||
// typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
|
||||
// /*
|
||||
// ** Type for warning functions
|
||||
// */
|
||||
|
||||
// typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
||||
|
||||
// /*
|
||||
// ** Type used by the debug API to collect debug information
|
||||
// */
|
||||
|
||||
// typedef struct lua_Debug lua_Debug;
|
||||
|
||||
// /*
|
||||
// ** Functions to be called by the debugger in specific events
|
||||
// */
|
||||
|
||||
// typedef void (*lua_Hook) (State *L, lua_Debug *ar);
|
||||
|
||||
// /*
|
||||
// ** generic extra include file
|
||||
// */
|
||||
|
||||
// #if defined(LUA_USER_H)
|
||||
// #include LUA_USER_H
|
||||
// #endif
|
||||
|
||||
// /*
|
||||
// ** RCS ident string
|
||||
// */
|
||||
|
||||
// extern const char lua_ident[];
|
||||
|
||||
// /*
|
||||
// ** state manipulation
|
||||
// */
|
||||
// llgo:link (*State).Close C.lua_close
|
||||
func (L *State) Close() {}
|
||||
|
||||
// State *(lua_newstate) (lua_Alloc f, void *ud);
|
||||
// State *(lua_newthread) (State *L);
|
||||
|
||||
// llgo:link (*State).Newthread C.lua_newthread
|
||||
func (L *State) Newthread() *State { return nil }
|
||||
|
||||
// int (lua_closethread) (State *L, State *from);
|
||||
// int (lua_resetthread) (State *L); /* Deprecated! */
|
||||
// lua_CFunction (lua_atpanic) (State *L, lua_CFunction panicf);
|
||||
// lua_Number (lua_version) (State *L);
|
||||
|
||||
// /*
|
||||
// ** basic stack manipulation
|
||||
// */
|
||||
|
||||
// llgo:link (*State).Absindex C.lua_absindex
|
||||
func (L *State) Absindex(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Gettop C.lua_gettop
|
||||
func (L *State) Gettop() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Settop C.lua_settop
|
||||
func (L *State) Settop(idx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Pushvalue C.lua_pushvalue
|
||||
func (L *State) Pushvalue(idx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Rotate C.lua_rotate
|
||||
func (L *State) Rotate(idx c.Int, n c.Int) {}
|
||||
|
||||
// llgo:link (*State).Copy C.lua_copy
|
||||
func (L *State) Copy(fromidx c.Int, toidx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Checkstack C.lua_checkstack
|
||||
func (L *State) Checkstack(n c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Xmove C.lua_xmove
|
||||
func (L *State) Xmove(to *State, n c.Int) {}
|
||||
|
||||
// /*
|
||||
// ** access functions (stack -> C)
|
||||
// */
|
||||
// LUA_API int (lua_isinteger) (State *L, int idx);
|
||||
// llgo:link (*State).Isinteger C.lua_isinteger
|
||||
func (L *State) Isinteger(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Isnumber C.lua_isnumber
|
||||
func (L *State) Isnumber(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Isstring C.lua_isstring
|
||||
func (L *State) Isstring(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// TODO(zzy):add to demo
|
||||
// llgo:link (*State).Type C.lua_type
|
||||
func (L *State) Type(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// TODO(zzy)
|
||||
// llgo:link (*State).Typename C.lua_typename
|
||||
func (L *State) Typename(tp c.Int) *c.Char { return nil }
|
||||
|
||||
// llgo:link (*State).Tonumberx C.lua_tonumberx
|
||||
func (L *State) Tonumberx(idx c.Int, isnum *c.Int) Number { return 0 }
|
||||
|
||||
// llgo:link (*State).Tointegerx C.lua_tointegerx
|
||||
func (L *State) Tointegerx(idx c.Int, isnum *c.Int) Integer { return 0 }
|
||||
|
||||
// llgo:link (*State).Toboolean C.lua_toboolean
|
||||
func (L *State) Toboolean(idx c.Int) bool { return false }
|
||||
|
||||
// llgo:link (*State).Tolstring C.lua_tolstring
|
||||
func (L *State) Tolstring(idx c.Int, len *c.Ulong) *c.Char { return nil }
|
||||
|
||||
// LUA_API int (lua_iscfunction) (State *L, int idx);
|
||||
// LUA_API int (lua_isuserdata) (State *L, int idx);
|
||||
|
||||
// LUA_API lua_Unsigned (lua_rawlen) (State *L, int idx);
|
||||
// LUA_API lua_CFunction (lua_tocfunction) (State *L, int idx);
|
||||
// LUA_API void *(lua_touserdata) (State *L, int idx);
|
||||
// LUA_API State *(lua_tothread) (State *L, int idx);
|
||||
// LUA_API const void *(lua_topointer) (State *L, int idx);
|
||||
|
||||
// /*
|
||||
// ** Comparison and arithmetic functions
|
||||
// */
|
||||
|
||||
// /*
|
||||
// ** push functions (C -> stack)
|
||||
// */
|
||||
// llgo:link (*State).Pushnil C.lua_pushnil
|
||||
func (L *State) Pushnil() {}
|
||||
|
||||
// llgo:link (*State).Pushnumber C.lua_pushnumber
|
||||
func (L *State) Pushnumber(n Number) {}
|
||||
|
||||
// llgo:link (*State).Pushinteger C.lua_pushinteger
|
||||
func (L *State) Pushinteger(n Integer) {}
|
||||
|
||||
// llgo:link (*State).Pushstring C.lua_pushstring
|
||||
func (L *State) Pushstring(s *c.Char) *c.Char {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*State).Pushlstring C.lua_pushlstring
|
||||
func (L *State) Pushlstring(s *c.Char, len c.Ulong) *c.Char {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*State).Pushfstring C.lua_pushfstring
|
||||
func (L *State) Pushfstring(format *c.Char, __llgo_va_list ...any) *c.Char { return nil }
|
||||
|
||||
// llgo:link (*State).Pushboolean C.lua_pushboolean
|
||||
func (L *State) Pushboolean(b c.Int) {}
|
||||
|
||||
//const char *(lua_pushvfstring) (State *L, const char *fmt,va_list argp);
|
||||
//void (lua_pushcclosure) (State *L, lua_CFunction fn, int n);
|
||||
//void (lua_pushlightuserdata) (State *L, void *p);
|
||||
//int (lua_pushthread) (State *L);
|
||||
|
||||
// /*
|
||||
// ** get functions (Lua -> stack)
|
||||
// */
|
||||
|
||||
// llgo:link (*State).Getglobal C.lua_getglobal
|
||||
func (L *State) Getglobal(name *c.Char) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Gettable C.lua_gettable
|
||||
func (L *State) Gettable(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Getfield C.lua_getfield
|
||||
func (L *State) Getfield(idx c.Int, k *c.Char) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Createtable C.lua_createtable
|
||||
func (L *State) Createtable(narr c.Int, nrec c.Int) {}
|
||||
|
||||
// LUA_API int (lua_geti) (State *L, int idx, lua_Integer n);
|
||||
// LUA_API int (lua_rawget) (State *L, int idx);
|
||||
// LUA_API int (lua_rawgeti) (State *L, int idx, lua_Integer n);
|
||||
// LUA_API int (lua_rawgetp) (State *L, int idx, const void *p);
|
||||
|
||||
// LUA_API void *(lua_newuserdatauv) (State *L, size_t sz, int nuvalue);
|
||||
// LUA_API int (lua_getmetatable) (State *L, int objindex);
|
||||
// LUA_API int (lua_getiuservalue) (State *L, int idx, int n);
|
||||
|
||||
// /*
|
||||
// ** set functions (stack -> Lua)
|
||||
// */
|
||||
|
||||
// TODO(zzy):add to demo
|
||||
// llgo:link (*State).Setglobal C.lua_setglobal
|
||||
func (L *State) Setglobal(name *c.Char) {}
|
||||
|
||||
// llgo:link (*State).Settable C.lua_settable
|
||||
func (L *State) Settable(idx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Setfield C.lua_setfield
|
||||
func (L *State) Setfield(idx c.Int, k *c.Char) {}
|
||||
|
||||
//void (lua_seti) (State *L, int idx, lua_Integer n);
|
||||
//void (lua_rawset) (State *L, int idx);
|
||||
//void (lua_rawseti) (State *L, int idx, lua_Integer n);
|
||||
//void (lua_rawsetp) (State *L, int idx, const void *p);
|
||||
//int (lua_setmetatable) (State *L, int objindex);
|
||||
//int (lua_setiuservalue) (State *L, int idx, int n);
|
||||
|
||||
// /*
|
||||
// ** 'load' and 'call' functions (load and run Lua code)
|
||||
// */
|
||||
|
||||
// llgo:link (*State).Pcallk C.lua_pcallk
|
||||
func (L *State) Pcallk(nargs c.Int, nresults c.Int, errfunc c.Int, ctx KContext, k *KFunction) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (L *State) Pcall(nargs c.Int, nresults c.Int, errfunc c.Int) c.Int {
|
||||
return L.Pcallk(nargs, nresults, errfunc, KContext(c.Int(0)), nil)
|
||||
}
|
||||
|
||||
// void (lua_callk) (State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k);
|
||||
// #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
|
||||
|
||||
// int (lua_load) (State *L, lua_Reader reader, void *dt, const char *chunkname, const char *mode);
|
||||
|
||||
// int (lua_dump) (State *L, lua_Writer writer, void *data, int strip);
|
||||
|
||||
// /*
|
||||
// ** coroutine functions
|
||||
// */
|
||||
|
||||
// llgo:link (*State).Resume C.lua_resume
|
||||
func (L *State) Resume(from *State, narg c.Int, nres *c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Status C.lua_status
|
||||
func (L *State) Status() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Isyieldable C.lua_isyieldable
|
||||
func (L *State) Isyieldable() c.Int { return 0 }
|
||||
|
||||
// TODO(zzy)
|
||||
// int (lua_yieldk) (State *L, int nresults, lua_KContext ctx, lua_KFunction k);
|
||||
// #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
|
||||
|
||||
// /*
|
||||
// ** Warning-related functions
|
||||
// */
|
||||
|
||||
//void (lua_setwarnf) (State *L, lua_WarnFunction f, void *ud);
|
||||
//void (lua_warning) (State *L, const char *msg, int tocont);
|
||||
|
||||
// /*
|
||||
// ** garbage-collection function and options
|
||||
// */
|
||||
|
||||
const (
|
||||
GCSTOP = 0
|
||||
GCRESTART = 1
|
||||
GCCOLLECT = 2
|
||||
GCCOUNT = 3
|
||||
GCCOUNTB = 4
|
||||
GCSTEP = 5
|
||||
GCSETPAUSE = 6
|
||||
GCSETSTEPMUL = 7
|
||||
GCISRUNNING = 9
|
||||
GCGEN = 10
|
||||
GCINC = 11
|
||||
)
|
||||
|
||||
// LUA_API int (lua_gc) (State *L, int what, ...);
|
||||
|
||||
// /*
|
||||
// ** miscellaneous functions
|
||||
// */
|
||||
// llgo:link (*State).Next C.lua_next
|
||||
func (L *State) Next(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// LUA_API int (lua_error) (State *L);
|
||||
|
||||
// LUA_API void (lua_concat) (State *L, int n);
|
||||
// LUA_API void (lua_len) (State *L, int idx);
|
||||
|
||||
// LUA_API size_t (lua_stringtonumber) (State *L, const char *s);
|
||||
|
||||
// LUA_API lua_Alloc (lua_getallocf) (State *L, void **ud);
|
||||
// LUA_API void (lua_setallocf) (State *L, lua_Alloc f, void *ud);
|
||||
|
||||
// LUA_API void (lua_toclose) (State *L, int idx);
|
||||
// LUA_API void (lua_closeslot) (State *L, int idx);
|
||||
|
||||
// /*
|
||||
// ** {==============================================================
|
||||
// ** some useful macros
|
||||
// ** ===============================================================
|
||||
// */
|
||||
|
||||
func (L *State) Tonumber(idx c.Int) Number { return L.Tonumberx(idx, nil) }
|
||||
func (L *State) Tostring(idx c.Int) *c.Char { return L.Tolstring(idx, nil) }
|
||||
func (L *State) Tointeger(idx c.Int) Integer { return L.Tointegerx(idx, nil) }
|
||||
func (L *State) Pop(n c.Int) { L.Settop(-(n) - 1) }
|
||||
func (L *State) Newtable() { L.Createtable(0, 0) }
|
||||
func (L *State) Isfunction(n c.Int) bool { return L.Type(n) == c.Int(FUNCTION) }
|
||||
func (L *State) Istable(n c.Int) bool { return L.Type(n) == c.Int(TABLE) }
|
||||
func (L *State) Islightuserdata(n c.Int) bool { return L.Type(n) == c.Int(LIGHTUSERDATA) }
|
||||
func (L *State) Isnil(n c.Int) bool { return L.Type(n) == c.Int(NIL) }
|
||||
func (L *State) Isboolean(n c.Int) bool { return L.Type(n) == c.Int(BOOLEAN) }
|
||||
func (L *State) Isthread(n c.Int) bool { return L.Type(n) == c.Int(THREAD) }
|
||||
func (L *State) Isnone(n c.Int) bool { return L.Type(n) == c.Int(NONE) }
|
||||
func (L *State) Isnoneornil(n c.Int) bool { return L.Type(n) <= 0 }
|
||||
|
||||
// #define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
|
||||
|
||||
// #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
||||
|
||||
// #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
|
||||
|
||||
// #define lua_pushliteral(L, s) lua_pushstring(L, "" s)
|
||||
|
||||
// #define lua_pushglobaltable(L) ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
|
||||
|
||||
// #define lua_insert(L,idx) lua_rotate(L, (idx), 1)
|
||||
|
||||
// #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
|
||||
|
||||
// #define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
|
||||
|
||||
// /* }============================================================== */
|
||||
|
||||
// /*
|
||||
// ** {==============================================================
|
||||
// ** compatibility macros
|
||||
// ** ===============================================================
|
||||
// */
|
||||
|
||||
// #define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
||||
// #define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
||||
// #define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
||||
|
||||
// #define LUA_NUMTAGS LUA_NUMTYPES
|
||||
|
||||
// /* }============================================================== */
|
||||
|
||||
// /*
|
||||
// ** {======================================================================
|
||||
// ** Debug API
|
||||
// ** =======================================================================
|
||||
// */
|
||||
// /*
|
||||
// ** Event codes
|
||||
// */
|
||||
|
||||
const (
|
||||
HOOKCALL = 0
|
||||
HOOKRET = 1
|
||||
HOOKLINE = 2
|
||||
HOOKCOUNT = 3
|
||||
HOOKTAILCALL = 4
|
||||
)
|
||||
|
||||
// /*
|
||||
// ** Event masks
|
||||
// */
|
||||
// #define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||
// #define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||
// #define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||
// #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||
|
||||
const (
|
||||
MASKCALL = 1 << HOOKCOUNT
|
||||
MASKRET = 1 << HOOKRET
|
||||
MASKLINE = 1 << HOOKLINE
|
||||
MASKCOUNT = 1 << HOOKCOUNT
|
||||
)
|
||||
|
||||
// LUA_API int (lua_getstack) (State *L, int level, lua_Debug *ar);
|
||||
// LUA_API int (lua_getinfo) (State *L, const char *what, lua_Debug *ar);
|
||||
// LUA_API const char *(lua_getlocal) (State *L, const lua_Debug *ar, int n);
|
||||
// LUA_API const char *(lua_setlocal) (State *L, const lua_Debug *ar, int n);
|
||||
// LUA_API const char *(lua_getupvalue) (State *L, int funcindex, int n);
|
||||
// LUA_API const char *(lua_setupvalue) (State *L, int funcindex, int n);
|
||||
|
||||
// LUA_API void *(lua_upvalueid) (State *L, int fidx, int n);
|
||||
// LUA_API void (lua_upvaluejoin) (State *L, int fidx1, int n1, int fidx2, int n2);
|
||||
|
||||
// LUA_API void (lua_sethook) (State *L, lua_Hook func, int mask, int count);
|
||||
// LUA_API lua_Hook (lua_gethook) (State *L);
|
||||
// LUA_API int (lua_gethookmask) (State *L);
|
||||
// LUA_API int (lua_gethookcount) (State *L);
|
||||
|
||||
// LUA_API int (lua_setcstacklimit) (State *L, unsigned int limit);
|
||||
|
||||
// struct lua_Debug
|
||||
// /* }====================================================================== */
|
||||
8
c/lua/lualib.go
Normal file
8
c/lua/lualib.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package lua
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
// llgo:link (*State).Openlibs C.luaL_openlibs
|
||||
func (L *State) Openlibs() {}
|
||||
8
c/neco/README.md
Normal file
8
c/neco/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
llgo wrapper of tidwall/neco
|
||||
=====
|
||||
|
||||
## How to update source to llgo
|
||||
|
||||
```sh
|
||||
TODO
|
||||
```
|
||||
34
c/neco/_demo/cgen/_c/gen.c
Normal file
34
c/neco/_demo/cgen/_c/gen.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "../../../_wrap/neco.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void coroutine(int argc, void *argv[]) {
|
||||
// Yield each int to the caller, one at a time.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
neco_gen_yield(&i);
|
||||
}
|
||||
}
|
||||
|
||||
static int __neco_main() {
|
||||
|
||||
// Create a new generator coroutine that is used to send ints.
|
||||
neco_gen *gen;
|
||||
neco_gen_start(&gen, sizeof(int), coroutine, 0);
|
||||
|
||||
// Iterate over each int until the generator is closed.
|
||||
int i;
|
||||
while (neco_gen_next(gen, &i) != NECO_CLOSED) {
|
||||
printf("%d\n", i);
|
||||
}
|
||||
|
||||
// This coroutine no longer needs the generator.
|
||||
neco_gen_release(gen);
|
||||
return 0;
|
||||
}
|
||||
static void _neco_main() { __neco_exit_prog(__neco_main()); }
|
||||
void run_main() {
|
||||
neco_env_setpaniconerror(true);
|
||||
neco_env_setcanceltype(NECO_CANCEL_ASYNC);
|
||||
int ret = neco_start(_neco_main, 0);
|
||||
fprintf(stderr, "neco_start: %s (code %d)\n", neco_strerror(ret), ret);
|
||||
};
|
||||
19
c/neco/_demo/cgen/cgen.go
Normal file
19
c/neco/_demo/cgen/cgen.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
_ "github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_c/gen.c; ../../_wrap/neco.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
func main() {
|
||||
runMain()
|
||||
}
|
||||
|
||||
//go:linkname runMain C.run_main
|
||||
func runMain()
|
||||
37
c/neco/_demo/gen/gen.go
Normal file
37
c/neco/_demo/gen/gen.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/neco"
|
||||
)
|
||||
|
||||
func coroutine(argc c.Int, argv *c.Pointer) {
|
||||
// Yield each int to the caller, one at a time.
|
||||
for i := 0; i < 10; i++ {
|
||||
neco.GenYield(unsafe.Pointer(&i))
|
||||
}
|
||||
}
|
||||
|
||||
func necoMain(argc c.Int, argv *c.Pointer) {
|
||||
// Create a new generator coroutine that is used to send ints.
|
||||
var gen *neco.Gen
|
||||
neco.GenStart(&gen, unsafe.Sizeof(0), coroutine, 0)
|
||||
|
||||
// Iterate over each int until the generator is closed.
|
||||
var i int
|
||||
for neco.GenNext(gen, unsafe.Pointer(&i)) != neco.CLOSED {
|
||||
c.Printf(c.Str("%d\n"), i)
|
||||
}
|
||||
|
||||
neco.GenRelease(gen)
|
||||
neco.ExitProg(0)
|
||||
}
|
||||
|
||||
func main() {
|
||||
neco.EnvSetpaniconerror(true)
|
||||
neco.EnvSetcanceltype(neco.CANCEL_ASYNC)
|
||||
var ret = neco.Start(necoMain, 0)
|
||||
c.Fprintf(c.Stderr, c.Str("neco_start: %s (code %d)\n"), neco.Strerror(ret), ret)
|
||||
}
|
||||
8762
c/neco/_wrap/neco.c
Normal file
8762
c/neco/_wrap/neco.c
Normal file
File diff suppressed because it is too large
Load Diff
453
c/neco/_wrap/neco.h
Normal file
453
c/neco/_wrap/neco.h
Normal file
@@ -0,0 +1,453 @@
|
||||
// https://github.com/tidwall/neco
|
||||
//
|
||||
// Copyright 2024 Joshua J Baker. All rights reserved.
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// Neco -- Coroutine library for C
|
||||
|
||||
#ifndef NECO_H
|
||||
#define NECO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// basic operations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup BasicOperations Basic operations
|
||||
/// Neco provides standard operations for starting a coroutine, sleeping,
|
||||
/// suspending, resuming, yielding to another coroutine, joining/waiting for
|
||||
/// child coroutines, and exiting a running coroutine.
|
||||
/// @{
|
||||
int neco_start(void(*coroutine)(int argc, void *argv[]), int argc, ...);
|
||||
int neco_startv(void(*coroutine)(int argc, void *argv[]), int argc, void *argv[]);
|
||||
int neco_yield(void);
|
||||
int neco_sleep(int64_t nanosecs);
|
||||
int neco_sleep_dl(int64_t deadline);
|
||||
int neco_join(int64_t id);
|
||||
int neco_join_dl(int64_t id, int64_t deadline);
|
||||
int neco_suspend(void);
|
||||
int neco_suspend_dl(int64_t deadline);
|
||||
int neco_resume(int64_t id);
|
||||
void neco_exit(void);
|
||||
int64_t neco_getid(void);
|
||||
int64_t neco_lastid(void);
|
||||
int64_t neco_starterid(void);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// channels
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Channels Channels
|
||||
/// Channels allow for sending and receiving values between coroutines.
|
||||
/// By default, sends and receives will block until the other side is ready.
|
||||
/// This allows the coroutines to synchronize without using locks or condition
|
||||
/// variables.
|
||||
/// @{
|
||||
typedef struct neco_chan neco_chan;
|
||||
|
||||
int neco_chan_make(neco_chan **chan, size_t data_size, size_t capacity);
|
||||
int neco_chan_retain(neco_chan *chan);
|
||||
int neco_chan_release(neco_chan *chan);
|
||||
int neco_chan_send(neco_chan *chan, void *data);
|
||||
int neco_chan_send_dl(neco_chan *chan, void *data, int64_t deadline);
|
||||
int neco_chan_broadcast(neco_chan *chan, void *data);
|
||||
int neco_chan_recv(neco_chan *chan, void *data);
|
||||
int neco_chan_recv_dl(neco_chan *chan, void *data, int64_t deadline);
|
||||
int neco_chan_tryrecv(neco_chan *chan, void *data);
|
||||
int neco_chan_close(neco_chan *chan);
|
||||
int neco_chan_select(int nchans, ...);
|
||||
int neco_chan_select_dl(int64_t deadline, int nchans, ...);
|
||||
int neco_chan_selectv(int nchans, neco_chan *chans[]);
|
||||
int neco_chan_selectv_dl(int nchans, neco_chan *chans[], int64_t deadline);
|
||||
int neco_chan_tryselect(int nchans, ...);
|
||||
int neco_chan_tryselectv(int nchans, neco_chan *chans[]);
|
||||
int neco_chan_case(neco_chan *chan, void *data);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// generators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Generators Generators
|
||||
/// A generator is a specialized iterator-bound coroutine that can produce a
|
||||
/// sequence of values to be iterated over.
|
||||
/// @{
|
||||
typedef struct neco_gen neco_gen;
|
||||
|
||||
int neco_gen_start(neco_gen **gen, size_t data_size, void(*coroutine)(int argc, void *argv[]), int argc, ...);
|
||||
int neco_gen_startv(neco_gen **gen, size_t data_size, void(*coroutine)(int argc, void *argv[]), int argc, void *argv[]);
|
||||
int neco_gen_retain(neco_gen *gen);
|
||||
int neco_gen_release(neco_gen *gen);
|
||||
int neco_gen_yield(void *data);
|
||||
int neco_gen_yield_dl(void *data, int64_t deadline);
|
||||
int neco_gen_next(neco_gen *gen, void *data);
|
||||
int neco_gen_next_dl(neco_gen *gen, void *data, int64_t deadline);
|
||||
int neco_gen_close(neco_gen *gen);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// synchronization mechanisms
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Mutexes Mutexes
|
||||
/// A mutex is synchronization mechanism that blocks access to variables by
|
||||
/// multiple coroutines at once. This enforces exclusive access by a coroutine
|
||||
/// to a variable or set of variables and helps to avoid data inconsistencies
|
||||
/// due to race conditions.
|
||||
/// @{
|
||||
typedef struct { _Alignas(16) char _[48]; } neco_mutex;
|
||||
|
||||
#define NECO_MUTEX_INITIALIZER { 0 }
|
||||
|
||||
int neco_mutex_init(neco_mutex *mutex);
|
||||
int neco_mutex_lock(neco_mutex *mutex);
|
||||
int neco_mutex_lock_dl(neco_mutex *mutex, int64_t deadline);
|
||||
int neco_mutex_trylock(neco_mutex *mutex);
|
||||
int neco_mutex_unlock(neco_mutex *mutex);
|
||||
int neco_mutex_rdlock(neco_mutex *mutex);
|
||||
int neco_mutex_rdlock_dl(neco_mutex *mutex, int64_t deadline);
|
||||
int neco_mutex_tryrdlock(neco_mutex *mutex);
|
||||
/// @}
|
||||
|
||||
/// @defgroup WaitGroups WaitGroups
|
||||
/// A WaitGroup waits for a multiple coroutines to finish.
|
||||
/// The main coroutine calls neco_waitgroup_add() to set the number of
|
||||
/// coroutines to wait for. Then each of the coroutines runs and calls
|
||||
/// neco_waitgroup_done() when complete.
|
||||
/// At the same time, neco_waitgroup_wait() can be used to block until all
|
||||
/// coroutines are completed.
|
||||
/// @{
|
||||
typedef struct { _Alignas(16) char _[48]; } neco_waitgroup;
|
||||
|
||||
#define NECO_WAITGROUP_INITIALIZER { 0 }
|
||||
|
||||
int neco_waitgroup_init(neco_waitgroup *waitgroup);
|
||||
int neco_waitgroup_add(neco_waitgroup *waitgroup, int delta);
|
||||
int neco_waitgroup_done(neco_waitgroup *waitgroup);
|
||||
int neco_waitgroup_wait(neco_waitgroup *waitgroup);
|
||||
int neco_waitgroup_wait_dl(neco_waitgroup *waitgroup, int64_t deadline);
|
||||
/// @}
|
||||
|
||||
/// @defgroup CondVar Condition variables
|
||||
/// A condition variable is a synchronization mechanism that allows coroutines
|
||||
/// to suspend execution until some condition is true.
|
||||
/// @{
|
||||
typedef struct { _Alignas(16) char _[48]; } neco_cond;
|
||||
#define NECO_COND_INITIALIZER { 0 }
|
||||
|
||||
int neco_cond_init(neco_cond *cond);
|
||||
int neco_cond_signal(neco_cond *cond);
|
||||
int neco_cond_broadcast(neco_cond *cond);
|
||||
int neco_cond_wait(neco_cond *cond, neco_mutex *mutex);
|
||||
int neco_cond_wait_dl(neco_cond *cond, neco_mutex *mutex, int64_t deadline);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// file descriptors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Posix Posix wrappers
|
||||
/// Functions that work like their Posix counterpart but do not block, allowing
|
||||
/// for usage in a Neco coroutine.
|
||||
/// @{
|
||||
|
||||
// wrappers for various posix operations.
|
||||
ssize_t neco_read(int fd, void *data, size_t nbytes);
|
||||
ssize_t neco_read_dl(int fd, void *data, size_t nbytes, int64_t deadline);
|
||||
ssize_t neco_write(int fd, const void *data, size_t nbytes);
|
||||
ssize_t neco_write_dl(int fd, const void *data, size_t nbytes, int64_t deadline);
|
||||
int neco_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int neco_accept_dl(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int64_t deadline);
|
||||
int neco_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int neco_connect_dl(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int64_t deadline);
|
||||
int neco_getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
int neco_getaddrinfo_dl(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res, int64_t deadline);
|
||||
/// @}
|
||||
|
||||
/// @defgroup Posix2 File descriptor helpers
|
||||
/// Functions for working with file descriptors.
|
||||
/// @{
|
||||
|
||||
// utility for enabling non-blocking on existing file descriptors
|
||||
int neco_setnonblock(int fd, bool nonblock, bool *oldnonblock);
|
||||
|
||||
// wait for a file descriptor to be readable or writeable.
|
||||
#define NECO_WAIT_READ 1
|
||||
#define NECO_WAIT_WRITE 2
|
||||
|
||||
int neco_wait(int fd, int mode);
|
||||
int neco_wait_dl(int fd, int mode, int64_t deadline);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// networking
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Networking Networking utilities
|
||||
/// @{
|
||||
|
||||
int neco_serve(const char *network, const char *address);
|
||||
int neco_serve_dl(const char *network, const char *address, int64_t deadline);
|
||||
int neco_dial(const char *network, const char *address);
|
||||
int neco_dial_dl(const char *network, const char *address, int64_t deadline);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cancelation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Cancelation Cancelation
|
||||
/// @{
|
||||
|
||||
int neco_cancel(int64_t id);
|
||||
int neco_cancel_dl(int64_t id, int64_t deadline);
|
||||
|
||||
#define NECO_CANCEL_ASYNC 1
|
||||
#define NECO_CANCEL_INLINE 2
|
||||
#define NECO_CANCEL_ENABLE 3
|
||||
#define NECO_CANCEL_DISABLE 4
|
||||
|
||||
int neco_setcanceltype(int type, int *oldtype);
|
||||
int neco_setcancelstate(int state, int *oldstate);
|
||||
|
||||
#define neco_cleanup_push(routine, arg) {__neco_c0(&(char[32]){0},routine,arg);
|
||||
#define neco_cleanup_pop(execute) __neco_c1(execute);}
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// random number generator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Random Random number generator
|
||||
/// @{
|
||||
|
||||
#define NECO_CSPRNG 0 // Cryptographically secure pseudorandom number generator
|
||||
#define NECO_PRNG 1 // Pseudorandom number generator (non-crypto, faster)
|
||||
|
||||
int neco_rand_setseed(int64_t seed, int64_t *oldseed);
|
||||
int neco_rand(void *data, size_t nbytes, int attr);
|
||||
int neco_rand_dl(void *data, size_t nbytes, int attr, int64_t deadline);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// signal handling
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Signals Signals
|
||||
/// Allows for signals, such as SIGINT (Ctrl-C), to be intercepted or ignored.
|
||||
/// @{
|
||||
|
||||
int neco_signal_watch(int signo);
|
||||
int neco_signal_wait(void);
|
||||
int neco_signal_wait_dl(int64_t deadline);
|
||||
int neco_signal_unwatch(int signo);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// background worker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Worker Background worker
|
||||
/// Run arbitrary code in a background worker thread
|
||||
/// @{
|
||||
|
||||
int neco_work(int64_t pin, void(*work)(void *udata), void *udata);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Stats and information
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Stats Stats and information
|
||||
/// @{
|
||||
|
||||
typedef struct neco_stats {
|
||||
size_t coroutines; ///< Number of active coroutines
|
||||
size_t sleepers; ///< Number of sleeping coroutines
|
||||
size_t evwaiters; ///< Number of coroutines waiting on I/O events
|
||||
size_t sigwaiters; ///<
|
||||
size_t senders; ///<
|
||||
size_t receivers; ///<
|
||||
size_t locked; ///<
|
||||
size_t waitgroupers; ///<
|
||||
size_t condwaiters; ///<
|
||||
size_t suspended; ///<
|
||||
size_t workers; ///< Number of background worker threads
|
||||
} neco_stats;
|
||||
|
||||
int neco_getstats(neco_stats *stats);
|
||||
int neco_is_main_thread(void);
|
||||
const char *neco_switch_method(void);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// global behaviors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup GlobalFuncs Global environment
|
||||
/// @{
|
||||
|
||||
void neco_env_setallocator(void *(*malloc)(size_t), void *(*realloc)(void*, size_t), void (*free)(void*));
|
||||
void neco_env_setpaniconerror(bool paniconerror);
|
||||
void neco_env_setcanceltype(int type);
|
||||
void neco_env_setcancelstate(int state);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// time and duration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Time Time
|
||||
/// Functions for working with time.
|
||||
///
|
||||
/// The following defines are available for convenience.
|
||||
///
|
||||
/// ```c
|
||||
/// #define NECO_NANOSECOND INT64_C(1)
|
||||
/// #define NECO_MICROSECOND INT64_C(1000)
|
||||
/// #define NECO_MILLISECOND INT64_C(1000000)
|
||||
/// #define NECO_SECOND INT64_C(1000000000)
|
||||
/// #define NECO_MINUTE INT64_C(60000000000)
|
||||
/// #define NECO_HOUR INT64_C(3600000000000)
|
||||
/// ```
|
||||
///
|
||||
/// @{
|
||||
|
||||
#define NECO_NANOSECOND INT64_C(1)
|
||||
#define NECO_MICROSECOND INT64_C(1000)
|
||||
#define NECO_MILLISECOND INT64_C(1000000)
|
||||
#define NECO_SECOND INT64_C(1000000000)
|
||||
#define NECO_MINUTE INT64_C(60000000000)
|
||||
#define NECO_HOUR INT64_C(3600000000000)
|
||||
|
||||
int64_t neco_now(void);
|
||||
|
||||
///@}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// errors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup ErrorFuncs Error handling
|
||||
/// Functions for working with [Neco errors](./API.md#neco-errors).
|
||||
/// @{
|
||||
|
||||
#define NECO_OK 0 ///< Successful result (no error)
|
||||
#define NECO_ERROR -1 ///< System error (check errno)
|
||||
#define NECO_INVAL -2 ///< Invalid argument
|
||||
#define NECO_PERM -3 ///< Operation not permitted
|
||||
#define NECO_NOMEM -4 ///< Cannot allocate memory
|
||||
#define NECO_EOF -5 ///< End of file or stream (neco_stream_*)
|
||||
#define NECO_NOTFOUND -6 ///< No such coroutine (neco_cancel)
|
||||
#define NECO_NOSIGWATCH -7 ///< Not watching on a signal
|
||||
#define NECO_CLOSED -8 ///< Channel is closed
|
||||
#define NECO_EMPTY -9 ///< Channel is empty (neco_chan_tryrecv)
|
||||
#define NECO_TIMEDOUT -10 ///< Deadline has elapsed (neco_*_dl)
|
||||
#define NECO_CANCELED -11 ///< Operation canceled (by neco_cancel)
|
||||
#define NECO_BUSY -12 ///< Resource busy (mutex_trylock)
|
||||
#define NECO_NEGWAITGRP -13 ///< Negative waitgroup counter
|
||||
#define NECO_GAIERROR -14 ///< Error with getaddrinfo (check neco_gai_error)
|
||||
#define NECO_UNREADFAIL -15 ///< Failed to unread byte (neco_stream_unread_byte)
|
||||
#define NECO_PARTIALWRITE -16 ///< Failed to write all data (neco_stream_flush)
|
||||
#define NECO_NOTGENERATOR -17 ///< Coroutine is not a generator (neco_gen_yield)
|
||||
#define NECO_NOTSUSPENDED -18 ///< Coroutine is not suspended (neco_resume)
|
||||
|
||||
const char *neco_strerror(ssize_t errcode);
|
||||
int neco_lasterr(void);
|
||||
int neco_gai_lasterr(void);
|
||||
int neco_panic(const char *fmt, ...);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// streama
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Streams Streams and Buffered I/O
|
||||
/// Create a Neco stream from a file descriptor using neco_stream_make() or
|
||||
/// a buffered stream using neco_stream_make_buffered().
|
||||
/// @{
|
||||
|
||||
typedef struct neco_stream neco_stream;
|
||||
|
||||
int neco_stream_make(neco_stream **stream, int fd);
|
||||
int neco_stream_make_buffered(neco_stream **stream, int fd);
|
||||
int neco_stream_close(neco_stream *stream);
|
||||
int neco_stream_close_dl(neco_stream *stream, int64_t deadline);
|
||||
ssize_t neco_stream_read(neco_stream *stream, void *data, size_t nbytes);
|
||||
ssize_t neco_stream_read_dl(neco_stream *stream, void *data, size_t nbytes, int64_t deadline);
|
||||
ssize_t neco_stream_write(neco_stream *stream, const void *data, size_t nbytes);
|
||||
ssize_t neco_stream_write_dl(neco_stream *stream, const void *data, size_t nbytes, int64_t deadline);
|
||||
ssize_t neco_stream_readfull(neco_stream *stream, void *data, size_t nbytes);
|
||||
ssize_t neco_stream_readfull_dl(neco_stream *stream, void *data, size_t nbytes, int64_t deadline);
|
||||
int neco_stream_read_byte(neco_stream *stream);
|
||||
int neco_stream_read_byte_dl(neco_stream *stream, int64_t deadline);
|
||||
int neco_stream_unread_byte(neco_stream *stream);
|
||||
int neco_stream_flush(neco_stream *stream);
|
||||
int neco_stream_flush_dl(neco_stream *stream, int64_t deadline);
|
||||
ssize_t neco_stream_buffered_read_size(neco_stream *stream);
|
||||
ssize_t neco_stream_buffered_write_size(neco_stream *stream);
|
||||
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// happy convenience macro
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// int neco_main(int argc, char *argv[]);
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define neco_main \
|
||||
__neco_main(int argc, char *argv[]); \
|
||||
static void _neco_main(int argc, void *argv[]) { \
|
||||
(void)argc; \
|
||||
__neco_exit_prog(__neco_main(*(int*)argv[0], *(char***)argv[1])); \
|
||||
} \
|
||||
int main(int argc, char *argv[]) { \
|
||||
neco_env_setpaniconerror(true); \
|
||||
neco_env_setcanceltype(NECO_CANCEL_ASYNC); \
|
||||
int ret = neco_start(_neco_main, 2, &argc, &argv); \
|
||||
fprintf(stderr, "neco_start: %s (code %d)\n", neco_strerror(ret), ret); \
|
||||
return -1; \
|
||||
}; \
|
||||
int __neco_main
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private functions, not to be call directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void __neco_c0(void*,void(*)(void*),void*);
|
||||
void __neco_c1(int);
|
||||
void __neco_exit_prog(int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAI_SYSTEM
|
||||
#define EAI_SYSTEM 11
|
||||
#endif
|
||||
|
||||
#endif // NECO_H
|
||||
81
c/neco/neco.go
Normal file
81
c/neco/neco.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package neco
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_wrap/neco.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
const (
|
||||
OK = 0 ///< Successful result (no error)
|
||||
ERROR = -1 ///< System error (check errno)
|
||||
INVAL = -2 ///< Invalid argument
|
||||
PERM = -3 ///< Operation not permitted
|
||||
NOMEM = -4 ///< Cannot allocate memory
|
||||
EOF = -5 ///< End of file or stream (neco_stream_*)
|
||||
NOTFOUND = -6 ///< No such coroutine (neco_cancel)
|
||||
NOSIGWATCH = -7 ///< Not watching on a signal
|
||||
CLOSED = -8 ///< Channel is closed
|
||||
EMPTY = -9 ///< Channel is empty (neco_chan_tryrecv)
|
||||
TIMEDOUT = -10 ///< Deadline has elapsed (neco_*_dl)
|
||||
CANCELED = -11 ///< Operation canceled (by neco_cancel)
|
||||
BUSY = -12 ///< Resource busy (mutex_trylock)
|
||||
NEGWAITGRP = -13 ///< Negative waitgroup counter
|
||||
GAIERROR = -14 ///< Error with getaddrinfo (check neco_gai_error)
|
||||
UNREADFAIL = -15 ///< Failed to unread byte (neco_stream_unread_byte)
|
||||
PARTIALWRITE = -16 ///< Failed to write all data (neco_stream_flush)
|
||||
NOTGENERATOR = -17 ///< Coroutine is not a generator (neco_gen_yield)
|
||||
NOTSUSPENDED = -18 ///< Coroutine is not suspended (neco_resume)
|
||||
|
||||
CANCEL_ASYNC = 1
|
||||
CANCEL_INLINE = 2
|
||||
CANCEL_ENABLE = 3
|
||||
CANCEL_DISABLE = 4
|
||||
|
||||
EAI_SYSTEM = 11
|
||||
|
||||
NANOSECOND = int64(1)
|
||||
MICROSECOND = int64(1000)
|
||||
MILLISECOND = int64(1000000)
|
||||
SECOND = int64(1000000000)
|
||||
MINUTE = int64(60000000000)
|
||||
HOUR = int64(3600000000000)
|
||||
)
|
||||
|
||||
// generator
|
||||
type Gen struct{}
|
||||
|
||||
// llgo:type C
|
||||
type Coro = func(argc c.Int, argv *c.Pointer)
|
||||
|
||||
//go:linkname GenYield C.neco_gen_yield
|
||||
func GenYield(data c.Pointer) c.Int
|
||||
|
||||
//go:linkname GenNext C.neco_gen_next
|
||||
func GenNext(gen *Gen, data c.Pointer) c.Int
|
||||
|
||||
//go:linkname GenStart C.neco_gen_start
|
||||
func GenStart(gen **Gen, dataSize uintptr, co Coro, argc c.Int, __llgo_va_list ...any) c.Int
|
||||
|
||||
//go:linkname GenRelease C.neco_gen_release
|
||||
func GenRelease(gen *Gen) c.Int
|
||||
|
||||
//go:linkname ExitProg C.__neco_exit_prog
|
||||
func ExitProg(code c.Int)
|
||||
|
||||
//go:linkname EnvSetpaniconerror C.neco_env_setpaniconerror
|
||||
func EnvSetpaniconerror(paniconerror bool)
|
||||
|
||||
//go:linkname EnvSetcanceltype C.neco_env_setcanceltype
|
||||
func EnvSetcanceltype(type_ c.Int)
|
||||
|
||||
//go:linkname Strerror C.neco_strerror
|
||||
func Strerror(errcode c.Int) *c.Char
|
||||
|
||||
//go:linkname Start C.neco_start
|
||||
func Start(co Coro, argc c.Int, __llgo_va_list ...any) c.Int
|
||||
203
c/net/net.go
Normal file
203
c/net/net.go
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = true
|
||||
)
|
||||
|
||||
const (
|
||||
AF_UNSPEC = 0 // unspecified
|
||||
AF_UNIX = 1 // local to host (pipes)
|
||||
AF_LOCAL = AF_UNIX // backward compatibility
|
||||
AF_INET = 2 // internetwork: UDP, TCP, etc.
|
||||
AF_IMPLINK = 3 // arpanet imp addresses
|
||||
AF_PUP = 4 // pup protocols: e.g. BSP
|
||||
AF_CHAOS = 5 // mit CHAOS protocols
|
||||
AF_NS = 6 // XEROX NS protocols
|
||||
AF_ISO = 7 // ISO protocols
|
||||
AF_OSI = AF_ISO
|
||||
AF_ECMA = 8 // European computer manufacturers
|
||||
AF_DATAKIT = 9 // datakit protocols
|
||||
AF_CCITT = 10 // CCITT protocols, X.25 etc
|
||||
AF_SNA = 11 // IBM SNA
|
||||
AF_DECnet = 12 // DECnet
|
||||
AF_DLI = 13 // DEC Direct data link interface
|
||||
AF_LAT = 14 // LAT
|
||||
AF_HYLINK = 15 // NSC Hyperchannel
|
||||
AF_APPLETALK = 16 // Apple Talk
|
||||
AF_ROUTE = 17 // Internal Routing Protocol
|
||||
AF_LINK = 18 // Link layer interface
|
||||
pseudo_AF_XTP = 19 // eXpress Transfer Protocol (no AF)
|
||||
AF_COIP = 20 // connection-oriented IP, aka ST II
|
||||
AF_CNT = 21 // Computer Network Technology
|
||||
pseudo_AF_RTIP = 22 // Help Identify RTIP packets
|
||||
AF_IPX = 23 // Novell Internet Protocol
|
||||
AF_SIP = 24 // Simple Internet Protocol
|
||||
pseudo_AF_PIP = 25 // Help Identify PIP packets
|
||||
AF_NDRV = 27 // Network Driver 'raw' access
|
||||
AF_ISDN = 28 // Integrated Services Digital Network
|
||||
AF_E164 = AF_ISDN // CCITT E.164 recommendation
|
||||
pseudo_AF_KEY = 29 // Internal key-management function
|
||||
AF_INET6 = 30 // IPv6
|
||||
AF_NATM = 31 // native ATM access
|
||||
AF_SYSTEM = 32 // Kernel event messages
|
||||
AF_NETBIOS = 33 // NetBIOS
|
||||
AF_PPP = 34 // PPP communication protocol
|
||||
pseudo_AF_HDRCMPLT = 35 // Used by BPF to not rewrite headers in interface output routine
|
||||
AF_RESERVED_36 = 36 // Reserved for internal usage
|
||||
AF_IEEE80211 = 37 // IEEE 802.11 protocol
|
||||
AF_UTUN = 38
|
||||
AF_VSOCK = 40 // VM Sockets
|
||||
AF_MAX = 41
|
||||
)
|
||||
|
||||
const (
|
||||
SOCK_STREAM = 1 // stream socket
|
||||
SOCK_DGRAM = 2 // datagram socket
|
||||
SOCK_RAW = 3 // raw-protocol interface
|
||||
SOCK_RDM = 4 // reliably-delivered message
|
||||
SOCK_SEQPACKET = 5 // sequenced packet stream
|
||||
)
|
||||
|
||||
const (
|
||||
EAI_ADDRFAMILY = iota + 1 /* address family for hostname not supported */
|
||||
EAI_AGAIN /* temporary failure in name resolution */
|
||||
EAI_BADFLAGS /* invalid value for ai_flags */
|
||||
EAI_FAIL /* non-recoverable failure in name resolution */
|
||||
EAI_FAMILY /* ai_family not supported */
|
||||
EAI_MEMORY /* memory allocation failure */
|
||||
EAI_NODATA /* no address associated with hostname */
|
||||
EAI_NONAME /* hostname nor servname provided, or not known */
|
||||
EAI_SERVICE /* servname not supported for ai_socktype */
|
||||
EAI_SOCKTYPE /* ai_socktype not supported */
|
||||
EAI_SYSTEM /* system error returned in errno */
|
||||
EAI_BADHINTS /* invalid value for hints */
|
||||
EAI_PROTOCOL /* resolved protocol is unknown */
|
||||
EAI_OVERFLOW /* argument buffer overflow */
|
||||
)
|
||||
|
||||
// (TODO) merge to inet
|
||||
const INET_ADDRSTRLEN = 16
|
||||
|
||||
type SockaddrIn struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Port uint16
|
||||
Addr InAddr
|
||||
Zero [8]c.Char
|
||||
}
|
||||
|
||||
type SockaddrIn6 struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Port uint16
|
||||
Flowinfo c.Uint
|
||||
Addr In6Addr
|
||||
ScopeId c.Uint
|
||||
}
|
||||
|
||||
type InAddr struct {
|
||||
Addr c.Uint
|
||||
}
|
||||
|
||||
type In6Addr struct {
|
||||
U6Addr [16]uint8
|
||||
}
|
||||
|
||||
type SockAddr struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Data [14]c.Char
|
||||
}
|
||||
|
||||
type Hostent struct {
|
||||
Name *c.Char // official name of host
|
||||
Aliases **c.Char // null-terminated array of alternate names for the host
|
||||
AddrType c.Int // host address type
|
||||
Length c.Int // length of address
|
||||
AddrList **c.Char // null-terminated array of addresses for the host
|
||||
}
|
||||
|
||||
//go:linkname Socket C.socket
|
||||
func Socket(domain c.Int, typ c.Int, protocol c.Int) c.Int
|
||||
|
||||
//go:linkname Bind C.bind
|
||||
func Bind(sockfd c.Int, addr *SockaddrIn, addrlen c.Uint) c.Int
|
||||
|
||||
//go:linkname Connect C.connect
|
||||
func Connect(sockfd c.Int, addr *SockAddr, addrlen c.Uint) c.Int
|
||||
|
||||
//go:linkname Listen C.listen
|
||||
func Listen(sockfd c.Int, backlog c.Int) c.Int
|
||||
|
||||
//go:linkname Accept C.accept
|
||||
func Accept(sockfd c.Int, addr *SockaddrIn, addrlen *c.Uint) c.Int
|
||||
|
||||
//go:linkname GetHostByName C.gethostbyname
|
||||
func GetHostByName(name *c.Char) *Hostent
|
||||
|
||||
// (TODO) merge to inet
|
||||
//
|
||||
//go:linkname InetNtop C.inet_ntop
|
||||
func InetNtop(af c.Int, src c.Pointer, dst *c.Char, size c.Uint) *c.Char
|
||||
|
||||
//go:linkname InetAddr C.inet_addr
|
||||
func InetAddr(s *c.Char) c.Uint
|
||||
|
||||
//go:linkname Send C.send
|
||||
func Send(c.Int, c.Pointer, uintptr, c.Int) c.Long
|
||||
|
||||
//go:linkname Recv C.recv
|
||||
func Recv(c.Int, c.Pointer, uintptr, c.Int) c.Long
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type AddrInfo struct {
|
||||
Flags c.Int
|
||||
Family c.Int
|
||||
SockType c.Int
|
||||
Protocol c.Int
|
||||
AddrLen c.Uint
|
||||
CanOnName *c.Char
|
||||
Addr *SockAddr
|
||||
Next *AddrInfo
|
||||
}
|
||||
|
||||
//go:linkname Getaddrinfo C.getaddrinfo
|
||||
func Getaddrinfo(host *c.Char, port *c.Char, addrInfo *AddrInfo, result **AddrInfo) c.Int
|
||||
|
||||
//go:linkname Freeaddrinfo C.freeaddrinfo
|
||||
func Freeaddrinfo(addrInfo *AddrInfo) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func swapInt16(data uint16) uint16 {
|
||||
return (data << 8) | (data >> 8)
|
||||
}
|
||||
|
||||
func Htons(x uint16) uint16 {
|
||||
return swapInt16(x)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
157
c/os/os.go
157
c/os/os.go
@@ -24,6 +24,7 @@ import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,13 +35,43 @@ const (
|
||||
PATH_MAX = C.PATH_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
/* get file status flags */
|
||||
F_GETFL = 3
|
||||
/* set file status flags */
|
||||
F_SETFL = 4
|
||||
|
||||
/* open for reading only */
|
||||
O_RDONLY = 0x0000
|
||||
/* open for writing only */
|
||||
O_WRONLY = 0x0001
|
||||
/* open for reading and writing */
|
||||
O_RDWR = 0x0002
|
||||
/* mask for above modes */
|
||||
O_ACCMODE = 0x0003
|
||||
|
||||
/* no delay */
|
||||
O_NONBLOCK = 0x00000004
|
||||
/* create if nonexistant */
|
||||
O_CREAT = 0x00000200
|
||||
/* truncate to zero length */
|
||||
O_TRUNC = 0x00000400
|
||||
)
|
||||
|
||||
const (
|
||||
EAGAIN = 35
|
||||
)
|
||||
|
||||
type (
|
||||
ModeT C.mode_t
|
||||
UidT C.uid_t
|
||||
GidT C.gid_t
|
||||
OffT C.off_t
|
||||
DevT C.dev_t
|
||||
StatT C.struct_stat
|
||||
)
|
||||
|
||||
type (
|
||||
StatT = syscall.Stat_t
|
||||
)
|
||||
|
||||
//go:linkname Errno errno
|
||||
@@ -104,8 +135,8 @@ func Chroot(path *c.Char) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Environ C.environ
|
||||
func Environ() **c.Char
|
||||
//go:linkname Environ environ
|
||||
var Environ **c.Char
|
||||
|
||||
//go:linkname Getenv C.getenv
|
||||
func Getenv(name *c.Char) *c.Char
|
||||
@@ -142,7 +173,7 @@ func Fstatat(dirfd c.Int, path *c.Char, buf *StatT, flags c.Int) c.Int
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Open C.open
|
||||
func Open(path *c.Char, flags c.Int, mode ModeT) c.Int
|
||||
func Open(path *c.Char, flags c.Int, __llgo_va_list ...any) c.Int
|
||||
|
||||
//go:linkname Openat C.openat
|
||||
func Openat(dirfd c.Int, path *c.Char, flags c.Int, mode ModeT) c.Int
|
||||
@@ -150,6 +181,9 @@ func Openat(dirfd c.Int, path *c.Char, flags c.Int, mode ModeT) c.Int
|
||||
//go:linkname Creat C.creat
|
||||
func Creat(path *c.Char, mode ModeT) c.Int
|
||||
|
||||
//go:linkname Fcntl C.fcntl
|
||||
func Fcntl(a c.Int, b c.Int, __llgo_va_list ...any) c.Int
|
||||
|
||||
//go:linkname Dup C.dup
|
||||
func Dup(fd c.Int) c.Int
|
||||
|
||||
@@ -204,18 +238,79 @@ func Isatty(fd c.Int) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Execl(const char *path, const char *arg0, ..., /*, (char *)0, */)
|
||||
//
|
||||
// Execl requires the full path of the program to be provided.
|
||||
//
|
||||
//go:linkname Execl C.execl
|
||||
func Execl(path *c.Char, __llgo_va_list ...any) c.Int
|
||||
|
||||
// Execle(const char *path, const char *arg0, ..., /* (char *)0, char *const envp[] */)
|
||||
//
|
||||
//go:linkname Execle C.execle
|
||||
func Execle(path *c.Char, __llgo_va_list ...any) c.Int
|
||||
|
||||
// Execlp(const char *file, const char *arg0, ..., /*, (char *)0, */)
|
||||
//
|
||||
// Execlp only needs to provide the program name and it will search for the program in the
|
||||
// paths specified in the PATH environment variable.
|
||||
//
|
||||
//go:linkname Execlp C.execlp
|
||||
func Execlp(file *c.Char, __llgo_va_list ...any) c.Int
|
||||
|
||||
//go:linkname Execv C.execv
|
||||
func Execv(path *c.Char, argv **c.Char) c.Int
|
||||
|
||||
//go:linkname Execve C.execve
|
||||
func Execve(path *c.Char, argv **c.Char, envp **c.Char) c.Int
|
||||
|
||||
//go:linkname Execvp C.execvp
|
||||
func Execvp(file *c.Char, argv **c.Char) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type PidT c.Int
|
||||
|
||||
//go:linkname Fork C.fork
|
||||
func Fork() PidT
|
||||
|
||||
//go:linkname Getpid C.getpid
|
||||
func Getpid() PidT
|
||||
|
||||
//go:linkname Getppid C.getppid
|
||||
func Getppid() PidT
|
||||
|
||||
//go:linkname Kill C.kill
|
||||
func Kill(pid c.Int, sig c.Int) c.Int
|
||||
func Kill(pid PidT, sig c.Int) c.Int
|
||||
|
||||
// If wait() returns due to a stopped or terminated child process, the process ID
|
||||
// of the child is returned to the calling process. Otherwise, a value of -1 is
|
||||
// returned and errno is set to indicate the error.
|
||||
//
|
||||
//go:linkname Wait C.wait
|
||||
func Wait(statLoc *c.Int) PidT
|
||||
|
||||
// If wait3(), wait4(), or waitpid() returns due to a stopped or terminated child
|
||||
// process, the process ID of the child is returned to the calling process. If
|
||||
// there are no children not previously awaited, -1 is returned with errno set to
|
||||
// [ECHILD]. Otherwise, if WNOHANG is specified and there are no stopped or exited
|
||||
// children, 0 is returned. If an error is detected or a caught signal aborts the
|
||||
// call, a value of -1 is returned and errno is set to indicate the error.
|
||||
//
|
||||
//go:linkname Wait3 C.wait3
|
||||
func Wait3(statLoc *c.Int, options c.Int, rusage *syscall.Rusage) PidT
|
||||
|
||||
//go:linkname Wait4 C.wait4
|
||||
func Wait4(pid PidT, statLoc *c.Int, options c.Int, rusage *syscall.Rusage) PidT
|
||||
|
||||
//go:linkname Waitpid C.waitpid
|
||||
func Waitpid(pid PidT, statLoc *c.Int, options c.Int) PidT
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Exit C.exit
|
||||
func Exit(c.Int)
|
||||
|
||||
//go:linkname Getpid C.getpid
|
||||
func Getpid() c.Int
|
||||
|
||||
//go:linkname Getppid C.getppid
|
||||
func Getppid() c.Int
|
||||
|
||||
//go:linkname Getuid C.getuid
|
||||
func Getuid() UidT
|
||||
|
||||
@@ -229,3 +324,43 @@ func Getgid() GidT
|
||||
func Getegid() GidT
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Getrlimit C.getrlimit
|
||||
func Getrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
//go:linkname Setrlimit C.setrlimit
|
||||
func Setrlimit(resource c.Int, rlp *syscall.Rlimit) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Upon successful completion, the value 0 is returned; otherwise the value -1
|
||||
// is returned and the global variable errno is set to indicate the error.
|
||||
//
|
||||
//go:linkname Sysctl C.sysctl
|
||||
func Sysctl(
|
||||
name *c.Int, namelen c.Uint,
|
||||
oldp c.Pointer, oldlenp *uintptr,
|
||||
newp c.Pointer, newlen uintptr) c.Int
|
||||
|
||||
//go:linkname Sysctlbyname C.sysctlbyname
|
||||
func Sysctlbyname(
|
||||
name *c.Char, oldp c.Pointer, oldlenp *uintptr,
|
||||
newp c.Pointer, newlen uintptr) c.Int
|
||||
|
||||
// The sysctlnametomib() function accepts an ASCII representation of the
|
||||
// name, looks up the integer name vector, and returns the numeric repre-
|
||||
// sentation in the mib array pointed to by mibp. The number of elements
|
||||
// in the mib array is given by the location specified by sizep before the
|
||||
// call, and that location gives the number of entries copied after a suc-
|
||||
// cessful call. The resulting mib and size may be used in subsequent
|
||||
// sysctl() calls to get the data associated with the requested ASCII
|
||||
// name. This interface is intended for use by applications that want to
|
||||
// repeatedly request the same variable (the sysctl() function runs in
|
||||
// about a third the time as the same request made via the sysctlbyname()
|
||||
// function). The sysctlnametomib() function is also useful for fetching
|
||||
// mib prefixes and then adding a final component.
|
||||
//
|
||||
//go:linkname Sysctlnametomib C.sysctlnametomib
|
||||
func Sysctlnametomib(name *c.Char, mibp *c.Int, sizep *uintptr) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Binary file not shown.
@@ -76,14 +76,18 @@ func (m *Mutex) Init(attr *MutexAttr) c.Int { return 0 }
|
||||
// llgo:link (*Mutex).Destroy C.pthread_mutex_destroy
|
||||
func (m *Mutex) Destroy() {}
|
||||
|
||||
// llgo:link (*Mutex).Lock C.pthread_mutex_lock
|
||||
func (m *Mutex) Lock() {}
|
||||
func (m *Mutex) Lock() { m.lockInternal() }
|
||||
|
||||
// llgo:link (*Mutex).lockInternal C.pthread_mutex_lock
|
||||
func (m *Mutex) lockInternal() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*Mutex).TryLock C.pthread_mutex_trylock
|
||||
func (m *Mutex) TryLock() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*Mutex).Unlock C.pthread_mutex_unlock
|
||||
func (m *Mutex) Unlock() {}
|
||||
func (m *Mutex) Unlock() { m.unlockInternal() }
|
||||
|
||||
// llgo:link (*Mutex).unlockInternal C.pthread_mutex_unlock
|
||||
func (m *Mutex) unlockInternal() c.Int { return 0 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
30
c/raylib/README.md
Normal file
30
c/raylib/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# LLGo wrapper of raysan5/raylib
|
||||
|
||||
## How to install
|
||||
|
||||
### on macOS (Homebrew)
|
||||
|
||||
```sh
|
||||
brew install raylib
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
|
||||
```sh
|
||||
TODO
|
||||
```
|
||||
|
||||
## Demos
|
||||
|
||||
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
|
||||
|
||||
- [tetris](_demo/tetris/tetris.go): tetris powered by raylib
|
||||
|
||||
### How to run demos
|
||||
|
||||
To run the demos in directory `_demo`:
|
||||
|
||||
```sh
|
||||
cd <demo-directory> # eg. cd _demo/tetris
|
||||
llgo run .
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
42
c/sys/_demo/selectdemo/select.go
Normal file
42
c/sys/_demo/selectdemo/select.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"github.com/goplus/llgo/c/sys"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var readFds sys.FdSet
|
||||
sys.FD_ZERO(&readFds)
|
||||
sys.FD_SET(0, &readFds)
|
||||
|
||||
var tv sys.Timeval
|
||||
tv.Sec = 5
|
||||
tv.Usec = 0
|
||||
|
||||
c.Printf(c.Str("Waiting for input on stdin...\n"))
|
||||
ret := sys.Select(1, &readFds, nil, nil, &tv)
|
||||
if ret == -1 {
|
||||
c.Perror(c.Str("select error"))
|
||||
c.Exit(1)
|
||||
} else if ret == 0 {
|
||||
c.Printf(c.Str("Timeout occurred! No data after 5 seconds.\n"))
|
||||
} else {
|
||||
if sys.FD_ISSET(0, &readFds) != 0 {
|
||||
var buffer [100]c.Char
|
||||
n := os.Read(0, c.Pointer(&buffer[:][0]), unsafe.Sizeof(buffer)-1)
|
||||
if n == -1 {
|
||||
c.Perror(c.Str("read error"))
|
||||
c.Exit(1)
|
||||
} else if n == 0 {
|
||||
c.Printf(c.Str("End of file\n"))
|
||||
} else {
|
||||
buffer[n] = c.Char(0)
|
||||
c.Printf(c.Str("Read %ld bytes: %s\n"), n, &buffer[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
c/sys/_demo/selectdemo2/select2.go
Normal file
88
c/sys/_demo/selectdemo2/select2.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/net"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"github.com/goplus/llgo/c/sys"
|
||||
)
|
||||
|
||||
const (
|
||||
SERVER_IP = "110.242.68.66" // Get the IP address by ping baidu.com
|
||||
SERVER_PORT = 80
|
||||
BUFFER_SIZE = 4096 * 1024
|
||||
)
|
||||
|
||||
func main() {
|
||||
var server net.SockaddrIn
|
||||
|
||||
sendBuf := c.Str("GET / HTTP/1.1\r\nHost: baidu.com\r\n\r\n")
|
||||
var recvBuf [BUFFER_SIZE]c.Char
|
||||
var bytes_sent, bytes_received c.Int
|
||||
|
||||
// create net
|
||||
sock := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
|
||||
if sock < 0 {
|
||||
c.Perror(c.Str("Socket creation failed"))
|
||||
return
|
||||
}
|
||||
|
||||
// set server addr
|
||||
c.Memset(c.Pointer(&server), 0, unsafe.Sizeof(server))
|
||||
server.Family = net.AF_INET
|
||||
server.Port = net.Htons(SERVER_PORT)
|
||||
server.Addr.Addr = net.InetAddr(c.Str(SERVER_IP))
|
||||
|
||||
// connect to server
|
||||
if net.Connect(sock, (*net.SockAddr)(c.Pointer(&server)), c.Uint(unsafe.Sizeof(server))) < 0 {
|
||||
c.Perror(c.Str("Connect failed"))
|
||||
return
|
||||
}
|
||||
|
||||
var writefds, readfds sys.FdSet
|
||||
var timeout sys.Timeval
|
||||
|
||||
// Monitor socket writes
|
||||
sys.FD_ZERO(&writefds)
|
||||
sys.FD_SET(sock, &writefds)
|
||||
timeout.Sec = 10
|
||||
timeout.Usec = 0
|
||||
|
||||
// Use select to monitor the readiness of writes
|
||||
if sys.Select(sock+1, nil, &writefds, nil, &timeout) > 0 {
|
||||
if sys.FD_ISSET(sock, &writefds) != 0 {
|
||||
bytes_sent = c.Int(net.Send(sock, c.Pointer(sendBuf), c.Strlen(sendBuf), 0))
|
||||
if bytes_sent < 0 {
|
||||
c.Perror(c.Str("send failed"))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c.Perror(c.Str("Select write error"))
|
||||
return
|
||||
}
|
||||
|
||||
// Monitor socket reads
|
||||
sys.FD_ZERO(&readfds)
|
||||
sys.FD_SET(sock, &readfds)
|
||||
|
||||
// Use select to monitor the readiness of the read operation
|
||||
if sys.Select(sock+1, &readfds, nil, nil, &timeout) > 0 {
|
||||
if sys.FD_ISSET(sock, &writefds) != -1 {
|
||||
bytes_received = c.Int(net.Recv(sock, c.Pointer(&recvBuf[:][0]), BUFFER_SIZE-1, 0))
|
||||
if bytes_received < 0 {
|
||||
c.Perror(c.Str("receive failed"))
|
||||
return
|
||||
}
|
||||
recvBuf[bytes_received] = c.Char(0)
|
||||
c.Printf(c.Str("Received:\n%s\n"), &recvBuf[0])
|
||||
}
|
||||
} else {
|
||||
c.Perror(c.Str("Select read error"))
|
||||
return
|
||||
}
|
||||
|
||||
os.Close(sock)
|
||||
}
|
||||
13
c/sys/_wrap/fddef.c
Normal file
13
c/sys/_wrap/fddef.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
int llgo_FD_ISSET(int n, fd_set *fd) {
|
||||
return FD_ISSET(n, fd);
|
||||
}
|
||||
|
||||
void llgo_FD_SET(int n, fd_set *fd) {
|
||||
FD_SET(n, fd);
|
||||
}
|
||||
|
||||
void llgo_FD_ZERO(fd_set *fd) {
|
||||
FD_ZERO(fd);
|
||||
}
|
||||
34
c/sys/select.go
Normal file
34
c/sys/select.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "_wrap/fddef.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type (
|
||||
FdSet = syscall.FdSet
|
||||
Timeval = syscall.Timeval
|
||||
)
|
||||
|
||||
//go:linkname FD_ZERO C.llgo_FD_ZERO
|
||||
func FD_ZERO(fds *FdSet)
|
||||
|
||||
//go:linkname FD_SET C.llgo_FD_SET
|
||||
func FD_SET(fd c.Int, fds *FdSet)
|
||||
|
||||
//go:linkname FD_ISSET C.llgo_FD_ISSET
|
||||
func FD_ISSET(fd c.Int, fds *FdSet) c.Int
|
||||
|
||||
//go:linkname Select C.select
|
||||
func Select(n c.Int, fdsRead, fdsWrite, fdsError *FdSet, timeout *Timeval) c.Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
27
c/syscall/syscall.go
Normal file
27
c/syscall/syscall.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
type Errno = uintptr
|
||||
|
||||
// A Signal is a number describing a process signal.
|
||||
// It implements the os.Signal interface.
|
||||
type Signal = int
|
||||
10
c/syscall/unix/at_sysnum_darwin.go
Normal file
10
c/syscall/unix/at_sysnum_darwin.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const AT_REMOVEDIR = 0x80
|
||||
const AT_SYMLINK_NOFOLLOW = 0x0020
|
||||
|
||||
const UTIME_OMIT = -0x2
|
||||
10
c/syscall/unix/at_sysnum_dragonfly.go
Normal file
10
c/syscall/unix/at_sysnum_dragonfly.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const AT_REMOVEDIR = 0x2
|
||||
const AT_SYMLINK_NOFOLLOW = 0x1
|
||||
|
||||
const UTIME_OMIT = -0x1
|
||||
12
c/syscall/unix/at_sysnum_freebsd.go
Normal file
12
c/syscall/unix/at_sysnum_freebsd.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
AT_REMOVEDIR = 0x800
|
||||
AT_SYMLINK_NOFOLLOW = 0x200
|
||||
|
||||
UTIME_OMIT = -0x2
|
||||
)
|
||||
14
c/syscall/unix/at_sysnum_linux.go
Normal file
14
c/syscall/unix/at_sysnum_linux.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
AT_EACCESS = 0x200
|
||||
AT_FDCWD = -0x64
|
||||
AT_REMOVEDIR = 0x200
|
||||
AT_SYMLINK_NOFOLLOW = 0x100
|
||||
|
||||
UTIME_OMIT = 0x3ffffffe
|
||||
)
|
||||
10
c/syscall/unix/at_sysnum_netbsd.go
Normal file
10
c/syscall/unix/at_sysnum_netbsd.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const AT_REMOVEDIR = 0x800
|
||||
const AT_SYMLINK_NOFOLLOW = 0x200
|
||||
|
||||
const UTIME_OMIT = (1 << 30) - 2
|
||||
10
c/syscall/unix/at_sysnum_openbsd.go
Normal file
10
c/syscall/unix/at_sysnum_openbsd.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
const AT_REMOVEDIR = 0x08
|
||||
const AT_SYMLINK_NOFOLLOW = 0x02
|
||||
|
||||
const UTIME_OMIT = -0x1
|
||||
21
c/syscall/unix/unix.go
Normal file
21
c/syscall/unix/unix.go
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
1153
c/syscall/zerrors_aix_ppc64.go
Normal file
1153
c/syscall/zerrors_aix_ppc64.go
Normal file
File diff suppressed because it is too large
Load Diff
1279
c/syscall/zerrors_darwin_amd64.go
Normal file
1279
c/syscall/zerrors_darwin_amd64.go
Normal file
File diff suppressed because it is too large
Load Diff
1291
c/syscall/zerrors_darwin_arm64.go
Normal file
1291
c/syscall/zerrors_darwin_arm64.go
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user