macros.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /// Print to stdout
  2. #[macro_export]
  3. macro_rules! print {
  4. ($($arg:tt)*) => ({
  5. use core::fmt::Write;
  6. let _ = write!($crate::platform::FileWriter(1), $($arg)*);
  7. });
  8. }
  9. /// Print with new line to stdout
  10. #[macro_export]
  11. macro_rules! println {
  12. () => (print!("\n"));
  13. ($fmt:expr) => (print!(concat!($fmt, "\n")));
  14. ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
  15. }
  16. /// Print to stderr
  17. #[macro_export]
  18. macro_rules! eprint {
  19. ($($arg:tt)*) => ({
  20. use core::fmt::Write;
  21. let _ = write!($crate::platform::FileWriter(2), $($arg)*);
  22. });
  23. }
  24. /// Print with new line to stderr
  25. #[macro_export]
  26. macro_rules! eprintln {
  27. () => (eprint!("\n"));
  28. ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
  29. ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
  30. }
  31. #[macro_export]
  32. #[cfg(not(feature = "trace"))]
  33. macro_rules! trace {
  34. ($($arg:tt)*) => ();
  35. }
  36. #[macro_export]
  37. #[cfg(feature = "trace")]
  38. macro_rules! trace {
  39. ($($arg:tt)*) => (eprintln!($($arg)*));
  40. }
  41. #[macro_export]
  42. #[cfg(not(feature = "trace"))]
  43. macro_rules! trace_expr {
  44. ($expr:expr, $($arg:tt)*) => ($expr);
  45. }
  46. #[cfg(feature = "trace")]
  47. pub fn trace_error() -> (isize, &'static str) {
  48. use header::errno::STR_ERROR;
  49. let errno = unsafe { ::platform::errno } as isize;
  50. if errno >= 0 && errno < STR_ERROR.len() as isize {
  51. (errno, STR_ERROR[errno as usize])
  52. } else {
  53. (errno, "Unknown error")
  54. }
  55. }
  56. #[macro_export]
  57. #[cfg(feature = "trace")]
  58. macro_rules! trace_expr {
  59. ($expr:expr, $($arg:tt)*) => ({
  60. trace!("{}", format_args!($($arg)*));
  61. unsafe {
  62. ::platform::errno = 0;
  63. }
  64. let ret = $expr;
  65. trace!("{} = {} {:?}", format_args!($($arg)*), ret, $crate::macros::trace_error());
  66. ret
  67. });
  68. }
  69. #[macro_export]
  70. macro_rules! strto_impl {
  71. (
  72. $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
  73. ) => {{
  74. // ensure these are constants
  75. const CHECK_SIGN: bool = $signed;
  76. const MAX_VAL: $rettype = $maxval;
  77. const MIN_VAL: $rettype = $minval;
  78. let set_endptr = |idx: isize| {
  79. if !$endptr.is_null() {
  80. // This is stupid, but apparently strto* functions want
  81. // const input but mut output, yet the man page says
  82. // "stores the address of the first invalid character in *endptr"
  83. // so obviously it doesn't want us to clone it.
  84. *$endptr = $s.offset(idx) as *mut _;
  85. }
  86. };
  87. let invalid_input = || {
  88. platform::errno = EINVAL;
  89. set_endptr(0);
  90. };
  91. // only valid bases are 2 through 36
  92. if $base != 0 && ($base < 2 || $base > 36) {
  93. invalid_input();
  94. return 0;
  95. }
  96. let mut idx = 0;
  97. // skip any whitespace at the beginning of the string
  98. while ctype::isspace(*$s.offset(idx) as c_int) != 0 {
  99. idx += 1;
  100. }
  101. // check for +/-
  102. let positive = match is_positive(*$s.offset(idx)) {
  103. Some((pos, i)) => {
  104. idx += i;
  105. pos
  106. }
  107. None => {
  108. invalid_input();
  109. return 0;
  110. }
  111. };
  112. // convert the string to a number
  113. let num_str = $s.offset(idx);
  114. let res = match $base {
  115. 0 => detect_base(num_str)
  116. .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)),
  117. 8 => convert_octal(num_str),
  118. 16 => convert_hex(num_str),
  119. _ => convert_integer(num_str, $base),
  120. };
  121. // check for error parsing octal/hex prefix
  122. // also check to ensure a number was indeed parsed
  123. let (num, i, overflow) = match res {
  124. Some(res) => res,
  125. None => {
  126. invalid_input();
  127. return 0;
  128. }
  129. };
  130. idx += i;
  131. let overflow = if CHECK_SIGN {
  132. overflow || (num as c_long).is_negative()
  133. } else {
  134. overflow
  135. };
  136. // account for the sign
  137. let num = num as $rettype;
  138. let num = if overflow {
  139. platform::errno = ERANGE;
  140. if CHECK_SIGN {
  141. if positive {
  142. MAX_VAL
  143. } else {
  144. MIN_VAL
  145. }
  146. } else {
  147. MAX_VAL
  148. }
  149. } else {
  150. if positive {
  151. num
  152. } else {
  153. // not using -num to keep the compiler happy
  154. num.overflowing_neg().0
  155. }
  156. };
  157. set_endptr(idx);
  158. num
  159. }};
  160. }