diff --git a/src/string/strverscmp.c b/src/string/strverscmp.c index 6f37cc6..9c7fa33 100644 --- a/src/string/strverscmp.c +++ b/src/string/strverscmp.c @@ -2,6 +2,55 @@ #include #include +#if 1 +int strverscmp(const char *l0, const char *r0) +{ + const unsigned char *l = (const void *)l0; + const unsigned char *r = (const void *)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximual matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for (dp=i=0; l[i]==r[i]; i++) { + int c = l[i]; + if (!c) return 0; + if (!isdigit(c)) dp=i+1, z=1; + else if (c!='0') z=0; + } + + /* This catches all cases where the mismatch is non-numeric -- + * either a matching digit sequence has just been completed and + * is followed by non-digits in both strings, or at most one + * of the two strings has an initial digit in the first + * mismatched position and the other has a non-digit. */ + if (!isdigit(l[i]) && !isdigit(r[i]) || + i==dp && (!isdigit(l[i]) || !isdigit(r[i]))) + return l[i] - r[i]; + + /* If this point is reached, the comparison is numeric. */ + + /* The only way one of the conditions can hold without the other + * is when dp==i, i.e. the mismatch is the start of a new + * digit sequence in both strings. */ + if (l[dp]=='0' || r[dp]=='0') { + /* If the shared prefix is all zeros, 0 r[i]-adj ? 1 : -1; + } + + /* In the only remaining cases, neither number has leading zeros. + * The longer is greater, with first mismatch breaking ties. */ + + for (j=i; isdigit(l[j]); j++) + if (!isdigit(r[j])) return 1; + if (isdigit(r[j])) return -1; + + return l[i] - r[i]; +} +#else int strverscmp(const char *l, const char *r) { int haszero=1; @@ -39,3 +88,4 @@ int strverscmp(const char *l, const char *r) return (*l - *r); } } +#endif