/* * File: dlua.cc * Summary: Dungeon-builder Lua interface. * Created by: dshaligram on Sat Jun 23 20:02:09 2007 UTC */ #include "AppHdr.h" #include #include "dlua.h" #include "l_libs.h" #include "tags.h" static int dlua_compiled_chunk_writer(lua_State *ls, const void *p, size_t sz, void *ud) { std::ostringstream &out = *static_cast(ud); out.write((const char *) p, sz); return (0); } /////////////////////////////////////////////////////////////////////////// // dlua_chunk dlua_chunk::dlua_chunk(const std::string &_context) : file(), chunk(), compiled(), context(_context), first(-1), last(-1), error() { clear(); } // Initialises a chunk from the function on the top of stack. // This function must not be a closure, i.e. must not have any upvalues. dlua_chunk::dlua_chunk(lua_State *ls) : file(), chunk(), compiled(), context(), first(-1), last(-1), error() { clear(); lua_stack_cleaner cln(ls); std::ostringstream out; const int err = lua_dump(ls, dlua_compiled_chunk_writer, &out); if (err) { const char *e = lua_tostring(ls, -1); error = e? e : "Unknown error compiling chunk"; } compiled = out.str(); } dlua_chunk dlua_chunk::precompiled(const std::string &chunk) { dlua_chunk dchunk; dchunk.compiled = chunk; return (dchunk); } void dlua_chunk::write(writer& outf) const { if (empty()) { marshallByte(outf, CT_EMPTY); return; } if (!compiled.empty()) { marshallByte(outf, CT_COMPILED); marshallString4(outf, compiled); } else { marshallByte(outf, CT_SOURCE); marshallString4(outf, chunk); } marshallString4(outf, file); marshallLong(outf, first); } void dlua_chunk::read(reader& inf) { clear(); chunk_t type = static_cast(unmarshallByte(inf)); switch (type) { case CT_EMPTY: return; case CT_SOURCE: unmarshallString4(inf, chunk); break; case CT_COMPILED: unmarshallString4(inf, compiled); break; } unmarshallString4(inf, file); first = unmarshallLong(inf); } void dlua_chunk::clear() { file.clear(); chunk.clear(); first = last = -1; error.clear(); compiled.clear(); } void dlua_chunk::set_file(const std::string &s) { file = s; } void dlua_chunk::add(int line, const std::string &s) { if (first == -1) first = line; if (line != last && last != -1) while (last++ < line) chunk += '\n'; chunk += " "; chunk += s; last = line; } void dlua_chunk::set_chunk(const std::string &s) { chunk = s; } int dlua_chunk::check_op(CLua &interp, int err) { error = interp.error; return (err); } int dlua_chunk::load(CLua &interp) { if (!compiled.empty()) return check_op( interp, interp.loadbuffer(compiled.c_str(), compiled.length(), context.c_str()) ); if (empty()) { chunk.clear(); return (-1000); } int err = check_op( interp, interp.loadstring(chunk.c_str(), context.c_str()) ); if (err) return (err); std::ostringstream out; err = lua_dump(interp, dlua_compiled_chunk_writer, &out); if (err) { const char *e = lua_tostring(interp, -1); error = e? e : "Unknown error compiling chunk"; lua_pop(interp, 2); } compiled = out.str(); chunk.clear(); return (err); } int dlua_chunk::run(CLua &interp) { int err = load(interp); if (err) return (err); // callfn returns true on success, but we want to return 0 on success. return (check_op(interp, !interp.callfn(NULL, 0, 0))); } int dlua_chunk::load_call(CLua &interp, const char *fn) { int err = load(interp); if (err == -1000) return (0); if (err) return (err); return check_op(interp, !interp.callfn(fn, fn? 1 : 0, 0)); } std::string dlua_chunk::orig_error() const { rewrite_chunk_errors(error); return (error); } bool dlua_chunk::empty() const { return compiled.empty() && trimmed_string(chunk).empty(); } bool dlua_chunk::rewrite_chunk_errors(std::string &s) const { const std::string contextm = "[string \"" + context + "\"]:"; std::string::size_type dlwhere = s.find(contextm); if (dlwhere == std::string::npos) return (false); if (!dlwhere) { s = rewrite_chunk_prefix(s); return (true); } // Our chunk is mentioned, go back through and rewrite lines. std::vector lines = split_string("\n", s); std::string newmsg = lines[0]; bool wrote_prefix = false; for (int i = 2, size = lines.size() - 1; i < size; ++i) { const std::string &st = lines[i]; if (st.find(context) != std::string::npos) { if (!wrote_prefix) { newmsg = get_chunk_prefix(st) + ": " + newmsg; wrote_prefix = true; } else newmsg += "\n" + rewrite_chunk_prefix(st); } } s = newmsg; return (true); } std::string dlua_chunk::rewrite_chunk_prefix(const std::string &line, bool skip_body) const { std::string s = line; const std::string contextm = "[string \"" + context + "\"]:"; const std::string::size_type ps = s.find(contextm); if (ps == std::string::npos) return (s); const std::string::size_type lns = ps + contextm.length(); std::string::size_type pe = s.find(':', ps + contextm.length()); if (pe != std::string::npos) { const std::string line_num = s.substr(lns, pe - lns); const int lnum = atoi(line_num.c_str()); const std::string newlnum = make_stringf("%d", lnum + first - 1); s = s.substr(0, lns) + newlnum + s.substr(pe); pe = lns + newlnum.length(); } return s.substr(0, ps) + (file.empty()? context : file) + ":" + (skip_body? s.substr(lns, pe - lns) : s.substr(lns)); } std::string dlua_chunk::get_chunk_prefix(const std::string &sorig) const { return rewrite_chunk_prefix(sorig, true); } void init_dungeon_lua() { lua_stack_cleaner clean(dlua); dluaopen_crawl(dlua); dluaopen_file(dlua); dluaopen_mapgrd(dlua); dluaopen_monsters(dlua); dluaopen_you(dlua); dluaopen_dgn(dlua); luaL_openlib(dlua, "feat", feat_dlib, 0); luaL_openlib(dlua, "spells", spells_dlib, 0); luaL_openlib(dlua, "debug", debug_dlib, 0); luaL_openlib(dlua, "los", los_dlib, 0); dlua.execfile("clua/dungeon.lua", true, true); dlua.execfile("clua/luamark.lua", true, true); lua_getglobal(dlua, "dgn_run_map"); luaopen_debug(dlua); luaL_newmetatable(dlua, MAP_METATABLE); luaopen_dgnevent(dlua); luaopen_mapmarker(dlua); luaopen_ray(dlua); register_itemlist(dlua); register_monslist(dlua); }