xref: /drstd/dlibc/src/unix/macros.rs (revision 0fe3ff0054d3aec7fbf9bddecfecb10bc7d23a51)
1 #[macro_export]
2 macro_rules! c_str {
3     ($lit:expr) => {
4         #[allow(unused_unsafe)]
5         unsafe {
6             $crate::c_str::CStr::from_bytes_with_nul_unchecked(concat!($lit, "\0").as_bytes())
7         }
8     };
9 }
10 
11 /// Print to stdout
12 #[macro_export]
13 macro_rules! print {
14     ($($arg:tt)*) => ({
15         use core::fmt::Write;
16         let _ = write!($crate::unix::platform::FileWriter(1), $($arg)*);
17     });
18 }
19 
20 /// Print with new line to stdout
21 #[macro_export]
22 macro_rules! println {
23     () => (print!("\n"));
24     ($fmt:expr) => (print!(concat!($fmt, "\n")));
25     ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
26 }
27 
28 /// Print to stderr
29 #[macro_export]
30 macro_rules! eprint {
31     ($($arg:tt)*) => ({
32         use core::fmt::Write;
33         let _ = write!($crate::unix::platform::FileWriter(2), $($arg)*);
34     });
35 }
36 
37 /// Print with new line to stderr
38 #[macro_export]
39 macro_rules! eprintln {
40     () => (eprint!("\n"));
41     ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
42     ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
43 }
44 
45 /// Lifted from libstd
46 #[macro_export]
47 macro_rules! dbg {
48     () => {
49         eprintln!("[{}:{}]", file!(), line!());
50     };
51     ($val:expr) => {
52         // Use of `match` here is intentional because it affects the lifetimes
53         // of temporaries - https://stackoverflow.com/a/48732525/1063961
54         match $val {
55             tmp => {
56                 eprintln!(
57                     "[{}:{}] {} = {:#?}",
58                     file!(),
59                     line!(),
60                     stringify!($val),
61                     &tmp
62                 );
63                 tmp
64             }
65         }
66     };
67 }
68 
69 #[macro_export]
70 #[cfg(not(feature = "trace"))]
71 macro_rules! trace {
72     ($($arg:tt)*) => {};
73 }
74 
75 #[macro_export]
76 #[cfg(feature = "trace")]
77 macro_rules! trace {
78     ($($arg:tt)*) => ({
79         use $crate::{Pal, Sys};
80         eprintln!($($arg)*);
81     });
82 }
83 
84 #[macro_export]
85 #[cfg(not(feature = "trace"))]
86 macro_rules! trace_expr {
87     ($expr:expr, $($arg:tt)*) => {
88         $expr
89     };
90 }
91 
92 #[macro_export]
93 #[cfg(feature = "trace")]
94 macro_rules! trace_expr {
95     ($expr:expr, $($arg:tt)*) => ({
96         use $crate::unix::header::errno::STR_ERROR;
97         use $crate::unix::platform;
98 
99         trace!("{}", format_args!($($arg)*));
100 
101         #[allow(unused_unsafe)]
102         let trace_old_errno = unsafe { platform::errno };
103         #[allow(unused_unsafe)]
104         unsafe { platform::errno = 0; }
105 
106         let ret = $expr;
107 
108         #[allow(unused_unsafe)]
109         let trace_errno = unsafe { platform::errno } as isize;
110         if trace_errno == 0 {
111             #[allow(unused_unsafe)]
112             unsafe { platform::errno = trace_old_errno; }
113         }
114 
115         let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize {
116             STR_ERROR[trace_errno as usize]
117         } else {
118             "Unknown error"
119         };
120 
121         trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
122 
123         ret
124     });
125 }
126 
127 #[macro_export]
128 macro_rules! strto_impl {
129     (
130         $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
131     ) => {{
132         // ensure these are constants
133         const CHECK_SIGN: bool = $signed;
134         const MAX_VAL: $rettype = $maxval;
135         const MIN_VAL: $rettype = $minval;
136         #[allow(unused_mut)]
137         let mut set_endptr = |idx: isize| {
138             if !$endptr.is_null() {
139                 // This is stupid, but apparently strto* functions want
140                 // const input but mut output, yet the man page says
141                 // "stores the address of the first invalid character in *endptr"
142                 // so obviously it doesn't want us to clone it.
143                 *$endptr = $s.offset(idx) as *mut _;
144             }
145         };
146 
147         #[allow(unused_mut)]
148         let mut invalid_input = || {
149             ::errno = EINVAL;
150             set_endptr(0);
151         };
152 
153         // only valid bases are 2 through 36
154         if $base != 0 && ($base < 2 || $base > 36) {
155             invalid_input();
156             return 0;
157         }
158 
159         let mut idx = 0;
160 
161         // skip any whitespace at the beginning of the string
162         while ctype::isspace(*$s.offset(idx) as ::c_int) != 0 {
163             idx += 1;
164         }
165 
166         // check for +/-
167         let positive = match is_positive(*$s.offset(idx)) {
168             Some((pos, i)) => {
169                 idx += i;
170                 pos
171             }
172             None => {
173                 invalid_input();
174                 return 0;
175             }
176         };
177 
178         // convert the string to a number
179         let num_str = $s.offset(idx);
180         let res = match $base {
181             0 => detect_base(num_str)
182                 .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)),
183             8 => convert_octal(num_str),
184             16 => convert_hex(num_str),
185             _ => convert_integer(num_str, $base),
186         };
187 
188         // check for error parsing octal/hex prefix
189         // also check to ensure a number was indeed parsed
190         let (num, i, overflow) = match res {
191             Some(res) => res,
192             None => {
193                 invalid_input();
194                 return 0;
195             }
196         };
197         idx += i;
198 
199         let overflow = if CHECK_SIGN {
200             overflow || (num as ::c_long).is_negative()
201         } else {
202             overflow
203         };
204         // account for the sign
205         let num = num as $rettype;
206         let num = if overflow {
207             ::errno = ERANGE;
208             if CHECK_SIGN {
209                 if positive {
210                     MAX_VAL
211                 } else {
212                     MIN_VAL
213                 }
214             } else {
215                 MAX_VAL
216             }
217         } else {
218             if positive {
219                 num
220             } else {
221                 // not using -num to keep the compiler happy
222                 num.overflowing_neg().0
223             }
224         };
225 
226         set_endptr(idx);
227 
228         num
229     }};
230 }
231 #[macro_export]
232 macro_rules! strto_float_impl {
233     ($type:ident, $s:expr, $endptr:expr) => {{
234         let mut s = $s;
235         let endptr = $endptr;
236 
237         // TODO: Handle named floats: NaN, Inf...
238 
239         while ctype::isspace(*s as ::c_int) != 0 {
240             s = s.offset(1);
241         }
242 
243         let mut result: $type = 0.0;
244         let mut radix = 10;
245 
246         let result_sign = match *s as u8 {
247             b'-' => {
248                 s = s.offset(1);
249                 -1.0
250             }
251             b'+' => {
252                 s = s.offset(1);
253                 1.0
254             }
255             _ => 1.0,
256         };
257 
258         if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
259             s = s.offset(2);
260             radix = 16;
261         }
262 
263         while let Some(digit) = (*s as u8 as char).to_digit(radix) {
264             result *= radix as $type;
265             result += digit as $type;
266             s = s.offset(1);
267         }
268 
269         if *s as u8 == b'.' {
270             s = s.offset(1);
271 
272             let mut i = 1.0;
273             while let Some(digit) = (*s as u8 as char).to_digit(radix) {
274                 i *= radix as $type;
275                 result += digit as $type / i;
276                 s = s.offset(1);
277             }
278         }
279 
280         let s_before_exponent = s;
281 
282         let exponent = match (*s as u8, radix) {
283             (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
284                 s = s.offset(1);
285 
286                 let is_exponent_positive = match *s as u8 {
287                     b'-' => {
288                         s = s.offset(1);
289                         false
290                     }
291                     b'+' => {
292                         s = s.offset(1);
293                         true
294                     }
295                     _ => true,
296                 };
297 
298                 // Exponent digits are always in base 10.
299                 if (*s as u8 as char).is_digit(10) {
300                     let mut exponent_value = 0;
301 
302                     while let Some(digit) = (*s as u8 as char).to_digit(10) {
303                         exponent_value *= 10;
304                         exponent_value += digit;
305                         s = s.offset(1);
306                     }
307 
308                     let exponent_base = match radix {
309                         10 => 10u128,
310                         16 => 2u128,
311                         _ => unreachable!(),
312                     };
313 
314                     if is_exponent_positive {
315                         Some(exponent_base.pow(exponent_value) as $type)
316                     } else {
317                         Some(1.0 / (exponent_base.pow(exponent_value) as $type))
318                     }
319                 } else {
320                     // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
321                     s = s_before_exponent;
322                     None
323                 }
324             }
325             _ => None,
326         };
327 
328         if !endptr.is_null() {
329             // This is stupid, but apparently strto* functions want
330             // const input but mut output, yet the man page says
331             // "stores the address of the first invalid character in *endptr"
332             // so obviously it doesn't want us to clone it.
333             *endptr = s as *mut _;
334         }
335 
336         if let Some(exponent) = exponent {
337             result_sign * result * exponent
338         } else {
339             result_sign * result
340         }
341     }};
342 }
343