if not modules then modules = { } end modules ['luat-iop'] = {
    version   = 1.001,
    comment   = "companion to luat-lib.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- this paranoid stuff in web2c ... we cannot hook checks into the
-- input functions because one can always change the callback but
-- we can feed back specific patterns and paths into the next
-- mechanism

local lower, find, sub = string.lower, string.find, string.sub

local allocate = utilities.storage.allocate

local ioinp = io.inp if not ioinp then ioinp = { } io.inp = ioinp end
local ioout = io.out if not ioout then ioout = { } io.out = ioout end

ioinp.modes, ioout.modes = allocate(), allocate()

local inp_blocked, inp_permitted = { }, { }
local out_blocked, out_permitted = { }, { }

local function i_inhibit(name) inp_blocked  [#inp_blocked  +1] = name end
local function o_inhibit(name) out_blocked  [#out_blocked  +1] = name end
local function i_permit (name) inp_permitted[#inp_permitted+1] = name end
local function o_permit (name) out_permitted[#out_permitted+1] = name end

ioinp.inhibit, ioinp.permit = i_inhibit, o_permit
ioout.inhibit, ioout.permit = o_inhibit, o_permit

local blockedopeners = { } -- *.open(name,method)

function io.registeropener(func)
    blockedopeners[#blockedopeners+1] = func
end

local function checked(name,blocked,permitted)
    local n = lower(name)
    for _,b in next, blocked do
        if find(n,b) then
            for _,p in next, permitted do
                if find(n,p) then
                    return true
                end
            end
            return false
        end
    end
    return true
end

function io.finalizeopeners(func)
    if #out_blocked > 0 or #inp_blocked > 0 then
        local open = func -- why not directly?
        return function(name,method)
            if method and find(method,'[wa]') then
                if #out_blocked > 0 and not checked(name,out_blocked,out_permitted) then
                    -- print("writing to " .. name .. " is not permitted")
                    return nil
                end
            else
                if #inp_blocked > 0 and not checked(name,inp_blocked,inp_permitted) then
                    -- print("reading from " .. name .. " is not permitted")
                    return nil
                end
            end
            return open(name,method)
        end
    else
        return func
    end
end

--~ io.inp.inhibit('^%.')
--~ io.inp.inhibit('^/etc')
--~ io.inp.inhibit('/windows/')
--~ io.inp.inhibit('/winnt/')
--~ io.inp.permit('c:/windows/wmsetup.log')

--~ io.open = io.finalizeopeners(io.open)

--~ f = io.open('.tex')                   print(f)
--~ f = io.open('tufte.tex')              print(f)
--~ f = io.open('t:/sources/tufte.tex')   print(f)
--~ f = io.open('/etc/passwd')            print(f)
--~ f = io.open('c:/windows/crap.log')    print(f)
--~ f = io.open('c:/windows/wmsetup.log') print(f)

-- restricted

function ioinp.modes.restricted()
    i_inhibit('^%.[%a]')
end

function ioout.modes.restricted()
    o_inhibit('^%.[%a]')
end

-- paranoid

function ioinp.modes.paranoid()
    i_inhibit('.*')
    i_inhibit('%.%.')
    i_permit('^%./')
    i_permit('[^/]')
    resolvers.dowithpath('TEXMF',i_permit)
end

function ioout.modes.paranoid()
    o_inhibit('.*')
    resolvers.dowithpath('TEXMFOUTPUT',o_permit)
end

-- handy

function ioinp.modes.handy()
    i_inhibit('%.%.')
    if os.type == 'windows' then
        i_inhibit('/windows/')
        i_inhibit('/winnt/')
    else
        i_inhibit('^/etc')
    end
end

function ioout.modes.handy()
    o_inhibit('.*')
    o_permit('%./')
    o_permit('^%./')
    o_permit('[^/]')
end

local input_mode   directives.register("system.inputmode",  function(v) input_mode  = v end)
local output_mode  directives.register("system.outputmode", function(v) output_mode = v end)

function io.checkopeners()
    local inp = input_mode  or resolvers.variable("input_mode")  -- or ... will become obsolete
    local out = output_mode or resolvers.variable("output_mode") -- or ... will become obsolete
    inp = inp and ioinp.modes[inp]
    out = out and ioinp.modes[out]
    if inp then inp() end
    if out then out() end
end

--~ io.checkopeners()
