tre_regex_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7#[cfg(test)]
8mod tests {
9    use super::*;
10    use std::ffi::c_int;
11    use std::mem;
12
13    #[cfg(feature = "approx")]
14    #[test]
15    fn reganexec() {
16        let mut preg = mem::MaybeUninit::<regex_t>::uninit();
17        if unsafe {
18            tre_regcomp(
19                preg.as_mut_ptr(),
20                b"Hello!\0".as_ptr() as *const _,
21                REG_ICASE as c_int,
22            )
23        } != 0
24        {
25            panic!("tre_regcomp");
26        }
27        let preg = unsafe { preg.assume_init() };
28
29        let params = regaparams_t {
30            cost_ins: 1,
31            cost_del: 1,
32            cost_subst: 1,
33            max_cost: 2,
34            max_del: 2,
35            max_ins: 2,
36            max_subst: 2,
37            max_err: 2,
38        };
39
40        let mut pmatch: Vec<regmatch_t> = vec![Default::default(); 1];
41        let mut amatch = regamatch_t {
42            nmatch: 1,
43            pmatch: pmatch.as_mut_ptr(),
44            ..Default::default()
45        };
46
47        if unsafe {
48            tre_reganexec(
49                &preg,
50                b"Hullo!".as_ptr() as *const _,
51                6,
52                &mut amatch,
53                params,
54                0,
55            )
56        } != 0
57        {
58            panic!("tre_regaexec");
59        }
60
61        assert_eq!(amatch.cost, 1);
62        assert_eq!(pmatch[0].rm_so, 0);
63        assert_eq!(pmatch[0].rm_eo, 6);
64    }
65
66    #[test]
67    fn regexec() {
68        let mut preg = mem::MaybeUninit::<regex_t>::uninit();
69        if unsafe {
70            tre_regcomp(
71                preg.as_mut_ptr(),
72                b"Hello(, [[:alpha:]]+)?!\0".as_ptr() as *const _,
73                (REG_EXTENDED | REG_ICASE) as c_int,
74            )
75        } != 0
76        {
77            panic!("tre_regcomp");
78        }
79
80        let preg = unsafe { preg.assume_init() };
81
82        let nmatch = 1;
83        let mut pmatch: Vec<regmatch_t> = vec![regmatch_t { rm_so: 0, rm_eo: 0 }; 1];
84        if unsafe {
85            tre_regexec(
86                &preg,
87                b"Hello!".as_ptr() as *const _,
88                nmatch,
89                pmatch.as_mut_ptr(),
90                0,
91            )
92        } != 0
93        {
94            panic!("tre_regexec");
95        }
96
97        assert!(pmatch[0].rm_so == 0, "Bad starting offset");
98        assert!(pmatch[0].rm_eo == 6, "Bad ending offset");
99
100        pmatch[0].rm_eo = 0;
101
102        let nmatch = 2;
103        pmatch.push(regmatch_t { rm_so: 0, rm_eo: 0 });
104        if unsafe {
105            tre_regexec(
106                &preg,
107                b"Hello, world!\0".as_ptr() as *const _,
108                nmatch,
109                pmatch.as_mut_ptr(),
110                0,
111            )
112        } != 0
113        {
114            panic!("tre_regexec");
115        }
116
117        assert!(pmatch[0].rm_so == 0, "Bad starting offset");
118        assert!(pmatch[0].rm_eo == 13, "Bad ending offset");
119        assert!(pmatch[1].rm_so == 5, "Bad starting offset for match group");
120        assert!(pmatch[1].rm_eo == 12, "Bad ending offset for match group");
121    }
122
123    #[test]
124    fn reguexec() {
125        use std::ffi::{c_int, c_uint, c_void};
126        #[repr(C)]
127        struct Data<'a>(pub &'a [u8], pub usize);
128
129        #[inline(never)]
130        #[no_mangle]
131        unsafe extern "C" fn get_next_char(
132            c: *mut tre_char_t,
133            pos_add: *mut c_uint,
134            context: *mut c_void,
135        ) -> c_int {
136            let data = context as *mut Data;
137            let string = (*data).0;
138            let i = (*data).1;
139
140            if i >= string.len() {
141                *c = b'\0';
142                return -1;
143            }
144
145            *c = string[i];
146            *pos_add = 1;
147            (*data).1 += 1;
148            0
149        }
150
151        #[inline(never)]
152        #[no_mangle]
153        unsafe extern "C" fn rewind(pos: usize, context: *mut c_void) {
154            let data = context as *mut Data;
155            (*data).1 = pos;
156        }
157
158        #[inline(never)]
159        #[no_mangle]
160        unsafe extern "C" fn compare(
161            pos1: usize,
162            pos2: usize,
163            len: usize,
164            context: *mut c_void,
165        ) -> c_int {
166            let data = context as *mut Data;
167            let string = (*data).0;
168            let slen = string.len();
169
170            if pos1 > slen || pos2 > slen {
171                return -1;
172            }
173
174            let mut i1_s = pos1;
175            let mut i1_e = if i1_s + len > string.len() {
176                slen - 1
177            } else {
178                i1_s + len
179            };
180
181            let mut i2_s = pos2;
182            let mut i2_e = if i2_s + len > string.len() {
183                slen - 1
184            } else {
185                i2_s + len
186            };
187
188            if (i1_s > i1_e || i2_s > i2_e) || ((i1_e - i1_s) != (i2_e - i2_s)) {
189                // Different lengths, therefore unequal
190                return -1;
191            }
192
193            if i1_s > i2_s {
194                // Swap
195                std::mem::swap(&mut i1_s, &mut i2_s);
196                std::mem::swap(&mut i1_e, &mut i2_e);
197            }
198
199            if string[i1_s..i1_e] == string[i2_s..i2_e] {
200                return 0;
201            }
202
203            -1
204        }
205
206        let mut preg = mem::MaybeUninit::<regex_t>::uninit();
207        if unsafe {
208            tre_regcomp(
209                preg.as_mut_ptr(),
210                b"(abracadabra)(\\1)*\0".as_ptr() as *const _,
211                (REG_ICASE | REG_EXTENDED) as c_int,
212            )
213        } != 0
214        {
215            panic!("tre_regcomp");
216        }
217        let preg = unsafe { preg.assume_init() };
218
219        let string = b"abracadabraabracadabra";
220        let mut data = Data(string, 0);
221        let source = tre_str_source {
222            get_next_char: Some(get_next_char),
223            rewind: Some(rewind),
224            compare: Some(compare),
225            context: &mut data as *mut _ as *mut c_void,
226        };
227
228        let mut matches = vec![regmatch_t::default(); 1];
229        if unsafe { tre_reguexec(&preg, &source, 1, matches.as_mut_ptr(), 0) } != 0 {
230            panic!("tre_reguexec");
231        }
232
233        assert_eq!(matches[0].rm_so, 0);
234        assert_eq!(matches[0].rm_eo, 22);
235    }
236}