| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 return %StringLocaleCompare(this_str, other_str); | 161 return %StringLocaleCompare(this_str, other_str); |
| 162 } | 162 } |
| 163 | 163 |
| 164 | 164 |
| 165 // ECMA-262 section 15.5.4.10 | 165 // ECMA-262 section 15.5.4.10 |
| 166 function StringMatch(regexp) { | 166 function StringMatch(regexp) { |
| 167 if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp); | 167 if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp); |
| 168 var subject = TO_STRING_INLINE(this); | 168 var subject = TO_STRING_INLINE(this); |
| 169 | 169 |
| 170 if (!regexp.global) return regexp.exec(subject); | 170 if (!regexp.global) return regexp.exec(subject); |
| 171 |
| 172 var cache = regExpCache; |
| 173 |
| 174 if (%_ObjectEquals(cache.type, 'match') && |
| 175 %_ObjectEquals(cache.regExp, regexp) && |
| 176 %_ObjectEquals(cache.subject, subject)) { |
| 177 var last = cache.answer; |
| 178 if (last == null) { |
| 179 return last; |
| 180 } else { |
| 181 return CloneRegexpAnswer(last); |
| 182 } |
| 183 } |
| 184 |
| 171 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); | 185 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); |
| 172 // lastMatchInfo is defined in regexp.js. | 186 // lastMatchInfo is defined in regexp.js. |
| 173 return %StringMatch(subject, regexp, lastMatchInfo); | 187 var result = %StringMatch(subject, regexp, lastMatchInfo); |
| 188 cache.type = 'match'; |
| 189 cache.regExp = regexp; |
| 190 cache.subject = subject; |
| 191 cache.answer = result; |
| 192 if (result == null) { |
| 193 return result; |
| 194 } else { |
| 195 return CloneRegexpAnswer(result); |
| 196 } |
| 174 } | 197 } |
| 175 | 198 |
| 176 | 199 |
| 177 // SubString is an internal function that returns the sub string of 'string'. | 200 // SubString is an internal function that returns the sub string of 'string'. |
| 178 // If resulting string is of length 1, we use the one character cache | 201 // If resulting string is of length 1, we use the one character cache |
| 179 // otherwise we call the runtime system. | 202 // otherwise we call the runtime system. |
| 180 function SubString(string, start, end) { | 203 function SubString(string, start, end) { |
| 181 // Use the one character string cache. | 204 // Use the one character string cache. |
| 182 if (start + 1 == end) { | 205 if (start + 1 == end) { |
| 183 var char_code = %_FastCharCodeAt(string, start); | 206 var char_code = %_FastCharCodeAt(string, start); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 199 | 222 |
| 200 | 223 |
| 201 // ECMA-262, section 15.5.4.11 | 224 // ECMA-262, section 15.5.4.11 |
| 202 function StringReplace(search, replace) { | 225 function StringReplace(search, replace) { |
| 203 var subject = TO_STRING_INLINE(this); | 226 var subject = TO_STRING_INLINE(this); |
| 204 | 227 |
| 205 // Delegate to one of the regular expression variants if necessary. | 228 // Delegate to one of the regular expression variants if necessary. |
| 206 if (IS_REGEXP(search)) { | 229 if (IS_REGEXP(search)) { |
| 207 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); | 230 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); |
| 208 if (IS_FUNCTION(replace)) { | 231 if (IS_FUNCTION(replace)) { |
| 232 regExpCache.type = 'none'; |
| 209 return StringReplaceRegExpWithFunction(subject, search, replace); | 233 return StringReplaceRegExpWithFunction(subject, search, replace); |
| 210 } else { | 234 } else { |
| 211 return StringReplaceRegExp(subject, search, replace); | 235 return StringReplaceRegExp(subject, search, replace); |
| 212 } | 236 } |
| 213 } | 237 } |
| 214 | 238 |
| 215 // Convert the search argument to a string and search for it. | 239 // Convert the search argument to a string and search for it. |
| 216 search = TO_STRING_INLINE(search); | 240 search = TO_STRING_INLINE(search); |
| 217 var start = %StringIndexOf(subject, search, 0); | 241 var start = %StringIndexOf(subject, search, 0); |
| 218 if (start < 0) return subject; | 242 if (start < 0) return subject; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 234 | 258 |
| 235 // suffix | 259 // suffix |
| 236 builder.addSpecialSlice(end, subject.length); | 260 builder.addSpecialSlice(end, subject.length); |
| 237 | 261 |
| 238 return builder.generate(); | 262 return builder.generate(); |
| 239 } | 263 } |
| 240 | 264 |
| 241 | 265 |
| 242 // Helper function for regular expressions in String.prototype.replace. | 266 // Helper function for regular expressions in String.prototype.replace. |
| 243 function StringReplaceRegExp(subject, regexp, replace) { | 267 function StringReplaceRegExp(subject, regexp, replace) { |
| 268 var cache = regExpCache; |
| 269 if (%_ObjectEquals(cache.regExp, regexp) && |
| 270 %_ObjectEquals(cache.type, 'replace') && |
| 271 %_ObjectEquals(cache.replaceString, replace) && |
| 272 %_ObjectEquals(cache.subject, subject)) { |
| 273 return cache.answer; |
| 274 } |
| 244 replace = TO_STRING_INLINE(replace); | 275 replace = TO_STRING_INLINE(replace); |
| 245 return %StringReplaceRegExpWithString(subject, | 276 var answer = %StringReplaceRegExpWithString(subject, |
| 246 regexp, | 277 regexp, |
| 247 replace, | 278 replace, |
| 248 lastMatchInfo); | 279 lastMatchInfo); |
| 249 }; | 280 cache.subject = subject; |
| 281 cache.regExp = regexp; |
| 282 cache.replaceString = replace; |
| 283 cache.answer = answer; |
| 284 cache.type = 'replace'; |
| 285 return answer; |
| 286 } |
| 250 | 287 |
| 251 | 288 |
| 252 // Expand the $-expressions in the string and return a new string with | 289 // Expand the $-expressions in the string and return a new string with |
| 253 // the result. | 290 // the result. |
| 254 function ExpandReplacement(string, subject, matchInfo, builder) { | 291 function ExpandReplacement(string, subject, matchInfo, builder) { |
| 255 var next = %StringIndexOf(string, '$', 0); | 292 var next = %StringIndexOf(string, '$', 0); |
| 256 if (next < 0) { | 293 if (next < 0) { |
| 257 builder.add(string); | 294 builder.add(string); |
| 258 return; | 295 return; |
| 259 } | 296 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 var matchInfo = DoRegExpExec(regexp, subject, 0); | 417 var matchInfo = DoRegExpExec(regexp, subject, 0); |
| 381 if (IS_NULL(matchInfo)) return subject; | 418 if (IS_NULL(matchInfo)) return subject; |
| 382 | 419 |
| 383 var result = new ReplaceResultBuilder(subject); | 420 var result = new ReplaceResultBuilder(subject); |
| 384 // There's at least one match. If the regexp is global, we have to loop | 421 // There's at least one match. If the regexp is global, we have to loop |
| 385 // over all matches. The loop is not in C++ code here like the one in | 422 // over all matches. The loop is not in C++ code here like the one in |
| 386 // RegExp.prototype.exec, because of the interleaved function application. | 423 // RegExp.prototype.exec, because of the interleaved function application. |
| 387 // Unfortunately, that means this code is nearly duplicated, here and in | 424 // Unfortunately, that means this code is nearly duplicated, here and in |
| 388 // jsregexp.cc. | 425 // jsregexp.cc. |
| 389 if (regexp.global) { | 426 if (regexp.global) { |
| 390 var numberOfCaptures = NUMBER_OF_CAPTURES(matchInfo) >> 1; | |
| 391 var previous = 0; | 427 var previous = 0; |
| 392 do { | 428 var startOfMatch; |
| 393 var startOfMatch = matchInfo[CAPTURE0]; | 429 if (NUMBER_OF_CAPTURES(matchInfo) == 2) { |
| 394 result.addSpecialSlice(previous, startOfMatch); | 430 // Both branches contain essentially the same loop except for the call |
| 395 previous = matchInfo[CAPTURE1]; | 431 // to the replace function. The branch is put outside of the loop for |
| 396 if (numberOfCaptures == 1) { | 432 // speed |
| 433 do { |
| 434 startOfMatch = matchInfo[CAPTURE0]; |
| 435 result.addSpecialSlice(previous, startOfMatch); |
| 436 previous = matchInfo[CAPTURE1]; |
| 397 var match = SubString(subject, startOfMatch, previous); | 437 var match = SubString(subject, startOfMatch, previous); |
| 398 // Don't call directly to avoid exposing the built-in global object. | 438 // Don't call directly to avoid exposing the built-in global object. |
| 399 result.add(replace.call(null, match, startOfMatch, subject)); | 439 result.add(replace.call(null, match, startOfMatch, subject)); |
| 400 } else { | 440 // Can't use matchInfo any more from here, since the function could |
| 441 // overwrite it. |
| 442 // Continue with the next match. |
| 443 // Increment previous if we matched an empty string, as per ECMA-262 |
| 444 // 15.5.4.10. |
| 445 if (previous == startOfMatch) { |
| 446 // Add the skipped character to the output, if any. |
| 447 if (previous < subject.length) { |
| 448 result.addSpecialSlice(previous, previous + 1); |
| 449 } |
| 450 previous++; |
| 451 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 452 // string length, there is no match |
| 453 if (previous > subject.length) { |
| 454 return result.generate(); |
| 455 } |
| 456 } |
| 457 matchInfo = DoRegExpExec(regexp, subject, previous); |
| 458 } while (!IS_NULL(matchInfo)); |
| 459 } else { |
| 460 do { |
| 461 startOfMatch = matchInfo[CAPTURE0]; |
| 462 result.addSpecialSlice(previous, startOfMatch); |
| 463 previous = matchInfo[CAPTURE1]; |
| 401 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); | 464 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); |
| 402 } | 465 // Can't use matchInfo any more from here, since the function could |
| 403 // Can't use matchInfo any more from here, since the function could | 466 // overwrite it. |
| 404 // overwrite it. | 467 // Continue with the next match. |
| 405 // Continue with the next match. | 468 // Increment previous if we matched an empty string, as per ECMA-262 |
| 406 // Increment previous if we matched an empty string, as per ECMA-262 | 469 // 15.5.4.10. |
| 407 // 15.5.4.10. | 470 if (previous == startOfMatch) { |
| 408 if (previous == startOfMatch) { | 471 // Add the skipped character to the output, if any. |
| 409 // Add the skipped character to the output, if any. | 472 if (previous < subject.length) { |
| 410 if (previous < subject.length) { | 473 result.addSpecialSlice(previous, previous + 1); |
| 411 result.addSpecialSlice(previous, previous + 1); | 474 } |
| 475 previous++; |
| 476 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 477 // string length, there is no match |
| 478 if (previous > subject.length) { |
| 479 return result.generate(); |
| 480 } |
| 412 } | 481 } |
| 413 previous++; | 482 matchInfo = DoRegExpExec(regexp, subject, previous); |
| 414 } | 483 } while (!IS_NULL(matchInfo)); |
| 484 } |
| 415 | 485 |
| 416 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | 486 // Tack on the final right substring after the last match. |
| 417 // string length, there is no match | 487 result.addSpecialSlice(previous, subject.length); |
| 418 matchInfo = (previous > subject.length) | |
| 419 ? null | |
| 420 : DoRegExpExec(regexp, subject, previous); | |
| 421 } while (!IS_NULL(matchInfo)); | |
| 422 | 488 |
| 423 // Tack on the final right substring after the last match, if necessary. | |
| 424 if (previous < subject.length) { | |
| 425 result.addSpecialSlice(previous, subject.length); | |
| 426 } | |
| 427 } else { // Not a global regexp, no need to loop. | 489 } else { // Not a global regexp, no need to loop. |
| 428 result.addSpecialSlice(0, matchInfo[CAPTURE0]); | 490 result.addSpecialSlice(0, matchInfo[CAPTURE0]); |
| 429 var endOfMatch = matchInfo[CAPTURE1]; | 491 var endOfMatch = matchInfo[CAPTURE1]; |
| 430 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); | 492 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); |
| 431 // Can't use matchInfo any more from here, since the function could | 493 // Can't use matchInfo any more from here, since the function could |
| 432 // overwrite it. | 494 // overwrite it. |
| 433 result.addSpecialSlice(endOfMatch, subject.length); | 495 result.addSpecialSlice(endOfMatch, subject.length); |
| 434 } | 496 } |
| 435 | 497 |
| 436 return result.generate(); | 498 return result.generate(); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 | 572 |
| 511 | 573 |
| 512 // ECMA-262 section 15.5.4.14 | 574 // ECMA-262 section 15.5.4.14 |
| 513 function StringSplit(separator, limit) { | 575 function StringSplit(separator, limit) { |
| 514 var subject = TO_STRING_INLINE(this); | 576 var subject = TO_STRING_INLINE(this); |
| 515 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); | 577 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); |
| 516 if (limit === 0) return []; | 578 if (limit === 0) return []; |
| 517 | 579 |
| 518 // ECMA-262 says that if separator is undefined, the result should | 580 // ECMA-262 says that if separator is undefined, the result should |
| 519 // be an array of size 1 containing the entire string. SpiderMonkey | 581 // be an array of size 1 containing the entire string. SpiderMonkey |
| 520 // and KJS have this behaviour only when no separator is given. If | 582 // and KJS have this behavior only when no separator is given. If |
| 521 // undefined is explicitly given, they convert it to a string and | 583 // undefined is explicitly given, they convert it to a string and |
| 522 // use that. We do as SpiderMonkey and KJS. | 584 // use that. We do as SpiderMonkey and KJS. |
| 523 if (%_ArgumentsLength() === 0) { | 585 if (%_ArgumentsLength() === 0) { |
| 524 return [subject]; | 586 return [subject]; |
| 525 } | 587 } |
| 526 | 588 |
| 527 var length = subject.length; | 589 var length = subject.length; |
| 528 if (!IS_REGEXP(separator)) { | 590 if (!IS_REGEXP(separator)) { |
| 529 separator = TO_STRING_INLINE(separator); | 591 separator = TO_STRING_INLINE(separator); |
| 530 var separator_length = separator.length; | 592 var separator_length = separator.length; |
| 531 | 593 |
| 532 // If the separator string is empty then return the elements in the subject. | 594 // If the separator string is empty then return the elements in the subject. |
| 533 if (separator_length === 0) return %StringToArray(subject); | 595 if (separator_length === 0) return %StringToArray(subject); |
| 534 | 596 |
| 535 var result = []; | 597 var result = %StringSplit(subject, separator, limit); |
| 536 var start_index = 0; | |
| 537 var index; | |
| 538 while (true) { | |
| 539 if (start_index + separator_length > length || | |
| 540 (index = %StringIndexOf(subject, separator, start_index)) === -1) { | |
| 541 result.push(SubString(subject, start_index, length)); | |
| 542 break; | |
| 543 } | |
| 544 if (result.push(SubString(subject, start_index, index)) === limit) break; | |
| 545 start_index = index + separator_length; | |
| 546 } | |
| 547 | 598 |
| 548 return result; | 599 return result; |
| 549 } | 600 } |
| 550 | 601 |
| 602 var cache = regExpCache; |
| 603 |
| 604 if (%_ObjectEquals(cache.type, 'split') && |
| 605 %_ObjectEquals(cache.regExp, separator) && |
| 606 %_ObjectEquals(cache.subject, subject)) { |
| 607 return CloneRegexpAnswer(cache.answer); |
| 608 } |
| 609 |
| 610 cache.type = 'split'; |
| 611 cache.regExp = separator; |
| 612 cache.subject = subject; |
| 613 |
| 551 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); | 614 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); |
| 552 | 615 |
| 553 if (length === 0) { | 616 if (length === 0) { |
| 554 if (splitMatch(separator, subject, 0, 0) != null) return []; | 617 if (splitMatch(separator, subject, 0, 0) != null) { |
| 618 cache.answer = []; |
| 619 return []; |
| 620 } |
| 621 cache.answer = [subject]; |
| 555 return [subject]; | 622 return [subject]; |
| 556 } | 623 } |
| 557 | 624 |
| 558 var currentIndex = 0; | 625 var currentIndex = 0; |
| 559 var startIndex = 0; | 626 var startIndex = 0; |
| 560 var result = []; | 627 var result = []; |
| 561 | 628 |
| 562 while (true) { | 629 while (true) { |
| 563 | 630 |
| 564 if (startIndex === length) { | 631 if (startIndex === length) { |
| 565 result[result.length] = subject.slice(currentIndex, length); | 632 result[result.length] = subject.slice(currentIndex, length); |
| 566 return result; | 633 cache.answer = result; |
| 634 return CloneRegexpAnswer(result); |
| 567 } | 635 } |
| 568 | 636 |
| 569 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); | 637 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); |
| 570 | 638 |
| 571 if (IS_NULL(matchInfo)) { | 639 if (IS_NULL(matchInfo)) { |
| 572 result[result.length] = subject.slice(currentIndex, length); | 640 result[result.length] = subject.slice(currentIndex, length); |
| 573 return result; | 641 cache.answer = result; |
| 642 return CloneRegexpAnswer(result); |
| 574 } | 643 } |
| 575 | 644 |
| 576 var endIndex = matchInfo[CAPTURE1]; | 645 var endIndex = matchInfo[CAPTURE1]; |
| 577 | 646 |
| 578 // We ignore a zero-length match at the currentIndex. | 647 // We ignore a zero-length match at the currentIndex. |
| 579 if (startIndex === endIndex && endIndex === currentIndex) { | 648 if (startIndex === endIndex && endIndex === currentIndex) { |
| 580 startIndex++; | 649 startIndex++; |
| 581 continue; | 650 continue; |
| 582 } | 651 } |
| 583 | 652 |
| 584 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); | 653 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); |
| 585 if (result.length === limit) return result; | 654 if (result.length === limit) { |
| 655 cache.answer = result; |
| 656 return CloneRegexpAnswer(result); |
| 657 } |
| 586 | 658 |
| 587 var num_captures = NUMBER_OF_CAPTURES(matchInfo); | 659 var num_captures = NUMBER_OF_CAPTURES(matchInfo); |
| 588 for (var i = 2; i < num_captures; i += 2) { | 660 for (var i = 2; i < num_captures; i += 2) { |
| 589 var start = matchInfo[CAPTURE(i)]; | 661 var start = matchInfo[CAPTURE(i)]; |
| 590 var end = matchInfo[CAPTURE(i + 1)]; | 662 var end = matchInfo[CAPTURE(i + 1)]; |
| 591 if (start != -1 && end != -1) { | 663 if (start != -1 && end != -1) { |
| 592 result[result.length] = SubString(subject, start, end); | 664 result[result.length] = SubString(subject, start, end); |
| 593 } else { | 665 } else { |
| 594 result[result.length] = void 0; | 666 result[result.length] = void 0; |
| 595 } | 667 } |
| 596 if (result.length === limit) return result; | 668 if (result.length === limit) { |
| 669 cache.answer = result; |
| 670 return CloneRegexpAnswer(result); |
| 671 } |
| 597 } | 672 } |
| 598 | 673 |
| 599 startIndex = currentIndex = endIndex; | 674 startIndex = currentIndex = endIndex; |
| 600 } | 675 } |
| 601 } | 676 } |
| 602 | 677 |
| 603 | 678 |
| 604 // ECMA-262 section 15.5.4.14 | 679 // ECMA-262 section 15.5.4.14 |
| 605 // Helper function used by split. This version returns the matchInfo | 680 // Helper function used by split. This version returns the matchInfo |
| 606 // instead of allocating a new array with basically the same information. | 681 // instead of allocating a new array with basically the same information. |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 } | 787 } |
| 713 | 788 |
| 714 function StringTrimLeft() { | 789 function StringTrimLeft() { |
| 715 return %StringTrim(TO_STRING_INLINE(this), true, false); | 790 return %StringTrim(TO_STRING_INLINE(this), true, false); |
| 716 } | 791 } |
| 717 | 792 |
| 718 function StringTrimRight() { | 793 function StringTrimRight() { |
| 719 return %StringTrim(TO_STRING_INLINE(this), false, true); | 794 return %StringTrim(TO_STRING_INLINE(this), false, true); |
| 720 } | 795 } |
| 721 | 796 |
| 797 var static_charcode_array = new $Array(4); |
| 798 |
| 722 // ECMA-262, section 15.5.3.2 | 799 // ECMA-262, section 15.5.3.2 |
| 723 function StringFromCharCode(code) { | 800 function StringFromCharCode(code) { |
| 724 var n = %_ArgumentsLength(); | 801 var n = %_ArgumentsLength(); |
| 725 if (n == 1) return %_CharFromCode(ToNumber(code) & 0xffff) | 802 if (n == 1) { |
| 803 if (!%_IsSmi(code)) code = ToNumber(code); |
| 804 return %_CharFromCode(code & 0xffff); |
| 805 } |
| 726 | 806 |
| 727 // NOTE: This is not super-efficient, but it is necessary because we | 807 // NOTE: This is not super-efficient, but it is necessary because we |
| 728 // want to avoid converting to numbers from within the virtual | 808 // want to avoid converting to numbers from within the virtual |
| 729 // machine. Maybe we can find another way of doing this? | 809 // machine. Maybe we can find another way of doing this? |
| 730 var codes = new $Array(n); | 810 var codes = static_charcode_array; |
| 731 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); | 811 for (var i = 0; i < n; i++) { |
| 812 var code = %_Arguments(i); |
| 813 if (!%_IsSmi(code)) code = ToNumber(code); |
| 814 codes[i] = code; |
| 815 } |
| 816 codes.length = n; |
| 732 return %StringFromCharCodeArray(codes); | 817 return %StringFromCharCodeArray(codes); |
| 733 } | 818 } |
| 734 | 819 |
| 735 | 820 |
| 736 // Helper function for very basic XSS protection. | 821 // Helper function for very basic XSS protection. |
| 737 function HtmlEscape(str) { | 822 function HtmlEscape(str) { |
| 738 return TO_STRING_INLINE(str).replace(/</g, "<") | 823 return TO_STRING_INLINE(str).replace(/</g, "<") |
| 739 .replace(/>/g, ">") | 824 .replace(/>/g, ">") |
| 740 .replace(/"/g, """) | 825 .replace(/"/g, """) |
| 741 .replace(/'/g, "'"); | 826 .replace(/'/g, "'"); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 "small", StringSmall, | 986 "small", StringSmall, |
| 902 "strike", StringStrike, | 987 "strike", StringStrike, |
| 903 "sub", StringSub, | 988 "sub", StringSub, |
| 904 "sup", StringSup, | 989 "sup", StringSup, |
| 905 "toJSON", StringToJSON | 990 "toJSON", StringToJSON |
| 906 )); | 991 )); |
| 907 } | 992 } |
| 908 | 993 |
| 909 | 994 |
| 910 SetupString(); | 995 SetupString(); |
| OLD | NEW |