syntastica_parsers_git/
lib.rs1#![doc = include_str!("../README.md")]
2#![cfg_attr(
4 feature = "docs",
5 cfg_attr(doc, doc = ::document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#))
6)]
7#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
8#![warn(rust_2018_idioms)]
9#![deny(missing_docs)]
10
11syntastica_macros::parsers_ffi!();
12
13#[cfg(all(
15 feature = "runtime-c2rust",
16 target_arch = "wasm32",
17 target_vendor = "unknown",
18 target_os = "unknown",
19 target_env = ""
20))]
21#[allow(non_camel_case_types)]
22mod wasm_c_bridge {
23 use std::{
24 alloc::{GlobalAlloc, Layout, System},
25 collections::HashMap,
26 ffi::{c_void, CStr},
27 sync::{LazyLock, Mutex},
28 };
29
30 type wint_t = u32;
31 type size_t = usize;
32 type c_char = i8;
33 type int = i32;
34
35 #[no_mangle]
37 extern "C" fn abort() {
38 panic!("program aborted");
39 }
40
41 #[no_mangle]
43 extern "C" fn towupper(wc: wint_t) -> wint_t {
44 let Some(char) = char::from_u32(wc) else {
45 return wc;
46 };
47 let mut uppercase = char.to_uppercase();
48 if uppercase.len() == 1 {
49 uppercase.next().unwrap() as wint_t
50 } else {
51 wc
52 }
53 }
54
55 #[no_mangle]
57 extern "C" fn towlower(wc: wint_t) -> wint_t {
58 let Some(char) = char::from_u32(wc) else {
59 return wc;
60 };
61 let mut uppercase = char.to_lowercase();
62 if uppercase.len() == 1 {
63 uppercase.next().unwrap() as wint_t
64 } else {
65 wc
66 }
67 }
68
69 #[no_mangle]
71 extern "C" fn iswalnum(ch: wint_t) -> int {
72 char::from_u32(ch).is_some_and(|ch| ch.is_alphanumeric()) as int
73 }
74
75 #[no_mangle]
77 extern "C" fn iswalpha(ch: wint_t) -> int {
78 char::from_u32(ch).is_some_and(|ch| ch.is_alphabetic()) as int
79 }
80
81 #[no_mangle]
83 extern "C" fn iswblank(ch: wint_t) -> int {
84 (ch == b' ' as wint_t || ch == b'\t' as wint_t) as int
85 }
86
87 #[no_mangle]
89 extern "C" fn iswcntrl(ch: wint_t) -> int {
90 char::from_u32(ch).is_some_and(|ch| ch.is_control()) as int
91 }
92
93 #[no_mangle]
95 extern "C" fn iswdigit(ch: wint_t) -> int {
96 char::from_u32(ch).is_some_and(|ch| ch.is_numeric()) as int
97 }
98
99 #[no_mangle]
101 extern "C" fn iswgraph(ch: wint_t) -> int {
102 char::from_u32(ch).is_some_and(|ch| ch.is_ascii_graphic()) as int
103 }
104
105 #[no_mangle]
107 extern "C" fn iswlower(ch: wint_t) -> int {
108 char::from_u32(ch).is_some_and(|ch| ch.is_lowercase()) as int
109 }
110
111 #[no_mangle]
113 extern "C" fn iswprint(ch: wint_t) -> int {
114 char::from_u32(ch).is_some_and(|ch| ch.is_ascii_graphic() || ch == ' ') as int
115 }
116
117 #[no_mangle]
119 extern "C" fn iswpunct(ch: wint_t) -> int {
120 char::from_u32(ch).is_some_and(|ch| ch.is_ascii_punctuation()) as int
121 }
122
123 #[no_mangle]
125 extern "C" fn iswspace(ch: wint_t) -> int {
126 char::from_u32(ch).is_some_and(|ch| ch.is_whitespace()) as int
127 }
128
129 #[no_mangle]
131 extern "C" fn iswupper(ch: wint_t) -> int {
132 char::from_u32(ch).is_some_and(|ch| ch.is_uppercase()) as int
133 }
134
135 #[no_mangle]
137 extern "C" fn iswxdigit(ch: wint_t) -> int {
138 char::from_u32(ch).is_some_and(|ch| ch.is_ascii_hexdigit()) as int
139 }
140
141 #[no_mangle]
142 unsafe extern "C" fn __assert2(
143 file: *const c_char,
144 line: int,
145 func: *const c_char,
146 error: *const c_char,
147 ) {
148 let file = CStr::from_ptr(file).to_string_lossy();
149 let func = CStr::from_ptr(func).to_string_lossy();
150 let error = CStr::from_ptr(error).to_string_lossy();
151 panic!("assertion failed in {file} on line {line} in {func}: {error}");
152 }
153
154 #[no_mangle]
156 unsafe extern "C" fn strcmp(lhs: *const c_char, rhs: *const c_char) -> int {
157 let lhs = CStr::from_ptr(lhs);
158 let rhs = CStr::from_ptr(rhs);
159 lhs.cmp(rhs) as int
160 }
161
162 #[no_mangle]
164 unsafe extern "C" fn strncpy(
165 dest: *mut c_char,
166 src: *const c_char,
167 count: size_t,
168 ) -> *mut c_char {
169 for i in 0..count {
170 let cp = src.add(i).read();
171 dest.add(i).write(cp)
172 }
173 dest
174 }
175
176 #[no_mangle]
178 unsafe extern "C" fn memchr(ptr: *const c_void, ch: int, count: size_t) -> *mut c_void {
179 let ptr = ptr as *const u8;
180 let ch = ch as u8;
181 for i in 0..count {
182 if ptr.add(i).read() == ch {
183 return ptr.add(i) as *mut _;
184 }
185 }
186 std::ptr::null_mut()
187 }
188
189 static LAYOUTS: LazyLock<Mutex<HashMap<usize, Layout>>> = LazyLock::new(Default::default);
190 const MIN_ALIGN: usize = 8;
191
192 #[no_mangle]
194 unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
195 let layout = Layout::from_size_align_unchecked(size, MIN_ALIGN);
196 let ptr = System.alloc(layout);
197 if !ptr.is_null() {
198 LAYOUTS.lock().unwrap().insert(ptr as usize, layout);
199 }
200 ptr as *mut _
201 }
202
203 #[no_mangle]
205 unsafe extern "C" fn calloc(num: size_t, size: size_t) -> *mut c_void {
206 let layout = Layout::from_size_align_unchecked(num * size, MIN_ALIGN);
207 let ptr = System.alloc_zeroed(layout);
208 if !ptr.is_null() {
209 LAYOUTS.lock().unwrap().insert(ptr as usize, layout);
210 }
211 ptr as *mut _
212 }
213
214 #[no_mangle]
216 unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: size_t) -> *mut c_void {
217 if ptr.is_null() {
218 return malloc(new_size);
219 }
220 let layout = *LAYOUTS
221 .lock()
222 .unwrap()
223 .get(&(ptr as usize))
224 .unwrap_unchecked();
225 let ptr = System.realloc(ptr as *mut _, layout, new_size);
226 if !ptr.is_null() {
227 LAYOUTS.lock().unwrap().insert(
228 ptr as usize,
229 Layout::from_size_align_unchecked(new_size, layout.align()),
230 );
231 }
232 ptr as *mut _
233 }
234
235 #[no_mangle]
237 unsafe extern "C" fn free(ptr: *mut c_void) {
238 if ptr.is_null() {
239 return;
240 }
241 let layout = LAYOUTS
242 .lock()
243 .unwrap()
244 .remove(&(ptr as usize))
245 .unwrap_unchecked();
246 System.dealloc(ptr as *mut _, layout);
247 }
248}