mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-11 12:46:35 +00:00
Compare commits
244 Commits
feature-ex
...
jshooks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ad6701757 | ||
|
|
176d7a1a0c | ||
|
|
ebfbb8a900 | ||
|
|
a94e8b9536 | ||
|
|
13910b23a4 | ||
|
|
6385c56832 | ||
|
|
3c879c7288 | ||
|
|
101ad3cb7e | ||
|
|
21a5e82fad | ||
|
|
c44b50b98c | ||
|
|
444152d077 | ||
|
|
d8c9e89043 | ||
|
|
285ea1d4e6 | ||
|
|
b619d03b22 | ||
|
|
34fd31dabe | ||
|
|
a6c4e39235 | ||
|
|
50a6499112 | ||
|
|
429f3289d8 | ||
|
|
257c46ec9c | ||
|
|
637d626518 | ||
|
|
cce9d372e7 | ||
|
|
aa571df467 | ||
|
|
ae8f6a16ed | ||
|
|
64441f7f40 | ||
|
|
0bf50c5dc7 | ||
|
|
8b0592ce06 | ||
|
|
c27e2a9c05 | ||
|
|
f8d22bbc24 | ||
|
|
95ab35a185 | ||
|
|
313ad7134b | ||
|
|
859dcbcabf | ||
|
|
a8e9448b1a | ||
|
|
cab4d63a07 | ||
|
|
9a90a7ffdc | ||
|
|
ddbbe91e5a | ||
|
|
2d9ac91cd1 | ||
|
|
9532ea7dec | ||
|
|
ed243745f8 | ||
|
|
5eac2d3e44 | ||
|
|
245cf4a676 | ||
|
|
864734f607 | ||
|
|
689740d818 | ||
|
|
a8c80e99c0 | ||
|
|
486003f1a8 | ||
|
|
c9f0fe02a1 | ||
|
|
a9c096e59c | ||
|
|
a83a157058 | ||
|
|
5e255e560f | ||
|
|
c953ee326d | ||
|
|
053a10a236 | ||
|
|
c53dcf1422 | ||
|
|
34b148bda0 | ||
|
|
19111a3739 | ||
|
|
3f98c15910 | ||
|
|
942227f8c3 | ||
|
|
e9461c827c | ||
|
|
3d9423dda6 | ||
|
|
5d41688e36 | ||
|
|
9bd6d2244e | ||
|
|
48919f028c | ||
|
|
46d745b43f | ||
|
|
5365bbcfe8 | ||
|
|
9c26f1f213 | ||
|
|
69b7728b2d | ||
|
|
15b679b1a7 | ||
|
|
9178aa9d8a | ||
|
|
17fdd09640 | ||
|
|
40dc69d642 | ||
|
|
e8560c2198 | ||
|
|
ca7533c14a | ||
|
|
eba913a68e | ||
|
|
ec849e0899 | ||
|
|
314fb6c9e0 | ||
|
|
643cd9fef1 | ||
|
|
3593d67df9 | ||
|
|
5571827be2 | ||
|
|
cfbfd762e8 | ||
|
|
c25fd875a8 | ||
|
|
043f1e96b6 | ||
|
|
17dfca6e61 | ||
|
|
74681718dd | ||
|
|
167417bfed | ||
|
|
2dd22648e8 | ||
|
|
e89aa05a2a | ||
|
|
8a5ccbf870 | ||
|
|
f6f87e468a | ||
|
|
d7167a9ebe | ||
|
|
7446dddddb | ||
|
|
d9388e1e51 | ||
|
|
73c1748241 | ||
|
|
58e3840345 | ||
|
|
61135c0ecb | ||
|
|
42a44d0cb8 | ||
|
|
d37039897e | ||
|
|
2061d6d44c | ||
|
|
8ea35ace02 | ||
|
|
a203314c68 | ||
|
|
092a29cd18 | ||
|
|
1ba18875ac | ||
|
|
2da58fe18f | ||
|
|
8d7cc68bda | ||
|
|
b73dd584e7 | ||
|
|
0726789d77 | ||
|
|
05bd9c6ea8 | ||
|
|
f9e7ea95fd | ||
|
|
618a933241 | ||
|
|
752dbf34ee | ||
|
|
fcf3848814 | ||
|
|
e4a6aecc18 | ||
|
|
1c4ebfe3ad | ||
|
|
f97165e4bc | ||
|
|
fc50c0fb0a | ||
|
|
1b12b400d7 | ||
|
|
f3ee0dd322 | ||
|
|
d9659dc226 | ||
|
|
fb7af36cef | ||
|
|
4bfe27d11f | ||
|
|
eaa2cc9e5c | ||
|
|
6aa1ff87b9 | ||
|
|
5ef3795cea | ||
|
|
da5f1d189b | ||
|
|
6fdf788b13 | ||
|
|
61f45055a7 | ||
|
|
f9e7fed929 | ||
|
|
5cfe566489 | ||
|
|
04409616ed | ||
|
|
ca04c2a802 | ||
|
|
f868b4d6e6 | ||
|
|
5502453de8 | ||
|
|
359ab70ba0 | ||
|
|
d82f60705d | ||
|
|
15515b84f8 | ||
|
|
8b29fc5ee1 | ||
|
|
92be8146e8 | ||
|
|
c0f55d0b00 | ||
|
|
802ea6c568 | ||
|
|
ecc779346e | ||
|
|
680c6095d4 | ||
|
|
6858861660 | ||
|
|
9faef17407 | ||
|
|
ee68cc2cd2 | ||
|
|
7c360bad33 | ||
|
|
26a66bc2ef | ||
|
|
4b93e1657f | ||
|
|
cd45285cab | ||
|
|
b7acfb9803 | ||
|
|
97a10d6556 | ||
|
|
fe43029272 | ||
|
|
bf33b6f637 | ||
|
|
c27518b846 | ||
|
|
7d8f5de93d | ||
|
|
858ea1bf25 | ||
|
|
7162fe0497 | ||
|
|
56c0e0dd5f | ||
|
|
20ca066454 | ||
|
|
171610d1a9 | ||
|
|
2f6cf0ab4b | ||
|
|
71884ad48a | ||
|
|
799a056313 | ||
|
|
eec61f16c9 | ||
|
|
1bed7f1196 | ||
|
|
211e63c568 | ||
|
|
81413a5ce8 | ||
|
|
36d630bed3 | ||
|
|
4f901788f4 | ||
|
|
72e773cbff | ||
|
|
39ec8fb901 | ||
|
|
534870f2f0 | ||
|
|
db245d237c | ||
|
|
f3118ef8fa | ||
|
|
ee21449757 | ||
|
|
9e7bee5564 | ||
|
|
8cb2bbb693 | ||
|
|
c240c1553b | ||
|
|
a498ebeac4 | ||
|
|
b13cab4ced | ||
|
|
783bff75a0 | ||
|
|
c1610a6dda | ||
|
|
f829a79d54 | ||
|
|
f35704c91f | ||
|
|
9db9ad2123 | ||
|
|
f96daa0014 | ||
|
|
5c7ec5f36f | ||
|
|
c662a8b0d2 | ||
|
|
a983120b5d | ||
|
|
f12b8cbb2d | ||
|
|
f591290589 | ||
|
|
f2becaf140 | ||
|
|
e4c6add794 | ||
|
|
78280e4b8c | ||
|
|
178fdbaff6 | ||
|
|
34d7435ff3 | ||
|
|
6429ec609d | ||
|
|
bea1697baa | ||
|
|
2b111b7f23 | ||
|
|
5254595063 | ||
|
|
52456a2d51 | ||
|
|
b340824711 | ||
|
|
f5bb779f61 | ||
|
|
bf99a1b05d | ||
|
|
d1e5eb87f5 | ||
|
|
b650d72f0b | ||
|
|
7567277dd8 | ||
|
|
13719a1357 | ||
|
|
033dedf979 | ||
|
|
6973540d52 | ||
|
|
c9dcff90fa | ||
|
|
71675c4fed | ||
|
|
70bc2d3283 | ||
|
|
c4d0fc0e0f | ||
|
|
5d61eea709 | ||
|
|
f4ffe4a3e0 | ||
|
|
59ecbd9932 | ||
|
|
6c3da46a1b | ||
|
|
46308e33b0 | ||
|
|
1f7355719d | ||
|
|
7cc395b284 | ||
|
|
a634318e8d | ||
|
|
82e754d180 | ||
|
|
9e72931bbb | ||
|
|
842a0388d1 | ||
|
|
280ba7d5de | ||
|
|
7b0bc67242 | ||
|
|
8e172e1846 | ||
|
|
7497d619bf | ||
|
|
34a159b662 | ||
|
|
663910c78a | ||
|
|
40b9aa7aed | ||
|
|
ec7d603bf9 | ||
|
|
f9137000e3 | ||
|
|
c3cf4b5999 | ||
|
|
6954abdd04 | ||
|
|
38a4b3c1b9 | ||
|
|
7e12b46169 | ||
|
|
4e91d5887f | ||
|
|
f051b87176 | ||
|
|
98d39db305 | ||
|
|
80df3adac7 | ||
|
|
a2c3567caf | ||
|
|
206773dcf4 | ||
|
|
54c00d0364 | ||
|
|
71a6f9c4d5 | ||
|
|
9ab33d580d | ||
|
|
0bd65bbb56 |
31
.codecov.yml
31
.codecov.yml
@@ -1,37 +1,6 @@
|
||||
codecov:
|
||||
require_ci_to_pass: true
|
||||
|
||||
comment:
|
||||
behavior: default
|
||||
layout: reach,diff,flags,tree,reach
|
||||
show_carryforward_flags: false
|
||||
|
||||
coverage:
|
||||
range: "60..80"
|
||||
precision: 1
|
||||
round: nearest
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 60%
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 2%
|
||||
changes: false
|
||||
|
||||
github_checks:
|
||||
annotations: true
|
||||
|
||||
parsers:
|
||||
cobertura:
|
||||
partials_as_hits: true
|
||||
handle_missing_conditions : true
|
||||
|
||||
slack_app: false
|
||||
|
||||
ignore:
|
||||
- "src/test/"
|
||||
- "include/xrpl/beast/test/"
|
||||
- "include/xrpl/beast/unit_test/"
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
# This feature requires Git >= 2.24
|
||||
# To use it by default in git blame:
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
# Format first-party source according to .clang-format
|
||||
50760c693510894ca368e90369b0cc2dabfd07f3
|
||||
# Reintroduce Clang-Format & Levelization
|
||||
da1d20d6d5d862716125d60899b80fab5302954a
|
||||
# Consolidate external libraries
|
||||
da1d20d6d5d862716125d60899b80fab5302954a
|
||||
# Rename .hpp to .h
|
||||
0345a2645d0f5ad900f4fbbcaff96040d3a887fc
|
||||
# Format formerly .hpp files
|
||||
5a227dc719016e10045e17c9396ad401118044f1
|
||||
# Rewrite includes
|
||||
e61880699997398f5a746e6c4034edc7632661f5
|
||||
# Move CMake directory (#4997)
|
||||
e47b1c1b3b97c3f6d11858ee02f463596e29e7f0
|
||||
# Rearrange sources (#4997)
|
||||
bfafa2bb39e562901736d656806bd700c3699a2f
|
||||
# Rewrite includes (#4997)
|
||||
e61880699997398f5a746e6c4034edc7632661f5
|
||||
# Recompute loops (#4997)
|
||||
d25b5dcd568bb96c18e347d55fac10fe901a1bfb
|
||||
# Reformat code with clang-format-18
|
||||
02749feea88ce61c1f7eeb2d61a57d8ecf07ab11
|
||||
e2384885f5f630c8f0ffe4bf21a169b433a16858
|
||||
241b9ddde9e11beb7480600fd5ed90e1ef109b21
|
||||
760f16f56835663d9286bd29294d074de26a7ba6
|
||||
0eebe6a5f4246fced516d52b83ec4e7f47373edd
|
||||
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -11,3 +11,6 @@ LICENSE binary
|
||||
*.vcxproj text eol=crlf
|
||||
*.props text eol=crlf
|
||||
*.filters text eol=crlf
|
||||
|
||||
# Mark it as generated and folded out by default
|
||||
src/test/app/SetJSHook_wasm.h linguist-generated=true
|
||||
2
.github/workflows/check-genesis-hooks.yml
vendored
2
.github/workflows/check-genesis-hooks.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
run: |
|
||||
# Download install.sh
|
||||
curl -o /tmp/wasienv-install.sh https://raw.githubusercontent.com/wasienv/wasienv/master/install.sh
|
||||
|
||||
|
||||
# Replace /bin to /local/bin
|
||||
sed -i 's|/bin|/local/bin|g' /tmp/wasienv-install.sh
|
||||
|
||||
|
||||
2
.github/workflows/clang-format.yml
vendored
2
.github/workflows/clang-format.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||
- name: Format first-party sources
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -not -path "src/quickjs/*" -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -124,11 +124,10 @@ pkg
|
||||
CMakeUserPresets.json
|
||||
bld.rippled/
|
||||
|
||||
# binary
|
||||
qjsc
|
||||
generated
|
||||
.vscode
|
||||
|
||||
# AI docs (local working documents)
|
||||
.ai-docs/
|
||||
|
||||
# Suggested in-tree build directory
|
||||
/.build/
|
||||
|
||||
4
.testnet/.gitignore
vendored
4
.testnet/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
output/
|
||||
__pycache__/
|
||||
scenarios/odd-cases/
|
||||
scenarios/suite-experiments.yml
|
||||
@@ -1,29 +0,0 @@
|
||||
"""Scenario: ConsensusEntropy amendment crashes non-supporting node.
|
||||
|
||||
Votes ConsensusEntropy accept on all nodes except n4, then waits for n4
|
||||
to crash as the amendment activates without its support.
|
||||
|
||||
x-testnet run --scenario-script consensus_entropy_crash.py
|
||||
"""
|
||||
|
||||
from helpers import CONSENSUS_ENTROPY_FEATURE
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await ctx.wait_for_ledger_close()
|
||||
ctx.feature(CONSENSUS_ENTROPY_FEATURE, vetoed=False, exclude_nodes=[4])
|
||||
|
||||
log("Waiting for ConsensusEntropy to be voted for...")
|
||||
await ctx.wait_for_feature(
|
||||
CONSENSUS_ENTROPY_FEATURE,
|
||||
check=lambda s: not s.get("vetoed"),
|
||||
exclude_nodes=[4],
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
log("Waiting for n4 to crash...")
|
||||
op = await ctx.wait_for_nodes_down(nodes=[4], timeout=600)
|
||||
|
||||
ctx.assert_log("unsupported amendments activated", since=op.started, nodes=[4])
|
||||
ctx.assert_exit_status(0, nodes=[4])
|
||||
log("PASS: n4 shut down due to unsupported amendment")
|
||||
@@ -1,52 +0,0 @@
|
||||
""":descr: entropy stays valid under transaction load"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_valid_entropy
|
||||
|
||||
variants = [
|
||||
{"label": "light", "min_txns": 5, "max_txns": 10},
|
||||
{"label": "heavy", "min_txns": 50, "max_txns": 60},
|
||||
{"label": "super_heavy", "min_txns": 90, "max_txns": 120},
|
||||
]
|
||||
|
||||
|
||||
async def scenario(ctx, log, *, min_txns=5, max_txns=10, **_):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
gen = ctx.txn_generator(min_txns=min_txns, max_txns=max_txns)
|
||||
await gen.start()
|
||||
await gen.wait_until_ready()
|
||||
log(f"Transaction generator ready ({min_txns}-{max_txns} txns/ledger)")
|
||||
|
||||
# Wait for pipeline warmup + a few txn-bearing ledgers.
|
||||
await ctx.wait_for_ledgers(3, node_id=0, timeout=60)
|
||||
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(10, node_id=0, timeout=120)
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Inspecting ledgers {start_seq + 1} → {end_seq}")
|
||||
|
||||
digests = set()
|
||||
total_user_txns = 0
|
||||
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
ce, user_txns = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_valid_entropy(ce, seq, seen_digests=digests)
|
||||
total_user_txns += len(user_txns)
|
||||
log(
|
||||
f" Ledger {seq}: EntropyCount={count} "
|
||||
f"user_txns={len(user_txns)} Digest={digest[:16]}..."
|
||||
)
|
||||
|
||||
await gen.stop()
|
||||
|
||||
log(
|
||||
f"Verified {end_seq - start_seq} ledgers: {total_user_txns} user txns, "
|
||||
f"all entropy valid and unique"
|
||||
)
|
||||
|
||||
if total_user_txns == 0:
|
||||
raise AssertionError("No user transactions were included in any ledger")
|
||||
|
||||
log("PASS")
|
||||
@@ -1,139 +0,0 @@
|
||||
""":descr: 4/5 liveness, 3/5 fallback-entropy (Tier 3), recovery"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import ZERO_DIGEST, require_entropy, get_entropy_tx, entropy_fields
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Baseline: wait 1 ledger to confirm network is healthy.
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
|
||||
# --- 4/5 liveness ---
|
||||
ctx.stop_node(4)
|
||||
await ctx.wait_for_nodes_down(nodes=[4], timeout=30)
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
log("4/5: liveness OK")
|
||||
|
||||
# Snapshot validated seq before dropping to 3/5.
|
||||
val_before = ctx.validated_ledger_index(0)
|
||||
|
||||
# --- 3/5 degraded window ---
|
||||
ctx.stop_node(3)
|
||||
await ctx.wait_for_nodes_down(nodes=[3], timeout=30)
|
||||
|
||||
# 10s ≈ 3 rounds at 3s cadence.
|
||||
await ctx.sleep(10)
|
||||
|
||||
val_after = ctx.validated_ledger_index(0)
|
||||
log(f"3/5: validated ledger {val_before} → {val_after}")
|
||||
|
||||
# Accepted/built ledgers may still later appear as validated once the full
|
||||
# network rejoins. For ConsensusEntropy the key invariant is that every
|
||||
# ledger created during this sub-quorum window carries FALLBACK entropy
|
||||
# (Tier 3: non-zero consensus-bound digest, EntropyCount=0) — never
|
||||
# validator-tier entropy.
|
||||
degraded_fallback = 0
|
||||
degraded_end = val_after or val_before
|
||||
if val_before and degraded_end and degraded_end > val_before:
|
||||
for seq in range(val_before + 1, degraded_end + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, entropy_count, is_fallback = entropy_fields(ce)
|
||||
|
||||
if not is_fallback:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected fallback entropy during 3/5 "
|
||||
f"window, got Digest={digest[:16]}... "
|
||||
f"EntropyCount={entropy_count}"
|
||||
)
|
||||
if digest == ZERO_DIGEST:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: fallback digest should be non-zero "
|
||||
f"(Tier 3), got zero"
|
||||
)
|
||||
|
||||
degraded_fallback += 1
|
||||
log(
|
||||
f" Degraded ledger {seq}: EntropyCount={entropy_count} "
|
||||
f"FALLBACK"
|
||||
)
|
||||
|
||||
log(f"3/5 entropy summary: {degraded_fallback} fallback")
|
||||
|
||||
# Log checks tied to current transition mechanics:
|
||||
# - commit-set SHAMap publication is the observable output of entering the
|
||||
# commit sidecar phase
|
||||
# - ConvergingCommit transition is the gateway out of seq=0-only behavior
|
||||
# - reason=impossible-quorum is the explicit degraded-window fallback path
|
||||
ctx.log_level("LedgerConsensus", "trace")
|
||||
ctx.log_level("ConsensusExtensions", "trace")
|
||||
op = await ctx.sleep(6, name="stall_window")
|
||||
|
||||
ctx.assert_not_log(
|
||||
r"RNG: transitioned to ConvergingCommit", within=op.window, nodes=[0, 1, 2]
|
||||
)
|
||||
ctx.assert_not_log(
|
||||
r"RNG: built commitSet SHAMap", within=op.window, nodes=[0, 1, 2]
|
||||
)
|
||||
|
||||
gate_blocked = ctx.search_logs(
|
||||
r"STALLDIAG: establish gate blocked reason=(pause|no-tx-consensus)",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2],
|
||||
)
|
||||
log(f"3/5: establish gate-blocked logs in 6s: {gate_blocked.count}")
|
||||
|
||||
impossible = ctx.search_logs(
|
||||
r"RNG: skipping commit wait reason=impossible-quorum",
|
||||
within=op.window,
|
||||
nodes=[0, 1, 2],
|
||||
)
|
||||
log(f"3/5: RNG impossible-quorum skips in 6s: {impossible.count}")
|
||||
|
||||
# --- Recovery: restart nodes, verify ledger advancement ---
|
||||
ctx.start_node(3)
|
||||
ctx.start_node(4)
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=120)
|
||||
|
||||
val_recovered = ctx.validated_ledger_index(0)
|
||||
pre_recovery = max(v for v in [val_before, val_after] if v is not None)
|
||||
log(f"Recovered: validated seq {pre_recovery} → {val_recovered}")
|
||||
|
||||
if not val_recovered or val_recovered <= pre_recovery:
|
||||
raise AssertionError(
|
||||
f"Validated ledger did not advance after recovery "
|
||||
f"({pre_recovery} → {val_recovered})"
|
||||
)
|
||||
|
||||
# Inspect post-recovery ledgers separately from the degraded window above.
|
||||
# Once the network is back at quorum, validator-tier entropy is expected
|
||||
# again (transitional fallback ledgers are fine) and must be quorum-met.
|
||||
fallback_count = 0
|
||||
validator_count = 0
|
||||
for seq in range(pre_recovery + 1, val_recovered + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, entropy_count, is_fallback = entropy_fields(ce)
|
||||
|
||||
if is_fallback:
|
||||
fallback_count += 1
|
||||
else:
|
||||
validator_count += 1
|
||||
if entropy_count < 4:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: validator entropy with sub-quorum "
|
||||
f"EntropyCount={entropy_count} (need >= 4)"
|
||||
)
|
||||
|
||||
log(
|
||||
f" Ledger {seq}: EntropyCount={entropy_count} "
|
||||
f"{'FALLBACK' if is_fallback else 'VALIDATOR'}"
|
||||
)
|
||||
|
||||
log(
|
||||
f"Entropy summary: {fallback_count} fallback, "
|
||||
f"{validator_count} validator"
|
||||
)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,44 +0,0 @@
|
||||
""":descr: drop 2 nodes (3/5 stall), restart both, verify recovery"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=60)
|
||||
log("Baseline OK")
|
||||
|
||||
# Drop 2 nodes → validation stall.
|
||||
ctx.stop_node(3)
|
||||
ctx.stop_node(4)
|
||||
await ctx.wait_for_nodes_down(nodes=[3, 4], timeout=30)
|
||||
|
||||
info = ctx.rpc.server_info(node_id=0)
|
||||
val_before = info.get("info", {}).get("validated_ledger", {}).get("seq", 0)
|
||||
log(f"Stalled at validated seq {val_before}")
|
||||
|
||||
# Let it sit for a few rounds in degraded state.
|
||||
await ctx.sleep(6)
|
||||
|
||||
# Bring both nodes back.
|
||||
ctx.start_node(3)
|
||||
ctx.start_node(4)
|
||||
log("Restarted n3 and n4, waiting for recovery...")
|
||||
|
||||
# Recovery: wait for ANY validated ledger advance on n0.
|
||||
await ctx.wait_for_ledger_close(node_id=0, timeout=60)
|
||||
|
||||
info = ctx.rpc.server_info(node_id=0)
|
||||
val_after = info.get("info", {}).get("validated_ledger", {}).get("seq", 0)
|
||||
log(f"Recovered: validated seq {val_before} → {val_after}")
|
||||
|
||||
if val_after <= val_before:
|
||||
raise AssertionError(
|
||||
f"Validated ledger did not advance after recovery "
|
||||
f"({val_before} → {val_after})"
|
||||
)
|
||||
|
||||
log("PASS")
|
||||
@@ -1,27 +0,0 @@
|
||||
""":descr: all 5 nodes healthy, every ledger has valid unique quorum-met entropy"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from helpers import require_entropy, get_entropy_tx, assert_valid_entropy
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_entropy(ctx, log)
|
||||
|
||||
# Wait for RNG pipeline to warm up past bootstrap skip.
|
||||
await ctx.wait_for_ledgers(3, node_id=0, timeout=60)
|
||||
log("Pipeline warmed up")
|
||||
|
||||
start_seq = ctx.validated_ledger_index(0)
|
||||
await ctx.wait_for_ledgers(10, node_id=0, timeout=120)
|
||||
end_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Inspecting ledgers {start_seq + 1} → {end_seq}")
|
||||
|
||||
digests = set()
|
||||
for seq in range(start_seq + 1, end_seq + 1):
|
||||
ce, _ = get_entropy_tx(ctx, seq)
|
||||
digest, count = assert_valid_entropy(ce, seq, seen_digests=digests)
|
||||
log(f" Ledger {seq}: EntropyCount={count} Digest={digest[:16]}...")
|
||||
|
||||
log(f"Verified {end_seq - start_seq} ledgers: all quorum entropy, all unique")
|
||||
log("PASS")
|
||||
@@ -1,88 +0,0 @@
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
- Export
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
XAHAU_RNG_POLL_MS: "333"
|
||||
|
||||
tests:
|
||||
# --- CE + Export (80% quorum, SHAMap convergence) ---
|
||||
- name: steady_state_export_ce
|
||||
script: .testnet/scenarios/export/steady_state_export.py
|
||||
|
||||
- name: retriable_export_ce
|
||||
script: .testnet/scenarios/export/retriable_export.py
|
||||
|
||||
- name: export_degradation_ce
|
||||
script: .testnet/scenarios/export/export_degradation.py
|
||||
network:
|
||||
node_env:
|
||||
3:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
4:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
|
||||
# CE + Export: 1 node suppressed, 4/5 = 80% quorum, should succeed
|
||||
- name: export_ce_one_node_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
node_env:
|
||||
4:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
|
||||
# --- Export only, no CE (80% active-view quorum) ---
|
||||
- name: export_only_all_up
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
|
||||
- name: export_only_one_node_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: true
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
node_env:
|
||||
4:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
|
||||
- name: export_only_two_nodes_down
|
||||
script: .testnet/scenarios/export/export_quorum.py
|
||||
params:
|
||||
expect_success: false
|
||||
network:
|
||||
features:
|
||||
- Export
|
||||
track_features:
|
||||
- Export
|
||||
node_env:
|
||||
3:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
4:
|
||||
XAHAUD_NO_EXPORT_SIG: "1"
|
||||
@@ -1,118 +0,0 @@
|
||||
""":descr: Submit ttEXPORT with 2 nodes suppressing export sigs, verify it
|
||||
retries via terRETRY_EXPORT until LLS expiry (insufficient signatures).
|
||||
|
||||
Nodes 3 and 4 have XAHAUD_NO_EXPORT_SIG=1, so only 3/5 nodes provide
|
||||
export signatures. With 80% quorum = ceil(5*0.8) = 4 required, the
|
||||
export cannot reach quorum and should expire via tecEXPORT_EXPIRED.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT with tight LLS
|
||||
3. Export retries (only 3/5 sigs available, need 4)
|
||||
4. Verify export expires with tecEXPORT_EXPIRED
|
||||
5. Verify subsequent payment still works (sequence not permanently blocked)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import require_export, assert_shadow_ticket
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
log("Nodes 3,4 have XAHAUD_NO_EXPORT_SIG=1 (3/5 sigs, need 4)")
|
||||
|
||||
# --- Submit ttEXPORT (should retry then expire -- only 3/5 sigs) ---
|
||||
export_start = ctx.mark("export-degradation-submit-start")
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 6,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
export_end = ctx.mark("export-degradation-submit-end")
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export completed at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
# With only 3/5 sigs and 80% quorum (4 required), export MUST fail
|
||||
if engine_result == "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
"Export should NOT have succeeded with only 3/5 sigs "
|
||||
"(need 4 for 80% quorum) -- check XAHAUD_NO_EXPORT_SIG config"
|
||||
)
|
||||
|
||||
# Should be tecEXPORT_EXPIRED (LLS reached without quorum)
|
||||
if engine_result != "tecEXPORT_EXPIRED":
|
||||
log(f"WARNING: expected tecEXPORT_EXPIRED, got {engine_result}")
|
||||
|
||||
log(f"Export failed as expected ({engine_result})")
|
||||
|
||||
retry_logs = ctx.assert_log(
|
||||
r"Export: insufficient signatures .*result=terRETRY_EXPORT",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export insufficient-signature retries: {retry_logs.count}")
|
||||
|
||||
expired_logs = ctx.assert_log(
|
||||
r"Export: last ledger expired .*result=tecEXPORT_EXPIRED",
|
||||
since=export_start,
|
||||
until=export_end,
|
||||
)
|
||||
log(f"Export LLS expiry logs: {expired_logs.count}")
|
||||
|
||||
# No shadow ticket should exist (export never reached quorum)
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=False)
|
||||
|
||||
# --- Verify subsequent payment works regardless ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Payment failed after expired export: {pay_engine} "
|
||||
f"-- sequence may be blocked"
|
||||
)
|
||||
|
||||
log("Payment succeeded -- account not permanently blocked")
|
||||
log("PASS")
|
||||
@@ -1,146 +0,0 @@
|
||||
"""Shared helpers for Export scenario tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from xahaud_scripts.testnet.config import feature_name_to_hash
|
||||
|
||||
|
||||
async def require_export(ctx, log):
|
||||
"""Wait for first ledger and assert Export is enabled."""
|
||||
await ctx.wait_for_ledger_close(timeout=120)
|
||||
feature = ctx.feature_check(feature_name_to_hash("Export"), node_id=0)
|
||||
if not feature or not feature.get("enabled", False):
|
||||
raise AssertionError(f"Export not enabled: {feature}")
|
||||
log("Export enabled")
|
||||
|
||||
|
||||
def find_export_txns(ctx, seq):
|
||||
"""Find Export transactions in a ledger.
|
||||
|
||||
Returns list of Export transaction dicts.
|
||||
"""
|
||||
result = ctx.ledger(seq, transactions=True)
|
||||
if not result:
|
||||
return []
|
||||
|
||||
txns = result.get("ledger", {}).get("transactions", [])
|
||||
return [tx for tx in txns if tx.get("TransactionType") == "Export"]
|
||||
|
||||
|
||||
def dst_param(address):
|
||||
"""Encode an address as a HookParameter entry for the DST param."""
|
||||
from xrpl.core.addresscodec import decode_classic_address
|
||||
|
||||
dst_hex = decode_classic_address(address).hex().upper()
|
||||
return {
|
||||
"HookParameter": {
|
||||
"HookParameterName": "445354", # "DST"
|
||||
"HookParameterValue": dst_hex,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def assert_hook_accepted(meta, log, *, expected_emits=1):
|
||||
"""Assert hook executed with ACCEPT and the expected emit count.
|
||||
|
||||
Checks sfHookExecutions in transaction metadata.
|
||||
Returns the hook execution entry for further inspection.
|
||||
"""
|
||||
hook_execs = meta.get("HookExecutions", [])
|
||||
if not hook_execs:
|
||||
raise AssertionError("No HookExecutions in metadata")
|
||||
|
||||
exec_entry = hook_execs[0].get("HookExecution", {})
|
||||
hook_result = exec_entry.get("HookResult", -1)
|
||||
emit_count = exec_entry.get("HookEmitCount", -1)
|
||||
return_code = exec_entry.get("HookReturnCode", "")
|
||||
|
||||
log(f" HookResult={hook_result} EmitCount={emit_count} ReturnCode={return_code}")
|
||||
|
||||
# HookResult 3 = ExitType::ACCEPT
|
||||
if hook_result != 3:
|
||||
raise AssertionError(
|
||||
f"Hook did not ACCEPT: HookResult={hook_result} "
|
||||
f"ReturnCode={return_code}"
|
||||
)
|
||||
|
||||
if emit_count != expected_emits:
|
||||
raise AssertionError(
|
||||
f"Expected {expected_emits} emits, got {emit_count}"
|
||||
)
|
||||
|
||||
# ReturnCode 0 = success; non-zero = ASSERT line number in hook
|
||||
if return_code and str(return_code) != "0":
|
||||
raise AssertionError(
|
||||
f"Hook returned error code {return_code} "
|
||||
f"(likely ASSERT failure at that line)"
|
||||
)
|
||||
|
||||
return exec_entry
|
||||
|
||||
|
||||
def assert_export_result(meta, log, *, require_signers=True):
|
||||
"""Assert ExportResult is present and well-formed in metadata.
|
||||
|
||||
Returns the ExportResult dict.
|
||||
"""
|
||||
export_result = meta.get("ExportResult", {})
|
||||
if not export_result:
|
||||
raise AssertionError("ExportResult not found in metadata")
|
||||
|
||||
# Must have LedgerSequence and TransactionHash
|
||||
if "LedgerSequence" not in export_result:
|
||||
raise AssertionError("ExportResult missing LedgerSequence")
|
||||
if "TransactionHash" not in export_result:
|
||||
raise AssertionError("ExportResult missing TransactionHash")
|
||||
|
||||
# Must have the inner ExportedTxn object
|
||||
inner = export_result.get("ExportedTxn", {})
|
||||
if not inner:
|
||||
raise AssertionError("ExportResult missing ExportedTxn (multisigned blob)")
|
||||
|
||||
log(f" ExportResult: seq={export_result['LedgerSequence']} "
|
||||
f"hash={export_result['TransactionHash'][:16]}...")
|
||||
|
||||
# Inner tx should have Account, Destination, TransactionType
|
||||
if "Account" not in inner:
|
||||
raise AssertionError("ExportedTxn missing Account")
|
||||
if "TransactionType" not in inner:
|
||||
raise AssertionError("ExportedTxn missing TransactionType")
|
||||
|
||||
# Should have empty SigningPubKey (multisigned)
|
||||
if inner.get("SigningPubKey", "NOT_EMPTY") != "":
|
||||
raise AssertionError(
|
||||
f"ExportedTxn SigningPubKey should be empty, "
|
||||
f"got '{inner.get('SigningPubKey')}'"
|
||||
)
|
||||
|
||||
if require_signers:
|
||||
signers = inner.get("Signers", [])
|
||||
if not signers:
|
||||
raise AssertionError("ExportedTxn has no Signers (multisig not applied)")
|
||||
log(f" Signers: {len(signers)} validator(s)")
|
||||
|
||||
return export_result
|
||||
|
||||
|
||||
def assert_shadow_ticket(ctx, account_address, log, *, expect_exists=True):
|
||||
"""Assert shadow ticket exists (or doesn't) for the account."""
|
||||
obj_result = ctx.rpc.request(
|
||||
0, "account_objects", {"account": account_address}
|
||||
)
|
||||
all_objects = (obj_result or {}).get("account_objects", [])
|
||||
shadow_tickets = [
|
||||
obj for obj in all_objects
|
||||
if obj.get("LedgerEntryType") == "ShadowTicket"
|
||||
]
|
||||
log(f" Shadow tickets: {len(shadow_tickets)}")
|
||||
|
||||
if expect_exists and not shadow_tickets:
|
||||
raise AssertionError("Expected shadow ticket but none found")
|
||||
if not expect_exists and shadow_tickets:
|
||||
raise AssertionError(
|
||||
f"Expected no shadow tickets but found {len(shadow_tickets)}"
|
||||
)
|
||||
|
||||
return shadow_tickets
|
||||
@@ -1,112 +0,0 @@
|
||||
""":descr: Test Export quorum behavior. When enough active validators sign,
|
||||
the export should succeed whether or not CE is enabled. When fewer than the
|
||||
active-view quorum sign, the export should expire.
|
||||
|
||||
Parameterized via `expect_success` kwarg from suite.yml.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT
|
||||
3. Verify result matches expectation (tesSUCCESS or tecEXPORT_EXPIRED)
|
||||
4. Verify ExportResult + shadow ticket on success, absence on failure
|
||||
5. Verify subsequent payment works regardless
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import (
|
||||
require_export,
|
||||
assert_export_result,
|
||||
assert_shadow_ticket,
|
||||
)
|
||||
|
||||
|
||||
async def scenario(ctx, log, expect_success=True):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
outcome = "success" if expect_success else "failure (below quorum)"
|
||||
log(f"Expecting export {outcome}")
|
||||
|
||||
# --- Submit ttEXPORT ---
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 8,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
final_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
meta = result.get("meta", {})
|
||||
|
||||
log(f"Export at ledger {final_seq}, result: {engine_result}")
|
||||
|
||||
if expect_success:
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Expected tesSUCCESS, got {engine_result}"
|
||||
)
|
||||
|
||||
# Assert ExportResult is well-formed with signers
|
||||
assert_export_result(meta, log, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
log("Export succeeded as expected (active-view quorum reached)")
|
||||
else:
|
||||
if engine_result == "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
"Export should NOT have succeeded below active-view quorum"
|
||||
)
|
||||
log(f"Export failed as expected ({engine_result})")
|
||||
|
||||
# No shadow ticket should exist
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=False)
|
||||
|
||||
# --- Verify subsequent payment works ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(f"Payment failed: {pay_engine}")
|
||||
|
||||
log("Payment succeeded -- account not blocked")
|
||||
log("PASS")
|
||||
@@ -1,94 +0,0 @@
|
||||
""":descr: Submit ttEXPORT directly (no hook), verify it succeeds with
|
||||
ExportResult in metadata. Then submit a payment from the same account
|
||||
to verify sequence handling doesn't block subsequent transactions.
|
||||
|
||||
Flow:
|
||||
1. Fund alice and bob
|
||||
2. alice submits ttEXPORT with inner payment -> tesSUCCESS (provisional)
|
||||
3. Validators attach sigs via proposals -> quorum -> ExportResult in metadata
|
||||
4. alice submits a Payment to bob -> should succeed (sequence not blocked)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import require_export, assert_export_result, assert_shadow_ticket
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
bob = ctx.account("bob")
|
||||
current_seq = ctx.validated_ledger_index(0)
|
||||
|
||||
log(f"Current ledger: {current_seq}")
|
||||
|
||||
# --- 1. Submit ttEXPORT ---
|
||||
result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Export",
|
||||
"LastLedgerSequence": current_seq + 15,
|
||||
"Fee": "1000000",
|
||||
"ExportedTxn": {
|
||||
"TransactionType": "Payment",
|
||||
"Account": alice.address,
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "10",
|
||||
"Sequence": 0,
|
||||
"TicketSequence": 1,
|
||||
"FirstLedgerSequence": current_seq + 1,
|
||||
"LastLedgerSequence": current_seq + 10,
|
||||
"Flags": 2147483648,
|
||||
"SigningPubKey": "",
|
||||
},
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
export_seq = ctx.validated_ledger_index(0)
|
||||
engine_result = result.get("engine_result", "")
|
||||
log(f"Export completed at ledger {export_seq}, result: {engine_result}")
|
||||
|
||||
if engine_result != "tesSUCCESS":
|
||||
raise AssertionError(
|
||||
f"Expected tesSUCCESS for export, got {engine_result}"
|
||||
)
|
||||
|
||||
# Assert ExportResult is well-formed with signers
|
||||
meta = result.get("meta", {})
|
||||
assert_export_result(meta, log, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
# --- 2. Submit Payment from same account ---
|
||||
log("Submitting payment from alice to bob...")
|
||||
pay_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": bob.address,
|
||||
"Amount": "1000000",
|
||||
"Fee": "12",
|
||||
},
|
||||
alice.wallet,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
pay_engine = pay_result.get("engine_result", "")
|
||||
log(f"Payment result: {pay_engine}")
|
||||
|
||||
if pay_engine != "tesSUCCESS":
|
||||
raise AssertionError(f"Payment failed: {pay_engine}")
|
||||
|
||||
log(
|
||||
f"Both transactions succeeded: "
|
||||
f"Export at ledger {export_seq}, Payment at ledger {ctx.validated_ledger_index(0)}"
|
||||
)
|
||||
log("Sequence handling OK - export didn't block subsequent txns")
|
||||
log("PASS")
|
||||
@@ -1,211 +0,0 @@
|
||||
""":descr: install xport hook, trigger export, verify emitted ttEXPORT lifecycle
|
||||
|
||||
1. Fund alice (hook holder), bob (trigger), carol (export destination)
|
||||
2. Install xport hook on alice
|
||||
3. bob pays alice with DST=carol → hook calls xport() → emits ttEXPORT
|
||||
4. Emitted ttEXPORT enters open ledger, validators attach sigs via proposals
|
||||
5. Verify Export transaction appears in a subsequent ledger
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from export_helpers import (
|
||||
require_export,
|
||||
find_export_txns,
|
||||
dst_param,
|
||||
assert_hook_accepted,
|
||||
assert_export_result,
|
||||
assert_shadow_ticket,
|
||||
)
|
||||
|
||||
# C source for the xport hook — verbatim from src/test/app/Export_test_hooks.h
|
||||
# On Payment to the hook account, exports a 1 XAH payment to the DST param.
|
||||
XPORT_HOOK_C = r"""
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t id, uint32_t maxiter);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t xport(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
extern int64_t xport_reserve(uint32_t count);
|
||||
extern int64_t hook_account(uint32_t write_ptr, uint32_t write_len);
|
||||
extern int64_t otxn_param(uint32_t write_ptr, uint32_t write_len, uint32_t name_ptr, uint32_t name_len);
|
||||
extern int64_t otxn_type(void);
|
||||
extern int64_t ledger_seq(void);
|
||||
|
||||
#define SBUF(x) (uint32_t)(x), sizeof(x)
|
||||
#define ASSERT(x) if (!(x)) rollback((uint32_t)#x, sizeof(#x), __LINE__)
|
||||
|
||||
#define ttPAYMENT 0
|
||||
#define tfCANONICAL 0x80000000UL
|
||||
#define amAMOUNT 1
|
||||
#define amFEE 8
|
||||
#define atACCOUNT 1
|
||||
#define atDESTINATION 3
|
||||
|
||||
#define ENCODE_TT(buf_out, tt) \
|
||||
buf_out[0] = 0x12U; buf_out[1] = (tt >> 8) & 0xFFU; buf_out[2] = tt & 0xFFU; buf_out += 3;
|
||||
|
||||
#define ENCODE_FLAGS(buf_out, flags) \
|
||||
buf_out[0] = 0x22U; buf_out[1] = (flags >> 24) & 0xFFU; buf_out[2] = (flags >> 16) & 0xFFU; \
|
||||
buf_out[3] = (flags >> 8) & 0xFFU; buf_out[4] = flags & 0xFFU; buf_out += 5;
|
||||
|
||||
#define ENCODE_SEQUENCE(buf_out, seq) \
|
||||
buf_out[0] = 0x24U; buf_out[1] = (seq >> 24) & 0xFFU; buf_out[2] = (seq >> 16) & 0xFFU; \
|
||||
buf_out[3] = (seq >> 8) & 0xFFU; buf_out[4] = seq & 0xFFU; buf_out += 5;
|
||||
|
||||
#define ENCODE_FLS(buf_out, fls) \
|
||||
buf_out[0] = 0x20U; buf_out[1] = 0x1AU; buf_out[2] = (fls >> 24) & 0xFFU; \
|
||||
buf_out[3] = (fls >> 16) & 0xFFU; buf_out[4] = (fls >> 8) & 0xFFU; \
|
||||
buf_out[5] = fls & 0xFFU; buf_out += 6;
|
||||
|
||||
#define ENCODE_LLS(buf_out, lls) \
|
||||
buf_out[0] = 0x20U; buf_out[1] = 0x1BU; buf_out[2] = (lls >> 24) & 0xFFU; \
|
||||
buf_out[3] = (lls >> 16) & 0xFFU; buf_out[4] = (lls >> 8) & 0xFFU; \
|
||||
buf_out[5] = lls & 0xFFU; buf_out += 6;
|
||||
|
||||
#define ENCODE_DROPS(buf_out, drops, amt_type) \
|
||||
buf_out[0] = 0x60U + amt_type; buf_out[1] = 0x40U + ((drops >> 56) & 0x3FU); \
|
||||
buf_out[2] = (drops >> 48) & 0xFFU; buf_out[3] = (drops >> 40) & 0xFFU; \
|
||||
buf_out[4] = (drops >> 32) & 0xFFU; buf_out[5] = (drops >> 24) & 0xFFU; \
|
||||
buf_out[6] = (drops >> 16) & 0xFFU; buf_out[7] = (drops >> 8) & 0xFFU; \
|
||||
buf_out[8] = drops & 0xFFU; buf_out += 9;
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_EMPTY(buf_out) \
|
||||
buf_out[0] = 0x73U; buf_out[1] = 0x00U; buf_out += 2;
|
||||
|
||||
#define ENCODE_ACCOUNT(buf_out, acc, acc_type) \
|
||||
buf_out[0] = 0x80U + acc_type; buf_out[1] = 0x14U; \
|
||||
for (int i = 0; i < 20; ++i) buf_out[2+i] = acc[i]; buf_out += 22;
|
||||
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
|
||||
|
||||
int64_t hook(uint32_t reserved) {
|
||||
_g(1, 1);
|
||||
|
||||
if (otxn_type() != ttPAYMENT)
|
||||
return accept(0, 0, 0);
|
||||
|
||||
ASSERT(xport_reserve(1) == 1);
|
||||
|
||||
uint8_t dst[20];
|
||||
int64_t dst_len = otxn_param(SBUF(dst), "DST", 3);
|
||||
ASSERT(dst_len == 20);
|
||||
|
||||
uint8_t acc[20];
|
||||
ASSERT(hook_account(SBUF(acc)) == 20);
|
||||
|
||||
uint32_t cls = (uint32_t)ledger_seq();
|
||||
|
||||
uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE];
|
||||
uint8_t* buf = tx;
|
||||
|
||||
ENCODE_TT(buf, ttPAYMENT);
|
||||
ENCODE_FLAGS(buf, tfCANONICAL);
|
||||
ENCODE_SEQUENCE(buf, 0);
|
||||
ENCODE_FLS(buf, cls + 1);
|
||||
ENCODE_LLS(buf, cls + 5);
|
||||
// sfTicketSequence = UINT32 field 41 = 0x20 0x29
|
||||
buf[0] = 0x20U; buf[1] = 0x29U;
|
||||
buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 1;
|
||||
buf += 6;
|
||||
|
||||
uint64_t drops = 1000000;
|
||||
ENCODE_DROPS(buf, drops, amAMOUNT);
|
||||
ENCODE_DROPS(buf, 10, amFEE);
|
||||
|
||||
ENCODE_SIGNING_PUBKEY_EMPTY(buf);
|
||||
ENCODE_ACCOUNT(buf, acc, atACCOUNT);
|
||||
ENCODE_ACCOUNT(buf, dst, atDESTINATION);
|
||||
|
||||
uint8_t hash[32];
|
||||
int64_t xport_result = xport(SBUF(hash), (uint32_t)tx, buf - tx);
|
||||
ASSERT(xport_result == 32);
|
||||
|
||||
return accept(0, 0, 0);
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
async def scenario(ctx, log):
|
||||
# Wait for network to start and amendments to activate
|
||||
await require_export(ctx, log)
|
||||
|
||||
# --- Setup ---
|
||||
await ctx.fund_accounts({"alice": 10000, "bob": 10000, "carol": 1000})
|
||||
log("Accounts funded")
|
||||
|
||||
alice = ctx.account("alice")
|
||||
carol = ctx.account("carol")
|
||||
|
||||
# Compile and install xport hook on alice
|
||||
wasm = ctx.compile_hook(XPORT_HOOK_C, label="xport")
|
||||
await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "SetHook",
|
||||
"Hooks": [
|
||||
{
|
||||
"Hook": {
|
||||
"CreateCode": wasm.hex().upper(),
|
||||
"HookOn": "0" * 64,
|
||||
"HookNamespace": "0" * 64,
|
||||
"HookApiVersion": 0,
|
||||
"Flags": 1, # hsfOVERRIDE
|
||||
}
|
||||
}
|
||||
],
|
||||
"Fee": "100000000",
|
||||
},
|
||||
alice.wallet,
|
||||
)
|
||||
log(
|
||||
f"Hook installed on alice ({alice.address[:12]}...) "
|
||||
f"ledger {ctx.validated_ledger_index(0)}"
|
||||
)
|
||||
|
||||
# --- Trigger ---
|
||||
# bob pays alice → hook calls xport() → emits ttEXPORT
|
||||
trigger_result = await ctx.submit_and_wait(
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Destination": alice.address,
|
||||
"Amount": "100000000",
|
||||
"Fee": "1000000",
|
||||
"HookParameters": [dst_param(carol.address)],
|
||||
},
|
||||
ctx.account("bob").wallet,
|
||||
)
|
||||
trigger_seq = ctx.validated_ledger_index(0)
|
||||
log(f"Export triggered at ledger {trigger_seq}")
|
||||
|
||||
# Assert hook fired with ACCEPT and emitted 1 tx
|
||||
trigger_meta = trigger_result.get("meta", {})
|
||||
assert_hook_accepted(trigger_meta, log, expected_emits=1)
|
||||
|
||||
# --- Verify: check each ledger close for the Export transaction ---
|
||||
max_ledgers = 10
|
||||
for i in range(max_ledgers):
|
||||
await ctx.wait_for_ledgers(1, node_id=0, timeout=30)
|
||||
seq = ctx.validated_ledger_index(0)
|
||||
exports = find_export_txns(ctx, seq)
|
||||
if exports:
|
||||
export_tx = exports[0]
|
||||
meta = export_tx.get("meta", export_tx.get("metaData", {}))
|
||||
result = meta.get("TransactionResult", "")
|
||||
log(f"Ledger {seq}: Export txn found, result={result}")
|
||||
|
||||
if result != "tesSUCCESS":
|
||||
raise AssertionError(f"Export did not succeed: {result}")
|
||||
|
||||
# Assert ExportResult is well-formed with signers and inner tx
|
||||
assert_export_result(meta, log, require_signers=True)
|
||||
|
||||
# Assert shadow ticket was created
|
||||
assert_shadow_ticket(ctx, alice.address, log, expect_exists=True)
|
||||
|
||||
log("PASS")
|
||||
return
|
||||
log(f"Ledger {seq}: no Export txn yet")
|
||||
|
||||
raise AssertionError(
|
||||
f"No Export transaction found after {max_ledgers} ledger closes"
|
||||
)
|
||||
@@ -1,91 +0,0 @@
|
||||
"""Shared helpers for ConsensusEntropy scenario tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from xahaud_scripts.testnet.config import feature_name_to_hash
|
||||
|
||||
ZERO_DIGEST = "0" * 64
|
||||
CONSENSUS_ENTROPY_FEATURE = feature_name_to_hash("ConsensusEntropy")
|
||||
|
||||
|
||||
def feature_hash(name: str) -> str:
|
||||
"""Return the amendment hash accepted by feature RPC."""
|
||||
return feature_name_to_hash(name)
|
||||
|
||||
|
||||
def feature_status(ctx, name: str, node_id=0):
|
||||
"""Query a feature by amendment hash; feature RPC names are ambiguous."""
|
||||
return ctx.feature_check(feature_hash(name), node_id=node_id)
|
||||
|
||||
|
||||
def consensus_entropy_feature(ctx, node_id=0):
|
||||
"""Query ConsensusEntropy by amendment hash."""
|
||||
return feature_status(ctx, "ConsensusEntropy", node_id=node_id)
|
||||
|
||||
|
||||
async def require_entropy(ctx, log):
|
||||
"""Wait for first ledger and assert ConsensusEntropy is enabled."""
|
||||
await ctx.wait_for_ledger_close(timeout=120)
|
||||
feature = consensus_entropy_feature(ctx, node_id=0)
|
||||
if not feature or not feature.get("enabled", False):
|
||||
raise AssertionError(f"ConsensusEntropy not enabled: {feature}")
|
||||
log("ConsensusEntropy enabled")
|
||||
|
||||
|
||||
def get_entropy_tx(ctx, seq):
|
||||
"""Fetch ledger and return (ce_tx, user_txns) or raise."""
|
||||
result = ctx.ledger(seq, transactions=True)
|
||||
if not result:
|
||||
raise AssertionError(f"Ledger {seq}: fetch failed")
|
||||
|
||||
ledger = result.get("ledger")
|
||||
if not isinstance(ledger, dict):
|
||||
raise AssertionError(f"Ledger {seq}: fetch returned no ledger: {result}")
|
||||
|
||||
txns = ledger.get("transactions", [])
|
||||
ce = [tx for tx in txns if tx.get("TransactionType") == "ConsensusEntropy"]
|
||||
user = [tx for tx in txns if tx.get("TransactionType") != "ConsensusEntropy"]
|
||||
|
||||
if len(ce) != 1:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: expected 1 ConsensusEntropy txn, got {len(ce)}"
|
||||
)
|
||||
|
||||
return ce[0], user
|
||||
|
||||
|
||||
def entropy_fields(ce_tx):
|
||||
"""Return (digest, entropy_count, is_fallback) from a ConsensusEntropy tx.
|
||||
|
||||
Tier 3: fallback rounds carry a deterministic non-zero consensus-bound
|
||||
digest with EntropyCount=0 and EntropyTier=1 (consensus_fallback).
|
||||
Validator entropy has EntropyTier=3 (validator_quorum).
|
||||
"""
|
||||
digest = ce_tx.get("Digest", "")
|
||||
entropy_count = ce_tx.get("EntropyCount", -1)
|
||||
tier = ce_tx.get("EntropyTier", None)
|
||||
if tier is not None:
|
||||
is_fallback = tier != 3
|
||||
else:
|
||||
is_fallback = entropy_count == 0
|
||||
return digest, entropy_count, is_fallback
|
||||
|
||||
|
||||
def assert_valid_entropy(ce_tx, seq, seen_digests=None):
|
||||
"""Assert quorum-met validator entropy. Optionally check uniqueness."""
|
||||
digest, entropy_count, is_fallback = entropy_fields(ce_tx)
|
||||
|
||||
if is_fallback or not digest or digest == ZERO_DIGEST:
|
||||
raise AssertionError(f"Ledger {seq}: fallback/empty Digest")
|
||||
|
||||
if entropy_count < 4:
|
||||
raise AssertionError(
|
||||
f"Ledger {seq}: EntropyCount={entropy_count} < 4 (sub-quorum)"
|
||||
)
|
||||
|
||||
if seen_digests is not None:
|
||||
if digest in seen_digests:
|
||||
raise AssertionError(f"Ledger {seq}: duplicate Digest {digest[:16]}...")
|
||||
seen_digests.add(digest)
|
||||
|
||||
return digest, entropy_count
|
||||
@@ -1,45 +0,0 @@
|
||||
defaults:
|
||||
network:
|
||||
node_count: 5
|
||||
launcher: tmux
|
||||
find_ports: true
|
||||
slave_delay: 0.2
|
||||
features:
|
||||
- ConsensusEntropy
|
||||
track_features:
|
||||
- ConsensusEntropy
|
||||
log_levels:
|
||||
TxQ: info
|
||||
Protocol: debug
|
||||
Peer: debug
|
||||
LedgerConsensus: debug
|
||||
ConsensusExtensions: debug
|
||||
NetworkOPs: info
|
||||
env:
|
||||
XAHAU_RESOURCE_PER_PORT: "1"
|
||||
XAHAU_RNG_POLL_MS: "333"
|
||||
|
||||
tests:
|
||||
- name: steady_state_entropy
|
||||
script: .testnet/scenarios/entropy/steady_state_entropy.py
|
||||
|
||||
- name: steady_state_entropy_fast_start
|
||||
script: .testnet/scenarios/entropy/steady_state_entropy.py
|
||||
network:
|
||||
env:
|
||||
XAHAUD_BOOTSTRAP_FAST_START: "1"
|
||||
|
||||
- name: entropy_with_transactions
|
||||
script: .testnet/scenarios/entropy/entropy_with_transactions.py
|
||||
|
||||
- name: quorum_recovery_smoke
|
||||
script: .testnet/scenarios/entropy/quorum_recovery_smoke.py
|
||||
|
||||
- name: quorum_degradation_smoke
|
||||
script: .testnet/scenarios/entropy/quorum_degradation_smoke.py
|
||||
network:
|
||||
log_levels:
|
||||
LedgerConsensus: trace
|
||||
ConsensusExtensions: trace
|
||||
|
||||
# Export scenarios: see export-suite.yml
|
||||
@@ -12,7 +12,6 @@ libxrpl.server > xrpl.basics
|
||||
libxrpl.server > xrpl.json
|
||||
libxrpl.server > xrpl.protocol
|
||||
libxrpl.server > xrpl.server
|
||||
test.app > test.shamap
|
||||
test.app > test.toplevel
|
||||
test.app > test.unit_test
|
||||
test.app > xrpl.basics
|
||||
@@ -44,7 +43,6 @@ test.consensus > xrpld.app
|
||||
test.consensus > xrpld.consensus
|
||||
test.consensus > xrpld.core
|
||||
test.consensus > xrpld.ledger
|
||||
test.consensus > xrpl.json
|
||||
test.consensus > xrpl.protocol
|
||||
test.core > test.jtx
|
||||
test.core > test.toplevel
|
||||
@@ -86,7 +84,6 @@ test.nodestore > xrpl.basics
|
||||
test.nodestore > xrpld.core
|
||||
test.nodestore > xrpld.nodestore
|
||||
test.nodestore > xrpld.unity
|
||||
test.nodestore > xrpl.protocol
|
||||
test.overlay > test.jtx
|
||||
test.overlay > test.toplevel
|
||||
test.overlay > test.unit_test
|
||||
@@ -121,7 +118,6 @@ test.rpc > xrpld.core
|
||||
test.rpc > xrpld.net
|
||||
test.rpc > xrpld.overlay
|
||||
test.rpc > xrpld.rpc
|
||||
test.rpc > xrpld.shamap
|
||||
test.rpc > xrpl.hook
|
||||
test.rpc > xrpl.json
|
||||
test.rpc > xrpl.protocol
|
||||
@@ -154,6 +150,7 @@ xrpl.resource > xrpl.protocol
|
||||
xrpl.server > xrpl.basics
|
||||
xrpl.server > xrpl.json
|
||||
xrpl.server > xrpl.protocol
|
||||
xrpld.app > quickjs.toplevel
|
||||
xrpld.app > test.unit_test
|
||||
xrpld.app > xrpl.basics
|
||||
xrpld.app > xrpld.conditions
|
||||
|
||||
@@ -145,6 +145,8 @@ target_link_libraries(ripple_libs INTERFACE
|
||||
SQLite::SQLite3
|
||||
)
|
||||
|
||||
include(deps/quickjs)
|
||||
|
||||
if(coverage)
|
||||
include(RippledCov)
|
||||
endif()
|
||||
|
||||
@@ -12,16 +12,17 @@ echo "-- GITHUB_REPOSITORY: $1"
|
||||
echo "-- GITHUB_SHA: $2"
|
||||
echo "-- GITHUB_RUN_NUMBER: $4"
|
||||
|
||||
umask 0000
|
||||
umask 0000;
|
||||
|
||||
####
|
||||
|
||||
cd /io
|
||||
mkdir -p src/certs
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h
|
||||
if [ "$(grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l)" -eq "0" ]; then
|
||||
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
|
||||
perl -i -pe "s/^{/{
|
||||
cd /io;
|
||||
mkdir -p src/certs;
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h;
|
||||
if [ "`grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l`" -eq "0" ]
|
||||
then
|
||||
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
|
||||
perl -i -pe "s/^{/{
|
||||
#ifdef EMBEDDED_CA_BUNDLE
|
||||
BIO *cbio = BIO_new_mem_buf(ca_bundle.data(), ca_bundle.size());
|
||||
X509_STORE *cts = SSL_CTX_get_cert_store(ctx.native_handle());
|
||||
@@ -67,14 +68,15 @@ fi
|
||||
source /opt/rh/gcc-toolset-11/enable
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
export CC='/usr/lib64/ccache/gcc' &&
|
||||
export CXX='/usr/lib64/ccache/g++' &&
|
||||
echo "-- Build Rippled --" &&
|
||||
pwd &&
|
||||
echo "MOVING TO [ build-core.sh ]"
|
||||
export CXX='/usr/lib64/ccache/g++' &&
|
||||
echo "-- Build Rippled --" &&
|
||||
pwd &&
|
||||
|
||||
printenv >.env.temp
|
||||
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g | sed s/\$/\\\"/g >.env
|
||||
rm .env.temp
|
||||
echo "MOVING TO [ build-core.sh ]";
|
||||
|
||||
printenv > .env.temp;
|
||||
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g|sed s/\$/\\\"/g > .env;
|
||||
rm .env.temp;
|
||||
|
||||
echo "Persisting ENV:"
|
||||
cat .env
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
"3C43D9A973AA4443EF3FC38E42DD306160FBFFDAB901CD8BAA15D09F2597EB87",
|
||||
"0285B7E5E08E1A8E4C15636F0591D87F73CB6A7B6452A932AD72BBC8E5D1CBE3",
|
||||
"6E739F4F8B07BED29FC9FF440DA3C301CD14A180DF45819F658FEC2F7DE31427",
|
||||
"36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6"
|
||||
"36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6",
|
||||
"DD4F86291F142A20761B32B4D0CE4291F86CA33F0B46F0D04171482FBA52E536"
|
||||
],
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Amendments",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# standalone: ./xahaud -a --ledgerfile config/genesis.json --conf config/xahaud-standalone.cfg
|
||||
# standalone: ./xahaud -a --ledgerfile cfg/genesis.json --conf cfg/xahaud-standalone.cfg
|
||||
[server]
|
||||
port_rpc_admin_local
|
||||
port_ws_public
|
||||
@@ -154,3 +154,4 @@ D686F2538F410C9D0D856788E98E3579595DAF7B38D38887F81ECAC934B06040 HooksUpdate1
|
||||
EDB4EE4C524E16BDD91D9A529332DED08DCAAA51CC6DC897ACFA1A0ED131C5B6 fix240819
|
||||
8063140E9260799D6716756B891CEC3E7006C4E4F277AB84670663A88F94B9C4 fixPageCap
|
||||
88693F108C3CD8A967F3F4253A32DEF5E35F9406ACD2A11B88B11D90865763A9 fix240911
|
||||
DD4F86291F142A20761B32B4D0CE4291F86CA33F0B46F0D04171482FBA52E536 JsHooks
|
||||
|
||||
@@ -95,9 +95,6 @@
|
||||
# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr
|
||||
# - add support for all gcovr output formats
|
||||
#
|
||||
# 2024-04-03, Bronek Kozicki
|
||||
# - add support for output formats: jacoco, clover, lcov
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Copy this file into your cmake modules path.
|
||||
@@ -259,10 +256,10 @@ endif()
|
||||
# BASE_DIRECTORY "../" # Base directory for report
|
||||
# # (defaults to PROJECT_SOURCE_DIR)
|
||||
# FORMAT "cobertura" # Output format, one of:
|
||||
# # xml cobertura sonarqube jacoco clover
|
||||
# # json-summary json-details coveralls csv
|
||||
# # txt html-single html-nested html-details
|
||||
# # lcov (xml is an alias to cobertura;
|
||||
# # xml cobertura sonarqube json-summary
|
||||
# # json-details coveralls csv txt
|
||||
# # html-single html-nested html-details
|
||||
# # (xml is an alias to cobertura;
|
||||
# # if no format is set, defaults to xml)
|
||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||
@@ -311,8 +308,6 @@ function(setup_target_for_coverage_gcovr)
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt)
|
||||
elseif(Coverage_FORMAT STREQUAL "csv")
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv)
|
||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov)
|
||||
else()
|
||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml)
|
||||
endif()
|
||||
@@ -325,14 +320,6 @@ function(setup_target_for_coverage_gcovr)
|
||||
set(Coverage_FORMAT cobertura) # overwrite xml
|
||||
elseif(Coverage_FORMAT STREQUAL "sonarqube")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" )
|
||||
elseif(Coverage_FORMAT STREQUAL "jacoco")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty )
|
||||
elseif(Coverage_FORMAT STREQUAL "clover")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty )
|
||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" )
|
||||
elseif(Coverage_FORMAT STREQUAL "json-summary")
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" )
|
||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty)
|
||||
|
||||
@@ -58,6 +58,7 @@ target_link_libraries(xrpl.imports.main
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
wasmedge::wasmedge
|
||||
NIH::quickjs
|
||||
Ripple::opts
|
||||
Ripple::syslibs
|
||||
absl::random_random
|
||||
|
||||
@@ -6,6 +6,7 @@ include(create_symbolic_link)
|
||||
|
||||
install (
|
||||
TARGETS
|
||||
quickjs
|
||||
common
|
||||
opts
|
||||
ripple_syslibs
|
||||
|
||||
@@ -22,9 +22,6 @@ target_compile_definitions (opts
|
||||
$<$<BOOL:${beast_no_unit_test_inline}>:BEAST_NO_UNIT_TEST_INLINE=1>
|
||||
$<$<BOOL:${beast_disable_autolink}>:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1>
|
||||
$<$<BOOL:${single_io_service_thread}>:RIPPLE_SINGLE_IO_SERVICE_THREAD=1>
|
||||
# Enhanced logging is enabled for Debug builds, or explicitly via
|
||||
# -DBEAST_ENHANCED_LOGGING=ON for other build types.
|
||||
$<$<OR:$<CONFIG:Debug>,$<BOOL:${BEAST_ENHANCED_LOGGING}>>:BEAST_ENHANCED_LOGGING=1>
|
||||
$<$<BOOL:${voidstar}>:ENABLE_VOIDSTAR>)
|
||||
target_compile_options (opts
|
||||
INTERFACE
|
||||
|
||||
52
cmake/deps/quickjs.cmake
Normal file
52
cmake/deps/quickjs.cmake
Normal file
@@ -0,0 +1,52 @@
|
||||
# QuickJS source files
|
||||
set(QUICKJS_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/libutf.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/qsort_r.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/tutf8e.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/vector.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/char-utils.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/buffer-utils.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/utils.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/ringbuffer.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/libregexp.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/quickjs.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/libregexp.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/libunicode.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/cutils.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/quickjs-libc.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/libbf.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/quickjs-textcode.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/quickjs-internal.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/debug.c
|
||||
)
|
||||
|
||||
# QuickJS include directories
|
||||
set(QUICKJS_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs)
|
||||
|
||||
# RHTODO: Fix this to be dynamic
|
||||
set(QUICKJS_VERSION "2023-01-01")
|
||||
|
||||
# QuickJS compile definitions
|
||||
set(QUICKJS_COMPILE_DEFINITIONS
|
||||
_GNU_SOURCE
|
||||
CONFIG_VERSION="${QUICKJS_VERSION}"
|
||||
CONFIG_BIGNUM
|
||||
)
|
||||
|
||||
# Create static library
|
||||
add_library(quickjs STATIC ${QUICKJS_SOURCES})
|
||||
target_include_directories(quickjs
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${QUICKJS_INCLUDE_DIRS}>
|
||||
$<INSTALL_INTERFACE:include/quickjs>
|
||||
)
|
||||
target_compile_definitions(quickjs PUBLIC ${QUICKJS_COMPILE_DEFINITIONS})
|
||||
|
||||
add_library(NIH::quickjs ALIAS quickjs)
|
||||
target_link_libraries(ripple_libs INTERFACE NIH::quickjs)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/quickjs/*.h
|
||||
DESTINATION include/quickjs
|
||||
)
|
||||
@@ -47,8 +47,5 @@
|
||||
#define MEM_OVERLAP -43
|
||||
#define TOO_MANY_STATE_MODIFICATIONS -44
|
||||
#define TOO_MANY_NAMESPACES -45
|
||||
#define EXPORT_FAILURE -46
|
||||
#define TOO_MANY_EXPORTED_TXN -47
|
||||
#define TOO_LITTLE_ENTROPY -48
|
||||
#define HOOK_ERROR_CODES
|
||||
#endif //HOOK_ERROR_CODES
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Generated using generate_extern.sh
|
||||
#include <stdint.h>
|
||||
#ifndef HOOK_EXTERN
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int32_t __attribute__((noduplicate))
|
||||
_g(uint32_t guard_id, uint32_t maxiter);
|
||||
@@ -339,31 +336,5 @@ prepare(
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
xport_reserve(uint32_t count);
|
||||
|
||||
extern int64_t
|
||||
xport(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
xport_cancel(uint32_t ticket_seq);
|
||||
|
||||
extern int64_t
|
||||
dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
|
||||
extern int64_t
|
||||
random(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t min_tier,
|
||||
uint32_t min_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#define HOOK_EXTERN
|
||||
#endif // HOOK_EXTERN
|
||||
|
||||
@@ -9,7 +9,7 @@ ENUM_FILE="$SCRIPT_DIR/../include/xrpl/hook/Enum.h"
|
||||
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
|
||||
echo '// Generated using generate_error.sh'
|
||||
echo '#ifndef HOOK_ERROR_CODES'
|
||||
sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
awk '
|
||||
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
|
||||
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
|
||||
@@ -31,7 +31,7 @@ sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||
|
||||
{
|
||||
line = $0
|
||||
if (line ~ /enum[[:space:]]+class[[:space:]]+hook_return_code/)
|
||||
if (line ~ /enum[[:space:]]+hook_return_code/)
|
||||
next
|
||||
if (line ~ /^[[:space:]]*\{/)
|
||||
next
|
||||
|
||||
@@ -11,9 +11,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
echo '// Generated using generate_extern.sh'
|
||||
echo '#include <stdint.h>'
|
||||
echo '#ifndef HOOK_EXTERN'
|
||||
echo '#ifdef __cplusplus'
|
||||
echo 'extern "C" {'
|
||||
echo '#endif'
|
||||
echo
|
||||
awk '
|
||||
function trim(s) {
|
||||
@@ -30,8 +27,8 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
next;
|
||||
}
|
||||
|
||||
# Look for comment lines that start with // and contain function signature
|
||||
if (line ~ /^[[:space:]]*\/\/[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]+[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]*\(/) {
|
||||
# Look for comment lines that start with // int64_t or // int32_t
|
||||
if (line ~ /^[[:space:]]*\/\/[[:space:]]*(int64_t|int32_t)[[:space:]]+[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]*\(/) {
|
||||
# Remove leading // and trim
|
||||
sub(/^[[:space:]]*\/\/[[:space:]]*/, "", line);
|
||||
line = trim(line);
|
||||
@@ -49,9 +46,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
}
|
||||
' "$APPLY_HOOK"
|
||||
|
||||
echo '#ifdef __cplusplus'
|
||||
echo '}'
|
||||
echo '#endif'
|
||||
echo '#define HOOK_EXTERN'
|
||||
echo '#endif // HOOK_EXTERN'
|
||||
} | (
|
||||
|
||||
@@ -630,7 +630,7 @@ int out_len = 0;\
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
@@ -661,8 +661,11 @@ int out_len = 0;\
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
|
||||
etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
|
||||
#define sfHookResult ((16U << 16U) + 18U)
|
||||
#define sfWasLockingChainSend ((16U << 16U) + 19U)
|
||||
#define sfSidecarType ((16U << 16U) + 20U)
|
||||
#define sfEntropyTier ((16U << 16U) + 21U)
|
||||
#define sfLedgerEntryType ((1U << 16U) + 1U)
|
||||
#define sfTransactionType ((1U << 16U) + 2U)
|
||||
#define sfSignerWeight ((1U << 16U) + 3U)
|
||||
@@ -24,8 +22,6 @@
|
||||
#define sfHookApiVersion ((1U << 16U) + 20U)
|
||||
#define sfHookStateScale ((1U << 16U) + 21U)
|
||||
#define sfLedgerFixType ((1U << 16U) + 22U)
|
||||
#define sfHookExportCount ((1U << 16U) + 98U)
|
||||
#define sfEntropyCount ((1U << 16U) + 99U)
|
||||
#define sfNetworkID ((2U << 16U) + 1U)
|
||||
#define sfFlags ((2U << 16U) + 2U)
|
||||
#define sfSourceTag ((2U << 16U) + 3U)
|
||||
@@ -84,7 +80,6 @@
|
||||
#define sfRewardTime ((2U << 16U) + 98U)
|
||||
#define sfRewardLgrFirst ((2U << 16U) + 99U)
|
||||
#define sfRewardLgrLast ((2U << 16U) + 100U)
|
||||
#define sfCancelTicketSequence ((2U << 16U) + 101U)
|
||||
#define sfIndexNext ((3U << 16U) + 1U)
|
||||
#define sfIndexPrevious ((3U << 16U) + 2U)
|
||||
#define sfBookNode ((3U << 16U) + 3U)
|
||||
@@ -164,7 +159,6 @@
|
||||
#define sfEmittedTxnID ((5U << 16U) + 97U)
|
||||
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
||||
#define sfGovernanceFlags ((5U << 16U) + 99U)
|
||||
#define sfEntropyDigest ((5U << 16U) + 100U)
|
||||
#define sfNumber ((9U << 16U) + 1U)
|
||||
#define sfAmount ((6U << 16U) + 1U)
|
||||
#define sfBalance ((6U << 16U) + 2U)
|
||||
@@ -195,7 +189,6 @@
|
||||
#define sfSignatureReward ((6U << 16U) + 29U)
|
||||
#define sfMinAccountCreateAmount ((6U << 16U) + 30U)
|
||||
#define sfLPTokenBalance ((6U << 16U) + 31U)
|
||||
#define sfTrustLineRewardAccumulator ((6U << 16U) + 99U)
|
||||
#define sfPublicKey ((7U << 16U) + 1U)
|
||||
#define sfMessageKey ((7U << 16U) + 2U)
|
||||
#define sfSigningPubKey ((7U << 16U) + 3U)
|
||||
@@ -227,7 +220,6 @@
|
||||
#define sfProvider ((7U << 16U) + 30U)
|
||||
#define sfMPTokenMetadata ((7U << 16U) + 31U)
|
||||
#define sfCredentialType ((7U << 16U) + 32U)
|
||||
#define sfHookName ((7U << 16U) + 97U)
|
||||
#define sfRemarkValue ((7U << 16U) + 98U)
|
||||
#define sfRemarkName ((7U << 16U) + 99U)
|
||||
#define sfAccount ((8U << 16U) + 1U)
|
||||
@@ -263,7 +255,6 @@
|
||||
#define sfIssuingChainIssue ((24U << 16U) + 2U)
|
||||
#define sfAsset ((24U << 16U) + 3U)
|
||||
#define sfAsset2 ((24U << 16U) + 4U)
|
||||
#define sfClaimCurrency ((24U << 16U) + 5U)
|
||||
#define sfXChainBridge ((25U << 16U) + 1U)
|
||||
#define sfTransactionMetaData ((14U << 16U) + 2U)
|
||||
#define sfCreatedNode ((14U << 16U) + 3U)
|
||||
@@ -294,7 +285,6 @@
|
||||
#define sfXChainCreateAccountAttestationCollectionElement ((14U << 16U) + 31U)
|
||||
#define sfPriceData ((14U << 16U) + 32U)
|
||||
#define sfCredential ((14U << 16U) + 33U)
|
||||
#define sfExportedTxn ((14U << 16U) + 90U)
|
||||
#define sfAmountEntry ((14U << 16U) + 91U)
|
||||
#define sfMintURIToken ((14U << 16U) + 92U)
|
||||
#define sfHookEmission ((14U << 16U) + 93U)
|
||||
@@ -302,9 +292,6 @@
|
||||
#define sfActiveValidator ((14U << 16U) + 95U)
|
||||
#define sfGenesisMint ((14U << 16U) + 96U)
|
||||
#define sfRemark ((14U << 16U) + 97U)
|
||||
#define sfHighReward ((14U << 16U) + 98U)
|
||||
#define sfLowReward ((14U << 16U) + 99U)
|
||||
#define sfExportResult ((14U << 16U) + 100U)
|
||||
#define sfSigners ((15U << 16U) + 3U)
|
||||
#define sfSignerEntries ((15U << 16U) + 4U)
|
||||
#define sfTemplate ((15U << 16U) + 5U)
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#define ttNFTOKEN_MODIFY 70
|
||||
#define ttPERMISSIONED_DOMAIN_SET 71
|
||||
#define ttPERMISSIONED_DOMAIN_DELETE 72
|
||||
#define ttEXPORT 91
|
||||
#define ttCRON 92
|
||||
#define ttCRON_SET 93
|
||||
#define ttREMARKS_SET 94
|
||||
@@ -75,4 +74,3 @@
|
||||
#define ttUNL_MODIFY 102
|
||||
#define ttEMIT_FAILURE 103
|
||||
#define ttUNL_REPORT 104
|
||||
#define ttCONSENSUS_ENTROPY 105
|
||||
|
||||
@@ -115,8 +115,3 @@ enum AMMClawbackFlags : uint32_t {
|
||||
enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
|
||||
enum ConsensusEntropyFlags : uint32_t {
|
||||
tfEntropyCommit = 0x00000001, // entry is a commitment in commitSet
|
||||
tfEntropyReveal = 0x00000002, // entry is a reveal in entropySet
|
||||
};
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
#define uint256 std::string
|
||||
#define featureHooksUpdate1 "1"
|
||||
#define featureHooksUpdate2 "1"
|
||||
#define featureExport "1"
|
||||
#define featureConsensusEntropy "1"
|
||||
#define fix20250131 "1"
|
||||
#define fixGuardDepth32 "1"
|
||||
namespace hook_api {
|
||||
struct Rules
|
||||
{
|
||||
@@ -267,8 +264,11 @@ enum hook_log_code : uint16_t {
|
||||
SECTIONS_OUT_OF_SEQUENCE =
|
||||
85, // the wasm contained sections out of sequence
|
||||
CUSTOM_SECTION_DISALLOWED =
|
||||
86, // the wasm contained a custom section (id=0)
|
||||
INTERNAL_ERROR = 87, // an internal error described by the log text
|
||||
86, // the wasm contained a custom section (id=0)
|
||||
INTERNAL_ERROR = 87, // an internal error described by the log text
|
||||
JS_TEST_FAILURE = 88, // smoke test of js bytecode failed
|
||||
JS_FEE_MISSING = 89,
|
||||
JS_FEE_OUT_OF_RANGE = 90,
|
||||
// RH NOTE: only HookSet msgs got log codes, possibly all Hook log lines
|
||||
// should get a code?
|
||||
};
|
||||
@@ -322,7 +322,7 @@ namespace compare_mode {
|
||||
enum compare_mode : uint32_t { EQUAL = 1, LESS = 2, GREATER = 4 };
|
||||
}
|
||||
|
||||
enum class hook_return_code : int64_t {
|
||||
enum hook_return_code : int64_t {
|
||||
SUCCESS =
|
||||
0, // return codes > 0 are reserved for hook apis to return "success"
|
||||
OUT_OF_BOUNDS =
|
||||
@@ -386,24 +386,29 @@ enum class hook_return_code : int64_t {
|
||||
MEM_OVERLAP = -43, // one or more specified buffers are the same memory
|
||||
TOO_MANY_STATE_MODIFICATIONS = -44, // more than 5000 modified state
|
||||
// entires in the combined hook chains
|
||||
TOO_MANY_NAMESPACES = -45,
|
||||
EXPORT_FAILURE = -46,
|
||||
TOO_MANY_EXPORTED_TXN = -47,
|
||||
TOO_LITTLE_ENTROPY = -48,
|
||||
TOO_MANY_NAMESPACES = -45
|
||||
};
|
||||
|
||||
enum class ExitType : uint8_t {
|
||||
enum ExitType : uint8_t {
|
||||
UNSET = 0,
|
||||
WASM_ERROR = 1,
|
||||
ROLLBACK = 2,
|
||||
ACCEPT = 3,
|
||||
JSVM_ERROR = 4,
|
||||
LEDGER_ERROR =
|
||||
5, // if the ledger contained for example a nonsense hookapi number
|
||||
INSTRUCTION_LIMIT_REACHED = 6,
|
||||
};
|
||||
|
||||
enum CodeType : uint8_t {
|
||||
WASM = 0,
|
||||
JS = 1,
|
||||
};
|
||||
|
||||
const uint16_t max_state_modifications = 256;
|
||||
const uint8_t max_slots = 255;
|
||||
const uint8_t max_nonce = 255;
|
||||
const uint8_t max_emit = 255;
|
||||
const uint8_t max_export = 2;
|
||||
const uint8_t max_params = 16;
|
||||
const double fee_base_multiplier = 1.1f;
|
||||
|
||||
@@ -431,6 +436,10 @@ getImportWhitelist(Rules const& rules)
|
||||
if (AMENDMENT == uint256{} || rules.enabled(AMENDMENT)) \
|
||||
whitelist[#FUNCTION_NAME] = { \
|
||||
RETURN_TYPE, HOOK_WRAP_PARAMS PARAMS_TUPLE};
|
||||
#define JSHOOK_API_DEFINITION( \
|
||||
RETURN_TYPE, FUNCTION_NAME, PARAMS_TUPLE, AMENDMENT) \
|
||||
{ \
|
||||
}
|
||||
|
||||
#include "hook_api.macro"
|
||||
|
||||
@@ -444,9 +453,12 @@ getImportWhitelist(Rules const& rules)
|
||||
return whitelist;
|
||||
}
|
||||
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef I32
|
||||
#undef I64
|
||||
|
||||
enum GuardRulesVersion : uint64_t {
|
||||
GuardRuleFix20250131 = 0x00000001,
|
||||
GuardRuleDepth32 = 0x00000002,
|
||||
};
|
||||
|
||||
inline uint64_t
|
||||
@@ -455,8 +467,6 @@ getGuardRulesVersion(Rules const& rules)
|
||||
uint64_t version = 0;
|
||||
if (rules.enabled(fix20250131))
|
||||
version |= GuardRuleFix20250131;
|
||||
if (rules.enabled(fixGuardDepth32))
|
||||
version |= GuardRuleDepth32;
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,13 +204,9 @@ struct WasmBlkInf
|
||||
}
|
||||
// compute worst case execution time
|
||||
inline uint64_t
|
||||
compute_wce(
|
||||
const WasmBlkInf* blk,
|
||||
int level,
|
||||
int max_level,
|
||||
bool* recursion_limit_reached)
|
||||
compute_wce(const WasmBlkInf* blk, int level, bool* recursion_limit_reached)
|
||||
{
|
||||
if (level > max_level)
|
||||
if (level > 16)
|
||||
{
|
||||
*recursion_limit_reached = true;
|
||||
return 0;
|
||||
@@ -237,8 +233,8 @@ compute_wce(
|
||||
|
||||
if (blk->children.size() > 0)
|
||||
for (auto const& child : blk->children)
|
||||
worst_case_execution += compute_wce(
|
||||
child, level + 1, max_level, recursion_limit_reached);
|
||||
worst_case_execution +=
|
||||
compute_wce(child, level + 1, recursion_limit_reached);
|
||||
|
||||
if (parent == 0 ||
|
||||
parent->iteration_bound ==
|
||||
@@ -792,17 +788,12 @@ check_guard(
|
||||
}
|
||||
|
||||
bool recursion_limit_reached = false;
|
||||
int max_level = 16;
|
||||
if (rulesVersion & hook_api::GuardRuleDepth32)
|
||||
max_level = 32;
|
||||
uint64_t wce =
|
||||
compute_wce(&(*root), 0, max_level, &recursion_limit_reached);
|
||||
uint64_t wce = compute_wce(&(*root), 0, &recursion_limit_reached);
|
||||
if (recursion_limit_reached)
|
||||
{
|
||||
GUARDLOG(hook::log::NESTING_LIMIT)
|
||||
<< "GuardCheck "
|
||||
<< "Maximum allowable depth of blocks reached (" << max_level
|
||||
<< " levels). Flatten "
|
||||
<< "Maximum allowable depth of blocks reached (16 levels). Flatten "
|
||||
"your loops and conditions!.\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
#define SEP_int32_t LPAREN int32_t COMMA
|
||||
#define SEP_uint64_t LPAREN uint64_t COMMA
|
||||
#define SEP_int64_t LPAREN int64_t COMMA
|
||||
#define SEP_JSValue LPAREN JSValue COMMA
|
||||
|
||||
#define VAL_uint32_t WasmEdge_ValueGetI32(in[_stack++])
|
||||
#define VAL_int32_t WasmEdge_ValueGetI32(in[_stack++])
|
||||
@@ -89,69 +90,174 @@
|
||||
|
||||
#define WASM_VAL_TYPE(T, b) CAT2(TYP_, T)
|
||||
|
||||
#define UNSIGNED_TYPE(T) std::make_unsigned_t<T>
|
||||
#define HALF_COUNT(...) \
|
||||
HALF_COUNT_IMPL( \
|
||||
__VA_ARGS__, \
|
||||
16, \
|
||||
16, \
|
||||
15, \
|
||||
15, \
|
||||
14, \
|
||||
14, \
|
||||
13, \
|
||||
13, \
|
||||
12, \
|
||||
12, \
|
||||
11, \
|
||||
11, \
|
||||
10, \
|
||||
10, \
|
||||
9, \
|
||||
9, \
|
||||
8, \
|
||||
8, \
|
||||
7, \
|
||||
7, \
|
||||
6, \
|
||||
6, \
|
||||
5, \
|
||||
5, \
|
||||
4, \
|
||||
4, \
|
||||
3, \
|
||||
3, \
|
||||
2, \
|
||||
2, \
|
||||
1, \
|
||||
1, \
|
||||
0, \
|
||||
0)
|
||||
|
||||
#define DECLARE_HOOK_FUNCTION(R, F, ...) \
|
||||
std::variant<UNSIGNED_TYPE(R), hook_api::hook_return_code> F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__)); \
|
||||
extern WasmEdge_Result WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out); \
|
||||
extern WasmEdge_ValType WasmFunctionParams##F[]; \
|
||||
extern WasmEdge_ValType WasmFunctionResult##F[]; \
|
||||
extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \
|
||||
#define HALF_COUNT_IMPL( \
|
||||
_1, \
|
||||
_2, \
|
||||
_3, \
|
||||
_4, \
|
||||
_5, \
|
||||
_6, \
|
||||
_7, \
|
||||
_8, \
|
||||
_9, \
|
||||
_10, \
|
||||
_11, \
|
||||
_12, \
|
||||
_13, \
|
||||
_14, \
|
||||
_15, \
|
||||
_16, \
|
||||
_17, \
|
||||
_18, \
|
||||
_19, \
|
||||
_20, \
|
||||
_21, \
|
||||
_22, \
|
||||
_23, \
|
||||
_24, \
|
||||
_25, \
|
||||
_26, \
|
||||
_27, \
|
||||
_28, \
|
||||
_29, \
|
||||
_30, \
|
||||
_31, \
|
||||
_32, \
|
||||
N, \
|
||||
...) \
|
||||
N
|
||||
|
||||
#define DECLARE_WASM_FUNCTION(R, F, ...) \
|
||||
R F(hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__)); \
|
||||
extern WasmEdge_Result WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out); \
|
||||
extern WasmEdge_ValType WasmFunctionParams##F[]; \
|
||||
extern WasmEdge_ValType WasmFunctionResult##F[]; \
|
||||
extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \
|
||||
extern WasmEdge_String WasmFunctionName##F;
|
||||
|
||||
#define DEFINE_HOOK_FUNCTION(R, F, ...) \
|
||||
WasmEdge_Result hook_api::WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out) \
|
||||
{ \
|
||||
__VA_OPT__(int _stack = 0;) \
|
||||
__VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \
|
||||
hook::HookContext* hookCtx = \
|
||||
reinterpret_cast<hook::HookContext*>(data_ptr); \
|
||||
auto const& return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
|
||||
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
|
||||
if (std::holds_alternative<hook_api::hook_return_code>(return_code) && \
|
||||
(std::get<hook_api::hook_return_code>(return_code) == \
|
||||
RC_ROLLBACK || \
|
||||
std::get<hook_api::hook_return_code>(return_code) == RC_ACCEPT)) \
|
||||
return WasmEdge_Result_Terminate; \
|
||||
out[0] = RET_ASSIGN( \
|
||||
R, \
|
||||
std::holds_alternative<UNSIGNED_TYPE(R)>(return_code) \
|
||||
? std::get<UNSIGNED_TYPE(R)>(return_code) \
|
||||
: R(std::get<hook_api::hook_return_code>(return_code))); \
|
||||
return WasmEdge_Result_Success; \
|
||||
}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \
|
||||
__VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \
|
||||
WASM_VAL_TYPE(R, dummy)}; \
|
||||
WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \
|
||||
WasmEdge_FunctionTypeCreate( \
|
||||
WasmFunctionParams##F, \
|
||||
VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \
|
||||
WasmFunctionResult##F, \
|
||||
1); \
|
||||
WasmEdge_String hook_api::WasmFunctionName##F = \
|
||||
WasmEdge_StringCreateByCString(#F); \
|
||||
std::variant<UNSIGNED_TYPE(R), hook_api::hook_return_code> hook_api::F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
#define DECLARE_JS_FUNCTION(R, F, ...) \
|
||||
extern JSValue JSFunction##F( \
|
||||
JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv); \
|
||||
const int JSFunctionParamCount##F = __VA_OPT__(HALF_COUNT(__VA_ARGS__) +) 0;
|
||||
|
||||
#define DEFINE_WASM_FUNCTION(R, F, ...) \
|
||||
WasmEdge_Result hook_api::WasmFunction##F( \
|
||||
void* data_ptr, \
|
||||
const WasmEdge_CallingFrameContext* frameCtx, \
|
||||
const WasmEdge_Value* in, \
|
||||
WasmEdge_Value* out) \
|
||||
{ \
|
||||
__VA_OPT__(int _stack = 0;) \
|
||||
__VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \
|
||||
hook::HookContext* hookCtx = \
|
||||
reinterpret_cast<hook::HookContext*>(data_ptr); \
|
||||
R return_code = hook_api::F( \
|
||||
*hookCtx, \
|
||||
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
|
||||
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
|
||||
if (return_code == RC_ROLLBACK || return_code == RC_ACCEPT) \
|
||||
return WasmEdge_Result_Terminate; \
|
||||
out[0] = RET_ASSIGN(R, return_code); \
|
||||
return WasmEdge_Result_Success; \
|
||||
}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \
|
||||
__VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \
|
||||
WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \
|
||||
WASM_VAL_TYPE(R, dummy)}; \
|
||||
WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \
|
||||
WasmEdge_FunctionTypeCreate( \
|
||||
WasmFunctionParams##F, \
|
||||
VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \
|
||||
WasmFunctionResult##F, \
|
||||
1); \
|
||||
WasmEdge_String hook_api::WasmFunctionName##F = \
|
||||
WasmEdge_StringCreateByCString(#F); \
|
||||
R hook_api::F( \
|
||||
hook::HookContext& hookCtx, \
|
||||
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
|
||||
COMMA __VA_ARGS__))
|
||||
|
||||
#define HOOK_SETUP() \
|
||||
using enum hook_api::hook_return_code; \
|
||||
#define VAR_JSASSIGN(T, V) \
|
||||
if (_stack >= argc) \
|
||||
returnJS(INVALID_ARGUMENT); \
|
||||
T& V = argv[_stack++]
|
||||
|
||||
#define FORWARD_JS_FUNCTION_CALL(F, ac, av) \
|
||||
hook_api::JSFunction##F(ctx, this_val, ac, av)
|
||||
|
||||
#define DEFINE_JS_FUNCTION(R, F, ...) \
|
||||
JSValue hook_api::JSFunction##F( \
|
||||
JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) \
|
||||
{ \
|
||||
__VA_OPT__(int _stack = 0;) \
|
||||
__VA_OPT__(FOR_VARS(VAR_JSASSIGN, 2, __VA_ARGS__);)
|
||||
|
||||
#define JS_HOOK_SETUP() \
|
||||
JSRuntime* rt = JS_GetRuntime(ctx); \
|
||||
hook::HookContext& hookCtx = \
|
||||
*reinterpret_cast<hook::HookContext*>(JS_GetRuntimeOpaque(rt)); \
|
||||
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
|
||||
[[maybe_unused]] auto& view = applyCtx.view(); \
|
||||
[[maybe_unused]] auto j = applyCtx.app.journal("View"); \
|
||||
[[maybe_unused]] auto& api = hookCtx.api(); \
|
||||
try \
|
||||
{
|
||||
#define JS_HOOK_TEARDOWN() \
|
||||
} \
|
||||
catch (const std::exception& e) \
|
||||
{ \
|
||||
JLOG(hookCtx.applyCtx.app.journal("View").error()) \
|
||||
<< "HookError[" << HC_ACC() << "]: (JS) " << __func__ \
|
||||
<< " threw uncaught exception, what=" << e.what(); \
|
||||
return JS_NewInt64(ctx, INTERNAL_ERROR); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WASM_HOOK_SETUP() \
|
||||
try \
|
||||
{ \
|
||||
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
|
||||
@@ -168,14 +274,14 @@
|
||||
if (!memoryCtx || !memory || !memory_length) \
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
#define HOOK_TEARDOWN() \
|
||||
} \
|
||||
catch (const std::exception& e) \
|
||||
{ \
|
||||
JLOG(hookCtx.applyCtx.app.journal("View").error()) \
|
||||
<< "HookError[" << HC_ACC() << "]: " << __func__ \
|
||||
<< " threw uncaught exception, what=" << e.what(); \
|
||||
return INTERNAL_ERROR; \
|
||||
#define WASM_HOOK_TEARDOWN() \
|
||||
} \
|
||||
catch (const std::exception& e) \
|
||||
{ \
|
||||
JLOG(hookCtx.applyCtx.app.journal("View").error()) \
|
||||
<< "HookError[" << HC_ACC() << "]: (WASM) " << __func__ \
|
||||
<< " threw uncaught exception, what=" << e.what(); \
|
||||
return INTERNAL_ERROR; \
|
||||
}
|
||||
|
||||
#define WRITE_WASM_MEMORY( \
|
||||
@@ -214,7 +320,7 @@
|
||||
host_memory_ptr, \
|
||||
guest_memory_length) \
|
||||
{ \
|
||||
uint64_t bytes_written = 0; \
|
||||
int64_t bytes_written = 0; \
|
||||
WRITE_WASM_MEMORY( \
|
||||
bytes_written, \
|
||||
guest_dst_ptr, \
|
||||
@@ -269,6 +375,28 @@
|
||||
: RC_ROLLBACK); \
|
||||
}
|
||||
|
||||
#define HOOK_EXIT_JS(error_msg, error_code, exit_type) \
|
||||
{ \
|
||||
int64_t val = 0; \
|
||||
if (JS_IsNumber(error_code)) \
|
||||
JS_ToInt64(ctx, &val, error_code); \
|
||||
hookCtx.result.exitCode = val; \
|
||||
hookCtx.result.exitType = exit_type; \
|
||||
if (JS_IsString(error_msg)) \
|
||||
{ \
|
||||
size_t len; \
|
||||
const char* cstr = JS_ToCStringLen(ctx, &len, error_msg); \
|
||||
if (len > 256) \
|
||||
len = 256; \
|
||||
hookCtx.result.exitReason = std::string(cstr, len); \
|
||||
JS_FreeCString(ctx, cstr); \
|
||||
} \
|
||||
return JS_Exit( \
|
||||
ctx, \
|
||||
exit_type == hook_api::ExitType::ACCEPT ? "HookExit Accept" \
|
||||
: "HookExit Rollback"); \
|
||||
}
|
||||
|
||||
#define WRITE_WASM_MEMORY_OR_RETURN_AS_INT64( \
|
||||
write_ptr_in, write_len_in, data_ptr_in, data_len_in, is_account_in) \
|
||||
{ \
|
||||
@@ -283,7 +411,7 @@
|
||||
data_ptr < (data_ptr_in)) \
|
||||
return INTERNAL_ERROR; \
|
||||
if (data_len == 0) \
|
||||
return 0ULL; \
|
||||
return 0; \
|
||||
if ((write_ptr_in) == 0) \
|
||||
return data_as_int64(data_ptr, data_len); \
|
||||
if (data_len > (write_len_in)) \
|
||||
|
||||
@@ -7,311 +7,559 @@ HOOK_API_DEFINITION(
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, accept, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
// function accept(error_msg: string, error_code: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, accept, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, rollback, (uint32_t, uint32_t, int64_t),
|
||||
uint256{})
|
||||
// function rollback(error_msg: string, error_code: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, rollback, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t util_raddr(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_raddr, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function util_raddr(acc_id:string): string
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, util_raddr, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t util_accid(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_accid, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function util_accid(acc_id:string): string
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, util_accid, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t util_verify(uint32_t dread_ptr, uint32_t dread_len, uint32_t sread_ptr, uint32_t sread_len, uint32_t kread_ptr, uint32_t kread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_verify, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function util_verify(data:string, sig: string, pubkey: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, util_verify, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t util_sha512h(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_sha512h, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function util_sha512h(data: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, util_sha512h, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t util_keylet(uint32_t write_ptr, uint32_t write_len, uint32_t keylet_type, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, util_keylet, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function util_keylet(keylet_type: number, keylet_data: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, util_keylet, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t sto_validate(uint32_t tread_ptr, uint32_t tread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_validate, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function sto_validate(sto: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_validate, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t sto_subfield(uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_subfield, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function sto_subfield(sto: string, field_id: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_subfield, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t sto_subarray(uint32_t read_ptr, uint32_t read_len, uint32_t array_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_subarray, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function sto_subarray(sto: string, array_id: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_subarray, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t sto_emplace(uint32_t write_ptr, uint32_t write_len, uint32_t sread_ptr, uint32_t sread_len, uint32_t fread_ptr, uint32_t fread_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_emplace, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function sto_emplace(sto: string, field_bytes: number, field_id: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_emplace, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t sto_erase(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, sto_erase, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function sto_erase(sto: string, field_id: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_erase, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_burden();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_burden, (),
|
||||
uint256{})
|
||||
// function etxn_burden(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_burden, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_details(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_details, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function etxn_details(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_details, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_fee_base(uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_fee_base, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function etxn_fee_base(txblob: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_fee_base, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_reserve(uint32_t count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_reserve, (uint32_t),
|
||||
uint256{})
|
||||
// function etxn_reserve(count: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_reserve, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_generation();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_generation, (),
|
||||
uint256{})
|
||||
// function etxn_generation(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_generation, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t etxn_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, etxn_nonce, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function etxn_nonce(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, etxn_nonce, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t emit(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, emit, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function emit(txn: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, emit, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_set(int32_t exponent, int64_t mantissa);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_set, (int32_t, int64_t),
|
||||
uint256{})
|
||||
// function float_set(e: number, m: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_set, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_multiply(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_multiply, (int64_t, int64_t),
|
||||
uint256{})
|
||||
// function float_multiply(f1: number, f2: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_multiply, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_mulratio(int64_t float1, uint32_t round_up, uint32_t numerator, uint32_t denominator);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_mulratio, (int64_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_mulratio(f1: number, round_up: number, numerator: number, denominator: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_mulratio, (JSValue, JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_negate(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_negate, (int64_t),
|
||||
uint256{})
|
||||
// function float_negate(f1: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_negate, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_compare(int64_t float1, int64_t float2, uint32_t mode);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_compare, (int64_t, int64_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_compare(f1: number, f2: number, mode: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_compare, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_sum(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sum, (int64_t, int64_t),
|
||||
uint256{})
|
||||
// function float_sum(f1: number, f2: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_sum, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_sto(uint32_t write_ptr, uint32_t write_len, uint32_t cread_ptr, uint32_t cread_len, uint32_t iread_ptr, uint32_t iread_len, int64_t float1, uint32_t field_code);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sto, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, int64_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_sto(cur: string, isu: string, float1: number, field_code: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_sto, (JSValue, JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_sto_set(uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sto_set, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_sto_set(buf: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_sto_set, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_invert(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_invert, (int64_t),
|
||||
uint256{})
|
||||
// function float_invert(f1: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_invert, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_divide(int64_t float1, int64_t float2);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_divide, (int64_t, int64_t),
|
||||
uint256{})
|
||||
// function float_divide(f1: number, f2: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_divide, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_one();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_one, (),
|
||||
uint256{})
|
||||
// function float_one(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_one, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_mantissa(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_mantissa, (int64_t),
|
||||
uint256{})
|
||||
// function float_mantissa(f1: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_mantissa, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_sign(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_sign, (int64_t),
|
||||
uint256{})
|
||||
// function float_sign(f1: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_sign, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_int(int64_t float1, uint32_t decimal_places, uint32_t abs);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_int, (int64_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_int(f1: number, decimal_places: number, abs: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_int, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_log(int64_t float1);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_log, (int64_t),
|
||||
uint256{})
|
||||
// function float_log(f1: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_log, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t float_root(int64_t float1, uint32_t n);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, float_root, (int64_t, uint32_t),
|
||||
uint256{})
|
||||
// function float_root(f1: number, n: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, float_root, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t fee_base();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, fee_base, (),
|
||||
uint256{})
|
||||
// function fee_base(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, fee_base, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t ledger_seq();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_seq, (),
|
||||
uint256{})
|
||||
// function ledger_seq(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, ledger_seq, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t ledger_last_time();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_last_time, (),
|
||||
uint256{})
|
||||
// function ledger_last_time(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, ledger_last_time, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t ledger_last_hash(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_last_hash, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function ledger_last_hash(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, ledger_last_hash, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t ledger_nonce(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_nonce, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function ledger_nonce(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, ledger_nonce, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t ledger_keylet(uint32_t write_ptr, uint32_t write_len, uint32_t lread_ptr, uint32_t lread_len, uint32_t hread_ptr, uint32_t hread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, ledger_keylet, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function ledger_keylet(low: string, high: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, ledger_keylet, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_account(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_account, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function hook_account(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_account, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_hash(uint32_t write_ptr, uint32_t write_len, int32_t hook_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_hash, (uint32_t, uint32_t, int32_t),
|
||||
uint256{})
|
||||
// function hook_hash(hook_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_hash, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_param_set(uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t hread_ptr, uint32_t hread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_param_set, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function hook_param_set(value: string, key: string, hash: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_param_set, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_param(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_param, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function hook_param(key: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_param, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_again();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_again, (),
|
||||
uint256{})
|
||||
// function hook_again(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_again, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_skip(uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_skip, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function hook_skip(hhash: string, flags: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_skip, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t hook_pos();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, hook_pos, (),
|
||||
uint256{})
|
||||
// function hook_pos(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, hook_pos, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function slot(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_clear(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_clear, (uint32_t),
|
||||
uint256{})
|
||||
// function slot_clear(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_clear, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_count(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_count, (uint32_t),
|
||||
uint256{})
|
||||
// function slot_count(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_count, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_set(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_set, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function slot_set(kl: string, slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_set, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_size(uint32_t slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_size, (uint32_t),
|
||||
uint256{})
|
||||
// function slot_size(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_size, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_subarray(uint32_t parent_slot, uint32_t array_id, uint32_t new_slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_subarray, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function slot_subarray(parent_slot_no: number, array_id: number, new_slot: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_subarray, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_subfield(uint32_t parent_slot, uint32_t field_id, uint32_t new_slot);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_subfield, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function slot_subfield(parent_slot_no: number, field_id: number, new_slot: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_subfield, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_type(uint32_t slot_no, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_type, (uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function slot_type(slot_no: number, flags: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_type, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t slot_float(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, slot_float, (uint32_t),
|
||||
uint256{})
|
||||
// function slot_float(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_float, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t state_set(uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_set, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function state_set(val: string, key: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, state_set, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t state_foreign_set(uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t aread_ptr, uint32_t aread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_foreign_set, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function state_foreign_set(val: string, key: string, ns: string, accid: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, state_foreign_set, (JSValue, JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t state(uint32_t write_ptr, uint32_t write_len, uint32_t kread_ptr, uint32_t kread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function state(key: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, state, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t state_foreign(uint32_t write_ptr, uint32_t write_len, uint32_t kread_ptr, uint32_t kread_len, uint32_t nread_ptr, uint32_t nread_len, uint32_t aread_ptr, uint32_t aread_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, state_foreign, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function state_foreign(key: string, ns: string, accid: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, state_foreign, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t trace(uint32_t mread_ptr, uint32_t mread_len, uint32_t dread_ptr, uint32_t dread_len, uint32_t as_hex);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, trace, (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function trace(msg: string, data: string, as_hex: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, trace, (JSValue, JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t trace_num(uint32_t read_ptr, uint32_t read_len, int64_t number);
|
||||
HOOK_API_DEFINITION(
|
||||
@@ -327,73 +575,108 @@ HOOK_API_DEFINITION(
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_burden, (),
|
||||
uint256{})
|
||||
// function otxn_burden(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_burden, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_field(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_field, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function otxn_field(field_id: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_field, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_generation();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_generation, (),
|
||||
uint256{})
|
||||
// function otxn_generation(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_generation, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_id(uint32_t write_ptr, uint32_t write_len, uint32_t flags);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_id, (uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function otxn_id(flags: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_id, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_type();
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_type, (),
|
||||
uint256{})
|
||||
// function otxn_type(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_type, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_slot(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_slot, (uint32_t),
|
||||
uint256{})
|
||||
// function otxn_slot(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_slot, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t otxn_param(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, otxn_param, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
uint256{})
|
||||
// function otxn_param(param_key: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_param, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t meta_slot(uint32_t slot_no);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, meta_slot, (uint32_t),
|
||||
uint256{})
|
||||
// function meta_slot(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, meta_slot, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t xpop_slot(uint32_t slot_no_tx, uint32_t slot_no_meta);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xpop_slot, (uint32_t, uint32_t),
|
||||
featureHooksUpdate1)
|
||||
// function xpop_slot(slot_no_tx: number, slot_no_meta: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, xpop_slot, (JSValue, JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t prepare(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, prepare, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureHooksUpdate2)
|
||||
// function prepare(tmpl: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, prepare, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t xport_reserve(uint32_t count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport_reserve, (uint32_t),
|
||||
featureExport)
|
||||
// function otxn_json(): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, otxn_json, (),
|
||||
uint256{})
|
||||
|
||||
// int64_t xport(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureExport)
|
||||
// function slot_json(slot_no: number): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, slot_json, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t xport_cancel(uint32_t ticket_seq);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, xport_cancel, (uint32_t),
|
||||
featureExport)
|
||||
// function sto_to_json(sto_in: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_to_json, (JSValue),
|
||||
uint256{})
|
||||
|
||||
// int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, dice, (uint32_t, uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
// int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, random, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
// function sto_from_json(json_in: string): number
|
||||
JSHOOK_API_DEFINITION(
|
||||
JSValue, sto_from_json, (JSValue),
|
||||
uint256{})
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
DisableFormat: true
|
||||
@@ -166,14 +166,6 @@ message TMProposeSet
|
||||
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 12 [deprecated=true];
|
||||
|
||||
// Export signatures for pending exports seen in the proposal set. The
|
||||
// proposal's ExtendedPosition includes a digest of this repeated field, so
|
||||
// these side-channel blobs are covered by the proposal signature.
|
||||
// Each entry is: txnHash (32 bytes) + validator pubkey (33 bytes)
|
||||
// + multisign signature (variable length). Validators attach these
|
||||
// so export quorum can be reached within the same consensus round.
|
||||
repeated bytes exportSignatures = 13;
|
||||
}
|
||||
|
||||
enum TxSetStatus
|
||||
@@ -392,3 +384,4 @@ message TMHaveTransactions
|
||||
{
|
||||
repeated bytes hashes = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_ENTROPY_TIER_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_ENTROPY_TIER_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/// Which gate the ledger's entropy passed. Stored in sfEntropyTier (UINT8)
|
||||
/// on the ttCONSENSUS_ENTROPY pseudo-transaction and the ConsensusEntropy
|
||||
/// ledger entry.
|
||||
///
|
||||
/// EntropyCount says how many validators contributed; EntropyTier says which
|
||||
/// gate the result passed. Values are strength-ordered so consumers can gate
|
||||
/// with a numeric comparison (tier >= required).
|
||||
enum EntropyTier : std::uint8_t {
|
||||
/// No usable entropy (reserved; a fresh ConsensusEntropy entry should
|
||||
/// always carry one of the tiers below).
|
||||
entropyTierNone = 0,
|
||||
|
||||
/// Consensus-bound deterministic fallback: derived from already-agreed
|
||||
/// round inputs (parent ledger hash, base tx set hash, sequence) under
|
||||
/// HashPrefix::entropyFallback when validator reveal quorum was not
|
||||
/// available. Unpredictable in practice but user-influenceable via
|
||||
/// transaction submission — never suitable for value-bearing outcomes.
|
||||
entropyTierConsensusFallback = 1,
|
||||
|
||||
/// Reserved for a future participant-aligned sub-quorum tier.
|
||||
entropyTierParticipantAligned = 2,
|
||||
|
||||
/// Validator commit/reveal entropy whose sidecar set passed the
|
||||
/// active-validator-view quorum alignment gate.
|
||||
entropyTierValidatorQuorum = 3,
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_EXPORT_LIMITS_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_EXPORT_LIMITS_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// Export system caps.
|
||||
//
|
||||
// These limits bound the DoS surface of the export signature system:
|
||||
// - Each pending export requires every validator to sign it every round
|
||||
// (sign-once, attach once via TMProposeSet)
|
||||
// - Inbound signature processing involves crypto verification per sig
|
||||
// - The open-ledger cap (maxPendingExports) is the root constraint;
|
||||
// signing throughput and inbound processing are transitively bounded by it
|
||||
struct ExportLimits
|
||||
{
|
||||
// Maximum exports a single hook execution may produce
|
||||
// (also enforced by hook_api::max_export in Enum.h)
|
||||
static constexpr std::uint8_t maxExportsPerHook = 2;
|
||||
|
||||
// Maximum pending export transactions in an open/apply ledger.
|
||||
// Hook-emitted export backlog drains into the open ledger at this cap.
|
||||
// This transitively caps:
|
||||
// - signatures per TMProposeSet message (1 per pending export)
|
||||
// - inbound proposal signature processing (clamped to this)
|
||||
// - validator signing work per round
|
||||
static constexpr std::uint8_t maxPendingExports = 8;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -33,39 +33,35 @@
|
||||
*
|
||||
* Steps required to add new features to the code:
|
||||
*
|
||||
* 1) Add the appropriate XRPL_FEATURE or XRPL_FIX macro definition for the
|
||||
* feature to features.macro with the feature's name, `Supported::no`, and
|
||||
* `VoteBehavior::DefaultNo`.
|
||||
*
|
||||
* 2) Use the generated variable name as the parameter to `view.rules.enabled()`
|
||||
* to control flow into new code that this feature limits. (featureName or
|
||||
* fixName)
|
||||
*
|
||||
* 3) If the feature development is COMPLETE, and the feature is ready to be
|
||||
* SUPPORTED, change the macro parameter in features.macro to Supported::yes.
|
||||
*
|
||||
* 4) In general, any newly supported amendments (`Supported::yes`) should have
|
||||
* a `VoteBehavior::DefaultNo` indefinitely so that external governance can
|
||||
* make the decision on when to activate it. High priority bug fixes can be
|
||||
* an exception to this rule. In such cases, ensure the fix has been
|
||||
* clearly communicated to the community using appropriate channels,
|
||||
* then change the macro parameter in features.macro to
|
||||
* `VoteBehavior::DefaultYes`. The communication process is beyond
|
||||
* the scope of these instructions.
|
||||
*
|
||||
* 1) In this file, increment `numFeatures` and add a uint256 declaration
|
||||
* for the feature at the bottom
|
||||
* 2) Add a uint256 definition for the feature to the corresponding source
|
||||
* file (Feature.cpp). Use `registerFeature` to create the feature with
|
||||
* the feature's name, `Supported::no`, and `VoteBehavior::DefaultNo`. This
|
||||
* should be the only place the feature's name appears in code as a string.
|
||||
* 3) Use the uint256 as the parameter to `view.rules.enabled()` to
|
||||
* control flow into new code that this feature limits.
|
||||
* 4) If the feature development is COMPLETE, and the feature is ready to be
|
||||
* SUPPORTED, change the `registerFeature` parameter to Supported::yes.
|
||||
* 5) When the feature is ready to be ENABLED, change the `registerFeature`
|
||||
* parameter to `VoteBehavior::DefaultYes`.
|
||||
* In general, any newly supported amendments (`Supported::yes`) should have
|
||||
* a `VoteBehavior::DefaultNo` for at least one full release cycle. High
|
||||
* priority bug fixes can be an exception to this rule of thumb.
|
||||
*
|
||||
* When a feature has been enabled for several years, the conditional code
|
||||
* may be removed, and the feature "retired". To retire a feature:
|
||||
*
|
||||
* 1) MOVE the macro definition in features.macro to the "retired features"
|
||||
* section at the end of the file, and change the macro to XRPL_RETIRE.
|
||||
*
|
||||
* 1) Remove the uint256 declaration from this file.
|
||||
* 2) MOVE the uint256 definition in Feature.cpp to the "retired features"
|
||||
* section at the end of the file.
|
||||
* 3) CHANGE the name of the variable to start with "retired".
|
||||
* 4) CHANGE the parameters of the `registerFeature` call to `Supported::yes`
|
||||
* and `VoteBehavior::DefaultNo`.
|
||||
* The feature must remain registered and supported indefinitely because it
|
||||
* may exist in the Amendments object on ledger. There is no need to vote
|
||||
* for it because there's nothing to vote for. If the feature definition is
|
||||
* removed completely from the code, any instances running that code will get
|
||||
* amendment blocked. Removing the feature from the ledger is beyond the scope
|
||||
* of these instructions.
|
||||
* still exists in the ledger, but there is no need to vote for it because
|
||||
* there's nothing to vote for. If it is removed completely from the code, any
|
||||
* instances running that code will get amendment blocked. Removing the
|
||||
* feature from the ledger is beyond the scope of these instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -80,32 +76,11 @@ allAmendments();
|
||||
|
||||
namespace detail {
|
||||
|
||||
#pragma push_macro("XRPL_FEATURE")
|
||||
#undef XRPL_FEATURE
|
||||
#pragma push_macro("XRPL_FIX")
|
||||
#undef XRPL_FIX
|
||||
#pragma push_macro("XRPL_RETIRE")
|
||||
#undef XRPL_RETIRE
|
||||
|
||||
#define XRPL_FEATURE(name, supported, vote) +1
|
||||
#define XRPL_FIX(name, supported, vote) +1
|
||||
#define XRPL_RETIRE(name) +1
|
||||
|
||||
// This value SHOULD be equal to the number of amendments registered in
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures =
|
||||
(0 +
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
);
|
||||
|
||||
#undef XRPL_RETIRE
|
||||
#pragma pop_macro("XRPL_RETIRE")
|
||||
#undef XRPL_FIX
|
||||
#pragma pop_macro("XRPL_FIX")
|
||||
#undef XRPL_FEATURE
|
||||
#pragma pop_macro("XRPL_FEATURE")
|
||||
static constexpr std::size_t numFeatures = 116;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -345,17 +320,12 @@ foreachFeature(FeatureBitset bs, F&& f)
|
||||
#undef XRPL_FEATURE
|
||||
#pragma push_macro("XRPL_FIX")
|
||||
#undef XRPL_FIX
|
||||
#pragma push_macro("XRPL_RETIRE")
|
||||
#undef XRPL_RETIRE
|
||||
|
||||
#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name;
|
||||
#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name;
|
||||
#define XRPL_RETIRE(name)
|
||||
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
|
||||
#undef XRPL_RETIRE
|
||||
#pragma pop_macro("XRPL_RETIRE")
|
||||
#undef XRPL_FIX
|
||||
#pragma pop_macro("XRPL_FIX")
|
||||
#undef XRPL_FEATURE
|
||||
|
||||
@@ -96,14 +96,6 @@ enum class HashPrefix : std::uint32_t {
|
||||
|
||||
/** Credentials signature */
|
||||
credential = detail::make_hash_prefix('C', 'R', 'D'),
|
||||
|
||||
/** consensus extension sidecar object */
|
||||
sidecar = detail::make_hash_prefix('S', 'C', 'R'),
|
||||
|
||||
/** consensus-bound fallback entropy digest (Tier 3: derived from
|
||||
already-agreed round inputs when validator reveal quorum is not
|
||||
available; never to be confused with validator entropy) */
|
||||
entropyFallback = detail::make_hash_prefix('E', 'F', 'B'),
|
||||
};
|
||||
|
||||
template <class Hasher>
|
||||
|
||||
@@ -62,9 +62,6 @@ emittedDir() noexcept;
|
||||
Keylet
|
||||
emittedTxn(uint256 const& id) noexcept;
|
||||
|
||||
Keylet
|
||||
shadowTicket(AccountID const& account, std::uint32_t ticketSeq) noexcept;
|
||||
|
||||
Keylet
|
||||
hookDefinition(uint256 const& hash) noexcept;
|
||||
|
||||
@@ -121,10 +118,6 @@ negativeUNL() noexcept;
|
||||
Keylet const&
|
||||
UNLReport() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing consensus-derived entropy. */
|
||||
Keylet const&
|
||||
consensusEntropy() noexcept;
|
||||
|
||||
/** The beginning of an order book */
|
||||
struct book_t
|
||||
{
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef RIPPLE_PROTOCOL_SIDECAR_TYPE_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_SIDECAR_TYPE_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/// Discriminator for sidecar set entries (SHAMap leaves used for
|
||||
/// consensus extension data: RNG commit/reveal, export signatures).
|
||||
///
|
||||
/// Stored in sfSidecarType (UINT8) on each STObject entry.
|
||||
/// Makes sidecar sets self-describing — no content-sniffing needed.
|
||||
enum SidecarType : std::uint8_t {
|
||||
sidecarRngCommit = 1,
|
||||
sidecarRngReveal = 2,
|
||||
sidecarExportSig = 3,
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -68,7 +68,6 @@ enum TELcodes : TERUnderlyingType {
|
||||
telNON_LOCAL_EMITTED_TXN,
|
||||
telIMPORT_VL_KEY_NOT_RECOGNISED,
|
||||
telCAN_NOT_QUEUE_IMPORT,
|
||||
telSHADOW_TICKET_REQUIRED,
|
||||
telENV_RPC_FAILED,
|
||||
};
|
||||
|
||||
@@ -138,7 +137,6 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temXCHAIN_BRIDGE_NONDOOR_OWNER,
|
||||
temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT,
|
||||
temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT,
|
||||
temXCHAIN_TOO_MANY_ATTESTATIONS, // RESERVED - not used
|
||||
|
||||
temHOOK_DATA_TOO_LARGE,
|
||||
temEMPTY_DID,
|
||||
@@ -235,10 +233,8 @@ enum TERcodes : TERUnderlyingType {
|
||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||
terNO_AMM, // AMM doesn't exist for the asset pair
|
||||
terNO_HOOK, // Transaction requires a non-existent hook definition
|
||||
terNO_HOOK // Transaction requires a non-existent hook definition
|
||||
// (referenced by sfHookHash)
|
||||
terRETRY_EXPORT // Export does not yet have enough validator signatures.
|
||||
// Retained in retriable set for next ledger.
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -366,7 +362,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecARRAY_TOO_LARGE = 197,
|
||||
tecLOCKED = 198,
|
||||
tecBAD_CREDENTIALS = 199,
|
||||
tecEXPORT_EXPIRED = 200,
|
||||
tecINVALID_HOOK_API_VERSION = 200,
|
||||
tecLAST_POSSIBLE_ENTRY = 255,
|
||||
};
|
||||
|
||||
|
||||
@@ -274,13 +274,6 @@ enum BridgeModifyFlags : uint32_t {
|
||||
tfClearAccountCreateAmount = 0x00010000,
|
||||
};
|
||||
constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount);
|
||||
|
||||
// ConsensusEntropy flags (used on ttCONSENSUS_ENTROPY SHAMap entries):
|
||||
enum ConsensusEntropyFlags : uint32_t {
|
||||
tfEntropyCommit = 0x00000001, // entry is a commitment in commitSet
|
||||
tfEntropyReveal = 0x00000002, // entry is a reveal in entropySet
|
||||
};
|
||||
// flag=0 (no tfEntropyCommit/tfEntropyReveal) = final injected pseudo-tx
|
||||
// clang-format on
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -140,12 +140,6 @@ public:
|
||||
mHookEmissions = hookEmissions;
|
||||
}
|
||||
|
||||
void
|
||||
setExportResult(STObject const& exportResult)
|
||||
{
|
||||
mExportResult = exportResult;
|
||||
}
|
||||
|
||||
bool
|
||||
hasHookExecutions() const
|
||||
{
|
||||
@@ -158,12 +152,6 @@ public:
|
||||
return static_cast<bool>(mHookEmissions);
|
||||
}
|
||||
|
||||
bool
|
||||
hasExportResult() const
|
||||
{
|
||||
return static_cast<bool>(mExportResult);
|
||||
}
|
||||
|
||||
STAmount
|
||||
getDeliveredAmount() const
|
||||
{
|
||||
@@ -188,7 +176,6 @@ private:
|
||||
std::optional<STAmount> mDelivered;
|
||||
std::optional<STArray> mHookExecutions;
|
||||
std::optional<STArray> mHookEmissions;
|
||||
std::optional<STObject> mExportResult;
|
||||
|
||||
STArray mNodes;
|
||||
};
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
#if !defined(XRPL_FIX)
|
||||
#error "undefined macro: XRPL_FIX"
|
||||
#endif
|
||||
#if !defined(XRPL_RETIRE)
|
||||
#error "undefined macro: XRPL_RETIRE"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
|
||||
@@ -34,9 +31,7 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(NamedHooks, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(IOURewardClaim, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(JSHooks, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (IOULockedBalanceInvariant, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ImportIssuer, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HookAPISerializedType240, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -62,18 +57,16 @@ XRPL_FIX (DisallowIncomingV1, Supported::yes, VoteBehavior::DefaultYe
|
||||
XRPL_FEATURE(XChainBridge, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(HookOnV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Export, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ConsensusEntropy, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (HookAPI20251128, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (CronStacking, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(Cron, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(IOUIssuerWeakTSH, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ProvisionalDoubleThreading, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FEATURE(HookOnV2, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FIX (HookAPI20251128, Supported::yes, VoteBehavior::DefaultYes);
|
||||
XRPL_FIX (CronStacking, Supported::yes, VoteBehavior::DefaultYes);
|
||||
XRPL_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultYes);
|
||||
XRPL_FEATURE(Cron, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FEATURE(IOUIssuerWeakTSH, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo);
|
||||
XRPL_FIX (ProvisionalDoubleThreading, Supported::yes, VoteBehavior::DefaultYes);
|
||||
XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RewardClaimFlags, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HookCanEmit, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -157,24 +150,4 @@ XRPL_FIX (NFTokenDirV1, Supported::yes, VoteBehavior::Obsolete)
|
||||
XRPL_FEATURE(NonFungibleTokensV1, Supported::yes, VoteBehavior::Obsolete)
|
||||
XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete)
|
||||
|
||||
// The following amendments have been active for at least two years. Their
|
||||
// pre-amendment code has been removed and the identifiers are deprecated.
|
||||
// All known amendments and amendments that may appear in a validated
|
||||
// ledger must be registered either here or above with the "active" amendments
|
||||
XRPL_RETIRE(MultiSign)
|
||||
XRPL_RETIRE(TrustSetAuth)
|
||||
XRPL_RETIRE(FeeEscalation)
|
||||
XRPL_RETIRE(PayChan)
|
||||
XRPL_RETIRE(CryptoConditions)
|
||||
XRPL_RETIRE(TickSize)
|
||||
XRPL_RETIRE(fix1368)
|
||||
XRPL_RETIRE(Escrow)
|
||||
XRPL_RETIRE(fix1373)
|
||||
XRPL_RETIRE(EnforceInvariants)
|
||||
XRPL_RETIRE(SortedDirectories)
|
||||
XRPL_RETIRE(fix1201)
|
||||
XRPL_RETIRE(fix1512)
|
||||
XRPL_RETIRE(fix1523)
|
||||
XRPL_RETIRE(fix1528)
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -223,21 +223,6 @@ LEDGER_ENTRY(ltURI_TOKEN, 0x0055, URIToken, uri_token, ({
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** The ledger object which stores consensus-derived entropy.
|
||||
|
||||
\note This is a singleton: only one such object exists in the ledger.
|
||||
|
||||
\sa keylet::consensusEntropy
|
||||
*/
|
||||
LEDGER_ENTRY_DUPLICATE(ltCONSENSUS_ENTROPY, 0x0058, ConsensusEntropy, consensus_entropy, ({
|
||||
{sfDigest, soeREQUIRED},
|
||||
{sfEntropyCount, soeREQUIRED},
|
||||
{sfEntropyTier, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes an account.
|
||||
|
||||
\sa keylet::account
|
||||
@@ -411,8 +396,6 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfHighQualityOut, soeOPTIONAL},
|
||||
{sfLockedBalance, soeOPTIONAL},
|
||||
{sfLockCount, soeOPTIONAL},
|
||||
{sfHighReward, soeOPTIONAL},
|
||||
{sfLowReward, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists the network's fee settings.
|
||||
@@ -607,22 +590,6 @@ LEDGER_ENTRY(ltDID, 0x008D, DID, did, ({
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
//@@start shadow-ticket-ledger-entry
|
||||
/** A shadow ticket for export replay protection.
|
||||
|
||||
Created when a transaction is exported. Consumed when
|
||||
proof-of-execution is imported back. Account-owned (pays reserve).
|
||||
|
||||
\sa keylet::shadowTicket
|
||||
*/
|
||||
LEDGER_ENTRY(ltSHADOW_TICKET, 0x5374, ShadowTicket, shadow_ticket, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfTicketSequence, soeREQUIRED},
|
||||
{sfTransactionHash, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
}))
|
||||
//@@end shadow-ticket-ledger-entry
|
||||
|
||||
#undef EXPAND
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
|
||||
@@ -42,8 +42,6 @@ TYPED_SFIELD(sfTickSize, UINT8, 16)
|
||||
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
|
||||
TYPED_SFIELD(sfHookResult, UINT8, 18)
|
||||
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
|
||||
TYPED_SFIELD(sfSidecarType, UINT8, 20)
|
||||
TYPED_SFIELD(sfEntropyTier, UINT8, 21)
|
||||
|
||||
// 16-bit integers (common)
|
||||
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never)
|
||||
@@ -61,8 +59,6 @@ TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
|
||||
TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
|
||||
TYPED_SFIELD(sfHookStateScale, UINT16, 21)
|
||||
TYPED_SFIELD(sfLedgerFixType, UINT16, 22)
|
||||
TYPED_SFIELD(sfHookExportCount, UINT16, 98)
|
||||
TYPED_SFIELD(sfEntropyCount, UINT16, 99)
|
||||
|
||||
// 32-bit integers (common)
|
||||
TYPED_SFIELD(sfNetworkID, UINT32, 1)
|
||||
@@ -127,7 +123,6 @@ TYPED_SFIELD(sfImportSequence, UINT32, 97)
|
||||
TYPED_SFIELD(sfRewardTime, UINT32, 98)
|
||||
TYPED_SFIELD(sfRewardLgrFirst, UINT32, 99)
|
||||
TYPED_SFIELD(sfRewardLgrLast, UINT32, 100)
|
||||
TYPED_SFIELD(sfCancelTicketSequence, UINT32, 101)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
@@ -222,7 +217,6 @@ TYPED_SFIELD(sfHookCanEmit, UINT256, 96)
|
||||
TYPED_SFIELD(sfEmittedTxnID, UINT256, 97)
|
||||
TYPED_SFIELD(sfGovernanceMarks, UINT256, 98)
|
||||
TYPED_SFIELD(sfGovernanceFlags, UINT256, 99)
|
||||
TYPED_SFIELD(sfEntropyDigest, UINT256, 100)
|
||||
|
||||
// number (common)
|
||||
TYPED_SFIELD(sfNumber, NUMBER, 1)
|
||||
@@ -263,7 +257,6 @@ TYPED_SFIELD(sfPrice, AMOUNT, 28)
|
||||
TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
|
||||
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
|
||||
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
|
||||
TYPED_SFIELD(sfTrustLineRewardAccumulator,AMOUNT, 99)
|
||||
|
||||
// variable length (common)
|
||||
TYPED_SFIELD(sfPublicKey, VL, 1)
|
||||
@@ -299,7 +292,6 @@ TYPED_SFIELD(sfAssetClass, VL, 29)
|
||||
TYPED_SFIELD(sfProvider, VL, 30)
|
||||
TYPED_SFIELD(sfMPTokenMetadata, VL, 31)
|
||||
TYPED_SFIELD(sfCredentialType, VL, 32)
|
||||
TYPED_SFIELD(sfHookName, VL, 97)
|
||||
TYPED_SFIELD(sfRemarkValue, VL, 98)
|
||||
TYPED_SFIELD(sfRemarkName, VL, 99)
|
||||
|
||||
@@ -348,7 +340,6 @@ TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1)
|
||||
TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2)
|
||||
TYPED_SFIELD(sfAsset, ISSUE, 3)
|
||||
TYPED_SFIELD(sfAsset2, ISSUE, 4)
|
||||
TYPED_SFIELD(sfClaimCurrency, ISSUE, 5)
|
||||
|
||||
// bridge
|
||||
TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1)
|
||||
@@ -388,7 +379,6 @@ UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31)
|
||||
UNTYPED_SFIELD(sfPriceData, OBJECT, 32)
|
||||
UNTYPED_SFIELD(sfCredential, OBJECT, 33)
|
||||
UNTYPED_SFIELD(sfExportedTxn, OBJECT, 90)
|
||||
UNTYPED_SFIELD(sfAmountEntry, OBJECT, 91)
|
||||
UNTYPED_SFIELD(sfMintURIToken, OBJECT, 92)
|
||||
UNTYPED_SFIELD(sfHookEmission, OBJECT, 93)
|
||||
@@ -396,9 +386,6 @@ UNTYPED_SFIELD(sfImportVLKey, OBJECT, 94)
|
||||
UNTYPED_SFIELD(sfActiveValidator, OBJECT, 95)
|
||||
UNTYPED_SFIELD(sfGenesisMint, OBJECT, 96)
|
||||
UNTYPED_SFIELD(sfRemark, OBJECT, 97)
|
||||
UNTYPED_SFIELD(sfHighReward, OBJECT, 98)
|
||||
UNTYPED_SFIELD(sfLowReward, OBJECT, 99)
|
||||
UNTYPED_SFIELD(sfExportResult, OBJECT, 100)
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
|
||||
@@ -500,17 +500,6 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 72, PermissionedDomainDelete, ({
|
||||
{sfDomainID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
//@@start export-transaction-types
|
||||
/* User-submittable export: creates a cross-chain transaction for
|
||||
validator signing. Retries via terRETRY_EXPORT until quorum.
|
||||
Also supports shadow ticket cancellation via sfCancelTicketSequence.
|
||||
At least one of sfExportedTxn or sfCancelTicketSequence must be present. */
|
||||
TRANSACTION(ttEXPORT, 91, Export, ({
|
||||
{sfExportedTxn, soeOPTIONAL},
|
||||
{sfCancelTicketSequence, soeOPTIONAL},
|
||||
}))
|
||||
//@@end export-transaction-types
|
||||
|
||||
/* A pseudo-txn alarm signal for invoking a hook, emitted by validators after alarm set conditions are met */
|
||||
TRANSACTION(ttCRON, 92, Cron, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
@@ -561,7 +550,6 @@ TRANSACTION(ttIMPORT, 97, Import, ({
|
||||
* from a specified hook */
|
||||
TRANSACTION(ttCLAIM_REWARD, 98, ClaimReward, ({
|
||||
{sfIssuer, soeOPTIONAL},
|
||||
{sfClaimCurrency, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction invokes a hook, providing arbitrary data. Essentially as a 0 drop payment. **/
|
||||
@@ -617,11 +605,3 @@ TRANSACTION(ttUNL_REPORT, 104, UNLReport, ({
|
||||
{sfActiveValidator, soeOPTIONAL},
|
||||
{sfImportVLKey, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
TRANSACTION(ttCONSENSUS_ENTROPY, 105, ConsensusEntropy, ({
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfDigest, soeREQUIRED},
|
||||
{sfEntropyCount, soeREQUIRED},
|
||||
{sfEntropyTier, soeREQUIRED},
|
||||
{sfBlob, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
@@ -76,7 +76,6 @@ JSS(Holder); // field.
|
||||
JSS(HookApiVersion); // field
|
||||
JSS(HookCanEmit); // field
|
||||
JSS(HookHash); // field
|
||||
JSS(HookName); // field
|
||||
JSS(HookNamespace); // field
|
||||
JSS(HookOn); // field
|
||||
JSS(HookOnIncoming); // field
|
||||
|
||||
@@ -109,22 +109,14 @@ public:
|
||||
Consumer
|
||||
newInboundEndpoint(beast::IP::Endpoint const& address)
|
||||
{
|
||||
//@@start rng-local-testnet-resource-bucket
|
||||
// Inbound connections from the same IP normally share one
|
||||
// resource bucket (port stripped) for DoS protection. For
|
||||
// loopback addresses, preserve the port so local testnet nodes
|
||||
// each get their own bucket instead of all sharing one.
|
||||
auto const key = is_loopback(address) ? address : address.at_port(0);
|
||||
//@@end rng-local-testnet-resource-bucket
|
||||
|
||||
Entry* entry(nullptr);
|
||||
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
auto [resultIt, resultInserted] = table_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(kindInbound, key),
|
||||
std::make_tuple(m_clock.now()));
|
||||
std::make_tuple(kindInbound, address.at_port(0)), // Key
|
||||
std::make_tuple(m_clock.now())); // Entry
|
||||
|
||||
entry = &resultIt->second;
|
||||
entry->key = &resultIt->first;
|
||||
|
||||
@@ -11,11 +11,11 @@ echo "START BUILDING (HOST)"
|
||||
echo "Cleaning previously built binary"
|
||||
rm -f release-build/xahaud
|
||||
|
||||
BUILD_CORES=$(echo "scale=0 ; $(nproc) / 1.337" | bc)
|
||||
BUILD_CORES=$(echo "scale=0 ; `nproc` / 1.337" | bc)
|
||||
|
||||
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
|
||||
#Default
|
||||
BUILD_CORES=${BUILD_CORES:-8}
|
||||
BUILD_CORES=${BUILD_CORES:-8}
|
||||
fi
|
||||
|
||||
# Ensure still works outside of GH Actions by setting these to /dev/null
|
||||
@@ -31,19 +31,21 @@ echo "-- GITHUB_SHA: $GITHUB_SHA"
|
||||
echo "-- GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER"
|
||||
echo "-- CONTAINER_NAME: $CONTAINER_NAME"
|
||||
|
||||
which docker 2>/dev/null 2>/dev/null
|
||||
if [ "$?" -eq "1" ]; then
|
||||
which docker 2> /dev/null 2> /dev/null
|
||||
if [ "$?" -eq "1" ]
|
||||
then
|
||||
echo 'Docker not found. Install it first.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
stat .git 2>/dev/null 2>/dev/null
|
||||
if [ "$?" -eq "1" ]; then
|
||||
stat .git 2> /dev/null 2> /dev/null
|
||||
if [ "$?" -eq "1" ]
|
||||
then
|
||||
echo 'Run this inside the source directory. (.git dir not found).'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME | wc -l)
|
||||
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME |wc -l)
|
||||
|
||||
CACHE_VOLUME_NAME="xahau-release-builder-cache"
|
||||
|
||||
@@ -55,14 +57,13 @@ if false; then
|
||||
docker stop $CONTAINER_NAME
|
||||
else
|
||||
echo "No static container, build on temp container"
|
||||
rm -rf release-build
|
||||
mkdir -p release-build
|
||||
rm -rf release-build;
|
||||
mkdir -p release-build;
|
||||
|
||||
docker volume create $CACHE_VOLUME_NAME
|
||||
|
||||
# Create inline Dockerfile with environment setup for build-full.sh
|
||||
DOCKERFILE_CONTENT=$(
|
||||
cat <<'DOCKERFILE_EOF'
|
||||
DOCKERFILE_CONTENT=$(cat <<'DOCKERFILE_EOF'
|
||||
FROM ghcr.io/phusion/holy-build-box:4.0.1-amd64
|
||||
|
||||
ARG BUILD_CORES=8
|
||||
@@ -217,7 +218,7 @@ RUN /hbb_exe/activate-exec bash -c "ccache -M 100G && \
|
||||
ln -s ../../bin/ccache /usr/lib64/ccache/c++"
|
||||
|
||||
DOCKERFILE_EOF
|
||||
)
|
||||
)
|
||||
|
||||
# Build custom Docker image
|
||||
IMAGE_NAME="xahaud-builder:latest"
|
||||
@@ -227,14 +228,14 @@ DOCKERFILE_EOF
|
||||
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
|
||||
# Non GH, local building
|
||||
echo "Non-GH runner, local building, temp container"
|
||||
docker run -i --user 0:$(id -g) --rm -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
|
||||
docker run -i --user 0:$(id -g) --rm -v /data/builds:/data/builds -v `pwd`:/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
|
||||
else
|
||||
# GH Action, runner
|
||||
echo "GH Action, runner, clean & re-create create persistent container"
|
||||
docker rm -f $CONTAINER_NAME
|
||||
echo "echo 'Stopping container: $CONTAINER_NAME'" >>"$JOB_CLEANUP_SCRIPT"
|
||||
echo "docker stop --time=15 \"$CONTAINER_NAME\" || echo 'Failed to stop container or container not running'" >>"$JOB_CLEANUP_SCRIPT"
|
||||
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash
|
||||
echo "echo 'Stopping container: $CONTAINER_NAME'" >> "$JOB_CLEANUP_SCRIPT"
|
||||
echo "docker stop --time=15 \"$CONTAINER_NAME\" || echo 'Failed to stop container or container not running'" >> "$JOB_CLEANUP_SCRIPT"
|
||||
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v `pwd`:/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash
|
||||
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
|
||||
docker stop $CONTAINER_NAME
|
||||
fi
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@@ -352,18 +351,9 @@ Logs::format(
|
||||
|
||||
if (useLocalTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local = date::make_zoned(date::current_zone(), now);
|
||||
output = date::format(fmt, local);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
// Enhanced logging should not make startup fatal if tzdb lookup is
|
||||
// unavailable or misconfigured. Fall back to UTC formatting.
|
||||
output = date::format(fmt, std::chrono::system_clock::now());
|
||||
}
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local = date::make_zoned(date::current_zone(), now);
|
||||
output = date::format(fmt, local);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ invalidAMMAsset(
|
||||
Issue const& issue,
|
||||
std::optional<std::pair<Issue, Issue>> const& pair)
|
||||
{
|
||||
if (isBadCurrency(issue.currency))
|
||||
if (badCurrency() == issue.currency)
|
||||
return temBAD_CURRENCY;
|
||||
if (isXRP(issue) && issue.account.isNonZero())
|
||||
return temBAD_ISSUER;
|
||||
|
||||
@@ -250,9 +250,12 @@ FeatureCollections::registerFeature(
|
||||
Feature const* i = getByName(name);
|
||||
if (!i)
|
||||
{
|
||||
// If this check fails, and you just added a feature, increase the
|
||||
// numFeatures value in Feature.h
|
||||
check(
|
||||
features.size() < detail::numFeatures,
|
||||
"More features defined than allocated.");
|
||||
"More features defined than allocated. Adjust numFeatures in "
|
||||
"Feature.h.");
|
||||
|
||||
auto const f = sha512Half(Slice(name.data(), name.size()));
|
||||
|
||||
@@ -421,26 +424,45 @@ featureToName(uint256 const& f)
|
||||
#undef XRPL_FEATURE
|
||||
#pragma push_macro("XRPL_FIX")
|
||||
#undef XRPL_FIX
|
||||
#pragma push_macro("XRPL_RETIRE")
|
||||
#undef XRPL_RETIRE
|
||||
|
||||
#define XRPL_FEATURE(name, supported, vote) \
|
||||
uint256 const feature##name = registerFeature(#name, supported, vote);
|
||||
#define XRPL_FIX(name, supported, vote) \
|
||||
uint256 const fix##name = registerFeature("fix" #name, supported, vote);
|
||||
#define XRPL_RETIRE(name) \
|
||||
[[deprecated("The referenced amendment has been retired"), maybe_unused]] \
|
||||
uint256 const retired##name = retireFeature(#name);
|
||||
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
|
||||
#undef XRPL_RETIRE
|
||||
#pragma pop_macro("XRPL_RETIRE")
|
||||
#undef XRPL_FIX
|
||||
#pragma pop_macro("XRPL_FIX")
|
||||
#undef XRPL_FEATURE
|
||||
#pragma pop_macro("XRPL_FEATURE")
|
||||
|
||||
// clang-format off
|
||||
|
||||
// The following amendments have been active for at least two years. Their
|
||||
// pre-amendment code has been removed and the identifiers are deprecated.
|
||||
// All known amendments and amendments that may appear in a validated
|
||||
// ledger must be registered either here or above with the "active" amendments
|
||||
[[deprecated("The referenced amendment has been retired"), maybe_unused]]
|
||||
uint256 const
|
||||
retiredMultiSign = retireFeature("MultiSign"),
|
||||
retiredTrustSetAuth = retireFeature("TrustSetAuth"),
|
||||
retiredFeeEscalation = retireFeature("FeeEscalation"),
|
||||
retiredPayChan = retireFeature("PayChan"),
|
||||
retiredCryptoConditions = retireFeature("CryptoConditions"),
|
||||
retiredTickSize = retireFeature("TickSize"),
|
||||
retiredFix1368 = retireFeature("fix1368"),
|
||||
retiredEscrow = retireFeature("Escrow"),
|
||||
retiredFix1373 = retireFeature("fix1373"),
|
||||
retiredEnforceInvariants = retireFeature("EnforceInvariants"),
|
||||
retiredSortedDirectories = retireFeature("SortedDirectories"),
|
||||
retiredFix1201 = retireFeature("fix1201"),
|
||||
retiredFix1512 = retireFeature("fix1512"),
|
||||
retiredFix1523 = retireFeature("fix1523"),
|
||||
retiredFix1528 = retireFeature("fix1528");
|
||||
|
||||
// clang-format on
|
||||
|
||||
// All of the features should now be registered, since variables in a cpp file
|
||||
// are initialized from top to bottom.
|
||||
//
|
||||
|
||||
@@ -74,7 +74,6 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
HOOK_DEFINITION = 'D',
|
||||
EMITTED_TXN = 'E',
|
||||
EMITTED_DIR = 'F',
|
||||
SHADOW_TICKET = 0x5374, // St
|
||||
NFTOKEN_OFFER = 'q',
|
||||
NFTOKEN_BUY_OFFERS = 'h',
|
||||
NFTOKEN_SELL_OFFERS = 'i',
|
||||
@@ -82,7 +81,6 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
IMPORT_VLSEQ = 'I',
|
||||
UNL_REPORT = 'R',
|
||||
CRON = 'L',
|
||||
CONSENSUS_ENTROPY = 'X',
|
||||
AMM = 'A',
|
||||
BRIDGE = LEDGER_NAMESPACE2(0x01, 'H'),
|
||||
XCHAIN_CLAIM_ID = 'Q',
|
||||
@@ -190,15 +188,6 @@ emittedTxn(uint256 const& id) noexcept
|
||||
return {ltEMITTED_TXN, indexHash(LedgerNameSpace::EMITTED_TXN, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
shadowTicket(AccountID const& account, std::uint32_t ticketSeq) noexcept
|
||||
{
|
||||
return {
|
||||
ltSHADOW_TICKET,
|
||||
indexHash(
|
||||
LedgerNameSpace::SHADOW_TICKET, account, std::uint32_t(ticketSeq))};
|
||||
}
|
||||
|
||||
Keylet
|
||||
hook(AccountID const& id) noexcept
|
||||
{
|
||||
@@ -557,14 +546,6 @@ cron(uint32_t timestamp, std::optional<AccountID> const& id)
|
||||
return {ltCRON, uint256::fromVoid(h)};
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
consensusEntropy() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltCONSENSUS_ENTROPY, indexHash(LedgerNameSpace::CONSENSUS_ENTROPY)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Keylet
|
||||
amm(Asset const& issue1, Asset const& issue2) noexcept
|
||||
{
|
||||
|
||||
@@ -78,7 +78,6 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfHookExecutionIndex, soeREQUIRED},
|
||||
{sfHookStateChangeCount, soeREQUIRED},
|
||||
{sfHookEmitCount, soeREQUIRED},
|
||||
{sfHookExportCount, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL}});
|
||||
|
||||
add(sfHookEmission.jsonName,
|
||||
@@ -100,7 +99,7 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfHookOnOutgoing, soeOPTIONAL},
|
||||
{sfHookCanEmit, soeOPTIONAL},
|
||||
{sfHookApiVersion, soeOPTIONAL},
|
||||
{sfHookName, soeOPTIONAL},
|
||||
{sfFee, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL}});
|
||||
|
||||
add(sfHookGrant.jsonName,
|
||||
@@ -255,24 +254,6 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
});
|
||||
|
||||
add(sfHighReward.jsonName,
|
||||
sfHighReward.getCode(),
|
||||
{
|
||||
{sfRewardLgrFirst, soeREQUIRED},
|
||||
{sfRewardLgrLast, soeREQUIRED},
|
||||
{sfRewardTime, soeREQUIRED},
|
||||
{sfTrustLineRewardAccumulator, soeREQUIRED},
|
||||
});
|
||||
|
||||
add(sfLowReward.jsonName,
|
||||
sfLowReward.getCode(),
|
||||
{
|
||||
{sfRewardLgrFirst, soeREQUIRED},
|
||||
{sfRewardLgrLast, soeREQUIRED},
|
||||
{sfRewardTime, soeREQUIRED},
|
||||
{sfTrustLineRewardAccumulator, soeREQUIRED},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -111,7 +111,7 @@ issueFromJson(Json::Value const& v)
|
||||
}
|
||||
|
||||
auto const currency = to_currency(curStr.asString());
|
||||
if (isBadCurrency(currency) || currency == noCurrency())
|
||||
if (currency == badCurrency() || currency == noCurrency())
|
||||
{
|
||||
Throw<Json::error>("issueFromJson currency must be a valid currency");
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ currencyFromJson(SField const& name, Json::Value const& v)
|
||||
}
|
||||
|
||||
auto const currency = to_currency(v.asString());
|
||||
if (isBadCurrency(currency) || currency == noCurrency())
|
||||
if (currency == badCurrency() || currency == noCurrency())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"currencyFromJson currency must be a valid currency");
|
||||
|
||||
@@ -684,8 +684,7 @@ isPseudoTx(STObject const& tx)
|
||||
|
||||
auto tt = safe_cast<TxType>(*t);
|
||||
return tt == ttAMENDMENT || tt == ttFEE || tt == ttUNL_MODIFY ||
|
||||
tt == ttEMIT_FAILURE || tt == ttUNL_REPORT || tt == ttCRON ||
|
||||
tt == ttCONSENSUS_ENTROPY;
|
||||
tt == ttEMIT_FAILURE || tt == ttUNL_REPORT || tt == ttCRON;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -124,7 +124,7 @@ transResults()
|
||||
MAKE_ERROR(tecARRAY_TOO_LARGE, "Array is too large."),
|
||||
MAKE_ERROR(tecLOCKED, "Fund is locked."),
|
||||
MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."),
|
||||
MAKE_ERROR(tecEXPORT_EXPIRED, "Export expired without reaching signature quorum."),
|
||||
MAKE_ERROR(tecINVALID_HOOK_API_VERSION, "Invalid field for current hook API version."),
|
||||
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
@@ -172,7 +172,6 @@ transResults()
|
||||
MAKE_ERROR(telNON_LOCAL_EMITTED_TXN, "Emitted transaction cannot be applied because it was not generated locally."),
|
||||
MAKE_ERROR(telIMPORT_VL_KEY_NOT_RECOGNISED, "Import vl key was not recognized."),
|
||||
MAKE_ERROR(telCAN_NOT_QUEUE_IMPORT, "Import transaction was not able to be directly applied and cannot be queued."),
|
||||
MAKE_ERROR(telSHADOW_TICKET_REQUIRED, "The imported transaction uses a TicketSequence but no shadow ticket exists."),
|
||||
MAKE_ERROR(telENV_RPC_FAILED, "Unit test RPC failure."),
|
||||
|
||||
MAKE_ERROR(temMALFORMED, "Malformed transaction."),
|
||||
@@ -240,7 +239,6 @@ transResults()
|
||||
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
||||
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
|
||||
MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."),
|
||||
MAKE_ERROR(terRETRY_EXPORT, "Export awaiting validator signatures."),
|
||||
|
||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||
MAKE_ERROR(tesPARTIAL, "The transaction was applied but should be submitted again until returning tesSUCCESS."),
|
||||
|
||||
@@ -48,7 +48,6 @@ TxFormats::TxFormats()
|
||||
{sfFirstLedgerSequence, soeOPTIONAL},
|
||||
{sfNetworkID, soeOPTIONAL},
|
||||
{sfHookParameters, soeOPTIONAL},
|
||||
{sfHookName, soeOPTIONAL},
|
||||
};
|
||||
|
||||
#pragma push_macro("UNWRAP")
|
||||
|
||||
@@ -49,11 +49,6 @@ TxMeta::TxMeta(
|
||||
|
||||
if (obj.isFieldPresent(sfHookEmissions))
|
||||
setHookEmissions(obj.getFieldArray(sfHookEmissions));
|
||||
|
||||
if (obj.isFieldPresent(sfExportResult))
|
||||
setExportResult(const_cast<STObject&>(obj)
|
||||
.getField(sfExportResult)
|
||||
.downcast<STObject>());
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
|
||||
@@ -80,11 +75,6 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
|
||||
|
||||
if (obj.isFieldPresent(sfHookEmissions))
|
||||
setHookEmissions(obj.getFieldArray(sfHookEmissions));
|
||||
|
||||
if (obj.isFieldPresent(sfExportResult))
|
||||
setExportResult(const_cast<STObject&>(obj)
|
||||
.getField(sfExportResult)
|
||||
.downcast<STObject>());
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
|
||||
@@ -255,14 +245,6 @@ TxMeta::getAsObject() const
|
||||
if (hasHookEmissions())
|
||||
metaData.setFieldArray(sfHookEmissions, getHookEmissions());
|
||||
|
||||
if (hasExportResult())
|
||||
{
|
||||
Serializer s;
|
||||
mExportResult->add(s);
|
||||
SerialIter sit(s.slice());
|
||||
metaData.emplace_back(STObject(sit, sfExportResult));
|
||||
}
|
||||
|
||||
return metaData;
|
||||
}
|
||||
|
||||
|
||||
820
src/quickjs/buffer-utils.c
Normal file
820
src/quickjs/buffer-utils.c
Normal file
@@ -0,0 +1,820 @@
|
||||
#include "defines.h"
|
||||
#include "char-utils.h"
|
||||
#include "buffer-utils.h"
|
||||
#include "utils.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif defined(HAVE_TERMIOS_H)
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* \addtogroup buffer-utils
|
||||
* @{
|
||||
*/
|
||||
size_t
|
||||
ansi_length(const char* str, size_t len) {
|
||||
size_t i, n = 0, p;
|
||||
for(i = 0; i < len;) {
|
||||
if(str[i] == 0x1b && (p = ansi_skip(&str[i], len - i)) > 0) {
|
||||
i += p;
|
||||
continue;
|
||||
}
|
||||
n++;
|
||||
i++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
ansi_skip(const char* str, size_t len) {
|
||||
size_t pos = 0;
|
||||
if(str[pos] == 0x1b) {
|
||||
if(++pos < len && str[pos] == '[') {
|
||||
while(++pos < len)
|
||||
if(is_alphanumeric_char(str[pos]))
|
||||
break;
|
||||
if(++pos < len && str[pos] == '~')
|
||||
++pos;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
ansi_truncate(const char* str, size_t len, size_t limit) {
|
||||
size_t i, n = 0, p;
|
||||
for(i = 0; i < len;) {
|
||||
if((p = ansi_skip(&str[i], len - i)) > 0) {
|
||||
i += p;
|
||||
continue;
|
||||
}
|
||||
n += is_escape_char(str[i]) ? 2 : 1;
|
||||
|
||||
i++;
|
||||
if(n > limit)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int64_t
|
||||
array_search(void* a, size_t m, size_t elsz, void* needle) {
|
||||
char* ptr = a;
|
||||
int64_t n, ret;
|
||||
n = m / elsz;
|
||||
for(ret = 0; ret < n; ret++) {
|
||||
if(!memcmp(ptr, needle, elsz))
|
||||
return ret;
|
||||
|
||||
ptr += elsz;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char*
|
||||
str_escape(const char* s) {
|
||||
DynBuf dbuf;
|
||||
dbuf_init2(&dbuf, 0, 0);
|
||||
dbuf_put_escaped(&dbuf, s, strlen(s));
|
||||
dbuf_0(&dbuf);
|
||||
return (char*)dbuf.buf;
|
||||
}
|
||||
|
||||
char*
|
||||
byte_escape(const void* s, size_t n) {
|
||||
DynBuf dbuf;
|
||||
dbuf_init2(&dbuf, 0, 0);
|
||||
dbuf_put_escaped(&dbuf, s, n);
|
||||
dbuf_0(&dbuf);
|
||||
return (char*)dbuf.buf;
|
||||
}
|
||||
|
||||
size_t
|
||||
byte_findb(const void* haystack, size_t hlen, const void* what, size_t wlen) {
|
||||
size_t i, last;
|
||||
const char* s = (const char*)haystack;
|
||||
if(hlen < wlen)
|
||||
return hlen;
|
||||
last = hlen - wlen;
|
||||
for(i = 0; i <= last; i++) {
|
||||
if(byte_equal(s, wlen, what))
|
||||
return i;
|
||||
s++;
|
||||
}
|
||||
return hlen;
|
||||
}
|
||||
|
||||
size_t
|
||||
byte_finds(const void* haystack, size_t hlen, const char* what) {
|
||||
return byte_findb(haystack, hlen, what, strlen(what));
|
||||
}
|
||||
|
||||
size_t
|
||||
byte_equal(const void* s, size_t n, const void* t) {
|
||||
return memcmp(s, t, n) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
byte_copy(void* out, size_t len, const void* in) {
|
||||
char* s = (char*)out;
|
||||
const char* t = (const char*)in;
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i)
|
||||
s[i] = t[i];
|
||||
}
|
||||
|
||||
void
|
||||
byte_copyr(void* out, size_t len, const void* in) {
|
||||
char* s = (char*)out + len;
|
||||
const char* t = (const char*)in;
|
||||
const char* u = t + len;
|
||||
|
||||
for(;;) {
|
||||
if(t >= u)
|
||||
break;
|
||||
--u;
|
||||
--s;
|
||||
*s = *u;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
byte_rchrs(const char* in, size_t len, const char needles[], size_t nn) {
|
||||
const char *s = in, *end = in + len, *found = 0;
|
||||
size_t i;
|
||||
for(; s < end; s++) {
|
||||
for(i = 0; i < nn; ++i) {
|
||||
if(*s == needles[i])
|
||||
found = s;
|
||||
}
|
||||
}
|
||||
return (size_t)((found ? found : s) - in);
|
||||
}
|
||||
|
||||
char*
|
||||
dbuf_at_n(const DynBuf* db, size_t i, size_t* n, char sep) {
|
||||
size_t p, l = 0;
|
||||
for(p = 0; p < db->size; ++p) {
|
||||
if(l == i) {
|
||||
*n = byte_chr((const char*)&db->buf[p], db->size - p, sep);
|
||||
return (char*)&db->buf[p];
|
||||
}
|
||||
if(db->buf[p] == sep)
|
||||
++l;
|
||||
}
|
||||
*n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char*
|
||||
dbuf_last_line(DynBuf* db, size_t* len) {
|
||||
size_t i;
|
||||
|
||||
if((i = byte_rchr(db->buf, db->size, '\n')) < db->size)
|
||||
i++;
|
||||
else
|
||||
i = 0;
|
||||
|
||||
if(len)
|
||||
*len = db->size - i;
|
||||
|
||||
return (const char*)&db->buf[i];
|
||||
}
|
||||
|
||||
int
|
||||
dbuf_prepend(DynBuf* s, const uint8_t* data, size_t len) {
|
||||
int ret;
|
||||
if(!(ret = dbuf_reserve_start(s, len)))
|
||||
memcpy(s->buf, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_colorstr(DynBuf* db, const char* str, const char* color, int with_color) {
|
||||
if(with_color)
|
||||
dbuf_putstr(db, color);
|
||||
|
||||
dbuf_putstr(db, str);
|
||||
if(with_color)
|
||||
dbuf_putstr(db, COLOR_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_escaped_pred(DynBuf* db, const char* str, size_t len, int (*pred)(int)) {
|
||||
size_t i = 0, j;
|
||||
char c;
|
||||
|
||||
while(i < len) {
|
||||
if((j = predicate_find(&str[i], len - i, pred))) {
|
||||
dbuf_append(db, (const uint8_t*)&str[i], j);
|
||||
i += j;
|
||||
}
|
||||
|
||||
if(i == len)
|
||||
break;
|
||||
|
||||
dbuf_putc(db, '\\');
|
||||
|
||||
if(str[i] == 0x1b) {
|
||||
dbuf_append(db, (const uint8_t*)"x1b", 3);
|
||||
} else {
|
||||
int r = pred(str[i]);
|
||||
|
||||
dbuf_putc(db, (r > 1 && r <= 127) ? r : (c = escape_char_letter(str[i])) ? c : str[i]);
|
||||
|
||||
if(r == 'u' || r == 'x')
|
||||
dbuf_printf(db, r == 'u' ? "%04x" : "%02x", str[i]);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t escape_url_tab[256] = {
|
||||
'%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%',
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '%',
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
'%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%', '%',
|
||||
};
|
||||
|
||||
const uint8_t escape_noquote_tab[256] = {
|
||||
'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 0x62, 0x74, 0x6e, 0x76, 0x66, 0x72, 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
|
||||
'x', 'x', 'x', 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
};
|
||||
|
||||
const uint8_t escape_singlequote_tab[256] = {
|
||||
'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 0x62, 0x74, 0x6e, 0x76, 0x66, 0x72, 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
|
||||
'x', 'x', 'x', 'x', 0, 0, 0, 0, 0, 0, 0, 0x27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
};
|
||||
|
||||
const uint8_t escape_doublequote_tab[256] = {
|
||||
'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 0x62, 0x74, 0x6e, 0x76, 0x66, 0x72, 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
|
||||
|
||||
'x', 'x', 'x', 'x', 0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
};
|
||||
|
||||
const uint8_t escape_backquote_tab[256] = {
|
||||
'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 0x62, 0x74, 0, 0x76, 0x66, 0, 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
|
||||
'x', 'x', 'x', 'x', 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'u', 'u', 'u', 'u', 'u',
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
|
||||
};
|
||||
|
||||
void
|
||||
dbuf_put_escaped_table(DynBuf* db, const char* str, size_t len, const uint8_t table[256]) {
|
||||
size_t i = 0, clen;
|
||||
int32_t c;
|
||||
const uint8_t *pos, *end, *next;
|
||||
|
||||
for(pos = (const uint8_t*)str, end = pos + len; pos < end; pos = next) {
|
||||
uint8_t r, ch;
|
||||
|
||||
if((c = unicode_from_utf8(pos, end - pos, &next)) < 0)
|
||||
break;
|
||||
clen = next - pos;
|
||||
ch = c;
|
||||
r = (clen >= 2 || c > 0xff) ? 'u' : table[c];
|
||||
|
||||
if(r == 'u' && clen > 1 && (c & 0xffffff00) == 0) {
|
||||
r = 'x';
|
||||
// ch = c >> 8;
|
||||
}
|
||||
|
||||
if(r == '%') {
|
||||
static const char hexdigits[] = "0123456789ABCDEF";
|
||||
|
||||
dbuf_putc(db, '%');
|
||||
dbuf_putc(db, hexdigits[c >> 4]);
|
||||
dbuf_putc(db, hexdigits[c & 0xf]);
|
||||
} else if(c == 0x1b) {
|
||||
dbuf_putstr(db, "\\x1b");
|
||||
} else if(r == 'u') {
|
||||
dbuf_printf(db, c > 0xffff ? "\\u{%X}" : "\\u%04x", c);
|
||||
} else if(r == 'x') {
|
||||
dbuf_printf(db, "\\x%02x", ch);
|
||||
} else if(r) {
|
||||
dbuf_putc(db, '\\');
|
||||
dbuf_putc(db, (r > 1 && r <= 127) ? r : (c = escape_char_letter(ch)) ? c : ch);
|
||||
} else {
|
||||
dbuf_put(db, pos, next - pos);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_unescaped_pred(DynBuf* db, const char* str, size_t len, int (*pred)(const char*, size_t*)) {
|
||||
size_t i = 0, j;
|
||||
// char c;
|
||||
|
||||
while(i < len) {
|
||||
int r = 0;
|
||||
if((j = byte_chr(&str[i], len - i, '\\'))) {
|
||||
dbuf_append(db, (const uint8_t*)&str[i], j);
|
||||
i += j;
|
||||
}
|
||||
if(i == len)
|
||||
break;
|
||||
size_t n = 1;
|
||||
|
||||
if(pred) {
|
||||
r = pred(&str[i + 1], &n);
|
||||
|
||||
if(!r && n == 1)
|
||||
dbuf_putc(db, '\\');
|
||||
}
|
||||
|
||||
if(r >= 0)
|
||||
dbuf_putc(db, /*n > 1 ||*/ r ? /*(r > 1 && r < 256) ?*/ r : str[i]);
|
||||
i += n;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
hexdigit(char c) {
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
|
||||
if(c >= 'a' && c <= 'f')
|
||||
c -= 32;
|
||||
|
||||
if(c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_unescaped_table(DynBuf* db, const char* str, size_t len, const uint8_t table[256]) {
|
||||
size_t i = 0, j;
|
||||
char escape_char = table == escape_url_tab ? '%' : '\\';
|
||||
|
||||
while(i < len) {
|
||||
if((j = byte_chr(&str[i], len - i, escape_char))) {
|
||||
dbuf_append(db, (const uint8_t*)&str[i], j);
|
||||
i += j;
|
||||
}
|
||||
|
||||
if(i == len)
|
||||
break;
|
||||
|
||||
if(escape_char == '%') {
|
||||
int hi = hexdigit(str[i + 1]), lo = hexdigit(str[i + 2]);
|
||||
uint8_t c = (hi << 4) | (lo & 0xf);
|
||||
dbuf_putc(db, c);
|
||||
|
||||
i += 2;
|
||||
|
||||
} else {
|
||||
++i;
|
||||
|
||||
uint8_t c;
|
||||
|
||||
switch(str[i]) {
|
||||
case 'b': c = '\b'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'v': c = '\v'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
default: c = str[i]; break;
|
||||
}
|
||||
|
||||
uint8_t r = table[c];
|
||||
|
||||
if(!(r && r != 'x' && r != 'u')) {
|
||||
dbuf_putc(db, '\\');
|
||||
dbuf_putc(db, c);
|
||||
} else {
|
||||
dbuf_putc(db, str[i] == r ? c : r);
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_escaped(DynBuf* db, const char* str, size_t len) {
|
||||
return dbuf_put_escaped_table(db, str, len, escape_noquote_tab);
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_value(DynBuf* db, JSContext* ctx, JSValueConst value) {
|
||||
const char* str;
|
||||
size_t len;
|
||||
str = JS_ToCStringLen(ctx, &len, value);
|
||||
dbuf_append(db, str, len);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_uint32(DynBuf* db, uint32_t num) {
|
||||
char buf[FMT_ULONG];
|
||||
dbuf_put(db, (const uint8_t*)buf, fmt_ulong(buf, num));
|
||||
}
|
||||
|
||||
void
|
||||
dbuf_put_atom(DynBuf* db, JSContext* ctx, JSAtom atom) {
|
||||
const char* str;
|
||||
str = JS_AtomToCString(ctx, atom);
|
||||
dbuf_putstr(db, str);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
|
||||
int
|
||||
dbuf_reserve_start(DynBuf* s, size_t len) {
|
||||
if(unlikely((s->size + len) > s->allocated_size)) {
|
||||
if(dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
if(s->size > 0)
|
||||
memcpy(s->buf + len, s->buf, s->size);
|
||||
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
dbuf_reserve(DynBuf* s, size_t len) {
|
||||
if(unlikely((s->size + len) > s->allocated_size))
|
||||
if(dbuf_realloc(s, s->size + len))
|
||||
return 0;
|
||||
|
||||
return &s->buf[s->size];
|
||||
}
|
||||
|
||||
size_t
|
||||
dbuf_token_pop(DynBuf* db, char delim) {
|
||||
size_t n, p, len;
|
||||
len = db->size;
|
||||
for(n = db->size; n > 0;) {
|
||||
if((p = byte_rchr(db->buf, n, delim)) == n) {
|
||||
db->size = 0;
|
||||
break;
|
||||
}
|
||||
if(p > 0 && db->buf[p - 1] == '\\') {
|
||||
n = p - 1;
|
||||
continue;
|
||||
}
|
||||
db->size = p;
|
||||
break;
|
||||
}
|
||||
return len - db->size;
|
||||
}
|
||||
|
||||
size_t
|
||||
dbuf_token_push(DynBuf* db, const char* str, size_t len, char delim) {
|
||||
size_t pos;
|
||||
if(db->size)
|
||||
dbuf_putc(db, delim);
|
||||
|
||||
pos = db->size;
|
||||
dbuf_put_escaped_pred(db, str, len, is_dot_char);
|
||||
return db->size - pos;
|
||||
}
|
||||
|
||||
JSValue
|
||||
dbuf_tostring_free(DynBuf* s, JSContext* ctx) {
|
||||
JSValue r;
|
||||
r = JS_NewStringLen(ctx, s->buf ? (const char*)s->buf : "", s->buf ? s->size : 0);
|
||||
dbuf_free(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
dbuf_load(DynBuf* s, const char* filename) {
|
||||
FILE* fp;
|
||||
size_t nbytes = 0;
|
||||
if((fp = fopen(filename, "rb"))) {
|
||||
char buf[4096];
|
||||
size_t r;
|
||||
while(!feof(fp)) {
|
||||
if((r = fread(buf, 1, sizeof(buf), fp)) == 0) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
dbuf_put(s, (uint8_t const*)buf, r);
|
||||
nbytes += r;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
int
|
||||
dbuf_vprintf(DynBuf* s, const char* fmt, va_list ap) {
|
||||
|
||||
s->size += vsnprintf((char*)(s->buf + s->size), s->allocated_size - s->size, fmt, ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
InputBuffer
|
||||
js_input_buffer(JSContext* ctx, JSValueConst value) {
|
||||
InputBuffer ret = {{{0, 0}}, 0, &input_buffer_free_default, JS_UNDEFINED, {0, INT64_MAX}};
|
||||
|
||||
if(js_is_typedarray(ctx, value)) {
|
||||
ret.value = offset_typedarray(&ret.range, value, ctx);
|
||||
} else if(js_is_arraybuffer(ctx, value) || js_is_sharedarraybuffer(ctx, value)) {
|
||||
ret.value = JS_DupValue(ctx, value);
|
||||
}
|
||||
|
||||
if(js_is_arraybuffer(ctx, ret.value) || js_is_sharedarraybuffer(ctx, ret.value)) {
|
||||
block_arraybuffer(&ret.block, ret.value, ctx);
|
||||
} else {
|
||||
JS_ThrowTypeError(ctx, "Invalid type (%s) for input buffer", js_value_typestr(ctx, ret.value));
|
||||
JS_FreeValue(ctx, ret.value);
|
||||
ret.value = JS_EXCEPTION;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef free
|
||||
|
||||
InputBuffer
|
||||
js_input_chars(JSContext* ctx, JSValueConst value) {
|
||||
InputBuffer ret = {{{0, 0}}, 0, &input_buffer_free_default, JS_UNDEFINED, OFFSET_INIT()};
|
||||
|
||||
if(JS_IsString(value)) {
|
||||
ret.data = (uint8_t*)JS_ToCStringLen(ctx, &ret.size, value);
|
||||
ret.value = JS_DupValue(ctx, value);
|
||||
ret.free = &input_buffer_free_default;
|
||||
} else {
|
||||
ret = js_input_buffer(ctx, value);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
InputBuffer
|
||||
js_input_args(JSContext* ctx, int argc, JSValueConst argv[]) {
|
||||
InputBuffer input = js_input_chars(ctx, argv[0]);
|
||||
|
||||
if(argc > 1)
|
||||
js_offset_length(ctx, input.size, argc - 1, argv + 1, &input.range);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
InputBuffer
|
||||
js_output_args(JSContext* ctx, int argc, JSValueConst argv[]) {
|
||||
InputBuffer output = js_input_buffer(ctx, argv[0]);
|
||||
|
||||
if(argc > 1)
|
||||
js_offset_length(ctx, output.size, argc - 1, argv + 1, &output.range);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
BOOL
|
||||
input_buffer_valid(const InputBuffer* in) {
|
||||
return !JS_IsException(in->value);
|
||||
}
|
||||
|
||||
InputBuffer
|
||||
input_buffer_clone(const InputBuffer* in, JSContext* ctx) {
|
||||
InputBuffer ret = js_input_buffer(ctx, in->value);
|
||||
|
||||
ret.pos = in->pos;
|
||||
ret.size = in->size;
|
||||
ret.free = in->free;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
input_buffer_dump(const InputBuffer* in, DynBuf* db) {
|
||||
dbuf_printf(db, "(InputBuffer){ .data = %p, .size = %lu, .pos = %lu, .free = %p }", in->data, (unsigned long)in->size, (unsigned long)in->pos, in->free);
|
||||
}
|
||||
|
||||
void
|
||||
input_buffer_free(InputBuffer* in, JSContext* ctx) {
|
||||
if(in->data) {
|
||||
in->free(ctx, (const char*)in->data, in->value);
|
||||
in->data = 0;
|
||||
in->size = 0;
|
||||
in->pos = 0;
|
||||
in->value = JS_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
input_buffer_peek(InputBuffer* in, size_t* lenp) {
|
||||
input_buffer_peekc(in, lenp);
|
||||
return input_buffer_data(in) + in->pos;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
input_buffer_get(InputBuffer* in, size_t* lenp) {
|
||||
const uint8_t* ret = input_buffer_peek(in, lenp);
|
||||
|
||||
in->pos += *lenp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char*
|
||||
input_buffer_currentline(InputBuffer* in, size_t* len) {
|
||||
size_t i;
|
||||
|
||||
if((i = byte_rchr(input_buffer_data(in), in->pos, '\n')) < in->pos)
|
||||
i++;
|
||||
|
||||
if(len)
|
||||
*len = in->pos - i;
|
||||
|
||||
return (const char*)&input_buffer_data(in)[i];
|
||||
}
|
||||
|
||||
size_t
|
||||
input_buffer_column(InputBuffer* in, size_t* len) {
|
||||
size_t i;
|
||||
|
||||
if((i = byte_rchr(input_buffer_data(in), in->pos, '\n')) < in->pos)
|
||||
i++;
|
||||
|
||||
return in->pos - i;
|
||||
}
|
||||
|
||||
int
|
||||
js_offset_length(JSContext* ctx, int64_t size, int argc, JSValueConst argv[], OffsetLength* off_len_p) {
|
||||
int ret = 0;
|
||||
int64_t off = 0, len = size;
|
||||
|
||||
if(argc >= 1 && JS_IsNumber(argv[0])) {
|
||||
if(!JS_ToInt64(ctx, &off, argv[0]))
|
||||
ret = 1;
|
||||
|
||||
if(argc >= 2 && JS_IsNumber(argv[1]))
|
||||
if(!JS_ToInt64(ctx, &len, argv[1]))
|
||||
ret = 2;
|
||||
|
||||
if(size && off != size)
|
||||
off = ((off % size) + size) % size;
|
||||
|
||||
if(len >= 0)
|
||||
len = MIN_NUM(len, size - off);
|
||||
else
|
||||
len = size - off;
|
||||
|
||||
if(off_len_p) {
|
||||
off_len_p->offset = off;
|
||||
off_len_p->length = len;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
js_index_range(JSContext* ctx, int64_t size, int argc, JSValueConst argv[], IndexRange* idx_rng_p) {
|
||||
int ret = 0;
|
||||
int64_t start = 0, end = size;
|
||||
|
||||
if(argc >= 1 && JS_IsNumber(argv[0])) {
|
||||
if(!JS_ToInt64(ctx, &start, argv[0]))
|
||||
ret = 1;
|
||||
|
||||
if(argc >= 2 && JS_IsNumber(argv[1]))
|
||||
if(!JS_ToInt64(ctx, &end, argv[1]))
|
||||
ret = 2;
|
||||
|
||||
if(size > 0) {
|
||||
start = ((start % size) + size) % size;
|
||||
end = ((end % size) + size) % size;
|
||||
}
|
||||
|
||||
if(end > size)
|
||||
end = size;
|
||||
|
||||
if(idx_rng_p) {
|
||||
idx_rng_p->start = start;
|
||||
idx_rng_p->end = end;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
screen_size(int size[2]) {
|
||||
#ifdef _WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
||||
size[0] = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
size[1] = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||
return 0;
|
||||
|
||||
#elif defined(HAVE_TERMIOS_H)
|
||||
{
|
||||
struct winsize w = {.ws_col = -1, .ws_row = -1};
|
||||
|
||||
if(isatty(STDIN_FILENO))
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
|
||||
else if(isatty(STDOUT_FILENO))
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
else if(isatty(STDERR_FILENO))
|
||||
ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
size[0] = w.ws_col;
|
||||
size[1] = w.ws_row;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
size[0] = 80;
|
||||
size[1] = 25;
|
||||
return 0;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef js_realloc_rt
|
||||
void
|
||||
js_dbuf_allocator(JSContext* ctx, DynBuf* s) {
|
||||
dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc*)js_realloc_rt);
|
||||
}
|
||||
|
||||
inline int
|
||||
input_buffer_peekc(InputBuffer* in, size_t* lenp) {
|
||||
const uint8_t *pos, *end, *next;
|
||||
int cp;
|
||||
pos = input_buffer_data(in) + in->pos;
|
||||
end = input_buffer_data(in) + input_buffer_length(in);
|
||||
cp = unicode_from_utf8(pos, end - pos, &next);
|
||||
|
||||
*lenp = next - pos;
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
inline int
|
||||
input_buffer_putc(InputBuffer* in, unsigned int c, JSContext* ctx) {
|
||||
int len;
|
||||
|
||||
if(in->pos + UTF8_CHAR_LEN_MAX > in->size)
|
||||
if(block_realloc(&in->block, in->pos + UTF8_CHAR_LEN_MAX, ctx))
|
||||
return -1;
|
||||
|
||||
len = unicode_to_utf8(&in->data[in->pos], c);
|
||||
|
||||
in->pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
dbuf_bitflags(DynBuf* db, uint32_t bits, const char* const names[]) {
|
||||
size_t i, n = 0;
|
||||
for(i = 0; i < sizeof(bits) * 8; i++) {
|
||||
if(bits & (1 << i)) {
|
||||
size_t len = strlen(names[i]);
|
||||
if(n) {
|
||||
n++;
|
||||
dbuf_putstr(db, "|");
|
||||
}
|
||||
dbuf_append(db, names[i], len);
|
||||
n += len;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
348
src/quickjs/buffer-utils.h
Normal file
348
src/quickjs/buffer-utils.h
Normal file
@@ -0,0 +1,348 @@
|
||||
#ifndef BUFFER_UTILS_H
|
||||
#define BUFFER_UTILS_H
|
||||
|
||||
#include <quickjs.h>
|
||||
#include <cutils.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "char-utils.h"
|
||||
|
||||
/**
|
||||
* \defgroup buffer-utils buffer-utils: Buffer Utilities
|
||||
* @{
|
||||
*/
|
||||
int64_t array_search(void* a, size_t m, size_t elsz, void* needle);
|
||||
#define array_contains(a, m, elsz, needle) (array_search((a), (m), (elsz), (needle)) != -1)
|
||||
|
||||
size_t ansi_length(const char*, size_t);
|
||||
size_t ansi_skip(const char*, size_t);
|
||||
size_t ansi_truncate(const char*, size_t, size_t limit);
|
||||
int64_t array_search(void*, size_t, size_t elsz, void* needle);
|
||||
char* str_escape(const char*);
|
||||
|
||||
char* byte_escape(const void*, size_t);
|
||||
size_t byte_findb(const void*, size_t, const void* what, size_t wlen);
|
||||
size_t byte_finds(const void*, size_t, const char* what);
|
||||
size_t byte_equal(const void* s, size_t n, const void* t);
|
||||
void byte_copy(void* out, size_t len, const void* in);
|
||||
void byte_copyr(void* out, size_t len, const void* in);
|
||||
size_t byte_rchrs(const char* in, size_t len, const char needles[], size_t nn);
|
||||
|
||||
#define DBUF_INIT_0() \
|
||||
(DynBuf) { 0, 0, 0, 0, 0, 0 }
|
||||
#define DBUF_INIT_CTX(ctx) \
|
||||
(DynBuf) { 0, 0, 0, 0, (DynBufReallocFunc*)js_realloc_rt, JS_GetRuntime(ctx) }
|
||||
|
||||
extern const uint8_t escape_url_tab[256], escape_noquote_tab[256], escape_singlequote_tab[256], escape_doublequote_tab[256], escape_backquote_tab[256];
|
||||
|
||||
char* dbuf_at_n(const DynBuf*, size_t, size_t* n, char sep);
|
||||
const char* dbuf_last_line(DynBuf*, size_t*);
|
||||
int dbuf_prepend(DynBuf*, const uint8_t*, size_t len);
|
||||
void dbuf_put_colorstr(DynBuf*, const char*, const char* color, int with_color);
|
||||
void dbuf_put_escaped_pred(DynBuf*, const char*, size_t len, int (*pred)(int));
|
||||
void dbuf_put_escaped_table(DynBuf*, const char*, size_t len, const uint8_t table[256]);
|
||||
void dbuf_put_unescaped_table(DynBuf* db, const char* str, size_t len, const uint8_t table[256]);
|
||||
void dbuf_put_unescaped_pred(DynBuf*, const char*, size_t len, int (*pred)());
|
||||
void dbuf_put_escaped(DynBuf*, const char*, size_t len);
|
||||
void dbuf_put_value(DynBuf*, JSContext*, JSValue value);
|
||||
void dbuf_put_uint32(DynBuf* db, uint32_t num);
|
||||
void dbuf_put_atom(DynBuf* db, JSContext* ctx, JSAtom atom);
|
||||
int dbuf_reserve_start(DynBuf*, size_t);
|
||||
uint8_t* dbuf_reserve(DynBuf*, size_t);
|
||||
size_t dbuf_token_pop(DynBuf*, char);
|
||||
size_t dbuf_token_push(DynBuf*, const char*, size_t len, char delim);
|
||||
JSValue dbuf_tostring_free(DynBuf*, JSContext*);
|
||||
ssize_t dbuf_load(DynBuf*, const char*);
|
||||
int dbuf_vprintf(DynBuf*, const char*, va_list);
|
||||
|
||||
int screen_size(int size[2]);
|
||||
|
||||
static inline int
|
||||
dbuf_putm(DynBuf* db, ...) {
|
||||
int r = 0;
|
||||
va_list a;
|
||||
const char* s;
|
||||
va_start(a, db);
|
||||
while((s = va_arg(a, char*)))
|
||||
if(dbuf_putstr(db, s))
|
||||
return -1;
|
||||
va_end(a);
|
||||
return r;
|
||||
}
|
||||
|
||||
#define dbuf_append(d, x, n) dbuf_put((d), (const uint8_t*)(x), (n))
|
||||
|
||||
static inline size_t
|
||||
dbuf_count(DynBuf* db, int ch) {
|
||||
return byte_count(db->buf, db->size, ch);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dbuf_0(DynBuf* db) {
|
||||
dbuf_putc(db, '\0');
|
||||
db->size--;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dbuf_zero(DynBuf* db) {
|
||||
dbuf_realloc(db, 0);
|
||||
db->size = 0;
|
||||
}
|
||||
|
||||
size_t dbuf_bitflags(DynBuf* db, uint32_t bits, const char* const names[]);
|
||||
|
||||
#define js_dbuf_init(ctx, buf) dbuf_init2((buf), (ctx), (realloc_func*)&utils_js_realloc)
|
||||
#define js_dbuf_init_rt(rt, buf) dbuf_init2((buf), (rt), (realloc_func*)&utils_js_realloc_rt)
|
||||
|
||||
void js_dbuf_allocator(JSContext* ctx, DynBuf* s);
|
||||
|
||||
typedef struct {
|
||||
uint8_t* base;
|
||||
size_t size;
|
||||
} MemoryBlock;
|
||||
|
||||
static inline void
|
||||
block_init(MemoryBlock* mb) {
|
||||
mb->base = 0;
|
||||
mb->size = 0;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
static inline void* block_data(const MemoryBlock* mb) { return mb->base; }
|
||||
static inline size_t block_length(const MemoryBlock* mb) { return mb->size; }
|
||||
static inline void* block_begin(const MemoryBlock* mb) { return mb->base; }
|
||||
static inline void* block_end(const MemoryBlock* mb) { return mb->base + mb->size; }
|
||||
/* clang-format on */
|
||||
|
||||
static inline BOOL
|
||||
block_arraybuffer(MemoryBlock* mb, JSValueConst ab, JSContext* ctx) {
|
||||
mb->base = JS_GetArrayBuffer(ctx, &mb->size, ab);
|
||||
return mb->base != 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t *start, *end;
|
||||
} PointerRange;
|
||||
|
||||
static inline void
|
||||
range_init(PointerRange* pr) {
|
||||
pr->end = pr->start = 0;
|
||||
}
|
||||
|
||||
static inline PointerRange
|
||||
range_from(const MemoryBlock* mb) {
|
||||
return (PointerRange){mb->base, mb->base + mb->size};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int64_t start, end;
|
||||
} IndexRange;
|
||||
|
||||
typedef struct {
|
||||
int64_t offset, length;
|
||||
} OffsetLength;
|
||||
|
||||
#define OFFSET_INIT() \
|
||||
(OffsetLength) { 0, INT64_MAX }
|
||||
|
||||
static inline void
|
||||
offset_init(OffsetLength* ol) {
|
||||
ol->offset = 0;
|
||||
ol->length = INT64_MAX;
|
||||
}
|
||||
|
||||
static inline BOOL
|
||||
offset_is_default(const OffsetLength* ol) {
|
||||
return ol->offset == 0 && ol->length == INT64_MAX;
|
||||
}
|
||||
|
||||
static inline void*
|
||||
offset_data(const OffsetLength* ol, const void* x) {
|
||||
return (uint8_t*)x + ol->offset;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
offset_size(const OffsetLength* ol, size_t n) {
|
||||
if(ol->length == -1)
|
||||
return (signed long)n - ol->offset;
|
||||
return MIN_NUM(ol->length, (signed long)n - ol->offset);
|
||||
}
|
||||
|
||||
static inline MemoryBlock
|
||||
offset_block(const OffsetLength* ol, const void* x, size_t n) {
|
||||
return (MemoryBlock){offset_data(ol, x), offset_size(ol, n)};
|
||||
}
|
||||
|
||||
static inline PointerRange
|
||||
offset_range(const OffsetLength* ol, const void* x, size_t n) {
|
||||
MemoryBlock mb = offset_block(ol, x, n);
|
||||
return range_from(&mb);
|
||||
}
|
||||
|
||||
static inline OffsetLength
|
||||
offset_slice(const OffsetLength ol, int64_t start, int64_t end) {
|
||||
if(start < 0)
|
||||
start = ol.length + (start % ol.length);
|
||||
else if(start > ol.length)
|
||||
start = ol.length;
|
||||
if(end < 0)
|
||||
end = ol.length + (end % ol.length);
|
||||
else if(end > ol.length)
|
||||
end = ol.length;
|
||||
|
||||
return (OffsetLength){start, end - start};
|
||||
}
|
||||
|
||||
static inline OffsetLength
|
||||
offset_offset(const OffsetLength* ol, const OffsetLength* by) {
|
||||
OffsetLength ret;
|
||||
ret.offset = ol->offset + by->offset;
|
||||
ret.length = MIN_NUM(by->length, ol->length - by->offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline OffsetLength
|
||||
offset_from_indexrange(const IndexRange* ir) {
|
||||
OffsetLength ret;
|
||||
ret.offset = ir->start;
|
||||
ret.length = ir->end - ir->start;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline JSValue
|
||||
offset_typedarray(OffsetLength* ol, JSValueConst array, JSContext* ctx) {
|
||||
JSValue ret;
|
||||
size_t offset, length;
|
||||
|
||||
ret = JS_GetTypedArrayBuffer(ctx, array, &offset, &length, NULL);
|
||||
|
||||
if(!JS_IsException(ret)) {
|
||||
ol->offset = offset;
|
||||
ol->length = length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline IndexRange
|
||||
indexrange_from_offset(const OffsetLength* ol) {
|
||||
IndexRange ret;
|
||||
ret.start = ol->offset;
|
||||
ret.end = ol->offset + ol->length;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline MemoryBlock
|
||||
block_range(const MemoryBlock* mb, const OffsetLength* range) {
|
||||
MemoryBlock ret;
|
||||
ret.base = mb->base + range->offset;
|
||||
ret.size = MIN_NUM((size_t)range->length, mb->size - range->offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
block_realloc(MemoryBlock* mb, size_t new_size, JSContext* ctx) {
|
||||
if((mb->base = js_realloc(ctx, mb->base, new_size))) {
|
||||
mb->size = new_size;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct InputBuffer {
|
||||
union {
|
||||
MemoryBlock block;
|
||||
struct {
|
||||
uint8_t* data;
|
||||
size_t size;
|
||||
};
|
||||
};
|
||||
size_t pos;
|
||||
void (*free)(JSContext*, const char*, JSValue);
|
||||
JSValue value;
|
||||
OffsetLength range;
|
||||
} InputBuffer;
|
||||
|
||||
static inline void
|
||||
input_buffer_free_default(JSContext* ctx, const char* str, JSValue val) {
|
||||
if(JS_IsString(val))
|
||||
JS_FreeCString(ctx, str);
|
||||
|
||||
if(!JS_IsUndefined(val))
|
||||
JS_FreeValue(ctx, val);
|
||||
}
|
||||
|
||||
InputBuffer js_input_buffer(JSContext* ctx, JSValueConst value);
|
||||
InputBuffer js_input_chars(JSContext* ctx, JSValueConst value);
|
||||
InputBuffer js_input_args(JSContext* ctx, int argc, JSValueConst argv[]);
|
||||
InputBuffer js_output_args(JSContext* ctx, int argc, JSValueConst argv[]);
|
||||
|
||||
InputBuffer input_buffer_clone(const InputBuffer* in, JSContext* ctx);
|
||||
BOOL input_buffer_valid(const InputBuffer* in);
|
||||
void input_buffer_dump(const InputBuffer* in, DynBuf* db);
|
||||
void input_buffer_free(InputBuffer* in, JSContext* ctx);
|
||||
|
||||
static inline uint8_t*
|
||||
input_buffer_data(const InputBuffer* in) {
|
||||
return offset_data(&in->range, in->data);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
input_buffer_length(const InputBuffer* in) {
|
||||
return offset_size(&in->range, in->size);
|
||||
}
|
||||
|
||||
static inline MemoryBlock
|
||||
input_buffer_block(InputBuffer* in) {
|
||||
return (MemoryBlock){input_buffer_data(in), input_buffer_length(in)};
|
||||
}
|
||||
|
||||
static inline MemoryBlock*
|
||||
input_buffer_blockptr(InputBuffer* in) {
|
||||
return &in->block;
|
||||
}
|
||||
|
||||
const uint8_t* input_buffer_get(InputBuffer* in, size_t* lenp);
|
||||
const uint8_t* input_buffer_peek(InputBuffer* in, size_t* lenp);
|
||||
const char* input_buffer_currentline(InputBuffer*, size_t* len);
|
||||
size_t input_buffer_column(InputBuffer*, size_t* len);
|
||||
|
||||
int input_buffer_peekc(InputBuffer* in, size_t* lenp);
|
||||
int input_buffer_putc(InputBuffer*, unsigned int, JSContext*);
|
||||
|
||||
static inline int
|
||||
input_buffer_getc(InputBuffer* in) {
|
||||
size_t n;
|
||||
int ret;
|
||||
ret = input_buffer_peekc(in, &n);
|
||||
in->pos += n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void*
|
||||
input_buffer_begin(const InputBuffer* in) {
|
||||
return input_buffer_data(in);
|
||||
}
|
||||
|
||||
static inline void*
|
||||
input_buffer_end(const InputBuffer* in) {
|
||||
return input_buffer_data(in) + input_buffer_length(in);
|
||||
}
|
||||
|
||||
static inline BOOL
|
||||
input_buffer_eof(const InputBuffer* in) {
|
||||
return in->pos == input_buffer_length(in);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
input_buffer_remain(const InputBuffer* in) {
|
||||
return input_buffer_length(in) - in->pos;
|
||||
}
|
||||
|
||||
int js_offset_length(JSContext*, int64_t size, int argc, JSValueConst argv[], OffsetLength* off_len_p);
|
||||
int js_index_range(JSContext*, int64_t size, int argc, JSValueConst argv[], IndexRange* idx_rng_p);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* defined(BUFFER_UTILS) */
|
||||
578
src/quickjs/char-utils.c
Normal file
578
src/quickjs/char-utils.c
Normal file
@@ -0,0 +1,578 @@
|
||||
#include "char-utils.h"
|
||||
#include "libutf.h"
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
|
||||
#include <winnls.h>
|
||||
#include <windows.h>
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup char-utils
|
||||
* @{
|
||||
*/
|
||||
size_t
|
||||
token_length(const char* str, size_t len, char delim) {
|
||||
const char *s, *e;
|
||||
size_t pos;
|
||||
|
||||
for(s = str, e = s + len; s < e; s += pos + 1) {
|
||||
pos = byte_chr(s, e - s, delim);
|
||||
|
||||
if(s + pos == e)
|
||||
break;
|
||||
|
||||
if(pos == 0 || s[pos - 1] != '\\') {
|
||||
s += pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return s - str;
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_ulong(char* dest, uint32_t i) {
|
||||
uint32_t len, tmp, len2;
|
||||
|
||||
for(len = 1, tmp = i; tmp > 9; ++len)
|
||||
tmp /= 10;
|
||||
|
||||
if(dest)
|
||||
for(tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10)
|
||||
*--dest = (char)((tmp % 10) + '0');
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_longlong(char* dest, int64_t i) {
|
||||
if(i < 0) {
|
||||
if(dest)
|
||||
*dest++ = '-';
|
||||
return fmt_ulonglong(dest, (uint64_t)-i) + 1;
|
||||
}
|
||||
|
||||
return fmt_ulonglong(dest, (uint64_t)i);
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_ulonglong(char* dest, uint64_t i) {
|
||||
size_t len;
|
||||
uint64_t tmp, len2;
|
||||
|
||||
for(len = 1, tmp = i; tmp > 9ll; ++len)
|
||||
tmp /= 10ll;
|
||||
|
||||
if(dest)
|
||||
for(tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10ll)
|
||||
*--dest = (tmp % 10ll) + '0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#define tohex(c) (char)((c) >= 10 ? (c)-10 + 'a' : (c) + '0')
|
||||
|
||||
size_t
|
||||
fmt_xlonglong(char* dest, uint64_t i) {
|
||||
uint64_t len, tmp;
|
||||
|
||||
for(len = 1, tmp = i; tmp > 15ll; ++len)
|
||||
tmp >>= 4ll;
|
||||
|
||||
if(dest)
|
||||
for(tmp = i, dest += len;;) {
|
||||
*--dest = tohex(tmp & 15ll);
|
||||
|
||||
if(!(tmp >>= 4ll))
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_xlonglong0(char* dest, uint64_t num, size_t n) {
|
||||
size_t i = 0, len;
|
||||
|
||||
if((len = fmt_xlonglong(NULL, num)) < n) {
|
||||
len = n - len;
|
||||
|
||||
while(i < len)
|
||||
dest[i++] = '0';
|
||||
}
|
||||
|
||||
i += fmt_xlonglong(&dest[i], num);
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_8long(char* dest, uint32_t i) {
|
||||
uint32_t len, tmp;
|
||||
|
||||
/* first count the number of bytes needed */
|
||||
for(len = 1, tmp = i; tmp > 7; ++len)
|
||||
tmp >>= 3;
|
||||
|
||||
if(dest)
|
||||
for(tmp = i, dest += len;;) {
|
||||
*--dest = (char)((tmp & 7) + '0');
|
||||
|
||||
if(!(tmp >>= 3))
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#define tohex(c) (char)((c) >= 10 ? (c)-10 + 'a' : (c) + '0')
|
||||
|
||||
size_t
|
||||
fmt_xlong(char* dest, uint32_t i) {
|
||||
uint32_t len, tmp;
|
||||
|
||||
/* first count the number of bytes needed */
|
||||
for(len = 1, tmp = i; tmp > 15; ++len)
|
||||
tmp >>= 4;
|
||||
|
||||
if(dest)
|
||||
for(tmp = i, dest += len;;) {
|
||||
*--dest = tohex(tmp & 15);
|
||||
|
||||
if(!(tmp >>= 4))
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
fmt_xlong0(char* dest, uint32_t num, size_t n) {
|
||||
size_t i = 0, len;
|
||||
|
||||
if((len = fmt_xlong(NULL, num)) < n) {
|
||||
len = n - len;
|
||||
|
||||
while(i < len)
|
||||
dest[i++] = '0';
|
||||
}
|
||||
|
||||
i += fmt_xlong(&dest[i], num);
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_ushort(const char* src, uint16_t* dest) {
|
||||
const char* cur;
|
||||
uint16_t l;
|
||||
|
||||
for(cur = src, l = 0; *cur >= '0' && *cur <= '9'; ++cur) {
|
||||
uint32_t tmp = l * 10ul + *cur - '0';
|
||||
|
||||
if((uint16_t)tmp != tmp)
|
||||
break;
|
||||
|
||||
l = tmp;
|
||||
}
|
||||
|
||||
if(cur > src)
|
||||
*dest = l;
|
||||
|
||||
return (size_t)(cur - src);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_uint(const char* src, uint32_t* dest) {
|
||||
uint64_t u64;
|
||||
size_t r = scan_ulonglong(src, &u64);
|
||||
*dest = u64;
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_int(const char* src, int32_t* dest) {
|
||||
int64_t i64;
|
||||
size_t r = scan_longlong(src, &i64);
|
||||
*dest = i64;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifndef MAXLONG
|
||||
#define MAXLONG (((uint32_t)-1) >> 1)
|
||||
#endif
|
||||
|
||||
size_t
|
||||
scan_longlong(const char* src, int64_t* dest) {
|
||||
size_t i, o;
|
||||
uint64_t l;
|
||||
char c = src[0];
|
||||
unsigned int neg = c == '-';
|
||||
o = c == '-' || c == '+';
|
||||
|
||||
if((i = scan_ulonglong(src + o, &l))) {
|
||||
if(i > 0ll && l > MAXLONG + neg) {
|
||||
l /= 10ll;
|
||||
--i;
|
||||
}
|
||||
|
||||
if(i + o)
|
||||
*dest = (int64_t)(c == '-' ? -l : l);
|
||||
|
||||
return i + o;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_ulonglong(const char* src, uint64_t* dest) {
|
||||
const char* tmp = src;
|
||||
uint64_t l = 0;
|
||||
unsigned char c;
|
||||
|
||||
while((c = (unsigned char)(*tmp - '0')) < 10) {
|
||||
uint64_t n;
|
||||
n = l << 3ll;
|
||||
|
||||
if((n >> 3ll) != l)
|
||||
break;
|
||||
|
||||
if(n + (l << 1ll) < n)
|
||||
break;
|
||||
|
||||
n += l << 1ll;
|
||||
|
||||
if(n + c < n)
|
||||
break;
|
||||
|
||||
l = n + c;
|
||||
++tmp;
|
||||
}
|
||||
|
||||
if(tmp - src)
|
||||
*dest = l;
|
||||
|
||||
return (size_t)(tmp - src);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_xlonglong(const char* src, uint64_t* dest) {
|
||||
const char* tmp = src;
|
||||
int64_t l = 0;
|
||||
unsigned char c;
|
||||
|
||||
while((c = scan_fromhex(*tmp)) < 16) {
|
||||
l = (l << 4) + c;
|
||||
++tmp;
|
||||
}
|
||||
|
||||
*dest = l;
|
||||
return tmp - src;
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_8longn(const char* src, size_t n, uint32_t* dest) {
|
||||
const char* tmp = src;
|
||||
uint32_t l = 0;
|
||||
unsigned char c;
|
||||
|
||||
while(n-- > 0 && (c = (unsigned char)(*tmp - '0')) < 8) {
|
||||
if(l >> (sizeof(l) * 8 - 3))
|
||||
break;
|
||||
|
||||
l = l * 8 + c;
|
||||
++tmp;
|
||||
}
|
||||
|
||||
*dest = l;
|
||||
return (size_t)(tmp - src);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_whitenskip(const char* s, size_t limit) {
|
||||
const char *t, *u;
|
||||
|
||||
for(t = s, u = t + limit; t < u; ++t)
|
||||
if(!is_whitespace_char(*t))
|
||||
break;
|
||||
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_nonwhitenskip(const char* s, size_t limit) {
|
||||
const char *t, *u;
|
||||
|
||||
for(t = s, u = t + limit; t < u; ++t)
|
||||
if(is_whitespace_char(*t))
|
||||
break;
|
||||
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_line(const char* s, size_t limit) {
|
||||
const char *t, *u;
|
||||
|
||||
for(t = s, u = s + limit; t < u; ++t)
|
||||
if(*t == '\n' || *t == '\r')
|
||||
break;
|
||||
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_lineskip(const char* s, size_t limit) {
|
||||
const char *t, *u;
|
||||
|
||||
for(t = s, u = s + limit; t < u; ++t)
|
||||
if(*t == '\n') {
|
||||
++t;
|
||||
break;
|
||||
}
|
||||
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_lineskip_escaped(const char* s, size_t limit) {
|
||||
const char *t, *u;
|
||||
|
||||
for(t = s, u = s + limit; t < u; ++t) {
|
||||
if(*t == '\\') {
|
||||
++t;
|
||||
continue;
|
||||
}
|
||||
if(*t == '\n') {
|
||||
++t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
size_t
|
||||
scan_eolskip(const char* s, size_t limit) {
|
||||
size_t n = 0;
|
||||
|
||||
if(n + 1 < limit && s[0] == '\r' && s[1] == '\n')
|
||||
n += 2;
|
||||
else if(n < limit && s[0] == '\n')
|
||||
n += 1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
utf8_strlen(const void* in, size_t len) {
|
||||
const uint8_t *pos, *end, *next;
|
||||
size_t i = 0;
|
||||
|
||||
for(pos = (const uint8_t*)in, end = pos + len; pos < end; pos = next, ++i)
|
||||
unicode_from_utf8(pos, end - pos, &next);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
|
||||
wchar_t*
|
||||
utf8_towcs(const char* s) {
|
||||
int len = (int)strlen(s);
|
||||
int n = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0);
|
||||
wchar_t* ret;
|
||||
|
||||
if((ret = (wchar_t*)malloc((n + 1) * sizeof(wchar_t)))) {
|
||||
MultiByteToWideChar(CP_UTF8, 0, s, len, ret, n);
|
||||
ret[n] = L'\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char*
|
||||
utf8_fromwcs(const wchar_t* wstr) {
|
||||
int len = (int)wcslen(wstr);
|
||||
int n = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
|
||||
char* ret;
|
||||
|
||||
if((ret = malloc((n + 1)))) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, ret, n, NULL, NULL);
|
||||
ret[n] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL
|
||||
utf16_multiword(const void* in) {
|
||||
const uint16_t* p16 = in;
|
||||
LibutfC16Type type = libutf_c16_type(p16[0]);
|
||||
|
||||
return !((LIBUTF_UTF16_NOT_SURROGATE == type) || (LIBUTF_UTF16_SURROGATE_HIGH != type || LIBUTF_UTF16_SURROGATE_LOW != libutf_c16_type(p16[1])));
|
||||
}
|
||||
|
||||
int
|
||||
case_lowerc(int c) {
|
||||
if(c >= 'A' && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
case_starts(const char* a, const char* b) {
|
||||
const char *s, *t;
|
||||
|
||||
for(s = a, t = b;; ++s, ++t) {
|
||||
unsigned char x, y;
|
||||
|
||||
if(!*t)
|
||||
return 1;
|
||||
|
||||
x = case_lowerc(*s);
|
||||
y = case_lowerc(*t);
|
||||
|
||||
if(x != y)
|
||||
break;
|
||||
|
||||
if(!x)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
case_diffb(const void* S, size_t len, const void* T) {
|
||||
unsigned char x, y;
|
||||
const char *s, *t;
|
||||
|
||||
for(s = (const char*)S, t = (const char*)T; len > 0;) {
|
||||
--len;
|
||||
x = case_lowerc(*s);
|
||||
y = case_lowerc(*t);
|
||||
|
||||
++s;
|
||||
++t;
|
||||
|
||||
if(x != y)
|
||||
return ((int)(unsigned int)x) - ((int)(unsigned int)y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
case_findb(const void* haystack, size_t hlen, const void* what, size_t wlen) {
|
||||
size_t i, last;
|
||||
const char* s = haystack;
|
||||
|
||||
if(hlen < wlen)
|
||||
return hlen;
|
||||
|
||||
last = hlen - wlen;
|
||||
|
||||
for(i = 0; i <= last; i++, s++)
|
||||
if(!case_diffb(s, wlen, what))
|
||||
return i;
|
||||
|
||||
return hlen;
|
||||
}
|
||||
|
||||
size_t
|
||||
case_finds(const void* haystack, const char* what) {
|
||||
return case_findb(haystack, strlen(haystack), what, strlen(what));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
write_file(const char* file, const void* buf, size_t len) {
|
||||
FILE* f;
|
||||
ssize_t ret = -1;
|
||||
|
||||
if((f = fopen(file, "w+")))
|
||||
switch(fwrite(buf, len, 1, f)) {
|
||||
case 1: {
|
||||
ret = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fflush(f);
|
||||
ret = ftell(f);
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
puts_file(const char* file, const char* s) {
|
||||
return write_file(file, s, strlen(s));
|
||||
}
|
||||
|
||||
size_t
|
||||
u64toa(char* x, uint64_t num, int base) {
|
||||
size_t len = 0;
|
||||
uint64_t n = num;
|
||||
|
||||
do {
|
||||
n /= base;
|
||||
len++;
|
||||
x++;
|
||||
} while(n != 0);
|
||||
|
||||
*x-- = '\0';
|
||||
|
||||
do {
|
||||
char c = num % base;
|
||||
num /= base;
|
||||
|
||||
if(c >= 10)
|
||||
c += 'a' - '0' - 10;
|
||||
*x-- = c + '0';
|
||||
} while(num != 0);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
i64toa(char* x, int64_t num, int base) {
|
||||
size_t pos = 0, len;
|
||||
|
||||
if(num < 0) {
|
||||
x[pos++] = '-';
|
||||
num = -num;
|
||||
}
|
||||
|
||||
len = u64toa(&x[pos], num, base);
|
||||
|
||||
return pos + len;
|
||||
}
|
||||
|
||||
size_t
|
||||
str_findb(const char* s1, const char* x, size_t n) {
|
||||
const char* b;
|
||||
size_t i, j, len = strlen(s1);
|
||||
|
||||
if(len >= n) {
|
||||
size_t end = len - n + 1;
|
||||
|
||||
for(i = 0; i < end; i++) {
|
||||
b = &s1[i];
|
||||
|
||||
for(j = 0; x[j] == b[j];)
|
||||
if(++j == n)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t
|
||||
str_find(const void* s, const void* what) {
|
||||
return str_findb(s, what, strlen(what));
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
441
src/quickjs/char-utils.h
Normal file
441
src/quickjs/char-utils.h
Normal file
@@ -0,0 +1,441 @@
|
||||
#ifndef CHAR_UTILS_H
|
||||
#define CHAR_UTILS_H
|
||||
|
||||
#include <cutils.h>
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* \defgroup char-utils char-utils: Character Utilities
|
||||
* @{
|
||||
*/
|
||||
#define is_control_char(c) ((c) == '\a' || (c) == '\b' || (c) == '\t' || (c) == '\n' || (c) == '\v' || (c) == '\f' || (c) == '\r')
|
||||
#define is_alphanumeric_char(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
|
||||
|
||||
#define is_digit_char(c) ((c) >= '0' && (c) <= '9')
|
||||
#define is_print_char(c) ((c) >= ' ' && (c) <= '\x7f')
|
||||
#define is_newline_char(c) ((c) == '\n')
|
||||
#define is_identifier_char(c) (is_alphanumeric_char(c) || is_digit_char(c) || (c) == '$' || (c) == '_')
|
||||
#define is_whitespace_char(c) ((c) == ' ' || (c) == '\t' || (c) == '\v' || (c) == '\n' || (c) == '\r')
|
||||
|
||||
#define str_equal(s, t) (!strcmp((s), (t)))
|
||||
|
||||
static inline int
|
||||
escape_char_pred(int c) {
|
||||
static const unsigned char table[256] = {
|
||||
'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 0x62, 0x74, 0x6e, 0x76, 0x66, 0x72, 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
|
||||
'x', 'x', 'x', 0, 0, 0, 0, 0, 0, 0, 0x27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'x', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
return table[(unsigned char)c];
|
||||
}
|
||||
|
||||
static inline int
|
||||
unescape_char_pred(int c) {
|
||||
switch(c) {
|
||||
case 'b': return 8;
|
||||
case 'f': return 12;
|
||||
case 'n': return 10;
|
||||
case 'r': return 13;
|
||||
case 't': return 9;
|
||||
case 'v': return 11;
|
||||
case '\'': return 39;
|
||||
case '\\': return 92;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_escape_char(int c) {
|
||||
return is_control_char(c) || c == '\\' || c == '\'' || c == 0x1b || c == 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_backslash_char(int c) {
|
||||
return c == '\\';
|
||||
}
|
||||
|
||||
//#define is_dot_char(c) ((c) == '.')0
|
||||
//#define is_backslash_char(c) ((c) == '\\')
|
||||
|
||||
static inline int
|
||||
is_dot_char(int c) {
|
||||
return c == '.';
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_identifier(const char* str) {
|
||||
if(!((*str >= 'A' && *str <= 'Z') || (*str >= 'a' && *str <= 'z') || *str == '$' || *str == '_'))
|
||||
return 0;
|
||||
|
||||
while(*++str)
|
||||
if(!is_identifier_char(*str))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_integer(const char* str) {
|
||||
if(*str == '-')
|
||||
++str;
|
||||
|
||||
if(!(*str >= '1' && *str <= '9') && !(*str == '0' && str[1] == '\0'))
|
||||
return 0;
|
||||
|
||||
while(*++str)
|
||||
if(!is_digit_char(*str))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
byte_count(const void* s, size_t n, char c) {
|
||||
const uint8_t* t;
|
||||
uint8_t ch = (uint8_t)c;
|
||||
size_t count;
|
||||
|
||||
for(t = (uint8_t*)s, count = 0; n; ++t, --n)
|
||||
if(*t == ch)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
byte_chr(const void* str, size_t len, char c) {
|
||||
const char* s = memchr(str, c, len);
|
||||
|
||||
if(s)
|
||||
return s - (const char*)str;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
byte_rchr(const void* haystack, size_t len, char needle) {
|
||||
const char *s, *t;
|
||||
|
||||
for(s = (const char*)haystack, t = s + len;;) {
|
||||
--t;
|
||||
|
||||
if(s > t)
|
||||
break;
|
||||
|
||||
if(*t == needle)
|
||||
return (size_t)(t - s);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*size_t
|
||||
byte_rchr(const void* str, size_t len, char c) {
|
||||
const char* s = memrchr(str, c, len);
|
||||
if(s)
|
||||
return s - (const char*)str;
|
||||
return len;
|
||||
}*/
|
||||
|
||||
static inline size_t
|
||||
byte_chrs(const void* str, size_t len, const char needle[], size_t nl) {
|
||||
const char *s, *t;
|
||||
|
||||
for(s = str, t = s + len; s != t; s++)
|
||||
if(byte_chr(needle, nl, *s) < nl)
|
||||
break;
|
||||
|
||||
return s - (const char*)str;
|
||||
}
|
||||
|
||||
static inline int
|
||||
byte_diff(const void* a, size_t len, const void* b) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < len; ++i) {
|
||||
int r = ((unsigned char*)a)[i] - ((unsigned char*)b)[i];
|
||||
|
||||
if(r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
byte_diff2(const char* a, size_t alen, const char* b, size_t blen) {
|
||||
|
||||
if(alen < blen)
|
||||
return -b[alen];
|
||||
|
||||
if(blen < alen)
|
||||
return a[blen];
|
||||
|
||||
return byte_diff(a, alen, b);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_chr(const char* in, char needle) {
|
||||
const char *t, c = needle;
|
||||
|
||||
for(t = in; *t; ++t)
|
||||
if(*t == c)
|
||||
break;
|
||||
|
||||
return (size_t)(t - in);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_chrs(const char* in, const char needles[], size_t nn) {
|
||||
const char* t;
|
||||
size_t i;
|
||||
|
||||
for(t = in; *t; ++t)
|
||||
for(i = 0; i < nn; i++)
|
||||
if(*t == needles[i])
|
||||
return (size_t)(t - in);
|
||||
|
||||
return (size_t)(t - in);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_rchr(const char* s, char needle) {
|
||||
const char *in, *found = 0;
|
||||
|
||||
for(in = s; *in; ++in)
|
||||
if(*in == needle)
|
||||
found = in;
|
||||
|
||||
return (size_t)((found ? found : in) - s);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_rchrs(const char* in, const char needles[], size_t nn) {
|
||||
const char *s, *found = 0;
|
||||
size_t i;
|
||||
|
||||
for(s = in; *s; ++s)
|
||||
for(i = 0; i < nn; ++i)
|
||||
if(*s == needles[i])
|
||||
found = s;
|
||||
|
||||
return (size_t)((found ? found : s) - in);
|
||||
}
|
||||
|
||||
static inline int
|
||||
str_endb(const char* a, const char* x, size_t n) {
|
||||
size_t alen = strlen(a);
|
||||
a += alen - n;
|
||||
|
||||
return alen >= n && !memcmp(a, x, n);
|
||||
}
|
||||
|
||||
/* str_ends returns 1 if the b is a suffix of a, 0 otherwise */
|
||||
static inline int
|
||||
str_ends(const char* a, const char* b) {
|
||||
return str_endb(a, b, strlen(b));
|
||||
}
|
||||
|
||||
static inline int
|
||||
str_startb(const char* a, const char* x, size_t len) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0;; i++) {
|
||||
if(i == len)
|
||||
return 1;
|
||||
if(a[i] != x[i])
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
str_start(const char* a, const char* b) {
|
||||
return str_startb(a, b, strlen(b));
|
||||
}
|
||||
|
||||
#define str_contains(s, needle) (!!strchr((s), (needle)))
|
||||
|
||||
char* str_escape(const char*);
|
||||
|
||||
static inline size_t
|
||||
str_count(const char* s, char c) {
|
||||
size_t i, count = 0;
|
||||
|
||||
for(i = 0; s[i]; i++)
|
||||
if(s[i] == c)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_copy(char* out, const char* in) {
|
||||
char* s;
|
||||
|
||||
for(s = out; (*s = *in); ++s)
|
||||
++in;
|
||||
|
||||
return (size_t)(s - out);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
str_copyn(char* out, const char* in, size_t n) {
|
||||
char* s;
|
||||
|
||||
for(s = out; n-- && (*s = *in); ++s)
|
||||
++in;
|
||||
|
||||
*s = '\0';
|
||||
return (size_t)(s - out);
|
||||
}
|
||||
|
||||
static inline char*
|
||||
str_ndup(const char* s, size_t n) {
|
||||
char* r = malloc(n + 1);
|
||||
|
||||
if(r == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(r, s, n);
|
||||
r[n] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t str_findb(const char*, const char*, size_t);
|
||||
size_t str_find(const void*, const void*);
|
||||
|
||||
static inline size_t
|
||||
predicate_find(const char* str, size_t len, int (*pred)(int32_t)) {
|
||||
size_t pos;
|
||||
|
||||
for(pos = 0; pos < len; pos++)
|
||||
if(pred(str[pos]))
|
||||
break;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
lookup_find(const char* str, size_t len, const char table[256]) {
|
||||
size_t pos;
|
||||
|
||||
for(pos = 0; pos < len; pos++)
|
||||
if(table[(unsigned char)str[pos]])
|
||||
break;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static inline char
|
||||
escape_char_letter(char c) {
|
||||
switch(c) {
|
||||
case '\0': return '0';
|
||||
case '\a': return 'a';
|
||||
case '\b': return 'b';
|
||||
case '\t': return 't';
|
||||
case '\n': return 'n';
|
||||
case '\v': return 'v';
|
||||
case '\f': return 'f';
|
||||
case '\r': return 'r';
|
||||
case '\\': return '\\';
|
||||
case '\'': return '\'';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FMT_LONG 41 /* enough space to hold -2^127 in decimal, plus \0 */
|
||||
#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
|
||||
#define FMT_8LONG 44 /* enough space to hold 2^128 - 1 in octal, plus \0 */
|
||||
#define FMT_XLONG 33 /* enough space to hold 2^128 - 1 in hexadecimal, plus \0 */
|
||||
|
||||
size_t token_length(const char*, size_t, char delim);
|
||||
size_t fmt_ulong(char*, uint32_t);
|
||||
size_t scan_ushort(const char*, uint16_t*);
|
||||
size_t fmt_longlong(char*, int64_t);
|
||||
size_t fmt_ulonglong(char*, uint64_t);
|
||||
size_t fmt_xlonglong(char*, uint64_t);
|
||||
size_t fmt_xlonglong0(char*, uint64_t, size_t);
|
||||
size_t fmt_8long(char* dest, uint32_t i);
|
||||
size_t fmt_xlong(char* dest, uint32_t num);
|
||||
size_t fmt_xlong0(char* dest, uint32_t num, size_t n);
|
||||
size_t scan_longlong(const char*, int64_t*);
|
||||
size_t scan_int(const char*, int32_t*);
|
||||
size_t scan_uint(const char*, uint32_t*);
|
||||
size_t scan_ulonglong(const char*, uint64_t*);
|
||||
size_t scan_xlonglong(const char*, uint64_t*);
|
||||
size_t scan_8longn(const char*, size_t, uint32_t* dest);
|
||||
size_t scan_whitenskip(const char*, size_t);
|
||||
size_t scan_nonwhitenskip(const char*, size_t);
|
||||
size_t scan_line(const char*, size_t);
|
||||
size_t scan_lineskip(const char*, size_t);
|
||||
size_t scan_lineskip_escaped(const char*, size_t);
|
||||
size_t scan_eolskip(const char*, size_t);
|
||||
size_t utf8_strlen(const void*, size_t);
|
||||
wchar_t* utf8_towcs(const char*);
|
||||
char* utf8_fromwcs(const wchar_t*);
|
||||
BOOL utf16_multiword(const void*);
|
||||
int case_lowerc(int);
|
||||
int case_starts(const char*, const char*);
|
||||
int case_diffb(const void*, size_t, const void* T);
|
||||
size_t case_findb(const void*, size_t, const void* what, size_t wlen);
|
||||
size_t case_finds(const void*, const char*);
|
||||
|
||||
static inline int
|
||||
scan_fromhex(unsigned char c) {
|
||||
c -= '0';
|
||||
|
||||
if(c <= 9)
|
||||
return c;
|
||||
|
||||
c &= ~0x20;
|
||||
c -= 'A' - '0';
|
||||
|
||||
if(c < 6)
|
||||
return c + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
scan_8long(const char* src, uint32_t* dest) {
|
||||
return scan_8longn(src, (size_t)-1, dest);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
utf8_charlen(const char* in, size_t len) {
|
||||
const uint8_t* next = (const void*)in;
|
||||
int r = unicode_from_utf8((const uint8_t*)in, len, &next);
|
||||
return r == -1 ? 0 : next - (const uint8_t*)in;
|
||||
}
|
||||
|
||||
static inline int
|
||||
utf8_charcode(const char* in, size_t len) {
|
||||
const uint8_t* next = (const void*)in;
|
||||
int r = unicode_from_utf8((const uint8_t*)in, len, &next);
|
||||
return next > in ? r : -1;
|
||||
}
|
||||
|
||||
BOOL utf16_multiword(const void*);
|
||||
|
||||
ssize_t write_file(const char* file, const void* buf, size_t len);
|
||||
ssize_t puts_file(const char* file, const char* s);
|
||||
|
||||
size_t u64toa(char*, uint64_t num, int base);
|
||||
size_t i64toa(char*, int64_t num, int base);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* defined(CHAR_UTILS_H) */
|
||||
631
src/quickjs/cutils.c
Normal file
631
src/quickjs/cutils.c
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_suffix(const char *str, const char *suffix)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
size_t slen = strlen(suffix);
|
||||
return (len >= slen && !memcmp(str + len - slen, suffix, slen));
|
||||
}
|
||||
|
||||
/* Dynamic buffer package */
|
||||
|
||||
static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
if (!realloc_func)
|
||||
realloc_func = dbuf_default_realloc;
|
||||
s->opaque = opaque;
|
||||
s->realloc_func = realloc_func;
|
||||
}
|
||||
|
||||
void dbuf_init(DynBuf *s)
|
||||
{
|
||||
dbuf_init2(s, NULL, NULL);
|
||||
}
|
||||
|
||||
/* return < 0 if error */
|
||||
int dbuf_realloc(DynBuf *s, size_t new_size)
|
||||
{
|
||||
size_t size;
|
||||
uint8_t *new_buf;
|
||||
if (new_size > s->allocated_size) {
|
||||
if (s->error)
|
||||
return -1;
|
||||
size = s->allocated_size * 3 / 2;
|
||||
if (size > new_size)
|
||||
new_size = size;
|
||||
new_buf = s->realloc_func(s->opaque, s->buf, new_size);
|
||||
if (!new_buf) {
|
||||
s->error = TRUE;
|
||||
return -1;
|
||||
}
|
||||
s->buf = new_buf;
|
||||
s->allocated_size = new_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
|
||||
{
|
||||
size_t end;
|
||||
end = offset + len;
|
||||
if (dbuf_realloc(s, end))
|
||||
return -1;
|
||||
memcpy(s->buf + offset, data, len);
|
||||
if (end > s->size)
|
||||
s->size = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
|
||||
{
|
||||
if (unlikely((s->size + len) > s->allocated_size)) {
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
memcpy_no_ub(s->buf + s->size, data, len);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
|
||||
{
|
||||
if (unlikely((s->size + len) > s->allocated_size)) {
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
memcpy(s->buf + s->size, s->buf + offset, len);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbuf_putc(DynBuf *s, uint8_t c)
|
||||
{
|
||||
return dbuf_put(s, &c, 1);
|
||||
}
|
||||
|
||||
int dbuf_putstr(DynBuf *s, const char *str)
|
||||
{
|
||||
return dbuf_put(s, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
if (len < sizeof(buf)) {
|
||||
/* fast case */
|
||||
return dbuf_put(s, (uint8_t *)buf, len);
|
||||
} else {
|
||||
if (dbuf_realloc(s, s->size + len + 1))
|
||||
return -1;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
|
||||
fmt, ap);
|
||||
va_end(ap);
|
||||
s->size += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbuf_free(DynBuf *s)
|
||||
{
|
||||
/* we test s->buf as a fail safe to avoid crashing if dbuf_free()
|
||||
is called twice */
|
||||
if (s->buf) {
|
||||
s->realloc_func(s->opaque, s->buf, 0);
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
|
||||
are output. */
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c)
|
||||
{
|
||||
uint8_t *q = buf;
|
||||
|
||||
if (c < 0x80) {
|
||||
*q++ = c;
|
||||
} else {
|
||||
if (c < 0x800) {
|
||||
*q++ = (c >> 6) | 0xc0;
|
||||
} else {
|
||||
if (c < 0x10000) {
|
||||
*q++ = (c >> 12) | 0xe0;
|
||||
} else {
|
||||
if (c < 0x00200000) {
|
||||
*q++ = (c >> 18) | 0xf0;
|
||||
} else {
|
||||
if (c < 0x04000000) {
|
||||
*q++ = (c >> 24) | 0xf8;
|
||||
} else if (c < 0x80000000) {
|
||||
*q++ = (c >> 30) | 0xfc;
|
||||
*q++ = ((c >> 24) & 0x3f) | 0x80;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
*q++ = ((c >> 18) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 12) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = (c & 0x3f) | 0x80;
|
||||
}
|
||||
return q - buf;
|
||||
}
|
||||
|
||||
static const unsigned int utf8_min_code[5] = {
|
||||
0x80, 0x800, 0x10000, 0x00200000, 0x04000000,
|
||||
};
|
||||
|
||||
static const unsigned char utf8_first_code_mask[5] = {
|
||||
0x1f, 0xf, 0x7, 0x3, 0x1,
|
||||
};
|
||||
|
||||
/* return -1 if error. *pp is not updated in this case. max_len must
|
||||
be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
||||
{
|
||||
int l, c, b, i;
|
||||
|
||||
c = *p++;
|
||||
if (c < 0x80) {
|
||||
*pp = p;
|
||||
return c;
|
||||
}
|
||||
switch(c) {
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb:
|
||||
case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
||||
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb:
|
||||
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
l = 1;
|
||||
break;
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
l = 2;
|
||||
break;
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
|
||||
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
l = 3;
|
||||
break;
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
|
||||
l = 4;
|
||||
break;
|
||||
case 0xfc: case 0xfd:
|
||||
l = 5;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
/* check that we have enough characters */
|
||||
if (l > (max_len - 1))
|
||||
return -1;
|
||||
c &= utf8_first_code_mask[l - 1];
|
||||
for(i = 0; i < l; i++) {
|
||||
b = *p++;
|
||||
if (b < 0x80 || b >= 0xc0)
|
||||
return -1;
|
||||
c = (c << 6) | (b & 0x3f);
|
||||
}
|
||||
if (c < utf8_min_code[l - 1])
|
||||
return -1;
|
||||
*pp = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
||||
|
||||
static void *rqsort_arg;
|
||||
static int (*rqsort_cmp)(const void *, const void *, void *);
|
||||
|
||||
static int rqsort_cmp2(const void *p1, const void *p2)
|
||||
{
|
||||
return rqsort_cmp(p1, p2, rqsort_arg);
|
||||
}
|
||||
|
||||
/* not reentrant, but not needed with emscripten */
|
||||
void rqsort(void *base, size_t nmemb, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *arg)
|
||||
{
|
||||
rqsort_arg = arg;
|
||||
rqsort_cmp = cmp;
|
||||
qsort(base, nmemb, size, rqsort_cmp2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
typedef void (*exchange_f)(void *a, void *b, size_t size);
|
||||
typedef int (*cmp_f)(const void *, const void *, void *opaque);
|
||||
|
||||
static void exchange_bytes(void *a, void *b, size_t size) {
|
||||
uint8_t *ap = (uint8_t *)a;
|
||||
uint8_t *bp = (uint8_t *)b;
|
||||
|
||||
while (size-- != 0) {
|
||||
uint8_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_byte(void *a, void *b, size_t size) {
|
||||
uint8_t *ap = (uint8_t *)a;
|
||||
uint8_t *bp = (uint8_t *)b;
|
||||
uint8_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int16s(void *a, void *b, size_t size) {
|
||||
uint16_t *ap = (uint16_t *)a;
|
||||
uint16_t *bp = (uint16_t *)b;
|
||||
|
||||
for (size /= sizeof(uint16_t); size-- != 0;) {
|
||||
uint16_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int16(void *a, void *b, size_t size) {
|
||||
uint16_t *ap = (uint16_t *)a;
|
||||
uint16_t *bp = (uint16_t *)b;
|
||||
uint16_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int32s(void *a, void *b, size_t size) {
|
||||
uint32_t *ap = (uint32_t *)a;
|
||||
uint32_t *bp = (uint32_t *)b;
|
||||
|
||||
for (size /= sizeof(uint32_t); size-- != 0;) {
|
||||
uint32_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int32(void *a, void *b, size_t size) {
|
||||
uint32_t *ap = (uint32_t *)a;
|
||||
uint32_t *bp = (uint32_t *)b;
|
||||
uint32_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int64s(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
|
||||
for (size /= sizeof(uint64_t); size-- != 0;) {
|
||||
uint64_t t = *ap;
|
||||
*ap++ = *bp;
|
||||
*bp++ = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int64(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
uint64_t t = *ap;
|
||||
*ap = *bp;
|
||||
*bp = t;
|
||||
}
|
||||
|
||||
static void exchange_int128s(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
|
||||
for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {
|
||||
uint64_t t = ap[0];
|
||||
uint64_t u = ap[1];
|
||||
ap[0] = bp[0];
|
||||
ap[1] = bp[1];
|
||||
bp[0] = t;
|
||||
bp[1] = u;
|
||||
}
|
||||
}
|
||||
|
||||
static void exchange_one_int128(void *a, void *b, size_t size) {
|
||||
uint64_t *ap = (uint64_t *)a;
|
||||
uint64_t *bp = (uint64_t *)b;
|
||||
uint64_t t = ap[0];
|
||||
uint64_t u = ap[1];
|
||||
ap[0] = bp[0];
|
||||
ap[1] = bp[1];
|
||||
bp[0] = t;
|
||||
bp[1] = u;
|
||||
}
|
||||
|
||||
static inline exchange_f exchange_func(const void *base, size_t size) {
|
||||
switch (((uintptr_t)base | (uintptr_t)size) & 15) {
|
||||
case 0:
|
||||
if (size == sizeof(uint64_t) * 2)
|
||||
return exchange_one_int128;
|
||||
else
|
||||
return exchange_int128s;
|
||||
case 8:
|
||||
if (size == sizeof(uint64_t))
|
||||
return exchange_one_int64;
|
||||
else
|
||||
return exchange_int64s;
|
||||
case 4:
|
||||
case 12:
|
||||
if (size == sizeof(uint32_t))
|
||||
return exchange_one_int32;
|
||||
else
|
||||
return exchange_int32s;
|
||||
case 2:
|
||||
case 6:
|
||||
case 10:
|
||||
case 14:
|
||||
if (size == sizeof(uint16_t))
|
||||
return exchange_one_int16;
|
||||
else
|
||||
return exchange_int16s;
|
||||
default:
|
||||
if (size == 1)
|
||||
return exchange_one_byte;
|
||||
else
|
||||
return exchange_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
||||
{
|
||||
uint8_t *basep = (uint8_t *)base;
|
||||
size_t i, n, c, r;
|
||||
exchange_f swap = exchange_func(base, size);
|
||||
|
||||
if (nmemb > 1) {
|
||||
i = (nmemb / 2) * size;
|
||||
n = nmemb * size;
|
||||
|
||||
while (i > 0) {
|
||||
i -= size;
|
||||
for (r = i; (c = r * 2 + size) < n; r = c) {
|
||||
if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)
|
||||
c += size;
|
||||
if (cmp(basep + r, basep + c, opaque) > 0)
|
||||
break;
|
||||
swap(basep + r, basep + c, size);
|
||||
}
|
||||
}
|
||||
for (i = n - size; i > 0; i -= size) {
|
||||
swap(basep, basep + i, size);
|
||||
|
||||
for (r = 0; (c = r * 2 + size) < i; r = c) {
|
||||
if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)
|
||||
c += size;
|
||||
if (cmp(basep + r, basep + c, opaque) > 0)
|
||||
break;
|
||||
swap(basep + r, basep + c, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
|
||||
{
|
||||
return cmp(a, b, opaque) < 0 ?
|
||||
(cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :
|
||||
(cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));
|
||||
}
|
||||
|
||||
/* pointer based version with local stack and insertion sort threshhold */
|
||||
void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
||||
{
|
||||
struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
|
||||
uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
|
||||
size_t m4, i, lt, gt, span, span2;
|
||||
int c, depth;
|
||||
exchange_f swap = exchange_func(base, size);
|
||||
exchange_f swap_block = exchange_func(base, size | 128);
|
||||
|
||||
if (nmemb < 2 || size <= 0)
|
||||
return;
|
||||
|
||||
sp->base = (uint8_t *)base;
|
||||
sp->count = nmemb;
|
||||
sp->depth = 0;
|
||||
sp++;
|
||||
|
||||
while (sp > stack) {
|
||||
sp--;
|
||||
ptr = sp->base;
|
||||
nmemb = sp->count;
|
||||
depth = sp->depth;
|
||||
|
||||
while (nmemb > 6) {
|
||||
if (++depth > 50) {
|
||||
/* depth check to ensure worst case logarithmic time */
|
||||
heapsortx(ptr, nmemb, size, cmp, opaque);
|
||||
nmemb = 0;
|
||||
break;
|
||||
}
|
||||
/* select median of 3 from 1/4, 1/2, 3/4 positions */
|
||||
/* should use median of 5 or 9? */
|
||||
m4 = (nmemb >> 2) * size;
|
||||
m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);
|
||||
swap(ptr, m, size); /* move the pivot to the start or the array */
|
||||
i = lt = 1;
|
||||
pi = plt = ptr + size;
|
||||
gt = nmemb;
|
||||
pj = pgt = top = ptr + nmemb * size;
|
||||
for (;;) {
|
||||
while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {
|
||||
if (c == 0) {
|
||||
swap(plt, pi, size);
|
||||
lt++;
|
||||
plt += size;
|
||||
}
|
||||
i++;
|
||||
pi += size;
|
||||
}
|
||||
while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {
|
||||
if (c == 0) {
|
||||
gt--;
|
||||
pgt -= size;
|
||||
swap(pgt, pj, size);
|
||||
}
|
||||
}
|
||||
if (pi >= pj)
|
||||
break;
|
||||
swap(pi, pj, size);
|
||||
i++;
|
||||
pi += size;
|
||||
}
|
||||
/* array has 4 parts:
|
||||
* from 0 to lt excluded: elements identical to pivot
|
||||
* from lt to pi excluded: elements smaller than pivot
|
||||
* from pi to gt excluded: elements greater than pivot
|
||||
* from gt to n excluded: elements identical to pivot
|
||||
*/
|
||||
/* move elements identical to pivot in the middle of the array: */
|
||||
/* swap values in ranges [0..lt[ and [i-lt..i[
|
||||
swapping the smallest span between lt and i-lt is sufficient
|
||||
*/
|
||||
span = plt - ptr;
|
||||
span2 = pi - plt;
|
||||
lt = i - lt;
|
||||
if (span > span2)
|
||||
span = span2;
|
||||
swap_block(ptr, pi - span, span);
|
||||
/* swap values in ranges [gt..top[ and [i..top-(top-gt)[
|
||||
swapping the smallest span between top-gt and gt-i is sufficient
|
||||
*/
|
||||
span = top - pgt;
|
||||
span2 = pgt - pi;
|
||||
pgt = top - span2;
|
||||
gt = nmemb - (gt - i);
|
||||
if (span > span2)
|
||||
span = span2;
|
||||
swap_block(pi, top - span, span);
|
||||
|
||||
/* now array has 3 parts:
|
||||
* from 0 to lt excluded: elements smaller than pivot
|
||||
* from lt to gt excluded: elements identical to pivot
|
||||
* from gt to n excluded: elements greater than pivot
|
||||
*/
|
||||
/* stack the larger segment and keep processing the smaller one
|
||||
to minimize stack use for pathological distributions */
|
||||
if (lt > nmemb - gt) {
|
||||
sp->base = ptr;
|
||||
sp->count = lt;
|
||||
sp->depth = depth;
|
||||
sp++;
|
||||
ptr = pgt;
|
||||
nmemb -= gt;
|
||||
} else {
|
||||
sp->base = pgt;
|
||||
sp->count = nmemb - gt;
|
||||
sp->depth = depth;
|
||||
sp++;
|
||||
nmemb = lt;
|
||||
}
|
||||
}
|
||||
/* Use insertion sort for small fragments */
|
||||
for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {
|
||||
for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)
|
||||
swap(pj, pj - size, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
341
src/quickjs/cutils.h
Normal file
341
src/quickjs/cutils.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CUTILS_H
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define force_inline inline __attribute__((always_inline))
|
||||
#define no_inline __attribute__((noinline))
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
#ifndef countof
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
#ifndef container_of
|
||||
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
|
||||
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
|
||||
#endif
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef FALSE
|
||||
enum {
|
||||
FALSE = 0,
|
||||
TRUE = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
int has_suffix(const char *str, const char *suffix);
|
||||
|
||||
/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
|
||||
static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
|
||||
if (n)
|
||||
memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
static inline int max_int(int a, int b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int min_int(int a, int b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t max_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t min_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t max_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t min_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz32(unsigned int a)
|
||||
{
|
||||
return __builtin_clz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz64(uint64_t a)
|
||||
{
|
||||
return __builtin_clzll(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz32(unsigned int a)
|
||||
{
|
||||
return __builtin_ctz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz64(uint64_t a)
|
||||
{
|
||||
return __builtin_ctzll(a);
|
||||
}
|
||||
|
||||
struct __attribute__((packed)) packed_u64 {
|
||||
uint64_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u32 {
|
||||
uint32_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u16 {
|
||||
uint16_t v;
|
||||
};
|
||||
|
||||
static inline uint64_t get_u64(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int64_t get_i64(const uint8_t *tab)
|
||||
{
|
||||
return (int64_t)((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u64(uint8_t *tab, uint64_t val)
|
||||
{
|
||||
((struct packed_u64 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u32(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i32(const uint8_t *tab)
|
||||
{
|
||||
return (int32_t)((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u32(uint8_t *tab, uint32_t val)
|
||||
{
|
||||
((struct packed_u32 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u16(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i16(const uint8_t *tab)
|
||||
{
|
||||
return (int16_t)((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u16(uint8_t *tab, uint16_t val)
|
||||
{
|
||||
((struct packed_u16 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u8(const uint8_t *tab)
|
||||
{
|
||||
return *tab;
|
||||
}
|
||||
|
||||
static inline int32_t get_i8(const uint8_t *tab)
|
||||
{
|
||||
return (int8_t)*tab;
|
||||
}
|
||||
|
||||
static inline void put_u8(uint8_t *tab, uint8_t val)
|
||||
{
|
||||
*tab = val;
|
||||
}
|
||||
|
||||
#ifndef bswap16
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap32
|
||||
static inline uint32_t bswap32(uint32_t v)
|
||||
{
|
||||
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
|
||||
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap64
|
||||
static inline uint64_t bswap64(uint64_t v)
|
||||
{
|
||||
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
|
||||
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: should take an extra argument to pass slack information to the caller */
|
||||
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
|
||||
|
||||
typedef struct DynBuf {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
size_t allocated_size;
|
||||
BOOL error; /* true if a memory allocation error occurred */
|
||||
DynBufReallocFunc *realloc_func;
|
||||
void *opaque; /* for realloc_func */
|
||||
} DynBuf;
|
||||
|
||||
void dbuf_init(DynBuf *s);
|
||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
|
||||
int dbuf_realloc(DynBuf *s, size_t new_size);
|
||||
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
|
||||
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
|
||||
int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
|
||||
int dbuf_putc(DynBuf *s, uint8_t c);
|
||||
int dbuf_putstr(DynBuf *s, const char *str);
|
||||
static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 2);
|
||||
}
|
||||
static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 4);
|
||||
}
|
||||
static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
|
||||
{
|
||||
return dbuf_put(s, (uint8_t *)&val, 8);
|
||||
}
|
||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
const char *fmt, ...);
|
||||
void dbuf_free(DynBuf *s);
|
||||
static inline BOOL dbuf_error(DynBuf *s) {
|
||||
return s->error;
|
||||
}
|
||||
static inline void dbuf_set_error(DynBuf *s)
|
||||
{
|
||||
s->error = TRUE;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c);
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
|
||||
|
||||
static inline BOOL is_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
|
||||
}
|
||||
|
||||
static inline BOOL is_hi_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
|
||||
}
|
||||
|
||||
static inline BOOL is_lo_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
|
||||
}
|
||||
|
||||
static inline uint32_t get_hi_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) - (0x10000 >> 10) + 0xD800;
|
||||
}
|
||||
|
||||
static inline uint32_t get_lo_surrogate(uint32_t c)
|
||||
{
|
||||
return (c & 0x3FF) | 0xDC00;
|
||||
}
|
||||
|
||||
static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
|
||||
{
|
||||
return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
|
||||
}
|
||||
|
||||
static inline int from_hex(int c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void rqsort(void *base, size_t nmemb, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
#endif /* CUTILS_H */
|
||||
483
src/quickjs/debug.c
Normal file
483
src/quickjs/debug.c
Normal file
@@ -0,0 +1,483 @@
|
||||
#define _IN_DEBUG_C 1
|
||||
#include "debug.h"
|
||||
#include <quickjs.h>
|
||||
#include <list.h>
|
||||
#include <cutils.h>
|
||||
#include <assert.h>
|
||||
#include "defines.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* \addtogroup debug
|
||||
* @{
|
||||
*/
|
||||
struct alloc_block {
|
||||
struct list_head link;
|
||||
const char* file;
|
||||
int line;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#define ALLOC_BLOCK_SIZE sizeof(struct alloc_block)
|
||||
#define ALLOC_BLOCK(p) (((struct alloc_block*)(p)) - 1)
|
||||
#define ALLOC_PTR struct alloc_block*
|
||||
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
#undef strdup
|
||||
#undef free
|
||||
#undef js_malloc
|
||||
#undef js_mallocz
|
||||
#undef js_realloc
|
||||
#undef js_strdup
|
||||
#undef js_strndup
|
||||
#undef js_free
|
||||
#undef js_malloc_usable_size
|
||||
#undef js_malloc_rt
|
||||
#undef js_mallocz_rt
|
||||
#undef js_realloc_rt
|
||||
#undef js_free_rt
|
||||
#undef js_malloc_usable_size_rt
|
||||
|
||||
thread_local struct list_head alloc_block_list = {0, 0};
|
||||
|
||||
static inline void
|
||||
add_to_list(struct list_head* el, struct list_head* head) {
|
||||
if(alloc_block_list.prev == 0 && alloc_block_list.next == 0)
|
||||
init_list_head(&alloc_block_list);
|
||||
|
||||
list_add_tail(el, head);
|
||||
}
|
||||
|
||||
int64_t
|
||||
check_pointer(void* p) {
|
||||
ALLOC_PTR ptr = ALLOC_BLOCK(p);
|
||||
struct list_head* link;
|
||||
int64_t ret = 0;
|
||||
list_for_each(link, &alloc_block_list) {
|
||||
if(link == &ptr->link)
|
||||
return ret;
|
||||
ret++;
|
||||
}
|
||||
// assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_malloc(size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = malloc(n + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_calloc(size_t m, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
m *= n;
|
||||
n = 1;
|
||||
|
||||
if((ptr = calloc(m + ALLOC_BLOCK_SIZE, 1))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_realloc(void* p, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if(p) {
|
||||
|
||||
check_pointer(p);
|
||||
|
||||
ptr = ALLOC_BLOCK(p);
|
||||
list_del(&ptr->link);
|
||||
|
||||
if(n == 0) {
|
||||
free(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = realloc(ptr, n + ALLOC_BLOCK_SIZE);
|
||||
} else {
|
||||
ptr = malloc(n + ALLOC_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(ptr) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_strdup(const char* s, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
size_t len = strlen(s);
|
||||
|
||||
if((ptr = malloc(len + 1 + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = len + 1;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
|
||||
memcpy(&ptr[1], s, len + 1);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
debug_free(void* p, const char* file, int line) {
|
||||
ALLOC_PTR ptr = ALLOC_BLOCK(p);
|
||||
|
||||
list_del(&ptr->link);
|
||||
|
||||
memset(ptr, 0xff, ALLOC_BLOCK_SIZE);
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_malloc(JSContext* ctx, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = js_malloc(ctx, n + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_mallocz(JSContext* ctx, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = js_mallocz(ctx, n + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_realloc(JSContext* ctx, void* p, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if(p) {
|
||||
|
||||
check_pointer(p);
|
||||
|
||||
ptr = ALLOC_BLOCK(p);
|
||||
list_del(&ptr->link);
|
||||
|
||||
if(n == 0) {
|
||||
js_free(ctx, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = js_realloc(ctx, ptr, n + ALLOC_BLOCK_SIZE);
|
||||
} else {
|
||||
ptr = js_malloc(ctx, n + ALLOC_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(ptr) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_realloc2(JSContext* ctx, void* p, size_t size, size_t* pslack, const char* file, int line) {
|
||||
void* ptr;
|
||||
|
||||
if((ptr = debug_js_realloc(ctx, p, size, file, line))) {
|
||||
if(pslack) {
|
||||
size_t new_size = debug_js_malloc_usable_size(ctx, ptr, file, line);
|
||||
*pslack = (new_size > size) ? new_size - size : 0;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_strdup(JSContext* ctx, const char* s, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
size_t len = strlen(s);
|
||||
|
||||
if((ptr = js_malloc(ctx, len + 1 + ALLOC_BLOCK_SIZE))) {
|
||||
char* p = (char*)&ptr[1];
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = len + 1;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
|
||||
memcpy(p, s, len + 1);
|
||||
return p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_strndup(JSContext* ctx, const char* s, size_t len, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = js_malloc(ctx, len + 1 + ALLOC_BLOCK_SIZE))) {
|
||||
char* p = (char*)&ptr[1];
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = len + 1;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
|
||||
memcpy(p, s, len);
|
||||
p[len] = '\0';
|
||||
|
||||
return p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
debug_js_malloc_usable_size(JSContext* ctx, const void* p, const char* file, int line) {
|
||||
ALLOC_PTR ptr = ALLOC_BLOCK(p);
|
||||
|
||||
return js_malloc_usable_size(ctx, ptr) - ALLOC_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
void
|
||||
debug_js_free(JSContext* ctx, void* p, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
check_pointer(p);
|
||||
ptr = ALLOC_BLOCK(p);
|
||||
list_del(&ptr->link);
|
||||
|
||||
memset(ptr, 0xff, ALLOC_BLOCK_SIZE);
|
||||
|
||||
js_free(ctx, ptr);
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_malloc_rt(JSRuntime* rt, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = js_malloc_rt(rt, n + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_mallocz_rt(JSRuntime* rt, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if((ptr = js_mallocz_rt(rt, n + ALLOC_BLOCK_SIZE))) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
debug_js_realloc_rt(JSRuntime* rt, void* p, size_t n, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
|
||||
if(p) {
|
||||
check_pointer(p);
|
||||
|
||||
ptr = ALLOC_BLOCK(p);
|
||||
list_del(&ptr->link);
|
||||
if(n == 0) {
|
||||
js_free_rt(rt, ptr);
|
||||
return 0;
|
||||
}
|
||||
ptr = js_realloc_rt(rt, ptr, n + ALLOC_BLOCK_SIZE);
|
||||
} else {
|
||||
ptr = js_malloc_rt(rt, n + ALLOC_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(ptr) {
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = n;
|
||||
|
||||
add_to_list(&ptr->link, &alloc_block_list);
|
||||
return &ptr[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
debug_js_malloc_usable_size_rt(JSRuntime* rt, const void* p, const char* file, int line) {
|
||||
ALLOC_PTR ptr = ALLOC_BLOCK(p);
|
||||
|
||||
return js_malloc_usable_size_rt(rt, ptr) - ALLOC_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
void
|
||||
debug_js_free_rt(JSRuntime* rt, void* p, const char* file, int line) {
|
||||
ALLOC_PTR ptr;
|
||||
check_pointer(p);
|
||||
|
||||
ptr = ALLOC_BLOCK(p);
|
||||
|
||||
// printf("debug_js_free_rt %p\n", p);
|
||||
|
||||
list_del(&ptr->link);
|
||||
|
||||
memset(ptr, 0xff, ALLOC_BLOCK_SIZE);
|
||||
|
||||
js_free_rt(rt, ptr);
|
||||
}
|
||||
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
#undef strdup
|
||||
#undef free
|
||||
#undef js_malloc
|
||||
#undef js_mallocz
|
||||
#undef js_realloc
|
||||
#undef js_strdup
|
||||
#undef js_strndup
|
||||
#undef js_malloc_usable_size
|
||||
#undef js_free
|
||||
#undef js_malloc_rt
|
||||
#undef js_mallocz_rt
|
||||
#undef js_realloc_rt
|
||||
#undef js_malloc_usable_size_rt
|
||||
#undef js_free_rt
|
||||
|
||||
void*
|
||||
orig_malloc(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_calloc(size_t nelem, size_t elemsz) {
|
||||
return calloc(nelem, elemsz);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_realloc(void* ptr, size_t size) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_strdup(const char* str) {
|
||||
return strdup(str);
|
||||
}
|
||||
|
||||
void
|
||||
orig_free(void* ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_malloc(JSContext* ctx, size_t size) {
|
||||
return js_malloc(ctx, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_mallocz(JSContext* ctx, size_t size) {
|
||||
return js_mallocz(ctx, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_realloc(JSContext* ctx, void* p, size_t size) {
|
||||
return js_realloc(ctx, p, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_strdup(JSContext* ctx, const char* str) {
|
||||
return js_strdup(ctx, str);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_strndup(JSContext* ctx, const char* str, size_t size) {
|
||||
return js_strndup(ctx, str, size);
|
||||
}
|
||||
|
||||
size_t
|
||||
orig_js_malloc_usable_size(JSContext* ctx, const void* p) {
|
||||
return js_malloc_usable_size(ctx, p);
|
||||
}
|
||||
|
||||
void
|
||||
orig_js_free(JSContext* ctx, void* p) {
|
||||
return js_free(ctx, p);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_malloc_rt(JSRuntime* rt, size_t size) {
|
||||
return js_malloc_rt(rt, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_mallocz_rt(JSRuntime* rt, size_t size) {
|
||||
return js_mallocz_rt(rt, size);
|
||||
}
|
||||
|
||||
void*
|
||||
orig_js_realloc_rt(JSRuntime* rt, void* p, size_t size) {
|
||||
return js_realloc_rt(rt, p, size);
|
||||
}
|
||||
|
||||
size_t
|
||||
orig_js_malloc_usable_size_rt(JSRuntime* rt, const void* p) {
|
||||
return js_malloc_usable_size_rt(rt, p);
|
||||
}
|
||||
|
||||
void
|
||||
orig_js_free_rt(JSRuntime* rt, void* p) {
|
||||
return js_free_rt(rt, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
165
src/quickjs/debug.h
Normal file
165
src/quickjs/debug.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <quickjs.h>
|
||||
#include <cutils.h>
|
||||
#include "defines.h"
|
||||
|
||||
#ifndef QUICKJS_H
|
||||
#error "quickjs.h not included"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup debug debug: Debugging helpers
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern thread_local struct list_head alloc_block_list;
|
||||
|
||||
int64_t check_pointer(void*);
|
||||
void* debug_malloc(size_t, const char*, int);
|
||||
void* debug_calloc(size_t, size_t, const char*, int line);
|
||||
void* debug_realloc(void*, size_t, const char*, int line);
|
||||
void* debug_strdup(const char*, const char*, int);
|
||||
void debug_free(void*, const char*, int);
|
||||
void* debug_js_malloc(JSContext*, size_t, const char*, int line);
|
||||
void* debug_js_mallocz(JSContext*, size_t, const char*, int line);
|
||||
void* debug_js_realloc(JSContext*, void*, size_t, const char* file, int line);
|
||||
void* debug_js_realloc2(JSContext*, void*, size_t, size_t* pslack, const char* file, int line);
|
||||
void* debug_js_strdup(JSContext*, const char*, const char*, int line);
|
||||
void* debug_js_strndup(JSContext*, const char*, size_t, const char* file, int line);
|
||||
size_t debug_js_malloc_usable_size(JSContext*, const void*, const char*, int line);
|
||||
void debug_js_free(JSContext*, void*, const char*, int line);
|
||||
void* debug_js_malloc_rt(JSRuntime*, size_t, const char*, int line);
|
||||
void* debug_js_mallocz_rt(JSRuntime*, size_t, const char*, int line);
|
||||
void* debug_js_realloc_rt(JSRuntime*, void*, size_t, const char* file, int line);
|
||||
size_t debug_js_malloc_usable_size_rt(JSRuntime*, const void*, const char*, int line);
|
||||
void debug_js_free_rt(JSRuntime*, void*, const char*, int line);
|
||||
|
||||
#if !defined(_IN_DEBUG_C)
|
||||
|
||||
#if defined(DEBUG_ALLOC)
|
||||
#define malloc(size) debug_malloc(size, __FILE__, __LINE__)
|
||||
#define calloc(nelem, size) debug_calloc(nelem, size, __FILE__, __LINE__)
|
||||
#define realloc(ptr, size) debug_realloc(ptr, size, __FILE__, __LINE__)
|
||||
#define strdup(str) debug_strdup(str, __FILE__, __LINE__)
|
||||
#define free(ptr) debug_free(ptr, __FILE__, __LINE__)
|
||||
#define js_malloc(ctx, size) debug_js_malloc(ctx, size, __FILE__, __LINE__)
|
||||
#define js_mallocz(ctx, size) debug_js_mallocz(ctx, size, __FILE__, __LINE__)
|
||||
#define js_realloc(ctx, ptr, size) debug_js_realloc(ctx, ptr, size, __FILE__, __LINE__)
|
||||
#define js_strdup(ctx, str) debug_js_strdup(ctx, str, __FILE__, __LINE__)
|
||||
#define js_strndup(ctx, str, len) debug_js_strndup(ctx, str, len, __FILE__, __LINE__)
|
||||
#define js_free(ctx, ptr) debug_js_free(ctx, ptr, __FILE__, __LINE__)
|
||||
#define js_malloc_usable_size(ctx, ptr) debug_js_malloc_usable_size(ctx, ptr, __FILE__, __LINE__)
|
||||
#define js_malloc_rt(rt, size) debug_js_malloc_rt(rt, size, __FILE__, __LINE__)
|
||||
#define js_mallocz_rt(rt, size) debug_js_mallocz_rt(rt, size, __FILE__, __LINE__)
|
||||
#define js_realloc_rt(rt, ptr, size) debug_js_realloc_rt(rt, ptr, size, __FILE__, __LINE__)
|
||||
#define js_malloc_usable_size_rt(rt, ptr) debug_js_malloc_usable_size_rt(rt, ptr, __FILE__, __LINE__)
|
||||
#define js_free_rt(rt, ptr) debug_js_free_rt(rt, ptr, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
#define realloc_helper(name) \
|
||||
void* name(void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return debug_malloc(size, __FILE__, __LINE__); \
|
||||
if(size == 0) \
|
||||
return debug_free(ptr, __FILE__, __LINE__); \
|
||||
return debug_realloc(ptr, size, __FILE__, __LINE__); \
|
||||
}
|
||||
#define realloc2_helper(name) \
|
||||
void* name(void* opaque, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return debug_malloc(size, __FILE__, __LINE__); \
|
||||
if(size == 0) { \
|
||||
debug_free(ptr, __FILE__, __LINE__); \
|
||||
return 0; \
|
||||
} \
|
||||
return debug_realloc(ptr, size, __FILE__, __LINE__); \
|
||||
}
|
||||
#define js_realloc_helper(name) \
|
||||
void* name(JSContext* ctx, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return debug_js_malloc(ctx, size, __FILE__, __LINE__); \
|
||||
if(size == 0) { \
|
||||
debug_js_free(ctx, ptr, __FILE__, __LINE__); \
|
||||
return 0; \
|
||||
} \
|
||||
return debug_js_realloc(ctx, ptr, size, __FILE__, __LINE__); \
|
||||
}
|
||||
#define js_realloc_rt_helper(name) \
|
||||
void* name(JSRuntime* rt, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return debug_js_malloc_rt(rt, size, __FILE__, __LINE__); \
|
||||
if(size == 0) { \
|
||||
debug_js_free_rt(rt, ptr, __FILE__, __LINE__); \
|
||||
return 0; \
|
||||
} \
|
||||
return debug_js_realloc_rt(rt, ptr, size, __FILE__, __LINE__); \
|
||||
}
|
||||
#else
|
||||
#define realloc_helper(name) \
|
||||
void* name(void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return malloc(size); \
|
||||
if(size == 0) { \
|
||||
free(ptr); \
|
||||
return 0; \
|
||||
} \
|
||||
return realloc(ptr, size); \
|
||||
}
|
||||
#define realloc2_helper(name) \
|
||||
void* name(void* opaque, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return malloc(size); \
|
||||
if(size == 0) { \
|
||||
free(ptr); \
|
||||
return 0; \
|
||||
} \
|
||||
return realloc(ptr, size); \
|
||||
}
|
||||
#define js_realloc_helper(name) \
|
||||
void* name(JSContext* ctx, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return orig_js_malloc(ctx, size); \
|
||||
if(size == 0) { \
|
||||
orig_js_free(ctx, ptr); \
|
||||
return 0; \
|
||||
} \
|
||||
return orig_js_realloc(ctx, ptr, size); \
|
||||
}
|
||||
#define js_realloc_rt_helper(name) \
|
||||
void* name(JSRuntime* rt, void* ptr, size_t size) { \
|
||||
if(ptr == 0) \
|
||||
return orig_js_malloc_rt(rt, size); \
|
||||
if(size == 0) { \
|
||||
orig_js_free_rt(rt, ptr); \
|
||||
return 0; \
|
||||
} \
|
||||
return orig_js_realloc_rt(rt, ptr, size); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void* orig_malloc(size_t);
|
||||
void* orig_calloc(size_t, size_t);
|
||||
void* orig_realloc(void*, size_t);
|
||||
void* orig_strdup(const char*);
|
||||
void orig_free(void*);
|
||||
void* orig_js_malloc(JSContext*, size_t);
|
||||
void* orig_js_mallocz(JSContext*, size_t);
|
||||
void* orig_js_realloc(JSContext*, void*, size_t);
|
||||
void* orig_js_strdup(JSContext*, const char*);
|
||||
void* orig_js_strndup(JSContext*, const char*, size_t);
|
||||
size_t orig_js_malloc_usable_size(JSContext*, const void*);
|
||||
void orig_js_free(JSContext*, void*);
|
||||
void* orig_js_malloc_rt(JSRuntime*, size_t);
|
||||
void* orig_js_mallocz_rt(JSRuntime*, size_t);
|
||||
void* orig_js_realloc_rt(JSRuntime*, void*, size_t);
|
||||
size_t orig_js_malloc_usable_size_rt(JSRuntime*, const void*);
|
||||
void orig_js_free_rt(JSRuntime*, void*);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* defined(DEBUG_H) */
|
||||
181
src/quickjs/defines.h
Normal file
181
src/quickjs/defines.h
Normal file
@@ -0,0 +1,181 @@
|
||||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
/**
|
||||
* \defgroup defines defines: Preprocessor definitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#define FD_TO_SOCKET(fd) ((SOCKET)_get_osfhandle((fd)))
|
||||
#define SOCKET_TO_FD(fh) (_open_osfhandle((intptr_t)(fh), O_RDWR | O_BINARY))
|
||||
#else
|
||||
#define FD_TO_SOCKET(fd) (fd)
|
||||
#define SOCKET_TO_FD(fh) (fh)
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) & ((type*)0)->field)
|
||||
#endif
|
||||
|
||||
#ifndef inrange
|
||||
#define inrange(value, min, max) ((value) >= (min) && (value) <= (max))
|
||||
#endif
|
||||
|
||||
#define trim_dotslash(str) (!strncmp((str), "./", 2) ? (str) + 2 : (str))
|
||||
|
||||
#ifndef thread_local
|
||||
#ifdef _Thread_local
|
||||
#define thread_local _Thread_local
|
||||
#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
|
||||
#define thread_local __thread
|
||||
#elif defined(_WIN32)
|
||||
#define thread_local __declspec(thread)
|
||||
#else
|
||||
#error No TLS implementation found.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define PACK __attribute__((packed))
|
||||
#define ENDPACK
|
||||
#else
|
||||
#define PACK #pragma pack(push, 1)
|
||||
#define ENDPACK #pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define JS_CGETSET_ENUMERABLE_DEF(prop_name, fgetter, fsetter, magic_num) \
|
||||
{ \
|
||||
.name = prop_name, .prop_flags = JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE, .def_type = JS_DEF_CGETSET_MAGIC, .magic = magic_num, .u = { \
|
||||
.getset = {.get = {.getter_magic = fgetter}, .set = {.setter_magic = fsetter}} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define JS_CGETSET_MAGIC_FLAGS_DEF(prop_name, fgetter, fsetter, magic_num, flags) \
|
||||
{ \
|
||||
.name = prop_name, .prop_flags = flags, .def_type = JS_DEF_CGETSET_MAGIC, .magic = magic_num, .u = { \
|
||||
.getset = {.get = {.getter_magic = fgetter}, .set = {.setter_magic = fsetter}} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define JS_CFUNC_DEF_FLAGS(prop_name, length, func1, flags) \
|
||||
{ \
|
||||
.name = prop_name, .prop_flags = flags, .def_type = JS_DEF_CFUNC, .magic = 0, .u = {.func = {length, JS_CFUNC_generic, {.generic = func1}} } \
|
||||
}
|
||||
|
||||
#define JS_CONSTANT_FLAGS(name, flags) JS_PROP_INT32_DEF(#name, name, (flags))
|
||||
#define JS_CONSTANT(name) JS_PROP_INT32_DEF(#name, name, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)
|
||||
#define JS_CONSTANT_NONENUMERABLE(name) JS_PROP_INT32_DEF(#name, name, JS_PROP_CONFIGURABLE)
|
||||
|
||||
#ifdef JS_SHARED_LIBRARY
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
#define VISIBLE __declspec(dllexport)
|
||||
#define HIDDEN
|
||||
#else
|
||||
#define VISIBLE __attribute__((visibility("default")))
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
#else
|
||||
#define VISIBLE
|
||||
#define HIDDEN
|
||||
#endif
|
||||
|
||||
#ifndef MAX_NUM
|
||||
#define MAX_NUM(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MIN_NUM
|
||||
#define MIN_NUM(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef ABS_NUM
|
||||
#define ABS_NUM(n) ((n) < 0 ? -(n) : (n))
|
||||
#endif
|
||||
#ifndef MOD_NUM
|
||||
#define MOD_NUM(n, divisor) ((((n) % (divisor)) + (divisor)) % (divisor))
|
||||
#endif
|
||||
#ifndef SIGN_NUM
|
||||
#define SIGN_NUM(n) ((n) < 0)
|
||||
#endif
|
||||
|
||||
#define COLOR_BLACK "\x1b[0;30m"
|
||||
#define COLOR_RED "\x1b[0;31m"
|
||||
#define COLOR_GREEN "\x1b[0;32m"
|
||||
#define COLOR_BROWN "\x1b[0;33m"
|
||||
#define COLOR_BLUE "\x1b[0;34m"
|
||||
#define COLOR_PURPLE "\x1b[0;35m"
|
||||
#define COLOR_MARINE "\x1b[0;36m"
|
||||
#define COLOR_LIGHTGRAY "\x1b[0;37m"
|
||||
#define COLOR_GRAY "\x1b[1;30m"
|
||||
#define COLOR_NONE "\x1b[0m"
|
||||
|
||||
#define COLOR_LIGHTRED "\x1b[1;31m"
|
||||
|
||||
#define COLOR_LIGHTGREEN "\x1b[1;32m"
|
||||
#define COLOR_YELLOW "\x1b[1;33m"
|
||||
#define COLOR_LIGHTBLUE "\x1b[1;34m"
|
||||
#define COLOR_MAGENTA "\x1b[1;35m"
|
||||
#define COLOR_CYAN "\x1b[1;36m"
|
||||
#define COLOR_WHITE "\x1b[1;37m"
|
||||
|
||||
#define BGCOLOR_RED "\x1b[48;5;124m"
|
||||
#define BGCOLOR_BLUE "\x1b[48;5;20m"
|
||||
#define BGCOLOR_YELLOW "\x1b[48;5;214m"
|
||||
#define BGCOLOR_GREEN "\x1b[48;5;28m"
|
||||
#define BGCOLOR_PINK "\x1b[48;5;165m"
|
||||
|
||||
#define JS_VALUE_FREE(ctx, value) \
|
||||
do { \
|
||||
JS_FreeValue((ctx), (value)); \
|
||||
(value) = JS_UNDEFINED; \
|
||||
} while(0);
|
||||
#define JS_VALUE_FREE_RT(ctx, value) \
|
||||
do { \
|
||||
JS_FreeValueRT((ctx), (value)); \
|
||||
(value) = JS_UNDEFINED; \
|
||||
} while(0);
|
||||
|
||||
#if 0
|
||||
#define js_object_tmpmark_set(value) \
|
||||
do { \
|
||||
((uint8_t*)JS_VALUE_GET_OBJ((value)))[5] |= 0x40; \
|
||||
} while(0);
|
||||
#define js_object_tmpmark_clear(value) \
|
||||
do { \
|
||||
((uint8_t*)JS_VALUE_GET_OBJ((value)))[5] &= ~0x40; \
|
||||
} while(0);
|
||||
#define js_object_tmpmark_isset(value) (((uint8_t*)JS_VALUE_GET_OBJ((value)))[5] & 0x40)
|
||||
#else
|
||||
#define js_object_tmpmark_set(value) \
|
||||
do { \
|
||||
JS_VALUE_GET_OBJ((value))->tmp_mark |= 0x40; \
|
||||
} while(0);
|
||||
#define js_object_tmpmark_clear(value) \
|
||||
do { \
|
||||
JS_VALUE_GET_OBJ((value))->tmp_mark &= ~0x40; \
|
||||
} while(0);
|
||||
#define js_object_tmpmark_isset(value) (JS_VALUE_GET_OBJ((value))->tmp_mark & 0x40)
|
||||
#endif
|
||||
|
||||
#define js_runtime_exception_set(rt, value) \
|
||||
do { \
|
||||
*(JSValue*)((uint8_t*)(rt) + 216) = value; \
|
||||
} while(0);
|
||||
#define js_runtime_exception_get(rt) (*(JSValue*)((uint8_t*)(rt) + 216))
|
||||
#define js_runtime_exception_clear(rt) \
|
||||
do { \
|
||||
if(!JS_IsNull(js_runtime_exception_get(rt))) \
|
||||
JS_FreeValueRT((rt), js_runtime_exception_get(rt)); \
|
||||
js_runtime_exception_set(rt, JS_NULL); \
|
||||
} while(0)
|
||||
|
||||
#define JS_ATOM_TAG_INT (1U << 31)
|
||||
#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
|
||||
|
||||
#define JS_ATOM_ISINT(i) ((JSAtom)((i)&JS_ATOM_TAG_INT))
|
||||
#define JS_ATOM_FROMINT(i) ((JSAtom)((i)&JS_ATOM_MAX_INT) | JS_ATOM_TAG_INT)
|
||||
#define JS_ATOM_TOINT(i) (unsigned int)(((JSAtom)(i) & (~(JS_ATOM_TAG_INT))))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* defined(DEFINES_H) */
|
||||
45
src/quickjs/hello.c
Normal file
45
src/quickjs/hello.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* File generated automatically by the QuickJS compiler. */
|
||||
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
const uint32_t qjsc_hello_size = 87;
|
||||
|
||||
const uint8_t qjsc_hello[87] = {
|
||||
0x43, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
|
||||
0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48,
|
||||
0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
|
||||
0x6c, 0x64, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x2e, 0x6a, 0x73, 0x0c, 0x00, 0x06, 0x00,
|
||||
0xa2, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
|
||||
0x14, 0x01, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x38,
|
||||
0xe3, 0x00, 0x00, 0x00, 0x42, 0xe4, 0x00, 0x00,
|
||||
0x00, 0x04, 0xe5, 0x00, 0x00, 0x00, 0x24, 0x01,
|
||||
0x00, 0xcf, 0x28, 0xcc, 0x03, 0x01, 0x00,
|
||||
};
|
||||
|
||||
static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
{
|
||||
JSContext *ctx = JS_NewContextRaw(rt);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
JS_AddIntrinsicBaseObjects(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSContext *ctx;
|
||||
rt = JS_NewRuntime();
|
||||
js_std_set_worker_new_context_func(JS_NewCustomContext);
|
||||
js_std_init_handlers(rt);
|
||||
ctx = JS_NewCustomContext(rt);
|
||||
js_std_add_helpers(ctx, argc, argv);
|
||||
js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
|
||||
js_std_loop(ctx);
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
27
src/quickjs/iso_8859_1.h
Normal file
27
src/quickjs/iso_8859_1.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_1_H
|
||||
#define TUTF8E_ISO_8859_1_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_1_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_1, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_1_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_1, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_1_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_1, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_1_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_1, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_10.h
Normal file
27
src/quickjs/iso_8859_10.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_10_H
|
||||
#define TUTF8E_ISO_8859_10_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_10_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_10, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_10_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_10, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_10_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_10, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_10_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_10, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_11.h
Normal file
27
src/quickjs/iso_8859_11.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_11_H
|
||||
#define TUTF8E_ISO_8859_11_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_11_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_11, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_11_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_11, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_11_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_11, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_11_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_11, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_13.h
Normal file
27
src/quickjs/iso_8859_13.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_13_H
|
||||
#define TUTF8E_ISO_8859_13_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_13_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_13, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_13_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_13, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_13_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_13, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_13_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_13, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_14.h
Normal file
27
src/quickjs/iso_8859_14.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_14_H
|
||||
#define TUTF8E_ISO_8859_14_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_14_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_14, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_14_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_14, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_14_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_14, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_14_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_14, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_15.h
Normal file
27
src/quickjs/iso_8859_15.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_15_H
|
||||
#define TUTF8E_ISO_8859_15_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_15_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_15, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_15_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_15, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_15_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_15, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_15_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_15, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_16.h
Normal file
27
src/quickjs/iso_8859_16.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_16_H
|
||||
#define TUTF8E_ISO_8859_16_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_16_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_16, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_16_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_16, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_16_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_16, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_16_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_16, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_2.h
Normal file
27
src/quickjs/iso_8859_2.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_2_H
|
||||
#define TUTF8E_ISO_8859_2_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_2_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_2, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_2_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_2, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_2_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_2, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_2_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_2, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_3.h
Normal file
27
src/quickjs/iso_8859_3.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_3_H
|
||||
#define TUTF8E_ISO_8859_3_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_3_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_3, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_3_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_3, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_3_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_3, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_3_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_3, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_4.h
Normal file
27
src/quickjs/iso_8859_4.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_4_H
|
||||
#define TUTF8E_ISO_8859_4_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_4_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_4, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_4_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_4, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_4_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_4, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_4_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_4, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_5.h
Normal file
27
src/quickjs/iso_8859_5.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_5_H
|
||||
#define TUTF8E_ISO_8859_5_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_5_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_5, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_5_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_5, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_5_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_5, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_5_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_5, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_6.h
Normal file
27
src/quickjs/iso_8859_6.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_6_H
|
||||
#define TUTF8E_ISO_8859_6_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_6_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_6, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_6_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_6, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_6_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_6, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_6_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_6, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_7.h
Normal file
27
src/quickjs/iso_8859_7.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_7_H
|
||||
#define TUTF8E_ISO_8859_7_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_7_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_7, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_7_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_7, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_7_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_7, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_7_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_7, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_8.h
Normal file
27
src/quickjs/iso_8859_8.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_8_H
|
||||
#define TUTF8E_ISO_8859_8_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_8_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_8, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_8_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_8, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_8_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_8, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_8_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_8, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/quickjs/iso_8859_9.h
Normal file
27
src/quickjs/iso_8859_9.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef TUTF8E_ISO_8859_9_H
|
||||
#define TUTF8E_ISO_8859_9_H
|
||||
|
||||
#include <tutf8e.h>
|
||||
|
||||
static inline int tutf8e_iso_8859_9_string_length(const char *input, size_t *input_length, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_length(tutf8e_encoder_iso_8859_9, input, input_length, invalid, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_9_string_encode(const char *input, char *output, const char *invalid, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_string_encode(tutf8e_encoder_iso_8859_9, input, invalid, output, output_length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_9_buffer_length(const char *i, size_t input_length, const char *invalid, size_t *length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_length(tutf8e_encoder_iso_8859_9, input, input_length, invalid, length);
|
||||
}
|
||||
|
||||
static inline int tutf8e_iso_8859_9_buffer_encode(const char *i, size_t input_length, const char *invalid, char *output, size_t *output_length)
|
||||
{
|
||||
return tutf8e_encoder_buffer_encode(tutf8e_encoder_iso_8859_9, input, input_length, invalid, output, output_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
8473
src/quickjs/libbf.c
Normal file
8473
src/quickjs/libbf.c
Normal file
File diff suppressed because it is too large
Load Diff
535
src/quickjs/libbf.h
Normal file
535
src/quickjs/libbf.h
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Tiny arbitrary precision floating point library
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBBF_H
|
||||
#define LIBBF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
|
||||
#define LIMB_LOG2_BITS 6
|
||||
#else
|
||||
#define LIMB_LOG2_BITS 5
|
||||
#endif
|
||||
|
||||
#define LIMB_BITS (1 << LIMB_LOG2_BITS)
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
typedef __int128 int128_t;
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef int64_t slimb_t;
|
||||
typedef uint64_t limb_t;
|
||||
typedef uint128_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT64_MIN
|
||||
#define BF_RAW_EXP_MAX INT64_MAX
|
||||
|
||||
#define LIMB_DIGITS 19
|
||||
#define BF_DEC_BASE UINT64_C(10000000000000000000)
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t slimb_t;
|
||||
typedef uint32_t limb_t;
|
||||
typedef uint64_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT32_MIN
|
||||
#define BF_RAW_EXP_MAX INT32_MAX
|
||||
|
||||
#define LIMB_DIGITS 9
|
||||
#define BF_DEC_BASE 1000000000U
|
||||
|
||||
#endif
|
||||
|
||||
/* in bits */
|
||||
/* minimum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MIN 3
|
||||
/* maximum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
|
||||
/* extended range for exponent, used internally */
|
||||
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MIN 2
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
|
||||
/* some operations support infinite precision */
|
||||
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
|
||||
#else
|
||||
#define BF_CHKSUM_MOD 975620677U
|
||||
#endif
|
||||
|
||||
#define BF_EXP_ZERO BF_RAW_EXP_MIN
|
||||
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
|
||||
#define BF_EXP_NAN BF_RAW_EXP_MAX
|
||||
|
||||
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
|
||||
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
|
||||
NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
|
||||
*/
|
||||
typedef struct {
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bf_t;
|
||||
|
||||
typedef struct {
|
||||
/* must be kept identical to bf_t */
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bfdec_t;
|
||||
|
||||
typedef enum {
|
||||
BF_RNDN, /* round to nearest, ties to even */
|
||||
BF_RNDZ, /* round to zero */
|
||||
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
|
||||
BF_RNDU, /* round to +inf */
|
||||
BF_RNDNA, /* round to nearest, ties away from zero */
|
||||
BF_RNDA, /* round away from zero */
|
||||
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
|
||||
inexact flag is always set) */
|
||||
} bf_rnd_t;
|
||||
|
||||
/* allow subnormal numbers. Only available if the number of exponent
|
||||
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
|
||||
#define BF_FLAG_SUBNORMAL (1 << 3)
|
||||
/* 'prec' is the precision after the radix point instead of the whole
|
||||
mantissa. Can only be used with bf_round() and
|
||||
bfdec_[add|sub|mul|div|sqrt|round](). */
|
||||
#define BF_FLAG_RADPNT_PREC (1 << 4)
|
||||
|
||||
#define BF_RND_MASK 0x7
|
||||
#define BF_EXP_BITS_SHIFT 5
|
||||
#define BF_EXP_BITS_MASK 0x3f
|
||||
|
||||
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
|
||||
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
|
||||
|
||||
/* contains the rounding mode and number of exponents bits */
|
||||
typedef uint32_t bf_flags_t;
|
||||
|
||||
typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
|
||||
|
||||
typedef struct {
|
||||
bf_t val;
|
||||
limb_t prec;
|
||||
} BFConstCache;
|
||||
|
||||
typedef struct bf_context_t {
|
||||
void *realloc_opaque;
|
||||
bf_realloc_func_t *realloc_func;
|
||||
BFConstCache log2_cache;
|
||||
BFConstCache pi_cache;
|
||||
struct BFNTTState *ntt_state;
|
||||
} bf_context_t;
|
||||
|
||||
static inline int bf_get_exp_bits(bf_flags_t flags)
|
||||
{
|
||||
int e;
|
||||
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
|
||||
if (e == BF_EXP_BITS_MASK)
|
||||
return BF_EXP_BITS_MAX + 1;
|
||||
else
|
||||
return BF_EXP_BITS_MAX - e;
|
||||
}
|
||||
|
||||
static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
{
|
||||
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
|
||||
}
|
||||
|
||||
/* returned status */
|
||||
#define BF_ST_INVALID_OP (1 << 0)
|
||||
#define BF_ST_DIVIDE_ZERO (1 << 1)
|
||||
#define BF_ST_OVERFLOW (1 << 2)
|
||||
#define BF_ST_UNDERFLOW (1 << 3)
|
||||
#define BF_ST_INEXACT (1 << 4)
|
||||
/* indicate that a memory allocation error occured. NaN is returned */
|
||||
#define BF_ST_MEM_ERROR (1 << 5)
|
||||
|
||||
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
|
||||
|
||||
static inline slimb_t bf_max(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline slimb_t bf_min(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
|
||||
void *realloc_opaque);
|
||||
void bf_context_end(bf_context_t *s);
|
||||
/* free memory allocated for the bf cache data */
|
||||
void bf_clear_cache(bf_context_t *s);
|
||||
|
||||
static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
|
||||
{
|
||||
return s->realloc_func(s->realloc_opaque, ptr, size);
|
||||
}
|
||||
|
||||
/* 'size' must be != 0 */
|
||||
static inline void *bf_malloc(bf_context_t *s, size_t size)
|
||||
{
|
||||
return bf_realloc(s, NULL, size);
|
||||
}
|
||||
|
||||
static inline void bf_free(bf_context_t *s, void *ptr)
|
||||
{
|
||||
/* must test ptr otherwise equivalent to malloc(0) */
|
||||
if (ptr)
|
||||
bf_realloc(s, ptr, 0);
|
||||
}
|
||||
|
||||
void bf_init(bf_context_t *s, bf_t *r);
|
||||
|
||||
static inline void bf_delete(bf_t *r)
|
||||
{
|
||||
bf_context_t *s = r->ctx;
|
||||
/* we accept to delete a zeroed bf_t structure */
|
||||
if (s && r->tab) {
|
||||
bf_realloc(s, r->tab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bf_neg(bf_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bf_is_finite(const bf_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bf_is_nan(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bf_is_zero(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bf_memcpy(bf_t *r, const bf_t *a)
|
||||
{
|
||||
*r = *a;
|
||||
}
|
||||
|
||||
int bf_set_ui(bf_t *r, uint64_t a);
|
||||
int bf_set_si(bf_t *r, int64_t a);
|
||||
void bf_set_nan(bf_t *r);
|
||||
void bf_set_zero(bf_t *r, int is_neg);
|
||||
void bf_set_inf(bf_t *r, int is_neg);
|
||||
int bf_set(bf_t *r, const bf_t *a);
|
||||
void bf_move(bf_t *r, bf_t *a);
|
||||
int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
|
||||
int bf_set_float64(bf_t *a, double d);
|
||||
|
||||
int bf_cmpu(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_full(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp(const bf_t *a, const bf_t *b);
|
||||
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) <= 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
|
||||
int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
#define BF_DIVREM_EUCLIDIAN BF_RNDF
|
||||
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
/* round to integer with infinite precision */
|
||||
int bf_rint(bf_t *r, int rnd_mode);
|
||||
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
|
||||
int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
slimb_t bf_get_exp_min(const bf_t *a);
|
||||
int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
|
||||
/* additional flags for bf_atof */
|
||||
/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
|
||||
#define BF_ATOF_NO_HEX (1 << 16)
|
||||
/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
|
||||
#define BF_ATOF_BIN_OCT (1 << 17)
|
||||
/* Do not parse NaN or Inf */
|
||||
#define BF_ATOF_NO_NAN_INF (1 << 18)
|
||||
/* return the exponent separately */
|
||||
#define BF_ATOF_EXPONENT (1 << 19)
|
||||
|
||||
int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
/* this version accepts prec = BF_PREC_INF and returns the radix
|
||||
exponent */
|
||||
int bf_atof2(bf_t *r, slimb_t *pexponent,
|
||||
const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
||||
slimb_t expn, limb_t prec, bf_flags_t flags);
|
||||
|
||||
|
||||
/* Conversion of floating point number to string. Return a null
|
||||
terminated string or NULL if memory error. *plen contains its
|
||||
length if plen != NULL. The exponent letter is "e" for base 10,
|
||||
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
|
||||
bases. */
|
||||
|
||||
#define BF_FTOA_FORMAT_MASK (3 << 16)
|
||||
|
||||
/* fixed format: prec significant digits rounded with (flags &
|
||||
BF_RND_MASK). Exponential notation is used if too many zeros are
|
||||
needed.*/
|
||||
#define BF_FTOA_FORMAT_FIXED (0 << 16)
|
||||
/* fractional format: prec digits after the decimal point rounded with
|
||||
(flags & BF_RND_MASK) */
|
||||
#define BF_FTOA_FORMAT_FRAC (1 << 16)
|
||||
/* free format:
|
||||
|
||||
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
|
||||
number of digits to represent 'a'. The precision and the rounding
|
||||
mode are ignored.
|
||||
|
||||
For the non binary radices with bf_ftoa(): use as many digits as
|
||||
necessary so that bf_atof() return the same number when using
|
||||
precision 'prec', rounding to nearest and the subnormal
|
||||
configuration of 'flags'. The result is meaningful only if 'a' is
|
||||
already rounded to 'prec' bits. If the subnormal flag is set, the
|
||||
exponent in 'flags' must also be set to the desired exponent range.
|
||||
*/
|
||||
#define BF_FTOA_FORMAT_FREE (2 << 16)
|
||||
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
|
||||
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
|
||||
binary radices with bf_ftoa() and for bfdec_ftoa(). */
|
||||
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
|
||||
|
||||
/* force exponential notation for fixed or free format */
|
||||
#define BF_FTOA_FORCE_EXP (1 << 20)
|
||||
/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
|
||||
base 2 if non zero value */
|
||||
#define BF_FTOA_ADD_PREFIX (1 << 21)
|
||||
/* return "Infinity" instead of "Inf" and add a "+" for positive
|
||||
exponents */
|
||||
#define BF_FTOA_JS_QUIRKS (1 << 22)
|
||||
|
||||
char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
|
||||
/* modulo 2^n instead of saturation. NaN and infinity return 0 */
|
||||
#define BF_GET_INT_MOD (1 << 0)
|
||||
int bf_get_int32(int *pres, const bf_t *a, int flags);
|
||||
int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
|
||||
int bf_get_uint64(uint64_t *pres, const bf_t *a);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
void mp_print_str(const char *str, const limb_t *tab, limb_t n);
|
||||
void bf_print_str(const char *str, const bf_t *a);
|
||||
int bf_resize(bf_t *r, limb_t len);
|
||||
int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
|
||||
int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
|
||||
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
|
||||
slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
|
||||
int is_ceil1);
|
||||
int mp_mul(bf_context_t *s, limb_t *result,
|
||||
const limb_t *op1, limb_t op1_size,
|
||||
const limb_t *op2, limb_t op2_size);
|
||||
limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
|
||||
limb_t n, limb_t carry);
|
||||
limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
|
||||
int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
|
||||
int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
|
||||
limb_t bf_isqrt(limb_t a);
|
||||
|
||||
/* transcendental functions */
|
||||
int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
|
||||
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
|
||||
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* decimal floating point */
|
||||
|
||||
static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
|
||||
{
|
||||
bf_init(s, (bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_delete(bfdec_t *r)
|
||||
{
|
||||
bf_delete((bf_t *)r);
|
||||
}
|
||||
|
||||
static inline void bfdec_neg(bfdec_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bfdec_is_finite(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_nan(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_zero(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
bf_memcpy((bf_t *)r, (const bf_t *)a);
|
||||
}
|
||||
|
||||
int bfdec_set_ui(bfdec_t *r, uint64_t a);
|
||||
int bfdec_set_si(bfdec_t *r, int64_t a);
|
||||
|
||||
static inline void bfdec_set_nan(bfdec_t *r)
|
||||
{
|
||||
bf_set_nan((bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_zero((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_inf((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
return bf_set((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
|
||||
{
|
||||
bf_move((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmpu((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) == 0;
|
||||
}
|
||||
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) <= 0;
|
||||
}
|
||||
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rint(bfdec_t *r, int rnd_mode);
|
||||
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_get_int32(int *pres, const bfdec_t *a);
|
||||
int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
|
||||
|
||||
char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
|
||||
void bfdec_print_str(const char *str, const bfdec_t *a);
|
||||
static inline int bfdec_resize(bfdec_t *r, limb_t len)
|
||||
{
|
||||
return bf_resize((bf_t *)r, len);
|
||||
}
|
||||
int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
|
||||
|
||||
#endif /* LIBBF_H */
|
||||
57
src/quickjs/libregexp-opcode.h
Normal file
57
src/quickjs/libregexp-opcode.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Regular Expression Engine
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef DEF
|
||||
|
||||
DEF(invalid, 1) /* never used */
|
||||
DEF(char, 3)
|
||||
DEF(char32, 5)
|
||||
DEF(dot, 1)
|
||||
DEF(any, 1) /* same as dot but match any character including line terminator */
|
||||
DEF(line_start, 1)
|
||||
DEF(line_end, 1)
|
||||
DEF(goto, 5)
|
||||
DEF(split_goto_first, 5)
|
||||
DEF(split_next_first, 5)
|
||||
DEF(match, 1)
|
||||
DEF(save_start, 2) /* save start position */
|
||||
DEF(save_end, 2) /* save end position, must come after saved_start */
|
||||
DEF(save_reset, 3) /* reset save positions */
|
||||
DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
|
||||
DEF(push_i32, 5) /* push integer on the stack */
|
||||
DEF(drop, 1)
|
||||
DEF(word_boundary, 1)
|
||||
DEF(not_word_boundary, 1)
|
||||
DEF(back_reference, 2)
|
||||
DEF(backward_back_reference, 2) /* must come after back_reference */
|
||||
DEF(range, 3) /* variable length */
|
||||
DEF(range32, 3) /* variable length */
|
||||
DEF(lookahead, 5)
|
||||
DEF(negative_lookahead, 5)
|
||||
DEF(push_char_pos, 1) /* push the character position on the stack */
|
||||
DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
|
||||
DEF(prev, 1) /* go to the previous char */
|
||||
DEF(simple_greedy_quant, 17)
|
||||
|
||||
#endif /* DEF */
|
||||
2528
src/quickjs/libregexp.c
Normal file
2528
src/quickjs/libregexp.c
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