kjs Library API Documentation

string_object.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2003 Apple Computer, Inc.
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Lesser General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Lesser General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Lesser General Public
00018  *  License along with this library; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 // ------------------------------ StringInstanceImp ----------------------------
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 // ------------------------------ StringPrototypeImp ---------------------------
00118 const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0};
00119 /* Source for string_object.lut.h
00120 @begin stringTable 28
00121   toString      StringProtoFuncImp::ToString    DontEnum|Function   0
00122   valueOf       StringProtoFuncImp::ValueOf DontEnum|Function   0
00123   charAt        StringProtoFuncImp::CharAt  DontEnum|Function   1
00124   charCodeAt        StringProtoFuncImp::CharCodeAt  DontEnum|Function   1
00125   concat        StringProtoFuncImp::Concat  DontEnum|Function   0
00126   indexOf       StringProtoFuncImp::IndexOf DontEnum|Function   2
00127   lastIndexOf       StringProtoFuncImp::LastIndexOf DontEnum|Function   2
00128   match         StringProtoFuncImp::Match   DontEnum|Function   1
00129   replace       StringProtoFuncImp::Replace DontEnum|Function   2
00130   search        StringProtoFuncImp::Search  DontEnum|Function   1
00131   slice         StringProtoFuncImp::Slice   DontEnum|Function   2
00132   split         StringProtoFuncImp::Split   DontEnum|Function   2
00133   substr        StringProtoFuncImp::Substr  DontEnum|Function   2
00134   substring     StringProtoFuncImp::Substring   DontEnum|Function   2
00135   toLowerCase       StringProtoFuncImp::ToLowerCase DontEnum|Function   0
00136   toUpperCase       StringProtoFuncImp::ToUpperCase DontEnum|Function   0
00137 #
00138 # Under here: html extension, should only exist if KJS_PURE_ECMA is not defined
00139 # I guess we need to generate two hashtables in the .lut.h file, and use #ifdef
00140 # to select the right one... TODO. #####
00141   big           StringProtoFuncImp::Big     DontEnum|Function   0
00142   small         StringProtoFuncImp::Small   DontEnum|Function   0
00143   blink         StringProtoFuncImp::Blink   DontEnum|Function   0
00144   bold          StringProtoFuncImp::Bold    DontEnum|Function   0
00145   fixed         StringProtoFuncImp::Fixed   DontEnum|Function   0
00146   italics       StringProtoFuncImp::Italics DontEnum|Function   0
00147   strike        StringProtoFuncImp::Strike  DontEnum|Function   0
00148   sub           StringProtoFuncImp::Sub     DontEnum|Function   0
00149   sup           StringProtoFuncImp::Sup     DontEnum|Function   0
00150   fontcolor     StringProtoFuncImp::Fontcolor   DontEnum|Function   1
00151   fontsize      StringProtoFuncImp::Fontsize    DontEnum|Function   1
00152   anchor        StringProtoFuncImp::Anchor  DontEnum|Function   1
00153   link          StringProtoFuncImp::Link    DontEnum|Function   1
00154 @end
00155 */
00156 // ECMA 15.5.4
00157 StringPrototypeImp::StringPrototypeImp(ExecState */*exec*/,
00158                                        ObjectPrototypeImp *objProto)
00159   : StringInstanceImp(objProto)
00160 {
00161   Value protect(this);
00162   // The constructor will be added later, after StringObjectImp has been built
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 // ------------------------------ StringProtoFuncImp ---------------------------
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 // ECMA 15.5.4.2 - 15.5.4.20
00189 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00190 {
00191   Value result;
00192 
00193   // toString and valueOf are no generic functions.
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     // handled above
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        *  ECMA 15.5.4.12 String.prototype.search (regexp)
00275        *  If regexp is not an object whose [[Class]] property is "RegExp", it is
00276        *  replaced with the result of the expression new RegExp(regexp).
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 { // Match
00286       if (mstr.isNull()) {
00287         result = Null(); // no match
00288       } else if ((reg->flags() & RegExp::Global) == 0) {
00289     // case without 'g' flag is handled like RegExp.prototype.exec
00290     regExpObj->setSubPatterns(reg->subPatterns());
00291     result = regExpObj->arrayOfMatches(exec,mstr);
00292       } else {
00293     // return array of matches
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       // Test if 2nd arg is a function (new in JS 1.3)
00322       if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00323         o1 = a1.toObject(exec);
00324       else
00325         u3 = a1.toString(exec); // 2nd arg is the replacement string
00326 
00327       // This is either a loop (if global is set) or a one-way (if not).
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         // Prepare replacement
00338         if (!o1.isValid())
00339         {
00340           rstr = u3;
00341           bool ok;
00342           // check if u3 matches $1 or $2 etc
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             // Assume number part is one char exactly
00349             unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false /* tolerate empty string */);
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; // -1 offsets i++
00356             }
00357           }
00358         } else // 2nd arg is a function call. Spec from http://devedge.netscape.com/library/manuals/2000/javascript/1.5/reference/string.html#1194258
00359         {
00360           List l;
00361           l.append(String(mstr)); // First arg: complete matched substring
00362           // Then the submatch strings
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)); // The offset within the string where the match occurred
00367           l.append(String(s)); // Last arg: the string itself. Can't see the difference with the 1st arg!
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         //fprintf(stderr,"pos=%d,len=%d,lastIndex=%d,s=%s\n",pos,len,lastIndex,s.ascii());
00374       } while (global);
00375 
00376       result = String(s);
00377     } else { // First arg is a string
00378       u2 = a0.toString(exec);
00379       pos = s.find(u2);
00380       len = u2.size();
00381       // Do the replacement
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: // http://developer.netscape.com/docs/manuals/js/client/jsref/string.htm#1194366 or 15.5.4.13
00392     {
00393         // The arg processing is very much like ArrayProtoFunc::Slice
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         //printf( "Slicing from %d to %d \n", begin, end );
00408         result = String(s.substr(begin, end-begin));
00409         break;
00410     }
00411     case Split: { // 15.5.4.14
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; // optional max number
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     // empty string matched by regexp -> empty array
00422     res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00423     break;
00424       }
00425       pos = 0;
00426       while (pos < s.size()) {
00427     // TODO: back references
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       // empty separator matches empty string -> empty array
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     // add remaining string, if any
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 // ------------------------------ StringObjectImp ------------------------------
00567 
00568 StringObjectImp::StringObjectImp(ExecState *exec,
00569                                  FunctionPrototypeImp *funcProto,
00570                                  StringPrototypeImp *stringProto)
00571   : InternalFunctionImp(funcProto)
00572 {
00573   Value protect(this);
00574   // ECMA 15.5.3.1 String.prototype
00575   putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00576 
00577   putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00578 
00579   // no. of arguments for constructor
00580   putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00581 }
00582 
00583 
00584 bool StringObjectImp::implementsConstruct() const
00585 {
00586   return true;
00587 }
00588 
00589 // ECMA 15.5.2
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 // ECMA 15.5.1
00604 Value StringObjectImp::call(ExecState *exec, Object &/*thisObj*/, 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 // ------------------------------ StringObjectFuncImp --------------------------
00615 
00616 // ECMA 15.5.3.2 fromCharCode()
00617 StringObjectFuncImp::StringObjectFuncImp(ExecState* /*exec*/, 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 &/*thisObj*/, 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 }
KDE Logo
This file is part of the documentation for kjs Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jul 22 10:17:02 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003