00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "value.h"
00024 #include "object.h"
00025 #include "types.h"
00026 #include "interpreter.h"
00027 #include "operations.h"
00028 #include "regexp.h"
00029 #include "regexp_object.h"
00030 #include "string_object.h"
00031 #include "error_object.h"
00032 #include <stdio.h>
00033 #include "string_object.lut.h"
00034
00035 using namespace KJS;
00036
00037
00038
00039 const ClassInfo StringInstanceImp::info = {"String", 0, 0, 0};
00040
00041 StringInstanceImp::StringInstanceImp(ObjectImp *proto)
00042 : ObjectImp(proto)
00043 {
00044 setInternalValue(String(""));
00045 }
00046
00047 StringInstanceImp::StringInstanceImp(ObjectImp *proto, const UString &string)
00048 : ObjectImp(proto)
00049 {
00050 setInternalValue(String(string));
00051 }
00052
00053 Value StringInstanceImp::get(ExecState *exec, const Identifier &propertyName) const
00054 {
00055 if (propertyName == lengthPropertyName)
00056 return Number(internalValue().toString(exec).size());
00057
00058 bool ok;
00059 const unsigned index = propertyName.toArrayIndex(&ok);
00060 if (ok) {
00061 const UString s = internalValue().toString(exec);
00062 const unsigned length = s.size();
00063 if (index < length) {
00064 const UChar c = s[index];
00065 return String(UString(&c, 1));
00066 }
00067 }
00068
00069 return ObjectImp::get(exec, propertyName);
00070 }
00071
00072 void StringInstanceImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
00073 {
00074 if (propertyName == lengthPropertyName)
00075 return;
00076 ObjectImp::put(exec, propertyName, value, attr);
00077 }
00078
00079 bool StringInstanceImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
00080 {
00081 if (propertyName == lengthPropertyName)
00082 return true;
00083
00084 bool ok;
00085 unsigned index = propertyName.toULong(&ok);
00086 if (ok && index < (unsigned)internalValue().toString(exec).size())
00087 return true;
00088
00089 return ObjectImp::hasProperty(exec, propertyName);
00090 }
00091
00092 bool StringInstanceImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
00093 {
00094 if (propertyName == lengthPropertyName)
00095 return false;
00096
00097 bool ok;
00098 unsigned index = propertyName.toULong(&ok);
00099 if (ok && index < (unsigned)internalValue().toString(exec).size())
00100 return false;
00101
00102 return ObjectImp::deleteProperty(exec, propertyName);
00103 }
00104
00105 ReferenceList StringInstanceImp::propList(ExecState *exec, bool recursive)
00106 {
00107 ReferenceList properties = ObjectImp::propList(exec,recursive);
00108
00109 UString str = internalValue().toString(exec);
00110 for (int i = 0; i < str.size(); i++)
00111 if (!ObjectImp::hasProperty(exec,Identifier::from(i)))
00112 properties.append(Reference(this, i));
00113
00114 return properties;
00115 }
00116
00117
00118 const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0};
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 StringPrototypeImp::StringPrototypeImp(ExecState *,
00158 ObjectPrototypeImp *objProto)
00159 : StringInstanceImp(objProto)
00160 {
00161 Value protect(this);
00162
00163 putDirect(lengthPropertyName, NumberImp::zero(), DontDelete|ReadOnly|DontEnum);
00164
00165 }
00166
00167 Value StringPrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
00168 {
00169 return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this );
00170 }
00171
00172
00173
00174 StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len)
00175 : InternalFunctionImp(
00176 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
00177 ), id(i)
00178 {
00179 Value protect(this);
00180 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00181 }
00182
00183 bool StringProtoFuncImp::implementsCall() const
00184 {
00185 return true;
00186 }
00187
00188
00189 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00190 {
00191 Value result;
00192
00193
00194 if (id == ToString || id == ValueOf) {
00195 KJS_CHECK_THIS( StringInstanceImp, thisObj );
00196
00197 return String(thisObj.internalValue().toString(exec));
00198 }
00199
00200 int n, m;
00201 UString u2, u3;
00202 int pos, p0, i;
00203 double d = 0.0;
00204
00205 UString s = thisObj.toString(exec);
00206
00207 int len = s.size();
00208 Value a0 = args[0];
00209 Value a1 = args[1];
00210
00211 switch (id) {
00212 case ToString:
00213 case ValueOf:
00214
00215 break;
00216 case CharAt:
00217 pos = a0.toInteger(exec);
00218 if (pos < 0 || pos >= len)
00219 s = "";
00220 else
00221 s = s.substr(pos, 1);
00222 result = String(s);
00223 break;
00224 case CharCodeAt:
00225 pos = a0.toInteger(exec);
00226 if (pos < 0 || pos >= len)
00227 d = NaN;
00228 else {
00229 UChar c = s[pos];
00230 d = (c.high() << 8) + c.low();
00231 }
00232 result = Number(d);
00233 break;
00234 case Concat: {
00235 ListIterator it = args.begin();
00236 for ( ; it != args.end() ; ++it) {
00237 s += it->dispatchToString(exec);
00238 }
00239 result = String(s);
00240 break;
00241 }
00242 case IndexOf:
00243 u2 = a0.toString(exec);
00244 if (a1.type() == UndefinedType)
00245 pos = 0;
00246 else
00247 pos = a1.toInteger(exec);
00248 d = s.find(u2, pos);
00249 result = Number(d);
00250 break;
00251 case LastIndexOf:
00252 u2 = a0.toString(exec);
00253 d = a1.toNumber(exec);
00254 if (a1.type() == UndefinedType || KJS::isNaN(d) || KJS::isPosInf(d))
00255 pos = len;
00256 else
00257 pos = a1.toInteger(exec);
00258 if (pos < 0)
00259 pos = 0;
00260 d = s.rfind(u2, pos);
00261 result = Number(d);
00262 break;
00263 case Match:
00264 case Search: {
00265 RegExp *reg, *tmpReg = 0;
00266 RegExpImp *imp = 0;
00267 if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
00268 {
00269 imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00270 reg = imp->regExp();
00271 }
00272 else
00273 {
00274
00275
00276
00277
00278 reg = tmpReg = new RegExp(a0.toString(exec), RegExp::None);
00279 }
00280 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00281 int **ovector = regExpObj->registerRegexp(reg, s);
00282 UString mstr = reg->match(s, -1, &pos, ovector);
00283 if (id == Search) {
00284 result = Number(pos);
00285 } else {
00286 if (mstr.isNull()) {
00287 result = Null();
00288 } else if ((reg->flags() & RegExp::Global) == 0) {
00289
00290 regExpObj->setSubPatterns(reg->subPatterns());
00291 result = regExpObj->arrayOfMatches(exec,mstr);
00292 } else {
00293
00294 List list;
00295 int lastIndex = 0;
00296 while (pos >= 0) {
00297 list.append(String(mstr));
00298 lastIndex = pos;
00299 pos += mstr.isEmpty() ? 1 : mstr.size();
00300 delete [] *ovector;
00301 mstr = reg->match(s, pos, &pos, ovector);
00302 }
00303 result = exec->interpreter()->builtinArray().construct(exec, list);
00304 }
00305 }
00306 delete tmpReg;
00307 break;
00308 }
00309 case Replace:
00310 if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
00311 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00312 RegExp *reg = imp->regExp();
00313 bool global = false;
00314 Value tmp = imp->get(exec,"global");
00315 if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
00316 global = true;
00317
00318 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00319 int lastIndex = 0;
00320 Object o1;
00321
00322 if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00323 o1 = a1.toObject(exec);
00324 else
00325 u3 = a1.toString(exec);
00326
00327
00328 do {
00329 int **ovector = regExpObj->registerRegexp( reg, s );
00330 UString mstr = reg->match(s, lastIndex, &pos, ovector);
00331 regExpObj->setSubPatterns(reg->subPatterns());
00332 if (pos == -1)
00333 break;
00334 len = mstr.size();
00335
00336 UString rstr;
00337
00338 if (!o1.isValid())
00339 {
00340 rstr = u3;
00341 bool ok;
00342
00343 for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00344 if (i+1<rstr.size() && rstr[i+1] == '$') {
00345 rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00346 continue;
00347 }
00348
00349 unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false );
00350 if (ok && pos <= (unsigned)reg->subPatterns()) {
00351 rstr = rstr.substr(0,i)
00352 + s.substr((*ovector)[2*pos],
00353 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00354 + rstr.substr(i+2);
00355 i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1;
00356 }
00357 }
00358 } else
00359 {
00360 List l;
00361 l.append(String(mstr));
00362
00363 for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00364 l.append( String( s.substr((*ovector)[2*sub],
00365 (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00366 l.append(Number(pos));
00367 l.append(String(s));
00368 Object thisObj = exec->interpreter()->globalObject();
00369 rstr = o1.call( exec, thisObj, l ).toString(exec);
00370 }
00371 lastIndex = pos + rstr.size();
00372 s = s.substr(0, pos) + rstr + s.substr(pos + len);
00373
00374 } while (global);
00375
00376 result = String(s);
00377 } else {
00378 u2 = a0.toString(exec);
00379 pos = s.find(u2);
00380 len = u2.size();
00381
00382 if (pos == -1)
00383 result = String(s);
00384 else {
00385 u3 = s.substr(0, pos) + a1.toString(exec) +
00386 s.substr(pos + len);
00387 result = String(u3);
00388 }
00389 }
00390 break;
00391 case Slice:
00392 {
00393
00394 int begin = args[0].toUInt32(exec);
00395 if (begin < 0)
00396 begin = maxInt(begin + len, 0);
00397 else
00398 begin = minInt(begin, len);
00399 int end = len;
00400 if (args[1].type() != UndefinedType) {
00401 end = args[1].toInteger(exec);
00402 if (end < 0)
00403 end = maxInt(len + end, 0);
00404 else
00405 end = minInt(end, len);
00406 }
00407
00408 result = String(s.substr(begin, end-begin));
00409 break;
00410 }
00411 case Split: {
00412 Object constructor = exec->interpreter()->builtinArray();
00413 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00414 result = res;
00415 i = p0 = 0;
00416 d = (a1.type() != UndefinedType) ? a1.toInteger(exec) : -1;
00417 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00418 Object obj0 = Object::dynamicCast(a0);
00419 RegExp reg(obj0.get(exec,"source").toString(exec));
00420 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00421
00422 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00423 break;
00424 }
00425 pos = 0;
00426 while (pos < s.size()) {
00427
00428 int mpos;
00429 int *ovector = 0L;
00430 UString mstr = reg.match(s, pos, &mpos, &ovector);
00431 delete [] ovector; ovector = 0L;
00432 if (mpos < 0)
00433 break;
00434 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00435 if (mpos != p0 || !mstr.isEmpty()) {
00436 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00437 p0 = mpos + mstr.size();
00438 i++;
00439 }
00440 }
00441 } else if (a0.type() != UndefinedType) {
00442 u2 = a0.toString(exec);
00443 if (u2.isEmpty()) {
00444 if (s.isEmpty()) {
00445
00446 put(exec,lengthPropertyName, Number(0));
00447 break;
00448 } else {
00449 while (i != d && i < s.size()-1)
00450 res.put(exec,i++, String(s.substr(p0++, 1)));
00451 }
00452 } else {
00453 while (i != d && (pos = s.find(u2, p0)) >= 0) {
00454 res.put(exec,i, String(s.substr(p0, pos-p0)));
00455 p0 = pos + u2.size();
00456 i++;
00457 }
00458 }
00459 }
00460
00461 if (i != d)
00462 res.put(exec,i++, String(s.substr(p0)));
00463 res.put(exec,lengthPropertyName, Number(i));
00464 }
00465 break;
00466 case Substr: {
00467 n = a0.toInteger(exec);
00468 m = a1.toInteger(exec);
00469 int d, d2;
00470 if (n >= 0)
00471 d = n;
00472 else
00473 d = maxInt(len + n, 0);
00474 if (a1.type() == UndefinedType)
00475 d2 = len - d;
00476 else
00477 d2 = minInt(maxInt(m, 0), len - d);
00478 result = String(s.substr(d, d2));
00479 break;
00480 }
00481 case Substring: {
00482 double start = a0.toNumber(exec);
00483 double end = a1.toNumber(exec);
00484 if (KJS::isNaN(start))
00485 start = 0;
00486 if (KJS::isNaN(end))
00487 end = 0;
00488 if (start < 0)
00489 start = 0;
00490 if (end < 0)
00491 end = 0;
00492 if (start > len)
00493 start = len;
00494 if (end > len)
00495 end = len;
00496 if (a1.type() == UndefinedType)
00497 end = len;
00498 if (start > end) {
00499 double temp = end;
00500 end = start;
00501 start = temp;
00502 }
00503 result = String(s.substr((int)start, (int)end-(int)start));
00504 }
00505 break;
00506 case ToLowerCase:
00507 for (i = 0; i < len; i++)
00508 s[i] = s[i].toLower();
00509 result = String(s);
00510 break;
00511 case ToUpperCase:
00512 for (i = 0; i < len; i++)
00513 s[i] = s[i].toUpper();
00514 result = String(s);
00515 break;
00516 #ifndef KJS_PURE_ECMA
00517 case Big:
00518 result = String("<BIG>" + s + "</BIG>");
00519 break;
00520 case Small:
00521 result = String("<SMALL>" + s + "</SMALL>");
00522 break;
00523 case Blink:
00524 result = String("<BLINK>" + s + "</BLINK>");
00525 break;
00526 case Bold:
00527 result = String("<B>" + s + "</B>");
00528 break;
00529 case Fixed:
00530 result = String("<TT>" + s + "</TT>");
00531 break;
00532 case Italics:
00533 result = String("<I>" + s + "</I>");
00534 break;
00535 case Strike:
00536 result = String("<STRIKE>" + s + "</STRIKE>");
00537 break;
00538 case Sub:
00539 result = String("<SUB>" + s + "</SUB>");
00540 break;
00541 case Sup:
00542 result = String("<SUP>" + s + "</SUP>");
00543 break;
00544 case Fontcolor:
00545 result = String("<FONT COLOR=\"" + a0.toString(exec) + "\">"
00546 + s + "</FONT>");
00547 break;
00548 case Fontsize:
00549 result = String("<FONT SIZE=\"" + a0.toString(exec) + "\">"
00550 + s + "</FONT>");
00551 break;
00552 case Anchor:
00553 result = String("<a name=\"" + a0.toString(exec) + "\">"
00554 + s + "</a>");
00555 break;
00556 case Link:
00557 result = String("<a href=\"" + a0.toString(exec) + "\">"
00558 + s + "</a>");
00559 break;
00560 #endif
00561 }
00562
00563 return result;
00564 }
00565
00566
00567
00568 StringObjectImp::StringObjectImp(ExecState *exec,
00569 FunctionPrototypeImp *funcProto,
00570 StringPrototypeImp *stringProto)
00571 : InternalFunctionImp(funcProto)
00572 {
00573 Value protect(this);
00574
00575 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00576
00577 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00578
00579
00580 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00581 }
00582
00583
00584 bool StringObjectImp::implementsConstruct() const
00585 {
00586 return true;
00587 }
00588
00589
00590 Object StringObjectImp::construct(ExecState *exec, const List &args)
00591 {
00592 ObjectImp *proto = exec->interpreter()->builtinStringPrototype().imp();
00593 if (args.size() == 0)
00594 return Object(new StringInstanceImp(proto));
00595 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00596 }
00597
00598 bool StringObjectImp::implementsCall() const
00599 {
00600 return true;
00601 }
00602
00603
00604 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00605 {
00606 if (args.isEmpty())
00607 return String("");
00608 else {
00609 Value v = args[0];
00610 return String(v.toString(exec));
00611 }
00612 }
00613
00614
00615
00616
00617 StringObjectFuncImp::StringObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto)
00618 : InternalFunctionImp(funcProto)
00619 {
00620 Value protect(this);
00621 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00622 }
00623
00624 bool StringObjectFuncImp::implementsCall() const
00625 {
00626 return true;
00627 }
00628
00629 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00630 {
00631 UString s;
00632 if (args.size()) {
00633 UChar *buf = new UChar[args.size()];
00634 UChar *p = buf;
00635 ListIterator it = args.begin();
00636 while (it != args.end()) {
00637 unsigned short u = it->toUInt16(exec);
00638 *p++ = UChar(u);
00639 it++;
00640 }
00641 s = UString(buf, args.size(), false);
00642 } else
00643 s = "";
00644
00645 return String(s);
00646 }