static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); int length = c->getArgumentsLength()-((int)userdata & 1); bool slice = ((int)userdata & 2) == 0; int start = c->getArgument("start")->getInt(); int end = (int)str.size(); if(slice && start<0) start = str.size()+start; if(length>1) { end = c->getArgument("end")->getInt(); if(slice && end<0) end = str.size()+end; } if(!slice && end < start) { end^=start; start^=end; end^=start; } if(start<0) start = 0; if(start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(end <= start) c->setReturnVar(c->newScriptVar("")); else c->setReturnVar(c->newScriptVar(str.substr(start, end-start))); }
static void scStringCharAt(const CFunctionsScopePtr &c, void *) { string str = this2string(c); int p = c->getArgument("pos")->toNumber().toInt32(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar(str.substr(p, 1))); else c->setReturnVar(c->newScriptVar("")); }
static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) { string str = this2string(c); int p = c->getArgument("pos")->toNumber().toInt32(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar((unsigned char)str.at(p))); else c->setReturnVar(c->constScriptVar(NaN)); }
static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("this")->getString(); int p = c->getArgument("pos")->getInt(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar(str.at(p))); else c->setReturnVar(c->newScriptVar(0)); }
static void scArrayPop(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); uint32_t len = c->getLength(arr); if(len) { c->setReturnVar(c->getPropertyValue(arr, len-1)); arr->removeChild(int2string(len-1)); } else c->setReturnVar(c->constScriptVar(Undefined)); }
static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); int32_t length = c->getArgumentsLength()-ptr2int32(userdata); int32_t start = c->getArgument("start")->toNumber().toInt32(); if(start<0 || start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(length>1) { int length = c->getArgument("length")->toNumber().toInt32(); c->setReturnVar(c->newScriptVar(str.substr(start, length))); } else c->setReturnVar(c->newScriptVar(str.substr(start))); }
static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); int length = c->getArgumentsLength()-(int)userdata; int start = c->getArgument("start")->getInt(); if(start<0 || start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(length>1) { int length = c->getArgument("length")->getInt(); c->setReturnVar(c->newScriptVar(str.substr(start, length))); } else c->setReturnVar(c->newScriptVar(str.substr(start))); }
static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string search = c->getArgument("search")->toString(); CNumber pos_n = c->getArgument("pos")->toNumber(); string::size_type pos; pos = (userdata) ? string::npos : 0; if(pos_n.sign()<0) pos = 0; else if(pos_n.isInfinity()) pos = string::npos; else if(pos_n.isFinite()) pos = pos_n.toInt32(); string::size_type p = (userdata==0) ? str.find(search, pos) : str.rfind(search, pos); if(p==string::npos) c->setReturnVar(c->newScriptVar(-1)); else c->setReturnVar(c->newScriptVar(p)); }
static void scArrayContains(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr obj = c->getArgument("obj"); CScriptVarPtr arr = c->getArgument("this"); int l = arr->getArrayLength(); CScriptVarPtr equal = c->constScriptVar(Undefined); for (int i=0;i<l;i++) { equal = obj->mathsOp(arr->getArrayIndex(i), LEX_EQUAL); if(equal->toBoolean()) { c->setReturnVar(c->constScriptVar(true)); return; } } c->setReturnVar(c->constScriptVar(false)); }
/* static void scIntegerValueOf(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("str")->toString(); int val = 0; if (str.length()==1) val = str.operator[](0); c->setReturnVar(c->newScriptVar(val)); } */ static void scJSONStringify(const CFunctionsScopePtr &c, void *) { uint32_t UniqueID = c->getContext()->allocUniqueID(); bool hasRecursion=false; c->setReturnVar(c->newScriptVar(c->getArgument("obj")->getParsableString("", " ", UniqueID, hasRecursion))); c->getContext()->freeUniqueID(); if(hasRecursion) c->throwError(TypeError, "cyclic object value"); }
static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); string search = c->getArgument("search")->getString(); size_t p = (userdata==0) ? str.find(search) : str.rfind(search); int val = (p==string::npos) ? -1 : p; c->setReturnVar(c->newScriptVar(val)); }
static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) { int length = c->getArgumentsLength(); string str = c->getArgument("this")->getString(); for(int i=(int)userdata; i<length; i++) str.append(c->getArgument(i)->getString()); c->setReturnVar(c->newScriptVar(str)); }
static void scArraySort(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); CScriptVarFunctionPtr cmp_fnc; uint32_t len = arr->getLength(); if(len > 1) { int args = c->getArgumentsLength(); if(args) { cmp_fnc = c->getArgument(0); if(!cmp_fnc) c->throwError(TypeError, "invalid Array.prototype.sort argument"); } SCRIPTVAR_CHILDS_it begin = lower_bound(arr->Childs.begin(), arr->Childs.end(), "0"); /* in ECMAScript the sort algorithm is not specified * in some cases sort throws a TypeError e.G. an array element is read-only, non-configurable, getter or setter * this will result in a partially sorted array * in worst case the sort algorithm results in an endless loop (more getters with constant return value) * * 42TinyJS checks before sort if an element read-only, setter or getter and throws immediately a TypeError */ for(SCRIPTVAR_CHILDS_it it = begin; it != arr->Childs.end(); ++it) { if(!(*it)->isWritable()) c->throwError(TypeError, "property "+(*it)->getName()+" is read-only"); if(!(*it)->isConfigurable()) c->throwError(TypeError, "property "+(*it)->getName()+" is non-configurable"); if(!(*it)->getVarPtr()->isAccessor()) c->throwError(TypeError, "property "+(*it)->getName()+" is a getter and/or a setter"); } sort(begin, arr->Childs.end(), ::cmp_fnc(c, cmp_fnc)); uint32_t idx = 0; for(SCRIPTVAR_CHILDS_it it=begin; it != arr->Childs.end(); ++it, ++idx) (*it)->reName(int2string(idx)); sort(begin, arr->Childs.end(), cmp_by_name); } c->setReturnVar(arr); }
static void scRegExpExec(const CFunctionsScopePtr &c, void *) { CScriptVarRegExpPtr This = c->getArgument("this"); if(This) c->setReturnVar(This->exec(c->getArgument("str")->toString())); else c->throwError(TypeError, "Object is not a RegExp-Object in exec(str)"); }
static void scCharToInt(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("ch")->toString();; int val = 0; if (str.length()>0) val = (int)str.c_str()[0]; c->setReturnVar(c->newScriptVar(val)); }
static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) { int length = c->getArgumentsLength(); string str = this2string(c); for(int32_t i=ptr2int32(userdata); i<length; i++) str.append(c->getArgument(i)->toString()); c->setReturnVar(c->newScriptVar(str)); }
static void scStringLocaleCompare(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string compareString = c->getArgument("compareString")->toString(); int32_t val = 0; if(str<compareString) val = -1; else if(str>compareString) val = 1; c->setReturnVar(c->newScriptVar(val)); }
static void scStringSearch(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string substr; bool global, ignoreCase, sticky; getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky); string::const_iterator search_begin=str.begin(), match_begin, match_end; #ifndef NO_REGEXP try { c->setReturnVar(c->newScriptVar(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } #else /* NO_REGEXP */ c->setReturnVar(c->newScriptVar(string_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1)); #endif /* NO_REGEXP */ }
static void scStringReplace(const CFunctionsScopePtr &c, void *) { const string str = this2string(c); CScriptVarPtr newsubstrVar = c->getArgument("newsubstr"); string substr, ret_str; bool global, ignoreCase, sticky; bool isRegExp = getRegExpData(c, "substr", false, "flags", substr, global, ignoreCase, sticky); if(isRegExp && !newsubstrVar->isFunction()) { #ifndef NO_REGEXP regex::flag_type flags = regex_constants::ECMAScript; if(ignoreCase) flags |= regex_constants::icase; regex_constants::match_flag_type mflags = regex_constants::match_default; if(!global) mflags |= regex_constants::format_first_only; if(sticky) mflags |= regex_constants::match_continuous; ret_str = regex_replace(str, regex(substr, flags), newsubstrVar->toString(), mflags); #endif /* NO_REGEXP */ } else { bool (*search)(const string &, const string::const_iterator &, const string &, bool, bool, string::const_iterator &, string::const_iterator &); #ifndef NO_REGEXP if(isRegExp) search = regex_search; else #endif /* NO_REGEXP */ search = string_search; string newsubstr; vector<CScriptVarPtr> arguments; if(!newsubstrVar->isFunction()) newsubstr = newsubstrVar->toString(); global = global && substr.length(); string::const_iterator search_begin=str.begin(), match_begin, match_end; if(search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) { do { ret_str.append(search_begin, match_begin); if(newsubstrVar->isFunction()) { arguments.push_back(c->newScriptVar(string(match_begin, match_end))); newsubstr = c->getContext()->callFunction(newsubstrVar, arguments)->toString(); arguments.pop_back(); } ret_str.append(newsubstr); #if 1 /* Fix from "vcmpeq" (see Issue 14) currently untested */ if (match_begin == match_end) { if (search_begin != str.end()) ++search_begin; else break; } else { search_begin = match_end; } #else search_begin = match_end; #endif } while(global && search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)); } ret_str.append(search_begin, str.end()); } c->setReturnVar(c->newScriptVar(ret_str)); }
static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); int32_t length = c->getArgumentsLength()-(ptr2int32(userdata) & 1); bool slice = (ptr2int32(userdata) & 2) == 0; int32_t start = c->getArgument("start")->toNumber().toInt32(); int32_t end = (int32_t)str.size(); if(slice && start<0) start = (int32_t)(str.size())+start; if(length>1) { end = c->getArgument("end")->toNumber().toInt32(); if(slice && end<0) end = (int32_t)(str.size())+end; } if(!slice && end < start) { end^=start; start^=end; end^=start; } if(start<0) start = 0; if(start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(end <= start) c->setReturnVar(c->newScriptVar("")); else c->setReturnVar(c->newScriptVar(str.substr(start, end-start))); }
static void scArrayJoin(const CFunctionsScopePtr &c, void *data) { string sep = c->getArgument("separator")->toString(); CScriptVarPtr arr = c->getArgument("this"); ostringstream sstr; int l = arr->getArrayLength(); for (int i=0;i<l;i++) { if (i>0) sstr << sep; sstr << arr->getArrayIndex(i)->toString(); } c->setReturnVar(c->newScriptVar(sstr.str())); }
static void scStringTrim(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string::size_type start = 0; string::size_type end = string::npos; if(((ptr2int32(userdata)) & 2) == 0) { start = str.find_first_not_of(" \t\r\n"); if(start == string::npos) start = 0; } if(((ptr2int32(userdata)) & 1) == 0) { end = str.find_last_not_of(" \t\r\n"); if(end != string::npos) end = 1+end-start; } c->setReturnVar(c->newScriptVar(str.substr(start, end))); }
static void scArrayFill(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); uint32_t len = c->getLength(arr); CNumber startNumber=0, endNumber=len; CScriptVarPtr value = c->getArgument(0); CScriptVarPtr startVar = c->getArgument(1); CScriptVarPtr endVar = c->getArgument(2); c->setReturnVar(arr); if(!startVar->isUndefined()) startNumber = startVar->toNumber(); if(!endVar->isUndefined()) endNumber = endVar->toNumber(); uint32_t start = (startNumber.sign()<0 ? startNumber+len : startNumber).clamp(0, len).toUInt32(); uint32_t end = (endNumber.sign()<0 ? endNumber+len : endNumber).clamp(0, len).toUInt32(); for(; start < end; ++start) c->setProperty(arr, start, value); }
static void scStringMatch(const CFunctionsScopePtr &c, void *) { string str = this2string(c); string flags="flags", substr, newsubstr, match; bool global, ignoreCase, sticky; CScriptVarRegExpPtr RegExp = getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky); if(!global) { if(!RegExp) RegExp = ::newScriptVar(c->getContext(), substr, flags); if(RegExp) { try { c->setReturnVar(RegExp->exec(str)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } } else { try { CScriptVarArrayPtr retVar = c->newScriptVar(Array); int idx=0; string::size_type offset=0; global = global && substr.length(); string::const_iterator search_begin=str.begin(), match_begin, match_end; if(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) { do { offset = match_begin-str.begin(); retVar->addChild(int2string(idx++), c->newScriptVar(string(match_begin, match_end))); #if 1 /* Fix from "vcmpeq" (see Issue 14) currently untested */ if (match_begin == match_end) { if (search_begin != str.end()) ++search_begin; else break; } else { search_begin = match_end; } #else search_begin = match_end; #endif } while(global && regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)); } if(idx) { retVar->addChild("input", c->newScriptVar(str)); retVar->addChild("index", c->newScriptVar((int)offset)); c->setReturnVar(retVar); } else c->setReturnVar(c->constScriptVar(Null)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } }
static void scStringSplit(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("this")->getString(); CScriptVarPtr sep_var = c->getArgument("separator"); CScriptVarPtr limit_var = c->getArgument("limit"); int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->getInt(); CScriptVarPtr result(newScriptVar(c->getContext(), Array)); c->setReturnVar(result); if(limit == 0 || !str.size()) return; else if(sep_var->isUndefined()) { result->setArrayIndex(0, c->newScriptVar(str)); return; } string sep = sep_var->getString(); if(sep.size() == 0) { for(int i=0; i<min((int)sep.size(), limit); ++i) result->setArrayIndex(i, c->newScriptVar(str.substr(i,1))); return; } int length = 0; string::size_type pos = 0, last_pos=0; do { pos = str.find(sep, last_pos); result->setArrayIndex(length++, c->newScriptVar(str.substr(last_pos ,pos-last_pos))); if(length == limit || pos == string::npos) break; last_pos = pos+sep.size(); } while (last_pos < str.size()); }
static void scStringSplit(const CFunctionsScopePtr &c, void *) { const string str = this2string(c); string seperator; bool global, ignoreCase, sticky; #ifndef NO_REGEXP CScriptVarRegExpPtr RegExp = getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky); #else getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky); #endif CScriptVarPtr sep_var = c->getArgument("separator"); CScriptVarPtr limit_var = c->getArgument("limit"); int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->toNumber().toInt32(); CScriptVarPtr result(c->newScriptVar(Array)); c->setReturnVar(result); if(limit == 0) return; else if(!str.size() || sep_var->isUndefined()) { result->addChild("0", c->newScriptVar(str)); return; } if(seperator.size() == 0) { for(int i=0; i<min((int)str.size(), limit); ++i) result->addChild(i, c->newScriptVar(str.substr(i,1))); return; } int length = 0; string::const_iterator search_begin=str.begin(), match_begin, match_end; #ifndef NO_REGEXP smatch match; #endif bool found=true; while(found) { #ifndef NO_REGEXP if(RegExp) { try { found = regex_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end, match); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } else /* NO_REGEXP */ #endif found = string_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end); string f; if(found) { result->addChild(length++, c->newScriptVar(string(search_begin, match_begin))); if(length>=limit) break; #ifndef NO_REGEXP for(uint32_t i=1; i<match.size(); i++) { if(match[i].matched) result->addChild(length++, c->newScriptVar(string(match[i].first, match[i].second))); else result->addChild(length++, c->constScriptVar(Undefined)); if(length>=limit) break; } if(length>=limit) break; #endif search_begin = match_end; } else { result->addChild(length++, c->newScriptVar(string(search_begin,str.end()))); if(length>=limit) break; } } }
static void scObjectClone(const CFunctionsScopePtr &c, void *) { CScriptVarPtr obj = c->getArgument("this"); c->setReturnVar(obj->clone()); }
static void scStringQuote(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); c->setReturnVar(c->newScriptVar(getJSString(str))); }
static void scStringToUpperCase(const CFunctionsScopePtr &c, void *) { string str = this2string(c); transform(str.begin(), str.end(), str.begin(), ::toupper); c->setReturnVar(c->newScriptVar(str)); }
static void scStringFromCharCode(const CFunctionsScopePtr &c, void *) { char str[2]; str[0] = c->getArgument("char")->toNumber().toInt32(); str[1] = 0; c->setReturnVar(c->newScriptVar(str)); }