From c3e24436f2968b8610275fce9b28e3b32588562b Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Thu, 11 Apr 2019 22:17:00 +0100 Subject: [PATCH] Lua string optimisation in file.c + get/put contents methods (#2717) * Lua string optimisation in file.c + get/put contents methods * Doc fix: move putcontents() into correct alphabetic order slot in list of static methods --- app/modules/file.c | 119 ++++++++++++++++++++++++++----------------- docs/modules/file.md | 45 ++++++++++++++++ 2 files changed, 118 insertions(+), 46 deletions(-) diff --git a/app/modules/file.c b/app/modules/file.c index 1d9dc9f8..d1de588c 100644 --- a/app/modules/file.c +++ b/app/modules/file.c @@ -421,67 +421,42 @@ static int file_stat( lua_State* L ) // g_read() static int file_g_read( lua_State* L, int n, int16_t end_char, int fd ) { - static char *heap_mem = NULL; - // free leftover memory - if (heap_mem) { - luaM_free(L, heap_mem); - heap_mem = NULL; - } - - if(n <= 0) - n = FILE_READ_CHUNK; - - if(end_char < 0 || end_char >255) - end_char = EOF; - + int i, j; + luaL_Buffer b; + char p[LUAL_BUFFERSIZE/2]; if(!fd) return luaL_error(L, "open a file first"); - char *p; - int i; + luaL_buffinit(L, &b); - if (n > LUAL_BUFFERSIZE) { - // get buffer from heap - p = heap_mem = luaM_malloc(L, n); - } else { - // small chunks go onto the stack - p = alloca(n); - } + for (j = 0; j < n; j += sizeof(p)) { + int nwanted = (j <= n - sizeof(p)) ? sizeof(p) : n - j; + int nread = vfs_read(fd, p, nwanted); - n = vfs_read(fd, p, n); - // bypass search if no end character provided - if (n > 0 && end_char != EOF) { - for (i = 0; i < n; ++i) - if (p[i] == end_char) - { - ++i; + if (nread == VFS_RES_ERR || nread == 0) { + lua_pushnil(L); + return 1; + } + + for (i = 0; i < nread; ++i) { + luaL_addchar(&b, p[i]); + if (p[i] == end_char) { + vfs_lseek(fd, -nread + j + i + 1, VFS_SEEK_CUR); //reposition after end char found + nread = 0; // force break on outer loop break; } - } else { - i = n; - } - - if (i == 0 || n == VFS_RES_ERR) { - if (heap_mem) { - luaM_free(L, heap_mem); - heap_mem = NULL; } - lua_pushnil(L); - return 1; - } - vfs_lseek(fd, -(n - i), VFS_SEEK_CUR); - lua_pushlstring(L, p, i); - if (heap_mem) { - luaM_free(L, heap_mem); - heap_mem = NULL; + if (nread < nwanted) + break; } + luaL_pushresult(&b); return 1; } // Lua: read() -// file.read() will read all byte in file +// file.read() will read FILE_READ_CHUNK bytes, or EOF is reached. // file.read(10) will read 10 byte from file, or EOF is reached. // file.read('q') will read until 'q' or EOF is reached. static int file_read( lua_State* L ) @@ -516,6 +491,28 @@ static int file_readline( lua_State* L ) return file_g_read(L, FILE_READ_CHUNK, '\n', fd); } +// Lua: getfile(filename) +static int file_getfile( lua_State* L ) +{ + // Warning this code C calls other file_* routines to avoid duplication code. These + // use Lua stack addressing of arguments, so this does Lua stack maniplation to + // align these + int ret_cnt = 0; + lua_settop(L ,1); + // Stack [1] = FD + file_open(L); + // Stack [1] = filename; [2] = FD or nil + if (!lua_isnil(L, -1)) { + lua_remove(L, 1); // dump filename, so [1] = FD + file_fd_ud *ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj"); + ret_cnt = file_g_read(L, LUAI_MAXINT32, EOF, ud->fd); + // Stack [1] = FD; [2] = contents if ret_cnt = 1; + file_close(L); // leaves Stack unchanged if [1] = FD + lua_remove(L, 1); // Dump FD leaving contents as [1] / ToS + } + return ret_cnt; +} + // Lua: write("string") static int file_write( lua_State* L ) { @@ -556,6 +553,34 @@ static int file_writeline( lua_State* L ) return 1; } +// Lua: getfile(filename) +static int file_putfile( lua_State* L ) +{ + // Warning this code C calls other file_* routines to avoid duplication code. These + // use Lua stack addressing of arguments, so this does Lua stack maniplation to + // align these + int ret_cnt = 0; + lua_settop(L, 2); + lua_pushvalue(L, 2); //dup contents onto the ToS [3] + lua_pushliteral(L, "w+"); + lua_replace(L, 2); + // Stack [1] = filename; [2] "w+" [3] contents; + file_open(L); + // Stack [1] = filename; [2] "w+" [3] contents; [4] FD or nil + + if (!lua_isnil(L, -1)) { + lua_remove(L, 2); //dump "w+" attribute literal + lua_replace(L, 1); + // Stack [1] = FD; [2] contents + file_write(L); + // Stack [1] = FD; [2] contents; [3] result status + lua_remove(L, 2); //dump contents + file_close(L); + lua_remove(L, 1); // Dump FD leaving status as ToS + } + return 1; +} + // Lua: fsinfo() static int file_fsinfo( lua_State* L ) { @@ -661,6 +686,8 @@ static const LUA_REG_TYPE file_map[] = { { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) }, { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) }, { LSTRKEY( "exists" ), LFUNCVAL( file_exists ) }, + { LSTRKEY( "getcontents" ), LFUNCVAL( file_getfile ) }, + { LSTRKEY( "putcontents" ), LFUNCVAL( file_putfile ) }, { LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) }, { LSTRKEY( "on" ), LFUNCVAL( file_on ) }, { LSTRKEY( "stat" ), LFUNCVAL( file_stat ) }, diff --git a/docs/modules/file.md b/docs/modules/file.md index 43f11b51..75ecc2ef 100644 --- a/docs/modules/file.md +++ b/docs/modules/file.md @@ -139,6 +139,27 @@ remaining, used, total=file.fsinfo() print("\nFile system info:\nTotal : "..total.." (k)Bytes\nUsed : "..used.." (k)Bytes\nRemain: "..remaining.." (k)Bytes\n") ``` +## file.getcontents() + +Open and read the contents of a file. + +#### Syntax +`file.getcontents(filename)` + +#### Parameters +- `filename` file to be opened and read + +#### Returns +file contents if the file exists. `nil` if the file does not exist. + +#### Example (basic model) +```lua +print(file.getcontents('welcome.txt')) +``` +#### See also +- [`file.putcontents()`](#fileputcontents) + + ## file.list() Lists all files in the file system. @@ -287,6 +308,30 @@ file.remove("foo.lua") #### See also [`file.open()`](#fileopen) +## file.putcontents() + +Open and write the contents of a file. + +#### Syntax +`file.putcontents(filename, contents)` + +#### Parameters +- `filename` file to be created +- `contents` to be written to the file + +#### Returns +`true` if the write is ok, `nil` on error + +#### Example (basic model) +```lua +file.putcontents('welcome.txt', [[ + Hello to new user + ----------------- +]]) +``` +#### See also +- [`file.getcontents()`](#filegetcontents) + ## file.rename() Renames a file. If a file is currently open, it will be closed first.