#!/usr/bin/env lua ----- lua 5.1 script to convert a lua file into a C file ----- ----- Usage: lua2c foo.lua > lfoo.c # compiled, so not portable ----- lua2c -s foo.lua > lfoo.c # source, and so portable ---------------- general utility functions ------------- function io.contents(filename) local f, msg = io.open(filename, 'r') if not f then return f, msg end local s = assert(f:read '*a') f:close() return s end function os.capture(cmd, raw) local f = assert(io.popen(cmd, 'r')) local s = assert(f:read('*a')) f:close() if raw then return s end s = string.gsub(s, '^%s+', '') s = string.gsub(s, '%s+$', '') s = string.gsub(s, '[\n\r]+', ' ') return s end local quote_me = '[^%w%+%-%=%@%_%/]' -- easier to complement what doesn't need quotes local strfind = string.find function os.quote(s) if strfind(s, quote_me) or s == '' then return "'" .. string.gsub(s, "'", [['"'"']]) .. "'" else return s end end function os.runf(...) return os.execute(string.format(...)) end ------------------------------------------------------- local lua -- program to be loaded (source or binary) local libname if arg[1]:find '^-lib' and arg[2] then libname = arg[2] table.remove(arg, 1) table.remove(arg, 1) end if arg[1] == '-a' or arg[1] == '-s' then -- don't compile; -- use ascii source table.remove(arg, 1) assert(#arg == 1) lua = io.contents(arg[1]):gsub('^#!.-\n', '') else assert(#arg == 1) local bin = os.capture 'PATH=/bin:$PATH tempfile' assert(os.runf('luac -o %s %s', os.quote(bin), os.quote(arg[1])) == 0) lua = io.contents(bin) os.remove(bin) end libname = libname or arg[1]:gsub('.*/', ''):gsub('%.lua$', '') outfile = io.stdout ------------------------ outfile:write [[ #include #include static unsigned char program[] = { ]] outfile:write ' ' local function printf(...) return outfile:write(string.format(...)) end local last = lua:len() for i = 1, last do local n = string.byte(lua, i) printf('%3d%s', n, i < last and ', ' or '') if i % 10 == 0 then printf '\n ' end end printf '\n};\n\n' outfile:write((([[ int luaload_$lib(lua_State *L) { return luaL_loadbuffer(L, (const char*)program, sizeof(program), "@$source"); } int luaopen_$lib(lua_State *L) { if (luaL_loadbuffer(L, (const char*)program, sizeof(program), "@$source")) return luaL_error(L, "Internal library '%s' failed to parse", "$lib"); if (lua_pcall(L, 0, 1, 0)) return luaL_error(L, "Internal library '%s' failed to run: %s", "$lib", lua_tostring(L, -1)); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushboolean(L, 1); } lua_getglobal(L, "package"); // s: lib package lua_getfield(L, -1, "loaded"); // s: lib package loaded lua_remove(L, -2); // s: lib loaded lua_pushstring(L, "$lib"); // s: lib loaded libname lua_pushvalue(L, -3); // s: lib loaded libname lib lua_settable(L, -3); // s: lib loaded lua_pop(L, 1); // s: lib return 1; } ]]):gsub('$(%a+)', { lib = libname, source = arg[1]:gsub('.*/', '') })))