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
This commit is contained in:
Terry Ellison 2019-04-11 22:17:00 +01:00 committed by GitHub
parent 5a6992c26a
commit c3e24436f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 118 additions and 46 deletions

View File

@ -421,67 +421,42 @@ static int file_stat( lua_State* L )
// g_read() // g_read()
static int file_g_read( lua_State* L, int n, int16_t end_char, int fd ) static int file_g_read( lua_State* L, int n, int16_t end_char, int fd )
{ {
static char *heap_mem = NULL; int i, j;
// free leftover memory luaL_Buffer b;
if (heap_mem) { char p[LUAL_BUFFERSIZE/2];
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;
if(!fd) if(!fd)
return luaL_error(L, "open a file first"); return luaL_error(L, "open a file first");
char *p; luaL_buffinit(L, &b);
int i;
if (n > LUAL_BUFFERSIZE) { for (j = 0; j < n; j += sizeof(p)) {
// get buffer from heap int nwanted = (j <= n - sizeof(p)) ? sizeof(p) : n - j;
p = heap_mem = luaM_malloc(L, n); int nread = vfs_read(fd, p, nwanted);
} else {
// small chunks go onto the stack
p = alloca(n);
}
n = vfs_read(fd, p, n); if (nread == VFS_RES_ERR || nread == 0) {
// 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;
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); lua_pushnil(L);
return 1; return 1;
} }
vfs_lseek(fd, -(n - i), VFS_SEEK_CUR); for (i = 0; i < nread; ++i) {
lua_pushlstring(L, p, i); luaL_addchar(&b, p[i]);
if (heap_mem) { if (p[i] == end_char) {
luaM_free(L, heap_mem); vfs_lseek(fd, -nread + j + i + 1, VFS_SEEK_CUR); //reposition after end char found
heap_mem = NULL; nread = 0; // force break on outer loop
break;
} }
}
if (nread < nwanted)
break;
}
luaL_pushresult(&b);
return 1; return 1;
} }
// Lua: read() // 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(10) will read 10 byte from file, or EOF is reached.
// file.read('q') will read until 'q' or EOF is reached. // file.read('q') will read until 'q' or EOF is reached.
static int file_read( lua_State* L ) 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); 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") // Lua: write("string")
static int file_write( lua_State* L ) static int file_write( lua_State* L )
{ {
@ -556,6 +553,34 @@ static int file_writeline( lua_State* L )
return 1; 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() // Lua: fsinfo()
static int file_fsinfo( lua_State* L ) static int file_fsinfo( lua_State* L )
{ {
@ -661,6 +686,8 @@ static const LUA_REG_TYPE file_map[] = {
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) }, { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) }, { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
{ LSTRKEY( "exists" ), LFUNCVAL( file_exists ) }, { LSTRKEY( "exists" ), LFUNCVAL( file_exists ) },
{ LSTRKEY( "getcontents" ), LFUNCVAL( file_getfile ) },
{ LSTRKEY( "putcontents" ), LFUNCVAL( file_putfile ) },
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) }, { LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
{ LSTRKEY( "on" ), LFUNCVAL( file_on ) }, { LSTRKEY( "on" ), LFUNCVAL( file_on ) },
{ LSTRKEY( "stat" ), LFUNCVAL( file_stat ) }, { LSTRKEY( "stat" ), LFUNCVAL( file_stat ) },

View File

@ -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") 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() ## file.list()
Lists all files in the file system. Lists all files in the file system.
@ -287,6 +308,30 @@ file.remove("foo.lua")
#### See also #### See also
[`file.open()`](#fileopen) [`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() ## file.rename()
Renames a file. If a file is currently open, it will be closed first. Renames a file. If a file is currently open, it will be closed first.