Fork of Relibc
1/// Print to stdout
2#[macro_export]
3macro_rules! print {
4 ($($arg:tt)*) => ({
5 use core::fmt::Write;
6 let _ = write!($crate::platform::FileWriter::new(1), $($arg)*);
7 });
8}
9
10/// Print with new line to stdout
11#[macro_export]
12macro_rules! println {
13 () => (print!("\n"));
14 ($fmt:expr) => (print!(concat!($fmt, "\n")));
15 ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
16}
17
18/// Print to stderr
19#[macro_export]
20macro_rules! eprint {
21 ($($arg:tt)*) => ({
22 use core::fmt::Write;
23 let _ = write!($crate::platform::FileWriter::new(2), $($arg)*);
24 });
25}
26
27/// Print with new line to stderr
28#[macro_export]
29macro_rules! eprintln {
30 () => (eprint!("\n"));
31 ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
32 ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
33}
34
35/// Lifted from libstd
36#[macro_export]
37macro_rules! dbg {
38 // NOTE: We cannot use `concat!` to make a static string as a format argument
39 // of `eprintln!` because `file!` could contain a `{` or
40 // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
41 // will be malformed.
42 () => {
43 eprintln!("[{}:{}:{}]", file!(), line!(), column!());
44 };
45 ($val:expr) => {
46 // Use of `match` here is intentional because it affects the lifetimes
47 // of temporaries - https://stackoverflow.com/a/48732525/1063961
48 match $val {
49 tmp => {
50 eprintln!(
51 "[{}:{}:{}] {} = {:#?}",
52 file!(),
53 line!(),
54 column!(),
55 stringify!($val),
56 &tmp
57 );
58 tmp
59 }
60 }
61 };
62 ($($val:expr),+ $(,)?) => {
63 ($(dbg!($val)),+,)
64 };
65}
66
67#[macro_export]
68#[cfg(not(feature = "trace"))]
69macro_rules! trace {
70 ($($arg:tt)*) => {};
71}
72
73#[macro_export]
74#[cfg(feature = "trace")]
75macro_rules! trace {
76 ($($arg:tt)*) => ({
77 eprintln!($($arg)*);
78 });
79}
80
81#[macro_export]
82#[cfg(not(feature = "trace"))]
83macro_rules! trace_expr {
84 ($expr:expr, $($arg:tt)*) => {
85 $expr
86 };
87}
88
89#[macro_export]
90#[cfg(feature = "trace")]
91macro_rules! trace_expr {
92 ($expr:expr, $($arg:tt)*) => ({
93 use $crate::header::errno::STR_ERROR;
94 use $crate::platform;
95
96 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 trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
115
116 ret
117 });
118}
119
120#[macro_export]
121macro_rules! strto_impl {
122 (
123 $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
124 ) => {{
125 // ensure these are constants
126 const CHECK_SIGN: bool = $signed;
127 const MAX_VAL: $rettype = $maxval;
128 const MIN_VAL: $rettype = $minval;
129
130 let set_endptr = |idx: isize| {
131 if !$endptr.is_null() {
132 // This is stupid, but apparently strto* functions want
133 // const input but mut output, yet the man page says
134 // "stores the address of the first invalid character in *endptr"
135 // so obviously it doesn't want us to clone it.
136 *$endptr = $s.offset(idx) as *mut _;
137 }
138 };
139
140 let invalid_input = || {
141 platform::ERRNO.set(EINVAL);
142 set_endptr(0);
143 };
144
145 // only valid bases are 2 through 36
146 if $base != 0 && ($base < 2 || $base > 36) {
147 invalid_input();
148 return 0;
149 }
150
151 let mut idx = 0;
152
153 // skip any whitespace at the beginning of the string
154 while ctype::isspace(*$s.offset(idx) as c_int) != 0 {
155 idx += 1;
156 }
157
158 // check for +/-
159 let positive = match is_positive(*$s.offset(idx)) {
160 Some((pos, i)) => {
161 idx += i;
162 pos
163 }
164 None => {
165 invalid_input();
166 return 0;
167 }
168 };
169
170 // convert the string to a number
171 let num_str = $s.offset(idx);
172 let res = match $base {
173 0 => detect_base(num_str).and_then(|($base, i)| {
174 idx += i;
175 convert_integer(num_str.offset(i), $base)
176 }),
177 8 => convert_octal(num_str),
178 16 => convert_hex(num_str),
179 _ => convert_integer(num_str, $base),
180 };
181
182 // check for error parsing octal/hex prefix
183 // also check to ensure a number was indeed parsed
184 let (num, i, overflow) = match res {
185 Some(res) => res,
186 None => {
187 invalid_input();
188 return 0;
189 }
190 };
191 idx += i;
192
193 let overflow = if CHECK_SIGN {
194 overflow || (num as c_long).is_negative()
195 } else {
196 overflow
197 };
198 // account for the sign
199 let num = num as $rettype;
200 let num = if overflow {
201 platform::ERRNO.set(ERANGE);
202 if CHECK_SIGN {
203 if positive { MAX_VAL } else { MIN_VAL }
204 } else {
205 MAX_VAL
206 }
207 } else {
208 if positive {
209 num
210 } else {
211 // not using -num to keep the compiler happy
212 num.overflowing_neg().0
213 }
214 };
215
216 set_endptr(idx);
217
218 num
219 }};
220}
221
222#[macro_export]
223macro_rules! strto_float_impl {
224 ($type:ident, $s:expr, $endptr:expr) => {{
225 let mut s = $s;
226 let endptr = $endptr;
227
228 while ctype::isspace(*s as c_int) != 0 {
229 s = s.offset(1);
230 }
231
232 let mut result: $type = 0.0;
233 let mut exponent: Option<$type> = None;
234 let mut radix = 10;
235
236 let result_sign = match *s as u8 {
237 b'-' => {
238 s = s.offset(1);
239 -1.0
240 }
241 b'+' => {
242 s = s.offset(1);
243 1.0
244 }
245 _ => 1.0,
246 };
247
248 let rust_s = CStr::from_ptr(s).to_string_lossy();
249
250 // detect NaN, Inf
251 if rust_s.to_lowercase().starts_with("inf") {
252 result = $type::INFINITY;
253 s = s.offset(3);
254 } else if rust_s.to_lowercase().starts_with("nan") {
255 // we cannot signal negative NaN in LLVM backed languages
256 // https://github.com/rust-lang/rust/issues/73328 , https://github.com/rust-lang/rust/issues/81261
257 result = $type::NAN;
258 s = s.offset(3);
259 } else {
260 if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
261 s = s.offset(2);
262 radix = 16;
263 }
264
265 while let Some(digit) = (*s as u8 as char).to_digit(radix) {
266 result *= radix as $type;
267 result += digit as $type;
268 s = s.offset(1);
269 }
270
271 if *s as u8 == b'.' {
272 s = s.offset(1);
273
274 let mut i = 1.0;
275 while let Some(digit) = (*s as u8 as char).to_digit(radix) {
276 i *= radix as $type;
277 result += digit as $type / i;
278 s = s.offset(1);
279 }
280 }
281
282 let s_before_exponent = s;
283
284 exponent = match (*s as u8, radix) {
285 (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
286 s = s.offset(1);
287
288 let is_exponent_positive = match *s as u8 {
289 b'-' => {
290 s = s.offset(1);
291 false
292 }
293 b'+' => {
294 s = s.offset(1);
295 true
296 }
297 _ => true,
298 };
299
300 // Exponent digits are always in base 10.
301 if (*s as u8 as char).is_digit(10) {
302 let mut exponent_value = 0;
303
304 while let Some(digit) = (*s as u8 as char).to_digit(10) {
305 exponent_value *= 10;
306 exponent_value += digit;
307 s = s.offset(1);
308 }
309
310 let exponent_base = match radix {
311 10 => 10u128,
312 16 => 2u128,
313 _ => unreachable!(),
314 };
315
316 if is_exponent_positive {
317 Some(exponent_base.pow(exponent_value) as $type)
318 } else {
319 Some(1.0 / (exponent_base.pow(exponent_value) as $type))
320 }
321 } else {
322 // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
323 s = s_before_exponent;
324 None
325 }
326 }
327 _ => None,
328 };
329 }
330
331 if !endptr.is_null() {
332 // This is stupid, but apparently strto* functions want
333 // const input but mut output, yet the man page says
334 // "stores the address of the first invalid character in *endptr"
335 // so obviously it doesn't want us to clone it.
336 *endptr = s as *mut _;
337 }
338
339 if let Some(exponent) = exponent {
340 result_sign * result * exponent
341 } else {
342 result_sign * result
343 }
344 }};
345}
346
347/// Project an `Out<struct X { field: Type }>` to `struct X { field: Out<Type> }`.
348///
349/// It is allowed to include only a subset of the struct's fields. The struct must implement
350/// `OutProject`.
351#[macro_export]
352macro_rules! out_project {
353 {
354 let $struct:ty { $($field:ident : $fieldty:ty),*$(,)? } = $src:ident;
355 } => {
356 // Verify $src actually has type Out<$struct>. Also verify it implements `OutProject`. This
357 // excludes
358 //
359 // - the case where $src is Out<&Struct>, where it would be very UB to just construct a
360 // writable reference to $src.$field, or a smart pointer
361 // - the case where there are unaligned fields where it would be UB to call ptr::write to
362 // them (requiring packed structs)
363 {
364 fn ensure_type<U: $crate::out::OutProject>(_t: &$crate::out::Out<U>) {}
365 ensure_type::<$struct>(&$src);
366 }
367 // Verify there are no duplicate struct fields. This is not strictly necessary as Out lacks
368 // the noalias requirement, but forbidding the same field to occur multiple times would
369 // allow both cases. The compiler will reject any struct that reuses the same identifier.
370 const _: () = {
371 $(
372 if ::core::mem::offset_of!($struct, $field) % ::core::mem::align_of::<$fieldty>() != 0 {
373 panic!(concat!("unaligned field ", stringify!($field), " of struct ", stringify!($struct), "."));
374 }
375 )*
376 struct S {
377 $(
378 $field: $fieldty
379 ),*
380 }
381 };
382
383 // Finally, create an Out<$fieldty> for each field.
384 $(
385 // getting the pointer to $field is safe
386 let $field = unsafe { &raw mut (*$crate::out::Out::<_>::as_mut_ptr(&mut $src)).$field };
387 )*
388 $(
389 let mut $field: $crate::out::Out<$fieldty> = unsafe {
390 // SAFETY: the only guarantee is that the pointer is valid and writable for the
391 // duration of 'b where $src: Out<'b, T>. But if so, and T is a struct, that
392 // must also be true for all the struct fields.
393 $crate::out::Out::with_lifetime_of(
394 $crate::out::Out::nonnull($field),
395 &$src,
396 )
397 };
398 )*
399 }
400}
401#[macro_export]
402macro_rules! OutProject {
403 derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
404 $(
405 $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
406 ),*$(,)?
407 } } => {
408 // SAFETY: As simple as it is, OutProject is valid for any struct, and the pattern we have
409 // matched above ensures $name is one.
410 unsafe impl $crate::out::OutProject for $name {}
411 }
412}