diff options
author | daurnimator <quae@daurnimator.com> | 2017-08-30 13:55:59 +1000 |
---|---|---|
committer | daurnimator <quae@daurnimator.com> | 2017-08-30 13:55:59 +1000 |
commit | 7333333568b13db56136e2354c55556adc7714ed (patch) | |
tree | 028cec7c885ebbbdd404d9db7aba8510f87681a4 /compat53 | |
download | luaossl-7333333568b13db56136e2354c55556adc7714ed.tar.gz luaossl-7333333568b13db56136e2354c55556adc7714ed.tar.bz2 luaossl-7333333568b13db56136e2354c55556adc7714ed.zip |
Squashed 'vendor/compat53/' content from commit 6f3deea
git-subtree-dir: vendor/compat53
git-subtree-split: 6f3deeaa6a4743e1f5148c613addb3f94a22d2df
Diffstat (limited to 'compat53')
-rw-r--r-- | compat53/init.lua | 373 | ||||
-rw-r--r-- | compat53/module.lua | 827 |
2 files changed, 1200 insertions, 0 deletions
diff --git a/compat53/init.lua b/compat53/init.lua new file mode 100644 index 0000000..a7f0c80 --- /dev/null +++ b/compat53/init.lua @@ -0,0 +1,373 @@ +local lua_version = _VERSION:sub(-3) + + +if lua_version < "5.3" then + + local _G, pairs, require, select, type = + _G, pairs, require, select, type + local debug, io = debug, io + local unpack = lua_version == "5.1" and unpack or table.unpack + + local M = require("compat53.module") + + -- select the most powerful getmetatable function available + local gmt = type(debug) == "table" and debug.getmetatable or + getmetatable or function() return false end + -- metatable for file objects from Lua's standard io library + local file_meta = gmt(io.stdout) + + + -- make '*' optional for file:read and file:lines + if type(file_meta) == "table" and type(file_meta.__index) == "table" then + + local function addasterisk(fmt) + if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then + return "*"..fmt + else + return fmt + end + end + + local file_lines = file_meta.__index.lines + file_meta.__index.lines = function(self, ...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return file_lines(self, unpack(args, 1, n)) + end + end + return file_lines(self, ...) + end + + local file_read = file_meta.__index.read + file_meta.__index.read = function(self, ...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return file_read(self, unpack(args, 1, n)) + end + end + return file_read(self, ...) + end + + end -- got a valid metatable for file objects + + + -- changes for Lua 5.1 only + if lua_version == "5.1" then + + -- cache globals + local error, pcall, rawset, setmetatable, tostring, xpcall = + error, pcall, rawset, setmetatable, tostring, xpcall + local coroutine, package, string = coroutine, package, string + local coroutine_resume = coroutine.resume + local coroutine_running = coroutine.running + local coroutine_status = coroutine.status + local coroutine_yield = coroutine.yield + local io_type = io.type + + + -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) + local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" + local is_luajit52 = is_luajit and + #setmetatable({}, { __len = function() return 1 end }) == 1 + + + -- make package.searchers available as an alias for package.loaders + local p_index = { searchers = package.loaders } + setmetatable(package, { + __index = p_index, + __newindex = function(p, k, v) + if k == "searchers" then + rawset(p, "loaders", v) + p_index.searchers = v + else + rawset(p, k, v) + end + end + }) + + + if type(file_meta) == "table" and type(file_meta.__index) == "table" then + if not is_luajit then + local function helper(_, var_1, ...) + if var_1 == nil then + if (...) ~= nil then + error((...), 2) + end + end + return var_1, ... + end + + local function lines_iterator(st) + return helper(st, st.f:read(unpack(st, 1, st.n))) + end + + local file_write = file_meta.__index.write + file_meta.__index.write = function(self, ...) + local res, msg, errno = file_write(self, ...) + if res then + return self + else + return nil, msg, errno + end + end + + file_meta.__index.lines = function(self, ...) + if io_type(self) == "closed file" then + error("attempt to use a closed file", 2) + end + local st = { f=self, n=select('#', ...), ... } + for i = 1, st.n do + local t = type(st[i]) + if t == "string" then + local fmt = st[i]:match("^*?([aln])") + if not fmt then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + st[i] = "*"..fmt + elseif t ~= "number" then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + end + return lines_iterator, st + end + end -- not luajit + end -- file_meta valid + + + -- the (x)pcall implementations start a new coroutine internally + -- to allow yielding even in Lua 5.1. to allow for accurate + -- stack traces we keep track of the nested coroutine activations + -- in the weak tables below: + local weak_meta = { __mode = "kv" } + -- maps the internal pcall coroutines to the user coroutine that + -- *should* be running if pcall didn't use coroutines internally + local pcall_mainOf = setmetatable({}, weak_meta) + -- table that maps each running coroutine started by pcall to + -- the coroutine that resumed it (user coroutine *or* pcall + -- coroutine!) + local pcall_previous = setmetatable({}, weak_meta) + -- reverse of `pcall_mainOf`. maps a user coroutine to the + -- currently active pcall coroutine started within it + local pcall_callOf = setmetatable({}, weak_meta) + -- similar to `pcall_mainOf` but is used only while executing + -- the error handler of xpcall (thus no nesting is necessary!) + local xpcall_running = setmetatable({}, weak_meta) + + -- handle debug functions + if type(debug) == "table" then + local debug_getinfo = debug.getinfo + local debug_traceback = debug.traceback + + if not is_luajit then + local function calculate_trace_level(co, level) + if level ~= nil then + for out = 1, 1/0 do + local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") + if info == nil then + local max = out-1 + if level <= max then + return level + end + return nil, level-max + end + end + end + return 1 + end + + local stack_pattern = "\nstack traceback:" + local stack_replace = "" + function debug.traceback(co, msg, level) + local lvl + local nilmsg + if type(co) ~= "thread" then + co, msg, level = coroutine_running(), co, msg + end + if msg == nil then + msg = "" + nilmsg = true + elseif type(msg) ~= "string" then + return msg + end + if co == nil then + msg = debug_traceback(msg, level or 1) + else + local xpco = xpcall_running[co] + if xpco ~= nil then + lvl, level = calculate_trace_level(xpco, level) + if lvl then + msg = debug_traceback(xpco, msg, lvl) + else + msg = msg..stack_pattern + end + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end + else + co = pcall_callOf[co] or co + lvl, level = calculate_trace_level(co, level) + if lvl then + msg = debug_traceback(co, msg, lvl) + else + msg = msg..stack_pattern + end + end + co = pcall_previous[co] + while co ~= nil do + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end + co = pcall_previous[co] + end + end + if nilmsg then + msg = msg:gsub("^\n", "") + end + msg = msg:gsub("\n\t%(tail call%): %?", "\000") + msg = msg:gsub("\n\t%.%.%.\n", "\001\n") + msg = msg:gsub("\n\t%.%.%.$", "\001") + msg = msg:gsub("(%z+)\001(%z+)", function(some, other) + return "\n\t(..."..#some+#other.."+ tail call(s)...)" + end) + msg = msg:gsub("\001(%z+)", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("(%z+)\001", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("%z+", function(zeros) + return "\n\t(..."..#zeros.." tail call(s)...)" + end) + msg = msg:gsub("\001", function() + return "\n\t..." + end) + return msg + end + end -- is not luajit + end -- debug table available + + + if not is_luajit52 then + local coroutine_running52 = M.coroutine.running + function M.coroutine.running() + local co, ismain = coroutine_running52() + if ismain then + return co, true + else + return pcall_mainOf[co] or co, false + end + end + end + + if not is_luajit then + local function pcall_results(current, call, success, ...) + if coroutine_status(call) == "suspended" then + return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) + end + if pcall_previous then + pcall_previous[call] = nil + local main = pcall_mainOf[call] + if main == current then current = nil end + pcall_callOf[main] = current + end + pcall_mainOf[call] = nil + return success, ... + end + + local function pcall_exec(current, call, ...) + local main = pcall_mainOf[current] or current + pcall_mainOf[call] = main + if pcall_previous then + pcall_previous[call] = current + pcall_callOf[main] = call + end + return pcall_results(current, call, coroutine_resume(call, ...)) + end + + local coroutine_create52 = M.coroutine.create + + local function pcall_coroutine(func) + if type(func) ~= "function" then + local callable = func + func = function (...) return callable(...) end + end + return coroutine_create52(func) + end + + function M.pcall(func, ...) + local current = coroutine_running() + if not current then return pcall(func, ...) end + return pcall_exec(current, pcall_coroutine(func), ...) + end + + local function xpcall_catch(current, call, msgh, success, ...) + if not success then + xpcall_running[current] = call + local ok, result = pcall(msgh, ...) + xpcall_running[current] = nil + if not ok then + return false, "error in error handling ("..tostring(result)..")" + end + return false, result + end + return true, ... + end + + function M.xpcall(f, msgh, ...) + local current = coroutine_running() + if not current then + local args, n = { ... }, select('#', ...) + return xpcall(function() return f(unpack(args, 1, n)) end, msgh) + end + local call = pcall_coroutine(f) + return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) + end + end -- not luajit + + end -- lua 5.1 + + + -- handle exporting to global scope + local function extend_table(from, to) + if from ~= to then + for k,v in pairs(from) do + if type(v) == "table" and + type(to[k]) == "table" and + v ~= to[k] then + extend_table(v, to[k]) + else + to[k] = v + end + end + end + end + + extend_table(M, _G) + +end -- lua < 5.3 + +-- vi: set expandtab softtabstop=3 shiftwidth=3 : diff --git a/compat53/module.lua b/compat53/module.lua new file mode 100644 index 0000000..30be6b5 --- /dev/null +++ b/compat53/module.lua @@ -0,0 +1,827 @@ +local _G, _VERSION = _G, _VERSION +local lua_version = _VERSION:sub(-3) + + +local M = _G + +if lua_version < "5.3" then + + -- cache globals in upvalues + local error, ipairs, pairs, pcall, require, select, setmetatable, type = + error, ipairs, pairs, pcall, require, select, setmetatable, type + local debug, io, math, package, string, table = + debug, io, math, package, string, table + local io_lines = io.lines + local io_read = io.read + local unpack = lua_version == "5.1" and unpack or table.unpack + + -- create module table + M = {} + local M_meta = { + __index = _G, + -- __newindex is set at the end + } + setmetatable(M, M_meta) + + -- create subtables + M.io = setmetatable({}, { __index = io }) + M.math = setmetatable({}, { __index = math }) + M.string = setmetatable({}, { __index = string }) + M.table = setmetatable({}, { __index = table }) + M.utf8 = {} + + + -- select the most powerful getmetatable function available + local gmt = type(debug) == "table" and debug.getmetatable or + getmetatable or function() return false end + + -- type checking functions + local checkinteger -- forward declararation + + local function argcheck(cond, i, f, extra) + if not cond then + error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) + end + end + + + -- load utf8 library + local utf8_ok, utf8lib = pcall(require, "compat53.utf8") + if utf8_ok then + if lua_version == "5.1" then + utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" + end + for k,v in pairs(utf8lib) do + M.utf8[k] = v + end + package.loaded["utf8"] = M.utf8 + end + + + -- load table library + local table_ok, tablib = pcall(require, "compat53.table") + if table_ok then + for k,v in pairs(tablib) do + M.table[k] = v + end + end + + + -- load string packing functions + local str_ok, strlib = pcall(require, "compat53.string") + if str_ok then + for k,v in pairs(strlib) do + M.string[k] = v + end + end + + + -- try Roberto's struct module for string packing/unpacking if + -- compat53.string is unavailable + if not str_ok then + local struct_ok, struct = pcall(require, "struct") + if struct_ok then + M.string.pack = struct.pack + M.string.packsize = struct.size + M.string.unpack = struct.unpack + end + end + + + -- update math library + do + local maxint, minint = 1 + + while maxint+1 > maxint and 2*maxint > maxint do + maxint = maxint * 2 + end + if 2*maxint <= maxint then + maxint = 2*maxint-1 + minint = -maxint-1 + else + maxint = maxint + minint = -maxint + end + M.math.maxinteger = maxint + M.math.mininteger = minint + + function M.math.tointeger(n) + if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then + return n + end + return nil + end + + function M.math.type(n) + if type(n) == "number" then + if n <= maxint and n >= minint and n % 1 == 0 then + return "integer" + else + return "float" + end + else + return nil + end + end + + function checkinteger(x, i, f) + local t = type(x) + if t ~= "number" then + error("bad argument #"..i.." to '"..f.. + "' (number expected, got "..t..")", 0) + elseif x > maxint or x < minint or x % 1 ~= 0 then + error("bad argument #"..i.." to '"..f.. + "' (number has no integer representation)", 0) + else + return x + end + end + + function M.math.ult(m, n) + m = checkinteger(m, "1", "math.ult") + n = checkinteger(n, "2", "math.ult") + if m >= 0 and n < 0 then + return true + elseif m < 0 and n >= 0 then + return false + else + return m < n + end + end + end + + + -- assert should allow non-string error objects + function M.assert(cond, ...) + if cond then + return cond, ... + elseif select('#', ...) > 0 then + error((...), 0) + else + error("assertion failed!", 0) + end + end + + + -- ipairs should respect __index metamethod + do + local function ipairs_iterator(st, var) + var = var + 1 + local val = st[var] + if val ~= nil then + return var, st[var] + end + end + function M.ipairs(t) + if gmt(t) ~= nil then -- t has metatable + return ipairs_iterator, t, 0 + else + return ipairs(t) + end + end + end + + + -- make '*' optional for io.read and io.lines + do + local function addasterisk(fmt) + if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then + return "*"..fmt + else + return fmt + end + end + + function M.io.read(...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere. + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return io_read(unpack(args, 1, n)) + end + end + return io_read(...) + end + + -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! + function M.io.lines(...) + local n = select('#', ...) + for i = 2, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere. + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return io_lines(unpack(args, 1, n)) + end + end + return io_lines(...) + end + end + + + -- update table library (if C module not available) + if not table_ok then + local table_concat = table.concat + local table_insert = table.insert + local table_remove = table.remove + local table_sort = table.sort + + function M.table.concat(list, sep, i, j) + local mt = gmt(list) + if type(mt) == "table" and type(mt.__len) == "function" then + local src = list + list, i, j = {}, i or 1, j or mt.__len(src) + for k = i, j do + list[k] = src[k] + end + end + return table_concat(list, sep, i, j) + end + + function M.table.insert(list, ...) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index or mt.__newindex) then + local e = (has_len and mt.__len(list) or #list)+1 + local nargs, pos, value = select('#', ...), ... + if nargs == 1 then + pos, value = e, pos + elseif nargs == 2 then + pos = checkinteger(pos, "2", "table.insert") + argcheck(1 <= pos and pos <= e, "2", "table.insert", + "position out of bounds" ) + else + error("wrong number of arguments to 'insert'", 0) + end + for i = e-1, pos, -1 do + list[i+1] = list[i] + end + list[pos] = value + else + return table_insert(list, ...) + end + end + + function M.table.move(a1, f, e, t, a2) + a2 = a2 or a1 + f = checkinteger(f, "2", "table.move") + argcheck(f > 0, "2", "table.move", + "initial position must be positive") + e = checkinteger(e, "3", "table.move") + t = checkinteger(t, "4", "table.move") + if e >= f then + local m, n, d = 0, e-f, 1 + if t > f then m, n, d = n, m, -1 end + for i = m, n, d do + a2[t+i] = a1[f+i] + end + end + return a2 + end + + function M.table.remove(list, pos) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index or mt.__newindex) then + local e = (has_len and mt.__len(list) or #list) + pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e + if pos ~= e then + argcheck(1 <= pos and pos <= e+1, "2", "table.remove", + "position out of bounds" ) + end + local result = list[pos] + while pos < e do + list[pos] = list[pos+1] + pos = pos + 1 + end + list[pos] = nil + return result + else + return table_remove(list, pos) + end + end + + do + local function pivot(list, cmp, a, b) + local m = b - a + if m > 2 then + local c = a + (m-m%2)/2 + local x, y, z = list[a], list[b], list[c] + if not cmp(x, y) then + x, y, a, b = y, x, b, a + end + if not cmp(y, z) then + y, b = z, c + end + if not cmp(x, y) then + y, b = x, a + end + return b, y + else + return b, list[b] + end + end + + local function lt_cmp(a, b) + return a < b + end + + local function qsort(list, cmp, b, e) + if b < e then + local i, j, k, val = b, e, pivot(list, cmp, b, e) + while i < j do + while i < j and cmp(list[i], val) do + i = i + 1 + end + while i < j and not cmp(list[j], val) do + j = j - 1 + end + if i < j then + list[i], list[j] = list[j], list[i] + if i == k then k = j end -- update pivot position + i, j = i+1, j-1 + end + end + if i ~= k and not cmp(list[i], val) then + list[i], list[k] = val, list[i] + k = i -- update pivot position + end + qsort(list, cmp, b, i == k and i-1 or i) + return qsort(list, cmp, i+1, e) + end + end + + function M.table.sort(list, cmp) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_len then + cmp = cmp or lt_cmp + local len = mt.__len(list) + return qsort(list, cmp, 1, len) + else + return table_sort(list, cmp) + end + end + end + + local function unpack_helper(list, i, j, ...) + if j < i then + return ... + else + return unpack_helper(list, i, j-1, list[j], ...) + end + end + function M.table.unpack(list, i, j) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index) then + i, j = i or 1, j or (has_len and mt.__len(list)) or #list + return unpack_helper(list, i, j) + else + return unpack(list, i, j) + end + end + end -- update table library + + + -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 + if lua_version == "5.1" then + -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) + local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" + local is_luajit52 = is_luajit and + #setmetatable({}, { __len = function() return 1 end }) == 1 + + -- cache globals in upvalues + local load, loadfile, loadstring, setfenv, xpcall = + load, loadfile, loadstring, setfenv, xpcall + local coroutine, os = coroutine, os + local coroutine_create = coroutine.create + local coroutine_resume = coroutine.resume + local coroutine_running = coroutine.running + local coroutine_status = coroutine.status + local coroutine_yield = coroutine.yield + local io_input = io.input + local io_open = io.open + local io_output = io.output + local io_write = io.write + local math_log = math.log + local os_execute = os.execute + local string_find = string.find + local string_format = string.format + local string_gmatch = string.gmatch + local string_gsub = string.gsub + local string_match = string.match + local string_rep = string.rep + local table_concat = table.concat + + -- create subtables + M.coroutine = setmetatable({}, { __index = coroutine }) + M.os = setmetatable({}, { __index = os }) + M.package = setmetatable({}, { __index = package }) + + -- handle debug functions + if type(debug) == "table" then + local debug_setfenv = debug.setfenv + local debug_getfenv = debug.getfenv + local debug_setmetatable = debug.setmetatable + + M.debug = setmetatable({}, { __index = debug }) + + if not is_luajit52 then + function M.debug.setuservalue(obj, value) + if type(obj) ~= "userdata" then + error("bad argument #1 to 'setuservalue' (userdata expected, got ".. + type(obj)..")", 2) + end + if value == nil then value = _G end + if type(value) ~= "table" then + error("bad argument #2 to 'setuservalue' (table expected, got ".. + type(value)..")", 2) + end + return debug_setfenv(obj, value) + end + + function M.debug.getuservalue(obj) + if type(obj) ~= "userdata" then + return nil + else + local v = debug_getfenv(obj) + if v == _G or v == package then + return nil + end + return v + end + end + + function M.debug.setmetatable(value, tab) + debug_setmetatable(value, tab) + return value + end + end -- not luajit with compat52 enabled + end -- debug table available + + + if not is_luajit52 then + function M.pairs(t) + local mt = gmt(t) + if type(mt) == "table" and type(mt.__pairs) == "function" then + return mt.__pairs(t) + else + return pairs(t) + end + end + end + + + if not is_luajit then + local function check_mode(mode, prefix) + local has = { text = false, binary = false } + for i = 1,#mode do + local c = mode:sub(i, i) + if c == "t" then has.text = true end + if c == "b" then has.binary = true end + end + local t = prefix:sub(1, 1) == "\27" and "binary" or "text" + if not has[t] then + return "attempt to load a "..t.." chunk (mode is '"..mode.."')" + end + end + + function M.load(ld, source, mode, env) + mode = mode or "bt" + local chunk, msg + if type( ld ) == "string" then + if mode ~= "bt" then + local merr = check_mode(mode, ld) + if merr then return nil, merr end + end + chunk, msg = loadstring(ld, source) + else + local ld_type = type(ld) + if ld_type ~= "function" then + error("bad argument #1 to 'load' (function expected, got ".. + ld_type..")", 2) + end + if mode ~= "bt" then + local checked, merr = false, nil + local function checked_ld() + if checked then + return ld() + else + checked = true + local v = ld() + merr = check_mode(mode, v or "") + if merr then return nil end + return v + end + end + chunk, msg = load(checked_ld, source) + if merr then return nil, merr end + else + chunk, msg = load(ld, source) + end + end + if not chunk then + return chunk, msg + end + if env ~= nil then + setfenv(chunk, env) + end + return chunk + end + + M.loadstring = M.load + + function M.loadfile(file, mode, env) + mode = mode or "bt" + if mode ~= "bt" then + local f = io_open(file, "rb") + if f then + local prefix = f:read(1) + f:close() + if prefix then + local merr = check_mode(mode, prefix) + if merr then return nil, merr end + end + end + end + local chunk, msg = loadfile(file) + if not chunk then + return chunk, msg + end + if env ~= nil then + setfenv(chunk, env) + end + return chunk + end + end -- not luajit + + + if not is_luajit52 then + function M.rawlen(v) + local t = type(v) + if t ~= "string" and t ~= "table" then + error("bad argument #1 to 'rawlen' (table or string expected)", 2) + end + return #v + end + end + + + if not is_luajit then + function M.xpcall(f, msgh, ...) + local args, n = { ... }, select('#', ...) + return xpcall(function() return f(unpack(args, 1, n)) end, msgh) + end + end + + + if not is_luajit52 then + function M.os.execute(cmd) + local code = os_execute(cmd) + -- Lua 5.1 does not report exit by signal. + if code == 0 then + return true, "exit", code + else + if package.config:sub(1, 1) == '/' then + code = code/256 -- only correct on Linux! + end + return nil, "exit", code + end + end + end + + + if not table_ok and not is_luajit52 then + M.table.pack = function(...) + return { n = select('#', ...), ... } + end + end + + + local main_coroutine = coroutine_create(function() end) + + function M.coroutine.create(func) + local success, result = pcall(coroutine_create, func) + if not success then + if type(func) ~= "function" then + error("bad argument #1 (function expected)", 0) + end + result = coroutine_create(function(...) return func(...) end) + end + return result + end + + if not is_luajit52 then + function M.coroutine.running() + local co = coroutine_running() + if co then + return co, false + else + return main_coroutine, true + end + end + end + + function M.coroutine.yield(...) + local co, flag = coroutine_running() + if co and not flag then + return coroutine_yield(...) + else + error("attempt to yield from outside a coroutine", 0) + end + end + + if not is_luajit then + function M.coroutine.resume(co, ...) + if co == main_coroutine then + return false, "cannot resume non-suspended coroutine" + else + return coroutine_resume(co, ...) + end + end + + function M.coroutine.status(co) + local notmain = coroutine_running() + if co == main_coroutine then + return notmain and "normal" or "running" + else + return coroutine_status(co) + end + end + end -- not luajit + + + if not is_luajit then + M.math.log = function(x, base) + if base ~= nil then + return math_log(x)/math_log(base) + else + return math_log(x) + end + end + end + + + if not is_luajit then + function M.package.searchpath(name, path, sep, rep) + sep = (sep or "."):gsub("(%p)", "%%%1") + rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") + local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") + local msg = {} + for subpath in path:gmatch("[^;]+") do + local fpath = subpath:gsub("%?", pname) + local f = io_open(fpath, "r") + if f then + f:close() + return fpath + end + msg[#msg+1] = "\n\tno file '" .. fpath .. "'" + end + return nil, table_concat(msg) + end + end + + + local function fix_pattern(pattern) + return (string_gsub(pattern, "%z", "%%z")) + end + + function M.string.find(s, pattern, ...) + return string_find(s, fix_pattern(pattern), ...) + end + + function M.string.gmatch(s, pattern) + return string_gmatch(s, fix_pattern(pattern)) + end + + function M.string.gsub(s, pattern, ...) + return string_gsub(s, fix_pattern(pattern), ...) + end + + function M.string.match(s, pattern, ...) + return string_match(s, fix_pattern(pattern), ...) + end + + if not is_luajit then + function M.string.rep(s, n, sep) + if sep ~= nil and sep ~= "" and n >= 2 then + return s .. string_rep(sep..s, n-1) + else + return string_rep(s, n) + end + end + end + + if not is_luajit then + do + local addqt = { + ["\n"] = "\\\n", + ["\\"] = "\\\\", + ["\""] = "\\\"" + } + + local function addquoted(c, d) + return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d + end + + function M.string.format(fmt, ...) + local args, n = { ... }, select('#', ...) + local i = 0 + local function adjust_fmt(lead, mods, kind) + if #lead % 2 == 0 then + i = i + 1 + if kind == "s" then + args[i] = _G.tostring(args[i]) + elseif kind == "q" then + args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' + return lead.."%"..mods.."s" + end + end + end + fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) + return string_format(fmt, unpack(args, 1, n)) + end + end + end + + + function M.io.write(...) + local res, msg, errno = io_write(...) + if res then + return io_output() + else + return nil, msg, errno + end + end + + if not is_luajit then + local function helper(st, var_1, ...) + if var_1 == nil then + if st.doclose then st.f:close() end + if (...) ~= nil then + error((...), 2) + end + end + return var_1, ... + end + + local function lines_iterator(st) + return helper(st, st.f:read(unpack(st, 1, st.n))) + end + + function M.io.lines(fname, ...) + local doclose, file, msg + if fname ~= nil then + doclose, file, msg = true, io_open(fname, "r") + if not file then error(msg, 2) end + else + doclose, file = false, io_input() + end + local st = { f=file, doclose=doclose, n=select('#', ...), ... } + for i = 1, st.n do + local t = type(st[i]) + if t == "string" then + local fmt = st[i]:match("^%*?([aln])") + if not fmt then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + st[i] = "*"..fmt + elseif t ~= "number" then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + end + return lines_iterator, st + end + end -- not luajit + + end -- lua 5.1 + + -- further write should be forwarded to _G + M_meta.__newindex = _G + +end -- lua < 5.3 + + +-- return module table +return M + +-- vi: set expandtab softtabstop=3 shiftwidth=3 : |