1#![allow(non_upper_case_globals)]
5#![allow(non_camel_case_types)]
6#![allow(non_snake_case)]
7#![deny(unsafe_op_in_unsafe_fn)]
8
9include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
10
11#[cfg(test)]
12mod tests {
13 use super::*;
14 use std::ffi::c_int;
15 use std::mem;
16
17 #[cfg(feature = "approx")]
18 #[test]
19 fn reganexec() {
20 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
21 if unsafe {
22 tre_regcomp(
23 preg.as_mut_ptr(),
24 b"Hello!\0".as_ptr() as *const _,
25 REG_ICASE as c_int,
26 )
27 } != 0
28 {
29 panic!("tre_regcomp");
30 }
31 let preg = unsafe { preg.assume_init() };
32
33 let params = regaparams_t {
34 cost_ins: 1,
35 cost_del: 1,
36 cost_subst: 1,
37 max_cost: 2,
38 max_del: 2,
39 max_ins: 2,
40 max_subst: 2,
41 max_err: 2,
42 };
43
44 let mut pmatch: Vec<regmatch_t> = vec![Default::default(); 1];
45 let mut amatch = regamatch_t {
46 nmatch: 1,
47 pmatch: pmatch.as_mut_ptr(),
48 ..Default::default()
49 };
50
51 if unsafe {
52 tre_reganexec(
53 &preg,
54 b"Hullo!".as_ptr() as *const _,
55 6,
56 &mut amatch,
57 params,
58 0,
59 )
60 } != 0
61 {
62 panic!("tre_regaexec");
63 }
64
65 assert_eq!(amatch.cost, 1);
66 assert_eq!(pmatch[0].rm_so, 0);
67 assert_eq!(pmatch[0].rm_eo, 6);
68 }
69
70 #[test]
71 fn regexec() {
72 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
73 if unsafe {
74 tre_regcomp(
75 preg.as_mut_ptr(),
76 b"Hello(, [[:alpha:]]+)?!\0".as_ptr() as *const _,
77 (REG_EXTENDED | REG_ICASE) as c_int,
78 )
79 } != 0
80 {
81 panic!("tre_regcomp");
82 }
83
84 let preg = unsafe { preg.assume_init() };
85
86 let nmatch = 1;
87 let mut pmatch: Vec<regmatch_t> = vec![regmatch_t { rm_so: 0, rm_eo: 0 }; 1];
88 if unsafe {
89 tre_regexec(
90 &preg,
91 b"Hello!".as_ptr() as *const _,
92 nmatch,
93 pmatch.as_mut_ptr(),
94 0,
95 )
96 } != 0
97 {
98 panic!("tre_regexec");
99 }
100
101 assert!(pmatch[0].rm_so == 0, "Bad starting offset");
102 assert!(pmatch[0].rm_eo == 6, "Bad ending offset");
103
104 pmatch[0].rm_eo = 0;
105
106 let nmatch = 2;
107 pmatch.push(regmatch_t { rm_so: 0, rm_eo: 0 });
108 if unsafe {
109 tre_regexec(
110 &preg,
111 b"Hello, world!\0".as_ptr() as *const _,
112 nmatch,
113 pmatch.as_mut_ptr(),
114 0,
115 )
116 } != 0
117 {
118 panic!("tre_regexec");
119 }
120
121 assert!(pmatch[0].rm_so == 0, "Bad starting offset");
122 assert!(pmatch[0].rm_eo == 13, "Bad ending offset");
123 assert!(pmatch[1].rm_so == 5, "Bad starting offset for match group");
124 assert!(pmatch[1].rm_eo == 12, "Bad ending offset for match group");
125 }
126
127 #[cfg(feature = "vendored")]
128 #[test]
129 fn regnexecb_with_embedded_nul() {
130 let pattern = b"a\0b";
131 let string = b"xxa\0byy";
132 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
133
134 assert_eq!(
135 unsafe {
136 tre_regncompb(
137 preg.as_mut_ptr(),
138 pattern.as_ptr().cast(),
139 pattern.len(),
140 REG_EXTENDED as c_int,
141 )
142 },
143 0
144 );
145 let mut preg = unsafe { preg.assume_init() };
146 let mut pmatch = regmatch_t::default();
147
148 assert_eq!(
149 unsafe {
150 tre_regnexecb(
151 &preg,
152 string.as_ptr().cast(),
153 string.len(),
154 1,
155 &mut pmatch,
156 0,
157 )
158 },
159 0
160 );
161 assert_eq!(pmatch.rm_so, 2);
162 assert_eq!(pmatch.rm_eo, 5);
163
164 unsafe { tre_regfree(&mut preg) };
165 }
166
167 #[cfg(feature = "vendored")]
168 #[test]
169 fn regexecb_with_non_utf8_bytes() {
170 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
171 assert_eq!(
172 unsafe {
173 tre_regcompb(
174 preg.as_mut_ptr(),
175 b"\xff\0".as_ptr().cast(),
176 REG_EXTENDED as c_int,
177 )
178 },
179 0
180 );
181 let mut preg = unsafe { preg.assume_init() };
182 let mut pmatch = regmatch_t::default();
183
184 assert_eq!(
185 unsafe { tre_regexecb(&preg, b"x\xff\0".as_ptr().cast(), 1, &mut pmatch, 0,) },
186 0
187 );
188 assert_eq!(pmatch.rm_so, 1);
189 assert_eq!(pmatch.rm_eo, 2);
190
191 unsafe { tre_regfree(&mut preg) };
192 }
193
194 #[cfg(all(feature = "vendored", feature = "approx"))]
195 #[test]
196 fn regaexecb_with_non_utf8_bytes() {
197 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
198 assert_eq!(
199 unsafe {
200 tre_regcompb(
201 preg.as_mut_ptr(),
202 b"\xff\0".as_ptr().cast(),
203 REG_EXTENDED as c_int,
204 )
205 },
206 0
207 );
208 let mut preg = unsafe { preg.assume_init() };
209 let params = regaparams_t {
210 cost_ins: 1,
211 cost_del: 1,
212 cost_subst: 1,
213 max_cost: 1,
214 max_del: 1,
215 max_ins: 1,
216 max_subst: 1,
217 max_err: 1,
218 };
219 let mut pmatch = regmatch_t::default();
220 let mut amatch = regamatch_t {
221 nmatch: 1,
222 pmatch: &mut pmatch,
223 ..Default::default()
224 };
225
226 assert_eq!(
227 unsafe { tre_regaexecb(&preg, b"\xfe\0".as_ptr().cast(), &mut amatch, params, 0,) },
228 0
229 );
230 assert_eq!(amatch.cost, 1);
231 assert_eq!(pmatch.rm_so, 0);
232 assert_eq!(pmatch.rm_eo, 1);
233
234 unsafe { tre_regfree(&mut preg) };
235 }
236
237 #[test]
238 fn reguexec() {
239 use std::ffi::{c_int, c_uint, c_void};
240 #[repr(C)]
241 struct Data<'a>(pub &'a [u8], pub usize);
242
243 #[inline(never)]
244 #[unsafe(no_mangle)]
245 unsafe extern "C" fn get_next_char(
246 c: *mut tre_char_t,
247 pos_add: *mut c_uint,
248 context: *mut c_void,
249 ) -> c_int {
250 let data = context as *mut Data;
251 let (string, i) = unsafe { ((*data).0, (*data).1) };
252
253 if i >= string.len() {
254 unsafe { *c = b'\0' as tre_char_t };
255 return -1;
256 }
257
258 unsafe {
259 *c = string[i] as tre_char_t;
260 *pos_add = 1;
261 (*data).1 += 1;
262 }
263 0
264 }
265
266 #[inline(never)]
267 #[unsafe(no_mangle)]
268 unsafe extern "C" fn rewind(pos: usize, context: *mut c_void) {
269 let data = context as *mut Data;
270 unsafe { (*data).1 = pos };
271 }
272
273 #[inline(never)]
274 #[unsafe(no_mangle)]
275 unsafe extern "C" fn compare(
276 pos1: usize,
277 pos2: usize,
278 len: usize,
279 context: *mut c_void,
280 ) -> c_int {
281 let data = context as *mut Data;
282 let string = unsafe { (*data).0 };
283 let slen = string.len();
284
285 if pos1 > slen || pos2 > slen {
286 return -1;
287 }
288
289 let mut i1_s = pos1;
290 let mut i1_e = if i1_s + len > string.len() {
291 slen - 1
292 } else {
293 i1_s + len
294 };
295
296 let mut i2_s = pos2;
297 let mut i2_e = if i2_s + len > string.len() {
298 slen - 1
299 } else {
300 i2_s + len
301 };
302
303 if (i1_s > i1_e || i2_s > i2_e) || ((i1_e - i1_s) != (i2_e - i2_s)) {
304 return -1;
306 }
307
308 if i1_s > i2_s {
309 std::mem::swap(&mut i1_s, &mut i2_s);
311 std::mem::swap(&mut i1_e, &mut i2_e);
312 }
313
314 if string[i1_s..i1_e] == string[i2_s..i2_e] {
315 return 0;
316 }
317
318 -1
319 }
320
321 let mut preg = mem::MaybeUninit::<regex_t>::uninit();
322 if unsafe {
323 tre_regcomp(
324 preg.as_mut_ptr(),
325 b"(abracadabra)(\\1)*\0".as_ptr() as *const _,
326 (REG_ICASE | REG_EXTENDED) as c_int,
327 )
328 } != 0
329 {
330 panic!("tre_regcomp");
331 }
332 let preg = unsafe { preg.assume_init() };
333
334 let string = b"abracadabraabracadabra";
335 let mut data = Data(string, 0);
336 let source = tre_str_source {
337 get_next_char: Some(get_next_char),
338 rewind: Some(rewind),
339 compare: Some(compare),
340 context: &mut data as *mut _ as *mut c_void,
341 };
342
343 let mut matches = vec![regmatch_t::default(); 1];
344 if unsafe { tre_reguexec(&preg, &source, 1, matches.as_mut_ptr(), 0) } != 0 {
345 panic!("tre_reguexec");
346 }
347
348 assert_eq!(matches[0].rm_so, 0);
349 assert_eq!(matches[0].rm_eo, 22);
350 }
351}