aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2024-08-29 17:16:49 -0300
committerGitHub <noreply@github.com>2024-08-29 17:16:49 -0300
commit7a82c38437075cb2beb2fe7c6453aa91e019d6b7 (patch)
tree4b77c7e02eb1e6e5f2b875f7a5947b4fdf23c0f5
parent1c679a282bf1255cddfbb6b3e8c5c72d9ebe57e8 (diff)
downloadlua-compat-5.3-7a82c38437075cb2beb2fe7c6453aa91e019d6b7.tar.gz
lua-compat-5.3-7a82c38437075cb2beb2fe7c6453aa91e019d6b7.tar.bz2
lua-compat-5.3-7a82c38437075cb2beb2fe7c6453aa91e019d6b7.zip
adjust file metatables even in compat53.module mode (#67)
* adjust file metatables even in compat53.module mode * apply tweaks only to LuaJIT; file:write() only to compat=none
-rw-r--r--compat53/file_mt.lua71
-rw-r--r--compat53/init.lua62
-rw-r--r--compat53/module.lua66
-rw-r--r--liolib.c2
-rw-r--r--rockspecs/compat53-scm-0.rockspec1
-rwxr-xr-xtests/test.lua23
6 files changed, 160 insertions, 65 deletions
diff --git a/compat53/file_mt.lua b/compat53/file_mt.lua
new file mode 100644
index 0000000..6433619
--- /dev/null
+++ b/compat53/file_mt.lua
@@ -0,0 +1,71 @@
1local lua_version = _VERSION:sub(-3)
2
3local M = {}
4
5local unpack = lua_version == "5.1" and unpack or table.unpack
6
7local function addasterisk(fmt)
8 if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then
9 return "*"..fmt
10 else
11 return fmt
12 end
13end
14
15function M.update_file_meta(file_meta, is_luajit52)
16
17 -- make '*' optional for file:read and file:lines
18
19 local file_lines = file_meta.__index.lines
20 file_meta.__index.lines = function(self, ...)
21 local n = select('#', ...)
22 for i = 1, n do
23 local a = select(i, ...)
24 local b = addasterisk(a)
25 -- as an optimization we only allocate a table for the
26 -- modified format arguments when we have a '*' somewhere
27 if a ~= b then
28 local args = { ... }
29 args[i] = b
30 for j = i+1, n do
31 args[j] = addasterisk(args[j])
32 end
33 return file_lines(self, unpack(args, 1, n))
34 end
35 end
36 return file_lines(self, ...)
37 end
38
39 local file_read = file_meta.__index.read
40 file_meta.__index.read = function(self, ...)
41 local n = select('#', ...)
42 for i = 1, n do
43 local a = select(i, ...)
44 local b = addasterisk(a)
45 -- as an optimization we only allocate a table for the
46 -- modified format arguments when we have a '*' somewhere
47 if a ~= b then
48 local args = { ... }
49 args[i] = b
50 for j = i+1, n do
51 args[j] = addasterisk(args[j])
52 end
53 return file_read(self, unpack(args, 1, n))
54 end
55 end
56 return file_read(self, ...)
57 end
58
59 if not is_luajit52 then
60 local file_write = file_meta.__index.write
61 file_meta.__index.write = function(self, ...)
62 local ret, err = file_write(self, ...)
63 if ret then
64 return self
65 end
66 return ret, err
67 end
68 end
69end
70
71return M
diff --git a/compat53/init.lua b/compat53/init.lua
index a7f0c80..b507571 100644
--- a/compat53/init.lua
+++ b/compat53/init.lua
@@ -17,57 +17,15 @@ if lua_version < "5.3" then
17 local file_meta = gmt(io.stdout) 17 local file_meta = gmt(io.stdout)
18 18
19 19
20 -- make '*' optional for file:read and file:lines 20 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
21 if type(file_meta) == "table" and type(file_meta.__index) == "table" then 21 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
22 22 local is_luajit52 = is_luajit and
23 local function addasterisk(fmt) 23 #setmetatable({}, { __len = function() return 1 end }) == 1
24 if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then
25 return "*"..fmt
26 else
27 return fmt
28 end
29 end
30
31 local file_lines = file_meta.__index.lines
32 file_meta.__index.lines = function(self, ...)
33 local n = select('#', ...)
34 for i = 1, n do
35 local a = select(i, ...)
36 local b = addasterisk(a)
37 -- as an optimization we only allocate a table for the
38 -- modified format arguments when we have a '*' somewhere
39 if a ~= b then
40 local args = { ... }
41 args[i] = b
42 for j = i+1, n do
43 args[j] = addasterisk(args[j])
44 end
45 return file_lines(self, unpack(args, 1, n))
46 end
47 end
48 return file_lines(self, ...)
49 end
50 24
51 local file_read = file_meta.__index.read
52 file_meta.__index.read = function(self, ...)
53 local n = select('#', ...)
54 for i = 1, n do
55 local a = select(i, ...)
56 local b = addasterisk(a)
57 -- as an optimization we only allocate a table for the
58 -- modified format arguments when we have a '*' somewhere
59 if a ~= b then
60 local args = { ... }
61 args[i] = b
62 for j = i+1, n do
63 args[j] = addasterisk(args[j])
64 end
65 return file_read(self, unpack(args, 1, n))
66 end
67 end
68 return file_read(self, ...)
69 end
70 25
26 if type(file_meta) == "table" and type(file_meta.__index) == "table" then
27 local file_mt = require("compat53.file_mt")
28 file_mt.update_file_meta(file_meta, is_luajit52)
71 end -- got a valid metatable for file objects 29 end -- got a valid metatable for file objects
72 30
73 31
@@ -85,12 +43,6 @@ if lua_version < "5.3" then
85 local io_type = io.type 43 local io_type = io.type
86 44
87 45
88 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
89 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
90 local is_luajit52 = is_luajit and
91 #setmetatable({}, { __len = function() return 1 end }) == 1
92
93
94 -- make package.searchers available as an alias for package.loaders 46 -- make package.searchers available as an alias for package.loaders
95 local p_index = { searchers = package.loaders } 47 local p_index = { searchers = package.loaders }
96 setmetatable(package, { 48 setmetatable(package, {
diff --git a/compat53/module.lua b/compat53/module.lua
index 67b2a4a..90b2f06 100644
--- a/compat53/module.lua
+++ b/compat53/module.lua
@@ -13,7 +13,11 @@ if lua_version < "5.3" then
13 debug, io, math, package, string, table 13 debug, io, math, package, string, table
14 local io_lines = io.lines 14 local io_lines = io.lines
15 local io_read = io.read 15 local io_read = io.read
16 local io_open = io.open
17 local io_popen = io.popen
18 local io_tmpfile = io.tmpfile
16 local unpack = lua_version == "5.1" and unpack or table.unpack 19 local unpack = lua_version == "5.1" and unpack or table.unpack
20 local debug_setmetatable = type(debug) == "table" and debug.setmetatable
17 21
18 -- create module table 22 -- create module table
19 M = {} 23 M = {}
@@ -451,7 +455,6 @@ if lua_version < "5.3" then
451 if type(debug) == "table" then 455 if type(debug) == "table" then
452 local debug_setfenv = debug.setfenv 456 local debug_setfenv = debug.setfenv
453 local debug_getfenv = debug.getfenv 457 local debug_getfenv = debug.getfenv
454 local debug_setmetatable = debug.setmetatable
455 458
456 M.debug = setmetatable({}, { __index = debug }) 459 M.debug = setmetatable({}, { __index = debug })
457 460
@@ -823,6 +826,67 @@ if lua_version < "5.3" then
823 end 826 end
824 end -- not luajit 827 end -- not luajit
825 828
829 if is_luajit then
830 local compat_file_meta = {}
831 local compat_file_meta_loaded = false
832
833 local function load_compat_file_meta(file_meta)
834 -- fill compat_file_meta with original entries
835 for k, v in pairs(file_meta) do
836 compat_file_meta[k] = v
837 end
838 compat_file_meta.__index = {}
839 for k, v in pairs(file_meta.__index) do
840 compat_file_meta.__index[k] = v
841 end
842
843 -- update it with compatibility functions
844 local file_mt = require("compat53.file_mt")
845 file_mt.update_file_meta(compat_file_meta, is_luajit52)
846
847 compat_file_meta_loaded = true
848 end
849
850 function M.io.open(...)
851 local fd, err = io_open(...)
852 if fd and debug_setmetatable then
853 if not compat_file_meta_loaded then
854 local file_meta = gmt(fd)
855 load_compat_file_meta(file_meta)
856 end
857 debug_setmetatable(fd, compat_file_meta)
858 end
859
860 return fd, err
861 end
862
863 function M.io.popen(...)
864 local fd, err = io_popen(...)
865 if fd and debug_setmetatable then
866 if not compat_file_meta_loaded then
867 local file_meta = gmt(fd)
868 load_compat_file_meta(file_meta)
869 end
870 debug_setmetatable(fd, compat_file_meta)
871 end
872
873 return fd, err
874 end
875
876 function M.io.tmpfile(...)
877 local fd, err = io_tmpfile(...)
878 if fd and debug_setmetatable then
879 if not compat_file_meta_loaded then
880 local file_meta = gmt(fd)
881 load_compat_file_meta(file_meta)
882 end
883 debug_setmetatable(fd, compat_file_meta)
884 end
885
886 return fd, err
887 end
888 end
889
826 end -- lua 5.1 890 end -- lua 5.1
827 891
828 -- further write should be forwarded to _G 892 -- further write should be forwarded to _G
diff --git a/liolib.c b/liolib.c
index 8a9e75c..7f425c1 100644
--- a/liolib.c
+++ b/liolib.c
@@ -142,7 +142,7 @@ static int l_checkmode (const char *mode) {
142typedef luaL_Stream LStream; 142typedef luaL_Stream LStream;
143 143
144 144
145#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) 145#define tolstream(L) (luaL_checktype(L, 1, LUA_TUSERDATA), (LStream *)lua_touserdata(L, 1))
146 146
147#define isclosed(p) ((p)->closef == NULL) 147#define isclosed(p) ((p)->closef == NULL)
148 148
diff --git a/rockspecs/compat53-scm-0.rockspec b/rockspecs/compat53-scm-0.rockspec
index e0820d4..702036b 100644
--- a/rockspecs/compat53-scm-0.rockspec
+++ b/rockspecs/compat53-scm-0.rockspec
@@ -24,6 +24,7 @@ build = {
24 modules = { 24 modules = {
25 ["compat53.init"] = "compat53/init.lua", 25 ["compat53.init"] = "compat53/init.lua",
26 ["compat53.module"] = "compat53/module.lua", 26 ["compat53.module"] = "compat53/module.lua",
27 ["compat53.file_mt"] = "compat53/file_mt.lua",
27 ["compat53.utf8"] = "lutf8lib.c", 28 ["compat53.utf8"] = "lutf8lib.c",
28 ["compat53.table"] = "ltablib.c", 29 ["compat53.table"] = "ltablib.c",
29 ["compat53.string"] = "lstrlib.c", 30 ["compat53.string"] = "lstrlib.c",
diff --git a/tests/test.lua b/tests/test.lua
index ddc00fe..503e3f4 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -36,6 +36,8 @@ end
36local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") 36local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2")
37if jit then V = "jit" end 37if jit then V = "jit" end
38 38
39local is_puclua51 = (_VERSION == "Lua 5.1" and not jit)
40
39local mode = "global" 41local mode = "global"
40if arg[1] == "module" then 42if arg[1] == "module" then
41 mode = "module" 43 mode = "module"
@@ -576,7 +578,7 @@ ___''
576do 578do
577 print("io.write()", io.type(io.write("hello world\n"))) 579 print("io.write()", io.type(io.write("hello world\n")))
578 local f = assert(io.tmpfile()) 580 local f = assert(io.tmpfile())
579 print("file:write()", io.type(f:write("hello world\n"))) 581 print("io.tmpfile => file:write()", io.type(f:write("hello world\n")))
580 f:close() 582 f:close()
581end 583end
582 584
@@ -589,13 +591,18 @@ do
589 io.input("data.txt") 591 io.input("data.txt")
590 print("io.read()", io.read("n", "number", "l", "a")) 592 print("io.read()", io.read("n", "number", "l", "a"))
591 io.input(io.stdin) 593 io.input(io.stdin)
592 if mode ~= "module" then 594 if not is_puclua51 then
593 local f = assert(io.open("data.txt", "r")) 595 local f = assert(io.open("data.txt", "r"))
594 print("file:read()", f:read("*n", "*number", "*l", "*a")) 596 print("file:read()", f:read("*n", "*number", "*l", "*a"))
595 f:close() 597 f:close()
596 f = assert(io.open("data.txt", "r")) 598 f = assert(io.open("data.txt", "r"))
597 print("file:read()", f:read("n", "number", "l", "a")) 599 print("file:read()", f:read("n", "number", "l", "a"))
598 f:close() 600 f:close()
601 os.remove("data.txt")
602
603 local g = assert(io.open("data.txt", "w"))
604 print("io.open => file:write()", type(g:write("hello")))
605 g:close()
599 end 606 end
600 os.remove("data.txt") 607 os.remove("data.txt")
601end 608end