From 8d1795ad1a5f148a5f9595366d897b6bfebe6d8c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 8 Oct 2023 11:25:39 +0200 Subject: [PATCH] strncmp --- .envrc | 1 + libuwuc/src/env.rs | 4 +- libuwuc/src/io/mod.rs | 2 +- libuwuc/src/mem.rs | 104 ++++++++++++++++++++++++++++++++++++++ libuwuc/src/utils/mod.rs | 2 +- rawc/src/string.rs | 13 ++++- shell.nix | 4 ++ tests/real_world/clone.sh | 1 + 8 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 .envrc diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/libuwuc/src/env.rs b/libuwuc/src/env.rs index 4d792fa..2d586e6 100644 --- a/libuwuc/src/env.rs +++ b/libuwuc/src/env.rs @@ -73,8 +73,8 @@ fn getenv_inner(mut envp: EnvP, name: SharedThinCstr<'_>) -> Option, s2: SharedThinCstr<'_>) -> i32 { + s1.into_iter().cmp(s2) as i8 as i32 +} + +// This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful. +#[inline] +pub unsafe fn strncmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>, size: usize) -> i32 { + s1.into_iter().take(size).cmp(s2.into_iter().take(size)) as i8 as i32 +} + #[inline] pub unsafe fn strlen(mut s: *const u8) -> usize { let mut len = 0; @@ -68,6 +81,8 @@ pub unsafe fn strlen(mut s: *const u8) -> usize { #[cfg(test)] mod tests { + use crate::{cstr, utils::SharedThinCstr}; + #[test] fn memcpy_null() { unsafe { super::memcpy(std::ptr::null_mut(), std::ptr::null_mut(), 0) }; @@ -204,6 +219,95 @@ mod tests { assert_eq!(result, 1); } + #[test] + fn strcmp_empty() { + let a = cstr!(""); + let b = cstr!(""); + let result = unsafe { super::strcmp(a, b) }; + assert_eq!(result, 0); + } + + #[test] + fn strcmp_against_empty() { + let a = cstr!("aa"); + let b = cstr!(""); + let result = unsafe { super::strcmp(a, b) }; + assert_eq!(result, 1); + } + + #[test] + fn strcmp_against_empty_rev() { + let a = cstr!(""); + let b = cstr!("aa"); + let result = unsafe { super::strcmp(a, b) }; + assert_eq!(result, -1); + } + + #[test] + fn strcmp_equal_len() { + let a = cstr!("00"); + let b = cstr!("11"); + let result = unsafe { super::strcmp(a, b) }; + assert_eq!(result, -1); + } + + #[test] + fn strcmp_equal_len_rev() { + let a = cstr!("11"); + let b = cstr!("00"); + let result = unsafe { super::strcmp(a, b) }; + assert_eq!(result, 1); + } + + #[test] + fn strncmp_empty() { + let a = cstr!(""); + let b = cstr!(""); + let result = unsafe { super::strncmp(a, b, 10) }; + assert_eq!(result, 0); + } + + #[test] + fn strncmp_no_null_term() { + // Note: this is violating the safety invariant of SharedThinCstr but thats fine, we're careful. + let a = unsafe { SharedThinCstr::from_raw(b"0000".as_ptr()) }; + let b = unsafe { SharedThinCstr::from_raw(b"0001".as_ptr()) }; + let result = unsafe { super::strncmp(a, b, 4) }; + assert_eq!(result, -1); + } + + #[test] + fn strncmp_against_empty() { + let a = cstr!("aa"); + let b = cstr!(""); + let result = unsafe { super::strncmp(a, b, 2) }; + assert_eq!(result, 1); + } + + #[test] + fn strncmp_against_empty_rev() { + let a = cstr!(""); + let b = cstr!("aa"); + let result = unsafe { super::strncmp(a, b, 2) }; + assert_eq!(result, -1); + } + + #[test] + fn strncmp_equal_len() { + let a = cstr!("00"); + let b = cstr!("11"); + let result = unsafe { super::strncmp(a, b, 2) }; + assert_eq!(result, -1); + } + + #[test] + fn strncmp_equal_len_rev() { + let a = cstr!("11"); + let b = cstr!("00"); + let result = unsafe { super::strncmp(a, b, 2) }; + assert_eq!(result, 1); + } + #[test] fn strlen_empty() { let str = b"\0"; diff --git a/libuwuc/src/utils/mod.rs b/libuwuc/src/utils/mod.rs index 4904d18..772fdc0 100644 --- a/libuwuc/src/utils/mod.rs +++ b/libuwuc/src/utils/mod.rs @@ -73,7 +73,7 @@ impl<'a> Iterator for CStrIter<'a> { } self.0 = self.0.add(1); - Some(c as u8) + Some(c) } } } diff --git a/rawc/src/string.rs b/rawc/src/string.rs index 9ffd8b4..a571d74 100644 --- a/rawc/src/string.rs +++ b/rawc/src/string.rs @@ -1,4 +1,4 @@ -use libuwuc::error::Error; +use libuwuc::{error::Error, utils::SharedThinCstr}; #[no_mangle] pub unsafe extern "C" fn memset(ptr: *mut u8, constant: u8, len: usize) { @@ -25,6 +25,17 @@ pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 libuwuc::mem::memcmp(s1, s2, size) } +#[no_mangle] +pub unsafe extern "C" fn strcmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>) -> i32 { + libuwuc::mem::strcmp(s1, s2) +} + +// This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful. +#[no_mangle] +pub unsafe extern "C" fn strncmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>, n: usize) -> i32 { + libuwuc::mem::strncmp(s1, s2, n) +} + #[no_mangle] pub unsafe extern "C" fn strlen(s: *const u8) -> usize { libuwuc::mem::strlen(s) diff --git a/shell.nix b/shell.nix index ca7b3d9..a990d01 100644 --- a/shell.nix +++ b/shell.nix @@ -3,6 +3,10 @@ rustup gcc clang_16 + + + # for building things + gnumake ]; shellHook = '' export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin diff --git a/tests/real_world/clone.sh b/tests/real_world/clone.sh index 320f80b..45c9d1a 100755 --- a/tests/real_world/clone.sh +++ b/tests/real_world/clone.sh @@ -16,3 +16,4 @@ ensure_cloned() { ensure_cloned "https://github.com/tsoding/noed.git" "tsoding_noed" "1c2bd182139080a8448a59589e8d457a7019d553" ensure_cloned "https://github.com/zesterer/tosh.git" "zest_tosh" "fa43ee9ec01a625f6a96cb48662f6c8911d8cc8c" +ensure_cloned "https://github.com/tsoding/ebisp.git" "tsoding_ebisp" "1f522883ac99b5fdcd310cccc2b03e73a281f962"