123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- use alloc::string::String;
- use alloc::vec::Vec;
- use io::Read;
- use platform::types::*;
- use va_list::VaList;
- #[derive(PartialEq, Eq)]
- enum IntKind {
- Byte,
- Short,
- Int,
- Long,
- LongLong,
- IntMax,
- PtrDiff,
- Size,
- }
- /// Helper function for progressing a C string
- unsafe fn next_byte(string: &mut *const c_char) -> Result<u8, c_int> {
- let c = **string as u8;
- *string = string.offset(1);
- if c == 0 {
- Err(-1)
- } else {
- Ok(c)
- }
- }
- unsafe fn inner_scanf<R: Read>(
- mut r: R,
- mut format: *const c_char,
- mut ap: VaList,
- ) -> Result<c_int, c_int> {
- let mut matched = 0;
- let mut byte = 0;
- let mut skip_read = false;
- let mut count = 0;
- macro_rules! read {
- () => {{
- let buf = &mut [byte];
- match r.read(buf) {
- Ok(0) => false,
- Ok(_) => {
- byte = buf[0];
- count += 1;
- true
- }
- Err(_) => return Err(-1),
- }
- }};
- }
- macro_rules! maybe_read {
- () => {
- maybe_read!(inner false);
- };
- (noreset) => {
- maybe_read!(inner);
- };
- (inner $($placeholder:expr)*) => {
- if !skip_read && !read!() {
- return Ok(matched);
- }
- $(else {
- // Hacky way of having this optional
- skip_read = $placeholder;
- })*
- }
- }
- while *format != 0 {
- let mut c = *format as u8;
- format = format.offset(1);
- if c == b' ' {
- maybe_read!(noreset);
- while (byte as char).is_whitespace() {
- if !read!() {
- return Ok(matched);
- }
- }
- skip_read = true;
- } else if c != b'%' {
- maybe_read!();
- if c != byte {
- return Ok(matched);
- }
- } else {
- c = next_byte(&mut format)?;
- let mut ignore = false;
- if c == b'*' {
- ignore = true;
- c = next_byte(&mut format)?;
- }
- let mut width = String::new();
- while c >= b'0' && c <= b'9' {
- width.push(c as char);
- c = next_byte(&mut format)?;
- }
- let mut width = if width.is_empty() {
- None
- } else {
- match width.parse::<usize>() {
- Ok(n) => Some(n),
- Err(_) => return Err(-1),
- }
- };
- let mut kind = IntKind::Int;
- loop {
- kind = match c {
- b'h' => {
- if kind == IntKind::Short || kind == IntKind::Byte {
- IntKind::Byte
- } else {
- IntKind::Short
- }
- }
- b'j' => IntKind::IntMax,
- b'l' => {
- if kind == IntKind::Long || kind == IntKind::LongLong {
- IntKind::LongLong
- } else {
- IntKind::Long
- }
- }
- b'q' | b'L' => IntKind::LongLong,
- b't' => IntKind::PtrDiff,
- b'z' => IntKind::Size,
- _ => break,
- };
- c = next_byte(&mut format)?;
- }
- if c != b'n' {
- maybe_read!(noreset);
- }
- match c {
- b'%' => {
- while (byte as char).is_whitespace() {
- if !read!() {
- return Ok(matched);
- }
- }
- if byte != b'%' {
- return Err(matched);
- } else if !read!() {
- return Ok(matched);
- }
- }
- b'd' | b'i' | b'o' | b'u' | b'x' | b'X' | b'f' | b'e' | b'g' | b'E' | b'a'
- | b'p' => {
- while (byte as char).is_whitespace() {
- if !read!() {
- return Ok(matched);
- }
- }
- let pointer = c == b'p';
- // Pointers aren't automatic, but we do want to parse "0x"
- let auto = c == b'i' || pointer;
- let float = c == b'f' || c == b'e' || c == b'g' || c == b'E' || c == b'a';
- let mut radix = match c {
- b'o' => 8,
- b'x' | b'X' | b'p' => 16,
- _ => 10,
- };
- let mut n = String::new();
- let mut dot = false;
- while width.map(|w| w > 0).unwrap_or(true)
- && ((byte >= b'0' && byte <= b'7')
- || (radix >= 10 && (byte >= b'8' && byte <= b'9'))
- || (float && !dot && byte == b'.')
- || (radix == 16
- && ((byte >= b'a' && byte <= b'f')
- || (byte >= b'A' && byte <= b'F'))))
- {
- if auto
- && n.is_empty()
- && byte == b'0'
- && width.map(|w| w > 0).unwrap_or(true)
- {
- if !pointer {
- radix = 8;
- }
- width = width.map(|w| w - 1);
- if !read!() {
- break;
- }
- if width.map(|w| w > 0).unwrap_or(true)
- && (byte == b'x' || byte == b'X')
- {
- radix = 16;
- width = width.map(|w| w - 1);
- if width.map(|w| w > 0).unwrap_or(true) && !read!() {
- break;
- }
- }
- continue;
- }
- if byte == b'.' {
- // Don't allow another dot
- dot = true;
- }
- n.push(byte as char);
- width = width.map(|w| w - 1);
- if width.map(|w| w > 0).unwrap_or(true) && !read!() {
- break;
- }
- }
- macro_rules! parse_type {
- (noformat $type:ident) => {{
- let n = if n.is_empty() {
- 0 as $type
- } else {
- n.parse::<$type>().map_err(|_| 0)?
- };
- if !ignore {
- *ap.get::<*mut $type>() = n;
- matched += 1;
- }
- }};
- (c_double) => {
- parse_type!(noformat c_double);
- };
- (c_float) => {
- parse_type!(noformat c_float);
- };
- ($type:ident) => {
- parse_type!($type, $type);
- };
- ($type:ident, $final:ty) => {{
- let n = if n.is_empty() {
- 0 as $type
- } else {
- $type::from_str_radix(&n, radix).map_err(|_| 0)?
- };
- if !ignore {
- *ap.get::<*mut $final>() = n as $final;
- matched += 1;
- }
- }};
- }
- if float {
- if kind == IntKind::Long || kind == IntKind::LongLong {
- parse_type!(c_double);
- } else {
- parse_type!(c_float);
- }
- } else if c == b'p' {
- parse_type!(size_t, *mut c_void);
- } else {
- let unsigned = c == b'o' || c == b'u' || c == b'x' || c == b'X';
- match kind {
- IntKind::Byte => {
- if unsigned {
- parse_type!(c_uchar);
- } else {
- parse_type!(c_char);
- }
- }
- IntKind::Short => {
- if unsigned {
- parse_type!(c_ushort)
- } else {
- parse_type!(c_short)
- }
- }
- IntKind::Int => {
- if unsigned {
- parse_type!(c_uint)
- } else {
- parse_type!(c_int)
- }
- }
- IntKind::Long => {
- if unsigned {
- parse_type!(c_ulong)
- } else {
- parse_type!(c_long)
- }
- }
- IntKind::LongLong => {
- if unsigned {
- parse_type!(c_ulonglong)
- } else {
- parse_type!(c_longlong)
- }
- }
- IntKind::IntMax => {
- if unsigned {
- parse_type!(uintmax_t)
- } else {
- parse_type!(intmax_t)
- }
- }
- IntKind::PtrDiff => parse_type!(ptrdiff_t),
- IntKind::Size => {
- if unsigned {
- parse_type!(size_t)
- } else {
- parse_type!(ssize_t)
- }
- }
- }
- }
- }
- b's' => {
- while (byte as char).is_whitespace() {
- if !read!() {
- return Ok(matched);
- }
- }
- let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.get()) };
- while width.map(|w| w > 0).unwrap_or(true) && !(byte as char).is_whitespace() {
- if let Some(ref mut ptr) = ptr {
- **ptr = byte as c_char;
- *ptr = ptr.offset(1);
- }
- width = width.map(|w| w - 1);
- if width.map(|w| w > 0).unwrap_or(true) && !read!() {
- break;
- }
- }
- if let Some(ptr) = ptr {
- *ptr = 0;
- matched += 1;
- }
- }
- b'c' => {
- let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.get()) };
- for i in 0..width.unwrap_or(1) {
- if let Some(ptr) = ptr {
- *ptr.add(i) = byte as c_char;
- }
- width = width.map(|w| w - 1);
- if width.map(|w| w > 0).unwrap_or(true) && !read!() {
- break;
- }
- }
- if ptr.is_some() {
- matched += 1;
- }
- }
- b'[' => {
- c = next_byte(&mut format)?;
- let mut matches = Vec::new();
- let mut invert = false;
- if c == b'^' {
- c = next_byte(&mut format)?;
- invert = true;
- }
- let mut prev;
- loop {
- matches.push(c);
- prev = c;
- c = next_byte(&mut format)?;
- if c == b'-' {
- if prev == b']' {
- continue;
- }
- c = next_byte(&mut format)?;
- if c == b']' {
- matches.push(b'-');
- break;
- }
- prev += 1;
- while prev < c {
- matches.push(prev);
- prev += 1;
- }
- } else if c == b']' {
- break;
- }
- }
- let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.get()) };
- while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte)
- {
- if let Some(ref mut ptr) = ptr {
- **ptr = byte as c_char;
- *ptr = ptr.offset(1);
- }
- width = width.map(|w| w - 1);
- if width.map(|w| w > 0).unwrap_or(true) && !read!() {
- break;
- }
- }
- if let Some(ptr) = ptr {
- *ptr = 0;
- matched += 1;
- }
- }
- b'n' => {
- if !ignore {
- *ap.get::<*mut c_int>() = count as c_int;
- }
- }
- _ => return Err(-1),
- }
- if width != Some(0) && c != b'n' {
- // It didn't hit the width, so an extra character was read and matched.
- // But this character did not match so let's reuse it.
- skip_read = true;
- }
- }
- }
- Ok(matched)
- }
- pub unsafe fn scanf<R: Read>(r: R, format: *const c_char, ap: VaList) -> c_int {
- match inner_scanf(r, format, ap) {
- Ok(n) => n,
- Err(n) => n,
- }
- }
|