2003-10-09 Dick Porter <dick@ximian.com>
authorDick Porter <dick@acm.org>
Thu, 9 Oct 2003 21:00:27 +0000 (21:00 -0000)
committerDick Porter <dick@acm.org>
Thu, 9 Oct 2003 21:00:27 +0000 (21:00 -0000)
* acconfig.h:
* configure.in: Check for ICU availability

2003-10-09  Dick Porter  <dick@ximian.com>

* icall.c:
* locales.h:
* locales.c: Internal calls for constructing CultureInfo and
related objects from libicu (if its available.)

svn path=/trunk/mono/; revision=18818

ChangeLog
acconfig.h
configure.in
mono/interpreter/Makefile.am
mono/metadata/ChangeLog
mono/metadata/Makefile.am
mono/metadata/icall.c
mono/metadata/locales.c [new file with mode: 0644]
mono/metadata/locales.h [new file with mode: 0644]
mono/mini/Makefile.am

index 3ac5253edbc0b6c58e071cd4a7dca6f575b74365..9e2faeeb70c224fdf057001f5aea2c4e759a0e67 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-10-09  Dick Porter  <dick@ximian.com>
+
+       * acconfig.h:
+       * configure.in: Check for ICU availability
+
 2003-10-09  Bernie Solomon  <bernard@ugsolutions.com>
 
        * mono/tests/libtest.c: fix after merge of pinvoke2.cs
index c3084fbaa3bb38d661642b5ded5daa883f0c966e..270e2cc06bb33d4fed8db73a16996efac0f42884 100644 (file)
@@ -27,3 +27,4 @@
 #undef HAVE_GC_GCJ_MALLOC
 #undef WITH_BUNDLE
 #undef HAVE_GETHOSTBYNAME2_R
+#undef HAVE_ICU
index d295453888f9fdbc3d4cb8321f184af2cb6836d7..93bf79e497a33731d4eb7a86d73654e7eea94955 100644 (file)
@@ -649,6 +649,19 @@ if test "x$try_shared_handles" != "xyes"; then
        AC_SUBST(DISABLE_SHARED_HANDLES)
 fi
 
+ICU_CFLAGS=""
+ICU_LIBS=""
+AC_PATH_PROG(ICU_CONFIG, icu-config, no)
+if test "x$ICU_CONFIG" = "xno"; then
+       AC_MSG_WARN([Only invariant locale available; install ICU for I18N support])
+else
+       AC_DEFINE(HAVE_ICU)
+       ICU_CFLAGS=`$ICU_CONFIG --cppflags`
+       ICU_LIBS=`$ICU_CONFIG --ldflags`
+fi
+AC_SUBST(ICU_CFLAGS)
+AC_SUBST(ICU_LIBS)
+
 TARGET="unknown"
 ACCESS_UNALIGNED="yes"
 
index a0b67be9a67734ff23883af07caa32615f0fd9b2..0b34c78088e983448b6fd4dd36cfb35b9aeb31e3 100644 (file)
@@ -28,6 +28,7 @@ mint_LDADD =                          \
        $(LIBGC_LIBS)                   \
        $(GLIB_LIBS)                    \
        $(GMODULE_LIBS)                 \
+       $(ICU_LIBS)                     \
        -lm
 
 man_MANS = mint.1
index 0e72eb98de62707ea2af91a04b7dc41c16eb89fe..95f56523d31ec5813a99cf2d99a43d823f343bf2 100644 (file)
@@ -1,3 +1,10 @@
+2003-10-09  Dick Porter  <dick@ximian.com>
+
+       * icall.c:
+       * locales.h:
+       * locales.c: Internal calls for constructing CultureInfo and
+       related objects from libicu (if its available.)
+
 2003-10-09  Zoltan Varga  <vargaz@freemail.hu>
 
        * debug-helpers.c (wrapper_type_names): Add 'unknown' wrapper type.
index fb3dd8f9b2d5fc33ce7e1960e0b136097b73aa40..b4ed2d983ba5084ce47034ab5d5bc2977738016b 100644 (file)
@@ -18,7 +18,7 @@ bin_PROGRAMS = monosn pedump
 noinst_LTLIBRARIES = libmetadata.la libmonoruntime.la
 
 
-INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) $(ICU_CFLAGS) \
        -DMONO_ASSEMBLIES=\"$(assembliesdir)\" -DMONO_CFG_DIR=\"$(confdir)\"
 
 if WITH_BUNDLE
@@ -69,7 +69,9 @@ libmonoruntime_la_SOURCES = \
        process.c       \
        process.h       \
        environment.c   \
-       environment.h
+       environment.h   \
+       locales.c       \
+       locales.h
 
 libmetadata_la_SOURCES = \
        assembly.c      \
@@ -101,7 +103,8 @@ libmonoruntimeinclude_HEADERS = \
        threads-types.h \
        threads.h       \
        environment.h   \
-       monitor.h
+       monitor.h       \
+       locales.h
 
 libmetadatainclude_HEADERS = \
        assembly.h      \
index 9c5fb2d7ac6ae2b5d6c6b4e7df45a9066b7324c2..2508ba8ae5dd25fd2239ddc6192cff0fa083793e 100644 (file)
@@ -41,6 +41,7 @@
 #include <mono/metadata/process.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/profiler-private.h>
+#include <mono/metadata/locales.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/strtod.h>
 
@@ -4503,6 +4504,15 @@ static gconstpointer icall_map [] = {
        "System.Web.Util.ICalls::GetMachineInstallDirectory",
        ves_icall_System_Web_Util_ICalls_get_machine_install_dir,
 
+       /*
+        * System.Globalization
+        */
+       "System.Globalization.CultureInfo::construct_internal_locale(string)", ves_icall_System_Globalization_CultureInfo_construct_internal_locale,
+       "System.Globalization.CultureInfo::construct_compareinfo(object,string)", ves_icall_System_Globalization_CultureInfo_construct_compareinfo,
+       "System.Globalization.CompareInfo::internal_compare(string,string,System.Globalization.CompareOptions)", ves_icall_System_Globalization_CompareInfo_internal_compare,
+       "System.Globalization.CompareInfo::free_internal_collator()", ves_icall_System_Globalization_CompareInfo_free_internal_collator,
+       "System.Globalization.CompareInfo::assign_sortkey(object,string,System.Globalization.CompareOptions)", ves_icall_System_Globalization_CompareInfo_assign_sortkey,
+
        /*
         * add other internal calls here
         */
diff --git a/mono/metadata/locales.c b/mono/metadata/locales.c
new file mode 100644 (file)
index 0000000..3f3955e
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * locales.c: Culture-sensitive handling
+ *
+ * Author:
+ *     Dick Porter (dick@ximian.com)
+ *
+ * (C) 2003 Ximian, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/object.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/exception.h>
+#include <mono/metadata/locales.h>
+
+#define DEBUG
+
+static void set_field_by_name (MonoObject *obj, const guchar *fieldname,
+                              gpointer value)
+{
+       MonoClassField *field;
+
+       field=mono_class_get_field_from_name (mono_object_class (obj),
+                                             fieldname);
+       mono_field_set_value (obj, field, value);
+}
+
+static gpointer get_field_by_name (MonoObject *obj, const guchar *fieldname)
+{
+       MonoClassField *field;
+       gpointer ret;
+       
+       field=mono_class_get_field_from_name (mono_object_class (obj),
+                                             fieldname);
+       mono_field_get_value (obj, field, &ret);
+       return(ret);
+}
+
+#ifdef HAVE_ICU
+
+#include <unicode/utypes.h>
+#include <unicode/ustring.h>
+#include <unicode/ures.h>
+#include <unicode/ucnv.h>
+#include <unicode/ucol.h>
+
+static MonoString *monostring_from_UChars (const UChar *res_str,
+                                          UConverter *conv)
+{
+       MonoString *str;
+       UErrorCode ec;
+       char *utf16_str;
+       int32_t ret, utf16_strlen;
+       
+       utf16_strlen=u_strlen (res_str)*ucnv_getMaxCharSize (conv)+2;
+       utf16_str=(char *)g_malloc0 (sizeof(char)*utf16_strlen);
+       
+       ec=U_ZERO_ERROR;
+       ret=ucnv_fromUChars (conv, utf16_str, utf16_strlen, res_str, -1, &ec);
+       if(ec==U_BUFFER_OVERFLOW_ERROR ||
+          ec==U_STRING_NOT_TERMINATED_WARNING) {
+               /* This should never happen, cos we gave ourselves the
+                * maximum length needed above
+                */
+               g_assert_not_reached ();
+       }
+       
+       str=mono_string_from_utf16 ((gunichar2 *)utf16_str);
+       
+       g_free (utf16_str);
+       
+       return(str);
+}
+
+static UChar *monostring_to_UChars (const MonoString *str, UConverter *conv)
+{
+       UErrorCode ec;
+       UChar *dest;
+       int32_t ret, dest_strlen;
+       
+       /* Add 1 for the trailing NULL */
+       dest_strlen=mono_string_length (str)+1;
+       dest=(UChar *)g_malloc0 (sizeof(UChar)*dest_strlen);
+       
+       ec=U_ZERO_ERROR;
+       /* mono_string_length()*2 because its counting bytes not chars */
+       ret=ucnv_toUChars (conv, dest, dest_strlen,
+                          (const char *)mono_string_chars (str),
+                          mono_string_length (str)*2, &ec);
+       if(ec==U_BUFFER_OVERFLOW_ERROR ||
+          ec==U_STRING_NOT_TERMINATED_WARNING) {
+               /* This should never happen, cos we gave ourselves the
+                * length needed above
+                */
+               g_assert_not_reached ();
+       }
+       
+       return(dest);
+}
+
+static MonoString *monostring_from_resource_index (const UResourceBundle *bundle, UConverter *conv, int32_t idx)
+{
+       const UChar *res_str;
+       int32_t res_strlen;
+       UErrorCode ec;
+       
+       ec=U_ZERO_ERROR;
+       res_str=ures_getStringByIndex (bundle, idx, &res_strlen, &ec);
+       if(U_FAILURE (ec)) {
+               return(NULL);
+       }
+
+       return(monostring_from_UChars (res_str, conv));
+}
+
+static UResourceBundle *open_subbundle (const UResourceBundle *bundle,
+                                       const char *name, int32_t req_count)
+{
+       UResourceBundle *subbundle;
+       UErrorCode ec;
+       int32_t count;
+       
+       ec=U_ZERO_ERROR;
+       subbundle=ures_getByKey (bundle, name, NULL, &ec);
+       if(U_FAILURE (ec)) {
+               /* Couldn't find the subbundle */
+               return(NULL);
+       }
+       
+       count=ures_countArrayItems (bundle, name, &ec);
+       if(U_FAILURE (ec)) {
+               /* Couldn't count the subbundle */
+               ures_close (subbundle);
+               return(NULL);
+       }
+       
+       if(count!=req_count) {
+               /* Bummer */
+               ures_close (subbundle);
+               return(NULL);
+       }
+
+       return(subbundle);
+}
+
+static void set_array (MonoObject *obj, const guchar *fieldname,
+                      const UResourceBundle *bundle, const char *resname,
+                      int32_t req_count, UConverter *conv)
+{
+       MonoArray *arr;
+       UResourceBundle *subbundle;
+       int i;
+       
+       subbundle=open_subbundle (bundle, resname, req_count);
+       if(subbundle!=NULL) {
+               arr=mono_array_new(mono_domain_get (),
+                                  mono_defaults.string_class, req_count);
+               
+               for(i=0; i<req_count; i++) {
+                       mono_array_set(arr, MonoString *, i, monostring_from_resource_index (subbundle, conv, i));
+               }
+               set_field_by_name (obj, fieldname, arr);
+
+               ures_close (subbundle);
+       }
+}
+
+
+static MonoObject *create_DateTimeFormat (const char *locale)
+{
+       MonoObject *new_dtf;
+       MonoClass *class;
+       UConverter *conv;
+       UResourceBundle *bundle, *subbundle;
+       UErrorCode ec;
+       
+       class=mono_class_from_name (mono_defaults.corlib,
+                                   "System.Globalization",
+                                   "DateTimeFormatInfo");
+       new_dtf=mono_object_new (mono_domain_get (), class);
+       mono_runtime_object_init (new_dtf);
+       
+       ec=U_ZERO_ERROR;
+       conv=ucnv_open ("UTF-16LE", &ec);
+       if(U_FAILURE (ec)) {
+               goto error0;
+       }
+       
+       bundle=ures_open (NULL, locale, &ec);
+       if(U_FAILURE (ec)) {
+               goto error1;
+       }
+       
+       /* AM/PM markers */
+       subbundle=open_subbundle (bundle, "AmPmMarkers", 2);
+       if(subbundle!=NULL) {
+               set_field_by_name (new_dtf, "_AMDesignator",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 0));
+               set_field_by_name (new_dtf, "_PMDesignator",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 1));
+               
+               ures_close (subbundle);
+       }
+       
+       /* Date/Time patterns.  Don't set FullDateTimePattern.  As it
+        * seems to always default to LongDatePattern + " " +
+        * LongTimePattern, let the property accessor deal with it.
+        */
+       subbundle=open_subbundle (bundle, "DateTimePatterns", 9);
+       if(subbundle!=NULL) {
+               set_field_by_name (new_dtf, "_ShortDatePattern",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 7));
+               set_field_by_name (new_dtf, "_LongDatePattern",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 5));
+               set_field_by_name (new_dtf, "_ShortTimePattern",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 3));
+               set_field_by_name (new_dtf, "_LongTimePattern",
+                                  monostring_from_resource_index (subbundle,
+                                                                  conv, 2));
+
+               /* RFC1123Pattern, SortableDateTimePattern and
+                * UniversalSortableDateTimePattern all seem to be
+                * constant, and all the same as the invariant default
+                * set in the ctor
+                */
+       
+               ures_close (subbundle);
+       }
+       
+#if 0
+       /* Not sure what to do with these yet, so leave them set to
+        * the invariant default
+        */
+       set_field_string (new_dtf, "_DateSeparator", str);
+       set_field_string (new_dtf, "_TimeSeparator", str);
+       set_field_string (new_dtf, "_MonthDayPattern", str);
+       set_field_string (new_dtf, "_YearMonthPattern", str);
+#endif
+
+       /* Day names.  Luckily both ICU and .net start Sunday at index 0 */
+       set_array (new_dtf, "_DayNames", bundle, "DayNames", 7, conv);
+
+       /* Abbreviated day names */
+       set_array (new_dtf, "_AbbreviatedDayNames", bundle,
+                  "DayAbbreviations", 7, conv);
+
+       /* Month names */
+       set_array (new_dtf, "_MonthNames", bundle, "MonthNames", 12, conv);
+       
+       /* Abbreviated month names */
+       set_array (new_dtf, "_AbbreviatedMonthNames", bundle,
+                  "MonthAbbreviations", 12, conv);
+
+       /* TODO: DayOfWeek _FirstDayOfWeek, Calendar _Calendar, CalendarWeekRule _CalendarWeekRule */
+
+       ures_close (bundle);
+error1:
+       ucnv_close (conv);
+error0:
+       return(new_dtf);
+}
+
+static char *mono_string_to_icu_locale (MonoString *locale)
+{
+       UErrorCode ec;
+       char *passed_locale, *icu_locale=NULL;
+       int32_t loc_len, ret;
+
+       passed_locale=mono_string_to_utf8 (locale);
+       
+       ec=U_ZERO_ERROR;
+       ret=uloc_getName (passed_locale, NULL, 0, &ec);
+       if(ec==U_BUFFER_OVERFLOW_ERROR) {
+               ec=U_ZERO_ERROR;
+               loc_len=ret+1;
+               icu_locale=(char *)g_malloc0 (sizeof(char)*loc_len);
+               ret=uloc_getName (passed_locale, icu_locale, loc_len, &ec);
+       }
+       g_free (passed_locale);
+       
+       return(icu_locale);
+}
+
+void ves_icall_System_Globalization_CultureInfo_construct_internal_locale (MonoObject *this, MonoString *locale)
+{
+       UConverter *conv;
+       UChar *ustr;
+       char *str;
+       UErrorCode ec;
+       char *icu_locale;
+       int32_t str_len, ret;
+       
+       icu_locale=mono_string_to_icu_locale (locale);
+       if(icu_locale==NULL) {
+               /* Something went wrong */
+               mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+               return;
+       }
+       
+       ec=U_ZERO_ERROR;
+       conv=ucnv_open ("UTF-16LE", &ec);
+       if(U_FAILURE (ec)) {
+               g_free (icu_locale);
+               mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+               return;
+       }
+       
+       /* Fill in the static fields */
+
+       /* TODO: Calendar, CurrentCulture,
+        * CurrentUICulture, InstalledUICulture, NumberFormat,
+        * OptionalCalendars, Parent, TextInfo
+        */
+
+       str_len=256;    /* Should be big enough for anything */
+       str=(char *)g_malloc0 (sizeof(char)*str_len);
+       ustr=(UChar *)g_malloc0 (sizeof(UChar)*str_len);
+       
+       ret=uloc_getDisplayName (icu_locale, "en", ustr, str_len, &ec);
+       if(U_SUCCESS (ec) && ret<str_len) {
+               set_field_by_name (this, "englishname",
+                                  monostring_from_UChars (ustr, conv));
+       }
+       
+       ret=uloc_getDisplayName (icu_locale, uloc_getDefault (), ustr, str_len,
+                                &ec);
+       if(U_SUCCESS (ec) && ret<str_len) {
+               set_field_by_name (this, "displayname",
+                                  monostring_from_UChars (ustr, conv));
+       }
+       
+       ret=uloc_getDisplayName (icu_locale, icu_locale, ustr, str_len, &ec);
+       if(U_SUCCESS (ec) && ret<str_len) {
+               set_field_by_name (this, "nativename",
+                                  monostring_from_UChars (ustr, conv));
+       }
+
+       set_field_by_name (this, "iso3lang",mono_string_new_wrapper (uloc_getISO3Language (icu_locale)));
+
+       ret=uloc_getLanguage (icu_locale, str, str_len, &ec);
+       if(U_SUCCESS (ec) && ret<str_len) {
+               set_field_by_name (this, "iso2lang",
+                                  mono_string_new_wrapper (str));
+       }
+
+       set_field_by_name (this, "datetime_format",
+                          create_DateTimeFormat (icu_locale));
+       
+       g_free (str);
+       g_free (ustr);
+       g_free (icu_locale);
+       ucnv_close (conv);
+}
+
+void ves_icall_System_Globalization_CultureInfo_construct_compareinfo (MonoObject *comp, MonoString *locale)
+{
+       UCollator *coll;
+       UErrorCode ec;
+       char *icu_locale;
+       
+       icu_locale=mono_string_to_icu_locale (locale);
+       if(icu_locale==NULL) {
+               /* Something went wrong */
+               mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+               return;
+       }
+
+       ec=U_ZERO_ERROR;
+       coll=ucol_open (icu_locale, &ec);
+       if(U_SUCCESS (ec)) {
+               set_field_by_name (comp, "ICU_collator", &coll);
+       }
+
+       g_free (icu_locale);
+}
+
+/* Set up the collator to reflect the options required.  Some of these
+ * options clash, as they adjust the collator strength level.  Try to
+ * make later checks reduce the strength level, and attempt to take
+ * previous options into account.
+ *
+ * Don't bother to check the error returns when setting the
+ * attributes, as a failure here is hardly grounds to error out.
+ */
+static void set_collator_options (UCollator *coll, gint32 options)
+{
+       UErrorCode ec=U_ZERO_ERROR;
+       
+       /* Set up the defaults */
+       ucol_setAttribute (coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE,
+                          &ec);
+       ucol_setAttribute (coll, UCOL_CASE_LEVEL, UCOL_OFF, &ec);
+       
+       /* Do this first so other options will override the quaternary
+        * level strength setting if necessary
+        */
+       if(!(options & CompareOptions_IgnoreKanaType)) {
+               ucol_setAttribute (coll, UCOL_HIRAGANA_QUATERNARY_MODE,
+                                  UCOL_ON, &ec);
+               ucol_setAttribute (coll, UCOL_STRENGTH, UCOL_QUATERNARY, &ec);
+       }
+
+       /* Word sort, the default */
+       if(!(options & CompareOptions_StringSort)) {
+               ucol_setAttribute (coll, UCOL_ALTERNATE_HANDLING,
+                                  UCOL_SHIFTED, &ec);
+               /* Tertiary strength is the default, but it might have
+                * been set to quaternary above.  (We don't want that
+                * here, because that will order all the punctuation
+                * first instead of just ignoring it.)
+                */
+               ucol_setAttribute (coll, UCOL_STRENGTH, UCOL_TERTIARY, &ec);
+       }
+
+       if(options & CompareOptions_IgnoreCase) {
+               ucol_setAttribute (coll, UCOL_STRENGTH, UCOL_SECONDARY, &ec);
+       }
+
+       if(options & CompareOptions_IgnoreWidth) {
+               /* Kana width is a tertiary strength difference.  This
+                * will totally break the !IgnoreKanaType option
+                */
+               ucol_setAttribute (coll, UCOL_STRENGTH, UCOL_SECONDARY, &ec);
+       }
+               
+       if(options & CompareOptions_IgnoreNonSpace) {
+               ucol_setAttribute (coll, UCOL_STRENGTH, UCOL_PRIMARY, &ec);
+               /* We can still compare case even when just checking
+                * primary strength
+                */
+               if(!(options & CompareOptions_IgnoreCase) ||
+                  !(options & CompareOptions_IgnoreWidth)) {
+                       /* Not sure if CASE_LEVEL handles kana width
+                        */
+                       ucol_setAttribute (coll, UCOL_CASE_LEVEL, UCOL_ON,
+                                          &ec);
+               }
+       }
+
+       if(options & CompareOptions_IgnoreSymbols) {
+               /* Don't know what to do here */
+       }
+
+       if(options == CompareOptions_Ordinal) {
+               /* TODO */
+       }
+}
+
+gint32 ves_icall_System_Globalization_CompareInfo_internal_compare (MonoObject *this, MonoString *str1, MonoString *str2, gint32 options)
+{
+       UConverter *conv;
+       UCollator *coll;
+       UChar *ustr1, *ustr2;
+       UCollationResult result;
+       UErrorCode ec;
+       
+       coll=get_field_by_name (this, "ICU_collator");
+       if(coll==NULL) {
+               return(0);
+       }
+       
+       ec=U_ZERO_ERROR;
+       conv=ucnv_open ("UTF-16LE", &ec);
+       if(U_FAILURE (ec)) {
+               return(0);
+       }
+       
+       ustr1=monostring_to_UChars (str1, conv);
+       ustr2=monostring_to_UChars (str2, conv);
+       
+       ucnv_close (conv);
+       
+       set_collator_options (coll, options);
+                       
+       result=ucol_strcoll (coll, ustr1, -1, ustr2, -1);
+       
+       g_free (ustr1);
+       g_free (ustr2);
+       
+       return(result);
+}
+
+void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoObject *this)
+{
+       UCollator *coll;
+       
+       coll=get_field_by_name (this, "ICU_collator");
+       if(coll!=NULL) {
+               ucol_close (coll);
+       }
+}
+
+void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoObject *this, MonoObject *key, MonoString *source, gint32 options)
+{
+       UCollator *coll;
+       UConverter *conv;
+       UChar *ustr;
+       UErrorCode ec;
+       MonoArray *arr;
+       char *keybuf;
+       int32_t keylen, i;
+       
+       coll=get_field_by_name (this, "ICU_collator");
+       if(coll==NULL) {
+               mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+               return;
+       }
+       
+       ec=U_ZERO_ERROR;
+       conv=ucnv_open ("UTF-16LE", &ec);
+       if(U_FAILURE (ec)) {
+               mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+               return;
+       }
+       ustr=monostring_to_UChars (source, conv);
+       ucnv_close (conv);
+       
+       set_collator_options (coll, options);
+
+       keylen=ucol_getSortKey (coll, ustr, -1, NULL, 0);
+       keybuf=g_malloc (sizeof(char)* keylen);
+       ucol_getSortKey (coll, ustr, -1, keybuf, keylen);
+       
+       arr=mono_array_new (mono_domain_get (), mono_defaults.byte_class,
+                           keylen);
+       for(i=0; i<keylen; i++) {
+               mono_array_set (arr, guint8, i, keybuf[i]);
+       }
+       
+       set_field_by_name (key, "key", arr);
+
+       g_free (ustr);
+       g_free (keybuf);
+}
+
+#else /* HAVE_ICU */
+void ves_icall_System_Globalization_CultureInfo_construct_internal_locale (MonoObject *this, MonoString *locale)
+{
+       /* Always claim "unknown locale" if we don't have ICU (only
+        * called for non-invariant locales)
+        */
+       mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "ArgumentException"));
+}
+
+void ves_icall_System_Globalization_CultureInfo_construct_compareinfo (MonoObject *comp, MonoString *locale)
+{
+       /* Nothing to do here */
+}
+
+int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoObject *this, MonoString *str1, MonoString *str2, gint32 options)
+{
+       /* Do a normal ascii string compare, as we only know the
+        * invariant locale if we dont have ICU
+        */
+       /* TODO */
+       mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
+}
+
+void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoObject *this)
+{
+       /* Nothing to do here */
+}
+
+void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoObject *this, MonoObject *key, MonoString *source, gint32 options)
+{
+       MonoArray *arr;
+       int32_t keylen, i;
+
+       keylen=mono_string_length (source);
+       
+       arr=mono_array_new (mono_domain_get (), mono_defaults.byte_class,
+                           keylen);
+       for(i=0; i<keylen; i++) {
+               mono_array_set (arr, guint8, i, mono_string_chars (source)[i]);
+       }
+       
+       set_field_by_name (key, "key", arr);
+}
+
+#endif /* HAVE_ICU */
diff --git a/mono/metadata/locales.h b/mono/metadata/locales.h
new file mode 100644 (file)
index 0000000..3ecc871
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * locales.h: Culture-sensitive handling
+ *
+ * Authors:
+ *     Dick Porter (dick@ximian.com)
+ *
+ * (C) 2003 Ximian, Inc.
+ */
+
+#ifndef _MONO_METADATA_LOCALES_H_
+#define _MONO_METADATA_LOCALES_H_
+
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/object.h>
+
+/* This is a copy of System.Globalization.CompareOptions */
+typedef enum {
+       CompareOptions_None=0x00,
+       CompareOptions_IgnoreCase=0x01,
+       CompareOptions_IgnoreNonSpace=0x02,
+       CompareOptions_IgnoreSymbols=0x04,
+       CompareOptions_IgnoreKanaType=0x08,
+       CompareOptions_IgnoreWidth=0x10,
+       CompareOptions_StringSort=0x20000000,
+       CompareOptions_Ordinal=0x40000000
+} MonoCompareOptions;
+
+extern void ves_icall_System_Globalization_CultureInfo_construct_internal_locale (MonoObject *this, MonoString *locale);
+extern void ves_icall_System_Globalization_CultureInfo_construct_compareinfo (MonoObject *comp, MonoString *locale);
+extern int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoObject *this, MonoString *str1, MonoString *str2, gint32 options);
+extern void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoObject *this);
+extern void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoObject *this, MonoObject *key, MonoString *source, gint32 options);
+
+#endif /* _MONO_METADATA_FILEIO_H_ */
index 0c3b38d0ab57e468feff8a13b338b5dc91df4eec..ddf1f82ef90fae44dd61b471ed1001937f6998cf 100644 (file)
@@ -6,7 +6,8 @@ libs=   \
        $(monodir)/mono/metadata/libmetadata.la \
        $(monodir)/mono/io-layer/libwapi.la     \
        $(monodir)/mono/utils/libmonoutils.la \
-       $(LIBGC_LIBS)
+       $(LIBGC_LIBS)   \
+       $(ICU_LIBS)
 
 MCS=mcs
 RUNTIME=mono
@@ -45,7 +46,8 @@ mono_SOURCES = \
 mono_LDADD = \
        libmono.la              \
        $(GLIB_LIBS)            \
-       $(GMODULE_LIBS) -lm
+       $(GMODULE_LIBS) -lm     \
+       $(ICU_LIBS)
 
 mono_LDFLAGS = \
        -export-dynamic