1local _G, _VERSION = _G, _VERSION 2local lua_version = _VERSION:sub(-3) 3 4 5local M = _G 6 7if lua_version < "5.3" then 8 9 -- cache globals in upvalues 10 local error, ipairs, pairs, pcall, require, select, setmetatable, type = 11 error, ipairs, pairs, pcall, require, select, setmetatable, type 12 local debug, io, math, package, string, table = 13 debug, io, math, package, string, table 14 local io_lines = io.lines 15 local io_read = io.read 16 local unpack = lua_version == "5.1" and unpack or table.unpack 17 18 -- create module table 19 M = {} 20 local M_meta = { 21 __index = _G, 22 -- __newindex is set at the end 23 } 24 setmetatable(M, M_meta) 25 26 -- create subtables 27 M.io = setmetatable({}, { __index = io }) 28 M.math = setmetatable({}, { __index = math }) 29 M.string = setmetatable({}, { __index = string }) 30 M.table = setmetatable({}, { __index = table }) 31 M.utf8 = {} 32 33 34 -- select the most powerful getmetatable function available 35 local gmt = type(debug) == "table" and debug.getmetatable or 36 getmetatable or function() return false end 37 38 -- type checking functions 39 local checkinteger -- forward declararation 40 41 local function argcheck(cond, i, f, extra) 42 if not cond then 43 error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) 44 end 45 end 46 47 48 -- load utf8 library 49 local utf8_ok, utf8lib = pcall(require, "compat53.utf8") 50 if utf8_ok then 51 if lua_version == "5.1" then 52 utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" 53 end 54 for k,v in pairs(utf8lib) do 55 M.utf8[k] = v 56 end 57 package.loaded["utf8"] = M.utf8 58 end 59 60 61 -- load table library 62 local table_ok, tablib = pcall(require, "compat53.table") 63 if table_ok then 64 for k,v in pairs(tablib) do 65 M.table[k] = v 66 end 67 end 68 69 70 -- load string packing functions 71 local str_ok, strlib = pcall(require, "compat53.string") 72 if str_ok then 73 for k,v in pairs(strlib) do 74 M.string[k] = v 75 end 76 end 77 78 79 -- try Roberto's struct module for string packing/unpacking if 80 -- compat53.string is unavailable 81 if not str_ok then 82 local struct_ok, struct = pcall(require, "struct") 83 if struct_ok then 84 M.string.pack = struct.pack 85 M.string.packsize = struct.size 86 M.string.unpack = struct.unpack 87 end 88 end 89 90 91 -- update math library 92 do 93 local maxint, minint = 1 94 95 while maxint+1 > maxint and 2*maxint > maxint do 96 maxint = maxint * 2 97 end 98 if 2*maxint <= maxint then 99 maxint = 2*maxint-1 100 minint = -maxint-1 101 else 102 maxint = maxint 103 minint = -maxint 104 end 105 M.math.maxinteger = maxint 106 M.math.mininteger = minint 107 108 function M.math.tointeger(n) 109 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then 110 return n 111 end 112 return nil 113 end 114 115 function M.math.type(n) 116 if type(n) == "number" then 117 if n <= maxint and n >= minint and n % 1 == 0 then 118 return "integer" 119 else 120 return "float" 121 end 122 else 123 return nil 124 end 125 end 126 127 function checkinteger(x, i, f) 128 local t = type(x) 129 if t ~= "number" then 130 error("bad argument #"..i.." to '"..f.. 131 "' (number expected, got "..t..")", 0) 132 elseif x > maxint or x < minint or x % 1 ~= 0 then 133 error("bad argument #"..i.." to '"..f.. 134 "' (number has no integer representation)", 0) 135 else 136 return x 137 end 138 end 139 140 function M.math.ult(m, n) 141 m = checkinteger(m, "1", "math.ult") 142 n = checkinteger(n, "2", "math.ult") 143 if m >= 0 and n < 0 then 144 return true 145 elseif m < 0 and n >= 0 then 146 return false 147 else 148 return m < n 149 end 150 end 151 end 152 153 154 -- assert should allow non-string error objects 155 function M.assert(cond, ...) 156 if cond then 157 return cond, ... 158 elseif select('#', ...) > 0 then 159 error((...), 0) 160 else 161 error("assertion failed!", 0) 162 end 163 end 164 165 166 -- ipairs should respect __index metamethod 167 do 168 local function ipairs_iterator(st, var) 169 var = var + 1 170 local val = st[var] 171 if val ~= nil then 172 return var, st[var] 173 end 174 end 175 function M.ipairs(t) 176 if gmt(t) ~= nil then -- t has metatable 177 return ipairs_iterator, t, 0 178 else 179 return ipairs(t) 180 end 181 end 182 end 183 184 185 -- make '*' optional for io.read and io.lines 186 do 187 local function addasterisk(fmt) 188 if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then 189 return "*"..fmt 190 else 191 return fmt 192 end 193 end 194 195 function M.io.read(...) 196 local n = select('#', ...) 197 for i = 1, n do 198 local a = select(i, ...) 199 local b = addasterisk(a) 200 -- as an optimization we only allocate a table for the 201 -- modified format arguments when we have a '*' somewhere. 202 if a ~= b then 203 local args = { ... } 204 args[i] = b 205 for j = i+1, n do 206 args[j] = addasterisk(args[j]) 207 end 208 return io_read(unpack(args, 1, n)) 209 end 210 end 211 return io_read(...) 212 end 213 214 -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! 215 function M.io.lines(...) 216 local n = select('#', ...) 217 for i = 2, n do 218 local a = select(i, ...) 219 local b = addasterisk(a) 220 -- as an optimization we only allocate a table for the 221 -- modified format arguments when we have a '*' somewhere. 222 if a ~= b then 223 local args = { ... } 224 args[i] = b 225 for j = i+1, n do 226 args[j] = addasterisk(args[j]) 227 end 228 return io_lines(unpack(args, 1, n)) 229 end 230 end 231 return io_lines(...) 232 end 233 end 234 235 236 -- update table library (if C module not available) 237 if not table_ok then 238 local table_concat = table.concat 239 local table_insert = table.insert 240 local table_remove = table.remove 241 local table_sort = table.sort 242 243 function M.table.concat(list, sep, i, j) 244 local mt = gmt(list) 245 if type(mt) == "table" and type(mt.__len) == "function" then 246 local src = list 247 list, i, j = {}, i or 1, j or mt.__len(src) 248 for k = i, j do 249 list[k] = src[k] 250 end 251 end 252 return table_concat(list, sep, i, j) 253 end 254 255 function M.table.insert(list, ...) 256 local mt = gmt(list) 257 local has_mt = type(mt) == "table" 258 local has_len = has_mt and type(mt.__len) == "function" 259 if has_mt and (has_len or mt.__index or mt.__newindex) then 260 local e = (has_len and mt.__len(list) or #list)+1 261 local nargs, pos, value = select('#', ...), ... 262 if nargs == 1 then 263 pos, value = e, pos 264 elseif nargs == 2 then 265 pos = checkinteger(pos, "2", "table.insert") 266 argcheck(1 <= pos and pos <= e, "2", "table.insert", 267 "position out of bounds" ) 268 else 269 error("wrong number of arguments to 'insert'", 0) 270 end 271 for i = e-1, pos, -1 do 272 list[i+1] = list[i] 273 end 274 list[pos] = value 275 else 276 return table_insert(list, ...) 277 end 278 end 279 280 function M.table.move(a1, f, e, t, a2) 281 a2 = a2 or a1 282 f = checkinteger(f, "2", "table.move") 283 argcheck(f > 0, "2", "table.move", 284 "initial position must be positive") 285 e = checkinteger(e, "3", "table.move") 286 t = checkinteger(t, "4", "table.move") 287 if e >= f then 288 local m, n, d = 0, e-f, 1 289 if t > f then m, n, d = n, m, -1 end 290 for i = m, n, d do 291 a2[t+i] = a1[f+i] 292 end 293 end 294 return a2 295 end 296 297 function M.table.remove(list, pos) 298 local mt = gmt(list) 299 local has_mt = type(mt) == "table" 300 local has_len = has_mt and type(mt.__len) == "function" 301 if has_mt and (has_len or mt.__index or mt.__newindex) then 302 local e = (has_len and mt.__len(list) or #list) 303 pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e 304 if pos ~= e then 305 argcheck(1 <= pos and pos <= e+1, "2", "table.remove", 306 "position out of bounds" ) 307 end 308 local result = list[pos] 309 while pos < e do 310 list[pos] = list[pos+1] 311 pos = pos + 1 312 end 313 list[pos] = nil 314 return result 315 else 316 return table_remove(list, pos) 317 end 318 end 319 320 do 321 local function pivot(list, cmp, a, b) 322 local m = b - a 323 if m > 2 then 324 local c = a + (m-m%2)/2 325 local x, y, z = list[a], list[b], list[c] 326 if not cmp(x, y) then 327 x, y, a, b = y, x, b, a 328 end 329 if not cmp(y, z) then 330 y, b = z, c 331 end 332 if not cmp(x, y) then 333 y, b = x, a 334 end 335 return b, y 336 else 337 return b, list[b] 338 end 339 end 340 341 local function lt_cmp(a, b) 342 return a < b 343 end 344 345 local function qsort(list, cmp, b, e) 346 if b < e then 347 local i, j, k, val = b, e, pivot(list, cmp, b, e) 348 while i < j do 349 while i < j and cmp(list[i], val) do 350 i = i + 1 351 end 352 while i < j and not cmp(list[j], val) do 353 j = j - 1 354 end 355 if i < j then 356 list[i], list[j] = list[j], list[i] 357 if i == k then k = j end -- update pivot position 358 i, j = i+1, j-1 359 end 360 end 361 if i ~= k and not cmp(list[i], val) then 362 list[i], list[k] = val, list[i] 363 k = i -- update pivot position 364 end 365 qsort(list, cmp, b, i == k and i-1 or i) 366 return qsort(list, cmp, i+1, e) 367 end 368 end 369 370 function M.table.sort(list, cmp) 371 local mt = gmt(list) 372 local has_mt = type(mt) == "table" 373 local has_len = has_mt and type(mt.__len) == "function" 374 if has_len then 375 cmp = cmp or lt_cmp 376 local len = mt.__len(list) 377 return qsort(list, cmp, 1, len) 378 else 379 return table_sort(list, cmp) 380 end 381 end 382 end 383 384 local function unpack_helper(list, i, j, ...) 385 if j < i then 386 return ... 387 else 388 return unpack_helper(list, i, j-1, list[j], ...) 389 end 390 end 391 function M.table.unpack(list, i, j) 392 local mt = gmt(list) 393 local has_mt = type(mt) == "table" 394 local has_len = has_mt and type(mt.__len) == "function" 395 if has_mt and (has_len or mt.__index) then 396 i, j = i or 1, j or (has_len and mt.__len(list)) or #list 397 return unpack_helper(list, i, j) 398 else 399 return unpack(list, i, j) 400 end 401 end 402 end -- update table library 403 404 405 -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 406 if lua_version == "5.1" then 407 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) 408 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" 409 local is_luajit52 = is_luajit and 410 #setmetatable({}, { __len = function() return 1 end }) == 1 411 412 -- cache globals in upvalues 413 local load, loadfile, loadstring, setfenv, xpcall = 414 load, loadfile, loadstring, setfenv, xpcall 415 local coroutine, os = coroutine, os 416 local coroutine_create = coroutine.create 417 local coroutine_resume = coroutine.resume 418 local coroutine_running = coroutine.running 419 local coroutine_status = coroutine.status 420 local coroutine_yield = coroutine.yield 421 local io_input = io.input 422 local io_open = io.open 423 local io_output = io.output 424 local io_write = io.write 425 local math_log = math.log 426 local os_execute = os.execute 427 local string_find = string.find 428 local string_format = string.format 429 local string_gmatch = string.gmatch 430 local string_gsub = string.gsub 431 local string_match = string.match 432 local string_rep = string.rep 433 local table_concat = table.concat 434 435 -- create subtables 436 M.coroutine = setmetatable({}, { __index = coroutine }) 437 M.os = setmetatable({}, { __index = os }) 438 M.package = setmetatable({}, { __index = package }) 439 440 -- handle debug functions 441 if type(debug) == "table" then 442 local debug_setfenv = debug.setfenv 443 local debug_getfenv = debug.getfenv 444 local debug_setmetatable = debug.setmetatable 445 446 M.debug = setmetatable({}, { __index = debug }) 447 448 if not is_luajit52 then 449 function M.debug.setuservalue(obj, value) 450 if type(obj) ~= "userdata" then 451 error("bad argument #1 to 'setuservalue' (userdata expected, got ".. 452 type(obj)..")", 2) 453 end 454 if value == nil then value = _G end 455 if type(value) ~= "table" then 456 error("bad argument #2 to 'setuservalue' (table expected, got ".. 457 type(value)..")", 2) 458 end 459 return debug_setfenv(obj, value) 460 end 461 462 function M.debug.getuservalue(obj) 463 if type(obj) ~= "userdata" then 464 return nil 465 else 466 local v = debug_getfenv(obj) 467 if v == _G or v == package then 468 return nil 469 end 470 return v 471 end 472 end 473 474 function M.debug.setmetatable(value, tab) 475 debug_setmetatable(value, tab) 476 return value 477 end 478 end -- not luajit with compat52 enabled 479 end -- debug table available 480 481 482 if not is_luajit52 then 483 function M.pairs(t) 484 local mt = gmt(t) 485 if type(mt) == "table" and type(mt.__pairs) == "function" then 486 return mt.__pairs(t) 487 else 488 return pairs(t) 489 end 490 end 491 end 492 493 494 if not is_luajit then 495 local function check_mode(mode, prefix) 496 local has = { text = false, binary = false } 497 for i = 1,#mode do 498 local c = mode:sub(i, i) 499 if c == "t" then has.text = true end 500 if c == "b" then has.binary = true end 501 end 502 local t = prefix:sub(1, 1) == "\27" and "binary" or "text" 503 if not has[t] then 504 return "attempt to load a "..t.." chunk (mode is '"..mode.."')" 505 end 506 end 507 508 function M.load(ld, source, mode, env) 509 mode = mode or "bt" 510 local chunk, msg 511 if type( ld ) == "string" then 512 if mode ~= "bt" then 513 local merr = check_mode(mode, ld) 514 if merr then return nil, merr end 515 end 516 chunk, msg = loadstring(ld, source) 517 else 518 local ld_type = type(ld) 519 if ld_type ~= "function" then 520 error("bad argument #1 to 'load' (function expected, got ".. 521 ld_type..")", 2) 522 end 523 if mode ~= "bt" then 524 local checked, merr = false, nil 525 local function checked_ld() 526 if checked then 527 return ld() 528 else 529 checked = true 530 local v = ld() 531 merr = check_mode(mode, v or "") 532 if merr then return nil end 533 return v 534 end 535 end 536 chunk, msg = load(checked_ld, source) 537 if merr then return nil, merr end 538 else 539 chunk, msg = load(ld, source) 540 end 541 end 542 if not chunk then 543 return chunk, msg 544 end 545 if env ~= nil then 546 setfenv(chunk, env) 547 end 548 return chunk 549 end 550 551 M.loadstring = M.load 552 553 function M.loadfile(file, mode, env) 554 mode = mode or "bt" 555 if mode ~= "bt" then 556 local f = io_open(file, "rb") 557 if f then 558 local prefix = f:read(1) 559 f:close() 560 if prefix then 561 local merr = check_mode(mode, prefix) 562 if merr then return nil, merr end 563 end 564 end 565 end 566 local chunk, msg = loadfile(file) 567 if not chunk then 568 return chunk, msg 569 end 570 if env ~= nil then 571 setfenv(chunk, env) 572 end 573 return chunk 574 end 575 end -- not luajit 576 577 578 if not is_luajit52 then 579 function M.rawlen(v) 580 local t = type(v) 581 if t ~= "string" and t ~= "table" then 582 error("bad argument #1 to 'rawlen' (table or string expected)", 2) 583 end 584 return #v 585 end 586 end 587 588 589 if not is_luajit then 590 function M.xpcall(f, msgh, ...) 591 local args, n = { ... }, select('#', ...) 592 return xpcall(function() return f(unpack(args, 1, n)) end, msgh) 593 end 594 end 595 596 597 if not is_luajit52 then 598 function M.os.execute(cmd) 599 local code = os_execute(cmd) 600 -- Lua 5.1 does not report exit by signal. 601 if code == 0 then 602 return true, "exit", code 603 else 604 if package.config:sub(1, 1) == '/' then 605 code = code/256 -- only correct on Linux! 606 end 607 return nil, "exit", code 608 end 609 end 610 end 611 612 613 if not table_ok and not is_luajit52 then 614 M.table.pack = function(...) 615 return { n = select('#', ...), ... } 616 end 617 end 618 619 620 local main_coroutine = coroutine_create(function() end) 621 622 function M.coroutine.create(func) 623 local success, result = pcall(coroutine_create, func) 624 if not success then 625 if type(func) ~= "function" then 626 error("bad argument #1 (function expected)", 0) 627 end 628 result = coroutine_create(function(...) return func(...) end) 629 end 630 return result 631 end 632 633 if not is_luajit52 then 634 function M.coroutine.running() 635 local co = coroutine_running() 636 if co then 637 return co, false 638 else 639 return main_coroutine, true 640 end 641 end 642 end 643 644 function M.coroutine.yield(...) 645 local co, flag = coroutine_running() 646 if co and not flag then 647 return coroutine_yield(...) 648 else 649 error("attempt to yield from outside a coroutine", 0) 650 end 651 end 652 653 if not is_luajit then 654 function M.coroutine.resume(co, ...) 655 if co == main_coroutine then 656 return false, "cannot resume non-suspended coroutine" 657 else 658 return coroutine_resume(co, ...) 659 end 660 end 661 662 function M.coroutine.status(co) 663 local notmain = coroutine_running() 664 if co == main_coroutine then 665 return notmain and "normal" or "running" 666 else 667 return coroutine_status(co) 668 end 669 end 670 end -- not luajit 671 672 673 if not is_luajit then 674 M.math.log = function(x, base) 675 if base ~= nil then 676 return math_log(x)/math_log(base) 677 else 678 return math_log(x) 679 end 680 end 681 end 682 683 684 if not is_luajit then 685 function M.package.searchpath(name, path, sep, rep) 686 sep = (sep or "."):gsub("(%p)", "%%%1") 687 rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") 688 local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") 689 local msg = {} 690 for subpath in path:gmatch("[^;]+") do 691 local fpath = subpath:gsub("%?", pname) 692 local f = io_open(fpath, "r") 693 if f then 694 f:close() 695 return fpath 696 end 697 msg[#msg+1] = "\n\tno file '" .. fpath .. "'" 698 end 699 return nil, table_concat(msg) 700 end 701 end 702 703 704 local function fix_pattern(pattern) 705 return (string_gsub(pattern, "%z", "%%z")) 706 end 707 708 function M.string.find(s, pattern, ...) 709 return string_find(s, fix_pattern(pattern), ...) 710 end 711 712 function M.string.gmatch(s, pattern) 713 return string_gmatch(s, fix_pattern(pattern)) 714 end 715 716 function M.string.gsub(s, pattern, ...) 717 return string_gsub(s, fix_pattern(pattern), ...) 718 end 719 720 function M.string.match(s, pattern, ...) 721 return string_match(s, fix_pattern(pattern), ...) 722 end 723 724 if not is_luajit then 725 function M.string.rep(s, n, sep) 726 if sep ~= nil and sep ~= "" and n >= 2 then 727 return s .. string_rep(sep..s, n-1) 728 else 729 return string_rep(s, n) 730 end 731 end 732 end 733 734 if not is_luajit then 735 do 736 local addqt = { 737 ["\n"] = "\\\n", 738 ["\\"] = "\\\\", 739 ["\""] = "\\\"" 740 } 741 742 local function addquoted(c, d) 743 return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d 744 end 745 746 function M.string.format(fmt, ...) 747 local args, n = { ... }, select('#', ...) 748 local i = 0 749 local function adjust_fmt(lead, mods, kind) 750 if #lead % 2 == 0 then 751 i = i + 1 752 if kind == "s" then 753 args[i] = _G.tostring(args[i]) 754 elseif kind == "q" then 755 args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' 756 return lead.."%"..mods.."s" 757 end 758 end 759 end 760 fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) 761 return string_format(fmt, unpack(args, 1, n)) 762 end 763 end 764 end 765 766 767 function M.io.write(...) 768 local res, msg, errno = io_write(...) 769 if res then 770 return io_output() 771 else 772 return nil, msg, errno 773 end 774 end 775 776 if not is_luajit then 777 local function helper(st, var_1, ...) 778 if var_1 == nil then 779 if st.doclose then st.f:close() end 780 if (...) ~= nil then 781 error((...), 2) 782 end 783 end 784 return var_1, ... 785 end 786 787 local function lines_iterator(st) 788 return helper(st, st.f:read(unpack(st, 1, st.n))) 789 end 790 791 function M.io.lines(fname, ...) 792 local doclose, file, msg 793 if fname ~= nil then 794 doclose, file, msg = true, io_open(fname, "r") 795 if not file then error(msg, 2) end 796 else 797 doclose, file = false, io_input() 798 end 799 local st = { f=file, doclose=doclose, n=select('#', ...), ... } 800 for i = 1, st.n do 801 local t = type(st[i]) 802 if t == "string" then 803 local fmt = st[i]:match("^%*?([aln])") 804 if not fmt then 805 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) 806 end 807 st[i] = "*"..fmt 808 elseif t ~= "number" then 809 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) 810 end 811 end 812 return lines_iterator, st 813 end 814 end -- not luajit 815 816 end -- lua 5.1 817 818 -- further write should be forwarded to _G 819 M_meta.__newindex = _G 820 821end -- lua < 5.3 822 823 824-- return module table 825return M 826 827-- vi: set expandtab softtabstop=3 shiftwidth=3 : 828