relibc/header/regex/
mod.rs1use crate::{
6 header::string::strlen,
7 platform::types::{c_char, c_int, c_void, size_t},
8};
9use alloc::{borrow::Cow, boxed::Box};
10use core::{ptr, slice};
11use posix_regex::{PosixRegex, PosixRegexBuilder, compile::Error as CompileError, tree::Tree};
12
13pub type regoff_t = size_t;
15
16#[repr(C)]
18pub struct regex_t {
19 ptr: *mut c_void,
21 cflags: c_int,
22 re_nsub: size_t,
23}
24
25#[repr(C)]
27pub struct regmatch_t {
28 rm_so: regoff_t,
29 rm_eo: regoff_t,
30}
31
32pub const REG_EXTENDED: c_int = 1;
33pub const REG_ICASE: c_int = 2;
34pub const REG_NOSUB: c_int = 4;
35pub const REG_NEWLINE: c_int = 8;
36pub const REG_NOTBOL: c_int = 16;
37pub const REG_NOTEOL: c_int = 32;
38pub const REG_MINIMAL: c_int = 64;
39
40pub const REG_NOMATCH: c_int = 1;
41pub const REG_BADPAT: c_int = 2;
42pub const REG_ECOLLATE: c_int = 3;
43pub const REG_ECTYPE: c_int = 4;
44pub const REG_EESCAPE: c_int = 5;
45pub const REG_ESUBREG: c_int = 6;
46pub const REG_EBRACK: c_int = 7;
47pub const REG_ENOSYS: c_int = 8;
48pub const REG_EPAREN: c_int = 9;
49pub const REG_EBRACE: c_int = 10;
50pub const REG_BADBR: c_int = 11;
51pub const REG_ERANGE: c_int = 12;
52pub const REG_ESPACE: c_int = 13;
53pub const REG_BADRPT: c_int = 14;
54
55#[unsafe(no_mangle)]
57#[linkage = "weak"] pub unsafe extern "C" fn regcomp(out: *mut regex_t, pat: *const c_char, cflags: c_int) -> c_int {
59 let pat = unsafe { slice::from_raw_parts(pat.cast::<u8>(), strlen(pat)) };
60 let res = PosixRegexBuilder::new(pat)
61 .with_default_classes()
62 .extended(cflags & REG_EXTENDED == REG_EXTENDED)
63 .compile_tokens();
64
65 match res {
66 Ok(branches) => {
67 let re_nsub = PosixRegex::new(Cow::Borrowed(&branches)).count_groups();
68 unsafe {
69 *out = regex_t {
70 ptr: Box::into_raw(Box::new(branches)).cast::<c_void>(),
71
72 cflags,
73 re_nsub,
74 }
75 };
76 0
77 }
78 Err(CompileError::EmptyRepetition)
79 | Err(CompileError::IntegerOverflow)
80 | Err(CompileError::IllegalRange) => REG_BADBR,
81 Err(CompileError::UnclosedRepetition) => REG_EBRACE,
82 Err(CompileError::LeadingRepetition) => REG_BADRPT,
83 Err(CompileError::UnknownCollation) => REG_ECOLLATE,
84 Err(CompileError::UnknownClass(_)) => REG_ECTYPE,
85 Err(_) => REG_BADPAT,
86 }
87}
88
89#[unsafe(no_mangle)]
91#[linkage = "weak"] pub unsafe extern "C" fn regfree(regex: *mut regex_t) {
93 unsafe { drop(Box::from_raw((*regex).ptr)) };
94}
95
96#[unsafe(no_mangle)]
98#[linkage = "weak"] pub unsafe extern "C" fn regexec(
100 regex: *const regex_t,
101 input: *const c_char,
102 nmatch: size_t,
103 pmatch: *mut regmatch_t,
104 eflags: c_int,
105) -> c_int {
106 let regex = unsafe { &*regex };
107
108 let flags = regex.cflags | eflags;
111
112 let input = unsafe { slice::from_raw_parts(input.cast::<u8>(), strlen(input)) };
113 let branches = unsafe { &*(regex.ptr.cast::<Tree>()) };
114
115 let matches = PosixRegex::new(Cow::Borrowed(branches))
116 .case_insensitive(flags & REG_ICASE == REG_ICASE)
117 .newline(flags & REG_NEWLINE == REG_NEWLINE)
118 .no_start(flags & REG_NOTBOL == REG_NOTBOL)
119 .no_end(flags & REG_NOTEOL == REG_NOTEOL)
120 .matches(input, Some(1));
121
122 if !matches.is_empty() && eflags & REG_NOSUB != REG_NOSUB && !pmatch.is_null() && nmatch > 0 {
123 let first = &matches[0];
124
125 for i in 0..nmatch {
126 let (start, end) = first.get(i).and_then(|&range| range).unwrap_or((!0, !0));
127 unsafe {
128 *pmatch.add(i) = regmatch_t {
129 rm_so: start,
130 rm_eo: end,
131 }
132 };
133 }
134 }
135
136 if matches.is_empty() { REG_NOMATCH } else { 0 }
137}
138
139#[unsafe(no_mangle)]
141#[linkage = "weak"] pub extern "C" fn regerror(
143 code: c_int,
144 _regex: *const regex_t,
145 out: *mut c_char,
146 max: size_t,
147) -> size_t {
148 let string = match code {
149 0 => "No error\0",
150 REG_NOMATCH => "No match\0",
151 REG_BADPAT => "Invalid regexp\0",
152 REG_ECOLLATE => "Unknown collating element\0",
153 REG_ECTYPE => "Unknown character class name\0",
154 REG_EESCAPE => "Trailing backslash\0",
155 REG_ESUBREG => "Invalid back reference\0",
156 REG_EBRACK => "Missing ']'\0",
157 REG_ENOSYS => "Unsupported operation\0",
158 REG_EPAREN => "Missing ')'\0",
159 REG_EBRACE => "Missing '}'\0",
160 REG_BADBR => "Invalid contents of {}\0",
161 REG_ERANGE => "Invalid character range\0",
162 REG_ESPACE => "Out of memory\0",
163 REG_BADRPT => "Repetition not preceded by valid expression\0",
164 _ => "Unknown error\0",
165 };
166
167 unsafe {
168 ptr::copy_nonoverlapping(string.as_ptr(), out.cast::<u8>(), string.len().min(max));
169 }
170
171 string.len()
172}