ee6cb330c0897bf8d350a18814168676adeda14f
[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  *   Duncan Mak  (duncan@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/string-icalls.h>
16 #include <mono/metadata/class-internals.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/debug-helpers.h>
23
24 /* Internal helper methods */
25
26 static gboolean
27 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
28
29 /* This function is redirected to String.CreateString ()
30    by mono_marshal_get_native_wrapper () */
31 void
32 ves_icall_System_String_ctor_RedirectToCreateString (void)
33 {
34         g_assert_not_reached ();
35 }
36
37 MonoString * 
38 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
39 {
40         MonoString * ret;
41         MonoString *current;
42         gint32 length;
43         gint32 pos;
44         gint32 insertlen;
45         gint32 destpos;
46         gint32 srclen;
47         gunichar2 *insert;
48         gunichar2 *dest;
49         gunichar2 *src;
50
51         MONO_ARCH_SAVE_REGS;
52
53         insert = mono_string_chars(separator);
54         insertlen = mono_string_length(separator);
55
56         length = 0;
57         for (pos = sindex; pos != sindex + count; pos++) {
58                 current = mono_array_get (value, MonoString *, pos);
59                 if (current != NULL)
60                         length += mono_string_length (current);
61
62                 if (pos < sindex + count - 1)
63                         length += insertlen;
64         }
65
66         ret = mono_string_new_size( mono_domain_get (), length);
67         dest = mono_string_chars(ret);
68         destpos = 0;
69
70         for (pos = sindex; pos != sindex + count; pos++) {
71                 current = mono_array_get (value, MonoString *, pos);
72                 if (current != NULL) {
73                         src = mono_string_chars (current);
74                         srclen = mono_string_length (current);
75
76                         memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
77                         destpos += srclen;
78                 }
79
80                 if (pos < sindex + count - 1) {
81                         memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
82                         destpos += insertlen;
83                 }
84         }
85
86         return ret;
87 }
88
89 void
90 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
91 {
92         gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
93         gunichar2 *src =  mono_string_chars(me);
94
95         MONO_ARCH_SAVE_REGS;
96
97         memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
98 }
99
100 MonoArray * 
101 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count)
102 {
103         MonoString * tmpstr;
104         MonoArray * retarr;
105         gunichar2 *src;
106         gint32 arrsize, srcsize, splitsize;
107         gint32 i, lastpos, arrpos;
108         gint32 tmpstrsize;
109         gunichar2 *tmpstrptr;
110
111         gunichar2 cmpchar;
112
113         MONO_ARCH_SAVE_REGS;
114
115         src = mono_string_chars(me);
116         srcsize = mono_string_length(me);
117         arrsize = mono_array_length(separator);
118
119         cmpchar = mono_array_get(separator, gunichar2, 0);
120
121         splitsize = 0;
122         for (i = 0; i != srcsize && splitsize < count; i++) {
123                 if (string_icall_is_in_array(separator, arrsize, src[i]))
124                         splitsize++;
125         }
126
127         lastpos = 0;
128         arrpos = 0;
129
130         /* if no split chars found return the string */
131         if (splitsize == 0) {
132                 retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), 1);
133                 mono_array_setref (retarr, 0, me);
134
135                 return retarr;
136         }
137
138         if (splitsize != count)
139                 splitsize++;
140
141         retarr = mono_array_new(mono_domain_get(), mono_get_string_class (), splitsize);
142         for (i = 0; i != srcsize && arrpos != count; i++) {
143                 if (string_icall_is_in_array(separator, arrsize, src[i])) {
144                         if (arrpos == count - 1)
145                                 tmpstrsize = srcsize - lastpos;
146                         else
147                                 tmpstrsize = i - lastpos;
148
149                         tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
150                         tmpstrptr = mono_string_chars(tmpstr);
151
152                         memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
153                         mono_array_setref (retarr, arrpos, tmpstr);
154                         arrpos++;
155                         lastpos = i + 1;
156                 }
157         }
158
159         if (arrpos < count) {
160                 tmpstrsize = srcsize - lastpos;
161                 tmpstr = mono_string_new_size( mono_domain_get (), tmpstrsize);
162                 tmpstrptr = mono_string_chars(tmpstr);
163
164                 memcpy(tmpstrptr, src + lastpos, tmpstrsize * sizeof(gunichar2));
165                 mono_array_setref (retarr, arrpos, tmpstr);
166         }
167
168         return retarr;
169 }
170
171 static gboolean
172 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
173 {
174         gunichar2 cmpchar;
175         gint32 arrpos;
176
177         for (arrpos = 0; arrpos != arraylength; arrpos++) {
178                 cmpchar = mono_array_get(chars, gunichar2, arrpos);
179                 if (cmpchar == chr)
180                         return TRUE;
181         }
182         
183         return FALSE;
184 }
185
186 MonoString * 
187 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
188 {
189         MonoString * ret;
190         gunichar2 *src, *dest;
191         gint32 srclen, newlen, arrlen;
192         gint32 i, lenfirst, lenlast;
193
194         MONO_ARCH_SAVE_REGS;
195
196         srclen = mono_string_length(me);
197         src = mono_string_chars(me);
198         arrlen = mono_array_length(chars);
199
200         lenfirst = 0;
201         lenlast = 0;
202
203         if (0 == typ || 1 == typ) {
204                 for (i = 0; i != srclen; i++) {
205                         if (string_icall_is_in_array(chars, arrlen, src[i]))
206                                 lenfirst++;
207                         else 
208                                 break;
209                 }
210         }
211
212         if (0 == typ || 2 == typ) {
213                 for (i = srclen - 1; i > lenfirst - 1; i--) {
214                         if (string_icall_is_in_array(chars, arrlen, src[i]))
215                                 lenlast++;
216                         else 
217                                 break;
218                 }
219         }
220
221         newlen = srclen - lenfirst - lenlast;
222         if (newlen == srclen)
223                 return me;
224
225         ret = mono_string_new_size( mono_domain_get (), newlen);
226         dest = mono_string_chars(ret);
227
228         memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
229
230         return ret;
231 }
232
233 gint32 
234 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
235 {
236         gint32 pos;
237         gint32 loop;
238         gint32 arraysize;
239         gunichar2 *src;
240
241         MONO_ARCH_SAVE_REGS;
242
243         arraysize = mono_array_length(anyOf);
244         src = mono_string_chars(me);
245
246         for (pos = sindex; pos > sindex - count; pos--) {
247                 for (loop = 0; loop != arraysize; loop++)
248                         if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
249                                 return pos;
250         }
251
252         return -1;
253 }
254
255 MonoString *
256 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
257 {
258         MonoString * ret;
259         gunichar2 *src;
260         gunichar2 *dest;
261         gint32 fillcount;
262         gint32 srclen;
263         gint32 i;
264
265         MONO_ARCH_SAVE_REGS;
266
267         srclen = mono_string_length(me);
268         src = mono_string_chars(me);
269
270         ret = mono_string_new_size( mono_domain_get (), width);
271         dest = mono_string_chars(ret);
272         fillcount = width - srclen;
273
274         if (right) {
275                 memcpy(dest, src, srclen * sizeof(gunichar2));
276                 for (i = srclen; i != width; i++)
277                         dest[i] = chr;
278
279                 return ret;
280         }
281
282         /* left fill */
283         for (i = 0; i != fillcount; i++)
284                 dest[i] = chr;
285
286         memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
287
288         return ret;
289 }
290
291 MonoString *
292 ves_icall_System_String_InternalAllocateStr (gint32 length)
293 {
294         MONO_ARCH_SAVE_REGS;
295
296         return mono_string_new_size(mono_domain_get (), length);
297 }
298
299 void 
300 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
301 {
302         gunichar2 *srcptr;
303         gunichar2 *destptr;
304
305         MONO_ARCH_SAVE_REGS;
306
307         srcptr = mono_string_chars (src);
308         destptr = mono_string_chars (dest);
309
310         g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
311 }
312
313 void 
314 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
315 {
316         gunichar2 *srcptr;
317         gunichar2 *destptr;
318
319         MONO_ARCH_SAVE_REGS;
320
321         srcptr = mono_string_chars (src);
322         destptr = mono_string_chars (dest);
323         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
324 }
325
326 void 
327 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
328 {
329         gunichar2 *srcptr;
330         gunichar2 *destptr;
331
332         MONO_ARCH_SAVE_REGS;
333
334         srcptr = mono_array_addr (src, gunichar2, 0);
335         destptr = mono_string_chars (dest);
336
337         g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
338 }
339
340 void 
341 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
342 {
343         gunichar2 *srcptr;
344         gunichar2 *destptr;
345
346         MONO_ARCH_SAVE_REGS;
347
348         srcptr = mono_array_addr (src, gunichar2, 0);
349         destptr = mono_string_chars (dest);
350
351         g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
352 }
353
354 MonoString  *
355 ves_icall_System_String_InternalIntern (MonoString *str)
356 {
357         MONO_ARCH_SAVE_REGS;
358
359         return mono_string_intern(str);
360 }
361
362 MonoString * 
363 ves_icall_System_String_InternalIsInterned (MonoString *str)
364 {
365         MONO_ARCH_SAVE_REGS;
366
367         return mono_string_is_interned(str);
368 }
369
370 gunichar2 
371 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
372 {
373         MONO_ARCH_SAVE_REGS;
374
375         if ((idx < 0) || (idx >= mono_string_length (me)))
376                 mono_raise_exception (mono_get_exception_index_out_of_range ());
377         return mono_string_chars(me)[idx];
378 }
379