/*JSON{ "type" : "method", "ifndef" : "SAVE_ON_FLASH", "class" : "RegExp", "name" : "exec", "params" : [ ["str","JsVar","A string to match on"] ], "generate" : "jswrap_regexp_exec", "return" : ["JsVar","A result array, or null"] } Test this regex on a string - returns a result array on success, or `null` otherwise. `/Wo/.exec("Hello World")` will return: ``` [ "Wo", "index": 6, "input": "Hello World" ] ``` Or with groups `/W(o)rld/.exec("Hello World")` returns: ``` [ "World", "o", "index": 6, "input": "Hello World" ] ``` */ JsVar *jswrap_regexp_exec(JsVar *parent, JsVar *arg) { JsVar *str = jsvAsString(arg); JsVarInt lastIndex = jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, "lastIndex", 0)); JsVar *regex = jsvObjectGetChild(parent, "source", 0); if (!jsvIsString(regex)) { jsvUnLock2(str,regex); return 0; } size_t regexLen = jsvGetStringLength(regex); char *regexPtr = (char *)alloca(regexLen+1); if (!regexPtr) { jsvUnLock2(str,regex); return 0; } jsvGetString(regex, regexPtr, regexLen+1); jsvUnLock(regex); JsVar *rmatch = match(regexPtr, str, (size_t)lastIndex, jswrap_regexp_hasFlag(parent,'i')); jsvUnLock(str); if (!rmatch) { rmatch = jsvNewWithFlags(JSV_NULL); lastIndex = 0; } else { // if it's global, set lastIndex if (jswrap_regexp_hasFlag(parent,'g')) { JsVar *matchStr = jsvGetArrayItem(rmatch,0); lastIndex = jsvGetIntegerAndUnLock(jsvObjectGetChild(rmatch, "index", 0)) + (JsVarInt)jsvGetStringLength(matchStr); jsvUnLock(matchStr); } else lastIndex = 0; } jsvObjectSetChildAndUnLock(parent, "lastIndex", jsvNewFromInteger(lastIndex)); return rmatch; }
/*JSON{ "type" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The start character index"] ], "return" : ["JsVar","Part of this string from start for len characters"] } Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==[1,2,3]``` */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { JsVar *array = jsvNewWithFlags(JSV_ARRAY); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } split = jsvAsString(split, false); int idx, last = 0; int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split); int l = (int)jsvGetStringLength(parent) + 1 - splitlen; for (idx=0;idx<=l;idx++) { if (splitlen==0 && idx==0) continue; // special case for where split string is "" if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) { if (idx==l) { idx=l+splitlen; // if the last element, do to the end of the string if (splitlen==0) break; } JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)); if (!part) break; // out of memory jsvArrayPush(array, part); jsvUnLock(part); last = idx+splitlen; } } jsvUnLock(split); return array; }
/*JSON{ "type":"function", "name" : "eval", "description" : "Evaluate a string containing JavaScript code", "generate" : "jswrap_eval", "params" : [ [ "code", "JsVar", ""] ], "return" : ["JsVar", "The result of evaluating the string"] }*/ JsVar *jswrap_eval(JsVar *v) { if (!v) return 0; JsVar *s = jsvAsString(v, false); // get as a string JsVar *result = jspEvaluateVar(s, 0); jsvUnLock(s); return result; }
void serverResponseWrite(JsVar *httpServerResponseVar, JsVar *data) { // Append data to sendData JsVar *sendData = jsvObjectGetChild(httpServerResponseVar, HTTP_NAME_SEND_DATA, 0); if (!sendData) { // no sendData, so no headers - add them! JsVar *sendHeaders = jsvObjectGetChild(httpServerResponseVar, HTTP_NAME_HEADERS, 0); if (sendHeaders) { sendData = jsvVarPrintf("HTTP/1.0 %d OK\r\nServer: Espruino "JS_VERSION"\r\n", jsvGetIntegerAndUnLock(jsvObjectGetChild(httpServerResponseVar, HTTP_NAME_CODE, 0))); httpAppendHeaders(sendData, sendHeaders); jsvObjectSetChild(httpServerResponseVar, HTTP_NAME_HEADERS, 0); jsvUnLock(sendHeaders); // finally add ending newline jsvAppendString(sendData, "\r\n"); } else if (!jsvIsUndefined(data)) { // we have already sent headers, but want to send more sendData = jsvNewFromEmptyString(); } jsvObjectSetChild(httpServerResponseVar, HTTP_NAME_SEND_DATA, sendData); } if (sendData && !jsvIsUndefined(data)) { JsVar *s = jsvAsString(data, false); if (s) jsvAppendStringVarComplete(sendData,s); jsvUnLock(s); } jsvUnLock(sendData); }
/*JSON{ "type" : "method", "class" : "String", "name" : "trim", "generate" : "jswrap_string_trim", "return" : ["JsVar","A String with Whitespace removed from the beginning and end"], "return_object" : "String" } Return a new string with any whitespace (tabs, space, form feed, newline, carriage return, etc) removed from the beginning and end. */ JsVar *jswrap_string_trim(JsVar *parent) { JsVar *s = jsvAsString(parent); if (!s) return s; unsigned int start = 0; int end = -1; // work out beginning and end JsvStringIterator it; jsvStringIteratorNew(&it, s, 0); while (jsvStringIteratorHasChar(&it)) { bool ws = isWhitespace(jsvStringIteratorGetChar(&it)); if (!ws) { if (end<0) start = (unsigned int)jsvStringIteratorGetIndex(&it); end = (int)jsvStringIteratorGetIndex(&it); // last } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); // work out length unsigned int len = 0; if (end>=(int)start) len = 1+(unsigned int)end-start; JsVar *res = jsvNewFromStringVar(s, start, len); jsvUnLock(s); return res; }
/*JSON{ "type" : "method", "class" : "String", "name" : "replace", "generate" : "jswrap_string_replace", "params" : [ ["subStr","JsVar","The string to search for"], ["newSubStr","JsVar","The string to replace it with"] ], "return" : ["JsVar","This string with `subStr` replaced"] } Search and replace ONE occurrance of `subStr` with `newSubStr` and return the result. This doesn't alter the original string. Regular expressions not supported. */ JsVar *jswrap_string_replace(JsVar *parent, JsVar *subStr, JsVar *newSubStr) { JsVar *str = jsvAsString(parent, false); subStr = jsvAsString(subStr, false); newSubStr = jsvAsString(newSubStr, false); int idx = jswrap_string_indexOf(parent, subStr, 0, false); if (idx>=0) { JsVar *newStr = jsvNewFromStringVar(str, 0, (size_t)idx); jsvAppendStringVar(newStr, newSubStr, 0, JSVAPPENDSTRINGVAR_MAXLENGTH); jsvAppendStringVar(newStr, str, (size_t)idx+jsvGetStringLength(subStr), JSVAPPENDSTRINGVAR_MAXLENGTH); jsvUnLock(str); str = newStr; } jsvUnLock2(subStr, newSubStr); return str; }
static void httpAppendHeaders(JsVar *string, JsVar *headerObject) { // append headers JsvObjectIterator it; jsvObjectIteratorNew(&it, headerObject); while (jsvObjectIteratorHasValue(&it)) { JsVar *k = jsvAsString(jsvObjectIteratorGetKey(&it), true); JsVar *v = jsvAsString(jsvObjectIteratorGetValue(&it), true); jsvAppendStringVarComplete(string, k); jsvAppendString(string, ": "); jsvAppendStringVarComplete(string, v); jsvAppendString(string, "\r\n"); jsvUnLock2(k, v); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); // free headers }
/*JSON{ "type" : "method", "class" : "String", "name" : "startsWith", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_string_startsWith", "params" : [ ["searchString","JsVar","The string to search for"], ["position","int","The start character index (or 0 if not defined)"] ], "return" : ["bool","`true` if the given characters are found at the beginning of the string, otherwise, `false`."] } */ bool jswrap_string_startsWith(JsVar *parent, JsVar *search, int position) { if (!jsvIsString(parent)) return false; JsVar *searchStr = jsvAsString(search); bool match = false; if (position >= 0 && jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent)) match = jsvCompareString(parent, searchStr, position,0,true)==0; jsvUnLock(searchStr); return match; }
/*JSON{ "type":"method", "class": "Array", "name" : "join", "description" : "Join all elements of this array together into one string, using 'separator' between them. eg. ```[1,2,3].join(' ')=='1 2 3'```", "generate" : "jswrap_array_join", "params" : [ [ "separator", "JsVar", "The separator"] ], "return" : ["JsVar", "A String representing the Joined array"] }*/ JsVar *jswrap_array_join(JsVar *parent, JsVar *filler) { if (jsvIsUndefined(filler)) filler = jsvNewFromString(","); // the default it seems else filler = jsvAsString(filler, false); if (!filler) return 0; // out of memory JsVar *str = jsvArrayJoin(parent, filler); jsvUnLock(filler); return str; }
/*JSON{ "type":"method", "class": "Object", "name" : "toString", "description" : "Convert the Object to a string", "generate" : "jswrap_object_toString", "params" : [ [ "radix", "JsVar", "If the object is an integer, the radix (between 2 and 36) to use. NOTE: Setting a radix does not work on floating point numbers."] ], "return" : ["JsVar", "A String representing the object"] }*/ JsVar *jswrap_object_toString(JsVar *parent, JsVar *arg0) { if (jsvIsInt(arg0) && jsvIsInt(parent)) { JsVarInt radix = jsvGetInteger(arg0); if (radix>=2 && radix<=36) { char buf[JS_NUMBER_BUFFER_SIZE]; itoa(parent->varData.integer, buf, (unsigned int)radix); return jsvNewFromString(buf); } } return jsvAsString(parent, false); }
/*JSON{ "type" : "staticmethod", "class" : "JSON", "name" : "parse", "generate" : "jswrap_json_parse", "params" : [ ["string","JsVar","A JSON string"] ], "return" : ["JsVar","The JavaScript object created by parsing the data string"] } Parse the given JSON string into a JavaScript object NOTE: This implementation uses eval() internally, and as such it is unsafe as it can allow arbitrary JS commands to be executed. */ JsVar *jswrap_json_parse(JsVar *v) { JsLex lex; JsVar *str = jsvAsString(v); JsLex *oldLex = jslSetLex(&lex); jslInit(str); jsvUnLock(str); JsVar *res = jswrap_json_parse_internal(); jslKill(); jslSetLex(oldLex); return res; }
/*JSON{ "type":"function", "name" : "edit", "description" : ["Fill the console with the contents of the given function, so you can edit it.", "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], "generate" : "jswrap_interface_edit", "params" : [ [ "funcName", "JsVar", "The name of the function to edit (either a string or just the unquoted name)"] ] }*/ void jswrap_interface_edit(JsVar *funcName) { JsVar *func = 0; if (jsvIsString(funcName)) { funcName = jsvLockAgain(funcName); func = jsvSkipNameAndUnLock(jsvFindChildFromVar(execInfo.root, funcName, 0)); } else { func = funcName; funcName = jsvGetPathTo(execInfo.root, func, 2); } if (jsvIsString(funcName)) { if (jsvIsFunction(func)) { JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); JsVar *inRoot = jsvGetArrayIndexOf(execInfo.root, func, true); bool normalDecl = scopeVar==0 && inRoot!=0; jsvUnLock(inRoot); jsvUnLock(scopeVar); JsVar *newLine = jsvNewFromEmptyString(); if (newLine) { // could be out of memory /* normalDecl: * * function foo() { ... } * * NOT normalDecl: * * foo.replaceWith(function() { ... }); * */ JsVar *funcData = jsvAsString(func, false); if (normalDecl) { jsvAppendString(newLine, "function "); jsvAppendStringVarComplete(newLine, funcName); jsvAppendStringVar(newLine, funcData, 9, JSVAPPENDSTRINGVAR_MAXLENGTH); } else { jsvAppendStringVarComplete(newLine, funcName); jsvAppendString(newLine, ".replaceWith("); jsvAppendStringVarComplete(newLine, funcData); jsvAppendString(newLine, ");"); } jsvUnLock(funcData); jsiReplaceInputLine(newLine); jsvUnLock(newLine); } } else { jsError("Edit should be called with the name of a function"); } } else { jsError("Edit should be called with edit(funcName) or edit('funcName')"); } jsvUnLock(func); jsvUnLock(funcName); }
/*JSON{ "type":"method", "class": "Serial", "name" : "println", "description" : "Print a line to the serial port (newline character sent are '\r\n')", "generate" : "jswrap_serial_println", "params" : [ [ "string", "JsVar", "A String to print"] ] }*/ void _jswrap_serial_print(JsVar *parent, JsVar *str, bool newLine) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); str = jsvAsString(str, false); jsiTransmitStringVar(device,str); jsvUnLock(str); if (newLine) { jshTransmit(device, (unsigned char)'\r'); jshTransmit(device, (unsigned char)'\n'); } }
/*JSON{ "type" : "method", "class" : "String", "name" : "endsWith", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_string_endsWith", "params" : [ ["searchString","JsVar","The string to search for"], ["length","JsVar","The 'end' of the string - if left off the actual length of the string is used"] ], "return" : ["bool","`true` if the given characters are found at the end of the string, otherwise, `false`."] } */ bool jswrap_string_endsWith(JsVar *parent, JsVar *search, JsVar *length) { if (!jsvIsString(parent)) return false; int position = jsvIsNumeric(length) ? jsvGetInteger(length) : (int)jsvGetStringLength(parent); JsVar *searchStr = jsvAsString(search); position -= jsvGetStringLength(searchStr); bool match = false; if (position >= 0 && jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent)) match = jsvCompareString(parent, searchStr, position,0,true)==0; jsvUnLock(searchStr); return match; }
/*JSON{ "type" : "method", "class" : "String", "name" : "match", "generate" : "jswrap_string_match", "params" : [ ["subStr","JsVar","Substring or RegExp to match"] ], "return" : ["JsVar","This match array"] } Matches `subStr` occurrence in the string. */ JsVar *jswrap_string_match(JsVar *parent, JsVar *subStr) { if (!jsvIsString(parent)) return 0; if (jsvIsUndefined(subStr)) return 0; #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(subStr, "RegExp")) { jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); JsVar *match; match = jswrap_regexp_exec(subStr, parent); if (!jswrap_regexp_hasFlag(subStr,'g')) { return match; } // global JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); int last = idx+len; jsvArrayPushAndUnLock(array, matchStr); // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(subStr, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); return array; } #endif subStr = jsvAsString(subStr); int idx = jswrap_string_indexOf(parent, subStr, 0, false); if (idx>=0) { JsVar *array = jsvNewEmptyArray(); if (!array) { jsvUnLock(subStr); return 0; // out of memory } jsvArrayPush(array, subStr); jsvObjectSetChildAndUnLock(array, "index", jsvNewFromInteger(idx)); jsvObjectSetChildAndUnLock(array, "input", subStr); return array; } jsvUnLock(subStr); return NULL; }
JsVar *_jswrap_error_constructor(JsVar *msg, char *type) { JsVar *d = jspNewObject(0,type); if (!d) return 0; if (msg) { msg = jsvAsString(msg, false); jsvObjectSetChildAndUnLock(d, "msg", msg); } jsvObjectSetChildAndUnLock(d, "type", jsvNewFromString(type)); return d; }
void _jswrap_serial_print(JsVar *parent, JsVar *arg, bool isPrint, bool newLine) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_USART(device)) return; if (isPrint) arg = jsvAsString(arg, false); jsvIterateCallback(arg, _jswrap_serial_print_cb, (void*)&device); if (isPrint) jsvUnLock(arg); if (newLine) { _jswrap_serial_print_cb((unsigned char)'\r', (void*)&device); _jswrap_serial_print_cb((unsigned char)'\n', (void*)&device); } }
/*JSON{ "type" : "method", "class" : "Object", "name" : "toString", "generate" : "jswrap_object_toString", "params" : [ ["radix","JsVar","If the object is an integer, the radix (between 2 and 36) to use. NOTE: Setting a radix does not work on floating point numbers."] ], "return" : ["JsVar","A String representing the object"] } Convert the Object to a string */ JsVar *jswrap_object_toString(JsVar *parent, JsVar *arg0) { if (jsvIsInt(arg0) && jsvIsNumeric(parent)) { JsVarInt radix = jsvGetInteger(arg0); if (radix>=2 && radix<=36) { char buf[JS_NUMBER_BUFFER_SIZE]; if (jsvIsInt(parent)) itostr(jsvGetInteger(parent), buf, (unsigned int)radix); else ftoa_bounded_extra(jsvGetFloat(parent), buf, sizeof(buf), (int)radix, -1); return jsvNewFromString(buf); } } return jsvAsString(parent, false); }
/*JSON{ "type":"method", "class": "String", "name" : "indexOf", "description" : "Return the index of substring in this string, or -1 if not found", "generate" : "jswrap_string_indexOf", "params" : [ [ "substring", "JsVar", "The string to search for"] ], "return" : ["int", "The index of the string, or -1 if not found"] }*/ JsVarInt jswrap_string_indexOf(JsVar *parent, JsVar *v) { // slow, but simple! v = jsvAsString(v, false); if (!v) return 0; // out of memory int idx = -1; int l = (int)jsvGetStringLength(parent) - (int)jsvGetStringLength(v); for (idx=0;idx<l;idx++) { if (jsvCompareString(parent, v, idx, 0, true)==0) { jsvUnLock(v); return idx; } } jsvUnLock(v); return -1; }
void clientRequestWrite(JsVar *httpClientReqVar, JsVar *data) { SocketType socketType = socketGetType(httpClientReqVar); // Append data to sendData JsVar *sendData = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, 0); if (!sendData) { JsVar *options = 0; // Only append a header if we're doing HTTP if (socketType == ST_HTTP) options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, 0); if (options) { JsVar *method = jsvObjectGetChild(options, "method", 0); JsVar *path = jsvObjectGetChild(options, "path", 0); sendData = jsvVarPrintf("%v %v HTTP/1.0\r\nUser-Agent: Espruino "JS_VERSION"\r\nConnection: close\r\n", method, path); jsvUnLock(method); jsvUnLock(path); JsVar *headers = jsvObjectGetChild(options, "headers", 0); bool hasHostHeader = false; if (jsvIsObject(headers)) { JsVar *hostHeader = jsvObjectGetChild(headers, "Host", 0); hasHostHeader = hostHeader!=0; jsvUnLock(hostHeader); httpAppendHeaders(sendData, headers); } jsvUnLock(headers); if (!hasHostHeader) { JsVar *host = jsvObjectGetChild(options, "host", 0); int port = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0)); if (port>0 && port!=80) jsvAppendPrintf(sendData, "Host: %v:%d\r\n", host, port); else jsvAppendPrintf(sendData, "Host: %v\r\n", host); jsvUnLock(host); } // finally add ending newline jsvAppendString(sendData, "\r\n"); } else { sendData = jsvNewFromString(""); } jsvObjectSetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, sendData); jsvUnLock(options); } if (data && sendData) { JsVar *s = jsvAsString(data, false); if (s) jsvAppendStringVarComplete(sendData,s); jsvUnLock(s); } jsvUnLock(sendData); }
/*JSON{ "type":"staticmethod", "class":"console", "name" : "log", "description" : "Print the supplied string(s)", "generate" : "jswrap_interface_print", "params" : [ [ "text", "JsVarArray", "One or more arguments to print"] ] }*/ void jswrap_interface_print(JsVar *v) { assert(jsvIsArray(v)); JsArrayIterator it; jsvArrayIteratorNew(&it, v); while (jsvArrayIteratorHasElement(&it)) { JsVar *v = jsvAsString(jsvArrayIteratorGetElement(&it), true); jsiConsoleRemoveInputLine(); jsiConsolePrintStringVar(v); jsvUnLock(v); jsvArrayIteratorNext(&it); if (jsvArrayIteratorHasElement(&it)) jsiConsolePrint(" "); } jsvArrayIteratorFree(&it); jsiConsolePrint("\n"); }
void serverResponseWrite(JsVar *httpServerResponseVar, JsVar *data) { // Append data to sendData JsVar *sendData = jsvObjectGetChild(httpServerResponseVar, HTTP_NAME_SEND_DATA, 0); if (!sendData) { // There was no sent data, which means we haven't written headers yet. // Do that now with default values serverResponseWriteHead(httpServerResponseVar, 200, 0); // sendData should now have been set sendData = jsvObjectGetChild(httpServerResponseVar, HTTP_NAME_SEND_DATA, 0); } // check, just in case! if (sendData && !jsvIsUndefined(data)) { JsVar *s = jsvAsString(data, false); if (s) jsvAppendStringVarComplete(sendData,s); jsvUnLock(s); } jsvUnLock(sendData); }
/*JSON{ "type" : "method", "class" : "String", "name" : "lastIndexOf", "generate_full" : "jswrap_string_indexOf(parent, substring, fromIndex, true)", "params" : [ ["substring","JsVar","The string to search for"], ["fromIndex","JsVar","Index to search from"] ], "return" : ["int32","The index of the string, or -1 if not found"] } Return the last index of substring in this string, or -1 if not found */ int jswrap_string_indexOf(JsVar *parent, JsVar *substring, JsVar *fromIndex, bool lastIndexOf) { if (!jsvIsString(parent)) return 0; // slow, but simple! substring = jsvAsString(substring, false); if (!substring) return 0; // out of memory int parentLength = (int)jsvGetStringLength(parent); int subStringLength = (int)jsvGetStringLength(substring); if (subStringLength > parentLength) { jsvUnLock(substring); return -1; } int lastPossibleSearch = parentLength - subStringLength; int idx, dir, end; if (!lastIndexOf) { // normal indexOf dir = 1; end = lastPossibleSearch+1; idx = 0; if (jsvIsNumeric(fromIndex)) { idx = (int)jsvGetInteger(fromIndex); if (idx<0) idx=0; if (idx>end) idx=end; } } else { dir = -1; end = -1; idx = lastPossibleSearch; if (jsvIsNumeric(fromIndex)) { idx = (int)jsvGetInteger(fromIndex); if (idx<0) idx=0; if (idx>lastPossibleSearch) idx=lastPossibleSearch; } } for (;idx!=end;idx+=dir) { if (jsvCompareString(parent, substring, (size_t)idx, 0, true)==0) { jsvUnLock(substring); return idx; } } jsvUnLock(substring); return -1; }
/*JSON{ "type":"function", "name" : "edit", "description" : ["Fill the console with the contents of the given function, so you can edit it.", "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], "generate" : "jswrap_interface_edit", "params" : [ [ "funcName", "JsVarName", "The name of the function to edit (either a string or just the unquoted name)"] ] }*/ void jswrap_interface_edit(JsVar *funcName) { if (jsvIsString(funcName)) { JsVar *func = 0; if (jsvIsName(funcName)) func = jsvSkipName(funcName); else func = jsvSkipNameAndUnLock(jsvFindChildFromVar(jsiGetParser()->root, funcName, 0)); if (jsvIsFunction(func)) { JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); JsVarRef scope = jsvGetRef(scopeVar); jsvUnLock(scopeVar); JsVar *newLine = jsvNewFromEmptyString(); if (newLine) { // could be out of memory jsvAppendStringVarComplete(newLine, funcName); if (scope) { // If we have a scope, it's an internal function so we will need to write different code jsvAppendString(newLine, ".replaceWith("); } else { jsvAppendString(newLine, " = "); } JsVar *funcData = jsvAsString(func, false); if (funcData) jsvAppendStringVarComplete(newLine, funcData); jsvUnLock(funcData); if (scope) { jsvAppendString(newLine, ");"); } else { jsvAppendString(newLine, ";"); } jsiReplaceInputLine(newLine); jsvUnLock(newLine); } } else { jsError("Edit should be called with the name of a function"); } jsvUnLock(func); } else { jsError("Edit should be called with edit(funcName) or edit('funcName')"); } }
/*JSON{ "type" : "method", "class" : "String", "name" : "toUpperCase", "generate_full" : "jswrap_string_toUpperLowerCase(parent, true)", "params" : [ ], "return" : ["JsVar","The uppercase version of this string"] }*/ JsVar *jswrap_string_toUpperLowerCase(JsVar *parent, bool upper) { JsVar *res = jsvNewFromEmptyString(); if (!res) return 0; // out of memory JsVar *parentStr = jsvAsString(parent); JsvStringIterator itsrc, itdst; jsvStringIteratorNew(&itsrc, parentStr, 0); jsvStringIteratorNew(&itdst, res, 0); while (jsvStringIteratorHasChar(&itsrc)) { char ch = jsvStringIteratorGetChar(&itsrc); ch = upper ? jsvStringCharToUpper(ch) : jsvStringCharToLower(ch); jsvStringIteratorAppend(&itdst, ch); jsvStringIteratorNext(&itsrc); } jsvStringIteratorFree(&itsrc); jsvStringIteratorFree(&itdst); jsvUnLock(parentStr); return res; }
/*JSON{ "type" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The separator `String` or `RegExp` to use"] ], "return" : ["JsVar","Part of this string from start for len characters"] } Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==['1', '2', '3']``` Regular Expressions can also be used to split strings, eg. `'1a2b3 4'.split(/[^0-9]/)==['1', '2', '3', '4']`. */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { if (!jsvIsString(parent)) return 0; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(split, "RegExp")) { unsigned int last = 0; JsVar *match; jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); match = jswrap_regexp_exec(split, parent); while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); jsvUnLock(matchStr); // do the replacement jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last))); last = idx+len; // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(split, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); // add remaining string after last match if (last<=jsvGetStringLength(parent)) jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, JSVAPPENDSTRINGVAR_MAXLENGTH)); return array; } #endif split = jsvAsString(split); int idx, last = 0; int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split); int l = (int)jsvGetStringLength(parent) + 1 - splitlen; for (idx=0;idx<=l;idx++) { if (splitlen==0 && idx==0) continue; // special case for where split string is "" if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) { if (idx==l) { idx=l+splitlen; // if the last element, do to the end of the string if (splitlen==0) break; } JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)); if (!part) break; // out of memory jsvArrayPush(array, part); jsvUnLock(part); last = idx+splitlen; } } jsvUnLock(split); return array; }
/*JSON{ "type" : "constructor", "class" : "String", "name" : "String", "generate" : "jswrap_string_constructor", "params" : [ ["str","JsVar","A value to turn into a string. If undefined or not supplied, an empty String is created."] ], "return" : ["JsVar","A String"] } Create a new String */ JsVar *jswrap_string_constructor(JsVar *a) { if (!a) return jsvNewFromEmptyString(); // no argument - return an empty string return jsvAsString(a, false); }
/*JSON{ "type" : "constructor", "class" : "String", "name" : "String", "generate" : "jswrap_string_constructor", "params" : [ ["str","JsVarArray","A value to turn into a string. If undefined or not supplied, an empty String is created."] ], "return" : ["JsVar","A String"] } Create a new String */ JsVar *jswrap_string_constructor(JsVar *args) { if (jsvGetArrayLength(args)==0) return jsvNewFromEmptyString(); // no argument - return an empty string return jsvAsString(jsvGetArrayItem(args, 0), true); }
void clientRequestWrite(JsNetwork *net, JsVar *httpClientReqVar, JsVar *data) { SocketType socketType = socketGetType(httpClientReqVar); // Append data to sendData JsVar *sendData = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, 0); if (!sendData) { JsVar *options = 0; // Only append a header if we're doing HTTP AND we haven't already connected if ((socketType&ST_TYPE_MASK) == ST_HTTP) if (jsvGetIntegerAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SOCKET, 0))==0) options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, 0); if (options) { // We're an HTTP client - make a header JsVar *method = jsvObjectGetChild(options, "method", 0); JsVar *path = jsvObjectGetChild(options, "path", 0); sendData = jsvVarPrintf("%v %v HTTP/1.0\r\nUser-Agent: Espruino "JS_VERSION"\r\nConnection: close\r\n", method, path); jsvUnLock2(method, path); JsVar *headers = jsvObjectGetChild(options, "headers", 0); bool hasHostHeader = false; if (jsvIsObject(headers)) { JsVar *hostHeader = jsvObjectGetChild(headers, "Host", 0); hasHostHeader = hostHeader!=0; jsvUnLock(hostHeader); httpAppendHeaders(sendData, headers); // if Transfer-Encoding:chunked was set, subsequent writes need to 'chunk' the data that is sent if (jsvIsStringEqualAndUnLock(jsvObjectGetChild(headers, "Transfer-Encoding", 0), "chunked")) { jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CHUNKED, jsvNewFromBool(true)); } } jsvUnLock(headers); if (!hasHostHeader) { JsVar *host = jsvObjectGetChild(options, "host", 0); int port = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0)); if (port>0 && port!=80) jsvAppendPrintf(sendData, "Host: %v:%d\r\n", host, port); else jsvAppendPrintf(sendData, "Host: %v\r\n", host); jsvUnLock(host); } // finally add ending newline jsvAppendString(sendData, "\r\n"); } else { // !options // We're not HTTP (or were already connected), so don't send any header sendData = jsvNewFromString(""); } jsvObjectSetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, sendData); jsvUnLock(options); } // We have data and aren't out of memory... if (data && sendData) { // append the data to what we want to send JsVar *s = jsvAsString(data, false); if (s) { if ((socketType&ST_TYPE_MASK) == ST_HTTP && jsvGetBoolAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_CHUNKED, 0))) { // If we asked to send 'chunked' data, we need to wrap it up, // prefixed with the length jsvAppendPrintf(sendData, "%x\r\n%v\r\n", jsvGetStringLength(s), s); } else { jsvAppendStringVarComplete(sendData,s); } jsvUnLock(s); } } jsvUnLock(sendData); if ((socketType&ST_TYPE_MASK) == ST_HTTP) { // on HTTP we connect after the first write clientRequestConnect(net, httpClientReqVar); } }
JsVar *wrap_fat_readdir(JsVar *path) { JsVar *arr = 0; // undefined unless we can open card char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); #ifdef LINUX if (!pathStr[0]) strcpy(pathStr, "."); // deal with empty readdir #endif FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX DIR dirs; if ((res=f_opendir(&dirs, pathStr)) == FR_OK) { char lfnBuf[_MAX_LFN+1]; FILINFO Finfo; Finfo.lfname = lfnBuf; Finfo.lfsize = sizeof(lfnBuf); #else DIR *dir = opendir(pathStr); if(dir) { #endif arr = jsvNewWithFlags(JSV_ARRAY); if (arr) { // could be out of memory #ifndef LINUX while (((res=f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) { char *fn = GET_FILENAME(Finfo); #else struct dirent *pDir=NULL; while((pDir = readdir(dir)) != NULL) { char *fn = (*pDir).d_name; #endif JsVar *fnVar = jsvNewFromString(fn); if (fnVar) // out of memory? jsvArrayPush(arr, fnVar); } } #ifdef LINUX closedir(dir); #endif } } if (res) jsfsReportError("Unable to list files", res); return arr; } /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFile", "generate" : "wrap_fat_writeFile", "description" : [ "Write the data to the given file", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_writeFile", "description" : [ "Write the data to the given file" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFile", "generate" : "wrap_fat_appendFile", "description" : [ "Append the data to the given file, created a new file if it doesn't exist", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_appendFile", "description" : [ "Append the data to the given file, created a new file if it doesn't exist" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ void wrap_fat_writeOrAppendFile(JsVar *path, JsVar *data, bool append) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX FIL file; if ((res=f_open(&file, pathStr, FA_WRITE|(append ? FA_OPEN_ALWAYS : FA_CREATE_ALWAYS))) == FR_OK) { if (append) { // move to end of file to append data f_lseek(&file, file.fsize); // if (res != FR_OK) jsfsReportError("Unable to move to end of file", res); } #else FILE *file = fopen(pathStr, append?"a":"w"); if (file) { #endif JsvStringIterator it; JsVar *dataString = jsvAsString(data, false); jsvStringIteratorNew(&it, dataString, 0); size_t toWrite = 0; size_t written = 0; while (jsvStringIteratorHasChar(&it) && res==FR_OK && written==toWrite) { // re-use pathStr buffer toWrite = 0; while (jsvStringIteratorHasChar(&it) && toWrite < JS_DIR_BUF_SIZE) { pathStr[toWrite++] = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); } #ifndef LINUX res = f_write(&file, pathStr, toWrite, &written); #else written = fwrite(pathStr, 1, toWrite, file); #endif } jsvStringIteratorFree(&it); jsvUnLock(dataString); #ifndef LINUX f_close(&file); #else fclose(file); #endif } } if (res) jsfsReportError("Unable to write file", res); } void wrap_fat_writeFile(JsVar *path, JsVar *data) { wrap_fat_writeOrAppendFile(path, data, false); } void wrap_fat_appendFile(JsVar *path, JsVar *data) { wrap_fat_writeOrAppendFile(path, data, true); }