/*JSON{ "type" : "method", "class" : "File", "name" : "read", "generate" : "jswrap_file_read", "description" : [ "Read data in a file in byte size chunks"], "params" : [ ["length", "int32", "is an integer specifying the number of bytes to read."] ], "return" : [ "JsVar", "A string containing the characters that were read" ] }*/ JsVar *jswrap_file_read(JsVar* parent, int length) { JsVar *buffer = 0; JsvStringIterator it; FRESULT res = 0; size_t bytesRead = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data.mode == FM_READ || file.data.mode == FM_READ_WRITE) { char buf[32]; size_t actual = 0; while (bytesRead < (size_t)length) { size_t requested = (size_t)length - bytesRead; if (requested > sizeof( buf )) requested = sizeof( buf ); actual = 0; #ifndef LINUX res = f_read(&file.data.handle, buf, requested, &actual); if(res) break; #else actual = fread(buf, 1, requested, file.data.handle); #endif if (actual>0) { if (!buffer) { buffer = jsvNewFromEmptyString(); if (!buffer) return 0; // out of memory jsvStringIteratorNew(&it, buffer, 0); } size_t i; for (i=0;i<actual;i++) jsvStringIteratorAppend(&it, buf[i]); } bytesRead += actual; if(actual != requested) break; } fileSetVar(&file); } } } if (res) jsfsReportError("Unable to read file", res); if (buffer) jsvStringIteratorFree(&it); // automatically close this file if we're at the end of it if (bytesRead!=(size_t)length) jswrap_file_close(parent); return buffer; }
/*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "unlinkSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_fs_unlink", "description" : [ "Delete the given file" ], "params" : [ [ "path", "JsVar", "The path of the file to delete" ] ], "return" : [ "bool", "True on success, or false on failure" ] }*/ bool jswrap_fs_unlink(JsVar *path) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); #ifndef LINUX FRESULT res = 0; if (jsfsInit()) { res = f_unlink(pathStr); } #else FRESULT res = remove(pathStr); #endif if (res) { jsfsReportError("Unable to delete file", res); return false; } return true; }
/*JSON{ "type" : "method", "class" : "File", "name" : "skip", "generate" : "jswrap_file_skip", "description" : [ "Skip the specified number of bytes forwards"], "params" : [ ["nBytes", "int32", "is an integer specifying the number of bytes to skip forwards."] ] }*/ void jswrap_file_skip(JsVar* parent, int length) { if (length<=0) { jsWarn("length for skip must be greater than 0"); return; } FRESULT res = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data.mode == FM_READ || file.data.mode == FM_WRITE || file.data.mode == FM_READ_WRITE) { #ifndef LINUX res = (FRESULT)f_lseek(&file.data.handle, (DWORD)f_tell(&file.data.handle) + (DWORD)length); #else fseek(file.data.handle, length, SEEK_CUR); #endif fileSetVar(&file); } } } if (res) jsfsReportError("Unable to skip", res); }
/*JSON{ "type" : "method", "class" : "File", "name" : "seek", "generate_full" : "jswrap_file_skip_or_seek(parent,nBytes,false)", "params" : [ ["nBytes","int32","is an integer specifying the number of bytes to skip forwards."] ] } Seek to a certain position in the file */ void jswrap_file_skip_or_seek(JsVar* parent, int nBytes, bool is_skip) { if (nBytes<0) { jsWarn(is_skip ? "Bytes to skip must be >=0" : "Position to seek to must be >=0"); return; } FRESULT res = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data.mode == FM_READ || file.data.mode == FM_WRITE || file.data.mode == FM_READ_WRITE) { #ifndef LINUX res = (FRESULT)f_lseek(&file.data.handle, (DWORD)(is_skip ? f_tell(&file.data.handle) : 0) + (DWORD)nBytes); #else fseek(file.data.handle, nBytes, is_skip ? SEEK_CUR : SEEK_SET); #endif fileSetVar(&file); } } } if (res) jsfsReportError(is_skip?"Unable to skip":"Unable to seek", res); }
int jswrap_E_flashFatFS(JsVar* options) { uint32_t addr = FS_FLASH_BASE; uint16_t sectors = FS_SECTOR_COUNT; uint8_t format = 0; if (jsvIsObject(options)) { JsVar *a = jsvObjectGetChild(options, "addr", false); if (a) { if (jsvIsNumeric(a) && jsvGetInteger(a)>0x100000) addr = (uint32_t)jsvGetInteger(a); } JsVar *s = jsvObjectGetChild(options, "sectors", false); if (s) { if (jsvIsNumeric(s) && jsvGetInteger(s)>0) sectors = (uint16_t)jsvGetInteger(s); } JsVar *f = jsvObjectGetChild(options, "format", false); if (f) { if (jsvIsBoolean(f)) format = jsvGetBool(f); } } else if (!jsvIsUndefined(options)) { jsExceptionHere(JSET_TYPEERROR, "'options' must be an object, or undefined"); } uint8_t init=flashFatFsInit(addr, sectors); if (init) { if ( format ) { uint8_t res = f_mount(&jsfsFAT, "", 0); jsDebug("Formatting Flash"); res = f_mkfs("", 1, 0); // Super Floppy format, using all space (not partition table) if (res != FR_OK) { jsExceptionHere(JSET_INTERNALERROR, "Flash Formatting error:",res); return false; } } } jsfsInit(); return true; }
/*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "readFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_readFile", "description" : [ "Read all data from a file and return as a string" ], "params" : [ [ "path", "JsVar", "The path of the file to read" ] ], "return" : [ "JsVar", "A string containing the contents of the file" ] }*/ JsVar *wrap_fat_readFile(JsVar *path) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); JsVar *result = jsvNewFromEmptyString(); if (!result) return 0; // out of memory FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX FIL file; if ((res=f_open(&file, pathStr, FA_READ)) == FR_OK) { #else FILE *file = fopen(pathStr, "r"); if (file) { #endif // re-use pathStr buffer size_t bytesRead = JS_DIR_BUF_SIZE; while (res==FR_OK && bytesRead==JS_DIR_BUF_SIZE) { #ifndef LINUX res = f_read (&file, pathStr, JS_DIR_BUF_SIZE, &bytesRead); #else bytesRead = fread(pathStr,1,JS_DIR_BUF_SIZE,file); #endif jsvAppendStringBuf(result, pathStr, (int)bytesRead); } #ifndef LINUX f_close(&file); #else fclose(file); #endif } } if (res) jsfsReportError("Unable to read file", res); return result; }
/*JSON{ "type":"staticmethod", "class" : "E", "name" : "openFile", "generate" : "jswrap_E_openFile", "description" : [ "Open a file" ], "params" : [ [ "path", "JsVar", "the path to the file to open." ], [ "mode", "JsVar", "The mode to use when opening the file. Valid values for mode are 'r' for read, 'w' for write new, 'w+' for write existing, and 'a' for append. If not specified, the default is 'r'."] ], "return" : ["JsVar", "A File object"] }*/ JsVar *jswrap_E_openFile(JsVar* path, JsVar* mode) { FRESULT res = FR_INVALID_NAME; JsFile file; file.fileVar = 0; FileMode fMode = FM_NONE; if (jsfsInit()) { JsVar *arr = fsGetArray(true); if (!arr) return 0; // out of memory char pathStr[JS_DIR_BUF_SIZE] = ""; char modeStr[3] = "r"; if (!jsvIsUndefined(path)) { jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); if (!jsvIsUndefined(mode)) jsvGetString(mode, modeStr, 3); #ifndef LINUX BYTE ff_mode = 0; bool append = false; #endif if(strcmp(modeStr,"r") == 0) { fMode = FM_READ; #ifndef LINUX ff_mode = FA_READ | FA_OPEN_EXISTING; #endif } else if(strcmp(modeStr,"a") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; append = true; #endif } else if(strcmp(modeStr,"w") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_CREATE_ALWAYS; #endif } else if(strcmp(modeStr,"w+") == 0) { fMode = FM_READ_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; #endif } if(fMode != FM_NONE && allocateJsFile(&file, fMode, FT_FILE)) { #ifndef LINUX if ((res=f_open(&file.data.handle, pathStr, ff_mode)) == FR_OK) { if (append) f_lseek(&file.data.handle, file.data.handle.fsize); // move to end of file #else file.data.handle = fopen(pathStr, modeStr); if (file.data.handle) { res=FR_OK; #endif file.data.state = FS_OPEN; fileSetVar(&file); // add to list of open files jsvArrayPush(arr, file.fileVar); jsvUnLock(arr); } else { // File open failed jsvUnLock(file.fileVar); file.fileVar = 0; } if(res != FR_OK) jsfsReportError("Could not open file", res); } } else { jsError("Path is undefined"); } } return file.fileVar; } /*JSON{ "type" : "method", "class" : "File", "name" : "close", "generate_full" : "jswrap_file_close(parent)", "description" : [ "Close an open file."] }*/ void jswrap_file_close(JsVar* parent) { if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent) && file.data.state == FS_OPEN) { #ifndef LINUX f_close(&file.data.handle); #else fclose(file.data.handle); file.data.handle = 0; #endif file.data.state = FS_CLOSED; fileSetVar(&file); // TODO: could try and free the memory used by file.data ? JsVar *arr = fsGetArray(false); if (arr) { JsVar *idx = jsvGetArrayIndexOf(arr, file.fileVar, true); if (idx) { jsvRemoveChild(arr, idx); jsvUnLock(idx); } jsvUnLock(arr); } } } } /*JSON{ "type" : "method", "class" : "File", "name" : "write", "generate" : "jswrap_file_write", "description" : [ "write data to a file"], "params" : [ ["buffer", "JsVar", "A string containing the bytes to write"] ], "return" : [ "int32", "the number of bytes written" ] }*/ size_t jswrap_file_write(JsVar* parent, JsVar* buffer) { FRESULT res = 0; size_t bytesWritten = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data.mode == FM_WRITE || file.data.mode == FM_READ_WRITE) { JsvIterator it; jsvIteratorNew(&it, buffer); char buf[32]; while (jsvIteratorHasElement(&it)) { // pull in a buffer's worth of data size_t n = 0; while (jsvIteratorHasElement(&it) && n<sizeof(buf)) { buf[n++] = (char)jsvIteratorGetIntegerValue(&it); jsvIteratorNext(&it); } // write it out size_t written = 0; #ifndef LINUX res = f_write(&file.data.handle, &buf, n, &written); #else written = fwrite(&buf, 1, n, file.data.handle); #endif bytesWritten += written; if(written == 0) res = FR_DISK_ERR; if (res) break; } jsvIteratorFree(&it); // finally, sync - just in case there's a reset or something #ifndef LINUX f_sync(&file.data.handle); #else fflush(file.data.handle); #endif } fileSetVar(&file); } } if (res) { jsfsReportError("Unable to write file", res); } return bytesWritten; }
/*JSON{ "type" : "method", "class" : "File", "name" : "read", "generate" : "jswrap_file_read", "params" : [ ["length","int32","is an integer specifying the number of bytes to read."] ], "return" : ["JsVar","A string containing the characters that were read"] } Read data in a file in byte size chunks */ JsVar *jswrap_file_read(JsVar* parent, int length) { if (length<0) length=0; JsVar *buffer = 0; JsvStringIterator it; FRESULT res = 0; size_t bytesRead = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data->mode == FM_READ || file.data->mode == FM_READ_WRITE) { size_t actual = 0; #ifndef LINUX // if we're able to load this into a flat string, do it! size_t len = f_size(&file.data->handle)-f_tell(&file.data->handle); if ( len == 0 ) { // file all read return 0; // if called from a pipe signal end callback } if (len > (size_t)length) len = (size_t)length; buffer = jsvNewFlatStringOfLength(len); if (buffer) { res = f_read(&file.data->handle, jsvGetFlatStringPointer(buffer), len, &actual); if (res) jsfsReportError("Unable to read file", res); return buffer; } #endif char buf[32]; while (bytesRead < (size_t)length) { size_t requested = (size_t)length - bytesRead; if (requested > sizeof( buf )) requested = sizeof( buf ); actual = 0; #ifndef LINUX res = f_read(&file.data->handle, buf, requested, &actual); if(res) break; #else actual = fread(buf, 1, requested, file.data->handle); #endif if (actual>0) { if (!buffer) { buffer = jsvNewFromEmptyString(); if (!buffer) return 0; // out of memory jsvStringIteratorNew(&it, buffer, 0); } size_t i; for (i=0;i<actual;i++) jsvStringIteratorAppend(&it, buf[i]); } bytesRead += actual; if(actual != requested) break; } } } } if (res) jsfsReportError("Unable to read file", res); if (buffer) jsvStringIteratorFree(&it); return buffer; }
/*JSON{ "type" : "staticmethod", "class" : "E", "name" : "openFile", "generate" : "jswrap_E_openFile", "params" : [ ["path","JsVar","the path to the file to open."], ["mode","JsVar","The mode to use when opening the file. Valid values for mode are 'r' for read, 'w' for write new, 'w+' for write existing, and 'a' for append. If not specified, the default is 'r'."] ], "return" : ["JsVar","A File object"], "return_object" : "File" } Open a file */ JsVar *jswrap_E_openFile(JsVar* path, JsVar* mode) { FRESULT res = FR_INVALID_NAME; JsFile file; file.data = 0; file.fileVar = 0; FileMode fMode = FM_NONE; if (jsfsInit()) { JsVar *arr = fsGetArray(true); if (!arr) return 0; // out of memory char pathStr[JS_DIR_BUF_SIZE] = ""; char modeStr[3] = "r"; if (!jsvIsUndefined(path)) { if (!jsfsGetPathString(pathStr, path)) { jsvUnLock(arr); return 0; } if (!jsvIsUndefined(mode)) jsvGetString(mode, modeStr, 3); #ifndef LINUX BYTE ff_mode = 0; bool append = false; #endif if(strcmp(modeStr,"r") == 0) { fMode = FM_READ; #ifndef LINUX ff_mode = FA_READ | FA_OPEN_EXISTING; #endif } else if(strcmp(modeStr,"a") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; append = true; #endif } else if(strcmp(modeStr,"w") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_CREATE_ALWAYS; #endif } else if(strcmp(modeStr,"w+") == 0) { fMode = FM_READ_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; #endif } if(fMode != FM_NONE && allocateJsFile(&file, fMode, FT_FILE)) { #ifndef LINUX if ((res=f_open(&file.data->handle, pathStr, ff_mode)) == FR_OK) { if (append) f_lseek(&file.data->handle, file.data->handle.fsize); // move to end of file #else file.data->handle = fopen(pathStr, modeStr); if (file.data->handle) { res=FR_OK; #endif file.data->state = FS_OPEN; // add to list of open files jsvArrayPush(arr, file.fileVar); } else { // File open failed jsvUnLock(file.fileVar); file.fileVar = 0; } if(res != FR_OK) jsfsReportError("Could not open file", res); } } else { jsExceptionHere(JSET_ERROR,"Path is undefined"); } jsvUnLock(arr); } return file.fileVar; } /*JSON{ "type" : "method", "class" : "File", "name" : "close", "generate_full" : "jswrap_file_close(parent)" } Close an open file. */ void jswrap_file_close(JsVar* parent) { if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent) && file.data->state == FS_OPEN) { #ifndef LINUX f_close(&file.data->handle); #else fclose(file.data->handle); file.data->handle = 0; #endif file.data->state = FS_CLOSED; // TODO: could try and free the memory used by file.data ? JsVar *arr = fsGetArray(false); if (arr) { JsVar *idx = jsvGetIndexOf(arr, file.fileVar, true); if (idx) { jsvRemoveChild(arr, idx); jsvUnLock(idx); } jsvUnLock(arr); } } } } /*JSON{ "type" : "method", "class" : "File", "name" : "write", "generate" : "jswrap_file_write", "params" : [ ["buffer","JsVar","A string containing the bytes to write"] ], "return" : ["int32","the number of bytes written"] } Write data to a file. **Note:** By default this function flushes all changes to the SD card, which makes it slow (but also safe!). You can use `E.setFlags({unsyncFiles:1})` to disable this behaviour and really speed up writes - but then you must be sure to close all files you are writing before power is lost or you will cause damage to your SD card's filesystem. */ size_t jswrap_file_write(JsVar* parent, JsVar* buffer) { FRESULT res = 0; size_t bytesWritten = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data->mode == FM_WRITE || file.data->mode == FM_READ_WRITE) { JsvIterator it; jsvIteratorNew(&it, buffer, JSIF_EVERY_ARRAY_ELEMENT); char buf[32]; while (jsvIteratorHasElement(&it)) { // pull in a buffer's worth of data size_t n = 0; while (jsvIteratorHasElement(&it) && n<sizeof(buf)) { buf[n++] = (char)jsvIteratorGetIntegerValue(&it); jsvIteratorNext(&it); } // write it out size_t written = 0; #ifndef LINUX res = f_write(&file.data->handle, &buf, n, &written); #else written = fwrite(&buf, 1, n, file.data->handle); #endif bytesWritten += written; if(written == 0) res = FR_DISK_ERR; if (res) break; } jsvIteratorFree(&it); // finally, sync - just in case there's a reset or something if (!jsfGetFlag(JSF_UNSYNC_FILES)) { #ifndef LINUX f_sync(&file.data->handle); #else fflush(file.data->handle); #endif } } } } if (res) { jsfsReportError("Unable to write file", res); } return bytesWritten; }
/*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "readFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_readFile", "description" : [ "Read all data from a file and return as a string" ], "params" : [ [ "path", "JsVar", "The path of the file to read" ] ], "return" : [ "JsVar", "A string containing the contents of the file (or undefined if the file doesn't exist)" ] }*/ JsVar *wrap_fat_readFile(JsVar *path) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); JsVar *result = 0; // undefined unless we read the file FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX FIL file; if ((res=f_open(&file, pathStr, FA_READ)) == FR_OK) { #else FILE *file = fopen(pathStr, "r"); if (file) { #endif result = jsvNewFromEmptyString(); if (result) { // out of memory? // re-use pathStr buffer size_t bytesRead = JS_DIR_BUF_SIZE; while (res==FR_OK && bytesRead==JS_DIR_BUF_SIZE) { #ifndef LINUX res = f_read (&file, pathStr, JS_DIR_BUF_SIZE, &bytesRead); #else bytesRead = fread(pathStr,1,JS_DIR_BUF_SIZE,file); #endif if (!jsvAppendStringBuf(result, pathStr, (int)bytesRead)) break; // was out of memory } } #ifndef LINUX f_close(&file); #else fclose(file); #endif } } if (res) jsfsReportError("Unable to read file", res); return result; } /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "unlink", "generate" : "wrap_fat_unlink", "description" : [ "Delete 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 delete" ] ], "return" : [ "bool", "True on success, or false on failure" ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "unlinkSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_unlink", "description" : [ "Delete the given file" ], "params" : [ [ "path", "JsVar", "The path of the file to delete" ] ], "return" : [ "bool", "True on success, or false on failure" ] }*/ bool wrap_fat_unlink(JsVar *path) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); #ifndef LINUX FRESULT res = 0; if (jsfsInit()) { f_unlink(pathStr); } #else FRESULT res = remove(pathStr); #endif if (res) { jsfsReportError("Unable to delete file", res); return false; } return true; }
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); }