Skip to main content

c/
strverscmp.rs

1// strverscmp() - ported from musl/src/string/strverscmp.c
2// Add to libc/src/lib.rs in the "String/memory functions" section.
3
4#[no_mangle]
5pub unsafe extern "C" fn strverscmp(a: *const c_char, b: *const c_char) -> c_int {
6    let l = a as *const u8;
7    let r = b as *const u8;
8    let mut i: usize = 0;
9    let mut dp: usize = 0;
10    let mut z: c_int = 1;
11
12    // Find maximal matching prefix and track its maximal digit
13    // suffix and whether those digits are all zeros.
14    while *l.add(i) == *r.add(i) {
15        let c = *l.add(i) as c_int;
16        if c == 0 {
17            return 0;
18        }
19        if isdigit(c) == 0 {
20            dp = i + 1;
21            z = 1;
22        } else if c != b'0' as c_int {
23            z = 0;
24        }
25        i += 1;
26    }
27
28    if (*l.add(dp)).wrapping_sub(b'1') < 9 && (*r.add(dp)).wrapping_sub(b'1') < 9 {
29        // Non-degenerate digit sequences starting with nonzero digits:
30        // longest digit string is greater.
31        let mut j = i;
32        while isdigit(*l.add(j) as c_int) != 0 {
33            if isdigit(*r.add(j) as c_int) == 0 {
34                return 1;
35            }
36            j += 1;
37        }
38        if isdigit(*r.add(j) as c_int) != 0 {
39            return -1;
40        }
41    } else if z != 0
42        && dp < i
43        && (isdigit(*l.add(i) as c_int) != 0 || isdigit(*r.add(i) as c_int) != 0)
44    {
45        // Common prefix of digit sequence is all zeros:
46        // digits order less than non-digits.
47        return (*l.add(i)).wrapping_sub(b'0') as c_int
48            - (*r.add(i)).wrapping_sub(b'0') as c_int;
49    }
50
51    *l.add(i) as c_int - *r.add(i) as c_int
52}