Lua: open_file
This variant has support for relative file locating and reading inside .zip files.
This commit is contained in:
parent
e3bcf53676
commit
9f9bddccb6
3 changed files with 147 additions and 1 deletions
48
lua.lyx
48
lua.lyx
|
@ -388,6 +388,54 @@ Execute lua script from <filename>, resolved relative to <base> (if empty,
|
|||
current directory) and return all return values.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
open_file: Open a stream
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: FILEREADER open_file(string filename[, string base])
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Open file <filename>, resolved relative to <base> (if empty, current directory)
|
||||
and return a handle.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
FILEREADER(): Read line/bytes from stream
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: string/nil FILEREADER()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: string/nil FILEREADER(number bytes)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Reads next line or <bytes> bytes from specified file handle.
|
||||
On EOF, nil is returned.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Note: The line-oriented variant reads in text mode, so CR at end of line
|
||||
is stripped.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
FILEREADER:lines: Iterator to read all lines
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: for line in <foo>:lines() do ...
|
||||
end
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Iterator for reading all lines of <foo> in a loop.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
resolve_filename: Resolve name of file relative to another
|
||||
\end_layout
|
||||
|
|
BIN
lua.pdf
BIN
lua.pdf
Binary file not shown.
|
@ -135,7 +135,74 @@ namespace
|
|||
std::istream& s;
|
||||
replace rpl;
|
||||
};
|
||||
|
||||
|
||||
class lua_file_reader
|
||||
{
|
||||
public:
|
||||
lua_file_reader(lua_state* L, std::istream* strm);
|
||||
~lua_file_reader()
|
||||
{
|
||||
delete &s;
|
||||
}
|
||||
int read(lua_state& L)
|
||||
{
|
||||
if(L.type(2) == LUA_TNUMBER) {
|
||||
//Read specified number of bytes.
|
||||
size_t sz = L.get_numeric_argument<size_t>(2, "FILEREADER::read");
|
||||
std::vector<char> buf;
|
||||
buf.resize(sz);
|
||||
s.read(&buf[0], sz);
|
||||
if(!s && !s.gcount()) {
|
||||
L.pushnil();
|
||||
return 1;
|
||||
}
|
||||
L.pushlstring(&buf[0], s.gcount());
|
||||
return 1;
|
||||
} else if(L.type(2) == LUA_TNIL || L.type(2) == LUA_TNONE) {
|
||||
//Read next line.
|
||||
std::string tmp;
|
||||
std::getline(s, tmp);
|
||||
if(!s) {
|
||||
L.pushnil();
|
||||
return 1;
|
||||
}
|
||||
istrip_CR(tmp);
|
||||
L.pushlstring(tmp);
|
||||
return 1;
|
||||
} else
|
||||
throw std::runtime_error("Expected number or nil as the 2nd argument of "
|
||||
"FILEREADER::read");
|
||||
}
|
||||
int lines(lua_state& L)
|
||||
{
|
||||
L.pushlightuserdata(this);
|
||||
L.pushcclosure(lua_file_reader::lines_helper2, 1);
|
||||
//Trick: The first parameter is the userdata for this object, so by making it state, we
|
||||
//can pin this object.
|
||||
L.pushvalue(1);
|
||||
L.pushboolean(true);
|
||||
return 3;
|
||||
}
|
||||
int lines_helper(lua_State* L)
|
||||
{
|
||||
std::string tmp;
|
||||
std::getline(s, tmp);
|
||||
if(!s) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
istrip_CR(tmp);
|
||||
lua_pushlstring(L, tmp.c_str(), tmp.length());
|
||||
return 1;
|
||||
}
|
||||
static int lines_helper2(lua_State* L)
|
||||
{
|
||||
reinterpret_cast<lua_file_reader*>(lua_touserdata(L, lua_upvalueindex(1)))->lines_helper(L);
|
||||
}
|
||||
private:
|
||||
std::istream& s;
|
||||
};
|
||||
|
||||
const char* reader::rfn(lua_State* L, size_t* size)
|
||||
{
|
||||
auto g = rpl.run([this]() -> std::pair<const char*, size_t> {
|
||||
|
@ -210,4 +277,35 @@ namespace
|
|||
L.pushlstring(absfilename);
|
||||
return 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun openfile(lua_func_load, "open_file", [](lua_state& L, const std::string& fname) -> int {
|
||||
std::string file2;
|
||||
std::string file1 = L.get_string(1, fname.c_str());
|
||||
if(L.type(2) != LUA_TNIL && L.type(2) != LUA_TNONE)
|
||||
file2 = L.get_string(2, fname.c_str());
|
||||
std::istream& s = open_file_relative(file1, file2);
|
||||
try {
|
||||
lua_class<lua_file_reader>::create(L, &L, &s);
|
||||
return 1;
|
||||
} catch(...) {
|
||||
delete &s;
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DECLARE_LUACLASS(lua_file_reader, "FILEREADER");
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
lua_file_reader::lua_file_reader(lua_state* L, std::istream* strm)
|
||||
: s(*strm)
|
||||
{
|
||||
static char doonce_key;
|
||||
if(L->do_once(&doonce_key)) {
|
||||
objclass<lua_file_reader>().bind(*L, "__call", &lua_file_reader::read);
|
||||
objclass<lua_file_reader>().bind(*L, "lines", &lua_file_reader::lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue