-- Virtual file system facilities for Lunatic

local ffi = require("ffi")
local C = ffi.C

local decl = require("lprivate").decl

local assert = assert
local error = error
local type = type

----------

decl[[
int32_t pathsearchmode;

typedef struct _CACHE1D_FIND_REC {
	char *name;
	int32_t type, source;
	struct _CACHE1D_FIND_REC *next, *prev, *usera, *userb;
} CACHE1D_FIND_REC;

void klistfree(CACHE1D_FIND_REC *rec);
CACHE1D_FIND_REC *klistpath(const char *path, const char *mask, int32_t type);
]]


-- The API table
local fs = {}

local CACHE1D = ffi.new[[
struct {
	static const int FIND_FILE = 1;
	static const int FIND_DIR = 2;
	static const int FIND_DRIVE = 4;

	static const int OPT_NOSTACK = 0x100;

	// the lower the number, the higher the priority
	static const int SOURCE_DRIVE = 0;
	static const int SOURCE_CURDIR = 1;
	static const int SOURCE_PATH = 2;  // + path stack depth
	static const int SOURCE_ZIP = 0x7ffffffe;
	static const int SOURCE_GRP = 0x7fffffff;
}
]]

-- files = fs.listpath(path, mask)
-- TODO: filter by 'source' (path, zip and/or grp)
-- TODO: directories too, so that one can list them recursively, for example
function fs.listpath(path, mask)
    if (path ~= nil and type(path)~="string") then
        error("Invalid argument #1: must be nil or a string", 2)
    end

    if (type(mask) ~= "string") then
        error("Invalid argument #2: must be a string", 2)
    end

    local opsm = C.pathsearchmode
    C.pathsearchmode = 0
    local rootrec = C.klistpath(path, mask, CACHE1D.FIND_FILE)
    C.pathsearchmode = opsm

    if (rootrec == nil) then
        -- TODO: discern?
        error("out of memory or failed listing path")
    end

    local files = {}

    local rec = rootrec
    while (rec ~= nil) do
        assert(rec.name ~= nil)
        files[#files+1] = ffi.string(rec.name)
        rec = rec.next
    end

    C.klistfree(rootrec)

    return files
end

return fs
