/*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" : "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.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; fileSetVar(&file); // 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 { jsError("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; 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", "params" : [ ["buffer","JsVar","A string containing the bytes to write"] ], "return" : ["int32","the number of bytes written"] } write data to a file */ 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; }