Skip to content

Commit

Permalink
add strverscmp (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
KGrewal1 committed Dec 19, 2023
1 parent af18956 commit 4782df5
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 4 deletions.
117 changes: 117 additions & 0 deletions c-scape/src/mem/ntbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,123 @@ unsafe extern "C" fn strcmp(mut s1: *const c_char, mut s2: *const c_char) -> c_i
*s1 as c_uchar as c_int - *s2 as c_uchar as c_int
}

// enum for strverscmp state
// internal so no surface
// Tracks the current state of the comparison
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum StrverscmpState {
/// Normal string comparison
Normal,
/// compare whole numbers: 1<2<10
Integral,
/// compare fractional 01 < 011 < 02
Fractional,
/// compare leading zeros 000 < 00
LeadingZeros,
}

enum CharType {
Zero,
Digit,
NonNumeric,
}

impl CharType {
fn from_char(c: c_char) -> Self {
match c as c_uchar {
// ASCII 0
b'0' => Self::Zero,
// ASCII 1-9
b'1'..=b'9' => Self::Digit,
// non numeric ASCII
_ => Self::NonNumeric,
}
}
}

impl StrverscmpState {
fn transition(&mut self, s: CharType) {
match s {
CharType::Zero => {
if self == &Self::Normal {
*self = Self::LeadingZeros;
}
}
// ASCII 1-9
CharType::Digit => {
if self == &Self::Normal {
*self = Self::Integral;
}
if self == &Self::LeadingZeros {
*self = Self::Fractional;
}
}
// non numeric ASCII
CharType::NonNumeric => *self = Self::Normal,
}
}

unsafe fn exit(&mut self, mut s1: *const c_char, mut s2: *const c_char) -> c_int {
let chartype1 = CharType::from_char(*s1);
let chartype2 = CharType::from_char(*s2);
match (self, chartype1, chartype2) {
// compare the strings based on length of the numeric part
(StrverscmpState::Normal, CharType::Digit, CharType::Digit)
| (StrverscmpState::Integral, CharType::Digit, CharType::Digit)
| (StrverscmpState::Integral, CharType::Digit, CharType::Zero)
| (StrverscmpState::Integral, CharType::Zero, CharType::Digit)
| (StrverscmpState::Integral, CharType::Zero, CharType::Zero) => {
let diff = *s1 as c_uchar as c_int - *s2 as c_uchar as c_int;
loop {
let chartype1 = CharType::from_char(*s1);
let chartype2 = CharType::from_char(*s2);
match (chartype1, chartype2) {
(CharType::Zero, CharType::NonNumeric) => return 1,
(CharType::Digit, CharType::NonNumeric) => return 1,
(CharType::NonNumeric, CharType::Zero) => return -1,
(CharType::NonNumeric, CharType::Digit) => return -1,
(CharType::NonNumeric, CharType::NonNumeric) => break,
(_, _) => {
s1 = s1.add(1);
s2 = s2.add(1);
}
}
}
diff
}

(StrverscmpState::Integral, CharType::Zero, CharType::NonNumeric)
| (StrverscmpState::Integral, CharType::Digit, CharType::NonNumeric)
| (StrverscmpState::LeadingZeros, CharType::NonNumeric, CharType::Zero)
| (StrverscmpState::LeadingZeros, CharType::NonNumeric, CharType::Digit) => 1,

(StrverscmpState::Integral, CharType::NonNumeric, CharType::Zero)
| (StrverscmpState::Integral, CharType::NonNumeric, CharType::Digit)
| (StrverscmpState::LeadingZeros, CharType::Zero, CharType::NonNumeric)
| (StrverscmpState::LeadingZeros, CharType::Digit, CharType::NonNumeric) => -1,

// Compare the strings the same as strcmp
(_, _, _) => *s1 as c_uchar as c_int - *s2 as c_uchar as c_int,
}
}
}

#[no_mangle]
unsafe extern "C" fn strverscmp(mut s1: *const c_char, mut s2: *const c_char) -> c_int {
// libc!(libc::strverscmp(s1, s2));
let mut state = StrverscmpState::Normal;
while *s1 != NUL && *s2 != NUL {
if *s1 != *s2 {
return state.exit(s1, s2);
}
state.transition(CharType::from_char(*s1));
s1 = s1.add(1);
s2 = s2.add(1);
}

*s1 as c_uchar as c_int - *s2 as c_uchar as c_int
}

#[no_mangle]
unsafe extern "C" fn strcpy(d: *mut c_char, s: *const c_char) -> *mut c_char {
libc!(libc::strcpy(d, s));
Expand Down
4 changes: 0 additions & 4 deletions c-scape/src/todo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,10 +827,6 @@ unsafe extern "C" fn __stpcpy_chk() {
todo!("__stpcpy_chk")
}
#[no_mangle]
unsafe extern "C" fn strverscmp() {
todo!("strverscmp")
}
#[no_mangle]
unsafe extern "C" fn strtold() {
todo!("strtold")
}
Expand Down

0 comments on commit 4782df5

Please sign in to comment.