1 #include "lua/internal.hpp"
2 #include "library/minmax.hpp"
3 #include "library/zip.hpp"
4 #include "core/memorymanip.hpp"
9 std::string
dashstring(char ch
, int dashes
)
12 return std::string(1, ch
) + std::string(dashes
, '=') + std::string(1, ch
);
14 return std::string(1, ch
) + std::string(1, ch
);
31 replace(const std::string
& _target
)
36 std::pair
<const char*, size_t> run(std::function
<std::pair
<const char*, size_t>()> fn
);
43 const char* upper_buf
;
50 std::string pattern
= "@@LUA_SCRIPT_FILENAME@@";
52 std::pair
<const char*, size_t> replace::run(std::function
<std::pair
<const char*, size_t>()> fn
)
55 while(emitted
< sizeof(buffer
)) {
56 while(upper_ptr
== upper_size
&& !upper_eof
) {
59 upper_size
= g
.second
;
61 if(!upper_buf
&& !upper_size
)
64 static char binary_lua_id
[] = {0x1B, 0x4C, 0x75, 0x61};
65 if(upper_size
>= 4 && !memcmp(upper_buf
, binary_lua_id
, 4))
66 throw std::runtime_error("Binary Lua chunks are not allowed");
70 if(upper_ptr
== upper_size
&& source
== 0) {
78 if(upper_buf
[upper_ptr
] == pattern
[matched
]) {
81 if(matched
== pattern
.length()) {
90 buffer
[emitted
++] = upper_buf
[upper_ptr
++];
94 if(matched
== 2 && upper_ptr
< upper_size
&& upper_buf
[upper_ptr
] == '@') {
95 //This is exceptional, just flush the first '@'.
96 buffer
[emitted
++] = '@';
100 } else if(copied
== matched
) {
105 buffer
[emitted
++] = pattern
[copied
++];
109 if(copied
== target
.size()) {
114 buffer
[emitted
++] = target
[copied
++];
120 return std::make_pair(reinterpret_cast<const char*>(NULL
), 0);
121 return std::make_pair(buffer
, emitted
);
126 reader(std::istream
& _s
, const std::string
& fn
)
131 std::string tmpl
= dashstring(']', dashes
);
132 if(fn
.find(tmpl
) == std::string::npos
)
135 rpl
= replace(dashstring('[', dashes
) + fn
+ dashstring(']', dashes
));
137 const char* rfn(lua_State
* L
, size_t* size
);
138 static const char* rfn(lua_State
* L
, void* data
, size_t* size
)
140 return reinterpret_cast<reader
*>(data
)->rfn(L
, size
);
142 const std::string
& get_err() { return err
; }
149 class lua_file_reader
152 lua_file_reader(lua_state
& L
, std::istream
* strm
);
157 int read(lua_state
& L
, const std::string
& fname
)
159 if(L
.type(2) == LUA_TNUMBER
) {
160 //Read specified number of bytes.
161 size_t sz
= L
.get_numeric_argument
<size_t>(2, fname
.c_str());
162 std::vector
<char> buf
;
165 if(!s
&& !s
.gcount()) {
169 L
.pushlstring(&buf
[0], s
.gcount());
171 } else if(L
.type(2) == LUA_TNIL
|| L
.type(2) == LUA_TNONE
) {
174 std::getline(s
, tmp
);
183 (stringfmt() << "Expected number or nil as the 2nd argument of " << fname
).throwex();
185 int lines(lua_state
& L
, const std::string
& fname
)
187 L
.pushlightuserdata(this);
188 L
.pushcclosure(lua_file_reader::lines_helper2
, 1);
189 //Trick: The first parameter is the userdata for this object, so by making it state, we
190 //can pin this object.
195 int lines_helper(lua_State
* L
)
198 std::getline(s
, tmp
);
204 lua_pushlstring(L
, tmp
.c_str(), tmp
.length());
207 static int lines_helper2(lua_State
* L
)
209 reinterpret_cast<lua_file_reader
*>(lua_touserdata(L
, lua_upvalueindex(1)))->lines_helper(L
);
219 const char* reader::rfn(lua_State
* L
, size_t* size
)
222 auto g
= rpl
.run([this]() -> std::pair
<const char*, size_t> {
224 static char buffer
[4096];
226 return std::make_pair(reinterpret_cast<const char*>(NULL
), 0);
227 this->s
.read(buffer
, sizeof(buffer
));
228 size
= this->s
.gcount();
230 return std::make_pair(reinterpret_cast<const char*>(NULL
), 0);
232 return std::make_pair(buffer
, size
);
236 } catch(std::exception
& e
) {
243 void load_chunk(lua_state
& L
, const std::string
& fname
)
246 std::string file1
= L
.get_string(1, fname
.c_str());
247 if(L
.type(2) != LUA_TNIL
&& L
.type(2) != LUA_TNONE
)
248 file2
= L
.get_string(2, fname
.c_str());
249 std::string absfilename
= resolve_file_relative(file1
, file2
);
250 std::istream
& file
= open_file_relative(file1
, file2
);
251 std::string chunkname
;
253 chunkname
= file2
+ "[" + file1
+ "]";
256 reader
rc(file
, absfilename
);
257 int r
= lua_load(L
.handle(), reader::rfn
, &rc
, chunkname
.c_str()
258 #if LUA_VERSION_NUM == 502
263 if(rc
.get_err() != "")
264 throw std::runtime_error(rc
.get_err());
267 } else if(r
== LUA_ERRSYNTAX
) {
268 (stringfmt() << "Syntax error: " << L
.tostring(-1)).throwex();
269 } else if(r
== LUA_ERRMEM
) {
270 (stringfmt() << "Out of memory: " << L
.tostring(-1)).throwex();
272 (stringfmt() << "Unknown error: " << L
.tostring(-1)).throwex();
276 function_ptr_luafun
loadfile2(lua_func_load
, "loadfile2", [](lua_state
& L
, const std::string
& fname
)
278 load_chunk(L
, fname
);
282 function_ptr_luafun
dofile2(lua_func_load
, "dofile2", [](lua_state
& L
, const std::string
& fname
)
284 load_chunk(L
, fname
);
285 int old_sp
= lua_gettop(L
.handle());
286 lua_call(L
.handle(), 0, LUA_MULTRET
);
287 int new_sp
= lua_gettop(L
.handle());
288 return new_sp
- (old_sp
- 1);
291 function_ptr_luafun
resolvefile(lua_func_load
, "resolve_filename", [](lua_state
& L
, const std::string
& fname
)
294 std::string file1
= L
.get_string(1, fname
.c_str());
295 if(L
.type(2) != LUA_TNIL
&& L
.type(2) != LUA_TNONE
)
296 file2
= L
.get_string(2, fname
.c_str());
297 std::string absfilename
= resolve_file_relative(file1
, file2
);
298 L
.pushlstring(absfilename
);
302 function_ptr_luafun
openfile(lua_func_load
, "open_file", [](lua_state
& L
, const std::string
& fname
) -> int {
304 std::string file1
= L
.get_string(1, fname
.c_str());
305 if(L
.type(2) != LUA_TNIL
&& L
.type(2) != LUA_TNONE
)
306 file2
= L
.get_string(2, fname
.c_str());
307 std::istream
& s
= open_file_relative(file1
, file2
);
309 lua_class
<lua_file_reader
>::create(L
, &s
);
318 DECLARE_LUACLASS(lua_file_reader
, "FILEREADER");
323 lua_file_reader::lua_file_reader(lua_state
& L
, std::istream
* strm
)
326 objclass
<lua_file_reader
>().bind_multi(L
, {
327 {"__call", &lua_file_reader::read
},
328 {"lines", &lua_file_reader::lines
}