compat52.lua 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. -- utility module to make the Lua 5.1 standard libraries behave more like Lua 5.2
  2. if _VERSION == "Lua 5.1" then
  3. local _type, _select, _unpack, _error = type, select, unpack, error
  4. bit32 = require("bit32")
  5. -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
  6. -- note that string.dump panics in glua so we short-circuit the below check
  7. local is_luajit = false and (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
  8. local is_luajit52 = is_luajit and
  9. #setmetatable({}, { __len = function() return 1 end }) == 1
  10. local weak_meta = { __mode = "kv" }
  11. -- table that maps each running coroutine to the coroutine that resumed it
  12. -- this is used to build complete tracebacks when "coroutine-friendly" pcall
  13. -- is used.
  14. local pcall_previous = setmetatable({}, weak_meta)
  15. local pcall_callOf = setmetatable({}, weak_meta)
  16. local xpcall_running = setmetatable({}, weak_meta)
  17. local coroutine_running = coroutine.running
  18. -- the most powerful getmetatable we can get (preferably from debug)
  19. local sudo_getmetatable = getmetatable
  20. if _type(debug) == "table" then
  21. if _type(debug.getmetatable) == "function" then
  22. sudo_getmetatable = debug.getmetatable
  23. end
  24. if not is_luajit52 then
  25. local _G, package = _G, package
  26. local debug_setfenv = debug.setfenv
  27. debug.setuservalue = function(obj, value)
  28. if _type(obj) ~= "userdata" then
  29. _error("bad argument #1 to 'setuservalue' (userdata expected, got "..
  30. _type(obj)..")", 2)
  31. end
  32. if value == nil then value = _G end
  33. if _type(value) ~= "table" then
  34. _error("bad argument #2 to 'setuservalue' (table expected, got "..
  35. _type(value)..")", 2)
  36. end
  37. return debug_setfenv(obj, value)
  38. end
  39. local debug_getfenv = debug.getfenv
  40. debug.getuservalue = function(obj)
  41. if _type(obj) ~= "userdata" then
  42. return nil
  43. else
  44. local v = debug_getfenv(obj)
  45. if v == _G or v == package then
  46. return nil
  47. end
  48. return v
  49. end
  50. end
  51. local debug_setmetatable = debug.setmetatable
  52. if _type(debug_setmetatable) == "function" then
  53. debug.setmetatable = function(value, tab)
  54. debug_setmetatable(value, tab)
  55. return value
  56. end
  57. end
  58. end -- not luajit with compat52 enabled
  59. if not is_luajit then
  60. local debug_getinfo = debug.getinfo
  61. local function calculate_trace_level(co, level)
  62. if level ~= nil then
  63. for out = 1, 1/0 do
  64. local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
  65. if info == nil then
  66. local max = out-1
  67. if level <= max then
  68. return level
  69. end
  70. return nil, level-max
  71. end
  72. end
  73. end
  74. return 1
  75. end
  76. local stack_pattern = "\nstack traceback:"
  77. local stack_replace = ""
  78. local debug_traceback = debug.traceback
  79. debug.traceback = function (co, msg, level)
  80. local lvl
  81. local nilmsg
  82. if _type(co) ~= "thread" then
  83. co, msg, level = coroutine_running(), co, msg
  84. end
  85. if msg == nil then
  86. msg = ""
  87. nilmsg = true
  88. elseif _type(msg) ~= "string" then
  89. return msg
  90. end
  91. if co == nil then
  92. msg = debug_traceback(msg, level or 1)
  93. else
  94. local xpco = xpcall_running[co]
  95. if xpco ~= nil then
  96. lvl, level = calculate_trace_level(xpco, level)
  97. if lvl then
  98. msg = debug_traceback(xpco, msg, lvl)
  99. else
  100. msg = msg..stack_pattern
  101. end
  102. lvl, level = calculate_trace_level(co, level)
  103. if lvl then
  104. local trace = debug_traceback(co, "", lvl)
  105. msg = msg..trace:gsub(stack_pattern, stack_replace)
  106. end
  107. else
  108. co = pcall_callOf[co] or co
  109. lvl, level = calculate_trace_level(co, level)
  110. if lvl then
  111. msg = debug_traceback(co, msg, lvl)
  112. else
  113. msg = msg..stack_pattern
  114. end
  115. end
  116. co = pcall_previous[co]
  117. while co ~= nil do
  118. lvl, level = calculate_trace_level(co, level)
  119. if lvl then
  120. local trace = debug_traceback(co, "", lvl)
  121. msg = msg..trace:gsub(stack_pattern, stack_replace)
  122. end
  123. co = pcall_previous[co]
  124. end
  125. end
  126. if nilmsg then
  127. msg = msg:gsub("^\n", "")
  128. end
  129. msg = msg:gsub("\n\t%(tail call%): %?", "\000")
  130. msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
  131. msg = msg:gsub("\n\t%.%.%.$", "\001")
  132. msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
  133. return "\n\t(..."..#some+#other.."+ tail call(s)...)"
  134. end)
  135. msg = msg:gsub("\001(%z+)", function(zeros)
  136. return "\n\t(..."..#zeros.."+ tail call(s)...)"
  137. end)
  138. msg = msg:gsub("(%z+)\001", function(zeros)
  139. return "\n\t(..."..#zeros.."+ tail call(s)...)"
  140. end)
  141. msg = msg:gsub("%z+", function(zeros)
  142. return "\n\t(..."..#zeros.." tail call(s)...)"
  143. end)
  144. msg = msg:gsub("\001", function(zeros)
  145. return "\n\t..."
  146. end)
  147. return msg
  148. end
  149. end -- is not luajit
  150. end -- debug table available
  151. if not is_luajit52 then
  152. local _pairs = pairs
  153. pairs = function(t)
  154. local mt = sudo_getmetatable(t)
  155. if _type(mt) == "table" and _type(mt.__pairs) == "function" then
  156. return mt.__pairs(t)
  157. else
  158. return _pairs(t)
  159. end
  160. end
  161. local _ipairs = ipairs
  162. ipairs = function(t)
  163. local mt = sudo_getmetatable(t)
  164. if _type(mt) == "table" and _type(mt.__ipairs) == "function" then
  165. return mt.__ipairs(t)
  166. else
  167. return _ipairs(t)
  168. end
  169. end
  170. end -- not luajit with compat52 enabled
  171. if not is_luajit then
  172. local function check_mode(mode, prefix)
  173. local has = { text = false, binary = false }
  174. for i = 1,#mode do
  175. local c = mode:sub(i, i)
  176. if c == "t" then has.text = true end
  177. if c == "b" then has.binary = true end
  178. end
  179. local t = prefix:sub(1, 1) == "\27" and "binary" or "text"
  180. if not has[t] then
  181. return "attempt to load a "..t.." chunk (mode is '"..mode.."')"
  182. end
  183. end
  184. local _setfenv = setfenv
  185. local _load, _loadstring = load, loadstring
  186. load = function(ld, source, mode, env)
  187. mode = mode or "bt"
  188. local chunk, msg
  189. if _type( ld ) == "string" then
  190. if mode ~= "bt" then
  191. local merr = check_mode(mode, ld)
  192. if merr then return nil, merr end
  193. end
  194. chunk, msg = _loadstring(ld, source)
  195. else
  196. local ld_type = _type(ld)
  197. if ld_type ~= "function" then
  198. _error("bad argument #1 to 'load' (function expected, got "..ld_type..")", 2)
  199. end
  200. if mode ~= "bt" then
  201. local checked, merr = false, nil
  202. local function checked_ld()
  203. if checked then
  204. return ld()
  205. else
  206. checked = true
  207. local v = ld()
  208. merr = check_mode(mode, v or "")
  209. if merr then return nil end
  210. return v
  211. end
  212. end
  213. chunk, msg = _load(checked_ld, source)
  214. if merr then return nil, merr end
  215. else
  216. chunk, msg = _load(ld, source)
  217. end
  218. end
  219. if not chunk then
  220. return chunk, msg
  221. end
  222. if env ~= nil then
  223. _setfenv(chunk, env)
  224. end
  225. return chunk
  226. end
  227. loadstring = load
  228. local _loadfile = loadfile
  229. local io_open = io.open
  230. loadfile = function(file, mode, env)
  231. mode = mode or "bt"
  232. if mode ~= "bt" then
  233. local f = io_open(file, "rb")
  234. if f then
  235. local prefix = f:read(1)
  236. f:close()
  237. if prefix then
  238. local merr = check_mode(mode, prefix)
  239. if merr then return nil, merr end
  240. end
  241. end
  242. end
  243. local chunk, msg = _loadfile(file)
  244. if not chunk then
  245. return chunk, msg
  246. end
  247. if env ~= nil then
  248. _setfenv(chunk, env)
  249. end
  250. return chunk
  251. end
  252. end -- not luajit
  253. if not is_luajit52 then
  254. function rawlen(v)
  255. local t = _type(v)
  256. if t ~= "string" and t ~= "table" then
  257. _error("bad argument #1 to 'rawlen' (table or string expected)", 2)
  258. end
  259. return #v
  260. end
  261. end -- not luajit with compat52 enabled
  262. local gc_isrunning = true
  263. local _collectgarbage = collectgarbage
  264. local math_floor = math.floor
  265. collectgarbage = function(opt, ...)
  266. opt = opt or "collect"
  267. local v = 0
  268. if opt == "collect" then
  269. v = _collectgarbage(opt, ...)
  270. if not gc_isrunning then _collectgarbage("stop") end
  271. elseif opt == "stop" then
  272. gc_isrunning = false
  273. return _collectgarbage(opt, ...)
  274. elseif opt == "restart" then
  275. gc_isrunning = true
  276. return _collectgarbage(opt, ...)
  277. elseif opt == "count" then
  278. v = _collectgarbage(opt, ...)
  279. return v, (v-math_floor(v))*1024
  280. elseif opt == "step" then
  281. v = _collectgarbage(opt, ...)
  282. if not gc_isrunning then _collectgarbage("stop") end
  283. elseif opt == "isrunning" then
  284. return gc_isrunning
  285. elseif opt ~= "generational" and opt ~= "incremental" then
  286. return _collectgarbage(opt, ...)
  287. end
  288. return v
  289. end
  290. if not is_luajit52 then
  291. local os_execute = os.execute
  292. local bit32_rshift = bit32.rshift
  293. os.execute = function(cmd)
  294. local code = os_execute(cmd)
  295. -- Lua 5.1 does not report exit by signal.
  296. if code == 0 then
  297. return true, "exit", code
  298. else
  299. return nil, "exit", bit32_rshift(code, 8)
  300. end
  301. end
  302. end -- not luajit with compat52 enabled
  303. if not is_luajit52 then
  304. table.pack = function(...)
  305. return { n = _select('#', ...), ... }
  306. end
  307. table.unpack = _unpack
  308. end -- not luajit with compat52 enabled
  309. local main_coroutine = coroutine.create(function() end)
  310. local _assert = assert
  311. local _pcall = pcall
  312. local coroutine_create = coroutine.create
  313. coroutine.create = function (func)
  314. local success, result = _pcall(coroutine_create, func)
  315. if not success then
  316. _assert(_type(func) == "function", "bad argument #1 (function expected)")
  317. result = coroutine_create(function(...) return func(...) end)
  318. end
  319. return result
  320. end
  321. local pcall_mainOf = setmetatable({}, weak_meta)
  322. if not is_luajit52 then
  323. coroutine.running = function()
  324. local co = coroutine_running()
  325. if co then
  326. return pcall_mainOf[co] or co, false
  327. else
  328. return main_coroutine, true
  329. end
  330. end
  331. end
  332. local coroutine_yield = coroutine.yield
  333. coroutine.yield = function(...)
  334. local co, flag = coroutine_running()
  335. if co and not flag then
  336. return coroutine_yield(...)
  337. else
  338. _error("attempt to yield from outside a coroutine", 0)
  339. end
  340. end
  341. if not is_luajit then
  342. local coroutine_resume = coroutine.resume
  343. coroutine.resume = function(co, ...)
  344. if co == main_coroutine then
  345. return false, "cannot resume non-suspended coroutine"
  346. else
  347. return coroutine_resume(co, ...)
  348. end
  349. end
  350. local coroutine_status = coroutine.status
  351. coroutine.status = function(co)
  352. local notmain = coroutine_running()
  353. if co == main_coroutine then
  354. return notmain and "normal" or "running"
  355. else
  356. return coroutine_status(co)
  357. end
  358. end
  359. local function pcall_results(current, call, success, ...)
  360. if coroutine_status(call) == "suspended" then
  361. return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
  362. end
  363. if pcall_previous then
  364. pcall_previous[call] = nil
  365. local main = pcall_mainOf[call]
  366. if main == current then current = nil end
  367. pcall_callOf[main] = current
  368. end
  369. pcall_mainOf[call] = nil
  370. return success, ...
  371. end
  372. local function pcall_exec(current, call, ...)
  373. local main = pcall_mainOf[current] or current
  374. pcall_mainOf[call] = main
  375. if pcall_previous then
  376. pcall_previous[call] = current
  377. pcall_callOf[main] = call
  378. end
  379. return pcall_results(current, call, coroutine_resume(call, ...))
  380. end
  381. local coroutine_create52 = coroutine.create
  382. local function pcall_coroutine(func)
  383. if _type(func) ~= "function" then
  384. local callable = func
  385. func = function (...) return callable(...) end
  386. end
  387. return coroutine_create52(func)
  388. end
  389. pcall = function (func, ...)
  390. local current = coroutine_running()
  391. if not current then return _pcall(func, ...) end
  392. return pcall_exec(current, pcall_coroutine(func), ...)
  393. end
  394. local _tostring = tostring
  395. local function xpcall_catch(current, call, msgh, success, ...)
  396. if not success then
  397. xpcall_running[current] = call
  398. local ok, result = _pcall(msgh, ...)
  399. xpcall_running[current] = nil
  400. if not ok then
  401. return false, "error in error handling (".._tostring(result)..")"
  402. end
  403. return false, result
  404. end
  405. return true, ...
  406. end
  407. local _xpcall = xpcall
  408. xpcall = function(f, msgh, ...)
  409. local current = coroutine_running()
  410. if not current then
  411. local args, n = { ... }, _select('#', ...)
  412. return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh)
  413. end
  414. local call = pcall_coroutine(f)
  415. return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
  416. end
  417. end -- not luajit
  418. if not is_luajit then
  419. local math_log = math.log
  420. math.log = function(x, base)
  421. if base ~= nil then
  422. return math_log(x)/math_log(base)
  423. else
  424. return math_log(x)
  425. end
  426. end
  427. end
  428. local package = package
  429. if not is_luajit then
  430. local io_open = io.open
  431. local table_concat = table.concat
  432. package.searchpath = function(name, path, sep, rep)
  433. sep = (sep or "."):gsub("(%p)", "%%%1")
  434. rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
  435. local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
  436. local msg = {}
  437. for subpath in path:gmatch("[^;]+") do
  438. local fpath = subpath:gsub("%?", pname)
  439. local f = io_open(fpath, "r")
  440. if f then
  441. f:close()
  442. return fpath
  443. end
  444. msg[#msg+1] = "\n\tno file '" .. fpath .. "'"
  445. end
  446. return nil, table_concat(msg)
  447. end
  448. end -- not luajit
  449. local p_index = { searchers = package.loaders }
  450. local _rawset = rawset
  451. setmetatable(package, {
  452. __index = p_index,
  453. __newindex = function(p, k, v)
  454. if k == "searchers" then
  455. _rawset(p, "loaders", v)
  456. p_index.searchers = v
  457. else
  458. _rawset(p, k, v)
  459. end
  460. end
  461. })
  462. local string_gsub = string.gsub
  463. local function fix_pattern(pattern)
  464. return (string_gsub(pattern, "%z", "%%z"))
  465. end
  466. local string_find = string.find
  467. function string.find(s, pattern, ...)
  468. return string_find(s, fix_pattern(pattern), ...)
  469. end
  470. local string_gmatch = string.gmatch
  471. function string.gmatch(s, pattern)
  472. return string_gmatch(s, fix_pattern(pattern))
  473. end
  474. function string.gsub(s, pattern, ...)
  475. return string_gsub(s, fix_pattern(pattern), ...)
  476. end
  477. local string_match = string.match
  478. function string.match(s, pattern, ...)
  479. return string_match(s, fix_pattern(pattern), ...)
  480. end
  481. if not is_luajit then
  482. local string_rep = string.rep
  483. function string.rep(s, n, sep)
  484. if sep ~= nil and sep ~= "" and n >= 2 then
  485. return s .. string_rep(sep..s, n-1)
  486. else
  487. return string_rep(s, n)
  488. end
  489. end
  490. end -- not luajit
  491. if not is_luajit then
  492. local _tostring = tostring
  493. local string_format = string.format
  494. do
  495. local addqt = {
  496. ["\n"] = "\\\n",
  497. ["\\"] = "\\\\",
  498. ["\""] = "\\\""
  499. }
  500. local function addquoted(c, d)
  501. return (addqt[c] or string_format(d~= "" and "\\%03d" or "\\%d", c:byte()))..d
  502. end
  503. function string.format(fmt, ...)
  504. local args, n = { ... }, _select('#', ...)
  505. local i = 0
  506. local function adjust_fmt(lead, mods, kind)
  507. if #lead % 2 == 0 then
  508. i = i + 1
  509. if kind == "s" then
  510. args[i] = _tostring(args[i])
  511. elseif kind == "q" then
  512. args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"'
  513. return lead.."%"..mods.."s"
  514. end
  515. end
  516. end
  517. fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
  518. return string_format(fmt, _unpack(args, 1, n))
  519. end
  520. end
  521. end -- not luajit
  522. local io_open = io.open
  523. local io_write = io.write
  524. local io_output = io.output
  525. function io.write(...)
  526. local res, msg, errno = io_write(...)
  527. if res then
  528. return io_output()
  529. else
  530. return nil, msg, errno
  531. end
  532. end
  533. if not is_luajit then
  534. local lines_iterator
  535. do
  536. local function helper( st, var_1, ... )
  537. if var_1 == nil then
  538. if st.doclose then st.f:close() end
  539. if (...) ~= nil then
  540. _error((...), 2)
  541. end
  542. end
  543. return var_1, ...
  544. end
  545. function lines_iterator(st)
  546. return helper(st, st.f:read(_unpack(st, 1, st.n)))
  547. end
  548. end
  549. local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
  550. local io_input = io.input
  551. function io.lines(fname, ...)
  552. local doclose, file, msg
  553. if fname ~= nil then
  554. doclose, file, msg = true, io_open(fname, "r")
  555. if not file then _error(msg, 2) end
  556. else
  557. doclose, file = false, io_input()
  558. end
  559. local st = { f=file, doclose=doclose, n=_select('#', ...), ... }
  560. for i = 1, st.n do
  561. if _type(st[i]) ~= "number" and not valid_format[st[i]] then
  562. _error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
  563. end
  564. end
  565. return lines_iterator, st
  566. end
  567. do
  568. local io_stdout = io.stdout
  569. local io_type = io.type
  570. local file_meta = sudo_getmetatable(io_stdout)
  571. if _type(file_meta) == "table" and _type(file_meta.__index) == "table" then
  572. local file_write = file_meta.__index.write
  573. file_meta.__index.write = function(self, ...)
  574. local res, msg, errno = file_write(self, ...)
  575. if res then
  576. return self
  577. else
  578. return nil, msg, errno
  579. end
  580. end
  581. file_meta.__index.lines = function(self, ...)
  582. if io_type(self) == "closed file" then
  583. _error("attempt to use a closed file", 2)
  584. end
  585. local st = { f=self, doclose=false, n=_select('#', ...), ... }
  586. for i = 1, st.n do
  587. if _type(st[i]) ~= "number" and not valid_format[st[i]] then
  588. _error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
  589. end
  590. end
  591. return lines_iterator, st
  592. end
  593. end
  594. end
  595. end -- not luajit
  596. end