diff --git a/src/c_vec.rs b/src/c_vec.rs index e9036fe5a2..806d5396ad 100644 --- a/src/c_vec.rs +++ b/src/c_vec.rs @@ -107,7 +107,8 @@ impl CVec { pub fn truncate(&mut self, len: usize) { if len < self.len { unsafe { - self.drop_range(len, self.len); + let old_len = self.len; + self.drop_range(len, old_len); } self.len = len; } @@ -115,7 +116,8 @@ impl CVec { pub fn shrink_to_fit(&mut self) -> Result<(), AllocError> { if self.len < self.cap { unsafe { - self.resize(self.len)?; + let new_cap = self.len; + self.resize(new_cap)?; } } Ok(()) @@ -155,7 +157,8 @@ impl DerefMut for CVec { impl Drop for CVec { fn drop(&mut self) { unsafe { - self.drop_range(0, self.len); + let len = self.len; + self.drop_range(0, len); } } } diff --git a/src/fs.rs b/src/fs.rs index f3daf4bc20..39c952d715 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -3,15 +3,9 @@ use core::ops::Deref; use header::fcntl::O_CREAT; use header::unistd::{SEEK_CUR, SEEK_END, SEEK_SET}; use io; -use platform; use platform::types::*; use platform::{Pal, Sys}; -fn last_os_error() -> io::Error { - let errno = unsafe { platform::errno }; - io::Error::from_raw_os_error(errno) -} - pub struct File { pub fd: c_int, /// To avoid self referential FILE struct that needs both a reader and a writer, @@ -29,35 +23,35 @@ impl File { pub fn open(path: &CStr, oflag: c_int) -> io::Result { match Sys::open(path, oflag, 0) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(Self::new(ok)), } } pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result { match Sys::open(path, oflag | O_CREAT, mode) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(Self::new(ok)), } } pub fn sync_all(&self) -> io::Result<()> { match Sys::fsync(self.fd) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), _ok => Ok(()), } } pub fn set_len(&self, size: u64) -> io::Result<()> { match Sys::ftruncate(self.fd, size as off_t) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), _ok => Ok(()), } } pub fn try_clone(&self) -> io::Result { match Sys::dup(self.fd) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(Self::new(ok)), } } @@ -76,7 +70,7 @@ impl File { impl io::Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result { match Sys::read(self.fd, buf) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(ok as usize), } } @@ -85,7 +79,7 @@ impl io::Read for File { impl io::Write for File { fn write(&mut self, buf: &[u8]) -> io::Result { match Sys::write(self.fd, buf) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(ok as usize), } } @@ -104,7 +98,7 @@ impl io::Seek for File { }; match Sys::lseek(self.fd, offset, whence) { - -1 => Err(last_os_error()), + -1 => Err(io::last_os_error()), ok => Ok(ok as u64), } } diff --git a/src/header/stdio/printf.rs b/src/header/stdio/printf.rs index ead7fbfd81..ed9144a1cb 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -4,11 +4,12 @@ use alloc::string::ToString; use alloc::vec::Vec; use core::ffi::VaList; use core::ops::Range; -use core::{cmp, f64, fmt, slice}; +use core::{char, cmp, f64, fmt, slice}; use io::{self, Write}; -use platform; -use platform::types::*; +use crate::header::errno::EILSEQ; +use crate::platform::types::*; +use crate::platform; // ____ _ _ _ _ // | __ ) ___ (_) | ___ _ __ _ __ | | __ _| |_ ___ _ @@ -72,6 +73,7 @@ impl Number { VaArg::pointer(i) => i as usize, VaArg::ptrdiff_t(i) => i as usize, VaArg::ssize_t(i) => i as usize, + VaArg::wint_t(i) => i as usize, } } } @@ -87,6 +89,7 @@ enum VaArg { pointer(*const c_void), ptrdiff_t(ptrdiff_t), ssize_t(ssize_t), + wint_t(wint_t), } impl VaArg { unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg { @@ -100,6 +103,9 @@ impl VaArg { match (fmtkind, intkind) { (FmtKind::Percent, _) => panic!("Can't call arg_from on %"), + (FmtKind::Char, IntKind::Long) + | (FmtKind::Char, IntKind::LongLong) => VaArg::wint_t(ap.arg::()), + (FmtKind::Char, _) | (FmtKind::Unsigned, IntKind::Byte) | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(ap.arg::()), @@ -154,6 +160,7 @@ impl VaArg { pointer: *const c_void, ptrdiff_t: ptrdiff_t, ssize_t: ssize_t, + wint_t: wint_t, } let untyped = match *self { VaArg::c_char(i) => Untyped { c_char: i }, @@ -166,10 +173,14 @@ impl VaArg { VaArg::pointer(i) => Untyped { pointer: i }, VaArg::ptrdiff_t(i) => Untyped { ptrdiff_t: i }, VaArg::ssize_t(i) => Untyped { ssize_t: i }, + VaArg::wint_t(i) => Untyped { wint_t: i }, }; match (fmtkind, intkind) { (FmtKind::Percent, _) => panic!("Can't call transmute on %"), + (FmtKind::Char, IntKind::Long) + | (FmtKind::Char, IntKind::LongLong) => VaArg::wint_t(untyped.wint_t), + (FmtKind::Char, _) | (FmtKind::Unsigned, IntKind::Byte) | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char), @@ -646,6 +657,7 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> VaArg::pointer(i) => (i as usize).to_string(), VaArg::ptrdiff_t(i) => i.to_string(), VaArg::ssize_t(i) => i.to_string(), + VaArg::wint_t(_) => unreachable!("this should not be possible"), }; let positive = !string.starts_with('-'); let zero = precision == Some(0) && string == "0"; @@ -693,6 +705,7 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> VaArg::pointer(i) => fmt_int(fmt, i as usize), VaArg::ptrdiff_t(i) => fmt_int(fmt, i as size_t), VaArg::ssize_t(i) => fmt_int(fmt, i as size_t), + VaArg::wint_t(_) => unreachable!("this should not be possible"), }; let zero = precision == Some(0) && string == "0"; @@ -785,8 +798,6 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> } } FmtKind::String => { - // if intkind == IntKind::Long || intkind == IntKind::LongLong, handle *const wchar_t - let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { VaArg::pointer(p) => p, _ => panic!("this should not be possible"), @@ -796,27 +807,65 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> w.write_all(b"(null)")?; } else { let max = precision.unwrap_or(::core::usize::MAX); - let mut len = 0; - while *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))?; - pad(w, left, b' ', len..pad_space)?; + if intkind == IntKind::Long || intkind == IntKind::LongLong { + // Handle wchar_t + let mut ptr = ptr as *const wchar_t; + let mut string = String::new(); + + while *ptr != 0 { + let c = match char::from_u32(*ptr as _) { + Some(c) => c, + None => { + platform::errno = EILSEQ; + return Err(io::last_os_error()); + } + }; + if string.len() + c.len_utf8() >= max { + break; + } + string.push(c); + ptr = ptr.add(1); + } + + pad(w, !left, b' ', string.len()..pad_space)?; + w.write_all(string.as_bytes())?; + pad(w, left, b' ', string.len()..pad_space)?; + } else { + let mut len = 0; + while *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))?; + pad(w, left, b' ', len..pad_space)?; + } } } FmtKind::Char => { - // if intkind == IntKind::Long || intkind == IntKind::LongLong, handle wint_t + 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 = EILSEQ; + return Err(io::last_os_error()); + } + }; + let mut buf = [0; 4]; - let c = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { - VaArg::c_char(c) => c, - _ => panic!("this should not be possible"), - }; - - pad(w, !left, b' ', 1..pad_space)?; - w.write_all(&[c as u8])?; - 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"), + } } FmtKind::Pointer => { let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { diff --git a/src/header/wchar/mod.rs b/src/header/wchar/mod.rs index fa721176f8..35a9662c9a 100644 --- a/src/header/wchar/mod.rs +++ b/src/header/wchar/mod.rs @@ -1,8 +1,10 @@ //! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html use core::ffi::VaList as va_list; -use core::{mem, ptr, usize}; +use core::{char, mem, ptr, usize}; +use header::ctype::isspace; +use header::errno::ERANGE; use header::stdio::*; use header::stdlib::MB_CUR_MAX; use header::string; @@ -470,9 +472,52 @@ pub extern "C" fn wcsstr(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar unimplemented!(); } -// #[no_mangle] -pub extern "C" fn wcstod(nptr: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 { - unimplemented!(); +macro_rules! skipws { + ($ptr:expr) => { + while isspace(*$ptr) != 0 { + $ptr = $ptr.add(1); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wcstod(mut ptr: *const wchar_t, end: *mut *mut wchar_t) -> c_double { + const RADIX: u32 = 10; + + skipws!(ptr); + let negative = *ptr == '-' as wchar_t; + if negative { + ptr = ptr.add(1); + } + + let mut result: c_double = 0.0; + while let Some(digit) = char::from_u32(*ptr as _).and_then(|c| c.to_digit(RADIX)) { + result *= 10.0; + if negative { + result -= digit as c_double; + } else { + result += digit as c_double; + } + ptr = ptr.add(1); + } + if *ptr == '.' as wchar_t { + ptr = ptr.add(1); + + let mut scale = 1.0; + while let Some(digit) = char::from_u32(*ptr as _).and_then(|c| c.to_digit(RADIX)) { + scale /= 10.0; + if negative { + result -= digit as c_double * scale; + } else { + result += digit as c_double * scale; + } + ptr = ptr.add(1); + } + } + if !end.is_null() { + *end = ptr as *mut _; + } + result } #[no_mangle] @@ -510,14 +555,64 @@ pub unsafe extern "C" fn wcstok( wcs } -// #[no_mangle] -pub extern "C" fn wcstol(nptr: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_long { - unimplemented!(); +macro_rules! strtou_impl { + ($type:ident, $ptr:expr, $base:expr) => { + strtou_impl!($type, $ptr, $base, false) + }; + ($type:ident, $ptr:expr, $base:expr, $negative:expr) => {{ + if $base == 16 && *$ptr == '0' as wchar_t && *$ptr.add(1) | 0x20 == 'x' as wchar_t { + $ptr = $ptr.add(2); + } + + let mut result: $type = 0; + while let Some(digit) = char::from_u32(*$ptr as u32).and_then(|c| c.to_digit($base as u32)) { + let new = result.checked_mul($base as $type) + .and_then(|result| if $negative { + result.checked_sub(digit as $type) + } else { + result.checked_add(digit as $type) + }); + result = match new { + Some(new) => new, + None => { + platform::errno = ERANGE; + return !0; + } + }; + + $ptr = $ptr.add(1); + } + result + }} +} +macro_rules! strto_impl { + ($type:ident, $ptr:expr, $base:expr) => {{ + let negative = *$ptr == '-' as wchar_t; + if negative { + $ptr = $ptr.add(1); + } + strtou_impl!($type, $ptr, $base, negative) + }} } -// #[no_mangle] -pub extern "C" fn wcstoul(nptr: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulong { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn wcstol(mut ptr: *const wchar_t, end: *mut *mut wchar_t, base: c_int) -> c_long { + skipws!(ptr); + let result = strto_impl!(c_long, ptr, base); + if !end.is_null() { + *end = ptr as *mut _; + } + result +} + +#[no_mangle] +pub unsafe extern "C" fn wcstoul(mut ptr: *const wchar_t, end: *mut *mut wchar_t, base: c_int) -> c_ulong { + skipws!(ptr); + let result = strtou_impl!(c_ulong, ptr, base); + if !end.is_null() { + *end = ptr as *mut _; + } + result } // #[no_mangle] diff --git a/src/io.rs b/src/io.rs index 42640cf192..d65ab2dddd 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1 +1,8 @@ pub use core_io::*; + +use crate::platform; + +pub fn last_os_error() -> Error { + let errno = unsafe { platform::errno }; + Error::from_raw_os_error(errno) +} diff --git a/tests/Makefile b/tests/Makefile index 858a711cc1..da4d243bbf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -15,8 +15,6 @@ EXPECT_NAMES=\ libgen \ locale \ math \ - netdb/netdb \ - netdb/getaddrinfo \ regex \ select \ setjmp \ @@ -90,12 +88,18 @@ EXPECT_NAMES=\ waitpid \ wchar/mbrtowc \ wchar/mbsrtowcs \ + wchar/printf-on-wchars \ wchar/putwchar \ wchar/wcrtomb \ wchar/wcscspn \ wchar/wcsrchr \ - wchar/wcstok - # signal (TODO: Fix) + wchar/wcstod \ + wchar/wcstok \ + wchar/wcstol + # TODO: Fix these + # netdb/getaddrinfo \ + # netdb/netdb \ + # signal # Binaries that may generate varied output NAMES=\ diff --git a/tests/expected/netdb/getaddrinfo.stdout b/tests/expected/netdb/getaddrinfo.stdout deleted file mode 100644 index 6bc12bb59b..0000000000 --- a/tests/expected/netdb/getaddrinfo.stdout +++ /dev/null @@ -1 +0,0 @@ -IPv4 address: 23.21.162.66 (www.redox-os.org) diff --git a/tests/expected/netdb/netdb.stdout b/tests/expected/netdb/netdb.stdout deleted file mode 100644 index 26a2f0f906..0000000000 --- a/tests/expected/netdb/netdb.stdout +++ /dev/null @@ -1 +0,0 @@ -No visible errors occurred! diff --git a/tests/expected/netdb/getaddrinfo.stderr b/tests/expected/wchar/printf-on-wchars.stderr similarity index 100% rename from tests/expected/netdb/getaddrinfo.stderr rename to tests/expected/wchar/printf-on-wchars.stderr diff --git a/tests/expected/wchar/printf-on-wchars.stdout b/tests/expected/wchar/printf-on-wchars.stdout new file mode 100644 index 0000000000..b14ed25516 --- /dev/null +++ b/tests/expected/wchar/printf-on-wchars.stdout @@ -0,0 +1,4 @@ +This is a few one-byte chars: 1 2 a b +Long one-byte string: Hello World +This is a few multi-byte chars: ❤ R 😠 C +Long multi-byte string: 👉😎👉 Zoop! diff --git a/tests/expected/netdb/netdb.stderr b/tests/expected/wchar/wcstod.stderr similarity index 100% rename from tests/expected/netdb/netdb.stderr rename to tests/expected/wchar/wcstod.stderr diff --git a/tests/expected/wchar/wcstod.stdout b/tests/expected/wchar/wcstod.stdout new file mode 100644 index 0000000000..0292990d95 --- /dev/null +++ b/tests/expected/wchar/wcstod.stdout @@ -0,0 +1,6 @@ +strtod(1.2345wowzah) = (1.234500, wowzah) +strtod(53) = (53.000000, ) +strtod(-254352.5...) = (-254352.500000, ...) +strtod( 19.2 wat) = (19.200000, wat) +strtod(365.24 29.53) = (365.240000, 29.53) +strtod( 29.53) = (29.530000, ) diff --git a/tests/expected/wchar/wcstol.stderr b/tests/expected/wchar/wcstol.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/wchar/wcstol.stdout b/tests/expected/wchar/wcstol.stdout new file mode 100644 index 0000000000..ec5ae58779 --- /dev/null +++ b/tests/expected/wchar/wcstol.stdout @@ -0,0 +1 @@ +The decimal equivalents are: 2001, 6340800, -3624224 and 0. diff --git a/tests/wchar/printf-on-wchars.c b/tests/wchar/printf-on-wchars.c new file mode 100644 index 0000000000..20860c74f1 --- /dev/null +++ b/tests/wchar/printf-on-wchars.c @@ -0,0 +1,22 @@ +#include +#include +#include + +int main() { + wint_t a = L'1'; + wint_t b = L'2'; + wint_t c = L'a'; + wint_t d = L'b'; + printf("This is a few one-byte chars: %lc %lc %lc %lc\n", a, b, c, d); + wchar_t *s = L"Hello World"; + printf("Long one-byte string: %ls\n", s); + + a = L'❤'; + b = L'R'; + c = L'😠'; + d = L'C'; + printf("This is a few multi-byte chars: %lc %lc %lc %lc\n", a, b, c, d); + + s = L"👉😎👉 Zoop!"; + printf("Long multi-byte string: %ls\n", s); +} diff --git a/tests/wchar/wcstod.c b/tests/wchar/wcstod.c new file mode 100644 index 0000000000..c51d51823c --- /dev/null +++ b/tests/wchar/wcstod.c @@ -0,0 +1,16 @@ +#include +#include + +void attempt(wchar_t *s) { + wchar_t *end; + double result = wcstod(s, &end); + printf("strtod(%lls) = (%f, %lls)\n", s, result, end); +} +int main() { + attempt(L"1.2345wowzah"); + attempt(L"53"); + attempt(L"-254352.5..."); + attempt(L" 19.2 wat"); + attempt(L"365.24 29.53"); + attempt(L" 29.53"); +} diff --git a/tests/wchar/wcstol.c b/tests/wchar/wcstol.c new file mode 100644 index 0000000000..e33b5343ab --- /dev/null +++ b/tests/wchar/wcstol.c @@ -0,0 +1,17 @@ +// from http://www.cplusplus.com/reference/cwchar/wcstol/ +#include +#include + +int main () { + wchar_t wsNumbers[] = L"2001 60c0c0 -1101110100110100100000 0x6fffff"; + wchar_t * pEnd; + long int li1, li2, li3, li4; + + li1 = wcstol(wsNumbers,&pEnd,10); + li2 = wcstol(pEnd,&pEnd,16); + li3 = wcstol(pEnd,&pEnd,2); + li4 = wcstol(pEnd,NULL,0); + + printf("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4); + return 0; +}