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:
parent
5a6992c26a
commit
c3e24436f2
|
@ -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 ) },
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue