summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx')
-rw-r--r--Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx544
1 files changed, 544 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
new file mode 100644
index 00000000000..9c2936f4ce8
--- /dev/null
+++ b/Master/texmf-dist/source/luatex/luatexbase/luatexbase-modutils.dtx
@@ -0,0 +1,544 @@
+% \iffalse meta-comment
+%
+% Written in 2009, 2010 by Manuel Pégourié-Gonnard and Élie Roux.
+% <mpg@elzevir.fr>
+% <elie.roux@telecom-bretagne.eu>
+%
+% This work is under the CC0 license.
+%
+% This work consists of the main source file luatexbase-modutils.dtx
+% and the derived files
+% luatexbase-modutils.sty modutils.lua
+% test-modutils-plain.tex test-modutils-latex.tex test-modutils.lua
+%
+% Unpacking:
+% tex luatexbase-modutils.dtx
+% Documentation:
+% pdflatex luatexbase-modutils.dtx
+%
+%<*ignore>
+\begingroup
+ \def\x{LaTeX2e}%
+\expandafter\endgroup
+\ifcase 0\ifx\install y1\fi\expandafter
+ \ifx\csname processbatchFile\endcsname\relax\else1\fi
+ \ifx\fmtname\x\else 1\fi\relax
+\else\csname fi\endcsname
+%</ignore>
+%<*install>
+\input docstrip.tex
+
+\keepsilent
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+
+\preamble
+
+Written in 2009, 2010 by Manuel Pegourie-Gonnard and Elie Roux.
+
+This work is under the CC0 license.
+See source file '\inFileName' for details.
+
+\endpreamble
+
+\let\MetaPrefix\DoubleperCent
+
+\generate{%
+ \usedir{tex/luatex/luatexbase}%
+ \file{luatexbase-modutils.sty}{\from{luatexbase-modutils.dtx}{texpackage}}%
+}
+
+\generate{%
+ \usedir{doc/luatex/luatexbase}%
+ \file{test-modutils-plain.tex}{\from{luatexbase-modutils.dtx}{testplain}}%
+ \file{test-modutils-latex.tex}{\from{luatexbase-modutils.dtx}{testlatex}}%
+}
+
+\def\MetaPrefix{-- }
+
+\def\luapostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+
+\def\currentpostamble{\luapostamble}%
+
+\generate{%
+ \usedir{tex/luatex/luatexbase}%
+ \file{modutils.lua}{\from{luatexbase-modutils.dtx}{luamodule}}%
+ \usedir{doc/luatex/luatexbase}%
+ \file{test-modutils.lua}{\from{luatexbase-modutils.dtx}{testdummy}}%
+}
+
+\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-modutils.sty modutils.lua}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*}
+\Msg{************************************************************************}
+
+\endbatchfile
+%</install>
+%<*ignore>
+\fi
+%</ignore>
+%<*driver>
+\documentclass{ltxdoc}
+\input{lltxb-dtxstyle}
+\begin{document}
+ \DocInput{luatexbase-modutils.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-modutils} package}
+% \date{v0.2 2010-05-12}
+% \author{%
+% Manuel P\'egouri\'e-Gonnard \\ \email{mpg@elzevir.fr} \and
+% \'Elie Roux \\ \email{elie.roux@telecom-bretagne.eu}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% This package provides functions similar to \latex's |\usepackage| and
+% |\ProvidesPackage| macros,\footnote{and their variants or synonyms such as
+% \cs{documentclass} and \cs{RequirePackage} or \cs{ProvidesClass} and
+% \cs{ProvidesFiles}} or more precisely the part of these macros that deals
+% with identification and version checking (no attempt is done at implementing
+% an option mechanism). Functions for error reporting are provided too.
+%
+% It also loads \pk{luatexbase-loader}.
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Documentation}
+%
+% Lua's standard function |require()| is similar to \tex's |\input| primitive
+% but is somehow more evolved in that it makes a few checks to avoid loading
+% the same module twice. In the \tex world, this needs to be taken care of by
+% macro packages; in the \latex world this is done by |\usepackage|.
+%
+% But |\usepackage| also takes care of many other things. Most notably, it
+% implements a complex option system, and does some identification and version
+% checking. The present package doesn't try to provide anything for options,
+% but implements a system for identification and version checking similar to
+% \latex's system. Both \tex macros and Lua functions are provided.
+%
+% This package also provides Lua functions for reporting errors, warnings,
+% etc.
+%
+% It is important to notice that Lua's standard function |module()| is
+% completely unrelated to the present package. It has nothing to do with
+% identification and deals only with namespaces.\footnote{More precisely, it
+% modifies the current environment.} So, you should continue to
+% use it normally, unlike the |require()| function which can be replaced with
+% this package's |luatexbase.require_module()|.
+%
+% \subsection{\tex macros}
+%
+% The two macros |\luatexUseModule| and |\luatexRequireModule| are very
+% similar and are interfaces to the Lua functions |use_module| and
+% |require_module|. The only difference between those macros is the number of
+% arguments (just as the underlying Lua functions): |\luatexUseModule| only
+% take one argument: the module name\footnote{without extension} while
+% |\luatexRequireModule| takes another argument for specifying a minimal
+% version (see below). With \latex, this argument is the first and is
+% optional. Otherwise, it's the second one and it's mandatory.
+%
+% \subsection{Lua functions}
+%
+% The main functions are |luatexbase.require_module| and
+% |luatexbase.use_module| which may be used as a replacement to |require()|.
+% The only difference between these functions is, |require_module| accepts a
+% second, optional argument in order to specify a minimal version. They do the
+% same as |require()| but also make sure the module loaded correctly
+% identifies itself with the name given, and its version is greater than the
+% minimal version required. The version can be given either as a (floating
+% point) number or as a date in YYYY/MM/DD format.
+%
+% Modules identify themselves using |luatexbase.provides_module|, whose only
+% argument is a table with some information about the module. The mandatory
+% fields are |name| (a string), |version| (a number), |date| (a string) and
+% |description| (a string). Other fields are optional and ignored, and usually
+% include |copyright|, |author| and |license|.
+%
+% \bigskip
+%
+% Functions for reporting are provided; similarly to \latex's |\PackageError|
+% etc. they take the module name as their first argument and include it in the
+% printed message in an appropriate way. The remaining arguments are passed to
+% |string.format()| before being printed.
+%
+% The functions provided (all found in the |luatexbase| table) are
+% |module_error|, |module_warning|, |module_info| (writes to terminal and
+% log), |module_log| (writes only to the log file) and |module_term| (writes
+% only to the terminal).
+%
+% \section{Implementation}
+%
+% \subsection{\tex package}
+%
+% \begin{macrocode}
+%<*texpackage>
+% \end{macrocode}
+%
+% \subsubsection{Preliminaries}
+%
+% Reload protection, especially for \plaintex.
+%
+% \begin{macrocode}
+ \csname lltxb@modutils@loaded\endcsname
+\expandafter\let\csname lltxb@modutils@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@modutils@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-modutils}[2010/05/12 v0.2 Module utilities 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-modutils}{LuaTeX is required for this package. Aborting.}
+ \lltxb@modutils@AtEnd
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% Load \pk{luatexbase-loader} (hence \pk{luatexbase-compat}) and require
+% supporting Lua module.
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname RequirePackage\endcsname\relax
+ \input luatexbase-loader.sty
+\else
+ \RequirePackage{luatexbase-loader}
+\fi
+\luatexbase@directlua{require('luatexbase.modutils')}
+% \end{macrocode}
+%
+% Make sure the primitives we need are available.
+%
+% \begin{macrocode}
+\luatexbase@ensure@primitive{luaescapestring}
+% \end{macrocode}
+%
+% \subsubsection{User macros}
+%
+% Interface to |use_module()|.
+%
+% \begin{macrocode}
+\def\luatexUseModule#1{\luatexbase@directlua{%
+ luatexbase.use_module("\luatexluescapestring{#1}")}}
+% \end{macrocode}
+%
+% Interface to |require_module()| with syntax depending on the format.
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname newcommand\endcsname\relax
+ \def\luatexRequireModule#1#2{%
+ \luatexbase@directlua{luatexbase.require_module(
+ "\luatexluaescapestring{#1}", "\luatexluaescapestring{#2}")}}
+\else
+ \newcommand\luatexRequireModule[2][0]{%
+ \luatexbase@directlua{luatexbase.require_module(
+ "\luatexluaescapestring{#2}", "\luatexluaescapestring{#1}")}}
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\lltxb@modutils@AtEnd
+%</texpackage>
+% \end{macrocode}
+%
+% \subsection{Lua module}
+%
+% \begin{macrocode}
+%<*luamodule>
+module("luatexbase", package.seeall)
+% \end{macrocode}
+%
+% \subsection{Internal functions and data}
+%
+% Tables holding informations about the modules loaded and the versions
+% required.
+%
+% \begin{macrocode}
+local modules = modules or {}
+local requiredversions = {}
+% \end{macrocode}
+%
+% Convert a date in YYYY/MM/DD format into a number
+%
+% \begin{macrocode}
+local function datetonumber(date)
+ numbers = string.gsub(date, "(%d+)/(%d+)/(%d+)", "%1%2%3")
+ return tonumber(numbers)
+end
+% \end{macrocode}
+%
+% Say if a string is a date in YYYY//MM/DD format.
+%
+% \begin{macrocode}
+local function isdate(date)
+ for _, _ in string.gmatch(date, "%d+/%d+/%d+") do
+ return true
+ end
+ return false
+end
+% \end{macrocode}
+%
+% Parse a version into a table indicating a type (date or number), a
+% numeric version and the original version string.
+%
+% \begin{macrocode}
+local date, number = 1, 2
+local function parse_version(version)
+ if isdate(version) then
+ return {type = date, version = datetonumber(version), orig = version}
+ else
+ return {type = number, version = tonumber(version), orig = version}
+ end
+end
+% \end{macrocode}
+%
+% \subsubsection{Error, warning and info function for modules}
+%
+% Here are the reporting functions for the modules. For errors, Lua's
+% |error()| is used. For now, the error reports look less good than with
+% \tex's |\errmessage|, but hopefully it will be improved in future
+% versions of \luatex. We could invoke |\errmessage| using |tex.sprint()|,
+% but it may cause problems on the \tex end, and moreover |error()| will
+% still be used by Lua for other errors, so it makes messages more
+% consistent.
+%
+% \begin{macrocode}
+local function module_error_int(mod, ...)
+ error('Module '..mod..' error: '..string.format(...), 3)
+end
+function module_error(mod, ...)
+ module_error_int(mod, ...)
+end
+function module_warning(mod, ...)
+ texio.write_nl("Module "..mod.." warning: "..string.format(...))
+end
+function module_info(mod, ...)
+ texio.write_nl(mod..": "..string.format(...))
+end
+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}
+%
+% For our own convenience, local functions for warning and errors in the
+% present module.
+%
+% \begin{macrocode}
+local function err(...) module_error_int('luatexbase.modutils', ...) end
+local function warn(...) module_warning('luatexbase.modutils', ...) end
+% \end{macrocode}
+%
+% \subsubsection{module loading and providing functions}
+%
+% Load a module without version checking.
+%
+% \begin{macrocode}
+function use_module(name)
+ require(name)
+ if not modules[name] then
+ warn("Module didn't properly identified itself: %s", name)
+ end
+end
+% \end{macrocode}
+%
+% Load a module with optional version checking.
+%
+% \begin{macrocode}
+function require_module(name, version)
+ if not version then
+ return use_module(name)
+ end
+ luaversion = parse_version(version)
+ if modules[name] then
+ if luaversion.type == date then
+ if datetonumber(modules[name].date) < luaversion.version then
+ err("found module `%s' loaded in version %s, "
+ .."but version %s was required",
+ name, modules[name].date, version)
+ end
+ else
+ if modules[name].version < luaversion.version then
+ err("found module `%s' loaded in version %.02f, "
+ .."but version %s was required",
+ name, modules[name].version, version)
+ end
+ end
+ else
+ requiredversions[name] = luaversion
+ use_module(name)
+ end
+end
+% \end{macrocode}
+%
+% Provide identification information for a module.
+%
+% \begin{macrocode}
+function provides_module(mod)
+ if not mod then
+ err('cannot provide nil module')
+ return
+ end
+ if not mod.version or not mod.name or not mod.date
+ or not mod.description then
+ err("invalid module registered: "
+ .."fields name, version, date and description are mandatory")
+ return
+ end
+ requiredversion = requiredversions[mod.name]
+ if requiredversion then
+ if requiredversion.type == date
+ and requiredversion.version > datetonumber(mod.date) then
+ err("loading module %s in version %s, "
+ .."but version %s was required",
+ mod.name, mod.date, requiredversion.orig)
+ elseif requiredversion.type == number
+ and requiredversion.version > mod.version then
+ err("loading module %s in version %.02f, "
+ .."but version %s was required",
+ mod.name, mod.version, requiredversion.orig)
+ end
+ end
+ 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}
+%
+% \begin{macrocode}
+%</luamodule>
+% \end{macrocode}
+%
+% \section{Test files}
+%
+% A dummy lua file for tests.
+%
+% \begin{macrocode}
+%<*testdummy>
+luatexbase.provides_module {
+ name = 'test-modutils',
+ date = '2000/01/01',
+ version = 1,
+ description = 'dummy test package',
+}
+%</testdummy>
+% \end{macrocode}
+%
+% We just check that the package loads properly, under both LaTeX and Plain
+% TeX. Anyway, the test files of other modules using this one already are a
+% test\dots
+%
+% \begin{macrocode}
+%<testplain>\input luatexbase-modutils.sty
+%<testlatex>\RequirePackage{luatexbase-modutils}
+%<*testplain,testlatex>
+\luatexRequireModule
+%<testlatex>[1970/01/01]
+{test-modutils}
+%<testplain>{1970/01/01}
+%</testplain,testlatex>
+%<testplain>\bye
+%<testlatex>\stop
+% \end{macrocode}
+%
+% \Finale
+\endinput