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>
26 #ifndef DISABLE_NORMALIZATION
27 #include <mono/metadata/normalization-tables.h>
31 #if defined(__APPLE__)
32 #include <CoreFoundation/CoreFoundation.h>
37 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
39 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
40 gint32 len1
, MonoString
*str2
,
41 gint32 off2
, gint32 len2
,
43 static MonoString
*string_invariant_replace (MonoString
*me
,
45 MonoString
*newValue
);
46 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
47 gint32 count
, MonoString
*value
,
49 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
50 gint32 count
, gunichar2 value
,
53 static const CultureInfoEntry
* culture_info_entry_from_lcid (int lcid
);
55 static const RegionInfoEntry
* region_info_entry_from_lcid (int lcid
);
58 culture_lcid_locator (const void *a
, const void *b
)
60 const CultureInfoEntry
*aa
= a
;
61 const CultureInfoEntry
*bb
= b
;
63 return (aa
->lcid
- bb
->lcid
);
67 region_lcid_locator (const void *a
, const void *b
)
70 const CultureInfoEntry
*bb
= b
;
72 return *lcid
- bb
->lcid
;
76 culture_name_locator (const void *a
, const void *b
)
79 const CultureInfoNameEntry
*bb
= b
;
82 ret
= strcmp (aa
, idx2string (bb
->name
));
88 region_name_locator (const void *a
, const void *b
)
91 const RegionInfoNameEntry
*bb
= b
;
94 ret
= strcmp (aa
, idx2string (bb
->name
));
100 create_group_sizes_array (const gint
*gs
, gint ml
)
105 for (i
= 0; i
< ml
; i
++) {
111 ret
= mono_array_new_cached (mono_domain_get (),
112 mono_get_int32_class (), len
);
114 for(i
= 0; i
< len
; i
++)
115 mono_array_set (ret
, gint32
, i
, gs
[i
]);
121 create_names_array_idx (const guint16
*names
, int ml
)
130 domain
= mono_domain_get ();
132 for (i
= 0; i
< ml
; i
++) {
138 ret
= mono_array_new_cached (mono_domain_get (), mono_get_string_class (), len
);
140 for(i
= 0; i
< len
; i
++)
141 mono_array_setref (ret
, i
, mono_string_new (domain
, idx2string (names
[i
])));
147 ves_icall_System_Globalization_CultureInfo_construct_datetime_format (MonoCultureInfo
*this)
150 MonoDateTimeFormatInfo
*datetime
;
151 const DateTimeFormatEntry
*dfe
;
155 g_assert (this->datetime_index
>= 0);
157 datetime
= this->datetime_format
;
158 dfe
= &datetime_format_entries
[this->datetime_index
];
160 domain
= mono_domain_get ();
162 datetime
->readOnly
= this->is_read_only
;
163 MONO_OBJECT_SETREF (datetime
, AbbreviatedDayNames
, create_names_array_idx (dfe
->abbreviated_day_names
,
165 MONO_OBJECT_SETREF (datetime
, AbbreviatedMonthNames
, create_names_array_idx (dfe
->abbreviated_month_names
,
167 MONO_OBJECT_SETREF (datetime
, AMDesignator
, mono_string_new (domain
, idx2string (dfe
->am_designator
)));
168 datetime
->CalendarWeekRule
= dfe
->calendar_week_rule
;
169 MONO_OBJECT_SETREF (datetime
, DateSeparator
, mono_string_new (domain
, idx2string (dfe
->date_separator
)));
170 MONO_OBJECT_SETREF (datetime
, DayNames
, create_names_array_idx (dfe
->day_names
, NUM_DAYS
));
171 datetime
->FirstDayOfWeek
= dfe
->first_day_of_week
;
172 MONO_OBJECT_SETREF (datetime
, FullDateTimePattern
, mono_string_new (domain
, idx2string (dfe
->full_date_time_pattern
)));
173 MONO_OBJECT_SETREF (datetime
, LongDatePattern
, mono_string_new (domain
, idx2string (dfe
->long_date_pattern
)));
174 MONO_OBJECT_SETREF (datetime
, LongTimePattern
, mono_string_new (domain
, idx2string (dfe
->long_time_pattern
)));
175 MONO_OBJECT_SETREF (datetime
, MonthDayPattern
, mono_string_new (domain
, idx2string (dfe
->month_day_pattern
)));
176 MONO_OBJECT_SETREF (datetime
, MonthNames
, create_names_array_idx (dfe
->month_names
, NUM_MONTHS
));
177 MONO_OBJECT_SETREF (datetime
, PMDesignator
, mono_string_new (domain
, idx2string (dfe
->pm_designator
)));
178 MONO_OBJECT_SETREF (datetime
, ShortDatePattern
, mono_string_new (domain
, idx2string (dfe
->short_date_pattern
)));
179 MONO_OBJECT_SETREF (datetime
, ShortTimePattern
, mono_string_new (domain
, idx2string (dfe
->short_time_pattern
)));
180 MONO_OBJECT_SETREF (datetime
, TimeSeparator
, mono_string_new (domain
, idx2string (dfe
->time_separator
)));
181 MONO_OBJECT_SETREF (datetime
, YearMonthPattern
, mono_string_new (domain
, idx2string (dfe
->year_month_pattern
)));
182 MONO_OBJECT_SETREF (datetime
, ShortDatePatterns
, create_names_array_idx (dfe
->short_date_patterns
,
183 NUM_SHORT_DATE_PATTERNS
));
184 MONO_OBJECT_SETREF (datetime
, LongDatePatterns
, create_names_array_idx (dfe
->long_date_patterns
,
185 NUM_LONG_DATE_PATTERNS
));
186 MONO_OBJECT_SETREF (datetime
, ShortTimePatterns
, create_names_array_idx (dfe
->short_time_patterns
,
187 NUM_SHORT_TIME_PATTERNS
));
188 MONO_OBJECT_SETREF (datetime
, LongTimePatterns
, create_names_array_idx (dfe
->long_time_patterns
,
189 NUM_LONG_TIME_PATTERNS
));
194 ves_icall_System_Globalization_CultureInfo_construct_number_format (MonoCultureInfo
*this)
197 MonoNumberFormatInfo
*number
;
198 const NumberFormatEntry
*nfe
;
202 g_assert (this->number_format
!= 0);
203 if (this->number_index
< 0)
206 number
= this->number_format
;
207 nfe
= &number_format_entries
[this->number_index
];
209 domain
= mono_domain_get ();
211 number
->readOnly
= this->is_read_only
;
212 number
->currencyDecimalDigits
= nfe
->currency_decimal_digits
;
213 MONO_OBJECT_SETREF (number
, currencyDecimalSeparator
, mono_string_new (domain
,
214 idx2string (nfe
->currency_decimal_separator
)));
215 MONO_OBJECT_SETREF (number
, currencyGroupSeparator
, mono_string_new (domain
,
216 idx2string (nfe
->currency_group_separator
)));
217 MONO_OBJECT_SETREF (number
, currencyGroupSizes
, create_group_sizes_array (nfe
->currency_group_sizes
,
219 number
->currencyNegativePattern
= nfe
->currency_negative_pattern
;
220 number
->currencyPositivePattern
= nfe
->currency_positive_pattern
;
221 MONO_OBJECT_SETREF (number
, currencySymbol
, mono_string_new (domain
, idx2string (nfe
->currency_symbol
)));
222 MONO_OBJECT_SETREF (number
, naNSymbol
, mono_string_new (domain
, idx2string (nfe
->nan_symbol
)));
223 MONO_OBJECT_SETREF (number
, negativeInfinitySymbol
, mono_string_new (domain
,
224 idx2string (nfe
->negative_infinity_symbol
)));
225 MONO_OBJECT_SETREF (number
, negativeSign
, mono_string_new (domain
, idx2string (nfe
->negative_sign
)));
226 number
->numberDecimalDigits
= nfe
->number_decimal_digits
;
227 MONO_OBJECT_SETREF (number
, numberDecimalSeparator
, mono_string_new (domain
,
228 idx2string (nfe
->number_decimal_separator
)));
229 MONO_OBJECT_SETREF (number
, numberGroupSeparator
, mono_string_new (domain
, idx2string (nfe
->number_group_separator
)));
230 MONO_OBJECT_SETREF (number
, numberGroupSizes
, create_group_sizes_array (nfe
->number_group_sizes
,
232 number
->numberNegativePattern
= nfe
->number_negative_pattern
;
233 number
->percentDecimalDigits
= nfe
->percent_decimal_digits
;
234 MONO_OBJECT_SETREF (number
, percentDecimalSeparator
, mono_string_new (domain
,
235 idx2string (nfe
->percent_decimal_separator
)));
236 MONO_OBJECT_SETREF (number
, percentGroupSeparator
, mono_string_new (domain
,
237 idx2string (nfe
->percent_group_separator
)));
238 MONO_OBJECT_SETREF (number
, percentGroupSizes
, create_group_sizes_array (nfe
->percent_group_sizes
,
240 number
->percentNegativePattern
= nfe
->percent_negative_pattern
;
241 number
->percentPositivePattern
= nfe
->percent_positive_pattern
;
242 MONO_OBJECT_SETREF (number
, percentSymbol
, mono_string_new (domain
, idx2string (nfe
->percent_symbol
)));
243 MONO_OBJECT_SETREF (number
, perMilleSymbol
, mono_string_new (domain
, idx2string (nfe
->per_mille_symbol
)));
244 MONO_OBJECT_SETREF (number
, positiveInfinitySymbol
, mono_string_new (domain
,
245 idx2string (nfe
->positive_infinity_symbol
)));
246 MONO_OBJECT_SETREF (number
, positiveSign
, mono_string_new (domain
, idx2string (nfe
->positive_sign
)));
250 construct_culture (MonoCultureInfo
*this, const CultureInfoEntry
*ci
)
252 MonoDomain
*domain
= mono_domain_get ();
254 this->lcid
= ci
->lcid
;
255 MONO_OBJECT_SETREF (this, name
, mono_string_new (domain
, idx2string (ci
->name
)));
256 MONO_OBJECT_SETREF (this, icu_name
, mono_string_new (domain
, idx2string (ci
->icu_name
)));
257 MONO_OBJECT_SETREF (this, displayname
, mono_string_new (domain
, idx2string (ci
->displayname
)));
258 MONO_OBJECT_SETREF (this, englishname
, mono_string_new (domain
, idx2string (ci
->englishname
)));
259 MONO_OBJECT_SETREF (this, nativename
, mono_string_new (domain
, idx2string (ci
->nativename
)));
260 MONO_OBJECT_SETREF (this, win3lang
, mono_string_new (domain
, idx2string (ci
->win3lang
)));
261 MONO_OBJECT_SETREF (this, iso3lang
, mono_string_new (domain
, idx2string (ci
->iso3lang
)));
262 MONO_OBJECT_SETREF (this, iso2lang
, mono_string_new (domain
, idx2string (ci
->iso2lang
)));
263 MONO_OBJECT_SETREF (this, territory
, mono_string_new (domain
, idx2string (ci
->territory
)));
264 this->parent_lcid
= ci
->parent_lcid
;
265 this->specific_lcid
= ci
->specific_lcid
;
266 this->datetime_index
= ci
->datetime_format_index
;
267 this->number_index
= ci
->number_format_index
;
268 this->calendar_data
= ci
->calendar_data
;
269 this->text_info_data
= &ci
->text_info
;
275 construct_region (MonoRegionInfo
*this, const RegionInfoEntry
*ri
)
277 MonoDomain
*domain
= mono_domain_get ();
279 this->region_id
= ri
->region_id
;
280 MONO_OBJECT_SETREF (this, iso2name
, mono_string_new (domain
, idx2string (ri
->iso2name
)));
281 MONO_OBJECT_SETREF (this, iso3name
, mono_string_new (domain
, idx2string (ri
->iso3name
)));
282 MONO_OBJECT_SETREF (this, win3name
, mono_string_new (domain
, idx2string (ri
->win3name
)));
283 MONO_OBJECT_SETREF (this, english_name
, mono_string_new (domain
, idx2string (ri
->english_name
)));
284 MONO_OBJECT_SETREF (this, currency_symbol
, mono_string_new (domain
, idx2string (ri
->currency_symbol
)));
285 MONO_OBJECT_SETREF (this, iso_currency_symbol
, mono_string_new (domain
, idx2string (ri
->iso_currency_symbol
)));
286 MONO_OBJECT_SETREF (this, currency_english_name
, mono_string_new (domain
, idx2string (ri
->currency_english_name
)));
292 construct_culture_from_specific_name (MonoCultureInfo
*ci
, gchar
*name
)
294 const CultureInfoEntry
*entry
;
295 const CultureInfoNameEntry
*ne
;
299 ne
= bsearch (name
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
300 sizeof (CultureInfoNameEntry
), culture_name_locator
);
305 entry
= &culture_entries
[ne
->culture_entry_index
];
307 /* try avoiding another lookup, often the culture is its own specific culture */
308 if (entry
->lcid
!= entry
->specific_lcid
)
309 entry
= culture_info_entry_from_lcid (entry
->specific_lcid
);
312 return construct_culture (ci
, entry
);
317 static const CultureInfoEntry
*
318 culture_info_entry_from_lcid (int lcid
)
320 const CultureInfoEntry
*ci
;
321 CultureInfoEntry key
;
324 ci
= bsearch (&key
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
329 static const RegionInfoEntry
*
330 region_info_entry_from_lcid (int lcid
)
332 const RegionInfoEntry
*entry
;
333 const CultureInfoEntry
*ne
;
337 ne
= bsearch (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
,
338 sizeof (CultureInfoEntry
), region_lcid_locator
);
343 entry
= ®ion_entries
[ne
->region_entry_index
];
349 * The following two methods are modified from the ICU source code. (http://oss.software.ibm.com/icu)
350 * Copyright (c) 1995-2003 International Business Machines Corporation and others
351 * All rights reserved.
354 get_posix_locale (void)
356 const gchar
* posix_locale
= NULL
;
358 posix_locale
= g_getenv("LC_ALL");
359 if (posix_locale
== 0) {
360 posix_locale
= g_getenv("LANG");
361 if (posix_locale
== 0) {
362 posix_locale
= setlocale(LC_ALL
, NULL
);
366 if (posix_locale
== NULL
)
369 if ((strcmp ("C", posix_locale
) == 0) || (strchr (posix_locale
, ' ') != NULL
)
370 || (strchr (posix_locale
, '/') != NULL
)) {
372 * HPUX returns 'C C C C C C C'
373 * Solaris can return /en_US/C/C/C/C/C on the second try.
374 * Maybe we got some garbage.
379 return g_strdup (posix_locale
);
382 #if defined (__APPLE__)
384 get_darwin_locale (void)
386 static gchar
*darwin_locale
= NULL
;
387 CFLocaleRef locale
= NULL
;
388 CFStringRef locale_cfstr
= NULL
;
392 if (darwin_locale
!= NULL
)
393 return g_strdup (darwin_locale
);
395 locale
= CFLocaleCopyCurrent ();
398 locale_cfstr
= CFLocaleGetIdentifier (locale
);
401 len
= CFStringGetMaximumSizeForEncoding (CFStringGetLength (locale_cfstr
), kCFStringEncodingMacRoman
) + 1;
402 darwin_locale
= (char *) malloc (len
);
403 if (!CFStringGetCString (locale_cfstr
, darwin_locale
, len
, kCFStringEncodingMacRoman
)) {
404 free (darwin_locale
);
406 darwin_locale
= NULL
;
410 for (i
= 0; i
< strlen (darwin_locale
); i
++)
411 if (darwin_locale
[i
] == '_')
412 darwin_locale
[i
] = '-';
418 return g_strdup (darwin_locale
);
423 get_current_locale_name (void)
426 gchar
*corrected
= NULL
;
431 locale
= g_win32_getlocale ();
432 #elif defined (__APPLE__)
433 locale
= get_darwin_locale ();
435 locale
= get_posix_locale ();
437 locale
= get_posix_locale ();
443 if ((p
= strchr (locale
, '.')) != NULL
) {
444 /* assume new locale can't be larger than old one? */
445 corrected
= g_malloc (strlen (locale
));
446 strncpy (corrected
, locale
, p
- locale
);
447 corrected
[p
- locale
] = 0;
449 /* do not copy after the @ */
450 if ((p
= strchr (corrected
, '@')) != NULL
)
451 corrected
[p
- corrected
] = 0;
454 /* Note that we scan the *uncorrected* ID. */
455 if ((p
= strrchr (locale
, '@')) != NULL
) {
458 * In Mono we dont handle the '@' modifier because we do
459 * not have any cultures that use it. We just trim it
460 * off of the end of the name.
463 if (corrected
== NULL
) {
464 corrected
= g_malloc (strlen (locale
));
465 strncpy (corrected
, locale
, p
- locale
);
466 corrected
[p
- locale
] = 0;
470 if (corrected
== NULL
)
475 if ((c
= strchr (corrected
, '_')) != NULL
)
479 corrected
= g_ascii_strdown (c
, -1);
486 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_current_locale (MonoCultureInfo
*ci
)
493 locale
= get_current_locale_name ();
497 ret
= construct_culture_from_specific_name (ci
, locale
);
499 ci
->is_read_only
= TRUE
;
500 ci
->use_user_override
= TRUE
;
506 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo
*this,
509 const CultureInfoEntry
*ci
;
513 ci
= culture_info_entry_from_lcid (lcid
);
517 return construct_culture (this, ci
);
521 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo
*this,
524 const CultureInfoNameEntry
*ne
;
529 n
= mono_string_to_utf8 (name
);
530 ne
= bsearch (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
531 sizeof (CultureInfoNameEntry
), culture_name_locator
);
534 /*g_print ("ne (%s) is null\n", n);*/
540 return construct_culture (this, &culture_entries
[ne
->culture_entry_index
]);
544 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo
*ci
,
552 locale
= mono_string_to_utf8 (name
);
553 ret
= construct_culture_from_specific_name (ci
, locale
);
560 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo
*this,
563 const RegionInfoEntry
*ri
;
567 ri
= region_info_entry_from_lcid (lcid
);
571 return construct_region (this, ri
);
575 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo
*this,
578 const RegionInfoNameEntry
*ne
;
583 n
= mono_string_to_utf8 (name
);
584 ne
= bsearch (n
, region_name_entries
, NUM_REGION_ENTRIES
,
585 sizeof (RegionInfoNameEntry
), region_name_locator
);
588 /*g_print ("ne (%s) is null\n", n);*/
594 return construct_region (this, ®ion_entries
[ne
->region_entry_index
]);
598 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral
,
599 MonoBoolean specific
, MonoBoolean installed
)
603 MonoCultureInfo
*culture
;
605 const CultureInfoEntry
*ci
;
611 domain
= mono_domain_get ();
614 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
615 ci
= &culture_entries
[i
];
616 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
617 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
))
621 class = mono_class_from_name (mono_get_corlib (),
622 "System.Globalization", "CultureInfo");
624 /* The InvariantCulture is not in culture_entries */
625 /* We reserve the first slot in the array for it */
629 ret
= mono_array_new (domain
, class, len
);
636 mono_array_setref (ret
, len
++, NULL
);
638 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
639 ci
= &culture_entries
[i
];
640 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
641 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
)) {
642 culture
= (MonoCultureInfo
*) mono_object_new (domain
, class);
643 mono_runtime_object_init ((MonoObject
*) culture
);
644 construct_culture (culture
, ci
);
645 culture
->use_user_override
= TRUE
;
646 mono_array_setref (ret
, len
++, culture
);
654 * ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral:
656 * Set is_neutral and return TRUE if the culture is found. If it is not found return FALSE.
659 ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral (gint lcid
, MonoBoolean
*is_neutral
)
661 const CultureInfoEntry
*entry
;
665 entry
= culture_info_entry_from_lcid (lcid
);
670 *is_neutral
= (entry
->specific_lcid
== 0);
675 void ves_icall_System_Globalization_CompareInfo_construct_compareinfo (MonoCompareInfo
*comp
, MonoString
*locale
)
677 /* Nothing to do here */
680 int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoCompareInfo
*this, MonoString
*str1
, gint32 off1
, gint32 len1
, MonoString
*str2
, gint32 off2
, gint32 len2
, gint32 options
)
684 /* Do a normal ascii string compare, as we only know the
685 * invariant locale if we dont have ICU
687 return(string_invariant_compare (str1
, off1
, len1
, str2
, off2
, len2
,
691 void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoCompareInfo
*this)
693 /* Nothing to do here */
696 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo
*this, MonoSortKey
*key
, MonoString
*source
, gint32 options
)
703 keylen
=mono_string_length (source
);
705 arr
=mono_array_new (mono_domain_get (), mono_get_byte_class (),
707 for(i
=0; i
<keylen
; i
++) {
708 mono_array_set (arr
, guint8
, i
, mono_string_chars (source
)[i
]);
711 MONO_OBJECT_SETREF (key
, key
, arr
);
714 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, MonoString
*value
, gint32 options
, MonoBoolean first
)
718 return(string_invariant_indexof (source
, sindex
, count
, value
, first
));
721 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, gunichar2 value
, gint32 options
, MonoBoolean first
)
725 return(string_invariant_indexof_char (source
, sindex
, count
, value
,
729 int ves_icall_System_Threading_Thread_current_lcid (void)
737 MonoString
*ves_icall_System_String_InternalReplace_Str_Comp (MonoString
*this, MonoString
*old
, MonoString
*new, MonoCompareInfo
*comp
)
741 /* Do a normal ascii string compare and replace, as we only
742 * know the invariant locale if we dont have ICU
744 return(string_invariant_replace (this, old
, new));
747 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
752 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
753 if (options
& CompareOptions_Ordinal
)
754 return (gint32
) c1
- c2
;
756 if (options
& CompareOptions_IgnoreCase
) {
757 GUnicodeType c1type
, c2type
;
759 c1type
= g_unichar_type (c1
);
760 c2type
= g_unichar_type (c2
);
762 result
= (gint32
) (c1type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c1
) : c1
) -
763 (c2type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c2
) : c2
);
766 * No options. Kana, symbol and spacing options don't
767 * apply to the invariant culture.
771 * FIXME: here we must use the information from c1type and c2type
772 * to find out the proper collation, even on the InvariantCulture, the
773 * sorting is not done by computing the unicode values, but their
776 result
= (gint32
) c1
- c2
;
779 return ((result
< 0) ? -1 : (result
> 0) ? 1 : 0);
782 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
783 gint32 len1
, MonoString
*str2
,
784 gint32 off2
, gint32 len2
,
787 /* c translation of C# code from old string.cs.. :) */
800 ustr1
= mono_string_chars(str1
)+off1
;
801 ustr2
= mono_string_chars(str2
)+off2
;
805 for (pos
= 0; pos
!= length
; pos
++) {
806 if (pos
>= len1
|| pos
>= len2
)
809 charcmp
= string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
],
816 /* the lesser wins, so if we have looped until length we just
817 * need to check the last char
820 return(string_invariant_compare_char(ustr1
[pos
- 1],
821 ustr2
[pos
- 1], options
));
824 /* Test if one of the strings has been compared to the end */
831 } else if (pos
>= len2
) {
835 /* if not, check our last char only.. (can this happen?) */
836 return(string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
], options
));
839 static MonoString
*string_invariant_replace (MonoString
*me
,
840 MonoString
*oldValue
,
841 MonoString
*newValue
)
845 gunichar2
*dest
=NULL
; /* shut gcc up */
847 gunichar2
*newstr
=NULL
; /* shut gcc up here too */
858 oldstr
= mono_string_chars(oldValue
);
859 oldstrlen
= mono_string_length(oldValue
);
861 if (NULL
!= newValue
) {
862 newstr
= mono_string_chars(newValue
);
863 newstrlen
= mono_string_length(newValue
);
867 src
= mono_string_chars(me
);
868 srclen
= mono_string_length(me
);
870 if (oldstrlen
!= newstrlen
) {
872 while (i
<= srclen
- oldstrlen
) {
873 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
882 newsize
= srclen
+ ((newstrlen
- oldstrlen
) * occurr
);
889 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
891 ret
= mono_string_new_size( mono_domain_get (), newsize
);
892 dest
= mono_string_chars(ret
);
893 memcpy (dest
, src
, i
* sizeof(gunichar2
));
896 memcpy(dest
+ destpos
, newstr
, newstrlen
* sizeof(gunichar2
));
897 destpos
+= newstrlen
;
901 } else if (ret
!= NULL
) {
902 dest
[destpos
] = src
[i
];
914 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
915 gint32 count
, MonoString
*value
,
923 lencmpstr
= mono_string_length(value
);
925 src
= mono_string_chars(source
);
926 cmpstr
= mono_string_chars(value
);
930 for(pos
=sindex
;pos
<= sindex
+count
;pos
++) {
931 for(i
=0;src
[pos
+i
]==cmpstr
[i
];) {
940 for(pos
=sindex
-lencmpstr
+1;pos
>sindex
-count
;pos
--) {
941 if(memcmp (src
+pos
, cmpstr
,
942 lencmpstr
*sizeof(gunichar2
))==0) {
951 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
952 gint32 count
, gunichar2 value
,
958 src
= mono_string_chars(source
);
960 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
961 if (src
[pos
] == value
) {
968 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
969 if (src
[pos
] == value
)
977 void load_normalization_resource (guint8
**argProps
,
978 guint8
**argMappedChars
,
979 guint8
**argCharMapIndex
,
980 guint8
**argHelperIndex
,
981 guint8
**argMapIdxToComposite
,
982 guint8
**argCombiningClass
)
984 #ifdef DISABLE_NORMALIZATION
985 mono_raise_exception (mono_get_exception_not_supported ("This runtime has been compiled without string normalization support."));
987 *argProps
= (guint8
*)props
;
988 *argMappedChars
= (guint8
*) mappedChars
;
989 *argCharMapIndex
= (guint8
*) charMapIndex
;
990 *argHelperIndex
= (guint8
*) helperIndex
;
991 *argMapIdxToComposite
= (guint8
*) mapIdxToComposite
;
992 *argCombiningClass
= (guint8
*)combiningClass
;