2 * string-icalls.c: String internal calls for the corlib
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
7 * (C) 2001 Ximian, Inc.
14 #include <mono/metadata/string-icalls.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/unicode.h>
20 #include <mono/metadata/exception.h>
23 mono_string_Internal_ctor_charp (gpointer dummy, gunichar2 *value)
28 domain = mono_domain_get ();
33 for (i = 0; *(value + i) != '\0'; i++);
37 return mono_string_new_utf16 (domain, value, length);
41 mono_string_Internal_ctor_char_int (gpointer dummy, gunichar2 value, gint32 count)
48 domain = mono_domain_get ();
49 res = mono_string_new_size (domain, count);
51 chars = mono_string_chars (res);
52 for (i = 0; i < count; i++)
59 mono_string_Internal_ctor_charp_int_int (gpointer dummy, gunichar2 *value, gint32 sindex, gint32 length)
64 domain = mono_domain_get ();
66 if ((value == NULL) && (sindex != 0) && (length != 0))
67 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
69 if ((sindex < 0) || (length < 0))
70 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
72 begin = (gunichar2 *) (value + sindex);
74 return mono_string_new_utf16 (domain, begin, length);
78 mono_string_Internal_ctor_sbytep (gpointer dummy, gint8 *value)
83 domain = mono_domain_get ();
88 for (i = 0; *(value + i) != '\0'; i++);
92 return mono_string_new_utf16 (domain, (gunichar2 *) value, length);
96 mono_string_Internal_ctor_sbytep_int_int (gpointer dummy, gint8 *value, gint32 sindex, gint32 length)
101 domain = mono_domain_get ();
103 if ((value == NULL) && (sindex != 0) && (length != 0))
104 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
106 if ((sindex > 0) || (length < 0))
107 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
109 begin = (gunichar2 *) (value + sindex);
111 return mono_string_new_utf16 (domain, begin, length);
115 mono_string_Internal_ctor_chara (gpointer dummy, MonoArray *value)
119 MONO_CHECK_ARG_NULL (value);
121 domain = mono_domain_get ();
123 return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, 0), value->max_length);
127 mono_string_Internal_ctor_chara_int_int (gpointer dummy, MonoArray *value,
128 gint32 sindex, gint32 length)
132 MONO_CHECK_ARG_NULL (value);
134 domain = ((MonoObject *) value)->vtable->domain;
136 return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, sindex), length);
140 mono_string_Internal_ctor_encoding (gpointer dummy, gint8 *value, gint32 sindex,
141 gint32 length, MonoObject *enc)
143 g_assert_not_reached ();
148 mono_string_InternalEquals (MonoString *str1, MonoString *str2)
154 /* Length checking is done in C# */
155 str1len = mono_string_length(str1);
157 str1ptr = mono_string_chars(str1);
158 str2ptr = mono_string_chars(str2);
160 return (0 == memcmp(str1ptr, str2ptr, str1len * sizeof(gunichar2)));
164 mono_string_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
176 insert = mono_string_chars(separator);
177 insertlen = mono_string_length(separator);
180 for (pos = sindex; pos != sindex + count; pos++) {
181 length += mono_string_length(mono_array_get(value, MonoString *, pos));
182 if (pos < sindex + count - 1)
186 ret = mono_string_InternalAllocateStr(length);
187 dest = mono_string_chars(ret);
190 for (pos = sindex; pos != sindex + count; pos++) {
191 src = mono_string_chars(mono_array_get(value, MonoString *, pos));
192 srclen = mono_string_length(mono_array_get(value, MonoString *, pos));
194 memcpy(dest + destpos, src, srclen * sizeof(gunichar2));
197 if (pos < sindex + count - 1) {
198 memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
199 destpos += insertlen;
207 mono_string_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
211 gunichar2 *insertsrc;
216 src = mono_string_chars(me);
217 srclen = mono_string_length(me);
219 insertsrc = mono_string_chars(value);
220 insertlen = mono_string_length(value);
222 ret = mono_string_InternalAllocateStr(mono_string_length(me) + insertlen);
223 dest = mono_string_chars(ret);
225 memcpy(dest, src, sindex * sizeof(gunichar2));
226 memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
227 memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
233 mono_string_InternalReplaceChar (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
235 g_warning("mono_string_InternalReplaceChar not impl");
236 return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
240 mono_string_InternalReplaceStr (MonoString *me, MonoString *oldValue, MonoString *newValue)
242 g_warning("mono_string_InternalReplaceStr not impl");
243 return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
247 mono_string_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
254 srclen = mono_string_length(me);
255 ret = mono_string_InternalAllocateStr(srclen - count);
257 src = mono_string_chars(me);
258 dest = mono_string_chars(ret);
260 memcpy(dest, src, sindex * sizeof(gunichar2));
261 memcpy(dest + sindex, src + sindex + count, (srclen - count - sindex) * sizeof(gunichar2));
267 mono_string_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
269 gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
270 gunichar2 *src = mono_string_chars(me);
272 memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
276 mono_string_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
281 gint32 arrsize, srcsize, splitsize;
282 gint32 i, lastpos, arrpos;
284 gunichar2 *tmpstrptr;
288 src = mono_string_chars(me);
289 srcsize = mono_string_length(me);
290 arrsize = mono_array_length(separator);
292 cmpchar = mono_array_get(separator, gunichar2, 0);
295 for (i = 0; i != srcsize && splitsize < count; i++) {
296 if (mono_string_isinarray(separator, arrsize, src[i]))
303 /* if no split chars found return the string */
304 if (splitsize == 0) {
305 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, 1);
306 tmpstr = mono_string_InternalAllocateStr(srcsize);
307 tmpstrptr = mono_string_chars(tmpstr);
309 memcpy(tmpstrptr, src, srcsize * sizeof(gunichar2));
310 mono_array_set(retarr, MonoString *, 0, tmpstr);
315 if (splitsize + 1 < count)
318 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, splitsize);
319 for (i = 0; i != srcsize && arrpos != count; i++) {
320 if (mono_string_isinarray(separator, arrsize, src[i])) {
321 if (arrpos == count - 1)
322 tmpstrsize = srcsize - lastpos;
324 tmpstrsize = i - lastpos;
326 tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
327 tmpstrptr = mono_string_chars(tmpstr);
329 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
330 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
336 if (arrpos < count) {
337 tmpstrsize = srcsize - lastpos;
338 tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
339 tmpstrptr = mono_string_chars(tmpstr);
341 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
342 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
349 mono_string_isinarray (MonoArray *chars, gint32 arraylength, gunichar2 chr)
354 for (arrpos = 0; arrpos != arraylength; arrpos++) {
355 cmpchar = mono_array_get(chars, gunichar2, arrpos);
356 if (mono_string_cmp_char(cmpchar, chr, 1) == 0)
364 mono_string_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
367 gunichar2 *src, *dest;
368 gint32 srclen, newlen, arrlen;
369 gint32 i, lenfirst, lenlast;
371 srclen = mono_string_length(me);
372 src = mono_string_chars(me);
373 arrlen = mono_array_length(chars);
378 if (0 == typ || 1 == typ) {
379 for (i = 0; i != srclen; i++) {
380 if (mono_string_isinarray(chars, arrlen, src[i]))
387 if (0 == typ || 2 == typ) {
388 for (i = srclen - 1; i > lenfirst - 1; i--) {
389 if (mono_string_isinarray(chars, arrlen, src[i]))
396 newlen = srclen - lenfirst - lenlast;
398 ret = mono_string_InternalAllocateStr(newlen);
399 dest = mono_string_chars(ret);
401 memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
407 mono_string_InternalIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
412 src = mono_string_chars(me);
413 for (pos = sindex; pos != count + sindex; pos++) {
414 if ( src [pos] == value)
422 mono_string_InternalIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
429 lencmpstr = mono_string_length(value);
431 src = mono_string_chars(me);
432 cmpstr = mono_string_chars(value);
434 for (pos = sindex; pos != count + sindex; pos++) {
435 if (pos + lencmpstr > count + sindex)
438 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
446 mono_string_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
453 arraysize = mono_array_length(arr);
454 src = mono_string_chars(me);
456 for (pos = sindex; pos != count + sindex; pos++) {
457 for (loop = 0; loop != arraysize; loop++)
458 if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
466 mono_string_InternalLastIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
471 src = mono_string_chars(me);
472 for (pos = sindex; pos > sindex - count; pos--) {
473 if (src [pos] == value)
481 mono_string_InternalLastIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
488 lencmpstr = mono_string_length(value);
490 src = mono_string_chars(me);
491 cmpstr = mono_string_chars(value);
493 for (pos = sindex - lencmpstr + 1; pos > sindex - count; pos--) {
494 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
502 mono_string_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
509 arraysize = mono_array_length(anyOf);
510 src = mono_string_chars(me);
512 for (pos = sindex; pos > sindex - count; pos--) {
513 for (loop = 0; loop != arraysize; loop++)
514 if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
522 mono_string_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
531 srclen = mono_string_length(me);
532 src = mono_string_chars(me);
534 ret = mono_string_InternalAllocateStr(width);
535 dest = mono_string_chars(ret);
536 fillcount = width - srclen;
539 memcpy(dest, src, srclen * sizeof(gunichar2));
540 for (i = srclen; i != width; i++)
547 for (i = 0; i != fillcount; i++)
550 memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
556 mono_string_InternalToLower (MonoString *me)
563 ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
565 src = mono_string_chars (me);
566 dest = mono_string_chars (ret);
568 for (i = 0; i < mono_string_length (me); ++i)
569 dest[i] = g_unichar_tolower(src[i]);
575 mono_string_InternalToUpper (MonoString *me)
582 ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
584 src = mono_string_chars (me);
585 dest = mono_string_chars (ret);
587 for (i = 0; i < mono_string_length (me); ++i)
588 dest[i] = g_unichar_toupper(src[i]);
594 mono_string_InternalAllocateStr(gint32 length)
596 return mono_string_new_size(mono_domain_get (), length);
600 mono_string_InternalStrcpyStr (MonoString *dest, gint32 destPos, MonoString *src)
605 srcptr = mono_string_chars (src);
606 destptr = mono_string_chars (dest);
608 memcpy(destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
612 mono_string_InternalStrcpyStrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
617 srcptr = mono_string_chars (src);
618 destptr = mono_string_chars (dest);
619 memcpy(destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
623 mono_string_InternalIntern (MonoString *str)
625 return mono_string_intern(str);
629 mono_string_InternalIsInterned (MonoString *str)
631 return mono_string_is_interned(str);
635 mono_string_InternalCompareStrN (MonoString *s1, gint32 i1, MonoString *s2, gint32 i2, gint32 length, MonoBoolean inCase)
637 /* c translation of C# code.. :)
653 lenstr1 = mono_string_length(s1);
654 lenstr2 = mono_string_length(s2);
656 str1 = mono_string_chars(s1);
657 str2 = mono_string_chars(s2);
661 for (pos = 0; pos != length; pos++) {
662 if (i1 + pos >= lenstr1 || i2 + pos >= lenstr2)
665 charcmp = mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
670 /* the lesser wins, so if we have looped until length we just need to check the last char */
672 return mono_string_cmp_char(str1[i1 + pos - 1], str2[i2 + pos - 1], mode);
675 /* Test if one the strings has been compared to the end */
676 if (i1 + pos >= lenstr1) {
677 if (i2 + pos >= lenstr2)
681 } else if (i2 + pos >= lenstr2)
684 /* if not, check our last char only.. (can this happen?) */
685 return mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
689 mono_string_GetHashCode (MonoString *me)
692 gunichar2 *data = mono_string_chars (me);
694 for (i = 0; i < mono_string_length (me); ++i)
695 h = (h << 5) - h + data [i];
701 mono_string_get_Chars (MonoString *me, gint32 idx)
703 return mono_string_chars(me)[idx];
706 /* @mode : 0 = StringCompareModeDirect
707 1 = StringCompareModeCaseInsensitive
708 2 = StringCompareModeOrdinal
711 mono_string_cmp_char (gunichar2 c1, gunichar2 c2, gint16 mode)
714 GUnicodeType c1type, c2type;
716 c1type = g_unichar_type (c1);
717 c2type = g_unichar_type (c2);
720 /* TODO: compare with culture info */
721 if (c1type == G_UNICODE_UPPERCASE_LETTER && c2type == G_UNICODE_LOWERCASE_LETTER)
724 if (c1type == G_UNICODE_LOWERCASE_LETTER && c2type == G_UNICODE_UPPERCASE_LETTER)
727 result = (gint32) c1 - c2;
730 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) -
731 (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
733 /* fix: compare ordinal */
735 result = (gint32) g_unichar_tolower(c1) - g_unichar_tolower(c2);
739 return ((result < 0) ? -1 : (result > 0) ? 1 : 0);