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 if (len == 0 && lastIndex > 0) {
00334 pos = lastIndex + 1;
00335 if (pos > s.size())
00336 break;
00337 }
00338
00339 UString rstr;
00340
00341 if (!o1.isValid())
00342 {
00343 rstr = u3;
00344 bool ok;
00345
00346 for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00347 if (i+1<rstr.size() && rstr[i+1] == '$') {
00348 rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00349 continue;
00350 }
00351
00352 unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false );
00353 if (ok && pos <= (unsigned)reg->subPatterns()) {
00354 rstr = rstr.substr(0,i)
00355 + s.substr((*ovector)[2*pos],
00356 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00357 + rstr.substr(i+2);
00358 i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1;
00359 }
00360 }
00361 } else
00362 {
00363 List l;
00364 l.append(String(mstr));
00365
00366 for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00367 l.append( String( s.substr((*ovector)[2*sub],
00368 (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00369 l.append(Number(pos));
00370 l.append(String(s));
00371 Object thisObj = exec->interpreter()->globalObject();
00372 rstr = o1.call( exec, thisObj, l ).toString(exec);
00373 }
00374 lastIndex = pos + rstr.size();
00375 s = s.substr(0, pos) + rstr + s.substr(pos + len);
00376
00377 } while (global);
00378
00379 result = String(s);
00380 } else {
00381 u2 = a0.toString(exec);
00382 pos = s.find(u2);
00383 len = u2.size();
00384
00385 if (pos == -1)
00386 result = String(s);
00387 else {
00388 u3 = s.substr(0, pos) + a1.toString(exec) +
00389 s.substr(pos + len);
00390 result = String(u3);
00391 }
00392 }
00393 break;
00394 case Slice:
00395 {
00396
00397 int begin = args[0].toUInt32(exec);
00398 if (begin < 0)
00399 begin = maxInt(begin + len, 0);
00400 else
00401 begin = minInt(begin, len);
00402 int end = len;
00403 if (args[1].type() != UndefinedType) {
00404 end = args[1].toInteger(exec);
00405 if (end < 0)
00406 end = maxInt(len + end, 0);
00407 else
00408 end = minInt(end, len);
00409 }
00410
00411 result = String(s.substr(begin, end-begin));
00412 break;
00413 }
00414 case Split: {
00415 Object constructor = exec->interpreter()->builtinArray();
00416 Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00417 result = res;
00418 i = p0 = 0;
00419 d = (a1.type() != UndefinedType) ? a1.toInteger(exec) : -1;
00420 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00421 Object obj0 = Object::dynamicCast(a0);
00422 RegExp reg(obj0.get(exec,"source").toString(exec));
00423 if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00424
00425 res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00426 break;
00427 }
00428 pos = 0;
00429 while (pos < s.size()) {
00430
00431 int mpos;
00432 int *ovector = 0L;
00433 UString mstr = reg.match(s, pos, &mpos, &ovector);
00434 delete [] ovector; ovector = 0L;
00435 if (mpos < 0)
00436 break;
00437 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00438 if (mpos != p0 || !mstr.isEmpty()) {
00439 res.put(exec,i, String(s.substr(p0, mpos-p0)));
00440 p0 = mpos + mstr.size();
00441 i++;
00442 }
00443 }
00444 } else if (a0.type() != UndefinedType) {
00445 u2 = a0.toString(exec);
00446 if (u2.isEmpty()) {
00447 if (s.isEmpty()) {
00448
00449 put(exec,lengthPropertyName, Number(0));
00450 break;
00451 } else {
00452 while (i != d && i < s.size()-1)
00453 res.put(exec,i++, String(s.substr(p0++, 1)));
00454 }
00455 } else {
00456 while (i != d && (pos = s.find(u2, p0)) >= 0) {
00457 res.put(exec,i, String(s.substr(p0, pos-p0)));
00458 p0 = pos + u2.size();
00459 i++;
00460 }
00461 }
00462 }
00463
00464 if (i != d)
00465 res.put(exec,i++, String(s.substr(p0)));
00466 res.put(exec,lengthPropertyName, Number(i));
00467 }
00468 break;
00469 case Substr: {
00470 n = a0.toInteger(exec);
00471 m = a1.toInteger(exec);
00472 int d, d2;
00473 if (n >= 0)
00474 d = n;
00475 else
00476 d = maxInt(len + n, 0);
00477 if (a1.type() == UndefinedType)
00478 d2 = len - d;
00479 else
00480 d2 = minInt(maxInt(m, 0), len - d);
00481 result = String(s.substr(d, d2));
00482 break;
00483 }
00484 case Substring: {
00485 double start = a0.toNumber(exec);
00486 double end = a1.toNumber(exec);
00487 if (KJS::isNaN(start))
00488 start = 0;
00489 if (KJS::isNaN(end))
00490 end = 0;
00491 if (start < 0)
00492 start = 0;
00493 if (end < 0)
00494 end = 0;
00495 if (start > len)
00496 start = len;
00497 if (end > len)
00498 end = len;
00499 if (a1.type() == UndefinedType)
00500 end = len;
00501 if (start > end) {
00502 double temp = end;
00503 end = start;
00504 start = temp;
00505 }
00506 result = String(s.substr((int)start, (int)end-(int)start));
00507 }
00508 break;
00509 case ToLowerCase:
00510 for (i = 0; i < len; i++)
00511 s[i] = s[i].toLower();
00512 result = String(s);
00513 break;
00514 case ToUpperCase:
00515 for (i = 0; i < len; i++)
00516 s[i] = s[i].toUpper();
00517 result = String(s);
00518 break;
00519 #ifndef KJS_PURE_ECMA
00520 case Big:
00521 result = String("<BIG>" + s + "</BIG>");
00522 break;
00523 case Small:
00524 result = String("<SMALL>" + s + "</SMALL>");
00525 break;
00526 case Blink:
00527 result = String("<BLINK>" + s + "</BLINK>");
00528 break;
00529 case Bold:
00530 result = String("<B>" + s + "</B>");
00531 break;
00532 case Fixed:
00533 result = String("<TT>" + s + "</TT>");
00534 break;
00535 case Italics:
00536 result = String("<I>" + s + "</I>");
00537 break;
00538 case Strike:
00539 result = String("<STRIKE>" + s + "</STRIKE>");
00540 break;
00541 case Sub:
00542 result = String("<SUB>" + s + "</SUB>");
00543 break;
00544 case Sup:
00545 result = String("<SUP>" + s + "</SUP>");
00546 break;
00547 case Fontcolor:
00548 result = String("<FONT COLOR=" + a0.toString(exec) + ">"
00549 + s + "</FONT>");
00550 break;
00551 case Fontsize:
00552 result = String("<FONT SIZE=" + a0.toString(exec) + ">"
00553 + s + "</FONT>");
00554 break;
00555 case Anchor:
00556 result = String("<a name=" + a0.toString(exec) + ">"
00557 + s + "</a>");
00558 break;
00559 case Link:
00560 result = String("<a href=" + a0.toString(exec) + ">"
00561 + s + "</a>");
00562 break;
00563 #endif
00564 }
00565
00566 return result;
00567 }
00568
00569
00570
00571 StringObjectImp::StringObjectImp(ExecState *exec,
00572 FunctionPrototypeImp *funcProto,
00573 StringPrototypeImp *stringProto)
00574 : InternalFunctionImp(funcProto)
00575 {
00576 Value protect(this);
00577
00578 putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00579
00580 putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00581
00582
00583 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00584 }
00585
00586
00587 bool StringObjectImp::implementsConstruct() const
00588 {
00589 return true;
00590 }
00591
00592
00593 Object StringObjectImp::construct(ExecState *exec, const List &args)
00594 {
00595 ObjectImp *proto = exec->interpreter()->builtinStringPrototype().imp();
00596 if (args.size() == 0)
00597 return Object(new StringInstanceImp(proto));
00598 return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00599 }
00600
00601 bool StringObjectImp::implementsCall() const
00602 {
00603 return true;
00604 }
00605
00606
00607 Value StringObjectImp::call(ExecState *exec, Object &, const List &args)
00608 {
00609 if (args.isEmpty())
00610 return String("");
00611 else {
00612 Value v = args[0];
00613 return String(v.toString(exec));
00614 }
00615 }
00616
00617
00618
00619
00620 StringObjectFuncImp::StringObjectFuncImp(ExecState *, FunctionPrototypeImp *funcProto)
00621 : InternalFunctionImp(funcProto)
00622 {
00623 Value protect(this);
00624 putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00625 }
00626
00627 bool StringObjectFuncImp::implementsCall() const
00628 {
00629 return true;
00630 }
00631
00632 Value StringObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00633 {
00634 UString s;
00635 if (args.size()) {
00636 UChar *buf = new UChar[args.size()];
00637 UChar *p = buf;
00638 ListIterator it = args.begin();
00639 while (it != args.end()) {
00640 unsigned short u = it->toUInt16(exec);
00641 *p++ = UChar(u);
00642 it++;
00643 }
00644 s = UString(buf, args.size(), false);
00645 } else
00646 s = "";
00647
00648 return String(s);
00649 }