X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgunicollate.c;h=f9d8b3df048faffb9e5b318daef9e9eae9c4ae99;hb=9f5afe3966d31ef6f1e880d950206a0325e6c777;hp=13a8ed5b80047fb1e5df5e228e52a1a7c10f2f94;hpb=c795837524011471eb3a1287994720205678da3a;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gunicollate.c b/glib/gunicollate.c index 13a8ed5..f9d8b3d 100644 --- a/glib/gunicollate.c +++ b/glib/gunicollate.c @@ -14,8 +14,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with the Gnome Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * see . */ #include "config.h" @@ -26,16 +25,28 @@ #include #endif -#include "glib.h" +#ifdef HAVE_CARBON +#include +#endif + +#include "gmem.h" +#include "gunicode.h" #include "gunicodeprivate.h" -#include "galias.h" +#include "gstring.h" +#include "gstrfuncs.h" +#include "gtestutils.h" +#include "gcharset.h" +#ifndef __STDC_ISO_10646__ +#include "gconvert.h" +#endif + #ifdef _MSC_VER /* Workaround for bug in MSVCR80.DLL */ -static size_t +static gsize msc_strxfrm_wrapper (char *string1, const char *string2, - size_t count) + gsize count) { if (!string1 || count <= 0) { @@ -54,22 +65,44 @@ msc_strxfrm_wrapper (char *string1, * @str2: a UTF-8 encoded string * * Compares two strings for ordering using the linguistically - * correct rules for the current locale. When sorting a large - * number of strings, it will be significantly faster to - * obtain collation keys with g_utf8_collate_key() and - * compare the keys with strcmp() when - * sorting instead of sorting the original strings. + * correct rules for the [current locale][setlocale]. + * When sorting a large number of strings, it will be significantly + * faster to obtain collation keys with g_utf8_collate_key() and + * compare the keys with strcmp() when sorting instead of sorting + * the original strings. * - * Return value: < 0 if @str1 compares before @str2, - * 0 if they compare equal, > 0 if @str1 compares after @str2. + * Returns: < 0 if @str1 compares before @str2, + * 0 if they compare equal, > 0 if @str1 compares after @str2. **/ gint g_utf8_collate (const gchar *str1, const gchar *str2) { gint result; - -#ifdef __STDC_ISO_10646__ + +#ifdef HAVE_CARBON + + UniChar *str1_utf16; + UniChar *str2_utf16; + glong len1; + glong len2; + SInt32 retval = 0; + + g_return_val_if_fail (str1 != NULL, 0); + g_return_val_if_fail (str2 != NULL, 0); + + str1_utf16 = g_utf8_to_utf16 (str1, -1, NULL, &len1, NULL); + str2_utf16 = g_utf8_to_utf16 (str2, -1, NULL, &len2, NULL); + + UCCompareTextDefault (kUCCollateStandardOptions, + str1_utf16, len1, str2_utf16, len2, + NULL, &retval); + result = retval; + + g_free (str2_utf16); + g_free (str1_utf16); + +#elif defined(__STDC_ISO_10646__) gunichar *str1_norm; gunichar *str2_norm; @@ -127,7 +160,7 @@ g_utf8_collate (const gchar *str1, return result; } -#ifdef __STDC_ISO_10646__ +#if defined(__STDC_ISO_10646__) || defined(HAVE_CARBON) /* We need UTF-8 encoding of numbers to encode the weights if * we are using wcsxfrm. However, we aren't encoding Unicode * characters, so we can't simply use g_unichar_to_utf8. @@ -174,7 +207,148 @@ utf8_encode (char *buf, wchar_t val) return retval; } -#endif /* __STDC_ISO_10646__ */ +#endif /* __STDC_ISO_10646__ || HAVE_CARBON */ + +#ifdef HAVE_CARBON + +static gchar * +collate_key_to_string (UCCollationValue *key, + gsize key_len) +{ + gchar *result; + gsize result_len = 0; + const gsize start = 2 * sizeof (void *) / sizeof (UCCollationValue); + gsize i; + + /* The first codes should be skipped: the same string on the same + * system can get different values at runtime in those positions, + * and they do not sort correctly. The exact size of the prefix + * depends on whether we are building 64 or 32 bit. + */ + if (key_len <= start) + return g_strdup (""); + + for (i = start; i < key_len; i++) + result_len += utf8_encode (NULL, g_htonl (key[i] + 1)); + + result = g_malloc (result_len + 1); + result_len = 0; + for (i = start; i < key_len; i++) + result_len += utf8_encode (result + result_len, g_htonl (key[i] + 1)); + + result[result_len] = '\0'; + + return result; +} + +static gchar * +carbon_collate_key_with_collator (const gchar *str, + gssize len, + CollatorRef collator) +{ + UniChar *str_utf16 = NULL; + glong len_utf16; + OSStatus ret; + UCCollationValue staticbuf[512]; + UCCollationValue *freeme = NULL; + UCCollationValue *buf; + ItemCount buf_len; + ItemCount key_len; + ItemCount try_len; + gchar *result = NULL; + + str_utf16 = g_utf8_to_utf16 (str, len, NULL, &len_utf16, NULL); + try_len = len_utf16 * 5 + 2; + + if (try_len <= sizeof staticbuf) + { + buf = staticbuf; + buf_len = sizeof staticbuf; + } + else + { + freeme = g_new (UCCollationValue, try_len); + buf = freeme; + buf_len = try_len; + } + + ret = UCGetCollationKey (collator, str_utf16, len_utf16, + buf_len, &key_len, buf); + + if (ret == kCollateBufferTooSmall) + { + freeme = g_renew (UCCollationValue, freeme, try_len * 2); + buf = freeme; + buf_len = try_len * 2; + ret = UCGetCollationKey (collator, str_utf16, len_utf16, + buf_len, &key_len, buf); + } + + if (ret == 0) + result = collate_key_to_string (buf, key_len); + else + result = g_strdup (""); + + g_free (freeme); + g_free (str_utf16); + return result; +} + +static gchar * +carbon_collate_key (const gchar *str, + gssize len) +{ + static CollatorRef collator; + + if (G_UNLIKELY (!collator)) + { + UCCreateCollator (NULL, 0, kUCCollateStandardOptions, &collator); + + if (!collator) + { + static gboolean been_here; + if (!been_here) + g_warning ("%s: UCCreateCollator failed", G_STRLOC); + been_here = TRUE; + return g_strdup (""); + } + } + + return carbon_collate_key_with_collator (str, len, collator); +} + +static gchar * +carbon_collate_key_for_filename (const gchar *str, + gssize len) +{ + static CollatorRef collator; + + if (G_UNLIKELY (!collator)) + { + /* http://developer.apple.com/qa/qa2004/qa1159.html */ + UCCreateCollator (NULL, 0, + kUCCollateComposeInsensitiveMask + | kUCCollateWidthInsensitiveMask + | kUCCollateCaseInsensitiveMask + | kUCCollateDigitsOverrideMask + | kUCCollateDigitsAsNumberMask + | kUCCollatePunctuationSignificantMask, + &collator); + + if (!collator) + { + static gboolean been_here; + if (!been_here) + g_warning ("%s: UCCreateCollator failed", G_STRLOC); + been_here = TRUE; + return g_strdup (""); + } + } + + return carbon_collate_key_with_collator (str, len, collator); +} + +#endif /* HAVE_CARBON */ /** * g_utf8_collate_key: @@ -184,11 +358,14 @@ utf8_encode (char *buf, wchar_t val) * Converts a string into a collation key that can be compared * with other collation keys produced by the same function using * strcmp(). + * * The results of comparing the collation keys of two strings - * with strcmp() will always be the same as - * comparing the two original keys with g_utf8_collate(). + * with strcmp() will always be the same as comparing the two + * original keys with g_utf8_collate(). * - * Return value: a newly allocated string. This string should + * Note that this function depends on the [current locale][setlocale]. + * + * Returns: a newly allocated string. This string should * be freed with g_free() when you are done with it. **/ gchar * @@ -196,31 +373,34 @@ g_utf8_collate_key (const gchar *str, gssize len) { gchar *result; - size_t xfrm_len; - -#ifdef __STDC_ISO_10646__ +#ifdef HAVE_CARBON + + g_return_val_if_fail (str != NULL, NULL); + result = carbon_collate_key (str, len); + +#elif defined(__STDC_ISO_10646__) + + gsize xfrm_len; gunichar *str_norm; wchar_t *result_wc; - size_t i; - size_t result_len = 0; + gsize i; + gsize result_len = 0; g_return_val_if_fail (str != NULL, NULL); str_norm = _g_utf8_normalize_wc (str, len, G_NORMALIZE_ALL_COMPOSE); - setlocale (LC_COLLATE, ""); - xfrm_len = wcsxfrm (NULL, (wchar_t *)str_norm, 0); result_wc = g_new (wchar_t, xfrm_len + 1); wcsxfrm (result_wc, (wchar_t *)str_norm, xfrm_len + 1); - for (i=0; i < xfrm_len; i++) + for (i = 0; i < xfrm_len; i++) result_len += utf8_encode (NULL, result_wc[i]); result = g_malloc (result_len + 1); result_len = 0; - for (i=0; i < xfrm_len; i++) + for (i = 0; i < xfrm_len; i++) result_len += utf8_encode (result + result_len, result_wc[i]); result[result_len] = '\0'; @@ -231,6 +411,7 @@ g_utf8_collate_key (const gchar *str, return result; #else /* !__STDC_ISO_10646__ */ + gsize xfrm_len; const gchar *charset; gchar *str_norm; @@ -238,11 +419,16 @@ g_utf8_collate_key (const gchar *str, str_norm = g_utf8_normalize (str, len, G_NORMALIZE_ALL_COMPOSE); + result = NULL; + if (g_get_charset (&charset)) { xfrm_len = strxfrm (NULL, str_norm, 0); - result = g_malloc (xfrm_len + 1); - strxfrm (result, str_norm, xfrm_len + 1); + if (xfrm_len >= 0 && xfrm_len < G_MAXINT - 2) + { + result = g_malloc (xfrm_len + 1); + strxfrm (result, str_norm, xfrm_len + 1); + } } else { @@ -265,14 +451,15 @@ g_utf8_collate_key (const gchar *str, g_free (str_locale); } - else - { - xfrm_len = strlen (str_norm); - result = g_malloc (xfrm_len + 2); - result[0] = 'B'; - memcpy (result + 1, str_norm, xfrm_len); - result[xfrm_len+1] = '\0'; - } + } + + if (!result) + { + xfrm_len = strlen (str_norm); + result = g_malloc (xfrm_len + 2); + result[0] = 'B'; + memcpy (result + 1, str_norm, xfrm_len); + result[xfrm_len+1] = '\0'; } g_free (str_norm); @@ -282,9 +469,9 @@ g_utf8_collate_key (const gchar *str, } /* This is a collation key that is very very likely to sort before any - collation key that libc strxfrm generates. We use this before any - special case (dot or number) to make sure that its sorted before - anything else. + * collation key that libc strxfrm generates. We use this before any + * special case (dot or number) to make sure that its sorted before + * anything else. */ #define COLLATION_SENTINEL "\1\1\1" @@ -302,16 +489,19 @@ g_utf8_collate_key (const gchar *str, * "event.h" instead of "event.c" "event.h" "eventgenerator.c". Also, we * would like to treat numbers intelligently so that "file1" "file10" "file5" * is sorted as "file1" "file5" "file10". + * + * Note that this function depends on the [current locale][setlocale]. * - * Return value: a newly allocated string. This string should + * Returns: a newly allocated string. This string should * be freed with g_free() when you are done with it. * * Since: 2.8 */ -gchar* +gchar * g_utf8_collate_key_for_filename (const gchar *str, gssize len) { +#ifndef HAVE_CARBON GString *result; GString *append; const gchar *p; @@ -483,8 +673,7 @@ g_utf8_collate_key_for_filename (const gchar *str, g_string_free (append, TRUE); return g_string_free (result, FALSE); +#else /* HAVE_CARBON */ + return carbon_collate_key_for_filename (str, len); +#endif } - - -#define __G_UNICOLLATE_C__ -#include "galiasdef.c"