[gnumeric] Fix locale specific sorting. [#638874]



commit 581f36434729dd80223af35743aef150be0d0b54
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Sun Jan 9 14:56:14 2011 -0700

    Fix locale specific sorting. [#638874]
    
    2011-01-09  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* src/sort.c (sort_compare_cells): add argument and use it to
    	  decide whether to use the cacheing version of value_compare
    	(sort_compare_sets): add argument and change all callers
    	(gnm_sort_contents): if we are not in the default locale, do not cache
    	  collation keys
    	* src/value.h (value_compare_no_cache): new
    	* src/value.c (value_compare_no_cache): new
    	(value_compare_real): new
    	(value_cmp): use value_compare_real
    	(value_compare): use value_compare_real
    	(gnm_string_cmp): new
    	(gnm_string_cmp_ignorecase): new

 ChangeLog   |   15 ++++++++++++
 NEWS        |    1 +
 src/sort.c  |   42 ++++++++++++++++++++++++---------
 src/value.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/value.h |    2 +
 5 files changed, 115 insertions(+), 18 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index aa056aa..1b75bf4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-01-09  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* src/sort.c (sort_compare_cells): add argument and use it to
+	  decide whether to use the cacheing version of value_compare
+	(sort_compare_sets): add argument and change all callers
+	(gnm_sort_contents): if we are not in the default locale, do not cache
+	  collation keys
+	* src/value.h (value_compare_no_cache): new
+	* src/value.c (value_compare_no_cache): new
+	(value_compare_real): new
+	(value_cmp): use value_compare_real
+	(value_compare): use value_compare_real
+	(gnm_string_cmp): new
+	(gnm_string_cmp_ignorecase): new
+	
 2011-01-08  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* src/item-edit.c (item_edit_draw): add NULL argument to call of
diff --git a/NEWS b/NEWS
index f79b56e..4fcee28 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Andreas:
 	* Fix leaks in potentially failing analysis tools.
 	* Make the row and column headers and selection match the theme better.
 	  [#639019]
+	* Fix locale specific sorting. [#638874]
 
 Jean:
 	* Only disable the formula bar when a chart sheet is selected. [#636031]
diff --git a/src/sort.c b/src/sort.c
index 59e6b98..716bcbe 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -1,3 +1,5 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
 /*
  * sort.c : Routines for sorting cell ranges
  *
@@ -47,7 +49,8 @@ gnm_sort_data_length (GnmSortData const *data)
 
 /* The routines to do the sorting */
 static int
-sort_compare_cells (GnmCell const *ca, GnmCell const *cb, GnmSortClause *clause)
+sort_compare_cells (GnmCell const *ca, GnmCell const *cb, 
+		    GnmSortClause *clause, gboolean default_locale)
 {
 	GnmValue *a, *b;
 	GnmValueType ta, tb;
@@ -75,7 +78,8 @@ sort_compare_cells (GnmCell const *ca, GnmCell const *cb, GnmSortClause *clause)
 	} else if (tb == VALUE_ERROR && ta != VALUE_ERROR) {
 		comp = IS_LESS;
 	} else {
-		comp = value_compare (a, b, clause->cs);
+		comp = default_locale ? value_compare (a, b, clause->cs)
+			: value_compare_no_cache (a, b, clause->cs);
 	}
 
 	if (comp == IS_LESS) {
@@ -88,7 +92,8 @@ sort_compare_cells (GnmCell const *ca, GnmCell const *cb, GnmSortClause *clause)
 }
 
 static int
-sort_compare_sets (GnmSortData const *data, int indexa, int indexb)
+sort_compare_sets (GnmSortData const *data, int indexa, int indexb,
+		   gboolean default_locale)
 {
 	GnmCell *ca, *cb;
 	int clause = 0;
@@ -113,7 +118,8 @@ sort_compare_sets (GnmSortData const *data, int indexa, int indexb)
 					     data->range->start.row + offset);
 		}
 
-		result = sort_compare_cells (ca, cb, &(data->clauses[clause]));
+		result = sort_compare_cells (ca, cb, &(data->clauses[clause]),
+					     default_locale);
 		if (result) {
 			return result;
 		}
@@ -130,7 +136,16 @@ sort_qsort_compare (void const *_a, void const *_b)
 	SortDataPerm const *a = (SortDataPerm const *)_a;
 	SortDataPerm const *b = (SortDataPerm const *)_b;
 
-	return sort_compare_sets (a->data, a->index, b->index);
+	return sort_compare_sets (a->data, a->index, b->index, TRUE);
+}
+
+static int
+sort_qsort_compare_in_locale (void const *_a, void const *_b)
+{
+	SortDataPerm const *a = (SortDataPerm const *)_a;
+	SortDataPerm const *b = (SortDataPerm const *)_b;
+
+	return sort_compare_sets (a->data, a->index, b->index, FALSE);
 }
 
 
@@ -285,19 +300,22 @@ gnm_sort_contents (GnmSortData *data, GOCmdContext *cc)
 	}
 
 	if (real_length > 1) {
-		char *old_locale = NULL;
-
 		if (data->locale) {
-			old_locale = g_strdup (go_setlocale (LC_ALL, NULL));
+			char *old_locale 
+				= g_strdup (go_setlocale (LC_ALL, NULL));
 			go_setlocale (LC_ALL, data->locale);
-		}
 
-		qsort (perm, real_length, sizeof (SortDataPerm), sort_qsort_compare);
+			qsort (perm, real_length, sizeof (SortDataPerm), 
+			       g_str_has_prefix 
+			       (old_locale, data->locale) 
+			       ? sort_qsort_compare
+			       : sort_qsort_compare_in_locale);
 
-		if (old_locale) {
 			go_setlocale (LC_ALL, old_locale);
 			g_free (old_locale);
-		}
+		} else
+			qsort (perm, real_length, sizeof (SortDataPerm), 
+			       sort_qsort_compare);
 	}
 
 	cur = 0;
diff --git a/src/value.c b/src/value.c
index c9611b6..3600be8 100644
--- a/src/value.c
+++ b/src/value.c
@@ -650,6 +650,12 @@ value_dup (GnmValue const *src)
 	return res;
 }
 
+static GnmValDiff
+value_compare_real (GnmValue const *a, GnmValue const *b, 
+		    gboolean case_sensitive,
+		    gboolean default_locale);
+
+
 /**
  * value_cmp :
  * @ptr_a :
@@ -662,7 +668,7 @@ value_cmp (void const *ptr_a, void const *ptr_b)
 {
 	GnmValue const *a = *(GnmValue const **)ptr_a;
 	GnmValue const *b = *(GnmValue const **)ptr_b;
-	switch (value_compare (a, b, TRUE)) {
+	switch (value_compare_real (a, b, TRUE, TRUE)) {
 	case IS_EQUAL :   return  0;
 	case IS_LESS :    return -1;
 	case IS_GREATER : return  1;
@@ -1224,6 +1230,37 @@ value_diff (GnmValue const *a, GnmValue const *b)
 	}
 }
 
+static int
+gnm_string_cmp (gconstpointer gstr_a, gconstpointer gstr_b)
+{
+	return (gstr_a == gstr_b)
+		? 0
+		: g_utf8_collate (((GOString const *)gstr_a)->str, 
+				  ((GOString const *)gstr_b)->str);
+}
+
+static int
+gnm_string_cmp_ignorecase (gconstpointer gstr_a, gconstpointer gstr_b)
+{
+	gchar *a;
+	gchar *b;
+	int res;
+	
+	if (gstr_a == gstr_b)
+		return 0;
+
+	a = g_utf8_casefold (((GOString const *)gstr_a)->str, -1);
+	b = g_utf8_casefold (((GOString const *)gstr_b)->str, -1);
+	
+	res = g_utf8_collate (a, b);
+
+	g_free (a);
+	g_free (b);
+
+	return res;
+}
+
+
 /**
  * value_compare :
  *
@@ -1233,8 +1270,10 @@ value_diff (GnmValue const *a, GnmValue const *b)
  *
  * IGNORES format.
  */
-GnmValDiff
-value_compare (GnmValue const *a, GnmValue const *b, gboolean case_sensitive)
+static GnmValDiff
+value_compare_real (GnmValue const *a, GnmValue const *b, 
+		    gboolean case_sensitive,
+		    gboolean default_locale)
 {
 	GnmValueType ta, tb;
 	int t;
@@ -1263,9 +1302,18 @@ value_compare (GnmValue const *a, GnmValue const *b, gboolean case_sensitive)
 
 		/* If both are strings compare as string */
 		case VALUE_STRING :
-			t = case_sensitive
-				? go_string_cmp (a->v_str.val, b->v_str.val)
-				: go_string_cmp_ignorecase (a->v_str.val, b->v_str.val);
+			t = (default_locale) ? 
+				(case_sensitive
+				 ? go_string_cmp 
+				 (a->v_str.val, b->v_str.val)
+				 : go_string_cmp_ignorecase 
+				 (a->v_str.val, b->v_str.val))
+				: (case_sensitive
+				   ? gnm_string_cmp 
+				   (a->v_str.val, b->v_str.val)
+				   : gnm_string_cmp_ignorecase 
+				   (a->v_str.val, b->v_str.val));
+					
 			if (t > 0)
 				return IS_GREATER;
 			else if (t < 0)
@@ -1315,6 +1363,19 @@ value_compare (GnmValue const *a, GnmValue const *b, gboolean case_sensitive)
 	}
 }
 
+GnmValDiff
+value_compare (GnmValue const *a, GnmValue const *b, gboolean case_sensitive)
+{
+	return value_compare_real (a, b, case_sensitive, TRUE);
+}
+
+GnmValDiff
+value_compare_no_cache (GnmValue const *a, GnmValue const *b, 
+			gboolean case_sensitive)
+{
+	return value_compare_real (a, b, case_sensitive, FALSE);
+}
+
 void
 value_set_fmt (GnmValue *v, GOFormat const *fmt)
 {
diff --git a/src/value.h b/src/value.h
index 9ed22da..5aee330 100644
--- a/src/value.h
+++ b/src/value.h
@@ -136,6 +136,8 @@ GnmValue   *value_dup		   (GnmValue const *v);
 gnm_float   value_diff		   (GnmValue const *a, GnmValue const *b);
 GnmValDiff  value_compare	   (GnmValue const *a, GnmValue const *b,
 				    gboolean case_sensitive);
+GnmValDiff  value_compare_no_cache (GnmValue const *a, GnmValue const *b,
+				    gboolean case_sensitive);
 int	    value_cmp		   (void const *ptr_a, void const *ptr_b);
 int	    value_cmp_reverse	   (void const *ptr_a, void const *ptr_b);
 gboolean    value_equal		   (GnmValue const *a, GnmValue const *b);



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