summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2024-03-17 22:25:42 +0000
committerKarl Berry <karl@freefriends.org>2024-03-17 22:25:42 +0000
commitea67c4bf07925652f3079c63f6f6625cc2f1ed68 (patch)
tree80eb9dd2b81020829279ffa7479addedd6c74524
parent634e0f5dd8edba941dbfa19f2483fde313b4a641 (diff)
l3sys-query new script, included in shell_escape_commands
git-svn-id: svn://tug.org/texlive/trunk@70681 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Build/source/texk/kpathsea/ChangeLog5
-rw-r--r--Build/source/texk/kpathsea/texmf.cnf1
-rw-r--r--Build/source/texk/texlive/linked_scripts/Makefile.am1
-rw-r--r--Build/source/texk/texlive/linked_scripts/Makefile.in1
-rwxr-xr-xBuild/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua569
-rw-r--r--Build/source/texk/texlive/linked_scripts/scripts.lst1
l---------Master/bin/aarch64-linux/l3sys-query1
l---------Master/bin/amd64-freebsd/l3sys-query1
l---------Master/bin/amd64-netbsd/l3sys-query1
l---------Master/bin/armhf-linux/l3sys-query1
l---------Master/bin/i386-freebsd/l3sys-query1
l---------Master/bin/i386-linux/l3sys-query1
l---------Master/bin/i386-netbsd/l3sys-query1
l---------Master/bin/i386-solaris/l3sys-query1
l---------Master/bin/universal-darwin/l3sys-query1
-rwxr-xr-xMaster/bin/windows/l3sys-query.exebin0 -> 6144 bytes
l---------Master/bin/x86_64-cygwin/l3sys-query1
l---------Master/bin/x86_64-darwinlegacy/l3sys-query1
l---------Master/bin/x86_64-linux/l3sys-query1
l---------Master/bin/x86_64-linuxmusl/l3sys-query1
l---------Master/bin/x86_64-solaris/l3sys-query1
-rw-r--r--Master/texmf-dist/doc/man/man1/l3sys-query.116
-rw-r--r--Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdfbin0 -> 11905 bytes
-rw-r--r--Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md25
-rw-r--r--Master/texmf-dist/doc/support/l3sys-query/README.md36
-rw-r--r--Master/texmf-dist/doc/support/l3sys-query/SECURITY.md17
-rw-r--r--Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdfbin0 -> 374018 bytes
-rw-r--r--Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex264
-rwxr-xr-xMaster/texmf-dist/scripts/l3sys-query/l3sys-query.lua569
-rw-r--r--Master/texmf-dist/web2c/texmf.cnf1
-rwxr-xr-xMaster/tlpkg/bin/tl-update-asy3
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/doc/releng.txt5
-rwxr-xr-xMaster/tlpkg/libexec/ctan2tds2
-rw-r--r--Master/tlpkg/tlpsrc/collection-binextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/l3sys-query.tlpsrc4
36 files changed, 1535 insertions, 2 deletions
diff --git a/Build/source/texk/kpathsea/ChangeLog b/Build/source/texk/kpathsea/ChangeLog
index 61602772f0e..68be0ec6891 100644
--- a/Build/source/texk/kpathsea/ChangeLog
+++ b/Build/source/texk/kpathsea/ChangeLog
@@ -1,3 +1,8 @@
+2024-03-17 Karl Berry <karl@tug.org>
+
+ * texmf.cnf (shell_escape_commands): add l3sys-query
+ after analysis on tex-live. https://ctan.org/pkg/l3sys-query
+
2024-03-10 Karl Berry <karl@tug.org>
* TL'24 release.
diff --git a/Build/source/texk/kpathsea/texmf.cnf b/Build/source/texk/kpathsea/texmf.cnf
index 4cb01e45b15..a3fa528268b 100644
--- a/Build/source/texk/kpathsea/texmf.cnf
+++ b/Build/source/texk/kpathsea/texmf.cnf
@@ -652,6 +652,7 @@ bibtex,bibtex8,\
extractbb,\
gregorio,\
kpsewhich,\
+l3sys-query,\
makeindex,\
memoize-extract.pl,\
memoize-extract.py,\
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am
index d59131d316f..e6645224af8 100644
--- a/Build/source/texk/texlive/linked_scripts/Makefile.am
+++ b/Build/source/texk/texlive/linked_scripts/Makefile.am
@@ -162,6 +162,7 @@ texmf_other_scripts = \
kotex-utils/komkindex.pl \
kotex-utils/ttf2kotexfont.pl \
l3build/l3build.lua \
+ l3sys-query/l3sys-query.lua \
latex-git-log/latex-git-log \
latex-papersize/latex-papersize.py \
latex2man/latex2man \
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in
index 5d643ccb129..fe85e5e3e29 100644
--- a/Build/source/texk/texlive/linked_scripts/Makefile.in
+++ b/Build/source/texk/texlive/linked_scripts/Makefile.in
@@ -379,6 +379,7 @@ texmf_other_scripts = \
kotex-utils/komkindex.pl \
kotex-utils/ttf2kotexfont.pl \
l3build/l3build.lua \
+ l3sys-query/l3sys-query.lua \
latex-git-log/latex-git-log \
latex-papersize/latex-papersize.py \
latex2man/latex2man \
diff --git a/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua b/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua
new file mode 100755
index 00000000000..03e86296af4
--- /dev/null
+++ b/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua
@@ -0,0 +1,569 @@
+#!/usr/bin/env texlua
+
+--[[
+
+File l3sys-query.lua Copyright (C) 2024 The LaTeX Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/l3sys-query
+
+for those people who are interested.
+
+--]]
+
+--
+-- Details of the script itself, etc.
+--
+local copyright = "Copyright (C) 2024 The LaTeX Project"
+local release_date = "2024-03-15"
+local script_desc = "System queries for LaTeX using Lua\n"
+local script_name = "l3sys-query"
+
+--
+-- Setup for the CLI: commands and options
+--
+local cmd_impl = {}
+local cmd_desc = {}
+
+local option_list =
+ {
+ exclude =
+ {
+ cmds = {"ls"},
+ desc = "Exclude entries from directory listing",
+ type = "string"
+ },
+ ["ignore-case"] =
+ {
+ cmds = {"ls"},
+ desc = "Ignore case when sorting directory listing",
+ type = "boolean"
+ },
+ help =
+ {
+ desc = "Prints this message and exits",
+ short = "h",
+ type = "boolean"
+ },
+ pattern =
+ {
+ cmds = {"ls"},
+ desc = "Treat (x)args as a Lua pattern",
+ short = "p",
+ type = "boolean"
+ },
+ recursive =
+ {
+ cmds = {"ls"},
+ desc = "Activates recursive directory listing",
+ short = "r",
+ type = "boolean"
+ },
+ reverse =
+ {
+ cmds = {"ls"},
+ desc = "Reversing sorting order",
+ type = "boolean"
+ },
+ sort =
+ {
+ cmds = {"ls"},
+ desc = "Method used to sort directory listing",
+ type = "string"
+ },
+ type =
+ {
+ cmds = {"ls"},
+ desc = "Selects the type of entry in a directory listing",
+ type = "string"
+ },
+ version =
+ {
+ desc = "Prints version information and exits",
+ short = "v",
+ type = "boolean"
+ }
+ }
+
+--
+-- Local copies of globals used here
+--
+local io = io
+local stderr = io.stderr
+
+local lfs = lfs
+local attributes = lfs.attributes
+local currentdir = lfs.currentdir
+local dir = lfs.dir
+
+local os = os
+local exit = os.exit
+
+local string = string
+local find = string.find
+local gmatch = string.gmatch
+local lower = string.lower
+local match = string.match
+local rep = string.rep
+local sub = string.sub
+
+local table = table
+local concat = table.concat
+local insert = table.insert
+local sort = table.sort
+
+--
+-- Support functions and data
+--
+
+-- Remove '...' around an entire text:
+-- we need this to support restricted shell escape on Windows
+local function dequote(text)
+ if (match(text,"^'") and match(text,"'$")) then
+ return sub(text,2,-2)
+ end
+ return text
+end
+
+
+-- A short auxiliary used whever the script bails out
+local function info_and_quit(s)
+ stderr:write("\n" .. s .. "\nTry '" .. script_name .. " --help' for more information.\n")
+ exit(1)
+end
+
+-- Convert a file glob into a pattern for use by e.g. string.gub
+-- Based on https://github.com/davidm/lua-glob-pattern
+-- Simplified substantially: "[...]" syntax not supported as is not
+-- required by the file patterns used by the team. Also note style
+-- changes to match coding approach in rest of this file.
+--
+-- License for original globtopattern
+--[[
+
+ (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
+
+--]]
+local function glob_to_pattern(glob,skip_convert)
+ if skip_convert then
+ return glob
+ end
+
+ local pattern = "^" -- pattern being built
+ local i = 0 -- index in glob
+ local char -- char at index i in glob
+
+ -- escape pattern char
+ local function escape(char)
+ return match(char,"^%w$") and char or "%" .. char
+ end
+
+ -- Convert tokens.
+ while true do
+ i = i + 1
+ char = sub(glob,i,i)
+ if char == "" then
+ pattern = pattern .. "$"
+ break
+ elseif char == "?" then
+ pattern = pattern .. "."
+ elseif char == "*" then
+ pattern = pattern .. ".*"
+ elseif char == "[" then -- ]
+ -- Ignored
+ info_and_quit("[...] syntax not supported in globs!")
+ elseif char == "\\" then
+ i = i + 1
+ char = sub(glob,i,i)
+ if char == "" then
+ pattern = pattern .. "\\$"
+ break
+ end
+ pattern = pattern .. escape(char)
+ else
+ pattern = pattern .. escape(char)
+ end
+ end
+ return pattern
+end
+
+
+-- Initial data for the command line parser
+local cmd = ""
+local options = {}
+local arg_list = ""
+
+local function parse_args()
+ -- Turn long/short options into two lookup tables
+ local long_options = {}
+ local short_options = {}
+ for k,v in pairs(option_list) do
+ if v.short then
+ short_options[v.short] = k
+ end
+ long_options[k] = k
+ end
+
+ -- Minor speed-up
+ local arg = arg
+
+ -- arg[1] is a special case: must be a command or a very limited
+ -- subset (--help|-h or --version|-v)
+ local a = arg[1]
+ if a then
+ -- No options are allowed in position 1, so filter those out
+ if a == "--version" or a == "-v" then
+ cmd = "version"
+ elseif not match(a,"^%-") then
+ cmd = a
+ end
+ end
+
+ -- Stop here if help or version is required
+ if cmd == "help" or cmd == "version" then
+ return
+ end
+
+ -- An auxiliary to grab all file names into a string:
+ -- this reflects the fact that the use case for l3sys-query doesn't
+ -- allow quoting spaces
+ local function tidy(num)
+ local t = {}
+ for i = num,#arg do
+ insert(t,dequote(arg[i]))
+ end
+ return concat(t," ")
+ end
+
+ -- Examine all other arguments
+ -- Use a while loop rather than for as this makes it easier
+ -- to grab arg for optionals where appropriate
+ local i = 2
+ while i <= #arg do
+ local a = arg[i]
+ -- Terminate search for options
+ if a == "--" then
+ arg_list = tidy(i + 1)
+ return
+ end
+
+ -- Look for optionals
+ local opt
+ local optarg
+ local opts
+ -- Look for and option and get it into a variable
+ if match(a,"^%-") then
+ if match(a,"^%-%-") then
+ opts = long_options
+ local pos = find(a,"=")
+ if pos then
+ opt = sub(a,3,pos - 1)
+ optarg = sub(a,pos + 1)
+ else
+ opt = sub(a,3)
+ end
+ else
+ opts = short_options
+ opt = sub(a,2,2)
+ -- Only set optarg if it is there
+ if #a > 2 then
+ optarg = sub(a,3)
+ end
+ end
+
+ -- Now check that the option is valid and sort out the argument
+ -- if required
+ local optname = opts[opt]
+ if optname then
+ -- Tidy up arguments
+ if option_list[optname].type == "boolean" then
+ if optarg then
+ local opt = "-" .. (match(a,"^%-%-") and "-" or "") .. opt
+ info_and_quit("Value not allowed for option " .. opt)
+ end
+ else
+ if not optarg then
+ optarg = arg[i + 1]
+ if not optarg then
+ info_and_quit("Missing value for option " .. a)
+ end
+ i = i + 1
+ end
+ end
+ else
+ info_and_quit("Unknown option " .. a)
+ end
+
+ -- Store the result
+ if optarg then
+ if option_list[optname].type == "string" then
+ options[optname] = optarg
+ else
+ local opts = options[optname] or {}
+ for hit in gmatch(optarg,"([^,%s]+)") do
+ insert(opts,hit)
+ end
+ options[optname] = opts
+ end
+ else
+ options[optname] = true
+ end
+ i = i + 1
+ end
+
+ -- Collect up the remaining arguments
+ if not opt then
+ arg_list = tidy(i)
+ break
+ end
+ end
+end
+
+parse_args()
+
+--
+-- The help functions: local only and hard-coded
+--
+
+local function help()
+ -- Find the longest entry to pad
+ local function format_list(list)
+ local longest = 0
+ for k,_ in pairs(list) do
+ if k:len() > longest then
+ longest = k:len()
+ end
+ end
+ -- Sort the list
+ local t = {}
+ for k,_ in pairs(list) do
+ insert(t,k)
+ end
+ sort(t)
+ return t,longest
+ end
+
+ -- 'Header' of fixed info
+ print("Usage: " .. script_name .. " <cmd> [<options>] [<args>]\n")
+ print("Valid <cmd>s are:")
+
+ -- Sort the commands, pad the descriptions, print
+ local t,longest = format_list(cmd_desc)
+ for _,k in ipairs(t) do
+ local cmd = cmd_desc[k]
+ local filler = rep(" ",longest - k:len() + 1)
+ print(" " .. k .. filler .. cmd)
+ end
+
+ -- Same for the options
+ print("\nValid <options> are:")
+ t,longest = format_list(option_list)
+ for _,name in ipairs(t) do
+ local opt = option_list[name]
+ local filler = rep(" ",longest - name:len() + 1)
+ if opt.desc then
+ if opt.short then
+ print(" --" .. name .. "|-" .. opt.short .. filler .. opt.desc)
+ else
+ print(" --" .. name .. " " .. filler .. opt.desc)
+ end
+ end
+ end
+
+ -- Postamble
+ print("\nFull manual available via 'texdoc " .. script_name .. "'.\n")
+ print("Repository : https://github.com/latex3/" .. script_name)
+ print("Bug tracker: https://github.com/latex3/" .. script_name .. "/issues")
+ print("\n" .. copyright)
+end
+
+local function version()
+ print(script_name .. " " .. release_date)
+end
+
+--
+-- The functions for commands: all held in the table cmd_impl
+-- with docstrings in the table cmd_desc.
+--
+
+-- The aim here is to convert a user file specification (if given) into a
+-- Lua pattern, and then to do a listing.
+cmd_desc.ls = "Prints a listing based on the <args> and <options>"
+function cmd_impl.ls(arg_list)
+ if not arg_list or arg_list == "" or arg_list == "." then
+ arg_list = "*"
+ end
+ -- Look for absolute paths or any trying to leave the confines of the current
+ -- directory: this is not supported.
+ if match(arg_list,"%.%.") or
+ match(arg_list,"^/") or
+ match(arg_list,"^\\") or
+ match(arg_list,"[a-zA-Z]:") then
+ return
+ end
+ -- Tidy up and convert to a pattern.
+ path,glob = match(arg_list,"^(.*)/([^/]*)$")
+ if not path then
+ path = "."
+ glob = arg_list
+ end
+ if path == "" then
+ path = "."
+ end
+ if not match(path,"^%.") then
+ path = "./" .. path
+ end
+ local conv_pattern = options.pattern
+ local pattern = glob_to_pattern(glob,conv_pattern)
+ local exclude_pattern
+ if options.exclude then
+ local exclude = dequote(options.exclude)
+ exclude_pattern = glob_to_pattern(exclude,conv_pattern)
+ end
+ -- A lookup table for attributes: map between lfs- and Unix-type naming
+ local attrib_map = {d = "directory", f = "file"}
+
+ -- A bit of setup to store the sorting data as well as the entry itself
+ local i = 0 -- If no sorting active, just track the order from lfs
+ local entries = {}
+ local sort_mode = options.sort or "none"
+ local function store(entry,full_entry)
+ if not match(entry,pattern)
+ or (exclude_pattern and match(entry,exclude_pattern)) then
+ return
+ end
+ i = i + 1
+ local key = i
+ if sort_mode == "date" then
+ key = attributes(full_entry,"modification")
+ elseif sort_mode == "name" then
+ key = full_entry
+ end
+ entries[key] = full_entry
+ end
+
+ -- Build a table of entries, excluding "." and "..", and return as a string
+ -- with one entry per line.
+ local opt = options.type
+ local is_rec = options.recursive
+ local function browse(path)
+ for entry in dir(path) do
+ if entry ~= "." and entry ~= ".." and not match(entry,"^%.") then
+ local full_entry = path .. "/" .. entry
+ local ft = attributes(full_entry,"mode")
+ if not opt or ft == attrib_map[opt] then
+ store(entry,full_entry)
+ end
+ if is_rec and ft == "directory" then
+ browse(full_entry)
+ end
+ end
+ end
+ end
+ -- Start a search at the top level
+ browse(path)
+
+ -- Extract keys and sort
+ local s = {}
+ for k,_ in pairs(entries) do
+ insert(s,k)
+ end
+
+ -- Setup for case-insensitve sorting
+ local function case(s)
+ return s
+ end
+ if options["ignore-case"] then
+ function case(s)
+ return lower(s)
+ end
+ end
+
+ if options.reverse then
+ sort(s,function(a,b) return case(a) > case(b) end)
+ else
+ sort(s,function(a,b) return case(a) < case(b) end)
+ end
+
+ local result = {}
+ for _,v in ipairs(s) do
+ insert(result,entries[v])
+ end
+
+ return concat(result,"\n")
+end
+
+-- A simple rename
+cmd_desc.pwd = "Prints the present working directory"
+function cmd_impl.pwd()
+ return currentdir()
+end
+
+--
+-- Execute the given command
+--
+
+-- Only 'known' commands do anything at all
+if cmd == "version" then
+ version()
+ exit(0)
+elseif not cmd_impl[cmd] then
+ if cmd == "" then
+ help()
+ else
+ info_and_quit(script_name .. ": '" .. cmd .. "' is not a " .. script_name ..
+ " command.")
+ end
+ exit(1)
+end
+
+-- Check options are valid for cmd
+for k,_ in pairs(options) do
+ local cmds = option_list[k].cmds
+ if not cmds then
+ -- Should not be possible:
+ -- everything except --help and --version should have an entry
+ print("Internal error")
+ exit(1)
+ else
+ -- Make a lookup table
+ local t = {}
+ for _,v in pairs(cmds) do
+ t[v] = true
+ end
+ if not t[cmd] then
+ info_and_quit(script_name .. ": Option '" .. k ..
+ "' does not apply to '" .. cmd .. "'")
+ end
+ end
+end
+
+local result = cmd_impl[cmd](arg_list)
+
+if result then
+ print(result)
+ exit(0)
+else
+ exit(1)
+end
diff --git a/Build/source/texk/texlive/linked_scripts/scripts.lst b/Build/source/texk/texlive/linked_scripts/scripts.lst
index efa9be90b7c..12fa2241416 100644
--- a/Build/source/texk/texlive/linked_scripts/scripts.lst
+++ b/Build/source/texk/texlive/linked_scripts/scripts.lst
@@ -103,6 +103,7 @@ kotex-utils/jamo-normalize.pl
kotex-utils/komkindex.pl
kotex-utils/ttf2kotexfont.pl
l3build/l3build.lua
+l3sys-query/l3sys-query.lua
latex-git-log/latex-git-log
latex-papersize/latex-papersize.py
latex2man/latex2man
diff --git a/Master/bin/aarch64-linux/l3sys-query b/Master/bin/aarch64-linux/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/aarch64-linux/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/amd64-freebsd/l3sys-query b/Master/bin/amd64-freebsd/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/amd64-freebsd/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/amd64-netbsd/l3sys-query b/Master/bin/amd64-netbsd/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/amd64-netbsd/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/armhf-linux/l3sys-query b/Master/bin/armhf-linux/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/armhf-linux/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/i386-freebsd/l3sys-query b/Master/bin/i386-freebsd/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/i386-freebsd/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/i386-linux/l3sys-query b/Master/bin/i386-linux/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/i386-linux/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/i386-netbsd/l3sys-query b/Master/bin/i386-netbsd/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/i386-netbsd/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/i386-solaris/l3sys-query b/Master/bin/i386-solaris/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/i386-solaris/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/universal-darwin/l3sys-query b/Master/bin/universal-darwin/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/universal-darwin/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/windows/l3sys-query.exe b/Master/bin/windows/l3sys-query.exe
new file mode 100755
index 00000000000..3332231b08c
--- /dev/null
+++ b/Master/bin/windows/l3sys-query.exe
Binary files differ
diff --git a/Master/bin/x86_64-cygwin/l3sys-query b/Master/bin/x86_64-cygwin/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/x86_64-cygwin/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/x86_64-darwinlegacy/l3sys-query b/Master/bin/x86_64-darwinlegacy/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/x86_64-darwinlegacy/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/x86_64-linux/l3sys-query b/Master/bin/x86_64-linux/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/x86_64-linux/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/x86_64-linuxmusl/l3sys-query b/Master/bin/x86_64-linuxmusl/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/x86_64-linuxmusl/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/bin/x86_64-solaris/l3sys-query b/Master/bin/x86_64-solaris/l3sys-query
new file mode 120000
index 00000000000..2d072dc033b
--- /dev/null
+++ b/Master/bin/x86_64-solaris/l3sys-query
@@ -0,0 +1 @@
+../../texmf-dist/scripts/l3sys-query/l3sys-query.lua \ No newline at end of file
diff --git a/Master/texmf-dist/doc/man/man1/l3sys-query.1 b/Master/texmf-dist/doc/man/man1/l3sys-query.1
new file mode 100644
index 00000000000..146d0e4c2c6
--- /dev/null
+++ b/Master/texmf-dist/doc/man/man1/l3sys-query.1
@@ -0,0 +1,16 @@
+.TH L3SYS-QUERY 1 "2024-03-15" "LaTeX"
+
+.SH NAME
+l3sys-query
+
+.SH SYNOPSIS
+ Usage l3sys-query <cmd> [<options>] [<args>]
+
+.SH DESCRIPTION
+
+The l3sys-query script provides a method for TeX runs to obtain system
+information via shell escape to Lua. The facilities are more limited than the
+similar Java script texosquery, but since it uses Lua, l3sys-query can be
+used 'out of the box' with any install TeX system. The script is written taking
+account of TeX Live security requirement; it is therefore suitable for use with
+restricted shell escape, the standard setting when installing a TeX system.
diff --git a/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf b/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf
new file mode 100644
index 00000000000..e518f97c762
--- /dev/null
+++ b/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md b/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md
new file mode 100644
index 00000000000..b11654d5124
--- /dev/null
+++ b/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md
@@ -0,0 +1,25 @@
+# Changelog
+All notable changes to the `l3sys-query` will be documented in this file.
+
+The format is based on [Keep a
+Changelog](https://keepachangelog.com/en/1.0.0/), this project uses date-based
+'snapshot' version identifiers.
+
+## [Unreleased]
+
+## [2024-03-15]
+
+### Added
+- PDF documentation in distribution
+- `man` file in distribution
+
+### Changed
+- Documentation tweaks
+
+## [2024-03-14]
+
+### Added
+- New script
+
+[Unreleased]: https://github.com/latex3/l3sys-query/compare/2024-03-15...HEAD
+[2024-03-15]: https://github.com/latex3/l3sys-query/compare/2024-03-14...2024-03-15
diff --git a/Master/texmf-dist/doc/support/l3sys-query/README.md b/Master/texmf-dist/doc/support/l3sys-query/README.md
new file mode 100644
index 00000000000..1b9998f29ee
--- /dev/null
+++ b/Master/texmf-dist/doc/support/l3sys-query/README.md
@@ -0,0 +1,36 @@
+# `l3sys-query`: System queries for LaTeX using Lua
+
+Release 2024-03-15
+
+## Overview
+
+The `l3sys-query` script provides a method for TeX runs to obtain system
+information _via_ shell escape to Lua. The facilities are more limited than the
+similar Java script `texosquery`, but since it uses Lua, `l3sys-query` can be
+used 'out of the box' with any install TeX system. The script is written taking
+account of TeX Live security requirement; it is therefore suitable for use with
+restricted shell escape, the standard setting when installing a TeX system.
+
+The supported queries are
+- `ls`: Directory listing supporting a range of options
+- `pwd`: Obtaining details of the current working directory
+
+## Issues
+
+The issue tracker for LaTeX is currently located
+[on GitHub](https://github.com/latex3/l3sys-query/issues).
+
+## Development team
+
+This code is developed by [The LaTeX Project](https://latex-project.org).
+
+## License
+
+This project licensed under the same terms as Lua (MIT): see LICENSE or the top
+of source files for the legal text.
+
+-----
+
+<p>Copyright (C) 2024 The LaTeX Project <br />
+<a href="https://latex-project.org/">https://latex-project.org/</a> <br />
+All rights reserved.</p>
diff --git a/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md b/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md
new file mode 100644
index 00000000000..6eacf730129
--- /dev/null
+++ b/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md
@@ -0,0 +1,17 @@
+# Security Policy
+
+## Link to TeX Live Security Model
+
+As described in the script documentation, the primary aim of `l3sys-query` is
+to support system queries in the context of restricted shell escape from a TeX
+run. Specifically, the script is intended to respect _restricted_ shell escape.
+
+## Reporting a Vulnerability
+
+Security vulnerabilities can be reported privately _via_ GitHub at
+https://github.com/latex3/l3sys-query/security. Using this mechanism means that
+the potential issue does not show in the public issues list, and will give the
+team chance to review the report before it is made public.
+
+Alternative, the LaTeX Team can be contacted by email:
+latex-team@latex-project.org.
diff --git a/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf
new file mode 100644
index 00000000000..78e26662695
--- /dev/null
+++ b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex
new file mode 100644
index 00000000000..d9b99d59c1c
--- /dev/null
+++ b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex
@@ -0,0 +1,264 @@
+\iffalse meta-comment
+
+File l3sys-query-tool.tex Copyright (C) 2024 The LaTeX Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/l3sys-query
+
+for those people who are interested.
+
+-----------------------------------------------------------------------
+
+\fi
+
+\documentclass{l3doc}
+
+\begin{document}
+
+\title{The \pkg{l3sys-query} script: System queries for LaTeX using Lua}
+
+\author{%
+ The \LaTeX{} Project\thanks{%
+ Email: \href{mailto:latex-team@latex-project.org}
+ {latex-team@latex-project.org}%
+ }%
+}
+
+\date{Release 2024-03-15}
+
+\maketitle
+\tableofcontents
+
+\begin{documentation}
+
+\section{Introduction}
+
+\TeX{} engines provide only very limited access to information about the system
+they are used on: using primitives, one can for example get the size of a single
+file, but not a list of files in a given location. For most documents, this is
+not an issue as they are self-contained. However, for cases where
+\enquote{dynamic} construction of parts of a document is needed based on file
+lists or other system-dependent data, methods to obtain this from (restricted)
+shell escape are desirable.
+
+Security considerations mean that directly querying the system shell is
+problematic for general use. Instead, \emph{restricted} shell escape may be used
+to get many details, provided a suitable tool is available to provide the
+information in a platform-neutral and security-conscious way. The Java program
+\texttt{texosquery}, written by Nicola Talbot, has been available for a number
+of years to provide this facility. As well as file system insight,
+\texttt{texosquery} also provides for example locale data and other system
+information. However, the requirement for Java means that the script is not
+automatically usable when a \TeX{} system is installed.
+
+The \LaTeX{} team have therefore provided a Lua-based script,
+\texttt{l3sys-query}, which conforms to the security requirements of \TeX{} Live
+using Lua to obtain the system information. This means that it can be used
+\enquote{out of the box} across platforms. The facilities provided by
+\texttt{l3sys-query} are more limited than \texttt{texosquery}, partly as some
+information is available in modern \TeX{} systems using primitives, and partly
+as the aim of \texttt{l3sys-query} is to provide information where there are
+defined use cases. Requests for additional data interfaces are welcome.
+
+\section{The command line interface}
+
+The command line interface to
+\begin{center}
+ \ttfamily
+ l3sys-query \meta{cmd} [\meta{option(s)}] [\meta{args}]
+\end{center}
+where \texttt{\meta{cmd}} can be one of the following:
+\begin{itemize}[noitemsep]\ttfamily
+ \item ls
+ \item ls \meta{args}
+ \item pwd
+\end{itemize}
+The \meta{cmd} are described below. The result of the \meta{cmd} will be printed
+to the terminal in an interactive run; in normal usage, this will be piped to
+the calling \TeX{} process. Results containing path separators \emph{always}
+use~|/|, irrespective of the platform in use.
+
+As well as these targets, the script recognizes the options
+\begin{itemize}
+ \item |--exclude| Specification for directory entries to exclude
+ \item |--ignore-case| Ignores case when sorting directory listings
+ \item |--pattern| (|-p|) Treat the \meta{args} as Lua patterns rather
+ than converting from wildcards
+ \item |--recursive| (|-r|) Enables recursive searching during directory
+ listings
+ \item |--reverse| Causes sorting to go from highest to lowest rather
+ than lowest to highest
+ \item |--sort| Sets the method used to sort entries returned by |ls|
+ \item |--type| Selects the type of entry returned by |ls|
+\end{itemize}
+The action of these options on the appropriate \meta{cmd(s)} is detailed below.
+
+\subsection{\texttt{ls [\meta{args}]}}
+
+Lists the contents of one or more directories, in a manner somewhat reminiscent
+of the Unix command |ls| or the Windows command |dir|. The exact nature of the
+output will depend on the \meta{args}, if given, along with the prevailing
+options. Note that the options names are inspired by ideas from the Unix
+commands |ls| and |find| as well as the Windows command |dir|: they therefore do
+not map directly to those of any one of the command line tools that they
+somewhat mirror.
+
+When no \meta{args} are given, all entries in the current directory will be
+listed, one per line in the output. This will include both files and
+subdirectories. Each entry will include a path relative to the current
+directory: for files \emph{in} the current directory, this will be |./|. The
+order of results will be determined by the underlying operating system process:
+unless requested \emph{via} an option, no sorting takes place.
+
+As standard, the \meta{args} are treated as a file/path name potentially
+including |?| and |*| as wildcards, for example |*.png| or |file?.txt|.
+\begin{verbatim}
+ l3sys-query ls '*.png'
+\end{verbatim}
+Some care is needed in preventing expansion of such wildcards by the shell or
+\texttt{texlua} process: these are detailed in Section~\ref{sec:wildcard}. In
+this section, |'| is used to indicate a character being used to suppress
+expansion: this is for example normal on macOS and Linux.
+
+Removal of entries from the listing can be achieved using the |--exclude|
+option, which should be given with a \meta{xarg}, for example
+\begin{verbatim}
+ l3sys-query ls --exclude '*.bak' 'graphics/*'
+\end{verbatim}
+Directory entries starting |.| are traditionally hidden on Linux and macOS
+systems: these \enquote{dot} entries are excluded from the output of
+\texttt{l3sys-query}. The entries |.| and |..| for the current and parent
+directory are also excluded from the results returned by \texttt{l3sys-query} as
+they can always be assumed.
+
+For more complex matching, the \meta{args} can be treated as a Lua pattern using
+the |--pattern| (|-p|) option; this also applies to the \meta{xarg} argument to
+the |--exclude| option. For example, the equivalent to wildcard |*.png| could be
+obtained using
+\begin{verbatim}
+ l3sys-query ls --pattern '^.*%.png$'
+\end{verbatim}
+
+The results returned by |ls| can be sorted using the |--sort| option. This can
+be set to |none| (use the order from the file system: the default), |name| (sort
+by file name) or |date| (sort by date last modified). The sorting order can be
+reversed using |--reverse|. Sorting normally takes account of case: this can be
+suppressed with the |--ignore-case| option.
+
+The listing can be filtered based on the type of entry using the |--type|
+option. This takes a string argument, one of |d| (directory) or |f| (file).
+
+As standard, only the path specified as part of the \meta{args} is queried.
+However, if the |--recursive| (|-r|) option is set, the query is applied within
+all subdirectories. Subdirectories starting with~|.| (macOS and Linux hidden)
+are excluded from recursion.
+
+For security reasons, only paths within the current working directory can be
+queried, this for example |graphics/*.png| will list all |png| files in the
+|graphics| subdirectory, but |../graphics/*.png| will yield no output.
+
+\subsection{\texttt{pwd}}
+
+Returns the absolute path to the current working directory from which
+\texttt{l3sys-query} is run. From within a \TeX{} run, this will (usually) be
+the directory containing the main file, assuming a command such as
+\begin{verbatim}
+ pdflatex main.tex
+\end{verbatim}
+The \texttt{pwd} command is unaffected by any options.
+
+\section{Spaces in arguments}
+
+Since \texttt{l3sys-query} is intended primarily for use with restricted shell
+escape calls from \TeX{} processes, handling of spaces is unusual. It is not
+possible to quote spaces in such a call, so for example whilst
+\begin{verbatim}
+ l3sys-query ls "foo *"
+\end{verbatim}
+does work from the command prompt to find all files with names starting
+\verb*|foo |, it would not work \emph{via} restricted shell escape. To
+circumvent this, \texttt{l3sys-query} will collect all command line arguments
+after any \meta{options}, and combine these as a space-separated \meta{args},
+for example allowing
+\begin{verbatim}
+ l3sys-query ls foo '*'
+\end{verbatim}
+to achieve the same result as the first example. The result is that the
+\meta{args} will only every be interpreted by \texttt{l3sys-query} as a single
+argument. It also means that spaces cannot be used at the start or end of the
+argument, nor can multiple spaces appear between non-space arguments.
+
+\section{Wildcard expansion handling\label{sec:wildcard}}
+
+The handling of wildcards needs some further comment for those using
+\texttt{l3sys-query} from the command line: the \pkg{expl3} interface described
+in Section~\ref{sec:expl3} handles this aspect automatically for the user.
+
+On macOS and Linux, the shell normally expands globs, which include the
+wildcards |*| and |?|, before passing arguments to the appropriate command.
+This can be suppressed by surrounding the argument with |'| characters, hence
+the formulation
+\begin{verbatim}
+ l3sys-query ls '*.png'
+\end{verbatim}
+earlier.
+
+On Windows, the shell does no expansion, and thus arguments are passed as-is to
+the relevant command. As such, |'| has no special meaning here. However, to
+allow quoting of wildcards from the shell in a platform-neutral manner,
+\texttt{l3sys-query} will strip exactly one set of |'| characters around each
+argument before further processing.
+
+It is not possible to use |"| quotes at all in the argument passed to
+\texttt{l3sys-query} from \TeX{}, as the \TeX{} system removes all |"| in
+|\input| while handling space quoting.
+
+Restricted shell escape prevents shell expansion of wildcards entirely. On
+non-Windows systems, it does this by ensuring that each argument is |'| quoted
+to ensure further expansion. Thus a \TeX{} call such as
+\begin{verbatim}
+ \input|"l3sys-query ls '*.png'"
+\end{verbatim}
+will work if |--shell-escape| is used as the argument is passed directly to the
+shell, but in restricted shell escape will give an error such as:
+\begin{verbatim}
+! I can't find file `"|l3sys-query ls '*.png'"'.
+\end{verbatim}
+The \LaTeX{} interfaces described below adust the quoting used depending on the
+|shell-escape| status.
+
+\section{The \LaTeX{} interface\label{sec:expl3}}
+
+Using \texttt{l3sys-query} is not tied to access \emph{via} \pkg{expl3}, but
+this is the preferred approach for the \LaTeX{} Team. Details of how to use
+\texttt{l3sys-query} as an \pkg{expl3} programmer will covered in
+\texttt{interface3.pdf} once the macro code is finalized. A document level
+interface will also be provided via a \pkg{l3sys-query} package which is based
+on the \pkg{expl3} interface and will be described here.
+
+\end{documentation}
+
+\PrintIndex
+
+\end{document}
diff --git a/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua b/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua
new file mode 100755
index 00000000000..03e86296af4
--- /dev/null
+++ b/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua
@@ -0,0 +1,569 @@
+#!/usr/bin/env texlua
+
+--[[
+
+File l3sys-query.lua Copyright (C) 2024 The LaTeX Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/l3sys-query
+
+for those people who are interested.
+
+--]]
+
+--
+-- Details of the script itself, etc.
+--
+local copyright = "Copyright (C) 2024 The LaTeX Project"
+local release_date = "2024-03-15"
+local script_desc = "System queries for LaTeX using Lua\n"
+local script_name = "l3sys-query"
+
+--
+-- Setup for the CLI: commands and options
+--
+local cmd_impl = {}
+local cmd_desc = {}
+
+local option_list =
+ {
+ exclude =
+ {
+ cmds = {"ls"},
+ desc = "Exclude entries from directory listing",
+ type = "string"
+ },
+ ["ignore-case"] =
+ {
+ cmds = {"ls"},
+ desc = "Ignore case when sorting directory listing",
+ type = "boolean"
+ },
+ help =
+ {
+ desc = "Prints this message and exits",
+ short = "h",
+ type = "boolean"
+ },
+ pattern =
+ {
+ cmds = {"ls"},
+ desc = "Treat (x)args as a Lua pattern",
+ short = "p",
+ type = "boolean"
+ },
+ recursive =
+ {
+ cmds = {"ls"},
+ desc = "Activates recursive directory listing",
+ short = "r",
+ type = "boolean"
+ },
+ reverse =
+ {
+ cmds = {"ls"},
+ desc = "Reversing sorting order",
+ type = "boolean"
+ },
+ sort =
+ {
+ cmds = {"ls"},
+ desc = "Method used to sort directory listing",
+ type = "string"
+ },
+ type =
+ {
+ cmds = {"ls"},
+ desc = "Selects the type of entry in a directory listing",
+ type = "string"
+ },
+ version =
+ {
+ desc = "Prints version information and exits",
+ short = "v",
+ type = "boolean"
+ }
+ }
+
+--
+-- Local copies of globals used here
+--
+local io = io
+local stderr = io.stderr
+
+local lfs = lfs
+local attributes = lfs.attributes
+local currentdir = lfs.currentdir
+local dir = lfs.dir
+
+local os = os
+local exit = os.exit
+
+local string = string
+local find = string.find
+local gmatch = string.gmatch
+local lower = string.lower
+local match = string.match
+local rep = string.rep
+local sub = string.sub
+
+local table = table
+local concat = table.concat
+local insert = table.insert
+local sort = table.sort
+
+--
+-- Support functions and data
+--
+
+-- Remove '...' around an entire text:
+-- we need this to support restricted shell escape on Windows
+local function dequote(text)
+ if (match(text,"^'") and match(text,"'$")) then
+ return sub(text,2,-2)
+ end
+ return text
+end
+
+
+-- A short auxiliary used whever the script bails out
+local function info_and_quit(s)
+ stderr:write("\n" .. s .. "\nTry '" .. script_name .. " --help' for more information.\n")
+ exit(1)
+end
+
+-- Convert a file glob into a pattern for use by e.g. string.gub
+-- Based on https://github.com/davidm/lua-glob-pattern
+-- Simplified substantially: "[...]" syntax not supported as is not
+-- required by the file patterns used by the team. Also note style
+-- changes to match coding approach in rest of this file.
+--
+-- License for original globtopattern
+--[[
+
+ (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
+
+--]]
+local function glob_to_pattern(glob,skip_convert)
+ if skip_convert then
+ return glob
+ end
+
+ local pattern = "^" -- pattern being built
+ local i = 0 -- index in glob
+ local char -- char at index i in glob
+
+ -- escape pattern char
+ local function escape(char)
+ return match(char,"^%w$") and char or "%" .. char
+ end
+
+ -- Convert tokens.
+ while true do
+ i = i + 1
+ char = sub(glob,i,i)
+ if char == "" then
+ pattern = pattern .. "$"
+ break
+ elseif char == "?" then
+ pattern = pattern .. "."
+ elseif char == "*" then
+ pattern = pattern .. ".*"
+ elseif char == "[" then -- ]
+ -- Ignored
+ info_and_quit("[...] syntax not supported in globs!")
+ elseif char == "\\" then
+ i = i + 1
+ char = sub(glob,i,i)
+ if char == "" then
+ pattern = pattern .. "\\$"
+ break
+ end
+ pattern = pattern .. escape(char)
+ else
+ pattern = pattern .. escape(char)
+ end
+ end
+ return pattern
+end
+
+
+-- Initial data for the command line parser
+local cmd = ""
+local options = {}
+local arg_list = ""
+
+local function parse_args()
+ -- Turn long/short options into two lookup tables
+ local long_options = {}
+ local short_options = {}
+ for k,v in pairs(option_list) do
+ if v.short then
+ short_options[v.short] = k
+ end
+ long_options[k] = k
+ end
+
+ -- Minor speed-up
+ local arg = arg
+
+ -- arg[1] is a special case: must be a command or a very limited
+ -- subset (--help|-h or --version|-v)
+ local a = arg[1]
+ if a then
+ -- No options are allowed in position 1, so filter those out
+ if a == "--version" or a == "-v" then
+ cmd = "version"
+ elseif not match(a,"^%-") then
+ cmd = a
+ end
+ end
+
+ -- Stop here if help or version is required
+ if cmd == "help" or cmd == "version" then
+ return
+ end
+
+ -- An auxiliary to grab all file names into a string:
+ -- this reflects the fact that the use case for l3sys-query doesn't
+ -- allow quoting spaces
+ local function tidy(num)
+ local t = {}
+ for i = num,#arg do
+ insert(t,dequote(arg[i]))
+ end
+ return concat(t," ")
+ end
+
+ -- Examine all other arguments
+ -- Use a while loop rather than for as this makes it easier
+ -- to grab arg for optionals where appropriate
+ local i = 2
+ while i <= #arg do
+ local a = arg[i]
+ -- Terminate search for options
+ if a == "--" then
+ arg_list = tidy(i + 1)
+ return
+ end
+
+ -- Look for optionals
+ local opt
+ local optarg
+ local opts
+ -- Look for and option and get it into a variable
+ if match(a,"^%-") then
+ if match(a,"^%-%-") then
+ opts = long_options
+ local pos = find(a,"=")
+ if pos then
+ opt = sub(a,3,pos - 1)
+ optarg = sub(a,pos + 1)
+ else
+ opt = sub(a,3)
+ end
+ else
+ opts = short_options
+ opt = sub(a,2,2)
+ -- Only set optarg if it is there
+ if #a > 2 then
+ optarg = sub(a,3)
+ end
+ end
+
+ -- Now check that the option is valid and sort out the argument
+ -- if required
+ local optname = opts[opt]
+ if optname then
+ -- Tidy up arguments
+ if option_list[optname].type == "boolean" then
+ if optarg then
+ local opt = "-" .. (match(a,"^%-%-") and "-" or "") .. opt
+ info_and_quit("Value not allowed for option " .. opt)
+ end
+ else
+ if not optarg then
+ optarg = arg[i + 1]
+ if not optarg then
+ info_and_quit("Missing value for option " .. a)
+ end
+ i = i + 1
+ end
+ end
+ else
+ info_and_quit("Unknown option " .. a)
+ end
+
+ -- Store the result
+ if optarg then
+ if option_list[optname].type == "string" then
+ options[optname] = optarg
+ else
+ local opts = options[optname] or {}
+ for hit in gmatch(optarg,"([^,%s]+)") do
+ insert(opts,hit)
+ end
+ options[optname] = opts
+ end
+ else
+ options[optname] = true
+ end
+ i = i + 1
+ end
+
+ -- Collect up the remaining arguments
+ if not opt then
+ arg_list = tidy(i)
+ break
+ end
+ end
+end
+
+parse_args()
+
+--
+-- The help functions: local only and hard-coded
+--
+
+local function help()
+ -- Find the longest entry to pad
+ local function format_list(list)
+ local longest = 0
+ for k,_ in pairs(list) do
+ if k:len() > longest then
+ longest = k:len()
+ end
+ end
+ -- Sort the list
+ local t = {}
+ for k,_ in pairs(list) do
+ insert(t,k)
+ end
+ sort(t)
+ return t,longest
+ end
+
+ -- 'Header' of fixed info
+ print("Usage: " .. script_name .. " <cmd> [<options>] [<args>]\n")
+ print("Valid <cmd>s are:")
+
+ -- Sort the commands, pad the descriptions, print
+ local t,longest = format_list(cmd_desc)
+ for _,k in ipairs(t) do
+ local cmd = cmd_desc[k]
+ local filler = rep(" ",longest - k:len() + 1)
+ print(" " .. k .. filler .. cmd)
+ end
+
+ -- Same for the options
+ print("\nValid <options> are:")
+ t,longest = format_list(option_list)
+ for _,name in ipairs(t) do
+ local opt = option_list[name]
+ local filler = rep(" ",longest - name:len() + 1)
+ if opt.desc then
+ if opt.short then
+ print(" --" .. name .. "|-" .. opt.short .. filler .. opt.desc)
+ else
+ print(" --" .. name .. " " .. filler .. opt.desc)
+ end
+ end
+ end
+
+ -- Postamble
+ print("\nFull manual available via 'texdoc " .. script_name .. "'.\n")
+ print("Repository : https://github.com/latex3/" .. script_name)
+ print("Bug tracker: https://github.com/latex3/" .. script_name .. "/issues")
+ print("\n" .. copyright)
+end
+
+local function version()
+ print(script_name .. " " .. release_date)
+end
+
+--
+-- The functions for commands: all held in the table cmd_impl
+-- with docstrings in the table cmd_desc.
+--
+
+-- The aim here is to convert a user file specification (if given) into a
+-- Lua pattern, and then to do a listing.
+cmd_desc.ls = "Prints a listing based on the <args> and <options>"
+function cmd_impl.ls(arg_list)
+ if not arg_list or arg_list == "" or arg_list == "." then
+ arg_list = "*"
+ end
+ -- Look for absolute paths or any trying to leave the confines of the current
+ -- directory: this is not supported.
+ if match(arg_list,"%.%.") or
+ match(arg_list,"^/") or
+ match(arg_list,"^\\") or
+ match(arg_list,"[a-zA-Z]:") then
+ return
+ end
+ -- Tidy up and convert to a pattern.
+ path,glob = match(arg_list,"^(.*)/([^/]*)$")
+ if not path then
+ path = "."
+ glob = arg_list
+ end
+ if path == "" then
+ path = "."
+ end
+ if not match(path,"^%.") then
+ path = "./" .. path
+ end
+ local conv_pattern = options.pattern
+ local pattern = glob_to_pattern(glob,conv_pattern)
+ local exclude_pattern
+ if options.exclude then
+ local exclude = dequote(options.exclude)
+ exclude_pattern = glob_to_pattern(exclude,conv_pattern)
+ end
+ -- A lookup table for attributes: map between lfs- and Unix-type naming
+ local attrib_map = {d = "directory", f = "file"}
+
+ -- A bit of setup to store the sorting data as well as the entry itself
+ local i = 0 -- If no sorting active, just track the order from lfs
+ local entries = {}
+ local sort_mode = options.sort or "none"
+ local function store(entry,full_entry)
+ if not match(entry,pattern)
+ or (exclude_pattern and match(entry,exclude_pattern)) then
+ return
+ end
+ i = i + 1
+ local key = i
+ if sort_mode == "date" then
+ key = attributes(full_entry,"modification")
+ elseif sort_mode == "name" then
+ key = full_entry
+ end
+ entries[key] = full_entry
+ end
+
+ -- Build a table of entries, excluding "." and "..", and return as a string
+ -- with one entry per line.
+ local opt = options.type
+ local is_rec = options.recursive
+ local function browse(path)
+ for entry in dir(path) do
+ if entry ~= "." and entry ~= ".." and not match(entry,"^%.") then
+ local full_entry = path .. "/" .. entry
+ local ft = attributes(full_entry,"mode")
+ if not opt or ft == attrib_map[opt] then
+ store(entry,full_entry)
+ end
+ if is_rec and ft == "directory" then
+ browse(full_entry)
+ end
+ end
+ end
+ end
+ -- Start a search at the top level
+ browse(path)
+
+ -- Extract keys and sort
+ local s = {}
+ for k,_ in pairs(entries) do
+ insert(s,k)
+ end
+
+ -- Setup for case-insensitve sorting
+ local function case(s)
+ return s
+ end
+ if options["ignore-case"] then
+ function case(s)
+ return lower(s)
+ end
+ end
+
+ if options.reverse then
+ sort(s,function(a,b) return case(a) > case(b) end)
+ else
+ sort(s,function(a,b) return case(a) < case(b) end)
+ end
+
+ local result = {}
+ for _,v in ipairs(s) do
+ insert(result,entries[v])
+ end
+
+ return concat(result,"\n")
+end
+
+-- A simple rename
+cmd_desc.pwd = "Prints the present working directory"
+function cmd_impl.pwd()
+ return currentdir()
+end
+
+--
+-- Execute the given command
+--
+
+-- Only 'known' commands do anything at all
+if cmd == "version" then
+ version()
+ exit(0)
+elseif not cmd_impl[cmd] then
+ if cmd == "" then
+ help()
+ else
+ info_and_quit(script_name .. ": '" .. cmd .. "' is not a " .. script_name ..
+ " command.")
+ end
+ exit(1)
+end
+
+-- Check options are valid for cmd
+for k,_ in pairs(options) do
+ local cmds = option_list[k].cmds
+ if not cmds then
+ -- Should not be possible:
+ -- everything except --help and --version should have an entry
+ print("Internal error")
+ exit(1)
+ else
+ -- Make a lookup table
+ local t = {}
+ for _,v in pairs(cmds) do
+ t[v] = true
+ end
+ if not t[cmd] then
+ info_and_quit(script_name .. ": Option '" .. k ..
+ "' does not apply to '" .. cmd .. "'")
+ end
+ end
+end
+
+local result = cmd_impl[cmd](arg_list)
+
+if result then
+ print(result)
+ exit(0)
+else
+ exit(1)
+end
diff --git a/Master/texmf-dist/web2c/texmf.cnf b/Master/texmf-dist/web2c/texmf.cnf
index 4cb01e45b15..a3fa528268b 100644
--- a/Master/texmf-dist/web2c/texmf.cnf
+++ b/Master/texmf-dist/web2c/texmf.cnf
@@ -652,6 +652,7 @@ bibtex,bibtex8,\
extractbb,\
gregorio,\
kpsewhich,\
+l3sys-query,\
makeindex,\
memoize-extract.pl,\
memoize-extract.py,\
diff --git a/Master/tlpkg/bin/tl-update-asy b/Master/tlpkg/bin/tl-update-asy
index 027e4bf30d2..da3929daee4 100755
--- a/Master/tlpkg/bin/tl-update-asy
+++ b/Master/tlpkg/bin/tl-update-asy
@@ -69,7 +69,8 @@ elif test "x$1" = x--build; then
./configure --prefix=/tmp/ainst --enable-static \
--with-latex=/tmp/ainst/latex --with-context=/tmp/ainst/context \
--disable-fftw --disable-gl --disable-gsl --disable-lsp \
- --enable-texlive-build CFLAGS=-g CXXFLAGS=-std=c++11
+ --enable-texlive-build \
+ CFLAGS=-g CXXFLAGS=-std=c++11 LDFLAGS="-static-libgcc -static-libstdc++"
make
make check
make install-prebuilt
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index d1808505931..d08a54f851b 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -467,7 +467,7 @@ my @TLP_working = qw(
ktv-texdata ku-template kurdishlipsum kurier
kvdefinekeys kvmap kvoptions kvsetkeys
l2picfaq l2tabu l2tabu-english l2tabu-french l2tabu-italian l2tabu-spanish
- l3backend l3build l3kernel l3packages l3experimental
+ l3backend l3build l3kernel l3packages l3experimental l3sys-query
labbook labels labels4easylist labelschanged
labyrinth ladder lambda-lists lambdax langcode langnames
langsci langsci-avm
diff --git a/Master/tlpkg/doc/releng.txt b/Master/tlpkg/doc/releng.txt
index 6df5b43542f..380244c7522 100644
--- a/Master/tlpkg/doc/releng.txt
+++ b/Master/tlpkg/doc/releng.txt
@@ -121,8 +121,13 @@ critical=--critical # tlcritical needed for new release version
tl_update_auto=false # keep files as-is for now
net_frozen=true # stay local for now, no update of tlpretest
catalogue_compare=false # avoid for initial test
+
First build happens below, after many more changes; don't start it yet.
+Even if tlmgr itself is up to date, probably need to set --critical
+because of other changes, such as doc or certs; see /tmp/tlcrit.diff.
+In any case, doesn't hurt, so safest to always set it.
+
4. After setting up for pretest (not before), basic updates for release year:
Master/.mkisofsrc
Master/release-texlive.txt
diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds
index 4baae7a746c..845ea589098 100755
--- a/Master/tlpkg/libexec/ctan2tds
+++ b/Master/tlpkg/libexec/ctan2tds
@@ -3772,6 +3772,7 @@ $standardttf = '\.ttf|\.TTC';
'ketcindy' => 'ketcindy\.pl',
'kotex-utils' => '\.pl$',
'l3build' => 'l3build\.lua$',
+ 'l3sys-query' => 'l3sys-query\.lua$',
'latex-git-log' => 'latex-git-log$',
'latex-papersize' => '\.py$',
'latex2man' => 'latex2man$',
@@ -3908,6 +3909,7 @@ $standardttf = '\.ttf|\.TTC';
'git-latexdiff' => '\.1$',
'glossaries' => '\.1$',
'l3build' => '\.1$',
+ 'l3sys-query' => '\.1$',
'latex-git-log' => '\.1$',
'latex2man' => '\.1$',
'latexdiff' => '\.1$',
diff --git a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
index 663e3d337f2..f05a7edd868 100644
--- a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc
@@ -48,6 +48,7 @@ depend gsftopk
depend hook-pre-commit-pkg
depend installfont
depend ketcindy
+depend l3sys-query
depend lacheck
depend latex-git-log
depend latex-papersize
diff --git a/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc b/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc
new file mode 100644
index 00000000000..03a5f997080
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc
@@ -0,0 +1,4 @@
+binpattern f bin/${ARCH}/${PKGNAME}
+
+# just in case someone wants it early.
+depend luatex