macros.rs 6.7 KB

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