macros.rs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. /// Print to stdout
  11. #[macro_export]
  12. macro_rules! print {
  13. ($($arg:tt)*) => ({
  14. use core::fmt::Write;
  15. let _ = write!($crate::platform::FileWriter(1), $($arg)*);
  16. });
  17. }
  18. /// Print with new line to stdout
  19. #[macro_export]
  20. macro_rules! println {
  21. () => (print!("\n"));
  22. ($fmt:expr) => (print!(concat!($fmt, "\n")));
  23. ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
  24. }
  25. /// Print to stderr
  26. #[macro_export]
  27. macro_rules! eprint {
  28. ($($arg:tt)*) => ({
  29. use core::fmt::Write;
  30. let _ = write!($crate::platform::FileWriter(2), $($arg)*);
  31. });
  32. }
  33. /// Print with new line to stderr
  34. #[macro_export]
  35. macro_rules! eprintln {
  36. () => (eprint!("\n"));
  37. ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
  38. ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
  39. }
  40. /// Lifted from libstd
  41. #[macro_export]
  42. macro_rules! dbg {
  43. () => {
  44. eprintln!("[{}:{}]", file!(), line!());
  45. };
  46. ($val:expr) => {
  47. // Use of `match` here is intentional because it affects the lifetimes
  48. // of temporaries - https://stackoverflow.com/a/48732525/1063961
  49. match $val {
  50. tmp => {
  51. eprintln!(
  52. "[{}:{}] {} = {:#?}",
  53. file!(),
  54. line!(),
  55. stringify!($val),
  56. &tmp
  57. );
  58. tmp
  59. }
  60. }
  61. };
  62. }
  63. #[macro_export]
  64. #[cfg(not(feature = "trace"))]
  65. macro_rules! trace {
  66. ($($arg:tt)*) => {};
  67. }
  68. #[macro_export]
  69. #[cfg(feature = "trace")]
  70. macro_rules! trace {
  71. ($($arg:tt)*) => ({
  72. use $crate::{Pal, Sys};
  73. eprintln!($($arg)*);
  74. Sys::fsync(2);
  75. });
  76. }
  77. #[macro_export]
  78. #[cfg(not(feature = "trace"))]
  79. macro_rules! trace_expr {
  80. ($expr:expr, $($arg:tt)*) => {
  81. $expr
  82. };
  83. }
  84. #[macro_export]
  85. #[cfg(feature = "trace")]
  86. macro_rules! trace_expr {
  87. ($expr:expr, $($arg:tt)*) => ({
  88. use $crate::header::errno::STR_ERROR;
  89. use $crate::platform;
  90. trace!("{}", format_args!($($arg)*));
  91. #[allow(unused_unsafe)]
  92. let trace_old_errno = unsafe { platform::errno };
  93. #[allow(unused_unsafe)]
  94. unsafe { platform::errno = 0; }
  95. let ret = $expr;
  96. #[allow(unused_unsafe)]
  97. let trace_errno = unsafe { platform::errno } as isize;
  98. if trace_errno == 0 {
  99. #[allow(unused_unsafe)]
  100. unsafe { platform::errno = trace_old_errno; }
  101. }
  102. let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize {
  103. STR_ERROR[trace_errno as usize]
  104. } else {
  105. "Unknown error"
  106. };
  107. trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
  108. ret
  109. });
  110. }
  111. #[macro_export]
  112. macro_rules! strto_impl {
  113. (
  114. $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
  115. ) => {{
  116. // ensure these are constants
  117. const CHECK_SIGN: bool = $signed;
  118. const MAX_VAL: $rettype = $maxval;
  119. const MIN_VAL: $rettype = $minval;
  120. let set_endptr = |idx: isize| {
  121. if !$endptr.is_null() {
  122. // This is stupid, but apparently strto* functions want
  123. // const input but mut output, yet the man page says
  124. // "stores the address of the first invalid character in *endptr"
  125. // so obviously it doesn't want us to clone it.
  126. *$endptr = $s.offset(idx) as *mut _;
  127. }
  128. };
  129. let invalid_input = || {
  130. platform::errno = EINVAL;
  131. set_endptr(0);
  132. };
  133. // only valid bases are 2 through 36
  134. if $base != 0 && ($base < 2 || $base > 36) {
  135. invalid_input();
  136. return 0;
  137. }
  138. let mut idx = 0;
  139. // skip any whitespace at the beginning of the string
  140. while ctype::isspace(*$s.offset(idx) as c_int) != 0 {
  141. idx += 1;
  142. }
  143. // check for +/-
  144. let positive = match is_positive(*$s.offset(idx)) {
  145. Some((pos, i)) => {
  146. idx += i;
  147. pos
  148. }
  149. None => {
  150. invalid_input();
  151. return 0;
  152. }
  153. };
  154. // convert the string to a number
  155. let num_str = $s.offset(idx);
  156. let res = match $base {
  157. 0 => detect_base(num_str)
  158. .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)),
  159. 8 => convert_octal(num_str),
  160. 16 => convert_hex(num_str),
  161. _ => convert_integer(num_str, $base),
  162. };
  163. // check for error parsing octal/hex prefix
  164. // also check to ensure a number was indeed parsed
  165. let (num, i, overflow) = match res {
  166. Some(res) => res,
  167. None => {
  168. invalid_input();
  169. return 0;
  170. }
  171. };
  172. idx += i;
  173. let overflow = if CHECK_SIGN {
  174. overflow || (num as c_long).is_negative()
  175. } else {
  176. overflow
  177. };
  178. // account for the sign
  179. let num = num as $rettype;
  180. let num = if overflow {
  181. platform::errno = ERANGE;
  182. if CHECK_SIGN {
  183. if positive {
  184. MAX_VAL
  185. } else {
  186. MIN_VAL
  187. }
  188. } else {
  189. MAX_VAL
  190. }
  191. } else {
  192. if positive {
  193. num
  194. } else {
  195. // not using -num to keep the compiler happy
  196. num.overflowing_neg().0
  197. }
  198. };
  199. set_endptr(idx);
  200. num
  201. }};
  202. }
  203. #[macro_export]
  204. macro_rules! strto_float_impl {
  205. ($type:ident, $s:expr, $endptr:expr) => {{
  206. let mut s = $s;
  207. let endptr = $endptr;
  208. while ctype::isspace(*s as c_int) != 0 {
  209. s = s.offset(1);
  210. }
  211. let mut result: $type = 0.0;
  212. let mut radix = 10;
  213. let negative = match *s as u8 {
  214. b'-' => {
  215. s = s.offset(1);
  216. true
  217. }
  218. b'+' => {
  219. s = s.offset(1);
  220. false
  221. }
  222. _ => false,
  223. };
  224. if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
  225. s = s.offset(2);
  226. radix = 16;
  227. }
  228. while let Some(digit) = (*s as u8 as char).to_digit(radix) {
  229. result *= radix as $type;
  230. result += digit as $type;
  231. s = s.offset(1);
  232. }
  233. if *s as u8 == b'.' {
  234. s = s.offset(1);
  235. let mut i = 1.0;
  236. while let Some(digit) = (*s as u8 as char).to_digit(radix) {
  237. i *= radix as $type;
  238. result += digit as $type / i;
  239. s = s.offset(1);
  240. }
  241. }
  242. if !endptr.is_null() {
  243. // This is stupid, but apparently strto* functions want
  244. // const input but mut output, yet the man page says
  245. // "stores the address of the first invalid character in *endptr"
  246. // so obviously it doesn't want us to clone it.
  247. *endptr = s as *mut _;
  248. }
  249. if negative {
  250. -result
  251. } else {
  252. result
  253. }
  254. }};
  255. }