summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/luatex/luatexbase
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-11-18 00:35:41 +0000
committerKarl Berry <karl@freefriends.org>2010-11-18 00:35:41 +0000
commit75a9ad6b597ca31c07f38850761832951b0f6224 (patch)
treed09aa23cca95f7ea69dfbd5f2683ec1869f9d0aa /Master/texmf-dist/source/luatex/luatexbase
parente1353b47437cbc7c93c601670ce39cc2bfede42d (diff)
luatexbase (17nov10)
git-svn-id: svn://tug.org/texlive/trunk@20476 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/luatex/luatexbase')
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/Makefile25
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-attr.dtx21
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-cctb.dtx48
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-compat.dtx21
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-loader.dtx21
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-mcb.dtx984
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx469
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-regs.dtx23
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase.dtx55
9 files changed, 1015 insertions, 652 deletions
diff --git a/Master/texmf-dist/source/luatex/luatexbase/Makefile b/Master/texmf-dist/source/luatex/luatexbase/Makefile
index 0b854b07500..03784a546cd 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/Makefile
+++ b/Master/texmf-dist/source/luatex/luatexbase/Makefile
@@ -7,20 +7,21 @@ DTXSTY = lltxb-dtxstyle.tex
# Files grouped by generation mode
UNPACKED_MCB = luatexbase-mcb.sty mcb.lua \
- test-mcb-latex.tex test-mcb-plain.tex
+ test-mcb-latex.tex test-mcb-plain.tex \
+ test-mcb.lua $(TEST_MCB)
UNPACKED_REGS = luatexbase-regs.sty \
- test-regs-plain.tex test-regs-latex.tex
+ test-regs-plain.tex test-regs-latex.tex
UNPACKED_ATTR = luatexbase-attr.sty attr.lua \
- test-attr-plain.tex test-attr-latex.tex
+ test-attr-plain.tex test-attr-latex.tex
UNPACKED_CCTB = luatexbase-cctb.sty cctb.lua \
- test-cctb-plain.tex test-cctb-latex.tex
+ test-cctb-plain.tex test-cctb-latex.tex
UNPACKED_LOADER = luatexbase-loader.sty luatexbase.loader.lua \
- test-loader-plain.tex test-loader-latex.tex \
- $(TEST_LOADER).lua test-loader.sub.lua
+ test-loader-plain.tex test-loader-latex.tex \
+ $(TEST_LOADER).lua test-loader.sub.lua
UNPACKED_MODUTILS = luatexbase-modutils.sty modutils.lua test-modutils.lua \
- test-modutils-plain.tex test-modutils-latex.tex
+ test-modutils-plain.tex test-modutils-latex.tex
UNPACKED_COMPAT = luatexbase-compat.sty \
- test-compat-plain.tex test-compat-latex.tex
+ test-compat-plain.tex test-compat-latex.tex
UNPACKED_BASE = luatexbase.sty test-base-plain.tex test-base-latex.tex
UNPACKED = $(UNPACKED_MCB) $(UNPACKED_REGS) $(UNPACKED_ATTR) $(UNPACKED_CCTB) \
$(UNPACKED_LOADER) $(UNPACKED_MODUTILS) $(UNPACKED_COMPAT) \
@@ -32,6 +33,7 @@ SOURCE = $(DTX) $(DTXSTY) README TODO Changes Makefile
# used for check
TEST_LOADER = test-loader
TMP_LOADER = $(TEST_LOADER).tex
+TEST_MCB = test-mcb-aux.tex
# Files grouped by installation location
RUNFILES = $(filter-out test-%, $(UNPACKED))
@@ -60,7 +62,7 @@ TDS_ZIP = $(NAME).tds.zip
ZIPS = $(CTAN_ZIP) $(TDS_ZIP)
DO_TEX = tex --interaction=batchmode $< >/dev/null
-DO_LATEXMK = latexmk -silent $< >/dev/null
+DO_LATEXMK = latexmk -pdf -silent $< >/dev/null
# Main targets definition
all: $(GENERATED)
@@ -80,6 +82,7 @@ luatexbase.%.lua: %.lua
$(UNPACKED_MCB): luatexbase-mcb.dtx
$(DO_TEX)
+ echo \\\\relax > $(TEST_MCB)
$(UNPACKED_REGS): luatexbase-regs.dtx
$(DO_TEX)
@@ -123,7 +126,7 @@ check-modutils: install-runfiles
$(TESTENV) luatex --interaction=batchmode test-modutils-plain.tex >/dev/null
$(TESTENV) lualatex --interaction=batchmode test-modutils-latex.tex >/dev/null
-check-mcb: install-runfiles
+check-mcb: install-runfiles $(UNPACKED_MCB)
$(TESTENV) luatex --interaction=batchmode test-mcb-plain.tex >/dev/null
$(TESTENV) lualatex --interaction=batchmode test-mcb-latex.tex >/dev/null
@@ -170,7 +173,7 @@ manifest:
clean:
@latexmk -silent -c *.dtx >/dev/null
- @# for tex-only runs
+ @#for non-latexmk runs
@$(RM) -- *.log
mrproper: clean
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-attr.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-attr.dtx
index 5847daec422..d377f7c619f 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-attr.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-attr.dtx
@@ -113,11 +113,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-attr} package}
-% \date{v0.2a 2010-05-27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-attr}{v0.3 2010-05-27}
%
% \maketitle
%
@@ -238,7 +234,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-attr}[2010/05/27 v0.2a Attributes allocation for LuaTeX]
+\x{luatexbase-attr}[2010/10/10 v0.3 Attributes allocation for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -252,14 +248,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@attr@AtEnd
\expandafter\endinput
\fi
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-cctb.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-cctb.dtx
index 4b7b8c64231..c60cdc0c709 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-cctb.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-cctb.dtx
@@ -113,11 +113,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-cctb} package}
-% \date{v0.2a 2010-05-27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \texttt{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-cctb}{v0.3 2010-05-27}
%
% \maketitle
%
@@ -246,7 +242,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-cctb}[2010/05/27 v0.2a Catcodetable allocation for LuaTeX]
+\x{luatexbase-cctb}[2010/10/10 v0.3 Catcodetable allocation for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -260,14 +256,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-cctb}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@cctb@AtEnd
\expandafter\endinput
\fi
@@ -505,6 +504,7 @@ end
% Plain TeX.
%
% \begin{macrocode}
+%<testplain,testlatex>\catcode00 15
%<testplain>\input luatexbase-cctb.sty
%<testlatex>\RequirePackage{luatexbase-cctb}
%<*testplain,testlatex>
@@ -524,13 +524,29 @@ end
\lua{assert(luatexbase.catcodetables.anothercctb)}
% \end{macrocode}
%
-% Now, play a little bit with predefined tables.
+% Now, play a little bit with predefined tables. Be careful to change
+% catcodes only inside a group to avoid chaos.
%
% \begin{macrocode}
-\luatexcatcodetable\CatcodeTableLaTeXAtLetter
-\ifnum\catcode64=11 \else \ERROR \fi
-\luatexcatcodetable\CatcodeTableLaTeX
-\ifnum\catcode64=12 \else \ERROR \fi
+\def\test#1#2#3{%
+ \begingroup
+ \ifcsname CatcodeTable#1\endcsname \else \INTERR \fi
+ \luatexcatcodetable\csname CatcodeTable#1\endcsname
+ \ifnum\catcode#2=#3 \else \ERROR \fi
+ \endgroup}
+\test {IniTeX} {00} {09}
+\test {IniTeX} {92} {00}
+\test {IniTeX} {64} {12}
+\test {IniTeX} {65} {11}
+\test {String} {92} {12}
+\test {String} {65} {12}
+\test {String} {32} {10}
+\test {Other} {92} {12}
+\test {Other} {65} {12}
+\test {Other} {32} {12}
+\test {LaTeXAtLetter} {64} {11}
+\test {LaTeX} {64} {12}
+\test {Expl} {32} {09}
%<testlatex>\documentclass{minimal}
\lua{%
tex.sprint('\string\\setbox0=\string\\hbox{')
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-compat.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-compat.dtx
index f4a903b74be..e7d29b2b107 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-compat.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-compat.dtx
@@ -102,11 +102,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-compat} package}
-% \date{v0.2a 2010/05/27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-compat}{2010/10/10 v0.3}
%
% \maketitle
%
@@ -258,7 +254,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-compat}[2010/05/27 v0.2a Compatibility tools for LuaTeX]
+\x{luatexbase-compat}[2010/10/10 v0.3 Compatibility tools for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -272,14 +268,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-compat}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@compat@AtEnd
\expandafter\endinput
\fi
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-loader.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-loader.dtx
index bd900c26969..9d57ac57c86 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-loader.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-loader.dtx
@@ -116,11 +116,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-loader} package}
-% \date{v0.2a 2010-05-27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \texttt{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-loader}{v0.3 2010-05-27}
%
% \maketitle
%
@@ -230,7 +226,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-loader}[2010/05/27 v0.2a Lua module loader for LuaTeX]
+\x{luatexbase-loader}[2010/10/10 v0.3 Lua module loader for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -244,14 +240,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-loader}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@loader@AtEnd
\expandafter\endinput
\fi
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-mcb.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-mcb.dtx
index 09c8c1c53dd..b944cd261e4 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-mcb.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-mcb.dtx
@@ -69,6 +69,11 @@ See source file '\inFileName' for details.
\file{mcb.lua}{\from{luatexbase-mcb.dtx}{lua}}%
}
+\generate{%
+ \usedir{doc/luatex/luatexbase}%
+ \file{test-mcb.lua}{\from{luatexbase-mcb.dtx}{testlua}}%
+}
+
\obeyspaces
\Msg{************************************************************************}
\Msg{*}
@@ -113,73 +118,163 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \textsf{luatexbase-mcb} package}
-% \date{2010/05/27 v0.2a}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-mcb}{2010/10/10 v0.3}
%
% \maketitle
%
% \begin{abstract}
-% This package manages the callback adding and removing, by providing new
-% functions and overwriting \texttt{callback.register}. It also allows to
-% create and call new callbacks.\par
-% The user part of this documentation is currently very incomplete, and will
-% be expanded later. Sorry for this and thanks for your patience.\par
-% \textbf{Warning.} Currently assumes that \textsf{luatexbase-modutils}
-% has been previously loaded. (This is a temporary limitation.)
+% The primary feature of this package is to allow many functions to be
+% registered in the same callback. Depending of the type of the callback, the
+% functions will be combined in some way when the callback is called. Functions
+% are provided for addition and removal of individual functions from a
+% callback's list, with a priority system.\par
+% Additionally, you can create new callbacks that will be handled the same way
+% as predefined callbacks, except that they must be called explicitly.
% \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
+% Before we start, let me mention that test files are provided (they should be
+% in the same directory as this PDF file). You can have a look at them,
+% compile them and have a look at the log, if you want examples of how this
+% module works.
+%
+% \subsection{Managing functions in callbacks}
+%
+% \luatex 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
+% The \luatex 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
-% \verb+luatexbase.add_to_callback+ 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. There are
-% also functions to remove one or all functions from a callback.
-% See comments in the implementation section for details.
-%
-% 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.
-% See comments in the implementation section for details.
-%
-% This package also privides a way to create and call new callbacks, in
-% addition to the default Lua\TeX\ callbacks.
-% See comments in the implementation section for details.
-%
-% \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}.
+% The problem with |callback.register| is that is registers only one function
+% in a callback. This package solves the problem by disabling
+% |callback.register| and providing a new interface allowing many functions to
+% be registered in a single callback.
+%
+% The way the functions are combined together depends on
+% the type of the callback. There are currently 4 types of callback, depending
+% on the calling convention of the functions the callback can hold:
+% \begin{description}
+% \item[simple] is for functions that don't return anything: they are called
+% in order, all with the same argument;
+% \item[data] is for functions receiving a piece of data of nay type
+% except node list head (and possibly other arguments) and returning it
+% (possibly modified): the functions are called in order, and each is
+% passed the return value of the previous (and the other arguments
+% untouched, if any). The return value is that of the last function;
+% \item[list] is a specialized variant of \emph{data} for functions
+% filtering node lists. Such functions may return either the head of a
+% modified node list, or the boolean values |true| or |false|. The
+% functions are chained the same way as for \emph{data} except that for
+% the following. If
+% one function returns |false|, then |false| is immediately return and the
+% following functions are \emph{not} called. If one function returns
+% |true|, then the same head is passed to the next function. If all
+% functions return |true|, then |true| is returned, otherwise the return
+% value of the last function not returning |true| is used.
+% \item[first] is for functions with more complex signatures; functions in
+% this type of callback are \emph{not} combined: only the first one
+% (according to priorities) is executed.
+% \end{description}
+%
+% To add a function to a callback, use:
+% \begin{verbatim}
+% luatexbase.add_to_callback(name, func, description, priority)
+% \end{verbatim}
+% The first argument is the name of the callback, the second is a function,
+% the third one is a string used to identify the function later, and the
+% optional priority is a positive integer, representing the rank of the
+% function in the list of functions to be executing for this callback. So,
+% |1| is the highest priority. If no priority is specified, the function is
+% appended to the list, that is, its priority is the one of the last function
+% plus one.
+%
+% The priority system is intended to help resolving conflicts between packages
+% competing on the same callback, but it cannot solve every possible issue. If
+% two packages request priority |1| on the same callback, then the last one
+% loaded will win.
+%
+% To remove a function from a callback, use:
+% \begin{verbatim}
+% luatexbase.remove_from_callback(name, description)
+% \end{verbatim}
+% The first argument must be the name of the callback, and the second one the
+% description used when adding the function to this callback. You can also
+% remove all functions from a callback at once using
+% \begin{verbatim}
+% luatexbase.reset_callback(name, make_false)
+% \end{verbatim}
+% The |make_false| argument is optional. If it is |true| (repeat: |true|, not
+% |false|) then the value |false| is registered in the callback, which has a
+% special meaning for some callback.
+%
+% Note that |reset_callback| is very invasive since it removes all functions
+% possibly installed by other packages in this callback. So, use it with care
+% if there is any chance that another package wants to share this callback
+% with you.
+%
+% When new functions are added at the beginning of the list, other functions
+% are shifted down the list. To get the current rank of a function in a
+% callback's list, use:
+% \begin{verbatim}
+% priority = luatexbase.priority_in_callback(name, description)
+% \end{verbatim}
+% Again, the description is the string used when adding the function. If the
+% function identified by this string is not in this callback's list, the
+% priority returned is the boolean value |false|.
+%
+% \subsection{Creating new callbacks}
+%
+% This package also provides a way to create and call new callbacks, in
+% addition to the default \luatex callbacks.
+% \begin{verbatim}
+% luatexbase.create_callback(name, type, default)
+% \end{verbatim}
+% The first argument is the callback's name, it must be unique. Then, the type
+% goes as explained above, it is given as a string. Finally all user-defined
+% callbacks have a default function which must\footnote{You can obviously
+% provide a dummy function. If you're doing so often, please tell me, I may
+% want to make this argument optional.} be provided as the third
+% argument. It will be used when no other function is registered for this
+% callback.
+%
+% Functions are added to and removed from user-defined callbacks just the same
+% way as predefined callback, so the previous section still applies. There is
+% one difference, however: user-defined callbacks must be called explicitly at
+% some point in your code, while predefined callbacks are called automatically
+% by \luatex. To do so, use:
+% \begin{verbatim}
+% luatexbase.call_callback(name, arguments...)
+% \end{verbatim}
+% The functions registered for this callback (or the default function) will be
+% called with |arguments...| as arguments.
+%
+% \subsubsection{Limitations}
+%
+% For callbacks of type |first|, our new management system isn't actually
+% better than good old |callback.register|. For some of them, is may be
+% possible to split them into many callbacks, so that these callbacks can
+% accept multiple functions. However, its seems risky and limited in use and
+% is therefore nor implemented.
+%
+% At some point, \pk{luatextra} used to split |open_read_file| that way, but
+% support for this was removed. It may be added back (as well as support for
+% other split callbacks) if it appears there is an actual need for it.
+%
+% \subsection{Compatibility}
+%
+% Some callbacks have a calling convention that varies depending on the
+% version of \luatex used. This package \emph{does not} try to track the type
+% of the callbacks in every possible version of \luatex. The types are based
+% on the last stable beta version (0.60.2 at the time this doc is written).
+%
+% However, for callbacks that have the same calling convention for every
+% version of \luatex, this package should work with the same range of \luatex
+% version as other packages in the \pk{luatexbase} bundle (currently, 0.25.4
+% to 0.60.2).
%
% \section{Implementation}
%
@@ -245,7 +340,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-mcb}[2010/05/27 v0.2a Callback management for LuaTeX]
+\x{luatexbase-mcb}[2010/10/10 v0.3 Callback management for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -259,14 +354,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-mcb}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@mcb@AtEnd
\expandafter\endinput
\fi
@@ -304,309 +402,280 @@ See source file '\inFileName' for details.
%
% \begin{macrocode}
module('luatexbase', package.seeall)
-luatexbase.provides_module({
- name = "luamcallbacks",
+local err, warning, info = luatexbase.provides_module({
+ name = "luatexbase-mcb",
version = 0.2,
date = "2010/05/12",
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",
+ author = "Hans Hagen, Elie Roux and Manuel Pegourie-Gonnard",
+ copyright = "Hans Hagen, Elie Roux and Manuel Pegourie-Gonnard",
license = "CC0",
})
% \end{macrocode}
%
-% Shortcuts for error functions.
+% \subsubsection{Housekeeping}
+%
+% The main table: keys are callback names, and values are the associated
+% lists of functions. More precisely, the entries in the list are tables
+% holding the actual function as |func| and the identifying description as
+% |description|. Only callbacks with a non-empty list of functions have an
+% entry in this list.
%
% \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
+local callbacklist = callbacklist or { }
% \end{macrocode}
%
-% \subsubsection{Initialisations}
+% Numerical codes for callback types, and name to value association (the
+% table keys are strings, the values are numbers).
%
-% \texttt{callbacklist} is the main list, that contains the callbacks as
-% keys and a table of the registered functions a values.
+% \begin{macrocode}
+local list, data, first, simple = 1, 2, 3, 4
+local types = {
+ list = list,
+ data = data,
+ first = first,
+ simple = simple,
+}
+% \end{macrocode}
+%
+% Now, list all predefined callbacks with their current type, based on the
+% LuaTeX manual version 0.60.2.
%
% \begin{macrocode}
-local callbacklist = callbacklist or { }
+local callbacktypes = callbacktypes or {
% \end{macrocode}
%
-% A table with the default functions of the created callbacks. See
-% \texttt{create} for further informations.
+% Section 4.1.1: file discovery callbacks.
%
% \begin{macrocode}
-local lua_callbacks_defaults = { }
+ find_read_file = first,
+ find_write_file = first,
+ find_font_file = data,
+ find_output_file = data,
+ find_format_file = data,
+ find_vf_file = data,
+ find_ocp_file = data,
+ find_map_file = data,
+ find_enc_file = data,
+ find_sfd_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,
% \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}
+% Section 4.1.2: file reading callbacks.
%
% \begin{macrocode}
-local list = 1
-local data = 2
-local first = 3
-local simple = 4
+ open_read_file = first,
+ read_font_file = first,
+ read_vf_file = first,
+ read_ocp_file = first,
+ read_map_file = first,
+ read_enc_file = first,
+ read_sfd_file = first,
+ read_pk_file = first,
+ read_data_file = first,
+ read_truetype_file = first,
+ read_type1_file = first,
+ read_opentype_file = first,
% \end{macrocode}
%
-% \texttt{callbacktypes} is the list that contains the callbacks as keys
-% and the type (list or data) as values.
+% Section 4.1.3: data processing callbacks.
%
% \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,
-}
+ process_input_buffer = data,
+ process_output_buffer = data,
+ token_filter = 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.
+% Section 4.1.4: node list processiong callbacks.
%
% \begin{macrocode}
-if luatexbase.luatexversion > 42 then
- callbacktypes["process_output_buffer"] = data
-end
+ buildpage_filter = simple,
+ pre_linebreak_filter = list,
+ linebreak_filter = list,
+ post_linebreak_filter = list,
+ hpack_filter = list,
+ vpack_filter = list,
+ pre_output_filter = list,
+ hyphenate = simple,
+ ligaturing = simple,
+ kerning = simple,
+ mlist_to_hlist = list,
% \end{macrocode}
%
-% As we overwrite \texttt{callback.register}, we save it as
-% \texttt{internalregister}.
+% Section 4.1.5: information reporting callbacks.
%
% \begin{macrocode}
-local internalregister = internalregister or callback.register
+ start_run = simple,
+ stop_run = simple,
+ start_page_number = simple,
+ stop_page_number = simple,
+ show_error_hook = simple,
% \end{macrocode}
%
-% \subsubsection{Unsorted stuff}
+% Section 4.1.6: font-related callbacks.
%
-% 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}
+ define_font = first,
+}
+% \end{macrocode}
+%
+% All user-defined callbacks have a default function. The following table's
+% keys are the names of the user-defined callback, the associated value is
+% the default functon for this callback. This table is also used to
+% identify the user-defined callbacks.
%
% \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
+local lua_callbacks_defaults = { }
+% \end{macrocode}
+%
+% Overwrite |callback.register|, but save it first. Also define a wrapper
+% that automatically raise an error when something goes wrong.
+%
+% \begin{macrocode}
+local original_register = original_register or callback.register
+callback.register = function ()
+ err("function callback.register has been trapped,\n"
+ .."please use luatexbase.add_to_callback instead.")
+end
+local function register_callback(...)
+ return assert(original_register(...))
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.
+% \subsubsection{Handlers}
+%
+% Normal (as opposed to user-defined) callbacks have handlers depending on
+% their type. The handler function is registered into the callback when the
+% first function is added to this callback's list. Then, when the callback
+% is called, then handler takes care of running all functions in the list.
+% When the last function is removed from the callback's list, the handler
+% is unregistered.
+%
+% More precisely, the functions below are used to generate a specialized
+% function (closure) for a given callback, which is the actual handler.
+%
+% Handler for |list| callbacks.
%
% \begin{macrocode}
--- local
-function listhandler (name)
+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
+ local ret
+ local alltrue = true
+ for _, f in ipairs(callbacklist[name]) do
+ ret = f.func(head, ...)
+ if ret == false then
+ warn("function '%s' returned false\nin callback '%s'",
+ f.description, name)
+ break
+ end
+ if ret ~= true then
+ alltrue = false
+ head = ret
end
- return head, done
- else
- return head, false
end
+ return alltrue and true or head
end
end
% \end{macrocode}
%
-% The handler for callbacks taking datas and returning modified ones.
+% Handler for |data| callbacks.
%
% \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
+ return function(data, ...)
+ for _, f in ipairs(callbacklist[name]) do
+ data = f.func(data, ...)
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.
+% Handler for |first| callbacks. We can assume |callbacklist[name]| is not
+% empty: otherwise, the function wouldn't be registered in the callback any
+% more.
%
% \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
+ return callbacklist[name][1].func(...)
end
end
% \end{macrocode}
%
-% Handler for simple functions that don't return anything.
+% Handler for |simple| callbacks.
%
% \begin{macrocode}
local function simplehandler (name)
return function(...)
- local l = callbacklist[name]
- if l then
- for _, f in ipairs(l) do
- f.func(...)
- end
+ for _, f in ipairs(callbacklist[name]) do
+ f.func(...)
end
end
end
% \end{macrocode}
%
-% \subsubsection{Public functions}
+% Finally, keep a handlers table for indexed access.
%
-% 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.
+% \begin{macrocode}
+local handlers = {
+ [list] = listhandler,
+ [data] = datahandler,
+ [first] = firsthandler,
+ [simple] = simplehandler,
+}
+% \end{macrocode}
%
-% 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.
+% \subsubsection{Public functions for functions management}
%
-% 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.
+% Add a function to a callback. First check arguments.
%
% \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
+ return err("unable to add function:\nno proper function passed")
end
if not name or name == "" then
- err("unable to add function, no proper callback name passed")
+ err("unable to add function:\nno proper callback name passed")
return
elseif not callbacktypes[name] then
- err("unable to add function, '%s' is not a valid callback", name)
+ err("unable to add function:\n'%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",
+ err("unable to add function to '%s':\nno proper description passed",
name)
return
end
- if priority_in_callback(name, description) ~= 0 then
- warning("function '%s' already registered in callback '%s'",
+ if priority_in_callback(name, description) then
+ err("function '%s' already registered\nin callback '%s'",
description, name)
+ return
end
+% \end{macrocode}
+%
+% Then test if this callback is already in use. If not, initialise its list
+% and register the proper handler.
+%
+% \begin{macrocode}
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
+ register_callback(name, handlers[callbacktypes[name]](name))
end
end
+% \end{macrocode}
+%
+% Actually register the function.
+%
+% \begin{macrocode}
local f = {
func = func,
description = description,
@@ -617,33 +686,35 @@ function add_to_callback (name,func,description,priority)
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'",
+% \end{macrocode}
+%
+% Keep user informed.
+%
+% \begin{macrocode}
+ if callbacktypes[name] == first and #l ~= 1 then
+ warning("several functions in '%s',\n"
+ .."only one will be active.", name)
+ end
+ info("inserting '%s'\nat position %s in '%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}.
+% Remove a function from a callback. First check arguments.
%
% \begin{macrocode}
function remove_from_callback (name, description)
if not name or name == "" then
- err("unable to remove function, no proper callback name passed")
+ err("unable to remove function:\nno proper callback name passed")
return
elseif not callbacktypes[name] then
- err("unable to remove function, '%s' is not a valid callback", name)
+ err("unable to remove function:\n'%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",
+ "unable to remove function from '%s':\nno proper description passed",
name)
return
end
@@ -652,45 +723,84 @@ function remove_from_callback (name, description)
err("no callback list for '%s'",name)
return
end
+% \end{macrocode}
+%
+% Then loop over the callback's function list until we find a matching
+% entry. Remove it and check if the list gets empty: if so, unregister the
+% callback handler unless the callback is user-defined.
+%
+% \begin{macrocode}
+ local index = false
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
+ index = k
+ break
+ end
+ end
+ if not index then
+ err("unable to remove '%s'\nfrom '%s'", description, name)
+ return
+ end
+ table.remove(l, index)
+ info("removing '%s'\nfrom '%s'", description, name)
+ if table.maxn(l) == 0 then
+ callbacklist[name] = nil
+ if not lua_callbacks_defaults[name] then
+ register_callback(name, nil)
end
end
- warning("unable to remove function '%s' from '%s'",description,name)
+ return
end
% \end{macrocode}
%
-% This function removes all the functions registered in a callback.
+% Remove all the functions registered in a callback. Unregisters the
+% callback handler unless the callback is user-defined.
%
% \begin{macrocode}
-function reset_callback (name)
+function reset_callback (name, make_false)
if not name or name == "" then
- err("unable to reset, no proper callback name passed")
+ err("unable to reset:\nno proper callback name passed")
return
elseif not callbacktypes[name] then
- err("reset error, '%s' is not a valid callback", name)
+ err("unable to reset '%s':\nis not a valid callback", name)
return
end
+ info("resetting callback '%s'", name)
+ callbacklist[name] = nil
if not lua_callbacks_defaults[name] then
- internalregister(name, nil)
+ if make_false == true then
+ info("setting '%s' to false", name)
+ register_callback(name, false)
+ else
+ register_callback(name, nil)
+ end
+ end
+end
+% \end{macrocode}
+%
+% Get a function's priority in a callback list, or false if the function is
+% not in the list.
+%
+% \begin{macrocode}
+function priority_in_callback (name, description)
+ if not name or name == ""
+ or not callbacktypes[name]
+ or not description then
+ return false
end
local l = callbacklist[name]
- if l then
- log("resetting callback list '%s'",name)
- callbacklist[name] = nil
+ if not l then return false end
+ for p, f in pairs(l) do
+ if f.description == description then
+ return p
+ end
end
+ return false
end
% \end{macrocode}
%
+% \subsubsection{Public functions for user-defined callbacks}
+%
% 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
@@ -705,24 +815,24 @@ end
% \begin{macrocode}
function create_callback(name, ctype, default)
if not name then
- err("unable to call callback, no proper name passed", name)
+ err("unable to call callback:\nno proper name passed", name)
return nil
end
if not ctype or not default then
- err("unable to create callback '%s': "
+ err("unable to create callback '%s':\n"
.."callbacktype or default function not specified", name)
return nil
end
if callbacktypes[name] then
- err("unable to create callback '%s', callback already exists", name)
+ err("unable to create callback '%s':\ncallback 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)
+ ctype = types[ctype]
+ if not ctype then
+ err("unable to create callback '%s':\ntype '%s' undefined", name, ctype)
return nil
end
- ctype = temp
+ info("creating '%s' type %s", name, ctype)
lua_callbacks_defaults[name] = default
callbacktypes[name] = ctype
end
@@ -734,11 +844,11 @@ end
% \begin{macrocode}
function call_callback(name, ...)
if not name then
- err("unable to call callback, no proper name passed", name)
+ err("unable to call callback:\nno proper name passed", name)
return nil
end
if not lua_callbacks_defaults[name] then
- err("unable to call lua callback '%s', unknown callback", name)
+ err("unable to call lua callback '%s':\nunknown callback", name)
return nil
end
local l = callbacklist[name]
@@ -746,92 +856,254 @@ function call_callback(name, ...)
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
+ f = handlers[callbacktypes[name]](name)
+ if not f then
err("unknown callback type")
+ return
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.
+% That's all folks!
%
% \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
+%</lua>
+% \end{macrocode}
+%
+% \section{Test files}
+%
+% A few basic tests for Plain and LaTeX. Use a separate Lua file for
+% convenience, since this package works on the Lua side of the force.
+%
+% \begin{macrocode}
+%<*testlua>
+local msg = texio.write_nl
+% \end{macrocode}
+%
+% Test the management functions with a predefined callback.
+%
+% \begin{macrocode}
+local function sample(head,...)
+ return head, true
end
+local prio = luatexbase.priority_in_callback
+msg("\n*********\n* Testing management functions\n*********")
+luatexbase.add_to_callback("hpack_filter", sample, "sample one", 1)
+luatexbase.add_to_callback("hpack_filter", sample, "sample two", 2)
+luatexbase.add_to_callback("hpack_filter", sample, "sample three", 1)
+assert(prio("hpack_filter", "sample three"))
+luatexbase.remove_from_callback("hpack_filter", "sample three")
+assert(not prio("hpack_filter", "sample three"))
+luatexbase.reset_callback("hpack_filter")
+assert(not prio("hpack_filter", "sample one"))
% \end{macrocode}
%
-% Finally we
-% overwrite \texttt{callback.register} so that it outputs an error.
+% Create a callback, and check that the managment functions work with this
+% callback too.
%
% \begin{macrocode}
-callback.register = function ()
-err("function callback.register has been deleted by luamcallbacks, "
-.."please use luatexbase.add_to_callback instead.")
+local function data_one(s)
+ texio.write_nl("I'm data 1 whith argument: "..s)
+ return s
end
+local function data_two(s)
+ texio.write_nl("I'm data 2 whith argument: "..s)
+ return s
+end
+local function data_three(s)
+ texio.write_nl("I'm data 3 whith argument: "..s)
+ return s
+end
+msg("\n*********\n* Testing user-defined callbacks\n*********")
+msg("* create one")
+luatexbase.create_callback("fooback", "data", data_one)
+msg("* call it")
+luatexbase.call_callback("fooback", "default")
+msg("* add two functions")
+luatexbase.add_to_callback("fooback", data_two, "function two", 2)
+luatexbase.add_to_callback("fooback", data_three, "function three", 1)
+msg("* call")
+luatexbase.call_callback("fooback", "all")
+msg("* rm one function")
+luatexbase.remove_from_callback("fooback", "function three")
+msg("* call")
+luatexbase.call_callback("fooback", "all but three")
+msg("* reset")
+luatexbase.reset_callback("fooback")
+msg("* call")
+luatexbase.call_callback("fooback", "default")
% \end{macrocode}
%
-% That's all folks!
+% Now, we want to make each handler run at least once. So, define dummy
+% functions and register them in various callbacks. We will make sure the
+% callbacks are executed on the \tex end. Also, we want to check that
+% everything works when we unload the functions either one by one, or using
+% reset.
+%
+% A |list| callback.
%
% \begin{macrocode}
-%</lua>
+function add_hpack_filter()
+ luatexbase.add_to_callback('hpack_filter', function(head, ...)
+ texio.write_nl("I'm a dummy hpack_filter")
+ return head
+ end,
+ 'dummy hpack filter')
+ luatexbase.add_to_callback('hpack_filter', function(head, ...)
+ texio.write_nl("I'm an optimized dummy hpack_filter")
+ return true
+ end,
+ 'optimized dummy hpack filter')
+end
+function rm_one_hpack_filter()
+ luatexbase.remove_from_callback('hpack_filter', 'dummy hpack filter')
+end
+function rm_two_hpack_filter()
+ luatexbase.remove_from_callback('hpack_filter',
+ 'optimized dummy hpack filter')
+end
% \end{macrocode}
%
-% \section{Test files}
+% A |simple| callback.
+%
+% \begin{macrocode}
+function add_hyphenate()
+ luatexbase.add_to_callback('hyphenate', function(head, tail)
+ texio.write_nl("I'm a dummy hyphenate")
+ end,
+ 'dummy hyphenate')
+ luatexbase.add_to_callback('hyphenate', function(head, tail)
+ texio.write_nl("I'm an other dummy hyphenate")
+ end,
+ 'other dummy hyphenate')
+end
+function rm_one_hyphenate()
+ luatexbase.remove_from_callback('hyphenate', 'dummy hyphenate')
+end
+function rm_two_hyphenate()
+ luatexbase.remove_from_callback('hyphenate', 'other dummy hyphenate')
+end
+% \end{macrocode}
+%
+% A |first| callback.
+%
+% \begin{macrocode}
+function add_find_write_file()
+ luatexbase.add_to_callback('find_write_file', function(id, name)
+ texio.write_nl("I'm a dummy find_write_file")
+ return "dummy-"..name
+ end,
+ 'dummy find_write_file')
+ luatexbase.add_to_callback('find_write_file', function(id, name)
+ texio.write_nl("I'm an other dummy find_write_file")
+ return "dummy-other-"..name
+ end,
+ 'other dummy find_write_file')
+end
+function rm_one_find_write_file()
+ luatexbase.remove_from_callback('find_write_file',
+ 'dummy find_write_file')
+end
+function rm_two_find_write_file()
+ luatexbase.remove_from_callback('find_write_file',
+ 'other dummy find_write_file')
+end
+% \end{macrocode}
%
-% A few basic tests for Plain and LaTeX.
+% A |data| callback.
+%
+% \begin{macrocode}
+function add_process_input_buffer()
+ luatexbase.add_to_callback('process_input_buffer', function(buffer)
+ return buffer.."\\msg{dummy}"
+ end,
+ 'dummy process_input_buffer')
+ luatexbase.add_to_callback('process_input_buffer', function(buffer)
+ return buffer.."\\msg{otherdummy}"
+ end,
+ 'other dummy process_input_buffer')
+end
+function rm_one_process_input_buffer()
+ luatexbase.remove_from_callback('process_input_buffer',
+ 'dummy process_input_buffer')
+end
+function rm_two_process_input_buffer()
+ luatexbase.remove_from_callback('process_input_buffer',
+ 'other dummy process_input_buffer')
+end
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</testlua>
+% \end{macrocode}
%
% \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")
+\def\msg{\immediate\write16}
+\msg{===== BEGIN =====}
+% \end{macrocode}
+%
+% Loading the lua files tests that the management functions can be called
+% without raising errors.
+%
+% \begin{macrocode}
+\luatexbase@directlua{dofile('test-mcb.lua')}
+% \end{macrocode}
+%
+% We now want to load and unload stuff from the various callbacks have them
+% called to test the handlers. Here is a helper macro for that.
+%
+% \begin{macrocode}
+\def\test#1#2{%
+ \msg{^^J*********^^J* Testing #1 (type #2)^^J*********}
+ \msg{* Add two functions}
+ \luatexbase@directlua{add_#1()}
+ \csname test_#1\endcsname
+ \msg{* Remove one}
+ \luatexbase@directlua{rm_one_#1()}
+ \csname test_#1\endcsname
+ \msg{* Remove the second}
+ \luatexbase@directlua{rm_two_#1()}
+ \csname test_#1\endcsname
+ \msg{* Add two functions again}
+ \luatexbase@directlua{add_#1()}
+ \csname test_#1\endcsname
+ \msg{* Remove all functions}
+ \luatexbase@directlua{luatexbase.reset_callback("#1")}
+ \csname test_#1\endcsname
}
+% \end{macrocode}
+%
+% For each callback, we need a specific macro that triggers it. For the
+% hyphenate test, we need to untrap |\everypar| first, in the \latex case.
+%
+% \begin{macrocode}
+\catcode`\_ 11
+%<testlatex>\everypar{}
+\def\test_hpack_filter{\setbox0=\hbox{bla}}
+\def\test_hyphenate{\showhyphens{hyphenation}}
+\def\test_find_write_file{\immediate\openout15 test-mcb-out.log}
+\def\test_process_input_buffer{\input test-mcb-aux.tex}
+% \end{macrocode}
+%
+% Now actually test them
+%
+% \begin{macrocode}
+\test{hpack_filter}{list}
+\test{hyphenate}{simple}
+\test{find_write_file}{first}
+\test{process_input_buffer}{data}
+% \end{macrocode}
+%
+% Done.
+%
+% \begin{macrocode}
+\msg{===== END =====}
%</testplain,testlatex>
%<testplain>\bye
%<testlatex>\stop
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
index dd5b118f9aa..81394be2f93 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
@@ -115,11 +115,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-modutils} package}
-% \date{v0.2 2010-05-12}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-modutils}{v0.2 2010-05-12}
%
% \maketitle
%
@@ -129,15 +125,16 @@ See source file '\inFileName' for details.
% \cs{documentclass} and \cs{RequirePackage} or \cs{ProvidesClass} and
% \cs{ProvidesFiles}} or more precisely the part of these macros that deals
% with identification and version checking (no attempt is done at implementing
-% an option mechanism). Functions for error reporting are provided too.
-%
-% It also loads \pk{luatexbase-loader}.
+% an option mechanism). It also provides functions for reporting errors and
+% warnings in a standardised format.
% \end{abstract}
%
% \tableofcontents
%
% \section{Documentation}
%
+% \subsection{Scope of this package}
+%
% Lua's standard function |require()| is similar to \tex's |\input| primitive
% but is somehow more evolved in that it makes a few checks to avoid loading
% the same module twice. In the \tex world, this needs to be taken care of by
@@ -147,57 +144,148 @@ See source file '\inFileName' for details.
% implements a complex option system, and does some identification and version
% checking. The present package doesn't try to provide anything for options,
% but implements a system for identification and version checking similar to
-% \latex's system. Both \tex macros and Lua functions are provided.
+% \latex's system.
%
-% This package also provides Lua functions for reporting errors, warnings,
-% etc.
+% \medskip
%
% It is important to notice that Lua's standard function |module()| is
-% completely unrelated to the present package. It has nothing to do with
-% identification and deals only with namespaces.\footnote{More precisely, it
-% modifies the current environment.} So, you should continue to
-% use it normally, unlike the |require()| function which can be replaced with
-% this package's |luatexbase.require_module()|.
+% completely orthogonal with the present package. It has nothing to do with
+% identification and deals only with namespaces: more precisely, it
+% modifies the current environment. So, you should continue to
+% use it normally regardless of whether you chose to use this package's
+% features for identification.
+%
+% It is recommended to always use |module()| or any other method that ensure
+% the global name space remains clean. For example, you may heavily use the
+% |local| keyword and explicitly qualify the name of every non-local symbol.
+% Chapter 15 of \href{http://www.lua.org/pil/}{Programming in Lua, 1st ed.}
+% discusses various methods for managing packages.
%
% \subsection{\tex macros}
%
-% The two macros |\luatexUseModule| and |\luatexRequireModule| are very
-% similar and are interfaces to the Lua functions |use_module| and
-% |require_module|. The only difference between those macros is the number of
-% arguments (just as the underlying Lua functions): |\luatexUseModule| only
-% take one argument: the module name\footnote{without extension} while
-% |\luatexRequireModule| takes another argument for specifying a minimal
-% version (see below). With \latex, this argument is the first and is
-% optional. Otherwise, it's the second one and it's mandatory.
+% \begin{qcode}
+% \cs{RequireLuaModule}\marg{name}\oarg{date}
+% \end{qcode}
+%
+% The macro |\RequireLuaModule| is an interface to the Lua function
+% |require_module|; it take the same arguments with the same meaning. The
+% second argument is optional.
%
% \subsection{Lua functions}
%
-% The main functions are |luatexbase.require_module| and
-% |luatexbase.use_module| which may be used as a replacement to |require()|.
-% The only difference between these functions is, |require_module| accepts a
-% second, optional argument in order to specify a minimal version. They do the
-% same as |require()| but also make sure the module loaded correctly
-% identifies itself with the name given, and its version is greater than the
-% minimal version required. The version can be given either as a (floating
-% point) number or as a date in YYYY/MM/DD format.
-%
-% Modules identify themselves using |luatexbase.provides_module|, whose only
-% argument is a table with some information about the module. The mandatory
-% fields are |name| (a string), |version| (a number), |date| (a string) and
-% |description| (a string). Other fields are optional and ignored, and usually
-% include |copyright|, |author| and |license|.
-%
-% \bigskip
-%
-% Functions for reporting are provided; similarly to \latex's |\PackageError|
-% etc. they take the module name as their first argument and include it in the
-% printed message in an appropriate way. The remaining arguments are passed to
-% |string.format()| before being printed.
-%
-% The functions provided (all found in the |luatexbase| table) are
-% |module_error|, |module_warning|, |module_info| (writes to terminal and
-% log), |module_log| (writes only to the log file) and |module_term| (writes
-% only to the terminal).
+% \begin{qcode}
+% luatexbase.require_module({\meta{name}} [, \meta{required date}])
+% \end{qcode}
+%
+% The function |luatexbase.require_module()| may be used as a replacement to
+% |require()|. If only one argument is given, the only difference with
+% |require()| is it checks that the module properly identifies itself (as
+% explained below) with the same name.
+%
+% The second argument is optional; if used, it must be a
+% string\footnote{Previous versions of the package supported floating-point
+% version numbers as well, but it caused confusion with authors trying to use
+% version strings such as |0.3a| and probably isn't worth the trouble.}
+% containing a date in |YYYY//MM/DD| format which specifies the minimum
+% version of the module required.
+%
+% \begin{qcode}
+% luatexbase.provides_module(\meta{info})
+% \end{qcode}
+% This function is used by modules to identify themselves; the argument is a
+% table containing information about the module. The required field |name|
+% must contain the name of the module. It is recommended to provide a field
+% |date| with the same format as above. Optional fields |version| (number or
+% string) and |description| may be used if present. Other fields are ignored.
+%
+% If a date was required, then a warning is issued if the required date is
+% strictly newer than the declared date (or if no date was declared). A list
+% of loaded modules and their associated information is kept, and used to
+% check the date without reloading the module (since |require()| won't reload
+% it anyway) if a module is required several times.
+%
+% \begin{qcode}
+% luatexbase.module_error(\meta{name}, \meta{message}, ...)
+% luatexbase.module_warning(\meta{name}, \meta{message}, ...)
+% luatexbase.module_info(\meta{name}, \meta{message}, ...)
+% luatexbase.module_log(\meta{name}, \meta{message}, ...)
+% \end{qcode}
+% These functions are similar to \latex's |\PackageError|, |\PackageWarning|
+% and |\PackageInfo| in the way they format the output. No automatic line
+% breaking is done, you may still use |\n| as usual for that, and the name of
+% the package will be prepended to each output line (except for |log| which is
+% intended for short messages in a non-verbose format). The first argument
+% is the name of the current module; the remaining arguments are passed to
+% |string.format()|.
+%
+% Note that |module_error| raises an actual Lua error with |error()|, which
+% currently means a call stack will be dumped. While this may not look pretty,
+% at least it provides useful information for tracking the error down.
+%
+% \begin{qcode}
+% local err, warn, info, log = luatexbase.errwarinf(\meta{name})
+% local err, warn, info, log = luatexbase.provides_module(\meta{name})
+% \end{qcode}
+% Customised versions of the above commands maybe obtained by invoking
+% |errwarinf()| and are also returned by |provides_module()|. They don't take
+% the name of the module as their first argument any more, so that you don't
+% need to repeat it all over the place. (Notice that |error| is the name of a
+% standard Lua function, so you may want to avoid overwriting it, hence the
+% use of |err| in the above example.)
+%
+% \subsection{Templates}
+%
+% Let me emphasize again that, while |luatexbase.require_module()| is meant to
+% be used as a replacement for |require()|, the function
+% |luatexbase.provides_module()| \emph{is not} a replacement for |module()|:
+% they just don't do the same thing (declaring information vs changing the
+% current name space).
+%
+% Now, here is how you module may begin:
+% \begin{verbatim}
+% local err, warn, info, log = luatexbase.provides_module({
+% -- required
+% name = 'mymodule',
+% -- recommended
+% date = '1970/01/01',
+% version = 0.0, -- or version = '0.0a',
+% description = 'a Lua module template',
+% -- optional and ignored
+% author = 'A. U. Thor',
+% licence = 'LPPL v1.3+',
+% })
+%
+% module('mynamespace', package.seeall)
+% -- or any other method (see chapter 15 of PIL for examples)
+% \end{verbatim}
+%
+% Alternatively, if you don't want to assume \pk{luatexbase-modutils} is
+% loaded, you may load your module with:
+% \begin{verbatim}
+% (luatexbase.require_module or require)('mymodule')
+% \end{verbatim}
+% and begin your module's code with:
+% \begin{verbatim}
+% if luatexbase._provides_module then
+% luatexbase.provides_module({
+% -- required
+% name = 'mymodule',
+% -- recommended
+% date = '1970/01/01',
+% version = 0.0, -- or version = '0.0a',
+% description = 'a Lua module template',
+% -- optional and ignored
+% author = 'A. U. Thor',
+% licence = 'LPPL v1.3+',
+% })
+% end
+%
+% module('mynamespace', package.seeall)
+% -- or any other method (see chapter 15 of PIL for examples)
+%
+% local function err(msg)
+% -- etc.
+% \end{verbatim}
%
% \section{Implementation}
%
@@ -263,7 +351,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-modutils}[2010/05/27 v0.2a Module utilities for LuaTeX]
+\x{luatexbase-modutils}[2010/10/10 v0.3 Module utilities for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -277,60 +365,94 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-modutils}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@modutils@AtEnd
\expandafter\endinput
\fi
% \end{macrocode}
%
-% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}) and require
-% supporting Lua module.
+% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), require the
+% supporting Lua module and make sure |luaescapestring| is available.
%
% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname RequirePackage\endcsname\relax
- \input luatexbase-loader.sty
-\else
+\ifdefined\RequirePackage
\RequirePackage{luatexbase-loader}
+\else
+ \input luatexbase-loader.sty
\fi
\luatexbase@directlua{require('luatexbase.modutils')}
-% \end{macrocode}
-%
-% Make sure the primitives we need are available.
-%
-% \begin{macrocode}
\luatexbase@ensure@primitive{luaescapestring}
% \end{macrocode}
%
-% \subsubsection{User macros}
+% \subsection{Auxiliary definitions}
%
-% Interface to |use_module()|.
+% We need a version of |\@ifnextchar|. The definitions for the not-\latex
+% case are stolen from \pk{ltxcmds} verbatim, only the prefix is changed.
%
% \begin{macrocode}
-\def\luatexUseModule#1{\luatexbase@directlua{%
- luatexbase.use_module("\luatexluaescapestring{#1}")}}
+\ifdefined\kernel@ifnextchar
+ \let\lltxb@ifnextchar\kernel@ifnextchar
+\else
+ \chardef\lltxb@zero0
+ \chardef\lltxb@two2
+ \long\def\lltxb@ifnextchar#1#2#3{%
+ \begingroup
+ \let\lltxb@CharToken= #1\relax
+ \toks\lltxb@zero{#2}%
+ \toks\lltxb@two{#3}%
+ \futurelet\lltxb@LetToken\lltxb@ifnextchar@
+ }
+ \def\lltxb@ifnextchar@{%
+ \ifx\lltxb@LetToken\lltxb@CharToken
+ \expandafter\endgroup\the\toks\expandafter\lltxb@zero
+ \else
+ \ifx\lltxb@LetToken\lltxb@SpaceToken
+ \expandafter\expandafter\expandafter\lltxb@@ifnextchar
+ \else
+ \expandafter\endgroup\the\toks
+ \expandafter\expandafter\expandafter\lltxb@two
+ \fi
+ \fi
+ }
+ \begingroup
+ \def\x#1{\endgroup
+ \def\lltxb@@ifnextchar#1{%
+ \futurelet\lltxb@LetToken\lltxb@ifnextchar@
+ }%
+ }%
+ \x{ }
+ \begingroup
+ \def\x#1{\endgroup
+ \let\lltxb@SpaceToken= #1%
+ }%
+ \x{ }
+\fi
% \end{macrocode}
%
-% Interface to |require_module()| with syntax depending on the format.
+% \subsubsection{User macro}
+%
+% Interface to the Lua function for module loading. Avoid passing a second
+% argument to the function if empty (most probably not specified).
%
% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname newcommand\endcsname\relax
- \def\luatexRequireModule#1#2{%
- \luatexbase@directlua{luatexbase.require_module(
- "\luatexluaescapestring{#1}", "\luatexluaescapestring{#2}")}}
-\else
- \newcommand\luatexRequireModule[2][0]{%
- \luatexbase@directlua{luatexbase.require_module(
- "\luatexluaescapestring{#2}", "\luatexluaescapestring{#1}")}}
-\fi
+\def\RequireLuaModule#1{%
+ \lltxb@ifnextchar[{\lltxb@requirelua{#1}}{\lltxb@requirelua{#1}[]}}
+\def\lltxb@requirelua#1[#2]{%
+ \luatexbase@directlua{luatexbase.require_module(
+ "\luatexluaescapestring{#1}"
+ \expandafter\ifx\expandafter\/\detokenize{#2}\/\else
+ , "\luatexluaescapestring{#2}"
+ \fi)}}
% \end{macrocode}
%
% \begin{macrocode}
@@ -348,75 +470,75 @@ module("luatexbase", package.seeall)
% \subsection{Internal functions and data}
%
% Tables holding informations about the modules loaded and the versions
-% required.
+% required. Keys are module names and values are the info tables as passed
+% to |provides_module()|.
%
% \begin{macrocode}
local modules = modules or {}
-local requiredversions = {}
% \end{macrocode}
%
-% Convert a date in YYYY/MM/DD format into a number
+% Convert a date in YYYY/MM/DD format into a number.
%
% \begin{macrocode}
-local function datetonumber(date)
+local function date_to_int(date)
numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
return tonumber(numbers)
end
% \end{macrocode}
%
-% Say if a string is a date in YYYY//MM/DD format.
-%
-% \begin{macrocode}
-local function isdate(date)
- for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
- return true
- end
- return false
-end
-% \end{macrocode}
-%
-% Parse a version into a table indicating a type (date or number), a
-% numeric version and the original version string.
-%
-% \begin{macrocode}
-local date, number = 1, 2
-local function parse_version(version)
- if isdate(version) then
- return {type = date, version = datetonumber(version), orig = version}
- else
- return {type = number, version = tonumber(version), orig = version}
- end
-end
-% \end{macrocode}
-%
% \subsubsection{Error, warning and info function for modules}
%
-% Here are the reporting functions for the modules. For errors, Lua's
-% |error()| is used. For now, the error reports look less good than with
-% \tex's |\errmessage|, but hopefully it will be improved in future
-% versions of \luatex. We could invoke |\errmessage| using |tex.sprint()|,
-% but it may cause problems on the \tex end, and moreover |error()| will
-% still be used by Lua for other errors, so it makes messages more
-% consistent.
+% Here are the reporting functions for the modules. An internal function is
+% used for error messages, so that the calling level (last argument of
+% |error()| remains constant using either |module_error()| or a custom
+% version as returned by |errwarinf()|.
%
% \begin{macrocode}
+local function msg_format(msg_type, mod_name, ...)
+ local cont = '('..mod_name..')' .. ('Module: '..msg_type):gsub('.', ' ')
+ return 'Module '..mod_name..' '..msg_type..': '
+ .. string.format(...):gsub('\n', '\n'..cont) .. '\n'
+end
local function module_error_int(mod, ...)
- error('Module '..mod..' error: '..string.format(...), 3)
+ error(msg_format('error', mod, ...), 3)
end
function module_error(mod, ...)
module_error_int(mod, ...)
end
+% \end{macrocode}
+%
+% Split the lines explicitly in order not to depend on the value of
+% |\newlinechar|.
+%
+% \begin{macrocode}
function module_warning(mod, ...)
- texio.write_nl("Module "..mod.." warning: "..string.format(...))
+ for _, line in ipairs(msg_format('warning', mod, ...):explode('\n')) do
+ texio.write_nl(line)
+ end
end
function module_info(mod, ...)
- texio.write_nl(mod..": "..string.format(...))
+ for _, line in ipairs(msg_format('info', mod, ...):explode('\n')) do
+ texio.write_nl(line)
+ end
end
-function module_log(mod, ...)
- texio.write_nl('log', mod..": "..string.format(...))
+% \end{macrocode}
+%
+% No line splitting or advanced formating here.
+%
+% \begin{macrocode}
+function module_log(mod, msg, ...)
+ texio.write_nl('log', mod..': '..msg:format(...))
end
-function module_term(mod, ...)
- texio.write_nl('term', mod..": "..string.format(...))
+% \end{macrocode}
+%
+% Produce custom versions of the reporting functions.
+%
+% \begin{macrocode}
+function errwarinf(name)
+ return function(...) module_error_int(name, ...) end,
+ function(...) module_warning(name, ...) end,
+ function(...) module_info(name, ...) end,
+ function(...) module_log(name, ...) end
end
% \end{macrocode}
%
@@ -424,83 +546,42 @@ end
% present module.
%
% \begin{macrocode}
-local function err(...) module_error_int('luatexbase.modutils', ...) end
-local function warn(...) module_warning('luatexbase.modutils', ...) end
+local err, warn = errwarinf('luatexbase.modutils')
% \end{macrocode}
%
% \subsubsection{module loading and providing functions}
%
-% Load a module without version checking.
+% Load a module with mandatory name checking and optional version checking.
%
% \begin{macrocode}
-function use_module(name)
+function require_module(name, req_date)
require(name)
- if not modules[name] then
- warn("Module didn't properly identified itself: %s", name)
- end
-end
-% \end{macrocode}
-%
-% Load a module with optional version checking.
-%
-% \begin{macrocode}
-function require_module(name, version)
- if not version then
- return use_module(name)
- end
- luaversion = parse_version(version)
- if modules[name] then
- if luaversion.type == date then
- if datetonumber(modules[name].date) < luaversion.version then
- err("found module `%s' loaded in version %s, "
- .."but version %s was required",
- name, modules[name].date, version)
- end
- else
- if modules[name].version < luaversion.version then
- err("found module `%s' loaded in version %.02f, "
- .."but version %s was required",
- name, modules[name].version, version)
- end
+ local info = modules[name]
+ if not info then
+ warn("module '%s' was not properly identified", name)
+ elseif version then
+ if not (info.date and date_to_int(info.date) > date_to_int(req_date))
+ then
+ warn("module '%s' required in version '%s'\n"
+ .. "but found in version '%s'", name, req_date, info.date)
end
- else
- requiredversions[name] = luaversion
- use_module(name)
end
end
% \end{macrocode}
%
-% Provide identification information for a module.
+% Provide identification information for a module. As a bonus, custom
+% reporting functions are returned. No need to do any check here,
+% everything done in |require_module()|.
%
% \begin{macrocode}
-function provides_module(mod)
- if not mod then
- err('cannot provide nil module')
- return
- end
- if not mod.version or not mod.name or not mod.date
- or not mod.description then
- err("invalid module registered: "
- .."fields name, version, date and description are mandatory")
- return
- end
- requiredversion = requiredversions[mod.name]
- if requiredversion then
- if requiredversion.type == date
- and requiredversion.version > datetonumber(mod.date) then
- err("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
- err("loading module %s in version %.02f, "
- .."but version %s was required",
- mod.name, mod.version, requiredversion.orig)
- end
+function provides_module(info)
+ if not (info and info.name) then
+ err('provides_module: missing information')
end
- modules[mod.name] = mod
- texio.write_nl('log', string.format("Lua module: %s %s v%.02f %s\n",
- mod.name, mod.date, mod.version, mod.description))
+ texio.write_nl('log', string.format("Lua module: %s %s %s %s\n",
+ info.name, info.date or '', info.version or '', info.description or ''))
+ modules[info.name] = info
+ return errwarinf(info.name)
end
% \end{macrocode}
%
@@ -514,28 +595,26 @@ end
%
% \begin{macrocode}
%<*testdummy>
-luatexbase.provides_module {
+local err, warn, info, log = luatexbase.provides_module {
name = 'test-modutils',
date = '2000/01/01',
version = 1,
description = 'dummy test package',
}
+info('It works!\nOh, rly?\nYeah rly!')
+log("I'm a one-line info.")
%</testdummy>
% \end{macrocode}
%
% We just check that the package loads properly, under both LaTeX and Plain
-% TeX. Anyway, the test files of other modules using this one already are a
-% test\dots
+% TeX, is able to load and identify the above dummy module.
%
% \begin{macrocode}
%<testplain>\input luatexbase-modutils.sty
%<testlatex>\RequirePackage{luatexbase-modutils}
%<*testplain,testlatex>
-\luatexUseModule{test-modutils}
-\luatexRequireModule
-%<testlatex>[1970/01/01]
-{test-modutils}
-%<testplain>{1970/01/01}
+\RequireLuaModule{test-modutils}
+\RequireLuaModule{test-modutils}[1970/01/01]
%</testplain,testlatex>
%<testplain>\bye
%<testlatex>\stop
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-regs.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-regs.dtx
index 08d1060ab23..079b0045fba 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-regs.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-regs.dtx
@@ -103,11 +103,7 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase-regs} package}
-% \date{v0.2a 2010/05/27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase-regs}{2010/10/10 v0.3}
%
% \maketitle
%
@@ -211,7 +207,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase-regs}[2010/05/27 v0.2a Registers allocation for LuaTeX]
+\x{luatexbase-regs}[2010/10/10 v0.3 Registers allocation for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -225,14 +221,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase-regs}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@regs@AtEnd
\expandafter\endinput
\fi
@@ -267,7 +266,7 @@ See source file '\inFileName' for details.
\let\x\PackageWarningNoLine
\fi
\expandafter\endgroup
- \x{luatexbase-regs}{etex macros not loaded!^^J
+ \x{luatexbase-regs}{etex macros not loaded!^^J%
Registers allocation scheme will not be extended.}
\else
% \end{macrocode}
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase.dtx
index 3e14f4cf1f4..405e72007de 100644
--- a/Master/texmf-dist/source/luatex/luatexbase/luatexbase.dtx
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase.dtx
@@ -96,24 +96,20 @@ See source file '\inFileName' for details.
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \title{The \pk{luatexbase} package}
-% \date{v0.2a 2010-05-27}
-% \author{%
-% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
-% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+% \pkdate{luatexbase}{v0.3 2010-05-27}
%
% \maketitle
%
% \begin{abstract}
-% This convenience package loads all of the (stable) packages in the
-% \pk{luatexbase} bundle.
+% This package provides resource management for the LuaTeX macro programmer.
+% It is divided in sub-packages which can be used independantly if desired.
% \end{abstract}
%
% \tableofcontents
%
% \section{Documentation}
%
-% The \pk{luatexbase} package loads the following packages:
+% The \pk{luatexbase} package consists of the following sub-packages:
% \begin{description}
% \subpk{compat} compatibility helpers for \verb+\directlua+, primitive
% names and version information from Lua.
@@ -124,25 +120,19 @@ See source file '\inFileName' for details.
% \emph{\`a la} \pk{etex}.
% \subpk{cctb} catcode table allocation.
% \subpk{attr} attribute allocation.
-% \end{description}
-%
-% These packages are almost stable: it is unlikely that backward-incompatible
-% changes will be made in the future (other than necessary for merging with
-% \pk{luatex.sty}, which strongly overlaps with the above). If they happen,
-% such changes will be announced on \email{lualatex-dev@tug.org} before they
-% are pushed to the master branch and then CTAN.
-%
-% Other packages included in the bundle, but currently not loaded by the
-% present package, are:
-% \begin{description}
-% \subpk{modutils} Lua module declaration, including version checks.
% \subpk{mcb} callbacks extensions allowing to register many functions in a
% single callback, and declare new callbacks for packages.
+% \subpk{modutils} Lua module declaration, including version checks.
% \end{description}
%
-% All packages in this bundle are supposed to work with \luatex 0.25.4 to
-% 0.60.x, with formats based on \plaintex or \latex, as included in \texlive
-% 2008, 2009, and 2010.
+% The package is mostly stable: it is unlikely that backward-incompatible
+% changes will be made in the future, other than necessary for merging with
+% \pk{luatex.sty}, with which a few sub-packages strongly overlap. If they do
+% happen, such changes will be announced on the development list, and clearly
+% identified in the \file{Changes} file.
+%
+% All sub-packages are tested with \luatex 0.25.4 to 0.60.x and formats based
+% on \plaintex or \latex, as included in \texlive 2008, 2009, and 2010.
%
% \section{Implementation}
%
@@ -206,7 +196,7 @@ See source file '\inFileName' for details.
\let\x\ProvidesPackage
\fi
\expandafter\endgroup
-\x{luatexbase}[2010/05/27 v0.2a Module utilities for LuaTeX]
+\x{luatexbase}[2010/10/06 v0.3 Module utilities for LuaTeX]
% \end{macrocode}
%
% Make sure \luatex is used.
@@ -220,14 +210,17 @@ See source file '\inFileName' for details.
\fi
\ifluatex\else
\begingroup
- \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax
- \def\x#1#2{\begingroup\newlinechar10
- \immediate\write16{Package #1 warning: #2}\endgroup}
+ \expandafter\ifx\csname PackageError\endcsname\relax
+ \def\x#1#2#3{\begingroup \newlinechar10
+ \errhelp{#3}\errmessage{Package #1 error: #2}\endgroup}
\else
- \let\x\PackageWarningNoLine
+ \let\x\PackageError
\fi
\expandafter\endgroup
- \x{luatexbase}{LuaTeX is required for this package. Aborting.}
+ \x{luatexbase-attr}{LuaTeX is required for this package. Aborting.}{%
+ This package can only be used with the LuaTeX engine^^J%
+ (command `lualatex' or `luatex').^^J%
+ Package loading has been stopped to prevent additional errors.}
\lltxb@core@AtEnd
\expandafter\endinput
\fi
@@ -243,12 +236,16 @@ See source file '\inFileName' for details.
\input luatexbase-regs.sty
\input luatexbase-attr.sty
\input luatexbase-cctb.sty
+ \input luatexbase-mcb.sty
+ \input luatexbase-modutils.sty
\else
\RequirePackage{luatexbase-compat}
\RequirePackage{luatexbase-loader}
\RequirePackage{luatexbase-regs}
\RequirePackage{luatexbase-attr}
\RequirePackage{luatexbase-cctb}
+ \RequirePackage{luatexbase-mcb}
+ \RequirePackage{luatexbase-modutils}
\fi
% \end{macrocode}
%