-- -- This is file `ltluatex.lua', -- generated with the docstrip utility. -- -- The original source files were: -- -- ltluatex.dtx (with options: `lua') -- -- This is a generated file. -- -- The source is maintained by the LaTeX Project team and bug -- reports for it can be opened at https://latex-project.org/bugs.html -- (but please observe conditions on bug reports sent to that address!) -- -- -- Copyright (C) 2015-2022 -- The LaTeX Project and any individual authors listed elsewhere -- in this file. -- -- This file was generated from file(s) of the LaTeX base system. -- -------------------------------------------------------------- -- -- It may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3c -- of this license or (at your option) any later version. -- The latest version of this license is in -- https://www.latex-project.org/lppl.txt -- and version 1.3c or later is part of all distributions of LaTeX -- version 2008 or later. -- -- This file has the LPPL maintenance status "maintained". -- -- This file may only be distributed together with a copy of the LaTeX -- base system. You may however distribute the LaTeX base system without -- such generated files. -- -- The list of all files belonging to the LaTeX base distribution is -- given in the file `manifest.txt'. See also `legal.txt' for additional -- information. -- -- The list of derived (unpacked) files belonging to the distribution -- and covered by LPPL is defined by the unpacking scripts (with -- extension .ins) which are part of the distribution. luatexbase = luatexbase or { } local luatexbase = luatexbase local string_gsub = string.gsub local tex_count = tex.count local tex_setattribute = tex.setattribute local tex_setcount = tex.setcount local texio_write_nl = texio.write_nl local flush_list = node.flush_list local luatexbase_warning local luatexbase_error local modules = modules or { } local function luatexbase_log(text) texio_write_nl("log", text) end local function provides_module(info) if not (info and info.name) then luatexbase_error("Missing module name for provides_module") end local function spaced(text) return text and (" " .. text) or "" end luatexbase_log( "Lua module: " .. info.name .. spaced(info.date) .. spaced(info.version) .. spaced(info.description) ) modules[info.name] = info end luatexbase.provides_module = provides_module local function msg_format(mod, msg_type, text) local leader = "" local cont local first_head if mod == "LaTeX" then cont = string_gsub(leader, ".", " ") first_head = leader .. "LaTeX: " else first_head = leader .. "Module " .. msg_type cont = "(" .. mod .. ")" .. string_gsub(first_head, ".", " ") first_head = leader .. "Module " .. mod .. " " .. msg_type .. ":" end if msg_type == "Error" then first_head = "\n" .. first_head end if string.sub(text,-1) ~= "\n" then text = text .. " " end return first_head .. " " .. string_gsub( text .. "on input line " .. tex.inputlineno, "\n", "\n" .. cont .. " " ) .. "\n" end local function module_info(mod, text) texio_write_nl("log", msg_format(mod, "Info", text)) end luatexbase.module_info = module_info local function module_warning(mod, text) texio_write_nl("term and log",msg_format(mod, "Warning", text)) end luatexbase.module_warning = module_warning local function module_error(mod, text) error(msg_format(mod, "Error", text)) end luatexbase.module_error = module_error function luatexbase_warning(text) module_warning("luatexbase", text) end function luatexbase_error(text) module_error("luatexbase", text) end local luaregisterbasetable = { } local registermap = { attributezero = "assign_attr" , charzero = "char_given" , CountZero = "assign_int" , dimenzero = "assign_dimen" , mathcharzero = "math_given" , muskipzero = "assign_mu_skip" , skipzero = "assign_skip" , tokszero = "assign_toks" , } local createtoken if tex.luatexversion > 81 then createtoken = token.create elseif tex.luatexversion > 79 then createtoken = newtoken.create end local hashtokens = tex.hashtokens() local luatexversion = tex.luatexversion for i,j in pairs (registermap) do if luatexversion < 80 then luaregisterbasetable[hashtokens[i][1]] = hashtokens[i][2] else luaregisterbasetable[j] = createtoken(i).mode end end local registernumber if luatexversion < 80 then function registernumber(name) local nt = hashtokens[name] if(nt and luaregisterbasetable[nt[1]]) then return nt[2] - luaregisterbasetable[nt[1]] else return false end end else function registernumber(name) local nt = createtoken(name) if(luaregisterbasetable[nt.cmdname]) then return nt.mode - luaregisterbasetable[nt.cmdname] else return false end end end luatexbase.registernumber = registernumber local attributes=setmetatable( {}, { __index = function(t,key) return registernumber(key) or nil end} ) luatexbase.attributes = attributes local attribute_count_name = attribute_count_name or "e@alloc@attribute@count" local function new_attribute(name) tex_setcount("global", attribute_count_name, tex_count[attribute_count_name] + 1) if tex_count[attribute_count_name] > 65534 then luatexbase_error("No room for a new \\attribute") end attributes[name]= tex_count[attribute_count_name] luatexbase_log("Lua-only attribute " .. name .. " = " .. tex_count[attribute_count_name]) return tex_count[attribute_count_name] end luatexbase.new_attribute = new_attribute local whatsit_count_name = whatsit_count_name or "e@alloc@whatsit@count" local function new_whatsit(name) tex_setcount("global", whatsit_count_name, tex_count[whatsit_count_name] + 1) if tex_count[whatsit_count_name] > 65534 then luatexbase_error("No room for a new custom whatsit") end luatexbase_log("Custom whatsit " .. (name or "") .. " = " .. tex_count[whatsit_count_name]) return tex_count[whatsit_count_name] end luatexbase.new_whatsit = new_whatsit local bytecode_count_name = bytecode_count_name or "e@alloc@bytecode@count" local function new_bytecode(name) tex_setcount("global", bytecode_count_name, tex_count[bytecode_count_name] + 1) if tex_count[bytecode_count_name] > 65534 then luatexbase_error("No room for a new bytecode register") end luatexbase_log("Lua bytecode " .. (name or "") .. " = " .. tex_count[bytecode_count_name]) return tex_count[bytecode_count_name] end luatexbase.new_bytecode = new_bytecode local chunkname_count_name = chunkname_count_name or "e@alloc@luachunk@count" local function new_chunkname(name) tex_setcount("global", chunkname_count_name, tex_count[chunkname_count_name] + 1) local chunkname_count = tex_count[chunkname_count_name] chunkname_count = chunkname_count + 1 if chunkname_count > 65534 then luatexbase_error("No room for a new chunkname") end lua.name[chunkname_count]=name luatexbase_log("Lua chunkname " .. (name or "") .. " = " .. chunkname_count .. "\n") return chunkname_count end luatexbase.new_chunkname = new_chunkname local luafunction_count_name = luafunction_count_name or "e@alloc@luafunction@count" local function new_luafunction(name) tex_setcount("global", luafunction_count_name, tex_count[luafunction_count_name] + 1) if tex_count[luafunction_count_name] > 65534 then luatexbase_error("No room for a new luafunction register") end luatexbase_log("Lua function " .. (name or "") .. " = " .. tex_count[luafunction_count_name]) return tex_count[luafunction_count_name] end luatexbase.new_luafunction = new_luafunction local callbacklist = callbacklist or { } local list, data, exclusive, simple, reverselist = 1, 2, 3, 4, 5 local types = { list = list, data = data, exclusive = exclusive, simple = simple, reverselist = reverselist, } local callbacktypes = callbacktypes or { find_read_file = exclusive, find_write_file = exclusive, find_font_file = data, find_output_file = data, find_format_file = data, find_vf_file = data, find_map_file = data, find_enc_file = data, find_pk_file = data, find_data_file = data, find_opentype_file = data, find_truetype_file = data, find_type1_file = data, find_image_file = data, open_read_file = exclusive, read_font_file = exclusive, read_vf_file = exclusive, read_map_file = exclusive, read_enc_file = exclusive, read_pk_file = exclusive, read_data_file = exclusive, read_truetype_file = exclusive, read_type1_file = exclusive, read_opentype_file = exclusive, find_cidmap_file = data, read_cidmap_file = exclusive, process_input_buffer = data, process_output_buffer = data, process_jobname = data, contribute_filter = simple, buildpage_filter = simple, build_page_insert = exclusive, pre_linebreak_filter = list, linebreak_filter = exclusive, append_to_vlist_filter = exclusive, post_linebreak_filter = reverselist, hpack_filter = list, vpack_filter = list, hpack_quality = exclusive, vpack_quality = exclusive, pre_output_filter = list, process_rule = exclusive, hyphenate = simple, ligaturing = simple, kerning = simple, insert_local_par = simple, pre_mlist_to_hlist_filter = list, mlist_to_hlist = exclusive, post_mlist_to_hlist_filter = reverselist, new_graf = exclusive, pre_dump = simple, start_run = simple, stop_run = simple, start_page_number = simple, stop_page_number = simple, show_error_hook = simple, show_warning_message = simple, show_error_message = simple, show_lua_error_hook = simple, start_file = simple, stop_file = simple, call_edit = simple, finish_synctex = simple, wrapup_run = simple, finish_pdffile = data, finish_pdfpage = data, page_objnum_provider = data, page_order_index = data, process_pdf_image_content = data, define_font = exclusive, glyph_info = exclusive, glyph_not_found = exclusive, glyph_stream_provider = exclusive, make_extensible = exclusive, font_descriptor_objnum_provider = exclusive, input_level_string = exclusive, provide_charproc_data = exclusive, } luatexbase.callbacktypes=callbacktypes local callback_register = callback_register or callback.register function callback.register() luatexbase_error("Attempt to use callback.register() directly\n") end local function data_handler(name) return function(data, ...) for _,i in ipairs(callbacklist[name]) do data = i.func(data,...) end return data end end local function data_handler_default(value) return value end local function exclusive_handler(name) return function(...) return callbacklist[name][1].func(...) end end local function list_handler(name) return function(head, ...) local ret for _,i in ipairs(callbacklist[name]) do ret = i.func(head, ...) if ret == false then luatexbase_warning( "Function `" .. i.description .. "' returned false\n" .. "in callback `" .. name .."'" ) return false end if ret ~= true then head = ret end end return head end end local function list_handler_default(head) return head end local function reverselist_handler(name) return function(head, ...) local ret local callbacks = callbacklist[name] for i = #callbacks, 1, -1 do local cb = callbacks[i] ret = cb.func(head, ...) if ret == false then luatexbase_warning( "Function `" .. cb.description .. "' returned false\n" .. "in callback `" .. name .."'" ) return false end if ret ~= true then head = ret end end return head end end local function simple_handler(name) return function(...) for _,i in ipairs(callbacklist[name]) do i.func(...) end end end local function simple_handler_default() end local handlers = { [data] = data_handler, [exclusive] = exclusive_handler, [list] = list_handler, [reverselist] = reverselist_handler, [simple] = simple_handler, } local defaults = { [data] = data_handler_default, [exclusive] = nil, [list] = list_handler_default, [reverselist] = list_handler_default, [simple] = simple_handler_default, } local user_callbacks_defaults = { pre_mlist_to_hlist_filter = list_handler_default, mlist_to_hlist = node.mlist_to_hlist, post_mlist_to_hlist_filter = list_handler_default, } local function create_callback(name, ctype, default) local ctype_id = types[ctype] if not name or name == "" or not ctype_id then luatexbase_error("Unable to create callback:\n" .. "valid callback name and type required") end if callbacktypes[name] then luatexbase_error("Unable to create callback `" .. name .. "':\ncallback is already defined") end default = default or defaults[ctype_id] if not default then luatexbase_error("Unable to create callback `" .. name .. "':\ndefault is required for `" .. ctype .. "' callbacks") elseif type (default) ~= "function" then luatexbase_error("Unable to create callback `" .. name .. "':\ndefault is not a function") end user_callbacks_defaults[name] = default callbacktypes[name] = ctype_id end luatexbase.create_callback = create_callback local function call_callback(name,...) if not name or name == "" then luatexbase_error("Unable to create callback:\n" .. "valid callback name required") end if user_callbacks_defaults[name] == nil then luatexbase_error("Unable to call callback `" .. name .. "':\nunknown or empty") end local l = callbacklist[name] local f if not l then f = user_callbacks_defaults[name] else f = handlers[callbacktypes[name]](name) end return f(...) end luatexbase.call_callback=call_callback local function add_to_callback(name, func, description) if not name or name == "" then luatexbase_error("Unable to register callback:\n" .. "valid callback name required") end if not callbacktypes[name] or type(func) ~= "function" or not description or description == "" then luatexbase_error( "Unable to register callback.\n\n" .. "Correct usage:\n" .. "add_to_callback(, , )" ) end local l = callbacklist[name] if l == nil then l = { } callbacklist[name] = l if user_callbacks_defaults[name] == nil then callback_register(name, handlers[callbacktypes[name]](name)) end end local f = { func = func, description = description, } local priority = #l + 1 if callbacktypes[name] == exclusive then if #l == 1 then luatexbase_error( "Cannot add second callback to exclusive function\n`" .. name .. "'") end end table.insert(l, priority, f) luatexbase_log( "Inserting `" .. description .. "' at position " .. priority .. " in `" .. name .. "'." ) end luatexbase.add_to_callback = add_to_callback local function remove_from_callback(name, description) if not name or name == "" then luatexbase_error("Unable to remove function from callback:\n" .. "valid callback name required") end if not callbacktypes[name] or not description or description == "" then luatexbase_error( "Unable to remove function from callback.\n\n" .. "Correct usage:\n" .. "remove_from_callback(, )" ) end local l = callbacklist[name] if not l then luatexbase_error( "No callback list for `" .. name .. "'\n") end local index = false for i,j in ipairs(l) do if j.description == description then index = i break end end if not index then luatexbase_error( "No callback `" .. description .. "' registered for `" .. name .. "'\n") end local cb = l[index] table.remove(l, index) luatexbase_log( "Removing `" .. description .. "' from `" .. name .. "'." ) if #l == 0 then callbacklist[name] = nil if user_callbacks_defaults[name] == nil then callback_register(name, nil) end end return cb.func,cb.description end luatexbase.remove_from_callback = remove_from_callback local function in_callback(name, description) if not name or name == "" or not callbacklist[name] or not callbacktypes[name] or not description then return false end for _, i in pairs(callbacklist[name]) do if i.description == description then return true end end return false end luatexbase.in_callback = in_callback local function disable_callback(name) if(callbacklist[name] == nil) then callback_register(name, false) else luatexbase_error("Callback list for " .. name .. " not empty") end end luatexbase.disable_callback = disable_callback local function callback_descriptions (name) local d = {} if not name or name == "" or not callbacklist[name] or not callbacktypes[name] then return d else for k, i in pairs(callbacklist[name]) do d[k]= i.description end end return d end luatexbase.callback_descriptions =callback_descriptions local function uninstall() module_info( "luatexbase", "Uninstalling kernel luatexbase code" ) callback.register = callback_register luatexbase = nil end luatexbase.uninstall = uninstall callback_register("mlist_to_hlist", function(head, display_type, need_penalties) local current = call_callback("pre_mlist_to_hlist_filter", head, display_type, need_penalties) if current == false then flush_list(head) return nil end current = call_callback("mlist_to_hlist", current, display_type, need_penalties) local post = call_callback("post_mlist_to_hlist_filter", current, display_type, need_penalties) if post == false then flush_list(current) return nil end return post end)