Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Building Databases from C

The C builder API creates .mxy databases from IP addresses, CIDR ranges, literal strings, and glob patterns. Entry type detection is handled by matchy_builder_add().

Basic Flow

#include <matchy/matchy.h>

matchy_builder_t *builder = matchy_builder_new();

matchy_builder_add(builder, "192.0.2.1", "{\"category\":\"scanner\"}");
matchy_builder_add(builder, "*.evil.com", "{\"category\":\"phishing\"}");

int32_t err = matchy_builder_save(builder, "database.mxy");
matchy_builder_free(builder);

Use {} when an entry has no metadata. json_data must not be NULL.

Builder Functions

matchy_builder_new

matchy_builder_t *matchy_builder_new(void);

Creates a new builder. Free it with matchy_builder_free().

matchy_builder_set_case_insensitive

int32_t matchy_builder_set_case_insensitive(
    matchy_builder_t *builder,
    bool case_insensitive
);

When enabled, literal and glob string matching is case-insensitive. IP matching is unaffected.

matchy_builder_set_schema

int32_t matchy_builder_set_schema(
    matchy_builder_t *builder,
    const char *schema_name
);

Enables built-in schema validation. For example:

int32_t err = matchy_builder_set_schema(builder, "threatdb");

matchy_builder_add

int32_t matchy_builder_add(
    matchy_builder_t *builder,
    const char *key,
    const char *json_data
);

key may be:

  • IPv4 or IPv6 address: "192.0.2.1", "2001:db8::1"
  • CIDR range: "10.0.0.0/8", "2001:db8::/32"
  • Glob pattern: "*.evil.com", "test[123].example"
  • Literal string: "example.com"

Examples:

int32_t err;

err = matchy_builder_add(builder, "8.8.8.8", "{}");
err = matchy_builder_add(builder, "10.0.0.0/8", "{\"type\":\"private\"}");
err = matchy_builder_add(builder, "*.google.com", "{\"category\":\"search\"}");
err = matchy_builder_add(builder, "example.com", "{\"safe\":true}");

JSON values that are not objects are wrapped under the "value" key internally:

matchy_builder_add(builder, "score.example", "42");

matchy_builder_save

int32_t matchy_builder_save(
    matchy_builder_t *builder,
    const char *filename
);

Builds and writes a database file. This consumes the builder’s current internal state; create a new builder for another independent build.

matchy_builder_build

int32_t matchy_builder_build(
    matchy_builder_t *builder,
    uint8_t **buffer,
    uintptr_t *size
);

Builds into a C-allocated buffer. The caller must free the returned buffer with free().

uint8_t *buffer = NULL;
uintptr_t size = 0;

if (matchy_builder_build(builder, &buffer, &size) == MATCHY_SUCCESS) {
    /* use buffer */
    free(buffer);
}

matchy_builder_free

void matchy_builder_free(matchy_builder_t *builder);

Safe to call with NULL. After calling it, the handle must not be used.

Complete Example

#include <matchy/matchy.h>
#include <stdio.h>

int main(void) {
    int32_t err = MATCHY_SUCCESS;
    matchy_builder_t *builder = matchy_builder_new();
    if (builder == NULL) {
        return 1;
    }

    err = matchy_builder_set_case_insensitive(builder, true);
    if (err != MATCHY_SUCCESS) goto cleanup;

    err = matchy_builder_add(builder, "192.0.2.1",
        "{\"country\":\"US\",\"category\":\"scanner\"}");
    if (err != MATCHY_SUCCESS) goto cleanup;

    err = matchy_builder_add(builder, "10.0.0.0/8",
        "{\"type\":\"private\"}");
    if (err != MATCHY_SUCCESS) goto cleanup;

    err = matchy_builder_add(builder, "*.google.com",
        "{\"category\":\"search\"}");
    if (err != MATCHY_SUCCESS) goto cleanup;

    err = matchy_builder_add(builder, "example.com",
        "{\"safe\":true}");
    if (err != MATCHY_SUCCESS) goto cleanup;

    err = matchy_builder_save(builder, "my_database.mxy");
    if (err != MATCHY_SUCCESS) goto cleanup;

    printf("database written to my_database.mxy\n");

cleanup:
    matchy_builder_free(builder);
    return err == MATCHY_SUCCESS ? 0 : 1;
}

Compile with the generated include directory and built library:

gcc -o build_db build_db.c \
    -I./crates/matchy/include \
    -L./target/release \
    -lmatchy

Error Codes

CodeConstantMeaning
0MATCHY_SUCCESSOperation succeeded
-2MATCHY_ERROR_INVALID_FORMATInvalid JSON, key, or build format
-4MATCHY_ERROR_OUT_OF_MEMORYAllocation failed
-5MATCHY_ERROR_INVALID_PARAMNULL pointer or invalid UTF-8
-6MATCHY_ERROR_IOWrite failed
-7MATCHY_ERROR_SCHEMA_VALIDATIONEntry failed configured schema
-8MATCHY_ERROR_UNKNOWN_SCHEMAUnknown schema name
-12MATCHY_ERROR_INTERNALPanic caught at FFI boundary

Thread Safety

Builders are not thread-safe. Add entries and build from a single thread.

for (size_t i = 0; ips[i] != NULL; i++) {
    int32_t err = matchy_builder_add(builder, ips[i], "{}");
    if (err != MATCHY_SUCCESS) {
        fprintf(stderr, "failed to add %s: %d\n", ips[i], err);
    }
}

See Also