Implement wcstol, wcstod, and printf:ing wchars

This commit is contained in:
jD91mZM2
2019-07-18 12:29:22 +02:00
parent 7c99077248
commit a8280e8991
17 changed files with 270 additions and 54 deletions
+6 -3
View File
@@ -107,7 +107,8 @@ impl<T> CVec<T> {
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<T> CVec<T> {
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<T> DerefMut for CVec<T> {
impl<T> Drop for CVec<T> {
fn drop(&mut self) {
unsafe {
self.drop_range(0, self.len);
let len = self.len;
self.drop_range(0, len);
}
}
}
+8 -14
View File
@@ -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<Self> {
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<Self> {
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<Self> {
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<usize> {
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<usize> {
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),
}
}
+70 -21
View File
@@ -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::<wint_t>()),
(FmtKind::Char, _)
| (FmtKind::Unsigned, IntKind::Byte)
| (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(ap.arg::<c_char>()),
@@ -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: Write>(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: Write>(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: Write>(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: Write>(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))) {
+105 -10
View File
@@ -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]
+7
View File
@@ -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)
}
+8 -4
View File
@@ -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=\
-1
View File
@@ -1 +0,0 @@
IPv4 address: 23.21.162.66 (www.redox-os.org)
-1
View File
@@ -1 +0,0 @@
No visible errors occurred!
@@ -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!
+6
View File
@@ -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, )
View File
+1
View File
@@ -0,0 +1 @@
The decimal equivalents are: 2001, 6340800, -3624224 and 0.
+22
View File
@@ -0,0 +1,22 @@
#include <stdio.h>
#include <sys/types.h>
#include <wchar.h>
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);
}
+16
View File
@@ -0,0 +1,16 @@
#include <sys/types.h>
#include <wchar.h>
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");
}
+17
View File
@@ -0,0 +1,17 @@
// from http://www.cplusplus.com/reference/cwchar/wcstol/
#include <stdio.h>
#include <wchar.h>
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;
}