diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2013-05-10 18:52:23 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2013-05-10 18:52:23 +0400 |
commit | 65ed588c8b68b4bbea0e48a0222f5e8844774bd9 (patch) | |
tree | 7f57fe941e77981bc6fbedf8837a742764b83db1 | |
parent | 384adf39b9b75f08aee1a399ff81e5671b06794c (diff) |
Fix #35270: files with numbers higher than 2147483648 or with different numbers
of leading zeros but otherwise the same would show in random order in the file
browser. Selecting an item would change the order of all the items.
Problem was that it was comparing by parsing the number into an int, which has
only limited precision and does not care about the number of leading zeros. Now
do the comparison directly on the string.
-rw-r--r-- | source/blender/blenlib/intern/string.c | 62 |
1 files changed, 50 insertions, 12 deletions
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 0982670eb5a..ed11d122e93 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -433,13 +433,57 @@ int BLI_strncasecmp(const char *s1, const char *s2, size_t len) return 0; } +/* compare number on the left size of the string */ +static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker) +{ + const char *p1 = s1, *p2 = s2; + int numdigit, numzero1, numzero2; + + /* count and skip leading zeros */ + for (numzero1 = 0; *p1 && (*p1 == '0'); numzero1++) + p1++; + for (numzero2 = 0; *p2 && (*p2 == '0'); numzero2++) + p2++; + + /* find number of consecutive digits */ + for (numdigit = 0; ; numdigit++) { + if (isdigit(*(p1 + numdigit)) && isdigit(*(p2 + numdigit))) + continue; + else if (isdigit(*(p1 + numdigit))) + return 1; /* s2 is bigger */ + else if (isdigit(*(p2 + numdigit))) + return -1; /* s1 is bigger */ + else + break; + } + + /* same number of digits, compare size of number */ + if (numdigit > 0) { + int compare = strncmp(p1, p2, numdigit); + + if (compare != 0) + return compare; + } + + /* use number of leading zeros as tie breaker if still equal */ + if (*tiebreaker == 0) { + if (numzero1 > numzero2) + *tiebreaker = 1; + else if (numzero1 < numzero2) + *tiebreaker = -1; + } + + return 0; +} + /* natural string compare, keeping numbers in order */ int BLI_natstrcmp(const char *s1, const char *s2) { register int d1 = 0, d2 = 0; register char c1, c2; + int tiebreaker = 0; - /* if both chars are numeric, to a strtol(). + /* if both chars are numeric, to a left_number_strcmp(). * then increase string deltas as long they are * numeric, else do a tolower and char compare */ @@ -448,17 +492,11 @@ int BLI_natstrcmp(const char *s1, const char *s2) c2 = tolower(s2[d2]); if (isdigit(c1) && isdigit(c2) ) { - int val1, val2; - - val1 = (int)strtol(s1 + d1, (char **)NULL, 10); - val2 = (int)strtol(s2 + d2, (char **)NULL, 10); + int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker); - if (val1 < val2) { - return -1; - } - else if (val1 > val2) { - return 1; - } + if (numcompare != 0) + return numcompare; + d1++; while (isdigit(s1[d1]) ) d1++; @@ -487,7 +525,7 @@ int BLI_natstrcmp(const char *s1, const char *s2) d1++; d2++; } - return 0; + return tiebreaker; } void BLI_timestr(double _time, char *str, size_t maxlen) |