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)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/appdomain.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/monitor.h>
25 #include <mono/metadata/locales.h>
26 #include <mono/metadata/culture-info.h>
27 #include <mono/metadata/culture-info-tables.h>
28 #include <mono/utils/bsearch.h>
30 #ifndef DISABLE_NORMALIZATION
31 #include <mono/metadata/normalization-tables.h>
35 #if defined(__APPLE__)
36 #include <CoreFoundation/CoreFoundation.h>
41 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
43 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
44 gint32 len1
, MonoString
*str2
,
45 gint32 off2
, gint32 len2
,
47 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
48 gint32 count
, MonoString
*value
,
50 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
51 gint32 count
, gunichar2 value
,
54 static const CultureInfoEntry
* culture_info_entry_from_lcid (int lcid
);
56 static const RegionInfoEntry
* region_info_entry_from_lcid (int lcid
);
58 /* Lazy class loading functions */
59 static GENERATE_GET_CLASS_WITH_CACHE (culture_info
, System
.Globalization
, CultureInfo
)
62 culture_lcid_locator (const void *a
, const void *b
)
64 const int *lcid
= (const int *)a
;
65 const CultureInfoEntry
*bb
= (const CultureInfoEntry
*)b
;
67 return *lcid
- bb
->lcid
;
71 culture_name_locator (const void *a
, const void *b
)
73 const char *aa
= (const char *)a
;
74 const CultureInfoNameEntry
*bb
= (const CultureInfoNameEntry
*)b
;
77 ret
= strcmp (aa
, idx2string (bb
->name
));
83 region_name_locator (const void *a
, const void *b
)
85 const char *aa
= (const char *)a
;
86 const RegionInfoNameEntry
*bb
= (const RegionInfoNameEntry
*)b
;
89 ret
= strcmp (aa
, idx2string (bb
->name
));
95 create_group_sizes_array (const gint
*gs
, gint ml
, MonoError
*error
)
100 mono_error_init (error
);
102 for (i
= 0; i
< ml
; i
++) {
108 ret
= mono_array_new_cached (mono_domain_get (),
109 mono_get_int32_class (), len
, error
);
110 return_val_if_nok (error
, NULL
);
112 for(i
= 0; i
< len
; i
++)
113 mono_array_set (ret
, gint32
, i
, gs
[i
]);
119 create_names_array_idx (const guint16
*names
, int ml
, MonoError
*error
)
125 mono_error_init (error
);
130 domain
= mono_domain_get ();
132 ret
= mono_array_new_cached (mono_domain_get (), mono_get_string_class (), ml
, error
);
133 return_val_if_nok (error
, NULL
);
135 for(i
= 0; i
< ml
; i
++)
136 mono_array_setref (ret
, i
, mono_string_new (domain
, dtidx2string (names
[i
])));
142 create_names_array_idx_dynamic (const guint16
*names
, int ml
, MonoError
*error
)
148 mono_error_init (error
);
153 domain
= mono_domain_get ();
155 for (i
= 0; i
< ml
; i
++) {
161 ret
= mono_array_new_cached (mono_domain_get (), mono_get_string_class (), len
, error
);
162 return_val_if_nok (error
, NULL
);
164 for(i
= 0; i
< len
; i
++)
165 mono_array_setref (ret
, i
, mono_string_new (domain
, pattern2string (names
[i
])));
171 ves_icall_System_Globalization_CalendarData_fill_calendar_data (MonoCalendarData
*this_obj
, MonoString
*name
, gint32 calendar_index
)
175 const DateTimeFormatEntry
*dfe
;
176 const CultureInfoNameEntry
*ne
;
177 const CultureInfoEntry
*ci
;
180 n
= mono_string_to_utf8_checked (name
, &error
);
181 if (mono_error_set_pending_exception (&error
))
183 ne
= (const CultureInfoNameEntry
*)mono_binary_search (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
184 sizeof (CultureInfoNameEntry
), culture_name_locator
);
190 ci
= &culture_entries
[ne
->culture_entry_index
];
191 dfe
= &datetime_format_entries
[ci
->datetime_format_index
];
193 domain
= mono_domain_get ();
195 MONO_OBJECT_SETREF (this_obj
, NativeName
, mono_string_new (domain
, idx2string (ci
->nativename
)));
196 MonoArray
*short_date_patterns
= create_names_array_idx_dynamic (dfe
->short_date_patterns
,
197 NUM_SHORT_DATE_PATTERNS
, &error
);
198 return_val_and_set_pending_if_nok (&error
, FALSE
);
199 MONO_OBJECT_SETREF (this_obj
, ShortDatePatterns
, short_date_patterns
);
200 MonoArray
*year_month_patterns
=create_names_array_idx_dynamic (dfe
->year_month_patterns
,
201 NUM_YEAR_MONTH_PATTERNS
, &error
);
202 return_val_and_set_pending_if_nok (&error
, FALSE
);
203 MONO_OBJECT_SETREF (this_obj
, YearMonthPatterns
, year_month_patterns
);
205 MonoArray
*long_date_patterns
= create_names_array_idx_dynamic (dfe
->long_date_patterns
,
206 NUM_LONG_DATE_PATTERNS
, &error
);
207 return_val_and_set_pending_if_nok (&error
, FALSE
);
208 MONO_OBJECT_SETREF (this_obj
, LongDatePatterns
, long_date_patterns
);
210 MONO_OBJECT_SETREF (this_obj
, MonthDayPattern
, mono_string_new (domain
, pattern2string (dfe
->month_day_pattern
)));
212 MonoArray
*day_names
= create_names_array_idx (dfe
->day_names
, NUM_DAYS
, &error
);
213 return_val_and_set_pending_if_nok (&error
, FALSE
);
214 MONO_OBJECT_SETREF (this_obj
, DayNames
, day_names
);
216 MonoArray
*abbr_day_names
= create_names_array_idx (dfe
->abbreviated_day_names
,
218 return_val_and_set_pending_if_nok (&error
, FALSE
);
219 MONO_OBJECT_SETREF (this_obj
, AbbreviatedDayNames
, abbr_day_names
);
221 MonoArray
*ss_day_names
= create_names_array_idx (dfe
->shortest_day_names
, NUM_DAYS
, &error
);
222 return_val_and_set_pending_if_nok (&error
, FALSE
);
223 MONO_OBJECT_SETREF (this_obj
, SuperShortDayNames
, ss_day_names
);
225 MonoArray
*month_names
= create_names_array_idx (dfe
->month_names
, NUM_MONTHS
, &error
);
226 return_val_and_set_pending_if_nok (&error
, FALSE
);
227 MONO_OBJECT_SETREF (this_obj
, MonthNames
, month_names
);
229 MonoArray
*abbr_mon_names
= create_names_array_idx (dfe
->abbreviated_month_names
,
231 return_val_and_set_pending_if_nok (&error
, FALSE
);
232 MONO_OBJECT_SETREF (this_obj
, AbbreviatedMonthNames
, abbr_mon_names
);
235 MonoArray
*gen_month_names
= create_names_array_idx (dfe
->month_genitive_names
, NUM_MONTHS
, &error
);
236 return_val_and_set_pending_if_nok (&error
, FALSE
);
237 MONO_OBJECT_SETREF (this_obj
, GenitiveMonthNames
, gen_month_names
);
239 MonoArray
*gen_abbr_mon_names
= create_names_array_idx (dfe
->abbreviated_month_genitive_names
, NUM_MONTHS
, &error
);
240 return_val_and_set_pending_if_nok (&error
, FALSE
);
241 MONO_OBJECT_SETREF (this_obj
, GenitiveAbbreviatedMonthNames
, gen_abbr_mon_names
);
247 ves_icall_System_Globalization_CultureData_fill_culture_data (MonoCultureData
*this_obj
, gint32 datetime_index
)
251 const DateTimeFormatEntry
*dfe
;
253 g_assert (datetime_index
>= 0);
255 dfe
= &datetime_format_entries
[datetime_index
];
257 domain
= mono_domain_get ();
259 MONO_OBJECT_SETREF (this_obj
, AMDesignator
, mono_string_new (domain
, idx2string (dfe
->am_designator
)));
260 MONO_OBJECT_SETREF (this_obj
, PMDesignator
, mono_string_new (domain
, idx2string (dfe
->pm_designator
)));
261 MONO_OBJECT_SETREF (this_obj
, TimeSeparator
, mono_string_new (domain
, idx2string (dfe
->time_separator
)));
263 MonoArray
*long_time_patterns
= create_names_array_idx_dynamic (dfe
->long_time_patterns
,
264 NUM_LONG_TIME_PATTERNS
, &error
);
265 if (mono_error_set_pending_exception (&error
))
267 MONO_OBJECT_SETREF (this_obj
, LongTimePatterns
, long_time_patterns
);
269 MonoArray
*short_time_patterns
= create_names_array_idx_dynamic (dfe
->short_time_patterns
,
270 NUM_SHORT_TIME_PATTERNS
, &error
);
271 if (mono_error_set_pending_exception (&error
))
273 MONO_OBJECT_SETREF (this_obj
, ShortTimePatterns
, short_time_patterns
);
274 this_obj
->FirstDayOfWeek
= dfe
->first_day_of_week
;
275 this_obj
->CalendarWeekRule
= dfe
->calendar_week_rule
;
279 ves_icall_System_Globalization_CultureData_fill_number_data (MonoNumberFormatInfo
* number
, gint32 number_index
)
283 const NumberFormatEntry
*nfe
;
285 g_assert (number_index
>= 0);
287 nfe
= &number_format_entries
[number_index
];
289 domain
= mono_domain_get ();
291 number
->currencyDecimalDigits
= nfe
->currency_decimal_digits
;
292 MONO_OBJECT_SETREF (number
, currencyDecimalSeparator
, mono_string_new (domain
,
293 idx2string (nfe
->currency_decimal_separator
)));
294 MONO_OBJECT_SETREF (number
, currencyGroupSeparator
, mono_string_new (domain
,
295 idx2string (nfe
->currency_group_separator
)));
296 MonoArray
*currency_sizes_arr
= create_group_sizes_array (nfe
->currency_group_sizes
,
298 if (mono_error_set_pending_exception (&error
))
300 MONO_OBJECT_SETREF (number
, currencyGroupSizes
, currency_sizes_arr
);
301 number
->currencyNegativePattern
= nfe
->currency_negative_pattern
;
302 number
->currencyPositivePattern
= nfe
->currency_positive_pattern
;
303 MONO_OBJECT_SETREF (number
, currencySymbol
, mono_string_new (domain
, idx2string (nfe
->currency_symbol
)));
304 MONO_OBJECT_SETREF (number
, naNSymbol
, mono_string_new (domain
, idx2string (nfe
->nan_symbol
)));
305 MONO_OBJECT_SETREF (number
, negativeInfinitySymbol
, mono_string_new (domain
,
306 idx2string (nfe
->negative_infinity_symbol
)));
307 MONO_OBJECT_SETREF (number
, negativeSign
, mono_string_new (domain
, idx2string (nfe
->negative_sign
)));
308 number
->numberDecimalDigits
= nfe
->number_decimal_digits
;
309 MONO_OBJECT_SETREF (number
, numberDecimalSeparator
, mono_string_new (domain
,
310 idx2string (nfe
->number_decimal_separator
)));
311 MONO_OBJECT_SETREF (number
, numberGroupSeparator
, mono_string_new (domain
, idx2string (nfe
->number_group_separator
)));
312 MonoArray
*number_sizes_arr
= create_group_sizes_array (nfe
->number_group_sizes
,
314 if (mono_error_set_pending_exception (&error
))
316 MONO_OBJECT_SETREF (number
, numberGroupSizes
, number_sizes_arr
);
317 number
->numberNegativePattern
= nfe
->number_negative_pattern
;
318 number
->percentNegativePattern
= nfe
->percent_negative_pattern
;
319 number
->percentPositivePattern
= nfe
->percent_positive_pattern
;
320 MONO_OBJECT_SETREF (number
, percentSymbol
, mono_string_new (domain
, idx2string (nfe
->percent_symbol
)));
321 MONO_OBJECT_SETREF (number
, perMilleSymbol
, mono_string_new (domain
, idx2string (nfe
->per_mille_symbol
)));
322 MONO_OBJECT_SETREF (number
, positiveInfinitySymbol
, mono_string_new (domain
,
323 idx2string (nfe
->positive_infinity_symbol
)));
324 MONO_OBJECT_SETREF (number
, positiveSign
, mono_string_new (domain
, idx2string (nfe
->positive_sign
)));
328 construct_culture (MonoCultureInfo
*this_obj
, const CultureInfoEntry
*ci
, MonoError
*error
)
330 MonoDomain
*domain
= mono_domain_get ();
332 mono_error_init (error
);
334 this_obj
->lcid
= ci
->lcid
;
335 MONO_OBJECT_SETREF (this_obj
, name
, mono_string_new (domain
, idx2string (ci
->name
)));
336 MONO_OBJECT_SETREF (this_obj
, englishname
, mono_string_new (domain
, idx2string (ci
->englishname
)));
337 MONO_OBJECT_SETREF (this_obj
, nativename
, mono_string_new (domain
, idx2string (ci
->nativename
)));
338 MONO_OBJECT_SETREF (this_obj
, win3lang
, mono_string_new (domain
, idx2string (ci
->win3lang
)));
339 MONO_OBJECT_SETREF (this_obj
, iso3lang
, mono_string_new (domain
, idx2string (ci
->iso3lang
)));
340 MONO_OBJECT_SETREF (this_obj
, iso2lang
, mono_string_new (domain
, idx2string (ci
->iso2lang
)));
342 // It's null for neutral cultures
343 if (ci
->territory
> 0)
344 MONO_OBJECT_SETREF (this_obj
, territory
, mono_string_new (domain
, idx2string (ci
->territory
)));
346 MonoArray
*native_calendar_names
= create_names_array_idx (ci
->native_calendar_names
, NUM_CALENDARS
, error
);
347 return_val_if_nok (error
, FALSE
);
348 MONO_OBJECT_SETREF (this_obj
, native_calendar_names
, native_calendar_names
);
349 this_obj
->parent_lcid
= ci
->parent_lcid
;
350 this_obj
->datetime_index
= ci
->datetime_format_index
;
351 this_obj
->number_index
= ci
->number_format_index
;
352 this_obj
->calendar_type
= ci
->calendar_type
;
353 this_obj
->text_info_data
= &ci
->text_info
;
359 construct_region (MonoRegionInfo
*this_obj
, const RegionInfoEntry
*ri
)
361 MonoDomain
*domain
= mono_domain_get ();
363 this_obj
->geo_id
= ri
->geo_id
;
364 MONO_OBJECT_SETREF (this_obj
, iso2name
, mono_string_new (domain
, idx2string (ri
->iso2name
)));
365 MONO_OBJECT_SETREF (this_obj
, iso3name
, mono_string_new (domain
, idx2string (ri
->iso3name
)));
366 MONO_OBJECT_SETREF (this_obj
, win3name
, mono_string_new (domain
, idx2string (ri
->win3name
)));
367 MONO_OBJECT_SETREF (this_obj
, english_name
, mono_string_new (domain
, idx2string (ri
->english_name
)));
368 MONO_OBJECT_SETREF (this_obj
, native_name
, mono_string_new (domain
, idx2string (ri
->native_name
)));
369 MONO_OBJECT_SETREF (this_obj
, currency_symbol
, mono_string_new (domain
, idx2string (ri
->currency_symbol
)));
370 MONO_OBJECT_SETREF (this_obj
, iso_currency_symbol
, mono_string_new (domain
, idx2string (ri
->iso_currency_symbol
)));
371 MONO_OBJECT_SETREF (this_obj
, currency_english_name
, mono_string_new (domain
, idx2string (ri
->currency_english_name
)));
372 MONO_OBJECT_SETREF (this_obj
, currency_native_name
, mono_string_new (domain
, idx2string (ri
->currency_native_name
)));
377 static const CultureInfoEntry
*
378 culture_info_entry_from_lcid (int lcid
)
380 const CultureInfoEntry
*ci
;
382 ci
= (const CultureInfoEntry
*)mono_binary_search (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
387 static const RegionInfoEntry
*
388 region_info_entry_from_lcid (int lcid
)
390 const RegionInfoEntry
*entry
;
391 const CultureInfoEntry
*ne
;
393 ne
= (const CultureInfoEntry
*)mono_binary_search (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
398 entry
= ®ion_entries
[ne
->region_entry_index
];
403 #if defined (__APPLE__)
405 get_darwin_locale (void)
407 static gchar
*darwin_locale
= NULL
;
408 CFLocaleRef locale
= NULL
;
409 CFStringRef locale_language
= NULL
;
410 CFStringRef locale_country
= NULL
;
411 CFStringRef locale_script
= NULL
;
412 CFStringRef locale_cfstr
= NULL
;
413 CFIndex bytes_converted
;
414 CFIndex bytes_written
;
418 if (darwin_locale
!= NULL
)
419 return g_strdup (darwin_locale
);
421 locale
= CFLocaleCopyCurrent ();
424 locale_language
= CFLocaleGetValue (locale
, kCFLocaleLanguageCode
);
425 if (locale_language
!= NULL
&& CFStringGetBytes(locale_language
, CFRangeMake (0, CFStringGetLength (locale_language
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
426 len
= bytes_converted
+ 1;
428 locale_country
= CFLocaleGetValue (locale
, kCFLocaleCountryCode
);
429 if (locale_country
!= NULL
&& CFStringGetBytes (locale_country
, CFRangeMake (0, CFStringGetLength (locale_country
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
430 len
+= bytes_converted
+ 1;
432 locale_script
= CFLocaleGetValue (locale
, kCFLocaleScriptCode
);
433 if (locale_script
!= NULL
&& CFStringGetBytes (locale_script
, CFRangeMake (0, CFStringGetLength (locale_script
)), kCFStringEncodingMacRoman
, 0, FALSE
, NULL
, 0, &bytes_converted
) > 0) {
434 len
+= bytes_converted
+ 1;
437 darwin_locale
= (char *) g_malloc (len
+ 1);
438 CFStringGetBytes (locale_language
, CFRangeMake (0, CFStringGetLength (locale_language
)), kCFStringEncodingMacRoman
, 0, FALSE
, (UInt8
*) darwin_locale
, len
, &bytes_converted
);
440 darwin_locale
[bytes_converted
] = '-';
441 bytes_written
= bytes_converted
+ 1;
442 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) {
443 darwin_locale
[bytes_written
+ bytes_converted
] = '-';
444 bytes_written
+= bytes_converted
+ 1;
447 CFStringGetBytes (locale_country
, CFRangeMake (0, CFStringGetLength (locale_country
)), kCFStringEncodingMacRoman
, 0, FALSE
, (UInt8
*) &darwin_locale
[bytes_written
], len
- bytes_written
, &bytes_converted
);
448 darwin_locale
[bytes_written
+ bytes_converted
] = '\0';
452 if (darwin_locale
== NULL
) {
453 locale_cfstr
= CFLocaleGetIdentifier (locale
);
456 len
= CFStringGetMaximumSizeForEncoding (CFStringGetLength (locale_cfstr
), kCFStringEncodingMacRoman
) + 1;
457 darwin_locale
= (char *) g_malloc (len
);
458 if (!CFStringGetCString (locale_cfstr
, darwin_locale
, len
, kCFStringEncodingMacRoman
)) {
459 g_free (darwin_locale
);
461 darwin_locale
= NULL
;
465 for (i
= 0; i
< strlen (darwin_locale
); i
++)
466 if (darwin_locale
[i
] == '_')
467 darwin_locale
[i
] = '-';
474 return g_strdup (darwin_locale
);
479 get_posix_locale (void)
483 locale
= g_getenv ("LC_ALL");
484 if (locale
== NULL
) {
485 locale
= g_getenv ("LANG");
487 locale
= setlocale (LC_ALL
, NULL
);
492 /* Skip English-only locale 'C' */
493 if (strcmp (locale
, "C") == 0)
496 return g_strdup (locale
);
501 get_current_locale_name (void)
507 locale
= g_win32_getlocale ();
508 #elif defined (__APPLE__)
509 locale
= get_darwin_locale ();
511 locale
= get_posix_locale ();
513 locale
= get_posix_locale ();
519 p
= strchr (locale
, '.');
522 p
= strchr (locale
, '@');
525 p
= strchr (locale
, '_');
529 ret
= g_ascii_strdown (locale
, -1);
536 ves_icall_System_Globalization_CultureInfo_get_current_locale_name (void)
542 locale
= get_current_locale_name ();
546 domain
= mono_domain_get ();
547 ret
= mono_string_new (domain
, locale
);
554 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo
*this_obj
,
558 const CultureInfoEntry
*ci
;
560 ci
= culture_info_entry_from_lcid (lcid
);
564 if (!construct_culture (this_obj
, ci
, &error
)) {
565 mono_error_set_pending_exception (&error
);
572 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo
*this_obj
,
576 const CultureInfoNameEntry
*ne
;
579 n
= mono_string_to_utf8_checked (name
, &error
);
580 if (mono_error_set_pending_exception (&error
))
582 ne
= (const CultureInfoNameEntry
*)mono_binary_search (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
583 sizeof (CultureInfoNameEntry
), culture_name_locator
);
586 /*g_print ("ne (%s) is null\n", n);*/
592 if (!construct_culture (this_obj
, &culture_entries
[ne
->culture_entry_index
], &error
)) {
593 mono_error_set_pending_exception (&error
);
600 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo *ci,
606 locale = mono_string_to_utf8 (name);
607 ret = construct_culture_from_specific_name (ci, locale);
614 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo
*this_obj
,
617 const RegionInfoEntry
*ri
;
619 ri
= region_info_entry_from_lcid (lcid
);
623 return construct_region (this_obj
, ri
);
627 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo
*this_obj
,
631 const RegionInfoNameEntry
*ne
;
634 n
= mono_string_to_utf8_checked (name
, &error
);
635 if (mono_error_set_pending_exception (&error
))
637 ne
= (const RegionInfoNameEntry
*)mono_binary_search (n
, region_name_entries
, NUM_REGION_ENTRIES
,
638 sizeof (RegionInfoNameEntry
), region_name_locator
);
641 /*g_print ("ne (%s) is null\n", n);*/
647 return construct_region (this_obj
, ®ion_entries
[ne
->region_entry_index
]);
651 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral
,
652 MonoBoolean specific
, MonoBoolean installed
)
657 MonoCultureInfo
*culture
;
659 const CultureInfoEntry
*ci
;
663 domain
= mono_domain_get ();
666 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
667 ci
= &culture_entries
[i
];
668 is_neutral
= ci
->territory
== 0;
669 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
))
673 klass
= mono_class_get_culture_info_class ();
675 /* The InvariantCulture is not in culture_entries */
676 /* We reserve the first slot in the array for it */
680 ret
= mono_array_new_checked (domain
, klass
, len
, &error
);
689 mono_array_setref (ret
, len
++, NULL
);
691 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
692 ci
= &culture_entries
[i
];
693 is_neutral
= ci
->territory
== 0;
694 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
)) {
695 culture
= (MonoCultureInfo
*) mono_object_new_checked (domain
, klass
, &error
);
696 if (!is_ok (&error
)) goto fail
;
697 mono_runtime_object_init_checked ((MonoObject
*) culture
, &error
);
698 if (!is_ok (&error
)) goto fail
;
699 if (!construct_culture (culture
, ci
, &error
))
701 culture
->use_user_override
= TRUE
;
702 mono_array_setref (ret
, len
++, culture
);
709 mono_error_set_pending_exception (&error
);
713 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
)
715 /* Do a normal ascii string compare, as we only know the
716 * invariant locale if we dont have ICU
718 return(string_invariant_compare (str1
, off1
, len1
, str2
, off2
, len2
,
722 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo
*this_obj
, MonoSortKey
*key
, MonoString
*source
, gint32 options
)
728 keylen
=mono_string_length (source
);
730 arr
=mono_array_new_checked (mono_domain_get (), mono_get_byte_class (),
732 if (mono_error_set_pending_exception (&error
))
735 for(i
=0; i
<keylen
; i
++) {
736 mono_array_set (arr
, guint8
, i
, mono_string_chars (source
)[i
]);
739 MONO_OBJECT_SETREF (key
, key
, arr
);
742 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo
*this_obj
, MonoString
*source
, gint32 sindex
, gint32 count
, MonoString
*value
, gint32 options
, MonoBoolean first
)
744 return(string_invariant_indexof (source
, sindex
, count
, value
, first
));
747 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo
*this_obj
, MonoString
*source
, gint32 sindex
, gint32 count
, gunichar2 value
, gint32 options
, MonoBoolean first
)
749 return(string_invariant_indexof_char (source
, sindex
, count
, value
,
753 int ves_icall_System_Threading_Thread_current_lcid (void)
759 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
764 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
765 if (options
& CompareOptions_Ordinal
)
766 return (gint32
) c1
- c2
;
768 if (options
& CompareOptions_IgnoreCase
) {
769 GUnicodeType c1type
, c2type
;
771 c1type
= g_unichar_type (c1
);
772 c2type
= g_unichar_type (c2
);
774 result
= (gint32
) (c1type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c1
) : c1
) -
775 (c2type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c2
) : c2
);
778 * No options. Kana, symbol and spacing options don't
779 * apply to the invariant culture.
783 * FIXME: here we must use the information from c1type and c2type
784 * to find out the proper collation, even on the InvariantCulture, the
785 * sorting is not done by computing the unicode values, but their
788 result
= (gint32
) c1
- c2
;
791 return ((result
< 0) ? -1 : (result
> 0) ? 1 : 0);
794 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
795 gint32 len1
, MonoString
*str2
,
796 gint32 off2
, gint32 len2
,
799 /* c translation of C# code from old string.cs.. :) */
812 ustr1
= mono_string_chars(str1
)+off1
;
813 ustr2
= mono_string_chars(str2
)+off2
;
817 for (pos
= 0; pos
!= length
; pos
++) {
818 if (pos
>= len1
|| pos
>= len2
)
821 charcmp
= string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
],
828 /* the lesser wins, so if we have looped until length we just
829 * need to check the last char
832 return(string_invariant_compare_char(ustr1
[pos
- 1],
833 ustr2
[pos
- 1], options
));
836 /* Test if one of the strings has been compared to the end */
843 } else if (pos
>= len2
) {
847 /* if not, check our last char only.. (can this happen?) */
848 return(string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
], options
));
851 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
852 gint32 count
, MonoString
*value
,
860 lencmpstr
= mono_string_length(value
);
862 src
= mono_string_chars(source
);
863 cmpstr
= mono_string_chars(value
);
867 for(pos
=sindex
;pos
<= sindex
+count
;pos
++) {
868 for(i
=0;src
[pos
+i
]==cmpstr
[i
];) {
877 for(pos
=sindex
-lencmpstr
+1;pos
>sindex
-count
;pos
--) {
878 if(memcmp (src
+pos
, cmpstr
,
879 lencmpstr
*sizeof(gunichar2
))==0) {
888 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
889 gint32 count
, gunichar2 value
,
895 src
= mono_string_chars(source
);
897 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
898 if (src
[pos
] == value
) {
905 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
906 if (src
[pos
] == value
)
914 void ves_icall_System_Text_Normalization_load_normalization_resource (guint8
**argProps
,
915 guint8
**argMappedChars
,
916 guint8
**argCharMapIndex
,
917 guint8
**argHelperIndex
,
918 guint8
**argMapIdxToComposite
,
919 guint8
**argCombiningClass
)
921 #ifdef DISABLE_NORMALIZATION
922 mono_set_pending_exception (mono_get_exception_not_supported ("This runtime has been compiled without string normalization support."));
925 *argProps
= (guint8
*)props
;
926 *argMappedChars
= (guint8
*) mappedChars
;
927 *argCharMapIndex
= (guint8
*) charMapIndex
;
928 *argHelperIndex
= (guint8
*) helperIndex
;
929 *argMapIdxToComposite
= (guint8
*) mapIdxToComposite
;
930 *argCombiningClass
= (guint8
*)combiningClass
;