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 CONST_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 const 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
] == CONST_pattern
[matched
]) {
81 if(matched
== CONST_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
++] = CONST_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
; }
150 class lua_file_reader
153 lua_file_reader(lua::state
& L
, std::istream
* strm
);
154 static size_t overcommit(std::istream
* strm
) { return 0; }
159 static int create(lua::state
& L
, lua::parameters
& P
)
161 auto file1
= P
.arg
<std::string
>();
162 auto file2
= P
.arg_opt
<std::string
>("");
163 std::istream
& s
= zip::openrel(file1
, file2
);
165 lua::_class
<lua_file_reader
>::create(L
, &s
);
172 int read(lua::state
& L
, lua::parameters
& P
)
177 //Read specified number of bytes.
180 std::vector
<char> buf
;
183 if(!s
&& !s
.gcount()) {
187 L
.pushlstring(&buf
[0], s
.gcount());
189 } else if(P
.is_novalue()) {
192 std::getline(s
, tmp
);
201 P
.expected("number or nil");
202 return 0; //NOTREACHED
204 int lines(lua::state
& L
, lua::parameters
& P
)
206 L
.pushlightuserdata(this);
207 L
.pushcclosure(lua_file_reader::lines_helper2
, 1);
208 //Trick: The first parameter is the userdata for this object, so by making it state, we
209 //can pin this object.
214 int lines_helper(lua_State
* L
)
217 std::getline(s
, tmp
);
223 lua_pushlstring(L
, tmp
.c_str(), tmp
.length());
226 static int lines_helper2(lua_State
* L
)
228 return reinterpret_cast<lua_file_reader
*>(lua_touserdata(L
, lua_upvalueindex(1)))->
235 const char* reader::rfn(lua_State
* L
, size_t* size
)
238 auto g
= rpl
.run([this]() -> std::pair
<const char*, size_t> {
241 return std::make_pair(reinterpret_cast<const char*>(NULL
), 0);
242 this->s
.read(this->buffer
, sizeof(this->buffer
));
243 size
= this->s
.gcount();
245 return std::make_pair(reinterpret_cast<const char*>(NULL
), 0);
247 return std::make_pair(this->buffer
, size
);
251 } catch(std::exception
& e
) {
258 void load_chunk(lua::state
& L
, lua::parameters
& P
)
260 auto file1
= P
.arg
<std::string
>();
261 auto file2
= P
.arg_opt
<std::string
>("");
262 std::string absfilename
= zip::resolverel(file1
, file2
);
263 std::istream
& file
= zip::openrel(file1
, file2
);
264 std::string chunkname
;
266 chunkname
= file2
+ "[" + file1
+ "]";
269 reader
rc(file
, absfilename
);
270 int r
= lua_load(L
.handle(), reader::rfn
, &rc
, chunkname
.c_str() LUA_LOADMODE_ARG("t") );
272 if(rc
.get_err() != "")
273 throw std::runtime_error(rc
.get_err());
276 } else if(r
== LUA_ERRSYNTAX
) {
277 (stringfmt() << "Syntax error: " << L
.tostring(-1)).throwex();
278 } else if(r
== LUA_ERRMEM
) {
279 (stringfmt() << "Out of memory: " << L
.tostring(-1)).throwex();
281 (stringfmt() << "Unknown error: " << L
.tostring(-1)).throwex();
285 lua_file_reader::lua_file_reader(lua::state
& L
, std::istream
* strm
)
290 int loadfile2(lua::state
& L
, lua::parameters
& P
)
296 int dofile2(lua::state
& L
, lua::parameters
& P
)
299 int old_sp
= lua_gettop(L
.handle());
300 lua_call(L
.handle(), 0, LUA_MULTRET
);
301 int new_sp
= lua_gettop(L
.handle());
302 return new_sp
- (old_sp
- 1);
305 int resolve_filename(lua::state
& L
, lua::parameters
& P
)
307 auto file1
= P
.arg
<std::string
>();
308 auto file2
= P
.arg_opt
<std::string
>("");
309 std::string absfilename
= zip::resolverel(file1
, file2
);
310 L
.pushlstring(absfilename
);
314 lua::functions
LUA_load_fns(lua_func_load
, "", {
315 {"loadfile2", loadfile2
},
316 {"dofile2", dofile2
},
317 {"resolve_filename", resolve_filename
},
320 lua::_class
<lua_file_reader
> LUA_class_filreader(lua_class_fileio
, "FILEREADER", {
321 {"open", lua_file_reader::create
},
323 {"__call", &lua_file_reader::read
},
324 {"lines", &lua_file_reader::lines
}