comparison dmdscript_tango/dstring.d @ 0:55c2951c07be

initial, files origin, premoved tree
author saaadel
date Sun, 24 Jan 2010 12:34:47 +0200
parents
children 8363a4bf6a8f
comparison
equal deleted inserted replaced
-1:000000000000 0:55c2951c07be
1
2 /* Digital Mars DMDScript source code.
3 * Copyright (c) 2000-2002 by Chromium Communications
4 * D version Copyright (c) 2004-2006 by Digital Mars
5 * All Rights Reserved
6 * written by Walter Bright
7 * www.digitalmars.com
8 * Use at your own risk. There is no warranty, express or implied.
9 * License for redistribution is by the GNU General Public License in gpl.txt.
10 *
11 * A binary, non-exclusive license for commercial use can be
12 * purchased from www.digitalmars.com/dscript/buy.html.
13 *
14 * DMDScript is implemented in the D Programming Language,
15 * www.digitalmars.com/d/
16 *
17 * For a C++ implementation of DMDScript, including COM support,
18 * see www.digitalmars.com/dscript/cppscript.html.
19 */
20
21
22 module dmdscript.dstring;
23
24 import std.regexp;
25 import std.utf;
26 import std.c.stdlib;
27 import std.c.string;
28
29 import dmdscript.script;
30 import dmdscript.dobject;
31 import dmdscript.dregexp;
32 import dmdscript.darray;
33 import dmdscript.value;
34 import dmdscript.threadcontext;
35 import dmdscript.dfunction;
36 import dmdscript.text;
37 import dmdscript.property;
38 import dmdscript.errmsgs;
39 import dmdscript.dnative;
40
41 //alias script.tchar tchar;
42
43 /* ===================== Dstring_fromCharCode ==================== */
44
45 void* Dstring_fromCharCode(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
46 {
47 // ECMA 15.5.3.2
48 d_string s;
49
50 for (size_t i = 0; i < arglist.length; i++)
51 { Value* v;
52 uint u;
53
54 v = &arglist[i];
55 u = v.toUint16();
56 //writefln("string.fromCharCode(%x)", u);
57 if (!std.utf.isValidDchar(u))
58 {
59 ErrInfo errinfo;
60
61 ret.putVundefined();
62 return pthis.RuntimeError(&errinfo,
63 errmsgtbl[ERR_NOT_VALID_UTF],
64 "String", "fromCharCode()",
65 u);
66 }
67 std.utf.encode(s, u);
68 //writefln("s[0] = %x, s = '%s'", s[0], s);
69 }
70 ret.putVstring(s);
71 return null;
72 }
73
74 /* ===================== Dstring_constructor ==================== */
75
76 class Dstring_constructor : Dfunction
77 {
78 this(ThreadContext *tc)
79 {
80 super(1, tc.Dfunction_prototype);
81 name = "String";
82
83 static NativeFunctionData nfd[] =
84 [
85 { &TEXT_fromCharCode, &Dstring_fromCharCode, 1 },
86 ];
87
88 DnativeFunction.init(this, nfd, 0);
89 }
90
91 void *Construct(CallContext *cc, Value *ret, Value[] arglist)
92 {
93 // ECMA 15.5.2
94 d_string s;
95 Dobject o;
96
97 s = (arglist.length) ? arglist[0].toString() : TEXT_;
98 o = new Dstring(s);
99 ret.putVobject(o);
100 return null;
101 }
102
103 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
104 {
105 // ECMA 15.5.1
106 d_string s;
107
108 s = (arglist.length) ? arglist[0].toString() : TEXT_;
109 ret.putVstring(s);
110 return null;
111 }
112 }
113
114
115 /* ===================== Dstring_prototype_toString =============== */
116
117 void* Dstring_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
118 {
119 //writef("Dstring.prototype.toString()\n");
120 // othis must be a String
121 if (!othis.isClass(TEXT_String))
122 {
123 ErrInfo errinfo;
124
125 ret.putVundefined();
126 return pthis.RuntimeError(&errinfo,
127 errmsgtbl[ERR_FUNCTION_WANTS_STRING],
128 TEXT_toString,
129 othis.classname);
130 }
131 else
132 { Value *v;
133
134 v = &(cast(Dstring)othis).value;
135 Value.copy(ret, v);
136 }
137 return null;
138 }
139
140 /* ===================== Dstring_prototype_valueOf =============== */
141
142 void* Dstring_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
143 {
144 // Does same thing as String.prototype.toString()
145
146 //writef("string.prototype.valueOf()\n");
147 // othis must be a String
148 if (!othis.isClass(TEXT_String))
149 {
150 ErrInfo errinfo;
151
152 ret.putVundefined();
153 return pthis.RuntimeError(&errinfo,
154 errmsgtbl[ERR_FUNCTION_WANTS_STRING],
155 TEXT_valueOf,
156 othis.classname);
157 }
158 else
159 { Value *v;
160
161 v = &(cast(Dstring)othis).value;
162 Value.copy(ret, v);
163 }
164 return null;
165 }
166
167 /* ===================== Dstring_prototype_charAt =============== */
168
169 void* Dstring_prototype_charAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
170 {
171 // ECMA 15.5.4.4
172
173 Value *v;
174 int pos; // ECMA says pos should be a d_number,
175 // but int should behave the same
176 d_string s;
177 d_string result;
178
179 v = &othis.value;
180 s = v.toString();
181 v = arglist.length ? &arglist[0] : &vundefined;
182 pos = cast(int) v.toInteger();
183
184 result = TEXT_;
185
186 if (pos >= 0)
187 { size_t idx;
188
189 while (1)
190 {
191 if (idx == s.length)
192 break;
193 if (pos == 0)
194 {
195 result = s[idx .. idx + std.utf.stride(s, idx)];
196 break;
197 }
198 idx += std.utf.stride(s, idx);
199 pos--;
200 }
201 }
202
203 ret.putVstring(result);
204 return null;
205 }
206
207 /* ===================== Dstring_prototype_charCodeAt ============= */
208
209 void* Dstring_prototype_charCodeAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
210 {
211 // ECMA 15.5.4.5
212
213 Value *v;
214 int pos; // ECMA says pos should be a d_number,
215 // but int should behave the same
216 d_string s;
217 uint len;
218 d_number result;
219
220 v = &othis.value;
221 s = v.toString();
222 v = arglist.length ? &arglist[0] : &vundefined;
223 pos = cast(int) v.toInteger();
224
225 result = d_number.nan;
226
227 if (pos >= 0)
228 { size_t idx;
229
230 while (1)
231 {
232 assert(idx <= s.length);
233 if (idx == s.length)
234 break;
235 if (pos == 0)
236 {
237 result = std.utf.decode(s, idx);
238 break;
239 }
240 idx += std.utf.stride(s, idx);
241 pos--;
242 }
243 }
244
245 ret.putVnumber(result);
246 return null;
247 }
248
249 /* ===================== Dstring_prototype_concat ============= */
250
251 void* Dstring_prototype_concat(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
252 {
253 // ECMA v3 15.5.4.6
254 d_string s;
255
256 //writefln("Dstring.prototype.concat()");
257
258 s = othis.value.toString();
259 for (size_t a = 0; a < arglist.length; a++)
260 s ~= arglist[a].toString();
261
262 ret.putVstring(s);
263 return null;
264 }
265
266 /* ===================== Dstring_prototype_indexOf ============= */
267
268 void* Dstring_prototype_indexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
269 {
270 // ECMA 15.5.4.6
271 // String.prototype.indexOf(searchString, position)
272
273 Value* v1;
274 Value* v2;
275 int pos; // ECMA says pos should be a d_number,
276 // but I can't find a reason.
277 d_string s;
278 size_t sUCSdim;
279
280 d_string searchString;
281 int k;
282
283 Value xx;
284 xx.putVobject(othis);
285 s = xx.toString();
286 sUCSdim = std.utf.toUCSindex(s, s.length);
287
288 v1 = arglist.length ? &arglist[0] : &vundefined;
289 v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
290
291 searchString = v1.toString();
292 pos = cast(int) v2.toInteger();
293
294 if (pos < 0)
295 pos = 0;
296 else if (pos > sUCSdim)
297 pos = sUCSdim;
298
299 if (searchString.length == 0)
300 k = pos;
301 else
302 { pos = std.utf.toUTFindex(s, pos);
303 k = std.string.find(s[pos .. length], searchString);
304 if (k != -1)
305 k = std.utf.toUCSindex(s, pos + k);
306 }
307
308 ret.putVnumber(k);
309 return null;
310 }
311
312 /* ===================== Dstring_prototype_lastIndexOf ============= */
313
314 void* Dstring_prototype_lastIndexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
315 {
316 // ECMA v3 15.5.4.8
317 // String.prototype.lastIndexOf(searchString, position)
318
319 Value *v1;
320 int pos; // ECMA says pos should be a d_number,
321 // but I can't find a reason.
322 d_string s;
323 size_t sUCSdim;
324 d_string searchString;
325 int k;
326
327 version (all)
328 {
329 {
330 // This is the 'transferable' version
331 Value *v;
332 void *a;
333 v = othis.Get(TEXT_toString);
334 a = v.Call(cc, othis, ret, null);
335 if (a) // if exception was thrown
336 return a;
337 s = ret.toString();
338 }
339 }
340 else
341 {
342 // the 'builtin' version
343 s = othis.value.toString();
344 }
345 sUCSdim = std.utf.toUCSindex(s, s.length);
346
347 v1 = arglist.length ? &arglist[0] : &vundefined;
348 searchString = v1.toString();
349 if (arglist.length >= 2)
350 { d_number n;
351 Value *v = &arglist[1];
352
353 n = v.toNumber();
354 if (std.math.isnan(n) || n > sUCSdim)
355 pos = sUCSdim;
356 else if (n < 0)
357 pos = 0;
358 else
359 pos = cast(int) n;
360 }
361 else
362 pos = sUCSdim;
363
364 //writef("len = %d, p = '%ls'\n", len, p);
365 //writef("pos = %d, sslen = %d, ssptr = '%ls'\n", pos, sslen, ssptr);
366 //writefln("s = '%s', pos = %s, searchString = '%s'", s, pos, searchString);
367
368 if (searchString.length == 0)
369 k = pos;
370 else
371 {
372 pos = std.utf.toUTFindex(s, pos);
373 pos += searchString.length;
374 if (pos > s.length)
375 pos = s.length;
376 k = std.string.rfind(s[0 .. pos], searchString);
377 //writefln("s = '%s', pos = %s, searchString = '%s', k = %d", s, pos, searchString, k);
378 if (k != -1)
379 k = std.utf.toUCSindex(s, k);
380 }
381 ret.putVnumber(k);
382 return null;
383 }
384
385 /* ===================== Dstring_prototype_localeCompare ============= */
386
387 void* Dstring_prototype_localeCompare(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
388 {
389 // ECMA v3 15.5.4.9
390 d_string s1;
391 d_string s2;
392 d_number n;
393 Value *v;
394
395 v = &othis.value;
396 s1 = v.toString();
397 s2 = arglist.length ? arglist[0].toString() : vundefined.toString();
398 n = localeCompare(cc, s1, s2);
399 ret.putVnumber(n);
400 return null;
401 }
402
403 /* ===================== Dstring_prototype_match ============= */
404
405 void* Dstring_prototype_match(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
406 {
407 // ECMA v3 15.5.4.10
408 Dregexp r;
409 Dobject o;
410
411 if (arglist.length && !arglist[0].isPrimitive() &&
412 (o = arglist[0].toObject()).isDregexp())
413 {
414 ;
415 }
416 else
417 {
418 Value regret;
419
420 regret.putVobject(null);
421 Dregexp.getConstructor().Construct(cc, &regret, arglist);
422 o = regret.object;
423 }
424
425 r = cast(Dregexp)o;
426 if (r.global.dbool)
427 {
428 Darray a = new Darray;
429 d_int32 n;
430 d_int32 i;
431 d_int32 lasti;
432
433 i = 0;
434 lasti = 0;
435 for (n = 0; ; n++)
436 {
437 r.lastIndex.putVnumber(i);
438 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING);
439 if (!ret.string) // if match failed
440 {
441 r.lastIndex.putVnumber(i);
442 break;
443 }
444 lasti = i;
445 i = cast(d_int32) r.lastIndex.toInt32();
446 if (i == lasti) // if no source was consumed
447 i++; // consume a character
448
449 a.Put(n, ret, 0); // a[n] = ret;
450 }
451 ret.putVobject(a);
452 }
453 else
454 {
455 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_ARRAY);
456 }
457 return null;
458 }
459
460 /* ===================== Dstring_prototype_replace ============= */
461
462 void* Dstring_prototype_replace(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
463 {
464 // ECMA v3 15.5.4.11
465 // String.prototype.replace(searchValue, replaceValue)
466
467 d_string string;
468 d_string searchString;
469 d_string newstring;
470 Value *searchValue;
471 Value *replaceValue;
472 Dregexp r;
473 RegExp re;
474 tchar[] replacement;
475 d_string result;
476 int m;
477 int i;
478 int lasti;
479 std.regexp.regmatch_t[1] pmatch;
480 Dfunction f;
481 Value* v;
482
483 v = &othis.value;
484 string = v.toString();
485 searchValue = (arglist.length >= 1) ? &arglist[0] : &vundefined;
486 replaceValue = (arglist.length >= 2) ? &arglist[1] : &vundefined;
487 r = Dregexp.isRegExp(searchValue);
488 f = Dfunction.isFunction(replaceValue);
489 if (r)
490 { int offset = 0;
491
492 re = r.re;
493 i = 0;
494 result = string;
495
496 r.lastIndex.putVnumber(0);
497 for (;;)
498 {
499 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING);
500 if (!ret.string) // if match failed
501 break;
502
503 m = re.re_nsub;
504 if (f)
505 {
506 Value* alist;
507
508 alist = cast(Value *)alloca((m + 3) * Value.sizeof);
509 assert(alist);
510 alist[0].putVstring(ret.string);
511 for (i = 0; i < m; i++)
512 {
513 alist[1 + i].putVstring(
514 string[re.pmatch[1 + i].rm_so .. re.pmatch[1 + i].rm_eo]);
515 }
516 alist[m + 1].putVnumber(re.pmatch[0].rm_so);
517 alist[m + 2].putVstring(string);
518 f.Call(cc, f, ret, alist[0 .. m + 3]);
519 replacement = ret.toString();
520 }
521 else
522 {
523 newstring = replaceValue.toString();
524 replacement = re.replace(newstring);
525 }
526 int starti = re.pmatch[0].rm_so + offset;
527 int endi = re.pmatch[0].rm_eo + offset;
528 result = string[0 .. starti] ~
529 replacement ~
530 string[endi .. length];
531
532 if (re.attributes & RegExp.REA.global)
533 {
534 offset += replacement.length - (endi - starti);
535
536 // If no source was consumed, consume a character
537 lasti = i;
538 i = cast(d_int32) r.lastIndex.toInt32();
539 if (i == lasti)
540 { i++;
541 r.lastIndex.putVnumber(i);
542 }
543 }
544 else
545 break;
546 }
547 }
548 else
549 { int match;
550
551 searchString = searchValue.toString();
552 match = std.string.find(string, searchString);
553 if (match >= 0)
554 {
555 pmatch[0].rm_so = match;
556 pmatch[0].rm_eo = match + searchString.length;
557 if (f)
558 {
559 Value[3] alist;
560
561 alist[0].putVstring(searchString);
562 alist[1].putVnumber(pmatch[0].rm_so);
563 alist[2].putVstring(string);
564 f.Call(cc, f, ret, alist);
565 replacement = ret.toString();
566 }
567 else
568 {
569 newstring = replaceValue.toString();
570 replacement = RegExp.replace3(newstring, string, pmatch);
571 }
572 result = string[0 .. match] ~
573 replacement ~
574 string[match + searchString.length .. length];
575 }
576 else
577 {
578 result = string;
579 }
580 }
581
582 ret.putVstring(result);
583 return null;
584 }
585
586 /* ===================== Dstring_prototype_search ============= */
587
588 void* Dstring_prototype_search(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
589 {
590 // ECMA v3 15.5.4.12
591 Dregexp r;
592 Dobject o;
593
594 //writef("String.prototype.search()\n");
595 if (arglist.length && !arglist[0].isPrimitive() &&
596 (o = arglist[0].toObject()).isDregexp())
597 {
598 ;
599 }
600 else
601 { Value regret;
602
603 regret.putVobject(null);
604 Dregexp.getConstructor().Construct(cc, &regret, arglist);
605 o = regret.object;
606 }
607
608 r = cast(Dregexp)o;
609 Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_INDEX);
610 return null;
611 }
612
613 /* ===================== Dstring_prototype_slice ============= */
614
615 void* Dstring_prototype_slice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
616 {
617 // ECMA v3 15.5.4.13
618 d_int32 start;
619 d_int32 end;
620 d_int32 sUCSdim;
621 d_string s;
622 d_string r;
623 Value *v;
624
625 v = &othis.value;
626 s = v.toString();
627 sUCSdim = std.utf.toUCSindex(s, s.length);
628 switch (arglist.length)
629 {
630 case 0:
631 start = 0;
632 end = sUCSdim;
633 break;
634
635 case 1:
636 start = arglist[0].toInt32();
637 end = sUCSdim;
638 break;
639
640 default:
641 start = arglist[0].toInt32();
642 end = arglist[1].toInt32();
643 break;
644 }
645
646 if (start < 0)
647 {
648 start += sUCSdim;
649 if (start < 0)
650 start = 0;
651 }
652 else if (start >= sUCSdim)
653 start = sUCSdim;
654
655 if (end < 0)
656 {
657 end += sUCSdim;
658 if (end < 0)
659 end = 0;
660 }
661 else if (end >= sUCSdim)
662 end = sUCSdim;
663
664 if (start > end)
665 end = start;
666
667 start = toUTFindex(s, start);
668 end = toUTFindex(s, end);
669 r = s[start .. end];
670
671 ret.putVstring(r);
672 return null;
673 }
674
675
676 /* ===================== Dstring_prototype_split ============= */
677
678 void* Dstring_prototype_split(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
679 {
680 // ECMA v3 15.5.4.14
681 // String.prototype.split(separator, limit)
682 d_uint32 lim;
683 d_uint32 p;
684 d_uint32 q;
685 d_uint32 e;
686 Value* separator = &vundefined;
687 Value* limit = &vundefined;
688 Dregexp R;
689 RegExp re;
690 d_string rs;
691 d_string T;
692 d_string S;
693 Darray A;
694 int str;
695
696 //writefln("Dstring_prototype_split()");
697 switch (arglist.length)
698 {
699 default:
700 limit = &arglist[1];
701 case 1:
702 separator = &arglist[0];
703 case 0:
704 break;
705 }
706
707 Value *v;
708 v = &othis.value;
709 S = v.toString();
710 A = new Darray;
711 if (limit.isUndefined())
712 lim = ~0u;
713 else
714 lim = limit.toUint32();
715 p = 0;
716 R = Dregexp.isRegExp(separator);
717 if (R) // regular expression
718 { re = R.re;
719 assert(re);
720 rs = null;
721 str = 0;
722 }
723 else // string
724 { re = null;
725 rs = separator.toString();
726 str = 1;
727 }
728 if (lim == 0)
729 goto Lret;
730
731 // ECMA v3 15.5.4.14 is specific: "If separator is undefined, then the
732 // result array contains just one string, which is the this value
733 // (converted to a string)." However, neither Javascript nor Jscript
734 // do that, they regard an undefined as being the string "undefined".
735 // We match Javascript/Jscript behavior here, not ECMA.
736
737 // Uncomment for ECMA compatibility
738 //if (!separator.isUndefined())
739 {
740 //writefln("test1 S = '%s', rs = '%s'", S, rs);
741 if (S.length)
742 {
743 L10:
744 for (q = p; q != S.length; q++)
745 {
746 if (str) // string
747 {
748 if (q + rs.length <= S.length && !memcmp(S.ptr + q, rs.ptr, rs.length * tchar.sizeof))
749 {
750 e = q + rs.length;
751 if (e != p)
752 {
753 T = S[p .. q];
754 A.Put(cast(uint) A.length.number, T, 0);
755 if (A.length.number == lim)
756 goto Lret;
757 p = e;
758 goto L10;
759 }
760 }
761 }
762 else // regular expression
763 {
764 if (re.test(S, q))
765 { q = re.pmatch[0].rm_so;
766 e = re.pmatch[0].rm_eo;
767 if (e != p)
768 {
769 T = S[p .. q];
770 //writefln("S = '%s', T = '%s', p = %d, q = %d, e = %d\n", S, T, p, q, e);
771 A.Put(cast(uint) A.length.number, T, 0);
772 if (A.length.number == lim)
773 goto Lret;
774 p = e;
775 for (uint i = 0; i < re.re_nsub; i++)
776 {
777 int so = re.pmatch[1 + i].rm_so;
778 int eo = re.pmatch[1 + i].rm_eo;
779
780 //writefln("i = %d, nsub = %s, so = %s, eo = %s, S.length = %s", i, re.re_nsub, so, eo, S.length);
781 if (so != -1 && eo != -1)
782 T = S[so .. eo];
783 else
784 T = null;
785 A.Put(cast(uint) A.length.number, T, 0);
786 if (A.length.number == lim)
787 goto Lret;
788 }
789 goto L10;
790 }
791 }
792 }
793 }
794 T = S[p .. S.length];
795 A.Put(cast(uint) A.length.number, T, 0);
796 goto Lret;
797 }
798 if (str) // string
799 {
800 if (rs.length <= S.length && S[0 .. rs.length] == rs[])
801 goto Lret;
802 }
803 else // regular expression
804 {
805 if (re.test(S, 0))
806 goto Lret;
807 }
808 }
809
810 A.Put(0u, S, 0);
811 Lret:
812 ret.putVobject(A);
813 return null;
814 }
815
816
817 /* ===================== Dstring_prototype_substr ============= */
818
819 void *dstring_substring(d_string s, size_t sUCSdim, d_number start, d_number end, Value *ret)
820 {
821 d_string sb;
822 d_int32 sb_len;
823
824 if (std.math.isnan(start))
825 start = 0;
826 else if (start > sUCSdim)
827 start = sUCSdim;
828 else if (start < 0)
829 start = 0;
830
831 if (std.math.isnan(end))
832 end = 0;
833 else if (end > sUCSdim)
834 end = sUCSdim;
835 else if (end < 0)
836 end = 0;
837
838 if (end < start) // swap
839 { d_number t;
840
841 t = start;
842 start = end;
843 end = t;
844 }
845
846 size_t st = std.utf.toUTFindex(s, cast(size_t)start);
847 size_t en = std.utf.toUTFindex(s, cast(size_t)end);
848 sb = s[st .. en];
849
850 ret.putVstring(sb);
851 return null;
852 }
853
854 void* Dstring_prototype_substr(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
855 {
856 // Javascript: TDG pg. 689
857 // String.prototype.substr(start, length)
858 d_number start;
859 d_number length;
860 d_string s;
861
862 s = othis.value.toString();
863 size_t sUCSdim = std.utf.toUCSindex(s, s.length);
864 start = 0;
865 length = 0;
866 if (arglist.length >= 1)
867 {
868 start = arglist[0].toInteger();
869 if (start < 0)
870 start = sUCSdim + start;
871 if (arglist.length >= 2)
872 {
873 length = arglist[1].toInteger();
874 if (std.math.isnan(length) || length < 0)
875 length = 0;
876 }
877 else
878 length = sUCSdim - start;
879 }
880
881 return dstring_substring(s, sUCSdim, start, start + length, ret);
882 }
883
884 /* ===================== Dstring_prototype_substring ============= */
885
886 void* Dstring_prototype_substring(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
887 {
888 // ECMA 15.5.4.9
889 // String.prototype.substring(start)
890 // String.prototype.substring(start, end)
891 d_number start;
892 d_number end;
893 d_string s;
894
895 //writefln("String.prototype.substring()");
896 s = othis.value.toString();
897 size_t sUCSdim = std.utf.toUCSindex(s, s.length);
898 start = 0;
899 end = sUCSdim;
900 if (arglist.length >= 1)
901 {
902 start = arglist[0].toInteger();
903 if (arglist.length >= 2)
904 end = arglist[1].toInteger();
905 //writef("s = '%ls', start = %d, end = %d\n", s, start, end);
906 }
907
908 void* p = dstring_substring(s, sUCSdim, start, end, ret);
909 return p;
910 }
911
912 /* ===================== Dstring_prototype_toLowerCase ============= */
913
914 enum CASE
915 {
916 Lower,
917 Upper,
918 LocaleLower,
919 LocaleUpper
920 };
921
922 void *tocase(Dobject othis, Value *ret, CASE caseflag)
923 {
924 d_string s;
925
926 s = othis.value.toString();
927 switch (caseflag)
928 {
929 case CASE.Lower:
930 s = std.string.tolower(s);
931 break;
932 case CASE.Upper:
933 s = std.string.toupper(s);
934 break;
935 case CASE.LocaleLower:
936 s = std.string.tolower(s);
937 break;
938 case CASE.LocaleUpper:
939 s = std.string.toupper(s);
940 break;
941 default:
942 assert(0);
943 }
944
945 ret.putVstring(s);
946 return null;
947 }
948
949 void* Dstring_prototype_toLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
950 {
951 // ECMA 15.5.4.11
952 // String.prototype.toLowerCase()
953
954 //writef("Dstring_prototype_toLowerCase()\n");
955 return tocase(othis, ret, CASE.Lower);
956 }
957
958 /* ===================== Dstring_prototype_toLocaleLowerCase ============= */
959
960 void* Dstring_prototype_toLocaleLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
961 {
962 // ECMA v3 15.5.4.17
963
964 //writef("Dstring_prototype_toLocaleLowerCase()\n");
965 return tocase(othis, ret, CASE.LocaleLower);
966 }
967
968 /* ===================== Dstring_prototype_toUpperCase ============= */
969
970 void* Dstring_prototype_toUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
971 {
972 // ECMA 15.5.4.12
973 // String.prototype.toUpperCase()
974
975 return tocase(othis, ret, CASE.Upper);
976 }
977
978 /* ===================== Dstring_prototype_toLocaleUpperCase ============= */
979
980 void* Dstring_prototype_toLocaleUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
981 {
982 // ECMA v3 15.5.4.18
983
984 return tocase(othis, ret, CASE.LocaleUpper);
985 }
986
987 /* ===================== Dstring_prototype_anchor ============= */
988
989 void *dstring_anchor(Dobject othis, Value* ret, tchar[] tag, tchar[] name, Value[] arglist)
990 {
991 // For example:
992 // "foo".anchor("bar")
993 // produces:
994 // <tag name="bar">foo</tag>
995
996 d_string foo = othis.value.toString();
997 Value* va = arglist.length ? &arglist[0] : &vundefined;
998 d_string bar = va.toString();
999
1000 d_string s;
1001
1002 s = "<" ~
1003 tag ~
1004 " " ~
1005 name ~
1006 "=\"" ~
1007 bar ~
1008 "\">" ~
1009 foo ~
1010 "</" ~
1011 tag ~
1012 ">";
1013
1014 ret.putVstring(s);
1015 return null;
1016 }
1017
1018
1019 void* Dstring_prototype_anchor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1020 {
1021 // Non-standard extension
1022 // String.prototype.anchor(anchor)
1023 // For example:
1024 // "foo".anchor("bar")
1025 // produces:
1026 // <A NAME="bar">foo</A>
1027
1028 return dstring_anchor(othis, ret, "A", "NAME", arglist);
1029 }
1030
1031 void* Dstring_prototype_fontcolor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1032 {
1033 return dstring_anchor(othis, ret, "FONT", "COLOR", arglist);
1034 }
1035
1036 void* Dstring_prototype_fontsize(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1037 {
1038 return dstring_anchor(othis, ret, "FONT", "SIZE", arglist);
1039 }
1040
1041 void* Dstring_prototype_link(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1042 {
1043 return dstring_anchor(othis, ret, "A", "HREF", arglist);
1044 }
1045
1046
1047 /* ===================== Dstring_prototype bracketing ============= */
1048
1049 /***************************
1050 * Produce <tag>othis</tag>
1051 */
1052
1053 void *dstring_bracket(Dobject othis, Value* ret, char[] tag)
1054 {
1055 d_string foo = othis.value.toString();
1056 d_string s;
1057
1058 s = "<" ~
1059 tag ~
1060 ">" ~
1061 foo ~
1062 "</" ~
1063 tag ~
1064 ">";
1065
1066 ret.putVstring(s);
1067 return null;
1068 }
1069
1070 void* Dstring_prototype_big(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1071 {
1072 // Non-standard extension
1073 // String.prototype.big()
1074 // For example:
1075 // "foo".big()
1076 // produces:
1077 // <BIG>foo</BIG>
1078
1079 return dstring_bracket(othis, ret, "BIG");
1080 }
1081
1082 void* Dstring_prototype_blink(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1083 {
1084 return dstring_bracket(othis, ret, "BLINK");
1085 }
1086
1087 void* Dstring_prototype_bold(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1088 {
1089 return dstring_bracket(othis, ret, "B");
1090 }
1091
1092 void* Dstring_prototype_fixed(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1093 {
1094 return dstring_bracket(othis, ret, "TT");
1095 }
1096
1097 void* Dstring_prototype_italics(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1098 {
1099 return dstring_bracket(othis, ret, "I");
1100 }
1101
1102 void* Dstring_prototype_small(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1103 {
1104 return dstring_bracket(othis, ret, "SMALL");
1105 }
1106
1107 void* Dstring_prototype_strike(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1108 {
1109 return dstring_bracket(othis, ret, "STRIKE");
1110 }
1111
1112 void* Dstring_prototype_sub(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1113 {
1114 return dstring_bracket(othis, ret, "SUB");
1115 }
1116
1117 void* Dstring_prototype_sup(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
1118 {
1119 return dstring_bracket(othis, ret, "SUP");
1120 }
1121
1122
1123
1124 /* ===================== Dstring_prototype ==================== */
1125
1126 class Dstring_prototype : Dstring
1127 {
1128 this(ThreadContext *tc)
1129 {
1130 super(tc.Dobject_prototype);
1131
1132 Put(TEXT_constructor, tc.Dstring_constructor, DontEnum);
1133
1134 static NativeFunctionData nfd[] =
1135 [
1136 { &TEXT_toString, &Dstring_prototype_toString, 0 },
1137 { &TEXT_valueOf, &Dstring_prototype_valueOf, 0 },
1138 { &TEXT_charAt, &Dstring_prototype_charAt, 1 },
1139 { &TEXT_charCodeAt, &Dstring_prototype_charCodeAt, 1 },
1140 { &TEXT_concat, &Dstring_prototype_concat, 1 },
1141 { &TEXT_indexOf, &Dstring_prototype_indexOf, 1 },
1142 { &TEXT_lastIndexOf, &Dstring_prototype_lastIndexOf, 1 },
1143 { &TEXT_localeCompare, &Dstring_prototype_localeCompare, 1 },
1144 { &TEXT_match, &Dstring_prototype_match, 1 },
1145 { &TEXT_replace, &Dstring_prototype_replace, 2 },
1146 { &TEXT_search, &Dstring_prototype_search, 1 },
1147 { &TEXT_slice, &Dstring_prototype_slice, 2 },
1148 { &TEXT_split, &Dstring_prototype_split, 2 },
1149 { &TEXT_substr, &Dstring_prototype_substr, 2 },
1150 { &TEXT_substring, &Dstring_prototype_substring, 2 },
1151 { &TEXT_toLowerCase, &Dstring_prototype_toLowerCase, 0 },
1152 { &TEXT_toLocaleLowerCase, &Dstring_prototype_toLocaleLowerCase, 0 },
1153 { &TEXT_toUpperCase, &Dstring_prototype_toUpperCase, 0 },
1154 { &TEXT_toLocaleUpperCase, &Dstring_prototype_toLocaleUpperCase, 0 },
1155 { &TEXT_anchor, &Dstring_prototype_anchor, 1 },
1156 { &TEXT_fontcolor, &Dstring_prototype_fontcolor, 1 },
1157 { &TEXT_fontsize, &Dstring_prototype_fontsize, 1 },
1158 { &TEXT_link, &Dstring_prototype_link, 1 },
1159 { &TEXT_big, &Dstring_prototype_big, 0 },
1160 { &TEXT_blink, &Dstring_prototype_blink, 0 },
1161 { &TEXT_bold, &Dstring_prototype_bold, 0 },
1162 { &TEXT_fixed, &Dstring_prototype_fixed, 0 },
1163 { &TEXT_italics, &Dstring_prototype_italics, 0 },
1164 { &TEXT_small, &Dstring_prototype_small, 0 },
1165 { &TEXT_strike, &Dstring_prototype_strike, 0 },
1166 { &TEXT_sub, &Dstring_prototype_sub, 0 },
1167 { &TEXT_sup, &Dstring_prototype_sup, 0 },
1168 ];
1169
1170 DnativeFunction.init(this, nfd, DontEnum);
1171 }
1172 }
1173
1174 /* ===================== Dstring ==================== */
1175
1176 class Dstring : Dobject
1177 {
1178 this(d_string s)
1179 {
1180 super(getPrototype());
1181 classname = TEXT_String;
1182
1183 Put(TEXT_length, std.utf.toUCSindex(s, s.length), DontEnum | DontDelete | ReadOnly);
1184 value.putVstring(s);
1185 }
1186
1187 this(Dobject prototype)
1188 {
1189 super(prototype);
1190
1191 classname = TEXT_String;
1192 Put(TEXT_length, 0, DontEnum | DontDelete | ReadOnly);
1193 value.putVstring(null);
1194 }
1195
1196 static void init(ThreadContext *tc)
1197 {
1198 tc.Dstring_constructor = new Dstring_constructor(tc);
1199 tc.Dstring_prototype = new Dstring_prototype(tc);
1200
1201 tc.Dstring_constructor.Put(TEXT_prototype, tc.Dstring_prototype, DontEnum | DontDelete | ReadOnly);
1202 }
1203
1204 static Dfunction getConstructor()
1205 {
1206 ThreadContext *tc = ThreadContext.getThreadContext();
1207 assert(tc);
1208 return tc.Dstring_constructor;
1209 }
1210
1211 static Dobject getPrototype()
1212 {
1213 ThreadContext *tc = ThreadContext.getThreadContext();
1214 assert(tc);
1215 return tc.Dstring_prototype;
1216 }
1217 }