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 }