ReviewOS

also looking at this

zig-utils/zig-regex

Port to latest zig-master

#2
Closed armagidon-exception wants to merge main into main
53 files +1149 -1017
src/c_api.zigmodified+214-215
Changes to src/c_api.zig
@@ -1,215 +1,214 @@
1const std = ;
2const Regex = .Regex;
3const Match = .Match;
4
5/// C FFI for the Zig regex library
6///
7/// This module provides a C-compatible API for using the regex library
8/// from other languages (C, C++, Python via ctypes, etc.)
9///
10/// Example usage from C:
11/// ```c
12/// #include "zig_regex.h"
13///
14/// ZigRegex* regex = zig_regex_compile("\\d+", NULL);
15/// if (regex) {
16/// bool matches = zig_regex_is_match(regex, "test 123");
17/// printf("Matches: %d\n", matches);
18/// zig_regex_free(regex);
19/// }
20/// ```
21
22/// Opaque handle to a compiled regex
23pub const ZigRegex = opaque {};
24
25/// Opaque handle to a match result
26pub const ZigMatch = opaque {};
27
28/// Error codes
29pub const ZigRegexError = enum(c_int) {
30 ok = 0,
31 compile_error = -1,
32 invalid_pattern = -2,
33 out_of_memory = -3,
34 no_match = -4,
35 null_pointer = -5,
36};
37
38// Global allocator for C API (uses C allocator)
39var c_allocator = std.heap.c_allocator;
40
41/// Compile a regex pattern
42///
43/// Returns NULL on error. Call zig_regex_get_last_error() to get error details.
44/// The returned regex must be freed with zig_regex_free().
45export fn zig_regex_compile(pattern: [*:0]const u8) ?*ZigRegex {
46 const pattern_slice = std.mem.span(pattern);
47
48 const regex_ptr = c_allocator.create(Regex) catch return null;
49 regex_ptr.* = Regex.compile(c_allocator, pattern_slice) catch {
50 c_allocator.destroy(regex_ptr);
51 return null;
52 };
53
54 return @ptrCast(regex_ptr);
55}
56
57/// Free a compiled regex
58export fn zig_regex_free(regex: ?*ZigRegex) void {
59 if (regex) |r| {
60 const regex_ptr: *Regex = @ptrCast(@alignCast(r));
61 regex_ptr.deinit();
62 c_allocator.destroy(regex_ptr);
63 }
64}
65
66/// Check if a pattern matches a string
67///
68/// Returns 1 if matches, 0 if no match, -1 on error
69export fn zig_regex_is_match(regex: ?*ZigRegex, input: [*:0]const u8) c_int {
70 if (regex == null) return @intFromEnum(ZigRegexError.null_pointer);
71
72 const regex_ptr: *const Regex = @ptrCast(@alignCast(regex.?));
73 const input_slice = std.mem.span(input);
74
75 const result = regex_ptr.isMatch(input_slice) catch return -1;
76 return if (result) 1 else 0;
77}
78
79/// Find the first match in a string
80///
81/// Returns NULL if no match or on error.
82/// The returned match must be freed with zig_match_free().
83export fn zig_regex_find(regex: ?*ZigRegex, input: [*:0]const u8) ?*ZigMatch {
84 if (regex == null) return null;
85
86 const regex_ptr: *const Regex = @ptrCast(@alignCast(regex.?));
87 const input_slice = std.mem.span(input);
88
89 const maybe_match = regex_ptr.find(input_slice) catch return null;
90 if (maybe_match) |match| {
91 const match_ptr = c_allocator.create(Match) catch return null;
92 match_ptr.* = match;
93 return @ptrCast(match_ptr);
94 }
95
96 return null;
97}
98
99/// Get the matched substring
100///
101/// Returns NULL if match is NULL.
102/// The returned string is owned by the match and should not be freed separately.
103export fn zig_match_get_text(match: ?*ZigMatch) ?[*:0]const u8 {
104 if (match == null) return null;
105
106 const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
107 // Note: This assumes the slice is null-terminated, which may not always be true
108 // In production, you'd want to copy to a null-terminated buffer
109 return @ptrCast(match_ptr.slice.ptr);
110}
111
112/// Get the start position of a match
113export fn zig_match_get_start(match: ?*ZigMatch) c_int {
114 if (match == null) return -1;
115
116 const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
117 return @intCast(match_ptr.start);
118}
119
120/// Get the end position of a match
121export fn zig_match_get_end(match: ?*ZigMatch) c_int {
122 if (match == null) return -1;
123
124 const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
125 return @intCast(match_ptr.end);
126}
127
128/// Free a match result
129export fn zig_match_free(match: ?*ZigMatch) void {
130 if (match) |m| {
131 const match_ptr: *Match = @ptrCast(@alignCast(m));
132 var mut_match = match_ptr.*;
133 mut_match.deinit(c_allocator);
134 c_allocator.destroy(match_ptr);
135 }
136}
137
138/// Get version string
139export fn zig_regex_version() [*:0]const u8 {
140 return "0.1.0";
141}
142
143// Header file generator (for documentation)
144pub fn generateHeader(writer: anytype) !void {
145 try writer.writeAll(
146 \\#ifndef ZIG_REGEX_H
147 \\#define ZIG_REGEX_H
148 \\
149 \\#ifdef __cplusplus
150 \\extern "C" {
151 \\#endif
152 \\
153 \\#include <stddef.h>
154 \\#include <stdbool.h>
155 \\
156 \\/* Opaque types */
157 \\typedef struct ZigRegex ZigRegex;
158 \\typedef struct ZigMatch ZigMatch;
159 \\
160 \\/* Error codes */
161 \\typedef enum {
162 \\ ZIG_REGEX_OK = 0,
163 \\ ZIG_REGEX_COMPILE_ERROR = -1,
164 \\ ZIG_REGEX_INVALID_PATTERN = -2,
165 \\ ZIG_REGEX_OUT_OF_MEMORY = -3,
166 \\ ZIG_REGEX_NO_MATCH = -4,
167 \\ ZIG_REGEX_NULL_POINTER = -5,
168 \\} ZigRegexError;
169 \\
170 \\/* Compile a regex pattern */
171 \\ZigRegex* zig_regex_compile(const char* pattern);
172 \\
173 \\/* Free a compiled regex */
174 \\void zig_regex_free(ZigRegex* regex);
175 \\
176 \\/* Check if pattern matches string (returns 1=match, 0=no match, -1=error) */
177 \\int zig_regex_is_match(ZigRegex* regex, const char* input);
178 \\
179 \\/* Find first match in string (returns NULL if no match) */
180 \\ZigMatch* zig_regex_find(ZigRegex* regex, const char* input);
181 \\
182 \\/* Get matched text from match result */
183 \\const char* zig_match_get_text(ZigMatch* match);
184 \\
185 \\/* Get start position of match */
186 \\int zig_match_get_start(ZigMatch* match);
187 \\
188 \\/* Get end position of match */
189 \\int zig_match_get_end(ZigMatch* match);
190 \\
191 \\/* Free a match result */
192 \\void zig_match_free(ZigMatch* match);
193 \\
194 \\/* Get library version */
195 \\const char* zig_regex_version(void);
196 \\
197 \\#ifdef __cplusplus
198 \\}
199 \\#endif
200 \\
201 \\#endif /* ZIG_REGEX_H */
202 \\
203 );
204}
205
206test "C API header generation" {
207 var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);
208 defer aw.deinit();
209
210 try generateHeader(&aw.writer);
211 var result = aw.toArrayList();
212 defer result.deinit(std.testing.allocator);
213 try std.testing.expect(result.items.len > 0);
214 try std.testing.expect(std.mem.indexOf(u8, result.items, "ZIG_REGEX_H") != null);
215}
1//const std = ;
2//const Regex = .Regex;
3//const Match = .Match;
4//
5///// C FFI for the Zig regex library
6/////
7///// This module provides a C-compatible API for using the regex library
8///// from other languages (C, C++, Python via ctypes, etc.)
9/////
10///// Example usage from C:
11///// ```c
12///// #include "zig_regex.h"
13/////
14///// ZigRegex* regex = zig_regex_compile("\\d+", NULL);
15///// if (regex) {
16///// bool matches = zig_regex_is_match(regex, "test 123");
17///// printf("Matches: %d\n", matches);
18///// zig_regex_free(regex);
19///// }
20///// ```
21///// Opaque handle to a compiled regex
22//pub const ZigRegex = opaque {};
23//
24///// Opaque handle to a match result
25//pub const ZigMatch = opaque {};
26//
27///// Error codes
28//pub const ZigRegexError = enum(c_int) {
29// ok = 0,
30// compile_error = -1,
31// invalid_pattern = -2,
32// out_of_memory = -3,
33// no_match = -4,
34// null_pointer = -5,
35//};
36//
37//// Global allocator for C API (uses C allocator)
38//var c_allocator = std.heap.c_allocator;
39//
40///// Compile a regex pattern
41/////
42///// Returns NULL on error. Call zig_regex_get_last_error() to get error details.
43///// The returned regex must be freed with zig_regex_free().
44//export fn zig_regex_compile(pattern: [*:0]const u8) ?*ZigRegex {
45// const pattern_slice = std.mem.span(pattern);
46//
47// const regex_ptr = c_allocator.create(Regex) catch return null;
48// regex_ptr.* = Regex.compile(c_allocator, pattern_slice) catch {
49// c_allocator.destroy(regex_ptr);
50// return null;
51// };
52//
53// return @ptrCast(regex_ptr);
54//}
55//
56///// Free a compiled regex
57//export fn zig_regex_free(regex: ?*ZigRegex) void {
58// if (regex) |r| {
59// const regex_ptr: *Regex = @ptrCast(@alignCast(r));
60// regex_ptr.deinit();
61// c_allocator.destroy(regex_ptr);
62// }
63//}
64//
65///// Check if a pattern matches a string
66/////
67///// Returns 1 if matches, 0 if no match, -1 on error
68//export fn zig_regex_is_match(regex: ?*ZigRegex, input: [*:0]const u8) c_int {
69// if (regex == null) return @intFromEnum(ZigRegexError.null_pointer);
70//
71// const regex_ptr: *const Regex = @ptrCast(@alignCast(regex.?));
72// const input_slice = std.mem.span(input);
73//
74// const result = regex_ptr.isMatch(input_slice) catch return -1;
75// return if (result) 1 else 0;
76//}
77//
78///// Find the first match in a string
79/////
80///// Returns NULL if no match or on error.
81///// The returned match must be freed with zig_match_free().
82//export fn zig_regex_find(regex: ?*ZigRegex, input: [*:0]const u8) ?*ZigMatch {
83// if (regex == null) return null;
84//
85// const regex_ptr: *const Regex = @ptrCast(@alignCast(regex.?));
86// const input_slice = std.mem.span(input);
87//
88// const maybe_match = regex_ptr.find(input_slice) catch return null;
89// if (maybe_match) |match| {
90// const match_ptr = c_allocator.create(Match) catch return null;
91// match_ptr.* = match;
92// return @ptrCast(match_ptr);
93// }
94//
95// return null;
96//}
97//
98///// Get the matched substring
99/////
100///// Returns NULL if match is NULL.
101///// The returned string is owned by the match and should not be freed separately.
102//export fn zig_match_get_text(match: ?*ZigMatch) ?[*:0]const u8 {
103// if (match == null) return null;
104//
105// const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
106// // Note: This assumes the slice is null-terminated, which may not always be true
107// // In production, you'd want to copy to a null-terminated buffer
108// return @ptrCast(match_ptr.slice.ptr);
109//}
110//
111///// Get the start position of a match
112//export fn zig_match_get_start(match: ?*ZigMatch) c_int {
113// if (match == null) return -1;
114//
115// const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
116// return @intCast(match_ptr.start);
117//}
118//
119///// Get the end position of a match
120//export fn zig_match_get_end(match: ?*ZigMatch) c_int {
121// if (match == null) return -1;
122//
123// const match_ptr: *const Match = @ptrCast(@alignCast(match.?));
124// return @intCast(match_ptr.end);
125//}
126//
127///// Free a match result
128//export fn zig_match_free(match: ?*ZigMatch) void {
129// if (match) |m| {
130// const match_ptr: *Match = @ptrCast(@alignCast(m));
131// var mut_match = match_ptr.*;
132// mut_match.deinit(c_allocator);
133// c_allocator.destroy(match_ptr);
134// }
135//}
136//
137///// Get version string
138//export fn zig_regex_version() [*:0]const u8 {
139// return "0.1.0";
140//}
141//
142//// Header file generator (for documentation)
143//pub fn generateHeader(writer: anytype) !void {
144// try writer.writeAll(
145// \\#ifndef ZIG_REGEX_H
146// \\#define ZIG_REGEX_H
147// \\
148// \\#ifdef __cplusplus
149// \\extern "C" {
150// \\#endif
151// \\
152// \\#include <stddef.h>
153// \\#include <stdbool.h>
154// \\
155// \\/* Opaque types */
156// \\typedef struct ZigRegex ZigRegex;
157// \\typedef struct ZigMatch ZigMatch;
158// \\
159// \\/* Error codes */
160// \\typedef enum {
161// \\ ZIG_REGEX_OK = 0,
162// \\ ZIG_REGEX_COMPILE_ERROR = -1,
163// \\ ZIG_REGEX_INVALID_PATTERN = -2,
164// \\ ZIG_REGEX_OUT_OF_MEMORY = -3,
165// \\ ZIG_REGEX_NO_MATCH = -4,
166// \\ ZIG_REGEX_NULL_POINTER = -5,
167// \\} ZigRegexError;
168// \\
169// \\/* Compile a regex pattern */
170// \\ZigRegex* zig_regex_compile(const char* pattern);
171// \\
172// \\/* Free a compiled regex */
173// \\void zig_regex_free(ZigRegex* regex);
174// \\
175// \\/* Check if pattern matches string (returns 1=match, 0=no match, -1=error) */
176// \\int zig_regex_is_match(ZigRegex* regex, const char* input);
177// \\
178// \\/* Find first match in string (returns NULL if no match) */
179// \\ZigMatch* zig_regex_find(ZigRegex* regex, const char* input);
180// \\
181// \\/* Get matched text from match result */
182// \\const char* zig_match_get_text(ZigMatch* match);
183// \\
184// \\/* Get start position of match */
185// \\int zig_match_get_start(ZigMatch* match);
186// \\
187// \\/* Get end position of match */
188// \\int zig_match_get_end(ZigMatch* match);
189// \\
190// \\/* Free a match result */
191// \\void zig_match_free(ZigMatch* match);
192// \\
193// \\/* Get library version */
194// \\const char* zig_regex_version(void);
195// \\
196// \\#ifdef __cplusplus
197// \\}
198// \\#endif
199// \\
200// \\#endif /* ZIG_REGEX_H */
201// \\
202// );
203//}
204//
205//test "C API header generation" {
206// var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);
207// defer aw.deinit();
208//
209// try generateHeader(&aw.writer);
210// var result = aw.toArrayList();
211// defer result.deinit(std.testing.allocator);
212// try std.testing.expect(result.items.len > 0);
213// try std.testing.expect(std.mem.indexOf(u8, result.items, "ZIG_REGEX_H") != null);
214//}