-- 
--  This is file `luatextra.lua',
--  generated with the docstrip utility.
-- 
--  The original source files were:
-- 
--  luatextra.dtx  (with options: `lua')
--  This is a generated file.
--  
--  Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
--  
--  This work is under the CC0 license.
--  
--  This work consists of the main source file luainputenc.dtx
--  and the derived files
--      luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf
--  
do
    local luatextrapath = kpse.find_file("luatextra.lua")
    if luatextrapath then
        if luatextrapath:sub(1,2) == "./" then
            luatextrapath = luatextrapath:sub(3)
        end
        texio.write(' ('..luatextrapath)
    end
end


luatextra = {}

module("luatextra", package.seeall)


luatextra.modules = {}

luatextra.modules['luatextra'] = {
    version     = 0.94,
    name        = "luatextra",
    date        = "2009/09/22",
    description = "Additional low level functions for LuaTeX",
    author      = "Elie Roux",
    copyright   = "Elie Roux, 2009",
    license     = "CC0",
}

local format = string.format


luatextra.internal_warning_spaces = "                   "

function luatextra.internal_warning(msg)
    if not msg then return end
    texio.write_nl(format("\nLuaTeXtra Warning: %s\n\n", msg))
end

luatextra.internal_error_spaces = "                 "

function luatextra.internal_error(msg)
    if not msg then return end
    tex.sprint(format("\\immediate\\write16{}\\errmessage{LuaTeXtra error: %s^^J^^J}", msg))
end


function luatextra.module_error(package, msg, helpmsg)
    if not package or not msg then
        return
    end
    if helpmsg then
        tex.sprint(format("\\errhelp{%s}", helpmsg))
    end
    tex.sprint(format("\\luatexModuleError{%s}{%s}", package, msg))
end

function luatextra.module_warning(modulename, msg)
    if not modulename or not msg then
        return
    end
    texio.write_nl(format("\nModule %s Warning: %s\n\n", modulename, msg))
end

function luatextra.module_log(modulename, msg)
    if not modulename or not msg then
        return
    end
    texio.write_nl('log', format("%s: %s", modulename, msg))
end

function luatextra.module_term(modulename, msg)
    if not modulename or not msg then
        return
    end
    texio.write_nl('term', format("%s: %s", modulename, msg))
end

function luatextra.module_info(modulename, msg)
    if not modulename or not msg then
        return
    end
    texio.write_nl(format("%s: %s\n", modulename, msg))
end


function luatextra.find_module_file(name)
    if string.sub(name, -4) ~= '.lua' then
        name = name..'.lua'
    end
    path = kpse.find_file(name, 'tex')
    if not path then
      path = kpse.find_file(name, 'texmfscripts')
    end
    return path, name
end


luatextra.module = module


function luatextra.use_module(name)
    if not name or luatextra.modules[name] then
        return
    end
    local path, filename = luatextra.find_module_file(name)
    if not path then
        luatextra.internal_error(format("unable to find lua module %s", name))
    else
        if path:sub(1,2) == "./" then
            path = path:sub(3)
        end
        texio.write(' ('..path)
        dofile(path)
        if not luatextra.modules[name] then
            luatextra.internal_warning(format("You have requested module `%s',\n%s but the file %s does not provide it.", name, luatextra.internal_warning_spaces, filename))
        end
        if not package.loaded[name] then
            luatextra.module(name, package.seeall)
        end
        texio.write(')')
    end
end


function luatextra.datetonumber(date)
    numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
    return tonumber(numbers)
end

function luatextra.isdate(date)
    for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
        return true
    end
    return false
end

local date, number = 1, 2

function luatextra.versiontonumber(version)
    if luatextra.isdate(version) then
        return {type = date, version = luatextra.datetonumber(version), orig = version}
    else
        return {type = number, version = tonumber(version), orig = version}
    end
end

luatextra.requiredversions = {}


function luatextra.require_module(name, version)
    if not name then
        return
    end
    if not version then
        return luatextra.use_module(name)
    end
    luaversion = luatextra.versiontonumber(version)
    if luatextra.modules[name] then
        if luaversion.type == date then
            if luatextra.datetonumber(luatextra.modules[name].date) < luaversion.version then
                luatextra.internal_error(format("found module `%s' loaded in version %s, but version %s was required", name, luatextra.modules[name].date, version))
            end
        else
            if luatextra.modules[name].version < luaversion.version then
                luatextra.internal_error(format("found module `%s' loaded in version %.02f, but version %s was required", name, luatextra.modules[name].version, version))
            end
        end
    else
        luatextra.requiredversions[name] = luaversion
        luatextra.use_module(name)
    end
end


function luatextra.provides_module(mod)
    if not mod then
        luatextra.internal_error('cannot provide nil module')
        return
    end
    if not mod.version or not mod.name or not mod.date or not mod.description then
        luatextra.internal_error('invalid module registered, fields name, version, date and description are mandatory')
        return
    end
    requiredversion = luatextra.requiredversions[mod.name]
    if requiredversion then
        if requiredversion.type == date and requiredversion.version > luatextra.datetonumber(mod.date) then
            luatextra.internal_error(format("loading module %s in version %s, but version %s was required", mod.name, mod.date, requiredversion.orig))
        elseif requiredversion.type == number and requiredversion.version > mod.version then
            luatextra.internal_error(format("loading module %s in version %.02f, but version %s was required", mod.name, mod.version, requiredversion.orig))
        end
    end
    luatextra.modules[mod.name] = module
    texio.write_nl('log', format("Lua module: %s %s v%.02f %s\n", mod.name, mod.date, mod.version, mod.description))
end


luatextra.use_module('luaextra')


function luatextra.kpse_module_loader(mod)
  local file = luatextra.find_module_file(mod)
  if file then
    local loader, error = loadfile(file)
    if loader then
      texio.write_nl("(" .. file .. ")")
      return loader
    end
    return "\n\t[luatextra.kpse_module_loader] Loading error:\n\t"
           .. error
  end
  return "\n\t[luatextra.kpse_module_loader] Search failed"
end

table.insert(package.loaders, luatextra.kpse_module_loader)


luatextra.attributes = {}

tex.attributenumber = luatextra.attributes

function luatextra.attributedef_from_tex(name, number)
    truename = name:gsub('[\\ ]', '')
    luatextra.attributes[truename] = tonumber(number)
end


luatextra.catcodetables = {}

tex.catcodetablenumber = luatextra.catcodetables

function luatextra.catcodetabledef_from_tex(name, number)
    truename = name:gsub('[\\ ]', '')
    luatextra.catcodetables[truename] = tonumber(number)
end


function luatextra.open_read_file(filename)
    local path = kpse.find_file(filename)
    local env = {
      ['filename'] = filename,
      ['path'] = path,
    }
    luamcallbacks.call('pre_read_file', env)
    path = env.path
    if not path then
        return
    end
    local f = env.file
    if not f then
        f = io.open(path)
        env.file = f
    end
    if not f then
        return
    end
    env.reader = luatextra.reader
    env.close = luatextra.close
    return env
end


function luatextra.reader(env)
    local line = (env.file):read()
    line = luamcallbacks.call('file_reader', env, line)
    return line
end

function luatextra.close(env)
    (env.file):close()
    luamcallbacks.call('file_close', env)
end


function luatextra.default_reader(env, line)
    return line
end

function luatextra.default_close(env)
    return
end

function luatextra.default_pre_read(env)
    return env
end


do
  if tex.luatexversion < 36 then
      fontloader = fontforge
  end
end

function luatextra.find_font(name)
    local types = {'ofm', 'ovf', 'opentype fonts', 'truetype fonts'}
    local path = kpse.find_file(name)
    if path then return path end
    for _,t in pairs(types) do
        path = kpse.find_file(name, t)
        if path then return path end
    end
    return nil
end

function luatextra.font_load_error(error)
    luatextra.module_warning('luatextra', string.format('%s\nloading lmr10 instead...', error))
end

function luatextra.load_default_font(size)
    return font.read_tfm("lmr10", size)
end

function luatextra.define_font(name, size)
    if (size < 0) then size = (- 655.36) * size end
    local fontinfos = {
        asked_name = name,
        name = name,
        size = size
        }
    callback.call('font_syntax', fontinfos)
    name = fontinfos.name
    local path = fontinfos.path
    if not path then
        path = luatextra.find_font(name)
        fontinfos.path = luatextra.find_font(name)
    end
    if not path then
        luatextra.font_load_error("unable to find font "..name)
        return luatextra.load_default_font(size)
    end
    if not fontinfos.filename then
        fontinfos.filename = fpath.basename(path)
    end
    local ext = fpath.suffix(path)
    local f
    if ext == 'tfm' or ext == 'ofm' then
        f =  font.read_tfm(name, size)
    elseif ext == 'vf' or ext == 'ovf' then
        f =  font.read_vf(name, size)
    elseif ext == 'ttf' or ext == 'otf' or ext == 'ttc' then
        f = callback.call('open_otf_font', fontinfos)
    else
        luatextra.font_load_error("unable to determine the type of font "..name)
        f = luatextra.load_default_font(size)
    end
    if not f then
        luatextra.font_load_error("unable to load font "..name)
        f = luatextra.load_default_font(size)
    end
    callback.call('post_font_opening', f, fontinfos)
    return f
end

function luatextra.default_font_syntax(fontinfos)
    return
end

function luatextra.default_open_otf(fontinfos)
    return nil
end

function luatextra.default_post_font(f, fontinfos)
    return true
end

function luatextra.register_font_callback()
    callback.add('define_font', luatextra.define_font, 'luatextra.define_font')
end

do
    luatextra.use_module('luamcallbacks')
    callback.create('pre_read_file', 'simple', luatextra.default_pre_read)
    callback.create('file_reader', 'data', luatextra.default_reader)
    callback.create('file_close', 'simple', luatextra.default_close)
    callback.add('open_read_file', luatextra.open_read_file, 'luatextra.open_read_file')
    callback.create('font_syntax', 'simple', luatextra.default_font_syntax)
    callback.create('open_otf_font', 'first', luatextra.default_open_otf)
    callback.create('post_font_opening', 'simple', luatextra.default_post_font)

    if luatextrapath then
        texio.write(')')
    end
end
-- 
--  End of File `luatextra.lua'.
