stdio, string, platform: fix a bug in printf() involving chars
Because we were previously converting the bytes in the format string into Rust's char type and then printing that using the format machinery, byte values that were not valid single-byte UTF-8 characters failed to print correctly. I found this while trying to implement qsort() because the output of my test program was mysteriously incorrect despite it working when I used glibc.
This commit is contained in:
+13
-10
@@ -11,11 +11,12 @@ extern crate va_list as vl;
|
||||
|
||||
use core::str;
|
||||
use core::ptr;
|
||||
use core::fmt::{Error, Result, Write};
|
||||
use core::fmt::{self, Error, Result};
|
||||
use core::fmt::Write as WriteFmt;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use platform::types::*;
|
||||
use platform::{c_str, errno};
|
||||
use platform::{c_str, errno, Write};
|
||||
use errno::STR_ERROR;
|
||||
use vl::VaList as va_list;
|
||||
|
||||
@@ -164,7 +165,7 @@ impl FILE {
|
||||
unsafe { platform::lseek(self.fd, off, whence) }
|
||||
}
|
||||
}
|
||||
impl Write for FILE {
|
||||
impl fmt::Write for FILE {
|
||||
fn write_str(&mut self, s: &str) -> Result {
|
||||
let s = s.as_bytes();
|
||||
if self.write(s) != s.len() {
|
||||
@@ -174,6 +175,15 @@ impl Write for FILE {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Write for FILE {
|
||||
fn write_u8(&mut self, byte: u8) -> Result {
|
||||
if self.write(&[byte]) != 1 {
|
||||
Err(Error)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears EOF and ERR indicators on a stream
|
||||
#[no_mangle]
|
||||
@@ -872,10 +882,3 @@ pub unsafe extern "C" fn vsnprintf(
|
||||
pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
|
||||
printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
|
||||
}
|
||||
|
||||
/*
|
||||
#[no_mangle]
|
||||
pub extern "C" fn func(args) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
*/
|
||||
|
||||
+12
-16
@@ -1,19 +1,18 @@
|
||||
use core::{fmt, slice, str};
|
||||
|
||||
use platform::{self, Write};
|
||||
use platform::types::*;
|
||||
use vl::VaList;
|
||||
|
||||
pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
|
||||
extern "C" {
|
||||
fn strlen(s: *const c_char) -> size_t;
|
||||
}
|
||||
pub unsafe fn printf<W: Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
|
||||
let format = unsafe { slice::from_raw_parts(format as *const u8, usize::max_value()) };
|
||||
|
||||
let format = slice::from_raw_parts(format as *const u8, strlen(format));
|
||||
|
||||
let mut i = 0;
|
||||
let mut found_percent = false;
|
||||
while i < format.len() {
|
||||
let b = format[i];
|
||||
for &b in format.iter() {
|
||||
// check for NUL
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if found_percent {
|
||||
match b as char {
|
||||
@@ -24,7 +23,7 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
|
||||
'c' => {
|
||||
let a = ap.get::<u32>();
|
||||
|
||||
w.write_char(a as u8 as char);
|
||||
w.write_u8(a as u8);
|
||||
|
||||
found_percent = false;
|
||||
}
|
||||
@@ -57,9 +56,8 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
|
||||
's' => {
|
||||
let a = ap.get::<usize>();
|
||||
|
||||
w.write_str(str::from_utf8_unchecked(slice::from_raw_parts(
|
||||
a as *const u8,
|
||||
strlen(a as *const c_char),
|
||||
w.write_str(str::from_utf8_unchecked(platform::c_str(
|
||||
a as *const c_char,
|
||||
)));
|
||||
|
||||
found_percent = false;
|
||||
@@ -102,10 +100,8 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
|
||||
} else if b == b'%' {
|
||||
found_percent = true;
|
||||
} else {
|
||||
w.write_char(b as char);
|
||||
w.write_u8(b);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
Reference in New Issue
Block a user