Fix for case sensitive sort



Hello!

I have investigated the problem with strcoll() and it appears that there
is a graceful (to a certain extent) solution.

MC gives the user choice between case sensitive and case insensitive sort.
There is no localized case sensitive sort, so strcmp() should be used for
that.

In the remaining case of case insensitive strcoll() is preferred since it
respects the user settings, but it's not case insensitive in the POSIX
locale.

On the other hand, POSIX locale is where g_strcasecmp() shines.  However,
it doesn't work well in some non-C locales (e.g. Turkish).

Solution: use strcoll() if it's case insensitive (i.e. it does what the
user has requested in the MC menu), but if it's case sensitive, then use
g_strcasecmp() from Glib.

-- 
Regards,
Pavel Roskin

------------------------------------------------
--- ChangeLog
+++ ChangeLog
@@ -1 +1,8 @@
+2001-08-12  Pavel Roskin  <proski gnu org>
+
+	* dir.c (string_sortcomp) [HAVE_STRCOLL]: Always use strcmp()
+	for case sensitive sort.  For case insensitive sort use
+	strcoll() if it's case insensitive for ASCII and g_strcasecmp()
+	otherwise.
+
 2001-08-11  Pavel Roskin  <proski gnu org>
--- dir.c
+++ dir.c
@@ -76,14 +76,44 @@ sort_orders_t sort_orders [SORT_TYPES_TO
     { N_("&Group"),       sort_group }
 };

+#ifdef HAVE_STRCOLL
 /*
- * FIXME: strcoll() is not case sensitive in some locales, including en_US.
- * The user gets a "choice" between two case insensitive sorts.
- * Ideally, the user should be able to select between all three functions -
- * strcoll() (if available), strcmp() and g_strcasecmp().
+ * g_strcasecmp() doesn't work well in some locales because it relies on
+ * the locale-specific toupper().  On the other hand, strcoll() is case
+ * sensitive in the "C" and "POSIX" locales, unlike other locales.
+ * Solution: always use strcmp() for case sensitive sort.  For case
+ * insensitive sort use strcoll() if it's case insensitive for ASCII and
+ * g_strcasecmp() otherwise.
  */
-#ifdef HAVE_STRCOLL
-#define string_sortcomp(a,b) (case_sensitive ? strcoll (a,b) : g_strcasecmp (a,b))
+typedef enum {
+    STRCOLL_NO,
+    STRCOLL_YES,
+    STRCOLL_TEST
+} strcoll_status;
+
+int string_sortcomp (char *str1, char *str2)
+{
+    static strcoll_status use_strcoll = STRCOLL_TEST;
+
+    if (case_sensitive) {
+	return strcmp (str1, str2);
+    }
+
+    /* Initialize use_strcoll once.  */
+    if (use_strcoll == STRCOLL_TEST) {
+	/* Only use strcoll() if it considers "B" between "a" and "c".  */
+	if (strcoll ("a", "B") * strcoll ("B", "c") > 0) {
+	    use_strcoll = STRCOLL_YES;
+	} else {
+	    use_strcoll = STRCOLL_NO;
+	}
+    }
+
+    if (use_strcoll == STRCOLL_NO)
+	return g_strcasecmp (str1, str2);
+    else
+	return strcoll (str1, str2);
+}
 #else
 #define string_sortcomp(a,b) (case_sensitive ? strcmp (a,b) : g_strcasecmp (a,b))
 #endif
------------------------------------------------





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]