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