/*JSON{ "type" : "staticmethod", "ifndef" : "SAVE_ON_FLASH", "class" : "E", "name" : "getErrorFlags", "generate" : "jswrap_espruino_getErrorFlags", "return" : ["JsVar","An array of error flags"] } Get and reset the error flags. Returns an array that can contain: `'FIFO_FULL'`: The receive FIFO filled up and data was lost. This could be state transitions for setWatch, or received characters. `'BUFFER_FULL'`: A buffer for a stream filled up and characters were lost. This can happen to any stream - Serial,HTTP,etc. `'CALLBACK'`: A callback (s`etWatch`, `setInterval`, `on('data',...)`) caused an error and so was removed. `'LOW_MEMORY'`: Memory is running low - Espruino had to run a garbage collection pass or remove some of the command history `'MEMORY'`: Espruino ran out of memory and was unable to allocate some data that it needed. */ JsVar *jswrap_espruino_getErrorFlags() { JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; if (jsErrorFlags&JSERR_RX_FIFO_FULL) jsvArrayPushAndUnLock(arr, jsvNewFromString("FIFO_FULL")); if (jsErrorFlags&JSERR_BUFFER_FULL) jsvArrayPushAndUnLock(arr, jsvNewFromString("BUFFER_FULL")); if (jsErrorFlags&JSERR_CALLBACK) jsvArrayPushAndUnLock(arr, jsvNewFromString("CALLBACK")); if (jsErrorFlags&JSERR_LOW_MEMORY) jsvArrayPushAndUnLock(arr, jsvNewFromString("LOW_MEMORY")); if (jsErrorFlags&JSERR_MEMORY) jsvArrayPushAndUnLock(arr, jsvNewFromString("MEMORY")); jsErrorFlags = JSERR_NONE; return arr; }
/*JSON{ "type":"staticmethod", "class": "Object", "name" : "keys", "description" : "Return all enumerable keys of the given object", "generate" : "jswrap_object_keys", "params" : [ [ "object", "JsVar", "The object to return keys for"] ], "return" : ["JsVar", "An array of strings - one for each key on the given object"] }*/ JsVar *jswrap_object_keys(JsVar *obj) { if (jsvIsIterable(obj)) { bool (*checkerFunction)(JsVar*) = 0; if (jsvIsFunction(obj)) checkerFunction = jsvIsInternalFunctionKey; else if (jsvIsObject(obj)) checkerFunction = jsvIsInternalObjectKey; JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; JsvIterator it; jsvIteratorNew(&it, obj); while (jsvIteratorHasElement(&it)) { JsVar *key = jsvIteratorGetKey(&it); if (!(checkerFunction && checkerFunction(key))) { JsVar *name = jsvCopyNameOnly(key,false,false); if (name) { jsvArrayPushAndUnLock(arr, name); } } jsvUnLock(key); jsvIteratorNext(&it); } jsvIteratorFree(&it); return arr; } else { jsWarn("Object.keys called on non-object"); return 0; } }
/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "getTrigger", "generate" : "jswrap_trig_getTrigger", "params" : [ ["num","int","The trigger number (0..7)"] ], "return" : ["JsVar","A structure containing all information about the trigger"] } Get the current state of a trigger */ JsVar *jswrap_trig_getTrigger(JsVarInt num) { TriggerStruct *trig = &mainTrigger; if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) { jsWarn("Invalid trigger number\n"); return 0; } TriggerPointStruct *tp = &trig->triggers[num]; // get offset in teeth JsVarFloat position = tp->tooth + (tp->toothFraction/256.0); // convert from teeth to degrees position = wrapAround((position * 360 / trig->teethTotal) + trig->keyPosition, 360); JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; JsVar *v; v = jsvNewFromFloat(position); jsvUnLock(jsvAddNamedChild(obj, v, "pos")); jsvUnLock(v); v = jsvNewFromFloat(jshGetMillisecondsFromTime(tp->pulseLength)); jsvUnLock(jsvAddNamedChild(obj, v, "pulseLength")); jsvUnLock(v); v = jsvNewWithFlags(JSV_ARRAY); int i; if (v) { for (i=0;i<TRIGGERPOINT_TRIGGERS_COUNT;i++) if (tp->pins[i] != PIN_UNDEFINED) { jsvArrayPushAndUnLock(v, jsvNewFromPin(tp->pins[i])); } } jsvUnLock(jsvAddNamedChild(obj, v, "pins")); jsvUnLock(v); return obj; }
JsVar *jswrap_arguments() { JsVar *scope = 0; if (execInfo.scopeCount>0) scope = jsvLock(execInfo.scopes[execInfo.scopeCount-1]); if (!jsvIsFunction(scope)) { jsvUnLock(scope); jsError("Can only use 'arguments' variable inside a function"); return 0; } JsVar *args = jsvNewWithFlags(JSV_ARRAY); if (!args) return 0; // out of memory JsvObjectIterator it; jsvObjectIteratorNew(&it, scope); while (jsvObjectIteratorHasElement(&it)) { JsVar *idx = jsvObjectIteratorGetKey(&it); if (jsvIsFunctionParameter(idx)) { JsVar *val = jsvSkipOneName(idx); jsvArrayPushAndUnLock(args, val); } jsvUnLock(idx); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(scope); return args; }
/*JSON{ "type" : "method", "class" : "Pin", "name" : "getInfo", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_pin_getInfo", "return" : ["JsVar","An object containing information about this pins"] } Get information about this pin and its capabilities. Of the form: ``` { "port" : "A", // the Pin's port on the chip "num" : 12, // the Pin's number "in_addr" : 0x..., // (if available) the address of the pin's input address in bit-banded memory (can be used with peek) "out_addr" : 0x..., // (if available) the address of the pin's output address in bit-banded memory (can be used with poke) "analog" : { ADCs : [1], channel : 12 }, // If analog input is available "functions" : { "TIM1":{type:"CH1, af:0}, "I2C3":{type:"SCL", af:1} } } ``` Will return undefined if pin is not valid. */ JsVar *jswrap_pin_getInfo( JsVar *parent //!< The class instance representing the pin. ) { Pin pin = jshGetPinFromVar(parent); if (!jshIsPinValid(pin)) return 0; const JshPinInfo *inf = &pinInfo[pin]; JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; char buf[2]; buf[0] = (char)('A'+(inf->port-JSH_PORTA)); buf[1] = 0; jsvObjectSetChildAndUnLock(obj, "port", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(obj, "num", jsvNewFromInteger(inf->pin-JSH_PIN0)); #ifdef STM32 volatile uint32_t *addr; addr = jshGetPinAddress(pin, JSGPAF_INPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "in_addr", jsvNewFromInteger((JsVarInt)addr)); addr = jshGetPinAddress(pin, JSGPAF_OUTPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "out_addr", jsvNewFromInteger((JsVarInt)addr)); #endif // ADC if (inf->analog) { JsVar *an = jsvNewWithFlags(JSV_OBJECT); if (an) { JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (arr) { int i; for (i=0;i<ADC_COUNT;i++) if (inf->analog&(JSH_ANALOG1<<i)) jsvArrayPushAndUnLock(arr, jsvNewFromInteger(1+i)); jsvObjectSetChildAndUnLock(an, "ADCs", arr); } jsvObjectSetChildAndUnLock(obj, "channel", jsvNewFromInteger(inf->analog & JSH_MASK_ANALOG_CH)); } } JsVar *funcs = jsvNewWithFlags(JSV_OBJECT); if (funcs) { int i; for (i=0;i<JSH_PININFO_FUNCTIONS;i++) { if (inf->functions[i]) { JsVar *func = jsvNewWithFlags(JSV_OBJECT); if (func) { char buf[16]; jshPinFunctionToString(inf->functions[i], JSPFTS_TYPE, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(func, "type", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(func, "af", jsvNewFromInteger(inf->functions[i] & JSH_MASK_AF)); jshPinFunctionToString(inf->functions[i], JSPFTS_DEVICE|JSPFTS_DEVICE_NUMBER, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(funcs, buf, func); } } } jsvObjectSetChildAndUnLock(obj, "functions", funcs); } return obj; }
// This is for Object.keys and Object. JsVar *jswrap_object_keys_or_property_names(JsVar *obj, bool includeNonEnumerable) { // strings are iterable, but we shouldn't try and show keys for them if (jsvIsIterable(obj) && !jsvIsString(obj)) { JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj); JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; JsvIterator it; jsvIteratorNew(&it, obj); while (jsvIteratorHasElement(&it)) { JsVar *key = jsvIteratorGetKey(&it); if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) { /* Not sure why constructor is included in getOwnPropertyNames, but * not in for (i in ...) but it is, so we must explicitly override the * check in jsvIsInternalObjectKey! */ JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false)); if (name) { jsvArrayPushAndUnLock(arr, name); } } jsvUnLock(key); jsvIteratorNext(&it); } jsvIteratorFree(&it); /* Search our built-in symbol table Assume that ALL builtins are non-enumerable. This isn't great but seems to work quite well right now! */ if (includeNonEnumerable) { const JswSymList *symbols = 0; JsVar *protoOwner = jspGetPrototypeOwner(obj); if (protoOwner) { symbols = jswGetSymbolListForObjectProto(protoOwner); jsvUnLock(protoOwner); } else if (!jsvIsObject(obj)) { // get symbols, but only if we're not doing it on a basic object symbols = jswGetSymbolListForObject(obj); } if (symbols) { unsigned int i; for (i=0;i<symbols->symbolCount;i++) jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]); } if (jsvIsArray(obj) || jsvIsString(obj)) { jsvArrayAddString(arr, "length"); } } return arr; } else { jsWarn("Object.keys called on non-object"); return 0; } }
/*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; }
/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "getErrorArray", "generate" : "jswrap_trig_getErrorArray", "return" : ["JsVar","An array of error strings"] } Get the current error flags from the trigger wheel - and zero them */ JsVar* jswrap_trig_getErrorArray() { TriggerStruct *trig = &mainTrigger; TriggerError errors = trig->errors; trig->errors = 0; JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (arr) { int i; for (i=1;i<=errors;i<<=1) { if (errors & i) { const char *s = trigGetErrorString(i); if (s) { jsvArrayPushAndUnLock(arr, jsvNewFromString(s)); } } } } return arr; }
/*JSON{ "type":"staticmethod", "class" : "Modules", "name" : "getCached", "description" : "Return an array of module names that have been cached", "generate" : "jswrap_modules_getCached", "return" : ["JsVar", "An array of module names"] }*/ JsVar *jswrap_modules_getCached() { JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; // out of memory JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return arr; // out of memory JsvObjectIterator it; jsvObjectIteratorNew(&it, moduleList); while (jsvObjectIteratorHasValue(&it)) { JsVar *idx = jsvObjectIteratorGetKey(&it); JsVar *idxCopy = jsvCopyNameOnly(idx, false, false); jsvArrayPushAndUnLock(arr, idxCopy); jsvUnLock(idx); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(moduleList); return arr; }
/*JSON{ "type" : "method", "class" : "Array", "name" : "splice", "generate" : "jswrap_array_splice", "params" : [ ["index","int","Index at which to start changing the array. If negative, will begin that many elements from the end"], ["howMany","JsVar","An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], ["elements","JsVarArray","One or more items to add to the array"] ], "return" : ["JsVar","An array containing the removed elements. If only one element is removed, an array of one element is returned."] } Both remove and add items to an array */ JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *elements) { if (!jsvIsArray(parent)) return 0; JsVarInt len = jsvGetArrayLength(parent); if (index<0) index+=len; if (index<0) index=0; if (index>len) index=len; JsVarInt howMany = len; // how many to delete! if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); if (howMany > len-index) howMany = len-index; JsVarInt newItems = jsvGetArrayLength(elements); JsVarInt shift = newItems-howMany; bool needToAdd = false; JsVar *result = jsvNewEmptyArray(); JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it) && !needToAdd) { bool goToNext = true; JsVar *idxVar = jsvObjectIteratorGetKey(&it); if (idxVar && jsvIsInt(idxVar)) { JsVarInt idx = jsvGetInteger(idxVar); if (idx<index) { // do nothing... } else if (idx<index+howMany) { // must delete if (result) { // append to result array JsVar *el = jsvObjectIteratorGetValue(&it); jsvArrayPushAndUnLock(result, el); } // delete goToNext = false; JsVar *toRemove = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); jsvRemoveChild(parent, toRemove); jsvUnLock(toRemove); } else { // we're greater than the amount we need to remove now needToAdd = true; goToNext = false; } } jsvUnLock(idxVar); if (goToNext) jsvObjectIteratorNext(&it); } // now we add everything JsVar *beforeIndex = jsvObjectIteratorGetKey(&it); JsvObjectIterator itElement; jsvObjectIteratorNew(&itElement, elements); while (jsvObjectIteratorHasValue(&itElement)) { JsVar *element = jsvObjectIteratorGetValue(&itElement); jsvArrayInsertBefore(parent, beforeIndex, element); jsvUnLock(element); jsvObjectIteratorNext(&itElement); } jsvObjectIteratorFree(&itElement); jsvUnLock(beforeIndex); // And finally renumber while (jsvObjectIteratorHasValue(&it)) { JsVar *idxVar = jsvObjectIteratorGetKey(&it); if (idxVar && jsvIsInt(idxVar)) { jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift); } jsvUnLock(idxVar); jsvObjectIteratorNext(&it); } // free jsvObjectIteratorFree(&it); // and reset array size jsvSetArrayLength(parent, len + shift, false); return result; }
JsVar *_jswrap_array_iterate_with_callback(const char *name, JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool wantArray, bool isBoolCallback, bool expectedValue) { if (!jsvIsIterable(parent)) { jsExceptionHere(JSET_ERROR, "Array.%s can only be called on something iterable", name); return 0; } if (!jsvIsFunction(funcVar)) { jsExceptionHere(JSET_ERROR, "Array.%s's first argument should be a function", name); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsExceptionHere(JSET_ERROR, "Array.%s's second argument should be undefined, or an object", name); return 0; } JsVar *result = 0; if (wantArray) result = jsvNewEmptyArray(); bool isDone = false; if (result || !wantArray) { JsvIterator it; jsvIteratorNew(&it, parent); while (jsvIteratorHasElement(&it) && !isDone) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[3], *cb_result; args[0] = jsvIteratorGetValue(&it); args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[2] = parent; cb_result = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLockMany(2,args); if (cb_result) { bool matched; if (isBoolCallback) matched = (jsvGetBool(cb_result) == expectedValue); if (wantArray) { if (isBoolCallback) { // filter if (matched) { jsvArrayPushAndUnLock(result, jsvIteratorGetValue(&it)); } } else { // map JsVar *name = jsvNewFromInteger(idxValue); if (name) { // out of memory? jsvMakeIntoVariableName(name, cb_result); jsvAddName(result, name); jsvUnLock(name); } } } else { // break the loop early if expecting a particular value and didn't get it if (isBoolCallback && !matched) isDone = true; } jsvUnLock(cb_result); } } jsvUnLock(index); jsvIteratorNext(&it); } jsvIteratorFree(&it); } /* boolean result depends on whether the loop terminated early for 'some' or completed for 'every' */ if (!wantArray && isBoolCallback) { result = jsvNewFromBool(isDone != expectedValue); } return result; }
/*JSON{ "type" : "method", "class" : "OneWire", "name" : "search", "generate" : "jswrap_onewire_search", "params" : [ ["command","int32","(Optional) command byte. If not specified (or zero), this defaults to 0xF0. This can could be set to 0xEC to perform a DS18B20 'Alarm Search Command'"] ], "return" : ["JsVar","An array of devices that were found"] } Search for devices */ JsVar *jswrap_onewire_search(JsVar *parent, int command) { // search - code from http://www.maximintegrated.com/app-notes/index.mvp/id/187 Pin pin = onewire_getpin(parent); if (!jshIsPinValid(pin)) return 0; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; if (command<=0 || command>255) command = 0xF0; // normal search command // global search state unsigned char ROM_NO[8]; int LastDiscrepancy; int LastFamilyDiscrepancy; int LastDeviceFlag; // reset the search state LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; int search_result = true; while (search_result) { int id_bit_number; int last_zero, rom_byte_number; unsigned char id_bit, cmp_id_bit; unsigned char rom_byte_mask, search_direction; // initialize for search id_bit_number = 1; last_zero = 0; rom_byte_number = 0; rom_byte_mask = 1; search_result = 0; // if the last call was not the last one if (!LastDeviceFlag) { // 1-Wire reset if (!OneWireReset(pin)) { // reset the search LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; return array; } // issue the search command OneWireWrite(pin, 8, (unsigned long long)command); // loop to do the search do { // read a bit and its complement id_bit = (unsigned char)OneWireRead(pin, 1); cmp_id_bit = (unsigned char)OneWireRead(pin, 1); // check for no devices on 1-wire if ((id_bit == 1) && (cmp_id_bit == 1)) break; else { // all devices coupled have 0 or 1 if (id_bit != cmp_id_bit) search_direction = id_bit; // bit write value for search else { // if this discrepancy if before the Last Discrepancy // on a previous next then pick the same as last time if (id_bit_number < LastDiscrepancy) search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == LastDiscrepancy); // if 0 was picked then record its position in LastZero if (search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if (last_zero < 9) LastFamilyDiscrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if (search_direction == 1) ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= (unsigned char)~rom_byte_mask; // serial number search direction write bit OneWireWrite(pin, 1, search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask = (unsigned char)(rom_byte_mask << 1); // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if (rom_byte_mask == 0) { rom_byte_number++; rom_byte_mask = 1; } } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if (!((id_bit_number < 65))) { // search successful so set LastDiscrepancy,LastDeviceFlag,search_result LastDiscrepancy = last_zero; // check for last device if (LastDiscrepancy == 0) LastDeviceFlag = TRUE; search_result = TRUE; } } // if no device found then reset counters so next 'search' will be like a first if (!search_result || !ROM_NO[0]) { LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; search_result = FALSE; } if (search_result) { int i; char buf[17]; for (i=0;i<8;i++) { buf[i*2] = itoch((ROM_NO[i]>>4) & 15); buf[i*2+1] = itoch(ROM_NO[i] & 15); } buf[16]=0; jsvArrayPushAndUnLock(array, jsvNewFromString(buf)); } NOT_USED(LastFamilyDiscrepancy); } return array; }
/*JSON{ "type":"method", "class": "Array", "name" : "splice", "description" : "Both remove and add items to an array", "generate" : "jswrap_array_splice", "params" : [ [ "index", "int", "Index at which to start changing the array. If negative, will begin that many elements from the end"], [ "howMany", "JsVar", "An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], [ "element1", "JsVar", "A new item to add (optional)" ], [ "element2", "JsVar", "A new item to add (optional)" ], [ "element3", "JsVar", "A new item to add (optional)" ], [ "element4", "JsVar", "A new item to add (optional)" ], [ "element5", "JsVar", "A new item to add (optional)" ], [ "element6", "JsVar", "A new item to add (optional)" ] ], "return" : ["JsVar", "An array containing the removed elements. If only one element is removed, an array of one element is returned."] }*/ JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *element1, JsVar *element2, JsVar *element3, JsVar *element4, JsVar *element5, JsVar *element6) { JsVarInt len = jsvGetArrayLength(parent); if (index<0) index+=len; if (index<0) index=0; if (index>len) index=len; JsVarInt howMany = len; // how many to delete! if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); if (howMany > len-index) howMany = len-index; JsVarInt newItems = 0; if (element1) newItems++; if (element2) newItems++; if (element3) newItems++; if (element4) newItems++; if (element5) newItems++; if (element6) newItems++; JsVarInt shift = newItems-howMany; bool needToAdd = false; JsVar *result = jsvNewWithFlags(JSV_ARRAY); JsArrayIterator it; jsvArrayIteratorNew(&it, parent); while (jsvArrayIteratorHasElement(&it) && !needToAdd) { bool goToNext = true; JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { JsVarInt idx = jsvGetInteger(idxVar); if (idx<index) { // do nothing... } else if (idx<index+howMany) { // must delete if (result) { // append to result array JsVar *el = jsvArrayIteratorGetElement(&it); jsvArrayPushAndUnLock(result, el); } // delete goToNext = false; JsVar *toRemove = jsvArrayIteratorGetIndex(&it); jsvArrayIteratorNext(&it); jsvRemoveChild(parent, toRemove); jsvUnLock(toRemove); } else { // we're greater than the amount we need to remove now needToAdd = true; goToNext = false; } } jsvUnLock(idxVar); if (goToNext) jsvArrayIteratorNext(&it); } // now we add everything JsVar *beforeIndex = jsvArrayIteratorGetIndex(&it); if (element1) jsvArrayInsertBefore(parent, beforeIndex, element1); if (element2) jsvArrayInsertBefore(parent, beforeIndex, element2); if (element3) jsvArrayInsertBefore(parent, beforeIndex, element3); if (element4) jsvArrayInsertBefore(parent, beforeIndex, element4); if (element5) jsvArrayInsertBefore(parent, beforeIndex, element5); if (element6) jsvArrayInsertBefore(parent, beforeIndex, element6); jsvUnLock(beforeIndex); // And finally renumber while (jsvArrayIteratorHasElement(&it)) { JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift); } jsvUnLock(idxVar); jsvArrayIteratorNext(&it); } // free jsvArrayIteratorFree(&it); return result; }
/*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; }