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_CultureInfo_construct_datetime_format (MonoCultureInfo
*this)
164 MonoDateTimeFormatInfo
*datetime
;
165 const DateTimeFormatEntry
*dfe
;
169 g_assert (this->datetime_index
>= 0);
171 datetime
= this->datetime_format
;
172 dfe
= &datetime_format_entries
[this->datetime_index
];
174 domain
= mono_domain_get ();
176 datetime
->readOnly
= this->is_read_only
;
177 MONO_OBJECT_SETREF (datetime
, AbbreviatedDayNames
, create_names_array_idx (dfe
->abbreviated_day_names
,
179 MONO_OBJECT_SETREF (datetime
, AbbreviatedMonthNames
, create_names_array_idx (dfe
->abbreviated_month_names
,
181 MONO_OBJECT_SETREF (datetime
, AMDesignator
, mono_string_new (domain
, idx2string (dfe
->am_designator
)));
182 datetime
->CalendarWeekRule
= dfe
->calendar_week_rule
;
183 MONO_OBJECT_SETREF (datetime
, DateSeparator
, mono_string_new (domain
, idx2string (dfe
->date_separator
)));
184 MONO_OBJECT_SETREF (datetime
, DayNames
, create_names_array_idx (dfe
->day_names
, NUM_DAYS
));
185 MONO_OBJECT_SETREF (datetime
, ShortestDayNames
, create_names_array_idx (dfe
->shortest_day_names
, NUM_DAYS
));
186 datetime
->FirstDayOfWeek
= dfe
->first_day_of_week
;
187 MONO_OBJECT_SETREF (datetime
, LongDatePattern
, mono_string_new (domain
, idx2string (dfe
->long_date_pattern
)));
188 MONO_OBJECT_SETREF (datetime
, LongTimePattern
, mono_string_new (domain
, idx2string (dfe
->long_time_pattern
)));
189 MONO_OBJECT_SETREF (datetime
, MonthDayPattern
, mono_string_new (domain
, idx2string (dfe
->month_day_pattern
)));
190 MONO_OBJECT_SETREF (datetime
, MonthNames
, create_names_array_idx (dfe
->month_names
, NUM_MONTHS
));
191 MONO_OBJECT_SETREF (datetime
, PMDesignator
, mono_string_new (domain
, idx2string (dfe
->pm_designator
)));
192 MONO_OBJECT_SETREF (datetime
, ShortDatePattern
, mono_string_new (domain
, idx2string (dfe
->short_date_pattern
)));
193 MONO_OBJECT_SETREF (datetime
, ShortTimePattern
, mono_string_new (domain
, idx2string (dfe
->short_time_pattern
)));
194 MONO_OBJECT_SETREF (datetime
, TimeSeparator
, mono_string_new (domain
, idx2string (dfe
->time_separator
)));
195 MONO_OBJECT_SETREF (datetime
, YearMonthPattern
, mono_string_new (domain
, idx2string (dfe
->year_month_pattern
)));
196 MONO_OBJECT_SETREF (datetime
, ShortDatePatterns
, create_names_array_idx_dynamic (dfe
->short_date_patterns
,
197 NUM_SHORT_DATE_PATTERNS
));
198 MONO_OBJECT_SETREF (datetime
, LongDatePatterns
, create_names_array_idx_dynamic (dfe
->long_date_patterns
,
199 NUM_LONG_DATE_PATTERNS
));
200 MONO_OBJECT_SETREF (datetime
, ShortTimePatterns
, create_names_array_idx_dynamic (dfe
->short_time_patterns
,
201 NUM_SHORT_TIME_PATTERNS
));
202 MONO_OBJECT_SETREF (datetime
, LongTimePatterns
, create_names_array_idx_dynamic (dfe
->long_time_patterns
,
203 NUM_LONG_TIME_PATTERNS
));
204 MONO_OBJECT_SETREF (datetime
, GenitiveMonthNames
, create_names_array_idx (dfe
->month_genitive_names
, NUM_MONTHS
));
205 MONO_OBJECT_SETREF (datetime
, GenitiveAbbreviatedMonthNames
, create_names_array_idx (dfe
->abbreviated_month_genitive_names
, NUM_MONTHS
));
209 ves_icall_System_Globalization_CultureInfo_construct_number_format (MonoCultureInfo
*this)
212 MonoNumberFormatInfo
*number
;
213 const NumberFormatEntry
*nfe
;
217 g_assert (this->number_format
!= 0);
218 if (this->number_index
< 0)
221 number
= this->number_format
;
222 nfe
= &number_format_entries
[this->number_index
];
224 domain
= mono_domain_get ();
226 number
->readOnly
= this->is_read_only
;
227 number
->currencyDecimalDigits
= nfe
->currency_decimal_digits
;
228 MONO_OBJECT_SETREF (number
, currencyDecimalSeparator
, mono_string_new (domain
,
229 idx2string (nfe
->currency_decimal_separator
)));
230 MONO_OBJECT_SETREF (number
, currencyGroupSeparator
, mono_string_new (domain
,
231 idx2string (nfe
->currency_group_separator
)));
232 MONO_OBJECT_SETREF (number
, currencyGroupSizes
, create_group_sizes_array (nfe
->currency_group_sizes
,
234 number
->currencyNegativePattern
= nfe
->currency_negative_pattern
;
235 number
->currencyPositivePattern
= nfe
->currency_positive_pattern
;
236 MONO_OBJECT_SETREF (number
, currencySymbol
, mono_string_new (domain
, idx2string (nfe
->currency_symbol
)));
237 MONO_OBJECT_SETREF (number
, naNSymbol
, mono_string_new (domain
, idx2string (nfe
->nan_symbol
)));
238 MONO_OBJECT_SETREF (number
, negativeInfinitySymbol
, mono_string_new (domain
,
239 idx2string (nfe
->negative_infinity_symbol
)));
240 MONO_OBJECT_SETREF (number
, negativeSign
, mono_string_new (domain
, idx2string (nfe
->negative_sign
)));
241 number
->numberDecimalDigits
= nfe
->number_decimal_digits
;
242 MONO_OBJECT_SETREF (number
, numberDecimalSeparator
, mono_string_new (domain
,
243 idx2string (nfe
->number_decimal_separator
)));
244 MONO_OBJECT_SETREF (number
, numberGroupSeparator
, mono_string_new (domain
, idx2string (nfe
->number_group_separator
)));
245 MONO_OBJECT_SETREF (number
, numberGroupSizes
, create_group_sizes_array (nfe
->number_group_sizes
,
247 number
->numberNegativePattern
= nfe
->number_negative_pattern
;
248 number
->percentDecimalDigits
= nfe
->percent_decimal_digits
;
249 MONO_OBJECT_SETREF (number
, percentDecimalSeparator
, mono_string_new (domain
,
250 idx2string (nfe
->percent_decimal_separator
)));
251 MONO_OBJECT_SETREF (number
, percentGroupSeparator
, mono_string_new (domain
,
252 idx2string (nfe
->percent_group_separator
)));
253 MONO_OBJECT_SETREF (number
, percentGroupSizes
, create_group_sizes_array (nfe
->percent_group_sizes
,
255 number
->percentNegativePattern
= nfe
->percent_negative_pattern
;
256 number
->percentPositivePattern
= nfe
->percent_positive_pattern
;
257 MONO_OBJECT_SETREF (number
, percentSymbol
, mono_string_new (domain
, idx2string (nfe
->percent_symbol
)));
258 MONO_OBJECT_SETREF (number
, perMilleSymbol
, mono_string_new (domain
, idx2string (nfe
->per_mille_symbol
)));
259 MONO_OBJECT_SETREF (number
, positiveInfinitySymbol
, mono_string_new (domain
,
260 idx2string (nfe
->positive_infinity_symbol
)));
261 MONO_OBJECT_SETREF (number
, positiveSign
, mono_string_new (domain
, idx2string (nfe
->positive_sign
)));
265 construct_culture (MonoCultureInfo
*this, const CultureInfoEntry
*ci
)
267 MonoDomain
*domain
= mono_domain_get ();
269 this->lcid
= ci
->lcid
;
270 MONO_OBJECT_SETREF (this, name
, mono_string_new (domain
, idx2string (ci
->name
)));
271 MONO_OBJECT_SETREF (this, englishname
, mono_string_new (domain
, idx2string (ci
->englishname
)));
272 MONO_OBJECT_SETREF (this, nativename
, mono_string_new (domain
, idx2string (ci
->nativename
)));
273 MONO_OBJECT_SETREF (this, win3lang
, mono_string_new (domain
, idx2string (ci
->win3lang
)));
274 MONO_OBJECT_SETREF (this, iso3lang
, mono_string_new (domain
, idx2string (ci
->iso3lang
)));
275 MONO_OBJECT_SETREF (this, iso2lang
, mono_string_new (domain
, idx2string (ci
->iso2lang
)));
277 // It's null for neutral cultures
278 if (ci
->territory
> 0)
279 MONO_OBJECT_SETREF (this, territory
, mono_string_new (domain
, idx2string (ci
->territory
)));
280 MONO_OBJECT_SETREF (this, native_calendar_names
, create_names_array_idx (ci
->native_calendar_names
, NUM_CALENDARS
));
281 this->parent_lcid
= ci
->parent_lcid
;
282 this->datetime_index
= ci
->datetime_format_index
;
283 this->number_index
= ci
->number_format_index
;
284 this->calendar_type
= ci
->calendar_type
;
285 this->text_info_data
= &ci
->text_info
;
291 construct_region (MonoRegionInfo
*this, const RegionInfoEntry
*ri
)
293 MonoDomain
*domain
= mono_domain_get ();
295 this->geo_id
= ri
->geo_id
;
296 MONO_OBJECT_SETREF (this, iso2name
, mono_string_new (domain
, idx2string (ri
->iso2name
)));
297 MONO_OBJECT_SETREF (this, iso3name
, mono_string_new (domain
, idx2string (ri
->iso3name
)));
298 MONO_OBJECT_SETREF (this, win3name
, mono_string_new (domain
, idx2string (ri
->win3name
)));
299 MONO_OBJECT_SETREF (this, english_name
, mono_string_new (domain
, idx2string (ri
->english_name
)));
300 MONO_OBJECT_SETREF (this, native_name
, mono_string_new (domain
, idx2string (ri
->native_name
)));
301 MONO_OBJECT_SETREF (this, currency_symbol
, mono_string_new (domain
, idx2string (ri
->currency_symbol
)));
302 MONO_OBJECT_SETREF (this, iso_currency_symbol
, mono_string_new (domain
, idx2string (ri
->iso_currency_symbol
)));
303 MONO_OBJECT_SETREF (this, currency_english_name
, mono_string_new (domain
, idx2string (ri
->currency_english_name
)));
304 MONO_OBJECT_SETREF (this, currency_native_name
, mono_string_new (domain
, idx2string (ri
->currency_native_name
)));
309 static const CultureInfoEntry
*
310 culture_info_entry_from_lcid (int lcid
)
312 const CultureInfoEntry
*ci
;
314 ci
= mono_binary_search (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
319 static const RegionInfoEntry
*
320 region_info_entry_from_lcid (int lcid
)
322 const RegionInfoEntry
*entry
;
323 const CultureInfoEntry
*ne
;
327 ne
= mono_binary_search (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
332 entry
= ®ion_entries
[ne
->region_entry_index
];
337 #if defined (__APPLE__)
339 get_darwin_locale (void)
341 static gchar
*darwin_locale
= NULL
;
342 CFLocaleRef locale
= NULL
;
343 CFStringRef locale_language
= NULL
;
344 CFStringRef locale_country
= NULL
;
345 CFStringRef locale_script
= NULL
;
346 CFStringRef locale_cfstr
= NULL
;
347 CFIndex bytes_converted
;
348 CFIndex bytes_written
;
352 if (darwin_locale
!= NULL
)
353 return g_strdup (darwin_locale
);
355 locale
= CFLocaleCopyCurrent ();
358 locale_language
= CFLocaleGetValue (locale
, kCFLocaleLanguageCode
);
359 if (locale_language
!= NULL
&& CFStringGetBytes(locale_language
, CFRangeMake (0, CFStringGetLength (locale_language
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
360 len
= bytes_converted
+ 1;
362 locale_country
= CFLocaleGetValue (locale
, kCFLocaleCountryCode
);
363 if (locale_country
!= NULL
&& CFStringGetBytes (locale_country
, CFRangeMake (0, CFStringGetLength (locale_country
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
364 len
+= bytes_converted
+ 1;
366 locale_script
= CFLocaleGetValue (locale
, kCFLocaleScriptCode
);
367 if (locale_script
!= NULL
&& CFStringGetBytes (locale_script
, CFRangeMake (0, CFStringGetLength (locale_script
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
368 len
+= bytes_converted
+ 1;
371 darwin_locale
= (char *) malloc (len
+ 1);
372 CFStringGetBytes (locale_language
, CFRangeMake (0, CFStringGetLength (locale_language
)), kCFStringEncodingMacRoman
, 0, FALSE
, (UInt8
*) darwin_locale
, len
, &bytes_converted
);
374 darwin_locale
[bytes_converted
] = '-';
375 bytes_written
= bytes_converted
+ 1;
376 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) {
377 darwin_locale
[bytes_written
+ bytes_converted
] = '-';
378 bytes_written
+= bytes_converted
+ 1;
381 CFStringGetBytes (locale_country
, CFRangeMake (0, CFStringGetLength (locale_country
)), kCFStringEncodingMacRoman
, 0, FALSE
, (UInt8
*) &darwin_locale
[bytes_written
], len
- bytes_written
, &bytes_converted
);
382 darwin_locale
[bytes_written
+ bytes_converted
] = '\0';
386 if (darwin_locale
== NULL
) {
387 locale_cfstr
= CFLocaleGetIdentifier (locale
);
390 len
= CFStringGetMaximumSizeForEncoding (CFStringGetLength (locale_cfstr
), kCFStringEncodingMacRoman
) + 1;
391 darwin_locale
= (char *) malloc (len
);
392 if (!CFStringGetCString (locale_cfstr
, darwin_locale
, len
, kCFStringEncodingMacRoman
)) {
393 free (darwin_locale
);
395 darwin_locale
= NULL
;
399 for (i
= 0; i
< strlen (darwin_locale
); i
++)
400 if (darwin_locale
[i
] == '_')
401 darwin_locale
[i
] = '-';
408 return g_strdup (darwin_locale
);
413 get_posix_locale (void)
417 locale
= g_getenv ("LC_ALL");
418 if (locale
== NULL
) {
419 locale
= g_getenv ("LANG");
421 locale
= setlocale (LC_ALL
, NULL
);
426 /* Skip English-only locale 'C' */
427 if (strcmp (locale
, "C") == 0)
430 return g_strdup (locale
);
435 get_current_locale_name (void)
441 locale
= g_win32_getlocale ();
442 #elif defined (__APPLE__)
443 locale
= get_darwin_locale ();
445 locale
= get_posix_locale ();
447 locale
= get_posix_locale ();
453 p
= strchr (locale
, '.');
456 p
= strchr (locale
, '@');
459 p
= strchr (locale
, '_');
463 ret
= g_ascii_strdown (locale
, -1);
470 ves_icall_System_Globalization_CultureInfo_get_current_locale_name (void)
478 locale
= get_current_locale_name ();
482 domain
= mono_domain_get ();
483 ret
= mono_string_new (domain
, locale
);
490 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo
*this,
493 const CultureInfoEntry
*ci
;
497 ci
= culture_info_entry_from_lcid (lcid
);
501 return construct_culture (this, ci
);
505 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo
*this,
508 const CultureInfoNameEntry
*ne
;
513 n
= mono_string_to_utf8 (name
);
514 ne
= mono_binary_search (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
515 sizeof (CultureInfoNameEntry
), culture_name_locator
);
518 /*g_print ("ne (%s) is null\n", n);*/
524 return construct_culture (this, &culture_entries
[ne
->culture_entry_index
]);
528 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo *ci,
536 locale = mono_string_to_utf8 (name);
537 ret = construct_culture_from_specific_name (ci, locale);
544 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo
*this,
547 const RegionInfoEntry
*ri
;
551 ri
= region_info_entry_from_lcid (lcid
);
555 return construct_region (this, ri
);
559 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo
*this,
562 const RegionInfoNameEntry
*ne
;
567 n
= mono_string_to_utf8 (name
);
568 ne
= mono_binary_search (n
, region_name_entries
, NUM_REGION_ENTRIES
,
569 sizeof (RegionInfoNameEntry
), region_name_locator
);
572 /*g_print ("ne (%s) is null\n", n);*/
578 return construct_region (this, ®ion_entries
[ne
->region_entry_index
]);
582 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral
,
583 MonoBoolean specific
, MonoBoolean installed
)
587 MonoCultureInfo
*culture
;
589 const CultureInfoEntry
*ci
;
595 domain
= mono_domain_get ();
598 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
599 ci
= &culture_entries
[i
];
600 is_neutral
= ci
->territory
== 0;
601 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
))
605 class = mono_class_from_name (mono_get_corlib (),
606 "System.Globalization", "CultureInfo");
608 /* The InvariantCulture is not in culture_entries */
609 /* We reserve the first slot in the array for it */
613 ret
= mono_array_new (domain
, class, len
);
620 mono_array_setref (ret
, len
++, NULL
);
622 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
623 ci
= &culture_entries
[i
];
624 is_neutral
= ci
->territory
== 0;
625 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
)) {
626 culture
= (MonoCultureInfo
*) mono_object_new (domain
, class);
627 mono_runtime_object_init ((MonoObject
*) culture
);
628 construct_culture (culture
, ci
);
629 culture
->use_user_override
= TRUE
;
630 mono_array_setref (ret
, len
++, culture
);
637 void ves_icall_System_Globalization_CompareInfo_construct_compareinfo (MonoCompareInfo
*comp
, MonoString
*locale
)
639 /* Nothing to do here */
642 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
)
665 keylen
=mono_string_length (source
);
667 arr
=mono_array_new (mono_domain_get (), mono_get_byte_class (),
669 for(i
=0; i
<keylen
; i
++) {
670 mono_array_set (arr
, guint8
, i
, mono_string_chars (source
)[i
]);
673 MONO_OBJECT_SETREF (key
, key
, arr
);
676 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, MonoString
*value
, gint32 options
, MonoBoolean first
)
680 return(string_invariant_indexof (source
, sindex
, count
, value
, first
));
683 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, gunichar2 value
, gint32 options
, MonoBoolean first
)
687 return(string_invariant_indexof_char (source
, sindex
, count
, value
,
691 int ves_icall_System_Threading_Thread_current_lcid (void)
699 MonoString
*ves_icall_System_String_InternalReplace_Str_Comp (MonoString
*this, MonoString
*old
, MonoString
*new, MonoCompareInfo
*comp
)
703 /* Do a normal ascii string compare and replace, as we only
704 * know the invariant locale if we dont have ICU
706 return(string_invariant_replace (this, old
, new));
709 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
714 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
715 if (options
& CompareOptions_Ordinal
)
716 return (gint32
) c1
- c2
;
718 if (options
& CompareOptions_IgnoreCase
) {
719 GUnicodeType c1type
, c2type
;
721 c1type
= g_unichar_type (c1
);
722 c2type
= g_unichar_type (c2
);
724 result
= (gint32
) (c1type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c1
) : c1
) -
725 (c2type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c2
) : c2
);
728 * No options. Kana, symbol and spacing options don't
729 * apply to the invariant culture.
733 * FIXME: here we must use the information from c1type and c2type
734 * to find out the proper collation, even on the InvariantCulture, the
735 * sorting is not done by computing the unicode values, but their
738 result
= (gint32
) c1
- c2
;
741 return ((result
< 0) ? -1 : (result
> 0) ? 1 : 0);
744 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
745 gint32 len1
, MonoString
*str2
,
746 gint32 off2
, gint32 len2
,
749 /* c translation of C# code from old string.cs.. :) */
762 ustr1
= mono_string_chars(str1
)+off1
;
763 ustr2
= mono_string_chars(str2
)+off2
;
767 for (pos
= 0; pos
!= length
; pos
++) {
768 if (pos
>= len1
|| pos
>= len2
)
771 charcmp
= string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
],
778 /* the lesser wins, so if we have looped until length we just
779 * need to check the last char
782 return(string_invariant_compare_char(ustr1
[pos
- 1],
783 ustr2
[pos
- 1], options
));
786 /* Test if one of the strings has been compared to the end */
793 } else if (pos
>= len2
) {
797 /* if not, check our last char only.. (can this happen?) */
798 return(string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
], options
));
801 static MonoString
*string_invariant_replace (MonoString
*me
,
802 MonoString
*oldValue
,
803 MonoString
*newValue
)
807 gunichar2
*dest
=NULL
; /* shut gcc up */
809 gunichar2
*newstr
=NULL
; /* shut gcc up here too */
820 oldstr
= mono_string_chars(oldValue
);
821 oldstrlen
= mono_string_length(oldValue
);
823 if (NULL
!= newValue
) {
824 newstr
= mono_string_chars(newValue
);
825 newstrlen
= mono_string_length(newValue
);
829 src
= mono_string_chars(me
);
830 srclen
= mono_string_length(me
);
832 if (oldstrlen
!= newstrlen
) {
834 while (i
<= srclen
- oldstrlen
) {
835 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
844 newsize
= srclen
+ ((newstrlen
- oldstrlen
) * occurr
);
851 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
853 ret
= mono_string_new_size( mono_domain_get (), newsize
);
854 dest
= mono_string_chars(ret
);
855 memcpy (dest
, src
, i
* sizeof(gunichar2
));
858 memcpy(dest
+ destpos
, newstr
, newstrlen
* sizeof(gunichar2
));
859 destpos
+= newstrlen
;
863 } else if (ret
!= NULL
) {
864 dest
[destpos
] = src
[i
];
876 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
877 gint32 count
, MonoString
*value
,
885 lencmpstr
= mono_string_length(value
);
887 src
= mono_string_chars(source
);
888 cmpstr
= mono_string_chars(value
);
892 for(pos
=sindex
;pos
<= sindex
+count
;pos
++) {
893 for(i
=0;src
[pos
+i
]==cmpstr
[i
];) {
902 for(pos
=sindex
-lencmpstr
+1;pos
>sindex
-count
;pos
--) {
903 if(memcmp (src
+pos
, cmpstr
,
904 lencmpstr
*sizeof(gunichar2
))==0) {
913 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
914 gint32 count
, gunichar2 value
,
920 src
= mono_string_chars(source
);
922 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
923 if (src
[pos
] == value
) {
930 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
931 if (src
[pos
] == value
)
939 void load_normalization_resource (guint8
**argProps
,
940 guint8
**argMappedChars
,
941 guint8
**argCharMapIndex
,
942 guint8
**argHelperIndex
,
943 guint8
**argMapIdxToComposite
,
944 guint8
**argCombiningClass
)
946 #ifdef DISABLE_NORMALIZATION
947 mono_raise_exception (mono_get_exception_not_supported ("This runtime has been compiled without string normalization support."));
949 *argProps
= (guint8
*)props
;
950 *argMappedChars
= (guint8
*) mappedChars
;
951 *argCharMapIndex
= (guint8
*) charMapIndex
;
952 *argHelperIndex
= (guint8
*) helperIndex
;
953 *argMapIdxToComposite
= (guint8
*) mapIdxToComposite
;
954 *argCombiningClass
= (guint8
*)combiningClass
;