2 * locales.c: Culture-sensitive handling
5 * Dick Porter (dick@ximian.com)
6 * Mohammad DAMT (mdamt@cdl2000.com)
8 * Copyright 2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * (C) 2003 PT Cakram Datalingga Duaribu http://www.cdl2000.com
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/monitor.h>
22 #include <mono/metadata/locales.h>
23 #include <mono/metadata/culture-info.h>
24 #include <mono/metadata/culture-info-tables.h>
25 #include <mono/metadata/normalization-tables.h>
29 #if defined(__APPLE__)
30 #include <CoreFoundation/CoreFoundation.h>
35 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
37 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
38 gint32 len1
, MonoString
*str2
,
39 gint32 off2
, gint32 len2
,
41 static MonoString
*string_invariant_replace (MonoString
*me
,
43 MonoString
*newValue
);
44 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
45 gint32 count
, MonoString
*value
,
47 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
48 gint32 count
, gunichar2 value
,
51 static const CultureInfoEntry
* culture_info_entry_from_lcid (int lcid
);
53 static const RegionInfoEntry
* region_info_entry_from_lcid (int lcid
);
56 culture_lcid_locator (const void *a
, const void *b
)
58 const CultureInfoEntry
*aa
= a
;
59 const CultureInfoEntry
*bb
= b
;
61 return (aa
->lcid
- bb
->lcid
);
65 region_lcid_locator (const void *a
, const void *b
)
68 const CultureInfoEntry
*bb
= b
;
70 return *lcid
- bb
->lcid
;
74 culture_name_locator (const void *a
, const void *b
)
77 const CultureInfoNameEntry
*bb
= b
;
80 ret
= strcmp (aa
, idx2string (bb
->name
));
86 region_name_locator (const void *a
, const void *b
)
89 const RegionInfoNameEntry
*bb
= b
;
92 ret
= strcmp (aa
, idx2string (bb
->name
));
98 create_group_sizes_array (const gint
*gs
, gint ml
)
103 for (i
= 0; i
< ml
; i
++) {
109 ret
= mono_array_new_cached (mono_domain_get (),
110 mono_get_int32_class (), len
);
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
)
128 domain
= mono_domain_get ();
130 for (i
= 0; i
< ml
; i
++) {
136 ret
= mono_array_new_cached (mono_domain_get (), mono_get_string_class (), len
);
138 for(i
= 0; i
< len
; i
++)
139 mono_array_setref (ret
, i
, mono_string_new (domain
, idx2string (names
[i
])));
145 ves_icall_System_Globalization_CultureInfo_construct_datetime_format (MonoCultureInfo
*this)
148 MonoDateTimeFormatInfo
*datetime
;
149 const DateTimeFormatEntry
*dfe
;
153 g_assert (this->datetime_index
>= 0);
155 datetime
= this->datetime_format
;
156 dfe
= &datetime_format_entries
[this->datetime_index
];
158 domain
= mono_domain_get ();
160 datetime
->readOnly
= this->is_read_only
;
161 MONO_OBJECT_SETREF (datetime
, AbbreviatedDayNames
, create_names_array_idx (dfe
->abbreviated_day_names
,
163 MONO_OBJECT_SETREF (datetime
, AbbreviatedMonthNames
, create_names_array_idx (dfe
->abbreviated_month_names
,
165 MONO_OBJECT_SETREF (datetime
, AMDesignator
, mono_string_new (domain
, idx2string (dfe
->am_designator
)));
166 datetime
->CalendarWeekRule
= dfe
->calendar_week_rule
;
167 MONO_OBJECT_SETREF (datetime
, DateSeparator
, mono_string_new (domain
, idx2string (dfe
->date_separator
)));
168 MONO_OBJECT_SETREF (datetime
, DayNames
, create_names_array_idx (dfe
->day_names
, NUM_DAYS
));
169 datetime
->FirstDayOfWeek
= dfe
->first_day_of_week
;
170 MONO_OBJECT_SETREF (datetime
, FullDateTimePattern
, mono_string_new (domain
, idx2string (dfe
->full_date_time_pattern
)));
171 MONO_OBJECT_SETREF (datetime
, LongDatePattern
, mono_string_new (domain
, idx2string (dfe
->long_date_pattern
)));
172 MONO_OBJECT_SETREF (datetime
, LongTimePattern
, mono_string_new (domain
, idx2string (dfe
->long_time_pattern
)));
173 MONO_OBJECT_SETREF (datetime
, MonthDayPattern
, mono_string_new (domain
, idx2string (dfe
->month_day_pattern
)));
174 MONO_OBJECT_SETREF (datetime
, MonthNames
, create_names_array_idx (dfe
->month_names
, NUM_MONTHS
));
175 MONO_OBJECT_SETREF (datetime
, PMDesignator
, mono_string_new (domain
, idx2string (dfe
->pm_designator
)));
176 MONO_OBJECT_SETREF (datetime
, ShortDatePattern
, mono_string_new (domain
, idx2string (dfe
->short_date_pattern
)));
177 MONO_OBJECT_SETREF (datetime
, ShortTimePattern
, mono_string_new (domain
, idx2string (dfe
->short_time_pattern
)));
178 MONO_OBJECT_SETREF (datetime
, TimeSeparator
, mono_string_new (domain
, idx2string (dfe
->time_separator
)));
179 MONO_OBJECT_SETREF (datetime
, YearMonthPattern
, mono_string_new (domain
, idx2string (dfe
->year_month_pattern
)));
180 MONO_OBJECT_SETREF (datetime
, ShortDatePatterns
, create_names_array_idx (dfe
->short_date_patterns
,
181 NUM_SHORT_DATE_PATTERNS
));
182 MONO_OBJECT_SETREF (datetime
, LongDatePatterns
, create_names_array_idx (dfe
->long_date_patterns
,
183 NUM_LONG_DATE_PATTERNS
));
184 MONO_OBJECT_SETREF (datetime
, ShortTimePatterns
, create_names_array_idx (dfe
->short_time_patterns
,
185 NUM_SHORT_TIME_PATTERNS
));
186 MONO_OBJECT_SETREF (datetime
, LongTimePatterns
, create_names_array_idx (dfe
->long_time_patterns
,
187 NUM_LONG_TIME_PATTERNS
));
192 ves_icall_System_Globalization_CultureInfo_construct_number_format (MonoCultureInfo
*this)
195 MonoNumberFormatInfo
*number
;
196 const NumberFormatEntry
*nfe
;
200 g_assert (this->number_format
!= 0);
201 if (this->number_index
< 0)
204 number
= this->number_format
;
205 nfe
= &number_format_entries
[this->number_index
];
207 domain
= mono_domain_get ();
209 number
->readOnly
= this->is_read_only
;
210 number
->currencyDecimalDigits
= nfe
->currency_decimal_digits
;
211 MONO_OBJECT_SETREF (number
, currencyDecimalSeparator
, mono_string_new (domain
,
212 idx2string (nfe
->currency_decimal_separator
)));
213 MONO_OBJECT_SETREF (number
, currencyGroupSeparator
, mono_string_new (domain
,
214 idx2string (nfe
->currency_group_separator
)));
215 MONO_OBJECT_SETREF (number
, currencyGroupSizes
, create_group_sizes_array (nfe
->currency_group_sizes
,
217 number
->currencyNegativePattern
= nfe
->currency_negative_pattern
;
218 number
->currencyPositivePattern
= nfe
->currency_positive_pattern
;
219 MONO_OBJECT_SETREF (number
, currencySymbol
, mono_string_new (domain
, idx2string (nfe
->currency_symbol
)));
220 MONO_OBJECT_SETREF (number
, naNSymbol
, mono_string_new (domain
, idx2string (nfe
->nan_symbol
)));
221 MONO_OBJECT_SETREF (number
, negativeInfinitySymbol
, mono_string_new (domain
,
222 idx2string (nfe
->negative_infinity_symbol
)));
223 MONO_OBJECT_SETREF (number
, negativeSign
, mono_string_new (domain
, idx2string (nfe
->negative_sign
)));
224 number
->numberDecimalDigits
= nfe
->number_decimal_digits
;
225 MONO_OBJECT_SETREF (number
, numberDecimalSeparator
, mono_string_new (domain
,
226 idx2string (nfe
->number_decimal_separator
)));
227 MONO_OBJECT_SETREF (number
, numberGroupSeparator
, mono_string_new (domain
, idx2string (nfe
->number_group_separator
)));
228 MONO_OBJECT_SETREF (number
, numberGroupSizes
, create_group_sizes_array (nfe
->number_group_sizes
,
230 number
->numberNegativePattern
= nfe
->number_negative_pattern
;
231 number
->percentDecimalDigits
= nfe
->percent_decimal_digits
;
232 MONO_OBJECT_SETREF (number
, percentDecimalSeparator
, mono_string_new (domain
,
233 idx2string (nfe
->percent_decimal_separator
)));
234 MONO_OBJECT_SETREF (number
, percentGroupSeparator
, mono_string_new (domain
,
235 idx2string (nfe
->percent_group_separator
)));
236 MONO_OBJECT_SETREF (number
, percentGroupSizes
, create_group_sizes_array (nfe
->percent_group_sizes
,
238 number
->percentNegativePattern
= nfe
->percent_negative_pattern
;
239 number
->percentPositivePattern
= nfe
->percent_positive_pattern
;
240 MONO_OBJECT_SETREF (number
, percentSymbol
, mono_string_new (domain
, idx2string (nfe
->percent_symbol
)));
241 MONO_OBJECT_SETREF (number
, perMilleSymbol
, mono_string_new (domain
, idx2string (nfe
->per_mille_symbol
)));
242 MONO_OBJECT_SETREF (number
, positiveInfinitySymbol
, mono_string_new (domain
,
243 idx2string (nfe
->positive_infinity_symbol
)));
244 MONO_OBJECT_SETREF (number
, positiveSign
, mono_string_new (domain
, idx2string (nfe
->positive_sign
)));
248 construct_culture (MonoCultureInfo
*this, const CultureInfoEntry
*ci
)
250 MonoDomain
*domain
= mono_domain_get ();
252 this->lcid
= ci
->lcid
;
253 MONO_OBJECT_SETREF (this, name
, mono_string_new (domain
, idx2string (ci
->name
)));
254 MONO_OBJECT_SETREF (this, icu_name
, mono_string_new (domain
, idx2string (ci
->icu_name
)));
255 MONO_OBJECT_SETREF (this, displayname
, mono_string_new (domain
, idx2string (ci
->displayname
)));
256 MONO_OBJECT_SETREF (this, englishname
, mono_string_new (domain
, idx2string (ci
->englishname
)));
257 MONO_OBJECT_SETREF (this, nativename
, mono_string_new (domain
, idx2string (ci
->nativename
)));
258 MONO_OBJECT_SETREF (this, win3lang
, mono_string_new (domain
, idx2string (ci
->win3lang
)));
259 MONO_OBJECT_SETREF (this, iso3lang
, mono_string_new (domain
, idx2string (ci
->iso3lang
)));
260 MONO_OBJECT_SETREF (this, iso2lang
, mono_string_new (domain
, idx2string (ci
->iso2lang
)));
261 MONO_OBJECT_SETREF (this, territory
, mono_string_new (domain
, idx2string (ci
->territory
)));
262 this->parent_lcid
= ci
->parent_lcid
;
263 this->specific_lcid
= ci
->specific_lcid
;
264 this->datetime_index
= ci
->datetime_format_index
;
265 this->number_index
= ci
->number_format_index
;
266 this->calendar_data
= ci
->calendar_data
;
267 this->text_info_data
= &ci
->text_info
;
273 construct_region (MonoRegionInfo
*this, const RegionInfoEntry
*ri
)
275 MonoDomain
*domain
= mono_domain_get ();
277 this->region_id
= ri
->region_id
;
278 MONO_OBJECT_SETREF (this, iso2name
, mono_string_new (domain
, idx2string (ri
->iso2name
)));
279 MONO_OBJECT_SETREF (this, iso3name
, mono_string_new (domain
, idx2string (ri
->iso3name
)));
280 MONO_OBJECT_SETREF (this, win3name
, mono_string_new (domain
, idx2string (ri
->win3name
)));
281 MONO_OBJECT_SETREF (this, english_name
, mono_string_new (domain
, idx2string (ri
->english_name
)));
282 MONO_OBJECT_SETREF (this, currency_symbol
, mono_string_new (domain
, idx2string (ri
->currency_symbol
)));
283 MONO_OBJECT_SETREF (this, iso_currency_symbol
, mono_string_new (domain
, idx2string (ri
->iso_currency_symbol
)));
284 MONO_OBJECT_SETREF (this, currency_english_name
, mono_string_new (domain
, idx2string (ri
->currency_english_name
)));
290 construct_culture_from_specific_name (MonoCultureInfo
*ci
, gchar
*name
)
292 const CultureInfoEntry
*entry
;
293 const CultureInfoNameEntry
*ne
;
297 ne
= bsearch (name
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
298 sizeof (CultureInfoNameEntry
), culture_name_locator
);
303 entry
= &culture_entries
[ne
->culture_entry_index
];
305 /* try avoiding another lookup, often the culture is its own specific culture */
306 if (entry
->lcid
!= entry
->specific_lcid
)
307 entry
= culture_info_entry_from_lcid (entry
->specific_lcid
);
310 return construct_culture (ci
, entry
);
315 static const CultureInfoEntry
*
316 culture_info_entry_from_lcid (int lcid
)
318 const CultureInfoEntry
*ci
;
319 CultureInfoEntry key
;
322 ci
= bsearch (&key
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
327 static const RegionInfoEntry
*
328 region_info_entry_from_lcid (int lcid
)
330 const RegionInfoEntry
*entry
;
331 const CultureInfoEntry
*ne
;
335 ne
= bsearch (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
,
336 sizeof (CultureInfoEntry
), region_lcid_locator
);
341 entry
= ®ion_entries
[ne
->region_entry_index
];
347 * The following two methods are modified from the ICU source code. (http://oss.software.ibm.com/icu)
348 * Copyright (c) 1995-2003 International Business Machines Corporation and others
349 * All rights reserved.
352 get_posix_locale (void)
354 const gchar
* posix_locale
= NULL
;
356 posix_locale
= g_getenv("LC_ALL");
357 if (posix_locale
== 0) {
358 posix_locale
= g_getenv("LANG");
359 if (posix_locale
== 0) {
360 posix_locale
= setlocale(LC_ALL
, NULL
);
364 if (posix_locale
== NULL
)
367 if ((strcmp ("C", posix_locale
) == 0) || (strchr (posix_locale
, ' ') != NULL
)
368 || (strchr (posix_locale
, '/') != NULL
)) {
370 * HPUX returns 'C C C C C C C'
371 * Solaris can return /en_US/C/C/C/C/C on the second try.
372 * Maybe we got some garbage.
377 return g_strdup (posix_locale
);
380 #if defined (__APPLE__)
382 get_darwin_locale (void)
384 const gchar
*darwin_locale
= NULL
;
385 gchar
*cur_locale
= NULL
;
387 CFLocaleRef locale
= NULL
;
388 CFStringRef locale_cfstr
= NULL
;
390 locale
= CFLocaleCopyCurrent ();
393 locale_cfstr
= CFLocaleGetIdentifier (locale
);
396 darwin_locale
= CFStringGetCStringPtr (locale_cfstr
, kCFStringEncodingMacRoman
);
398 cur_locale
= g_strdup (darwin_locale
);
400 for (i
= 0; i
< strlen (cur_locale
); i
++)
401 if (cur_locale
[i
] == '_')
402 cur_locale
[i
] = '-';
414 get_current_locale_name (void)
417 gchar
*corrected
= NULL
;
422 locale
= g_win32_getlocale ();
423 #elif defined (__APPLE__)
424 locale
= get_darwin_locale ();
426 locale
= get_posix_locale ();
428 locale
= get_posix_locale ();
434 if ((p
= strchr (locale
, '.')) != NULL
) {
435 /* assume new locale can't be larger than old one? */
436 corrected
= g_malloc (strlen (locale
));
437 strncpy (corrected
, locale
, p
- locale
);
438 corrected
[p
- locale
] = 0;
440 /* do not copy after the @ */
441 if ((p
= strchr (corrected
, '@')) != NULL
)
442 corrected
[p
- corrected
] = 0;
445 /* Note that we scan the *uncorrected* ID. */
446 if ((p
= strrchr (locale
, '@')) != NULL
) {
449 * In Mono we dont handle the '@' modifier because we do
450 * not have any cultures that use it. We just trim it
451 * off of the end of the name.
454 if (corrected
== NULL
) {
455 corrected
= g_malloc (strlen (locale
));
456 strncpy (corrected
, locale
, p
- locale
);
457 corrected
[p
- locale
] = 0;
461 if (corrected
== NULL
)
466 if ((c
= strchr (corrected
, '_')) != NULL
)
470 corrected
= g_ascii_strdown (c
, -1);
477 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_current_locale (MonoCultureInfo
*ci
)
484 locale
= get_current_locale_name ();
488 ret
= construct_culture_from_specific_name (ci
, locale
);
490 ci
->is_read_only
= TRUE
;
491 ci
->use_user_override
= TRUE
;
497 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo
*this,
500 const CultureInfoEntry
*ci
;
504 ci
= culture_info_entry_from_lcid (lcid
);
508 return construct_culture (this, ci
);
512 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo
*this,
515 const CultureInfoNameEntry
*ne
;
520 n
= mono_string_to_utf8 (name
);
521 ne
= bsearch (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
522 sizeof (CultureInfoNameEntry
), culture_name_locator
);
525 /*g_print ("ne (%s) is null\n", n);*/
531 return construct_culture (this, &culture_entries
[ne
->culture_entry_index
]);
535 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo
*ci
,
543 locale
= mono_string_to_utf8 (name
);
544 ret
= construct_culture_from_specific_name (ci
, locale
);
551 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo
*this,
554 const RegionInfoEntry
*ri
;
558 ri
= region_info_entry_from_lcid (lcid
);
562 return construct_region (this, ri
);
566 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo
*this,
569 const RegionInfoNameEntry
*ne
;
574 n
= mono_string_to_utf8 (name
);
575 ne
= bsearch (n
, region_name_entries
, NUM_REGION_ENTRIES
,
576 sizeof (RegionInfoNameEntry
), region_name_locator
);
579 /*g_print ("ne (%s) is null\n", n);*/
585 return construct_region (this, ®ion_entries
[ne
->region_entry_index
]);
589 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral
,
590 MonoBoolean specific
, MonoBoolean installed
)
594 MonoCultureInfo
*culture
;
596 const CultureInfoEntry
*ci
;
602 domain
= mono_domain_get ();
605 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
606 ci
= &culture_entries
[i
];
607 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
608 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
))
612 class = mono_class_from_name (mono_get_corlib (),
613 "System.Globalization", "CultureInfo");
615 /* The InvariantCulture is not in culture_entries */
616 /* We reserve the first slot in the array for it */
620 ret
= mono_array_new (domain
, class, len
);
627 mono_array_setref (ret
, len
++, NULL
);
629 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
630 ci
= &culture_entries
[i
];
631 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
632 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
)) {
633 culture
= (MonoCultureInfo
*) mono_object_new (domain
, class);
634 mono_runtime_object_init ((MonoObject
*) culture
);
635 construct_culture (culture
, ci
);
636 culture
->use_user_override
= TRUE
;
637 mono_array_setref (ret
, len
++, culture
);
645 * ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral:
647 * Set is_neutral and return TRUE if the culture is found. If it is not found return FALSE.
650 ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral (gint lcid
, MonoBoolean
*is_neutral
)
652 const CultureInfoEntry
*entry
;
656 entry
= culture_info_entry_from_lcid (lcid
);
661 *is_neutral
= (entry
->specific_lcid
== 0);
666 void ves_icall_System_Globalization_CompareInfo_construct_compareinfo (MonoCompareInfo
*comp
, MonoString
*locale
)
668 /* Nothing to do here */
671 int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoCompareInfo
*this, MonoString
*str1
, gint32 off1
, gint32 len1
, MonoString
*str2
, gint32 off2
, gint32 len2
, gint32 options
)
675 /* Do a normal ascii string compare, as we only know the
676 * invariant locale if we dont have ICU
678 return(string_invariant_compare (str1
, off1
, len1
, str2
, off2
, len2
,
682 void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoCompareInfo
*this)
684 /* Nothing to do here */
687 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo
*this, MonoSortKey
*key
, MonoString
*source
, gint32 options
)
694 keylen
=mono_string_length (source
);
696 arr
=mono_array_new (mono_domain_get (), mono_get_byte_class (),
698 for(i
=0; i
<keylen
; i
++) {
699 mono_array_set (arr
, guint8
, i
, mono_string_chars (source
)[i
]);
702 MONO_OBJECT_SETREF (key
, key
, arr
);
705 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, MonoString
*value
, gint32 options
, MonoBoolean first
)
709 return(string_invariant_indexof (source
, sindex
, count
, value
, first
));
712 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, gunichar2 value
, gint32 options
, MonoBoolean first
)
716 return(string_invariant_indexof_char (source
, sindex
, count
, value
,
720 int ves_icall_System_Threading_Thread_current_lcid (void)
728 MonoString
*ves_icall_System_String_InternalReplace_Str_Comp (MonoString
*this, MonoString
*old
, MonoString
*new, MonoCompareInfo
*comp
)
732 /* Do a normal ascii string compare and replace, as we only
733 * know the invariant locale if we dont have ICU
735 return(string_invariant_replace (this, old
, new));
738 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
743 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
744 if (options
& CompareOptions_Ordinal
)
745 return (gint32
) c1
- c2
;
747 if (options
& CompareOptions_IgnoreCase
) {
748 GUnicodeType c1type
, c2type
;
750 c1type
= g_unichar_type (c1
);
751 c2type
= g_unichar_type (c2
);
753 result
= (gint32
) (c1type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c1
) : c1
) -
754 (c2type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c2
) : c2
);
757 * No options. Kana, symbol and spacing options don't
758 * apply to the invariant culture.
762 * FIXME: here we must use the information from c1type and c2type
763 * to find out the proper collation, even on the InvariantCulture, the
764 * sorting is not done by computing the unicode values, but their
767 result
= (gint32
) c1
- c2
;
770 return ((result
< 0) ? -1 : (result
> 0) ? 1 : 0);
773 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
774 gint32 len1
, MonoString
*str2
,
775 gint32 off2
, gint32 len2
,
778 /* c translation of C# code from old string.cs.. :) */
791 ustr1
= mono_string_chars(str1
)+off1
;
792 ustr2
= mono_string_chars(str2
)+off2
;
796 for (pos
= 0; pos
!= length
; pos
++) {
797 if (pos
>= len1
|| pos
>= len2
)
800 charcmp
= string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
],
807 /* the lesser wins, so if we have looped until length we just
808 * need to check the last char
811 return(string_invariant_compare_char(ustr1
[pos
- 1],
812 ustr2
[pos
- 1], options
));
815 /* Test if one of the strings has been compared to the end */
822 } else if (pos
>= len2
) {
826 /* if not, check our last char only.. (can this happen?) */
827 return(string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
], options
));
830 static MonoString
*string_invariant_replace (MonoString
*me
,
831 MonoString
*oldValue
,
832 MonoString
*newValue
)
836 gunichar2
*dest
=NULL
; /* shut gcc up */
838 gunichar2
*newstr
=NULL
; /* shut gcc up here too */
849 oldstr
= mono_string_chars(oldValue
);
850 oldstrlen
= mono_string_length(oldValue
);
852 if (NULL
!= newValue
) {
853 newstr
= mono_string_chars(newValue
);
854 newstrlen
= mono_string_length(newValue
);
858 src
= mono_string_chars(me
);
859 srclen
= mono_string_length(me
);
861 if (oldstrlen
!= newstrlen
) {
863 while (i
<= srclen
- oldstrlen
) {
864 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
873 newsize
= srclen
+ ((newstrlen
- oldstrlen
) * occurr
);
880 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
882 ret
= mono_string_new_size( mono_domain_get (), newsize
);
883 dest
= mono_string_chars(ret
);
884 memcpy (dest
, src
, i
* sizeof(gunichar2
));
887 memcpy(dest
+ destpos
, newstr
, newstrlen
* sizeof(gunichar2
));
888 destpos
+= newstrlen
;
892 } else if (ret
!= NULL
) {
893 dest
[destpos
] = src
[i
];
905 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
906 gint32 count
, MonoString
*value
,
914 lencmpstr
= mono_string_length(value
);
916 src
= mono_string_chars(source
);
917 cmpstr
= mono_string_chars(value
);
921 for(pos
=sindex
;pos
<= sindex
+count
;pos
++) {
922 for(i
=0;src
[pos
+i
]==cmpstr
[i
];) {
931 for(pos
=sindex
-lencmpstr
+1;pos
>sindex
-count
;pos
--) {
932 if(memcmp (src
+pos
, cmpstr
,
933 lencmpstr
*sizeof(gunichar2
))==0) {
942 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
943 gint32 count
, gunichar2 value
,
949 src
= mono_string_chars(source
);
951 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
952 if (src
[pos
] == value
) {
959 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
960 if (src
[pos
] == value
)
968 void load_normalization_resource (guint8
**argProps
,
969 guint8
**argMappedChars
,
970 guint8
**argCharMapIndex
,
971 guint8
**argHelperIndex
,
972 guint8
**argMapIdxToComposite
,
973 guint8
**argCombiningClass
)
975 *argProps
= (guint8
*)props
;
976 *argMappedChars
= (guint8
*) mappedChars
;
977 *argCharMapIndex
= (guint8
*) charMapIndex
;
978 *argHelperIndex
= (guint8
*) helperIndex
;
979 *argMapIdxToComposite
= (guint8
*) mapIdxToComposite
;
980 *argCombiningClass
= (guint8
*)combiningClass
;