examples/curl/
Call libcurl from Heroes, including a function that accepts a variable number of arguments.
- 99 lines
- uses C:
curl_bound.h
libcurl is a C library for transferring data over a network. This program prints the version installed on your computer. That version can differ between computers, so the example has no fixed output for the tests to compare.
Run it
This program has no recorded output.
The program
## The ladder's fourth rung: libcurl
#
# Author instruction, and it earned its place in the first minute.
# SQLite is pure C with plain `i64` returns; libcurl is where the boundary meets
# the two things §4.19 had only argued about.
#
# **A variadic.** `curl_easy_setopt(CURL *, CURLoption, ...)` takes its value
# through `...`, which is where Apple ARM64 passes arguments on the stack rather
# than in registers (panel 013 named it; this is the first Heroes program to
# depend on it). Heroes has no user variadics, and it does not need any: the
# declaration names the arguments this call site passes, and clang checks them
# against the real prototype.
#
# **An enum return.** `CURLcode` is an `enum`, and `_Generic` selects on an
# enum's own type rather than on `i64` — so the return-type assertion this
# compiler writes refused *every enum-returning C function in existence* until
# this program was compiled. Invisible against SQLite, which returns plain `i64`.
# The repair is in `emit/decls.rs`: unary `+` applies the integer promotions, and
# the accepted set is every signed integer plus every unsigned one narrower than
# 64 bits — which is exactly what fits in Heroes' `i64` without losing a value,
# and still leaves `size_t` firing.
#
# **Three enum constants**, since M-header-constants. `CURLOPT_URL` is a
# `CURLoption` enumerator, so this program named it by hand as `10002` — with the
# `CURLOPTTYPE_STRINGPOINT + 2` derivation in a comment above it and nothing on
# either side checking the arithmetic. `heroes mutate` measured that: five copied
# constants in `examples/`, none caught by anything. They are now group members
# with no value, so the digits are not in this file to be wrong.
#
# No request is made. A test that reaches the network is a test that fails on a
# train, and everything interesting here is settled before the first byte.
#
# **The group names `curl_bound.h`, beside this file, and not `curl/curl.h`**
# (defect 2229, 2026-10-26). libcurl 8.18 makes `curl_easy_setopt` a macro whose
# expansion holds a `_Pragma`, which changes how clang judges every line after
# the call, so the compiler refuses to bind it (`ffi_macro_name`); the header
# includes `curl/curl.h` and takes that macro off, as the refusal's note says,
# and the name binds the function libcurl declares.
extern "curl_bound.h" link "curl"
# The three values this program drives libcurl with. Their numbers are in
# `curl.h` and nowhere here, which is the whole point: `CURLOPT_URL` is
# `CURLOPTTYPE_STRINGPOINT + 2`, and the arithmetic is libcurl's business.
# This file used to say `10002`, with that derivation in a comment and nothing
# checking either (panel 038; `heroes mutate` scored it at 5 sites, 0 caught).
constant CURLOPT_URL: i32
constant CURLE_OK: i64
constant CURLE_UNSUPPORTED_PROTOCOL: i64
function curl_version() -> cstr
# The HANDLE, since 2026-09-13 (panel 145). `CURL` is `typedef void CURL;`
# on this Mac's SDK — a struct only under `CURL_STRICTER` — so there is no
# `struct CURL` to name, and this is exactly the case the completeness
# critic raised against the `struct <tag>` spelling every seat had proposed.
# The form writes the tag VERBATIM and starred, so `Curl` is `CURL *` and
# the binding needs nothing else.
record Curl tag CURL
function curl_easy_init() -> Curl acquires curl_easy_cleanup
function curl_easy_setopt(handle: Curl, option: u32, value: cstr) -> i64
function curl_easy_strerror(code: u32) -> cstr
function curl_easy_cleanup(handle: Curl consumes)
function main()
print("libcurl: ", validated(c: curl_version()).default("<unnamed>"))
handle = curl_easy_init()
# The variadic call. `CURLOPT_URL` takes a string, and that is a fact about
# this option rather than about the function — which is exactly what a
# variadic means and why the boundary cannot check it for you.
#
# `.to_u32()` is not noise: in C an enumeration CONSTANT has type `int`
# while the enumeration TYPE may be unsigned, so `CURLOPT_URL` is `i32`
# and the `CURLoption` parameter is `u32` — two different declarations of
# one enum, and both are what the header says. This line said `option:
# i32` and passed the constant straight through until the day when
# panel 092's repair to the probe made clang able to see it at last.
#
# And the string goes over as a LEASE rather than a lend, for the same
# reason: whether `curl_easy_setopt` keeps the pointer is a fact about the
# option, not the function. libcurl copies every string option but
# `CURLOPT_POSTFIELDS`, so no one word is true of `value` and the
# declaration carries none; an unmarked parameter is assumed to keep, so
# the lend is refused and this copy, released right after the call, is
# right under either option (spec § 13, panel 171).
url: cstr @= "https://example.invalid/".lease()
rc = curl_easy_setopt(handle, CURLOPT_URL.to_u32().must(), url)
end_lease(@url)
if rc == CURLE_OK
print("the url was accepted")
else
print("setopt refused it: ", validated(c: curl_easy_strerror(rc.to_u32().must())).default("<unnamed>"))
# A code the library knows and this program never provokes: the point is
# that the message comes from libcurl, not from a table written here.
print(
"code 1 means: ",
validated(c: curl_easy_strerror(CURLE_UNSUPPORTED_PROTOCOL.to_u32().must())).default("<unnamed>")
)
curl_easy_cleanup(handle)
The C side
/* The libcurl this program binds: `curl/curl.h`, with `curl_easy_setopt` the
* function `curl/easy.h` declares rather than the macro `curl.h` puts over it
* (defect 2229, 2026-10-26).
*
* Under a GNU C compiler, `curl.h` turns `curl_easy_setopt` into a macro that
* checks `value`'s type against `option` (`typecheck-gcc.h`). libcurl 8.18,
* the release Ubuntu 26.04 carries, wraps that check in
* `CURL_IGNORE_DEPRECATION`, whose `_Pragma("GCC diagnostic push")` changes how
* clang judges every line after the call, this program's binding checks among
* them, and the compiler refuses the binding (`ffi_macro_name`). The remedy is
* the one its note names: include the header, then take the macro off, so the
* name is the function again and clang holds this program's declaration to
* its prototype like any other. libcurl 8.7.1 on macOS defines the macro with
* no pragma, and the `#undef` takes it off there too. */
#include <curl/curl.h>
#undef curl_easy_setopt
fingerprint sha256 dbed2b31ebcd · 2 files · index.json
Next: raylib. All the examples. ← Previous: ledger
Run one yourself: the four commands. Learn the language, or read the full specification in one file.