Index: firmware/common/strnatcmp.c =================================================================== --- firmware/common/strnatcmp.c (revision 20356) +++ firmware/common/strnatcmp.c (working copy) @@ -29,9 +29,8 @@ * negative chars in their default char type. * * - * Changes for Rockbox: - * This version is changed slightly to deal better with the datatypes, - * it does not equal to the original software. + * This version is changed to ignore leading zeros, it does not equal to the + * original software. */ #include @@ -51,146 +50,166 @@ /* These are defined as macros to make it easier to adapt this code to * different characters types or comparison functions. */ - static inline int nat_isdigit(int a) { - return isdigit(a); + return isdigit(a); } - static inline int -nat_isspace(int a) +nat_isalphanum(int a) { - return isspace(a); + return isalnum(a); } - static inline int -nat_toupper(int a) +nat_tolower(int a) { - return toupper(a); + return tolower(a); } - - static int compare_right(char const *a, char const *b) { - int bias = 0; - int ca, cb; + int bias = 0; + int ca, cb; - /* The longest run of digits wins. That aside, the greatest - value wins, but we can't know that it will until we've scanned - both numbers to know that they have the same magnitude, so we - remember it in BIAS. */ - for (;; a++, b++) { - ca = to_int(*a); - cb = to_int(*b); - if (!nat_isdigit(ca) && !nat_isdigit(cb)) - return bias; - else if (!nat_isdigit(ca)) - return -1; - else if (!nat_isdigit(cb)) - return +1; - else if (ca < cb) { - if (!bias) - bias = -1; - } else if (ca > cb) { - if (!bias) - bias = +1; - } else if (!ca && !cb) - return bias; - } + /* The longest run of digits wins. That aside, the greatest + value wins, but we can't know that it will until we've scanned + both numbers to know that they have the same magnitude, so we + remember it in BIAS. */ + for (;; a++, b++) + { + ca = to_int(*a); + cb = to_int(*b); + if (!nat_isdigit(ca) && !nat_isdigit(cb)) + return bias; + else if (!nat_isdigit(ca)) + return -1; + else if (!nat_isdigit(cb)) + return +1; + else if (ca < cb) + { + if (!bias) + bias = -1; + } + else if (ca > cb) + { + if (!bias) + bias = +1; + } + else if (!ca && !cb) + return bias; + } - return 0; + return 0; } - -static int -compare_left(char const *a, char const *b) -{ - /* Compare two left-aligned numbers: the first to have a - different value wins. */ - for (;; a++, b++) { - if (!nat_isdigit(*a) && !nat_isdigit(*b)) - return 0; - else if (!nat_isdigit(*a)) - return -1; - else if (!nat_isdigit(*b)) - return +1; - else if (*a < *b) - return -1; - else if (*a > *b) - return +1; - } - - return 0; -} - static int strnatcmp0(char const *a, char const *b, int fold_case) { - int ai, bi; - int ca, cb; - int fractional, result; + int ai, bi; + int ca, cb; + int ca_next, cb_next; + int result; + int zero_bias = 0; - assert(a && b); - ai = bi = 0; - while (1) { - ca = to_int(a[ai]); - cb = to_int(b[bi]); + assert(a && b); + ai = bi = 0; + while (1) + { + int zero_count = 0; + + ca = to_int(a[ai]); + cb = to_int(b[bi]); + + ca_next = to_int(a[ai+1]); + cb_next = to_int(b[bi+1]); - /* skip over leading spaces or zeros */ - while (nat_isspace(ca)) - ca = to_int(a[++ai]); +#if 1 + /* skip over leading zeros on numbers + 00 < 0b < 01 -> 0 < 0 < 1 */ + while ('0' == ca && nat_isdigit(ca_next) ) + { + ca = to_int(a[++ai]); + ca_next = to_int(a[ai+1]); + --zero_count; + } + + while ('0' == cb && nat_isdigit(cb_next) ) + { + cb = to_int(b[++bi]); + cb_next = to_int(b[bi+1]); + ++zero_count; + } +#else + /* skip over leading zeros on numbers and letters + 00 < 01 < 0b -> 0 < 1 < b */ + while ('0' == ca && nat_isalphanum(ca_next) ) + { + ca = to_int(a[++ai]); + ca_next = to_int(a[ai+1]); + --zero_count; + } + + while ('0' == cb && nat_isalphanum(cb_next) ) + { + cb = to_int(b[++bi]); + cb_next = to_int(b[bi+1]); + ++zero_count; + } +#endif + + /* store bias for later if nat compared strings are equal */ + if (0 != zero_count) + zero_bias = zero_count; + + /* process run of digits */ + if (nat_isdigit(ca) && nat_isdigit(cb)) + { + if ((result = compare_right(a+ai, b+bi)) != 0) + return result; + } + + /* The strings compare the same. */ + if (!ca && !cb) + { + /* Favor more leading zeros in first number */ + if (zero_bias) + return zero_bias; + + /* Call str[case]cmp() to ensure + consistent results. */ + if(fold_case) + return strcasecmp(a,b); + else + return strcmp(a,b); + } - while (nat_isspace(cb)) - cb = to_int(b[++bi]); + if (fold_case) + { + ca = nat_tolower(ca); + cb = nat_tolower(cb); + } + + if (ca < cb) + return -1; + else if (ca > cb) + return +1; - /* process run of digits */ - if (nat_isdigit(ca) && nat_isdigit(cb)) { - fractional = (ca == '0' || cb == '0'); - - if (fractional) { - if ((result = compare_left(a+ai, b+bi)) != 0) - return result; - } else { - if ((result = compare_right(a+ai, b+bi)) != 0) - return result; - } - } - - if (!ca && !cb) { - /* The strings compare the same. Call str[case]cmp() to ensure - consistent results. */ - if(fold_case) - return strcasecmp(a,b); - else - return strcmp(a,b); - } - - if (fold_case) { - ca = nat_toupper(ca); - cb = nat_toupper(cb); - } - - if (ca < cb) - return -1; - else if (ca > cb) - return +1; - - ++ai; ++bi; - } + ++ai; ++bi; + } } -int strnatcmp(const char *a, const char *b) { - return strnatcmp0(a, b, 0); +int strnatcmp(const char *a, const char *b) +{ + return strnatcmp0(a, b, 0); } /* Compare, recognizing numeric string and ignoring case. */ -int strnatcasecmp(const char *a, const char *b) { - return strnatcmp0(a, b, 1); +int strnatcasecmp(const char *a, const char *b) +{ + return strnatcmp0(a, b, 1); }