Browse Source

Implement wcsstr(), fix return type of wcslen()

Peter Limkilde Svendsen 5 years ago
parent
commit
0b2c3fe5ea

+ 30 - 7
src/header/wchar/mod.rs

@@ -1,6 +1,6 @@
 //! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html
 
-use core::{char, ffi::VaList as va_list, mem, ptr, usize};
+use core::{char, ffi::VaList as va_list, mem, ptr, slice, usize};
 
 use crate::{
     header::{ctype::isspace, errno::ERANGE, stdio::*, stdlib::MB_CUR_MAX, string, time::*},
@@ -353,11 +353,11 @@ pub extern "C" fn wcsftime(
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn wcslen(ws: *const wchar_t) -> c_ulong {
+pub unsafe extern "C" fn wcslen(ws: *const wchar_t) -> size_t {
     let mut i = 0;
     loop {
         if *ws.add(i) == 0 {
-            return i as c_ulong;
+            return i;
         }
         i += 1;
     }
@@ -370,7 +370,7 @@ pub unsafe extern "C" fn wcsncat(
     n: size_t,
 ) -> *mut wchar_t {
     let len = wcslen(ws1);
-    let dest = ws1.add(len as usize);
+    let dest = ws1.add(len);
     let mut i = 0;
     while i < n {
         let wc = *ws2.add(i);
@@ -462,9 +462,32 @@ pub unsafe extern "C" fn wcsspn(wcs: *const wchar_t, set: *const wchar_t) -> siz
     inner_wcsspn(wcs, set, false)
 }
 
-// #[no_mangle]
-pub extern "C" fn wcsstr(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
-    unimplemented!();
+#[no_mangle]
+pub unsafe extern "C" fn wcsstr(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
+    // Get length of ws2, not including null terminator
+    let ws2_len = wcslen(ws2);
+
+    // The standard says that we must return ws1 if ws2 has length 0
+    if ws2_len == 0 {
+        ws1 as *mut wchar_t
+    } else {
+        let ws1_len = wcslen(ws1);
+
+        // Construct slices without null terminator
+        let ws1_slice = slice::from_raw_parts(ws1, ws1_len);
+        let ws2_slice = slice::from_raw_parts(ws2, ws2_len);
+
+        /* Sliding ws2-sized window iterator on ws1. The iterator
+         * returns None if ws2 is longer than ws1. */
+        let mut ws1_windows = ws1_slice.windows(ws2_len);
+
+        /* Find the first offset into ws1 where the window is equal to
+         * the ws2 contents. Return null pointer if no match is found. */
+        match ws1_windows.position(|ws1_window| ws1_window == ws2_slice) {
+            Some(pos) => ws1.add(pos) as *mut wchar_t,
+            None => ptr::null_mut(),
+        }
+    }
 }
 
 macro_rules! skipws {

+ 1 - 0
tests/Makefile

@@ -95,6 +95,7 @@ EXPECT_NAMES=\
 	wchar/wcrtomb \
 	wchar/wcscspn \
 	wchar/wcsrchr \
+	wchar/wcsstr \
 	wchar/wcstod \
 	wchar/wcstok \
 	wchar/wcstol \

+ 0 - 0
tests/expected/wchar/wcsstr.stderr


+ 0 - 0
tests/expected/wchar/wcsstr.stdout


+ 27 - 0
tests/wchar/wcsstr.c

@@ -0,0 +1,27 @@
+#include <assert.h>
+#include <wchar.h>
+
+int main(void) {
+    wchar_t *haystack = L"Hello, World!";
+    wchar_t *haystack_empty = L"";
+
+    wchar_t *needle_expected = L"World";
+    wchar_t *needle_expected_multiple = L"l";
+    wchar_t *needle_not_expected = L"Rust";
+    wchar_t *needle_too_long = L"Hello, World!!!";
+    wchar_t *needle_empty = L"";
+
+    assert(wcsstr(haystack, needle_expected) == haystack + 7);
+    assert(wcsstr(haystack, needle_expected_multiple) == haystack + 2);
+    assert(wcsstr(haystack, needle_not_expected) == NULL);
+    assert(wcsstr(haystack, needle_too_long) == NULL);
+    assert(wcsstr(haystack, needle_empty) == haystack);
+
+    assert(wcsstr(haystack_empty, needle_expected) == NULL);
+    assert(wcsstr(haystack_empty, needle_expected_multiple) == NULL);
+    assert(wcsstr(haystack_empty, needle_not_expected) == NULL);
+    assert(wcsstr(haystack_empty, needle_too_long) == NULL);
+    assert(wcsstr(haystack_empty, needle_empty) == haystack_empty);
+
+    return 0;
+}