summaryrefslogtreecommitdiff
path: root/luatexbase-mcb.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'luatexbase-mcb.dtx')
-rw-r--r--luatexbase-mcb.dtx837
1 files changed, 837 insertions, 0 deletions
diff --git a/luatexbase-mcb.dtx b/luatexbase-mcb.dtx
new file mode 100644
index 0000000..11c2a44
--- /dev/null
+++ b/luatexbase-mcb.dtx
@@ -0,0 +1,837 @@
+% \iffalse meta-comment
+%
+% Written in 2009, 2010 by Manuel Pégourié-Gonnard and Élie Roux.
+% <mpg@elzevir.fr>
+% <elie.roux@telecom-bretagne.eu>
+%
+% This work is under the CC0 license.
+%
+% This work consists of the main source file luatexbase-mcb.dtx
+% and the derived files
+% luatexbase-mcb.sty, mcb.lua, luatexbase-mcb.pdf,
+% test-mcb-plain.tex test-mcb-latex.tex
+%
+% Unpacking:
+% tex luatexbase-mcb.dtx
+% Documentation:
+% pdflatex luatexbase-mcb.dtx
+%
+%<*ignore>
+\begingroup
+ \def\x{LaTeX2e}%
+\expandafter\endgroup
+\ifcase 0\ifx\install y1\fi\expandafter
+ \ifx\csname processbatchFile\endcsname\relax\else1\fi
+ \ifx\fmtname\x\else 1\fi\relax
+\else\csname fi\endcsname
+%</ignore>
+%<*install>
+\input docstrip.tex
+
+\keepsilent
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+
+\preamble
+
+Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+
+This work is under the CC0 license.
+See source file '\inFileName' for details.
+
+\endpreamble
+
+\let\MetaPrefix\DoubleperCent
+
+\generate{%
+ \usedir{tex/luatex/luatexbase}%
+ \file{luatexbase-mcb.sty}{\from{luatexbase-mcb.dtx}{texpackage}}%
+}
+
+\generate{%
+ \usedir{doc/luatex/luatexbase}%
+ \file{test-mcb-plain.tex}{\from{luatexbase-mcb.dtx}{testplain}}%
+ \file{test-mcb-latex.tex}{\from{luatexbase-mcb.dtx}{testlatex}}%
+}
+
+\def\MetaPrefix{-- }
+
+\def\luapostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+
+\def\currentpostamble{\luapostamble}%
+
+\generate{%
+ \usedir{tex/luatex/luatexbase}%
+ \file{mcb.lua}{\from{luatexbase-mcb.dtx}{lua}}%
+}
+
+\obeyspaces
+\Msg{************************************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the following}
+\Msg{* files into a directory searched by TeX:}
+\Msg{*}
+\Msg{* luatexbase-mcb.sty mcb.lua}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*}
+\Msg{************************************************************************}
+
+\endbatchfile
+%</install>
+%<*ignore>
+\fi
+%</ignore>
+%<*driver>
+\documentclass{ltxdoc}
+\input{lltxb-dtxstyle}
+\begin{document}
+ \DocInput{luatexbase-mcb.dtx}%
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{0}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+% \title{The \textsf{luatexbase-mcb} package}
+% \date{2009/09/18 v0.93}
+% \author{%
+% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
+% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% This package manages the callback adding and removing, by adding
+% \texttt{callback.add} and \texttt{callback.remove}, and overwriting
+% \texttt{callback.register}. It also allows to create and call new callbacks.
+% For an introduction on this package (among others), please refer to the
+% document \texttt{luatextra-reference.pdf}.
+% \par\textbf{Warning.} Currently assumes that \textsf{luatexbase-modutils}
+% has been previously loaded. (This is a temporary limitation.)
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Documentation}
+%
+% Lua\TeX\ provides an extremely interesting feature, named callbacks. It
+% allows to call some lua functions at some points of the \TeX\ algorithm (a
+% \emph{callback}), like when \TeX\ breaks likes, puts vertical spaces, etc.
+% The Lua\TeX\ core offers a function called \texttt{callback.register} that
+% enables to register a function in a callback.
+%
+% The problem with \texttt{callback.register} is that is registers only one
+% function in a callback. For a lot of callbacks it can be common to have
+% several packages registering their function in a callback, and thus it is
+% impossible with them to be compatible with each other.
+%
+% This package solves this problem by adding mainly one new function
+% \texttt{callback.\\add} that adds a function in a callback. With this
+% function it is possible for packages to register their function in a
+% callback without overwriting the functions of the other packages.
+%
+% The functions are called in a certain order, and when a package registers a
+% callback it can assign a priority to its function. Conflicts can still
+% remain even with the priority mechanism, for example in the case where two
+% packages want to have the highest priority. In these cases the packages have
+% to solve the conflicts themselves.
+%
+% This package also privides a way to create and call new callbacks, in
+% addition to the default Lua\TeX\ callbacks.
+%
+% \subsubsection*{Limitations}
+%
+% This package only works for callbacks where it's safe to add multiple
+% functions without changing the functions' signatures. There are callbacks,
+% though, where registering several functions is not possible without changing
+% the function's signatures, like for example the readers callbacks. These
+% callbacks take a filename and give the datas in it. One solution would be to
+% change the functions' signature to open it when the function is the first,
+% and to take the datas and modify them eventually if they are called after
+% the first. But it seems rather fragile and useless, so it's not implemented.
+% With these callbacks, in this package we simply execute the first function
+% in the list.
+%
+% Other callbacks in this case are \texttt{define\_font} and
+% \texttt{open\_read\_file}. There is though a solution for several packages
+% to use these callbacks, see the implementation of \texttt{luatextra}.
+%
+% \section{Implementation}
+%
+% \subsection{\tex package}
+%
+% \begin{macrocode}
+%<*texpackage>
+% \end{macrocode}
+%
+% \subsubsection{Preliminaries}
+%
+% Reload protection, especially for \plaintex.
+%
+% \begin{macrocode}
+ \csname lltxb@mcb@loaded\endcsname
+\expandafter\let\csname lltxb@mcb@loaded\endcsname\endinput
+% \end{macrocode}
+%
+% Catcode defenses.
+%
+% \begin{macrocode}
+\begingroup
+ \catcode123 1 % {
+ \catcode125 2 % }
+ \catcode 35 6 % #
+ \toks0{}%
+ \def\x{}%
+ \def\y#1 #2 {%
+ \toks0\expandafter{\the\toks0 \catcode#1 \the\catcode#1}%
+ \edef\x{\x \catcode#1 #2}}%
+ \y 123 1 % {
+ \y 125 2 % }
+ \y 35 6 % #
+ \y 10 12 % ^^J
+ \y 34 12 % "
+ \y 36 3 % $ $
+ \y 39 12 % '
+ \y 40 12 % (
+ \y 41 12 % )
+ \y 42 12 % *
+ \y 43 12 % +
+ \y 44 12 % ,
+ \y 45 12 % -
+ \y 46 12 % .
+ \y 47 12 % /
+ \y 60 12 % <
+ \y 61 12 % =
+ \y 64 11 % @ (letter)
+ \y 62 12 % >
+ \y 95 12 % _ (other)
+ \y 96 12 % `
+ \edef\y#1{\endgroup\edef#1{\the\toks0\relax}\x}%
+\expandafter\y\csname lltxb@mcb@AtEnd\endcsname
+% \end{macrocode}
+%
+% Package declaration.
+%
+% \begin{macrocode}
+\begingroup
+ \expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \def\x#1[#2]{\immediate\write16{Package: #1 #2}}
+ \else
+ \let\x\ProvidesPackage
+ \fi
+\expandafter\endgroup
+\x{luatexbase-mcb}[2010/09/11 v0.93 Callback management for LuaTeX]
+% \end{macrocode}
+%
+% Make sure \luatex is used.
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname RequirePackage\endcsname\relax
+ \input ifluatex.sty
+\else
+ \RequirePackage{ifluatex}
+\fi
+\ifluatex\else
+ \begingroup
+ \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
+ \def\x#1#2{\begingroup\newlinechar10
+ \immediate\write16{Package #1 warning: #2}\endgroup}
+ \else
+ \let\x\PackageWarningNoLine
+ \fi
+ \expandafter\endgroup
+ \x{luatexbase-mcb}{LuaTeX is required for this package. Aborting.}
+ \lltxb@mcb@AtEnd
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \subsubsection{Load supporting Lua module}
+%
+% First load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), then
+% the supporting Lua module.
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname RequirePackage\endcsname\relax
+ \input luatexbase-modutils.sty
+\else
+ \RequirePackage{luatexbase-modutils}
+\fi
+\luatexbase@directlua{require('luatexbase.mcb')}
+% \end{macrocode}
+%
+% That's all folks!
+%
+% \begin{macrocode}
+\lltxb@mcb@AtEnd
+%</texpackage>
+% \end{macrocode}
+%
+% \subsection{Lua module}
+%
+% \begin{macrocode}
+%<*lua>
+% \end{macrocode}
+%
+% \subsubsection{Module identification}
+%
+% \begin{macrocode}
+module('luatexbase', package.seeall)
+luatexbase.provides_module({
+ name = "luamcallbacks",
+ version = 0.93,
+ date = "2009/09/18",
+ description = "register several functions in a callback",
+ author = "Hans Hagen, Elie Roux and Manuel Pégourie-Gonnard",
+ copyright = "Hans Hagen, Elie Roux and Manuel Pégourie-Gonnard",
+ license = "CC0",
+})
+% \end{macrocode}
+%
+% Shortcuts for error functions.
+%
+% \begin{macrocode}
+local log = log or function(...)
+ luatexbase.module_log('luamcallbacks', string.format(...))
+end
+local info = info or function(...)
+ luatexbase.module_info('luamcallbacks', string.format(...))
+end
+local warning = warning or function(...)
+ luatexbase.module_warning('luamcallbacks', string.format(...))
+end
+local err = err or function(...)
+ luatexbase.module_error('luamcallbacks', string.format(...))
+end
+% \end{macrocode}
+%
+% \subsubsection{Initialisations}
+%
+% \texttt{callbacklist} is the main list, that contains the callbacks as
+% keys and a table of the registered functions a values.
+%
+% \begin{macrocode}
+local callbacklist = callbacklist or { }
+% \end{macrocode}
+%
+% A table with the default functions of the created callbacks. See
+% \texttt{create} for further informations.
+%
+% \begin{macrocode}
+local lua_callbacks_defaults = { }
+% \end{macrocode}
+%
+% There are 4 types of callback:
+% \begin{itemize}
+% \item the ones taking a list of nodes and returning a boolean and
+% eventually a new head (\texttt{list})
+% \item the ones taking datas and returning the modified ones
+% (\texttt{data})
+% \item the ones that can't have multiple functions registered in them
+% (\texttt{first})
+% \item the ones for functions that don't return anything (\texttt{simple})
+% \end{itemize}
+%
+% \begin{macrocode}
+local list = 1
+local data = 2
+local first = 3
+local simple = 4
+% \end{macrocode}
+%
+% \texttt{callbacktypes} is the list that contains the callbacks as keys
+% and the type (list or data) as values.
+%
+% \begin{macrocode}
+local callbacktypes = callbacktypes or {
+ buildpage_filter = simple,
+ token_filter = first,
+ pre_output_filter = list,
+ hpack_filter = list,
+ process_input_buffer = data,
+ mlist_to_hlist = list,
+ vpack_filter = list,
+ define_font = first,
+ open_read_file = first,
+ linebreak_filter = list,
+ post_linebreak_filter = list,
+ pre_linebreak_filter = list,
+ start_page_number = simple,
+ stop_page_number = simple,
+ start_run = simple,
+ show_error_hook = simple,
+ stop_run = simple,
+ hyphenate = simple,
+ ligaturing = simple,
+ kerning = data,
+ find_write_file = first,
+ find_read_file = first,
+ find_vf_file = data,
+ find_map_file = data,
+ find_format_file = data,
+ find_opentype_file = data,
+ find_output_file = data,
+ find_truetype_file = data,
+ find_type1_file = data,
+ find_data_file = data,
+ find_pk_file = data,
+ find_font_file = data,
+ find_image_file = data,
+ find_ocp_file = data,
+ find_sfd_file = data,
+ find_enc_file = data,
+ read_sfd_file = first,
+ read_map_file = first,
+ read_pk_file = first,
+ read_enc_file = first,
+ read_vf_file = first,
+ read_ocp_file = first,
+ read_opentype_file = first,
+ read_truetype_file = first,
+ read_font_file = first,
+ read_type1_file = first,
+ read_data_file = first,
+}
+% \end{macrocode}
+%
+% In Lua\TeX\ version 0.43, a new callback called |process_output_buffer|
+% appeared, so we enable it. Test the version using the compat package for,
+% well, compatibility.
+%
+% \begin{macrocode}
+if luatexbase.luatexversion > 42 then
+ callbacktypes["process_output_buffer"] = data
+end
+% \end{macrocode}
+%
+% As we overwrite \texttt{callback.register}, we save it as
+% \texttt{internalregister}.
+%
+% \begin{macrocode}
+local internalregister = internalregister or callback.register
+% \end{macrocode}
+%
+% \subsubsection{Unsorted stuff}
+%
+% A simple function we'll use later to understand the arguments of the
+% \texttt{create} function. It takes a string and returns the type
+% corresponding to the string or nil.
+%
+% \begin{macrocode}
+local function str_to_type(str)
+ if str == 'list' then
+ return list
+ elseif str == 'data' then
+ return data
+ elseif str == 'first' then
+ return first
+ elseif str == 'simple' then
+ return simple
+ else
+ return nil
+ end
+end
+% \end{macrocode}
+%
+% This function and the following ones are only internal. This one is the
+% handler for the first type of callbacks: the ones that take a list head
+% and return true, false, or a new list head.
+%
+% \begin{macrocode}
+-- local
+function listhandler (name)
+ return function(head,...)
+ local l = callbacklist[name]
+ if l then
+ local done = true
+ for _, f in ipairs(l) do
+ -- the returned value is either true or a new head plus true
+ rtv1, rtv2 = f.func(head,...)
+ if type(rtv1) == 'boolean' then
+ done = rtv1
+ elseif type (rtv1) == 'userdata' then
+ head = rtv1
+ end
+ if type(rtv2) == 'boolean' then
+ done = rtv2
+ elseif type(rtv2) == 'userdata' then
+ head = rtv2
+ end
+ if done == false then
+ err("function \"%s\" returned false in callback '%s'",
+ f.description, name)
+ end
+ end
+ return head, done
+ else
+ return head, false
+ end
+ end
+end
+% \end{macrocode}
+%
+% The handler for callbacks taking datas and returning modified ones.
+%
+% \begin{macrocode}
+local function datahandler (name)
+ return function(data,...)
+ local l = callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ data = f.func(data,...)
+ end
+ end
+ return data
+ end
+end
+% \end{macrocode}
+%
+% This function is for the handlers that don't support more than one
+% functions in them. In this case we only call the first function of the
+% list.
+%
+% \begin{macrocode}
+local function firsthandler (name)
+ return function(...)
+ local l = callbacklist[name]
+ if l then
+ local f = l[1].func
+ return f(...)
+ else
+ return nil, false
+ end
+ end
+end
+% \end{macrocode}
+%
+% Handler for simple functions that don't return anything.
+%
+% \begin{macrocode}
+local function simplehandler (name)
+ return function(...)
+ local l = callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ f.func(...)
+ end
+ end
+ end
+end
+% \end{macrocode}
+%
+% \subsubsection{Public functions}
+%
+% The main function. The signature is \texttt{add (name,
+% func, description, priority)} with \texttt{name} being the name of the
+% callback in which the function is added; \texttt{func} is the added
+% function; \texttt{description} is a small character string describing the
+% function, and \texttt{priority} an optional argument describing the
+% priority the function will have.
+%
+% The functions for a callbacks are added in a list (in
+% \texttt{callbacklist\\.callbackname}). If they have no
+% priority or a high priority number, they will be added at the end of the
+% list, and will be called after the others. If they have a low priority
+% number, the will be added at the beginning of the list and will be called
+% before the others.
+%
+% Something that must be made clear, is that there is absolutely no
+% solution for packages conflicts: if two packages want the top priority on
+% a certain callback, they will have to decide the priority they will give
+% to their function themselves. Most of the time, the priority is not needed.
+%
+% \begin{macrocode}
+function add_to_callback (name,func,description,priority)
+ if type(func) ~= "function" then
+ err("unable to add function, no proper function passed")
+ return
+ end
+ if not name or name == "" then
+ err("unable to add function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ err("unable to add function, '%s' is not a valid callback", name)
+ return
+ end
+ if not description or description == "" then
+ err("unable to add function to '%s', no proper description passed",
+ name)
+ return
+ end
+ if priority_in_callback(name, description) ~= 0 then
+ warning("function '%s' already registered in callback '%s'",
+ description, name)
+ end
+ local l = callbacklist[name]
+ if not l then
+ l = {}
+ callbacklist[name] = l
+ if not lua_callbacks_defaults[name] then
+ if callbacktypes[name] == list then
+ internalregister(name, listhandler(name))
+ elseif callbacktypes[name] == data then
+ internalregister(name, datahandler(name))
+ elseif callbacktypes[name] == simple then
+ internalregister(name, simplehandler(name))
+ elseif callbacktypes[name] == first then
+ internalregister(name, firsthandler(name))
+ else
+ err("unknown callback type")
+ end
+ end
+ end
+ local f = {
+ func = func,
+ description = description,
+ }
+ priority = tonumber(priority)
+ if not priority or priority > #l then
+ priority = #l+1
+ elseif priority < 1 then
+ priority = 1
+ end
+ if callbacktypes[name] == first and (priority ~= 1 or #l ~= 0) then
+ warning("several callbacks registered in callback '%s', "
+ .."only the first function will be active.", name)
+ end
+ table.insert(l,priority,f)
+ log("inserting function '%s' at position %s in callback list for '%s'",
+ description, priority, name)
+end
+% \end{macrocode}
+%
+% The function that removes a function from a callback. The signature is
+% \texttt{remove (name, description)} with \texttt{name} being
+% the name of callbacks, and description the description passed to
+% \texttt{add}.
+%
+% \begin{macrocode}
+function remove_from_callback (name, description)
+ if not name or name == "" then
+ err("unable to remove function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ err("unable to remove function, '%s' is not a valid callback", name)
+ return
+ end
+ if not description or description == "" then
+ err(
+ "unable to remove function from '%s', no proper description passed",
+ name)
+ return
+ end
+ local l = callbacklist[name]
+ if not l then
+ err("no callback list for '%s'",name)
+ return
+ end
+ for k,v in ipairs(l) do
+ if v.description == description then
+ table.remove(l,k)
+ log("removing function '%s' from '%s'",description,name)
+ if not next(l) then
+ callbacklist[name] = nil
+ if not lua_callbacks_defaults[name] then
+ internalregister(name, nil)
+ end
+ end
+ return
+ end
+ end
+ warning("unable to remove function '%s' from '%s'",description,name)
+end
+% \end{macrocode}
+%
+% This function removes all the functions registered in a callback.
+%
+% \begin{macrocode}
+function reset_callback (name)
+ if not name or name == "" then
+ err("unable to reset, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ err("reset error, '%s' is not a valid callback", name)
+ return
+ end
+ if not lua_callbacks_defaults[name] then
+ internalregister(name, nil)
+ end
+ local l = callbacklist[name]
+ if l then
+ log("resetting callback list '%s'",name)
+ callbacklist[name] = nil
+ end
+end
+% \end{macrocode}
+%
+% This first function creates a new callback. The signature is
+% \texttt{create(name, ctype, default)} where \texttt{name} is the name of
+% the new callback to create, \texttt{ctype} is the type of callback, and
+% \texttt{default} is the default function to call if no function is
+% registered in this callback.
+%
+% The created callback will behave the same way Lua\TeX\ callbacks do, you
+% can add and remove functions in it. The difference is that the callback
+% is not automatically called, the package developer creating a new
+% callback must also call it, see next function.
+%
+% \begin{macrocode}
+function create_callback(name, ctype, default)
+ if not name then
+ err("unable to call callback, no proper name passed", name)
+ return nil
+ end
+ if not ctype or not default then
+ err("unable to create callback '%s': "
+ .."callbacktype or default function not specified", name)
+ return nil
+ end
+ if callbacktypes[name] then
+ err("unable to create callback '%s', callback already exists", name)
+ return nil
+ end
+ local temp = str_to_type(ctype)
+ if not temp then
+ err("unable to create callback '%s', type '%s' undefined", name, ctype)
+ return nil
+ end
+ ctype = temp
+ lua_callbacks_defaults[name] = default
+ callbacktypes[name] = ctype
+end
+% \end{macrocode}
+%
+% This function calls a callback. It can only call a callback created by
+% the \texttt{create} function.
+%
+% \begin{macrocode}
+function call_callback(name, ...)
+ if not name then
+ err("unable to call callback, no proper name passed", name)
+ return nil
+ end
+ if not lua_callbacks_defaults[name] then
+ err("unable to call lua callback '%s', unknown callback", name)
+ return nil
+ end
+ local l = callbacklist[name]
+ local f
+ if not l then
+ f = lua_callbacks_defaults[name]
+ else
+ if callbacktypes[name] == list then
+ f = listhandler(name)
+ elseif callbacktypes[name] == data then
+ f = datahandler(name)
+ elseif callbacktypes[name] == simple then
+ f = simplehandler(name)
+ elseif callbacktypes[name] == first then
+ f = firsthandler(name)
+ else
+ err("unknown callback type")
+ end
+ end
+ return f(...)
+end
+% \end{macrocode}
+%
+% This function tells if a function has already been registered in a
+% callback, and gives its current priority. The arguments are the name of
+% the callback and the description of the function. If it has already been
+% registered, it gives its priority, and if not it returns false.
+%
+% \begin{macrocode}
+function priority_in_callback (name, description)
+ if not name or name == ""
+ or not callbacktypes[name]
+ or not description then
+ return 0
+ end
+ local l = callbacklist[name]
+ if not l then return 0 end
+ for p, f in pairs(l) do
+ if f.description == description then
+ return p
+ end
+ end
+ return 0
+end
+% \end{macrocode}
+%
+% Finally we
+% overwrite \texttt{callback.register} so that it outputs an error.
+%
+% \begin{macrocode}
+callback.register = function ()
+err("function callback.register has been deleted by luamcallbacks, "
+.."please use callback.add instead.")
+end
+% \end{macrocode}
+%
+% That's all folks!
+%
+% \begin{macrocode}
+%</lua>
+% \end{macrocode}
+%
+% \section{Test files}
+%
+% A few basic tests for Plain and LaTeX.
+%
+% \begin{macrocode}
+%<testplain>\input luatexbase-mcb.sty
+%<testlatex>\RequirePackage{luatexbase-mcb}
+%<*testplain,testlatex>
+\catcode 64 11
+\luatexbase@directlua{
+ local function one(head,...)
+ texio.write_nl("I'm number 1")
+ return head, true
+ end
+
+ local function two(head,...)
+ texio.write_nl("I'm number 2")
+ return head, true
+ end
+
+ local function three(head,...)
+ texio.write_nl("I'm number 3")
+ return head, true
+ end
+
+ luatexbase.add_to_callback("hpack_filter",one,"my sample function one",1)
+ luatexbase.add_to_callback("hpack_filter",two,"my sample function two",2)
+ luatexbase.add_to_callback("hpack_filter",three,"my sample function three",1)
+
+ luatexbase.remove_from_callback("hpack_filter","my sample function three")
+}
+%</testplain,testlatex>
+%<testplain>\bye
+%<testlatex>\stop
+% \end{macrocode}
+%
+% \Finale
+\endinput