summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3luatex.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3luatex.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3luatex.dtx309
1 files changed, 215 insertions, 94 deletions
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
index b8f00b1187..ca26662658 100644
--- a/macros/latex/contrib/l3kernel/l3luatex.dtx
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-09-06}
+% \date{Released 2020-09-24}
%
% \maketitle
%
@@ -120,9 +120,15 @@
% 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.
+% \begin{function}{ltx.utils}
+% Most public interfaces provided by the module are stored within the
+% |ltx.utils| table.
+% \end{function}
+%
+% \begin{function}[deprecated = 2021-12-31]{l3kernel}
+% For compatibility reasons, there are also some deprecated interfaces provided
+% in the |l3kernel| table. These do not return their result as Lua values but
+% instead print them to \TeX.
% \end{function}
%
% \begin{function}{l3kernel.charcat}
@@ -143,8 +149,9 @@
% for user input.
% \end{function}
%
-% \begin{function}{l3kernel.filedump}
+% \begin{function}{ltx.utils.filedump, l3kernel.filedump}
% \begin{syntax}
+% \meta{dump}| = ltx.utils.filedump(|\meta{file}|,|\meta{offset}|,|\meta{length}|)| \\
% |l3kernel.filedump(|\meta{file}|,|\meta{offset}|,|\meta{length}|)|
% \end{syntax}
% Returns the uppercase hexadecimal representation of the content of the
@@ -154,8 +161,9 @@
% is read starting at the \meta{offset}.
% \end{function}
%
-% \begin{function}{l3kernel.filemdfivesum}
+% \begin{function}{ltx.utils.filemd5sum, l3kernel.filemdfivesum}
% \begin{syntax}
+% \meta{hash}| = ltx.utils.filemd5sum(|\meta{file}|)| \\
% |l3kernel.filemdfivesum(|\meta{file}|)|
% \end{syntax}
% Returns the MD5 sum of the file contents read as bytes; note that
@@ -164,8 +172,9 @@
% nothing is returned with \emph{no error raised}.
% \end{function}
%
-% \begin{function}{l3kernel.filemoddate}
+% \begin{function}{ltx.utils.filemoddate, l3kernel.filemoddate}
% \begin{syntax}
+% \meta{date}| = ltx.utils.filemoddate(|\meta{file}|)| \\
% |l3kernel.filemoddate(|\meta{file}|)|
% \end{syntax}
% Returns the date/time of last modification of the \meta{file} in the
@@ -179,8 +188,9 @@
% not found, nothing is returned with \emph{no error raised}.
% \end{function}
%
-% \begin{function}{l3kernel.filesize}
+% \begin{function}{ltx.utils.filesize, l3kernel.filesize}
% \begin{syntax}
+% |size = ltx.utils.filesize(|\meta{file}|)| \\
% |l3kernel.filesize(|\meta{file}|)|
% \end{syntax}
% Returns the size of the \meta{file} in bytes. If the \meta{file} is not
@@ -313,11 +323,17 @@
% \pkg{pdftexcmds} package.
%
% \begin{macro}{l3kernel}
+% \begin{macro}{ltx.utils}
% Create a table for the kernel's own use.
% \begin{macrocode}
l3kernel = l3kernel or { }
+local l3kernel = l3kernel
+ltx = ltx or {utils={}}
+ltx.utils = ltx.utils or { }
+local ltxutils = ltx.utils
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
% Local copies of global tables.
% \begin{macrocode}
@@ -331,7 +347,6 @@ local string = string
local tex = tex
local texio = texio
local tonumber = tonumber
-local unicode = unicode
% \end{macrocode}
%
% Local copies of standard functions.
@@ -342,23 +357,33 @@ 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 os_exec = os.execute
local setcatcode = tex.setcatcode
local sprint = tex.sprint
local cprint = tex.cprint
local write = tex.write
local write_nl = texio.write_nl
+local utf8_char = utf8.char
+
+local scan_int = token.scan_int or token.scan_integer
+local scan_string = token.scan_string
+local scan_keyword = token.scan_keyword
+local put_next = token.put_next
+
+local true_tok = token.create'prg_return_true:'
+local false_tok = token.create'prg_return_false:'
% \end{macrocode}
%
-% Newer Con\TeX{}t releases replace the |unicode| library by |utf| and
-% since Lua 5.3 we can even use the Lua standard |utf8| library.
% \begin{macrocode}
-local utf8_char = (utf8 and utf8.char) or (utf and utf.char) or unicode.utf8.char
-% \end{macrocode}
+local function deprecated(table, name, func)
+ table[name] = function(...)
+ write_nl(format("Calling deprecated Lua function %s", name))
+ table[name] = func
+ return func(...)
+ end
+end
+% \end{macrocode
%
% Deal with Con\TeX{}t: doesn't use |kpse| library.
% \begin{macrocode}
@@ -371,20 +396,20 @@ local kpse_find = (resolvers and resolvers.findfile) or kpse.find_file
% 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)))
+ return (gsub(str, ".",
+ function (ch) return format("%02X", byte(ch)) end))
end
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{l3kernel.charcat}
% Creating arbitrary chars using |tex.cprint|.
+% The alternative approach using |token.put_next(token.create(...))|
+% would be about 10\% slower.
% \begin{macrocode}
-local charcat
-function charcat(charcode, catcode)
+deprecated(l3kernel, 'charcat', function(charcode, catcode)
cprint(catcode, utf8_char(charcode))
-end
-l3kernel.charcat = charcat
+end)
% \end{macrocode}
% \end{macro}
%
@@ -392,9 +417,10 @@ l3kernel.charcat = charcat
% Simple timing set up: give the result from the system clock in scaled
% seconds.
% \begin{macrocode}
-local base_time = 0
+local os_clock = os.clock
+local base_clock_time = 0
local function elapsedtime()
- local val = (os_clock() - base_time) * 65536 + 0.5
+ local val = (os_clock() - base_clock_time) * 65536 + 0.5
if val > 2147483647 then
val = 2147483647
end
@@ -402,36 +428,56 @@ local function elapsedtime()
end
l3kernel.elapsedtime = elapsedtime
local function resettimer()
- base_time = os_clock()
+ base_clock_time = os_clock()
end
l3kernel.resettimer = resettimer
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{ltx.utils.filedump}
% \begin{macro}{l3kernel.filedump}
% Similar comments here to the next function: read the file in binary mode
% to avoid any line-end weirdness.
% \begin{macrocode}
local function filedump(name,offset,length)
local file = kpse_find(name,"tex",true)
- if file then
- local length = tonumber(length) or lfs_attr(file,"size")
- local offset = tonumber(offset) or 0
- local f = open(file,"rb")
- if f then
- if offset > 0 then
- f:seek("set",offset)
- end
- local data = f:read(length)
- escapehex(data)
- f:close()
- end
+ if not file then return end
+ local f = open(file,"rb")
+ if not f then return end
+ if offset and offset > 0 then
+ f:seek("set", offset)
end
+ local data = f:read(length or 'a')
+ f:close()
+ return escapehex(data)
end
-l3kernel.filedump = filedump
+ltxutils.filedump = filedump
+deprecated(l3kernel, "filedump", function(name, offset, length)
+ local dump = filedump(name, tonumber(offset), tonumber(length))
+ if dump then
+ write(dump)
+ end
+end)
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
+% \begin{macro}{md5.HEX}
+% Hash a string and return the hash in uppercase hexadecimal format.
+% In some engines, this is build-in. For traditional \LuaTeX{}, the conversion
+% to hexadecimal has to be done by us.
+% \begin{macrocode}
+local md5_HEX = md5.HEX
+if not md5_HEX then
+ local md5_sum = md5.sum
+ function md5_HEX(data)
+ return escapehex(md5_sum(data))
+ end
+ md5.HEX = md5_HEX
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.utils.filemd5sum}
% \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
@@ -439,94 +485,129 @@ l3kernel.filedump = filedump
% \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
+local function filemd5sum(name)
+ local file = kpse_find(name, "tex", true) if not file then return end
+ local f = open(file, "rb") if not f then return end
+
+ local data = f:read("*a")
+ f:close()
+ return md5_HEX(data)
end
-l3kernel.filemdfivesum = filemdfivesum
+ltxutils.filemd5sum = filemd5sum
+deprecated(l3kernel, "filemdfivesum", function(name)
+ local hash = filemd5sum(name)
+ if hash then
+ write(hash)
+ end
+end)
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
+% \begin{macro}{ltx.utils.filemoddate}
% \begin{macro}{l3kernel.filemoddate}
+% There are two cases: If the C standard library is C99 compliant,
+% we can use |%z| to get the timezone in almost the right format.
+% We only have to add primes and replace a zero or missing offset
+% with |Z|.
+%
+% Of course this would be boring, so Windows does things differently.
+% There we have to manually calculate the offset.
% 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 filemoddate
+if os_date'%z':match'^[+-]%d%d%d%d$' then
+ local pattern = lpeg.Cs(16 *
+ (lpeg.Cg(lpeg.S'+-' * '0000' * lpeg.Cc'Z')
+ + 3 * lpeg.Cc"'" * 2 * lpeg.Cc"'"
+ + lpeg.Cc'Z')
+ * -1)
+ function filemoddate(name)
+ local file = kpse_find(name, "tex", true)
+ if not file then return end
+ local date = lfs_attr(file, "modification")
+ if not date then return end
+ return pattern:match(os_date("D:%Y%m%d%H%M%S%z", date))
+ end
+else
+ local function filemoddate(name)
+ local file = kpse_find(name, "tex", true)
+ if not file then return end
local date = lfs_attr(file, "modification")
- if date then
- local d = os_date("*t", date)
- if d.sec >= 60 then
- d.sec = 59
+ if not date then return end
+ local d = os_date("*t", date)
+ 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
- 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
+ elseif d.yday ~= u.yday then
+ if d.yday > u.yday then
+ off = off + 1440
+ else
+ off = off - 1440
end
- local timezone
- if off == 0 then
- timezone = "Z"
+ end
+ local timezone
+ if off == 0 then
+ timezone = "Z"
+ else
+ if off < 0 then
+ timezone = "-"
+ off = -off
else
- local hours = floor(off / 60)
- local mins = abs(off - hours * 60)
- timezone = format("%+03d", hours)
- .. "'" .. format("%02d", mins) .. "'"
+ timezone = "+"
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)
+ timezone = format("%s%02d'%02d'", timezone, hours // 60, hours % 60)
end
+ return format("D:%04d%02d%02d%02d%02d%02d%s",
+ d.year, d.month, d.day, d.hour, d.min, d.sec, timezone)
end
end
-l3kernel.filemoddate = filemoddate
+ltxutils.filemoddate = filemoddate
+deprecated(l3kernel, "filemoddate", function(name)
+ local hash = filemoddate(name)
+ if hash then
+ write(hash)
+ end
+end)
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
+% \begin{macro}{ltx.utils.filesize}
% \begin{macro}{l3kernel.filesize}
% A simple disk lookup.
% \begin{macrocode}
local function filesize(name)
- local file = kpse_find(name, "tex", true)
+ local file = kpse_find(name, "tex", true)
if file then
local size = lfs_attr(file, "size")
if size then
- write(size)
+ return size
end
end
end
-l3kernel.filesize = filesize
+ltxutils.filesize = filesize
+deprecated(l3kernel, "filesize", function(name)
+ local size = filesize(name)
+ if size then
+ write(size)
+ end
+end)
% \end{macrocode}
% \end{macro}
+% \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)
+deprecated(l3kernel, "strcmp", function (A, B)
if A == B then
write("0")
elseif A < B then
@@ -534,15 +615,15 @@ local function strcmp(A, B)
else
write("1")
end
-end
-l3kernel.strcmp = strcmp
+end)
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{l3kernel.shellescape}
% Replicating the \pdfTeX{} log interaction for shell escape.
% \begin{macrocode}
-local function shellescape(cmd)
+local os_exec = os.execute
+deprecated(l3kernel, "shellescape", function(cmd)
local status,msg = os_exec(cmd)
if status == nil then
write_nl("log","runsystem(" .. cmd .. ")...(" .. msg .. ")\n")
@@ -551,8 +632,48 @@ local function shellescape(cmd)
else
write_nl("log","runsystem(" .. cmd .. ")...failed " .. (msg or "") .. "\n")
end
+end)
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{luadef}
+% An internal function for defining control sequences form Lua which behave
+% like primitives. This acts as a wrapper around |token.set_lua| which accepts
+% a function instead of an index into the functions table.
+% \begin{macrocode}
+local luacmd do
+ local token_create = token.create
+ local set_lua = token.set_lua
+ local undefined_cs = token.command_id'undefined_cs'
+
+ if not context and not luatexbase then require'ltluatex' end
+ if luatexbase then
+ local new_luafunction = luatexbase.new_luafunction
+ local functions = lua.get_functions_table()
+ function luacmd(name, func, ...)
+ local id
+ local tok = token_create(name)
+ if tok.command == undefined_cs then
+ id = new_luafunction(name)
+ set_lua(name, id, ...)
+ else
+ id = tok.index or tok.mode
+ end
+ functions[id] = func
+ end
+ elseif context then
+ local register = context.functions.register
+ local functions = context.functions.known
+ function luacmd(name, func, ...)
+ local tok = token.create(name)
+ if tok.command == undefined_cs then
+ token.set_lua(name, register(func), ...)
+ else
+ functions[tok.index or tok.mode] = func
+ end
+ end
+ end
end
-l3kernel.shellescape = shellescape
% \end{macrocode}
% \end{macro}
%