| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 | use alloc::String;use alloc::Vec;use platform::types::*;use platform::Read;use va_list::VaList;#[derive(PartialEq, Eq)]enum IntKind {    Byte,    Short,    Int,    Long,    LongLong,    IntMax,    PtrDiff,    Size,}/// Helper function for progressing a C stringunsafe 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 {        () => {{            match r.read_u8() {                Ok(Some(b)) => {                    byte = b;                    count += 1;                    true                },                Ok(None) => false,                Err(()) => return Err(-1)            }        }};    }    macro_rules! maybe_read {        () => {            maybe_read!(inner false);        };        (noreset) => {            maybe_read!(inner);        };        (inner $($placeholder:expr)*) => {            if !skip_read {                if !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 {                        IntKind::Byte                    } else {                        IntKind::Short                    },                    b'j' => IntKind::IntMax,                    b'l' => 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) {                                    if !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) {                            if !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) {                            if !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.offset(i as isize) = byte as c_char;                        }                        width = width.map(|w| w - 1);                        if width.map(|w| w > 0).unwrap_or(true) {                            if !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) {                            if !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,    }}
 |