summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3luatex.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/l3kernel/l3luatex.dtx
Initial commit
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3luatex.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3luatex.dtx539
1 files changed, 539 insertions, 0 deletions
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
new file mode 100644
index 0000000000..9557fc8a08
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -0,0 +1,539 @@
+% \iffalse meta-comment
+%
+%% File: l3luatex.dtx
+%
+% Copyright (C) 2010-2019 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3luatex} package: \LuaTeX-specific functions^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2019-08-25}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% The \LuaTeX{} engine provides access to the \Lua{} programming language,
+% and with it access to the \enquote{internals} of \TeX{}. In order to use
+% this within the framework provided here, a family of functions is
+% available. When used with \pdfTeX{}, \pTeX{}, \upTeX{} or \XeTeX{} these raise an
+% error: use \cs{sys_if_engine_luatex:T} to avoid this. Details on using
+% \Lua{} with the \LuaTeX{} engine are given in the \LuaTeX{} manual.
+%
+% \section{Breaking out to \Lua{}}
+%
+% \begin{function}[EXP, added = 2018-06-18]{\lua_now:n, \lua_now:e}
+% \begin{syntax}
+% \cs{lua_now:n} \Arg{token list}
+% \end{syntax}
+% The \meta{token list} is first tokenized by \TeX{}, which includes
+% converting line ends to spaces in the usual \TeX{} manner and which
+% respects currently-applicable \TeX{} category codes. The resulting
+% \meta{\Lua{} input} is passed to the \Lua{} interpreter for processing.
+% Each \cs{lua_now:n} block is treated by \Lua{} as a separate chunk.
+% The \Lua{} interpreter executes the \meta{\Lua{} input} immediately,
+% and in an expandable manner.
+% \begin{texnote}
+% \cs{lua_now:e} is a macro wrapper around \tn{directlua}: when
+% \LuaTeX{} is in use two expansions are required to yield the
+% result of the \Lua{} code.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[added = 2018-06-18]{\lua_shipout_e:n, \lua_shipout:n}
+% \begin{syntax}
+% \cs{lua_shipout:n} \Arg{token list}
+% \end{syntax}
+% The \meta{token list} is first tokenized by \TeX{}, which includes
+% converting line ends to spaces in the usual \TeX{} manner and which
+% respects currently-applicable \TeX{} category codes. The resulting
+% \meta{\Lua{} input} is passed to the \Lua{} interpreter when the
+% current page is finalised (\emph{i.e.}~at shipout). Each
+% \cs{lua_shipout:n} block is treated by \Lua{} as a separate chunk.
+% The \Lua{} interpreter will execute the \meta{\Lua{} input} during the
+% page-building routine: no \TeX{} expansion of the \meta{\Lua{} input}
+% will occur at this stage.
+%
+% In the case of the \cs{lua_shipout_e:n} version the input is fully
+% expanded by \TeX{} in an \texttt{e}-type manner during the shipout
+% operation.
+% \begin{texnote}
+% At a \TeX{} level, the \meta{\Lua{} input} is stored as a
+% \enquote{whatsit}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[EXP, added = 2015-06-29]{\lua_escape:n, \lua_escape:e}
+% \begin{syntax}
+% \cs{lua_escape:n} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} such that it can safely be passed to
+% \Lua{}: embedded backslashes, double and single quotes, and newlines
+% and carriage returns are escaped. This is done by prepending an extra
+% token consisting of a backslash with category code~$12$, and for the line
+% endings, converting them to |\n| and |\r|, respectively.
+% \begin{texnote}
+% \cs{lua_escape:e} is a macro wrapper around \tn{luaescapestring}:
+% when \LuaTeX{} is in use two expansions are required to yield the
+% result of the \Lua{} code.
+% \end{texnote}
+% \end{function}
+%
+% \section{Lua interfaces}
+%
+% As well as interfaces for \TeX{}, there are a small number of Lua functions
+% provided here.
+%
+% \begin{function}{l3kernel}
+% All public interfaces provided by the module are stored within the
+% |l3kernel| table.
+% \end{function}
+%
+% \begin{function}{l3kernel.charcat}
+% \begin{syntax}
+% |l3kernel.charcat(|\meta{charcode}, \meta{catcode}|)|
+% \end{syntax}
+% Constructs a character of \meta{charcode} and \meta{catcode} and returns
+% the result to \TeX{}.
+% \end{function}
+%
+% \begin{function}{l3kernel.elapsedtime}
+% \begin{syntax}
+% |l3kernel.elapsedtime()|
+% \end{syntax}
+% Returns the CPU time in \meta{scaled seconds} since the start of the
+% \TeX{} run or since |l3kernel.resettimer| was issued. This only
+% measures the time used by the CPU, not the real time, e.g., waiting
+% for user input.
+% \end{function}
+%
+% \begin{function}{l3kernel.filemdfivesum}
+% \begin{syntax}
+% |l3kernel.filemdfivesum(|\meta{file}|)|
+% \end{syntax}
+% Returns the of the MD5 sum of the file contents read as bytes; note that
+% the result will depend on the nature of the line endings used in the file,
+% in contrast to normal \TeX{} behaviour. If the \meta{file} is not found,
+% nothing is returned with \emph{no error raised}.
+% \end{function}
+%
+% \begin{function}{l3kernel.filemoddate}
+% \begin{syntax}
+% |l3kernel.filemoddate(|\meta{file}|)|
+% \end{syntax}
+% Returns the of the date/time of last modification of the \meta{file} in the
+% format
+% \begin{quote}
+% |D:|\meta{year}\meta{month}\meta{day}\meta{hour}\meta{minute}^^A
+% \meta{second}\meta{offset}
+% \end{quote}
+% where the latter may be |Z| (UTC) or
+% \meta{plus-minus}\meta{hours}|'|\meta{minutes}|'|. If the \meta{file} is
+% not found, nothing is returned with \emph{no error raised}.
+% \end{function}
+%
+% \begin{function}{l3kernel.filesize}
+% \begin{syntax}
+% |l3kernel.filesize(|\meta{file}|)|
+% \end{syntax}
+% Returns the size of the \meta{file} in bytes. If the \meta{file} is not
+% found, nothing is returned with \emph{no error raised}.
+% \end{function}
+%
+% \begin{function}{l3kernel.resettimer}
+% \begin{syntax}
+% |l3kernel.resettimer()|
+% \end{syntax}
+% Resets the timer used by |l3kernel.elapsetime|.
+% \end{function}
+%
+% \begin{function}{l3kernel.strcmp}
+% \begin{syntax}
+% |l3kernel.strcmp(|\meta{str one}, \meta{str two}|)|
+% \end{syntax}
+% Compares the two strings and returns |0| to \TeX{}
+% if the two are identical.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3luatex} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \subsection{Breaking out to \Lua{}}
+%
+% \begin{macrocode}
+%<*tex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=lua>
+% \end{macrocode}
+%
+% \begin{macro}[EXP]{\@@_escape:n, \@@_now:n, \@@_shipout:n}
+% Copies of primitives.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_escape:n \tex_luaescapestring:D
+\cs_new_eq:NN \@@_now:n \tex_directlua:D
+\cs_new_eq:NN \@@_shipout:n \tex_latelua:D
+% \end{macrocode}
+% \end{macro}
+%
+% These functions are set up in \pkg{l3str} for bootstrapping: we want to
+% replace them with a \enquote{proper} version at this stage, so clean up.
+% \begin{macrocode}
+\cs_undefine:N \lua_escape:e
+\cs_undefine:N \lua_now:e
+% \end{macrocode}
+%
+% \begin{macro}[EXP]{\lua_now:n, \lua_now:e}
+% \begin{macro}{\lua_shipout_e:n, \lua_shipout:n}
+% \begin{macro}[EXP]{\lua_escape:n, \lua_escape:e}
+% Wrappers around the primitives. As with engines other than \LuaTeX{}
+% these have to be macros, we give them the same status in all cases.
+% When \LuaTeX{} is not in use, simply give an error message/
+% \begin{macrocode}
+\cs_new:Npn \lua_now:e #1 { \@@_now:n {#1} }
+\cs_new:Npn \lua_now:n #1 { \lua_now:e { \exp_not:n {#1} } }
+\cs_new_protected:Npn \lua_shipout_e:n #1 { \@@_shipout:n {#1} }
+\cs_new_protected:Npn \lua_shipout:n #1
+ { \lua_shipout_e:n { \exp_not:n {#1} } }
+\cs_new:Npn \lua_escape:e #1 { \@@_escape:n {#1} }
+\cs_new:Npn \lua_escape:n #1 { \lua_escape:e { \exp_not:n {#1} } }
+\sys_if_engine_luatex:F
+ {
+ \clist_map_inline:nn
+ {
+ \lua_escape:n , \lua_escape:e ,
+ \lua_now:n , \lua_now:e
+ }
+ {
+ \cs_set:Npn #1 ##1
+ {
+ \__kernel_msg_expandable_error:nnn
+ { kernel } { luatex-required } { #1 }
+ }
+ }
+ \clist_map_inline:nn
+ { \lua_shipout_e:n , \lua_shipout:n }
+ {
+ \cs_set_protected:Npn #1 ##1
+ {
+ \__kernel_msg_error:nnn
+ { kernel } { luatex-required } { #1 }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% \begin{macrocode}
+\__kernel_msg_new:nnnn { kernel } { luatex-required }
+ { LuaTeX~engine~not~in~use!~Ignoring~#1. }
+ {
+ The~feature~you~are~using~is~only~available~
+ with~the~LuaTeX~engine.~LaTeX3~ignored~'#1'.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</tex>
+% \end{macrocode}
+%
+% \subsection{\Lua{} functions for internal use}
+%
+% \begin{macrocode}
+%<*lua>
+% \end{macrocode}
+%
+% Most of the emulation of \pdfTeX{} here is based heavily on Heiko Oberdiek's
+% \pkg{pdftexcmds} package.
+%
+% \begin{macro}{l3kernel}
+% Create a table for the kernel's own use.
+% \begin{macrocode}
+l3kernel = l3kernel or { }
+% \end{macrocode}
+% \end{macro}
+%
+% Local copies of global tables.
+% \begin{macrocode}
+local io = io
+local kpse = kpse
+local lfs = lfs
+local math = math
+local md5 = md5
+local os = os
+local string = string
+local tex = tex
+local unicode = unicode
+% \end{macrocode}
+%
+% Local copies of standard functions.
+% \begin{macrocode}
+local abs = math.abs
+local byte = string.byte
+local floor = math.floor
+local format = string.format
+local gsub = string.gsub
+local lfs_attr = lfs.attributes
+local md5_sum = md5.sum
+local open = io.open
+local os_clock = os.clock
+local os_date = os.date
+local setcatcode = tex.setcatcode
+local sprint = tex.sprint
+local write = tex.write
+% \end{macrocode}
+%
+% Newer Con\TeX{}t releases replace the |unicode| library by |utf|.
+% \begin{macrocode}
+local utf8_char = (utf and utf.char) or unicode.utf8.char
+% \end{macrocode}
+%
+% Deal with Con\TeX{}t: doesn't use |kpse| library.
+% \begin{macrocode}
+local kpse_find = (resolvers and resolvers.findfile) or kpse.find_file
+% \end{macrocode}
+%
+% \begin{macro}[int]{escapehex}
+% An internal auxiliary to convert a string to the matching hex escape.
+% This works on a byte basis: extension to handled UTF-8 input is
+% covered in \pkg{pdftexcmds} but is not currently required here.
+% \begin{macrocode}
+local function escapehex(str)
+ write((gsub(str, ".",
+ function (ch) return format("%02X", byte(ch)) end)))
+end
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.charcat}
+% Creating arbitrary chars needs a category code table. As set up here,
+% one may have been assigned earlier (see \pkg{l3bootstrap}) or a hard-coded
+% one is used. The latter is intended for format mode and should be adjusted
+% to match an eventual allocator.
+% \begin{macrocode}
+local charcat_table = l3kernel.charcat_table or 1
+local function charcat(charcode, catcode)
+ setcatcode(charcat_table, charcode, catcode)
+ sprint(charcat_table, utf8_char(charcode))
+end
+l3kernel.charcat = charcat
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.elapsedtime, l3kernel.resettimer}
+% Simple timing set up: give the result from the system clock in scaled
+% seconds.
+% \begin{macrocode}
+local base_time = 0
+local function elapsedtime()
+ local val = (os_clock() - base_time) * 65536 + 0.5
+ if val > 2147483647 then
+ val = 2147483647
+ end
+ write(format("%d",floor(val)))
+end
+l3kernel.elapsedtime = elapsedtime
+local function resettimer()
+ base_time = os_clock()
+end
+l3kernel.resettimer = resettimer
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.filemdfivesum}
+% Read an entire file and hash it: the hash function itself is a built-in.
+% As Lua is byte-based there is no work needed here in terms of UTF-8
+% (see \pkg{pdftexcmds} and how it handles strings that have passed through
+% \LuaTeX{}). The file is read in binary mode so that no line ending
+% normalisation occurs.
+% \begin{macrocode}
+local function filemdfivesum(name)
+ local file = kpse_find(name, "tex", true)
+ if file then
+ local f = open(file, "rb")
+ if f then
+ local data = f:read("*a")
+ escapehex(md5_sum(data))
+ f:close()
+ end
+ end
+end
+l3kernel.filemdfivesum = filemdfivesum
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.filemoddate}
+% See procedure \texttt{makepdftime} in \texttt{utils.c} of
+% \pdfTeX{}.
+% \begin{macrocode}
+local function filemoddate(name)
+ local file = kpse_find(name, "tex", true)
+ if file then
+ local date = lfs_attr(file, "modification")
+ if date then
+ local d = os_date("*t", date)
+ if d.sec >= 60 then
+ d.sec = 59
+ end
+ local u = os_date("!*t", date)
+ local off = 60 * (d.hour - u.hour) + d.min - u.min
+ if d.year ~= u.year then
+ if d.year > u.year then
+ off = off + 1440
+ else
+ off = off - 1440
+ end
+ elseif d.yday ~= u.yday then
+ if d.yday > u.yday then
+ off = off + 1440
+ else
+ off = off - 1440
+ end
+ end
+ local timezone
+ if off == 0 then
+ timezone = "Z"
+ else
+ local hours = floor(off / 60)
+ local mins = abs(off - hours * 60)
+ timezone = format("%+03d", hours)
+ .. "'" .. format("%02d", mins) .. "'"
+ end
+ write("D:"
+ .. format("%04d", d.year)
+ .. format("%02d", d.month)
+ .. format("%02d", d.day)
+ .. format("%02d", d.hour)
+ .. format("%02d", d.min)
+ .. format("%02d", d.sec)
+ .. timezone)
+ end
+ end
+end
+l3kernel.filemoddate = filemoddate
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.filesize}
+% A simple disk lookup.
+% \begin{macrocode}
+local function filesize(name)
+ local file = kpse_find(name, "tex", true)
+ if file then
+ local size = lfs_attr(file, "size")
+ if size then
+ write(size)
+ end
+ end
+end
+l3kernel.filesize = filesize
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{l3kernel.strcmp}
+% String comparison which gives the same results as \pdfTeX{}'s
+% \tn{pdfstrcmp}, although the ordering should likely not be relied upon!
+% \begin{macrocode}
+local function strcmp(A, B)
+ if A == B then
+ write("0")
+ elseif A < B then
+ write("-1")
+ else
+ write("1")
+ end
+end
+l3kernel.strcmp = strcmp
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Generic \Lua{} and font support}
+%
+% \begin{macrocode}
+%<*initex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=alloc>
+% \end{macrocode}
+%
+% A small amount of generic code is used by almost all \LuaTeX{} material so
+% needs to be loaded by the format.
+% \begin{macrocode}
+attribute_count_name = "g_@@_attribute_int"
+bytecode_count_name = "g_@@_bytecode_int"
+chunkname_count_name = "g_@@_chunkname_int"
+whatsit_count_name = "g_@@_whatsit_int"
+require("ltluatex")
+% \end{macrocode}
+%
+% With the above available the font loader code used by plain \TeX{} and
+% \LaTeXe{} when used with \LuaTeX{} can be loaded here. This is thus being
+% treated more-or-less as part of the engine itself.
+% \begin{macrocode}
+require("luaotfload-main")
+local _void = luaotfload.main()
+% \end{macrocode}
+% \begin{macrocode}
+%</initex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</lua>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+%\end{implementation}
+%
+%\PrintIndex