macros.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. });
  75. }
  76. #[macro_export]
  77. #[cfg(not(feature = "trace"))]
  78. macro_rules! trace_expr {
  79. ($expr:expr, $($arg:tt)*) => {
  80. $expr
  81. };
  82. }
  83. #[macro_export]
  84. #[cfg(feature = "trace")]
  85. macro_rules! trace_expr {
  86. ($expr:expr, $($arg:tt)*) => ({
  87. use $crate::header::errno::STR_ERROR;
  88. use $crate::platform;
  89. trace!("{}", format_args!($($arg)*));
  90. #[allow(unused_unsafe)]
  91. let trace_old_errno = unsafe { platform::errno };
  92. #[allow(unused_unsafe)]
  93. unsafe { platform::errno = 0; }
  94. let ret = $expr;
  95. #[allow(unused_unsafe)]
  96. let trace_errno = unsafe { platform::errno } as isize;
  97. if trace_errno == 0 {
  98. #[allow(unused_unsafe)]
  99. unsafe { platform::errno = trace_old_errno; }
  100. }
  101. let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize {
  102. STR_ERROR[trace_errno as usize]
  103. } else {
  104. "Unknown error"
  105. };
  106. trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
  107. ret
  108. });
  109. }
  110. #[macro_export]
  111. macro_rules! strto_impl {
  112. (
  113. $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
  114. ) => {{
  115. // ensure these are constants
  116. const CHECK_SIGN: bool = $signed;
  117. const MAX_VAL: $rettype = $maxval;
  118. const MIN_VAL: $rettype = $minval;
  119. let set_endptr = |idx: isize| {
  120. if !$endptr.is_null() {
  121. // This is stupid, but apparently strto* functions want
  122. // const input but mut output, yet the man page says
  123. // "stores the address of the first invalid character in *endptr"
  124. // so obviously it doesn't want us to clone it.
  125. *$endptr = $s.offset(idx) as *mut _;
  126. }
  127. };
  128. let invalid_input = || {
  129. platform::errno = EINVAL;
  130. set_endptr(0);
  131. };
  132. // only valid bases are 2 through 36
  133. if $base != 0 && ($base < 2 || $base > 36) {
  134. invalid_input();
  135. return 0;
  136. }
  137. let mut idx = 0;
  138. // skip any whitespace at the beginning of the string
  139. while ctype::isspace(*$s.offset(idx) as c_int) != 0 {
  140. idx += 1;
  141. }
  142. // check for +/-
  143. let positive = match is_positive(*$s.offset(idx)) {
  144. Some((pos, i)) => {
  145. idx += i;
  146. pos
  147. }
  148. None => {
  149. invalid_input();
  150. return 0;
  151. }
  152. };
  153. // convert the string to a number
  154. let num_str = $s.offset(idx);
  155. let res = match $base {
  156. 0 => detect_base(num_str)
  157. .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)),
  158. 8 => convert_octal(num_str),
  159. 16 => convert_hex(num_str),
  160. _ => convert_integer(num_str, $base),
  161. };
  162. // check for error parsing octal/hex prefix
  163. // also check to ensure a number was indeed parsed
  164. let (num, i, overflow) = match res {
  165. Some(res) => res,
  166. None => {
  167. invalid_input();
  168. return 0;
  169. }
  170. };
  171. idx += i;
  172. let overflow = if CHECK_SIGN {
  173. overflow || (num as c_long).is_negative()
  174. } else {
  175. overflow
  176. };
  177. // account for the sign
  178. let num = num as $rettype;
  179. let num = if overflow {
  180. platform::errno = ERANGE;
  181. if CHECK_SIGN {
  182. if positive {
  183. MAX_VAL
  184. } else {
  185. MIN_VAL
  186. }
  187. } else {
  188. MAX_VAL
  189. }
  190. } else {
  191. if positive {
  192. num
  193. } else {
  194. // not using -num to keep the compiler happy
  195. num.overflowing_neg().0
  196. }
  197. };
  198. set_endptr(idx);
  199. num
  200. }};
  201. }
  202. #[macro_export]
  203. macro_rules! strto_float_impl {
  204. ($type:ident, $s:expr, $endptr:expr) => {{
  205. let mut s = $s;
  206. let endptr = $endptr;
  207. // TODO: Handle named floats: NaN, Inf...
  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 result_sign = match *s as u8 {
  214. b'-' => {
  215. s = s.offset(1);
  216. -1.0
  217. }
  218. b'+' => {
  219. s = s.offset(1);
  220. 1.0
  221. }
  222. _ => 1.0,
  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. let s_before_exponent = s;
  243. let exponent = match (*s as u8, radix) {
  244. (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
  245. s = s.offset(1);
  246. let is_exponent_positive = match *s as u8 {
  247. b'-' => {
  248. s = s.offset(1);
  249. false
  250. }
  251. b'+' => {
  252. s = s.offset(1);
  253. true
  254. }
  255. _ => true,
  256. };
  257. // Exponent digits are always in base 10.
  258. if (*s as u8 as char).is_digit(10) {
  259. let mut exponent_value = 0;
  260. while let Some(digit) = (*s as u8 as char).to_digit(10) {
  261. exponent_value *= 10;
  262. exponent_value += digit;
  263. s = s.offset(1);
  264. }
  265. let exponent_base = match radix {
  266. 10 => 10u128,
  267. 16 => 2u128,
  268. _ => unreachable!(),
  269. };
  270. if is_exponent_positive {
  271. Some(exponent_base.pow(exponent_value) as $type)
  272. } else {
  273. Some(1.0 / (exponent_base.pow(exponent_value) as $type))
  274. }
  275. } else {
  276. // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
  277. s = s_before_exponent;
  278. None
  279. }
  280. }
  281. _ => None,
  282. };
  283. if !endptr.is_null() {
  284. // This is stupid, but apparently strto* functions want
  285. // const input but mut output, yet the man page says
  286. // "stores the address of the first invalid character in *endptr"
  287. // so obviously it doesn't want us to clone it.
  288. *endptr = s as *mut _;
  289. }
  290. if let Some(exponent) = exponent {
  291. result_sign * result * exponent
  292. } else {
  293. result_sign * result
  294. }
  295. }};
  296. }