diff --git a/src/c_vec.rs b/src/c_vec.rs index 1a335cce02cd026eb6ea63ab680249ed7230b61b..fea7aeffff73a8999b1beca1d5b52bd1ebbfc32c 100644 --- a/src/c_vec.rs +++ b/src/c_vec.rs @@ -1,6 +1,10 @@ -use crate::platform::{self, types::*}; +use crate::{ + io::{self, Write}, + platform::{self, WriteByte, types::*}, +}; use core::{ cmp, + fmt, iter::IntoIterator, mem, ops::{Deref, DerefMut}, @@ -67,6 +71,9 @@ impl<T> CVec<T> { start = start.add(1); } } + + // Push stuff + pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> { let reserved_len = self .len @@ -82,8 +89,8 @@ impl<T> CVec<T> { Ok(()) } pub fn push(&mut self, elem: T) -> Result<(), AllocError> { + self.reserve(1)?; unsafe { - self.reserve(1)?; ptr::write(self.ptr.as_ptr().add(self.len), elem); } self.len += 1; // no need to bounds check, as new len <= cap @@ -93,21 +100,26 @@ impl<T> CVec<T> { where T: Copy, { + self.reserve(elems.len())?; unsafe { - self.reserve(elems.len())?; ptr::copy_nonoverlapping(elems.as_ptr(), self.ptr.as_ptr().add(self.len), elems.len()); } self.len += elems.len(); // no need to bounds check, as new len <= cap Ok(()) } pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> { + let len = other.len; + other.len = 0; // move + self.reserve(len)?; unsafe { - self.reserve(other.len())?; - ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), other.len()); + ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), len); } self.len += other.len(); // no need to bounds check, as new len <= cap Ok(()) } + + // Pop stuff + pub fn truncate(&mut self, len: usize) { if len < self.len { unsafe { @@ -126,6 +138,18 @@ impl<T> CVec<T> { } Ok(()) } + pub fn pop(&mut self) -> Option<T> { + if self.is_empty() { + None + } else { + let elem = unsafe { ptr::read(self.as_ptr().add(self.len - 1)) }; + self.len -= 1; + Some(elem) + } + } + + // Misc stuff + pub fn capacity(&self) -> usize { self.cap } @@ -176,3 +200,28 @@ impl<'a, T> IntoIterator for &'a mut CVec<T> { <&mut [T]>::into_iter(&mut *self) } } + +impl Write for CVec<u8> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.extend_from_slice(buf).map_err(|err| io::Error::new( + io::ErrorKind::Other, + "AllocStringWriter::write failed to allocate", + ))?; + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} +impl fmt::Write for CVec<u8> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write(s.as_bytes()).map_err(|_| fmt::Error)?; + Ok(()) + } +} +impl WriteByte for CVec<u8> { + fn write_u8(&mut self, byte: u8) -> fmt::Result { + self.write(&[byte]).map_err(|_| fmt::Error)?; + Ok(()) + } +} diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 2b22cf4ac57a29698309c9e228cb202b028046ba..7693cd2157255e5cce08876fbaa9f5b9f4ea907d 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -16,6 +16,7 @@ use core::{ use crate::{ c_str::CStr, + c_vec::CVec, fs::File, header::{ errno::{self, STR_ERROR}, @@ -1021,9 +1022,11 @@ pub unsafe extern "C" fn vasprintf( format: *const c_char, ap: va_list, ) -> c_int { - let mut alloc_writer = platform::AllocStringWriter(ptr::null_mut(), 0); + let mut alloc_writer = CVec::new(); let ret = printf::printf(&mut alloc_writer, format, ap); - *strp = alloc_writer.0 as *mut c_char; + alloc_writer.push(0).unwrap(); + alloc_writer.shrink_to_fit().unwrap(); + *strp = alloc_writer.leak() as *mut c_char; ret } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 5b63f1a997aa3cceca47d8fb54fdc373bf62fa5b..3978625e4f991ee2197ecb2a3746a9118cf4d8d3 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -104,45 +104,6 @@ impl Read for FileReader { } } -pub struct AllocStringWriter(pub *mut u8, pub usize); -impl Write for AllocStringWriter { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let ptr = unsafe { realloc(self.0 as *mut c_void, self.1 + buf.len() + 1) as *mut u8 }; - if ptr.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "AllocStringWriter::write failed to allocate", - )); - } - self.0 = ptr; - - unsafe { - ptr::copy_nonoverlapping(buf.as_ptr(), self.0.add(self.1), buf.len()); - self.1 += buf.len(); - *self.0.add(self.1) = 0; - } - - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} -impl fmt::Write for AllocStringWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - // can't fail - self.write(s.as_bytes()).unwrap(); - Ok(()) - } -} -impl WriteByte for AllocStringWriter { - fn write_u8(&mut self, byte: u8) -> fmt::Result { - // can't fail - self.write(&[byte]).unwrap(); - Ok(()) - } -} - pub struct StringWriter(pub *mut u8, pub usize); impl Write for StringWriter { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { @@ -155,11 +116,14 @@ impl Write for StringWriter { self.0 = self.0.add(copy_size); *self.0 = 0; } - - Ok(copy_size) - } else { - Ok(0) } + + // Pretend the entire slice was written. This is because many functions + // (like snprintf) expects a return value that reflects how many bytes + // *would have* been written. So keeping track of this information is + // good, and then if we want the *actual* written size we can just go + // `cmp::min(written, maxlen)`. + Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(())