Heroes / Esempi / curl

examples/curl/

Un programma Heroes che chiama libcurl, anche con un numero variabile di argomenti.

Il programma stampa la versione di libcurl installata sul computer. L’output dipende quindi dalla macchina: i test verificano che il programma funzioni, ma non lo confrontano con un testo fisso.

Eseguilo

$ heroes run examples/curl/main.hero

Per questo programma non è stato registrato un output di riferimento.

Il programma

## 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)
examples/curl/main.hero, 99 righe

Il lato C

/* 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
examples/curl/curl_bound.h, 16 righe

impronta sha256 dbed2b31ebcd · 2 file · index.json

Successivo: raylib. Tutti gli esempi. ← Precedente: ledger

Eseguine uno: i quattro comandi. Impara il linguaggio, oppure leggi la specifica completa in un solo file.