diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Changes | 38 | ||||
-rw-r--r-- | Makefile | 56 | ||||
-rw-r--r-- | TODO | 53 | ||||
-rw-r--r-- | lltxb-dtxstyle.tex | 5 | ||||
-rw-r--r-- | luatexbase-attr.dtx | 55 | ||||
-rw-r--r-- | luatexbase-cctb.dtx | 89 | ||||
-rw-r--r-- | luatexbase-compat.dtx | 410 | ||||
-rw-r--r-- | luatexbase-loader.dtx | 167 | ||||
-rw-r--r-- | luatexbase-mcb.dtx (renamed from luamcallbacks.dtx) | 905 | ||||
-rw-r--r-- | luatexbase-modutils.dtx | 241 | ||||
-rw-r--r-- | luatexbase-regs.dtx | 14 |
12 files changed, 1320 insertions, 717 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d315825 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.lua +*.pdf +*.sty +test-* @@ -1,5 +1,43 @@ Changes in the luatexbase package/bundle +Summary of backwards-incompatible interface changes between 0.1 and 0.2: + - Lua objects are now in table luatexbase, not luatextra. + - Lua tables tex.attributenumber and tex.catcodetablenumber are not + created any more, use their couterparts in luatexbase. + - \luatexsetcatcoderange has been renamed to \setcatcoderange. + - luamcallbacks has been renamed; Lua objects are now in luatexbase, + no more in callback.* or luamcallbacks.* + - module error/warning etc now apply string.format to the arguments. + +2010/03/29 + all + - use luatexbase as the Lua module name + - change the filename of the lua module (suppress luatexbase.) + - load luatexbase-compat + luatexbase-compat + - new + luatexbase-attr + - don't create tex.attributenumber + - load luatexbase-compat + luatexbase-cctb + - don't create tex.catcodetablenumber + - rename \luatexsetcatcoderange to \setcatcoderange + - load lua-compat + luamcallbacks -> luatexbase-mcb + - rename package + - functions are now in luatexbase rather than luamcallbacks, they + are no more copied to callbacks either + - lua objects are now local (except for the public interface) + - test file now for plain and latex + luatexbase-loader + - require"foo.bar" now looks for foo/bar then foo.bar, see doc for + details + - better cooperation with the original package loader + - works with luatex 0.25.4 + luatexbase-modutils + - module error/warning etc now apply string.format to the arguments. + - use error() instead of \errmessage. + 2010/03/28 luatexbase-* - add catcode defenses @@ -4,24 +4,34 @@ NAME = luatexbase DTX = $(wildcard *.dtx) DOC = $(patsubst %.dtx, %.pdf, $(DTX)) DTXSTY = lltxb-dtxstyle.tex + +# used for check dependencies +COMPAT_RUN = luatexbase-compat.sty LOADER_RUN = luatexbase-loader.sty luatexbase.loader.lua -MOD_RUN = luatexbase-modutils.sty luatexbase.modutils.lua +MOD_RUN = luatexbase-modutils.sty modutils.lua +LINKS = luatexbase.attr.lua luatexbase.cctb.lua \ + luatexbase.mcb.lua luatexbase.modutils.lua # Files grouped by generation mode -UNPACKED_MCB = test-luamcallbacks.tex luamcallbacks.lua +UNPACKED_MCB = luatexbase-mcb.sty mcb.lua \ + test-mcb-latex.tex test-mcb-plain.tex UNPACKED_REGS = luatexbase-regs.sty \ test-regs-plain.tex test-regs-latex.tex -UNPACKED_ATTR = luatexbase-attr.sty luatexbase.attr.lua \ +UNPACKED_ATTR = luatexbase-attr.sty attr.lua \ test-attr-plain.tex test-attr-latex.tex -UNPACKED_CCTB = luatexbase-cctb.sty luatexbase.cctb.lua \ +UNPACKED_CCTB = luatexbase-cctb.sty cctb.lua \ test-cctb-plain.tex test-cctb-latex.tex -TMP_LOADER = test-loader # temporary file for testing +# temporary file for testing loader +TMP_LOADER = test-loader UNPACKED_LOADER = $(LOADER_RUN) \ + test-loader-plain.tex test-loader-latex.tex \ $(TMP_LOADER).lua test-loader.sub.lua -UNPACKED_MODUTILS = $(MOD_RUN) \ - test-modutils-plain.tex test-modutils-latex.tex test-modutils.lua +UNPACKED_MODUTILS = $(MOD_RUN) test-modutils.lua \ + test-modutils-plain.tex test-modutils-latex.tex +UNPACKED_COMPAT = $(COMPAT_RUN) \ + test-compat-plain.tex test-compat-latex.tex UNPACKED = $(UNPACKED_MCB) $(UNPACKED_REGS) $(UNPACKED_ATTR) $(UNPACKED_CCTB) \ - $(UNPACKED_LOADER) $(UNPACKED_MODUTILS) + $(UNPACKED_LOADER) $(UNPACKED_MODUTILS) $(UNPACKED_COMPAT) COMPILED = $(DOC) GENERATED = $(COMPILED) $(UNPACKED) SOURCE = $(DTX) $(DTXSTY) README TODO Changes Makefile @@ -52,7 +62,8 @@ DO_MAKEINDEX = makeindex -s gind.ist $(subst .dtx,,$<) >/dev/null 2>&1 # Main targets definition all: $(GENERATED) -check: check-regs check-attr check-cctb check-loader check-modutils check-mcb +check: check-regs check-attr check-cctb check-loader check-modutils check-mcb \ + check-compat doc: $(COMPILED) unpack: $(UNPACKED) ctan: check $(CTAN_ZIP) @@ -65,7 +76,10 @@ world: all ctan $(DO_PDFLATEX) $(DO_PDFLATEX) -$(UNPACKED_MCB): luamcallbacks.dtx +luatexbase.%.lua: %.lua + ln -sf $< $@ + +$(UNPACKED_MCB): luatexbase-mcb.dtx $(DO_TEX) $(UNPACKED_REGS): luatexbase-regs.dtx @@ -83,29 +97,37 @@ $(UNPACKED_LOADER): luatexbase-loader.dtx $(UNPACKED_MODUTILS): luatexbase-modutils.dtx $(DO_TEX) +$(UNPACKED_COMPAT): luatexbase-compat.dtx + $(DO_TEX) + check-regs: $(UNPACKED_REGS) luatex --interaction=batchmode test-regs-plain.tex >/dev/null lualatex --interaction=batchmode test-regs-latex.tex >/dev/null -check-attr: $(UNPACKED_ATTR) $(LOADER_RUN) +check-attr: $(UNPACKED_ATTR) $(LOADER_RUN) $(LINKS) $(COMPAT_RUN) luatex --interaction=batchmode test-attr-plain.tex >/dev/null lualatex --interaction=batchmode test-attr-latex.tex >/dev/null -check-cctb: $(UNPACKED_CCTB) $(LOADER_RUN) +check-cctb: $(UNPACKED_CCTB) $(LOADER_RUN) $(LINKS) $(COMPAT_RUN) luatex --interaction=batchmode test-cctb-plain.tex >/dev/null lualatex --interaction=batchmode test-cctb-latex.tex >/dev/null -check-loader: $(UNPACKED_LOADER) +check-loader: $(UNPACKED_LOADER) $(COMPAT_RUN) echo "this is no lua code" > $(TMP_LOADER).tex luatex --interaction=batchmode test-loader-plain.tex >/dev/null lualatex --interaction=batchmode test-loader-latex.tex >/dev/null -check-modutils: $(UNPACKED_MODUTILS) $(LOADER_RUN) +check-modutils: $(UNPACKED_MODUTILS) $(LOADER_RUN) $(LINKS) $(COMPAT_RUN) luatex --interaction=batchmode test-modutils-plain.tex >/dev/null lualatex --interaction=batchmode test-modutils-latex.tex >/dev/null -check-mcb: $(UNPACKED_MCB) $(LOADER_RUN) $(MOD_RUN) - luatex --interaction=batchmode test-luamcallbacks.tex >/dev/null +check-mcb: $(UNPACKED_MCB) $(LOADER_RUN) $(MOD_RUN) $(LINKS) $(COMPAT_RUN) + luatex --interaction=batchmode test-mcb-plain.tex >/dev/null + lualatex --interaction=batchmode test-mcb-latex.tex >/dev/null + +check-compat: $(UNPACKED_COMPAT) + luatex --interaction=batchmode test-compat-plain.tex >/dev/null + lualatex --interaction=batchmode test-compat-latex.tex >/dev/null $(CTAN_ZIP): $(SOURCE) $(COMPILED) $(TDS_ZIP) @echo "Making $@ for CTAN upload." @@ -143,5 +165,5 @@ clean: @$(RM) -- *.log *.aux *.toc *.idx *.ind *.ilg *.out test-*.pdf mrproper: clean - @$(RM) -- $(GENERATED) $(ZIPS) $(TMP_LOADER).tex + @$(RM) -- $(GENERATED) $(ZIPS) $(LINKS) $(TMP_LOADER).tex @@ -1,37 +1,32 @@ -Later -===== - -- check for user macros starting with \luatex -- change lua module name(s) (luatexbase or luatexbase.regs etc) -- compat with LuaTeX 0.25.4? (Means problems with \directlua, primitive names, - kpse.find_file(..., 'lua'), etc.) Maybe do a compat package? - -attr ----- - -- don't write in the tex table! - -cctb ----- - -- don't write in the tex table! -- don't define macros starting with \luatex - -loader ------- - -- a.b.c -> a/b/c or a/b.c or a.b.c? What do to with files under texmf/scripts? -- adujst names of the modules afterwards -- write doc -- make a real test using a fake texmf tree as TEXMFHOME? - modutils -------- -Review extensively. +- Renaming: + \luatexUseModule + \luatexRequireModule +- syntax of public TeX macros and Lua functions +- create private functions for infwarrerr? +- review logic (see what LaTeX2e does) +- General review of code and comments. +- Update user documentation. mcallbacks ---------- -Review extensively. +- Incorporate remaining bits from luatextra? +- Enhance test file? +- General review of code and comments. +- Update user documentation. + +luatexbase +---------- + +- create it, make it load the others (except maybe mcb for now) +- create general documentation + +afterwards +---------- +- check/adapt luatextra +- Bump version number, make zip, announce. +- engage discussion with Heiko diff --git a/lltxb-dtxstyle.tex b/lltxb-dtxstyle.tex index f3bafb4..50eb0da 100644 --- a/lltxb-dtxstyle.tex +++ b/lltxb-dtxstyle.tex @@ -32,5 +32,10 @@ \newcommand\pk{\textsf} \newcommand\cmdname{\texttt} +% for hyperref +\pdfstringdefDisableCommands{% + \def\cs#1{\@backslashchar #1}% + } + % easy verbatim \MakeShortVerb\| diff --git a/luatexbase-attr.dtx b/luatexbase-attr.dtx index 6332260..194cb8d 100644 --- a/luatexbase-attr.dtx +++ b/luatexbase-attr.dtx @@ -8,7 +8,7 @@ % % This work consists of the main source file luatexbase-attr.dtx % and the derived files -% luatexbase-attr.sty luatexbase.attr.lua +% luatexbase-attr.sty attr.lua % test-regs-plain.tex test-regs-latex.tex % % Unpacking: @@ -66,7 +66,7 @@ See source file '\inFileName' for details. \generate{% \usedir{tex/luatex/luatexbase}% - \file{luatexbase.attr.lua}{\from{luatexbase-attr.dtx}{luamodule}}% + \file{attr.lua}{\from{luatexbase-attr.dtx}{luamodule}}% } \obeyspaces @@ -75,7 +75,7 @@ See source file '\inFileName' for details. \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} -\Msg{* luatexbase-attr.sty luatexbase.attr.lua} +\Msg{* luatexbase-attr.sty attr.lua} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} @@ -127,6 +127,8 @@ See source file '\inFileName' for details. % just like Plain TeX and LaTeX do for other registers. % \end{abstract} % +% \tableofcontents +% % \section{Documentation} % % The main macro defined here is |\newluatexattribute|. It behaves in the same @@ -154,7 +156,7 @@ See source file '\inFileName' for details. % definition of |\fooattr| and remember it in a Lua variable. For your % convenience, this is automatically done by |\newluatexattribute|: the number % is remembered in a dedicated Lua table so that you can get it as -% |luatextra.attributes.foobar| (mind the absence of backslash here) at any +% |luatexbase.attributes.foobar| (mind the absence of backslash here) at any % time. % % \section{Implementation} @@ -221,7 +223,7 @@ See source file '\inFileName' for details. \let\x\ProvidesPackage \fi \expandafter\endgroup -\x{luatexbase-attr}[2010/03/11 v0.1 Attributes allocation for LuaTeX (mpg)] +\x{luatexbase-attr}[2010/03/11 v0.1 Attributes allocation for LuaTeX] % \end{macrocode} % % Make sure \luatex is used. @@ -248,9 +250,31 @@ See source file '\inFileName' for details. \fi % \end{macrocode} % -% \subsubsection{Main content} +% \subsubsection{Primitives needed} % -% Load the supporting Lua module. +% Load \pk{luatexbase-compat}. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input luatexbase-compat.sty +\else + \RequirePackage{luatexbase-compat} +\fi +% \end{macrocode} +% +% Make sure the primitives we need are available. +% +% \begin{macrocode} +\luatexbase@ensure@primitive{luaescapestring} +\luatexbase@ensure@primitive{attributedef} +\luatexbase@ensure@primitive{attribute} +% \end{macrocode} +% +% \subsubsection{Load supporting Lua module} +% +% First load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), then +% the supporting Lua module. % % \begin{macrocode} \begingroup\expandafter\expandafter\expandafter\endgroup @@ -259,9 +283,11 @@ See source file '\inFileName' for details. \else \RequirePackage{luatexbase-loader} \fi -\directlua{require('luatexbase.attr.lua')} +\luatexbase@directlua{require('luatexbase.attr')} % \end{macrocode} % +% \subsection{User macros} +% % The allocaton macro. % % \begin{macrocode} @@ -273,9 +299,10 @@ See source file '\inFileName' for details. \allocationnumber\lltxb@attribute@alloc \global\luatexattributedef#1=\allocationnumber \unsetluatexattribute#1% - \begingroup\escapechar\m@ne \expandafter\endgroup - \directlua{luatextra.attributedef_from_tex( + \begingroup\escapechar\m@ne + \luatexbase@directlua{luatexbase.attributedef_from_tex( '\luatexluaescapestring{\string#1}', '\number\allocationnumber')}% + \endgroup \wlog{\string#1=\string\luatexattribute\the\allocationnumber}% \else \errmessage{No room for a new \string\attribute}% @@ -311,14 +338,13 @@ See source file '\inFileName' for details. % % \begin{macrocode} %<*luamodule> -module('luatextra', package.seeall) +module('luatexbase', package.seeall) % \end{macrocode} % % Record the allocation number in a Lua table. % % \begin{macrocode} attributes = {} -tex.attributenumber = attributes function attributedef_from_tex(name, number) attributes[name] = tonumber(number) end @@ -342,13 +368,14 @@ end \newluatexattribute\testattr \setluatexattribute\testattr{1} \unsetluatexattribute\testattr -\directlua{assert(luatextra.attributes.testattr)} +\catcode64 11 +\luatexbase@directlua{assert(luatexbase.attributes.testattr)} \begingroup \escapechar64 \newluatexattribute\anotherattr \endgroup \setluatexattribute\anotherattr{1} -\directlua{assert(luatextra.attributes.anotherattr)} +\luatexbase@directlua{assert(luatexbase.attributes.anotherattr)} %</testplain,testlatex> %<testplain>\bye %<testlatex>\stop diff --git a/luatexbase-cctb.dtx b/luatexbase-cctb.dtx index 09ff77f..90dab94 100644 --- a/luatexbase-cctb.dtx +++ b/luatexbase-cctb.dtx @@ -8,7 +8,7 @@ % % This work consists of the main source file luatexbase-cctb.dtx % and the derived files -% luatexbase-cctb.sty luatexbase.cctb.lua +% luatexbase-cctb.sty cctb.lua % test-cctb-plain.tex test-cctb-latex.tex % % Unpacking: @@ -66,7 +66,7 @@ See source file '\inFileName' for details. \generate{% \usedir{tex/luatex/luatexbase}% - \file{luatexbase.cctb.lua}{\from{luatexbase-cctb.dtx}{luamodule}}% + \file{cctb.lua}{\from{luatexbase-cctb.dtx}{luamodule}}% } \obeyspaces @@ -75,7 +75,7 @@ See source file '\inFileName' for details. \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} -\Msg{* luatexbase-cctb.sty luatexbase.cctb.lua} +\Msg{* luatexbase-cctb.sty cctb.lua} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} @@ -127,6 +127,8 @@ See source file '\inFileName' for details. % allocation just like Plain TeX and LaTeX do for other registers. % \end{abstract} % +% \tableofcontents +% % \section{Documentation} % % The main macro defined here is |\newluatexcatcodetable|. It behaves the same @@ -135,7 +137,7 @@ See source file '\inFileName' for details. % (once they are allocated), two helper macros are available. % % \begin{quote} -% \cs{luatexsetcatcoderange}\marg{from}\marg{to}\marg{value} +% \cs{setcatcoderange}\marg{from}\marg{to}\marg{value} % \end{quote} % Set all characters code in the range \meta{from}--\meta{to} to the given % catcode \meta{value}. @@ -168,7 +170,7 @@ See source file '\inFileName' for details. % catcode table. Since |\chardef| is used for the definition of the control % sequence, this is rather easy to do. However, for extra ease of use, the % numbers are also directly accessible from Lua as the value of the table -% |luatextra.catcodetables|, whose keys is the name of the control sequence +% |luatexbase.catcodetables|, whose keys is the name of the control sequence % (without any leading backslash). Moreover, nickames are available for the % predefined catcode tables: % \begin{itemize} @@ -244,7 +246,7 @@ See source file '\inFileName' for details. \let\x\ProvidesPackage \fi \expandafter\endgroup -\x{luatexbase-cctb}[2010/03/26 v0.1 Catcodetable allocation for LuaTeX (mpg)] +\x{luatexbase-cctb}[2010/03/26 v0.1 Catcodetable allocation for LuaTeX] % \end{macrocode} % % Make sure \luatex is used. @@ -271,9 +273,10 @@ See source file '\inFileName' for details. \fi % \end{macrocode} % -% \subsubsection{Main content} +% \subsubsection{Load supporting Lua module} % -% Load the supporting Lua module. +% First load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), then +% the supporting Lua module. % % \begin{macrocode} \begingroup\expandafter\expandafter\expandafter\endgroup @@ -282,9 +285,33 @@ See source file '\inFileName' for details. \else \RequirePackage{luatexbase-loader} \fi -\directlua{require('luatexbase.cctb.lua')} +\luatexbase@directlua{require('luatexbase.cctb')} +% \end{macrocode} +% +% \subsubsection{Primitives needed} +% +% Load \pk{luatexbase-compat}. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input luatexbase-compat.sty +\else + \RequirePackage{luatexbase-compat} +\fi +% \end{macrocode} +% +% Make sure the primitives we need are available. +% +% \begin{macrocode} +\luatexbase@ensure@primitive{luaescapestring} +\luatexbase@ensure@primitive{catcodetable} +\luatexbase@ensure@primitive{initcatcodetable} +\luatexbase@ensure@primitive{savecatcodetable} % \end{macrocode} % +% \subsubsection{User macros} +% % The allocation macro. Allocate tables starting with 1, since table 0 is % reserved for IniTeX catcodes by LuaTeX. % @@ -297,9 +324,10 @@ See source file '\inFileName' for details. \allocationnumber\lltxb@catcodetable@alloc \global\chardef#1\allocationnumber \luatexinitcatcodetable\allocationnumber - \begingroup\escapechar\m@ne \expandafter\endgroup - \directlua{luatextra.catcodetabledef_from_tex( + \begingroup\escapechar\m@ne + \luatexbase@directlua{luatexbase.catcodetabledef_from_tex( '\luatexluaescapestring{\string#1}', '\number\allocationnumber')}% + \endgroup \wlog{\string#1=\string\luatexcatcodetable\the\allocationnumber}% \else \errmessage{No room for a new \string\luatexcatcodetable}% @@ -320,7 +348,7 @@ See source file '\inFileName' for details. % Set the catcodes for a range of characters. % % \begin{macrocode} -\def\luatexsetcatcoderange#1#2#3{% +\def\setcatcoderange#1#2#3{% \edef\luaSCR@temp{% \noexpand\@tempcnta=\the\@tempcnta \noexpand\@tempcntb=\the\@tempcntb @@ -346,6 +374,8 @@ See source file '\inFileName' for details. \endgroup} % \end{macrocode} % +% \subsubsection{Predefined tables} +% % The |IniTeX| catcode table needs no extra initialisation. % % \begin{macrocode} @@ -361,8 +391,8 @@ See source file '\inFileName' for details. \catcode0 12 % nul \catcode13 12 % carriage return \catcode37 12 % percent - \luatexsetcatcoderange{65}{90}{12}% A-Z - \luatexsetcatcoderange{97}{122}{12}% a-z + \setcatcoderange{65}{90}{12}% A-Z + \setcatcoderange{97}{122}{12}% a-z \catcode92 12 % backslash \catcode127 12 } % \end{macrocode} @@ -380,7 +410,7 @@ See source file '\inFileName' for details. \newluatexcatcodetable\CatcodeTableLaTeX \setluatexcatcodetable\CatcodeTableLaTeX{% \luatexcatcodetable\CatcodeTableIniTeX - \luatexsetcatcoderange{0}{31}{15}% + \setcatcoderange{0}{31}{15}% \catcode9 10 % tab \catcode12 13 % form feed \catcode13 5 % carriage return @@ -419,7 +449,7 @@ See source file '\inFileName' for details. % Finally do the shortcuts. % % \begin{macrocode} -\directlua{luatextra.catcodetable_do_shortcuts()} +\luatexbase@directlua{luatexbase.catcodetable_do_shortcuts()} % \end{macrocode} % % That's all, folks! @@ -433,28 +463,26 @@ See source file '\inFileName' for details. % % \begin{macrocode} %<*luamodule> -module('luatextra', package.seeall) +module('luatexbase', package.seeall) % \end{macrocode} % -% In the same way, the table \texttt{tex.catcodetablenumber} contains the -% numbers of the catcodetables registered with -% \texttt{\string\newluacatcodetable}. +% The number associated to a CS name is remembered in the |catcodetables| +% table. % % \begin{macrocode} catcodetables = {} -tex.catcodetablenumber = catcodetables function catcodetabledef_from_tex(name, number) catcodetables[name] = tonumber(number) end % \end{macrocode} % -% With this function we create some shortcuts for a better readability in -% lua code. This makes |tex.catcodetablenumber.latex| equivalent to -% |tex.catcodetablenumber['CatcodeTableLaTeX']|. +% The next function creates some shortcuts for better readability in lua +% code. This makes |luatexbase.catcodetables.latex| equivalent to +% |luatexbase.catcodetables.CatcodeTableLaTeX|. % % \begin{macrocode} function catcodetable_do_shortcuts() - local cat = luatextra.catcodetables + local cat = catcodetables cat['latex'] = cat.CatcodeTableLaTeX cat['latex-package'] = cat.CatcodeTableLaTeXAtLetter cat['latex-atletter'] = cat.CatcodeTableLaTeXAtLetter @@ -480,19 +508,20 @@ end %<testplain>\input luatexbase-cctb.sty %<testlatex>\RequirePackage{luatexbase-cctb} %<*testplain,testlatex> -\newluatexcatcodetable\testcctb -\directlua{assert(luatextra.catcodetables.testcctb)} +\begingroup \catcode64 11 \global\let\lua\luatexbase@directlua \endgroup % \end{macrocode} % % Also check that the catcodetable's number is remembered well, % independently of the current value of |\escapechar|. % \begin{macrocode} +\newluatexcatcodetable\testcctb +\lua{assert(luatexbase.catcodetables.testcctb)} \begingroup \escapechar64 \newluatexcatcodetable\anothercctb \endgroup -\directlua{assert(luatextra.catcodetables.anothercctb)} +\lua{assert(luatexbase.catcodetables.anothercctb)} % \end{macrocode} % % Now, play a little bit with predefined tables. @@ -503,9 +532,9 @@ end \luatexcatcodetable\CatcodeTableLaTeX \ifnum\catcode64=12 \else \ERROR \fi %<testlatex>\documentclass{minimal} -\directlua{% +\lua{% tex.sprint('\string\\setbox0=\string\\hbox{') - tex.sprint(luatextra.catcodetables.string, "\string\\undef # _^&") + tex.sprint(luatexbase.catcodetables.string, "\string\\undef # _^&") tex.sprint('}') } % \end{macrocode} diff --git a/luatexbase-compat.dtx b/luatexbase-compat.dtx new file mode 100644 index 0000000..e1b6381 --- /dev/null +++ b/luatexbase-compat.dtx @@ -0,0 +1,410 @@ +% \iffalse meta-comment +% +% Written in 2010 by Manuel Pégourié-Gonnard. +% <mpg@elzevir.fr> +% +% This work is under the CC0 license. +% +% This work consists of the main source file luatexbase-compat.dtx +% and the derived files +% luatexbase-compat.pdf luatexbase-compat.sty +% test-compat-plain.tex test-compat-latex.tex +% +% Unpacking: +% tex luatexbase-compat.dtx +% Documentation: +% pdflatex luatexbase-compat.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 + +\keepsilent +\askforoverwritefalse + +\preamble + +Written in 2010 by Manuel Pegourie-Gonnard. + +This work is under the CC0 license. +See source file '\inFileName' for details. + +\endpreamble + +\generate{% + \usedir{tex/luatex/luatexbase}% + \file{luatexbase-compat.sty}{\from{luatexbase-compat.dtx}{texpackage}}% +} + +\generate{% + \usedir{doc/luatex/luatexbase}% + \file{test-compat-plain.tex}{\from{luatexbase-compat.dtx}{testplain}}% + \file{test-compat-latex.tex}{\from{luatexbase-compat.dtx}{testlatex}}% +} + +\obeyspaces +\Msg{************************************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the following} +\Msg{* files into a directory searched by TeX:} +\Msg{*} +\Msg{* luatexbase-compat.sty} +\Msg{*} +\Msg{* Happy TeXing!} +\Msg{*} +\Msg{************************************************************************} + +\endbatchfile +%</install> +%<*ignore> +\fi +%</ignore> +%<*driver> +\NeedsTeXFormat{LaTeX2e} +\documentclass{ltxdoc} +\input lltxb-dtxstyle.tex +\EnableCrossrefs +\CodelineIndex +\begin{document} + \DocInput{luatexbase-compat.dtx}% +\end{document} +%</driver> +% \fi +% +% \CheckSum{0} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% \title{The \pk{luatexbase-compat} package} +% \date{2010/01/21 v0.1} +% \author{% +% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and +% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}} +% +% \maketitle +% +% \begin{abstract} +% The \luatex manual is very clear: everything may change. This package +% provides tools to help package writers deal with the changes. It helps +% supporting \luatex versions down to 0.25.4, and is regularly tested with +% \luatex 0.40.6 (\texlive 2009) and from trunk. +% \end{abstract} +% +% \tableofcontents +% +% \section{Documentation} +% +% Three problems are currently addressed by this package: changes in the +% syntax of |\directlua|, version information, and variable policies for +% primitives activation and naming (in \luatex itself as well as in \texlive). +% +% \medskip +% +% Older versions of \luatex used to support multiple Lua states. A number was +% mandatory with |\directlua| in order to specify the Lua state to be used. +% Later, support for multiple Lua states was removed and the old syntax +% resulted in a warning. Now (\luatex 0.50), |\directlua| again accepts a +% number after |\directlua|, but with a different meaning (see the \luatex +% manual for details). +% +% This package provides a macro |\luatexbase@directlua| that expands to +% |\directlua0| on \luatex 0.35 and lower (where the number is mandatory), and +% to |\directlua| otherwise. It is a macro in both case so that the number of +% expansion steps remains constant. +% +% \medskip +% +% Current versions of \luatex make the version available directly from Lua as +% |tex.luatexversion| and |tex.luatexrevision|. However, older versions (such +% as 0.25.4) didn't, which makes it particularly uneasy to test the version +% from within Lua. The present package makes this information available as +% |luatexbase.luatexversion| and |luatexbase.luatexrevision|. +% +% \medskip +% +% Starting with \luatex 0.39.0, the only primitives available in Ini\tex mode +% are the basic primitives from \tex{}82 and |\directlua|. All other +% primitives are hidden by default and have to be activated using a Lua +% function. In \texlive 2009 (\luatex 0.40.6), the following arrangement has +% been made in order to try preserving usability while avoiding name clashes +% in the \latex world: in \latex-based formats, all pdf\tex primitives are +% enabled with their normal name, but the primitives specific to \luatex are +% enabled with the |luatex| prefix.\footnote{The prefix is dropped for +% primitives whose name already starts with \texttt{luatex}.} In Plain based +% formats however, all the primitives are enabled with their natural name, but +% are also provided with the same name as in \latex-based formats in order to +% help writing generic packages. +% +% So, starting with \texlive 2009, the situation is clear: the prefixed +% version of the \luatex primitives is always available. But in earlier +% versions (\texlive 2008, \luatex 0.25.4) those primitives were available +% only with their natural names. Also, it is theoretically possible, however +% unlikely, that the prefixed primitives are not available for some reason. +% +% \begin{quote} +% \cs{luatexbase@ensure@primitive}\marg{name} +% \end{quote} +% The tool provided to deal with that is \cs{luatexbase@ensure@primitive}, +% whose argument is a primitive name (without a leading backslash nor any +% |luatex| prefix, eg just |{latelua}|). It makes sure that the primitive gets +% available as \cs{luatex\meta{name}}. +% +% \textbf{Warning.} In particular circumstances, this macro may fail silently +% for primitives whose natural name starts with |luatex|, hence such +% primitives shouldn't be used as arguments. This is actually not a problem, +% since the only three such primitives are |\luatexversion|, |\luatexrevision| +% and |\luatexdatestamp|. The first two are already activated by \pk{ifluatex} +% which is loaded by this package, so you don't need to activated them +% yourself. The third should never be used in production according to the +% \luatex manual. +% +% \textit{Remark.} If you only aim at compatibility down to \texlive 2009 +% (\luatex 0.40.6), then you can simply use the primitives with their prefixed +% name (except for |\directlua| which never needs a prefix). If you want extra +% security and/or compatibility down to \texlive 2008 (\luatex 0.25.4) then +% you should use \cs{luatebase@ensure@primitive} for each primitive you intend +% to use (except |\directlua| again). +% +% This package doesn't try to activate every primitive, since it would require +% and extensive list of primitives for each version of \luatex, so it seems +% simpler to leave that burden on package writers. +% +% \section{Implementation} +% +% \begin{macrocode} +%<*texpackage> +% \end{macrocode} +% +% \subsection{Preliminaries} +% +% Reload protection, especially for \plaintex. +% +% \begin{macrocode} + \csname lltxb@compat@loaded\endcsname +\expandafter\let\csname lltxb@compat@loaded\endcsname\endinput +% \end{macrocode} +% +% Catcode defenses. +% +% \begin{macrocode} +\begingroup + \catcode123 1 % { + \catcode125 2 % } + \catcode 35 6 % # + \toks0{}% + \def\x{}% + \def\y#1 #2 {% + \toks0\expandafter{\the\toks0 \catcode#1 \the\catcode#1}% + \edef\x{\x \catcode#1 #2}}% + \y 123 1 % { + \y 125 2 % } + \y 35 6 % # + \y 10 12 % ^^J + \y 34 12 % " + \y 36 3 % $ $ + \y 39 12 % ' + \y 40 12 % ( + \y 41 12 % ) + \y 42 12 % * + \y 43 12 % + + \y 44 12 % , + \y 45 12 % - + \y 46 12 % . + \y 47 12 % / + \y 60 12 % < + \y 61 12 % = + \y 64 11 % @ (letter) + \y 62 12 % > + \y 95 12 % _ (other) + \y 96 12 % ` + \edef\y#1{\endgroup\edef#1{\the\toks0\relax}\x}% +\expandafter\y\csname lltxb@compat@AtEnd\endcsname +% \end{macrocode} +% +% Package declaration. +% +% \begin{macrocode} +\begingroup + \expandafter\ifx\csname ProvidesPackage\endcsname\relax + \def\x#1[#2]{\immediate\write16{Package: #1 #2}} + \else + \let\x\ProvidesPackage + \fi +\expandafter\endgroup +\x{luatexbase-compat}[2010/01/21 v0.1 Compatibility tools for LuaTeX] +% \end{macrocode} +% +% Make sure \luatex is used. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input ifluatex.sty +\else + \RequirePackage{ifluatex} +\fi +\ifluatex\else + \begingroup + \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax + \def\x#1#2{\begingroup\newlinechar10 + \immediate\write16{Package #1 warning: #2}\endgroup} + \else + \let\x\PackageWarningNoLine + \fi + \expandafter\endgroup + \x{luatexbase-compat}{LuaTeX is required for this package. Aborting.} + \lltxb@compat@AtEnd + \expandafter\endinput +\fi +% \end{macrocode} +% +% \subsection{\cs{directlua} abstraction} +% +% Define |\luatexbase@directlua| to be either |\directlua0| or +% |\directlua|, depending on the version of \luatex. +% +% \begin{macrocode} +\begingroup +\expandafter\ifx\csname newcommand\endcsname\relax + \toks0{\long\def\luatexbase@directlua}% +\else + \toks0{\newcommand\luatexbase@directlua}% +\fi +\ifnum\luatexversion<36 + \toks0\expandafter{\the\toks0{\directlua0}}% +\else + \toks0\expandafter{\the\toks0{\directlua}}% +\fi +\expandafter\endgroup +\the\toks0 +% \end{macrocode} +% +% \subsection{Version information} +% +% Make |\luatexversion| and |\luatexrevision| available from Lua. +% +% \begin{macrocode} +\luatexbase@directlua{% + luatexbase = luatexbase or {} + luatexbase.luatexversion = \number\luatexversion\space + luatexbase.luatexrevision = \number\luatexrevision\space} +% \end{macrocode} +% +% \subsection{Primitives} +% +% Try reasonably hard to activate a primitive. First, check if it is +% already activated an do nothing in this case. +% +% \begin{macrocode} +\begingroup +\expandafter\ifx\csname newcommand\endcsname\relax + \toks0{\def\luatexbase@ensure@primitive#1} +\else + \toks0{\newcommand*\luatexbase@ensure@primitive[1]} +\fi +\toks2{}\def\x#1{\toks2\expandafter{\the\toks2 #1}} +\x{% + \ifcsname luatex#1\endcsname \else} +\ifnum\luatexversion<37\relax +% \end{macrocode} +% +% |tex.enableprimitives()| not available. If the unprefixed primitive is +% undefined, issue an error. +% +% \begin{macrocode} + \x{% + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname #1\endcsname\relax} + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname PackageError\endcsname\relax + \x{% + \errmessage{% + Package luatexbase-compat error: failed to enable `#1'.}} + \else + \x{% + \PackageError{luatexbase-compat}{% + Package luatexbase-compat error: failed to enable `#1'.}{}} + \fi + \x{% + \else} +% \end{macrocode} +% +% Use the unprefixed primitive to define the prefixed version. +% +% \begin{macrocode} + \x{% + \expandafter\let\csname luatex#1\expandafter\endcsname + \csname#1\endcsname + \fi} +\else +% \end{macrocode} +% +% |tex.enableprimitives()| available, use it. +% +% \begin{macrocode} + \x{% + \luatexbase@directlua{tex.enableprimitives('luatex', '#1')}} +\fi +\x{% + \fi} +\toks0\expandafter{\the\toks0\expandafter{\the\toks2}} +\expandafter\endgroup +\the\toks0 +% \end{macrocode} +% +% That's all folks! +% +% \begin{macrocode} +\lltxb@compat@AtEnd +%</texpackage> +% \end{macrocode} +% +% \section{Test files} +% +% Test fils for Plain and LaTeX +% +% \begin{macrocode} +%<testplain>\input luatexbase-compat.sty +%<testlatex>\RequirePackage{luatexbase-compat} +%<*testplain,testlatex> +\catcode64 11 +\luatexbase@directlua{local answer = 42} +\luatexbase@ensure@primitive{primitive} +\luatexprimitive\relax +\luatexbase@directlua{assert(type(luatexbase.luatexversion) == 'number')} +\luatexbase@directlua{assert(type(luatexbase.luatexrevision) == 'number')} +%</testplain,testlatex> +%<testplain>\bye +%<testlatex>\stop +% \end{macrocode} +% +% +% \Finale +\endinput diff --git a/luatexbase-loader.dtx b/luatexbase-loader.dtx index 695efe6..0a3945f 100644 --- a/luatexbase-loader.dtx +++ b/luatexbase-loader.dtx @@ -67,6 +67,9 @@ See source file '\inFileName' for details. \generate{% \usedir{tex/luatex/luatexbase}% \file{luatexbase.loader.lua}{\from{luatexbase-loader.dtx}{luamodule}}% + \usedir{doc/luatex/luatexbase}% + \file{test-loader.lua}{\from{luatexbase-loader.dtx}{testdummy}}% + \file{test-loader.sub.lua}{\from{luatexbase-loader.dtx}{testdummy}}% } \obeyspaces @@ -122,10 +125,45 @@ See source file '\inFileName' for details. % \maketitle % % \begin{abstract} +% Lua modules are loaded using the |require()| function which, similarly to +% \tex's |\input|, takes care of locating the file and load it, but also makes +% a few supplementary checks, for example to avoid loading the same module +% twice. This package adapts the way the files are searched in order to +% accommodate the TDS as well as usual Lua naming conventions. +% +% For higher-level functions related to Lua modules, see +% \href{file:luatexbase-modutils.pdf}{\pk{luatexbase-modutils}}, which also +% loads the present package. % \end{abstract} % % \section{Documentation} % +% Starting with \luatex 0.45.0, |require()| uses Kpathsea for file searching +% when the library is initialised (which is always the case in \tex mode, +% unless explicitly disabled by the user). However, it does not respect the +% Lua convention that |require("foo.bar")| should look for |foo/bar.lua|. +% \footnote{Support for that has been added in rev 3558 of \luatex, currently +% unreleased but probably part of \luatex 0.54.} This package implements such +% behaviour. +% +% More precisely, it implements a new kpse searcher that looks for file +% |foo/bar| using Kpathsea with the format |lua| (that is, search along +% |LUAINPUTS| and try the following extensions: |.luc|, |.luctex|, |.texluc|, +% |.lua|, |.luatex|, |.texlua|). If this search fails, it falls back to +% |foo.bar|. +% +% Also, older versions of \luatex, such as 0.25.4 (\texlive 2008), don't know +% about the |lua| format for kpse searching. So, an emulator for this function +% is provided. The emulator is not perfect, in particular it may find more +% results than the normal |lua| format search. In order to ensure more +% homogeneous results across versions, this emulator is used as a fall-back +% when the real |lua| format search doesn't find any result. +% +% Finally, a combined version of this new kpse searcher and the original +% function at |package.loaders[2]| (using first the new loader, then the old +% one if the new doesn't return any result) is installed as +% |package.loaders[2]|. +% % \section{Implementation} % % \subsection{\tex package} @@ -190,7 +228,7 @@ See source file '\inFileName' for details. \let\x\ProvidesPackage \fi \expandafter\endgroup -\x{luatexbase-loader}[2010/03/26 v0.1 Lua module loader for LuaTeX (mpg)] +\x{luatexbase-loader}[2010/03/26 v0.1 Lua module loader for LuaTeX] % \end{macrocode} % % Make sure \luatex is used. @@ -219,10 +257,23 @@ See source file '\inFileName' for details. % % \subsubsection{Main content} % -% Load the supporting Lua module. +% First load \pk{luatexbase-compat}. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input luatexbase-compat.sty +\else + \RequirePackage{luatexbase-compat} +\fi +% \end{macrocode} +% +% Load the supporting Lua module. This one doesn't follow the usual naming +% conventions, since it won't be loaded with the usual functions for +% obvious bootstraping reasons. % % \begin{macrocode} -\directlua{% +\luatexbase@directlua{% local file = "luatexbase.loader.lua" local path = assert(kpse.find_file(file, 'tex'), "File '"..file.."' no found") @@ -241,42 +292,130 @@ See source file '\inFileName' for details. % % \begin{macrocode} %<*luamodule> -module('luatextra', package.seeall) +module('luatexbase', package.seeall) +% \end{macrocode} +% +% Emulate (approximatively) kpse's lua format search. +% +% |lua_search_suffixes| is taken verbatim from Kpathsea's source +% (\file{tex-file.c}, constant |LUA_SUFFIXES|),\footnote{Unchanged since +% 2007-07-06, last checked 2010-05-10.} except for the addition of the +% empty string at the beginning (since this is what kpse does: first try +% without adding a suffix). +% +% There is a problem with using the |tex| search format: kpse will try to +% add suffixes from the |TEX_SUFFIXES| constant, which leads to problems +% when a file \meta{name}|.tex| exists. We prevent that by checking the +% extension of the file found. +% +% \begin{macrocode} +local lua_search_suffixes = { + "", ".luc", ".luctex", ".texluc", ".lua", ".luatex", ".texlua", + } +local lua_valid_suffixes = { + luc = true, + lua = true, + luctex = true, + texluc = true, + luatex = true, + texlua = true, +} +local function find_file_lua_emul(name) + for _, suf in ipairs(lua_search_suffixes) do + local name = name..suf + local f = kpse.find_file(name, 'texmfscripts') + or kpse.find_file(name, 'tex') + if suf == "" and f then + local ext = string.match(f,"^.+%.([^/\\]-)$") + if lua_valid_suffixes[suf] then + return f + end + elseif f then + return f + end + end +end +% \end{macrocode} +% +% If lua search format is available, use it with emulation as a fall-back, +% or just use emulation. +% +% \begin{macrocode} +local find_file_lua +if pcall('kpse.find_file', 'dummy', 'lua') then + find_file_lua = function (name) + return kpse.find_file(name, 'lua') or find_file_lua_emul(name) + end +else + find_file_lua = function (name) + return find_file_lua_emul(name) + end +end +% \end{macrocode} +% +% Find the full path corresponding to a module name. +% +% \begin{macrocode} +local function find_module_file(mod) + return find_file_lua(mod:gsub('%.', '/'), 'lua') + or find_file_lua(mod, 'lua') +end % \end{macrocode} % +% Combined searcher, using primarily the new kpse searcher, and the +% original as a fall-back. +% % \begin{macrocode} +local package_loader_two = package.loaders[2] local function load_module(mod) - local file = kpse.find_file(mod, 'lua') + local file = find_module_file(mod) if not file then - return "\n\t[luatextra.loader] Search failed" + local msg = "\n\t[luatexbase.loader] Search failed" + local ret = package_loader_two(mod) + if type(ret) == 'string' then + return msg..ret + elseif type(ret) == 'nil' then + return msg + else + return ret + end end local loader, error = loadfile(file) if not loader then - return "\n\t[luatextra.loader] Loading error:\n\t"..error + return "\n\t[luatexbase.loader] Loading error:\n\t"..error end texio.write_nl("("..file..")") return loader end % \end{macrocode} % +% Finally install this combined loader as loader 2. +% % \begin{macrocode} -table.insert(package.loaders, load_module) +package.loaders[2] = load_module %</luamodule> % \end{macrocode} % % \section{Test files} % -% We just check that the package loads properly, under both LaTeX and Plain -% TeX. Anyway, the test files of other modules using this one already are a -% test\dots +% A dummy lua file for tests. % % \begin{macrocode} -%<testplain>\input luatexbase-loader.sty -%<testlatex>\RequirePackage{luatexbase-loader} -%<*testplain,testlatex> +%<*testdummy> +return true +%</testdummy> % \end{macrocode} % +% Check that the package loads properly, under both LaTeX and Plain TeX, +% and load a dummy module in the current diretory. +% % \begin{macrocode} +%<testplain>\input luatexbase-loader.sty +%<testlatex>\RequirePackage{luatexbase-loader} +%<*testplain,testlatex> +\catcode64 11 +\luatexbase@directlua{require "test-loader"} +\luatexbase@directlua{require "test-loader.sub"} %</testplain,testlatex> %<testplain>\bye %<testlatex>\stop diff --git a/luamcallbacks.dtx b/luatexbase-mcb.dtx index c2d94f9..11c2a44 100644 --- a/luamcallbacks.dtx +++ b/luatexbase-mcb.dtx @@ -1,18 +1,20 @@ % \iffalse meta-comment % -% Copyright (C) 2009 by Elie Roux <elie.roux@telecom-bretagne.eu> +% Written in 2009, 2010 by Manuel Pégourié-Gonnard and Élie Roux. +% <mpg@elzevir.fr> +% <elie.roux@telecom-bretagne.eu> % % This work is under the CC0 license. % -% This work consists of the main source file luamcallbacks.dtx +% This work consists of the main source file luatexbase-mcb.dtx % and the derived files -% luamcallbacks.sty, luamcallbacks.tex, luamcallbacks.lua -% test-luamcallbacks.tex, luamcallbacks.pdf. +% luatexbase-mcb.sty, mcb.lua, luatexbase-mcb.pdf, +% test-mcb-plain.tex test-mcb-latex.tex % % Unpacking: -% tex luamcallbacks.dtx +% tex luatexbase-mcb.dtx % Documentation: -% pdflatex luamcallbacks.dtx +% pdflatex luatexbase-mcb.dtx % %<*ignore> \begingroup @@ -43,8 +45,14 @@ See source file '\inFileName' for details. \let\MetaPrefix\DoubleperCent \generate{% + \usedir{tex/luatex/luatexbase}% + \file{luatexbase-mcb.sty}{\from{luatexbase-mcb.dtx}{texpackage}}% +} + +\generate{% \usedir{doc/luatex/luatexbase}% - \file{test-luamcallbacks.tex}{\from{luamcallbacks.dtx}{test}}% + \file{test-mcb-plain.tex}{\from{luatexbase-mcb.dtx}{testplain}}% + \file{test-mcb-latex.tex}{\from{luatexbase-mcb.dtx}{testlatex}}% } \def\MetaPrefix{-- } @@ -58,7 +66,7 @@ See source file '\inFileName' for details. \generate{% \usedir{tex/luatex/luatexbase}% - \file{luamcallbacks.lua}{\from{luamcallbacks.dtx}{lua}}% + \file{mcb.lua}{\from{luatexbase-mcb.dtx}{lua}}% } \obeyspaces @@ -67,7 +75,7 @@ See source file '\inFileName' for details. \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} -\Msg{* luamcallbacks.lua} +\Msg{* luatexbase-mcb.sty mcb.lua} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} @@ -82,7 +90,7 @@ See source file '\inFileName' for details. \documentclass{ltxdoc} \input{lltxb-dtxstyle} \begin{document} - \DocInput{luamcallbacks.dtx}% + \DocInput{luatexbase-mcb.dtx}% \end{document} %</driver> % \fi @@ -105,11 +113,11 @@ See source file '\inFileName' for details. % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % -% \GetFileInfo{luamcallbacks.drv} -% -% \title{The \textsf{luamcallbacks} package} +% \title{The \textsf{luatexbase-mcb} package} % \date{2009/09/18 v0.93} -% \author{Elie Roux \\ \texttt{elie.roux@telecom-bretagne.eu}} +% \author{% +% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and +% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}} % % \maketitle % @@ -123,6 +131,8 @@ See source file '\inFileName' for details. % has been previously loaded. (This is a temporary limitation.) % \end{abstract} % +% \tableofcontents +% % \section{Documentation} % % Lua\TeX\ provides an extremely interesting feature, named callbacks. It @@ -150,11 +160,7 @@ See source file '\inFileName' for details. % 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} +% \subsubsection*{Limitations} % % This package only works for callbacks where it's safe to add multiple % functions without changing the functions' signatures. There are callbacks, @@ -171,57 +177,171 @@ See source file '\inFileName' for details. % \texttt{open\_read\_file}. There is though a solution for several packages % to use these callbacks, see the implementation of \texttt{luatextra}. % -% \StopEventually{ -% } +% \section{Implementation} % -% \section{Package code} +% \subsection{\tex package} % -% \iffalse -%<*lua> -% \fi +% \begin{macrocode} +%<*texpackage> +% \end{macrocode} % -% The package contains \texttt{luamcallbacks.lua} with the new functions, -% and an example of the use of luamcallbacks. +% \subsubsection{Preliminaries} % -% First the \texttt{luamcallbacks} module is registered as a Lua\TeX\ -% module, with some informations. +% Reload protection, especially for \plaintex. % % \begin{macrocode} - -luamcallbacks = { } - -luamcallbacks.module = { + \csname lltxb@mcb@loaded\endcsname +\expandafter\let\csname lltxb@mcb@loaded\endcsname\endinput +% \end{macrocode} +% +% Catcode defenses. +% +% \begin{macrocode} +\begingroup + \catcode123 1 % { + \catcode125 2 % } + \catcode 35 6 % # + \toks0{}% + \def\x{}% + \def\y#1 #2 {% + \toks0\expandafter{\the\toks0 \catcode#1 \the\catcode#1}% + \edef\x{\x \catcode#1 #2}}% + \y 123 1 % { + \y 125 2 % } + \y 35 6 % # + \y 10 12 % ^^J + \y 34 12 % " + \y 36 3 % $ $ + \y 39 12 % ' + \y 40 12 % ( + \y 41 12 % ) + \y 42 12 % * + \y 43 12 % + + \y 44 12 % , + \y 45 12 % - + \y 46 12 % . + \y 47 12 % / + \y 60 12 % < + \y 61 12 % = + \y 64 11 % @ (letter) + \y 62 12 % > + \y 95 12 % _ (other) + \y 96 12 % ` + \edef\y#1{\endgroup\edef#1{\the\toks0\relax}\x}% +\expandafter\y\csname lltxb@mcb@AtEnd\endcsname +% \end{macrocode} +% +% Package declaration. +% +% \begin{macrocode} +\begingroup + \expandafter\ifx\csname ProvidesPackage\endcsname\relax + \def\x#1[#2]{\immediate\write16{Package: #1 #2}} + \else + \let\x\ProvidesPackage + \fi +\expandafter\endgroup +\x{luatexbase-mcb}[2010/09/11 v0.93 Callback management for LuaTeX] +% \end{macrocode} +% +% Make sure \luatex is used. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input ifluatex.sty +\else + \RequirePackage{ifluatex} +\fi +\ifluatex\else + \begingroup + \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax + \def\x#1#2{\begingroup\newlinechar10 + \immediate\write16{Package #1 warning: #2}\endgroup} + \else + \let\x\PackageWarningNoLine + \fi + \expandafter\endgroup + \x{luatexbase-mcb}{LuaTeX is required for this package. Aborting.} + \lltxb@mcb@AtEnd + \expandafter\endinput +\fi +% \end{macrocode} +% +% \subsubsection{Load supporting Lua module} +% +% First load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}), then +% the supporting Lua module. +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input luatexbase-modutils.sty +\else + \RequirePackage{luatexbase-modutils} +\fi +\luatexbase@directlua{require('luatexbase.mcb')} +% \end{macrocode} +% +% That's all folks! +% +% \begin{macrocode} +\lltxb@mcb@AtEnd +%</texpackage> +% \end{macrocode} +% +% \subsection{Lua module} +% +% \begin{macrocode} +%<*lua> +% \end{macrocode} +% +% \subsubsection{Module identification} +% +% \begin{macrocode} +module('luatexbase', package.seeall) +luatexbase.provides_module({ name = "luamcallbacks", version = 0.93, date = "2009/09/18", - description = "Module to register several functions in a callback.", - author = "Hans Hagen & Elie Roux", - copyright = "Hans Hagen & Elie Roux", + description = "register several functions in a callback", + author = "Hans Hagen, Elie Roux and Manuel Pégourie-Gonnard", + copyright = "Hans Hagen, Elie Roux and Manuel Pégourie-Gonnard", license = "CC0", -} - -luatextra.provides_module(luamcallbacks.module) - +}) % \end{macrocode} % +% Shortcuts for error functions. +% +% \begin{macrocode} +local log = log or function(...) + luatexbase.module_log('luamcallbacks', string.format(...)) +end +local info = info or function(...) + luatexbase.module_info('luamcallbacks', string.format(...)) +end +local warning = warning or function(...) + luatexbase.module_warning('luamcallbacks', string.format(...)) +end +local err = err or function(...) + luatexbase.module_error('luamcallbacks', string.format(...)) +end +% \end{macrocode} +% +% \subsubsection{Initialisations} +% % \texttt{callbacklist} is the main list, that contains the callbacks as % keys and a table of the registered functions a values. % % \begin{macrocode} - -luamcallbacks.callbacklist = luamcallbacks.callbacklist or { } - +local callbacklist = callbacklist or { } % \end{macrocode} % % A table with the default functions of the created callbacks. See -% \texttt{luamcallbacks.create} for further informations. +% \texttt{create} for further informations. % % \begin{macrocode} - -luamcallbacks.lua_callbacks_defaults = { } - -local format = string.format - +local lua_callbacks_defaults = { } % \end{macrocode} % % There are 4 types of callback: @@ -236,117 +356,92 @@ local format = string.format % \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, +local callbacktypes = callbacktypes or { + buildpage_filter = simple, + token_filter = first, + pre_output_filter = list, + hpack_filter = list, + process_input_buffer = data, + mlist_to_hlist = list, + vpack_filter = list, + define_font = first, + open_read_file = first, + linebreak_filter = list, + post_linebreak_filter = list, + pre_linebreak_filter = list, + start_page_number = simple, + stop_page_number = simple, + start_run = simple, + show_error_hook = simple, + stop_run = simple, + hyphenate = simple, + ligaturing = simple, + kerning = data, + find_write_file = first, + find_read_file = first, + find_vf_file = data, + find_map_file = data, + find_format_file = data, + find_opentype_file = data, + find_output_file = data, + find_truetype_file = data, + find_type1_file = data, + find_data_file = data, + find_pk_file = data, + find_font_file = data, + find_image_file = data, + find_ocp_file = data, + find_sfd_file = data, + find_enc_file = data, + read_sfd_file = first, + read_map_file = first, + read_pk_file = first, + read_enc_file = first, + read_vf_file = first, + read_ocp_file = first, + read_opentype_file = first, + read_truetype_file = first, + read_font_file = first, + read_type1_file = first, + read_data_file = first, } - % \end{macrocode} % % In Lua\TeX\ version 0.43, a new callback called |process_output_buffer| -% appeared, so we enable it. +% appeared, so we enable it. Test the version using the compat package for, +% well, compatibility. % % \begin{macrocode} - -if tex.luatexversion > 42 then - luamcallbacks.callbacktypes["process_output_buffer"] = data +if luatexbase.luatexversion > 42 then + callbacktypes["process_output_buffer"] = data end - % \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. +% \texttt{internalregister}. % % \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 - +local internalregister = internalregister or callback.register % \end{macrocode} % +% \subsubsection{Unsorted stuff} +% % A simple function we'll use later to understand the arguments of the % \texttt{create} function. It takes a string and returns the type % corresponding to the string or nil. % % \begin{macrocode} - -function luamcallbacks.str_to_type(str) +local function str_to_type(str) if str == 'list' then return list elseif str == 'data' then @@ -359,94 +454,97 @@ function luamcallbacks.str_to_type(str) 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. +% This function and the following ones are only internal. This one is the +% handler for the first type of callbacks: the ones that take a list head +% and return true, false, or a new list head. % % \begin{macrocode} - -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 +-- local +function listhandler (name) + return function(head,...) + local l = callbacklist[name] + if l then + local done = true + for _, f in ipairs(l) do + -- the returned value is either true or a new head plus true + rtv1, rtv2 = f.func(head,...) + if type(rtv1) == 'boolean' then + done = rtv1 + elseif type (rtv1) == 'userdata' then + head = rtv1 + end + if type(rtv2) == 'boolean' then + done = rtv2 + elseif type(rtv2) == 'userdata' then + head = rtv2 + end + if done == false then + err("function \"%s\" returned false in callback '%s'", + f.description, name) + end + end + return head, done + else + return head, false + end end - ctype = temp - luamcallbacks.lua_callbacks_defaults[name] = default - callbacktypes[name] = ctype end - % \end{macrocode} % -% \end{macro} +% The handler for callbacks taking datas and returning modified ones. % -% \begin{macro}{luamcallbacks.call} +% \begin{macrocode} +local function datahandler (name) + return function(data,...) + local l = callbacklist[name] + if l then + for _, f in ipairs(l) do + data = f.func(data,...) + end + end + return data + end +end +% \end{macrocode} % -% This function calls a callback. It can only call a callback created by -% the \texttt{create} function. +% This function is for the handlers that don't support more than one +% functions in them. In this case we only call the first function of the +% list. % % \begin{macrocode} - -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) +local function firsthandler (name) + return function(...) + local l = callbacklist[name] + if l then + local f = l[1].func + return f(...) else - luamcallbacks.error("unknown callback type") + return nil, false end end - return f(...) end - % \end{macrocode} % -% \end{macro} +% Handler for simple functions that don't return anything. +% +% \begin{macrocode} +local function simplehandler (name) + return function(...) + local l = callbacklist[name] + if l then + for _, f in ipairs(l) do + f.func(...) + end + end + end +end +% \end{macrocode} % -% \begin{macro}{luamcallbacks.add} +% \subsubsection{Public functions} % -% The main function. The signature is \texttt{luamcallbacks.add (name, +% The main function. The signature is \texttt{add (name, % func, description, priority)} with \texttt{name} being the name of the % callback in which the function is added; \texttt{func} is the added % function; \texttt{description} is a small character string describing the @@ -454,7 +552,7 @@ end % priority the function will have. % % The functions for a callbacks are added in a list (in -% \texttt{luamcallbacks.callbacklist\\.callbackname}). If they have no +% \texttt{callbacklist\\.callbackname}). If they have no % priority or a high priority number, they will be added at the end of the % list, and will be called after the others. If they have a low priority % number, the will be added at the beginning of the list and will be called @@ -463,50 +561,45 @@ end % 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. +% to their function themselves. Most of the time, the priority is not needed. % % \begin{macrocode} - -function luamcallbacks.add (name,func,description,priority) +function add_to_callback (name,func,description,priority) if type(func) ~= "function" then - luamcallbacks.error("unable to add function, no proper function passed") + err("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") + err("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)) + err("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)) + err("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)) + if priority_in_callback(name, description) ~= 0 then + warning("function '%s' already registered in callback '%s'", + description, name) end - local l = luamcallbacks.callbacklist[name] + local l = callbacklist[name] if not l then l = {} - luamcallbacks.callbacklist[name] = l - if not luamcallbacks.lua_callbacks_defaults[name] then + callbacklist[name] = l + if not lua_callbacks_defaults[name] then if callbacktypes[name] == list then - luamcallbacks.internalregister(name, luamcallbacks.listhandler(name)) + internalregister(name, listhandler(name)) elseif callbacktypes[name] == data then - luamcallbacks.internalregister(name, luamcallbacks.datahandler(name)) + internalregister(name, datahandler(name)) elseif callbacktypes[name] == simple then - luamcallbacks.internalregister(name, luamcallbacks.simplehandler(name)) + internalregister(name, simplehandler(name)) elseif callbacktypes[name] == first then - luamcallbacks.internalregister(name, luamcallbacks.firsthandler(name)) + internalregister(name, firsthandler(name)) else - luamcallbacks.error("unknown callback type") + err("unknown callback type") end end end @@ -521,320 +614,224 @@ function luamcallbacks.add (name,func,description,priority) 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)) + warning("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 + log("inserting function '%s' at position %s in callback list for '%s'", + description, priority, name) 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 +% \texttt{remove (name, description)} with \texttt{name} being % the name of callbacks, and description the description passed to -% \texttt{mcallbacks.add}. +% \texttt{add}. % % \begin{macrocode} - -function luamcallbacks.remove (name, description) +function remove_from_callback (name, description) if not name or name == "" then - luamcallbacks.error("unable to remove function, no proper callback name passed") + err("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)) + err("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)) + err( + "unable to remove function from '%s', no proper description passed", + name) return end - local l = luamcallbacks.callbacklist[name] + local l = callbacklist[name] if not l then - luamcallbacks.error(format("no callback list for '%s'",name)) + err("no callback list for '%s'",name) return end for k,v in ipairs(l) do if v.description == description then table.remove(l,k) - luamcallbacks.log( - format("removing function '%s' from '%s'",description,name)) + log("removing function '%s' from '%s'",description,name) if not next(l) then - luamcallbacks.callbacklist[name] = nil - if not luamcallbacks.lua_callbacks_defaults[name] then - luamcallbacks.internalregister(name, nil) + callbacklist[name] = nil + if not lua_callbacks_defaults[name] then + internalregister(name, nil) end end return end end - luamcallbacks.warning( - format("unable to remove function '%s' from '%s'",description,name)) + warning("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) +function reset_callback (name) if not name or name == "" then - luamcallbacks.error("unable to reset, no proper callback name passed") + err("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)) + err("reset error, '%s' is not a valid callback", name) return end - if not luamcallbacks.lua_callbacks_defaults[name] then - luamcallbacks.internalregister(name, nil) + if not lua_callbacks_defaults[name] then + internalregister(name, nil) end - local l = luamcallbacks.callbacklist[name] + local l = callbacklist[name] if l then - luamcallbacks.log(format("resetting callback list '%s'",name)) - luamcallbacks.callbacklist[name] = nil + log("resetting callback list '%s'",name) + 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. +% 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. % -% \begin{macro}{luamcallbacks.listhandler} +% 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.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 +function create_callback(name, ctype, default) + if not name then + err("unable to call callback, no proper name passed", name) + return nil 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 + if not ctype or not default then + err("unable to create callback '%s': " + .."callbacktype or default function not specified", name) + return nil + end + if callbacktypes[name] then + err("unable to create callback '%s', callback already exists", name) + return nil end + local temp = str_to_type(ctype) + if not temp then + err("unable to create callback '%s', type '%s' undefined", name, ctype) + return nil + end + ctype = temp + lua_callbacks_defaults[name] = default + callbacktypes[name] = ctype end - % \end{macrocode} % -% \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} +% This function calls a callback. It can only call a callback created by +% the \texttt{create} function. % % \begin{macrocode} - -function luamcallbacks.firsthandler (name) - return function(...) - local l = luamcallbacks.callbacklist[name] - if l then - local f = l[1].func - return f(...) +function call_callback(name, ...) + if not name then + err("unable to call callback, no proper name passed", name) + return nil + end + if not lua_callbacks_defaults[name] then + err("unable to call lua callback '%s', unknown callback", name) + return nil + end + local l = callbacklist[name] + local f + if not l then + f = lua_callbacks_defaults[name] + else + if callbacktypes[name] == list then + f = listhandler(name) + elseif callbacktypes[name] == data then + f = datahandler(name) + elseif callbacktypes[name] == simple then + f = simplehandler(name) + elseif callbacktypes[name] == first then + f = firsthandler(name) else - return nil, false + err("unknown callback type") end end + return f(...) end - % \end{macrocode} % -% \end{macro} -% -% Handler for simple functions that don't return anything. -% -% \begin{macro}{luamcallbacks.simplehandler} +% 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.simplehandler (name) - return function(...) - local l = luamcallbacks.callbacklist[name] - if l then - for _, f in ipairs(l) do - f.func(...) - end +function priority_in_callback (name, description) + if not name or name == "" + or not callbacktypes[name] + or not description then + return 0 + end + local l = callbacklist[name] + if not l then return 0 end + for p, f in pairs(l) do + if f.description == description then + return p end end + return 0 end - % \end{macrocode} % -% \end{macro} -% -% Finally we add some functions to the \texttt{callback} module, and we +% Finally 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.") +callback.register = function () +err("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 luatexbase-loader.sty -\input luatexbase-modutils.sty -\directlua{require "luamcallbacks"} -This is just a test file. -% \end{macrocode} -% -% Then we declare three functions that we will use. -% -% \begin{macrocode} -\directlua{ -local function one(head,...) - texio.write_nl("I'm number 1") - return head, true -end - -local function two(head,...) - texio.write_nl("I'm number 2") - return head, true -end - -local function three(head,...) - texio.write_nl("I'm number 3") - return head, true -end -% \end{macrocode} -% -% Then we add the three functions to the hpack\_filter callback +% That's all folks! % % \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) +%</lua> % \end{macrocode} % -% We remove the function three from the callback. +% \section{Test files} % -% \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. +% A few basic tests for Plain and LaTeX. % % \begin{macrocode} +%<testplain>\input luatexbase-mcb.sty +%<testlatex>\RequirePackage{luatexbase-mcb} +%<*testplain,testlatex> +\catcode 64 11 +\luatexbase@directlua{ + local function one(head,...) + texio.write_nl("I'm number 1") + return head, true + end + + local function two(head,...) + texio.write_nl("I'm number 2") + return head, true + end + + local function three(head,...) + texio.write_nl("I'm number 3") + return head, true + end + + luatexbase.add_to_callback("hpack_filter",one,"my sample function one",1) + luatexbase.add_to_callback("hpack_filter",two,"my sample function two",2) + luatexbase.add_to_callback("hpack_filter",three,"my sample function three",1) + + luatexbase.remove_from_callback("hpack_filter","my sample function three") } - -\bye +%</testplain,testlatex> +%<testplain>\bye +%<testlatex>\stop % \end{macrocode} -% \iffalse -%</test> -% \fi +% % \Finale \endinput diff --git a/luatexbase-modutils.dtx b/luatexbase-modutils.dtx index bd84dc7..4a08c4c 100644 --- a/luatexbase-modutils.dtx +++ b/luatexbase-modutils.dtx @@ -66,7 +66,7 @@ See source file '\inFileName' for details. \generate{% \usedir{tex/luatex/luatexbase}% - \file{luatexbase.modutils.lua}{\from{luatexbase-modutils.dtx}{luamodule}}% + \file{modutils.lua}{\from{luatexbase-modutils.dtx}{luamodule}}% \usedir{doc/luatex/luatexbase}% \file{test-modutils.lua}{\from{luatexbase-modutils.dtx}{testdummy}}% } @@ -77,7 +77,7 @@ See source file '\inFileName' for details. \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} -\Msg{* luatexbase-modutils.sty luatexbase.modutils.lua} +\Msg{* luatexbase-modutils.sty modutils.lua} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} @@ -126,6 +126,8 @@ See source file '\inFileName' for details. % \begin{abstract} % \end{abstract} % +% \tableofcontents +% % \section{Documentation} % % Lua has some embedded module management, with the functions \texttt{module} @@ -135,8 +137,8 @@ See source file '\inFileName' for details. % \texttt{\string\luatexUseModule} and \texttt{\string\luatexRequireModule} % 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}. +% \texttt{luatexbase.provides\_module} and \texttt{luatexbase.use\_module} or +% \texttt{luatexbase.require\_module}. % % \section{Implementation} % @@ -202,7 +204,7 @@ See source file '\inFileName' for details. \let\x\ProvidesPackage \fi \expandafter\endgroup -\x{luatexbase-modutils}[2010/03/26 v0.1 Module utilities for LuaTeX (mpg)] +\x{luatexbase-modutils}[2010/03/26 v0.1 Module utilities for LuaTeX] % \end{macrocode} % % Make sure \luatex is used. @@ -229,7 +231,8 @@ See source file '\inFileName' for details. \fi % \end{macrocode} % -% Load the package loader. +% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}) and require +% supporting Lua module. % % \begin{macrocode} \begingroup\expandafter\expandafter\expandafter\endgroup @@ -238,37 +241,22 @@ See source file '\inFileName' for details. \else \RequirePackage{luatexbase-loader} \fi +\luatexbase@directlua{require('luatexbase.modutils')} % \end{macrocode} % -% \subsubsection{Main code} -% -% The \texttt{\string\luatexModuleError} 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} - -\def\luatexModuleError#1#2{% - \errorcontextlines=0\relax - \immediate\write16{}% - \errmessage{Module #1 error: #2^^J^^J% -See the module #1 documentation for explanation.^^J ...^^J}% -} - -% \end{macrocode} +% \subsubsection{User macros} % % Then we define % \texttt{\string\luatexUseModule} that simply calls -% \texttt{luatextra.use\_module}. +% \texttt{luatexbase.use\_module}. % If the package is loaded with Plain, we define % \texttt{\string\luaRequireModule} with two mandatory arguments. % % \begin{macrocode} -\def\luatexUseModule#1{\directlua{luatextra.use_module([[#1]])}} - +\def\luatexUseModule#1{\luatexbase@directlua{luatexbase.use_module([[#1]])}} \expandafter\ifx\csname ProvidesPackage\endcsname\relax - \def\luatexRequireModule#1#2{\directlua{% - luatextra.require_module([[#1]], [[#2]])}} + \def\luatexRequireModule#1#2{\luatexbase@directlua{% + luatexbase.require_module([[#1]], [[#2]])}} \else % \end{macrocode} % @@ -278,12 +266,12 @@ See the module #1 documentation for explanation.^^J ...^^J}% % date). % % \begin{macrocode} - \newcommand\luatexRequireModule[2][0]{\directlua{luatextra.require_module([[#2]], [[#1]])}} + \newcommand\luatexRequireModule[2][0]{% + \luatexbase@directlua{luatexbase.require_module([[#2]], [[#1]])}} \fi % \end{macrocode} % % \begin{macrocode} -\directlua{dofile(assert(kpse.find_file('luatexbase.modutils.lua', 'tex')))} % \end{macrocode} % % \begin{macrocode} @@ -295,37 +283,13 @@ See the module #1 documentation for explanation.^^J ...^^J}% % % \begin{macrocode} %<*luamodule> +module("luatexbase", package.seeall) % \end{macrocode} % % Initialisation borrowed from luatextra % % \begin{macrocode} -module("luatextra", package.seeall) - -local format = string.format - -luatextra.modules = luatextra.modules or {} -% \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 - +local modules = modules or {} % \end{macrocode} % % \subsubsection{Error, warning and info function for modules} @@ -337,153 +301,115 @@ end % 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("\\luatexModuleError{%s}{%s}", package, msg)) +local function module_error_int(mod, ...) + error('Module '..mod..' error: '..string.format(...), 3) 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)) +function module_error(mod, ...) + module_error_int(mod, ...) 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)) +function module_warning(mod, ...) + texio.write_nl("Module "..mod.." warning: "..string.format(...)) 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)) +function module_info(mod, ...) + texio.write_nl(mod..": "..string.format(...)) 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)) +function module_log(mod, ...) + texio.write_nl('log', mod..": "..string.format(...)) +end +function module_term(mod, ...) + texio.write_nl('term', mod..": "..string.format(...)) end - % \end{macrocode} % -% \subsubsection{module loading and providing functions} -% -% A small patch, for the \texttt{module} function to work in this file. I -% can't understand why it doens't otherwise. +% For our own convenience, local functions for warning and errors in this +% module. % % \begin{macrocode} - -luatextra.module = module - +local function err(...) module_error_int('luatexbase.modutils', ...) end +local function warn(...) module_warning('luatexbase.modutils', ...) end % \end{macrocode} % -% \begin{macro}{luatextra.use module} +% \subsubsection{module loading and providing functions} % % 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}. +% \texttt{provides\_module}. % % \begin{macrocode} -function luatextra.use_module(name) - if not name or luatextra.modules[name] then +function use_module(name) + if not name or modules[name] then return end require(name) - 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)) - end - if not package.loaded[name] then - luatextra.module(name, package.seeall) + if not modules[name] then + warn("You have requested module `%s', " + .."but no file seems to provide it.", name) 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 +% \texttt{require\_package} to understand if a user asks a % version with a date or a version number. % % \begin{macrocode} - -function luatextra.datetonumber(date) +local function datetonumber(date) numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3") return tonumber(numbers) end - -function luatextra.isdate(date) +local function 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} +local function versiontonumber(version) + if isdate(version) then + return {type = date, version = datetonumber(version), orig = version} else return {type = number, version = tonumber(version), orig = version} end end - -luatextra.requiredversions = {} - +local requiredversions = {} % \end{macrocode} % -% \begin{macro}{luatextra.require module} -% -% This function is like the \texttt{luatextra.use\_module} function, but +% This function is like the \texttt{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) +function require_module(name, version) if not name then return end if not version then - return luatextra.use_module(name) + return use_module(name) end - luaversion = luatextra.versiontonumber(version) - if luatextra.modules[name] then + luaversion = versiontonumber(version) + if 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)) + if datetonumber(modules[name].date) < luaversion.version then + err("found module `%s' loaded in version %s, " + .."but version %s was required", + name, modules[name].date, version) end else - if 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)) + if modules[name].version < luaversion.version then + err("found module `%s' loaded in version %.02f, " + .."but version %s was required", + name, modules[name].version, version) end end else - luatextra.requiredversions[name] = luaversion - luatextra.use_module(name) + requiredversions[name] = luaversion + 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 @@ -495,32 +421,37 @@ end % does for informations about packages. % % \begin{macrocode} - -function luatextra.provides_module(mod) +function provides_module(mod) if not mod then - luatextra.internal_error('cannot provide nil module') + err('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') + if not mod.version or not mod.name or not mod.date + or not mod.description then + err("invalid module registered: " + .."fields name, version, date and description are mandatory") return end - requiredversion = luatextra.requiredversions[mod.name] + requiredversion = 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)) + if requiredversion.type == date + and requiredversion.version > datetonumber(mod.date) then + err("loading module %s in version %s, " + .."but version %s was required", + mod.name, mod.date, requiredversion.orig) + elseif requiredversion.type == number + and requiredversion.version > mod.version then + err("loading module %s in version %.02f, " + .."but version %s was required", + mod.name, mod.version, requiredversion.orig) end 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)) + modules[mod.name] = module + texio.write_nl('log', string.format("Lua module: %s %s v%.02f %s\n", + mod.name, mod.date, mod.version, mod.description)) end - % \end{macrocode} % -% \end{macro} -% % \begin{macrocode} %</luamodule> % \end{macrocode} @@ -531,7 +462,7 @@ end % % \begin{macrocode} %<*testdummy> -luatextra.provides_module { +luatexbase.provides_module { name = 'test-modutils', date = '2000/01/01', version = 1, diff --git a/luatexbase-regs.dtx b/luatexbase-regs.dtx index 89c2313..5b0c648 100644 --- a/luatexbase-regs.dtx +++ b/luatexbase-regs.dtx @@ -117,6 +117,8 @@ See source file '\inFileName' for details. % \luatex. % \end{abstract} % +% \tableofcontents +% % \section{Documentation} % % Since the \plaintex and \latex formats are both frozen, they fail to take @@ -147,8 +149,6 @@ See source file '\inFileName' for details. % degraded performance due to implementation details, but with \luatex the % performance is uniform, so we just do it. % -% \clearpage -% % \section{Implementation} % % \begin{macrocode} @@ -211,7 +211,7 @@ See source file '\inFileName' for details. \let\x\ProvidesPackage \fi \expandafter\endgroup -\x{luatexbase-regs}[2010/01/21 v0.1 Registers allocation for LuaTeX (mpg)] +\x{luatexbase-regs}[2010/01/21 v0.1 Registers allocation for LuaTeX] % \end{macrocode} % % Make sure \luatex is used. @@ -238,7 +238,7 @@ See source file '\inFileName' for details. \fi % \end{macrocode} % -% \subsection{Main content} +% \subsection{Ensure etex.sty is loaded} % % If running \latex, load \file{etex.sty}. If not, either % \file{etex.src} was loaded at format generation time, or we cannot do @@ -272,6 +272,8 @@ See source file '\inFileName' for details. \else % \end{macrocode} % +% \subsection{Adapt range} +% % First, increase the upper bound for all kinds of registers. Copy code to % avoid defining a macro. % @@ -286,6 +288,8 @@ See source file '\inFileName' for details. \ifnum\count276=32768 \count276=65536 \fi % \end{macrocode} % +% \subsection{Patch macros that used \cs{mathchardef}} +% % |\box| registers and |\mark|s were previously defined % using |\mathchardef| since it had the biggest range under \etex % (15-bit number). However, this is not enough for \luatex's extended @@ -394,6 +398,8 @@ See source file '\inFileName' for details. \the\toks0 % \end{macrocode} % +% \subsection{Make room for inserts} +% % Finally, make allocation of |\count|, |\dimen|, |skip| and % |\box| start with numbers $>255$, in order to free the lower numbers % for insertions. Be careful with |\new...| macros which are |