2 * locales.c: Culture-sensitive handling
5 * Dick Porter (dick@ximian.com)
6 * Mohammad DAMT (mdamt@cdl2000.com)
8 * (C) 2003 Ximian, Inc.
9 * (C) 2003 PT Cakram Datalingga Duaribu http://www.cdl2000.com
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/object.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/exception.h>
20 #include <mono/metadata/monitor.h>
21 #include <mono/metadata/locales.h>
22 #include <mono/metadata/culture-info.h>
23 #include <mono/metadata/culture-info-tables.h>
24 #include <mono/metadata/normalization-tables.h>
31 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
33 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
34 gint32 len1
, MonoString
*str2
,
35 gint32 off2
, gint32 len2
,
37 static MonoString
*string_invariant_replace (MonoString
*me
,
39 MonoString
*newValue
);
40 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
41 gint32 count
, MonoString
*value
,
43 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
44 gint32 count
, gunichar2 value
,
47 static const CultureInfoEntry
* culture_info_entry_from_lcid (int lcid
);
49 static const RegionInfoEntry
* region_info_entry_from_lcid (int lcid
);
52 culture_lcid_locator (const void *a
, const void *b
)
54 const CultureInfoEntry
*aa
= a
;
55 const CultureInfoEntry
*bb
= b
;
57 return (aa
->lcid
- bb
->lcid
);
61 region_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 (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 for (i
= 0; i
< ml
; i
++) {
132 ret
= mono_array_new (mono_domain_get (), mono_get_string_class (), len
);
134 for(i
= 0; i
< len
; i
++)
135 mono_array_setref (ret
, i
, mono_string_new (domain
, idx2string (names
[i
])));
141 ves_icall_System_Globalization_CultureInfo_construct_datetime_format (MonoCultureInfo
*this)
144 MonoDateTimeFormatInfo
*datetime
;
145 const DateTimeFormatEntry
*dfe
;
149 g_assert (this->datetime_index
>= 0);
151 datetime
= this->datetime_format
;
152 dfe
= &datetime_format_entries
[this->datetime_index
];
154 domain
= mono_domain_get ();
156 MONO_OBJECT_SETREF (datetime
, AbbreviatedDayNames
, create_names_array_idx (dfe
->abbreviated_day_names
,
158 MONO_OBJECT_SETREF (datetime
, AbbreviatedMonthNames
, create_names_array_idx (dfe
->abbreviated_month_names
,
160 MONO_OBJECT_SETREF (datetime
, AMDesignator
, mono_string_new (domain
, idx2string (dfe
->am_designator
)));
161 datetime
->CalendarWeekRule
= dfe
->calendar_week_rule
;
162 MONO_OBJECT_SETREF (datetime
, DateSeparator
, mono_string_new (domain
, idx2string (dfe
->date_separator
)));
163 MONO_OBJECT_SETREF (datetime
, DayNames
, create_names_array_idx (dfe
->day_names
, NUM_DAYS
));
164 datetime
->FirstDayOfWeek
= dfe
->first_day_of_week
;
165 MONO_OBJECT_SETREF (datetime
, FullDateTimePattern
, mono_string_new (domain
, idx2string (dfe
->full_date_time_pattern
)));
166 MONO_OBJECT_SETREF (datetime
, LongDatePattern
, mono_string_new (domain
, idx2string (dfe
->long_date_pattern
)));
167 MONO_OBJECT_SETREF (datetime
, LongTimePattern
, mono_string_new (domain
, idx2string (dfe
->long_time_pattern
)));
168 MONO_OBJECT_SETREF (datetime
, MonthDayPattern
, mono_string_new (domain
, idx2string (dfe
->month_day_pattern
)));
169 MONO_OBJECT_SETREF (datetime
, MonthNames
, create_names_array_idx (dfe
->month_names
, NUM_MONTHS
));
170 MONO_OBJECT_SETREF (datetime
, PMDesignator
, mono_string_new (domain
, idx2string (dfe
->pm_designator
)));
171 MONO_OBJECT_SETREF (datetime
, ShortDatePattern
, mono_string_new (domain
, idx2string (dfe
->short_date_pattern
)));
172 MONO_OBJECT_SETREF (datetime
, ShortTimePattern
, mono_string_new (domain
, idx2string (dfe
->short_time_pattern
)));
173 MONO_OBJECT_SETREF (datetime
, TimeSeparator
, mono_string_new (domain
, idx2string (dfe
->time_separator
)));
174 MONO_OBJECT_SETREF (datetime
, YearMonthPattern
, mono_string_new (domain
, idx2string (dfe
->year_month_pattern
)));
175 MONO_OBJECT_SETREF (datetime
, ShortDatePatterns
, create_names_array_idx (dfe
->short_date_patterns
,
176 NUM_SHORT_DATE_PATTERNS
));
177 MONO_OBJECT_SETREF (datetime
, LongDatePatterns
, create_names_array_idx (dfe
->long_date_patterns
,
178 NUM_LONG_DATE_PATTERNS
));
179 MONO_OBJECT_SETREF (datetime
, ShortTimePatterns
, create_names_array_idx (dfe
->short_time_patterns
,
180 NUM_SHORT_TIME_PATTERNS
));
181 MONO_OBJECT_SETREF (datetime
, LongTimePatterns
, create_names_array_idx (dfe
->long_time_patterns
,
182 NUM_LONG_TIME_PATTERNS
));
187 ves_icall_System_Globalization_CultureInfo_construct_number_format (MonoCultureInfo
*this)
190 MonoNumberFormatInfo
*number
;
191 const NumberFormatEntry
*nfe
;
195 g_assert (this->number_format
!= 0);
197 number
= this->number_format
;
198 nfe
= &number_format_entries
[this->number_index
];
200 domain
= mono_domain_get ();
202 number
->currencyDecimalDigits
= nfe
->currency_decimal_digits
;
203 MONO_OBJECT_SETREF (number
, currencyDecimalSeparator
, mono_string_new (domain
,
204 idx2string (nfe
->currency_decimal_separator
)));
205 MONO_OBJECT_SETREF (number
, currencyGroupSeparator
, mono_string_new (domain
,
206 idx2string (nfe
->currency_group_separator
)));
207 MONO_OBJECT_SETREF (number
, currencyGroupSizes
, create_group_sizes_array (nfe
->currency_group_sizes
,
209 number
->currencyNegativePattern
= nfe
->currency_negative_pattern
;
210 number
->currencyPositivePattern
= nfe
->currency_positive_pattern
;
211 MONO_OBJECT_SETREF (number
, currencySymbol
, mono_string_new (domain
, idx2string (nfe
->currency_symbol
)));
212 MONO_OBJECT_SETREF (number
, naNSymbol
, mono_string_new (domain
, idx2string (nfe
->nan_symbol
)));
213 MONO_OBJECT_SETREF (number
, negativeInfinitySymbol
, mono_string_new (domain
,
214 idx2string (nfe
->negative_infinity_symbol
)));
215 MONO_OBJECT_SETREF (number
, negativeSign
, mono_string_new (domain
, idx2string (nfe
->negative_sign
)));
216 number
->numberDecimalDigits
= nfe
->number_decimal_digits
;
217 MONO_OBJECT_SETREF (number
, numberDecimalSeparator
, mono_string_new (domain
,
218 idx2string (nfe
->number_decimal_separator
)));
219 MONO_OBJECT_SETREF (number
, numberGroupSeparator
, mono_string_new (domain
, idx2string (nfe
->number_group_separator
)));
220 MONO_OBJECT_SETREF (number
, numberGroupSizes
, create_group_sizes_array (nfe
->number_group_sizes
,
222 number
->numberNegativePattern
= nfe
->number_negative_pattern
;
223 number
->percentDecimalDigits
= nfe
->percent_decimal_digits
;
224 MONO_OBJECT_SETREF (number
, percentDecimalSeparator
, mono_string_new (domain
,
225 idx2string (nfe
->percent_decimal_separator
)));
226 MONO_OBJECT_SETREF (number
, percentGroupSeparator
, mono_string_new (domain
,
227 idx2string (nfe
->percent_group_separator
)));
228 MONO_OBJECT_SETREF (number
, percentGroupSizes
, create_group_sizes_array (nfe
->percent_group_sizes
,
230 number
->percentNegativePattern
= nfe
->percent_negative_pattern
;
231 number
->percentPositivePattern
= nfe
->percent_positive_pattern
;
232 MONO_OBJECT_SETREF (number
, percentSymbol
, mono_string_new (domain
, idx2string (nfe
->percent_symbol
)));
233 MONO_OBJECT_SETREF (number
, perMilleSymbol
, mono_string_new (domain
, idx2string (nfe
->per_mille_symbol
)));
234 MONO_OBJECT_SETREF (number
, positiveInfinitySymbol
, mono_string_new (domain
,
235 idx2string (nfe
->positive_infinity_symbol
)));
236 MONO_OBJECT_SETREF (number
, positiveSign
, mono_string_new (domain
, idx2string (nfe
->positive_sign
)));
240 construct_culture (MonoCultureInfo
*this, const CultureInfoEntry
*ci
)
242 MonoDomain
*domain
= mono_domain_get ();
244 this->lcid
= ci
->lcid
;
245 MONO_OBJECT_SETREF (this, name
, mono_string_new (domain
, idx2string (ci
->name
)));
246 MONO_OBJECT_SETREF (this, icu_name
, mono_string_new (domain
, idx2string (ci
->icu_name
)));
247 MONO_OBJECT_SETREF (this, displayname
, mono_string_new (domain
, idx2string (ci
->displayname
)));
248 MONO_OBJECT_SETREF (this, englishname
, mono_string_new (domain
, idx2string (ci
->englishname
)));
249 MONO_OBJECT_SETREF (this, nativename
, mono_string_new (domain
, idx2string (ci
->nativename
)));
250 MONO_OBJECT_SETREF (this, win3lang
, mono_string_new (domain
, idx2string (ci
->win3lang
)));
251 MONO_OBJECT_SETREF (this, iso3lang
, mono_string_new (domain
, idx2string (ci
->iso3lang
)));
252 MONO_OBJECT_SETREF (this, iso2lang
, mono_string_new (domain
, idx2string (ci
->iso2lang
)));
253 this->parent_lcid
= ci
->parent_lcid
;
254 this->specific_lcid
= ci
->specific_lcid
;
255 this->datetime_index
= ci
->datetime_format_index
;
256 this->number_index
= ci
->number_format_index
;
257 this->calendar_data
= ci
->calendar_data
;
258 this->text_info_data
= &ci
->text_info
;
264 construct_region (MonoRegionInfo
*this, const RegionInfoEntry
*ri
)
266 MonoDomain
*domain
= mono_domain_get ();
268 this->region_id
= ri
->region_id
;
269 MONO_OBJECT_SETREF (this, iso2name
, mono_string_new (domain
, idx2string (ri
->iso2name
)));
270 MONO_OBJECT_SETREF (this, iso3name
, mono_string_new (domain
, idx2string (ri
->iso3name
)));
271 MONO_OBJECT_SETREF (this, win3name
, mono_string_new (domain
, idx2string (ri
->win3name
)));
272 MONO_OBJECT_SETREF (this, english_name
, mono_string_new (domain
, idx2string (ri
->english_name
)));
273 MONO_OBJECT_SETREF (this, currency_symbol
, mono_string_new (domain
, idx2string (ri
->currency_symbol
)));
274 MONO_OBJECT_SETREF (this, iso_currency_symbol
, mono_string_new (domain
, idx2string (ri
->iso_currency_symbol
)));
275 MONO_OBJECT_SETREF (this, currency_english_name
, mono_string_new (domain
, idx2string (ri
->currency_english_name
)));
281 construct_culture_from_specific_name (MonoCultureInfo
*ci
, gchar
*name
)
283 const CultureInfoEntry
*entry
;
284 const CultureInfoNameEntry
*ne
;
288 ne
= bsearch (name
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
289 sizeof (CultureInfoNameEntry
), culture_name_locator
);
294 entry
= &culture_entries
[ne
->culture_entry_index
];
296 /* try avoiding another lookup, often the culture is its own specific culture */
297 if (entry
->lcid
!= entry
->specific_lcid
)
298 entry
= culture_info_entry_from_lcid (entry
->specific_lcid
);
300 return construct_culture (ci
, entry
);
304 construct_region_from_specific_name (MonoRegionInfo
*ri
, gchar
*name
)
306 const RegionInfoEntry
*entry
;
307 const RegionInfoNameEntry
*ne
;
311 ne
= bsearch (name
, region_name_entries
, NUM_REGION_ENTRIES
,
312 sizeof (RegionInfoNameEntry
), region_name_locator
);
317 entry
= ®ion_entries
[ne
->region_entry_index
];
319 return construct_region (ri
, entry
);
322 static const CultureInfoEntry
*
323 culture_info_entry_from_lcid (int lcid
)
325 const CultureInfoEntry
*ci
;
326 CultureInfoEntry key
;
329 ci
= bsearch (&key
, culture_entries
, NUM_CULTURE_ENTRIES
, sizeof (CultureInfoEntry
), culture_lcid_locator
);
334 static const RegionInfoEntry
*
335 region_info_entry_from_lcid (int lcid
)
337 const RegionInfoEntry
*entry
;
338 const CultureInfoEntry
*ne
;
342 ne
= bsearch (&lcid
, culture_entries
, NUM_CULTURE_ENTRIES
,
343 sizeof (CultureInfoEntry
), region_lcid_locator
);
348 entry
= ®ion_entries
[ne
->region_entry_index
];
354 * The following two methods are modified from the ICU source code. (http://oss.software.ibm.com/icu)
355 * Copyright (c) 1995-2003 International Business Machines Corporation and others
356 * All rights reserved.
359 get_posix_locale (void)
361 const gchar
* posix_locale
= NULL
;
363 posix_locale
= g_getenv("LC_ALL");
364 if (posix_locale
== 0) {
365 posix_locale
= g_getenv("LANG");
366 if (posix_locale
== 0) {
367 posix_locale
= setlocale(LC_ALL
, NULL
);
371 if (posix_locale
== NULL
)
374 if ((strcmp ("C", posix_locale
) == 0) || (strchr (posix_locale
, ' ') != NULL
)
375 || (strchr (posix_locale
, '/') != NULL
)) {
377 * HPUX returns 'C C C C C C C'
378 * Solaris can return /en_US/C/C/C/C/C on the second try.
379 * Maybe we got some garbage.
384 return g_strdup (posix_locale
);
388 get_current_locale_name (void)
391 gchar
*corrected
= NULL
;
395 #ifdef PLATFORM_WIN32
396 locale
= g_win32_getlocale ();
398 locale
= get_posix_locale ();
404 if ((p
= strchr (locale
, '.')) != NULL
) {
405 /* assume new locale can't be larger than old one? */
406 corrected
= malloc (strlen (locale
));
407 strncpy (corrected
, locale
, p
- locale
);
408 corrected
[p
- locale
] = 0;
410 /* do not copy after the @ */
411 if ((p
= strchr (corrected
, '@')) != NULL
)
412 corrected
[p
- corrected
] = 0;
415 /* Note that we scan the *uncorrected* ID. */
416 if ((p
= strrchr (locale
, '@')) != NULL
) {
419 * In Mono we dont handle the '@' modifier because we do
420 * not have any cultures that use it. We just trim it
421 * off of the end of the name.
424 if (corrected
== NULL
) {
425 corrected
= malloc (strlen (locale
));
426 strncpy (corrected
, locale
, p
- locale
);
427 corrected
[p
- locale
] = 0;
431 if (corrected
== NULL
)
436 if ((c
= strchr (corrected
, '_')) != NULL
)
439 g_strdown (corrected
);
445 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_current_locale (MonoCultureInfo
*ci
)
452 locale
= get_current_locale_name ();
456 ret
= construct_culture_from_specific_name (ci
, locale
);
463 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_lcid (MonoCultureInfo
*this,
466 const CultureInfoEntry
*ci
;
470 ci
= culture_info_entry_from_lcid (lcid
);
474 return construct_culture (this, ci
);
478 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_name (MonoCultureInfo
*this,
481 const CultureInfoNameEntry
*ne
;
486 n
= mono_string_to_utf8 (name
);
487 ne
= bsearch (n
, culture_name_entries
, NUM_CULTURE_ENTRIES
,
488 sizeof (CultureInfoNameEntry
), culture_name_locator
);
491 /*g_print ("ne (%s) is null\n", n);*/
497 return construct_culture (this, &culture_entries
[ne
->culture_entry_index
]);
501 ves_icall_System_Globalization_CultureInfo_construct_internal_locale_from_specific_name (MonoCultureInfo
*ci
,
509 locale
= mono_string_to_utf8 (name
);
510 ret
= construct_culture_from_specific_name (ci
, locale
);
517 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_lcid (MonoRegionInfo
*this,
520 const RegionInfoEntry
*ri
;
524 ri
= region_info_entry_from_lcid (lcid
);
528 return construct_region (this, ri
);
532 ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (MonoRegionInfo
*this,
535 const RegionInfoNameEntry
*ne
;
540 n
= mono_string_to_utf8 (name
);
541 ne
= bsearch (n
, region_name_entries
, NUM_REGION_ENTRIES
,
542 sizeof (RegionInfoNameEntry
), region_name_locator
);
545 /*g_print ("ne (%s) is null\n", n);*/
551 return construct_region (this, ®ion_entries
[ne
->region_entry_index
]);
555 ves_icall_System_Globalization_CultureInfo_internal_get_cultures (MonoBoolean neutral
,
556 MonoBoolean specific
, MonoBoolean installed
)
560 MonoCultureInfo
*culture
;
562 const CultureInfoEntry
*ci
;
568 domain
= mono_domain_get ();
571 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
572 ci
= &culture_entries
[i
];
573 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
574 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
))
578 class = mono_class_from_name (mono_get_corlib (),
579 "System.Globalization", "CultureInfo");
581 /* The InvariantCulture is not in culture_entries */
582 /* We reserve the first slot in the array for it */
586 ret
= mono_array_new (domain
, class, len
);
593 mono_array_setref (ret
, len
++, NULL
);
595 for (i
= 0; i
< NUM_CULTURE_ENTRIES
; i
++) {
596 ci
= &culture_entries
[i
];
597 is_neutral
= ((ci
->lcid
& 0xff00) == 0 || ci
->specific_lcid
== 0);
598 if ((neutral
&& is_neutral
) || (specific
&& !is_neutral
)) {
599 culture
= (MonoCultureInfo
*) mono_object_new (domain
, class);
600 mono_runtime_object_init ((MonoObject
*) culture
);
601 construct_culture (culture
, ci
);
602 mono_array_setref (ret
, len
++, culture
);
610 * ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral:
612 * Set is_neutral and return TRUE if the culture is found. If it is not found return FALSE.
615 ves_icall_System_Globalization_CultureInfo_internal_is_lcid_neutral (gint lcid
, MonoBoolean
*is_neutral
)
617 const CultureInfoEntry
*entry
;
621 entry
= culture_info_entry_from_lcid (lcid
);
626 *is_neutral
= (entry
->specific_lcid
== 0);
631 void ves_icall_System_Globalization_CompareInfo_construct_compareinfo (MonoCompareInfo
*comp
, MonoString
*locale
)
633 /* Nothing to do here */
636 int ves_icall_System_Globalization_CompareInfo_internal_compare (MonoCompareInfo
*this, MonoString
*str1
, gint32 off1
, gint32 len1
, MonoString
*str2
, gint32 off2
, gint32 len2
, gint32 options
)
640 /* Do a normal ascii string compare, as we only know the
641 * invariant locale if we dont have ICU
643 return(string_invariant_compare (str1
, off1
, len1
, str2
, off2
, len2
,
647 void ves_icall_System_Globalization_CompareInfo_free_internal_collator (MonoCompareInfo
*this)
649 /* Nothing to do here */
652 void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo
*this, MonoSortKey
*key
, MonoString
*source
, gint32 options
)
659 keylen
=mono_string_length (source
);
661 arr
=mono_array_new (mono_domain_get (), mono_get_byte_class (),
663 for(i
=0; i
<keylen
; i
++) {
664 mono_array_set (arr
, guint8
, i
, mono_string_chars (source
)[i
]);
667 MONO_OBJECT_SETREF (key
, key
, arr
);
670 int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, MonoString
*value
, gint32 options
, MonoBoolean first
)
674 return(string_invariant_indexof (source
, sindex
, count
, value
, first
));
677 int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo
*this, MonoString
*source
, gint32 sindex
, gint32 count
, gunichar2 value
, gint32 options
, MonoBoolean first
)
681 return(string_invariant_indexof_char (source
, sindex
, count
, value
,
685 int ves_icall_System_Threading_Thread_current_lcid (void)
693 MonoString
*ves_icall_System_String_InternalReplace_Str_Comp (MonoString
*this, MonoString
*old
, MonoString
*new, MonoCompareInfo
*comp
)
697 /* Do a normal ascii string compare and replace, as we only
698 * know the invariant locale if we dont have ICU
700 return(string_invariant_replace (this, old
, new));
703 static gint32
string_invariant_compare_char (gunichar2 c1
, gunichar2 c2
,
707 GUnicodeType c1type
, c2type
;
709 /* Ordinal can not be mixed with other options, and must return the difference, not only -1, 0, 1 */
710 if (options
& CompareOptions_Ordinal
)
711 return (gint32
) c1
- c2
;
713 c1type
= g_unichar_type (c1
);
714 c2type
= g_unichar_type (c2
);
716 if (options
& CompareOptions_IgnoreCase
) {
717 result
= (gint32
) (c1type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c1
) : c1
) -
718 (c2type
!= G_UNICODE_LOWERCASE_LETTER
? g_unichar_tolower(c2
) : c2
);
721 * No options. Kana, symbol and spacing options don't
722 * apply to the invariant culture.
726 * FIXME: here we must use the information from c1type and c2type
727 * to find out the proper collation, even on the InvariantCulture, the
728 * sorting is not done by computing the unicode values, but their
731 result
= (gint32
) c1
- c2
;
734 return ((result
< 0) ? -1 : (result
> 0) ? 1 : 0);
737 static gint32
string_invariant_compare (MonoString
*str1
, gint32 off1
,
738 gint32 len1
, MonoString
*str2
,
739 gint32 off2
, gint32 len2
,
742 /* c translation of C# code from old string.cs.. :) */
755 ustr1
= mono_string_chars(str1
)+off1
;
756 ustr2
= mono_string_chars(str2
)+off2
;
760 for (pos
= 0; pos
!= length
; pos
++) {
761 if (pos
>= len1
|| pos
>= len2
)
764 charcmp
= string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
],
771 /* the lesser wins, so if we have looped until length we just
772 * need to check the last char
775 return(string_invariant_compare_char(ustr1
[pos
- 1],
776 ustr2
[pos
- 1], options
));
779 /* Test if one of the strings has been compared to the end */
786 } else if (pos
>= len2
) {
790 /* if not, check our last char only.. (can this happen?) */
791 return(string_invariant_compare_char(ustr1
[pos
], ustr2
[pos
], options
));
794 static MonoString
*string_invariant_replace (MonoString
*me
,
795 MonoString
*oldValue
,
796 MonoString
*newValue
)
800 gunichar2
*dest
=NULL
; /* shut gcc up */
802 gunichar2
*newstr
=NULL
; /* shut gcc up here too */
813 oldstr
= mono_string_chars(oldValue
);
814 oldstrlen
= mono_string_length(oldValue
);
816 if (NULL
!= newValue
) {
817 newstr
= mono_string_chars(newValue
);
818 newstrlen
= mono_string_length(newValue
);
822 src
= mono_string_chars(me
);
823 srclen
= mono_string_length(me
);
825 if (oldstrlen
!= newstrlen
) {
827 while (i
<= srclen
- oldstrlen
) {
828 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
837 newsize
= srclen
+ ((newstrlen
- oldstrlen
) * occurr
);
844 if (0 == memcmp(src
+ i
, oldstr
, oldstrlen
* sizeof(gunichar2
))) {
846 ret
= mono_string_new_size( mono_domain_get (), newsize
);
847 dest
= mono_string_chars(ret
);
848 memcpy (dest
, src
, i
* sizeof(gunichar2
));
851 memcpy(dest
+ destpos
, newstr
, newstrlen
* sizeof(gunichar2
));
852 destpos
+= newstrlen
;
856 } else if (ret
!= NULL
) {
857 dest
[destpos
] = src
[i
];
869 static gint32
string_invariant_indexof (MonoString
*source
, gint32 sindex
,
870 gint32 count
, MonoString
*value
,
878 lencmpstr
= mono_string_length(value
);
880 src
= mono_string_chars(source
);
881 cmpstr
= mono_string_chars(value
);
885 for(pos
=sindex
;pos
<= sindex
+count
;pos
++) {
886 for(i
=0;src
[pos
+i
]==cmpstr
[i
];) {
895 for(pos
=sindex
-lencmpstr
+1;pos
>sindex
-count
;pos
--) {
896 if(memcmp (src
+pos
, cmpstr
,
897 lencmpstr
*sizeof(gunichar2
))==0) {
906 static gint32
string_invariant_indexof_char (MonoString
*source
, gint32 sindex
,
907 gint32 count
, gunichar2 value
,
913 src
= mono_string_chars(source
);
915 for (pos
= sindex
; pos
!= count
+ sindex
; pos
++) {
916 if (src
[pos
] == value
) {
923 for (pos
= sindex
; pos
> sindex
- count
; pos
--) {
924 if (src
[pos
] == value
)
932 void load_normalization_resource (guint8
**argProps
,
933 guint8
**argMappedChars
,
934 guint8
**argCharMapIndex
,
935 guint8
**argHelperIndex
,
936 guint8
**argMapIdxToComposite
,
937 guint8
**argCombiningClass
)
940 *argMappedChars
= (guint8
*) mappedChars
;
941 *argCharMapIndex
= (guint8
*) charMapIndex
;
942 *argHelperIndex
= (guint8
*) helperIndex
;
943 *argMapIdxToComposite
= (guint8
*) mapIdxToComposite
;
944 *argCombiningClass
= combiningClass
;