2 * locales.c: Culture-sensitive handling
5 * Dick Porter (dick@ximian.com)
6 * Mohammad DAMT (mdamt@cdl2000.com)
7 * Marek Safar (marek.safar@gmail.com)
9 * Copyright 2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * (C) 2003 PT Cakram Datalingga Duaribu http://www.cdl2000.com
12 * Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/metadata/exception.h>
23 #include <mono/metadata/monitor.h>
24 #include <mono/metadata/locales.h>
25 #include <mono/metadata/culture-info.h>
26 #include <mono/metadata/culture-info-tables.h>
27 #include <mono/utils/bsearch.h>
29 #ifndef DISABLE_NORMALIZATION
30 #include <mono/metadata/normalization-tables.h>
34 #if defined(__APPLE__)
35 #include <CoreFoundation/CoreFoundation.h>
40 static gint32 string_invariant_compare_char (gunichar2 c1, gunichar2 c2,
42 static gint32 string_invariant_compare (MonoString *str1, gint32 off1,
43 gint32 len1, MonoString *str2,
44 gint32 off2, gint32 len2,
46 static MonoString *string_invariant_replace (MonoString *me,
48 MonoString *newValue);
49 static gint32 string_invariant_indexof (MonoString *source, gint32 sindex,
50 gint32 count, MonoString *value,
52 static gint32 string_invariant_indexof_char (MonoString *source, gint32 sindex,
53 gint32 count, gunichar2 value,
56 static const CultureInfoEntry* culture_info_entry_from_lcid (int lcid);
58 static const RegionInfoEntry* region_info_entry_from_lcid (int lcid);
61 culture_lcid_locator (const void *a, const void *b)
63 const int *lcid = (const int *)a;
64 const CultureInfoEntry *bb = (const CultureInfoEntry *)b;
66 return *lcid - bb->lcid;
70 culture_name_locator (const void *a, const void *b)
72 const char *aa = (const char *)a;
73 const CultureInfoNameEntry *bb = (const CultureInfoNameEntry *)b;
76 ret = strcmp (aa, idx2string (bb->name));
82 region_name_locator (const void *a, const void *b)
84 const char *aa = (const char *)a;
85 const RegionInfoNameEntry *bb = (const RegionInfoNameEntry *)b;
88 ret = strcmp (aa, idx2string (bb->name));
94 create_group_sizes_array (const gint *gs, gint ml)
99 for (i = 0; i < ml; i++) {
105 ret = mono_array_new_cached (mono_domain_get (),
106 mono_get_int32_class (), len);
108 for(i = 0; i < len; i++)
109 mono_array_set (ret, gint32, i, gs [i]);
115 create_names_array_idx (const guint16 *names, int ml)
124 domain = mono_domain_get ();
126 ret = mono_array_new_cached (mono_domain_get (), mono_get_string_class (), ml);
128 for(i = 0; i < ml; i++)
129 mono_array_setref (ret, i, mono_string_new (domain, idx2string (names [i])));
135 create_names_array_idx_dynamic (const guint16 *names, int ml)
144 domain = mono_domain_get ();
146 for (i = 0; i < ml; i++) {
152 ret = mono_array_new_cached (mono_domain_get (), mono_get_string_class (), len);
154 for(i = 0; i < len; i++)
155 mono_array_setref (ret, i, mono_string_new (domain, idx2string (names [i])));
161 ves_icall_System_Globalization_CalendarData_fill_calendar_data (MonoCalendarData *this_obj, MonoString *name, gint32 calendar_index)
164 const DateTimeFormatEntry *dfe;
165 const CultureInfoNameEntry *ne;
166 const CultureInfoEntry *ci;
169 n = mono_string_to_utf8 (name);
170 ne = (const CultureInfoNameEntry *)mono_binary_search (n, culture_name_entries, NUM_CULTURE_ENTRIES,
171 sizeof (CultureInfoNameEntry), culture_name_locator);
177 ci = &culture_entries [ne->culture_entry_index];
178 dfe = &datetime_format_entries [ci->datetime_format_index];
180 domain = mono_domain_get ();
182 MONO_OBJECT_SETREF (this_obj, NativeName, mono_string_new (domain, idx2string (ci->nativename)));
183 MONO_OBJECT_SETREF (this_obj, ShortDatePatterns, create_names_array_idx_dynamic (dfe->short_date_patterns,
184 NUM_SHORT_DATE_PATTERNS));
185 MONO_OBJECT_SETREF (this_obj, YearMonthPatterns, create_names_array_idx_dynamic (dfe->year_month_patterns,
186 NUM_YEAR_MONTH_PATTERNS));
188 MONO_OBJECT_SETREF (this_obj, LongDatePatterns, create_names_array_idx_dynamic (dfe->long_date_patterns,
189 NUM_LONG_DATE_PATTERNS));
190 MONO_OBJECT_SETREF (this_obj, MonthDayPattern, mono_string_new (domain, idx2string (dfe->month_day_pattern)));
192 MONO_OBJECT_SETREF (this_obj, DayNames, create_names_array_idx (dfe->day_names, NUM_DAYS));
193 MONO_OBJECT_SETREF (this_obj, AbbreviatedDayNames, create_names_array_idx (dfe->abbreviated_day_names,
195 MONO_OBJECT_SETREF (this_obj, SuperShortDayNames, create_names_array_idx (dfe->shortest_day_names, NUM_DAYS));
196 MONO_OBJECT_SETREF (this_obj, MonthNames, create_names_array_idx (dfe->month_names, NUM_MONTHS));
197 MONO_OBJECT_SETREF (this_obj, AbbreviatedMonthNames, create_names_array_idx (dfe->abbreviated_month_names,
199 MONO_OBJECT_SETREF (this_obj, GenitiveMonthNames, create_names_array_idx (dfe->month_genitive_names, NUM_MONTHS));
200 MONO_OBJECT_SETREF (this_obj, GenitiveAbbreviatedMonthNames, create_names_array_idx (dfe->abbreviated_month_genitive_names, NUM_MONTHS));
206 ves_icall_System_Globalization_CultureData_fill_culture_data (MonoCultureData *this_obj, gint32 datetime_index)
209 const DateTimeFormatEntry *dfe;
211 g_assert (datetime_index >= 0);
213 dfe = &datetime_format_entries [datetime_index];
215 domain = mono_domain_get ();
217 MONO_OBJECT_SETREF (this_obj, AMDesignator, mono_string_new (domain, idx2string (dfe->am_designator)));
218 MONO_OBJECT_SETREF (this_obj, PMDesignator, mono_string_new (domain, idx2string (dfe->pm_designator)));
219 MONO_OBJECT_SETREF (this_obj, TimeSeparator, mono_string_new (domain, idx2string (dfe->time_separator)));
220 MONO_OBJECT_SETREF (this_obj, LongTimePatterns, create_names_array_idx_dynamic (dfe->long_time_patterns,
221 NUM_LONG_TIME_PATTERNS));
222 MONO_OBJECT_SETREF (this_obj, ShortTimePatterns, create_names_array_idx_dynamic (dfe->short_time_patterns,
223 NUM_SHORT_TIME_PATTERNS));
224 this_obj->FirstDayOfWeek = dfe->first_day_of_week;
225 this_obj->CalendarWeekRule = dfe->calendar_week_rule;
229 ves_icall_System_Globalization_CultureData_fill_number_data (MonoNumberFormatInfo* number, gint32 number_index)
232 const NumberFormatEntry *nfe;
234 g_assert (number_index >= 0);
236 nfe = &number_format_entries [number_index];
238 domain = mono_domain_get ();
240 number->currencyDecimalDigits = nfe->currency_decimal_digits;
241 MONO_OBJECT_SETREF (number, currencyDecimalSeparator, mono_string_new (domain,
242 idx2string (nfe->currency_decimal_separator)));
243 MONO_OBJECT_SETREF (number, currencyGroupSeparator, mono_string_new (domain,
244 idx2string (nfe->currency_group_separator)));
245 MONO_OBJECT_SETREF (number, currencyGroupSizes, create_group_sizes_array (nfe->currency_group_sizes,
247 number->currencyNegativePattern = nfe->currency_negative_pattern;
248 number->currencyPositivePattern = nfe->currency_positive_pattern;
249 MONO_OBJECT_SETREF (number, currencySymbol, mono_string_new (domain, idx2string (nfe->currency_symbol)));
250 MONO_OBJECT_SETREF (number, naNSymbol, mono_string_new (domain, idx2string (nfe->nan_symbol)));
251 MONO_OBJECT_SETREF (number, negativeInfinitySymbol, mono_string_new (domain,
252 idx2string (nfe->negative_infinity_symbol)));
253 MONO_OBJECT_SETREF (number, negativeSign, mono_string_new (domain, idx2string (nfe->negative_sign)));
254 number->numberDecimalDigits = nfe->number_decimal_digits;
255 MONO_OBJECT_SETREF (number, numberDecimalSeparator, mono_string_new (domain,
256 idx2string (nfe->number_decimal_separator)));
257 MONO_OBJECT_SETREF (number, numberGroupSeparator, mono_string_new (domain, idx2string (nfe->number_group_separator)));
258 MONO_OBJECT_SETREF (number, numberGroupSizes, create_group_sizes_array (nfe->number_group_sizes,
260 number->numberNegativePattern = nfe->number_negative_pattern;
261 number->percentNegativePattern = nfe->percent_negative_pattern;
262 number->percentPositivePattern = nfe->percent_positive_pattern;
263 MONO_OBJECT_SETREF (number, percentSymbol, mono_string_new (domain, idx2string (nfe->percent_symbol)));
264 MONO_OBJECT_SETREF (number, perMilleSymbol, mono_string_new (domain, idx2string (nfe->per_mille_symbol)));
265 MONO_OBJECT_SETREF (number, positiveInfinitySymbol, mono_string_new (domain,
266 idx2string (nfe->positive_infinity_symbol)));
267 MONO_OBJECT_SETREF (number, positiveSign, mono_string_new (domain, idx2string (nfe->positive_sign)));
271 construct_culture (MonoCultureInfo *this_obj, const CultureInfoEntry *ci)
273 MonoDomain *domain = mono_domain_get ();
275 this_obj->lcid = ci->lcid;
276 MONO_OBJECT_SETREF (this_obj, name, mono_string_new (domain, idx2string (ci->name)));
277 MONO_OBJECT_SETREF (this_obj, englishname, mono_string_new (domain, idx2string (ci->englishname)));
278 MONO_OBJECT_SETREF (this_obj, nativename, mono_string_new (domain, idx2string (ci->nativename)));
279 MONO_OBJECT_SETREF (this_obj, win3lang, mono_string_new (domain, idx2string (ci->win3lang)));
280 MONO_OBJECT_SETREF (this_obj, iso3lang, mono_string_new (domain, idx2string (ci->iso3lang)));
281 MONO_OBJECT_SETREF (this_obj, iso2lang, mono_string_new (domain, idx2string (ci->iso2lang)));
283 // It's null for neutral cultures
284 if (ci->territory > 0)
285 MONO_OBJECT_SETREF (this_obj, territory, mono_string_new (domain, idx2string (ci->territory)));
286 MONO_OBJECT_SETREF (this_obj, native_calendar_names, create_names_array_idx (ci->native_calendar_names, NUM_CALENDARS));
287 this_obj->parent_lcid = ci->parent_lcid;
288 this_obj->datetime_index = ci->datetime_format_index;
289 this_obj->number_index = ci->number_format_index;
290 this_obj->calendar_type = ci->calendar_type;
291 this_obj->text_info_data = &ci->text_info;
297 construct_region (MonoRegionInfo *this_obj, const RegionInfoEntry *ri)
299 MonoDomain *domain = mono_domain_get ();
301 this_obj->geo_id = ri->geo_id;
302 MONO_OBJECT_SETREF (this_obj, iso2name, mono_string_new (domain, idx2string (ri->iso2name)));
303 MONO_OBJECT_SETREF (this_obj, iso3name, mono_string_new (domain, idx2string (ri->iso3name)));
304 MONO_OBJECT_SETREF (this_obj, win3name, mono_string_new (domain, idx2string (ri->win3name)));
305 MONO_OBJECT_SETREF (this_obj, english_name, mono_string_new (domain, idx2string (ri->english_name)));
306 MONO_OBJECT_SETREF (this_obj, native_name, mono_string_new (domain, idx2string (ri->native_name)));
307 MONO_OBJECT_SETREF (this_obj, currency_symbol, mono_string_new (domain, idx2string (ri->currency_symbol)));
308 MONO_OBJECT_SETREF (this_obj, iso_currency_symbol, mono_string_new (domain, idx2string (ri->iso_currency_symbol)));
309 MONO_OBJECT_SETREF (this_obj, currency_english_name, mono_string_new (domain, idx2string (ri->currency_english_name)));
310 MONO_OBJECT_SETREF (this_obj, currency_native_name, mono_string_new (domain, idx2string (ri->currency_native_name)));
315 static const CultureInfoEntry*
316 culture_info_entry_from_lcid (int lcid)
318 const CultureInfoEntry *ci;
320 ci = (const CultureInfoEntry *)mono_binary_search (&lcid, culture_entries, NUM_CULTURE_ENTRIES, sizeof (CultureInfoEntry), culture_lcid_locator);
325 static const RegionInfoEntry*
326 region_info_entry_from_lcid (int lcid)
328 const RegionInfoEntry *entry;
329 const CultureInfoEntry *ne;
331 ne = (const CultureInfoEntry *)mono_binary_search (&lcid, culture_entries, NUM_CULTURE_ENTRIES, sizeof (CultureInfoEntry), culture_lcid_locator);
336 entry = ®ion_entries [ne->region_entry_index];
341 #if defined (__APPLE__)
343 get_darwin_locale (void)
345 static gchar *darwin_locale = NULL;
346 CFLocaleRef locale = NULL;
347 CFStringRef locale_language = NULL;
348 CFStringRef locale_country = NULL;
349 CFStringRef locale_script = NULL;
350 CFStringRef locale_cfstr = NULL;
351 CFIndex bytes_converted;
352 CFIndex bytes_written;
356 if (darwin_locale != NULL)
357 return g_strdup (darwin_locale);
359 locale = CFLocaleCopyCurrent ();
362 locale_language = CFLocaleGetValue (locale, kCFLocaleLanguageCode);
363 if (locale_language != NULL && CFStringGetBytes(locale_language, CFRangeMake (0, CFStringGetLength (locale_language)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
364 len = bytes_converted + 1;
366 locale_country = CFLocaleGetValue (locale, kCFLocaleCountryCode);
367 if (locale_country != NULL && CFStringGetBytes (locale_country, CFRangeMake (0, CFStringGetLength (locale_country)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
368 len += bytes_converted + 1;
370 locale_script = CFLocaleGetValue (locale, kCFLocaleScriptCode);
371 if (locale_script != NULL && CFStringGetBytes (locale_script, CFRangeMake (0, CFStringGetLength (locale_script)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
372 len += bytes_converted + 1;
375 darwin_locale = (char *) malloc (len + 1);
376 CFStringGetBytes (locale_language, CFRangeMake (0, CFStringGetLength (locale_language)), kCFStringEncodingMacRoman, 0, FALSE, (UInt8 *) darwin_locale, len, &bytes_converted);
378 darwin_locale[bytes_converted] = '-';
379 bytes_written = bytes_converted + 1;
380 if (locale_script != NULL && CFStringGetBytes (locale_script, CFRangeMake (0, CFStringGetLength (locale_script)), kCFStringEncodingMacRoman, 0, FALSE, (UInt8 *) &darwin_locale[bytes_written], len - bytes_written, &bytes_converted) > 0) {
381 darwin_locale[bytes_written + bytes_converted] = '-';
382 bytes_written += bytes_converted + 1;
385 CFStringGetBytes (locale_country, CFRangeMake (0, CFStringGetLength (locale_country)), kCFStringEncodingMacRoman, 0, FALSE, (UInt8 *) &darwin_locale[bytes_written], len - bytes_written, &bytes_converted);
386 darwin_locale[bytes_written + bytes_converted] = '\0';
390 if (darwin_locale == NULL) {
391 locale_cfstr = CFLocaleGetIdentifier (locale);
394 len = CFStringGetMaximumSizeForEncoding (CFStringGetLength (locale_cfstr), kCFStringEncodingMacRoman) + 1;
395 darwin_locale = (char *) malloc (len);
396 if (!CFStringGetCString (locale_cfstr, darwin_locale, len, kCFStringEncodingMacRoman)) {
397 free (darwin_locale);
399 darwin_locale = NULL;
403 for (i = 0; i < strlen (darwin_locale); i++)
404 if (darwin_locale [i] == '_')
405 darwin_locale [i] = '-';
412 return g_strdup (darwin_locale);
417 get_posix_locale (void)
421 locale = g_getenv ("LC_ALL");
422 if (locale == NULL) {
423 locale = g_getenv ("LANG");
425 locale = setlocale (LC_ALL, NULL);
430 /* Skip English-only locale 'C' */
431 if (strcmp (locale, "C") == 0)
434 return g_strdup (locale);
439 get_current_locale_name (void)
445 locale = g_win32_getlocale ();
446 #elif defined (__APPLE__)
447 locale = get_darwin_locale ();
449 locale = get_posix_locale ();
451 locale = get_posix_locale ();
457 p = strchr (locale, '.');
460 p = strchr (locale, '@');
463 p = strchr (locale, '_');
467 ret = g_ascii_strdown (locale, -1);
474 ves_icall_System_Globalization_CultureInfo_get_current_locale_name (void)
480 locale = get_current_locale_name ();
484 domain = mono_domain_get ();
485 ret = mono_string_new (domain, locale);
492 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo *this_obj,
495 const CultureInfoEntry *ci;
497 ci = culture_info_entry_from_lcid (lcid);
501 return construct_culture (this_obj, ci);
505 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo *this_obj,
508 const CultureInfoNameEntry *ne;
511 n = mono_string_to_utf8 (name);
512 ne = (const CultureInfoNameEntry *)mono_binary_search (n, culture_name_entries, NUM_CULTURE_ENTRIES,
513 sizeof (CultureInfoNameEntry), culture_name_locator);
516 /*g_print ("ne (%s) is null\n", n);*/
522 return construct_culture (this_obj, &culture_entries [ne->culture_entry_index]);
526 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo *ci,
532 locale = mono_string_to_utf8 (name);
533 ret = construct_culture_from_specific_name (ci, locale);
540 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo *this_obj,
543 const RegionInfoEntry *ri;
545 ri = region_info_entry_from_lcid (lcid);
549 return construct_region (this_obj, ri);
553 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo *this_obj,
556 const RegionInfoNameEntry *ne;
559 n = mono_string_to_utf8 (name);
560 ne = (const RegionInfoNameEntry *)mono_binary_search (n, region_name_entries, NUM_REGION_ENTRIES,
561 sizeof (RegionInfoNameEntry), region_name_locator);
564 /*g_print ("ne (%s) is null\n", n);*/
570 return construct_region (this_obj, ®ion_entries [ne->region_entry_index]);
574 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral,
575 MonoBoolean specific, MonoBoolean installed)
579 MonoCultureInfo *culture;
581 const CultureInfoEntry *ci;
585 domain = mono_domain_get ();
588 for (i = 0; i < NUM_CULTURE_ENTRIES; i++) {
589 ci = &culture_entries [i];
590 is_neutral = ci->territory == 0;
591 if ((neutral && is_neutral) || (specific && !is_neutral))
595 klass = mono_class_from_name (mono_get_corlib (),
596 "System.Globalization", "CultureInfo");
598 /* The InvariantCulture is not in culture_entries */
599 /* We reserve the first slot in the array for it */
603 ret = mono_array_new (domain, klass, len);
610 mono_array_setref (ret, len++, NULL);
612 for (i = 0; i < NUM_CULTURE_ENTRIES; i++) {
613 ci = &culture_entries [i];
614 is_neutral = ci->territory == 0;
615 if ((neutral && is_neutral) || (specific && !is_neutral)) {
616 culture = (MonoCultureInfo *) mono_object_new (domain, klass);
617 mono_runtime_object_init ((MonoObject *) culture);
618 construct_culture (culture, ci);
619 culture->use_user_override = TRUE;
620 mono_array_setref (ret, len++, culture);
627 int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoCompareInfo *this_obj, MonoString *str1, gint32 off1, gint32 len1, MonoString *str2, gint32 off2, gint32 len2, gint32 options)
629 /* Do a normal ascii string compare, as we only know the
630 * invariant locale if we dont have ICU
632 return(string_invariant_compare (str1, off1, len1, str2, off2, len2,
636 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo *this_obj, MonoSortKey *key, MonoString *source, gint32 options)
641 keylen=mono_string_length (source);
643 arr=mono_array_new (mono_domain_get (), mono_get_byte_class (),
645 for(i=0; i<keylen; i++) {
646 mono_array_set (arr, guint8, i, mono_string_chars (source)[i]);
649 MONO_OBJECT_SETREF (key, key, arr);
652 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo *this_obj, MonoString *source, gint32 sindex, gint32 count, MonoString *value, gint32 options, MonoBoolean first)
654 return(string_invariant_indexof (source, sindex, count, value, first));
657 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo *this_obj, MonoString *source, gint32 sindex, gint32 count, gunichar2 value, gint32 options, MonoBoolean first)
659 return(string_invariant_indexof_char (source, sindex, count, value,
663 int ves_icall_System_Threading_Thread_current_lcid (void)
669 MonoString *ves_icall_System_String_InternalReplace_Str_Comp (MonoString *this_obj, MonoString *old, MonoString *new_, MonoCompareInfo *comp)
671 /* Do a normal ascii string compare and replace, as we only
672 * know the invariant locale if we dont have ICU
674 return(string_invariant_replace (this_obj, old, new_));
677 static gint32 string_invariant_compare_char (gunichar2 c1, gunichar2 c2,
682 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
683 if (options & CompareOptions_Ordinal)
684 return (gint32) c1 - c2;
686 if (options & CompareOptions_IgnoreCase) {
687 GUnicodeType c1type, c2type;
689 c1type = g_unichar_type (c1);
690 c2type = g_unichar_type (c2);
692 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) -
693 (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
696 * No options. Kana, symbol and spacing options don't
697 * apply to the invariant culture.
701 * FIXME: here we must use the information from c1type and c2type
702 * to find out the proper collation, even on the InvariantCulture, the
703 * sorting is not done by computing the unicode values, but their
706 result = (gint32) c1 - c2;
709 return ((result < 0) ? -1 : (result > 0) ? 1 : 0);
712 static gint32 string_invariant_compare (MonoString *str1, gint32 off1,
713 gint32 len1, MonoString *str2,
714 gint32 off2, gint32 len2,
717 /* c translation of C# code from old string.cs.. :) */
730 ustr1 = mono_string_chars(str1)+off1;
731 ustr2 = mono_string_chars(str2)+off2;
735 for (pos = 0; pos != length; pos++) {
736 if (pos >= len1 || pos >= len2)
739 charcmp = string_invariant_compare_char(ustr1[pos], ustr2[pos],
746 /* the lesser wins, so if we have looped until length we just
747 * need to check the last char
750 return(string_invariant_compare_char(ustr1[pos - 1],
751 ustr2[pos - 1], options));
754 /* Test if one of the strings has been compared to the end */
761 } else if (pos >= len2) {
765 /* if not, check our last char only.. (can this happen?) */
766 return(string_invariant_compare_char(ustr1[pos], ustr2[pos], options));
769 static MonoString *string_invariant_replace (MonoString *me,
770 MonoString *oldValue,
771 MonoString *newValue)
775 gunichar2 *dest=NULL; /* shut gcc up */
777 gunichar2 *newstr=NULL; /* shut gcc up here too */
788 oldstr = mono_string_chars(oldValue);
789 oldstrlen = mono_string_length(oldValue);
791 if (NULL != newValue) {
792 newstr = mono_string_chars(newValue);
793 newstrlen = mono_string_length(newValue);
797 src = mono_string_chars(me);
798 srclen = mono_string_length(me);
800 if (oldstrlen != newstrlen) {
802 while (i <= srclen - oldstrlen) {
803 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
812 newsize = srclen + ((newstrlen - oldstrlen) * occurr);
819 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
821 ret = mono_string_new_size( mono_domain_get (), newsize);
822 dest = mono_string_chars(ret);
823 memcpy (dest, src, i * sizeof(gunichar2));
826 memcpy(dest + destpos, newstr, newstrlen * sizeof(gunichar2));
827 destpos += newstrlen;
831 } else if (ret != NULL) {
832 dest[destpos] = src[i];
844 static gint32 string_invariant_indexof (MonoString *source, gint32 sindex,
845 gint32 count, MonoString *value,
853 lencmpstr = mono_string_length(value);
855 src = mono_string_chars(source);
856 cmpstr = mono_string_chars(value);
860 for(pos=sindex;pos <= sindex+count;pos++) {
861 for(i=0;src[pos+i]==cmpstr[i];) {
870 for(pos=sindex-lencmpstr+1;pos>sindex-count;pos--) {
871 if(memcmp (src+pos, cmpstr,
872 lencmpstr*sizeof(gunichar2))==0) {
881 static gint32 string_invariant_indexof_char (MonoString *source, gint32 sindex,
882 gint32 count, gunichar2 value,
888 src = mono_string_chars(source);
890 for (pos = sindex; pos != count + sindex; pos++) {
891 if (src [pos] == value) {
898 for (pos = sindex; pos > sindex - count; pos--) {
899 if (src [pos] == value)
907 void load_normalization_resource (guint8 **argProps,
908 guint8 **argMappedChars,
909 guint8 **argCharMapIndex,
910 guint8 **argHelperIndex,
911 guint8 **argMapIdxToComposite,
912 guint8 **argCombiningClass)
914 #ifdef DISABLE_NORMALIZATION
915 mono_set_pending_exception (mono_get_exception_not_supported ("This runtime has been compiled without string normalization support."));
918 *argProps = (guint8*)props;
919 *argMappedChars = (guint8*) mappedChars;
920 *argCharMapIndex = (guint8*) charMapIndex;
921 *argHelperIndex = (guint8*) helperIndex;
922 *argMapIdxToComposite = (guint8*) mapIdxToComposite;
923 *argCombiningClass = (guint8*)combiningClass;