[latex3-commits] [git/LaTeX3-latex3-latex3] luacmd: Implement file pseudo-primitives (a4272f4ae)
Marcel Fabian Krüger
tex at 2krueger.de
Fri Aug 21 15:43:58 CEST 2020
Repository : https://github.com/latex3/latex3
On branch : luacmd
Link : https://github.com/latex3/latex3/commit/a4272f4aec531a9dfe45bc8532cd0eaf21b34c25
>---------------------------------------------------------------
commit a4272f4aec531a9dfe45bc8532cd0eaf21b34c25
Author: Marcel Fabian Krüger <tex at 2krueger.de>
Date: Wed Aug 19 08:43:50 2020 +0200
Implement file pseudo-primitives
>---------------------------------------------------------------
a4272f4aec531a9dfe45bc8532cd0eaf21b34c25
l3kernel/l3file.dtx | 76 +++--------------------
l3kernel/l3luatex.dtx | 164 +++++++++++++++++++++++++++++++++++---------------
l3kernel/l3names.dtx | 62 +++++++++++++++++--
3 files changed, 180 insertions(+), 122 deletions(-)
diff --git a/l3kernel/l3file.dtx b/l3kernel/l3file.dtx
index 429fe9d96..491d27a34 100644
--- a/l3kernel/l3file.dtx
+++ b/l3kernel/l3file.dtx
@@ -2636,18 +2636,9 @@
% \end{macro}
%
% \begin{macro}{\@@_size:n}
-% A copy of the primitive where it's available, or the \LuaTeX{}
-% equivalent if relevant.
+% A copy of the primitive where it's available.
% \begin{macrocode}
\cs_new_eq:NN \@@_size:n \tex_filesize:D
-\sys_if_engine_luatex:T
- {
- \cs_gset:Npn \@@_size:n #1
- {
- \lua_now:e
- { l3kernel.filesize ( " \lua_escape:e {#1} " ) }
- }
- }
% \end{macrocode}
% \end{macro}
%
@@ -2753,9 +2744,7 @@
% \end{macrocode}
% Deal with the fact that the primitive might not be available.
% \begin{macrocode}
-\bool_lazy_or:nnF
- { \cs_if_exist_p:N \tex_filesize:D }
- { \sys_if_engine_luatex_p: }
+\cs_if_exist:NF \tex_filesize:D
{
\cs_gset:Npn \file_full_name:n #1
{
@@ -2817,9 +2806,7 @@
% existence of the file with |.tex| extension in that directory, and
% if it exists we include the |.tex| extension in the result.
% \begin{macrocode}
-\bool_lazy_or:nnF
- { \cs_if_exist_p:N \tex_filesize:D }
- { \sys_if_engine_luatex_p: }
+\cs_if_exist:NF \tex_filesize:D
{
\prg_set_protected_conditional:Npnn \file_get_full_name:nN #1#2 { T , F , TF }
{
@@ -2882,8 +2869,6 @@
% As the MD5 function has a slightly different syntax from the other commands,
% there is a little cleaning up to do.
% \begin{macrocode}
-\cs_new:Npn \file_mdfive_hash:n #1
- { \@@_details:nn {#1} { mdfivesum } }
\cs_new:Npn \file_size:n #1
{ \@@_details:nn {#1} { size } }
\cs_new:Npn \file_timestamp:n #1
@@ -2898,20 +2883,10 @@
\tl_if_blank:nF {#1}
{ \use:c { tex_file #2 :D } {#1} }
}
-\sys_if_engine_luatex:TF
- {
- \cs_gset:Npn \@@_details_aux:nn #1#2
- {
- \lua_now:e
- { l3kernel.file#2 ( " \lua_escape:e { #1 } " ) }
- }
- }
- {
- \cs_gset:Npn \file_mdfive_hash:n #1
- { \exp_args:Ne \@@_mdfive_hash:n { \file_full_name:n {#1} } }
- \cs_new:Npn \@@_mdfive_hash:n #1
- { \tex_mdfivesum:D file {#1} }
- }
+\cs_new:Npn \file_mdfive_hash:n #1
+ { \exp_args:Ne \@@_mdfive_hash:n { \file_full_name:n {#1} } }
+\cs_new:Npn \@@_mdfive_hash:n #1
+ { \tex_mdfivesum:D file {#1} }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2973,21 +2948,6 @@
length ~ \int_eval:n { #1 - #2 + 1 }
{#3}
}
-\sys_if_engine_luatex:T
- {
- \cs_gset:Npn \@@_hex_dump_auxiv:nnn #1#2#3
- {
- \lua_now:e
- {
- l3kernel.filedump
- (
- " \lua_escape:e {#3} " ,
- \int_eval:n { #2 - 1 } ,
- \int_eval:n { #1 - #2 + 1 }
- )
- }
- }
- }
\cs_new:Npn \file_hex_dump:n #1
{ \exp_args:Ne \@@_hex_dump:n { \file_full_name:n {#1} } }
\cs_new:Npn \@@_hex_dump:n #1
@@ -2995,14 +2955,6 @@
\tl_if_blank:nF {#1}
{ \tex_filedump:D length \tex_filesize:D {#1} {#1} }
}
-\sys_if_engine_luatex:T
- {
- \cs_gset:Npn \@@_hex_dump:n #1
- {
- \lua_now:e
- { l3kernel.filedump ( " \lua_escape:e { #1 } " ) }
- }
- }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -3048,9 +3000,7 @@
% Where the primitive is not available, issue an error: this is a little
% more conservative than absolutely needed, but does work.
% \begin{macrocode}
-\bool_lazy_or:nnF
- { \cs_if_exist_p:N \tex_filesize:D }
- { \sys_if_engine_luatex_p: }
+\cs_if_exist:NF \tex_filesize:D
{
\cs_set_protected:Npn \@@_get_details:nnN #1#2#3
{
@@ -3148,15 +3098,7 @@
}
}
}
-\sys_if_engine_luatex:TF
- {
- \cs_new:Npn \@@_timestamp:n #1
- {
- \lua_now:e
- { l3kernel.filemoddate ( " \lua_escape:e {#1} " ) }
- }
- }
- { \cs_new_eq:NN \@@_timestamp:n \tex_filemoddate:D }
+\cs_new_eq:NN \@@_timestamp:n \tex_filemoddate:D
\cs_if_exist:NF \@@_timestamp:n
{
\prg_set_conditional:Npnn \file_compare_timestamp:nNn #1#2#3
diff --git a/l3kernel/l3luatex.dtx b/l3kernel/l3luatex.dtx
index 7f9bcc825..3b96f0c09 100644
--- a/l3kernel/l3luatex.dtx
+++ b/l3kernel/l3luatex.dtx
@@ -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}{ltxutils}
+% Most public interfaces provided by the module are stored within the
+% |ltxutils| table.
+% \end{function}
+%
+% \begin{function}[dep]{l3kernel}
+% For compatibility reasons, there are also some 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}[dep]{l3kernel.charcat}
@@ -143,7 +149,11 @@
% for user input.
% \end{function}
%
-% \begin{function}{l3kernel.filedump}
+% \begin{function}{ltxutils.filedump}
+% \begin{function}[dep]{l3kernel.filedump}
+% \begin{syntax}
+% \meta{dump}| = ltxutils.filedump(|\meta{file}|,|\meta{offset}|,|\meta{length}|)|
+% \end{syntax}
% \begin{syntax}
% |l3kernel.filedump(|\meta{file}|,|\meta{offset}|,|\meta{length}|)|
% \end{syntax}
@@ -154,7 +164,11 @@
% is read starting at the \meta{offset}.
% \end{function}
%
-% \begin{function}{l3kernel.filemdfivesum}
+% \begin{function}{ltxutils.filemd5sum}
+% \begin{function}[dep]{l3kernel.filemdfivesum}
+% \begin{syntax}
+% \meta{hash}| = ltxutils.filemd5sum(|\meta{file}|)|
+% \end{syntax}
% \begin{syntax}
% |l3kernel.filemdfivesum(|\meta{file}|)|
% \end{syntax}
@@ -163,8 +177,13 @@
% in contrast to normal \TeX{} behaviour. If the \meta{file} is not found,
% nothing is returned with \emph{no error raised}.
% \end{function}
+% \end{function}
%
-% \begin{function}{l3kernel.filemoddate}
+% \begin{function}{ltxutils.filemoddate}
+% \begin{function}[dep]{l3kernel.filemoddate}
+% \begin{syntax}
+% \meta{date}| = ltxutils.filemoddate(|\meta{file}|)|
+% \end{syntax}
% \begin{syntax}
% |l3kernel.filemoddate(|\meta{file}|)|
% \end{syntax}
@@ -179,13 +198,18 @@
% not found, nothing is returned with \emph{no error raised}.
% \end{function}
%
-% \begin{function}{l3kernel.filesize}
+% \begin{function}{ltxutils.filesize}
+% \begin{function}[dep]{l3kernel.filesize}
+% \begin{syntax}
+% |size = ltxutils.filesize(|\meta{file}|)|
+% \end{syntax}
% \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}
+% \end{function}
%
% \begin{function}{l3kernel.resettimer}
% \begin{syntax}
@@ -313,14 +337,16 @@
% \pkg{pdftexcmds} package.
%
% \begin{macro}{l3kernel}
+% \begin{macro}{ltxutils}
% Create a table for the kernel's own use.
% \begin{macrocode}
l3kernel = l3kernel or { }
local l3kernel = l3kernel
-ltxutil = ltxutil or { }
-local l3kernel = l3kernel
+ltxutils = ltxutils or { }
+local ltxutils = ltxutils
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
% Local copies of global tables.
% \begin{macrocode}
@@ -345,7 +371,6 @@ 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
@@ -355,15 +380,17 @@ local sprint = tex.sprint
local cprint = tex.cprint
local write = tex.write
local write_nl = texio.write_nl
-local scan_int = token.scan_int or token.scan_integer
-local scan_string= token.scan_string
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
% \end{macrocode}
%
% \begin{macrocode}
local function deprecated(table, name, func)
table[name] = function(...)
- write_nl("Calling deprecated Lua function %s", name)
+ write_nl(format("Calling deprecated Lua function %s", name))
table[name] = func
return func(...)
end
@@ -381,8 +408,8 @@ 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}
@@ -418,58 +445,81 @@ l3kernel.resettimer = resettimer
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{l3kernel.filedump}
+% \begin{macro}{ltxutils.filedump}
+% \begin{macro}[dep]{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}{l3kernel.filemdfivesum}
+% \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}{ltxutils.filemd5sum}
+% \begin{macro}[dep]{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
+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}
%
-% \begin{macro}{l3kernel.filemoddate}
+% \begin{macro}[dep]{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)
+ local file = kpse_find(name, "tex", true)
if file then
local date = lfs_attr(file, "modification")
if date then
@@ -501,36 +551,50 @@ local function filemoddate(name)
timezone = format("%+03d", hours)
.. "'" .. format("%02d", mins) .. "'"
end
- write("D:"
+ return "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
end
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}
%
-% \begin{macro}{l3kernel.filesize}
+% \begin{macro}{ltxutils.filesize}
+% \begin{macro}[dep]{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}[dep]{l3kernel.strcmp}
% String comparison which gives the same results as \pdfTeX{}'s
diff --git a/l3kernel/l3names.dtx b/l3kernel/l3names.dtx
index 5da288e93..3ed1565f6 100644
--- a/l3kernel/l3names.dtx
+++ b/l3kernel/l3names.dtx
@@ -615,9 +615,6 @@
\@@_primitive:NN \pdfeachlinedepth \tex_eachlinedepth:D
\@@_primitive:NN \pdfeachlineheight \tex_eachlineheight:D
\@@_primitive:NN \pdfelapsedtime \tex_elapsedtime:D
- \@@_primitive:NN \pdffiledump \tex_filedump:D
- \@@_primitive:NN \pdffilemoddate \tex_filemoddate:D
- \@@_primitive:NN \pdffilesize \tex_filesize:D
\@@_primitive:NN \pdffirstlineheight \tex_firstlineheight:D
\@@_primitive:NN \pdffontexpand \tex_fontexpand:D
\@@_primitive:NN \pdffontsize \tex_fontsize:D
@@ -628,7 +625,6 @@
\@@_primitive:NN \pdflastypos \tex_lastypos:D
\@@_primitive:NN \pdfmapfile \tex_mapfile:D
\@@_primitive:NN \pdfmapline \tex_mapline:D
- \@@_primitive:NN \pdfmdfivesum \tex_mdfivesum:D
\@@_primitive:NN \pdfnoligatures \tex_noligatures:D
\@@_primitive:NN \pdfnormaldeviate \tex_normaldeviate:D
\@@_primitive:NN \pdfpageheight \tex_pageheight:D
@@ -687,9 +683,14 @@
%<*names|package>
% \end{macrocode}
% Some \pdfTeX{} primitives are handled here because they got dropped in
-% \LuaTeX{} but can be emulated there.
+% \LuaTeX{} but are emulated later. The Lua code is already loaded at this point,
+% so we shouldn't overwrite them.
% \begin{macrocode}
\@@_primitive:NN \pdfstrcmp \tex_strcmp:D
+ \@@_primitive:NN \pdffilesize \tex_filesize:D
+ \@@_primitive:NN \pdfmdfivesum \tex_mdfivesum:D
+ \@@_primitive:NN \pdffilemoddate \tex_filemoddate:D
+ \@@_primitive:NN \pdffiledump \tex_filedump:D
% \end{macrocode}
% \XeTeX{}-specific primitives. Note that \XeTeX{}'s \tn{strcmp} is
% handled earlier and is \enquote{rolled up} into \tn{pdfstrcmp}.
@@ -1481,6 +1482,57 @@ end, 'global')
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\tex_filesize:D}
+% Wrap the function from |ltxutils|.
+% \begin{macrocode}
+luacmd('tex_filesize:D', function()
+ local size = filesize(scan_string())
+ if size then write(size) end
+end, 'global')
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tex_mdfivesum:D}
+% There are two cases: Either hash a file or a string.
+% Both are already implemented in l3luatex or built-in.
+% \begin{macrocode}
+luacmd('tex_mdfivesum:D', function()
+ local hash
+ if scan_keyword"file" then
+ hash = filemd5sum(scan_string())
+ else
+ hash = md5_HEX(scan_string())
+ end
+ if hash then write(hash) end
+end, 'global')
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tex_filemoddate:D}
+% A primitive for getting the modification date of a file.
+% \begin{macrocode}
+luacmd('tex_filemoddate:D', function()
+ local date = filemoddate(scan_string())
+ if date then write(date) end
+end, 'global')
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tex_filedump:D}
+% An emulated primitive for getting a hexdump from a (partial) file.
+% The length has a default of |0|. This is consistent with
+% \pdfTeX, but it effectivly makes the primitive useless without an
+% explicit |length|.
+% \begin{macrocode}
+luacmd('tex_filedump:D', function()
+ local offset = scan_keyword'offset' and scan_int() or nil
+ local length = scan_keyword'length' and scan_int() or 0
+ local data = filedump(scan_string(), offset, length)
+ if data then write(data) end
+end, 'global')
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%</lua>
% \end{macrocode}
More information about the latex3-commits
mailing list.