summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-06-23 00:16:18 +0000
committerKarl Berry <karl@freefriends.org>2009-06-23 00:16:18 +0000
commita6f953f4816835c3e6460c8623361f6cc7978ee5 (patch)
treebebd23f3118698497ca50f1ac3b6f7fcbc49ac4e
parentb3e52d29b04fed8c4f0a8695fbca2b113a36d4ad (diff)
new luatex package luatextra
git-svn-id: svn://tug.org/texlive/trunk@13902 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/README76
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/luaextra.pdfbin0 -> 91521 bytes
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/luamcallbacks-test.tex45
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/luamcallbacks.pdfbin0 -> 100964 bytes
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/luatextra-reference.pdfbin0 -> 104317 bytes
-rw-r--r--Master/texmf-dist/doc/luatex/luatextra/luatextra.pdfbin0 -> 141658 bytes
-rw-r--r--Master/texmf-dist/source/luatex/luatextra/Makefile107
-rw-r--r--Master/texmf-dist/source/luatex/luatextra/luaextra.dtx969
-rw-r--r--Master/texmf-dist/source/luatex/luatextra/luamcallbacks.dtx768
-rw-r--r--Master/texmf-dist/source/luatex/luatextra/luatextra-reference.tex295
-rw-r--r--Master/texmf-dist/source/luatex/luatextra/luatextra.dtx1110
-rw-r--r--Master/texmf-dist/tex/luatex/luatextra/luaextra.lua600
-rw-r--r--Master/texmf-dist/tex/luatex/luatextra/luamcallbacks.lua407
-rw-r--r--Master/texmf-dist/tex/luatex/luatextra/luatextra-latex.tex36
-rw-r--r--Master/texmf-dist/tex/luatex/luatextra/luatextra.lua401
-rw-r--r--Master/texmf-dist/tex/luatex/luatextra/luatextra.sty237
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-luatex.tlpsrc3
-rw-r--r--Master/tlpkg/tlpsrc/luatextra.tlpsrc0
19 files changed, 5055 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/luatex/luatextra/README b/Master/texmf-dist/doc/luatex/luatextra/README
new file mode 100644
index 00000000000..416e28d930c
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/README
@@ -0,0 +1,76 @@
+ The luatextra generic bundle
+
+
+LuaTeXtra is a collection of three coherent packages:
+
+luatextra provides low-level functions for LuaTeX use with LaTeX and Plain, for
+instance the macro \newluaattribute. It also provides a way to use and register
+new lua modules, inspired by the LaTeX packages system.
+
+luamcallback provides a way to register several functions in a LuaTeX callback.
+
+luaextra provides extra lua functions useful for package development.
+
+These packages are really necessary if you want to take advantage of the new
+LuaTeX functions in a safe way.
+
+Note that this package automatically loads luaotfload.
+
+Please see the luatextra-reference.pdf documentation for more details.
+
+This package is developped on <http://github.com/eroux/lualatex/tree/master>.
+
+
+Installation
+------------
+
+Here are the recommended installation methods (preferred first).
+
+1. If you are using TeX Live 2008 or later, use 'tlmgr install luatextra'.
+Alternatively, try your (TeX or Linux) distribution's package management system.
+
+2. a. Grab luatextra.tds.zip on the CTAN.
+ b. Unzip it at the root of one or your TDS trees.
+ c. You may need to update some filename database after this, see your TeX
+distribution's manual for details.
+
+3. a. Grab the sources from CTAN or github.
+ b. Run 'make install TEXMF=/path/to/texmf'.
+ c. See 2c.
+
+4. Try to figure it out by looking at the Makefile and comments in the sources.
+
+
+Manifest
+--------
+
+Source files:
+ luaextra.dtx
+ luamcallbacks.dtx
+ luatextra.dtx
+ luatextra-reference.tex
+
+Derived files:
+ luatextra-reference.pdf introduction to luatextra packages
+ luaextra.pdf
+ luamcallbacks.pdf
+ luatextra.pdf
+ luamcallbacks-test.tex
+ luaextra.lua
+ luamcallbacks.lua
+ luatextra-latex.tex
+ luatextra.lua
+ luatextra.sty
+
+License
+-------
+
+This work and the derived files are under the Creative Commons CC0 license.
+
+See the full text at
+
+http://creativecommons.org/publicdomain/zero/1.0/legalcode
+
+and a FAQ at
+
+http://wiki.creativecommons.org/CC0
diff --git a/Master/texmf-dist/doc/luatex/luatextra/luaextra.pdf b/Master/texmf-dist/doc/luatex/luatextra/luaextra.pdf
new file mode 100644
index 00000000000..617a9f2686f
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/luaextra.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks-test.tex b/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks-test.tex
new file mode 100644
index 00000000000..0ca669b26c5
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks-test.tex
@@ -0,0 +1,45 @@
+%%
+%% This is file `luamcallbacks-test.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% luamcallbacks.dtx (with options: `test')
+%% This is a generated file.
+%%
+%% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%%
+%% This work is under the CC0 license.
+%%
+%% This work consists of the main source file luamcallbacks.dtx
+%% and the derived files
+%% luamcallbacks.lua, luamcallbacks-test.tex, luamcallbacks.pdf.
+%%
+\input luatextra.sty
+
+This is just a test file.
+\luadirect{
+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
+callback.add("hpack_filter",one,"my example function one",1)
+callback.add("hpack_filter",two,"my example function two",2)
+callback.add("hpack_filter",three,"my example function three",1)
+callback.remove("hpack_filter","my example function three")
+}
+
+\bye
+\endinput
+%%
+%% End of file `luamcallbacks-test.tex'.
diff --git a/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks.pdf b/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks.pdf
new file mode 100644
index 00000000000..e8722725147
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/luamcallbacks.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/luatex/luatextra/luatextra-reference.pdf b/Master/texmf-dist/doc/luatex/luatextra/luatextra-reference.pdf
new file mode 100644
index 00000000000..fc32d8d87d6
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/luatextra-reference.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/luatex/luatextra/luatextra.pdf b/Master/texmf-dist/doc/luatex/luatextra/luatextra.pdf
new file mode 100644
index 00000000000..8077deb1dd6
--- /dev/null
+++ b/Master/texmf-dist/doc/luatex/luatextra/luatextra.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/luatex/luatextra/Makefile b/Master/texmf-dist/source/luatex/luatextra/Makefile
new file mode 100644
index 00000000000..771b5085219
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatextra/Makefile
@@ -0,0 +1,107 @@
+# Makefile for luatextra.
+
+NAME = luatextra
+DTX = $(wildcard *.dtx)
+DOC_DTX = $(patsubst %.dtx, %.pdf, $(DTX))
+SRC_TEX = luatextra-reference.tex
+DOC_TEX = $(patsubst %.tex, %.pdf, $(SRC_TEX))
+
+# Files grouped by generation mode
+UNPACKED_EXTRA = luaextra.lua
+UNPACKED_MCB = luamcallbacks-test.tex luamcallbacks.lua
+UNPACKED_TEXTRA = luatextra-latex.tex luatextra.lua luatextra.sty
+UNPACKED = $(UNPACKED_EXTRA) $(UNPACKED_MCB) $(UNPACKED_TEXTRA)
+COMPILED = $(DOC_DTX) $(DOC_TEX)
+GENERATED = $(UNPACKED) $(COMPILED)
+SOURCE = $(DTX) $(SRC_TEX) README Makefile
+
+# Files grouped by installation location
+RUNFILES = $(UNPACKED_EXTRA) $(UNPACKED_TEXTRA) luamcallbacks.lua
+DOCFILES = $(DOC_DTX) $(DOC_TEX) README luamcallbacks-test.tex
+SRCFILES = $(DTX) $(SRC_TEX) Makefile
+
+# The following definitions should be equivalent
+# ALL_FILES = $(RUNFILES) $(DOCFILES) $(SRCFILES)
+ALL_FILES = $(GENERATED) $(SOURCE)
+
+# Installation locations
+FORMAT = luatex
+RUNDIR = $(TEXMF)/tex/$(FORMAT)/$(NAME)
+DOCDIR = $(TEXMF)/doc/$(FORMAT)/$(NAME)
+SRCDIR = $(TEXMF)/source/$(FORMAT)/$(NAME)
+TEXMF = ./texmf
+
+CTAN_ZIP = $(NAME).zip
+TDS_ZIP = $(NAME).tds.zip
+ZIPS = $(CTAN_ZIP) $(TDS_ZIP)
+
+DO_TEX = tex --interaction=batchmode $< >/dev/null
+DO_PDFLATEX = pdflatex --interaction=batchmode $< >/dev/null
+DO_PDFLUALATEX = pdflualatex --interaction=batchmode $< >/dev/null
+DO_MAKEINDEX = makeindex -s gind.ist $(subst .dtx,,$<) >/dev/null 2>&1
+
+all: $(GENERATED)
+doc: $(COMPILED)
+unpack: $(UNPACKED)
+ctan: $(CTAN_ZIP)
+tds: $(TDS_ZIP)
+world: all ctan
+
+%.pdf: %.dtx
+ $(DO_PDFLATEX)
+ $(DO_MAKEINDEX)
+ $(DO_PDFLATEX)
+ $(DO_PDFLATEX)
+
+$(DOC_TEX): $(SRC_TEX)
+ $(DO_PDFLUALATEX)
+ $(DO_PDFLUALATEX)
+ $(DO_PDFLUALATEX)
+
+$(UNPACKED_TEXTRA): luatextra.dtx
+ $(DO_TEX)
+
+$(UNPACKED_EXTRA): luaextra.dtx
+ $(DO_TEX)
+
+$(UNPACKED_MCB): luamcallbacks.dtx
+ $(DO_TEX)
+
+$(CTAN_ZIP): $(SOURCE) $(COMPILED) $(TDS_ZIP)
+ @echo "Making $@ for CTAN upload."
+ @$(RM) -- $@
+ @zip -9 $@ $^ >/dev/null
+
+define run-install
+@mkdir -p $(RUNDIR) && cp $(RUNFILES) $(RUNDIR)
+@mkdir -p $(DOCDIR) && cp $(DOCFILES) $(DOCDIR)
+@mkdir -p $(SRCDIR) && cp $(SRCFILES) $(SRCDIR)
+endef
+
+$(TDS_ZIP): TEXMF=./tmp-texmf
+$(TDS_ZIP): $(ALL_FILES)
+ @echo "Making TDS-ready archive $@."
+ @$(RM) -- $@
+ $(run-install)
+ @cd $(TEXMF) && zip -9 ../$@ -r . >/dev/null
+ @$(RM) -r -- $(TEXMF)
+
+.PHONY: install manifest clean mrproper
+
+install: $(ALL_FILES)
+ @echo "Installing in '$(TEXMF)'."
+ $(run-install)
+
+manifest:
+ @echo "Source files:"
+ @for f in $(SOURCE); do echo $$f; done
+ @echo ""
+ @echo "Derived files:"
+ @for f in $(GENERATED); do echo $$f; done
+
+clean:
+ @$(RM) -- *.log *.aux *.toc *.idx *.ind *.ilg
+
+mrproper: clean
+ @$(RM) -- $(GENERATED) $(ZIPS)
+
diff --git a/Master/texmf-dist/source/luatex/luatextra/luaextra.dtx b/Master/texmf-dist/source/luatex/luatextra/luaextra.dtx
new file mode 100644
index 00000000000..cb95dd882d5
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatextra/luaextra.dtx
@@ -0,0 +1,969 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2009 by PRAGMA ADE / ConTeXt Development Team
+%
+% See ConTeXt's mreadme.pdf for the license.
+%
+% This work consists of the main source file luaextra.dtx
+% and the derived file luaextra.lua.
+%
+% Unpacking:
+% tex luatextra.dtx
+%
+% Documentation:
+% pdftex luaextra.dtx
+%
+% The class ltxdoc loads the configuration file ltxdoc.cfg
+% if available. Here you can specify further options, e.g.
+% use A4 as paper format:
+% \PassOptionsToClass{a4paper}{article}
+%
+%
+%
+%<*ignore>
+\begingroup
+ \def\x{LaTeX2e}%
+\expandafter\endgroup
+\ifcase 0\ifx\install y1\fi\expandafter
+ \ifx\csname processbatchFile\endcsname\relax\else1\fi
+ \ifx\fmtname\x\else 1\fi\relax
+\else\csname fi\endcsname
+%</ignore>
+%<*install>
+\input docstrip.tex
+\Msg{************************************************************************}
+\Msg{* Installation}
+\Msg{* Package: luaextra 2009/04/15 v0.91 Lua additional functions.}
+\Msg{************************************************************************}
+
+\keepsilent
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+
+\preamble
+This is a generated file.
+
+Copyright (C) 2009 by PRAGMA ADE / ConTeXt Development Team
+
+See ConTeXt's mreadme.pdf for the license.
+
+This work consists of the main source file luaextra.dtx
+and the derived file luaextra.lua.
+
+\endpreamble
+
+% The following hacks are to generate a lua file with lua comments starting by -- instead of %%
+
+\def\MetaPrefix{-- }
+
+\def\luapostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+
+\def\currentpostamble{\luapostamble}%
+
+\generate{%
+ \usedir{tex/luatex/luatextra}%
+ \file{luaextra.lua}{\from{luaextra.dtx}{lua}}%
+}
+
+\obeyspaces
+\Msg{************************************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the following}
+\Msg{* files into a directory searched by TeX:}
+\Msg{*}
+\Msg{* luaextra.lua}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*}
+\Msg{************************************************************************}
+
+\endbatchfile
+%</install>
+%<*ignore>
+\fi
+%</ignore>
+%<*driver>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesFile{luaextra.drv}
+ [2009/04/15 v0.91 Lua additional functions.]
+\documentclass{ltxdoc}
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{luaextra.dtx}%
+\end{document}
+%</driver>
+% \fi
+% \CheckSum{0}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+% \GetFileInfo{luaextra.drv}
+%
+% \title{The \textsf{luaextra} package}
+% \date{2009/04/15 v0.91}
+% \author{Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% Additional lua functions taken from the libs of Con\TeX t. For an introduction on this package (among others), please refer to the document \texttt{luatex-reference.pdf}.
+% \end{abstract}
+%
+% \section{Overview}
+%
+% Lua is a very minimal language, and it does not have a lot of built-in functions. Some functions will certainly be needed by a lot of packages. Instead of making each of them implement these functions, the aim of this file is to provide a minimal set of functions. All functions are taken from Con\TeX t libraries.
+%
+% There are some differences with the Con\TeX t funtions though, especially on names: for example the \texttt{file.*} funtions are renamed in \texttt{fpath.*}. It seems more logical as they deal with file paths, not files. Also the \texttt{file.is\_readable} and \texttt{file.is\_writable} are renamed \texttt{lfs.is\_readable} and \texttt{lfs.is\_writable}.
+%
+% If you use a function you think is missing in this file, please tell the maintainer.
+%
+% \texttt{Warning:} Even if the names will certainly remain the same, some implementations may differ, and some functions might appear or dissapear. As Lua\TeX\ is not stable, this file is not neither.
+%
+% All functions are described in this document, but the one of the functions you'll use most will certainly be \texttt{table.serialize} (also named \texttt{table.tostring}) that takes a table and returns an intented string describing the table. It describes the table so that Lua\TeX\ can read it again as a table. You can do a lot of things with this functions, like printing a table for debugging, or saving a table into a file. Functions are also converted into bytecode to be saved.
+%
+% \section{\texttt{luaextra.lua}}
+%
+% \iffalse
+%<*lua>
+% \fi
+%
+% \begin{macrocode}
+do
+ local luatextra_module = {
+ name = "luaextra",
+ version = 0.91,
+ date = "2009/04/15",
+ description = "Lua additional functions.",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "See ConTeXt's mreadme.pdf for the license",
+ }
+
+ luatextra.provides_module(luatextra_module)
+end
+% \end{macrocode}
+%
+% \begin{macro}{string:stripspaces}
+%
+% A function to strip the spaces at the beginning and at the end of a string.
+%
+% \begin{macrocode}
+
+function string:stripspaces()
+ return (self:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{string.is boolean}
+%
+% If the argument is a string describing a boolean, this function returns the boolean, otherwise it retuns nil.
+%
+% \begin{macrocode}
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{string.is number}
+%
+% Returns true if the argument string is a number.
+%
+% \begin{macrocode}
+
+function string.is_number(str)
+ return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{lpeg.space and lpeg.newline}
+%
+% Two small helpers for \texttt{lpeg}, that will certainly be widely used: spaces and newlines.
+%
+% \begin{macrocode}
+
+lpeg.space = lpeg.S(" \t\f\v")
+lpeg.newline = lpeg.P("\r\n") + lpeg.P("\r") +lpeg.P("\n")
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.fastcopy}
+%
+% A function copying a table fastly.
+%
+% \begin{macrocode}
+
+if not table.fastcopy then do
+
+ local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
+
+ local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in pairs(old) do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+ end
+
+ table.fastcopy = fastcopy
+
+end end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.copy}
+%
+% A function copying a table in more cases than fastcopy, for example when a key is a table.
+%
+% \begin{macrocode}
+
+if not table.copy then do
+
+ local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
+
+ local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+ end
+
+ table.copy = copy
+
+end end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.serialize}
+%
+% A bunch of functions leading to \texttt{table.serialize}.
+%
+% \begin{macrocode}
+
+function table.sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in pairs(tab) do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ table.sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ table.sort(srt)
+ end
+ return srt
+end
+
+do
+ table.serialize_functions = true
+ table.serialize_compact = true
+ table.serialize_inline = true
+
+ local function key(k)
+ if type(k) == "number" then -- or k:find("^%d+$") then
+ return "["..k.."]"
+ elseif noquotes and k:find("^%a[%a%d%_]*$") then
+ return k
+ else
+ return '["'..k..'"]'
+ end
+ end
+
+ local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in pairs(t) do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" or tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = ("%q"):format(v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+ end
+
+ local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed)
+ handle = handle or print
+ reduce = reduce or false
+ if depth then
+ depth = depth .. " "
+ if indexed then
+ handle(("%s{"):format(depth))
+ else
+ handle(("%s%s={"):format(depth,key(name)))
+ end
+ else
+ depth = ""
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ handle("[" .. name .. "]={")
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ end
+ if root and next(root) then
+ local compact = table.serialize_compact
+ local inline = compact and table.serialize_inline
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ for k,v in ipairs(root) do -- NOT: for k=1,#root do (why)
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ for _,k in pairs(table.sortedkeys(root)) do
+ local v = root[k]
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ handle(("%s %s,"):format(depth,v))
+ elseif t == "string" then
+ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(("%s %s,"):format(depth,v))
+ else
+ handle(("%s %q,"):format(depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(("%s {},"):format(depth))
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ handle(("%s { %s },"):format(depth,table.concat(st,", ")))
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
+ end
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
+ end
+ elseif t == "boolean" then
+ handle(("%s %s,"):format(depth,tostring(v)))
+ elseif t == "function" then
+ if table.serialize_functions then
+ handle(('%s loadstring(%q),'):format(depth,string.dump(v)))
+ else
+ handle(('%s "function",'):format(depth))
+ end
+ else
+ handle(("%s %q,"):format(depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(("%s __p__=nil,"):format(depth))
+ end
+ elseif t == "number" then
+ handle(("%s %s=%s,"):format(depth,key(k),v))
+ elseif t == "string" then
+ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(("%s %s=%s,"):format(depth,key(k),v))
+ else
+ handle(("%s %s=%q,"):format(depth,key(k),v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(("%s %s={},"):format(depth,key(k)))
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", ")))
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes)
+ end
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes)
+ end
+ elseif t == "boolean" then
+ handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+ elseif t == "function" then
+ if table.serialize_functions then
+ handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v)))
+ else
+ handle(('%s %s="function",'):format(depth,key(k)))
+ end
+ else
+ handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
+ -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+ end
+ end
+ if level > 0 then
+ handle(("%s},"):format(depth))
+ else
+ handle(("%s}"):format(depth))
+ end
+ else
+ handle(("%s}"):format(depth))
+ end
+ end
+
+ function table.serialize(root,name,reduce,noquotes)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ return table.concat(t,"\n")
+ end
+
+ function table.tostring(t, name)
+ return table.serialize(t, name)
+ end
+
+ function table.tohandle(handle,root,name,reduce,noquotes)
+ serialize(root, name, handle, nil, 0, reduce, noquotes)
+ end
+
+ -- sometimes tables are real use (zapfino extra pro is some 85M) in which
+ -- case a stepwise serialization is nice; actually, we could consider:
+ --
+ -- for line in table.serializer(root,name,reduce,noquotes) do
+ -- ...(line)
+ -- end
+ --
+ -- so this is on the todo list
+
+ table.tofile_maxtab = 2*1024
+
+ function table.tofile(filename,root,name,reduce,noquotes)
+ local f = io.open(filename,'w')
+ if f then
+ local concat = table.concat
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ end
+ f:close()
+ end
+ end
+
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.tohash}
+%
+% Returning a table with all values of the argument table as keys, and \texttt{false} as values. This is what we will call a hash.
+%
+% \begin{macrocode}
+
+function table.tohash(t)
+ local h = { }
+ for _, v in pairs(t) do -- no ipairs here
+ h[v] = true
+ end
+ return h
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.fromhash}
+%
+% Returning a table built from a hash, with simple integer keys.
+%
+% \begin{macrocode}
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in pairs(t) do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.contains value}
+%
+% A function returning true if the value \texttt{val} is in the table \texttt{t}.
+%
+% \begin{macrocode}
+
+function table.contains_value(t, val)
+ if t then
+ for k, v in pairs(t) do
+ if v==val then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.contains key}
+%
+% A function returning true if the key \texttt{key} is in the table \texttt{t}
+%
+% \begin{macrocode}
+
+function table.contains_key(t, key)
+ if t then
+ for k, v in pairs(t) do
+ if k==key then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.value position}
+%
+% A function returning the position of a value in a table. This will be important to be able to remove a value.
+%
+% \begin{macrocode}
+
+function table.value_position(t, val)
+ if t then
+ local i=1
+ for k, v in pairs(t) do
+ if v==val then
+ return i
+ end
+ i=i+1
+ end
+ end
+ return 0
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.key position}
+%
+% A function returning the position of a key in a table.
+%
+% \begin{macrocode}
+
+function table.key_position(t, key)
+ if t then
+ local i=1
+ for k,v in pairs(t) do
+ if k==key then
+ return i
+ end
+ i = i+1
+ end
+ end
+ return -1
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.remove value}
+%
+% Removes the first occurence of a value from a table.
+%
+% \begin{macrocode}
+
+function table.remove_value(t, v)
+ local p = table.value_position(t,v)
+ if p ~= -1 then
+ table.remove(t, table.value_position(t,v))
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.remove key}
+%
+% Removing a key from a table.
+%
+% \begin{macrocode}
+
+function table.remove_key(t, k)
+ local p = table.key_position(t,k)
+ if p ~= -1 then
+ table.remove(t, table.key_position(t,k))
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{table.is empty}
+%
+% Returns true if a table is empty.
+%
+% \begin{macrocode}
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+% \end{macrocode}
+%
+% \texttt{fpath} will contain all the file path manipulation functions. Some functions certainly need a little update or cleanup...
+%
+% \begin{macrocode}
+
+fpath = { }
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.removesuffix}
+%
+% A function to remove the suffix (extention) of a filename.
+%
+% \begin{macrocode}
+
+function fpath.removesuffix(filename)
+ return filename:gsub("%.[%a%d]+$", "")
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.addsuffix}
+%
+% A function adding a suffix to a filename, except if it already has one.
+%
+% \begin{macrocode}
+
+function fpath.addsuffix(filename, suffix)
+ if not filename:find("%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.replacesuffix}
+%
+% A function replacing a suffix by a new one.
+%
+% \begin{macrocode}
+
+function fpath.replacesuffix(filename, suffix)
+ if not filename:find("%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return (filename:gsub("%.[%a%d]+$","."..suffix))
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.dirname}
+%
+% A function returning the directory of a file path.
+%
+% \begin{macrocode}
+
+function fpath.dirname(name)
+ return name:match("^(.+)[/\\].-$") or ""
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.basename}
+%
+% A function returning the basename (the name of the file, without the directories) of a file path.
+%
+% \begin{macrocode}
+
+function fpath.basename(fname)
+ if not fname then
+ return nil
+ end
+ return fname:match("^.+[/\\](.-)$") or fname
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.nameonly}
+%
+% Returning the basename of a file without the suffix.
+%
+% \begin{macrocode}
+
+function fpath.nameonly(name)
+ return ((name:match("^.+[/\\](.-)$") or name):gsub("%..*$",""))
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.suffix}
+%
+% Returns the suffix of a file name.
+%
+% \begin{macrocode}
+
+function fpath.suffix(name)
+ return name:match("^.+%.([^/\\]-)$") or ""
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.join}
+%
+% A function joining any number of arguments into a complete path.
+%
+% \begin{macrocode}
+
+function fpath.join(...)
+ local pth = table.concat({...},"/")
+ pth = pth:gsub("\\","/")
+ local a, b = pth:match("^(.*://)(.*)$")
+ if a and b then
+ return a .. b:gsub("//+","/")
+ end
+ a, b = pth:match("^(//)(.*)$")
+ if a and b then
+ return a .. b:gsub("//+","/")
+ end
+ return (pth:gsub("//+","/"))
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.split}
+%
+% A function returning a table with all directories from a filename.
+%
+% \begin{macrocode}
+
+function fpath.split(str)
+ local t = { }
+ str = str:gsub("\\", "/")
+ str = str:gsub("(%a):([;/])", "%1\001%2")
+ for name in str:gmatch("([^;:]+)") do
+ if name ~= "" then
+ name = name:gsub("\001",":")
+ t[#t+1] = name
+ end
+ end
+ return t
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.normalize sep}
+%
+% A function to change directory separators to canonical ones (\texttt{/}).
+%
+% \begin{macrocode}
+
+function fpath.normalize_sep(str)
+ return str:gsub("\\", "/")
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{fpath.localize sep}
+%
+% A function changing directory separators into local ones (\texttt{/} on Unix, |\| on Windows).
+%
+% \begin{macrocode}
+
+function fpath.localize_sep(str)
+ if os.type == 'windows' or type == 'msdos' then
+ return str:gsub("/", "\\")
+ else
+ return str:gsub("\\", "/")
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{lfs.is writable}
+%
+% Returns true if a file is writable. This function and the following ones are a bit too expensive, they should be made with |lfs.attributes|.
+%
+% \begin{macrocode}
+
+function lfs.is_writable(name)
+ local f = io.open(name, 'w')
+ if f then
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{lfs.is readable}
+%
+% Returns true if a file is readable.
+%
+% \begin{macrocode}
+
+function lfs.is_readable(name)
+ local f = io.open(name,'r')
+ if f then
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{math.round}
+%
+% Returns the closest integer.
+%
+% \begin{macrocode}
+
+if not math.round then
+ function math.round(x)
+ return math.floor(x + 0.5)
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{math.div}
+%
+% Returns the quotient of the euclidian division of n by m.
+%
+% \begin{macrocode}
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}\begin{macro}{math.mod}
+%
+% Returns the remainder of the euclidian division of n by m.
+%
+% \begin{macrocode}
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \iffalse
+%</lua>
+% \fi
+% \Finale
+\endinput
diff --git a/Master/texmf-dist/source/luatex/luatextra/luamcallbacks.dtx b/Master/texmf-dist/source/luatex/luatextra/luamcallbacks.dtx
new file mode 100644
index 00000000000..17e9ded637d
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatextra/luamcallbacks.dtx
@@ -0,0 +1,768 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%
+% This work is under the CC0 license.
+%
+% This work consists of the main source file luamcallbacks.dtx
+% and the derived files
+% luamcallbacks.sty, luamcallbacks.tex, luamcallbacks.lua
+% luamcallbacks-test.tex, luamcallbacks.pdf.
+%
+% Unpacking:
+% tex luamcallbacks.dtx
+% Documentation:
+% pdflatex luamcallbacks.dtx
+%
+% The class ltxdoc loads the configuration file ltxdoc.cfg
+% if available. Here you can specify further options, e.g.
+% use A4 as paper format:
+% \PassOptionsToClass{a4paper}{article}
+%
+%<*ignore>
+\begingroup
+ \def\x{LaTeX2e}%
+\expandafter\endgroup
+\ifcase 0\ifx\install y1\fi\expandafter
+ \ifx\csname processbatchFile\endcsname\relax\else1\fi
+ \ifx\fmtname\x\else 1\fi\relax
+\else\csname fi\endcsname
+%</ignore>
+%<*install>
+\input docstrip.tex
+\Msg{************************************************************************}
+\Msg{* Installation}
+\Msg{* Package: luamcallbacks 2009/03/19 v0.92 LuaTeX multiple callbacks package}
+\Msg{************************************************************************}
+
+\keepsilent
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+
+\preamble
+This is a generated file.
+
+Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+
+This work is under the CC0 license.
+
+This work consists of the main source file luamcallbacks.dtx
+and the derived files
+ luamcallbacks.lua, luamcallbacks-test.tex, luamcallbacks.pdf.
+
+\endpreamble
+
+\let\MetaPrefix\DoubleperCent
+
+\generate{%
+ \usedir{doc/luatex/luatextra}%
+ \file{luamcallbacks-test.tex}{\from{luamcallbacks.dtx}{test}}%
+}
+
+% The following hacks are to generate a lua file with lua comments starting by -- instead of %%
+
+\def\MetaPrefix{-- }
+
+\def\luapostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+
+\def\currentpostamble{\luapostamble}%
+
+\generate{%
+ \usedir{tex/luatex/luatextra}%
+ \file{luamcallbacks.lua}{\from{luamcallbacks.dtx}{lua}}%
+}
+
+\obeyspaces
+\Msg{************************************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the following}
+\Msg{* files into a directory searched by TeX:}
+\Msg{*}
+\Msg{* luamcallbacks.lua}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*}
+\Msg{************************************************************************}
+
+\endbatchfile
+%</install>
+%<*ignore>
+\fi
+%</ignore>
+%<*driver>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesFile{luamcallbacks.drv}
+ [2009/03/19 v0.92 LuaTeX multiple callbacks package]
+\documentclass{ltxdoc}
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{luamcallbacks.dtx}%
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{5}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+% \GetFileInfo{luamcallbacks.drv}
+%
+% \title{The \textsf{luamcallbacks} package}
+% \date{2009/03/19 v0.92}
+% \author{Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% This package manages the callback adding and removing, by adding \texttt{callback.add}
+% and \texttt{callback.remove}, and overwriting \texttt{callback.register}. It also allows to create and call new callbacks. For an introduction on this package (among others), please refer to the document \texttt{luatextra-reference.pdf}.
+% \end{abstract}
+%
+% \section{Documentation}
+%
+%Lua\TeX\ provides an extremely interesting feature, named callbacks. It allows to call some lua functions at some points of the \TeX\ algorithm (a \emph{callback}), like when \TeX\ breaks likes, puts vertical spaces, etc. The Lua\TeX\ core offers a function called \texttt{callback.register} that enables to register a function in a callback.
+%
+%The problem with \texttt{callback.register} is that is registers only one function in a callback. For a lot of callbacks it can be common to have several packages registering their function in a callback, and thus it is impossible with them to be compatible with each other.
+%
+%This package solves this problem by adding mainly one new function \texttt{callback.\\add} that adds a function in a callback. With this function it is possible for packages to register their function in a callback without overwriting the functions of the other packages.
+%
+%The functions are called in a certain order, and when a package registers a callback it can assign a priority to its function. Conflicts can still remain even with the priority mechanism, for example in the case where two packages want to have the highest priority. In these cases the packages have to solve the conflicts themselves.
+%
+% This package also privides a way to create and call new callbacks, in addition to the default Lua\TeX\ callbacks.
+%
+% This package contains only a \texttt{.lua} file, that can be called by another lua script. For example, this script is called in \textsf{luatextra}.
+%
+%\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}.
+%
+% \StopEventually{
+% }
+%
+% \section{Package code}
+%
+% The package contains \texttt{luamcallbacks.lua} with the new functions, and an example of the use of luamcallbacks.
+%
+% \iffalse
+%<*lua>
+% \fi
+%
+%
+% First the \texttt{luamcallbacks} module is registered as a Lua\TeX\ module, with some informations.
+%
+% \begin{macrocode}
+
+luamcallbacks = { }
+
+luamcallbacks.module = {
+ name = "luamcallbacks",
+ version = 0.92,
+ date = "2009/03/19",
+ description = "Module to register several functions in a callback.",
+ author = "Hans Hagen & Elie Roux",
+ copyright = "Hans Hagen & Elie Roux",
+ license = "CC0",
+}
+
+luatextra.provides_module(luamcallbacks.module)
+
+% \end{macrocode}
+%
+% \texttt{callbacklist} is the main list, that contains the callbacks as keys and a table of the registered functions a values.
+%
+% \begin{macrocode}
+
+luamcallbacks.callbacklist = luamcallbacks.callbacklist or { }
+
+% \end{macrocode}
+%
+% A table with the default functions of the created callbacks. See \texttt{luamcallbacks.create} for further informations.
+%
+% \begin{macrocode}
+
+luamcallbacks.lua_callbacks_defaults = { }
+
+local format = string.format
+
+% \end{macrocode}
+%
+% There are 4 types of callback:
+% \begin{itemize}
+% \item the ones taking a list of nodes and returning a boolean and eventually a new head (\texttt{list})
+% \item the ones taking datas and returning the modified ones (\texttt{data})
+% \item the ones that can't have multiple functions registered in them (\texttt{first})
+% \item the ones for functions that don't return anything (\texttt{simple})
+% \end{itemize}
+%
+% \begin{macrocode}
+
+local list = 1
+local data = 2
+local first = 3
+local simple = 4
+
+% \end{macrocode}
+%
+% \texttt{callbacktypes} is the list that contains the callbacks as keys and the type (list or data) as values.
+%
+% \begin{macrocode}
+
+luamcallbacks.callbacktypes = luamcallbacks.callbacktypes or {
+buildpage_filter = simple,
+token_filter = first,
+pre_output_filter = list,
+hpack_filter = list,
+process_input_buffer = data,
+mlist_to_hlist = list,
+vpack_filter = list,
+define_font = first,
+open_read_file = first,
+linebreak_filter = list,
+post_linebreak_filter = list,
+pre_linebreak_filter = list,
+start_page_number = simple,
+stop_page_number = simple,
+start_run = simple,
+show_error_hook = simple,
+stop_run = simple,
+hyphenate = simple,
+ligaturing = simple,
+kerning = data,
+find_write_file = first,
+find_read_file = first,
+find_vf_file = data,
+find_map_file = data,
+find_format_file = data,
+find_opentype_file = data,
+find_output_file = data,
+find_truetype_file = data,
+find_type1_file = data,
+find_data_file = data,
+find_pk_file = data,
+find_font_file = data,
+find_image_file = data,
+find_ocp_file = data,
+find_sfd_file = data,
+find_enc_file = data,
+read_sfd_file = first,
+read_map_file = first,
+read_pk_file = first,
+read_enc_file = first,
+read_vf_file = first,
+read_ocp_file = first,
+read_opentype_file = first,
+read_truetype_file = first,
+read_font_file = first,
+read_type1_file = first,
+read_data_file = first,
+}
+
+% \end{macrocode}
+%
+% As we overwrite \texttt{callback.register}, we save it as \texttt{luamcallbacks.internalregister}. After that we declare some functions to write the errors or the logs.
+%
+% \begin{macrocode}
+
+luamcallbacks.internalregister = luamcallbacks.internalregister or callback.register
+
+local callbacktypes = luamcallbacks.callbacktypes
+
+luamcallbacks.log = luamcallbacks.log or function(...)
+ luatextra.module_log('luamcallbacks', format(...))
+end
+
+luamcallbacks.info = luamcallbacks.info or function(...)
+ luatextra.module_info('luamcallbacks', format(...))
+end
+
+luamcallbacks.warning = luamcallbacks.warning or function(...)
+ luatextra.module_warning('luamcallbacks', format(...))
+end
+
+luamcallbacks.error = luamcallbacks.error or function(...)
+ luatextra.module_error('luamcallbacks', format(...))
+end
+
+% \end{macrocode}
+%
+% 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}
+
+function luamcallbacks.str_to_type(str)
+ if str == 'list' then
+ return list
+ elseif str == 'data' then
+ return data
+ elseif str == 'first' then
+ return first
+ elseif str == 'simple' then
+ return simple
+ else
+ return nil
+ end
+end
+
+% \end{macrocode}
+%
+% \begin{macro}{luamcallbacks.create}
+%
+% This first function creates a new callback. The signature is \texttt{create(name, ctype, default)} where \texttt{name} is the name of the new callback to create, \texttt{ctype} is the type of callback, and \texttt{default} is the default function to call if no function is registered in this callback.
+%
+% The created callback will behave the same way Lua\TeX\ callbacks do, you can add and remove functions in it. The difference is that the callback is not automatically called, the package developer creating a new callback must also call it, see next function.
+%
+% \begin{macrocode}
+
+function luamcallbacks.create(name, ctype, default)
+ if not name then
+ luamcallbacks.error(format("unable to call callback, no proper name passed", name))
+ return nil
+ end
+ if not ctype or not default then
+ luamcallbacks.error(format("unable to create callback '%s', callbacktype or default function not specified", name))
+ return nil
+ end
+ if callbacktypes[name] then
+ luamcallbacks.error(format("unable to create callback '%s', callback already exists", name))
+ return nil
+ end
+ local temp = luamcallbacks.str_to_type(ctype)
+ if not temp then
+ luamcallbacks.error(format("unable to create callback '%s', type '%s' undefined", name, ctype))
+ return nil
+ end
+ ctype = temp
+ luamcallbacks.lua_callbacks_defaults[name] = default
+ callbacktypes[name] = ctype
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luamcallbacks.call}
+%
+% This function calls a callback. It can only call a callback created by the \texttt{create} function.
+%
+% \begin{macrocode}
+
+function luamcallbacks.call(name, ...)
+ if not name then
+ luamcallbacks.error(format("unable to call callback, no proper name passed", name))
+ return nil
+ end
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.error(format("unable to call lua callback '%s', unknown callback", name))
+ return nil
+ end
+ local l = luamcallbacks.callbacklist[name]
+ local f
+ if not l then
+ f = luamcallbacks.lua_callbacks_defaults[name]
+ else
+ if callbacktypes[name] == list then
+ f = luamcallbacks.listhandler(name)
+ elseif callbacktypes[name] == data then
+ f = luamcallbacks.datahandler(name)
+ elseif callbacktypes[name] == simple then
+ f = luamcallbacks.simplehandler(name)
+ elseif callbacktypes[name] == first then
+ f = luamcallbacks.firsthandler(name)
+ else
+ luamcallbacks.error("unknown callback type")
+ end
+ end
+ return f(...)
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luamcallbacks.add}
+%
+%The main function. The signature is \texttt{luamcallbacks.add (name, func, description, priority)} with \texttt{name} being the name of the callback in which the function is added; \texttt{func} is the added function; \texttt{description} is a small character string describing the function, and \texttt{priority} an optional argument describing the priority the function will have.
+%
+%The functions for a callbacks are added in a list (in \texttt{luamcallbacks.callbacklist\\.callbackname}). If they have no priority or a high priority number, they will be added at the end of the list, and will be called after the others. If they have a low priority number, the will be added at the beginning of the list and will be called before the others.
+%
+%Something that must be made clear, is that there is absolutely no solution for packages conflicts: if two packages want the top priority on a certain callback, they will have to decide the priority they will give to their function themself. Most of the time, the priority is not needed.
+%
+% \begin{macrocode}
+
+function luamcallbacks.add (name,func,description,priority)
+ if type(func) ~= "function" then
+ luamcallbacks.error("unable to add function, no proper function passed")
+ return
+ end
+ if not name or name == "" then
+ luamcallbacks.error("unable to add function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("unable to add function, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not description or description == "" then
+ luamcallbacks.error(
+ format("unable to add function to '%s', no proper description passed",
+ name))
+ return
+ end
+ if luamcallbacks.get_priority(name, description) ~= 0 then
+ luamcallbacks.warning(
+ format("function '%s' already registered in callback '%s'",
+ description, name))
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then
+ l = {}
+ luamcallbacks.callbacklist[name] = l
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ if callbacktypes[name] == list then
+ luamcallbacks.internalregister(name, luamcallbacks.listhandler(name))
+ elseif callbacktypes[name] == data then
+ luamcallbacks.internalregister(name, luamcallbacks.datahandler(name))
+ elseif callbacktypes[name] == simple then
+ luamcallbacks.internalregister(name, luamcallbacks.simplehandler(name))
+ elseif callbacktypes[name] == first then
+ luamcallbacks.internalregister(name, luamcallbacks.firsthandler(name))
+ else
+ luamcallbacks.error("unknown callback type")
+ end
+ end
+ end
+ local f = {
+ func = func,
+ description = description,
+ }
+ priority = tonumber(priority)
+ if not priority or priority > #l then
+ priority = #l+1
+ elseif priority < 1 then
+ priority = 1
+ end
+ if callbacktypes[name] == first and (priority ~= 1 or #l ~= 0) then
+ luamcallbacks.warning(format("several callbacks registered in callback '%s', only the first function will be active.", name))
+ end
+ table.insert(l,priority,f)
+ luamcallbacks.log(
+ format("inserting function '%s' at position %s in callback list for '%s'",
+ description,priority,name))
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luamcallbacks.get priority}
+%
+% This function tells if a function has already been registered in a callback, and gives its current priority. The arguments are the name of the callback and the description of the function. If it has already been registered, it gives its priority, and if not it returns false.
+%
+% \begin{macrocode}
+
+function luamcallbacks.get_priority (name, description)
+ if not name or name == "" or not callbacktypes[name] or not description then
+ return 0
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then return 0 end
+ for p, f in pairs(l) do
+ if f.description == description then
+ return p
+ end
+ end
+ return 0
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luamcallbacks.remove}
+%
+% The function that removes a function from a callback. The signature is \texttt{mcallbacks.remove (name, description)} with \texttt{name} being the name of callbacks, and description the description passed to \texttt{mcallbacks.add}.
+%
+% \begin{macrocode}
+
+function luamcallbacks.remove (name, description)
+ if not name or name == "" then
+ luamcallbacks.error("unable to remove function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("unable to remove function, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not description or description == "" then
+ luamcallbacks.error(
+ format("unable to remove function from '%s', no proper description passed",
+ name))
+ return
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then
+ luamcallbacks.error(format("no callback list for '%s'",name))
+ return
+ end
+ for k,v in ipairs(l) do
+ if v.description == description then
+ table.remove(l,k)
+ luamcallbacks.log(
+ format("removing function '%s' from '%s'",description,name))
+ if l == {} and not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.internalregister(name, nil)
+ end
+ return
+ end
+ end
+ luamcallbacks.warning(
+ format("unable to remove function '%s' from '%s'",description,name))
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luamcallbacks.reset}
+%
+% This function removes all the functions registered in a callback.
+%
+% \begin{macrocode}
+
+function luamcallbacks.reset (name)
+ if not name or name == "" then
+ luamcallbacks.error("unable to reset, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("reset error, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.internalregister(name, nil)
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ luamcallbacks.log(format("resetting callback list '%s'",name))
+ luamcallbacks.callbacklist[name] = nil
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% This function and the following ones are only internal. This one is the handler for the first type of callbacks: the ones that take a list head and return true, false, or a new list head.
+%
+% \begin{macro}{luamcallbacks.listhandler}
+%
+% \begin{macrocode}
+
+function luamcallbacks.listhandler (name)
+ return function(head,...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ local done = true
+ for _, f in ipairs(l) do
+ -- the returned value can be 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
+ luamcallbacks.error(format(
+ "function \"%s\" returned false in callback '%s'",
+ f.description, name))
+ end
+ end
+ return head, done
+ else
+ return head, false
+ end
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% The handler for callbacks taking datas and returning modified ones.
+%
+% \begin{macro}{luamcallbacks.datahandler}
+%
+% \begin{macrocode}
+
+function luamcallbacks.datahandler (name)
+ return function(data,...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ data = f.func(data,...)
+ end
+ end
+ return data
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% This function is for the handlers that don't support more than one functions in them. In this case we only call the first function of the list.
+%
+% \begin{macro}{luamcallbacks.firsthandler}
+%
+% \begin{macrocode}
+
+function luamcallbacks.firsthandler (name)
+ return function(...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ local f = l[1].func
+ return f(...)
+ else
+ return nil, false
+ end
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% Handler for simple functions that don't return anything.
+%
+% \begin{macro}{luamcallbacks.simplehandler}
+%
+% \begin{macrocode}
+
+function luamcallbacks.simplehandler (name)
+ return function(...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ f.func(...)
+ end
+ end
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% Finally we add some functions to the \texttt{callback} module, and we overwrite \texttt{callback.register} so that it outputs an error.
+%
+% \begin{macrocode}
+
+callback.add = luamcallbacks.add
+callback.remove = luamcallbacks.remove
+callback.reset = luamcallbacks.reset
+callback.create = luamcallbacks.create
+callback.call = luamcallbacks.call
+callback.get_priority = luamcallbacks.get_priority
+
+callback.register = function (...)
+luamcallbacks.error("function callback.register has been deleted by luamcallbacks, please use callback.add instead.")
+end
+
+% \end{macrocode}
+%
+% \iffalse
+%</lua>
+% \fi
+%
+% \iffalse
+%<*test>
+% \fi
+%
+% \section{Test file}
+%
+% The test file is made to run in plainTeX, but is trivial to adapt for LaTeX.
+% First we input the package, and we typeset a small sentence to get a non-empty
+% document.
+%
+% \begin{macrocode}
+\input luatextra.sty
+
+This is just a test file.
+% \end{macrocode}
+%
+% Then we declare three functions that we will use.
+%
+% \begin{macrocode}
+\luadirect{
+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
+% \end{macrocode}
+%
+% Then we add the three functions to the hpack\_filter callback
+%
+% \begin{macrocode}
+callback.add("hpack_filter",one,"my example function one",1)
+callback.add("hpack_filter",two,"my example function two",2)
+callback.add("hpack_filter",three,"my example function three",1)
+% \end{macrocode}
+%
+% We remove the function three from the callback.
+%
+% \begin{macrocode}
+callback.remove("hpack_filter","my example function three")
+% \end{macrocode}
+%
+% And we remove a non-declared function to the callback, which will generate an
+% error.
+%
+% \begin{macrocode}
+}
+
+\bye
+% \end{macrocode}
+% \iffalse
+%</test>
+% \fi
+% \Finale
+\endinput
diff --git a/Master/texmf-dist/source/luatex/luatextra/luatextra-reference.tex b/Master/texmf-dist/source/luatex/luatextra/luatextra-reference.tex
new file mode 100644
index 00000000000..7f650bfb16e
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatextra/luatextra-reference.tex
@@ -0,0 +1,295 @@
+% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%
+% This work is under the CC0 license. Basically this means that you can do
+% (almost) whatever you want with it without asking for permission.
+%
+% To compile it, you must use LuaLaTeX.
+%
+
+\documentclass{article}
+\usepackage[english]{babel}
+\usepackage[utf8]{luainputenc}
+\usepackage[T1]{fontenc}
+\usepackage{amsfonts}
+\usepackage{eurosym}
+\usepackage[pdftex, bookmarks, colorlinks=false, pdftitle={LuaTeXtra references}, pdfauthor={Elie Roux}, pdfsubject={LuaTeXtra references}, pdfborder={0 0 0}]{hyperref}
+\usepackage[pdftex]{graphicx}
+
+\makeatletter
+\newlength\xxt@kern@Te
+\newlength\xxt@kern@eX
+\newlength\xxt@lower@e
+\newlength\xxt@kern@La
+\newlength\xxt@kern@aT
+\newlength\xxt@kern@eL
+\newcommand*\TeX@logo@spacing[6]{%
+ \setlength\xxt@kern@Te{#1}%
+ \setlength\xxt@kern@eX{#2}%
+ \setlength\xxt@lower@e{#3}%
+ \setlength\xxt@kern@La{#4}%
+ \setlength\xxt@kern@aT{#5}%
+ \setlength\xxt@kern@eL{#6}%
+}
+\DeclareRobustCommand\XeTeX{%
+ \leavevmode
+ \smash{%
+ X\lower\xxt@lower@e
+ \hbox{\kern\xxt@kern@eX
+ \setbox0=\hbox{E}\dimen0=\ht0\advance\dimen0by\dp0%
+ \raise\dimen0\hbox{\rotatebox{180}{\box0}}%
+ }\kern\xxt@kern@Te\TeX}}%
+\TeX@logo@spacing{-0.15em}{-0.15em}{0.5ex}{-0.36em}{-0.15em}{-0.1em}
+
+
+\usepackage{times}
+\title{Lua\TeX tra references}
+\author{Elie Roux \\ \url{elie.roux@telecom-bretagne.eu}}
+\begin{document}
+
+\maketitle
+
+\subsubsection*{Preamble: What is this document?}
+
+This document describes, from the user or developer point of view, how to use the coherent set of packages \textsf{luatextra}, \textsf{luainputenc}, \textsf{luaotfload}, \textsf{luamcallbacks} and \textsf{luaextra}.
+
+If you are looking for documentation on the \LuaTeX\ engine, please refer to the file \texttt{luatexref-t.pdf}, but note that using these packages will slightly modify some \LuaTeX\ behaviours, especially the \texttt{callback} library.
+
+If you are looking for technical details about one of the packages, you can refer to its documentation. Each of them have a complete documentation in the file \texttt{package.pdf} with package being the name of the package.
+
+\tableofcontents
+
+\section{Introduction}
+
+Before going any further, we need to explain the difference between an engine, a format, and a program. If you know the difference between these, please go to section \ref{sub:luatextra}.
+
+\subsection{What is \LuaTeX ?}
+
+\LuaTeX\ is a \TeX\ engine. A \TeX\ engine is a binary executable that provides some very low-level primitives, for example \texttt{\string\count} to set a counter to a certain value. Examples of engines are the old \TeX\ 82, \eTeX, pdf\TeX, Omega, Aleph, Lua\TeX\ and \XeTeX .
+
+There are two main differences between \LuaTeX\ and its predecessor, pdfTeX: \LuaTeX\ now truely understands UTF-8 and enables the execution of some lua code at certain points of the \TeX\ algorithm. These two features allow, among other things, to open modern fonts like OpenType or TrueType fonts.
+
+\subsection{What is the difference with \LaTeX ?}
+
+The nature of \LaTeX\ is fundamentally different: \LaTeX\ is a \TeX\ format. Examples of formats are Plain, \LaTeX\ and Con\TeX t.
+
+This distinction is very hard to make, first because you cannot find any documentation on it, and secondly because the only things everyone knows are programs. A program is a command you type in your terminal that calls an engine with a format. Here are the different things behind what you type:
+
+\begin{itemize}
+\item \texttt{tex} is the engine \TeX\ 82 with the format Plain. Both were created by Donald Knuth a very long time ago.
+\item \texttt{pdftex} is the engine pdf\TeX\ (in PDF mode) with the format Plain.
+\item \texttt{luatex} is the engine \LuaTeX\ (in PDF mode) with the format Plain.
+\item \texttt{xetex} is the engine \XeTeX\ (in PDF mode) with the format Plain.
+\item \texttt{latex} is the engine pdf\TeX\ (in DVI mode) with the format \LaTeX .
+\item \texttt{pdflatex} is the engine pdf\TeX\ (in PDF mode) with the format \LaTeX .
+\item \texttt{lualatex} is the engine \LuaTeX\ (in PDF mode) with the format \LaTeX .
+\item \texttt{xelatex} is the engine \XeTeX\ (in PDF mode) with the format \LaTeX .
+\end{itemize}
+
+pdf\TeX\ and \LuaTeX\ can produce both DVI and PDF output. To choose it, you can simply set \texttt{\string\pdfoutput} to 0 or 1.
+
+As you can see, there is absolutely no corellation between \LuaTeX\ and \LaTeX , even if the names are close\dots
+
+\subsection{What is Lua\TeX tra?\label{sub:luatextra}}
+
+Lua\TeX tra is the adaptation of the engine \LuaTeX\ to the formats Plain and \LaTeX . It enables these formats to benefit from the \LuaTeX\ new features, like UTF-8 reading, attributes handling, extended registers, modern font opening, etc.
+
+\LuaTeX\ provides only very low-level macros for these features, and a lot of code has to be done by the format to really provide a good user experience.
+
+With what I just said, a good question would be the following: why isn't \textsf{luatextra} integrated into \LaTeX\ and Plain?
+
+The answer is simple: because Plain and \LaTeX\ are frozen. This means that they don't accept new code anymore, even if it's totally necessary to benefit from new engines. Thus, the only solution is to provide a package that every user will have to load.
+
+\subsection{Why is it necessary?}
+
+\LuaTeX tra is necessary for users and developers because it provides a way for several packages to access ressources.
+
+Let's take a very concrete example: \LuaTeX\ has a totally new concept named attributes; basically they can be considered as special counts: you can name them with the primitive \texttt{\string\attribute}, like you can name an counter with \texttt{\string\count}, and you can give them a value with \texttt{\string\attributedef}, that works like \texttt{\string\countdef} (see the \LuaTeX\ documentation for more details about attributes). Attributes, like counts, are described by numbers, for example you have \texttt{\string\attribute0}, \texttt{\string\attribute1}, etc.
+
+Plain and \LaTeX\ provide a macro \texttt{\string\newcount} that takes the first free counter and attributes it a name, for example we can image that \texttt{\string\newcount\string\foo} will in fact do \texttt{\string\count25\string\foo}. This enables packages to automatically take a free counter. Without it, package developers would have to maintain a list saying ``please don't take attribute number foo, it's for the package bar!".
+
+Plain and \LaTeX\ do not provide \texttt{\string\newattribute} to allocate a free attribute; but we do it in \textsf{luatextra}. Without \LuaTeX tra, people have to take arbitrary attributes and cross their fingers hoping that noone else will use the attributes they've chosen. With \LuaTeX tra, you can safely take attributes, being sure that noone else will use them.
+
+Another similar problem is callback access: by default \LuaTeX\ does not provide a way to register several functions in a callback, so if two packages want to register a function in a callback, they won't be compatible, as only one will work. \textsf{luamcallback} provides a new mechanism for callbacks that enables this, allowing more package compatibility.
+
+These two problems are very concrete, that's the main reason why \LuaTeX tra has been created: without it a lot of package compatibility problems would have been raised.
+
+\subsection{The different packages}
+
+The \LuaTeX tra coherent set of packages contains:
+
+\begin{itemize}
+\item \textsf{luatextra}: the basic general macros and lua functions
+\item \textsf{luainputenc}: adaptation of \textsf{inputenc} to \LuaTeX
+\item \textsf{luamcallbacks}: pure lua package to be able to register several functions in a callback
+\item \textsf{luaextra}: additional lua functions
+\end{itemize}
+
+\subsection{Overview}
+
+The main idea, as explained above, is to provide a safe way to use different packages that are not coherent, without loading several times the same code, or taking ressources (like attributes) already used by other packages.
+
+To do so, we have used a concept for lua files named ``module", inspired by the \LaTeX\ packages. \textbf{Warning:} the module concept described here comes as an extention to the base lua module concept. We advise not to use the base lua modules, but the \LuaTeX tra module system, as it provides more informations, prints informations in logs, etc. The \LuaTeX tra lua module system works basically like the \LaTeX\ package system: you can simply use them, or require them with a version number, etc.
+
+As explained above, another important function provided by \LuaTeX tra is attributes allocation with \texttt{\string\newluaattribute}.
+
+\subsection{Naming conventions}
+
+In \LuaTeX tra we decided to adopt a simple naming convention: all macros start by \texttt{lua}. There are though a few exceptions: for instance we renamed the concept of \LuaTeX 's \texttt{attribute} to \texttt{luaattribute}, as attribute is already something used by a lot of packages and users. This lead us to name our macros \texttt{\string\newluaattribute}, \texttt{\string\unsetluaattribute}, etc. for backward compatibility. On the same principle, \texttt{catcodetable} is replaced by \texttt{luacatcodetable}.
+
+\section{Basic user point of view}
+
+\subsection{Plain and \LaTeX\ macros}
+
+The most useful macro provided by \textsf{luatextra} is certainly \texttt{\string\luadirect}, which is a wrapper for \texttt{\string\directlua}, but will keep the same signature whatever the \LuaTeX\ version. For example this macro works for \LuaTeX\ versions $<$ 0.36, and will most certainly work for future versions of \LuaTeX . It is advised to use this macro to keep the compatibility of your package with all versions of \LuaTeX . \texttt{\string\lualate} is also provided as a wrapper for \texttt{\string\latelua}.
+
+Some small but useful macros are \texttt{\string\LuaTeX} and \texttt{\string\LuaLaTeX} that produce \LaTeX\ and \LuaLaTeX .
+
+\textsf{luatextra} automatically loads \textsf{luaotfload}, so you can open otf fonts directly, for instance \texttt{\string\font\string\foo = "LinLibertine.otf"\string\foo} will work. You can also pass options to the font opening, for example the different OTF options you want. These options are passed with the \XeTeX\ font syntax (briefly described in \texttt{XeTeX-reference.pdf}), for example if you want to open a font with the usual \TeX\ substitutions and ligatures, with also the font default ligatures, you can try \newline \texttt{\string\font\string\foo = "LinLibertine.otf;+tlig;+tsub;+liga;+rlig;"\string\foo}.
+
+\subsection{\LaTeX -only macros}
+
+\subsubsection{luainputenc}
+
+From the user point of view, adapting an old document for \LuaTeX\ is really easy: replacing \textsf{inputenc} by \textsf{luainputenc} in the preamble is enough.
+
+\textsf{Warning:} the current version of \textsf{luainputenc} automatically loads the \LuaTeX tra packages. It won't necessarily be the case in the future. So if you use some functions of \LuaTeX tra (like \texttt{\string\newluaattribute}), it is advised to also explicitely use \texttt{luatextra}. A typical part of \LaTeX\ preamble for \LuaTeX\ will be for example:
+
+\begin{verbatim}
+\usepackage[utf8]{luainputenc}
+\usepackage{luatextra}
+\end{verbatim}
+
+Another important thing to know, for \LaTeX , is that loading \textsf{luainputenc} is necessary if you use old fonts. One could believe that \LuaTeX\ reading UTF-8 natively, \textsf{inputenc} is not necessary anymore. It's not the case! The exception to this is the case where you only use OTF fonts. But you can't simply suppress \textsf{inputenc} for your old documents.
+
+Note that \textsf{luainputenc} automatically loads \textsf{inputenc} if called with an old engine, so you will still be able to compile your documents with pdf\TeX\ without changing them.
+
+A new font encoding has been added: \texttt{EU2}. It is meant to be used with OTF fonts. It is very minimal and just defines a default font (lmodern). Use it if you use only OTF fonts. To use it simply call \textsf{fontenc} with the option \texttt{EU2}.
+
+EU2 encoding is special as it needs non-ASCII characters to be non-active (unlike other font encodings), so you cannot mix old encodings and EU2. If you want to use both old fonts and OTF fonts in your document, the way to do so is by using a new option of \textsf{luainputenc}: \texttt{lutf8x}. This option overrides \LaTeX 's mechanism to change the font encoding and activates or unactivates non-ASCII characters. If you use this option, you will be able to change the encoding, for example:
+
+\begin{verbatim}
+abc
+{
+\fontencoding{EU2}\usefont
+\font\foo="MyOtfFont.otf"\foo
+abc
+}
+abc
+\end{verbatim}
+
+Another new option has been added to \textsf{luainputenc}: \texttt{unactivate}. With this option, non-ASCII characters won't be activated, so you will be able to use only OTF fonts. Typically you can use this options with the \texttt{EU2} \textsf{fontenc} option.
+
+\subsubsection{luacode environment}
+
+\LuaTeX tra also provides an environment for lua code integration: \textsf{luacode}. You can simply use it this way:
+
+\begin{verbatim}
+\begin{luacode}
+texio.write_nl("It works!")
+\end{luacode}
+\end{verbatim}
+
+\section{Advanced user point of view}
+
+\subsection{lua modules}
+
+For more informations about this part (and the attributes and catcodetables), see the documentation \texttt{luatextra.pdf}.
+
+\LuaTeX tra provides the same kind of functions for lua modules as \LaTeX\ does for packages: it provides the macros \texttt{\string\luaUseModule} and \texttt{\string\luaRequireModule}, as well as the functions \texttt{luatextra.use\_module}, \texttt{luatextra.require\_module} and \texttt{luatextra.provides\_module}.
+
+If you want to use a lua file mypackage.lua, you can safely use \texttt{\string\luaUseModule\{mypackage\}}: it will automatically load the file; and will load it only once if the function is called several times. You can also use \texttt{\string\luaRequireModule} that takes the minimal version (or date) as a second (optional under \LaTeX ) argument.
+
+In a lua module, you have to call \texttt{luatextra.provides\_module}. It takes a table as an argument. This table must contain at least the fields \texttt{name}, \texttt{version}, \texttt{date} and \texttt{description}. You can also use the fields \texttt{author}, \texttt{copyright}, \texttt{license}, or any field you want.
+
+See section \ref{sub:luatemplate} for an example of a lua module.
+
+\subsection{attributes}
+
+We already talked about the most important function: \texttt{\string\newluaattribute}. It is the equivalent of \texttt{\string\newcount} for attributes.
+
+Another important function is \texttt{\string\unsetluaattribute} that unsets an attribute. It's adised to use this macro instead of unsetting it by hand, as the unset value may change (it changed in version 0.37 from \texttt{-1} to \texttt{-"7FFFFFFF}).
+
+You can also use the macro \texttt{\string\setluaattribute} that takes an attribute and a value as arguments, and set the argument to the asked value.
+
+\subsection{catcodetables}
+
+The equivalent of \texttt{\string\newcount} for catcodetables is \texttt{\string\newluacatcodetable}. Also a set of predefined catcodetables comes with \LuaTeX tra:
+
+\begin{itemize}
+\item \texttt{\string\CatcodeTableIniTeX}: the base \TeX\ catcodes
+\item \texttt{\string\CatcodeTableString}: almost all characters have catcode 12
+\item \texttt{\string\CatcodeTableOther}: all characters have catcode 12 (even space)
+\item \texttt{\string\CatcodeTableLaTeX}: the \LaTeX\ classical catcodes
+\end{itemize}
+
+\subsection{callbacks}
+
+For more informations about this part, see the documentation \texttt{luamcallbacks.pdf}.
+
+One of the main goals of \LuaTeX tra is also to provide a way for several packages to register their functions in one callback. The function \texttt{callback.register} does not provide any way to do so. To fix it, \LuaTeX tra provides the function \texttt{callback.add} that takes the same two first arguments as \texttt{callback.register} (name of the callback and function to register), and two other arguments: a mandatory description of the function, and an optional priority (the lower the number, the higher the priority).
+
+If people use \texttt{callback.register} all the \LuaTeX tra mechanism is broken, so we override \texttt{callback.register} with a function that simply outputs an error message.
+
+Three other very useful new functions are provided:
+
+\begin{itemize}
+\item \texttt{callback.remove} takes the name of a callback and the description of a register function (third argument of \texttt{callback.add}), and removes the function from a callback.
+\item \texttt{callback.reset} removes all register functions from a callback.
+\item \texttt{callback.get\_priority} takes the name of a callback and the description of a registered function, and returns the priority of the function in the callback, or 0 if the function is not registered.
+\end{itemize}
+
+
+\subsection{lua extra functions}
+
+Some extra functions have been added to the standard lua library, mostly coming from the Con\TeX t libraries, for the complete list of functions, please refer to the documentation \texttt{luaextra.pdf}.
+
+The most useful of these added functions is certainly \texttt{table.serialize} that returns the string describing a given table. This string can be used for debugging purposes, or table saving in files, as the string can be read by lua to rebuild the original table.
+
+\subsection{\texttt{.lua} module template\label{sub:luatemplate}}
+
+\begin{verbatim}
+mypackage = { }
+
+mypackage.module = {
+ name = "mypackage",
+ version = 1.0,
+ date = "2009/03/08",
+ description = "My fancy package",
+ author = "Me",
+ copyright = "Myself",
+ license = "My License",
+}
+
+luatextra.provides_module(mypackage.module)
+
+local format = string.format
+
+function mypackage.log (...)
+ luatextra.module_log('mypackage', format(...))
+end
+
+function mypackage.warning (...)
+ luatextra.module_warning('mypackage', format(...))
+end
+
+function mypackage.error (...)
+ luatextra.module_error('mypackage', format(...))
+end
+\end{verbatim}
+
+\subsection{\texttt{.sty} template}
+
+\begin{verbatim}
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \input luatextra.sty
+\else
+ \NeedsTeXFormat{LaTeX2e}
+ \ProvidesPackage{mypackage}
+ [2009/03/08 v1.00 My super package.]
+ \RequirePackage{luatextra}
+\fi
+
+\luaUseModule{mymodule}
+\end{verbatim}
+
+\end{document}
diff --git a/Master/texmf-dist/source/luatex/luatextra/luatextra.dtx b/Master/texmf-dist/source/luatex/luatextra/luatextra.dtx
new file mode 100644
index 00000000000..62c763d8484
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatextra/luatextra.dtx
@@ -0,0 +1,1110 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%
+% This work is under the CC0 license.
+%
+% This work consists of the main source file luamcallbacks.dtx
+% and the derived files
+% luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf.
+%
+% Unpacking:
+% tex luatextra.dtx
+%
+% Documentation:
+% pdflatex luatextra.dtx
+%
+% The class ltxdoc loads the configuration file ltxdoc.cfg
+% if available. Here you can specify further options, e.g.
+% use A4 as paper format:
+% \PassOptionsToClass{a4paper}{article}
+%
+%
+%
+%<*ignore>
+\begingroup
+ \def\x{LaTeX2e}%
+\expandafter\endgroup
+\ifcase 0\ifx\install y1\fi\expandafter
+ \ifx\csname processbatchFile\endcsname\relax\else1\fi
+ \ifx\fmtname\x\else 1\fi\relax
+\else\csname fi\endcsname
+%</ignore>
+%<*install>
+\input docstrip.tex
+\Msg{************************************************************************}
+\Msg{* Installation}
+\Msg{* Package: luatextra 2009/04/15 v0.93 Additional low level functions for LuaTeX}
+\Msg{************************************************************************}
+
+\keepsilent
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+
+\preamble
+This is a generated file.
+
+Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+
+This work is under the CC0 license.
+
+This work consists of the main source file luainputenc.dtx
+and the derived files
+ luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf
+
+\endpreamble
+
+\let\MetaPrefix\DoubleperCent
+
+
+\generate{%
+ \usedir{tex/luatex/luatextra}%
+ \file{luatextra.sty}{\from{luatextra.dtx}{package}}%
+ \file{luatextra-latex.tex}{\from{luatextra.dtx}{latex}}%
+}
+
+% The following hacks are to generate a lua file with lua comments starting by -- instead of %%
+
+\def\MetaPrefix{-- }
+
+\def\luapostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+
+\def\currentpostamble{\luapostamble}%
+
+\generate{%
+ \usedir{tex/luatex/luatextra}%
+ \file{luatextra.lua}{\from{luatextra.dtx}{lua}}%%
+}
+
+\obeyspaces
+\Msg{************************************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the following}
+\Msg{* files into a directory searched by TeX:}
+\Msg{*}
+\Msg{* luatextra.sty luatextra-latex.tex luatextra.lua}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*}
+\Msg{************************************************************************}
+
+\endbatchfile
+%</install>
+%<*ignore>
+\fi
+%</ignore>
+%<*driver>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesFile{luaminimalotf.drv}%
+ [2009/04/15 v0.93 LuaTeX extra low-level macros.]%
+\documentclass{ltxdoc}
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{luatextra.dtx}%
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{0}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+% \GetFileInfo{luatextra.drv}
+%
+% \title{The \textsf{luatextra} package}
+% \date{2009/04/15 v0.93}
+% \author{Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% \textsf{luatextra} provides low-level addition to the formats Plain and \LaTeX\ to be used with the engine Lua\TeX.
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Documentation}
+%
+% \subsection{Preamble}
+%
+% This document is made for people wanting to understand how the package was made. For an introduction to the use of Lua\TeX\ with the formats Plain and \LaTeX , please read the document \texttt{luatextra-reference.pdf} that you can find in your \TeX\ distribution (\TeX Live from version 2009) or on the CTAN.
+%
+% \subsection{History of formats and engines}
+%
+% To understand this package, one must fist understand some historical choices in the \TeX\ world.
+%
+% A \TeX\ engine is a binary executable that provides some very low-level primitives, for example \texttt{\string\count} to set a counter to a certain value. A \TeX\ format is a macro package that provides higher-level macros for the user and the package developer, for example \texttt{\string\newcount} that allocates a new counter and gives it a name. Examples of engines are the old \TeX\ 82, $\varepsilon$-\TeX, pdf\TeX, Omega/Aleph, Lua\TeX\ and Xe\TeX. Examples of formats are Plain, \LaTeX\ and Con\TeX t.
+%
+% This distinction is hard to make as only one command is invoked, for example when you call the command \texttt{tex}, you often have no idea that the engine \TeX\ 82 is invoked with the format Plain.
+%
+% Evolution is also something confusing in the \TeX\ world: engines often evolve, and new engines have always appeared, when most formats are frozen: the Plain and \LaTeX\ formats do not accept any new code to cope with the new engines. In theory, this package shouldn't exist, or at least shouldn't be a package, but its code should be integrated into a format. But as Plain and \LaTeX\ are frozen, people wanting to take advantage of the new engines have to use a package.
+%
+% This package is really necessary to take advantage of Lua\TeX\ as it provides things users are expecting a macro package to provide, for example \texttt{\string\newluaattribute} that acts like \texttt{\string\newcount} for lua attributes. It also enables all Lua\TeX\ primitives, that are disabled by default.
+%
+% \subsection{choices made in this package}
+%
+% In the very long term, it is higly possible that Lua\TeX\ will replace pdf\TeX\ as the default \LaTeX\ engine, so it is necessary to keep backward compatibility. This lead us to the decision of renaming Lua\TeX -only primitives so that they all start by \texttt{lua}, like the pdf\TeX -only primitives start by \texttt{pdf}. Thus attributes become luaattributes, \texttt{\string\directlua} becomes \texttt{\string\luadirect}, etc. This also allows primitives to keep having the same name, even if their name is changed later at the engine level.
+%
+% \subsection{registers allocation scheme}
+%
+% The default register allocation scheme of \LaTeX\ is old and limited (like the one of \TeX 82) to 256 values. The engine $\varepsilon$-\TeX allows more different registers (up to 32768), and Lua\TeX\ allows even 65536 ones. These new limits were not acknowledged by \LaTeX . A package \textsf{etex} was created for \LaTeX\ to extends the allocation scheme. \textsf{luatextra} loads \textsf{etex}, and overrides somes values to extend the allocation max number to 65536.
+%
+% \subsection{attributes}
+%
+% Attributes are a new concept in Lua\TeX\ (see the Lua\TeX\ documentation for details). As the macro \texttt{\string\attribute} is certainly very common in the user's documents, they are renamed \texttt{luaattribute}s. This package provides a simple way to allocate new attributes, with the macro \texttt{\string\newluaattribute}. For more informations about attribute handling in lua, please read section \ref{sub:attr}.
+%
+% \subsection{Module system}
+%
+% Lua has some embedded module management, with the functions \texttt{module} and \texttt{require}. With this package we try get more control on the module system, by implementing something close to the \LaTeX 's \texttt{\string\usepackage} and \texttt{\string\RequirePackage} macros: the \texttt{\string\luaUseModule} and \texttt{\string\luaRequireModule} that act like them, but for lua files. The functions \texttt{module} and \texttt{require} should not be used, in profit of the lua functions \texttt{luatextra.provides\_module} and \texttt{luatextra.use\_module} or \texttt{luatextra.require\_module}.
+%
+% \subsection{Multiple callbacks handling}
+%
+% Lua\TeX\ has no way to register multiple functions in a callback. This package loads \textsf{luamcallbacks} that provides a safe way to do so. But the \textsf{luamcallbacks} package can't register several functions in some callbacks, like \texttt{open\_read\_file} and \texttt{define\_font}. This package takes advantage of the callback creation possibilities of \textsf{luamcallbacks} to split these callbacks into several ones that can agregate several functions. Thus it allows several packages to safely use the callbacks. See section \ref{sub:orf} for more details.
+%
+%
+% \section{\texttt{luatextra.lua}}
+%
+% \subsection{Initialization and internal functions}
+%
+% \iffalse
+%<*lua>
+% \fi
+%
+% \TeX\ always prints the names of the files that are input. Unfortunatly it can't do so with lua files called with \texttt{dofile}. We will fix it with the \texttt{luatextra.use\_module} function, but in the meantime we print this information for the \texttt{luatextra.lua} file.
+%
+% A change compared to usual filename printings is the fact that Lua\TeX\ does not print the \texttt{./} for files in the current directory. We keep this convention for lua filename printings.
+%
+% \begin{macrocode}
+do
+ local luatextrapath = kpse.find_file("luatextra.lua")
+ if luatextrapath then
+ if luatextrapath:sub(1,2) == "./" then
+ luatextrapath = luatextrapath:sub(3)
+ end
+ texio.write(' ('..luatextrapath)
+ end
+end
+
+% \end{macrocode}
+%
+% We create the \texttt{luatextra} table that will contain all the functions and variables, and we register it as a normal lua module.
+%
+% \begin{macrocode}
+
+luatextra = {}
+
+module("luatextra", package.seeall)
+
+% \end{macrocode}
+%
+% We initiate the modules table that will contain informations about the loaded modules. And we register the \texttt{luatextra} module. The informations contained in the table describing the module are always the same, it can be taken as a template. See \texttt{luatextra.provides\_module} for more details.
+%
+% \begin{macrocode}
+
+luatextra.modules = {}
+
+luatextra.modules['luatextra'] = {
+ version = 0.93,
+ name = "luatextra",
+ date = "2009/04/15",
+ description = "Additional low level functions for LuaTeX",
+ author = "Elie Roux",
+ copyright = "Elie Roux, 2009",
+ license = "CC0",
+}
+
+local format = string.format
+
+% \end{macrocode}
+%
+% Here we define the warning and error functions specific to \texttt{luatextra}.
+%
+% \begin{macrocode}
+
+luatextra.internal_warning_spaces = " "
+
+function luatextra.internal_warning(msg)
+ if not msg then return end
+ texio.write_nl(format("\nLuaTeXtra Warning: %s\n\n", msg))
+end
+
+luatextra.internal_error_spaces = " "
+
+function luatextra.internal_error(msg)
+ if not msg then return end
+ tex.sprint(format("\\immediate\\write16{}\\errmessage{LuaTeXtra error: %s^^J^^J}", msg))
+end
+
+% \end{macrocode}
+%
+% \subsection{Error, warning and info function for modules}
+%
+% Some module printing functions are provided, they have the same philosophy as the \LaTeX 's \texttt{\string\PackageError} and \texttt{\string\PackageWarning} macros: their first argument is the name of the module, and the second is the message. These functions are meant to be used by lua module writers.
+%
+% \begin{macrocode}
+
+function luatextra.module_error(package, msg, helpmsg)
+ if not package or not msg then
+ return
+ end
+ if helpmsg then
+ tex.sprint(format("\\errhelp{%s}", helpmsg))
+ end
+ tex.sprint(format("\\luaModuleError{%s}{%s}", package, msg))
+end
+
+function luatextra.module_warning(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl(format("\nModule %s Warning: %s\n\n", modulename, msg))
+end
+
+function luatextra.module_log(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl('log', format("%s: %s", modulename, msg))
+end
+
+function luatextra.module_term(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl('term', format("%s: %s", modulename, msg))
+end
+
+function luatextra.module_info(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl(format("%s: %s\n", modulename, msg))
+end
+
+% \end{macrocode}
+%
+% \subsection{module loading and providing functions}
+%
+% A small function to find a lua module file according to its name, with or without the \texttt{.lua} at the end of the filename.
+%
+% \begin{macrocode}
+
+function luatextra.find_module_file(name)
+ if string.sub(name, -4) ~= '.lua' then
+ name = name..'.lua'
+ end
+ path = kpse.find_file(name, 'tex')
+ if not path then
+ path = kpse.find_file(name, 'texmfscripts')
+ end
+ return path, name
+end
+
+% \end{macrocode}
+%
+% A small patch, for the \texttt{module} function to work in this file. I can't understand why it doens't otherwise.
+%
+% \begin{macrocode}
+
+luatextra.module = module
+
+% \end{macrocode}
+%
+% \begin{macro}{luatextra.use module}
+%
+% This macro is the one used to simply load a lua module file. It does not reload it if it's already loaded, and prints the filename in the terminal and the log. A lua module must call the macro \texttt{luatextra.provides\_module}.
+%
+% \begin{macrocode}
+
+
+function luatextra.use_module(name)
+ if not name or luatextra.modules[name] then
+ return
+ end
+ local path, filename = luatextra.find_module_file(name)
+ if not path then
+ luatextra.internal_error(format("unable to find lua module %s", name))
+ else
+ if path:sub(1,2) == "./" then
+ path = path:sub(3)
+ end
+ texio.write(' ('..path)
+ dofile(path)
+ if not luatextra.modules[name] then
+ luatextra.internal_warning(format("You have requested module `%s',\n%s but the file %s does not provide it.", name, luatextra.internal_warning_spaces, filename))
+ end
+ if not package.loaded[name] then
+ luatextra.module(name, package.seeall)
+ end
+ texio.write(')')
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% Some internal functions to convert a date into a number, and to determine if a string is a date. It is useful for \texttt{luatextra.require\_package} to understand if a user asks a version with a date or a version number.
+%
+% \begin{macrocode}
+
+function luatextra.datetonumber(date)
+ numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
+ return tonumber(numbers)
+end
+
+function luatextra.isdate(date)
+ for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
+ return true
+ end
+ return false
+end
+
+local date, number = 1, 2
+
+function luatextra.versiontonumber(version)
+ if luatextra.isdate(version) then
+ return {type = date, version = luatextra.datetonumber(version), orig = version}
+ else
+ return {type = number, version = tonumber(version), orig = version}
+ end
+end
+
+luatextra.requiredversions = {}
+
+% \end{macrocode}
+%
+% \begin{macro}{luatextra.require module}
+%
+% This function is like the \texttt{luatextra.use\_module} function, but can accept a second argument that checks for the version of the module. The version can be a number or a date (format yyyy/mm/dd).
+%
+% \begin{macrocode}
+
+function luatextra.require_module(name, version)
+ if not name then
+ return
+ end
+ if not version then
+ return luatextra.use_module(name)
+ end
+ luaversion = luatextra.versiontonumber(version)
+ if luatextra.modules[name] then
+ if luaversion.type == date then
+ if luatextra.datetonumber(luatextra.modules[name].date) < luaversion.version then
+ luatextra.internal_error(format("found module `%s' loaded in version %s, but version %s was required", name, luatextra.modules[name].date, version))
+ end
+ else
+ if luatextra.modules[name].version < luaversion.version then
+ luatextra.internal_error(format("found module `%s' loaded in version %.02f, but version %s was required", name, luatextra.modules[name].version, version))
+ end
+ end
+ else
+ luatextra.requiredversions[name] = luaversion
+ luatextra.use_module(name)
+ end
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{luatextra.provides module}
+%
+% This macro is the one that must be called in the module files. It takes a table as argument. You can put any information you want in this table, but the mandatory ones are \texttt{name} (a string), \texttt{version} (a number), \texttt{date} (a string) and \texttt{description} (a string). Other fields are usually \texttt{copyright}, \texttt{author} and \texttt{license}.
+%
+% This function logs informations about the module the same way \LaTeX\ does for informations about packages.
+%
+% \begin{macrocode}
+
+function luatextra.provides_module(mod)
+ if not mod then
+ luatextra.internal_error('cannot provide nil module')
+ return
+ end
+ if not mod.version or not mod.name or not mod.date or not mod.description then
+ luatextra.internal_error('invalid module registered, fields name, version, date and description are mandatory')
+ return
+ end
+ requiredversion = luatextra.requiredversions[mod.name]
+ if requiredversion then
+ if requiredversion.type == date and requiredversion.version > luatextra.datetonumber(mod.date) then
+ luatextra.internal_error(format("loading module %s in version %s, but version %s was required", mod.name, mod.date, requiredversion.orig))
+ elseif requiredversion.type == number and requiredversion.version > mod.version then
+ luatextra.internal_error(format("loading module %s in version %.02f, but version %s was required", mod.name, mod.version, requiredversion.orig))
+ end
+ end
+ luatextra.modules[mod.name] = module
+ texio.write_nl('log', format("Lua module: %s %s v%.02f %s\n", mod.name, mod.date, mod.version, mod.description))
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% Here we load the \textsf{luaextra} module, that contains a bunch of very useful functions. See the documentation of \textsf{luaextra} for more details.
+%
+% \begin{macrocode}
+
+luatextra.use_module('luaextra')
+
+% \end{macrocode}
+%
+% \texttt{luatextra.kpse\_module\_loader} finds a module with the \texttt{kpse} library. This function is then registered in the table of the functions used by the lua function \texttt{require} to look for modules.
+%
+% \begin{macrocode}
+
+function luatextra.kpse_module_loader(mod)
+ local file = luatextra.find_module_file(mod)
+ if file then
+ local loader, error = loadfile(file)
+ if loader then
+ texio.write_nl("(" .. file .. ")")
+ return loader
+ end
+ return "\n\t[luatextra.kpse_module_loader] Loading error:\n\t"
+ .. error
+ end
+ return "\n\t[luatextra.kpse_module_loader] Search failed"
+end
+
+table.insert(package.loaders, luatextra.kpse_module_loader)
+
+% \end{macrocode}
+%
+% \subsection{Attributes handling\label{sub:attr}}
+%
+% Attribute allocation is done mainly in the \texttt{sty} file, but there is also a lua addition for attribute handling: Lua\TeX\ is by default unable to tell the attribute number corresponding to an attribute name. This attribute number is necessary for functions such as \texttt{node.has\_attribute}, which is used very often. The solution until now was to give a chosen attribute number to each attribute, and pray that someone else didn't use it before. With this method it was easy to know the number of an attribute, as it was chosen. Now with the \texttt{\string\newluaattribute} macro, it's impossible to know the number of an attribute. To fix it, when \texttt{\string\newluaattribute} is called, it calls \texttt{luatextra.attributedef\_from\_tex}. This function registers the number in the table \texttt{tex.attributenumber}. For example to get the number of the attribute \texttt{myattribute} registered with \texttt{\string\newluaattribute\string\myattribute}, you can simply call \texttt{tex.attributenumber[myattribute]}.
+%
+% \begin{macrocode}
+
+luatextra.attributes = {}
+
+tex.attributenumber = luatextra.attributes
+
+function luatextra.attributedef_from_tex(name, number)
+ truename = name:gsub('[\\ ]', '')
+ luatextra.attributes[truename] = tonumber(number)
+end
+
+% \end{macrocode}
+%
+% \subsection{Catcodetables handling}
+%
+% In the same way, the table \texttt{tex.catcodetablenumber} contains the numbers of the catcodetables registered with \texttt{\string\newluacatcodetable}.
+%
+% \begin{macrocode}
+
+luatextra.catcodetables = {}
+
+tex.catcodetablenumber = luatextra.catcodetables
+
+function luatextra.catcodetabledef_from_tex(name, number)
+ truename = name:gsub('[\\ ]', '')
+ luatextra.catcodetables[truename] = tonumber(number)
+end
+
+% \end{macrocode}
+%
+% \subsection{Multiple callbacks on the \texttt{open\_read\_file} callback\label{sub:orf}}
+%
+% The luamcallbacks (see documentation for details) cannot really provide a simple and reliable way of registering multiple functions in some callbacks. To be able to do so, the solution we implemented is to register one function in these callbacks, and to create "sub-callbacks" that can accept several functions. That's what we do here for the callback \texttt{open\_read\_file}.
+%
+% \begin{macro}{luatextra.open read file}
+%
+% This function is the one that will be registered in the callback. It calls new callbacks, that will be created later. These callbacks are:
+%
+%\begin{itemize}
+% \item \texttt{pre\_read\_file} in which you can register a function with the signature \texttt{pre\_read\_file(env)}, with \texttt{env} being a table containing the fields \texttt{filename} which is the argument of the callback \texttt{open\_read\_file}, and \texttt{path} which is the result of \texttt{kpse.find\_file}. You can put any field you want in the \texttt{env} table, you can even override the existing fields. This function is called at the very beginning of the callback, it allows for instance to register functions in the other callbacks. It is useless to add a field \texttt{reader} or \texttt{close}, as they will be overriden.
+% \item \texttt{file\_reader} is automatically registered in the \texttt{reader} callback for every file, it has the same signature.
+% \item \texttt{file\_close} is registered in the \texttt{close} callback for every file, and has the same signature.
+%\end{itemize}
+%
+% \begin{macrocode}
+
+function luatextra.open_read_file(filename)
+ local path = kpse.find_file(filename)
+ local env = {
+ ['filename'] = filename,
+ ['path'] = path,
+ }
+ luamcallbacks.call('pre_read_file', env)
+ path = env.path
+ if not path then
+ return
+ end
+ local f = env.file
+ if not f then
+ f = io.open(path)
+ env.file = f
+ end
+ if not f then
+ return
+ end
+ env.reader = luatextra.reader
+ env.close = luatextra.close
+ return env
+end
+
+% \end{macrocode}
+%
+% \end{macro}
+%
+% The two next functions are the one called in the \texttt{open\_read\_file} callback.
+%
+% \begin{macrocode}
+
+
+function luatextra.reader(env)
+ local line = (env.file):read()
+ line = luamcallbacks.call('file_reader', env, line)
+ return line
+end
+
+function luatextra.close(env)
+ (env.file):close()
+ luamcallbacks.call('file_close', env)
+end
+
+% \end{macrocode}
+%
+% In the callback creation process we need to have default behaviours. Here they are. These are called only when no function is registered in the created callback. See the documentation of \texttt{luamcallbacks} for more details.
+%
+% \begin{macrocode}
+
+
+function luatextra.default_reader(env, line)
+ return line
+end
+
+function luatextra.default_close(env)
+ return
+end
+
+function luatextra.default_pre_read(env)
+ return env
+end
+
+% \end{macrocode}
+%
+% \subsection{Multiple callbacks on the \texttt{define\_font} callback\label{sub:df}}
+%
+% The same principle is applied to the \texttt{define\_font} callback. The main difference is that this mechanism is not applied by default. The reason is that the callback most people will register in the \texttt{define\_font} callback is the one from Con\TeX t allowing the use of OT fonts. When the code will be more adapted (not so soon certainly), this mechanism will certainly be used, as it allows more flexibility in the font syntax, the OT font load mechanism, etc.
+%
+% The callbacks we register here are the following ones:
+%
+% \begin{itemize}
+% \item \texttt{font\_syntax} that takes a table with the fields \texttt{asked\_name}, \texttt{name} and \texttt{size}, and modifies this table to add more information. It must add at least a \texttt{path} field. The structure of the final table is not precisely defined, as it can vary from one syntax to another.
+% \item \texttt{open\_otf\_font} takes the previous table, and must return a valid font structure as described in the Lua\TeX\ manual.
+% \item \texttt{post\_font\_opening} takes the final font table and can modify it, before this table is returned to the \texttt{define\_font} callback.
+% \end{itemize}
+%
+% But first, we acknowledge the fact that \texttt{fontforge} has been renamed to \texttt{fontloader}. This check allows older versions of Lua\TeX\ to use \texttt{fontloader}.
+%
+% As this mechanism is not loaded by default and certainly won't be until version 1.0 of Lua\TeX , we don't document it further. See the documentation of \texttt{luatextra.sty} (macro \texttt{\string\ltxtra\string@RegisterFontCallback}) to know how to load this mechanism anyway.
+%
+% \begin{macrocode}
+
+do
+ if tex.luatexversion < 36 then
+ fontloader = fontforge
+ end
+end
+
+function luatextra.find_font(name)
+ local types = {'ofm', 'ovf', 'opentype fonts', 'truetype fonts'}
+ local path = kpse.find_file(name)
+ if path then return path end
+ for _,t in pairs(types) do
+ path = kpse.find_file(name, t)
+ if path then return path end
+ end
+ return nil
+end
+
+function luatextra.font_load_error(error)
+ luatextra.module_warning('luatextra', string.format('%s\nloading lmr10 instead...', error))
+end
+
+function luatextra.load_default_font(size)
+ return font.read_tfm("lmr10", size)
+end
+
+function luatextra.define_font(name, size)
+ if (size < 0) then size = (- 655.36) * size end
+ local fontinfos = {
+ asked_name = name,
+ name = name,
+ size = size
+ }
+ callback.call('font_syntax', fontinfos)
+ name = fontinfos.name
+ local path = fontinfos.path
+ if not path then
+ path = luatextra.find_font(name)
+ fontinfos.path = luatextra.find_font(name)
+ end
+ if not path then
+ luatextra.font_load_error("unable to find font "..name)
+ return luatextra.load_default_font(size)
+ end
+ if not fontinfos.filename then
+ fontinfos.filename = fpath.basename(path)
+ end
+ local ext = fpath.suffix(path)
+ local f
+ if ext == 'tfm' or ext == 'ofm' then
+ f = font.read_tfm(name, size)
+ elseif ext == 'vf' or ext == 'ovf' then
+ f = font.read_vf(name, size)
+ elseif ext == 'ttf' or ext == 'otf' or ext == 'ttc' then
+ f = callback.call('open_otf_font', fontinfos)
+ else
+ luatextra.font_load_error("unable to determine the type of font "..name)
+ f = luatextra.load_default_font(size)
+ end
+ if not f then
+ luatextra.font_load_error("unable to load font "..name)
+ f = luatextra.load_default_font(size)
+ end
+ callback.call('post_font_opening', f, fontinfos)
+ return f
+end
+
+function luatextra.default_font_syntax(fontinfos)
+ return
+end
+
+function luatextra.default_open_otf(fontinfos)
+ return nil
+end
+
+function luatextra.default_post_font(f, fontinfos)
+ return true
+end
+
+function luatextra.register_font_callback()
+ callback.add('define_font', luatextra.define_font, 'luatextra.define_font')
+end
+
+do
+ luatextra.use_module('luamcallbacks')
+ callback.create('pre_read_file', 'simple', luatextra.default_pre_read)
+ callback.create('file_reader', 'data', luatextra.default_reader)
+ callback.create('file_close', 'simple', luatextra.default_close)
+ callback.add('open_read_file', luatextra.open_read_file, 'luatextra.open_read_file')
+ callback.create('font_syntax', 'simple', luatextra.default_font_syntax)
+ callback.create('open_otf_font', 'first', luatextra.default_open_otf)
+ callback.create('post_font_opening', 'simple', luatextra.default_post_font)
+
+ if luatextrapath then
+ texio.write(')')
+ end
+end
+% \end{macrocode}
+% \iffalse
+%</lua>
+% \fi
+%
+% \section{\texttt{luatextra.sty}}
+%
+% \iffalse
+%<*package>
+% \fi
+%
+% \subsection{Initializations}
+%
+% First we prevent multiple loads of the file (useful for plain-\TeX ).
+%
+% \begin{macrocode}
+\csname ifluatextraloaded\endcsname
+\let\ifluatextraloaded\endinput
+
+% \end{macrocode}
+%
+% Then we load \textsf{ifluatex}.
+%
+% \begin{macrocode}
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \expandafter\ifx\csname ifluatex\endcsname\relax
+ \input ifluatex.sty
+ \fi
+\else
+ \RequirePackage{ifluatex}
+\fi
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+% \end{macrocode}
+%
+% If the package is loaded with Plain, we raise an error if the package is called with a non-Lua\TeX\ engine, and we define \texttt{\string\luaRequireModule} with two mandatory arguments.
+%
+% \begin{macrocode}
+ \ifluatex\else
+ \immediate\write16{}
+ \errmessage{Package luatextra Error: This package must be used with LuaTeX}
+ \fi
+ \def\luaRequireModule#1#2{\luadirect{luatextra.require_module([[#1]], [[#2]])}}
+\else
+% \end{macrocode}
+%
+% If the package is loaded with \LaTeX , we also print the error message, and we define \texttt{\string\luaRequireModule} with one mandatory argument (the name of the package) and one optional (the version or the date). We also define the environment \texttt{luacode}.
+%
+% \begin{macrocode}
+ \ifluatex\else
+ \PackageError{luatextra}{This package must be used with LuaTeX.}
+ \fi
+ \NeedsTeXFormat{LaTeX2e}
+ \ProvidesPackage{luatextra}
+ [2009/04/15 v0.93 LuaTeX extra low-level macros]
+ \RequirePackage{environ}
+ \NewEnviron{luacode}{\luadirect{\BODY}}
+ \newcommand\luaRequireModule[2][0]{\luadirect{luatextra.require_module([[#2]], [[#1]])}}
+% \end{macrocode}
+%
+% We also require the package \textsf{etex} to be loaded. The \texttt{\string\input} is a hack that modifies some values in the register attribution scheme of $\varepsilon$-\TeX\ and remaps \texttt{\string\newcount} to \textsf{etex}'s \texttt{\string\globcount}. We have to do such a remapping in a separate file that Plain doesn't see, otherwise it outputs an error if we try to change \texttt{\string\newcount} (because it is an \texttt{\string\outer} macro). See section \ref{sub:latex} for the file content.
+%
+% \begin{macrocode}
+ \RequirePackage{etex}[1998/03/26]%
+ \input luatextra-latex.tex
+\fi
+
+% \end{macrocode}
+%
+% The two macros \texttt{\string\LuaTeX} and \texttt{\string\LuaLaTeX} are defined to Lua\TeX\ and Lua\LaTeX , because that's the way it's written in the Lua\TeX 's manual (not in small capitals).
+%
+% \begin{macrocode}
+
+\def\LuaTeX{Lua\TeX }
+\def\LuaLaTeX{Lua\LaTeX }
+
+% \end{macrocode}
+%
+% \subsection{Primitives renaming}
+%
+% Here we differenciate two very different cases: Lua\TeX\ version < 0.36 has no \texttt{tex.enableprimitives} function, and has support for multiple lua states, and for versions > 0.35, the \texttt{tex.enableprimitives} is provided, and the old \texttt{\string\directlua} syntax prints a warning.
+%
+% \begin{macrocode}
+
+\ifnum\luatexversion<36
+% \end{macrocode}
+%
+% For old versions, we simply rename the primitives. You can note that \texttt{\string\attribute} (and also others) have no \texttt{\string\primitive} before them, because it would make users unable to call \texttt{\string\global\string\luaattribute}, which is a strong restriction. With this method, we can call it, but if \texttt{\string\attribute} was defined before, this means that \texttt{\string\luaattribute} will get its meaning, which is dangerous. Note also that you cannot use multiple states.
+%
+% \begin{macrocode}
+ \def\directlua{\pdfprimitive\directlua0}
+ \def\latelua{\pdfprimitive\latelua0}
+ \def\luadirect{\pdfprimitive\directlua0}
+ \def\lualate{\pdfprimitive\latelua0}
+ \def\luaattribute{\attribute}
+ \def\luaattributedef{\attributedef}
+ \def\luaclearmarks{\pdfprimitive\luaclearmarks}
+ \def\luaformatname{\pdfprimitive\formatname}
+ \def\luascantexttokens{\pdfprimitive\scantexttokens}
+ \def\luacatcodetable{\catcodetable}
+\else
+% \end{macrocode}
+%
+% For newer versions, we first enable all primitives with their default name. Then we add a prefix to some. Note that with this method, \texttt{\string\luaattribute} will always have the good meaning (except, of course, if it was defined before, but I think we can call it perversion...).
+%
+% \begin{macrocode}
+ \directlua{tex.enableprimitives('lua', {'attribute'})}
+ \directlua{tex.enableprimitives('lua', {'attributedef'})}
+ \directlua{tex.enableprimitives('lua', {'clearmarks'})}
+ \directlua{tex.enableprimitives('lua', {'formatname'})}
+ \directlua{tex.enableprimitives('lua', {'scantexttokens'})}
+ \directlua{tex.enableprimitives('lua', {'catcodetable'})}
+ \def\luadirect{\pdfprimitive\directlua}
+ \def\lualate{\pdfprimitive\latelua}
+\fi
+
+% \end{macrocode}
+%
+% Finally we add some common definitions that have lua inside their name, or that must remove their suffix.
+%
+% \begin{macrocode}
+\def\initluacatcodetable{\pdfprimitive\initcatcodetable}
+\def\saveluacatcodetable{\pdfprimitive\savecatcodetable}
+\def\luaclose{\pdfprimitive\closelua}
+
+% \end{macrocode}
+%
+% We load the \texttt{lua} file.
+%
+% \begin{macrocode}
+
+\luadirect{dofile(kpse.find_file("luatextra.lua"))}
+
+% \end{macrocode}
+%
+% A small macro to register the \texttt{define\_font} callback from \textsf{luatextra}. See section \ref{sub:df} for more details.
+%
+% \begin{macrocode}
+
+\def\ltxtra@RegisterFontCallback{
+ \luadirect{luatextra.register_font_callback()}
+}
+
+% \end{macrocode}
+%
+% \subsection{Module handling}
+%
+% The \texttt{\string\luaModuleError} macro is called by the lua function \texttt{luatextra.module\_error}. It is necessary because we can't call directly \texttt{\string\errmessage} in lua.
+%
+% \begin{macrocode}
+
+% \end{macrocode}
+%
+% \subsection{Module handling}
+%
+% The \texttt{\string\luaModuleError} macro is called by the lua function \texttt{luatextra.module\_error}. It is necessary because we can't call directly \texttt{\string\errmessage} in lua. Then we define \texttt{\string\luaUseModule} that simply calls \texttt{luatextra.use\_module}. Remember that \texttt{\string\luaRequireModule} is defined at the beginning of this file.
+%
+% \begin{macrocode}
+
+
+\def\luaModuleError#1#2{%
+ \errorcontextlines=0\relax
+ \immediate\write16{}%
+ \errmessage{Module #1 error: #2^^J^^J%
+See the module #1 documentation for explanation.^^J ...^^J}%
+}
+
+\def\luaUseModule#1{\luadirect{luatextra.use_module([[#1]])}}
+
+% \end{macrocode}
+%
+% \subsection{Attributes handling}
+%
+% The most important macro here is \texttt{\string\newluaattribute} that allocates a new attribute, and adds it in the \texttt{tex.attributename} table (see \texttt{luatextra.attributedef\_from\_tex} for more details. It works just like the other \texttt{\string\new*} macros, we can allocate up to 65536 different attributes.
+%
+% \begin{macrocode}
+
+
+\newcount\luaattdefcounter
+\luaattdefcounter = 1
+
+\def\newluaattribute#1{%
+ \ifnum\luaattdefcounter<65535\relax %
+ \global\advance\luaattdefcounter by 1\relax %
+ \allocationnumber\luaattdefcounter %
+ \ifluatex %
+ \global\luaattributedef#1=\allocationnumber %
+ \fi %
+ \wlog{\string#1=\string\attribute\the\allocationnumber}%
+ \luadirect{%
+ luatextra.attributedef_from_tex([[\noexpand#1]], '\number\allocationnumber')}%
+ \else %
+ \errmessage{No room for a new \string\attribute}%
+ \fi %
+}
+
+% \end{macrocode}
+%
+% Two convenient macros, one to set an attribute (basically just a wrapper), and another one to uset it. Unsetting attributes with this function is important, as the \texttt{unset} value may change, as it already has in the 0.37 version.
+%
+% \begin{macrocode}
+
+\def\setluaattribute#1#2{%
+ #1=\numexpr#2\relax %
+}
+
+\def\unsetluaattribute#1{%
+ \ifnum\luatexversion<37\relax %
+ #1=-1\relax %
+ \else %
+ #1=-"7FFFFFFF\relax %
+ \fi %
+}
+
+% \end{macrocode}
+%
+% \subsection{Catcodetables handling}
+%
+% Here we allocate catcodetables the same way we handle attributes.
+%
+% \begin{macrocode}
+
+\newcount\luacatcodetabledefcounter
+
+\luacatcodetabledefcounter = 1
+
+\def\newluacatcodetable#1{%
+ \ifnum\luacatcodetabledefcounter<1114110\relax % 0x10FFFF is maximal \chardef
+ \global\advance\luacatcodetabledefcounter by 1\relax %
+ \allocationnumber=\luacatcodetabledefcounter %
+ \global\chardef#1=\allocationnumber %
+ \luadirect{%
+ luatextra.catcodetabledef_from_tex([[\noexpand#1]], '\number\allocationnumber')}%
+ \wlog{\string#1=\string\catcodetable\the\allocationnumber}%
+ \else %
+ \errmessage{No room for a new \string\catcodetable}%
+ \fi %
+}
+
+% \end{macrocode}
+%
+% A small patch to manage the catcode of \@ in Plain, and to get two new counters in Plain too.
+%
+% \begin{macrocode}
+
+\expandafter\edef\csname ltxtra@AtEnd\endcsname{%
+ \catcode64 \the\catcode64\relax
+}
+
+\catcode 64=11\relax
+
+\expandafter\ifx\csname @tempcnta\endcsname\relax
+ \csname newcount\endcsname\@tempcnta
+\fi
+\expandafter\ifx\csname @tempcntb\endcsname\relax
+ \csname newcount\endcsname\@tempcntb
+\fi
+
+% \end{macrocode}
+%
+% A macro that sets the catcode of a range of characters. The first parameter is the character number of the first character of the range, the second parameter is one for the last character, and the third parameter is the catcode we want them to have.
+%
+% \begin{macrocode}
+
+\def\luasetcatcoderange#1#2#3{%
+ \edef\luaSCR@temp{%
+ \noexpand\@tempcnta=\the\@tempcnta
+ \noexpand\@tempcntb=\the\@tempcntb
+ \noexpand\count@=\the\count@
+ \relax
+ }%
+ \@tempcnta=#1\relax
+ \@tempcntb=#2\relax
+ \count@=#3\relax
+ \loop\unless\ifnum\@tempcnta>\@tempcntb
+ \catcode\@tempcnta=\count@
+ \advance\@tempcnta by 1\relax
+ \repeat
+ \luaSCR@temp
+}
+
+% \end{macrocode}
+%
+% Finally we create several catcodetables that may be used by the user. These are:
+%
+% \begin{itemize}
+% \item \texttt{\string\CatcodeTableIniTeX}: the base \TeX\ catcodes
+% \item \texttt{\string\CatcodeTableString}: almost all characters have catcode 12
+% \item \texttt{\string\CatcodeTableOther}: all characters have catcode 12 (even space)
+% \item \texttt{\string\CatcodeTableLaTeX}: the \LaTeX\ classical catcodes
+% \end{itemize}
+%
+% \begin{macrocode}
+
+\newluacatcodetable\CatcodeTableIniTeX
+\newluacatcodetable\CatcodeTableString
+\newluacatcodetable\CatcodeTableOther
+\newluacatcodetable\CatcodeTableLaTeX
+\initluacatcodetable\CatcodeTableIniTeX
+
+\expandafter\ifx\csname @firstofone\endcsname\relax
+ \long\def\@firstofone#1{#1}%
+\fi
+
+\begingroup
+ \def\@makeother#1{\catcode#1=12\relax}%
+ \@firstofone{%
+ \luacatcodetable\CatcodeTableIniTeX
+ \begingroup
+ \luasetcatcoderange{0}{8}{15}%
+ \catcode9=10 % tab
+ \catcode11=15 %
+ \catcode12=13 % form feed
+ \luasetcatcoderange{14}{31}{15}%
+ \catcode35=6 % hash
+ \catcode36=3 % dollar
+ \catcode38=4 % ampersand
+ \catcode94=7 % circumflex
+ \catcode95=8 % underscore
+ \catcode123=1 % brace left
+ \catcode125=2 % brace right
+ \catcode126=13 % tilde
+ \catcode127=15 %
+ \saveluacatcodetable\CatcodeTableLaTeX
+ \endgroup
+ \@makeother{0}% nul
+ \@makeother{13}% carriage return
+ \@makeother{37}% percent
+ \@makeother{92}% backslash
+ \@makeother{127}%
+ \luasetcatcoderange{65}{90}{12}% A-Z
+ \luasetcatcoderange{97}{122}{12}% a-z
+ \saveluacatcodetable\CatcodeTableString
+ \@makeother{32}% space
+ \saveluacatcodetable\CatcodeTableOther
+ \endgroup
+}
+
+% \end{macrocode}
+%
+% We load \textsf{luaotfload}.
+%
+% \begin{macrocode}
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \input luaotfload.sty
+\else
+ \RequirePackage{luaotfload}
+\fi
+
+\ltxtra@AtEnd
+% \end{macrocode}
+% \iffalse
+%</package>
+% \fi
+%
+% \section{\texttt{luatextra-latex.tex}\label{sub:latex}}
+%
+% This file is very small, it just changes the maximum values of allowed registers from 32768 to 65536, and remaps \texttt{\string\newcount} (and friends) to \textsf{etex}'s \texttt{\string\globcount}.
+%
+% \iffalse
+%<*latex>
+% \fi
+% \begin{macrocode}
+\def\ltxtra@temp#1{%
+\ifnum\count27#1=32768 %
+ \count27#1=65536 %
+\fi
+}%
+\ltxtra@temp0%
+\ltxtra@temp1%
+\ltxtra@temp2%
+\ltxtra@temp3%
+\ltxtra@temp4%
+\ltxtra@temp5%
+\ltxtra@temp6%
+\let\newcount\globcount
+\let\newdimen\globdimen
+\let\newskip\globskip
+\let\newbox\globbox
+% \end{macrocode}
+% \iffalse
+%</latex>
+% \fi
+%
+%
+% \Finale
+\endinput
diff --git a/Master/texmf-dist/tex/luatex/luatextra/luaextra.lua b/Master/texmf-dist/tex/luatex/luatextra/luaextra.lua
new file mode 100644
index 00000000000..4c21f24b157
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luatextra/luaextra.lua
@@ -0,0 +1,600 @@
+--
+-- This is file `luaextra.lua',
+-- generated with the docstrip utility.
+--
+-- The original source files were:
+--
+-- luaextra.dtx (with options: `lua')
+-- This is a generated file.
+--
+-- Copyright (C) 2009 by PRAGMA ADE / ConTeXt Development Team
+--
+-- See ConTeXt's mreadme.pdf for the license.
+--
+-- This work consists of the main source file luaextra.dtx
+-- and the derived file luaextra.lua.
+--
+do
+ local luatextra_module = {
+ name = "luaextra",
+ version = 0.91,
+ date = "2009/04/15",
+ description = "Lua additional functions.",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "See ConTeXt's mreadme.pdf for the license",
+ }
+
+ luatextra.provides_module(luatextra_module)
+end
+
+function string:stripspaces()
+ return (self:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+
+function string.is_number(str)
+ return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+
+lpeg.space = lpeg.S(" \t\f\v")
+lpeg.newline = lpeg.P("\r\n") + lpeg.P("\r") +lpeg.P("\n")
+
+
+if not table.fastcopy then do
+
+ local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
+
+ local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in pairs(old) do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+ end
+
+ table.fastcopy = fastcopy
+
+end end
+
+
+if not table.copy then do
+
+ local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
+
+ local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+ end
+
+ table.copy = copy
+
+end end
+
+
+function table.sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in pairs(tab) do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ table.sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ table.sort(srt)
+ end
+ return srt
+end
+
+do
+ table.serialize_functions = true
+ table.serialize_compact = true
+ table.serialize_inline = true
+
+ local function key(k)
+ if type(k) == "number" then -- or k:find("^%d+$") then
+ return "["..k.."]"
+ elseif noquotes and k:find("^%a[%a%d%_]*$") then
+ return k
+ else
+ return '["'..k..'"]'
+ end
+ end
+
+ local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in pairs(t) do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" or tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = ("%q"):format(v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+ end
+
+ local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed)
+ handle = handle or print
+ reduce = reduce or false
+ if depth then
+ depth = depth .. " "
+ if indexed then
+ handle(("%s{"):format(depth))
+ else
+ handle(("%s%s={"):format(depth,key(name)))
+ end
+ else
+ depth = ""
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ handle("[" .. name .. "]={")
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ end
+ if root and next(root) then
+ local compact = table.serialize_compact
+ local inline = compact and table.serialize_inline
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ for k,v in ipairs(root) do -- NOT: for k=1,#root do (why)
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ for _,k in pairs(table.sortedkeys(root)) do
+ local v = root[k]
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ handle(("%s %s,"):format(depth,v))
+ elseif t == "string" then
+ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(("%s %s,"):format(depth,v))
+ else
+ handle(("%s %q,"):format(depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(("%s {},"):format(depth))
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ handle(("%s { %s },"):format(depth,table.concat(st,", ")))
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
+ end
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
+ end
+ elseif t == "boolean" then
+ handle(("%s %s,"):format(depth,tostring(v)))
+ elseif t == "function" then
+ if table.serialize_functions then
+ handle(('%s loadstring(%q),'):format(depth,string.dump(v)))
+ else
+ handle(('%s "function",'):format(depth))
+ end
+ else
+ handle(("%s %q,"):format(depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(("%s __p__=nil,"):format(depth))
+ end
+ elseif t == "number" then
+ handle(("%s %s=%s,"):format(depth,key(k),v))
+ elseif t == "string" then
+ if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(("%s %s=%s,"):format(depth,key(k),v))
+ else
+ handle(("%s %s=%q,"):format(depth,key(k),v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(("%s %s={},"):format(depth,key(k)))
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", ")))
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes)
+ end
+ else
+ serialize(v,k,handle,depth,level+1,reduce,noquotes)
+ end
+ elseif t == "boolean" then
+ handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+ elseif t == "function" then
+ if table.serialize_functions then
+ handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v)))
+ else
+ handle(('%s %s="function",'):format(depth,key(k)))
+ end
+ else
+ handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
+ -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+ end
+ end
+ if level > 0 then
+ handle(("%s},"):format(depth))
+ else
+ handle(("%s}"):format(depth))
+ end
+ else
+ handle(("%s}"):format(depth))
+ end
+ end
+
+ function table.serialize(root,name,reduce,noquotes)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ return table.concat(t,"\n")
+ end
+
+ function table.tostring(t, name)
+ return table.serialize(t, name)
+ end
+
+ function table.tohandle(handle,root,name,reduce,noquotes)
+ serialize(root, name, handle, nil, 0, reduce, noquotes)
+ end
+
+ -- sometimes tables are real use (zapfino extra pro is some 85M) in which
+ -- case a stepwise serialization is nice; actually, we could consider:
+ --
+ -- for line in table.serializer(root,name,reduce,noquotes) do
+ -- ...(line)
+ -- end
+ --
+ -- so this is on the todo list
+
+ table.tofile_maxtab = 2*1024
+
+ function table.tofile(filename,root,name,reduce,noquotes)
+ local f = io.open(filename,'w')
+ if f then
+ local concat = table.concat
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root, name, flush, nil, 0, reduce, noquotes)
+ end
+ f:close()
+ end
+ end
+
+end
+
+
+function table.tohash(t)
+ local h = { }
+ for _, v in pairs(t) do -- no ipairs here
+ h[v] = true
+ end
+ return h
+end
+
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in pairs(t) do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+
+function table.contains_value(t, val)
+ if t then
+ for k, v in pairs(t) do
+ if v==val then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+
+function table.contains_key(t, key)
+ if t then
+ for k, v in pairs(t) do
+ if k==key then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+
+function table.value_position(t, val)
+ if t then
+ local i=1
+ for k, v in pairs(t) do
+ if v==val then
+ return i
+ end
+ i=i+1
+ end
+ end
+ return 0
+end
+
+
+function table.key_position(t, key)
+ if t then
+ local i=1
+ for k,v in pairs(t) do
+ if k==key then
+ return i
+ end
+ i = i+1
+ end
+ end
+ return -1
+end
+
+
+function table.remove_value(t, v)
+ local p = table.value_position(t,v)
+ if p ~= -1 then
+ table.remove(t, table.value_position(t,v))
+ end
+end
+
+
+function table.remove_key(t, k)
+ local p = table.key_position(t,k)
+ if p ~= -1 then
+ table.remove(t, table.key_position(t,k))
+ end
+end
+
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+
+fpath = { }
+
+
+function fpath.removesuffix(filename)
+ return filename:gsub("%.[%a%d]+$", "")
+end
+
+
+function fpath.addsuffix(filename, suffix)
+ if not filename:find("%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+
+function fpath.replacesuffix(filename, suffix)
+ if not filename:find("%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return (filename:gsub("%.[%a%d]+$","."..suffix))
+ end
+end
+
+
+function fpath.dirname(name)
+ return name:match("^(.+)[/\\].-$") or ""
+end
+
+
+function fpath.basename(fname)
+ if not fname then
+ return nil
+ end
+ return fname:match("^.+[/\\](.-)$") or fname
+end
+
+
+function fpath.nameonly(name)
+ return ((name:match("^.+[/\\](.-)$") or name):gsub("%..*$",""))
+end
+
+
+function fpath.suffix(name)
+ return name:match("^.+%.([^/\\]-)$") or ""
+end
+
+
+function fpath.join(...)
+ local pth = table.concat({...},"/")
+ pth = pth:gsub("\\","/")
+ local a, b = pth:match("^(.*://)(.*)$")
+ if a and b then
+ return a .. b:gsub("//+","/")
+ end
+ a, b = pth:match("^(//)(.*)$")
+ if a and b then
+ return a .. b:gsub("//+","/")
+ end
+ return (pth:gsub("//+","/"))
+end
+
+
+function fpath.split(str)
+ local t = { }
+ str = str:gsub("\\", "/")
+ str = str:gsub("(%a):([;/])", "%1\001%2")
+ for name in str:gmatch("([^;:]+)") do
+ if name ~= "" then
+ name = name:gsub("\001",":")
+ t[#t+1] = name
+ end
+ end
+ return t
+end
+
+
+function fpath.normalize_sep(str)
+ return str:gsub("\\", "/")
+end
+
+
+function fpath.localize_sep(str)
+ if os.type == 'windows' or type == 'msdos' then
+ return str:gsub("/", "\\")
+ else
+ return str:gsub("\\", "/")
+ end
+end
+
+
+function lfs.is_writable(name)
+ local f = io.open(name, 'w')
+ if f then
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+
+function lfs.is_readable(name)
+ local f = io.open(name,'r')
+ if f then
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+
+if not math.round then
+ function math.round(x)
+ return math.floor(x + 0.5)
+ end
+end
+
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+--
+-- End of File `luaextra.lua'.
diff --git a/Master/texmf-dist/tex/luatex/luatextra/luamcallbacks.lua b/Master/texmf-dist/tex/luatex/luatextra/luamcallbacks.lua
new file mode 100644
index 00000000000..03bebe0b7e9
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luatextra/luamcallbacks.lua
@@ -0,0 +1,407 @@
+--
+-- This is file `luamcallbacks.lua',
+-- generated with the docstrip utility.
+--
+-- The original source files were:
+--
+-- luamcallbacks.dtx (with options: `lua')
+-- This is a generated file.
+--
+-- Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+--
+-- This work is under the CC0 license.
+--
+-- This work consists of the main source file luamcallbacks.dtx
+-- and the derived files
+-- luamcallbacks.lua, luamcallbacks-test.tex, luamcallbacks.pdf.
+--
+
+luamcallbacks = { }
+
+luamcallbacks.module = {
+ name = "luamcallbacks",
+ version = 0.92,
+ date = "2009/03/19",
+ description = "Module to register several functions in a callback.",
+ author = "Hans Hagen & Elie Roux",
+ copyright = "Hans Hagen & Elie Roux",
+ license = "CC0",
+}
+
+luatextra.provides_module(luamcallbacks.module)
+
+
+luamcallbacks.callbacklist = luamcallbacks.callbacklist or { }
+
+
+luamcallbacks.lua_callbacks_defaults = { }
+
+local format = string.format
+
+
+local list = 1
+local data = 2
+local first = 3
+local simple = 4
+
+
+luamcallbacks.callbacktypes = luamcallbacks.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,
+}
+
+
+luamcallbacks.internalregister = luamcallbacks.internalregister or callback.register
+
+local callbacktypes = luamcallbacks.callbacktypes
+
+luamcallbacks.log = luamcallbacks.log or function(...)
+ luatextra.module_log('luamcallbacks', format(...))
+end
+
+luamcallbacks.info = luamcallbacks.info or function(...)
+ luatextra.module_info('luamcallbacks', format(...))
+end
+
+luamcallbacks.warning = luamcallbacks.warning or function(...)
+ luatextra.module_warning('luamcallbacks', format(...))
+end
+
+luamcallbacks.error = luamcallbacks.error or function(...)
+ luatextra.module_error('luamcallbacks', format(...))
+end
+
+
+function luamcallbacks.str_to_type(str)
+ if str == 'list' then
+ return list
+ elseif str == 'data' then
+ return data
+ elseif str == 'first' then
+ return first
+ elseif str == 'simple' then
+ return simple
+ else
+ return nil
+ end
+end
+
+
+function luamcallbacks.create(name, ctype, default)
+ if not name then
+ luamcallbacks.error(format("unable to call callback, no proper name passed", name))
+ return nil
+ end
+ if not ctype or not default then
+ luamcallbacks.error(format("unable to create callback '%s', callbacktype or default function not specified", name))
+ return nil
+ end
+ if callbacktypes[name] then
+ luamcallbacks.error(format("unable to create callback '%s', callback already exists", name))
+ return nil
+ end
+ local temp = luamcallbacks.str_to_type(ctype)
+ if not temp then
+ luamcallbacks.error(format("unable to create callback '%s', type '%s' undefined", name, ctype))
+ return nil
+ end
+ ctype = temp
+ luamcallbacks.lua_callbacks_defaults[name] = default
+ callbacktypes[name] = ctype
+end
+
+
+function luamcallbacks.call(name, ...)
+ if not name then
+ luamcallbacks.error(format("unable to call callback, no proper name passed", name))
+ return nil
+ end
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.error(format("unable to call lua callback '%s', unknown callback", name))
+ return nil
+ end
+ local l = luamcallbacks.callbacklist[name]
+ local f
+ if not l then
+ f = luamcallbacks.lua_callbacks_defaults[name]
+ else
+ if callbacktypes[name] == list then
+ f = luamcallbacks.listhandler(name)
+ elseif callbacktypes[name] == data then
+ f = luamcallbacks.datahandler(name)
+ elseif callbacktypes[name] == simple then
+ f = luamcallbacks.simplehandler(name)
+ elseif callbacktypes[name] == first then
+ f = luamcallbacks.firsthandler(name)
+ else
+ luamcallbacks.error("unknown callback type")
+ end
+ end
+ return f(...)
+end
+
+
+function luamcallbacks.add (name,func,description,priority)
+ if type(func) ~= "function" then
+ luamcallbacks.error("unable to add function, no proper function passed")
+ return
+ end
+ if not name or name == "" then
+ luamcallbacks.error("unable to add function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("unable to add function, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not description or description == "" then
+ luamcallbacks.error(
+ format("unable to add function to '%s', no proper description passed",
+ name))
+ return
+ end
+ if luamcallbacks.get_priority(name, description) ~= 0 then
+ luamcallbacks.warning(
+ format("function '%s' already registered in callback '%s'",
+ description, name))
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then
+ l = {}
+ luamcallbacks.callbacklist[name] = l
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ if callbacktypes[name] == list then
+ luamcallbacks.internalregister(name, luamcallbacks.listhandler(name))
+ elseif callbacktypes[name] == data then
+ luamcallbacks.internalregister(name, luamcallbacks.datahandler(name))
+ elseif callbacktypes[name] == simple then
+ luamcallbacks.internalregister(name, luamcallbacks.simplehandler(name))
+ elseif callbacktypes[name] == first then
+ luamcallbacks.internalregister(name, luamcallbacks.firsthandler(name))
+ else
+ luamcallbacks.error("unknown callback type")
+ end
+ end
+ end
+ local f = {
+ func = func,
+ description = description,
+ }
+ priority = tonumber(priority)
+ if not priority or priority > #l then
+ priority = #l+1
+ elseif priority < 1 then
+ priority = 1
+ end
+ if callbacktypes[name] == first and (priority ~= 1 or #l ~= 0) then
+ luamcallbacks.warning(format("several callbacks registered in callback '%s', only the first function will be active.", name))
+ end
+ table.insert(l,priority,f)
+ luamcallbacks.log(
+ format("inserting function '%s' at position %s in callback list for '%s'",
+ description,priority,name))
+end
+
+
+function luamcallbacks.get_priority (name, description)
+ if not name or name == "" or not callbacktypes[name] or not description then
+ return 0
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then return 0 end
+ for p, f in pairs(l) do
+ if f.description == description then
+ return p
+ end
+ end
+ return 0
+end
+
+
+function luamcallbacks.remove (name, description)
+ if not name or name == "" then
+ luamcallbacks.error("unable to remove function, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("unable to remove function, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not description or description == "" then
+ luamcallbacks.error(
+ format("unable to remove function from '%s', no proper description passed",
+ name))
+ return
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if not l then
+ luamcallbacks.error(format("no callback list for '%s'",name))
+ return
+ end
+ for k,v in ipairs(l) do
+ if v.description == description then
+ table.remove(l,k)
+ luamcallbacks.log(
+ format("removing function '%s' from '%s'",description,name))
+ if l == {} and not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.internalregister(name, nil)
+ end
+ return
+ end
+ end
+ luamcallbacks.warning(
+ format("unable to remove function '%s' from '%s'",description,name))
+end
+
+
+function luamcallbacks.reset (name)
+ if not name or name == "" then
+ luamcallbacks.error("unable to reset, no proper callback name passed")
+ return
+ elseif not callbacktypes[name] then
+ luamcallbacks.error(
+ format("reset error, '%s' is not a valid callback",
+ name))
+ return
+ end
+ if not luamcallbacks.lua_callbacks_defaults[name] then
+ luamcallbacks.internalregister(name, nil)
+ end
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ luamcallbacks.log(format("resetting callback list '%s'",name))
+ luamcallbacks.callbacklist[name] = nil
+ end
+end
+
+
+function luamcallbacks.listhandler (name)
+ return function(head,...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ local done = true
+ for _, f in ipairs(l) do
+ -- the returned value can be 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
+ luamcallbacks.error(format(
+ "function \"%s\" returned false in callback '%s'",
+ f.description, name))
+ end
+ end
+ return head, done
+ else
+ return head, false
+ end
+ end
+end
+
+
+function luamcallbacks.datahandler (name)
+ return function(data,...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ data = f.func(data,...)
+ end
+ end
+ return data
+ end
+end
+
+
+function luamcallbacks.firsthandler (name)
+ return function(...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ local f = l[1].func
+ return f(...)
+ else
+ return nil, false
+ end
+ end
+end
+
+
+function luamcallbacks.simplehandler (name)
+ return function(...)
+ local l = luamcallbacks.callbacklist[name]
+ if l then
+ for _, f in ipairs(l) do
+ f.func(...)
+ end
+ end
+ end
+end
+
+
+callback.add = luamcallbacks.add
+callback.remove = luamcallbacks.remove
+callback.reset = luamcallbacks.reset
+callback.create = luamcallbacks.create
+callback.call = luamcallbacks.call
+callback.get_priority = luamcallbacks.get_priority
+
+callback.register = function (...)
+luamcallbacks.error("function callback.register has been deleted by luamcallbacks, please use callback.add instead.")
+end
+
+--
+-- End of File `luamcallbacks.lua'.
diff --git a/Master/texmf-dist/tex/luatex/luatextra/luatextra-latex.tex b/Master/texmf-dist/tex/luatex/luatextra/luatextra-latex.tex
new file mode 100644
index 00000000000..024b1888307
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luatextra/luatextra-latex.tex
@@ -0,0 +1,36 @@
+%%
+%% This is file `luatextra-latex.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% luatextra.dtx (with options: `latex')
+%% This is a generated file.
+%%
+%% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%%
+%% This work is under the CC0 license.
+%%
+%% This work consists of the main source file luainputenc.dtx
+%% and the derived files
+%% luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf
+%%
+\def\ltxtra@temp#1{%
+\ifnum\count27#1=32768 %
+ \count27#1=65536 %
+\fi
+}%
+\ltxtra@temp0%
+\ltxtra@temp1%
+\ltxtra@temp2%
+\ltxtra@temp3%
+\ltxtra@temp4%
+\ltxtra@temp5%
+\ltxtra@temp6%
+\let\newcount\globcount
+\let\newdimen\globdimen
+\let\newskip\globskip
+\let\newbox\globbox
+\endinput
+%%
+%% End of file `luatextra-latex.tex'.
diff --git a/Master/texmf-dist/tex/luatex/luatextra/luatextra.lua b/Master/texmf-dist/tex/luatex/luatextra/luatextra.lua
new file mode 100644
index 00000000000..5c4a0f947af
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luatextra/luatextra.lua
@@ -0,0 +1,401 @@
+--
+-- This is file `luatextra.lua',
+-- generated with the docstrip utility.
+--
+-- The original source files were:
+--
+-- luatextra.dtx (with options: `lua')
+-- This is a generated file.
+--
+-- Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+--
+-- This work is under the CC0 license.
+--
+-- This work consists of the main source file luainputenc.dtx
+-- and the derived files
+-- luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf
+--
+do
+ local luatextrapath = kpse.find_file("luatextra.lua")
+ if luatextrapath then
+ if luatextrapath:sub(1,2) == "./" then
+ luatextrapath = luatextrapath:sub(3)
+ end
+ texio.write(' ('..luatextrapath)
+ end
+end
+
+
+luatextra = {}
+
+module("luatextra", package.seeall)
+
+
+luatextra.modules = {}
+
+luatextra.modules['luatextra'] = {
+ version = 0.93,
+ name = "luatextra",
+ date = "2009/04/15",
+ description = "Additional low level functions for LuaTeX",
+ author = "Elie Roux",
+ copyright = "Elie Roux, 2009",
+ license = "CC0",
+}
+
+local format = string.format
+
+
+luatextra.internal_warning_spaces = " "
+
+function luatextra.internal_warning(msg)
+ if not msg then return end
+ texio.write_nl(format("\nLuaTeXtra Warning: %s\n\n", msg))
+end
+
+luatextra.internal_error_spaces = " "
+
+function luatextra.internal_error(msg)
+ if not msg then return end
+ tex.sprint(format("\\immediate\\write16{}\\errmessage{LuaTeXtra error: %s^^J^^J}", msg))
+end
+
+
+function luatextra.module_error(package, msg, helpmsg)
+ if not package or not msg then
+ return
+ end
+ if helpmsg then
+ tex.sprint(format("\\errhelp{%s}", helpmsg))
+ end
+ tex.sprint(format("\\luaModuleError{%s}{%s}", package, msg))
+end
+
+function luatextra.module_warning(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl(format("\nModule %s Warning: %s\n\n", modulename, msg))
+end
+
+function luatextra.module_log(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl('log', format("%s: %s", modulename, msg))
+end
+
+function luatextra.module_term(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl('term', format("%s: %s", modulename, msg))
+end
+
+function luatextra.module_info(modulename, msg)
+ if not modulename or not msg then
+ return
+ end
+ texio.write_nl(format("%s: %s\n", modulename, msg))
+end
+
+
+function luatextra.find_module_file(name)
+ if string.sub(name, -4) ~= '.lua' then
+ name = name..'.lua'
+ end
+ path = kpse.find_file(name, 'tex')
+ if not path then
+ path = kpse.find_file(name, 'texmfscripts')
+ end
+ return path, name
+end
+
+
+luatextra.module = module
+
+
+function luatextra.use_module(name)
+ if not name or luatextra.modules[name] then
+ return
+ end
+ local path, filename = luatextra.find_module_file(name)
+ if not path then
+ luatextra.internal_error(format("unable to find lua module %s", name))
+ else
+ if path:sub(1,2) == "./" then
+ path = path:sub(3)
+ end
+ texio.write(' ('..path)
+ dofile(path)
+ if not luatextra.modules[name] then
+ luatextra.internal_warning(format("You have requested module `%s',\n%s but the file %s does not provide it.", name, luatextra.internal_warning_spaces, filename))
+ end
+ if not package.loaded[name] then
+ luatextra.module(name, package.seeall)
+ end
+ texio.write(')')
+ end
+end
+
+
+function luatextra.datetonumber(date)
+ numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
+ return tonumber(numbers)
+end
+
+function luatextra.isdate(date)
+ for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
+ return true
+ end
+ return false
+end
+
+local date, number = 1, 2
+
+function luatextra.versiontonumber(version)
+ if luatextra.isdate(version) then
+ return {type = date, version = luatextra.datetonumber(version), orig = version}
+ else
+ return {type = number, version = tonumber(version), orig = version}
+ end
+end
+
+luatextra.requiredversions = {}
+
+
+function luatextra.require_module(name, version)
+ if not name then
+ return
+ end
+ if not version then
+ return luatextra.use_module(name)
+ end
+ luaversion = luatextra.versiontonumber(version)
+ if luatextra.modules[name] then
+ if luaversion.type == date then
+ if luatextra.datetonumber(luatextra.modules[name].date) < luaversion.version then
+ luatextra.internal_error(format("found module `%s' loaded in version %s, but version %s was required", name, luatextra.modules[name].date, version))
+ end
+ else
+ if luatextra.modules[name].version < luaversion.version then
+ luatextra.internal_error(format("found module `%s' loaded in version %.02f, but version %s was required", name, luatextra.modules[name].version, version))
+ end
+ end
+ else
+ luatextra.requiredversions[name] = luaversion
+ luatextra.use_module(name)
+ end
+end
+
+
+function luatextra.provides_module(mod)
+ if not mod then
+ luatextra.internal_error('cannot provide nil module')
+ return
+ end
+ if not mod.version or not mod.name or not mod.date or not mod.description then
+ luatextra.internal_error('invalid module registered, fields name, version, date and description are mandatory')
+ return
+ end
+ requiredversion = luatextra.requiredversions[mod.name]
+ if requiredversion then
+ if requiredversion.type == date and requiredversion.version > luatextra.datetonumber(mod.date) then
+ luatextra.internal_error(format("loading module %s in version %s, but version %s was required", mod.name, mod.date, requiredversion.orig))
+ elseif requiredversion.type == number and requiredversion.version > mod.version then
+ luatextra.internal_error(format("loading module %s in version %.02f, but version %s was required", mod.name, mod.version, requiredversion.orig))
+ end
+ end
+ luatextra.modules[mod.name] = module
+ texio.write_nl('log', format("Lua module: %s %s v%.02f %s\n", mod.name, mod.date, mod.version, mod.description))
+end
+
+
+luatextra.use_module('luaextra')
+
+
+function luatextra.kpse_module_loader(mod)
+ local file = luatextra.find_module_file(mod)
+ if file then
+ local loader, error = loadfile(file)
+ if loader then
+ texio.write_nl("(" .. file .. ")")
+ return loader
+ end
+ return "\n\t[luatextra.kpse_module_loader] Loading error:\n\t"
+ .. error
+ end
+ return "\n\t[luatextra.kpse_module_loader] Search failed"
+end
+
+table.insert(package.loaders, luatextra.kpse_module_loader)
+
+
+luatextra.attributes = {}
+
+tex.attributenumber = luatextra.attributes
+
+function luatextra.attributedef_from_tex(name, number)
+ truename = name:gsub('[\\ ]', '')
+ luatextra.attributes[truename] = tonumber(number)
+end
+
+
+luatextra.catcodetables = {}
+
+tex.catcodetablenumber = luatextra.catcodetables
+
+function luatextra.catcodetabledef_from_tex(name, number)
+ truename = name:gsub('[\\ ]', '')
+ luatextra.catcodetables[truename] = tonumber(number)
+end
+
+
+function luatextra.open_read_file(filename)
+ local path = kpse.find_file(filename)
+ local env = {
+ ['filename'] = filename,
+ ['path'] = path,
+ }
+ luamcallbacks.call('pre_read_file', env)
+ path = env.path
+ if not path then
+ return
+ end
+ local f = env.file
+ if not f then
+ f = io.open(path)
+ env.file = f
+ end
+ if not f then
+ return
+ end
+ env.reader = luatextra.reader
+ env.close = luatextra.close
+ return env
+end
+
+
+function luatextra.reader(env)
+ local line = (env.file):read()
+ line = luamcallbacks.call('file_reader', env, line)
+ return line
+end
+
+function luatextra.close(env)
+ (env.file):close()
+ luamcallbacks.call('file_close', env)
+end
+
+
+function luatextra.default_reader(env, line)
+ return line
+end
+
+function luatextra.default_close(env)
+ return
+end
+
+function luatextra.default_pre_read(env)
+ return env
+end
+
+
+do
+ if tex.luatexversion < 36 then
+ fontloader = fontforge
+ end
+end
+
+function luatextra.find_font(name)
+ local types = {'ofm', 'ovf', 'opentype fonts', 'truetype fonts'}
+ local path = kpse.find_file(name)
+ if path then return path end
+ for _,t in pairs(types) do
+ path = kpse.find_file(name, t)
+ if path then return path end
+ end
+ return nil
+end
+
+function luatextra.font_load_error(error)
+ luatextra.module_warning('luatextra', string.format('%s\nloading lmr10 instead...', error))
+end
+
+function luatextra.load_default_font(size)
+ return font.read_tfm("lmr10", size)
+end
+
+function luatextra.define_font(name, size)
+ if (size < 0) then size = (- 655.36) * size end
+ local fontinfos = {
+ asked_name = name,
+ name = name,
+ size = size
+ }
+ callback.call('font_syntax', fontinfos)
+ name = fontinfos.name
+ local path = fontinfos.path
+ if not path then
+ path = luatextra.find_font(name)
+ fontinfos.path = luatextra.find_font(name)
+ end
+ if not path then
+ luatextra.font_load_error("unable to find font "..name)
+ return luatextra.load_default_font(size)
+ end
+ if not fontinfos.filename then
+ fontinfos.filename = fpath.basename(path)
+ end
+ local ext = fpath.suffix(path)
+ local f
+ if ext == 'tfm' or ext == 'ofm' then
+ f = font.read_tfm(name, size)
+ elseif ext == 'vf' or ext == 'ovf' then
+ f = font.read_vf(name, size)
+ elseif ext == 'ttf' or ext == 'otf' or ext == 'ttc' then
+ f = callback.call('open_otf_font', fontinfos)
+ else
+ luatextra.font_load_error("unable to determine the type of font "..name)
+ f = luatextra.load_default_font(size)
+ end
+ if not f then
+ luatextra.font_load_error("unable to load font "..name)
+ f = luatextra.load_default_font(size)
+ end
+ callback.call('post_font_opening', f, fontinfos)
+ return f
+end
+
+function luatextra.default_font_syntax(fontinfos)
+ return
+end
+
+function luatextra.default_open_otf(fontinfos)
+ return nil
+end
+
+function luatextra.default_post_font(f, fontinfos)
+ return true
+end
+
+function luatextra.register_font_callback()
+ callback.add('define_font', luatextra.define_font, 'luatextra.define_font')
+end
+
+do
+ luatextra.use_module('luamcallbacks')
+ callback.create('pre_read_file', 'simple', luatextra.default_pre_read)
+ callback.create('file_reader', 'data', luatextra.default_reader)
+ callback.create('file_close', 'simple', luatextra.default_close)
+ callback.add('open_read_file', luatextra.open_read_file, 'luatextra.open_read_file')
+ callback.create('font_syntax', 'simple', luatextra.default_font_syntax)
+ callback.create('open_otf_font', 'first', luatextra.default_open_otf)
+ callback.create('post_font_opening', 'simple', luatextra.default_post_font)
+
+ if luatextrapath then
+ texio.write(')')
+ end
+end
+--
+-- End of File `luatextra.lua'.
diff --git a/Master/texmf-dist/tex/luatex/luatextra/luatextra.sty b/Master/texmf-dist/tex/luatex/luatextra/luatextra.sty
new file mode 100644
index 00000000000..3b86be22d90
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luatextra/luatextra.sty
@@ -0,0 +1,237 @@
+%%
+%% This is file `luatextra.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% luatextra.dtx (with options: `package')
+%% This is a generated file.
+%%
+%% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu>
+%%
+%% This work is under the CC0 license.
+%%
+%% This work consists of the main source file luainputenc.dtx
+%% and the derived files
+%% luatextra.sty, luatextra.lua, luatextra-latex.tex, luatextra.pdf
+%%
+\csname ifluatextraloaded\endcsname
+\let\ifluatextraloaded\endinput
+
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \expandafter\ifx\csname ifluatex\endcsname\relax
+ \input ifluatex.sty
+ \fi
+\else
+ \RequirePackage{ifluatex}
+\fi
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \ifluatex\else
+ \immediate\write16{}
+ \errmessage{Package luatextra Error: This package must be used with LuaTeX}
+ \fi
+ \def\luaRequireModule#1#2{\luadirect{luatextra.require_module([[#1]], [[#2]])}}
+\else
+ \ifluatex\else
+ \PackageError{luatextra}{This package must be used with LuaTeX.}
+ \fi
+ \NeedsTeXFormat{LaTeX2e}
+ \ProvidesPackage{luatextra}
+ [2009/04/15 v0.93 LuaTeX extra low-level macros]
+ \RequirePackage{environ}
+ \NewEnviron{luacode}{\luadirect{\BODY}}
+ \newcommand\luaRequireModule[2][0]{\luadirect{luatextra.require_module([[#2]], [[#1]])}}
+ \RequirePackage{etex}[1998/03/26]%
+ \input luatextra-latex.tex
+\fi
+
+
+\def\LuaTeX{Lua\TeX }
+\def\LuaLaTeX{Lua\LaTeX }
+
+
+\ifnum\luatexversion<36
+ \def\directlua{\pdfprimitive\directlua0}
+ \def\latelua{\pdfprimitive\latelua0}
+ \def\luadirect{\pdfprimitive\directlua0}
+ \def\lualate{\pdfprimitive\latelua0}
+ \def\luaattribute{\attribute}
+ \def\luaattributedef{\attributedef}
+ \def\luaclearmarks{\pdfprimitive\luaclearmarks}
+ \def\luaformatname{\pdfprimitive\formatname}
+ \def\luascantexttokens{\pdfprimitive\scantexttokens}
+ \def\luacatcodetable{\catcodetable}
+\else
+ \directlua{tex.enableprimitives('lua', {'attribute'})}
+ \directlua{tex.enableprimitives('lua', {'attributedef'})}
+ \directlua{tex.enableprimitives('lua', {'clearmarks'})}
+ \directlua{tex.enableprimitives('lua', {'formatname'})}
+ \directlua{tex.enableprimitives('lua', {'scantexttokens'})}
+ \directlua{tex.enableprimitives('lua', {'catcodetable'})}
+ \def\luadirect{\pdfprimitive\directlua}
+ \def\lualate{\pdfprimitive\latelua}
+\fi
+
+\def\initluacatcodetable{\pdfprimitive\initcatcodetable}
+\def\saveluacatcodetable{\pdfprimitive\savecatcodetable}
+\def\luaclose{\pdfprimitive\closelua}
+
+
+\luadirect{dofile(kpse.find_file("luatextra.lua"))}
+
+
+\def\ltxtra@RegisterFontCallback{
+ \luadirect{luatextra.register_font_callback()}
+}
+
+
+
+\def\luaModuleError#1#2{%
+ \errorcontextlines=0\relax
+ \immediate\write16{}%
+ \errmessage{Module #1 error: #2^^J^^J%
+See the module #1 documentation for explanation.^^J ...^^J}%
+}
+
+\def\luaUseModule#1{\luadirect{luatextra.use_module([[#1]])}}
+
+
+\newcount\luaattdefcounter
+\luaattdefcounter = 1
+
+\def\newluaattribute#1{%
+ \ifnum\luaattdefcounter<65535\relax %
+ \global\advance\luaattdefcounter by 1\relax %
+ \allocationnumber\luaattdefcounter %
+ \ifluatex %
+ \global\luaattributedef#1=\allocationnumber %
+ \fi %
+ \wlog{\string#1=\string\attribute\the\allocationnumber}%
+ \luadirect{%
+ luatextra.attributedef_from_tex([[\noexpand#1]], '\number\allocationnumber')}%
+ \else %
+ \errmessage{No room for a new \string\attribute}%
+ \fi %
+}
+
+
+\def\setluaattribute#1#2{%
+ #1=\numexpr#2\relax %
+}
+
+\def\unsetluaattribute#1{%
+ \ifnum\luatexversion<37\relax %
+ #1=-1\relax %
+ \else %
+ #1=-"7FFFFFFF\relax %
+ \fi %
+}
+
+
+\newcount\luacatcodetabledefcounter
+
+\luacatcodetabledefcounter = 1
+
+\def\newluacatcodetable#1{%
+ \ifnum\luacatcodetabledefcounter<1114110\relax % 0x10FFFF is maximal \chardef
+ \global\advance\luacatcodetabledefcounter by 1\relax %
+ \allocationnumber=\luacatcodetabledefcounter %
+ \global\chardef#1=\allocationnumber %
+ \luadirect{%
+ luatextra.catcodetabledef_from_tex([[\noexpand#1]], '\number\allocationnumber')}%
+ \wlog{\string#1=\string\catcodetable\the\allocationnumber}%
+ \else %
+ \errmessage{No room for a new \string\catcodetable}%
+ \fi %
+}
+
+
+\expandafter\edef\csname ltxtra@AtEnd\endcsname{%
+ \catcode64 \the\catcode64\relax
+}
+
+\catcode 64=11\relax
+
+\expandafter\ifx\csname @tempcnta\endcsname\relax
+ \csname newcount\endcsname\@tempcnta
+\fi
+\expandafter\ifx\csname @tempcntb\endcsname\relax
+ \csname newcount\endcsname\@tempcntb
+\fi
+
+
+\def\luasetcatcoderange#1#2#3{%
+ \edef\luaSCR@temp{%
+ \noexpand\@tempcnta=\the\@tempcnta
+ \noexpand\@tempcntb=\the\@tempcntb
+ \noexpand\count@=\the\count@
+ \relax
+ }%
+ \@tempcnta=#1\relax
+ \@tempcntb=#2\relax
+ \count@=#3\relax
+ \loop\unless\ifnum\@tempcnta>\@tempcntb
+ \catcode\@tempcnta=\count@
+ \advance\@tempcnta by 1\relax
+ \repeat
+ \luaSCR@temp
+}
+
+
+\newluacatcodetable\CatcodeTableIniTeX
+\newluacatcodetable\CatcodeTableString
+\newluacatcodetable\CatcodeTableOther
+\newluacatcodetable\CatcodeTableLaTeX
+\initluacatcodetable\CatcodeTableIniTeX
+
+\expandafter\ifx\csname @firstofone\endcsname\relax
+ \long\def\@firstofone#1{#1}%
+\fi
+
+\begingroup
+ \def\@makeother#1{\catcode#1=12\relax}%
+ \@firstofone{%
+ \luacatcodetable\CatcodeTableIniTeX
+ \begingroup
+ \luasetcatcoderange{0}{8}{15}%
+ \catcode9=10 % tab
+ \catcode11=15 %
+ \catcode12=13 % form feed
+ \luasetcatcoderange{14}{31}{15}%
+ \catcode35=6 % hash
+ \catcode36=3 % dollar
+ \catcode38=4 % ampersand
+ \catcode94=7 % circumflex
+ \catcode95=8 % underscore
+ \catcode123=1 % brace left
+ \catcode125=2 % brace right
+ \catcode126=13 % tilde
+ \catcode127=15 %
+ \saveluacatcodetable\CatcodeTableLaTeX
+ \endgroup
+ \@makeother{0}% nul
+ \@makeother{13}% carriage return
+ \@makeother{37}% percent
+ \@makeother{92}% backslash
+ \@makeother{127}%
+ \luasetcatcoderange{65}{90}{12}% A-Z
+ \luasetcatcoderange{97}{122}{12}% a-z
+ \saveluacatcodetable\CatcodeTableString
+ \@makeother{32}% space
+ \saveluacatcodetable\CatcodeTableOther
+ \endgroup
+}
+
+
+\expandafter\ifx\csname ProvidesPackage\endcsname\relax
+ \input luaotfload.sty
+\else
+ \RequirePackage{luaotfload}
+\fi
+
+\ltxtra@AtEnd
+\endinput
+%%
+%% End of file `luatextra.sty'.
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index a6a82c1b889..0470ae59bef 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -147,7 +147,7 @@ my @WorkingTLP = qw(
lshort-polish lshort-portuguese lshort-slovak lshort-slovenian
lshort-spanish lshort-thai lshort-turkish lshort-ukr
lshort-vietnamese ltablex ltabptch ltxdockit
- ltxindex ltxmisc luamplib lxfonts
+ ltxindex ltxmisc luamplib luatextra lxfonts
macqassign mafr magyar mailing
makebarcode makebox makecell makecirc makecmds makeglos
makeplot maple margbib
diff --git a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
index fe7ac2b7a33..e0d3d580331 100644
--- a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
@@ -2,5 +2,8 @@ category Collection
shortdesc LuaTeX packages
longdesc Packages for LuaTeX, a Unicode-aware extension of pdfTeX, using Lua
longdesc as an embedded scripting and extension language. http://luatex.org/
+#
depend collection-basic
+#
depend luamplib
+depend luatextra
diff --git a/Master/tlpkg/tlpsrc/luatextra.tlpsrc b/Master/tlpkg/tlpsrc/luatextra.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/luatextra.tlpsrc