[906] | 1 | /*
|
---|
| 2 | * 42TinyJS
|
---|
| 3 | *
|
---|
| 4 | * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
|
---|
| 5 | *
|
---|
| 6 | * Authored By Armin Diedering <armin@diedering.de>
|
---|
| 7 | *
|
---|
| 8 | * Copyright (C) 2010-2013 ardisoft
|
---|
| 9 | *
|
---|
| 10 | *
|
---|
| 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
|
---|
| 12 | * this software and associated documentation files (the "Software"), to deal in
|
---|
| 13 | * the Software without restriction, including without limitation the rights to
|
---|
| 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
---|
| 15 | * of the Software, and to permit persons to whom the Software is furnished to do
|
---|
| 16 | * so, subject to the following conditions:
|
---|
| 17 |
|
---|
| 18 | * The above copyright notice and this permission notice shall be included in all
|
---|
| 19 | * copies or substantial portions of the Software.
|
---|
| 20 |
|
---|
| 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
---|
| 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
---|
| 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
---|
| 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
---|
| 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
---|
| 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
---|
| 27 | * SOFTWARE.
|
---|
| 28 | */
|
---|
| 29 |
|
---|
| 30 | #include <algorithm>
|
---|
| 31 | #include "TinyJS.h"
|
---|
| 32 |
|
---|
| 33 | #ifndef NO_REGEXP
|
---|
| 34 | # if defined HAVE_TR1_REGEX
|
---|
| 35 | # include <tr1/regex>
|
---|
| 36 | using namespace std::tr1;
|
---|
| 37 | # elif defined HAVE_BOOST_REGEX
|
---|
| 38 | # include <boost/regex.hpp>
|
---|
| 39 | using namespace boost;
|
---|
| 40 | # else
|
---|
| 41 | # include <regex>
|
---|
| 42 | # endif
|
---|
| 43 | #endif
|
---|
| 44 | using namespace std;
|
---|
| 45 | // ----------------------------------------------- Actual Functions
|
---|
| 46 |
|
---|
| 47 | #define CheckObjectCoercible(var) do { \
|
---|
| 48 | if(var->isUndefined() || var->isNull())\
|
---|
| 49 | c->throwError(TypeError, "can't convert undefined to object");\
|
---|
| 50 | }while(0)
|
---|
| 51 |
|
---|
| 52 | static string this2string(const CFunctionsScopePtr &c) {
|
---|
| 53 | CScriptVarPtr This = c->getArgument("this");
|
---|
| 54 | CheckObjectCoercible(This);
|
---|
| 55 | return This->toString();
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | static void scStringCharAt(const CFunctionsScopePtr &c, void *) {
|
---|
| 59 | string str = this2string(c);
|
---|
| 60 | int p = c->getArgument("pos")->toNumber().toInt32();
|
---|
| 61 | if (p>=0 && p<(int)str.length())
|
---|
| 62 | c->setReturnVar(c->newScriptVar(str.substr(p, 1)));
|
---|
| 63 | else
|
---|
| 64 | c->setReturnVar(c->newScriptVar(""));
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) {
|
---|
| 68 | string str = this2string(c);
|
---|
| 69 | int p = c->getArgument("pos")->toNumber().toInt32();
|
---|
| 70 | if (p>=0 && p<(int)str.length())
|
---|
| 71 | c->setReturnVar(c->newScriptVar((unsigned char)str.at(p)));
|
---|
| 72 | else
|
---|
| 73 | c->setReturnVar(c->constScriptVar(NaN));
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 77 | int length = c->getArgumentsLength();
|
---|
| 78 | string str = this2string(c);
|
---|
| 79 | for(int i=(int)userdata; i<length; i++)
|
---|
| 80 | str.append(c->getArgument(i)->toString());
|
---|
| 81 | c->setReturnVar(c->newScriptVar(str));
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 | static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 85 | string str = this2string(c);
|
---|
| 86 | string search = c->getArgument("search")->toString();
|
---|
| 87 | CNumber pos_n = c->getArgument("pos")->toNumber();
|
---|
| 88 | string::size_type pos;
|
---|
| 89 | pos = (userdata) ? string::npos : 0;
|
---|
| 90 | if(pos_n.sign()<0) pos = 0;
|
---|
| 91 | else if(pos_n.isInfinity()) pos = string::npos;
|
---|
| 92 | else if(pos_n.isFinite()) pos = pos_n.toInt32();
|
---|
| 93 | string::size_type p = (userdata==0) ? str.find(search) : str.rfind(search);
|
---|
| 94 | int val = (p==string::npos) ? -1 : p;
|
---|
| 95 | c->setReturnVar(c->newScriptVar(val));
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | static void scStringLocaleCompare(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 99 | string str = this2string(c);
|
---|
| 100 | string compareString = c->getArgument("compareString")->toString();
|
---|
| 101 | int val = 0;
|
---|
| 102 | if(str<compareString) val = -1;
|
---|
| 103 | else if(str>compareString) val = 1;
|
---|
| 104 | c->setReturnVar(c->newScriptVar(val));
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 | static void scStringQuote(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 108 | string str = this2string(c);
|
---|
| 109 | c->setReturnVar(c->newScriptVar(getJSString(str)));
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 | #ifndef NO_REGEXP
|
---|
| 113 | // helper-function for replace search
|
---|
| 114 | static bool regex_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end, smatch &match) {
|
---|
| 115 | regex::flag_type flags = regex_constants::ECMAScript;
|
---|
| 116 | if(ignoreCase) flags |= regex_constants::icase;
|
---|
| 117 | regex_constants::match_flag_type mflag = sticky?regex_constants::match_continuous:regex_constants::format_default;
|
---|
| 118 | if(str.begin() != search_begin) mflag |= regex_constants::match_prev_avail;
|
---|
| 119 | if(regex_search(search_begin, str.end(), match, regex(substr, flags), mflag)) {
|
---|
| 120 | match_begin = match[0].first;
|
---|
| 121 | match_end = match[0].second;
|
---|
| 122 | return true;
|
---|
| 123 | }
|
---|
| 124 | return false;
|
---|
| 125 | }
|
---|
| 126 | static bool regex_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end) {
|
---|
| 127 | smatch match;
|
---|
| 128 | return regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end, match);
|
---|
| 129 | }
|
---|
| 130 | #endif /* NO_REGEXP */
|
---|
| 131 |
|
---|
| 132 | static bool charcmp (char i, char j) { return (i==j); }
|
---|
| 133 | static bool charicmp (char i, char j) { return (toupper(i)==toupper(j)); }
|
---|
| 134 | // helper-function for replace search
|
---|
| 135 | static bool string_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end) {
|
---|
| 136 | bool (*cmp)(char,char) = ignoreCase ? charicmp : charcmp;
|
---|
| 137 | if(sticky) {
|
---|
| 138 | match_begin = match_end = search_begin;
|
---|
| 139 | string::const_iterator s1e=str.end();
|
---|
| 140 | string::const_iterator s2=substr.begin(), s2e=substr.end();
|
---|
| 141 | while(match_end!=s1e && s2!=s2e && cmp(*match_end++, *s2++));
|
---|
| 142 | return s2==s2e;
|
---|
| 143 | }
|
---|
| 144 | match_begin = search(search_begin, str.end(), substr.begin(), substr.end(), cmp);
|
---|
| 145 | if(match_begin==str.end()) return false;
|
---|
| 146 | match_end = match_begin + substr.length();
|
---|
| 147 | return true;
|
---|
| 148 | }
|
---|
| 149 | //************************************
|
---|
| 150 | // Method: getRegExpData
|
---|
| 151 | // FullName: getRegExpData
|
---|
| 152 | // Access: public static
|
---|
| 153 | // Returns: bool true if regexp-param=RegExp-Object / other false
|
---|
| 154 | // Qualifier:
|
---|
| 155 | // Parameter: const CFunctionsScopePtr & c
|
---|
| 156 | // Parameter: const string & regexp - parameter name of the regexp
|
---|
| 157 | // Parameter: bool noUndefined - true an undefined regexp aims in "" else in "undefined"
|
---|
| 158 | // Parameter: const string & flags - parameter name of the flags
|
---|
| 159 | // Parameter: string & substr - rgexp.source
|
---|
| 160 | // Parameter: bool & global
|
---|
| 161 | // Parameter: bool & ignoreCase
|
---|
| 162 | // Parameter: bool & sticky
|
---|
| 163 | //************************************
|
---|
| 164 | static CScriptVarPtr getRegExpData(const CFunctionsScopePtr &c, const string ®exp, bool noUndefined, const char *flags_argument, string &substr, bool &global, bool &ignoreCase, bool &sticky) {
|
---|
| 165 | CScriptVarPtr regexpVar = c->getArgument(regexp);
|
---|
| 166 | if(regexpVar->isRegExp()) {
|
---|
| 167 | #ifndef NO_REGEXP
|
---|
| 168 | CScriptVarRegExpPtr RegExp(regexpVar);
|
---|
| 169 | substr = RegExp->Regexp();
|
---|
| 170 | ignoreCase = RegExp->IgnoreCase();
|
---|
| 171 | global = RegExp->Global();
|
---|
| 172 | sticky = RegExp->Sticky();
|
---|
| 173 | return RegExp;
|
---|
| 174 | #endif /* NO_REGEXP */
|
---|
| 175 | } else {
|
---|
| 176 | substr.clear();
|
---|
| 177 | if(!noUndefined || !regexpVar->isUndefined()) substr = regexpVar->toString();
|
---|
| 178 | CScriptVarPtr flagVar;
|
---|
| 179 | if(flags_argument && (flagVar = c->getArgument(flags_argument)) && !flagVar->isUndefined()) {
|
---|
| 180 | string flags = flagVar->toString();
|
---|
| 181 | string::size_type pos = flags.find_first_not_of("gimy");
|
---|
| 182 | if(pos != string::npos) {
|
---|
| 183 | c->throwError(SyntaxError, string("invalid regular expression flag ")+flags[pos]);
|
---|
| 184 | }
|
---|
| 185 | global = flags.find_first_of('g')!=string::npos;
|
---|
| 186 | ignoreCase = flags.find_first_of('i')!=string::npos;
|
---|
| 187 | sticky = flags.find_first_of('y')!=string::npos;
|
---|
| 188 | } else
|
---|
| 189 | global = ignoreCase = sticky = false;
|
---|
| 190 | }
|
---|
| 191 | return CScriptVarPtr();
|
---|
| 192 | }
|
---|
| 193 |
|
---|
| 194 | static void scStringReplace(const CFunctionsScopePtr &c, void *) {
|
---|
| 195 | const string str = this2string(c);
|
---|
| 196 | CScriptVarPtr newsubstrVar = c->getArgument("newsubstr");
|
---|
| 197 | string substr, ret_str;
|
---|
| 198 | bool global, ignoreCase, sticky;
|
---|
| 199 | bool isRegExp = getRegExpData(c, "substr", false, "flags", substr, global, ignoreCase, sticky);
|
---|
| 200 | if(isRegExp && !newsubstrVar->isFunction()) {
|
---|
| 201 | #ifndef NO_REGEXP
|
---|
| 202 | regex::flag_type flags = regex_constants::ECMAScript;
|
---|
| 203 | if(ignoreCase) flags |= regex_constants::icase;
|
---|
| 204 | regex_constants::match_flag_type mflags = regex_constants::match_default;
|
---|
| 205 | if(!global) mflags |= regex_constants::format_first_only;
|
---|
| 206 | if(sticky) mflags |= regex_constants::match_continuous;
|
---|
| 207 | ret_str = regex_replace(str, regex(substr, flags), newsubstrVar->toString(), mflags);
|
---|
| 208 | #endif /* NO_REGEXP */
|
---|
| 209 | } else {
|
---|
| 210 | bool (*search)(const string &, const string::const_iterator &, const string &, bool, bool, string::const_iterator &, string::const_iterator &);
|
---|
| 211 | #ifndef NO_REGEXP
|
---|
| 212 | if(isRegExp)
|
---|
| 213 | search = regex_search;
|
---|
| 214 | else
|
---|
| 215 | #endif /* NO_REGEXP */
|
---|
| 216 | search = string_search;
|
---|
| 217 | string newsubstr;
|
---|
| 218 | vector<CScriptVarPtr> arguments;
|
---|
| 219 | if(!newsubstrVar->isFunction())
|
---|
| 220 | newsubstr = newsubstrVar->toString();
|
---|
| 221 | global = global && substr.length();
|
---|
| 222 | string::const_iterator search_begin=str.begin(), match_begin, match_end;
|
---|
| 223 | if(search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) {
|
---|
| 224 | do {
|
---|
| 225 | ret_str.append(search_begin, match_begin);
|
---|
| 226 | if(newsubstrVar->isFunction()) {
|
---|
| 227 | arguments.push_back(c->newScriptVar(string(match_begin, match_end)));
|
---|
| 228 | newsubstr = c->getContext()->callFunction(newsubstrVar, arguments, c)->toString();
|
---|
| 229 | arguments.pop_back();
|
---|
| 230 | }
|
---|
| 231 | ret_str.append(newsubstr);
|
---|
| 232 | search_begin = match_end;
|
---|
| 233 | } while(global && search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end));
|
---|
| 234 | }
|
---|
| 235 | ret_str.append(search_begin, str.end());
|
---|
| 236 | }
|
---|
| 237 | c->setReturnVar(c->newScriptVar(ret_str));
|
---|
| 238 | }
|
---|
| 239 | #ifndef NO_REGEXP
|
---|
| 240 | static void scStringMatch(const CFunctionsScopePtr &c, void *) {
|
---|
| 241 | string str = this2string(c);
|
---|
| 242 |
|
---|
| 243 | string flags="flags", substr, newsubstr, match;
|
---|
| 244 | bool global, ignoreCase, sticky;
|
---|
| 245 | CScriptVarRegExpPtr RegExp = getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky);
|
---|
| 246 | if(!global) {
|
---|
| 247 | if(!RegExp)
|
---|
| 248 | RegExp = ::newScriptVar(c->getContext(), substr, flags);
|
---|
| 249 | if(RegExp) {
|
---|
| 250 | try {
|
---|
| 251 | c->setReturnVar(RegExp->exec(str));
|
---|
| 252 | } catch(regex_error e) {
|
---|
| 253 | c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 | } else {
|
---|
| 257 | try {
|
---|
| 258 | CScriptVarArrayPtr retVar = c->newScriptVar(Array);
|
---|
| 259 | int idx=0;
|
---|
| 260 | string::size_type offset=0;
|
---|
| 261 | global = global && substr.length();
|
---|
| 262 | string::const_iterator search_begin=str.begin(), match_begin, match_end;
|
---|
| 263 | if(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) {
|
---|
| 264 | do {
|
---|
| 265 | offset = match_begin-str.begin();
|
---|
| 266 | retVar->addChild(int2string(idx++), c->newScriptVar(string(match_begin, match_end)));
|
---|
| 267 | search_begin = match_end;
|
---|
| 268 | } while(global && regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end));
|
---|
| 269 | }
|
---|
| 270 | if(idx) {
|
---|
| 271 | retVar->addChild("input", c->newScriptVar(str));
|
---|
| 272 | retVar->addChild("index", c->newScriptVar((int)offset));
|
---|
| 273 | c->setReturnVar(retVar);
|
---|
| 274 | } else
|
---|
| 275 | c->setReturnVar(c->constScriptVar(Null));
|
---|
| 276 | } catch(regex_error e) {
|
---|
| 277 | c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
|
---|
| 278 | }
|
---|
| 279 | }
|
---|
| 280 | }
|
---|
| 281 | #endif /* NO_REGEXP */
|
---|
| 282 |
|
---|
| 283 | static void scStringSearch(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 284 | string str = this2string(c);
|
---|
| 285 |
|
---|
| 286 | string substr;
|
---|
| 287 | bool global, ignoreCase, sticky;
|
---|
| 288 | getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky);
|
---|
| 289 | string::const_iterator search_begin=str.begin(), match_begin, match_end;
|
---|
| 290 | #ifndef NO_REGEXP
|
---|
| 291 | try {
|
---|
| 292 | c->setReturnVar(c->newScriptVar(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1));
|
---|
| 293 | } catch(regex_error e) {
|
---|
| 294 | c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
|
---|
| 295 | }
|
---|
| 296 | #else /* NO_REGEXP */
|
---|
| 297 | c->setReturnVar(c->newScriptVar(string_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1));
|
---|
| 298 | #endif /* NO_REGEXP */
|
---|
| 299 | }
|
---|
| 300 |
|
---|
| 301 | static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 302 | string str = this2string(c);
|
---|
| 303 | int length = c->getArgumentsLength()-((int)userdata & 1);
|
---|
| 304 | bool slice = ((int)userdata & 2) == 0;
|
---|
| 305 | int start = c->getArgument("start")->toNumber().toInt32();
|
---|
| 306 | int end = (int)str.size();
|
---|
| 307 | if(slice && start<0) start = str.size()+start;
|
---|
| 308 | if(length>1) {
|
---|
| 309 | end = c->getArgument("end")->toNumber().toInt32();
|
---|
| 310 | if(slice && end<0) end = str.size()+end;
|
---|
| 311 | }
|
---|
| 312 | if(!slice && end < start) { end^=start; start^=end; end^=start; }
|
---|
| 313 | if(start<0) start = 0;
|
---|
| 314 | if(start>=(int)str.size())
|
---|
| 315 | c->setReturnVar(c->newScriptVar(""));
|
---|
| 316 | else if(end <= start)
|
---|
| 317 | c->setReturnVar(c->newScriptVar(""));
|
---|
| 318 | else
|
---|
| 319 | c->setReturnVar(c->newScriptVar(str.substr(start, end-start)));
|
---|
| 320 | }
|
---|
| 321 |
|
---|
| 322 | //static void scStringSplit(const CFunctionsScopePtr &c, void *) {
|
---|
| 323 | // const string str = this2string(c);
|
---|
| 324 |
|
---|
| 325 | // string seperator;
|
---|
| 326 | // bool global, ignoreCase, sticky;
|
---|
| 327 | // CScriptVarRegExpPtr RegExp = getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky);
|
---|
| 328 |
|
---|
| 329 | // CScriptVarPtr sep_var = c->getArgument("separator");
|
---|
| 330 | // CScriptVarPtr limit_var = c->getArgument("limit");
|
---|
| 331 | // int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->toNumber().toInt32();
|
---|
| 332 |
|
---|
| 333 | // CScriptVarPtr result(newScriptVar(c->getContext(), Array));
|
---|
| 334 | // c->setReturnVar(result);
|
---|
| 335 | // if(limit == 0 || !str.size())
|
---|
| 336 | // return;
|
---|
| 337 | // else if(sep_var->isUndefined()) {
|
---|
| 338 | // result->setArrayIndex(0, c->newScriptVar(str));
|
---|
| 339 | // return;
|
---|
| 340 | // }
|
---|
| 341 | // if(seperator.size() == 0) {
|
---|
| 342 | // for(int i=0; i<min((int)seperator.size(), limit); ++i)
|
---|
| 343 | // result->setArrayIndex(i, c->newScriptVar(str.substr(i,1)));
|
---|
| 344 | // return;
|
---|
| 345 | // }
|
---|
| 346 | // int length = 0;
|
---|
| 347 | // string::const_iterator search_begin=str.begin(), match_begin, match_end;
|
---|
| 348 | // smatch match;
|
---|
| 349 | // bool found=true;
|
---|
| 350 | // while(found) {
|
---|
| 351 | // if(RegExp) {
|
---|
| 352 | // try {
|
---|
| 353 | // found = regex_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end, match);
|
---|
| 354 | // } catch(regex_error e) {
|
---|
| 355 | // c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
|
---|
| 356 | // }
|
---|
| 357 | // } else /* NO_REGEXP */
|
---|
| 358 | // found = string_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end);
|
---|
| 359 | // string f;
|
---|
| 360 | // if(found) {
|
---|
| 361 | // result->setArrayIndex(length++, c->newScriptVar(string(search_begin, match_begin)));
|
---|
| 362 | // if(length>=limit) break;
|
---|
| 363 | // for(uint32_t i=1; i<match.size(); i++) {
|
---|
| 364 | // if(match[i].matched)
|
---|
| 365 | // result->setArrayIndex(length++, c->newScriptVar(string(match[i].first, match[i].second)));
|
---|
| 366 | // else
|
---|
| 367 | // result->setArrayIndex(length++, c->constScriptVar(Undefined));
|
---|
| 368 | // if(length>=limit) break;
|
---|
| 369 | // }
|
---|
| 370 | // if(length>=limit) break;
|
---|
| 371 | // search_begin = match_end;
|
---|
| 372 | // } else {
|
---|
| 373 | // result->setArrayIndex(length++, c->newScriptVar(string(search_begin,str.end())));
|
---|
| 374 | // if(length>=limit) break;
|
---|
| 375 | // }
|
---|
| 376 | // }
|
---|
| 377 | //}
|
---|
| 378 |
|
---|
| 379 | static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 380 | string str = this2string(c);
|
---|
| 381 | int length = c->getArgumentsLength()-(int)userdata;
|
---|
| 382 | int start = c->getArgument("start")->toNumber().toInt32();
|
---|
| 383 | if(start<0 || start>=(int)str.size())
|
---|
| 384 | c->setReturnVar(c->newScriptVar(""));
|
---|
| 385 | else if(length>1) {
|
---|
| 386 | int length = c->getArgument("length")->toNumber().toInt32();
|
---|
| 387 | c->setReturnVar(c->newScriptVar(str.substr(start, length)));
|
---|
| 388 | } else
|
---|
| 389 | c->setReturnVar(c->newScriptVar(str.substr(start)));
|
---|
| 390 | }
|
---|
| 391 |
|
---|
| 392 | static void scStringToLowerCase(const CFunctionsScopePtr &c, void *) {
|
---|
| 393 | string str = this2string(c);
|
---|
| 394 | transform(str.begin(), str.end(), str.begin(), ::tolower);
|
---|
| 395 | c->setReturnVar(c->newScriptVar(str));
|
---|
| 396 | }
|
---|
| 397 |
|
---|
| 398 | static void scStringToUpperCase(const CFunctionsScopePtr &c, void *) {
|
---|
| 399 | string str = this2string(c);
|
---|
| 400 | transform(str.begin(), str.end(), str.begin(), ::toupper);
|
---|
| 401 | c->setReturnVar(c->newScriptVar(str));
|
---|
| 402 | }
|
---|
| 403 |
|
---|
| 404 | static void scStringTrim(const CFunctionsScopePtr &c, void *userdata) {
|
---|
| 405 | string str = this2string(c);
|
---|
| 406 | string::size_type start = 0;
|
---|
| 407 | string::size_type end = string::npos;
|
---|
| 408 | if((((int)userdata) & 2) == 0) {
|
---|
| 409 | start = str.find_first_not_of(" \t\r\n");
|
---|
| 410 | if(start == string::npos) start = 0;
|
---|
| 411 | }
|
---|
| 412 | if((((int)userdata) & 1) == 0) {
|
---|
| 413 | end = str.find_last_not_of(" \t\r\n");
|
---|
| 414 | if(end != string::npos) end = 1+end-start;
|
---|
| 415 | }
|
---|
| 416 | c->setReturnVar(c->newScriptVar(str.substr(start, end)));
|
---|
| 417 | }
|
---|
| 418 |
|
---|
| 419 |
|
---|
| 420 |
|
---|
| 421 | static void scCharToInt(const CFunctionsScopePtr &c, void *) {
|
---|
| 422 | string str = c->getArgument("ch")->toString();;
|
---|
| 423 | int val = 0;
|
---|
| 424 | if (str.length()>0)
|
---|
| 425 | val = (int)str.c_str()[0];
|
---|
| 426 | c->setReturnVar(c->newScriptVar(val));
|
---|
| 427 | }
|
---|
| 428 |
|
---|
| 429 |
|
---|
| 430 | static void scStringFromCharCode(const CFunctionsScopePtr &c, void *) {
|
---|
| 431 | char str[2];
|
---|
| 432 | str[0] = c->getArgument("char")->toNumber().toInt32();
|
---|
| 433 | str[1] = 0;
|
---|
| 434 | c->setReturnVar(c->newScriptVar(str));
|
---|
| 435 | }
|
---|
| 436 |
|
---|
| 437 | //////////////////////////////////////////////////////////////////////////
|
---|
| 438 | // RegExp-Stuff
|
---|
| 439 | //////////////////////////////////////////////////////////////////////////
|
---|
| 440 |
|
---|
| 441 | #ifndef NO_REGEXP
|
---|
| 442 |
|
---|
| 443 | static void scRegExpTest(const CFunctionsScopePtr &c, void *) {
|
---|
| 444 | CScriptVarRegExpPtr This = c->getArgument("this");
|
---|
| 445 | if(This)
|
---|
| 446 | c->setReturnVar(This->exec(c->getArgument("str")->toString(), true));
|
---|
| 447 | else
|
---|
| 448 | c->throwError(TypeError, "Object is not a RegExp-Object in test(str)");
|
---|
| 449 | }
|
---|
| 450 | static void scRegExpExec(const CFunctionsScopePtr &c, void *) {
|
---|
| 451 | CScriptVarRegExpPtr This = c->getArgument("this");
|
---|
| 452 | if(This)
|
---|
| 453 | c->setReturnVar(This->exec(c->getArgument("str")->toString()));
|
---|
| 454 | else
|
---|
| 455 | c->throwError(TypeError, "Object is not a RegExp-Object in exec(str)");
|
---|
| 456 | }
|
---|
| 457 | #endif /* NO_REGEXP */
|
---|
| 458 |
|
---|
| 459 | // ----------------------------------------------- Register Functions
|
---|
| 460 | void registerStringFunctions(CTinyJS *tinyJS) {}
|
---|
| 461 | extern "C" void _registerStringFunctions(CTinyJS *tinyJS) {
|
---|
| 462 | CScriptVarPtr fnc;
|
---|
| 463 | // charAt
|
---|
| 464 | tinyJS->addNative("function String.prototype.charAt(pos)", scStringCharAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 465 | tinyJS->addNative("function String.charAt(this,pos)", scStringCharAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 466 | // charCodeAt
|
---|
| 467 | tinyJS->addNative("function String.prototype.charCodeAt(pos)", scStringCharCodeAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 468 | tinyJS->addNative("function String.charCodeAt(this,pos)", scStringCharCodeAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 469 | // concat
|
---|
| 470 | tinyJS->addNative("function String.prototype.concat()", scStringConcat, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 471 | tinyJS->addNative("function String.concat(this)", scStringConcat, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 472 | // indexOf
|
---|
| 473 | tinyJS->addNative("function String.prototype.indexOf(search,pos)", scStringIndexOf, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the position of a string in a string, -1 if not
|
---|
| 474 | tinyJS->addNative("function String.indexOf(this,search,pos)", scStringIndexOf, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the position of a string in a string, -1 if not
|
---|
| 475 | // lastIndexOf
|
---|
| 476 | tinyJS->addNative("function String.prototype.lastIndexOf(search,pos)", scStringIndexOf, (void*)-1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
|
---|
| 477 | tinyJS->addNative("function String.lastIndexOf(this,search,pos)", scStringIndexOf, (void*)-1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
|
---|
| 478 | // localeCompare
|
---|
| 479 | tinyJS->addNative("function String.prototype.localeCompare(compareString)", scStringLocaleCompare, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 480 | tinyJS->addNative("function String.localeCompare(this,compareString)", scStringLocaleCompare, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 481 | // quote
|
---|
| 482 | tinyJS->addNative("function String.prototype.quote()", scStringQuote, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 483 | tinyJS->addNative("function String.quote(this)", scStringQuote, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 484 | #ifndef NO_REGEXP
|
---|
| 485 | // match
|
---|
| 486 | tinyJS->addNative("function String.prototype.match(regexp, flags)", scStringMatch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 487 | tinyJS->addNative("function String.match(this, regexp, flags)", scStringMatch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 488 | #endif /* !REGEXP */
|
---|
| 489 | // replace
|
---|
| 490 | tinyJS->addNative("function String.prototype.replace(substr, newsubstr, flags)", scStringReplace, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 491 | tinyJS->addNative("function String.replace(this, substr, newsubstr, flags)", scStringReplace, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 492 | // search
|
---|
| 493 | tinyJS->addNative("function String.prototype.search(regexp, flags)", scStringSearch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 494 | tinyJS->addNative("function String.search(this, regexp, flags)", scStringSearch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 495 | // slice
|
---|
| 496 | tinyJS->addNative("function String.prototype.slice(start,end)", scStringSlice, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
|
---|
| 497 | tinyJS->addNative("function String.slice(this,start,end)", scStringSlice, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
|
---|
| 498 | // split
|
---|
| 499 | //tinyJS->addNative("function String.prototype.split(separator,limit)", scStringSplit, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 500 | //tinyJS->addNative("function String.split(this,separator,limit)", scStringSplit, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 501 | // substr
|
---|
| 502 | tinyJS->addNative("function String.prototype.substr(start,length)", scStringSubstr, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 503 | tinyJS->addNative("function String.substr(this,start,length)", scStringSubstr, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 504 | // substring
|
---|
| 505 | tinyJS->addNative("function String.prototype.substring(start,end)", scStringSlice, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 506 | tinyJS->addNative("function String.substring(this,start,end)", scStringSlice, (void*)3, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 507 | // toLowerCase toLocaleLowerCase currently the same function
|
---|
| 508 | tinyJS->addNative("function String.prototype.toLowerCase()", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 509 | tinyJS->addNative("function String.toLowerCase(this)", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 510 | tinyJS->addNative("function String.prototype.toLocaleLowerCase()", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 511 | tinyJS->addNative("function String.toLocaleLowerCase(this)", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 512 | // toUpperCase toLocaleUpperCase currently the same function
|
---|
| 513 | tinyJS->addNative("function String.prototype.toUpperCase()", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 514 | tinyJS->addNative("function String.toUpperCase(this)", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 515 | tinyJS->addNative("function String.prototype.toLocaleUpperCase()", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 516 | tinyJS->addNative("function String.toLocaleUpperCase(this)", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 517 | // trim
|
---|
| 518 | tinyJS->addNative("function String.prototype.trim()", scStringTrim, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 519 | tinyJS->addNative("function String.trim(this)", scStringTrim, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 520 | // trimLeft
|
---|
| 521 | tinyJS->addNative("function String.prototype.trimLeft()", scStringTrim, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 522 | tinyJS->addNative("function String.trimLeft(this)", scStringTrim, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 523 | // trimRight
|
---|
| 524 | tinyJS->addNative("function String.prototype.trimRight()", scStringTrim, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 525 | tinyJS->addNative("function String.trimRight(this)", scStringTrim, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 526 |
|
---|
| 527 | tinyJS->addNative("function charToInt(ch)", scCharToInt, 0, SCRIPTVARLINK_BUILDINDEFAULT); // convert a character to an int - get its value
|
---|
| 528 |
|
---|
| 529 | tinyJS->addNative("function String.prototype.fromCharCode(char)", scStringFromCharCode, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 530 | #ifndef NO_REGEXP
|
---|
| 531 | tinyJS->addNative("function RegExp.prototype.test(str)", scRegExpTest, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 532 | tinyJS->addNative("function RegExp.prototype.exec(str)", scRegExpExec, 0, SCRIPTVARLINK_BUILDINDEFAULT);
|
---|
| 533 | #endif /* NO_REGEXP */
|
---|
| 534 | }
|
---|
| 535 |
|
---|