Use unsafe blocks in stdio.h implementation

This commit is contained in:
sourceturner
2026-01-16 22:14:47 +01:00
committed by sourceturner
parent b3add24654
commit b3f7db83cf
4 changed files with 384 additions and 306 deletions
+17 -12
View File
@@ -1,5 +1,8 @@
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use alloc::{string::String, vec::Vec};
use core::{fmt::Write, intrinsics::unlikely, ops::Deref, ptr};
@@ -27,7 +30,7 @@ pub unsafe extern "C" fn getline(
n: *mut size_t,
stream: *mut FILE,
) -> ssize_t {
getdelim(lineptr, n, b'\n' as c_int, stream)
unsafe { getdelim(lineptr, n, b'\n' as c_int, stream) }
}
// One *could* read the standard as 'getdelim sets the stream error flag on *any* error, though
@@ -55,15 +58,17 @@ pub unsafe extern "C" fn getdelim(
delim: c_int,
stream: *mut FILE,
) -> ssize_t {
let (lineptr, n, stream) =
if let (Some(ptr), Some(n), Some(file)) = (lineptr.as_mut(), n.as_mut(), stream.as_mut()) {
(ptr, n, file)
} else {
ERRNO.set(EINVAL);
return -1 as ssize_t;
};
let (lineptr, n, stream) = if let (Some(ptr), Some(n), Some(file)) =
(unsafe { lineptr.as_mut() }, unsafe { n.as_mut() }, unsafe {
stream.as_mut()
}) {
(ptr, n, file)
} else {
ERRNO.set(EINVAL);
return -1 as ssize_t;
};
if feof(stream) != 0 || ferror(stream) != 0 {
if unsafe { feof(stream) } != 0 || unsafe { ferror(stream) } != 0 {
return -1 as ssize_t;
}
@@ -121,7 +126,7 @@ pub unsafe extern "C" fn getdelim(
*n = count + 1;
// The advantage in always realloc'ing is that even if the user supplies a wrong n, this
// doesn't break
*lineptr = stdlib::realloc(*lineptr as *mut c_void, *n) as *mut c_char;
*lineptr = unsafe { stdlib::realloc(*lineptr as *mut c_void, *n) } as *mut c_char;
if unlikely(lineptr.is_null() && *n != 0usize) {
// memory error; realloc returns NULL on alloc'ing 0 bytes
ERRNO.set(ENOMEM);
@@ -129,10 +134,10 @@ pub unsafe extern "C" fn getdelim(
}
// Copy buf to lineptr
ptr::copy(buf.as_ptr(), *lineptr as *mut u8, count);
unsafe { ptr::copy(buf.as_ptr(), *lineptr as *mut u8, count) };
// NUL terminate lineptr
*lineptr.offset(count as isize) = 0;
unsafe { *lineptr.offset(count as isize) = 0 };
// TODO remove
/*eprintln!(
+227 -193
View File
File diff suppressed because it is too large Load Diff
+102 -75
View File
@@ -1,3 +1,6 @@
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
// TODO: reuse more code with the wide printf impl
use crate::{
c_str::{self, CStr, NulStr},
@@ -59,11 +62,11 @@ impl Number {
pub(crate) unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize {
let arg = match self {
Number::Static(num) => return num,
Number::Index(i) => varargs.get(i - 1, ap, None),
Number::Index(i) => unsafe { varargs.get(i - 1, ap, None) },
Number::Next => {
let i = varargs.i;
varargs.i += 1;
varargs.get(i, ap, None)
unsafe { varargs.get(i, ap, None) }
}
};
match arg {
@@ -108,44 +111,44 @@ impl VaArg {
(FmtKind::Percent, _) => panic!("Can't call arg_from on %"),
(FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => {
VaArg::wint_t(ap.arg::<wint_t>())
VaArg::wint_t(unsafe { ap.arg::<wint_t>() })
}
(FmtKind::Char, _)
| (FmtKind::Unsigned, IntKind::Byte)
| (FmtKind::Signed, IntKind::Byte) => {
// c_int is passed but truncated to c_char
VaArg::c_char(ap.arg::<c_int>() as c_char)
VaArg::c_char(unsafe { ap.arg::<c_int>() } as c_char)
}
(FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => {
// c_int is passed but truncated to c_short
VaArg::c_short(ap.arg::<c_int>() as c_short)
VaArg::c_short(unsafe { ap.arg::<c_int>() } as c_short)
}
(FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => {
VaArg::c_int(ap.arg::<c_int>())
VaArg::c_int(unsafe { ap.arg::<c_int>() })
}
(FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => {
VaArg::c_long(ap.arg::<c_long>())
VaArg::c_long(unsafe { ap.arg::<c_long>() })
}
(FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => {
VaArg::c_longlong(ap.arg::<c_longlong>())
VaArg::c_longlong(unsafe { ap.arg::<c_longlong>() })
}
(FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => {
VaArg::intmax_t(ap.arg::<intmax_t>())
VaArg::intmax_t(unsafe { ap.arg::<intmax_t>() })
}
(FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => {
VaArg::ptrdiff_t(ap.arg::<ptrdiff_t>())
VaArg::ptrdiff_t(unsafe { ap.arg::<ptrdiff_t>() })
}
(FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => {
VaArg::ssize_t(ap.arg::<ssize_t>())
VaArg::ssize_t(unsafe { ap.arg::<ssize_t>() })
}
(FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => {
VaArg::c_double(ap.arg::<c_double>())
VaArg::c_double(unsafe { ap.arg::<c_double>() })
}
(FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => {
VaArg::pointer(ap.arg::<*const c_void>())
VaArg::pointer(unsafe { ap.arg::<*const c_void>() })
}
}
}
@@ -188,40 +191,40 @@ impl VaArg {
(FmtKind::Percent, _) => panic!("Can't call transmute on %"),
(FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => {
VaArg::wint_t(untyped.wint_t)
VaArg::wint_t(unsafe { untyped.wint_t })
}
(FmtKind::Char, _)
| (FmtKind::Unsigned, IntKind::Byte)
| (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char),
| (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(unsafe { untyped.c_char }),
(FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => {
VaArg::c_short(untyped.c_short)
VaArg::c_short(unsafe { untyped.c_short })
}
(FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => {
VaArg::c_int(untyped.c_int)
VaArg::c_int(unsafe { untyped.c_int })
}
(FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => {
VaArg::c_long(untyped.c_long)
VaArg::c_long(unsafe { untyped.c_long })
}
(FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => {
VaArg::c_longlong(untyped.c_longlong)
VaArg::c_longlong(unsafe { untyped.c_longlong })
}
(FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => {
VaArg::intmax_t(untyped.intmax_t)
VaArg::intmax_t(unsafe { untyped.intmax_t })
}
(FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => {
VaArg::ptrdiff_t(untyped.ptrdiff_t)
VaArg::ptrdiff_t(unsafe { untyped.ptrdiff_t })
}
(FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => {
VaArg::ssize_t(untyped.ssize_t)
VaArg::ssize_t(unsafe { untyped.ssize_t })
}
(FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => {
VaArg::c_double(untyped.c_double)
VaArg::c_double(unsafe { untyped.c_double })
}
(FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => {
VaArg::pointer(untyped.pointer)
VaArg::pointer(unsafe { untyped.pointer })
}
}
}
@@ -243,7 +246,7 @@ impl VaListCache {
let mut arg = arg;
if let Some((fmtkind, intkind)) = default {
// ...but as a different type
arg = arg.transmute(fmtkind, intkind);
arg = unsafe { arg.transmute(fmtkind, intkind) };
}
return arg;
}
@@ -254,13 +257,13 @@ impl VaListCache {
// point. Reaching here means there are unused gaps in the
// arguments. Ultimately we'll have to settle down with
// defaulting to c_int.
self.args.push(VaArg::c_int(ap.arg::<c_int>()))
self.args.push(VaArg::c_int(unsafe { ap.arg::<c_int>() }))
}
// Add the value to the cache
self.args.push(match default {
Some((fmtkind, intkind)) => VaArg::arg_from(fmtkind, intkind, ap),
None => VaArg::c_int(ap.arg::<c_int>()),
Some((fmtkind, intkind)) => unsafe { VaArg::arg_from(fmtkind, intkind, ap) },
None => VaArg::c_int(unsafe { ap.arg::<c_int>() }),
});
// Return the value
@@ -656,7 +659,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
}
for num in &[arg.min_width, arg.precision.unwrap_or(Number::Static(0))] {
match num {
Number::Next => varargs.args.push(VaArg::c_int(ap.arg::<c_int>())),
Number::Next => varargs
.args
.push(VaArg::c_int(unsafe { ap.arg::<c_int>() })),
Number::Index(i) => {
positional.insert(i - 1, (FmtKind::Signed, IntKind::Int));
}
@@ -669,13 +674,13 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
}
None => varargs
.args
.push(VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap)),
.push(unsafe { VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap) }),
}
}
// Make sure, in order, the positional arguments exist with the specified type
for (i, arg) in positional {
varargs.get(i, &mut ap, Some(arg));
unsafe { varargs.get(i, &mut ap, Some(arg)) };
}
// Main loop
@@ -701,10 +706,10 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
let mut left = arg.left;
let sign_reserve = arg.sign_reserve;
let sign_always = arg.sign_always;
let min_width = arg.min_width.resolve(&mut varargs, &mut ap);
let min_width = unsafe { arg.min_width.resolve(&mut varargs, &mut ap) };
let precision = arg
.precision
.map(|n| n.resolve(&mut varargs, &mut ap))
.map(|n| unsafe { n.resolve(&mut varargs, &mut ap) })
.filter(|&n| (n as c_int) >= 0);
let pad_zero = if zero { min_width } else { 0 };
let signed_space = match pad_zero {
@@ -741,7 +746,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
match fmtkind {
FmtKind::Percent => w.write_all(&[b'%'])?,
FmtKind::Signed => {
let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let string = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::c_char(i) => i.to_string(),
VaArg::c_double(i) => panic!("this should not be possible"),
VaArg::c_int(i) => i.to_string(),
@@ -789,7 +796,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
pad(w, left, b' ', final_len..pad_space)?;
}
FmtKind::Unsigned => {
let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let string = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::c_char(i) => fmt_int::<_, T>(fmt, i as c_uchar),
VaArg::c_double(i) => panic!("this should not be possible"),
VaArg::c_int(i) => fmt_int::<_, T>(fmt, i as c_uint),
@@ -848,7 +857,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
pad(w, left, b' ', final_len..pad_space)?;
}
FmtKind::Scientific => {
let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let float = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::c_double(i) => i,
_ => panic!("this should not be possible"),
};
@@ -864,7 +875,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
}
}
FmtKind::Decimal => {
let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let float = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::c_double(i) => i,
_ => panic!("this should not be possible"),
};
@@ -877,7 +890,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
}
}
FmtKind::AnyNotation => {
let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let float = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::c_double(i) => i,
_ => panic!("this should not be possible"),
};
@@ -909,7 +924,9 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
}
}
FmtKind::String => {
let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let ptr = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::pointer(p) => p,
_ => panic!("this should not be possible"),
} as *const c_char;
@@ -924,8 +941,8 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
let mut ptr = ptr as *const wchar_t;
let mut string = String::new();
while *ptr != 0 {
let c = match char::from_u32(*ptr as _) {
while unsafe { *ptr } != 0 {
let c = match char::from_u32(unsafe { *ptr } as _) {
Some(c) => c,
None => {
platform::ERRNO.set(EILSEQ);
@@ -936,7 +953,7 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
break;
}
string.push(c);
ptr = ptr.add(1);
ptr = unsafe { ptr.add(1) };
}
pad(w, !left, b' ', string.len()..pad_space)?;
@@ -944,40 +961,44 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
pad(w, left, b' ', string.len()..pad_space)?;
} else {
let mut len = 0;
while *ptr.add(len) != 0 && len < max {
while unsafe { *ptr.add(len) } != 0 && len < max {
len += 1;
}
pad(w, !left, b' ', len..pad_space)?;
w.write_all(slice::from_raw_parts(ptr as *const u8, len))?;
w.write_all(unsafe { slice::from_raw_parts(ptr as *const u8, len) })?;
pad(w, left, b' ', len..pad_space)?;
}
}
}
FmtKind::Char => match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
VaArg::c_char(c) => {
pad(w, !left, b' ', 1..pad_space)?;
w.write_all(&[c as u8])?;
pad(w, left, b' ', 1..pad_space)?;
}
VaArg::wint_t(c) => {
let c = match char::from_u32(c as _) {
Some(c) => c,
None => {
platform::ERRNO.set(EILSEQ);
return Err(io::last_os_error());
}
};
let mut buf = [0; 4];
FmtKind::Char => {
match unsafe { varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) } {
VaArg::c_char(c) => {
pad(w, !left, b' ', 1..pad_space)?;
w.write_all(&[c as u8])?;
pad(w, left, b' ', 1..pad_space)?;
}
VaArg::wint_t(c) => {
let c = match char::from_u32(c as _) {
Some(c) => c,
None => {
platform::ERRNO.set(EILSEQ);
return Err(io::last_os_error());
}
};
let mut buf = [0; 4];
pad(w, !left, b' ', 1..pad_space)?;
w.write_all(c.encode_utf8(&mut buf).as_bytes())?;
pad(w, left, b' ', 1..pad_space)?;
pad(w, !left, b' ', 1..pad_space)?;
w.write_all(c.encode_utf8(&mut buf).as_bytes())?;
pad(w, left, b' ', 1..pad_space)?;
}
_ => unreachable!("this should not be possible"),
}
_ => unreachable!("this should not be possible"),
},
}
FmtKind::Pointer => {
let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let ptr = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::pointer(p) => p,
_ => panic!("this should not be possible"),
};
@@ -1002,20 +1023,26 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
pad(w, left, b' ', len..pad_space)?;
}
FmtKind::GetWritten => {
let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) {
let ptr = match unsafe {
varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind)))
} {
VaArg::pointer(p) => p,
_ => panic!("this should not be possible"),
};
match intkind {
IntKind::Byte => *(ptr as *mut c_char) = w.written as c_char,
IntKind::Short => *(ptr as *mut c_short) = w.written as c_short,
IntKind::Int => *(ptr as *mut c_int) = w.written as c_int,
IntKind::Long => *(ptr as *mut c_long) = w.written as c_long,
IntKind::LongLong => *(ptr as *mut c_longlong) = w.written as c_longlong,
IntKind::IntMax => *(ptr as *mut intmax_t) = w.written as intmax_t,
IntKind::PtrDiff => *(ptr as *mut ptrdiff_t) = w.written as ptrdiff_t,
IntKind::Size => *(ptr as *mut size_t) = w.written as size_t,
IntKind::Byte => unsafe { *(ptr as *mut c_char) = w.written as c_char },
IntKind::Short => unsafe { *(ptr as *mut c_short) = w.written as c_short },
IntKind::Int => unsafe { *(ptr as *mut c_int) = w.written as c_int },
IntKind::Long => unsafe { *(ptr as *mut c_long) = w.written as c_long },
IntKind::LongLong => unsafe {
*(ptr as *mut c_longlong) = w.written as c_longlong
},
IntKind::IntMax => unsafe { *(ptr as *mut intmax_t) = w.written as intmax_t },
IntKind::PtrDiff => unsafe {
*(ptr as *mut ptrdiff_t) = w.written as ptrdiff_t
},
IntKind::Size => unsafe { *(ptr as *mut size_t) = w.written as size_t },
}
}
}
@@ -1292,5 +1319,5 @@ pub(crate) unsafe fn inner_printf<T: c_str::Kind>(
/// Behavior is undefined if any of the following conditions are violated:
/// - `ap` must follow the safety contract of variable arguments of C.
pub unsafe fn printf(w: impl Write, format: CStr, ap: VaList) -> c_int {
inner_printf::<c_str::Thin>(w, format, ap).unwrap_or(-1)
unsafe { inner_printf::<c_str::Thin>(w, format, ap).unwrap_or(-1) }
}
+38 -26
View File
@@ -17,8 +17,8 @@ enum IntKind {
/// 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);
let c = unsafe { **string } as u8;
*string = unsafe { string.offset(1) };
if c == 0 { Err(-1) } else { Ok(c) }
}
@@ -67,8 +67,8 @@ unsafe fn inner_scanf(
}
}
while *format != 0 {
let mut c = next_byte(&mut format)?;
while unsafe { *format } != 0 {
let mut c = unsafe { next_byte(&mut format) }?;
if c == b' ' {
maybe_read!(noreset);
@@ -87,18 +87,18 @@ unsafe fn inner_scanf(
}
r.commit();
} else {
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
let mut ignore = false;
if c == b'*' {
ignore = true;
c = next_byte(&mut format)?;
c = unsafe { 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)?;
c = unsafe { next_byte(&mut format) }?;
}
let mut width = if width.is_empty() {
None
@@ -137,7 +137,7 @@ unsafe fn inner_scanf(
_ => break,
};
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
}
if c != b'n' {
@@ -231,7 +231,7 @@ unsafe fn inner_scanf(
n.parse::<$type>().map_err(|_| 0)?
};
if !ignore {
*ap.arg::<*mut $type>() = n;
unsafe { *ap.arg::<*mut $type>() = n };
matched += 1;
}
}};
@@ -251,7 +251,7 @@ unsafe fn inner_scanf(
$type::from_str_radix(&n, radix).map_err(|_| 0)?
};
if !ignore {
*ap.arg::<*mut $final>() = n as $final;
unsafe { *ap.arg::<*mut $final>() = n as $final};
matched += 1;
}
}};
@@ -329,12 +329,16 @@ unsafe fn inner_scanf(
}
}
let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
let mut ptr: Option<*mut c_char> = if ignore {
None
} else {
Some(unsafe { ap.arg() })
};
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);
unsafe { **ptr = byte as c_char };
*ptr = unsafe { ptr.offset(1) };
}
width = width.map(|w| w - 1);
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
@@ -344,17 +348,21 @@ unsafe fn inner_scanf(
}
if let Some(ptr) = ptr {
*ptr = 0;
unsafe { *ptr = 0 };
matched += 1;
r.commit();
}
}
b'c' => {
let ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
let ptr: Option<*mut c_char> = if ignore {
None
} else {
Some(unsafe { ap.arg() })
};
for i in 0..width.unwrap_or(1) {
if let Some(ptr) = ptr {
*ptr.add(i) = byte as c_char;
unsafe { *ptr.add(i) = byte as c_char };
}
width = width.map(|w| w - 1);
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
@@ -369,11 +377,11 @@ unsafe fn inner_scanf(
}
}
b'[' => {
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
let mut matches = Vec::new();
let invert = if c == b'^' {
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
true
} else {
false
@@ -383,12 +391,12 @@ unsafe fn inner_scanf(
loop {
matches.push(c);
prev = c;
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
if c == b'-' {
if prev == b']' {
continue;
}
c = next_byte(&mut format)?;
c = unsafe { next_byte(&mut format) }?;
if c == b']' {
matches.push(b'-');
break;
@@ -403,15 +411,19 @@ unsafe fn inner_scanf(
}
}
let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
let mut ptr: Option<*mut c_char> = if ignore {
None
} else {
Some(unsafe { ap.arg() })
};
// While we haven't used up all the width, and it matches
let mut data_stored = false;
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);
unsafe { **ptr = byte as c_char };
*ptr = unsafe { ptr.offset(1) };
data_stored = true;
}
r.commit();
@@ -426,13 +438,13 @@ unsafe fn inner_scanf(
}
if data_stored {
*ptr.unwrap() = 0;
unsafe { *ptr.unwrap() = 0 };
matched += 1;
}
}
b'n' => {
if !ignore {
*ap.arg::<*mut c_int>() = count as c_int;
unsafe { *ap.arg::<*mut c_int>() = count as c_int };
}
}
_ => return Err(-1),
@@ -453,7 +465,7 @@ unsafe fn inner_scanf(
}
pub unsafe fn scanf(r: LookAheadReader, format: *const c_char, ap: va_list) -> c_int {
match inner_scanf(r, format, ap) {
match unsafe { inner_scanf(r, format, ap) } {
Ok(n) => n,
Err(n) => n,
}