Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Penlight/lua/pl/compat.lua
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
252 lines (233 sloc)
8.68 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ---------------- | |
| --- Lua 5.1/5.2/5.3 compatibility. | |
| -- Injects `table.pack`, `table.unpack`, and `package.searchpath` in the global | |
| -- environment, to make sure they are available for Lua 5.1 and LuaJIT. | |
| -- | |
| -- All other functions are exported as usual in the returned module table. | |
| -- | |
| -- NOTE: everything in this module is also available in `pl.utils`. | |
| -- @module pl.compat | |
| local compat = {} | |
| --- boolean flag this is Lua 5.1 (or LuaJIT). | |
| -- @field lua51 | |
| compat.lua51 = _VERSION == 'Lua 5.1' | |
| --- boolean flag this is LuaJIT. | |
| -- @field jit | |
| compat.jit = (tostring(assert):match('builtin') ~= nil) | |
| --- boolean flag this is LuaJIT with 5.2 compatibility compiled in. | |
| -- @field jit52 | |
| if compat.jit then | |
| -- 'goto' is a keyword when 52 compatibility is enabled in LuaJit | |
| compat.jit52 = not loadstring("local goto = 1") | |
| end | |
| --- the directory separator character for the current platform. | |
| -- @field dir_separator | |
| compat.dir_separator = _G.package.config:sub(1,1) | |
| --- boolean flag this is a Windows platform. | |
| -- @field is_windows | |
| compat.is_windows = compat.dir_separator == '\\' | |
| --- execute a shell command, in a compatible and platform independent way. | |
| -- This is a compatibility function that returns the same for Lua 5.1 and | |
| -- Lua 5.2+. | |
| -- | |
| -- NOTE: Windows systems can use signed 32bit integer exitcodes. Posix systems | |
| -- only use exitcodes 0-255, anything else is undefined. | |
| -- | |
| -- NOTE2: In Lua 5.2 and 5.3 a Windows exitcode of -1 would not properly be | |
| -- returned, this function will return it properly for all versions. | |
| -- @param cmd a shell command | |
| -- @return true if successful | |
| -- @return actual return code | |
| function compat.execute(cmd) | |
| local res1,res2,res3 = os.execute(cmd) | |
| if res2 == "No error" and res3 == 0 and compat.is_windows then | |
| -- os.execute bug in Lua 5.2/5.3 not reporting -1 properly on Windows | |
| -- this was fixed in 5.4 | |
| res3 = -1 | |
| end | |
| if compat.lua51 and not compat.jit52 then | |
| if compat.is_windows then | |
| return res1==0,res1 | |
| else | |
| res1 = res1 > 255 and res1 / 256 or res1 | |
| return res1==0,res1 | |
| end | |
| else | |
| if compat.is_windows then | |
| return res3==0,res3 | |
| else | |
| return not not res1,res3 | |
| end | |
| end | |
| end | |
| ---------------- | |
| -- Load Lua code as a text or binary chunk (in a Lua 5.2 compatible way). | |
| -- @param ld code string or loader | |
| -- @param[opt] source name of chunk for errors | |
| -- @param[opt] mode 'b', 't' or 'bt' | |
| -- @param[opt] env environment to load the chunk in | |
| -- @function compat.load | |
| --------------- | |
| -- Get environment of a function (in a Lua 5.1 compatible way). | |
| -- Not 100% compatible, so with Lua 5.2 it may return nil for a function with no | |
| -- global references! | |
| -- Based on code by [Sergey Rozhenko](http://lua-users.org/lists/lua-l/2010-06/msg00313.html) | |
| -- @param f a function or a call stack reference | |
| -- @function compat.getfenv | |
| --------------- | |
| -- Set environment of a function (in a Lua 5.1 compatible way). | |
| -- @param f a function or a call stack reference | |
| -- @param env a table that becomes the new environment of `f` | |
| -- @function compat.setfenv | |
| if compat.lua51 then -- define Lua 5.2 style load() | |
| if not compat.jit then -- but LuaJIT's load _is_ compatible | |
| local lua51_load = load | |
| function compat.load(str,src,mode,env) | |
| local chunk,err | |
| if type(str) == 'string' then | |
| if str:byte(1) == 27 and not (mode or 'bt'):find 'b' then | |
| return nil,"attempt to load a binary chunk" | |
| end | |
| chunk,err = loadstring(str,src) | |
| else | |
| chunk,err = lua51_load(str,src) | |
| end | |
| if chunk and env then setfenv(chunk,env) end | |
| return chunk,err | |
| end | |
| else | |
| compat.load = load | |
| end | |
| compat.setfenv, compat.getfenv = setfenv, getfenv | |
| else | |
| compat.load = load | |
| -- setfenv/getfenv replacements for Lua 5.2 | |
| -- by Sergey Rozhenko | |
| -- http://lua-users.org/lists/lua-l/2010-06/msg00313.html | |
| -- Roberto Ierusalimschy notes that it is possible for getfenv to return nil | |
| -- in the case of a function with no globals: | |
| -- http://lua-users.org/lists/lua-l/2010-06/msg00315.html | |
| function compat.setfenv(f, t) | |
| f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func) | |
| local name | |
| local up = 0 | |
| repeat | |
| up = up + 1 | |
| name = debug.getupvalue(f, up) | |
| until name == '_ENV' or name == nil | |
| if name then | |
| debug.upvaluejoin(f, up, function() return name end, 1) -- use unique upvalue | |
| debug.setupvalue(f, up, t) | |
| end | |
| if f ~= 0 then return f end | |
| end | |
| function compat.getfenv(f) | |
| local f = f or 0 | |
| f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func) | |
| local name, val | |
| local up = 0 | |
| repeat | |
| up = up + 1 | |
| name, val = debug.getupvalue(f, up) | |
| until name == '_ENV' or name == nil | |
| return val | |
| end | |
| end | |
| --- Global exported functions (for Lua 5.1 & LuaJIT) | |
| -- @section lua52 | |
| --- pack an argument list into a table. | |
| -- @param ... any arguments | |
| -- @return a table with field n set to the length | |
| -- @function table.pack | |
| if not table.pack then | |
| function table.pack (...) -- luacheck: ignore | |
| return {n=select('#',...); ...} | |
| end | |
| end | |
| --- unpack a table and return the elements. | |
| -- | |
| -- NOTE: this version does NOT honor the n field, and hence it is not nil-safe. | |
| -- See `utils.unpack` for a version that is nil-safe. | |
| -- @param t table to unpack | |
| -- @param[opt] i index from which to start unpacking, defaults to 1 | |
| -- @param[opt] j index of the last element to unpack, defaults to #t | |
| -- @return multiple return values from the table | |
| -- @function table.unpack | |
| -- @see utils.unpack | |
| if not table.unpack then | |
| table.unpack = unpack -- luacheck: ignore | |
| end | |
| --- return the full path where a file name would be matched. | |
| -- This function was introduced in Lua 5.2, so this compatibility version | |
| -- will be injected in Lua 5.1 engines. | |
| -- @string name file name, possibly dotted | |
| -- @string path a path-template in the same form as package.path or package.cpath | |
| -- @string[opt] sep template separate character to be replaced by path separator. Default: "." | |
| -- @string[opt] rep the path separator to use, defaults to system separator. Default; "/" on Unixes, "\" on Windows. | |
| -- @see path.package_path | |
| -- @function package.searchpath | |
| -- @return on success: path of the file | |
| -- @return on failure: nil, error string listing paths tried | |
| if not package.searchpath then | |
| function package.searchpath (name,path,sep,rep) -- luacheck: ignore | |
| if type(name) ~= "string" then | |
| error(("bad argument #1 to 'searchpath' (string expected, got %s)"):format(type(path)), 2) | |
| end | |
| if type(path) ~= "string" then | |
| error(("bad argument #2 to 'searchpath' (string expected, got %s)"):format(type(path)), 2) | |
| end | |
| if sep ~= nil and type(sep) ~= "string" then | |
| error(("bad argument #3 to 'searchpath' (string expected, got %s)"):format(type(path)), 2) | |
| end | |
| if rep ~= nil and type(rep) ~= "string" then | |
| error(("bad argument #4 to 'searchpath' (string expected, got %s)"):format(type(path)), 2) | |
| end | |
| sep = sep or "." | |
| rep = rep or compat.dir_separator | |
| do | |
| local s, e = name:find(sep, nil, true) | |
| while s do | |
| name = name:sub(1, s-1) .. rep .. name:sub(e+1, -1) | |
| s, e = name:find(sep, s + #rep + 1, true) | |
| end | |
| end | |
| local tried = {} | |
| for m in path:gmatch('[^;]+') do | |
| local nm = m:gsub('?', name) | |
| tried[#tried+1] = nm | |
| local f = io.open(nm,'r') | |
| if f then f:close(); return nm end | |
| end | |
| return nil, "\tno file '" .. table.concat(tried, "'\n\tno file '") .. "'" | |
| end | |
| end | |
| --- Global exported functions (for Lua < 5.4) | |
| -- @section lua54 | |
| --- raise a warning message. | |
| -- This functions mimics the `warn` function added in Lua 5.4. | |
| -- @function warn | |
| -- @param ... any arguments | |
| if not rawget(_G, "warn") then | |
| local enabled = false | |
| local function warn(arg1, ...) | |
| if type(arg1) == "string" and arg1:sub(1, 1) == "@" then | |
| -- control message | |
| if arg1 == "@on" then | |
| enabled = true | |
| return | |
| end | |
| if arg1 == "@off" then | |
| enabled = false | |
| return | |
| end | |
| return -- ignore unknown control messages | |
| end | |
| if enabled then | |
| io.stderr:write("Lua warning: ", arg1, ...) | |
| io.stderr:write("\n") | |
| end | |
| end | |
| -- use rawset to bypass OpenResty's protection of global scope | |
| rawset(_G, "warn", warn) | |
| end | |
| return compat |