2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Torch Mobile, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "StringPrototype.h"
25 #include "CachedCall.h"
27 #include "JSFunction.h"
28 #include "ObjectPrototype.h"
29 #include "PropertyNameArray.h"
30 #include "RegExpConstructor.h"
31 #include "RegExpObject.h"
32 #include <wtf/ASCIICType.h>
33 #include <wtf/MathExtras.h>
34 #include <wtf/unicode/Collator.h>
40 ASSERT_CLASS_FITS_IN_CELL(StringPrototype);
42 static JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
43 static JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*, JSObject*, JSValue, const ArgList&);
44 static JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue, const ArgList&);
45 static JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*, JSObject*, JSValue, const ArgList&);
46 static JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
47 static JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
48 static JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*, JSObject*, JSValue, const ArgList&);
49 static JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*, JSObject*, JSValue, const ArgList&);
50 static JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*, JSObject*, JSValue, const ArgList&);
51 static JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*, JSObject*, JSValue, const ArgList&);
52 static JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*, JSObject*, JSValue, const ArgList&);
53 static JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*, JSObject*, JSValue, const ArgList&);
54 static JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*, JSObject*, JSValue, const ArgList&);
55 static JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*, JSObject*, JSValue, const ArgList&);
56 static JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*, JSObject*, JSValue, const ArgList&);
57 static JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*, JSObject*, JSValue, const ArgList&);
59 static JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*, JSObject*, JSValue, const ArgList&);
60 static JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*, JSObject*, JSValue, const ArgList&);
61 static JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*, JSObject*, JSValue, const ArgList&);
62 static JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*, JSObject*, JSValue, const ArgList&);
63 static JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*, JSObject*, JSValue, const ArgList&);
64 static JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*, JSObject*, JSValue, const ArgList&);
65 static JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*, JSObject*, JSValue, const ArgList&);
66 static JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*, JSObject*, JSValue, const ArgList&);
67 static JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*, JSObject*, JSValue, const ArgList&);
68 static JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*, JSObject*, JSValue, const ArgList&);
69 static JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*, JSObject*, JSValue, const ArgList&);
70 static JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*, JSObject*, JSValue, const ArgList&);
71 static JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*, JSObject*, JSValue, const ArgList&);
75 #include "StringPrototype.lut.h"
79 const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable };
81 /* Source for StringPrototype.lut.h
83 toString stringProtoFuncToString DontEnum|Function 0
84 valueOf stringProtoFuncToString DontEnum|Function 0
85 charAt stringProtoFuncCharAt DontEnum|Function 1
86 charCodeAt stringProtoFuncCharCodeAt DontEnum|Function 1
87 concat stringProtoFuncConcat DontEnum|Function 1
88 indexOf stringProtoFuncIndexOf DontEnum|Function 1
89 lastIndexOf stringProtoFuncLastIndexOf DontEnum|Function 1
90 match stringProtoFuncMatch DontEnum|Function 1
91 replace stringProtoFuncReplace DontEnum|Function 2
92 search stringProtoFuncSearch DontEnum|Function 1
93 slice stringProtoFuncSlice DontEnum|Function 2
94 split stringProtoFuncSplit DontEnum|Function 2
95 substr stringProtoFuncSubstr DontEnum|Function 2
96 substring stringProtoFuncSubstring DontEnum|Function 2
97 toLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
98 toUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
99 localeCompare stringProtoFuncLocaleCompare DontEnum|Function 1
101 # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase
102 toLocaleLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
103 toLocaleUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
105 big stringProtoFuncBig DontEnum|Function 0
106 small stringProtoFuncSmall DontEnum|Function 0
107 blink stringProtoFuncBlink DontEnum|Function 0
108 bold stringProtoFuncBold DontEnum|Function 0
109 fixed stringProtoFuncFixed DontEnum|Function 0
110 italics stringProtoFuncItalics DontEnum|Function 0
111 strike stringProtoFuncStrike DontEnum|Function 0
112 sub stringProtoFuncSub DontEnum|Function 0
113 sup stringProtoFuncSup DontEnum|Function 0
114 fontcolor stringProtoFuncFontcolor DontEnum|Function 1
115 fontsize stringProtoFuncFontsize DontEnum|Function 1
116 anchor stringProtoFuncAnchor DontEnum|Function 1
117 link stringProtoFuncLink DontEnum|Function 1
122 StringPrototype::StringPrototype(ExecState* exec, PassRefPtr<Structure> structure)
123 : StringObject(exec, structure)
125 // The constructor will be added later, after StringConstructor has been built
126 putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum);
129 bool StringPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
131 return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), this, propertyName, slot);
134 // ------------------------------ Functions --------------------------
136 static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
138 UString substitutedReplacement;
141 while ((i = replacement.find('$', i + 1)) != -1) {
142 if (i + 1 == replacement.size())
145 UChar ref = replacement[i + 1];
149 substitutedReplacement.append(replacement.data() + offset, i - offset);
158 backrefStart = ovector[0];
159 backrefLength = ovector[1] - backrefStart;
160 } else if (ref == '`') {
162 backrefLength = ovector[0];
163 } else if (ref == '\'') {
164 backrefStart = ovector[1];
165 backrefLength = source.size() - backrefStart;
166 } else if (reg && ref >= '0' && ref <= '9') {
167 // 1- and 2-digit back references are allowed
168 unsigned backrefIndex = ref - '0';
169 if (backrefIndex > reg->numSubpatterns())
171 if (replacement.size() > i + 2) {
172 ref = replacement[i + 2];
173 if (ref >= '0' && ref <= '9') {
174 backrefIndex = 10 * backrefIndex + ref - '0';
175 if (backrefIndex > reg->numSubpatterns())
176 backrefIndex = backrefIndex / 10; // Fall back to the 1-digit reference
183 backrefStart = ovector[2 * backrefIndex];
184 backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
189 substitutedReplacement.append(replacement.data() + offset, i - offset);
192 substitutedReplacement.append(source.data() + backrefStart, backrefLength);
198 if (replacement.size() - offset)
199 substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
201 return substitutedReplacement;
204 static inline int localeCompare(const UString& a, const UString& b)
206 return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size());
209 JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
211 JSString* sourceVal = thisValue.toThisJSString(exec);
212 const UString& source = sourceVal->value();
214 JSValue pattern = args.at(0);
216 JSValue replacement = args.at(1);
217 UString replacementString;
219 CallType callType = replacement.getCallData(callData);
220 if (callType == CallTypeNone)
221 replacementString = replacement.toString(exec);
223 if (pattern.isObject(&RegExpObject::info)) {
224 RegExp* reg = asRegExpObject(pattern)->regExp();
225 bool global = reg->global();
227 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
230 int startPosition = 0;
232 Vector<UString::Range, 16> sourceRanges;
233 Vector<UString, 16> replacements;
235 // This is either a loop (if global is set) or a one-way (if not).
236 if (global && callType == CallTypeJS) {
237 // reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue
238 int argCount = reg->numSubpatterns() + 1 + 2;
239 JSFunction* func = asFunction(replacement);
240 CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot());
241 if (exec->hadException())
247 regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
251 sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex));
253 int completeMatchStart = ovector[0];
255 for (; i < reg->numSubpatterns() + 1; ++i) {
256 int matchStart = ovector[i * 2];
257 int matchLen = ovector[i * 2 + 1] - matchStart;
260 cachedCall.setArgument(i, jsUndefined());
262 cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen));
265 cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart));
266 cachedCall.setArgument(i++, sourceVal);
268 cachedCall.setThis(exec->globalThisValue());
269 replacements.append(cachedCall.call().toString(cachedCall.newCallFrame()));
270 if (exec->hadException())
273 lastIndex = matchIndex + matchLen;
274 startPosition = lastIndex;
276 // special case of empty match
279 if (startPosition > source.size())
288 regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
292 sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex));
294 if (callType != CallTypeNone) {
295 int completeMatchStart = ovector[0];
296 MarkedArgumentBuffer args;
298 for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) {
299 int matchStart = ovector[i * 2];
300 int matchLen = ovector[i * 2 + 1] - matchStart;
303 args.append(jsUndefined());
305 args.append(jsSubstring(exec, source, matchStart, matchLen));
308 args.append(jsNumber(exec, completeMatchStart));
309 args.append(sourceVal);
311 replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec));
312 if (exec->hadException())
315 replacements.append(substituteBackreferences(replacementString, source, ovector, reg));
317 lastIndex = matchIndex + matchLen;
318 startPosition = lastIndex;
320 // special case of empty match
323 if (startPosition > source.size())
329 if (!lastIndex && replacements.isEmpty())
332 if (lastIndex < source.size())
333 sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex));
335 return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(),
336 replacements.data(), replacements.size()));
339 // Not a regular expression, so treat the pattern as a string.
341 UString patternString = pattern.toString(exec);
342 int matchPos = source.find(patternString);
347 int matchLen = patternString.size();
348 if (callType != CallTypeNone) {
349 MarkedArgumentBuffer args;
350 args.append(jsSubstring(exec, source, matchPos, matchLen));
351 args.append(jsNumber(exec, matchPos));
352 args.append(sourceVal);
354 replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec);
357 int ovector[2] = { matchPos, matchPos + matchLen };
358 return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0)));
361 JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
363 // Also used for valueOf.
365 if (thisValue.isString())
368 if (thisValue.isObject(&StringObject::info))
369 return asStringObject(thisValue)->internalValue();
371 return throwError(exec, TypeError);
374 JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
376 UString s = thisValue.toThisString(exec);
377 unsigned len = s.size();
378 JSValue a0 = args.at(0);
379 if (a0.isUInt32Fast()) {
380 uint32_t i = a0.getUInt32Fast();
382 return jsSingleCharacterSubstring(exec, s, i);
383 return jsEmptyString(exec);
385 double dpos = a0.toInteger(exec);
386 if (dpos >= 0 && dpos < len)
387 return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos));
388 return jsEmptyString(exec);
391 JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
393 UString s = thisValue.toThisString(exec);
394 unsigned len = s.size();
395 JSValue a0 = args.at(0);
396 if (a0.isUInt32Fast()) {
397 uint32_t i = a0.getUInt32Fast();
399 return jsNumber(exec, s.data()[i]);
402 double dpos = a0.toInteger(exec);
403 if (dpos >= 0 && dpos < len)
404 return jsNumber(exec, s[static_cast<int>(dpos)]);
408 JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
410 UString s = thisValue.toThisString(exec);
412 ArgList::const_iterator end = args.end();
413 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
414 s += (*it).toString(exec);
415 return jsString(exec, s);
418 JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
420 UString s = thisValue.toThisString(exec);
423 JSValue a0 = args.at(0);
424 JSValue a1 = args.at(1);
425 UString u2 = a0.toString(exec);
427 if (a1.isUndefined())
429 else if (a1.isUInt32Fast())
430 pos = min<uint32_t>(a1.getUInt32Fast(), len);
432 double dpos = a1.toInteger(exec);
437 pos = static_cast<int>(dpos);
440 return jsNumber(exec, s.find(u2, pos));
443 JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
445 UString s = thisValue.toThisString(exec);
448 JSValue a0 = args.at(0);
449 JSValue a1 = args.at(1);
451 UString u2 = a0.toString(exec);
452 double dpos = a1.toIntegerPreserveNaN(exec);
455 else if (!(dpos <= len)) // true for NaN
457 return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos)));
460 JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
462 UString s = thisValue.toThisString(exec);
464 JSValue a0 = args.at(0);
468 RegExpObject* imp = 0;
469 if (a0.isObject(&RegExpObject::info))
470 reg = asRegExpObject(a0)->regExp();
473 * ECMA 15.5.4.12 String.prototype.search (regexp)
474 * If regexp is not an object whose [[Class]] property is "RegExp", it is
475 * replaced with the result of the expression new RegExp(regexp).
477 reg = RegExp::create(&exec->globalData(), a0.toString(exec));
479 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
482 regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength);
483 if (!(reg->global())) {
484 // case without 'g' flag is handled like RegExp.prototype.exec
487 return regExpConstructor->arrayOfMatches(exec);
490 // return array of matches
491 MarkedArgumentBuffer list;
494 list.append(jsSubstring(exec, u, pos, matchLength));
496 pos += matchLength == 0 ? 1 : matchLength;
497 regExpConstructor->performMatch(reg.get(), u, pos, pos, matchLength);
500 imp->setLastIndex(lastIndex);
501 if (list.isEmpty()) {
502 // if there are no matches at all, it's important to return
503 // Null instead of an empty array, because this matches
504 // other browsers and because Null is a false value.
508 return constructArray(exec, list);
511 JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
513 UString s = thisValue.toThisString(exec);
515 JSValue a0 = args.at(0);
519 if (a0.isObject(&RegExpObject::info))
520 reg = asRegExpObject(a0)->regExp();
523 * ECMA 15.5.4.12 String.prototype.search (regexp)
524 * If regexp is not an object whose [[Class]] property is "RegExp", it is
525 * replaced with the result of the expression new RegExp(regexp).
527 reg = RegExp::create(&exec->globalData(), a0.toString(exec));
529 RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
532 regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength);
533 return jsNumber(exec, pos);
536 JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
538 UString s = thisValue.toThisString(exec);
541 JSValue a0 = args.at(0);
542 JSValue a1 = args.at(1);
544 // The arg processing is very much like ArrayProtoFunc::Slice
545 double start = a0.toInteger(exec);
546 double end = a1.isUndefined() ? len : a1.toInteger(exec);
547 double from = start < 0 ? len + start : start;
548 double to = end < 0 ? len + end : end;
549 if (to > from && to > 0 && from < len) {
554 return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
557 return jsEmptyString(exec);
560 JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
562 UString s = thisValue.toThisString(exec);
564 JSValue a0 = args.at(0);
565 JSValue a1 = args.at(1);
567 JSArray* result = constructEmptyArray(exec);
570 unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec);
571 if (a0.isObject(&RegExpObject::info)) {
572 RegExp* reg = asRegExpObject(a0)->regExp();
573 if (s.isEmpty() && reg->match(s, 0) >= 0) {
574 // empty string matched by regexp -> empty array
578 while (i != limit && pos < s.size()) {
579 Vector<int, 32> ovector;
580 int mpos = reg->match(s, pos, &ovector);
583 int mlen = ovector[1] - ovector[0];
584 pos = mpos + (mlen == 0 ? 1 : mlen);
585 if (mpos != p0 || mlen) {
586 result->put(exec, i++, jsSubstring(exec, s, p0, mpos - p0));
589 for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) {
590 int spos = ovector[si * 2];
592 result->put(exec, i++, jsUndefined());
594 result->put(exec, i++, jsSubstring(exec, s, spos, ovector[si * 2 + 1] - spos));
598 UString u2 = a0.toString(exec);
601 // empty separator matches empty string -> empty array
604 while (i != limit && p0 < s.size() - 1)
605 result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++));
608 while (i != limit && (pos = s.find(u2, p0)) >= 0) {
609 result->put(exec, i++, jsSubstring(exec, s, p0, pos - p0));
610 p0 = pos + u2.size();
615 // add remaining string
617 result->put(exec, i++, jsSubstring(exec, s, p0, s.size() - p0));
622 JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
624 UString s = thisValue.toThisString(exec);
627 JSValue a0 = args.at(0);
628 JSValue a1 = args.at(1);
630 double start = a0.toInteger(exec);
631 double length = a1.isUndefined() ? len : a1.toInteger(exec);
632 if (start >= len || length <= 0)
633 return jsEmptyString(exec);
639 if (start + length > len)
640 length = len - start;
641 return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length));
644 JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
646 UString s = thisValue.toThisString(exec);
649 JSValue a0 = args.at(0);
650 JSValue a1 = args.at(1);
652 double start = a0.toNumber(exec);
653 double end = a1.toNumber(exec);
666 if (a1.isUndefined())
673 return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(end) - static_cast<unsigned>(start));
676 JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
678 JSString* sVal = thisValue.toThisJSString(exec);
679 const UString& s = sVal->value();
681 int sSize = s.size();
685 const UChar* sData = s.data();
686 Vector<UChar> buffer(sSize);
689 for (int i = 0; i < sSize; i++) {
692 buffer[i] = toASCIILower(c);
695 return jsString(exec, UString(buffer.releaseBuffer(), sSize, false));
698 int length = Unicode::toLower(buffer.data(), sSize, sData, sSize, &error);
700 buffer.resize(length);
701 length = Unicode::toLower(buffer.data(), length, sData, sSize, &error);
705 if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
707 return jsString(exec, UString(buffer.releaseBuffer(), length, false));
710 JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
712 JSString* sVal = thisValue.toThisJSString(exec);
713 const UString& s = sVal->value();
715 int sSize = s.size();
719 const UChar* sData = s.data();
720 Vector<UChar> buffer(sSize);
723 for (int i = 0; i < sSize; i++) {
726 buffer[i] = toASCIIUpper(c);
729 return jsString(exec, UString(buffer.releaseBuffer(), sSize, false));
732 int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error);
734 buffer.resize(length);
735 length = Unicode::toUpper(buffer.data(), length, sData, sSize, &error);
739 if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
741 return jsString(exec, UString(buffer.releaseBuffer(), length, false));
744 JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
747 return jsNumber(exec, 0);
749 UString s = thisValue.toThisString(exec);
750 JSValue a0 = args.at(0);
751 return jsNumber(exec, localeCompare(s, a0.toString(exec)));
754 JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
756 UString s = thisValue.toThisString(exec);
757 return jsNontrivialString(exec, "<big>" + s + "</big>");
760 JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
762 UString s = thisValue.toThisString(exec);
763 return jsNontrivialString(exec, "<small>" + s + "</small>");
766 JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
768 UString s = thisValue.toThisString(exec);
769 return jsNontrivialString(exec, "<blink>" + s + "</blink>");
772 JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
774 UString s = thisValue.toThisString(exec);
775 return jsNontrivialString(exec, "<b>" + s + "</b>");
778 JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
780 UString s = thisValue.toThisString(exec);
781 return jsString(exec, "<tt>" + s + "</tt>");
784 JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
786 UString s = thisValue.toThisString(exec);
787 return jsNontrivialString(exec, "<i>" + s + "</i>");
790 JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
792 UString s = thisValue.toThisString(exec);
793 return jsNontrivialString(exec, "<strike>" + s + "</strike>");
796 JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
798 UString s = thisValue.toThisString(exec);
799 return jsNontrivialString(exec, "<sub>" + s + "</sub>");
802 JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
804 UString s = thisValue.toThisString(exec);
805 return jsNontrivialString(exec, "<sup>" + s + "</sup>");
808 JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
810 UString s = thisValue.toThisString(exec);
811 JSValue a0 = args.at(0);
812 return jsNontrivialString(exec, "<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
815 JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
817 UString s = thisValue.toThisString(exec);
818 JSValue a0 = args.at(0);
820 uint32_t smallInteger;
821 if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
822 unsigned stringSize = s.size();
823 unsigned bufferSize = 22 + stringSize;
824 UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar)));
826 return jsUndefined();
839 buffer[12] = '0' + smallInteger;
842 memcpy(&buffer[15], s.data(), stringSize * sizeof(UChar));
843 buffer[15 + stringSize] = '<';
844 buffer[16 + stringSize] = '/';
845 buffer[17 + stringSize] = 'f';
846 buffer[18 + stringSize] = 'o';
847 buffer[19 + stringSize] = 'n';
848 buffer[20 + stringSize] = 't';
849 buffer[21 + stringSize] = '>';
850 return jsNontrivialString(exec, UString(buffer, bufferSize, false));
853 return jsNontrivialString(exec, "<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
856 JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
858 UString s = thisValue.toThisString(exec);
859 JSValue a0 = args.at(0);
860 return jsNontrivialString(exec, "<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
863 JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
865 UString s = thisValue.toThisString(exec);
866 JSValue a0 = args.at(0);
867 UString linkText = a0.toString(exec);
869 unsigned linkTextSize = linkText.size();
870 unsigned stringSize = s.size();
871 unsigned bufferSize = 15 + linkTextSize + stringSize;
872 UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar)));
874 return jsUndefined();
884 memcpy(&buffer[9], linkText.data(), linkTextSize * sizeof(UChar));
885 buffer[9 + linkTextSize] = '"';
886 buffer[10 + linkTextSize] = '>';
887 memcpy(&buffer[11 + linkTextSize], s.data(), stringSize * sizeof(UChar));
888 buffer[11 + linkTextSize + stringSize] = '<';
889 buffer[12 + linkTextSize + stringSize] = '/';
890 buffer[13 + linkTextSize + stringSize] = 'a';
891 buffer[14 + linkTextSize + stringSize] = '>';
892 return jsNontrivialString(exec, UString(buffer, bufferSize, false));