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