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