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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! C API for Matchy
//!
//! Provides stable C FFI bindings for building and querying databases from C/C++
//! and other languages. The API uses opaque handles and integer error codes for
//! maximum compatibility across language boundaries.
//!
//! # API Modules
//!
//! - [`matchy`] - Core database building and querying API
//! - [`maxminddb_compat`] - MaxMind DB compatibility layer (drop-in replacement for libmaxminddb)
//!
//! # Safety Guarantees
//!
//! All C functions follow these safety rules:
//! - Null pointer checks on all inputs
//! - Panic catching at FFI boundaries
//! - Opaque handles for resource management
//! - Integer error codes (no exceptions)
//! - Memory ownership clearly documented
//!
//! # Basic Usage Pattern
//!
//! **Note**: Databases are **immutable** once built. To update, rebuild entirely.
//!
//! ```c
//! #include <matchy/matchy.h>
//!
//! // ============ BUILD PHASE (create new database) ============
//!
//! // 1. Create a builder
//! matchy_builder_t *builder = matchy_builder_new();
//! if (builder == NULL) { /* handle error */ }
//!
//! // 2. Add entries with JSON data
//! matchy_builder_add(builder, "1.2.3.4",
//! "{\"threat_level\": \"high\", \"score\": 95}");
//! matchy_builder_add(builder, "10.0.0.0/8",
//! "{\"type\": \"internal\"}");
//! matchy_builder_add(builder, "*.evil.com",
//! "{\"category\": \"malware\"}");
//!
//! // 3. Set optional metadata
//! matchy_builder_set_description(builder, "Threat intelligence database");
//!
//! // 4. Save to file
//! int err = matchy_builder_save(builder, "threats.mxy");
//! if (err != MATCHY_SUCCESS) { /* handle error */ }
//!
//! // 5. Cleanup builder
//! matchy_builder_free(builder);
//!
//! // ============ QUERY PHASE (read-only access) ============
//!
//! // 6. Open database (memory-mapped for fast loading)
//! matchy_t *db = matchy_open("threats.mxy");
//! if (db == NULL) { /* handle error */ }
//!
//! // 7. Query database
//! // Option A: Return by value (standard C)
//! matchy_result_t result = matchy_query(db, "1.2.3.4");
//! // Option B: Write into pointer (FFI-friendly for Java JNA, etc.)
//! // matchy_result_t result;
//! // matchy_query_into(db, "1.2.3.4", &result);
//! if (result.found) {
//! // Option A: Get data as JSON string
//! char *json = matchy_result_to_json(&result);
//! printf("Found: %s\n", json);
//! matchy_free_string(json);
//!
//! // Option B: Access structured data (MMDB-compatible API)
//! matchy_entry_s entry;
//! matchy_result_get_entry(&result, &entry);
//!
//! matchy_entry_data_t data;
//! const char *path[] = {"threat_level", NULL};
//! if (matchy_aget_value(&entry, &data, path) == MATCHY_SUCCESS) {
//! if (data.type_ == MATCHY_DATA_TYPE_UTF8_STRING) {
//! printf("Threat level: %s\n", data.value.utf8_string);
//! }
//! }
//! }
//! matchy_free_result(&result);
//!
//! // 8. Close database
//! matchy_close(db);
//! ```
//!
//! # Extractor API
//!
//! High-performance pattern extraction from text:
//!
//! ```c
//! // Create extractor (bitmask of what to extract)
//! matchy_extractor_t *ext = matchy_extractor_create(
//! MATCHY_EXTRACT_DOMAINS | MATCHY_EXTRACT_IPV4
//! );
//!
//! // Extract from data
//! matchy_matches_t matches;
//! matchy_extractor_extract_chunk(ext, data, len, &matches);
//!
//! // Process results
//! for (size_t i = 0; i < matches.count; i++) {
//! printf("%s: %s\n",
//! matchy_item_type_name(matches.items[i].item_type),
//! matches.items[i].value);
//! }
//!
//! // Cleanup
//! matchy_matches_free(&matches);
//! matchy_extractor_free(ext);
//! ```
//!
//! # Memory Management
//!
//! - **Builder**: Call `matchy_builder_free()` when done building
//! - **Database**: Call `matchy_close()` to unmap file and release resources
//! - **Results**: Call `matchy_free_result()` after processing query results
//! - **Strings**: Call `matchy_free_string()` for strings returned by matchy functions
//! - **Data lists**: Call `matchy_free_entry_data_list()` for full data traversals
//! - **Extractor**: Call `matchy_extractor_free()` when done extracting
//! - **Matches**: Call `matchy_matches_free()` after processing extraction results
//!
//! # Thread Safety
//!
//! - **Database handles**: Safe for concurrent reads from multiple threads
//! - **Extractor handles**: Safe for concurrent extraction from multiple threads
//! - **Builders**: NOT thread-safe, use one builder per thread
//! - **Results/Matches**: Thread-local, don't share between threads
//!
//! # Database Update Strategy
//!
//! Databases are **immutable** once built. To update:
//!
//! 1. Create new builder
//! 2. Add all entries (old + new + modified)
//! 3. Build new database
//! 4. Atomically replace old file (e.g., rename)
//! 5. Reopen database handles
//!
//! This ensures readers always see consistent state.
//!
//! # Error Handling
//!
//! All functions return error codes. Common values:
//! - `MATCHY_SUCCESS` (0) - Success
//! - `MATCHY_ERROR_INVALID_PARAM` - Null pointer or invalid argument
//! - `MATCHY_ERROR_FILE_NOT_FOUND` - Database file doesn't exist
//! - `MATCHY_ERROR_INVALID_FORMAT` - Corrupted or invalid database
//! - `MATCHY_ERROR_IO` - File I/O error during save
//! - `MATCHY_ERROR_OUT_OF_MEMORY` - Memory allocation failed