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)
64 const CultureInfoEntry *bb = b;
66 return *lcid - bb->lcid;
70 culture_name_locator (const void *a, const void *b)
73 const CultureInfoNameEntry *bb = b;
76 ret = strcmp (aa, idx2string (bb->name));
82 region_name_locator (const void *a, const void *b)
85 const RegionInfoNameEntry *bb = 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, 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 = 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, NativeName, mono_string_new (domain, idx2string (ci->nativename)));
183 MONO_OBJECT_SETREF (this, ShortDatePatterns, create_names_array_idx_dynamic (dfe->short_date_patterns,
184 NUM_SHORT_DATE_PATTERNS));
185 MONO_OBJECT_SETREF (this, YearMonthPatterns, create_names_array_idx_dynamic (dfe->year_month_patterns,
186 NUM_YEAR_MONTH_PATTERNS));
188 MONO_OBJECT_SETREF (this, LongDatePatterns, create_names_array_idx_dynamic (dfe->long_date_patterns,
189 NUM_LONG_DATE_PATTERNS));
190 MONO_OBJECT_SETREF (this, MonthDayPattern, mono_string_new (domain, idx2string (dfe->month_day_pattern)));
192 MONO_OBJECT_SETREF (this, DayNames, create_names_array_idx (dfe->day_names, NUM_DAYS));
193 MONO_OBJECT_SETREF (this, AbbreviatedDayNames, create_names_array_idx (dfe->abbreviated_day_names,
195 MONO_OBJECT_SETREF (this, SuperShortDayNames, create_names_array_idx (dfe->shortest_day_names, NUM_DAYS));
196 MONO_OBJECT_SETREF (this, MonthNames, create_names_array_idx (dfe->month_names, NUM_MONTHS));
197 MONO_OBJECT_SETREF (this, AbbreviatedMonthNames, create_names_array_idx (dfe->abbreviated_month_names,
199 MONO_OBJECT_SETREF (this, GenitiveMonthNames, create_names_array_idx (dfe->month_genitive_names, NUM_MONTHS));
200 MONO_OBJECT_SETREF (this, GenitiveAbbreviatedMonthNames, create_names_array_idx (dfe->abbreviated_month_genitive_names, NUM_MONTHS));
206 ves_icall_System_Globalization_CultureData_fill_culture_data (MonoCultureData *this, 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, AMDesignator, mono_string_new (domain, idx2string (dfe->am_designator)));
218 MONO_OBJECT_SETREF (this, PMDesignator, mono_string_new (domain, idx2string (dfe->pm_designator)));
219 MONO_OBJECT_SETREF (this, TimeSeparator, mono_string_new (domain, idx2string (dfe->time_separator)));
220 MONO_OBJECT_SETREF (this, LongTimePatterns, create_names_array_idx_dynamic (dfe->long_time_patterns,
221 NUM_LONG_TIME_PATTERNS));
222 MONO_OBJECT_SETREF (this, ShortTimePatterns, create_names_array_idx_dynamic (dfe->short_time_patterns,
223 NUM_SHORT_TIME_PATTERNS));
224 this->FirstDayOfWeek = dfe->first_day_of_week;
225 this->CalendarWeekRule = dfe->calendar_week_rule;
229 ves_icall_System_Globalization_CultureInfo_construct_number_format (MonoCultureInfo *this)
232 MonoNumberFormatInfo *number;
233 const NumberFormatEntry *nfe;
235 g_assert (this->number_format != 0);
236 if (this->number_index < 0)
239 number = this->number_format;
240 nfe = &number_format_entries [this->number_index];
242 domain = mono_domain_get ();
244 number->readOnly = this->is_read_only;
245 number->currencyDecimalDigits = nfe->currency_decimal_digits;
246 MONO_OBJECT_SETREF (number, currencyDecimalSeparator, mono_string_new (domain,
247 idx2string (nfe->currency_decimal_separator)));
248 MONO_OBJECT_SETREF (number, currencyGroupSeparator, mono_string_new (domain,
249 idx2string (nfe->currency_group_separator)));
250 MONO_OBJECT_SETREF (number, currencyGroupSizes, create_group_sizes_array (nfe->currency_group_sizes,
252 number->currencyNegativePattern = nfe->currency_negative_pattern;
253 number->currencyPositivePattern = nfe->currency_positive_pattern;
254 MONO_OBJECT_SETREF (number, currencySymbol, mono_string_new (domain, idx2string (nfe->currency_symbol)));
255 MONO_OBJECT_SETREF (number, naNSymbol, mono_string_new (domain, idx2string (nfe->nan_symbol)));
256 MONO_OBJECT_SETREF (number, negativeInfinitySymbol, mono_string_new (domain,
257 idx2string (nfe->negative_infinity_symbol)));
258 MONO_OBJECT_SETREF (number, negativeSign, mono_string_new (domain, idx2string (nfe->negative_sign)));
259 number->numberDecimalDigits = nfe->number_decimal_digits;
260 MONO_OBJECT_SETREF (number, numberDecimalSeparator, mono_string_new (domain,
261 idx2string (nfe->number_decimal_separator)));
262 MONO_OBJECT_SETREF (number, numberGroupSeparator, mono_string_new (domain, idx2string (nfe->number_group_separator)));
263 MONO_OBJECT_SETREF (number, numberGroupSizes, create_group_sizes_array (nfe->number_group_sizes,
265 number->numberNegativePattern = nfe->number_negative_pattern;
266 number->percentDecimalDigits = nfe->percent_decimal_digits;
267 MONO_OBJECT_SETREF (number, percentDecimalSeparator, mono_string_new (domain,
268 idx2string (nfe->percent_decimal_separator)));
269 MONO_OBJECT_SETREF (number, percentGroupSeparator, mono_string_new (domain,
270 idx2string (nfe->percent_group_separator)));
271 MONO_OBJECT_SETREF (number, percentGroupSizes, create_group_sizes_array (nfe->percent_group_sizes,
273 number->percentNegativePattern = nfe->percent_negative_pattern;
274 number->percentPositivePattern = nfe->percent_positive_pattern;
275 MONO_OBJECT_SETREF (number, percentSymbol, mono_string_new (domain, idx2string (nfe->percent_symbol)));
276 MONO_OBJECT_SETREF (number, perMilleSymbol, mono_string_new (domain, idx2string (nfe->per_mille_symbol)));
277 MONO_OBJECT_SETREF (number, positiveInfinitySymbol, mono_string_new (domain,
278 idx2string (nfe->positive_infinity_symbol)));
279 MONO_OBJECT_SETREF (number, positiveSign, mono_string_new (domain, idx2string (nfe->positive_sign)));
283 construct_culture (MonoCultureInfo *this, const CultureInfoEntry *ci)
285 MonoDomain *domain = mono_domain_get ();
287 this->lcid = ci->lcid;
288 MONO_OBJECT_SETREF (this, name, mono_string_new (domain, idx2string (ci->name)));
289 MONO_OBJECT_SETREF (this, englishname, mono_string_new (domain, idx2string (ci->englishname)));
290 MONO_OBJECT_SETREF (this, nativename, mono_string_new (domain, idx2string (ci->nativename)));
291 MONO_OBJECT_SETREF (this, win3lang, mono_string_new (domain, idx2string (ci->win3lang)));
292 MONO_OBJECT_SETREF (this, iso3lang, mono_string_new (domain, idx2string (ci->iso3lang)));
293 MONO_OBJECT_SETREF (this, iso2lang, mono_string_new (domain, idx2string (ci->iso2lang)));
295 // It's null for neutral cultures
296 if (ci->territory > 0)
297 MONO_OBJECT_SETREF (this, territory, mono_string_new (domain, idx2string (ci->territory)));
298 MONO_OBJECT_SETREF (this, native_calendar_names, create_names_array_idx (ci->native_calendar_names, NUM_CALENDARS));
299 this->parent_lcid = ci->parent_lcid;
300 this->datetime_index = ci->datetime_format_index;
301 this->number_index = ci->number_format_index;
302 this->calendar_type = ci->calendar_type;
303 this->text_info_data = &ci->text_info;
309 construct_region (MonoRegionInfo *this, const RegionInfoEntry *ri)
311 MonoDomain *domain = mono_domain_get ();
313 this->geo_id = ri->geo_id;
314 MONO_OBJECT_SETREF (this, iso2name, mono_string_new (domain, idx2string (ri->iso2name)));
315 MONO_OBJECT_SETREF (this, iso3name, mono_string_new (domain, idx2string (ri->iso3name)));
316 MONO_OBJECT_SETREF (this, win3name, mono_string_new (domain, idx2string (ri->win3name)));
317 MONO_OBJECT_SETREF (this, english_name, mono_string_new (domain, idx2string (ri->english_name)));
318 MONO_OBJECT_SETREF (this, native_name, mono_string_new (domain, idx2string (ri->native_name)));
319 MONO_OBJECT_SETREF (this, currency_symbol, mono_string_new (domain, idx2string (ri->currency_symbol)));
320 MONO_OBJECT_SETREF (this, iso_currency_symbol, mono_string_new (domain, idx2string (ri->iso_currency_symbol)));
321 MONO_OBJECT_SETREF (this, currency_english_name, mono_string_new (domain, idx2string (ri->currency_english_name)));
322 MONO_OBJECT_SETREF (this, currency_native_name, mono_string_new (domain, idx2string (ri->currency_native_name)));
327 static const CultureInfoEntry*
328 culture_info_entry_from_lcid (int lcid)
330 const CultureInfoEntry *ci;
332 ci = mono_binary_search (&lcid, culture_entries, NUM_CULTURE_ENTRIES, sizeof (CultureInfoEntry), culture_lcid_locator);
337 static const RegionInfoEntry*
338 region_info_entry_from_lcid (int lcid)
340 const RegionInfoEntry *entry;
341 const CultureInfoEntry *ne;
343 ne = mono_binary_search (&lcid, culture_entries, NUM_CULTURE_ENTRIES, sizeof (CultureInfoEntry), culture_lcid_locator);
348 entry = ®ion_entries [ne->region_entry_index];
353 #if defined (__APPLE__)
355 get_darwin_locale (void)
357 static gchar *darwin_locale = NULL;
358 CFLocaleRef locale = NULL;
359 CFStringRef locale_language = NULL;
360 CFStringRef locale_country = NULL;
361 CFStringRef locale_script = NULL;
362 CFStringRef locale_cfstr = NULL;
363 CFIndex bytes_converted;
364 CFIndex bytes_written;
368 if (darwin_locale != NULL)
369 return g_strdup (darwin_locale);
371 locale = CFLocaleCopyCurrent ();
374 locale_language = CFLocaleGetValue (locale, kCFLocaleLanguageCode);
375 if (locale_language != NULL && CFStringGetBytes(locale_language, CFRangeMake (0, CFStringGetLength (locale_language)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
376 len = bytes_converted + 1;
378 locale_country = CFLocaleGetValue (locale, kCFLocaleCountryCode);
379 if (locale_country != NULL && CFStringGetBytes (locale_country, CFRangeMake (0, CFStringGetLength (locale_country)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
380 len += bytes_converted + 1;
382 locale_script = CFLocaleGetValue (locale, kCFLocaleScriptCode);
383 if (locale_script != NULL && CFStringGetBytes (locale_script, CFRangeMake (0, CFStringGetLength (locale_script)), kCFStringEncodingMacRoman, 0, FALSE, NULL, 0, &bytes_converted) > 0) {
384 len += bytes_converted + 1;
387 darwin_locale = (char *) malloc (len + 1);
388 CFStringGetBytes (locale_language, CFRangeMake (0, CFStringGetLength (locale_language)), kCFStringEncodingMacRoman, 0, FALSE, (UInt8 *) darwin_locale, len, &bytes_converted);
390 darwin_locale[bytes_converted] = '-';
391 bytes_written = bytes_converted + 1;
392 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) {
393 darwin_locale[bytes_written + bytes_converted] = '-';
394 bytes_written += bytes_converted + 1;
397 CFStringGetBytes (locale_country, CFRangeMake (0, CFStringGetLength (locale_country)), kCFStringEncodingMacRoman, 0, FALSE, (UInt8 *) &darwin_locale[bytes_written], len - bytes_written, &bytes_converted);
398 darwin_locale[bytes_written + bytes_converted] = '\0';
402 if (darwin_locale == NULL) {
403 locale_cfstr = CFLocaleGetIdentifier (locale);
406 len = CFStringGetMaximumSizeForEncoding (CFStringGetLength (locale_cfstr), kCFStringEncodingMacRoman) + 1;
407 darwin_locale = (char *) malloc (len);
408 if (!CFStringGetCString (locale_cfstr, darwin_locale, len, kCFStringEncodingMacRoman)) {
409 free (darwin_locale);
411 darwin_locale = NULL;
415 for (i = 0; i < strlen (darwin_locale); i++)
416 if (darwin_locale [i] == '_')
417 darwin_locale [i] = '-';
424 return g_strdup (darwin_locale);
429 get_posix_locale (void)
433 locale = g_getenv ("LC_ALL");
434 if (locale == NULL) {
435 locale = g_getenv ("LANG");
437 locale = setlocale (LC_ALL, NULL);
442 /* Skip English-only locale 'C' */
443 if (strcmp (locale, "C") == 0)
446 return g_strdup (locale);
451 get_current_locale_name (void)
457 locale = g_win32_getlocale ();
458 #elif defined (__APPLE__)
459 locale = get_darwin_locale ();
461 locale = get_posix_locale ();
463 locale = get_posix_locale ();
469 p = strchr (locale, '.');
472 p = strchr (locale, '@');
475 p = strchr (locale, '_');
479 ret = g_ascii_strdown (locale, -1);
486 ves_icall_System_Globalization_CultureInfo_get_current_locale_name (void)
492 locale = get_current_locale_name ();
496 domain = mono_domain_get ();
497 ret = mono_string_new (domain, locale);
504 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo *this,
507 const CultureInfoEntry *ci;
509 ci = culture_info_entry_from_lcid (lcid);
513 return construct_culture (this, ci);
517 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo *this,
520 const CultureInfoNameEntry *ne;
523 n = mono_string_to_utf8 (name);
524 ne = mono_binary_search (n, culture_name_entries, NUM_CULTURE_ENTRIES,
525 sizeof (CultureInfoNameEntry), culture_name_locator);
528 /*g_print ("ne (%s) is null\n", n);*/
534 return construct_culture (this, &culture_entries [ne->culture_entry_index]);
538 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo *ci,
544 locale = mono_string_to_utf8 (name);
545 ret = construct_culture_from_specific_name (ci, locale);
552 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo *this,
555 const RegionInfoEntry *ri;
557 ri = region_info_entry_from_lcid (lcid);
561 return construct_region (this, ri);
565 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo *this,
568 const RegionInfoNameEntry *ne;
571 n = mono_string_to_utf8 (name);
572 ne = mono_binary_search (n, region_name_entries, NUM_REGION_ENTRIES,
573 sizeof (RegionInfoNameEntry), region_name_locator);
576 /*g_print ("ne (%s) is null\n", n);*/
582 return construct_region (this, ®ion_entries [ne->region_entry_index]);
586 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral,
587 MonoBoolean specific, MonoBoolean installed)
591 MonoCultureInfo *culture;
593 const CultureInfoEntry *ci;
597 domain = mono_domain_get ();
600 for (i = 0; i < NUM_CULTURE_ENTRIES; i++) {
601 ci = &culture_entries [i];
602 is_neutral = ci->territory == 0;
603 if ((neutral && is_neutral) || (specific && !is_neutral))
607 class = mono_class_from_name (mono_get_corlib (),
608 "System.Globalization", "CultureInfo");
610 /* The InvariantCulture is not in culture_entries */
611 /* We reserve the first slot in the array for it */
615 ret = mono_array_new (domain, class, len);
622 mono_array_setref (ret, len++, NULL);
624 for (i = 0; i < NUM_CULTURE_ENTRIES; i++) {
625 ci = &culture_entries [i];
626 is_neutral = ci->territory == 0;
627 if ((neutral && is_neutral) || (specific && !is_neutral)) {
628 culture = (MonoCultureInfo *) mono_object_new (domain, class);
629 mono_runtime_object_init ((MonoObject *) culture);
630 construct_culture (culture, ci);
631 culture->use_user_override = TRUE;
632 mono_array_setref (ret, len++, culture);
639 void ves_icall_System_Globalization_CompareInfo_construct_compareinfo (MonoCompareInfo *comp, MonoString *locale)
641 /* Nothing to do here */
644 int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoCompareInfo *this, MonoString *str1, gint32 off1, gint32 len1, MonoString *str2, gint32 off2, gint32 len2, gint32 options)
646 /* Do a normal ascii string compare, as we only know the
647 * invariant locale if we dont have ICU
649 return(string_invariant_compare (str1, off1, len1, str2, off2, len2,
653 void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoCompareInfo *this)
655 /* Nothing to do here */
658 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo *this, MonoSortKey *key, MonoString *source, gint32 options)
663 keylen=mono_string_length (source);
665 arr=mono_array_new (mono_domain_get (), mono_get_byte_class (),
667 for(i=0; i<keylen; i++) {
668 mono_array_set (arr, guint8, i, mono_string_chars (source)[i]);
671 MONO_OBJECT_SETREF (key, key, arr);
674 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo *this, MonoString *source, gint32 sindex, gint32 count, MonoString *value, gint32 options, MonoBoolean first)
676 return(string_invariant_indexof (source, sindex, count, value, first));
679 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo *this, MonoString *source, gint32 sindex, gint32 count, gunichar2 value, gint32 options, MonoBoolean first)
681 return(string_invariant_indexof_char (source, sindex, count, value,
685 int ves_icall_System_Threading_Thread_current_lcid (void)
691 MonoString *ves_icall_System_String_InternalReplace_Str_Comp (MonoString *this, MonoString *old, MonoString *new, MonoCompareInfo *comp)
693 /* Do a normal ascii string compare and replace, as we only
694 * know the invariant locale if we dont have ICU
696 return(string_invariant_replace (this, old, new));
699 static gint32 string_invariant_compare_char (gunichar2 c1, gunichar2 c2,
704 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
705 if (options & CompareOptions_Ordinal)
706 return (gint32) c1 - c2;
708 if (options & CompareOptions_IgnoreCase) {
709 GUnicodeType c1type, c2type;
711 c1type = g_unichar_type (c1);
712 c2type = g_unichar_type (c2);
714 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) -
715 (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
718 * No options. Kana, symbol and spacing options don't
719 * apply to the invariant culture.
723 * FIXME: here we must use the information from c1type and c2type
724 * to find out the proper collation, even on the InvariantCulture, the
725 * sorting is not done by computing the unicode values, but their
728 result = (gint32) c1 - c2;
731 return ((result < 0) ? -1 : (result > 0) ? 1 : 0);
734 static gint32 string_invariant_compare (MonoString *str1, gint32 off1,
735 gint32 len1, MonoString *str2,
736 gint32 off2, gint32 len2,
739 /* c translation of C# code from old string.cs.. :) */
752 ustr1 = mono_string_chars(str1)+off1;
753 ustr2 = mono_string_chars(str2)+off2;
757 for (pos = 0; pos != length; pos++) {
758 if (pos >= len1 || pos >= len2)
761 charcmp = string_invariant_compare_char(ustr1[pos], ustr2[pos],
768 /* the lesser wins, so if we have looped until length we just
769 * need to check the last char
772 return(string_invariant_compare_char(ustr1[pos - 1],
773 ustr2[pos - 1], options));
776 /* Test if one of the strings has been compared to the end */
783 } else if (pos >= len2) {
787 /* if not, check our last char only.. (can this happen?) */
788 return(string_invariant_compare_char(ustr1[pos], ustr2[pos], options));
791 static MonoString *string_invariant_replace (MonoString *me,
792 MonoString *oldValue,
793 MonoString *newValue)
797 gunichar2 *dest=NULL; /* shut gcc up */
799 gunichar2 *newstr=NULL; /* shut gcc up here too */
810 oldstr = mono_string_chars(oldValue);
811 oldstrlen = mono_string_length(oldValue);
813 if (NULL != newValue) {
814 newstr = mono_string_chars(newValue);
815 newstrlen = mono_string_length(newValue);
819 src = mono_string_chars(me);
820 srclen = mono_string_length(me);
822 if (oldstrlen != newstrlen) {
824 while (i <= srclen - oldstrlen) {
825 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
834 newsize = srclen + ((newstrlen - oldstrlen) * occurr);
841 if (0 == memcmp(src + i, oldstr, oldstrlen * sizeof(gunichar2))) {
843 ret = mono_string_new_size( mono_domain_get (), newsize);
844 dest = mono_string_chars(ret);
845 memcpy (dest, src, i * sizeof(gunichar2));
848 memcpy(dest + destpos, newstr, newstrlen * sizeof(gunichar2));
849 destpos += newstrlen;
853 } else if (ret != NULL) {
854 dest[destpos] = src[i];
866 static gint32 string_invariant_indexof (MonoString *source, gint32 sindex,
867 gint32 count, MonoString *value,
875 lencmpstr = mono_string_length(value);
877 src = mono_string_chars(source);
878 cmpstr = mono_string_chars(value);
882 for(pos=sindex;pos <= sindex+count;pos++) {
883 for(i=0;src[pos+i]==cmpstr[i];) {
892 for(pos=sindex-lencmpstr+1;pos>sindex-count;pos--) {
893 if(memcmp (src+pos, cmpstr,
894 lencmpstr*sizeof(gunichar2))==0) {
903 static gint32 string_invariant_indexof_char (MonoString *source, gint32 sindex,
904 gint32 count, gunichar2 value,
910 src = mono_string_chars(source);
912 for (pos = sindex; pos != count + sindex; pos++) {
913 if (src [pos] == value) {
920 for (pos = sindex; pos > sindex - count; pos--) {
921 if (src [pos] == value)
929 void load_normalization_resource (guint8 **argProps,
930 guint8 **argMappedChars,
931 guint8 **argCharMapIndex,
932 guint8 **argHelperIndex,
933 guint8 **argMapIdxToComposite,
934 guint8 **argCombiningClass)
936 #ifdef DISABLE_NORMALIZATION
937 mono_set_pending_exception (mono_get_exception_not_supported ("This runtime has been compiled without string normalization support."));
940 *argProps = (guint8*)props;
941 *argMappedChars = (guint8*) mappedChars;
942 *argCharMapIndex = (guint8*) charMapIndex;
943 *argHelperIndex = (guint8*) helperIndex;
944 *argMapIdxToComposite = (guint8*) mapIdxToComposite;
945 *argCombiningClass = (guint8*)combiningClass;