commit 36e7cab5b7a449113434b9422e22ba83a1bfa5b4
Author: Harald Fernengel <harald.fernengel@nokia.com>
Date:   Tue Nov 16 15:45:22 2010 +0100

    ICU support for strcoll
    
    This patch adds a new -icu configure option that uses ucol_strcoll
    for string collation instead of plain strcoll. This should fix most
    of the native language sorting problems we see at the moment.
    
    Reviewed-By: Robert Griebl

diff --git a/configure b/configure
index 5aab180..f0565e1 100755
--- a/configure
+++ b/configure
@@ -800,6 +800,7 @@ CFG_ALSA=auto
 CFG_PULSEAUDIO=auto
 CFG_COREWLAN=auto
 CFG_ICD=auto
+CFG_ICU=no
 
 # initalize variables used for installation
 QT_INSTALL_PREFIX=
@@ -958,7 +959,7 @@ while [ "$#" -gt 0 ]; do
         VAL=no
         ;;
     #Qt style yes options
-        -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles)
+    -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles|-icu)
         VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
         VAL=yes
         ;;
@@ -2243,6 +2244,13 @@ while [ "$#" -gt 0 ]; do
             UNKNOWN_OPT=yes
         fi
         ;;
+    icu)
+        if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then
+            CFG_ICU="$VAL"
+        else
+            UNKNOWN_OPT=yes
+        fi
+        ;;
     *)
         UNKNOWN_OPT=yes
         ;;
@@ -6998,6 +7006,10 @@ if [ "$CFG_ICD" = "yes" ]; then
     QT_CONFIG="$QT_CONFIG icd"
 fi
 
+if [ "$CFG_ICU" = "yes" ]; then
+    QT_CONFIG="$QT_CONFIG icu"
+fi
+
 #
 # Some Qt modules are too advanced in C++ for some old compilers
 # Detect here the platforms where they are known to work.
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 6b1de5e..a02b418 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -134,6 +134,10 @@ void qt_symbianUpdateSystemPrivate();
 void qt_symbianInitSystemLocale();
 #endif
 
+#ifdef QT_USE_ICU
+extern bool qt_initIcu(const QString &localeName);
+#endif
+
 /******************************************************************************
 ** Helpers for accessing Qt locale database
 */
@@ -2348,6 +2352,10 @@ void QLocale::setDefault(const QLocale &locale)
 {
     default_lp = locale.d();
     default_number_options = locale.numberOptions();
+
+#ifdef QT_USE_ICU
+    qt_initIcu(locale.name());
+#endif
 }
 
 /*!
diff --git a/src/corelib/tools/qlocale_icu.cpp b/src/corelib/tools/qlocale_icu.cpp
new file mode 100644
index 0000000..9ddb4b7
--- /dev/null
+++ b/src/corelib/tools/qlocale_icu.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+#include "qlibrary.h"
+#include "qdebug.h"
+
+#include "unicode/uversion.h"
+#include "unicode/ucol.h"
+
+QT_BEGIN_NAMESPACE
+
+typedef UCollator *(*Ptr_ucol_open)(const char *loc, UErrorCode *status);
+typedef void (*Ptr_ucol_close)(UCollator *coll);
+typedef UCollationResult (*Ptr_ucol_strcoll)(const UCollator *coll, const UChar *source, int32_t sourceLength, const UChar *target, int32_t targetLength);
+
+static Ptr_ucol_open ptr_ucol_open = 0;
+static Ptr_ucol_strcoll ptr_ucol_strcoll = 0;
+static Ptr_ucol_close ptr_ucol_close = 0;
+
+enum LibLoadStatus
+{
+    ErrorLoading = -1,
+    NotLoaded = 0,
+    Loaded = 1
+};
+
+static LibLoadStatus status = NotLoaded;
+
+static UCollator *icuCollator = 0;
+
+#define STRINGIFY2(x) #x
+#define STRINGIFY(x) STRINGIFY2(x)
+
+bool qt_initIcu(const QString &localeString)
+{
+    if (status == ErrorLoading)
+        return false;
+
+    if (status == NotLoaded) {
+
+        QLibrary lib(QLatin1String("icui18n"), QLatin1String(U_ICU_VERSION_SHORT));
+        if (!lib.load()) {
+            qWarning() << "Unable to load library icui18n" << lib.errorString();
+            status = ErrorLoading;
+            return false;
+        }
+
+        ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open");
+        ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close");
+        ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll");
+
+        if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) {
+            // try again with decorated symbol names
+            ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open" STRINGIFY(U_ICU_VERSION_SUFFIX));
+            ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close" STRINGIFY(U_ICU_VERSION_SUFFIX));
+            ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll" STRINGIFY(U_ICU_VERSION_SUFFIX));
+        }
+
+        if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) {
+            ptr_ucol_open = 0;
+            ptr_ucol_close = 0;
+            ptr_ucol_strcoll = 0;
+
+            qWarning("Unable to find symbols in icui18n");
+            status = ErrorLoading;
+            return false;
+        }
+
+        // success :)
+        status = Loaded;
+    }
+
+    if (icuCollator) {
+        ptr_ucol_close(icuCollator);
+        icuCollator = 0;
+    }
+
+    UErrorCode icuStatus = U_ZERO_ERROR;
+    icuCollator = ptr_ucol_open(localeString.toLatin1().constData(), &icuStatus);
+
+    if (!icuCollator) {
+        qWarning("Unable to open locale %s in ICU, error code %d", qPrintable(localeString), icuStatus);
+        return false;
+    }
+
+    return true;
+}
+
+bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result)
+{
+    Q_ASSERT(result);
+    Q_ASSERT(source);
+    Q_ASSERT(target);
+
+    if (!icuCollator)
+        return false;
+
+    *result = ptr_ucol_strcoll(icuCollator, reinterpret_cast<const UChar *>(source), int32_t(sourceLength),
+                               reinterpret_cast<const UChar *>(target), int32_t(targetLength));
+
+    return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index d4a1248..654e934 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -112,6 +112,11 @@ int qFindString(const QChar *haystack, int haystackLen, int from,
 int qFindStringBoyerMoore(const QChar *haystack, int haystackLen, int from,
     const QChar *needle, int needleLen, Qt::CaseSensitivity cs);
 
+#ifdef QT_USE_ICU
+// qlocale_icu.cpp
+extern bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result);
+#endif
+
 
 // Unicode case-insensitive comparison
 static int ucstricmp(const ushort *a, const ushort *ae, const ushort *b, const ushort *be)
@@ -4807,6 +4812,14 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
     TPtrC p2 = TPtrC16(reinterpret_cast<const TUint16 *>(data2), length2);
     return p1.CompareC(p2);
 #elif defined(Q_OS_UNIX)
+#  if defined(QT_USE_ICU)
+    int res;
+    if (qt_ucol_strcoll(data1, length1, data2, length2, &res)) {
+        if (res == 0)
+            res = ucstrcmp(data1, length1, data2, length2);
+        return res;
+    } // else fall through
+#  endif
     // declared in <string.h>
     int delta = strcoll(toLocal8Bit_helper(data1, length1), toLocal8Bit_helper(data2, length2));
     if (delta == 0)
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index d81ab04..46c39f3 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -92,6 +92,11 @@ else:SOURCES += tools/qelapsedtimer_generic.cpp
 contains(QT_CONFIG, zlib):include($$PWD/../../3rdparty/zlib.pri)
 else:include($$PWD/../../3rdparty/zlib_dependency.pri)
 
+contains(QT_CONFIG,icu) {
+    SOURCES += tools/qlocale_icu.cpp
+    DEFINES += QT_USE_ICU
+}
+
 DEFINES += HB_EXPORT=Q_CORE_EXPORT
 INCLUDEPATH += ../3rdparty/harfbuzz/src
 HEADERS += ../3rdparty/harfbuzz/src/harfbuzz.h
