summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luatexbase
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/luatex/generic/luatexbase
Initial commit
Diffstat (limited to 'macros/luatex/generic/luatexbase')
-rw-r--r--macros/luatex/generic/luatexbase/README.md7
-rw-r--r--macros/luatex/generic/luatexbase/luatexbase.dtx860
-rw-r--r--macros/luatex/generic/luatexbase/luatexbase.ins19
-rw-r--r--macros/luatex/generic/luatexbase/luatexbase.pdfbin0 -> 263467 bytes
4 files changed, 886 insertions, 0 deletions
diff --git a/macros/luatex/generic/luatexbase/README.md b/macros/luatex/generic/luatexbase/README.md
new file mode 100644
index 0000000000..bbcb8d4654
--- /dev/null
+++ b/macros/luatex/generic/luatexbase/README.md
@@ -0,0 +1,7 @@
+The LaTeX kernel (LaTeX2e 2015/10/01 onward) builds in support for
+LuaTeX functionality, also available as `ltluatex.tex` for users for
+users of plain TeX and those with older LaTeX kernel implementations.
+This support is based on ideas taken from the original `luatexbase`
+package, but there are interface differences. This 'stub' package
+provides a compatibility layer to allow existing packages to upgrade
+smoothly to the new support structure.
diff --git a/macros/luatex/generic/luatexbase/luatexbase.dtx b/macros/luatex/generic/luatexbase/luatexbase.dtx
new file mode 100644
index 0000000000..a00e9481d1
--- /dev/null
+++ b/macros/luatex/generic/luatexbase/luatexbase.dtx
@@ -0,0 +1,860 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2009-2013 by Élie Roux <elie.roux@telecom-bretagne.eu>
+% Copyright (C) 2010, 2011 by Manuel Pégourié-Gonnard <mpg@elzevir.fr>
+% Copyright (C) 2015 David Carlisle and Joseph Wright
+%
+% It may be distributed and/or modified under the conditions of
+% the LaTeX Project Public License (LPPL), either version 1.3c of
+% this license or (at your option) any later version. The latest
+% version of this license is in the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+%<emu>\ifx\BeginCatcodeRegime\undefined\else\expandafter\endinput\fi
+%<tex,sty>
+%<tex,sty>\ifx
+%<sty> \ProvidesPackage\undefined\begingroup\def\ProvidesPackage
+%<tex> \ProvidesFile\undefined\begingroup\def\ProvidesFile
+%<tex,sty> #1#2[#3]{\endgroup\immediate\write-1{Package: #1 #3}}
+%<tex,sty>\fi
+%<emu>\ProvidesPackage{luatexbase}
+%<emu-cmp>\ProvidesPackage{luatexbase-compat}
+%<emu-mod>\ProvidesPackage{luatexbase-modutils}
+%<emu-loa>\ProvidesPackage{luatexbase-loader}
+%<emu-reg>\ProvidesPackage{luatexbase-regs}
+%<emu-att>\ProvidesPackage{luatexbase-attr}
+%<emu-cct>\ProvidesPackage{luatexbase-cctb}
+%<emu-mcb>\ProvidesPackage{luatexbase-mcb}
+%<*driver>
+\ProvidesFile{luatexbase.dtx}
+%</driver>
+%<*tex,sty>
+[2015/10/04 v1.3
+%</tex,sty>
+%<emu> luatexbase interface to LuaTeX
+%<emu-cmp> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-mod> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-loa> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-reg> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-att> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-cct> luatexbase interface to LuaTeX (legacy subpackage)
+%<emu-mcb> luatexbase interface to LuaTeX (legacy subpackage)
+%<*tex,sty>
+]
+%</tex,sty>
+%<*driver>
+\documentclass{ltxdoc}
+\GetFileInfo{luatexbase.dtx}
+\begin{document}
+\title{\filename\\(Lua\TeX{}-specific support, luatexbase interface)}
+\author{David Carlisle and Joseph Wright\footnote{Significant portions
+ of the code here are adapted/simplified from the packages \textsf{luatex} and
+ \textsf{luatexbase} written by Heiko Oberdiek, \'{E}lie Roux,
+ Manuel P\'{e}gouri\'{e}-Gonnar and Philipp Gesang.}}
+\date{\filedate}
+\maketitle
+\setcounter{tocdepth}{2}
+\tableofcontents
+\DocInput{\filename}
+\end{document}
+%</driver>
+% \fi
+%
+% \section{Overview}
+%
+% Lua\TeX{} adds a number of engine-specific functions to \TeX{}. Support
+% for those is now available for this area in the \LaTeX{} kernel and as
+% an equivalent stand-alone file |ltluatex.tex| for plain users. The
+% functionality there is derived from the earlier \textsf{luatex}
+% and \textsf{luatexbase} packages by Heiko Oberdiek, \'{E}lie Roux,
+% Manuel P\'{e}gouri\'{e}-Gonnar and Philipp Gesang. However, the
+% interfaces are not all identical.
+%
+% The interfaces defined in this package are closely modelled on the original
+% \textsf{luatexbase} package, and provide a compatibility layer between
+% the new kernel-level support and existing code using \textsf{luatexbase}.
+%
+% \section{The \textsf{luatexbase} package interface}
+%
+% \subsection
+% [Catcode tables]
+% {Catcode tables\footnote{This
+% interface was previously defined in the \textsf{luatexbase-cctbl}
+% sub-package.}}
+%
+% \subsubsection{\TeX}
+%
+%
+% \noindent
+% \DescribeMacro{\CatcodeTableIniTeX}
+% \DescribeMacro{\CatcodeTableString}
+% \DescribeMacro{\CatcodeTableLaTeX}
+% \DescribeMacro{\CatcodeTableLaTeXAtLetter}
+% \DescribeMacro{\CatcodeTableOther}
+% \DescribeMacro{\CatcodeTableExpl}
+% \TeX\ access to predefined catcode tables.
+%
+% The first four tables are aliases giving alternative names for some
+% catcodetables that are defined in the \textsf{ltluatex} core.
+%
+% |\CatcodeTableOther| is like |\CatcodeTableString| except that
+% the catcode of space is $12$ (other).
+%
+% |\CatcodeTableExpl| is similar to the environment set by the
+% \textsf{expl3} command |\ExplSyntaxOn| note that this only affects
+% catcode settings, not for example |\endlinechar|.
+%
+% One difference between this implementation and the tables defined
+% in the earlier \textsf{luatexbase} package is that these tables are
+% defined to match the settings used by \LaTeX\ over the full Unicode
+% range (as set in the file \textsf{unicode-letters.def}).
+%
+% \noindent
+% \DescribeMacro{\SetCatcodeRange}
+% An alias for |\@setrangecatcode| which is defined in the
+% \textsf{ctablestack} package imported into this version of
+% \textsf{luatexbase}. (The order of arguments is the
+% same despite the variation in the naming). This is useful for
+% setting up a new catcode table and assigns a given catcode to a
+% range of characters.
+%
+% \noindent
+% \DescribeMacro{\BeginCatcodeRegime}
+% \DescribeMacro{\EndCatcodeRegime}
+% A simple wrapper around |\@pushcatcodetable| providing a slightly
+% different interface. The usage is:\\%
+% \verb|\BeginCatcodeRegime|\meta{catcode table}\\
+% \verb| |\meta{code}\\
+% \verb|\EndCatcodeRegime|
+%
+% \noindent
+% \DescribeMacro{\PushCatcodeTableNumStack}
+% \DescribeMacro{\PopCatcodeTableNumStack}
+% These are defined to be aliases for |\@pushcatcodetable| and
+% |\@popcatcodetable| although the actual implementation is quite different
+% to the older packages, the use of the commands should match.
+%
+% \noindent
+% \DescribeMacro{\newluatexcatcodetable}
+% \DescribeMacro{\setluatexcatcodetable}
+% Aliases for the \textsf{ltluatex} functions
+% dropping |luatex| from the name to match the convention of not
+% using |luatex|-prefixed names for the Lua\TeX\ primitives.
+%
+% \subsubsection{Lua}
+%
+% The standard way to access catcode table numbers from Lua in
+% \textsf{ltluatex} is the |registernumber| function. This
+% package provides a |catcodetables| table with a metatable
+% that accesses this function and is extended with aliases for the
+% predefined tables so you can use |catcodetables.expl| as an
+% alternative to |catcodetables.CatcodeTableExpl|, both being
+% equivalent to\\
+% |registernumber('CatcodeTableExpl')|.
+%
+%
+% \subsection
+% [Lua Callbacks]
+% {Lua Callbacks\footnote{This
+% interface was previously defined in the \textsf{luatexbase-mcb}
+% sub-package.}}
+%
+% The |luatexbase| table is extended with some additional Lua
+% functions to provide the interfaces provided by the previous
+% implementation.
+%
+%
+% \noindent
+% \DescribeMacro{priority\_in\_callback}\meta{name}\meta{description}\\%
+% As in the earlier interfaces the function
+% is provided to return a number indicating the position of a
+% specified function in a callback list. However it is usually used
+% just as a boolean test that the function is registered with the
+% callback. Kernel-level support does not directly expose the priority numbers,
+% however the function here is defined to return the number of the specified
+% function in the list returned by |luatexbase.callback_descriptions|.
+%
+%
+% \noindent
+% \DescribeMacro{is\_active\_callback}\meta{name}\meta{description}\\%
+% This boolean function was defined in the development sources
+% of the previous implementation. Here it is defined as an alias for
+% the function |in_callback| provided by \textsf{ltluatex}.
+% Given a callback and a description string, it returns true if a
+% callback function with that description is currently registered.
+%
+% \noindent
+% \DescribeMacro{reset\_callback}\meta{name}\meta{make\_false}\\
+% This function unregisters all functions registered for the callback
+% \meta{name}. If \meta{make\_false} is true, the callback is then set
+% to false (rather than nil). Unlike the earlier implementation
+% This version does call |remove_from_callback| on each function in
+% the callback list for \meta{name}, and each removal will be recorded
+% in the log.
+%
+% \noindent
+% \DescribeMacro{remove\_from\_callback}\meta{name}\meta{description}\\%
+% This function is unchanged from the kernel-level implementation.
+% It is backward compatible with the previous \textsf{luatexbase}
+% package but enhanced as it returns the removed callback and its
+% description.
+% Together with the |callback_descriptions| function this allows much
+% finer control over the order of functions in a callback list as the
+% functions can be removed then re-added to the list in any desired order.
+%
+% \noindent
+% \DescribeMacro{add\_to\_callback}\meta{name}\meta{function}\meta{description}\meta{priority}\\%
+% This function is defined as a wrapper around the kernel-level
+% implementation, which does not have the fourth \meta{priority}
+% argument.
+%
+% If multiple callbacks are registered to a callback of type
+% \textsf{exclusive} then \textsf{ltluatex} raises an error, but
+% here it is allowed if \texttt{priority} is $1$, in which case the
+% \verb|reset_callback| is first called to remove the existing
+% callback.
+%
+% In general the \texttt{priority} argument is implemented by
+% temporarily removing some callbacks from the list and replacing
+% them after having added the new callback.
+%
+% \noindent
+% \DescribeMacro{create\_callback}\meta{name}\meta{type}\meta{default}\\%
+% This function is unchanged from kernel-level
+% implementation, the only change is a change of terminology for the
+% types of callback, the type |first| is now classified as |exclusive|
+% and the kernel code raises an error if multiple callback functions
+% are registered. The previous \textsf{luatexbase} implementation
+% allowed multiple functions to be registered, but only activated the
+% first in the list.
+%
+% \subsection
+% [Module declaration]
+% {Module declaration\footnote{This
+% interface was previously defined in the \textsf{luatexbase-modutils}
+% sub-package.}}
+%
+% \subsubsection{\TeX}
+%
+% \noindent
+% \DescribeMacro{\RequireLuaModule}\meta{file}\oarg{info}\\
+% This command is provided as a wrapper around
+% |\directlua{require(|\meta{file}|}|, and executes the Lua code in
+% the specified file.
+% The optional argument is accepted but ignored.
+%
+% Current versions of Lua\TeX\ all use the |kpse| \TeX\ path searching
+% library with the |require| function, so the more complicated
+% definition used in earlier implementations is no
+% longer needed.
+%
+% \subsubsection{Lua}
+%
+% \noindent
+% \DescribeMacro{provides\_module}\meta{info}\\
+% The \textsf{luatexbase} version of |provides_module| returns a list of log
+% and error functions so that it is usually called as:\\
+% |local err, warning, info, log = luatexbase.provides_module({name=..|
+%
+% The returned functions are all instances of the functions provided by
+% the kernel: |module_error|,
+% |module_warning| and |module_info|, They all use their first argument
+% as a format string fo rany later arguments.
+%
+% \DescribeMacro{errwarinf}\meta{name}\\
+% Returns four error and warning functions associated with \meta{name}
+% mostly a helper function for \verb|provides\_module|, but can be called
+% separately.
+%
+% \subsection
+% [Lua Attributes]
+% {Lua Attributes and Whatsits\footnote{This
+% interface was previously defined in the \textsf{luatexbase-attr}
+% sub-package.}}
+%
+%
+% \subsubsection{\TeX}
+%
+% \noindent
+% \DescribeMacro{\newluatexattribute}
+% \DescribeMacro{\setluatexattribute}
+% \DescribeMacro{\unsetluatexattribute}
+% As for catcode tables, aliases for the attribute allocation functions are
+% provided with |luatex| in the names.
+%
+%
+% \subsubsection{Lua}
+% The lua code in this section is concerned with an experimental
+% whatsit handling suite of functions in the original package.
+% This is not fully documented here and is guraded by the
+% \textsf{docstrip} guard \verb|whatsit| so it may optionally be
+% included or excluded from the sources when the package is built.
+%
+% \subsection{Prefixed names for lua\TeX\ primitives}
+% \noindent
+% \DescribeMacro{\luatexattributedef}
+% \DescribeMacro{\luatexcatcodetable}
+% \DescribeMacro{\luatexluaescapestring}
+% \DescribeMacro{\luatexlatelua}
+% \DescribeMacro{\luatexoutputbox}
+% \DescribeMacro{\luatexscantextokens}
+% Aliases for commonly ued lua\TeX\ primitives that existing packages
+% using \textsf{luatexbase} use with prefixed names.
+%
+% If additional primtives are required it is recommended that the
+% code is updated to use unprefixed names. To ensure that the code
+% works with the original \textsf{luatexbase} package on older formats
+% you may use the lua function \texttt{tex.enableprimitives} to enable
+% some or all primitives to be available with unprefixed names.
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+%
+% \subsection{\textsf{luatexbase} interface}
+%
+% \begin{macrocode}
+%<*emu>
+\edef\emuatcatcode{\the\catcode`\@}
+\catcode`\@=11
+% \end{macrocode}
+%
+% Load |ctablestack|.
+% \begin{macrocode}
+\ifx\@setrangecatcode\@undefined
+ \ifx\RequirePackage\@undefined
+ \input{ctablestack.sty}%
+ \else
+ \RequirePackage{ctablestack}
+ \fi
+\fi
+% \end{macrocode}
+%
+% Simple require wrapper as we now assume |require| implicitly uses the
+% |kpathsea| search library.
+% \begin{macrocode}
+\def\RequireLuaModule#1{\directlua{require("#1")}\@gobbleoptarg}
+% \end{macrocode}
+%
+% In \LaTeX\ (or plain macro package that has defined |\@ifnextchar|)
+% use |\@ifnextchar| otherwise use a simple alternative, in practice this
+% will never be followed by a brace group, so full version of |\@ifnextchar|
+% not needed.
+% \begin{macrocode}
+\ifdefined\@ifnextchar
+\def\@gobbleoptarg{\@ifnextchar[\@gobble@optarg{}}%
+\else
+\long\def\@gobbleoptarg#1{\ifx[#1\expandafter\@gobble@optarg\fi#1}%
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\@gobble@optarg[#1]{}
+% \end{macrocode}
+%
+% Extended catcode table support. Use the names from the previous
+% \textsf{luatexbase} and \textsf{luatex} packages.
+% \begin{macrocode}
+\let\CatcodeTableIniTeX\catcodetable@initex
+\let\CatcodeTableString\catcodetable@string
+\let\CatcodeTableLaTeX\catcodetable@latex
+\let\CatcodeTableLaTeXAtLetter\catcodetable@atletter
+% \end{macrocode}
+%
+% Additional tables declared in the previous interface.
+% \begin{macrocode}
+\newcatcodetable\CatcodeTableOther
+\@setcatcodetable\CatcodeTableOther{%
+ \catcodetable\CatcodeTableString
+ \catcode32 12 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcatcodetable\CatcodeTableExpl
+\@setcatcodetable\CatcodeTableExpl{%
+ \catcodetable\CatcodeTableLaTeX
+ \catcode126 10 % tilde is a space char
+ \catcode32 9 % space is ignored
+ \catcode9 9 % tab also ignored
+ \catcode95 11 % underscore letter
+ \catcode58 11 % colon letter
+}
+% \end{macrocode}
+%
+% Top level access to catcodetable stack.
+% \begin{macrocode}
+\def\BeginCatcodeRegime#1{%
+ \@pushcatcodetable
+ \catcodetable#1\relax}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\EndCatcodeRegime{%
+ \@popcatcodetable}
+% \end{macrocode}
+%
+% The implementation of the stack is completely
+% different, but usage should match.
+% \begin{macrocode}
+\let\PushCatcodeTableNumStack\@pushcatcodetable
+\let\PopCatcodeTableNumStack\@popcatcodetable
+% \end{macrocode}
+%
+% A simple copy.
+% \begin{macrocode}
+\let\SetCatcodeRange\@setrangecatcode
+% \end{macrocode}
+%
+% Another copy.
+% \begin{macrocode}
+\let\setcatcodetable\@setcatcodetable
+% \end{macrocode}
+%
+% \subsubsection{Additional lua code}
+% \begin{macrocode}
+\directlua{
+% \end{macrocode}
+%
+% Remove all registered callbacks, then disable.
+% Set to false if optional second argument is |true|.
+% \begin{macrocode}
+function luatexbase.reset_callback(name,make_false)
+ for _,v in pairs(luatexbase.callback_descriptions(name))
+ do
+ luatexbase.remove_from_callback(name,v)
+ end
+ if make_false == true then
+ luatexbase.disable_callback(name)
+ end
+end
+% \end{macrocode}
+%
+% Allow exclusive callbacks to be over-written if priority argument is
+% 1 to match the ``first'' semantics of the original package.
+% \changes{v1.1}{2015/10/02}{Fully handle priority argument}
+%
+% First save the kernel function.
+% \begin{macrocode}
+luatexbase.base_add_to_callback=luatexbase.add_to_callback
+% \end{macrocode}
+%
+% Implement the priority argument by taking off existing callbacks
+% that have higher priority than the new one, adding the new one,
+% Then putting the saved callbacks back.
+% \begin{macrocode}
+function luatexbase.add_to_callback(name,fun,description,priority)
+% \end{macrocode}
+%^^A texio.write_nl('\string\n HERE: adding ' ..
+%^^A description ..
+%^^A ' to ' ..
+%^^A name ..
+%^^A ' with priority ' ..
+%^^A (priority or '@@@'))
+%^^A texio.write_nl('Original list')
+%^^A for k,v in pairs(luatexbase.callback_descriptions(name)) do
+%^^A texio.write_nl(' ' .. k .. ': ' .. v)
+%^^A end
+% \begin{macrocode}
+ local priority= priority
+ if priority==nil then
+ priority=\string#luatexbase.callback_descriptions(name)+1
+ end
+ if(luatexbase.callbacktypes[name] == 3 and
+ priority == 1 and
+ \string#luatexbase.callback_descriptions(name)==1) then
+ luatexbase.module_warning("luatexbase",
+ "resetting exclusive callback: " .. name)
+ luatexbase.reset_callback(name)
+ end
+ local saved_callback={},ff,dd
+ for k,v in pairs(luatexbase.callback_descriptions(name)) do
+ if k >= priority then
+ ff,dd= luatexbase.remove_from_callback(name, v)
+ saved_callback[k]={ff,dd}
+ end
+ end
+ luatexbase.base_add_to_callback(name,fun,description)
+ for k,v in pairs(saved_callback) do
+ luatexbase.base_add_to_callback(name,v[1],v[2])
+ end
+% \end{macrocode}
+%^^A texio.write_nl('New list')
+%^^A for k,v in pairs(luatexbase.callback_descriptions(name)) do
+%^^A texio.write_nl(' ' .. k .. ': ' .. v)
+%^^A end
+% \begin{macrocode}
+ return
+end
+% \end{macrocode}
+%
+% Emulate the catcodetables table.
+% Explicitly fill the table rather than rely on the metatable call to
+% |registernumber| as that is unreliable on old Lua\TeX{}.
+% \begin{macrocode}
+luatexbase.catcodetables=setmetatable(
+ {['latex-package'] = \number\CatcodeTableLaTeXAtLetter,
+ ini = \number\CatcodeTableIniTeX,
+ string = \number\CatcodeTableString,
+ other = \number\CatcodeTableOther,
+ latex = \number\CatcodeTableLaTeX,
+ expl = \number\CatcodeTableExpl,
+ expl3 = \number\CatcodeTableExpl},
+ { __index = function(t,key)
+ return luatexbase.registernumber(key) or nil
+ end}
+)}
+% \end{macrocode}
+%
+% On old Lua\TeX{} workaround hashtable issues.
+% Allocate in \TeX{}, and also directly add to |luatexbase.catcodetables|.
+% \begin{macrocode}
+\ifnum\luatexversion<80 %
+\def\newcatcodetable#1{%
+ \e@alloc\catcodetable\chardef
+ \e@alloc@ccodetable@count\m@ne{"8000}#1%
+ \initcatcodetable\allocationnumber
+ {\escapechar=\m@ne
+ \directlua{luatexbase.catcodetables['\string#1']=%
+ \the\allocationnumber}}%
+}
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\directlua{
+% \end{macrocode}
+%
+% |priority_in_callback| returns position in the callback list.
+% Not provided by default by the kernel as usually it is just used
+% as a boolean test, for which |in_callback| is provided.
+% \begin{macrocode}
+function luatexbase.priority_in_callback (name,description)
+ for i,v in ipairs(luatexbase.callback_descriptions(name))
+ do
+ if v == description then
+ return i
+ end
+ end
+ return false
+end
+% \end{macrocode}
+%
+% The (unreleased) version~0.7 of \textsf{luatexbase} provided this
+% boolean test under a different name, so we provide an alias here.
+% \begin{macrocode}
+luatexbase.is_active_callback = luatexbase.in_callback
+% \end{macrocode}
+%
+% \textsf{ltluatex} implementation of |provides_module| does not return
+% print functions so define modified version here.
+% \changes{v1.3}{2015/10/03}{Use the first argument as a format string for
+% later arguments}
+% \begin{macrocode}
+luatexbase.base_provides_module=luatexbase.provides_module
+function luatexbase.errwarinf(name)
+ return
+ function(s,...) return luatexbase.module_error(name, s:format(...)) end,
+ function(s,...) return luatexbase.module_warning(name, s:format(...)) end,
+ function(s,...) return luatexbase.module_info(name, s:format(...)) end,
+ function(s,...) return luatexbase.module_info(name, s:format(...)) end
+end
+function luatexbase.provides_module(info)
+ luatexbase.base_provides_module(info)
+ return luatexbase.errwarinf(info.name)
+end
+}
+% \end{macrocode}
+%
+% Same for attribute table as catcode tables. In old Lua\TeX{}, add to the
+% |luatexbase.attributes| table directly.
+% \begin{macrocode}
+\ifnum\luatexversion<80 %
+\def\newattribute#1{%
+ \e@alloc\attribute\attributedef
+ \e@alloc@attribute@count\m@ne\e@alloc@top#1%
+ {\escapechar=\m@ne
+ \directlua{luatexbase.attributes['\string#1']=%
+ \the\allocationnumber}}%
+}
+\fi
+% \end{macrocode}
+%
+% Define a safe percent command for plain \TeX.
+% \begin{macrocode}
+\ifx\@percentchar\@undefined
+ {\catcode`\%=12 \gdef\@percentchar{%}}
+\fi
+% \end{macrocode}
+% \changes{v1.2a}{2015/10/03}{Add missing local definitions for whatsit code}
+%
+% \begin{macrocode}
+%<*whatsit>
+\directlua{%
+% \end{macrocode}
+%
+% \begin{macrocode}
+local copynode = node.copy
+local newnode = node.new
+local nodesubtype = node.subtype
+local nodetype = node.id
+local stringformat = string.format
+local tableunpack = unpack or table.unpack
+local texiowrite_nl = texio.write_nl
+local texiowrite = texio.write
+local whatsit_t = nodetype"whatsit"
+local user_defined_t = nodesubtype"user_defined"
+local unassociated = "__unassociated"
+local user_whatsits = { __unassociated = { } }
+local whatsit_ids = { }
+local anonymous_whatsits = 0
+local anonymous_prefix = "anon"
+% \end{macrocode}
+%
+% User whatsit allocation is split into two functions:
+% \verb|new_user_whatsit_id| registers a new id (an integer)
+% and returns it. This is a wrapper around \verb|new_whatsit|
+% but with the extra \texttt{package} argument, and recording
+% the mapping in lua tables
+%
+% If no name given, generate a name from a counter.
+%
+% \begin{macrocode}
+local new_user_whatsit_id = function (name, package)
+ if name then
+ if not package then
+ package = unassociated
+ end
+ else % anonymous
+ anonymous_whatsits = anonymous_whatsits + 1
+ warning("defining anonymous user whatsit no. \@percentchar
+ d", anonymous_whatsits)
+ package = unassociated
+ name = anonymous_prefix .. tostring(anonymous_whatsits)
+ end
+
+ local whatsitdata = user_whatsits[package]
+ if not whatsitdata then
+ whatsitdata = { }
+ user_whatsits[package] = whatsitdata
+ end
+
+ local id = whatsitdata[name]
+ if id then %- warning
+ warning("replacing whatsit \@percentchar s:\@percentchar
+ s (\@percentchar d)", package, name, id)
+ else %- new id
+ id=luatexbase.new_whatsit(name)
+ whatsitdata[name] = id
+ whatsit_ids[id] = { name, package }
+ end
+ return id
+end
+luatexbase.new_user_whatsit_id = new_user_whatsit_id
+% \end{macrocode}
+%
+% \verb|new_user_whatsit| first registers a new id and then also
+% creates the corresponding whatsit node of subtype “user-defined”.
+% Return a nullary function that delivers copies of the whatsit.
+%
+% Alternatively, the first argument can be a whatsit node that
+% will then be used as prototype.
+%
+% \begin{macrocode}
+local new_user_whatsit = function (req, package)
+ local id, whatsit
+ if type(req) == "string" then
+ id = new_user_whatsit_id(req, package)
+ whatsit = newnode(whatsit_t, user_defined_t)
+ whatsit.user_id = id
+ elseif req.id == whatsit_t and req.subtype == user_defined_t then
+ id = req.user_id
+ whatsit = copynode(req)
+ if not whatsit_ids[id] then
+ warning("whatsit id \@percentchar d unregistered; "
+ .. "inconsistencies may arise", id)
+ end
+ end
+ return function () return copynode(whatsit) end, id
+end
+luatexbase.new_user_whatsit = new_user_whatsit
+% \end{macrocode}
+%
+% If one knows the name of a user whatsit, its corresponding id
+% can be retrieved by means of \verb|get_user_whatsit_id|.
+%
+% \begin{macrocode}
+local get_user_whatsit_id = function (name, package)
+ if not package then
+ package = unassociated
+ end
+ return user_whatsits[package][name]
+end
+luatexbase.get_user_whatsit_id = get_user_whatsit_id
+% \end{macrocode}
+%
+% The inverse lookup is also possible via \verb|get_user_whatsit_name|.
+% \begin{macrocode}
+local get_user_whatsit_name = function (asked)
+ local id
+ if type(asked) == "number" then
+ id = asked
+ elseif type(asked) == "function" then
+ %- node generator
+ local n = asked()
+ id = n.user_id
+ else %- node
+ id = asked.user_id
+ end
+ local metadata = whatsit_ids[id]
+ if not metadata then % unknown
+ warning("whatsit id \@percentchar d unregistered;
+ inconsistencies may arise", id)
+ return "", ""
+ end
+ return tableunpack(metadata)
+end
+luatexbase.get_user_whatsit_name = get_user_whatsit_name
+% \end{macrocode}
+% A function that outputs the
+% current allocation status to the terminal.
+%
+% \begin{macrocode}
+local dump_registered_whatsits = function (asked_package)
+ local whatsit_list = { }
+ if asked_package then
+ local whatsitdata = user_whatsits[asked_package]
+ if not whatsitdata then
+ error("(no user whatsits registered for package
+ \@percentchar s)", asked_package)
+ return
+ end
+ texiowrite_nl("(user whatsit allocation stats for " ..
+ asked_package)
+ for name, id in next, whatsitdata do
+ whatsit_list[\string#whatsit_list+1] =
+ stringformat("(\@percentchar s:\@percentchar
+ s \@percentchar d)", asked_package, name, id)
+ end
+ else
+ texiowrite_nl("(user whatsit allocation stats")
+ texiowrite_nl(stringformat(" ((total \@percentchar d)\string\n
+ (anonymous \@percentchar d))",
+ current_whatsit, anonymous_whatsits))
+ for package, whatsitdata in next, user_whatsits do
+ for name, id in next, whatsitdata do
+ whatsit_list[\string#whatsit_list+1] =
+ stringformat("(\@percentchar s:\@percentchar
+ s \@percentchar d)", package, name, id)
+ end
+ end
+ end
+ texiowrite_nl" ("
+ local first = true
+ for i=1, \string#whatsit_list do
+ if first then
+ first = false
+ else % indent
+ texiowrite_nl" "
+ end
+ texiowrite(whatsit_list[i])
+ end
+ texiowrite"))\string\n"
+end
+luatexbase.dump_registered_whatsits = dump_registered_whatsits
+% \end{macrocode}
+% Lastly, we define a couple synonyms for convenience.
+% \begin{macrocode}
+luatexbase.newattribute = new_attribute
+luatexbase.newuserwhatsit = new_user_whatsit
+luatexbase.newuserwhatsitid = new_user_whatsit_id
+luatexbase.getuserwhatsitid = get_user_whatsit_id
+luatexbase.getuserwhatsitname = get_user_whatsit_name
+luatexbase.dumpregisteredwhatsits = dump_registered_whatsits
+% \end{macrocode}
+%
+% \begin{macrocode}
+}
+%</whatsit>
+% \end{macrocode}
+%
+% Resolve name clashes and prefixed name issues.
+%
+% Top level \textsf{luatexbase} macros
+% \begin{macrocode}
+\let\newluatexattribute\newattribute
+\let\setluatexattribute\setattribute
+\let\unsetluatexattribute\unsetattribute
+\let\newluatexcatcodetable\newcatcodetable
+\let\setluatexcatcodetable\setcatcodetable
+% \end{macrocode}
+%
+% Internal \textsf{luatexbase} macros
+% \begin{macrocode}
+\let\luatexbase@directlua\directlua
+\let\luatexbase@ensure@primitive\@gobble
+% \end{macrocode}
+%
+% Lua\TeX\ primitives
+% \begin{macrocode}
+\let\luatexattribute\attribute
+\let\luatexattributedef\attributedef
+\let\luatexcatcodetable\catcodetable
+\let\luatexluaescapestring\luaescapestring
+\let\luatexlatelua\latelua
+\let\luatexoutputbox\outputbox
+\let\luatexscantextokens\scantextokens
+% \end{macrocode}
+%
+% Reset catcode of |@|.
+% \begin{macrocode}
+\catcode`\@=\emuatcatcode\relax
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</emu>
+% \end{macrocode}
+%
+% \subsection{Legacy \textsf{luatexbase} sub-packages}
+%
+% The original \textsf{luatexbase} was comprised of seven sub packages
+% that could in principle be loaded separately. Here we define them all
+% with the same code that just loads the main package, they are
+% distinguished just by the |\ProvidesPackage| specified above at the start
+% of the file.
+% \begin{macrocode}
+%<*emu-cmp,emu-mod,emu-loa,emu-reg,emu-att,emu-cct,emu-mcb>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ifx\RequirePackage\undefined
+ \input{luatexbase.sty}%
+\else
+ \RequirePackage{luatexbase}
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</emu-cmp,emu-mod,emu-loa,emu-reg,emu-att,emu-cct,emu-mcb>
+% \end{macrocode}
+%
+% \subsection{Legacy Lua code}
+%
+% \changes{v1.2}{2015/10/03}{Provide \texttt{luatexbase.loader.lua}}
+%
+% The original \textsf{luatexbase} included a file |luatexbase.loader.lua|
+% that could be loaded independently of the rest of the package. This really
+% doesn't need to do anything!
+% \begin{macrocode}
+%<*emu-lua>
+% \end{macrocode}
+%
+% \begin{macrocode}
+luatexbase = luatexbase or { }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</emu-lua>
+% \end{macrocode}
+%
+% \Finale
diff --git a/macros/luatex/generic/luatexbase/luatexbase.ins b/macros/luatex/generic/luatexbase/luatexbase.ins
new file mode 100644
index 0000000000..9730a75331
--- /dev/null
+++ b/macros/luatex/generic/luatexbase/luatexbase.ins
@@ -0,0 +1,19 @@
+\input docstrip
+\keepsilent
+\nopreamble
+\nopostamble
+
+\askforoverwritefalse
+
+\generate{\file{luatexbase.sty}{\from{luatexbase.dtx}{sty,emu,whatsit}}}
+\generate{\file{luatexbase-compat.sty}{\from{luatexbase.dtx}{sty,emu-cmp}}}
+\generate{\file{luatexbase-modutils.sty}{\from{luatexbase.dtx}{sty,emu-mod}}}
+\generate{\file{luatexbase-loader.sty}{\from{luatexbase.dtx}{sty,emu-loa}}}
+\generate{\file{luatexbase-regs.sty}{\from{luatexbase.dtx}{sty,emu-reg}}}
+\generate{\file{luatexbase-attr.sty}{\from{luatexbase.dtx}{sty,emu-att}}}
+\generate{\file{luatexbase-cctb.sty}{\from{luatexbase.dtx}{sty,emu-cct}}}
+\generate{\file{luatexbase-mcb.sty}{\from{luatexbase.dtx}{sty,emu-mcb}}}
+
+\generate{\file{luatexbase.loader.lua}{\from{luatexbase.dtx}{emu-lua}}}
+
+\endbatchfile
diff --git a/macros/luatex/generic/luatexbase/luatexbase.pdf b/macros/luatex/generic/luatexbase/luatexbase.pdf
new file mode 100644
index 0000000000..71626c1873
--- /dev/null
+++ b/macros/luatex/generic/luatexbase/luatexbase.pdf
Binary files differ