2009-03-11 Zoltan Varga <vargaz@gmail.com>
[mono-debugger.git] / mono / metadata / string-icalls.c
blob8a96afa7cc69a00e5c864b6ce77b76e3661d9878
1 /*
2 * string-icalls.c: String internal calls for the corlib
4 * Author:
5 * Patrik Torstensson (patrik.torstensson@labs2.com)
6 * Duncan Mak (duncan@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 #include <config.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <signal.h>
15 #include <string.h>
16 #include "mono/utils/mono-membar.h"
17 #include <mono/metadata/string-icalls.h>
18 #include <mono/metadata/class-internals.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/object.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/debug-helpers.h>
26 /* Internal helper methods */
28 static gboolean
29 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr);
31 /* This function is redirected to String.CreateString ()
32 by mono_marshal_get_native_wrapper () */
33 void
34 ves_icall_System_String_ctor_RedirectToCreateString (void)
36 g_assert_not_reached ();
39 MonoString *
40 ves_icall_System_String_InternalJoin (MonoString *separator, MonoArray * value, gint32 sindex, gint32 count)
42 MonoString * ret;
43 MonoString *current;
44 gint32 length;
45 gint32 pos;
46 gint32 insertlen;
47 gint32 destpos;
48 gint32 srclen;
49 gunichar2 *insert;
50 gunichar2 *dest;
51 gunichar2 *src;
53 MONO_ARCH_SAVE_REGS;
55 insert = mono_string_chars(separator);
56 insertlen = mono_string_length(separator);
58 length = 0;
59 for (pos = sindex; pos != sindex + count; pos++) {
60 current = mono_array_get (value, MonoString *, pos);
61 if (current != NULL)
62 length += mono_string_length (current);
64 if (pos < sindex + count - 1)
65 length += insertlen;
68 ret = mono_string_new_size( mono_domain_get (), length);
69 dest = mono_string_chars(ret);
70 destpos = 0;
72 for (pos = sindex; pos != sindex + count; pos++) {
73 current = mono_array_get (value, MonoString *, pos);
74 if (current != NULL) {
75 src = mono_string_chars (current);
76 srclen = mono_string_length (current);
78 memcpy (dest + destpos, src, srclen * sizeof(gunichar2));
79 destpos += srclen;
82 if (pos < sindex + count - 1) {
83 memcpy(dest + destpos, insert, insertlen * sizeof(gunichar2));
84 destpos += insertlen;
88 return ret;
91 void
92 ves_icall_System_String_InternalCopyTo (MonoString *me, gint32 sindex, MonoArray *dest, gint32 dindex, gint32 count)
94 gunichar2 *destptr = (gunichar2 *) mono_array_addr(dest, gunichar2, dindex);
95 gunichar2 *src = mono_string_chars(me);
97 MONO_ARCH_SAVE_REGS;
99 memcpy(destptr, src + sindex, sizeof(gunichar2) * count);
102 /* System.StringSplitOptions */
103 typedef enum {
104 STRINGSPLITOPTIONS_NONE = 0,
105 STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES = 1
106 } StringSplitOptions;
108 MonoArray *
109 ves_icall_System_String_InternalSplit (MonoString *me, MonoArray *separator, gint32 count, gint32 options)
111 static MonoClass *String_array;
112 MonoString * tmpstr;
113 MonoArray * retarr;
114 gunichar2 *src;
115 gint32 arrsize, srcsize, splitsize;
116 gint32 i, lastpos, arrpos;
117 gint32 tmpstrsize;
118 gint32 remempty;
119 gint32 flag;
120 gunichar2 *tmpstrptr;
122 remempty = options & STRINGSPLITOPTIONS_REMOVE_EMPTY_ENTRIES;
123 src = mono_string_chars (me);
124 srcsize = mono_string_length (me);
125 arrsize = mono_array_length (separator);
127 if (!String_array) {
128 MonoClass *klass = mono_array_class_get (mono_get_string_class (), 1);
129 mono_memory_barrier ();
130 String_array = klass;
133 splitsize = 1;
134 /* Count the number of elements we will return. Note that this operation
135 * guarantees that we will return exactly splitsize elements, and we will
136 * have enough data to fill each. This allows us to skip some checks later on.
138 if (remempty == 0) {
139 for (i = 0; i != srcsize && splitsize < count; i++) {
140 if (string_icall_is_in_array (separator, arrsize, src [i]))
141 splitsize++;
143 } else if (count > 1) {
144 /* Require pattern "Nondelim + Delim + Nondelim" to increment counter.
145 * Lastpos != 0 means first nondelim found.
146 * Flag = 0 means last char was delim.
147 * Efficient, though perhaps confusing.
149 lastpos = 0;
150 flag = 0;
151 for (i = 0; i != srcsize && splitsize < count; i++) {
152 if (string_icall_is_in_array (separator, arrsize, src [i])) {
153 flag = 0;
154 } else if (flag == 0) {
155 if (lastpos == 1)
156 splitsize++;
157 flag = 1;
158 lastpos = 1;
162 /* Nothing but separators */
163 if (lastpos == 0) {
164 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 0);
165 return retarr;
169 /* if no split chars found return the string */
170 if (splitsize == 1) {
171 if (remempty == 0 || count == 1) {
172 /* Copy the whole string */
173 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
174 mono_array_setref (retarr, 0, me);
175 } else {
176 /* otherwise we have to filter out leading & trailing delims */
178 /* find first non-delim char */
179 for (; srcsize != 0; srcsize--, src++) {
180 if (!string_icall_is_in_array (separator, arrsize, src [0]))
181 break;
183 /* find last non-delim char */
184 for (; srcsize != 0; srcsize--) {
185 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
186 break;
188 tmpstr = mono_string_new_size (mono_domain_get (), srcsize);
189 tmpstrptr = mono_string_chars (tmpstr);
191 memcpy (tmpstrptr, src, srcsize * sizeof (gunichar2));
192 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), 1);
193 mono_array_setref (retarr, 0, tmpstr);
195 return retarr;
198 lastpos = 0;
199 arrpos = 0;
201 retarr = mono_array_new_specific (mono_class_vtable (mono_domain_get (), String_array), splitsize);
203 for (i = 0; i != srcsize && arrpos != splitsize; i++) {
204 if (string_icall_is_in_array (separator, arrsize, src [i])) {
206 if (lastpos != i || remempty == 0) {
207 tmpstrsize = i - lastpos;
208 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
209 tmpstrptr = mono_string_chars (tmpstr);
211 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
212 mono_array_setref (retarr, arrpos, tmpstr);
213 arrpos++;
215 if (arrpos == splitsize - 1) {
216 /* Shortcut the last array element */
218 lastpos = i + 1;
219 if (remempty != 0) {
220 /* Search for non-delim starting char (guaranteed to find one) Note that loop
221 * condition is only there for safety. It will never actually terminate the loop. */
222 for (; lastpos != srcsize ; lastpos++) {
223 if (!string_icall_is_in_array (separator, arrsize, src [lastpos]))
224 break;
226 if (count > splitsize) {
227 /* Since we have fewer results than our limit, we must remove
228 * trailing delimiters as well.
230 for (; srcsize != lastpos + 1 ; srcsize--) {
231 if (!string_icall_is_in_array (separator, arrsize, src [srcsize - 1]))
232 break;
237 tmpstrsize = srcsize - lastpos;
238 tmpstr = mono_string_new_size (mono_domain_get (), tmpstrsize);
239 tmpstrptr = mono_string_chars (tmpstr);
241 memcpy (tmpstrptr, src + lastpos, tmpstrsize * sizeof (gunichar2));
242 mono_array_setref (retarr, arrpos, tmpstr);
244 /* Loop will ALWAYS end here. Test criteria in the FOR loop is technically unnecessary. */
245 break;
248 lastpos = i + 1;
252 return retarr;
255 static gboolean
256 string_icall_is_in_array (MonoArray *chars, gint32 arraylength, gunichar2 chr)
258 gunichar2 cmpchar;
259 gint32 arrpos;
261 for (arrpos = 0; arrpos != arraylength; arrpos++) {
262 cmpchar = mono_array_get(chars, gunichar2, arrpos);
263 if (cmpchar == chr)
264 return TRUE;
267 return FALSE;
270 MonoString *
271 ves_icall_System_String_InternalTrim (MonoString *me, MonoArray *chars, gint32 typ)
273 MonoString * ret;
274 gunichar2 *src, *dest;
275 gint32 srclen, newlen, arrlen;
276 gint32 i, lenfirst, lenlast;
278 MONO_ARCH_SAVE_REGS;
280 srclen = mono_string_length(me);
281 src = mono_string_chars(me);
282 arrlen = mono_array_length(chars);
284 lenfirst = 0;
285 lenlast = 0;
287 if (0 == typ || 1 == typ) {
288 for (i = 0; i != srclen; i++) {
289 if (string_icall_is_in_array(chars, arrlen, src[i]))
290 lenfirst++;
291 else
292 break;
296 if (0 == typ || 2 == typ) {
297 for (i = srclen - 1; i > lenfirst - 1; i--) {
298 if (string_icall_is_in_array(chars, arrlen, src[i]))
299 lenlast++;
300 else
301 break;
305 newlen = srclen - lenfirst - lenlast;
306 if (newlen == srclen)
307 return me;
309 ret = mono_string_new_size( mono_domain_get (), newlen);
310 dest = mono_string_chars(ret);
312 memcpy(dest, src + lenfirst, newlen *sizeof(gunichar2));
314 return ret;
317 gint32
318 ves_icall_System_String_InternalLastIndexOfAny (MonoString *me, MonoArray *anyOf, gint32 sindex, gint32 count)
320 gint32 pos;
321 gint32 loop;
322 gint32 arraysize;
323 gunichar2 *src;
325 MONO_ARCH_SAVE_REGS;
327 arraysize = mono_array_length(anyOf);
328 src = mono_string_chars(me);
330 for (pos = sindex; pos > sindex - count; pos--) {
331 for (loop = 0; loop != arraysize; loop++)
332 if ( src [pos] == mono_array_get(anyOf, gunichar2, loop) )
333 return pos;
336 return -1;
339 MonoString *
340 ves_icall_System_String_InternalPad (MonoString *me, gint32 width, gunichar2 chr, MonoBoolean right)
342 MonoString * ret;
343 gunichar2 *src;
344 gunichar2 *dest;
345 gint32 fillcount;
346 gint32 srclen;
347 gint32 i;
349 MONO_ARCH_SAVE_REGS;
351 srclen = mono_string_length(me);
352 src = mono_string_chars(me);
354 ret = mono_string_new_size( mono_domain_get (), width);
355 dest = mono_string_chars(ret);
356 fillcount = width - srclen;
358 if (right) {
359 memcpy(dest, src, srclen * sizeof(gunichar2));
360 for (i = srclen; i != width; i++)
361 dest[i] = chr;
363 return ret;
366 /* left fill */
367 for (i = 0; i != fillcount; i++)
368 dest[i] = chr;
370 memcpy(dest + fillcount, src, srclen * sizeof(gunichar2));
372 return ret;
375 MonoString *
376 ves_icall_System_String_InternalAllocateStr (gint32 length)
378 MONO_ARCH_SAVE_REGS;
380 return mono_string_new_size(mono_domain_get (), length);
383 void
384 ves_icall_System_String_InternalStrcpy_Str (MonoString *dest, gint32 destPos, MonoString *src)
386 gunichar2 *srcptr;
387 gunichar2 *destptr;
389 MONO_ARCH_SAVE_REGS;
391 srcptr = mono_string_chars (src);
392 destptr = mono_string_chars (dest);
394 g_memmove (destptr + destPos, srcptr, mono_string_length(src) * sizeof(gunichar2));
397 void
398 ves_icall_System_String_InternalStrcpy_StrN (MonoString *dest, gint32 destPos, MonoString *src, gint32 startPos, gint32 count)
400 gunichar2 *srcptr;
401 gunichar2 *destptr;
403 MONO_ARCH_SAVE_REGS;
405 srcptr = mono_string_chars (src);
406 destptr = mono_string_chars (dest);
407 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
410 void
411 ves_icall_System_String_InternalStrcpy_Chars (MonoString *dest, gint32 destPos, MonoArray *src)
413 gunichar2 *srcptr;
414 gunichar2 *destptr;
416 MONO_ARCH_SAVE_REGS;
418 srcptr = mono_array_addr (src, gunichar2, 0);
419 destptr = mono_string_chars (dest);
421 g_memmove (destptr + destPos, srcptr, mono_array_length (src) * sizeof(gunichar2));
424 void
425 ves_icall_System_String_InternalStrcpy_CharsN (MonoString *dest, gint32 destPos, MonoArray *src, gint32 startPos, gint32 count)
427 gunichar2 *srcptr;
428 gunichar2 *destptr;
430 MONO_ARCH_SAVE_REGS;
432 srcptr = mono_array_addr (src, gunichar2, 0);
433 destptr = mono_string_chars (dest);
435 g_memmove (destptr + destPos, srcptr + startPos, count * sizeof(gunichar2));
438 MonoString *
439 ves_icall_System_String_InternalIntern (MonoString *str)
441 MONO_ARCH_SAVE_REGS;
443 return mono_string_intern(str);
446 MonoString *
447 ves_icall_System_String_InternalIsInterned (MonoString *str)
449 MONO_ARCH_SAVE_REGS;
451 return mono_string_is_interned(str);
454 gunichar2
455 ves_icall_System_String_get_Chars (MonoString *me, gint32 idx)
457 MONO_ARCH_SAVE_REGS;
459 if ((idx < 0) || (idx >= mono_string_length (me)))
460 mono_raise_exception (mono_get_exception_index_out_of_range ());
461 return mono_string_chars(me)[idx];