1use std::{
2 cmp::Ordering,
3 ffi::CStr,
4 fmt,
5 io::{self, ErrorKind, Write},
6 os::{
7 self,
8 raw::{c_char, c_int, c_uint},
9 },
10 sync::atomic::{AtomicU32, AtomicUsize},
11 time::{Instant, SystemTime},
12};
13
14use crate::parser::{TSClock, TSDuration, __syscall_slong_t, __time_t};
15
16pub type size_t = usize;
17
18#[derive(Copy, Clone)]
19#[repr(C)]
20pub struct StackElement<T> {
21 pub contents: T,
22 pub size: u32,
23 pub capacity: u32,
24}
25
26#[derive(Copy, Clone)]
27#[repr(C)]
28pub union LongShortData {
29 pub long_data: *mut std::os::raw::c_char,
30 pub short_data: [std::os::raw::c_char; 24],
31}
32
33#[derive(Copy, Clone)]
34#[repr(C)]
35pub union ScannerStateWithLookahead {
36 pub c2rust_unnamed: ScannerStateLookaheadMeta,
37 pub external_scanner_state: crate::ExternalScannerState,
38 pub lookahead_char: std::os::raw::c_int,
39}
40
41#[derive(Copy, Clone)]
42#[repr(C)]
43pub struct ScannerStateLookaheadMeta {
44 pub visible_child_count: u32,
45 pub named_child_count: u32,
46 pub node_count: u32,
47 pub dynamic_precedence: std::os::raw::c_int,
48 pub repeat_depth: u16,
49 pub production_id: u16,
50 pub first_leaf: ScannerStateLookaheadFirstLeaf,
51}
52
53#[derive(Copy, Clone)]
54#[repr(C)]
55pub struct ScannerStateLookaheadFirstLeaf {
56 pub symbol: std::os::raw::c_ushort,
57 pub parse_state: std::os::raw::c_ushort,
58}
59
60pub(crate) trait WrappingOffsetFromExt<T: Sized> {
61 fn wrapping_offset_from_(self, origin: *const T) -> isize;
62}
63
64impl<T: Sized> WrappingOffsetFromExt<T> for *const T {
65 #[inline]
66 fn wrapping_offset_from_(self, origin: *const T) -> isize {
67 let pointee_size = std::mem::size_of::<T>();
68 assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
69
70 let d = isize::wrapping_sub(self as _, origin as _);
71 d.wrapping_div(pointee_size as _)
72 }
73}
74
75impl<T: Sized> WrappingOffsetFromExt<T> for *mut T {
76 fn wrapping_offset_from_(self, origin: *const T) -> isize {
77 (self as *const T).wrapping_offset_from_(origin)
78 }
79}
80
81pub(crate) unsafe fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
86 let s1 = CStr::from_ptr(s1);
87 let s2 = CStr::from_ptr(s2);
88
89 match s1.cmp(s2) {
90 Ordering::Less => -1,
91 Ordering::Equal => 0,
92 Ordering::Greater => 1,
93 }
94}
95
96pub(crate) unsafe fn strncmp(mut s1: *const c_char, mut s2: *const c_char, mut n: usize) -> c_int {
101 while n > 0 {
102 let a = *s1;
103 let b = *s2;
104
105 match a.cmp(&b) {
106 Ordering::Less => return -1,
107 Ordering::Greater => return 1,
108 Ordering::Equal => {}
109 }
110
111 if a == 0 {
112 return 0;
113 }
114
115 s1 = s1.add(1);
116 s2 = s2.add(1);
117 n -= 1;
118 }
119
120 0
121}
122
123#[derive(Debug)]
124pub struct WriteCounter<W> {
125 inner: W,
126 count: usize,
127}
128
129impl<W: Write> WriteCounter<W> {
130 pub(crate) fn new(write: W) -> Self {
131 Self {
132 inner: write,
133 count: 0,
134 }
135 }
136}
137
138impl<W> WriteCounter<W> {
139 pub fn count(&self) -> usize {
140 self.count
141 }
142}
143
144impl<W> Write for WriteCounter<W>
145where
146 W: Write,
147{
148 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
149 match self.inner.write(buf) {
150 Ok(count) => {
151 self.count += count;
152 Ok(count)
153 }
154 err => err,
155 }
156 }
157
158 fn flush(&mut self) -> std::io::Result<()> {
159 self.inner.flush()
160 }
161}
162
163struct VoidWriter;
164
165impl Write for VoidWriter {
166 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
167 Ok(buf.len())
168 }
169
170 fn flush(&mut self) -> io::Result<()> {
171 Ok(())
172 }
173}
174
175macro_rules! try_fmt_write_zero {
176 ($counter:expr, $args:expr) => {
177 match $counter.write_fmt($args) {
178 Ok(()) => Ok(()),
179 Err(err) if matches!(err.kind(), ErrorKind::WriteZero) => return Ok($counter.count()),
180 Err(err) => Err(err),
181 }
182 };
183}
184
185pub(crate) unsafe fn snwrite_runtime(
186 string: *mut c_char,
187 size: usize,
188 args: fmt::Arguments,
189) -> io::Result<usize> {
190 let raw = snwrite_inner(
191 WriteCounter::new(std::slice::from_raw_parts_mut(string as *mut u8, size)),
192 args,
193 )?;
194
195 if size == 1 {
197 snwrite_inner(WriteCounter::new(VoidWriter), args)
198 } else {
199 Ok(raw)
200 }
201}
202
203fn snwrite_inner<W>(mut counter: WriteCounter<W>, args: fmt::Arguments) -> io::Result<usize>
204where
205 W: Write,
206{
207 try_fmt_write_zero!(counter, args)?;
208 try_fmt_write_zero!(counter, format_args!("\0"))?;
209
210 Ok(counter.count() - 1)
211}
212
213#[macro_export]
214macro_rules! snwrite {
215 ($string:expr, $size:expr, $($arg:tt)*) => {
216 crate::util::snwrite_runtime($string, $size, ::std::format_args!($($arg)*))
217 }
218}
219
220#[repr(transparent)]
221#[cfg_attr(feature = "capi", derive(Clone, Copy))]
222pub struct File(
223 #[cfg(feature = "capi")] crate::capi::CFile,
224 #[cfg(not(feature = "capi"))] Option<Box<std::io::BufWriter<std::fs::File>>>,
225);
226
227impl File {
228 pub(crate) fn empty() -> Self {
229 #[cfg(feature = "capi")]
230 {
231 Self(crate::capi::CFile::new(std::ptr::null_mut()))
232 }
233
234 #[cfg(not(feature = "capi"))]
235 {
236 Self(None)
237 }
238 }
239
240 pub(crate) fn is_valid(&self) -> bool {
241 #[cfg(feature = "capi")]
242 {
243 !self.0.is_null()
244 }
245
246 #[cfg(not(feature = "capi"))]
247 {
248 self.0.is_some()
249 }
250 }
251
252 pub(crate) fn close(&mut self) {
253 if !self.is_valid() {
254 return;
255 }
256
257 #[cfg(feature = "capi")]
258 {
259 if self.0.close() != 0 {
260 panic!("cannot close libc file stream");
261 }
262 }
263
264 #[cfg(not(feature = "capi"))]
265 {
266 self.0 = None;
267 }
268 }
269}
270
271impl Write for File {
272 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
273 #[cfg(feature = "capi")]
274 {
275 self.0.write(buf)
276 }
277
278 #[cfg(not(feature = "capi"))]
279 {
280 self.0.as_mut().unwrap().write(buf)
281 }
282 }
283
284 fn flush(&mut self) -> io::Result<()> {
285 #[cfg(feature = "capi")]
286 {
287 self.0.flush()
288 }
289
290 #[cfg(not(feature = "capi"))]
291 {
292 self.0.as_mut().unwrap().flush()
293 }
294 }
295}
296
297#[cfg(feature = "capi")]
298impl<T> From<T> for File
299where
300 T: Into<crate::capi::CFile>,
301{
302 fn from(file: T) -> Self {
303 Self(file.into())
304 }
305}
306
307#[cfg(not(feature = "capi"))]
308impl From<std::io::BufWriter<std::fs::File>> for File {
309 fn from(file: std::io::BufWriter<std::fs::File>) -> Self {
310 Self(Some(Box::new(file)))
311 }
312}
313
314pub(crate) fn iswspace(wc: c_uint) -> c_int {
316 const SPACES: [c_uint; 21] = [
317 b' ' as _, b'\t' as _, b'\n' as _, b'\r' as _, 11, 12, 0x0085, 0x2000, 0x2001, 0x2002,
318 0x2003, 0x2004, 0x2005, 0x2006, 0x2008, 0x2009, 0x200a, 0x2028, 0x2029, 0x205f, 0x3000,
319 ];
320
321 (wc != 0 && SPACES.contains(&wc)) as c_int
322}
323
324pub(crate) fn iswdigit(wc: c_uint) -> c_int {
326 (wc.wrapping_sub(b'0' as c_uint) < 10) as c_int
327}
328
329pub(crate) fn iswalpha(wc: c_uint) -> c_int {
331 const TABLE: [c_uint; 3904] = include!("./alpha.data");
332
333 if wc < 0x20000 {
334 ((TABLE[(TABLE[(wc >> 8) as usize].wrapping_mul(32) + ((wc & 255) >> 3)) as usize]
335 >> (wc & 7))
336 & 1) as c_int
337 } else if wc < 0x2fffe {
338 1
339 } else {
340 0
341 }
342}
343
344pub(crate) fn iswalnum(wc: c_uint) -> c_int {
346 (iswdigit(wc) != 0 || iswalpha(wc) != 0) as c_int
347}
348
349#[inline]
350pub(crate) unsafe extern "C" fn atomic_inc(p: *const u32) -> u32 {
351 (&*(p as *const AtomicU32))
352 .fetch_add(1, std::sync::atomic::Ordering::SeqCst)
353 .wrapping_add(1)
354}
355
356#[inline]
357pub(crate) unsafe extern "C" fn atomic_dec(mut p: *mut u32) -> u32 {
358 (&*(p as *const AtomicU32))
359 .fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
360 .wrapping_sub(1)
361}
362
363#[inline]
364pub(crate) unsafe extern "C" fn clock_now() -> TSClock {
365 let now = SystemTime::now()
366 .duration_since(std::time::UNIX_EPOCH)
367 .unwrap();
368 let mut result: TSClock = TSClock {
369 tv_sec: now.as_secs() as isize,
370 tv_nsec: now.as_nanos() as isize,
371 };
372 return result;
373}
374
375#[inline]
376pub(crate) unsafe extern "C" fn clock_after(
377 mut base: TSClock,
378 mut duration: TSDuration,
379) -> TSClock {
380 let mut result: TSClock = base;
381 result.tv_sec = (result.tv_sec as usize)
382 .wrapping_add(duration.wrapping_div(1000000 as os::raw::c_int as u64) as usize)
383 as __time_t as __time_t;
384 result.tv_nsec = (result.tv_nsec as usize).wrapping_add(
385 duration
386 .wrapping_rem(1000000 as os::raw::c_int as u64)
387 .wrapping_mul(1000 as os::raw::c_int as u64) as usize,
388 ) as __syscall_slong_t as __syscall_slong_t;
389 return result;
390}
391
392#[inline]
393pub(crate) unsafe extern "C" fn atomic_load(mut p: *const usize) -> usize {
394 (&*(p as *const AtomicUsize)).load(std::sync::atomic::Ordering::SeqCst) as usize
395}