1#[macro_export]
3macro_rules! print {
4 ($($arg:tt)*) => {{
5 use core::fmt::Write;
6 let _ = $crate::platform::FileWriter::new(1).write_fmt(format_args!($($arg)*));
7 }};
8}
9
10#[macro_export]
13macro_rules! println {
14 () => {
15 $crate::print!("\n")
16 };
17 ($($arg:tt)*) => {
18 $crate::print!("{}\n", format_args!($($arg)*))
19 };
20}
21
22#[macro_export]
24macro_rules! eprint {
25 ($($arg:tt)*) => {{
26 use core::fmt::Write;
27 let _ = $crate::platform::FileWriter::new(2).write_fmt(format_args!($($arg)*));
28 }};
29}
30
31#[macro_export]
34macro_rules! eprintln {
35 () => {
36 $crate::eprint!("\n")
37 };
38 ($($arg:tt)*) => {
39 $crate::eprint!("{}\n", format_args!($($arg)*))
40 };
41}
42
43pub const ISSUE_URL: &str = "https://gitlab.redox-os.org/redox-os/relibc/-/issues/";
44
45#[macro_export]
47macro_rules! todo_skip {
48 ($issue:expr, $($arg:tt)*) => {
49 if $issue != 0 {
50 log::info!("TODO ({}{}): {}", $crate::macros::ISSUE_URL, $issue, format_args!($($arg)*))
51 } else {
52 log::info!("TODO: {}", format_args!($($arg)*))
53 }
54 };
55}
56
57#[macro_export]
59macro_rules! todo_error {
60 ($issue:expr, $err:expr, $($arg:tt)*) => {
61 if $issue != 0 {
62 log::error!("TODO ({}{}): {}: {}", $crate::macros::ISSUE_URL, $issue, format_args!($($arg)*), $err)
63 } else {
64 log::error!("TODO: {}: {:?}", format_args!($($arg)*), $err)
65 }
66 };
67}
68
69#[macro_export]
71macro_rules! todo_panic {
72 ($issue:expr, $($arg:tt)*) => {
73 if $issue != 0 {
74 todo!("{} ({}{})", format_args!($($arg)*), $crate::macros::ISSUE_URL, $issue)
75 } else {
76 todo!("{}", format_args!($($arg)*))
77 }
78 };
79}
80
81#[macro_export]
82#[cfg(feature = "no_trace")]
83macro_rules! trace_expr {
84 ($expr:expr, $($arg:tt)*) => {
85 $expr
86 };
87}
88
89#[macro_export]
90#[cfg(not(feature = "no_trace"))]
91macro_rules! trace_expr {
92 ($expr:expr, $($arg:tt)*) => ({
93 use $crate::header::errno::STR_ERROR;
94 use $crate::platform;
95
96 log::trace!("{}", format_args!($($arg)*));
97
98 let trace_old_errno = platform::ERRNO.get();
99 platform::ERRNO.set(0);
100
101 let ret = $expr;
102
103 let trace_errno = platform::ERRNO.get() as isize;
104 if trace_errno == 0 {
105 platform::ERRNO.set(trace_old_errno);
106 }
107
108 let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize {
109 STR_ERROR[trace_errno as usize]
110 } else {
111 "Unknown error"
112 };
113
114 log::trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
115
116 ret
117 });
118}
119
120#[macro_export]
121macro_rules! skipws {
122 ($ptr:expr) => {
123 while isspace(unsafe { *$ptr }) != 0 {
124 $ptr = unsafe { $ptr.add(1) };
125 }
126 };
127}
128
129#[macro_export]
130macro_rules! wcsto_impl {
131 ($type:ident, $ptr:expr, $base:expr) => {{
132 let has_minus = unsafe { *$ptr } == '-' as wchar_t;
133 let has_plus = unsafe { *$ptr } == '+' as wchar_t;
134 if has_minus || has_plus {
135 $ptr = unsafe { $ptr.add(1) };
136 }
137
138 let type_is_signed = $type::MIN != 0;
139
140 let mut base = $base;
141
142 if (base == 16 || base == 0)
143 && unsafe { *$ptr } == '0' as wchar_t
144 && (unsafe { *$ptr.add(1) } == 'x' as wchar_t
145 || unsafe { *$ptr.add(1) } == 'X' as wchar_t)
146 {
147 $ptr = unsafe { $ptr.add(2) };
148 base = 16;
149 }
150
151 if base == 0 {
152 base = if unsafe { *$ptr } == '0' as wchar_t {
153 8
154 } else {
155 10
156 };
157 };
158
159 let mut result: $type = 0;
160 while let Some(digit) =
161 char::from_u32(unsafe { *$ptr } as u32).and_then(|c| c.to_digit(base as u32))
162 {
163 let new = result.checked_mul(base as $type).and_then(|result| {
164 if has_minus && type_is_signed {
165 #[cfg(target_arch = "x86")]
166 {
167 result.checked_sub(
168 $type::try_from(digit).expect("single digit never overflows"),
169 )
170 }
171 #[cfg(not(target_arch = "x86"))]
172 {
173 result.checked_sub($type::from(digit))
174 }
175 } else {
176 #[cfg(target_arch = "x86")]
177 {
178 result.checked_add(
179 $type::try_from(digit).expect("single digit never overflows"),
180 )
181 }
182 #[cfg(not(target_arch = "x86"))]
183 {
184 result.checked_add($type::from(digit))
185 }
186 }
187 });
188 result = match new {
189 Some(new) => new,
190 None => {
191 platform::ERRNO.set(ERANGE);
192 return !0;
193 }
194 };
195
196 $ptr = unsafe { $ptr.add(1) };
197 }
198 if has_minus && !type_is_signed {
199 result = $type::MAX - result + 1;
200 }
201 result
202 }};
203}
204
205#[macro_export]
206macro_rules! strto_impl {
207 (
209 $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
210 ) => {{
211 const CHECK_SIGN: bool = $signed;
213 const MAX_VAL: $rettype = $maxval;
214 const MIN_VAL: $rettype = $minval;
215
216 let set_endptr = |idx: isize| {
217 if !$endptr.is_null() {
218 unsafe {
223 *$endptr = $s.offset(idx).cast_mut();
224 }
225 }
226 };
227
228 let invalid_input = || {
229 platform::ERRNO.set(EINVAL);
230 set_endptr(0);
231 };
232
233 if $base != 0 && !(2..=36).contains(&$base) {
235 invalid_input();
236 return 0;
237 }
238
239 let mut idx = 0;
240
241 while ctype::isspace(c_int::from(unsafe { *$s.offset(idx) })) != 0 {
243 idx += 1;
244 }
245
246 let positive = match is_positive(unsafe { *$s.offset(idx) }) {
248 Some((pos, i)) => {
249 idx += i;
250 pos
251 }
252 None => {
253 invalid_input();
254 return 0;
255 }
256 };
257
258 let num_str = unsafe { $s.offset(idx) };
260 let res = match $base {
261 0 => unsafe { detect_base(num_str) }.and_then(|($base, i)| {
262 idx += i;
263 unsafe { convert_integer(num_str.offset(i), $base) }
264 }),
265 8 => unsafe { convert_octal(num_str) },
266 16 => unsafe { convert_hex(num_str) },
267 _ => unsafe { convert_integer(num_str, $base) },
268 };
269
270 let (num, i, overflow) = match res {
273 Some(res) => res,
274 None => {
275 invalid_input();
276 return 0;
277 }
278 };
279 idx += i;
280
281 let overflow = if CHECK_SIGN {
282 overflow || (num as c_long).is_negative()
283 } else {
284 overflow
285 };
286 let num = num as $rettype;
288 let num = if overflow {
289 platform::ERRNO.set(ERANGE);
290 if CHECK_SIGN {
291 if positive { MAX_VAL } else { MIN_VAL }
292 } else {
293 MAX_VAL
294 }
295 } else {
296 if positive {
297 num
298 } else {
299 num.overflowing_neg().0
301 }
302 };
303
304 set_endptr(idx);
305
306 num
307 }};
308}
309
310#[macro_export]
311macro_rules! strto_float_impl {
312 ($type:ident, $s:expr, $endptr:expr) => {{
313 let mut s = $s;
314 let endptr = $endptr;
315
316 while ctype::isspace(c_int::from(unsafe{*s})) != 0 {
317 s = unsafe{ s.offset(1)};
318 }
319
320 let mut result: $type = 0.0;
321 let mut exponent: Option<$type> = None;
322 let mut radix = 10;
323
324 let result_sign = match unsafe{*s} as u8 {
325 b'-' => {
326 s = unsafe{s.offset(1)};
327 -1.0
328 }
329 b'+' => {
330 s = unsafe{s.offset(1)};
331 1.0
332 }
333 _ => 1.0,
334 };
335
336 let rust_s = unsafe{CStr::from_ptr(s)}.to_string_lossy();
337
338 if rust_s.to_lowercase().starts_with("inf") {
340 result = $type::INFINITY;
341 s = unsafe{s.offset(3)};
342 } else if rust_s.to_lowercase().starts_with("nan") {
343 result = $type::NAN;
346 s = unsafe{s.offset(3)};
347 } else {
348 if unsafe{*s} as u8 == b'0' && unsafe{*s.offset(1)} as u8 == b'x' {
349 s = unsafe{s.offset(2)};
350 radix = 16;
351 }
352
353 while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(radix) {
354 result *= radix as $type;
355 result += digit as $type;
356 s = unsafe{s.offset(1)};
357 }
358
359 if unsafe{*s} as u8 == b'.' {
360 s = unsafe{s.offset(1)};
361
362 let mut i = 1.0;
363 while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(radix) {
364 i *= radix as $type;
365 result += digit as $type / i;
366 s = unsafe{s.offset(1)};
367 }
368 }
369
370 let s_before_exponent = s;
371
372 exponent = match (unsafe{*s} as u8, radix) {
373 (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
374 s = unsafe{s.offset(1)};
375
376 let is_exponent_positive = match unsafe{*s} as u8 {
377 b'-' => {
378 s = unsafe{s.offset(1)};
379 false
380 }
381 b'+' => {
382 s = unsafe{s.offset(1)};
383 true
384 }
385 _ => true,
386 };
387
388 if (unsafe{*s} as u8 as char).is_digit(10) {
390 let mut exponent_value = 0;
391
392 while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(10) {
393 exponent_value *= 10;
394 exponent_value += digit;
395 s = unsafe{s.offset(1)};
396 }
397
398 let exponent_base = match radix {
399 10 => 10u128,
400 16 => 2u128,
401 _ => unreachable!(),
402 };
403
404 if is_exponent_positive {
405 Some(exponent_base.pow(exponent_value) as $type)
406 } else {
407 Some(1.0 / (exponent_base.pow(exponent_value) as $type))
408 }
409 } else {
410 s = s_before_exponent;
412 None
413 }
414 }
415 _ => None,
416 };
417 }
418
419 if !endptr.is_null() {
420 unsafe{*endptr = s.cast_mut()};
425 }
426
427 if let Some(exponent) = exponent {
428 result_sign * result * exponent
429 } else {
430 result_sign * result
431 }
432 }};
433}
434
435#[macro_export]
440macro_rules! out_project {
441 {
442 let $struct:ty { $($field:ident : $fieldty:ty),*$(,)? } = $src:ident;
443 } => {
444 {
452 fn ensure_type<U: $crate::out::OutProject>(_t: &$crate::out::Out<U>) {}
453 ensure_type::<$struct>(&$src);
454 }
455 const _: () = {
459 $(
460 if ::core::mem::offset_of!($struct, $field) % ::core::mem::align_of::<$fieldty>() != 0 {
461 panic!(concat!("unaligned field ", stringify!($field), " of struct ", stringify!($struct), "."));
462 }
463 )*
464 struct S {
465 $(
466 $field: $fieldty
467 ),*
468 }
469 };
470
471 $(
473 let $field = unsafe { &raw mut (*$crate::out::Out::<_>::as_mut_ptr(&mut $src)).$field };
475 )*
476 $(
477 let mut $field: $crate::out::Out<$fieldty> = unsafe {
478 $crate::out::Out::with_lifetime_of(
482 $crate::out::Out::nonnull($field),
483 &$src,
484 )
485 };
486 )*
487 }
488}
489#[macro_export]
490macro_rules! OutProject {
491 derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
492 $(
493 $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
494 ),*$(,)?
495 } } => {
496 unsafe impl $crate::out::OutProject for $name {}
499 }
500}
501#[macro_export]
502#[cfg(not(feature = "check_against_libc_crate"))]
503macro_rules! CheckVsLibcCrate {
504 derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
505 $(
506 $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
507 ),*$(,)?
508 } } => {
509 }
510}
511
512pub trait LibcTypeEquals<A, B> {}
515impl<A, B> LibcTypeEquals<*mut A, *mut B> for () where (): LibcTypeEquals<A, B> {}
517impl<A, B> LibcTypeEquals<*const A, *const B> for () where (): LibcTypeEquals<A, B> {}
518impl<A, B, const N: usize> LibcTypeEquals<[A; N], [B; N]> for () where (): LibcTypeEquals<A, B> {}
519macro_rules! for_primitive_int(
520 ($i:ident) => {
521 impl LibcTypeEquals<$i, $i> for () {}
522 }
523);
524for_primitive_int!(u8);
525for_primitive_int!(u16);
526for_primitive_int!(u32);
527for_primitive_int!(u64);
528for_primitive_int!(u128);
529for_primitive_int!(usize);
530for_primitive_int!(i8);
531for_primitive_int!(i16);
532for_primitive_int!(i32);
533for_primitive_int!(i64);
534for_primitive_int!(i128);
535for_primitive_int!(isize);
536impl LibcTypeEquals<crate::platform::types::c_void, crate::platform::types::c_void> for () {}
537#[cfg(feature = "check_against_libc_crate")]
538impl LibcTypeEquals<__libc_only_for_layout_checks::c_void, crate::platform::types::c_void> for () {}
539#[cfg(feature = "check_against_libc_crate")]
540impl LibcTypeEquals<crate::platform::types::c_void, __libc_only_for_layout_checks::c_void> for () {}
541
542#[macro_export]
547#[cfg(feature = "check_against_libc_crate")]
548macro_rules! CheckVsLibcCrate {
549 derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
552 $(
553 $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
554 ),*$(,)?
555 } } => {
556 #[allow(dead_code)]
558 const _: () = {
559 if ::core::mem::size_of::<$name>() != ::core::mem::size_of::<::__libc_only_for_layout_checks::$name>() {
560 panic!("struct size mismatch");
561 }
562 if ::core::mem::align_of::<$name>() != ::core::mem::align_of::<::__libc_only_for_layout_checks::$name>() {
563 panic!("struct alignment mismatch");
564 }
565 $(
566 if ::core::mem::offset_of!($name, $field) != ::core::mem::offset_of!(__libc_only_for_layout_checks::$name, $field) {
567 panic!("struct field offset mismatch");
568 }
569 )*
570 };
571 $(
572 #[allow(dead_code)]
574 const _: () = {
575 fn ensure_ty<A, B>(a: A, b: B) where (): $crate::macros::LibcTypeEquals::<A, B> {}
576 fn for_libc(a: $name, b: __libc_only_for_layout_checks::$name) {
577 #[allow(clippy::diverging_sub_expression)]
578 let a: $type = panic!("never called");
579 ensure_ty(a, b.$field);
580 }
581 };
582 )*
583 impl $crate::macros::LibcTypeEquals<$name, __libc_only_for_layout_checks::$name> for () {}
584 impl $crate::macros::LibcTypeEquals<__libc_only_for_layout_checks::$name, $name> for () {}
585 }
586}