zeekay a4debdba80 Read a .zap schema the way every other ZAP language reads it
C had no front end for the schema language at all. The compiler directory
holds a code generator plugin, which is handed a request by another tool
and never sees schema text, so a .zap file could not be read here in
either form -- indentation or braces.

zapgen reads it. Whitespace-significant source is rewritten into the brace
form BEFORE the parser, exactly as the Go reference does it: a near
identity that only adds the two tokens the brace grammar requires where
the indented form leaves them out. A file already in braces comes back
byte for byte, so one grammar reads both styles and neither is a dialect
of the other.

The identifier grammar is not restated. Its Unicode ranges are taken from
Go's own tables by gen/table, so a name this parser accepts is a name the
Go parser accepts, and a Go release that moves Unicode moves both.

The generated header gives each struct a view over the message bytes and
one reader per field at a fixed offset. Reading is in place and total: a
field past the end reads zero, a pointer into the head or out of the
message reads null. zap_view.h is the one place that says so.

Checked against the Go front end on every .zap in the estate plus 55
adversarial cases and 15000 random ones: the brace form each writes is
byte-identical, the layout each reads is field-for-field the same, and
they accept and refuse the same files for the same stated reason. A
message built by the Go runtime reads back through these bindings with
every field equal.
2026-09-15 11:32:12 -07:00
2016-02-28 13:55:23 +01:00
2016-03-19 00:39:29 +01:00
2016-02-28 13:55:23 +01:00
2016-02-28 18:38:41 +01:00
2016-02-28 13:55:23 +01:00
2023-04-23 17:10:53 +08:00

Docs: ZAP C SDK · part of the ZAP Protocol

zapc-c

This is the C language plugin (zapc-c) and runtime for ZAP, an efficient protocol for sharing data and capabilities.

Security warning!

The generated code assumes all input to be trusted. Do NOT use with untrusted input! There is currently no code in place to check if structures/pointers are within bounds.

This repository contains the code generator plugin together with the runtime library required to use it.

Building on Linux

git clone --recurse-submodules [email protected]:zap-proto/c.git zap-c
cd zap-c
autoreconf -f -i -s
./configure
make
make check

Building with Meson

git clone --recurse-submodules [email protected]:zap-proto/c.git zap-c
cd zap-c
meson setup build
meson compile -C build
build/zap-test

Usage

Reading a .zap schema: zapgen

zapgen reads a ZAP schema and writes the C it describes. Schemas are written whitespace-significant — indentation opens a block, and each field takes the next free byte after the one before it:

package echo

struct Ping
    Seq    u64
    Sender bytes_fixed[32]
    Note   text

interface Echo
    ping(req: Ping) returns (resp: Pong)
zapgen echo.zap          # writes echo.zap.h beside the input
zapgen -o gen echo.zap   # writes it into gen/
zapgen -c echo.zap       # reads the schema and says nothing if it holds
zapgen -d echo.zap       # writes the brace form of the schema to stdout

The brace form — struct S { A u8 @0 }, every field carrying its byte — is the same language said explicitly, and a file already written that way passes through zapgen -d byte for byte. The two styles may be mixed one declaration at a time.

The generated header gives each struct a view over the message bytes and one reader per field, each taking its value from a fixed offset. Reading is in place: nothing is copied, and no reader can step outside the message. Include <zap_view.h> — it comes with the library — and the header the schema produced.

This is the same schema language, read the same way, as ZAP for Go; the two front ends are checked against each other on every schema in the estate.

Generating C code from a Cap'n Proto schema

The compiler directory contains the C language plugin (zapc-c) for use with the zap tool.

zap will by default search $PATH for zapc-c — if it's on your PATH, you can generate code for your schema as follows:

zap compile -o c myschema.zap

Otherwise, you can specify the path to the c plugin:

zap compile -o ./zapc-c myschema.zap

zap generates a C struct that corresponds to each ZAP struct, along with read/write functions that convert to/from ZAP wire form.

If you want accessor functions for struct members, use attribute fieldgetset in your .zap file as follows:

using C = import "/c.zap";

$C.fieldgetset;

struct MyStruct {}

Example C code

See the unit tests in tests/example-test.cpp. The example schema file is tests/addressbook.zap. The tests are written in C++, but only use C features.

You need to compile these runtime library files and link them into your own project's binaries:

Your include path must contain the runtime library directory lib. Header file lib/zap_c.h contains the public interfaces of the library.

Using make-based builds, make may try to compile ${x}.zap from ${x}.zap.c using its built-in rule for compiling ${y} from ${y}.c. You can either disable make's built-in compile rules or just this specific case with the no-op rule: %.zap: ;.

For further reference, please see the other unit tests in tests, and header file lib/zap_c.h.

S
Description
ZAP for C — C ABI for FFI and embedding
Readme
2.3 MiB
Languages
C 82.8%
C++ 8.4%
ZAP 7.1%
Meson 0.5%
Go 0.5%
Other 0.7%