summaryrefslogtreecommitdiff
path: root/require.lua
blob: 4b4accf3d0d86ded7cbc32b8b85974eaa2122620 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
local bit, ffi = bit, ffi
if require then ffi = require("ffi") end

ffi.cdef [[
    void *fopen (const char *fname, const char *mode);
    int   fseek (void *f, long offset, int origin);
    long  ftell (void *f);
    int   fclose(void *f);
    size_t fread(void *ptr, size_t size, size_t count, void *f);
    char *strerror(int errnum);
    extern int errno;
    char *strchr (char *str, int ch);
    char *strrchr(char *str, int ch);
    void *memcpy(void *dest, const void *src, size_t n);
]]

local C = ffi.C

local loaded  = { ["ffi"] = ffi, ["bit"] = bit }
local loader = function(modname)
    local fname = ffi.new("char[?]", #modname + 5, modname)
    local p = C.strchr(fname, 46)
    while p ~= nil do
        p[0] = 47
        p = C.strchr(p, 46)
    end
    C.memcpy(fname + #modname, ".lua", 5)
    local f = C.fopen(fname, "rb")
    if f == nil then return ffi.string(C.strerror(C.errno)) end
    C.fseek(f, 0, 2) -- end
    local l = C.ftell(f)
    C.fseek(f, 0, 0) -- beg
    local buf = ffi.new("char[?]", l)
    C.fread(buf, 1, l, f)
    local cont = ffi.string(buf, l)
    C.fclose(f)
    local slash = C.strrchr(fname, 47)
    if slash ~= nil then fname = slash + 1 end
    fname = ffi.string(fname)
    f, err = load(cont, "@" .. fname)
    if not f then error("error loading module '" .. modname
        .. "' from file '" .. fname .. "':\n" .. err, 2)
    end
    return f
end

local find_loader = function(modname)
    local err = "module '" .. modname .. "' not found\n"
    local v = loader(modname)
    if type(v) == "function" then
        return v
    elseif type(v) == "string" then
        err = err .. v
    end
    return nil, err
end

require = function(modname)
    local v = loaded[modname]
    if v ~= nil then return v end
    local  loader, err = find_loader(modname)
    if not loader then error(err, 2) end
    local ret = loader(modname)
    if ret ~= nil then
        loaded[modname] = ret
        return ret
    elseif loaded[modname] == nil then
        loaded[modname] = true
        return true
    end
    return loaded[modname]
end