[latex3-commits] [git/LaTeX3-latex3-latex3] luacmd: Implement file pseudo-primitives (d4143c165)

Marcel Fabian Krüger tex at 2krueger.de
Fri Aug 21 14:53:04 CEST 2020


Repository : https://github.com/latex3/latex3
On branch  : luacmd
Link       : https://github.com/latex3/latex3/commit/d4143c16598666f59839f4f976e20738b171dd73

>---------------------------------------------------------------

commit d4143c16598666f59839f4f976e20738b171dd73
Author: Marcel Fabian Krüger <tex at 2krueger.de>
Date:   Wed Aug 19 08:43:50 2020 +0200

    Implement file pseudo-primitives


>---------------------------------------------------------------

d4143c16598666f59839f4f976e20738b171dd73
 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.