2002-04-17 Patrik Torstensson <patrik.torstensson@labs2.com>
[mono.git] / mono / metadata / string-icalls.c
1 /*
2  * string-icalls.c: String internal calls for the corlib
3  *
4  * Author:
5  *   Patrik Torstensson (patrik.torstensson@labs2.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <string.h>
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>
21
22 MonoString *
23 mono_string_Internal_ctor_charp (gpointer dummy, gunichar2 *value)
24 {
25         gint32 i, length;
26         MonoDomain *domain;
27
28         domain = mono_domain_get ();
29
30         if (value == NULL)
31                 length = 0;
32         else {
33                 for (i = 0; *(value + i) != '\0'; i++);
34                 length = i;
35         }
36
37         return mono_string_new_utf16 (domain, value, length);
38 }
39
40 MonoString *
41 mono_string_Internal_ctor_char_int (gpointer dummy, gunichar2 value, gint32 count)
42 {
43         MonoDomain *domain;
44         MonoString *res;
45         gunichar2 *chars;
46         gint32 i;
47
48         domain = mono_domain_get ();
49         res = mono_string_new_size (domain, count);
50
51         chars = mono_string_chars (res);
52         for (i = 0; i < count; i++)
53                 chars [i] = value;
54         
55         return res;
56 }
57
58 MonoString *
59 mono_string_Internal_ctor_charp_int_int (gpointer dummy, gunichar2 *value, gint32 sindex, gint32 length)
60 {
61         gunichar2 *begin;
62         MonoDomain * domain;
63         
64         domain = mono_domain_get ();
65
66         if ((value == NULL) && (sindex != 0) && (length != 0))
67                 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
68
69         if ((sindex < 0) || (length < 0))
70                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
71         
72         begin = (gunichar2 *) (value + sindex);
73
74         return mono_string_new_utf16 (domain, begin, length);
75 }
76
77 MonoString *
78 mono_string_Internal_ctor_sbytep (gpointer dummy, gint8 *value)
79 {
80         int i, length;
81         MonoDomain *domain;
82         
83         domain = mono_domain_get ();
84
85         if (value == NULL)
86                 length = 0;
87         else {
88                 for (i = 0; *(value + i) != '\0'; i++);
89                 length = i;
90         }
91
92         return mono_string_new_utf16 (domain, (gunichar2 *) value, length);
93 }
94
95 MonoString *
96 mono_string_Internal_ctor_sbytep_int_int (gpointer dummy, gint8 *value, gint32 sindex, gint32 length)
97 {
98         gunichar2 *begin;
99         MonoDomain *domain;
100         
101         domain = mono_domain_get ();
102
103         if ((value == NULL) && (sindex != 0) && (length != 0))
104                 mono_raise_exception (mono_get_exception_argument_null ("Argument null"));
105
106         if ((sindex > 0) || (length < 0))
107                 mono_raise_exception (mono_get_exception_argument_out_of_range ("Out of range"));
108
109         begin = (gunichar2 *) (value + sindex);
110
111         return mono_string_new_utf16 (domain, begin, length);
112 }
113
114 MonoString *
115 mono_string_Internal_ctor_chara (gpointer dummy, MonoArray *value)
116 {
117         MonoDomain *domain;
118
119         MONO_CHECK_ARG_NULL (value);
120         
121         domain = mono_domain_get ();
122         
123         return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, 0),  value->max_length);
124 }
125
126 MonoString *
127 mono_string_Internal_ctor_chara_int_int (gpointer dummy, MonoArray *value, 
128                                          gint32 sindex, gint32 length)
129 {
130         MonoDomain *domain;
131
132         MONO_CHECK_ARG_NULL (value);
133
134         domain = ((MonoObject *) value)->vtable->domain;
135         
136         return mono_string_new_utf16 (domain, (gunichar2 *) mono_array_addr(value, gunichar2, sindex), length);
137 }
138
139 MonoString *
140 mono_string_Internal_ctor_encoding (gpointer dummy, gint8 *value, gint32 sindex, 
141                                     gint32 length, MonoObject *enc)
142 {
143         g_assert_not_reached ();
144         return NULL;
145 }
146
147 MonoString * 
148 mono_string_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
149 {
150         MonoString * ret;
151         gint32 length;
152         gint32 pos;
153         gint32 insertlen;
154         gint32 destpos;
155         gint32 srclen;
156         gunichar2 *insert;
157         gunichar2 *dest;
158         gunichar2 *src;
159
160         insert = mono_string_chars(separator);
161         insertlen = mono_string_length(separator);
162
163         length = 0;
164         for (pos = sindex; pos != sindex + count; pos++) {
165                 length += mono_string_length(mono_array_get(value, MonoString *, pos));
166                 if (pos < sindex + count - 1)
167                         length += insertlen;
168         }
169
170         ret = mono_string_InternalAllocateStr(length);
171         dest = mono_string_chars(ret);
172         destpos = 0;
173
174         for (pos = sindex; pos != sindex + count; pos++) {
175                 src = mono_string_chars(mono_array_get(value, MonoString *, pos));
176                 srclen = mono_string_length(mono_array_get(value, MonoString *, pos));
177
178                 memcpy(dest + destpos, src, srclen * sizeof(gunichar2));
179                 destpos += srclen;
180
181                 if (pos < sindex + count - 1) {
182                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
183                         destpos += insertlen;
184                 }
185         }
186
187         return ret;
188 }
189
190 MonoString * 
191 mono_string_InternalInsert (MonoString *me, gint32 sindex, MonoString *value)
192 {
193         MonoString * ret;
194         gunichar2 *src;
195         gunichar2 *insertsrc;
196         gunichar2 *dest;
197         gint32 srclen;
198         gint32 insertlen;
199
200         src = mono_string_chars(me);
201         srclen = mono_string_length(me);
202
203         insertsrc = mono_string_chars(value);
204         insertlen = mono_string_length(value);
205
206         ret = mono_string_InternalAllocateStr(mono_string_length(me) + insertlen);
207         dest = mono_string_chars(ret);
208
209         memcpy(dest, src, sindex * sizeof(gunichar2));
210         memcpy(dest + sindex, insertsrc, insertlen * sizeof(gunichar2));
211         memcpy(dest + sindex + insertlen, src + sindex, (srclen - sindex) * sizeof(gunichar2));
212
213         return ret;
214 }
215
216 MonoString * 
217 mono_string_InternalReplaceChar (MonoString *me, gunichar2 oldChar, gunichar2 newChar)
218 {
219         g_warning("mono_string_InternalReplaceChar not impl");
220         return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
221 }
222
223 MonoString * 
224 mono_string_InternalReplaceStr (MonoString *me, MonoString *oldValue, MonoString *newValue)
225 {
226         g_warning("mono_string_InternalReplaceStr not impl");
227         return mono_string_new_utf16(mono_domain_get(), mono_string_chars(me), mono_string_length(me));
228 }
229
230 MonoString * 
231 mono_string_InternalRemove (MonoString *me, gint32 sindex, gint32 count)
232 {
233         MonoString * ret;
234         gint32 count_bytes;
235         gint32 index_bytes;
236         gint32 me_bytes;
237         gunichar2 *dest;
238         gunichar2 *src;
239
240         me_bytes = mono_string_length(me);
241         ret = mono_string_InternalAllocateStr(me_bytes - count);
242         index_bytes = sindex * sizeof(gunichar2);
243         count_bytes = count * sizeof(gunichar2);
244
245         src = mono_string_chars(me);
246         dest = mono_string_chars(ret);
247
248         memcpy(dest, src, index_bytes);
249         memcpy(dest + sindex, src + sindex + count, me_bytes - count_bytes);
250
251         return ret;
252 }
253
254 void
255 mono_string_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
256 {
257         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
258         gunichar2 *src =  mono_string_chars(me);
259
260         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
261 }
262
263 MonoArray * 
264 mono_string_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
265 {
266         MonoString * tmpstr;
267         MonoArray * retarr;
268         gunichar2 *src;
269         gint32 arrsize, srcsize, splitsize;
270         gint32 i, lastpos, arrpos;
271         gint32 tmpstrsize;
272         gunichar2 *tmpstrptr;
273
274         src = mono_string_chars(me);
275         srcsize = mono_string_length(me);
276         arrsize = mono_array_length(separator);
277
278         splitsize = 0;
279         for (i = 0; i != srcsize && splitsize < count; i++) {
280                 if (mono_string_isinarray(separator, arrsize, src[i]))
281                         splitsize++;
282         }
283
284         lastpos = 0;
285         arrpos = 0;
286
287         /* if no split chars found return the string */
288         if (splitsize == 0) {
289                 retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, 1);
290                 tmpstr = mono_string_InternalAllocateStr(srcsize);
291                 tmpstrptr = mono_string_chars(tmpstr);
292
293                 memcpy(tmpstrptr, src, srcsize * sizeof(gunichar2));
294                 mono_array_set(retarr, MonoString *, 0, tmpstr);
295
296                 return retarr;
297         }
298
299         if (splitsize + 1 < count)
300                 splitsize++;
301
302         retarr = mono_array_new(mono_domain_get(), mono_defaults.string_class, splitsize);
303         for (i = 0; i != srcsize && arrpos != count; i++) {
304                 if (mono_string_isinarray(separator, arrsize, src[i])) {
305                         if (arrpos == count - 1)
306                                 tmpstrsize = srcsize - lastpos;
307                         else
308                                 tmpstrsize = i - lastpos;
309
310                         tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
311                         tmpstrptr = mono_string_chars(tmpstr);
312
313                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
314                         mono_array_set(retarr, MonoString *, arrpos, tmpstr);
315                         arrpos++;
316                         lastpos = i + 1;
317                 }
318         }
319
320         if (arrpos < count) {
321                 tmpstrsize = srcsize - lastpos;
322                 tmpstr = mono_string_InternalAllocateStr(tmpstrsize);
323                 tmpstrptr = mono_string_chars(tmpstr);
324
325                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
326                 mono_array_set(retarr, MonoString *, arrpos, tmpstr);
327         }
328         
329         return retarr;
330 }
331
332 gboolean
333 mono_string_isinarray (MonoArray *chars, gint32 arraylength, gunichar2 chr)
334 {
335         gunichar2 cmpchar;
336         gint32 arrpos;
337
338         for (arrpos = 0; arrpos != arraylength; arrpos++) {
339                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
340                 if (mono_string_cmp_char(cmpchar, chr, 1) == 0)
341                         return TRUE;
342         }
343         
344         return FALSE;
345 }
346
347 MonoString * 
348 mono_string_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
349 {
350         MonoString * ret;
351         gunichar2 *src, *dest;
352         gint32 srclen, newlen, arrlen;
353         gint32 i, lenfirst, lenlast;
354
355         srclen = mono_string_length(me);
356         src = mono_string_chars(me);
357         arrlen = mono_array_length(chars);
358
359         lenfirst = 0;
360         lenlast = 0;
361
362         if (0 == typ || 1 == typ) {
363                 for (i = 0; i != srclen; i++) {
364                         if (mono_string_isinarray(chars, arrlen, src[i]))
365                                 lenfirst++;
366                         else 
367                                 break;
368                 }
369         }
370
371         if (0 == typ || 2 == typ) {
372                 for (i = srclen - 1; i > lenfirst - 1; i--) {
373                         if (mono_string_isinarray(chars, arrlen, src[i]))
374                                 lenlast++;
375                         else 
376                                 break;
377                 }
378         }
379
380         newlen = srclen - lenfirst - lenlast;
381
382         ret = mono_string_InternalAllocateStr(newlen);
383         dest = mono_string_chars(ret);
384
385         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
386
387         return ret;
388 }
389
390 gint32 
391 mono_string_InternalIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
392 {
393         gint32 pos;
394         gunichar2 *src;
395
396         src = mono_string_chars(me);
397         for (pos = sindex; pos != count + sindex; pos++) {
398                 if ( src [pos] == value)
399                         return pos;
400         }
401
402         return -1;
403 }
404
405 gint32 
406 mono_string_InternalIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
407 {
408         gint32 lencmpstr;
409         gint32 pos;
410         gunichar2 *src;
411         gunichar2 *cmpstr;
412
413         lencmpstr = mono_string_length(value);
414
415         src = mono_string_chars(me);
416         cmpstr = mono_string_chars(value);
417
418         for (pos = sindex; pos != count + sindex; pos++) {
419                 if (pos + lencmpstr > count + sindex)
420                         return -1;
421
422                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
423                         return pos;
424         }
425
426         return -1;
427 }
428
429 gint32 
430 mono_string_InternalIndexOfAny (MonoString *me, MonoArray *arr, gint32 sindex, gint32 count)
431 {
432         gint32 pos;
433         gint32 loop;
434         gint32 arraysize;
435         gunichar2 *src;
436
437         arraysize = mono_array_length(arr);
438         src = mono_string_chars(me);
439
440         for (pos = sindex; pos != count + sindex; pos++) {
441                 for (loop = 0; loop != arraysize; loop++)
442                         if ( src [pos] == mono_array_get(arr, gunichar2, loop) )
443                                 return pos;
444         }
445
446         return -1;
447 }
448
449 gint32 
450 mono_string_InternalLastIndexOfChar (MonoString *me, gunichar2 value, gint32 sindex, gint32 count)
451 {
452         gint32 pos;
453         gunichar2 *src;
454
455         src = mono_string_chars(me);
456         for (pos = sindex; pos > sindex - count; pos--) {
457                 if (src [pos] == value)
458                         return pos;
459         }
460
461         return -1;
462 }
463
464 gint32 
465 mono_string_InternalLastIndexOfStr (MonoString *me, MonoString *value, gint32 sindex, gint32 count)
466 {
467         gint32 lencmpstr;
468         gint32 pos;
469         gunichar2 *src;
470         gunichar2 *cmpstr;
471
472         lencmpstr = mono_string_length(value);
473
474         src = mono_string_chars(me);
475         cmpstr = mono_string_chars(value);
476
477         for (pos = sindex; pos > sindex - count; pos--) {
478                 if (0 == memcmp(src + pos, cmpstr, lencmpstr * sizeof(gunichar2)))
479                         return pos;
480         }
481
482         return -1;
483 }
484
485 gint32 
486 mono_string_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
487 {
488         gint32 pos;
489         gint32 loop;
490         gint32 arraysize;
491         gunichar2 *src;
492
493         arraysize = mono_array_length(anyOf);
494         src = mono_string_chars(me);
495
496         for (pos = sindex; pos > sindex - count; pos--) {
497                 for (loop = 0; loop != arraysize; loop++)
498                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
499                                 return pos;
500         }
501
502         return -1;
503 }
504
505 MonoString *
506 mono_string_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
507 {
508         MonoString * ret;
509         gunichar2 *src;
510         gunichar2 *dest;
511         gint32 fillcount;
512         gint32 srclen;
513         gint32 i;
514
515         srclen = mono_string_length(me);
516         src = mono_string_chars(me);
517
518         ret = mono_string_InternalAllocateStr(width);
519         dest = mono_string_chars(ret);
520         fillcount = width - srclen;
521
522         if (right) {
523                 memcpy(dest, src, srclen * sizeof(gunichar2));
524                 for (i = srclen; i != width; i++)
525                         dest[i] = chr;
526
527                 return ret;
528         }
529
530         /* left fill */
531         for (i = 0; i != fillcount; i++)
532                 dest[i] = chr;
533
534         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
535
536         return ret;
537 }
538
539 MonoString *
540 mono_string_InternalToLower (MonoString *me)
541 {
542         MonoString * ret;
543         gunichar2 *src; 
544         gunichar2 *dest;
545         gint32 i;
546
547         ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
548
549         src = mono_string_chars (me);
550         dest = mono_string_chars (ret);
551
552         for (i = 0; i < mono_string_length (me); ++i)
553                 dest[i] = g_unichar_tolower(src[i]);
554
555         return ret;
556 }
557
558 MonoString *
559 mono_string_InternalToUpper (MonoString *me)
560 {
561         int i;
562         MonoString * ret;
563         gunichar2 *src; 
564         gunichar2 *dest;
565
566         ret = mono_string_new_size(mono_domain_get (), mono_string_length(me));
567
568         src = mono_string_chars (me);
569         dest = mono_string_chars (ret);
570
571         for (i = 0; i < mono_string_length (me); ++i)
572                 dest[i] = g_unichar_toupper(src[i]);
573
574         return ret;
575 }
576
577 MonoString *
578 mono_string_InternalAllocateStr(gint32 length)
579 {
580         return mono_string_new_size(mono_domain_get (), length);
581 }
582
583 void 
584 mono_string_InternalStrcpyStr (MonoString *dest, gint32 destPos, MonoString *src)
585 {
586         gunichar2 *srcptr;
587         gunichar2 *destptr;
588
589         srcptr = mono_string_chars (src);
590         destptr = mono_string_chars (dest);
591
592         memcpy(destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
593 }
594
595 void 
596 mono_string_InternalStrcpyStrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
597 {
598         gunichar2 *srcptr;
599         gunichar2 *destptr;
600
601         srcptr = mono_string_chars (src);
602         destptr = mono_string_chars (dest);
603         memcpy(destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
604 }
605
606 MonoString  *
607 mono_string_InternalIntern (MonoString *str)
608 {
609         return mono_string_intern(str);
610 }
611
612 MonoString * 
613 mono_string_InternalIsInterned (MonoString *str)
614 {
615         return mono_string_is_interned(str);
616 }
617
618 gint32
619 mono_string_InternalCompareStrN (MonoString *s1, gint32 i1, MonoString *s2, gint32 i2, gint32 length, MonoBoolean inCase)
620 {
621         /* c translation of C# code.. :)
622         */
623         gint32 lenstr1;
624         gint32 lenstr2;
625         gint32 charcmp;
626         gunichar2 *str1;
627         gunichar2 *str2;
628
629         gint32 pos;
630         gint16 mode;
631         
632         if (inCase)
633                 mode = 1;
634         else
635                 mode = 0;
636
637         lenstr1 = mono_string_length(s1);
638         lenstr2 = mono_string_length(s2);
639
640         str1 = mono_string_chars(s1);
641         str2 = mono_string_chars(s2);
642
643         pos = 0;
644
645         for (pos = 0; pos != length; pos++) {
646                 if (i1 + pos >= lenstr1 || i2 + pos >= lenstr2)
647                         break;
648
649                 charcmp = mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
650                 if (charcmp != 0)
651                         return charcmp;
652         }
653
654         /* the lesser wins, so if we have looped until length we just need to check the last char */
655         if (pos == length) {
656                 return mono_string_cmp_char(str1[i1 + pos - 1], str2[i2 + pos - 1], mode);
657         }
658
659         /* Test if one the strings has been compared to the end */
660         if (i1 + pos >= lenstr1) {
661                 if (i2 + pos >= lenstr2)
662                         return 0;
663                 else
664                         return -1;
665         } else if (i2 + pos >= lenstr2)
666                 return 1;
667
668         /* if not, check our last char only.. (can this happen?) */
669         return mono_string_cmp_char(str1[i1 + pos], str2[i2 + pos], mode);
670 }
671
672 gint32
673 mono_string_GetHashCode (MonoString *me)
674 {
675         int i, h = 0;
676         gunichar2 *data = mono_string_chars (me);
677
678         for (i = 0; i < mono_string_length (me); ++i)
679                 h = (h << 5) - h + data [i];
680
681         return h;
682 }
683
684 gunichar2 
685 mono_string_get_Chars (MonoString *me, gint32 idx)
686 {
687         return mono_string_chars(me)[idx];
688 }
689
690 /* @mode :      0 = StringCompareModeDirect
691                         1 = StringCompareModeCaseInsensitive
692                         2 = StringCompareModeOrdinal
693 */
694 gint32 
695 mono_string_cmp_char (gunichar2 c1, gunichar2 c2, gint16 mode)
696 {
697         gint32 result;
698         GUnicodeType c1type, c2type;
699
700         c1type = g_unichar_type (c1);
701         c2type = g_unichar_type (c2);
702         switch (mode) {
703         case 0: 
704                 /* TODO: compare with culture info */
705                 if (c1type == G_UNICODE_UPPERCASE_LETTER && c2type == G_UNICODE_LOWERCASE_LETTER)
706                         return 1;
707                                         
708                 if (c1type == G_UNICODE_LOWERCASE_LETTER && c2type == G_UNICODE_UPPERCASE_LETTER)
709                         return -1;
710         
711                 result = (gint32) c1 - c2;
712                 break;
713         case 1: 
714                 result = (gint32) (c1type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c1) : c1) - 
715                                   (c2type != G_UNICODE_LOWERCASE_LETTER ? g_unichar_tolower(c2) : c2);
716                 break;
717                 /* fix: compare ordinal */
718         case 2: 
719                 result = (gint32) g_unichar_tolower(c1) - g_unichar_tolower(c2);
720                 break;
721         }
722
723         return ((result < 0) ? -1 : (result > 0) ? 1 : 0);
724 }