diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c index 1171527..5e18d6f 100644 --- a/thunar/thunar-file.c +++ b/thunar/thunar-file.c @@ -3111,26 +3111,73 @@ thunar_file_destroy (ThunarFile *file) static gint compare_by_name_using_number (const gchar *ap, - const gchar *bp) + const gchar *bp, + gint leadingzero) { - guint anum; - guint bnum; + gsize alen; + gsize blen; - /* determine the numbers in ap and bp */ - anum = strtoul (ap, NULL, 10); - bnum = strtoul (bp, NULL, 10); + /* up until now the numbers match. Now compare the numbers by digit + * count, the longest number is the largest. If the length are equal + * just compare this digit. + */ + + /* determine digit count in ap and bp */ + alen = strspn (ap, "0123456789"); + blen = strspn (bp, "0123456789"); /* compare the numbers */ - if (anum < bnum) + if (alen < blen) return -1; - else if (anum > bnum) + else if (alen > blen) return 1; - /* the numbers are equal, and so the higher first digit should - * be sorted first, i.e. 'file10' before 'file010', since we - * also sort 'file10' before 'file011'. + /* if leading zeros were skipped *ap and *bp might equal. Use the + * leasingzero count instead. + */ + if (G_UNLIKELY (*ap == *bp)) + return leadingzero; + + /* the numbers are equal in length, and so the lower first digit should + * be sorted first. */ - return (*bp - *ap); + return (*ap - *bp); +} + + + +static gint +skip_leading_zeros (const gchar **ap, + const gchar *name) +{ + const gchar *bp; + gchar bc = '0'; + + /* **ap must be '0' when calling this function */ + + /* do a backward search to check if the number starts with a '0' */ + for (bp = *ap - 1; bp >= name; --bp) + { + bc = *bp; + if (bc != '0') + break; + } + + /* if the number starts with a '0' skip all following '0' */ + if (!g_ascii_isdigit (bc) || bc == '0') + { + for (bp = *ap + 1;; ++bp) + { + if (*bp != '0') + break; + } + + *ap = bp; + + return 1; + } + + return 0; } @@ -3232,7 +3279,19 @@ thunar_file_compare_by_name (const ThunarFile *file_a, * to get sorting 'file1', 'file5', 'file10' done the right way. */ if (g_ascii_isdigit (ac) && g_ascii_isdigit (bc)) - return compare_by_name_using_number (ap, bp); + { + gint leadingzero = 0; + /* only one of ac and bc can be '0' otherwise thay would be equal */ + if (G_UNLIKELY (ac == '0')) + { + leadingzero = skip_leading_zeros(&ap, thunar_file_get_display_name (file_a)); + } + else if (G_UNLIKELY (bc == '0')) + { + leadingzero = -skip_leading_zeros(&bp, thunar_file_get_display_name (file_b)); + } + return compare_by_name_using_number (ap, bp, leadingzero); + } /* a second case is '20 file' and '2file', where comparison by number * makes sense, if the previous char for both strings is a digit. @@ -3241,7 +3300,7 @@ thunar_file_compare_by_name (const ThunarFile *file_a, && bp > thunar_file_get_display_name (file_b) && g_ascii_isdigit (*(ap - 1)) && g_ascii_isdigit (*(bp - 1))) { - return compare_by_name_using_number (ap - 1, bp - 1); + return compare_by_name_using_number (ap - 1, bp - 1, 0); } } @@ -3273,8 +3332,8 @@ thunar_file_compare_by_name (const ThunarFile *file_a, /* transform the unicode chars to strings and * make sure the strings are nul-terminated. */ - abuf[g_unichar_to_utf8 (ac, abuf)] = '\0'; - bbuf[g_unichar_to_utf8 (bc, bbuf)] = '\0'; + abuf[g_unichar_to_utf8 (g_unichar_tolower(ac), abuf)] = '\0'; + bbuf[g_unichar_to_utf8 (g_unichar_tolower(bc), bbuf)] = '\0'; /* compare the unicode chars (as strings) */ return strcoll (abuf, bbuf);