texlive[44351] Master/texmf-dist: l3 (14may17)

commits+karl at tug.org commits+karl at tug.org
Mon May 15 00:40:58 CEST 2017


Revision: 44351
          http://tug.org/svn/texlive?view=revision&revision=44351
Author:   karl
Date:     2017-05-15 00:40:58 +0200 (Mon, 15 May 2017)
Log Message:
-----------
l3 (14may17)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/l3build/README.md
    trunk/Master/texmf-dist/doc/latex/l3build/l3build.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/README.md
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
    trunk/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/README.md
    trunk/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3obsolete.txt
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
    trunk/Master/texmf-dist/doc/latex/l3packages/README.md
    trunk/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf
    trunk/Master/texmf-dist/doc/latex/l3packages/xfp/xfp.pdf
    trunk/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf
    trunk/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf
    trunk/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf
    trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-build.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
    trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3final.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3oldmodules.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
    trunk/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
    trunk/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx
    trunk/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx
    trunk/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
    trunk/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
    trunk/Master/texmf-dist/tex/latex/l3build/l3build.lua
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-convert.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88591.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885910.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885911.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885913.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885914.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885915.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885916.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88592.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88593.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88594.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88595.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88596.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88597.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88598.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88599.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf16.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf32.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf8.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-hex.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-name.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-string.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-url.def
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty
    trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3box.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3coffins.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3color.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3file.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3int.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3names.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3sort.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3str.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3token.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def
    trunk/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty
    trunk/Master/texmf-dist/tex/latex/l3packages/xfp/xfp.sty
    trunk/Master/texmf-dist/tex/latex/l3packages/xfrac/xfrac.sty
    trunk/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
    trunk/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf
    trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3intarray.dtx
    trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3intarray.sty

Modified: trunk/Master/texmf-dist/doc/latex/l3build/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3build/README.md	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3build/README.md	2017-05-14 22:40:58 UTC (rev 44351)
@@ -1,7 +1,7 @@
 l3build: a testing and building system for LaTeX3
 =================================================
 
-Release 2017/04/01
+Release 2017/05/13
 
 Overview
 --------

Modified: trunk/Master/texmf-dist/doc/latex/l3build/l3build.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3experimental/README.md	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3experimental/README.md	2017-05-14 22:40:58 UTC (rev 44351)
@@ -1,7 +1,7 @@
 Experimental LaTeX3 Concepts
 ============================
 
-Release 2017/04/01
+Release 2017/05/13
 
 Overview
 --------

Added: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf	2017-05-14 22:40:58 UTC (rev 44351)

Property changes on: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3intarray.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2017-05-14 22:40:58 UTC (rev 44351)
@@ -1,7 +1,7 @@
 LaTeX3 Programming Conventions
 ==============================
 
-Release 2017/04/01
+Release 2017/05/13
 
 Overview
 --------

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3obsolete.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3obsolete.txt	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3obsolete.txt	2017-05-14 22:40:58 UTC (rev 44351)
@@ -16,7 +16,8 @@
 Function                   Expires end
 --------------------------------------
 \c_minus_one                      2018
-\GetIdInfo                        2018
+\box_resize:cnn                   2018
+\box_resize:Nnn                   2018
 \ior_get_str:NN                   2017
 \sort_ordered:                    2018
 \sort_reversed:                   2018

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex	2017-05-14 22:40:58 UTC (rev 44351)
@@ -30,7 +30,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2017/04/01}
+\date{Released 2017/05/13}
 
 \begin{document}
 

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex	2017-05-14 22:40:58 UTC (rev 44351)
@@ -30,7 +30,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2017/04/01}
+\date{Released 2017/05/13}
 
 \newcommand{\TF}{\textit{(TF)}}
 

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3packages/README.md	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/doc/latex/l3packages/README.md	2017-05-14 22:40:58 UTC (rev 44351)
@@ -1,7 +1,7 @@
 LaTeX3 High-Level Concepts
 ==========================
 
-Release 2017/04/01
+Release 2017/05/13
 
 Overview
 --------

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/xfp/xfp.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -201,7 +201,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 % \tableofcontents
@@ -1026,8 +1026,7 @@
 % a suitable function might read as shown in Figure~\ref{fig:update-line}.
 % \begin{figure}
 %   \begin{lstlisting}[frame=single,language={[5.2]Lua},gobble = 6]
-%     function setversion_update_line(line, date, version)
-%       local i
+%     function setversion_update_line(line, date, release)
 %       -- No real regex so do it one type at a time
 %       for _,i in pairs({"Class", "File", "Package"}) do
 %         if string.match(
@@ -1037,7 +1036,7 @@
 %           line = string.gsub(line, "%[%d%d%d%d/%d%d/%d%d", "["
 %             .. string.gsub(date, "%-", "/")
 %           line = string.gsub(
-%             line, "(%[%d%d%d%d/%d%d/%d%d) [^ ]*", "%1 " .. version
+%             line, "(%[%d%d%d%d/%d%d/%d%d) [^ ]*", "%1 " .. release
 %           )
 %           break
 %         end
@@ -1105,6 +1104,177 @@
 %   \label{fig:PDF}
 % \end{figure}
 %
+% \section{Lua interfaces}
+%
+% Whilst for the majority of users the simple variable-based control methods
+% outlined above will suffice, for more advanced applications there will be
+% a need to adjust behavior by using interfaces within the Lua code. This
+% section details the global variables and functions provided.
+%
+% \subsection{Global variables}
+%
+% \begin{variable}{options}
+%   The |options| table holds the values passed to \pkg{l3build} at the
+%   command line. The possible entries in the table are given in the table
+%   below.
+%   \begin{center}
+%   \begin{tabular}{ll}
+%     \toprule
+%     Entry & Type \\
+%     \midrule
+%       \var{date}        & String  \\
+%       \var{engine}      & Table   \\
+%       \var{files}       & Table   \\
+%       \var{halt}        & Boolean \\
+%       \var{help}        & Boolean \\
+%       \var{pdf}         & Boolean \\
+%       \var{quiet}       & Boolean \\
+%       \var{release}     & String  \\
+%       \var{testfiledir} & String  \\
+%     \bottomrule
+%     \end{tabular}
+%   \end{center}
+% \end{variable}
+%
+% \subsection{Utility functions}
+%
+% The utility functions are largely focussed on file operations, though a small
+% number of others are provided. File paths should be given in Unix style
+% (using |/| as a path separator). File operations take place relative to the
+% path from which \pkg{l3build} is called. File operation syntax is largely
+% modelled on Unix command line commands but reflect the need to work on
+% Windows in a flexible way.
+%
+% \begin{function}{abspath()}
+%   \begin{syntax}
+%     |abspath(|\meta{target}|)|
+%   \end{syntax}
+%   Returns a string which gives the absolute location of the
+%   \meta{target} directory.
+% \end{function}
+%
+% \begin{function}{cleandir()}
+%   \begin{syntax}
+%     |cleandir(|\meta{dir}|)|
+%   \end{syntax}
+%   Removes any content within the \meta{dir}; returns an error level.
+% \end{function}
+%
+% \begin{function}{cp()}
+%   \begin{syntax}
+%     |cp(|\meta{glob}, \meta{source}, \meta{destination}|)|
+%   \end{syntax}
+%   Copies files matching the \meta{glob} from the \meta{source} directory
+%   to the \meta{destination}; returns an error level.
+% \end{function}
+%
+% \begin{function}{direxists()}
+%   \begin{syntax}
+%     |direxists(|\meta{dir}|)|
+%   \end{syntax}
+%   Tests if the \meta{dir} exists; returns a boolean value.
+% \end{function}
+%
+% \begin{function}{fileexists()}
+%   \begin{syntax}
+%     |fileexists(|\meta{file}|)|
+%   \end{syntax}
+%   Tests if the \meta{file} exists; returns a boolean value.
+% \end{function}
+%
+% \begin{function}{filelist()}
+%   \begin{syntax}
+%     |filelist(|\meta{path}, \oarg{glob}|)|
+%   \end{syntax}
+%   Returns a table containing all of the files with the \meta{path}
+%   which match the \meta{glob}; if the latter is absent returns a list of
+%   all files in the \meta{path}.
+% \end{function}
+%
+% \begin{function}{mkidr()}
+%   \begin{syntax}
+%     |mkdir(|\meta{dir}|)|
+%   \end{syntax}
+%   Creates the \meta{dir}; returns an error level.
+% \end{function}
+%
+% \begin{function}{ren()}
+%   \begin{syntax}
+%     |ren(|\meta{dir}, \meta{source}, \meta{destination}|)|
+%   \end{syntax}
+%   Renames the \meta{source} file to the \meta{destination} name within
+%   the \meta{dir}; returns an error level.
+% \end{function}
+%
+% \begin{function}{rm()}
+%   \begin{syntax}
+%     |rm(|\meta{dir}, \meta{glob}|)|
+%   \end{syntax}
+%   Removes files in the \meta{dir} matching the \meta{glob}; returns an
+%   error level.
+% \end{function}
+%
+% \begin{function}{run()}
+%   \begin{syntax}
+%     |run(|\meta{dir}, \meta{cmd}|)|
+%   \end{syntax}
+%   Executes the \meta{cmd}, starting it in the \meta{dir}; returns an
+%   error level.
+% \end{function}
+%
+% \begin{function}{unix_to_win()}
+%   \begin{syntax}
+%     |unix_to_win(|\meta{path}|)|
+%   \end{syntax}
+%   Returns a string comprising the \meta{path} with |/| characters replaced
+%   by |\\|  and thus suitable for use with Windows-specific commands which
+%   require this form of path.
+% \end{function}
+%
+% \subsection{System-dependent strings}
+%
+% To support creation of additional functionality, the following low-level
+% strings are exposed by \pkg{l3build}: these all have system-dependent
+% definitions and avoid the need to test |os.type| during the construction
+% of system calls.
+%
+% \begin{variable}{os_concat}
+%   The concatenation operation for using multiple commands in one
+%   system call, \emph{e.g.}
+%   \begin{verbatim}
+%     os.execute("tex " .. file .. os_concat .. "tex " .. file)
+%   \end{verbatim}
+% \end{variable}
+%
+% \begin{variable}{os_null}
+%   The location to redirect commands which should produce no output
+%   at the terminal: almost always used preded by |>|, \emph{e.g.}
+%   \begin{verbatim}
+%     os.execute("tex " .. file .. " > " .. os_null)
+%   \end{verbatim}
+% \end{variable}
+%
+% \begin{variable}{os_pathsep}
+%   The separator used when setting an environment variable to multiple
+%   paths, \emph{e.g.}
+%   \begin{verbatim}
+%     os.execute(os_setenv .. " PATH=../a" .. os_pathsep .. "../b")
+%   \end{verbatim}
+% \end{variable}
+%
+% \begin{variable}{os_setenv}
+%   The command to set an environmental variable, \emph{e.g.}
+%   \begin{verbatim}
+%     os.execute(os_setenv .. " PATH=../a")
+%   \end{verbatim}
+% \end{variable}
+%
+% \begin{variable}{os_yes}
+%   A command to generate a series of $200$ lines each containing the
+%   character |y|: this is useful as the Unix |yes| command cannot be
+%   used inside |os.execute| (it does not terminate).
+% \end{variable}
+%
 % \end{documentation}
 %
 % \begin{implementation}

Added: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3intarray.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3intarray.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3intarray.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -0,0 +1,271 @@
+% \iffalse meta-comment
+%
+%% File: l3intarray.dtx Copyright (C) 2017 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version.  The latest version
+% of this license is in the file
+%
+%    http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+%    https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver|package>
+% The version of expl3 required is tested as early as possible, as
+% some really old versions do not define \ProvidesExplPackage.
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
+%<package>  {}
+%<package>  {%
+%<package>    \PackageError{l3intarray}{Support package l3kernel too old}
+%<package>      {%
+%<package>        Please install an up to date version of l3kernel\MessageBreak
+%<package>        using your TeX package manager or from CTAN.\MessageBreak
+%<package>        \MessageBreak
+%<package>        Loading l3intarray will abort!%
+%<package>      }%
+%<package>    \endinput
+%<package>  }
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{^^A
+%   The \textsf{l3intarray} package: low-level arrays of small integers^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX3 Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team at latex-project.org}
+%          {latex-team at latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released 2017/05/13}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{\pkg{l3intarray} documentation}
+%
+% This module provides no user function: at present it is meant for
+% kernel use only.
+%
+% It is a wrapper around the \tn{fontdimen} primitive, used to store
+% arrays of integers (with a restricted range: absolute value at most
+% $2^{30}-1$).  In contrast to \pkg{l3seq} sequences the access to
+% individual entries is done in constant time rather than linear time,
+% but only integers can be stored.  More precisely, the primitive
+% \tn{fontdimen} stores dimensions but the \pkg{l3intarray} package
+% transparently converts these from/to integers.  Assignments are always
+% global.
+%
+% While \LuaTeX{}'s memory is extensible, other engines can
+% \enquote{only} deal with a bit less than $4\times 10^6$ entries in all
+% \tn{fontdimen} arrays combined (with default \TeX{}Live settings).
+%
+% \subsection{Internal functions}
+%
+% \begin{function}{\__intarray_new:Nn}
+%   \begin{syntax}
+%     \cs{__intarray_new:Nn} \meta{intarray~var} \Arg{size}
+%   \end{syntax}
+%   Evaluates the integer expression \meta{size} and allocates an
+%   \meta{integer array variable} with that number of (zero) entries.
+% \end{function}
+%
+% \begin{function}[EXP]{\__intarray_count:N}
+%   \begin{syntax}
+%     \cs{__intarray_count:N} \meta{intarray~var}
+%   \end{syntax}
+%   Expands to the number of entries in the \meta{integer array variable}.
+%   Contrarily to \cs{seq_count:N} this is performed in constant time.
+% \end{function}
+%
+% \begin{function}{\__intarray_gset:Nnn, \__intarray_gset_fast:Nnn}
+%   \begin{syntax}
+%     \cs{__intarray_gset:Nnn} \meta{intarray~var} \Arg{position} \Arg{value}
+%     \cs{__intarray_gset_fast:Nnn} \meta{intarray~var} \Arg{position} \Arg{value}
+%   \end{syntax}
+%   Stores the result of evaluating the integer expression \meta{value}
+%   into the \meta{integer array variable} at the (integer expression)
+%   \meta{position}.  While \cs{__intarray_gset:Nnn} checks that the
+%   \meta{position} is between $1$ and the \cs{__intarray_count:N} and that
+%   the \meta{value}'s absolute value is at most $2^{30}-1$, the
+%   \enquote{fast} function performs no such bound check.
+%   Assignments are always global.
+% \end{function}
+%
+% \begin{function}[EXP]{\__intarray_item:Nn, \__intarray_item_fast:Nn}
+%   \begin{syntax}
+%     \cs{__intarray_item:Nn} \meta{intarray~var} \Arg{position}
+%     \cs{__intarray_item_fast:Nn} \meta{intarray~var} \Arg{position}
+%   \end{syntax}
+%   Expands to the integer entry stored at the (integer expression)
+%   \meta{position} in the \meta{integer array variable}.  While
+%   \cs{__intarray_item:Nn} checks that the \meta{position} is between $1$
+%   and the \cs{__intarray_count:N}, the \enquote{fast} function performs
+%   no such bound check.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3intarray} implementation}
+%
+%    \begin{macrocode}
+%<*initex|package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=intarray>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ProvidesExplPackage{l3intarray}{2017/05/13}{}
+  {L3 Experimental low-level arrays of small integers}
+%    \end{macrocode}
+%
+% \subsection{Allocating arrays}
+%
+% \begin{variable}{\g_@@_font_int}
+%   Used to assign one font per array.
+%    \begin{macrocode}
+\int_new:N \g_@@_font_int
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\@@_new:Nn}
+%   Declare |#1| to be a font (arbitrarily |cmr10| at a never-used
+%   size).  Store the array's size as the \tn{hyphenchar} of that font
+%   and make sure enough \tn{fontdimen} are allocated, by setting the
+%   last one.  Then clear any \tn{fontdimen} that |cmr10| starts with.
+%   It seems \LuaTeX{}'s |cmr10| has an extra \tn{fontdimen} parameter
+%   number $8$ compared to other engines (for a math font we would
+%   replace $8$ by $22$ or some such).
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_new:Nn #1#2
+  {
+    \__chk_if_free_cs:N #1
+    \int_gincr:N \g_@@_font_int
+    \tex_global:D \tex_font:D #1 = cmr10~at~ \g_@@_font_int sp \scan_stop:
+    \tex_hyphenchar:D #1 = \int_eval:n {#2} \scan_stop:
+    \int_compare:nNnT { \tex_hyphenchar:D #1 } > 0
+      { \tex_fontdimen:D \tex_hyphenchar:D #1 #1 = 0 sp \scan_stop: }
+    \int_step_inline:nnnn { 1 } { 1 } { 8 }
+      { \tex_fontdimen:D ##1 #1 = 0 sp \scan_stop: }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_count:N}
+%   Size of an array.
+%    \begin{macrocode}
+\cs_new:Npn \@@_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Array items}
+%
+% \begin{macro}[int]{\@@_gset:Nnn, \@@_gset_fast:Nnn}
+% \begin{macro}[aux]{\@@_gset_aux:Nnn}
+%   Set the appropriate \tn{fontdimen}.  The slow version checks the
+%   position and value are within bounds.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_gset_fast:Nnn #1#2#3
+  { \tex_fontdimen:D \int_eval:n {#2} #1 = \int_eval:n {#3} sp \scan_stop: }
+\cs_new_protected:Npn \@@_gset:Nnn #1#2#3
+  {
+    \exp_args:Nff \@@_gset_aux:Nnn #1
+      { \int_eval:n {#2} } { \int_eval:n {#3} }
+  }
+\cs_new_protected:Npn \@@_gset_aux:Nnn #1#2#3
+  {
+    \int_compare:nTF { 1 <= #2 <= \@@_count:N #1 }
+      {
+        \int_compare:nTF { - \c_max_dim <= \int_abs:n {#3} <= \c_max_dim }
+          { \@@_gset_fast:Nnn #1 {#2} {#3} }
+          {
+            \__msg_kernel_error:nnxxxx { intarray } { overflow }
+              { \token_to_str:N #1 } {#2} {#3}
+              { \int_compare:nNnT {#3} < 0 { - } \__int_value:w \c_max_dim }
+            \@@_gset_fast:Nnn #1 {#2}
+              { \int_compare:nNnT {#3} < 0 { - } \c_max_dim }
+          }
+      }
+      {
+        \__msg_kernel_error:nnxxx { intarray } { out-of-bounds }
+          { \token_to_str:N #1 } {#2} { \@@_count:N #1 }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_item:Nn, \@@_item_fast:Nn}
+% \begin{macro}[aux]{\@@_item_aux:Nn}
+%   Get the appropriate \tn{fontdimen} and perform bound checks if requested.
+%    \begin{macrocode}
+\cs_new:Npn \@@_item_fast:Nn #1#2
+  { \__int_value:w \tex_fontdimen:D \int_eval:n {#2} #1 }
+\cs_new:Npn \@@_item:Nn #1#2
+  { \exp_args:Nf \@@_item_aux:Nn #1 { \int_eval:n {#2} } }
+\cs_new:Npn \@@_item_aux:Nn #1#2
+  {
+    \int_compare:nTF { 1 <= #2 <= \@@_count:N #1 }
+      { \@@_item_fast:Nn #1 {#2} }
+      {
+        \__msg_kernel_expandable_error:nnnnn { intarray } { out-of-bounds }
+          { \token_to_str:N #1 } {#2} { \@@_count:N #1 }
+        0
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+%    \begin{macrocode}
+\__msg_kernel_new:nnnn { intarray } { overflow }
+  { Integers~larger~than~2^{30}-1~cannot~be~stored~in~arrays. }
+  {
+    An~attempt~was~made~to~store~#3~at~position~#2~in~the~array~'#1'.~
+    The~largest~allowed~value~#4~will~be~used~instead.
+  }
+\__msg_kernel_new:nnnn { intarray } { out-of-bounds }
+  { Access~to~an~entry~beyond~an~array's~bounds. }
+  {
+    An~attempt~was~made~to~access~or~store~data~at~position~#2~of~the~
+    array~'#1',~but~this~array~has~entries~at~positions~from~1~to~#3.
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%</initex|package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex


Property changes on: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3intarray.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{l3regex}{Support package l3kernel too old}
@@ -59,7 +59,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -352,21 +352,37 @@
 % \subsection{Syntax of the replacement text}
 %
 % Most of the features described in regular expressions do not make
-% sense within the replacement text.  Escaped characters are supported
-% as inside regular expressions.  The whole match is accessed as~|\0|,
-% and the first~$9$ submatches are accessed as |\1|, \ldots{},~|\9|.
-% Further submatches are accessed through |\g{|\meta{number}|}| where
-% \meta{number} is any non-negative integer.  If there are fewer than
-% \meta{number} capturing groups, the submatch is empty.
+% sense within the replacement text.  Backslash introduces various
+% special constructions:
+% \begin{itemize}
+%   \item |\0| is the whole match;
+%   \item |\1|, |\2|, \ldots{}, |\9| or |\g{|\meta{number}|}| are the
+%     submatches (empty if there are fewer than \meta{number} capturing
+%     groups);
+%   \item \verb*|\ | inserts a space (spaces are ignored when not
+%     escaped);
+%   \item |\a|, |\e|, |\f|, |\n|, |\r|, |\t|, |\xhh|, |\x{hhh}|
+%     correspond to single characters as in regular expressions;
+%   \item |\c|\Arg{cs~name} inserts a control sequence;
+%   \item |\c|\meta{category}\meta{character} (see below);
+%   \item |\u|\Arg{tl~var~name} inserts the contents of the
+%     \meta{tl~var} (see below).
+% \end{itemize}
+% Characters other than backslash and space are simply inserted in the
+% result (but since the replacement text is first converted to a string,
+% one should also escape characters that are special for \TeX{}, for
+% instance use~|\#|).  Non-alphanumeric characters can always be safely
+% escaped with a backslash.
 %
 % For instance,
 % \begin{verbatim}
 %   \tl_set:Nn \l_my_tl { Hello,~world! }
-%   \regex_replace_all:nnN { ([er]?l|o) . } { \(\0\-\-\1\) } \l_my_tl
+%   \regex_replace_all:nnN { ([er]?l|o) . } { (\0--\1) } \l_my_tl
 % \end{verbatim}
 % results in \cs{l_my_tl} holding |H(ell--el)(o,--o) w(or--o)(ld--l)!|
 %
-% Submatches keep the same category codes as in the original token list.
+% Submatches always keep the same category codes as in the original
+% token list.
 % The characters inserted by the replacement have category code $12$
 % (other) by default, with the exception of space characters.  Spaces
 % inserted through \verb*|\ | have category code $10$, while spaces
@@ -374,21 +390,25 @@
 % The escape sequence |\c| allows to insert characters
 % with arbitrary category codes, as well as control sequences.
 % \begin{l3regex-syntax}
-% \item[\\cXY] Produces the character~|Y| (which can be given as an
-%   escape sequence such as~|\t| for tab, or |\(| or~|\)| for a
-%   parenthesis) with category code~|X|, which must be one of
-%   |CBEMTPUDSLOA|.
+% \item[\\cX(\ldots{})] Produces the characters \enquote{\ldots{}} with
+%   category~|X|, which must be one of |CBEMTPUDSLOA| as in regular
+%   expressions.  Parentheses are optional for a single character (which
+%   can be an escape sequence).  This can be nested, for instance
+%   |\cL(Hello\cS\ world)!|
 % \item[\\c\Arg{text}] Produces the control sequence with csname
 %   \meta{text}.  The \meta{text} may contain references to the
-%   submatches |\0|, |\1|, \emph{etc.}
+%   submatches |\0|, |\1|, and so on, as in the example for |\u| below.
 % \end{l3regex-syntax}
 %
 % The escape sequence |\u|\Arg{tl~var~name} allows to insert the
 % contents of the token list with name \meta{tl~var~name} directly into
-% the replacement, avoiding the need to escape special characters.
-% Within the construction |\c|\Arg{text}, the |\u|~escape sequence only
-% expands its argument once, in effect performing \cs{tl_to_str:v}.
-% Submatches can be used within the argument of |\u|.  For instance,
+% the replacement, giving an easier control of category codes.
+% Within |\c{|\ldots{}|}| and |\u{|\ldots{}|}| constructions, the |\u|
+% and |\c|~escape sequences perform \cs{tl_to_str:v}, namely extract the
+% value of the control sequence and turn it into a string.
+%
+% Matches can be used within the arguments of |\c| and |\u|.  For
+% instance,
 % \begin{verbatim}
 %   \tl_set:Nn \l_my_one_tl { first }
 %   \tl_set:Nn \l_my_two_tl { \emph{second} }
@@ -611,7 +631,8 @@
 %   \item Currently, |a{\x34}| is recognized as |a{4}|.
 %   \item Cleaner error reporting in the replacement phase.
 %   \item Add tracing information.
-%   \item Detect attempts to use back-references.
+%   \item Detect attempts to use back-references and other
+%     non-implemented syntax.
 %   \item Test for the maximum register \cs{c_max_register_int}.
 %   \item Find out whether the fact that |\W| and friends match the
 %     end-marker leads to bugs. Possibly update \cs{__regex_item_reverse:n}.
@@ -622,23 +643,19 @@
 %
 % Code improvements to come.
 % \begin{itemize}
-%   \item Change \tn{skip} to \tn{dimen} for the array of active
-%     threads, and shift the array of submatch informations so that it
-%     starts at \tn{skip}$0$.
-%   \item Optimize |\c{abc}| for matching a specific control sequence.
+%   \item Shift arrays so that the useful information starts at
+%     position~$1$.
 %   \item Only build \c{...} once.
-%   \item Use \tn{skip} for the left and right state stacks when
+%   \item Use arrays for the left and right state stacks when
 %     compiling a regex.
 %   \item Should \cs{__regex_action_free_group:n} only be used for greedy
 %     |{n,}| quantifier? (I think not.)
 %   \item Quantifiers for |\u| and assertions.
-%   \item Improve digit grabbing for the |\g| escape in replacement.
-%     Allow arbitrary integer expressions for all those numbers?
 %   \item When matching, keep track of an explicit stack of
 %     \texttt{current_state} and \texttt{current_submatches}.
 %   \item If possible, when a state is reused by the same thread, kill
 %     other subthreads.
-%   \item Use \tn{dimen} registers rather than \cs{l__regex_balance_tl}
+%   \item Use an array rather than \cs{l__regex_balance_tl}
 %     to build \cs{__regex_replacement_balance_one_match:n}.
 %   \item Reduce the number of epsilon-transitions in alternatives.
 %   \item Optimize simple strings: use less states (|abcade| should give
@@ -650,8 +667,6 @@
 %   \item Optimize the use of \cs{int_step_...} functions.
 %   \item Groups don't capture within regexes for csnames; optimize and
 %     document.
-%   \item Decide and document what |\c{\c{...}}| should do in the
-%     replacement text, similar questions for |\u|.
 %   \item Better \enquote{show} for anchors, properties, and catcode tests.
 %   \item Does |\K| really need a new state for itself?
 %   \item When compiling, use a boolean \texttt{in_cs} and less magic
@@ -664,7 +679,6 @@
 % The following features are likely to be implemented at some point
 % in the future.
 % \begin{itemize}
-%   \item Allow |\cL(abc)| in replacement text.
 %   \item General look-ahead/behind assertions.
 %   \item Regex matching on external files.
 %   \item Conditional subpatterns with look ahead/behind: \enquote{if
@@ -680,13 +694,11 @@
 %     This requires to manipulate a lot of data, probably using tree-boxes.
 % \end{itemize}
 %
-% The following features of \textsc{pcre} or Perl will probably not be
+% The following features of \textsc{pcre} or Perl may or may not be
 % implemented.
 % \begin{itemize}
 %   \item |\ddd|, matching the character with octal code \texttt{ddd};
-%   \item Callout with |(?C...)|, we cannot run arbitrary user code
-%     during the matching, because the regex code uses registers in an
-%     unsafe way;
+%   \item Callout with |(?C...)|;
 %   \item Conditional subpatterns (other than with a look-ahead or
 %     look-behind condition): this is non-regular, isn't it?
 %   \item Named subpatterns: \TeX{} programmers have lived so far
@@ -705,9 +717,7 @@
 %     non-backtracking algorithm, and difficult to implement.
 %   \item Subroutine calls: this syntactic sugar is difficult to include
 %     in a non-backtracking algorithm, in particular because the
-%     corresponding group should be treated as atomic. Also, we cannot
-%     afford to run user code within the regular expression matching,
-%     because of our \enquote{misuse} of registers.
+%     corresponding group should be treated as atomic.
 %   \item Recursion: this is a non-regular feature.
 %   \item Back-references: non-regular feature, this requires
 %     backtracking, which is prohibitively slow.
@@ -734,9 +744,9 @@
 %
 %    \begin{macrocode}
 %<*package>
-\ProvidesExplPackage{l3regex}{2017/04/01}{}
+\ProvidesExplPackage{l3regex}{2017/05/13}{}
   {L3 Experimental regular expressions}
-\RequirePackage{l3tl-build, l3tl-analysis, l3str-convert}
+\RequirePackage{l3tl-build, l3tl-analysis, l3intarray}
 %</package>
 %    \end{macrocode}
 %
@@ -754,7 +764,7 @@
 %   \item (Compiling.) Analyse the regex, finding invalid input, and
 %     convert it to an internal representation.
 %   \item (Building.) Convert the compiled regex to a non-deterministic
-%     finite automaton (\textsc{nfa}) with roughly $n$ states which
+%     finite automaton (\textsc{nfa}) with $O(n)$ states which
 %     accepts precisely token lists matching that regex.
 %   \item (Matching.) Loop through the query token list one token (one
 %     \enquote{position}) at a time, exploring in parallel every
@@ -787,46 +797,42 @@
 %     unique id for all the steps of the matching algorithm.
 % \end{itemize}
 %
-% To achieve a good performance, we abuse \TeX{}'s registers in two
-% ways.  We access registers directly by number rather than tying them
-% to control sequence using \cs{int_new:N} and other allocation
-% functions. And we store integers in \tn{dimen} registers in scaled
-% points (\texttt{sp}), using \TeX{}'s implicit conversion from
-% dimensions to integers in some contexts. Specifically, the registers
-% are used as follows. When compiling, \tn{toks} registers are used
-% under the hood by functions from the \pkg{l3tl-build} module.  When
-% building,
+% We use \pkg{l3intarray} to manipulate arrays of integers (stored into
+% some dimension registers in scaled points).  We also abuse \TeX{}'s
+% \tn{toks} registers, by accessing them directly by number rather than
+% tying them to control sequence using the \tn{newtoks} allocation
+% functions. Specifically, these arrays and \tn{toks} are used as
+% follows. When compiling, \tn{toks} registers are used under the hood
+% by functions from the \pkg{l3tl-build} module.  When building,
+% \tn{toks}\meta{state} holds the tests and actions to perform in the
+% \meta{state} of the \textsc{nfa}.  When matching,
 % \begin{itemize}
-%   \item \tn{toks}\meta{state} holds the tests and actions to perform
-%     in the \meta{state} of the \textsc{nfa}.
-%   \item (Not implemented yet.)
-%     \tn{skip}$i$ has the form \meta{group id} \texttt{plus}
-%     \meta{left state} \texttt{minus} \meta{right state}.
-% \end{itemize}
-% When matching,
-% \begin{itemize}
-%   \item \tn{dimen}\meta{state} is equal to the last \meta{step} in
-%     which the \meta{state} was active.
-%   \item (Currently, we use \tn{skip} instead of \tn{dimen}.)
-%     \tn{dimen}\meta{thread}, with $\texttt{min_active} \leq
-%     \meta{thread} < \texttt{max_active}$, is equal to the
-%     \meta{state} in which the \meta{thread} currently is. The
+%   \item \cs{g_@@_state_active_intarray} holds the last \meta{step} in
+%     which each \meta{state} was active.
+%   \item \cs{g_@@_thread_state_intarray} maps each \meta{thread} (with
+%     $\texttt{min_active} \leq \meta{thread} < \texttt{max_active}$) to
+%     the \meta{state} in which the \meta{thread} currently is. The
 %     \meta{threads} or ordered starting from the best to the least
 %     preferred.
 %   \item \tn{toks}\meta{thread} holds the submatch information for the
 %     \meta{thread}, as the contents of a property list.
-%   \item \tn{muskip}\meta{position} holds as its main and stretch
-%     components the character and category code of the token at this
+%   \item \cs{g_@@_charcode_intarray} and \cs{g_@@_catcode_intarray} hold the
+%     character codes and category codes of tokens at each
 %     \meta{position} in the query.
+%   \item \cs{g_@@_balance_intarray} holds the balance of begin-group and
+%     end-group character tokens which appear before that point in the
+%     token list.
 %   \item \tn{toks}\meta{position} holds \meta{tokens} which \texttt{o}-
 %     and \texttt{x}-expand to the \meta{position}-th token in the query.
-%   \item \tn{skip} registers hold the value of end-points of all
-%     submatches as would be extracted by the \cs{regex_extract}
-%     functions. Since smaller \tn{skip} registers are used, the minimum
-%     index is twice \texttt{max_state}, and the used registers go up to
-%     \cs{l_@@_submatch_int}. They are organized in blocks of
-%     \texttt{capturing_group}, each block corresponding to one match
-%     with all its submatches stored in consecutive \tn{skip}s.
+%   \item \cs{g_@@_submatch_prev_intarray}, \cs{g_@@_submatch_begin_intarray}
+%     and \cs{g_@@_submatch_end_intarray} hold, for each submatch (as would
+%     be extracted by \cs{regex_extract_all:nnN}), the place where the
+%     submatch started to be looked for and its two end-points.  For
+%     historical reasons, the minimum index is twice \texttt{max_state},
+%     and the used registers go up to \cs{l_@@_submatch_int}. They are
+%     organized in blocks of \cs{l_@@_capturing_group_int} entries, each
+%     block corresponding to one match with all its submatches stored in
+%     consecutive entries.
 % \end{itemize}
 % \tn{count} registers are not abused, which means that we can safely
 % use named integers in this module. Note that \tn{box} registers are
@@ -851,6 +857,89 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[int]{\@@_standard_escapechar:}
+%   Make the \tn{escapechar} into the standard backslash.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_standard_escapechar:
+  { \int_set:Nn \tex_escapechar:D { `\\ } }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_toks_use:w}
+%   Unpack a \tn{toks} given its number.
+%    \begin{macrocode}
+\cs_new:Npn \@@_toks_use:w { \tex_the:D \tex_toks:D }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_toks_clear:N, \@@_toks_set:Nn, \@@_toks_set:No}
+%   Empty a \tn{toks} or set it to a value, given its number.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_toks_clear:N #1
+  { \tex_toks:D #1 { } }
+\cs_new_eq:NN \@@_toks_set:Nn \tex_toks:D
+\cs_new_protected:Npn \@@_toks_set:No #1
+  { \@@_toks_set:Nn #1 \exp_after:wN }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_toks_memcpy:NNn}
+%   Copy |#3| \tn{toks} registers from |#2| onwards to |#1| onwards,
+%   like |C|'s |memcpy|.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_toks_memcpy:NNn #1#2#3
+  {
+    \prg_replicate:nn {#3}
+      {
+        \tex_toks:D #1 = \tex_toks:D #2
+        \int_incr:N #1
+        \int_incr:N #2
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_toks_put_left:Nx}
+% \begin{macro}[int]{\@@_toks_put_right:Nx, \@@_toks_put_right:Nn}
+%   During the building phase we wish to add \texttt{x}-expanded
+%   material to \tn{toks}, either to the left or to the right. The
+%   expansion is done \enquote{by hand} for optimization (these
+%   operations are used quite a lot). The \texttt{Nn} version of
+%   \cs{@@_toks_put_right:Nx} is provided because it is more
+%   efficient than \texttt{x}-expanding with \cs{exp_not:n}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_toks_put_left:Nx #1#2
+  {
+    \cs_set:Npx \@@_tmp:w { #2 }
+    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+      { \exp_after:wN \@@_tmp:w \tex_the:D \tex_toks:D #1 }
+  }
+\cs_new_protected:Npn \@@_toks_put_right:Nx #1#2
+  {
+    \cs_set:Npx \@@_tmp:w {#2}
+    \tex_toks:D #1 \exp_after:wN
+      { \tex_the:D \tex_toks:D \exp_after:wN #1 \@@_tmp:w }
+  }
+\cs_new_protected:Npn \@@_toks_put_right:Nn #1#2
+  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int, rEXP]{\@@_current_cs_to_str:}
+%   Expands to the string representation of the token (known to be a
+%   control sequence) at the current position \cs{l_@@_current_pos_int}.
+%   It should only be used in \texttt{x}-expansion to avoid losing a
+%   leading space.
+%    \begin{macrocode}
+\cs_new:Npn \@@_current_cs_to_str:
+  {
+    \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
+    \tex_the:D \tex_toks:D \l_@@_current_pos_int
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsubsection{Constants and variables}
 %
 % \begin{macro}[aux]{\@@_tmp:w}
@@ -894,15 +983,25 @@
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{variable}{\l_@@_balance_int}
+% \begin{variable}{\g_@@_charcode_intarray, \g_@@_catcode_intarray, \g_@@_balance_intarray}
 %   The first thing we do when matching is to go once through the query
-%   token list and store the information for each token as \tn{muskip}
-%   and \tn{toks} registers. During this phase, \cs{l_@@_balance_int}
-%   counts the balance of begin-group and end-group character tokens
-%   which appear before a given point in the token list, and we store it
-%   as the shrink component of each \tn{muskip} register. This variable
-%   is also used to keep track of the balance in the replacement text.
+%   token list and store the information for each token into
+%   \cs{g_@@_charcode_intarray}, \cs{g_@@_catcode_intarray} and \tn{toks}
+%   registers.  We also store the balance of begin-group/end-group
+%   characters into \cs{g_@@_balance_intarray}.
 %    \begin{macrocode}
+\__intarray_new:Nn \g_@@_charcode_intarray { 65536 }
+\__intarray_new:Nn \g_@@_catcode_intarray { 65536 }
+\__intarray_new:Nn \g_@@_balance_intarray { 65536 }
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_balance_int}
+%   During this phase, \cs{l_@@_balance_int} counts the balance of
+%   begin-group and end-group character tokens which appear before a
+%   given point in the token list. This variable is also used to keep
+%   track of the balance in the replacement text.
+%    \begin{macrocode}
 \int_new:N \l_@@_balance_int
 %    \end{macrocode}
 % \end{variable}
@@ -918,6 +1017,20 @@
 %
 % \subsubsection{Testing characters}
 %
+% \begin{macro}{\c_@@_ascii_min_int, \c_@@_ascii_max_control_int, \c_@@_ascii_max_int}
+%    \begin{macrocode}
+\int_const:Nn \c_@@_ascii_min_int { 0 }
+\int_const:Nn \c_@@_ascii_max_control_int { 31 }
+\int_const:Nn \c_@@_ascii_max_int { 127 }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\c_@@_ascii_lower_int}
+%    \begin{macrocode}
+\int_const:Nn \c_@@_ascii_lower_int { `a - `A }
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{macro}[int]{\@@_break_point:TF}
 % \begin{macro}[int]{\@@_break_true:w}
 %   When testing whether a character of the query token list matches
@@ -1027,12 +1140,12 @@
     \if_int_compare:w \l_@@_current_char_int > `Z \exp_stop_f:
       \if_int_compare:w \l_@@_current_char_int > `z \exp_stop_f: \else:
         \if_int_compare:w \l_@@_current_char_int < `a \exp_stop_f: \else:
-          \int_sub:Nn \l_@@_case_changed_char_int { \c__str_ascii_lower_int }
+          \int_sub:Nn \l_@@_case_changed_char_int { \c_@@_ascii_lower_int }
         \fi:
       \fi:
     \else:
       \if_int_compare:w \l_@@_current_char_int < `A \exp_stop_f: \else:
-        \int_add:Nn \l_@@_case_changed_char_int { \c__str_ascii_lower_int }
+        \int_add:Nn \l_@@_case_changed_char_int { \c_@@_ascii_lower_int }
       \fi:
     \fi:
   }
@@ -1099,12 +1212,7 @@
     \int_compare:nNnTF \l_@@_current_catcode_int = 0
       {
         \tl_set:Nx \l_@@_internal_a_tl
-          {
-            \scan_stop:
-            \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
-            \tex_the:D \tex_toks:D \l_@@_current_pos_int
-            \scan_stop:
-          }
+          { \scan_stop: \@@_current_cs_to_str: \scan_stop: }
         \tl_if_in:noTF { \scan_stop: #1 \scan_stop: } \l_@@_internal_a_tl
           { \@@_break_true:w } { }
       }
@@ -1128,12 +1236,7 @@
     \int_compare:nNnT \l_@@_current_catcode_int = 0
       {
         \group_begin:
-          \tl_set:Nx \l_@@_cs_name_tl
-            {
-              \exp_after:wN \exp_after:wN
-              \exp_after:wN \cs_to_str:N
-              \tex_the:D \tex_toks:D \l_@@_current_pos_int
-            }
+          \tl_set:Nx \l_@@_cs_name_tl { \@@_current_cs_to_str: }
           \@@_single_match:
           \@@_disable_submatches:
           \@@_build_for_cs:n {#1}
@@ -1214,16 +1317,16 @@
 \cs_new_protected:Npn \@@_posix_ascii:
   {
     \@@_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_int
+      \c_@@_ascii_min_int
+      \c_@@_ascii_max_int
   }
 \cs_new_eq:NN \@@_posix_blank: \@@_prop_h:
 \cs_new_protected:Npn \@@_posix_cntrl:
   {
     \@@_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_control_int
-    \@@_item_caseful_equal:n \c__str_ascii_max_int
+      \c_@@_ascii_min_int
+      \c_@@_ascii_max_control_int
+    \@@_item_caseful_equal:n \c_@@_ascii_max_int
   }
 \cs_new_eq:NN \@@_posix_digit: \@@_prop_d:
 \cs_new_protected:Npn \@@_posix_graph:
@@ -1301,8 +1404,8 @@
       \cs_set:Npn \@@_escape_unescaped:N ##1 { #1 }
       \cs_set:Npn \@@_escape_escaped:N ##1 { #2 }
       \cs_set:Npn \@@_escape_raw:N ##1 { #3 }
-      \int_set:Nn \tex_escapechar:D { `\\ }
-      \__str_gset_other:Nn \g_@@_internal_tl { #4 }
+      \@@_standard_escapechar:
+      \tl_gset:Nx \g_@@_internal_tl { \__str_to_other_fast:n {#4} }
       \tl_set:Nx \l_@@_internal_b_tl
         {
           \exp_after:wN \@@_escape_loop:N \g_@@_internal_tl
@@ -1389,12 +1492,11 @@
 %
 % \begin{macro}[aux]{\@@_escape_/x:w}
 % \begin{macro}[aux]{\@@_escape_x_end:w, \@@_escape_x_large:n}
-%   When |\x| is encountered, \cs{@@_escape_x_test:N} is responsible
-%   for grabbing some hexadecimal digits, and feeding the result to
-%   \cs{@@_escape_x_end:w}. If the number is $<256$, then it is
-%   turned into a byte and fed to \cs{@@_escape_raw:N}. Otherwise,
-%   interrupt the assignment, and either produce an error, or use a
-%   standard \tn{lowercase} trick depending on the precise value.
+%   When |\x| is encountered, \cs{@@_escape_x_test:N} is responsible for
+%   grabbing some hexadecimal digits, and feeding the result to
+%   \cs{@@_escape_x_end:w}. If the number is too big interrupt the
+%   assignment and produce an error, otherwise call \cs{@@_escape_raw:N}
+%   on the corresponding character token.
 %    \begin{macrocode}
 \cs_new:cpn { @@_escape_/x:w } \@@_escape_loop:N
   {
@@ -1403,40 +1505,23 @@
   }
 \cs_new:Npn \@@_escape_x_end:w #1 ;
   {
-    \int_compare:nNnTF {#1} > \c__str_max_byte_int
-      { \@@_escape_x_large:n {#1} }
+    \int_compare:nNnTF {#1} > \c_max_char_int
       {
+        \if_false: { \fi: }
+        \__tl_build_one:o \l_@@_internal_b_tl
+        \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
+        \tl_set:Nx \l_@@_internal_b_tl
+          { \if_false: } \fi:
+      }
+      {
         \exp_last_unbraced:Nf \@@_escape_raw:N
-          { \__str_output_byte:n {#1} }
+          { \char_generate:nn {#1} { 12 } }
       }
   }
-\group_begin:
-  \char_set_catcode_other:n { 0 }
-  \cs_new:Npn \@@_escape_x_large:n #1
-    {
-      \if_false: { \fi: }
-      \__tl_build_one:o \l_@@_internal_b_tl
-      \int_compare:nNnTF {#1} > \c_max_char_int
-        {
-          \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
-          \tl_set:Nx \l_@@_internal_b_tl
-            { \if_false: } \fi:
-        }
-        {
-          \char_set_lccode:nn { 0 } {#1}
-          \tex_lowercase:D
-            {
-              \tl_set:Nx \l_@@_internal_b_tl
-                { \if_false: } \fi:
-                \@@_escape_raw:N ^^@
-            }
-        }
-    }
-\group_end:
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
-% ^^A todo: use char_generate in above and rest of file
+%
 % \begin{macro}[aux]{\@@_escape_x_test:N, \@@_escape_x_testii:N}
 %   Find out whether the first character is a left brace (allowing any
 %   number of hexadecimal digits), or not (allowing up to two
@@ -1461,7 +1546,7 @@
     \if_charcode:w \c_left_brace_str #1
       \exp_after:wN \@@_escape_x_loop:N
     \else:
-      \__str_hexadecimal_use:NTF #1
+      \@@_hexadecimal_use:NTF #1
         { \exp_after:wN \@@_escape_x:N }
         { ; \exp_after:wN \@@_escape_loop:N \exp_after:wN #1 }
     \fi:
@@ -1476,7 +1561,7 @@
   {
     \str_if_eq_x:nnTF {#1} { break } { ; }
       {
-        \__str_hexadecimal_use:NTF #1
+        \@@_hexadecimal_use:NTF #1
           { ; \@@_escape_loop:N }
           { ; \@@_escape_loop:N #1 }
       }
@@ -1494,7 +1579,7 @@
     \str_if_eq_x:nnTF {#1} { break }
       { ; \@@_escape_x_loop_error:n { } {#1} }
       {
-        \__str_hexadecimal_use:NTF #1
+        \@@_hexadecimal_use:NTF #1
           { \@@_escape_x_loop:N }
           {
             \token_if_eq_charcode:NNTF \c_space_token #1
@@ -1520,6 +1605,35 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[aux, rEXP]{\@@_hexadecimal_use:NTF}
+%   \TeX{} detects uppercase hexadecimal digits for us but not the
+%   lowercase letters, which we need to detect and replace by their
+%   uppercase counterpart.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \@@_hexadecimal_use:N #1 { TF }
+  {
+    \if_int_compare:w 1 < "1 \token_to_str:N #1 \exp_stop_f:
+      #1 \prg_return_true:
+    \else:
+      \if_case:w \__int_eval:w
+          \exp_after:wN ` \token_to_str:N #1 - `a
+        \__int_eval_end:
+           A
+      \or: B
+      \or: C
+      \or: D
+      \or: E
+      \or: F
+      \else:
+        \prg_return_false:
+        \exp_after:wN \use_none:n
+      \fi:
+      \prg_return_true:
+    \fi:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[EXP, aux]
 %   {\@@_char_if_alphanumeric:NTF, \@@_char_if_special:NTF}
 %   These two tests are used in the first pass when parsing a regular
@@ -1549,7 +1663,7 @@
   {
     \if_int_compare:w `#1 > `Z \exp_stop_f:
       \if_int_compare:w `#1 > `z \exp_stop_f:
-        \if_int_compare:w `#1 < \c__str_ascii_max_int
+        \if_int_compare:w `#1 < \c_@@_ascii_max_int
           \prg_return_true: \else: \prg_return_false: \fi:
       \else:
         \if_int_compare:w `#1 < `a \exp_stop_f:
@@ -1991,7 +2105,7 @@
 \cs_new_protected:Npn \@@_compile:n #1
   {
     \@@_compile:w
-      \int_set:Nn \tex_escapechar:D { `\\ }
+      \@@_standard_escapechar:
       \int_set_eq:NN \l_@@_mode_int \c_@@_outer_mode_int
       \@@_escape_use:nnnn
         {
@@ -2915,7 +3029,7 @@
   {
     \if_int_odd:w \__int_eval:w \l_@@_catcodes_int / #1 \__int_eval_end:
     \else:
-      \tex_advance:D \l_@@_catcodes_int #1
+      \int_add:Nn \l_@@_catcodes_int {#1}
     \fi:
   }
 \cs_new_protected:Npn \@@_compile_c_lbrack_end:
@@ -3105,8 +3219,8 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_compile_u_in_cs:
   {
-    \exp_args:NNo \__str_gset_other:Nn \g_@@_internal_tl
-      { \l_@@_internal_a_tl }
+    \tl_gset:Nx \g_@@_internal_tl
+      { \exp_args:No \__str_to_other_fast:n { \l_@@_internal_a_tl } }
     \__tl_build_one:x
       {
         \tl_map_function:NN \g_@@_internal_tl
@@ -3396,10 +3510,11 @@
 % \begin{variable}{\l_@@_min_state_int, \l_@@_max_state_int}
 %   The last state that was allocated is $\cs{l_@@_max_state_int}-1$,
 %   so that \cs{l_@@_max_state_int} always points to a free state.
-%   The \texttt{min_state} variable is always $0$, but is included to
-%   avoid hard-coding this value.
+%   The \texttt{min_state} variable is $1$, but is included to
+%   avoid hard-coding this value everywhere.
 %    \begin{macrocode}
 \int_new:N  \l_@@_min_state_int
+\int_set:Nn \l_@@_min_state_int { 1 }
 \int_new:N  \l_@@_max_state_int
 %    \end{macrocode}
 % \end{variable}
@@ -3489,7 +3604,7 @@
 \cs_new_protected:Npn \@@_build:N #1
   {
 %<trace>    \trace_push:nnn { regex } { 1 } { @@_build }
-    \int_set:Nn \tex_escapechar:D { `\\ }
+    \@@_standard_escapechar:
     \int_zero:N \l_@@_capturing_group_int
     \int_set_eq:NN \l_@@_max_state_int \l_@@_min_state_int
     \@@_build_new_state:
@@ -3557,33 +3672,6 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_toks_put_left:Nx}
-% \begin{macro}[int]{\@@_toks_put_right:Nx, \@@_toks_put_right:Nn}
-%   During the building phase we wish to add \texttt{x}-expanded
-%   material to \tn{toks}, either to the left or to the right. The
-%   expansion is done \enquote{by hand} for optimization (these
-%   operations are used quite a lot). The \texttt{Nn} version of
-%   \cs{@@_toks_put_right:Nx} is provided because it is more
-%   efficient than \texttt{x}-expanding with \cs{exp_not:n}.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_toks_put_left:Nx #1#2
-  {
-    \cs_set:Npx \@@_tmp:w { #2 }
-    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
-      { \exp_after:wN \@@_tmp:w \tex_the:D \tex_toks:D #1 }
-  }
-\cs_new_protected:Npn \@@_toks_put_right:Nx #1#2
-  {
-    \cs_set:Npx \@@_tmp:w {#2}
-    \tex_toks:D #1 \exp_after:wN
-      { \tex_the:D \tex_toks:D \exp_after:wN #1 \@@_tmp:w }
-  }
-\cs_new_protected:Npn \@@_toks_put_right:Nn #1#2
-  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
 % \begin{macro}[int]
 %   {
 %     \@@_build_transition_left:NNN,
@@ -3620,7 +3708,7 @@
         \int_eval:n { \l_@@_max_state_int + 1 }
       }
 %</trace>
-    \tex_toks:D \l_@@_max_state_int { }
+    \@@_toks_clear:N \l_@@_max_state_int
     \int_set_eq:NN \l_@@_left_state_int \l_@@_right_state_int
     \int_set_eq:NN \l_@@_right_state_int \l_@@_max_state_int
     \int_incr:N \l_@@_max_state_int
@@ -3933,15 +4021,12 @@
           ( #1 - 1 )
           * ( \l_@@_internal_b_int - \l_@@_internal_a_int )
         }
-      \tex_advance:D \l_@@_right_state_int \l_@@_internal_c_int
-      \tex_advance:D \l_@@_max_state_int   \l_@@_internal_c_int
-      \prg_replicate:nn \l_@@_internal_c_int
-        {
-          \tex_toks:D \l_@@_internal_b_int
-            = \tex_toks:D \l_@@_internal_a_int
-          \int_incr:N \l_@@_internal_a_int
-          \int_incr:N \l_@@_internal_b_int
-        }
+      \int_add:Nn \l_@@_right_state_int { \l_@@_internal_c_int }
+      \int_add:Nn \l_@@_max_state_int   { \l_@@_internal_c_int }
+      \@@_toks_memcpy:NNn
+        \l_@@_internal_b_int
+        \l_@@_internal_a_int
+        \l_@@_internal_c_int
     \fi:
   }
 %    \end{macrocode}
@@ -4132,7 +4217,7 @@
 % transitions, the instruction at the new state of the \textsc{nfa} is
 % performed immediately.  When a transition consumes a character, the
 % new state is appended to a list of \enquote{active states}, stored in
-% \tn{skip} registers: this thread will be active again when the next
+% \cs{g_@@_thread_state_intarray}: this thread will be active again when the next
 % token is read from the query.  At every step (for each token in the
 % query), we unpack that list of active states and the corresponding
 % submatch props, and empty those.
@@ -4176,7 +4261,7 @@
 %   }
 %   The tokens in the query are indexed from \texttt{min_pos} for the
 %   first to $\texttt{max_pos}-1$ for the last, and their information is
-%   stored in \tn{muskip} and \tn{toks} registers with those numbers. We
+%   stored in several arrays and \tn{toks} registers with those numbers. We
 %   don't start from $0$ because the \tn{toks} registers with low
 %   numbers are used to hold the states of the \textsc{nfa}. We match
 %   without backtracking, keeping all threads in lockstep at the
@@ -4243,15 +4328,15 @@
 %
 % \begin{variable}{\l_@@_step_int}
 %   This integer, always even, is increased every time a character in
-%   the query is read, and not reset when doing multiple matches. For
-%   each \meta{state} in the \textsc{nfa} we store in
-%   \tn{dimen}\meta{state} the last step in which this state was
-%   encountered. This lets us break infinite loops by not visiting the
-%   same state twice in the same step. In fact, \tn{dimen}\meta{state}
-%   is equal \texttt{step} when we have started performing the
-%   operations of \tn{toks}\meta{state}, but not finished yet. However,
-%   once we finish, we set \tn{dimen}\meta{state} to
-%   $\text{\texttt{step}}+1$. This is needed to track submatches
+%   the query is read, and not reset when doing multiple matches.  We
+%   store in \cs{g_@@_state_active_intarray} the last step in which each
+%   \meta{state} in the \textsc{nfa} was encountered. This lets us break
+%   infinite loops by not visiting the same state twice in the same
+%   step. In fact, the step we store is equal to \texttt{step} when we
+%   have started performing the operations of \tn{toks}\meta{state}, but
+%   not finished yet. However, once we finish, we store
+%   $\text{\texttt{step}}+1$ in \cs{g_@@_state_active_intarray}.  This is
+%   needed to track submatches
 %   properly (see building phase). The \texttt{step} is also used to
 %   attach each set of submatch information to a given iteration (and
 %   automatically discard it when it corresponds to a past step).
@@ -4261,8 +4346,8 @@
 % \end{variable}
 %
 % \begin{variable}{\l_@@_min_active_int, \l_@@_max_active_int}
-%   All the currently active states are kept in order of precedence in
-%   the \tn{skip} registers, and the corresponding submatches in the
+%   All the currently active threads are kept in order of precedence in
+%   \cs{g_@@_thread_state_intarray}, and the corresponding submatches in the
 %   \tn{toks}. For our purposes, those serve as an array, indexed from
 %   \texttt{min_active} (inclusive) to \texttt{max_active} (excluded).
 %   At the start of every step, the whole array is unpacked, so that the
@@ -4274,6 +4359,17 @@
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}{\g_@@_state_active_intarray, \g_@@_thread_state_intarray}
+%   \cs{g_@@_state_active_intarray} stores the last \meta{step} in which
+%   each \meta{state} was active.  \cs{g_@@_thread_state_intarray} stores
+%   threads that will be considered in the next step, more precisely the
+%   states in which these threads are.
+%    \begin{macrocode}
+\__intarray_new:Nn \g_@@_state_active_intarray { 65536 }
+\__intarray_new:Nn \g_@@_thread_state_intarray { 65536 }
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{variable}{\l_@@_every_match_tl}
 %   Every time a match is found, this token list is used.  For single
 %   matching, the token list is empty. For multiple matching, the token
@@ -4332,11 +4428,11 @@
 % \subsubsection{Matching: framework}
 %
 % \begin{macro}[int]{\@@_match:n}
-%   First store the query into \tn{toks} and \tn{muskip} registers (see
+%   First store the query into \tn{toks} registers and arrays (see
 %   \cs{@@_query_set:nnn}). Then initialize the variables that should
 %   be set once for each user function (even for multiple
 %   matches). Namely, the overall matching is not yet successful; none of
-%   the states should be marked as visited (\tn{dimen} registers), and
+%   the states should be marked as visited (\cs{g_@@_state_active_intarray}), and
 %   we start at step $0$; we pretend that there was a previous match
 %   ending at the start of the query, which was not empty (to avoid
 %   smothering an empty match at the start). Once all this is set up, we
@@ -4358,12 +4454,13 @@
     \bool_gset_false:N \g_@@_success_bool
     \int_step_inline:nnnn
       \l_@@_min_state_int { 1 } { \l_@@_max_state_int - 1 }
-      { \tex_dimen:D ##1 ~ 1 sp \scan_stop: }
+      { \__intarray_gset_fast:Nnn \g_@@_state_active_intarray {##1} { 1 } }
     \int_set_eq:NN \l_@@_min_active_int \l_@@_max_state_int
     \int_zero:N \l_@@_step_int
     \int_set_eq:NN \l_@@_success_pos_int \l_@@_min_pos_int
-    \int_set:Nn \l_@@_submatch_int
+    \int_set:Nn \l_@@_min_submatch_int
       { 2 * \l_@@_max_state_int }
+    \int_set_eq:NN \l_@@_submatch_int \l_@@_min_submatch_int
     \bool_set_false:N \l_@@_empty_success_bool
     \@@_match_once:
 %<trace>    \trace_pop:nnx { regex } { 1 } { @@_match }
@@ -4433,7 +4530,7 @@
 % \end{macro}
 %
 % \begin{macro}[aux]{\@@_match_loop:}
-% \begin{macro}[aux, rEXP]{\@@_match_one_active:w}
+% \begin{macro}[aux, rEXP]{\@@_match_one_active:n}
 %   At each new position, set some variables and get the new character
 %   and category from the query. Then unpack the array of active
 %   threads, and clear it by resetting its length
@@ -4448,7 +4545,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_match_loop:
   {
-    \tex_advance:D \l_@@_step_int 2 \exp_stop_f:
+    \int_add:Nn \l_@@_step_int { 2 }
     \int_incr:N \l_@@_current_pos_int
     \int_set_eq:NN \l_@@_last_char_int \l_@@_current_char_int
     \int_set_eq:NN \l_@@_case_changed_char_int \c_max_int
@@ -4456,8 +4553,11 @@
     \use:x
       {
         \int_set_eq:NN \l_@@_max_active_int \l_@@_min_active_int
-        \exp_after:wN \@@_match_one_active:w
-          \int_use:N \l_@@_min_active_int ;
+        \int_step_function:nnnN
+          { \l_@@_min_active_int }
+          { 1 }
+          { \l_@@_max_active_int - 1 }
+          \@@_match_one_active:n
       }
     \__prg_break_point:
     \bool_set_false:N \l_@@_fresh_thread_bool %^^A was arg of break_point:n
@@ -4467,15 +4567,11 @@
       \fi:
     \fi:
   }
-\cs_new:Npn \@@_match_one_active:w #1;
+\cs_new:Npn \@@_match_one_active:n #1
   {
-    \if_int_compare:w #1 < \l_@@_max_active_int
-      \@@_use_state_and_submatches:nn
-        { \__int_value:w \tex_skip:D #1 }
-        { \tex_the:D \tex_toks:D #1 }
-      \exp_after:wN \@@_match_one_active:w
-        \__int_value:w \__int_eval:w #1 + 1 \exp_after:wN ;
-    \fi:
+    \@@_use_state_and_submatches:nn
+      { \__intarray_item_fast:Nn \g_@@_thread_state_intarray {#1} }
+      { \@@_toks_use:w #1 }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4485,18 +4581,18 @@
 %   The arguments are: tokens that \texttt{o} and \texttt{x} expand to
 %   one token of the query, the catcode, and the character code. Store
 %   those, and the current brace balance (used later to check for
-%   overall brace balance) in a \tn{muskip} register and a \tn{toks},
+%   overall brace balance) in a \tn{toks} register and some arrays,
 %   then update the \texttt{balance}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_query_set:nnn #1#2#3
   {
-    \tex_muskip:D \l_@@_current_pos_int
-      = \etex_gluetomu:D
-        #3 sp
-        plus #2 sp
-        minus \l_@@_balance_int sp
-      \scan_stop:
-    \tex_toks:D \l_@@_current_pos_int {#1}
+    \__intarray_gset_fast:Nnn \g_@@_charcode_intarray
+      { \l_@@_current_pos_int } {#3}
+    \__intarray_gset_fast:Nnn \g_@@_catcode_intarray
+      { \l_@@_current_pos_int } {#2}
+    \__intarray_gset_fast:Nnn \g_@@_balance_intarray
+      { \l_@@_current_pos_int } { \l_@@_balance_int }
+    \@@_toks_set:Nn \l_@@_current_pos_int {#1}
     \int_incr:N \l_@@_current_pos_int
     \if_case:w #2 \exp_stop_f:
     \or: \int_incr:N \l_@@_balance_int
@@ -4507,17 +4603,17 @@
 % \end{macro}
 %
 % \begin{macro}[aux]{\@@_query_get:}
-%   Extract the current character and category codes from the
-%   \tn{muskip} register of the current position: those are the main and
-%   the stretch components, and we need a conversion to avoid \TeX{}'s
-%   \enquote{incompatible glue units} error.
+%   Extract the current character and category codes at the current
+%   position from the appropriate arrays.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_query_get:
   {
     \l_@@_current_char_int
-      = \etex_mutoglue:D \tex_muskip:D \l_@@_current_pos_int
-    \l_@@_current_catcode_int = \etex_gluestretch:D
-      \etex_mutoglue:D \tex_muskip:D \l_@@_current_pos_int
+      = \__intarray_item_fast:Nn \g_@@_charcode_intarray
+          { \l_@@_current_pos_int } \scan_stop:
+    \l_@@_current_catcode_int
+      = \__intarray_item_fast:Nn \g_@@_catcode_intarray
+          { \l_@@_current_pos_int } \scan_stop:
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4537,11 +4633,11 @@
 %<*trace>
     \trace:nnx { regex } { 2 } { state~\int_use:N \l_@@_current_state_int }
 %</trace>
-    \tex_dimen:D \l_@@_current_state_int
-      = \l_@@_step_int sp \scan_stop:
-    \tex_the:D \tex_toks:D \l_@@_current_state_int
-    \tex_dimen:D \l_@@_current_state_int
-      = \__int_eval:w \l_@@_step_int + 1 \__int_eval_end: sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g_@@_state_active_intarray
+      { \l_@@_current_state_int } { \l_@@_step_int }
+    \@@_toks_use:w \l_@@_current_state_int
+    \__intarray_gset_fast:Nnn \g_@@_state_active_intarray
+      { \l_@@_current_state_int } { \l_@@_step_int + 1 }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4555,7 +4651,9 @@
 \cs_new_protected:Npn \@@_use_state_and_submatches:nn #1 #2
   {
     \int_set:Nn \l_@@_current_state_int {#1}
-    \if_int_compare:w \tex_dimen:D \l_@@_current_state_int
+    \if_int_compare:w
+        \__intarray_item_fast:Nn \g_@@_state_active_intarray
+          { \l_@@_current_state_int }
                       < \l_@@_step_int
       \tl_set:Nn \l_@@_current_submatches_prop {#2}
       \exp_after:wN \@@_use_state:
@@ -4610,7 +4708,10 @@
         \int_add:Nn \l_@@_current_state_int {#2}
         \exp_not:n
           {
-            \if_int_compare:w \tex_dimen:D \l_@@_current_state_int #1
+            \if_int_compare:w
+                \__intarray_item_fast:Nn \g_@@_state_active_intarray
+                  { \l_@@_current_state_int }
+                #1
               \exp_after:wN \@@_use_state:
             \fi:
           }
@@ -4626,7 +4727,7 @@
 %
 % \begin{macro}[int]{\@@_action_cost:n}
 %   A transition which consumes the current character and shifts the
-%   state by |#1|.  The resulting state is stored in the \tn{skip} array
+%   state by |#1|.  The resulting state is stored in the appropriate array
 %   for use at the next position, and we also store the current
 %   submatches.
 %    \begin{macrocode}
@@ -4640,22 +4741,20 @@
 %
 % \begin{macro}[int]{\@@_store_state:n}
 % \begin{macro}[aux]{\@@_store_submatches:}
-%   Put the given state in the array of \tn{skip} registers (converted
-%   to a dimension in scaled points), and increment the length of the
-%   array. Then store the current submatch in the This is done by
-%   increasing the pointer \cs{l_@@_max_active_int}, and converting
-%   the integer to a dimension (suitable for a \tn{skip} assignment) in
-%   scaled points.
+%   Put the given state in \cs{g_@@_thread_state_intarray}, and increment
+%   the length of the array. Also store the current submatch in the
+%   appropriate \tn{toks}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_store_state:n #1
   {
     \@@_store_submatches:
-    \tex_skip:D \l_@@_max_active_int = #1 sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g_@@_thread_state_intarray
+      { \l_@@_max_active_int } {#1}
     \int_incr:N \l_@@_max_active_int
   }
 \cs_new_protected:Npn \@@_store_submatches:
   {
-    \tex_toks:D \l_@@_max_active_int \exp_after:wN
+    \@@_toks_set:No \l_@@_max_active_int
       { \l_@@_current_submatches_prop }
   }
 %    \end{macrocode}
@@ -4729,6 +4828,15 @@
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}{\l_@@_replacement_category_tl, \l_@@_replacement_category_seq}
+%   This sequence of letters is used to correctly restore categories in
+%   nested constructions such as |\cL(abc\cD(_)d)|.
+%    \begin{macrocode}
+\tl_new:N \l_@@_replacement_category_tl
+\seq_new:N \l_@@_replacement_category_seq
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{variable}{\l_@@_balance_tl}
 %   This token list holds the replacement text for
 %   \cs{@@_replacement_balance_one_match:n} while it is being built
@@ -4739,8 +4847,9 @@
 % \end{variable}
 %
 % \begin{macro}[aux, rEXP]{\@@_replacement_balance_one_match:n}
-%   This expects as an argument the first index of a range of \tn{skip}
-%   registers which hold the submatch information for a given match. It
+%   This expects as an argument the first index of a set of entries in
+%   \cs{g_@@_submatch_begin_intarray} (and related arrays) which hold the
+%   submatch information for a given match. It
 %   can be used within an integer expression to obtain the brace balance
 %   incurred by performing the replacement on that match. This combines
 %   the braces lost by removing the match, braces added by all the
@@ -4764,13 +4873,13 @@
 %   with all possible arguments (one call for each match), as well as
 %   the range from the end of the last match to the end of the string,
 %   will produce the fully replaced token list. The initialization does
-%   not matter, but we set it as for an empty replacement.
+%   not matter, but (as an example) we set it as for an empty replacement.
 %    \begin{macrocode}
 \cs_new:Npn \@@_replacement_do_one_match:n #1
   {
     \@@_query_range:nn
-      { \etex_glueshrink:D \tex_skip:D #1 }
-      { \tex_skip:D #1 }
+      { \__intarray_item_fast:Nn \g_@@_submatch_prev_intarray {#1} }
+      { \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray {#1} }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4816,7 +4925,7 @@
     \else:
       \exp_after:wN \__prg_break:
     \fi:
-    \tex_the:D \tex_toks:D #1 \exp_stop_f:
+    \@@_toks_use:w #1 \exp_stop_f:
     \exp_after:wN \@@_query_range_loop:ww
       \__int_value:w \__int_eval:w #1 + 1 ; #2 ;
   }
@@ -4825,17 +4934,13 @@
 % \end{macro}
 %
 % \begin{macro}[int]{\@@_query_submatch:n}
-%   When this function is called, \tn{skip}$i$ holds the start and end
-%   positions for the $i$-th overall submatch as its main and stretch
-%   components. In the case of repeated matches, submatches from all the
-%   matches are put one after the other in blocks of
-%   \cs{l_@@_capturing_group_int} \tn{skip} registers.
+%   Find the start and end positions for a given submatch (of a given match).
 %    \begin{macrocode}
 \cs_new:Npn \@@_query_submatch:n #1
   {
     \@@_query_range:nn
-      { \tex_skip:D \__int_eval:w #1 }
-      { \etex_gluestretch:D \tex_skip:D \__int_eval:w #1 }
+      { \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray {#1} }
+      { \__intarray_item_fast:Nn \g_@@_submatch_end_intarray {#1} }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4843,21 +4948,31 @@
 % \begin{macro}[rEXP]{\@@_submatch_balance:n}
 %   Every user function must result in a balanced token list (unbalanced
 %   token lists cannot be stored by TeX). When we unpacked the query, we
-%   kept track of the brace balance as the shrink component of
-%   \tn{muskip} registers, hence the contribution from a given range is
-%   the difference between the shrink components of
-%   \tn{muskip}\meta{max~pos} and \tn{muskip}\meta{min~pos}. For the
-%   $i$-th submatch, the end-points of the range are the main and
-%   stretch components of \tn{skip}$i$. The trailing \cs{scan_stop:} is
-%   gobbled by \cs{etex_muexpr:D}, and the whole expression can be cast
-%   safely to an integer (no trailing expansion).
+%   kept track of the brace balance, hence the contribution from a given
+%   range is the difference between the brace balances at the
+%   \meta{max~pos} and \meta{min~pos}.  These two positions are found in
+%   the corresponding \enquote{submatch} arrays.
+%^^A todo: understand when these int_compare are needed
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_submatch_balance:n #1
   {
-    \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D
-      \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1
-      - \tex_muskip:D \tex_skip:D #1
-    \scan_stop:
+    \__int_eval:w
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g_@@_submatch_end_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g_@@_balance_intarray
+            { \__intarray_item_fast:Nn \g_@@_submatch_end_intarray {#1} }
+        }
+      -
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g_@@_balance_intarray
+            { \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray {#1} }
+        }
+    \__int_eval_end:
   }
 %    \end{macrocode}
 % \end{macro}
@@ -4886,10 +5001,14 @@
       \@@_escape_use:nnnn
         {
           \if_charcode:w \c_right_brace_str ##1
-            \@@_replacement_rbrace:N \else: \__tl_build_one:n \fi: ##1
+            \@@_replacement_rbrace:N
+          \else:
+            \@@_replacement_normal:n
+          \fi:
+          ##1
         }
         { \@@_replacement_escaped:N ##1 }
-        { \__tl_build_one:n ##1 }
+        { \@@_replacement_normal:n ##1 }
         {#1}
       \prg_do_nothing: \prg_do_nothing:
       \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
@@ -4898,6 +5017,12 @@
         \__tl_build_one:x
           { \prg_replicate:nn \l_@@_replacement_csnames_int \cs_end: }
       \fi:
+      \seq_if_empty:NF \l_@@_replacement_category_seq
+        {
+          \__msg_kernel_error:nnx { regex } { replacement-missing-rparen }
+            { \seq_count:N \l_@@_replacement_category_seq }
+          \seq_clear:N \l_@@_replacement_category_seq
+        }
       \cs_gset:Npx \@@_replacement_balance_one_match:n ##1
         {
           + \int_use:N \l_@@_balance_int
@@ -4913,8 +5038,8 @@
     \cs_set:Npn \@@_replacement_do_one_match:n ##1
       {
         \@@_query_range:nn
-          { \etex_glueshrink:D \tex_skip:D ##1 }
-          { \tex_skip:D ##1 }
+          { \__intarray_item_fast:Nn \g_@@_submatch_prev_intarray {##1} }
+          { \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray {##1} }
         #1
       }
   }
@@ -4922,6 +5047,35 @@
 % \end{macro}
 % \end{macro}
 %
+% \begin{macro}[aux]{\@@_replacement_normal:n}
+%   Most characters are simply sent to the output by
+%   \cs{__tl_build_one:n}, unless a particular category code has been
+%   requested: then \cs{@@_replacement_c_A:w} or a similar auxiliary is
+%   called.  One exception is right parentheses, which restore the
+%   category code in place before the group started.  Note that the
+%   sequence is non-empty there: it contains an empty entry
+%   corresponding to the initial value of
+%   \cs{l_@@_replacement_category_tl}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_replacement_normal:n #1
+  {
+    \tl_if_empty:NTF \l_@@_replacement_category_tl
+      { \__tl_build_one:n {#1} }
+      { % (
+        \token_if_eq_charcode:NNTF #1 )
+          {
+            \seq_pop:NN \l_@@_replacement_category_seq
+              \l_@@_replacement_category_tl
+          }
+          {
+            \use:c { @@_replacement_c_ \l_@@_replacement_category_tl :w }
+              \@@_replacement_normal:n {#1}
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[aux]{\@@_replacement_escaped:N}
 %   As in parsing a regular expression, we use an auxiliary built from
 %   |#1| if defined. Otherwise, check for escaped digits (standing from
@@ -4935,7 +5089,8 @@
         \if_int_compare:w 1 < 1#1 \exp_stop_f:
           \@@_replacement_put_submatch:n {#1}
         \else:
-          \__tl_build_one:o { \token_to_str:N #1 }
+          \exp_args:No \@@_replacement_normal:n
+            { \token_to_str:N #1 }
         \fi:
       }
   }
@@ -4967,34 +5122,34 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[aux]{\@@_replacement_g:w, \@@_replacement_g_digits:NN}
-%   An ugly method to grab digits for the |\g| escape sequence. At the
-%   end of the run of digits, check that it ends with a right brace.
+% \begin{macro}[aux]{\@@_replacement_g:w}
+% \begin{macro}[aux,rEXP]{\@@_replacement_g_digits:NN}
+%   Grab digits for the |\g| escape sequence in a primitive assignment
+%   to the integer \cs{l_@@_internal_a_int}.  At the end of the run of
+%   digits, check that it ends with a right brace.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_replacement_g:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \int_zero:N \l_@@_internal_a_int
-        \@@_replacement_g_digits:NN
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \@@_replacement_normal:n \c_left_brace_str }
+      { \l_@@_internal_a_int = \@@_replacement_g_digits:NN }
       { \@@_replacement_error:NNN g #1 #2 }
   }
-\cs_new_protected:Npn \@@_replacement_g_digits:NN #1#2
+\cs_new:Npn \@@_replacement_g_digits:NN #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \@@_replacement_normal:n
       {
         \if_int_compare:w 1 < 1#2 \exp_stop_f:
-          \int_set:Nn \l_@@_internal_a_int
-            { 10 * \l_@@_internal_a_int + #2 }
+          #2
           \exp_after:wN \use_i:nnn
           \exp_after:wN \@@_replacement_g_digits:NN
         \else:
+          \exp_stop_f:
           \exp_after:wN \@@_replacement_error:NNN
           \exp_after:wN g
         \fi:
       }
       {
+        \exp_stop_f:
         \if_meaning:w \@@_replacement_rbrace:N #1
           \exp_args:No \@@_replacement_put_submatch:n
             { \int_use:N \l_@@_internal_a_int }
@@ -5008,41 +5163,52 @@
   }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
 % \subsubsection{Csnames in replacement}
 %
 % \begin{macro}[aux]{\@@_replacement_c:w}
-% \begin{macro}[aux]+\@@_replacement_c_{:w+
-%   |\c| can be followed by a left brace, or by a letter for which we
-%   have defined a way to produce that category of characters.  The
-%   appropriate definitions for catcodes are introduced later.  For
-%   control sequences, if we are within a control sequence, convert
-%   the token list to a string, otherwise simply prevent expansion,
-%   with a weird cross-over between \cs{exp_not:n} and \cs{exp_not:N}
-%   (see this helper's description for an explanation).
+%   |\c| may only be followed by an unescaped character.  If followed by
+%   a left brace, start a control sequence by calling an auxiliary
+%   common with |\u|.  Otherwise test whether the category is known; if
+%   it is not, complain.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_replacement_c:w #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \@@_replacement_normal:n
       {
-        \cs_if_exist_use:cF { @@_replacement_c_#2:w }
-          { \@@_replacement_error:NNN c #1#2 }
+        \exp_after:wN \token_if_eq_charcode:NNTF \c_left_brace_str #2
+          { \@@_replacement_cu_aux:Nw \@@_replacement_exp_not:N }
+          {
+            \cs_if_exist:cTF { @@_replacement_c_#2:w }
+              { \@@_replacement_cat:NNN #2 }
+              { \@@_replacement_error:NNN c #1#2 }
+          }
       }
       { \@@_replacement_error:NNN c #1#2 }
   }
-\cs_new_protected:cpn { @@_replacement_c_ \c_left_brace_str :w }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_replacement_cu_aux:Nw}
+%   Start a control sequence with \cs{cs:w}, which will be protected
+%   from expansion by |#1| (either \cs{@@_replacement_exp_not:N} or
+%   \cs{exp_not:V}), or turned to a string by \cs{tl_to_str:V} if inside
+%   another csname construction |\c| or |\u|.  We use \cs{tl_to_str:V}
+%   rather than \cs{tl_to_str:N} to deal with integers and other
+%   registers.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_replacement_cu_aux:Nw #1
   {
     \if_case:w \l_@@_replacement_csnames_int
-      \__tl_build_one:n
-        { \exp_not:n { \exp_after:wN \@@_replacement_exp_not:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN #1 \cs:w } }
     \else:
-      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
     \fi:
     \int_incr:N \l_@@_replacement_csnames_int
   }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
 % \begin{macro}[aux]{\@@_replacement_u:w}
 %   Check that |\u| is followed by a left brace. If so, start a control
@@ -5051,15 +5217,8 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_replacement_u:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \if_case:w \l_@@_replacement_csnames_int
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } }
-        \else:
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
-        \fi:
-        \int_incr:N \l_@@_replacement_csnames_int
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \@@_replacement_normal:n \c_left_brace_str }
+      { \@@_replacement_cu_aux:Nw \exp_not:V }
       { \@@_replacement_error:NNN u #1#2 }
   }
 %    \end{macrocode}
@@ -5076,7 +5235,7 @@
       \__tl_build_one:n \cs_end:
       \int_decr:N \l_@@_replacement_csnames_int
     \else:
-      \__tl_build_one:n #1
+      \@@_replacement_normal:n {#1}
     \fi:
   }
 %    \end{macrocode}
@@ -5084,6 +5243,39 @@
 %
 % \subsubsection{Characters in replacement}
 %
+% \begin{macro}[aux]{\@@_replacement_cat:NNN}
+%   Here, |#1| is a letter among |BEMTPUDSLOA| and |#2#3| denote the
+%   next character.  Complain if we reach the end of the replacement or
+%   if the construction appears inside |\c{|\ldots{}|}| or
+%   |\u{|\ldots{}|}|, and detect the case of a parenthesis.  In that
+%   case, store the current category in a sequence and switch to a new
+%   one.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_replacement_cat:NNN #1#2#3
+  {
+    \token_if_eq_meaning:NNTF \prg_do_nothing: #3
+      { \__msg_kernel_error:nn { regex } { replacement-catcode-end } }
+      {
+        \int_compare:nNnTF { \l_@@_replacement_csnames_int } > 0
+          {
+            \__msg_kernel_error:nnnn
+              { regex } { replacement-catcode-in-cs } {#1} {#3}
+            #2 #3
+          }
+          {
+            \str_if_eq:nnTF { #2 #3 } { \@@_replacement_normal:n ( } % )
+              {
+                \seq_push:NV \l_@@_replacement_category_seq
+                  \l_@@_replacement_category_tl
+                \tl_set:Nn \l_@@_replacement_category_tl {#1}
+              }
+              { \use:c { @@_replacement_c_#1:w } #2 #3 }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % We will need to change the category code of the null character many
 % times, hence work in a group. The catcode-specific macros below are
 % defined in alphabetical order; if you are trying to understand the
@@ -5099,16 +5291,13 @@
 %   wrapper for our purposes. The first argument is the null character
 %   with various catcodes. The second and third arguments are grabbed
 %   from the input stream: |#3| is the character whose character code to
-%   reproduce.
+%   reproduce.  We could use \cs{char_generate:nn} but only for some
+%   catcodes (active characters and spaces are not supported).
 %    \begin{macrocode}
   \cs_new_protected:Npn \@@_replacement_char:nNN #1#2#3
     {
-      \if_meaning:w \prg_do_nothing: #3
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \tex_lccode:D 0 = `#3 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {#1} }
-      \fi:
+      \tex_lccode:D 0 = `#3 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {#1} }
     }
 %    \end{macrocode}
 % \end{macro}
@@ -5234,15 +5423,11 @@
 %    \begin{macrocode}
   \cs_new_protected:Npn \@@_replacement_c_S:w #1#2
     {
-      \if_meaning:w \prg_do_nothing: #2
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \if_int_compare:w `#2 = 0 \exp_stop_f:
-          \__msg_kernel_error:nn { regex } { replacement-null-space }
-        \fi:
-        \tex_lccode:D `\ = `#2 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {~} }
+      \if_int_compare:w `#2 = 0 \exp_stop_f:
+        \__msg_kernel_error:nn { regex } { replacement-null-space }
       \fi:
+      \tex_lccode:D `\ = `#2 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {~} }
     }
 %    \end{macrocode}
 % \end{macro}
@@ -5433,23 +5618,32 @@
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{variable}{\l_@@_submatch_int, \l_@@_zeroth_submatch_int}
-%   The end-points of each submatch are stored as main and stretch
-%   components of \tn{skip}\meta{submatch}, where \meta{submatch} ranges
-%   from \cs{l_@@_max_state_int} (inclusive) to
+% \begin{variable}{\l_@@_min_submatch_int, \l_@@_submatch_int, \l_@@_zeroth_submatch_int}
+%   The end-points of each submatch are stored in two arrays whose index \meta{submatch} ranges
+%   from \cs{l_@@_min_submatch_int} (inclusive) to
 %   \cs{l_@@_submatch_int} (exclusive). Each successful match comes
 %   with a $0$-th submatch (the full match), and one match for each
 %   capturing group: submatches corresponding to the last successful
-%   match are labelled starting at
-%   \texttt{zeroth_submatch}. Additionally, the shrink component of this
-%   $0$-th submatch is the position at which that match attempt started:
-%   this is used for splitting and replacements.
+%   match are labelled starting at \texttt{zeroth_submatch}. The entry
+%   \cs{l_@@_zeroth_submatch_int} in \cs{g_@@_submatch_prev_intarray} holds
+%   the position at which that match attempt started: this is used for
+%   splitting and replacements.
 %    \begin{macrocode}
+\int_new:N \l_@@_min_submatch_int
 \int_new:N \l_@@_submatch_int
 \int_new:N \l_@@_zeroth_submatch_int
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}{\g_@@_submatch_prev_intarray, \g_@@_submatch_begin_intarray, \g_@@_submatch_end_intarray}
+%   Hold the place where the match attempt begun and the end-points of each submatch.
+%    \begin{macrocode}
+\__intarray_new:Nn \g_@@_submatch_prev_intarray { 65536 }
+\__intarray_new:Nn \g_@@_submatch_begin_intarray { 65536 }
+\__intarray_new:Nn \g_@@_submatch_end_intarray { 65536 }
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{macro}[aux]{\@@_return:}
 %   This function triggers either \cs{prg_return_false:} or
 %   \cs{prg_return_true:} as appropriate to whether a match was found or
@@ -5543,8 +5737,7 @@
 %   match, store the last part of the token list, which ranges from the
 %   start of the match attempt to the end of the query. This step is
 %   inhibited if the last match was empty and at the very end: decrement
-%   \cs{l_@@_submatch_int}, which controls which \tn{skip} registers
-%   will be used.
+%   \cs{l_@@_submatch_int}, which controls which matches will be used.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_split:nnN #1#2#3
   {
@@ -5553,16 +5746,30 @@
         {
           \if_int_compare:w \l_@@_start_pos_int < \l_@@_success_pos_int
             \@@_extract:
-            \tex_skip:D \l_@@_zeroth_submatch_int
-              = \l_@@_start_pos_int sp
-                plus \tex_skip:D \l_@@_zeroth_submatch_int \scan_stop:
+            \__intarray_gset_fast:Nnn \g_@@_submatch_prev_intarray
+              { \l_@@_zeroth_submatch_int } { 0 }
+            \__intarray_gset_fast:Nnn \g_@@_submatch_end_intarray
+              { \l_@@_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g_@@_submatch_begin_intarray
+                  { \l_@@_zeroth_submatch_int }
+              }
+            \__intarray_gset_fast:Nnn \g_@@_submatch_begin_intarray
+              { \l_@@_zeroth_submatch_int }
+              { \l_@@_start_pos_int }
           \fi:
         }
       #1
       \@@_match:n {#2}
 %<assert>\assert_int:n { \l_@@_current_pos_int = \l_@@_max_pos_int }
-      \tex_skip:D \l_@@_submatch_int
-        = \l_@@_start_pos_int sp plus \l_@@_max_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g_@@_submatch_prev_intarray
+        { \l_@@_submatch_int } { 0 }
+      \__intarray_gset_fast:Nnn \g_@@_submatch_end_intarray
+        { \l_@@_submatch_int }
+        { \l_@@_max_pos_int }
+      \__intarray_gset_fast:Nnn \g_@@_submatch_begin_intarray
+        { \l_@@_submatch_int }
+        { \l_@@_start_pos_int }
       \int_incr:N \l_@@_submatch_int
       \if_meaning:w \c_true_bool \l_@@_empty_success_bool
         \if_int_compare:w \l_@@_start_pos_int = \l_@@_max_pos_int
@@ -5575,8 +5782,8 @@
 % \end{macro}
 %
 % \begin{macro}[aux]{\@@_group_end_extract_seq:N}
-%   The end-points of submatches are stored as the main and stretch
-%   components of \tn{skip} registers from \cs{l_@@_max_state_int} to
+%   The end-points of submatches are stored as entries of two arrays
+%   from \cs{l_@@_min_submatch_int} to
 %   \cs{l_@@_submatch_int} (exclusive). Extract the relevant ranges
 %   into \cs{l_@@_internal_a_tl}. We detect unbalanced results using
 %   the two flags \texttt{@@_begin} and \texttt{@@_end}, raised
@@ -5593,7 +5800,7 @@
         {
           \s__seq
           \int_step_function:nnnN
-            { 2 * \l_@@_max_state_int }
+            { \l_@@_min_submatch_int }
             { 1 }
             { \l_@@_submatch_int - 1 }
             \@@_extract_seq_aux:n
@@ -5649,14 +5856,14 @@
 %   {\@@_extract:, \@@_extract_b:wn, \@@_extract_e:wn}
 %   Our task here is to extract from the property list
 %   \cs{l_@@_success_submatches_prop} the list of end-points of
-%   submatches, and store them in \tn{skip} registers, from
+%   submatches, and store them in appropriate array entries, from
 %   \cs{l_@@_zeroth_submatch_int} upwards. We begin by emptying those
-%   \tn{skip} registers. Then for each \meta{key}--\meta{value} pair in
-%   the property list update the appropriate \tn{skip} component. This
+%   entries. Then for each \meta{key}--\meta{value} pair in
+%   the property list update the appropriate entry. This
 %   is somewhat a hack: the \meta{key} is a non-negative integer
 %   followed by |<| or |>|, which we use in a comparison to $-1$. At the
 %   end, store the information about the position at which the match
-%   attempt started, as a shrink component.
+%   attempt started, in \cs{g_@@_submatch_prev_intarray}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_extract:
   {
@@ -5664,7 +5871,12 @@
       \int_set_eq:NN \l_@@_zeroth_submatch_int \l_@@_submatch_int
       \prg_replicate:nn \l_@@_capturing_group_int
         {
-          \tex_skip:D \l_@@_submatch_int 0 sp \scan_stop:
+          \__intarray_gset_fast:Nnn \g_@@_submatch_begin_intarray
+            { \l_@@_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g_@@_submatch_end_intarray
+            { \l_@@_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g_@@_submatch_prev_intarray
+            { \l_@@_submatch_int } { 0 }
           \int_incr:N \l_@@_submatch_int
         }
       \prop_map_inline:Nn \l_@@_success_submatches_prop
@@ -5676,21 +5888,14 @@
           \fi:
           \__int_eval:w \l_@@_zeroth_submatch_int + ##1 {##2}
         }
-      \tex_skip:D \l_@@_zeroth_submatch_int
-        = \tex_the:D \tex_skip:D \l_@@_zeroth_submatch_int
-          minus \l_@@_start_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g_@@_submatch_prev_intarray
+        { \l_@@_zeroth_submatch_int } { \l_@@_start_pos_int }
     \fi:
   }
 \cs_new_protected:Npn \@@_extract_b:wn #1 < #2
-  {
-    \tex_skip:D #1 = #2 sp
-      plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g_@@_submatch_begin_intarray {#1} {#2} }
 \cs_new_protected:Npn \@@_extract_e:wn #1 > #2
-  {
-    \tex_skip:D #1
-      = 1 \tex_skip:D #1 plus #2 sp \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g_@@_submatch_end_intarray {#1} {#2} }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -5730,7 +5935,10 @@
           {
             \@@_replacement_do_one_match:n { \l_@@_zeroth_submatch_int }
             \@@_query_range:nn
-              { \etex_gluestretch:D \tex_skip:D \l_@@_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g_@@_submatch_end_intarray
+                  { \l_@@_zeroth_submatch_int }
+              }
               { \l_@@_max_pos_int }
           }
         \@@_group_end_replace:N #3
@@ -5741,12 +5949,11 @@
 %
 % \begin{macro}[aux]{\@@_replace_all:nnN}
 %   Match multiple times, and for every match, extract submatches and
-%   additionally store the position at which the match attempt started
-%   (as the shrink component of a \tn{skip} register). The \tn{skip}
-%   registers from \cs{l_@@_max_state_int} to
+%   additionally store the position at which the match attempt started.
+%   The entries from \cs{l_@@_min_submatch_int} to
 %   \cs{l_@@_submatch_int} hold information about submatches of every
 %   match in order; each match corresponds to
-%   \cs{l_@@_capturing_group_int} consecutive \tn{skip} registers.
+%   \cs{l_@@_capturing_group_int} consecutive entries.
 %   Compute the brace balance corresponding to doing all the
 %   replacements: this is the sum of brace balances for replacing each
 %   match. Join together the replacement texts for each match (including
@@ -5763,7 +5970,7 @@
         {
           0
           \int_step_function:nnnN
-            { 2 * \l_@@_max_state_int }
+            { \l_@@_min_submatch_int }
             \l_@@_capturing_group_int
             { \l_@@_submatch_int - 1 }
             \@@_replacement_balance_one_match:n
@@ -5771,7 +5978,7 @@
       \tl_set:Nx \l_@@_internal_a_tl
         {
           \int_step_function:nnnN
-            { 2 * \l_@@_max_state_int }
+            { \l_@@_min_submatch_int }
             \l_@@_capturing_group_int
             { \l_@@_submatch_int - 1 }
             \@@_replacement_do_one_match:n
@@ -5825,23 +6032,23 @@
 % Messages for the preparsing phase.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { trailing-backslash }
-  { Trailing~escape~character~`\iow_char:N\\'. }
+  { Trailing~escape~character~'\iow_char:N\\'. }
   {
     A~regular~expression~or~its~replacement~text~ends~with~
-    the~escape~character~`\iow_char:N\\'.~It~will~be~ignored.
+    the~escape~character~'\iow_char:N\\'.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { x-missing-rbrace }
-  { Missing~closing~brace~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Missing~closing~brace~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{...#1'.~
+    '\iow_char:N\\x\{...#1'.~
     The~closing~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { x-overflow }
-  { Character~code~`#1'~too~large~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Character~code~'#1'~too~large~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
+    '\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
     The~character~code~#1~is~larger~than~
     the~maximum~value~\int_use:N \c_max_char_int.
   }
@@ -5850,11 +6057,11 @@
 % Invalid quantifier.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { invalid-quantifier }
-  { Braced~quantifier~`#1'~may~not~be~followed~by~`#2'. }
+  { Braced~quantifier~'#1'~may~not~be~followed~by~'#2'. }
   {
-    The~character~`#2'~is~invalid~in~the~braced~quantifier~`#1'.~
-    The~only~valid~quantifiers~are~`*',~`?',~`+',~`{<int>}',~
-    `{<min>,}'~and~`{<min>,<max>}',~optionally~followed~by~`?'.
+    The~character~'#2'~is~invalid~in~the~braced~quantifier~'#1'.~
+    The~only~valid~quantifiers~are~'*',~'?',~'+',~'{<int>}',~
+    '{<min>,}'~and~'{<min>,<max>}',~optionally~followed~by~'?'.
   }
 %    \end{macrocode}
 %
@@ -5865,7 +6072,7 @@
   { Missing~right~bracket~inserted~in~regular~expression. }
   {
     LaTeX~was~given~a~regular~expression~where~a~character~class~
-    was~started~with~`[',~but~the~matching~`]'~is~missing.
+    was~started~with~'[',~but~the~matching~']'~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { missing-rparen }
   {
@@ -5889,7 +6096,7 @@
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { bad-escape }
   {
-    Invalid~escape~`\iow_char:N\\#1'~
+    Invalid~escape~'\iow_char:N\\#1'~
     \@@_if_in_cs:TF { within~a~control~sequence. }
       {
         \@@_if_in_class:TF
@@ -5898,16 +6105,16 @@
       }
   }
   {
-    The~escape~sequence~`\iow_char:N\\#1'~may~not~appear~
+    The~escape~sequence~'\iow_char:N\\#1'~may~not~appear~
     \@@_if_in_cs:TF
       {
         within~a~control~sequence~test~introduced~by~
-        `\iow_char:N\\c\iow_char:N\{'.
+        '\iow_char:N\\c\iow_char:N\{'.
       }
       {
         \@@_if_in_class:TF
           { within~a~character~class~ }
-          { following~a~category~test~such~as~`\iow_char:N\\cL'~ }
+          { following~a~category~test~such~as~'\iow_char:N\\cL'~ }
         because~it~does~not~match~exactly~one~character.
       }
   }
@@ -5916,19 +6123,19 @@
 % Range errors.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { range-missing-end }
-  { Invalid~end-point~for~range~`#1-#2'~in~character~class. }
+  { Invalid~end-point~for~range~'#1-#2'~in~character~class. }
   {
-    The~end-point~`#2'~of~the~range~`#1-#2'~may~not~serve~as~an~
+    The~end-point~'#2'~of~the~range~'#1-#2'~may~not~serve~as~an~
     end-point~for~a~range:~alphanumeric~characters~should~not~be~
     escaped,~and~non-alphanumeric~characters~should~be~escaped.
   }
 \__msg_kernel_new:nnnn { regex } { range-backwards }
-  { Range~`[#1-#2]'~out~of~order~in~character~class. }
+  { Range~'[#1-#2]'~out~of~order~in~character~class. }
   {
-    In~ranges~of~characters~`[x-y]'~appearing~in~character~classes,~
+    In~ranges~of~characters~'[x-y]'~appearing~in~character~classes,~
     the~first~character~code~must~not~be~larger~than~the~second.~
-    Here,~`#1'~has~character~code~\int_eval:n {`#1},~while~
-    `#2'~has~character~code~\int_eval:n {`#2}.
+    Here,~'#1'~has~character~code~\int_eval:n {`#1},~while~
+    '#2'~has~character~code~\int_eval:n {`#2}.
   }
 %    \end{macrocode}
 %
@@ -5935,53 +6142,53 @@
 % Errors related to |\c| and |\u|.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { c-bad-mode }
-  { Invalid~nested~`\iow_char:N\\c'~escape~in~regular~expression. }
+  { Invalid~nested~'\iow_char:N\\c'~escape~in~regular~expression. }
   {
-    The~`\iow_char:N\\c'~escape~cannot~be~used~within~
-    a~control~sequence~test~`\iow_char:N\\c{...}'.~
-    To~combine~several~category~tests,~use~`\iow_char:N\\c[...]'.
+    The~'\iow_char:N\\c'~escape~cannot~be~used~within~
+    a~control~sequence~test~'\iow_char:N\\c{...}'.~
+    To~combine~several~category~tests,~use~'\iow_char:N\\c[...]'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\c'~escape. }
   {
     LaTeX~was~given~a~regular~expression~where~a~
-    `\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
-    with~a~closing~brace~`\iow_char:N\}'.
+    '\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
+    with~a~closing~brace~'\iow_char:N\}'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrack }
-  { Missing~right~bracket~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~bracket~inserted~for~'\iow_char:N\\c'~escape. }
   {
-    A~construction~`\iow_char:N\\c[...'~appears~in~a~
-    regular~expression,~but~the~closing~`]'~is~not~present.
+    A~construction~'\iow_char:N\\c[...'~appears~in~a~
+    regular~expression,~but~the~closing~']'~is~not~present.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-category }
-  { Invalid~character~`#1'~following~`\iow_char:N\\c'~escape. }
+  { Invalid~character~'#1'~following~'\iow_char:N\\c'~escape. }
   {
-    In~regular~expressions,~the~`\iow_char:N\\c'~escape~sequence~
+    In~regular~expressions,~the~'\iow_char:N\\c'~escape~sequence~
     may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~
     capital~letter~representing~a~character~category,~namely~
-    one~of~`ABCDELMOPSTU'.
+    one~of~'ABCDELMOPSTU'.
   }
 \__msg_kernel_new:nnnn { regex } { c-trailing }
-  { Trailing~category~code~escape~`\iow_char:N\\c'... }
+  { Trailing~category~code~escape~'\iow_char:N\\c'... }
   {
-    A~regular~expression~ends~with~`\iow_char:N\\c'~followed~
+    A~regular~expression~ends~with~'\iow_char:N\\c'~followed~
     by~a~letter.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-lbrace }
-  { Missing~left~brace~following~`\iow_char:N\\u'~escape. }
+  { Missing~left~brace~following~'\iow_char:N\\u'~escape. }
   {
-    The~`\iow_char:N\\u'~escape~sequence~must~be~followed~by~
+    The~'\iow_char:N\\u'~escape~sequence~must~be~followed~by~
     a~brace~group~with~the~name~of~the~variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\u'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\u'~escape. }
   {
     LaTeX~
     \str_if_eq_x:nnTF { } {#2}
       { reached~the~end~of~the~string~ }
-      { encountered~an~escaped~alphanumeric~character `\iow_char:N\\#2'~ }
-    when~parsing~the~argument~of~an~`\iow_char:N\\u\iow_char:N\{...\}'~escape.
+      { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ }
+    when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape.
   }
 %    \end{macrocode}
 %
@@ -5988,24 +6195,24 @@
 % Errors when encountering the \textsc{posix} syntax |[:...:]|.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { posix-unsupported }
-  { POSIX~collating~element~`[#1 ~ #1]'~not~supported. }
+  { POSIX~collating~element~'[#1 ~ #1]'~not~supported. }
   {
-    The~`[.foo.]'~and~`[=bar=]'~syntaxes~have~a~special~meaning~
+    The~'[.foo.]'~and~'[=bar=]'~syntaxes~have~a~special~meaning~
     in~POSIX~regular~expressions.~This~is~not~supported~by~LaTeX.~
     Maybe~you~forgot~to~escape~a~left~bracket~in~a~character~class?
   }
 \__msg_kernel_new:nnnn { regex } { posix-unknown }
-  { POSIX~class~`[:#1:]'~unknown. }
+  { POSIX~class~'[:#1:]'~unknown. }
   {
-    `[:#1:]'~is~not~among~the~known~POSIX~classes~
-    `[:alnum:]',~`[:alpha:]',~`[:ascii:]',~`[:blank:]',~
-    `[:cntrl:]',~`[:digit:]',~`[:graph:]',~`[:lower:]',~
-    `[:print:]',~`[:punct:]',~`[:space:]',~`[:upper:]',~
-    `[:word:]',~and~`[:xdigit:]'.
+    '[:#1:]'~is~not~among~the~known~POSIX~classes~
+    '[:alnum:]',~'[:alpha:]',~'[:ascii:]',~'[:blank:]',~
+    '[:cntrl:]',~'[:digit:]',~'[:graph:]',~'[:lower:]',~
+    '[:print:]',~'[:punct:]',~'[:space:]',~'[:upper:]',~
+    '[:word:]',~and~'[:xdigit:]'.
   }
 \__msg_kernel_new:nnnn { regex } { posix-missing-close }
-  { Missing~closing~`:]'~for~POSIX~class. }
-  { The~POSIX~syntax~`#1'~must~be~followed~by~`:]',~not~`#2'. }
+  { Missing~closing~':]'~for~POSIX~class. }
+  { The~POSIX~syntax~'#1'~must~be~followed~by~':]',~not~'#2'. }
 %    \end{macrocode}
 %
 % In various cases, the result of a \pkg{l3regex} operation can leave us
@@ -6025,16 +6232,16 @@
 % Error message for unknown options.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { unknown-option }
-  { Unknown~option~`#1'~for~regular~expressions. }
+  { Unknown~option~'#1'~for~regular~expressions. }
   {
-    The~only~available~option~is~`case-insensitive',~toggled~by~
-    `(?i)'~and~`(?-i)'.
+    The~only~available~option~is~'case-insensitive',~toggled~by~
+    '(?i)'~and~'(?-i)'.
   }
 \__msg_kernel_new:nnnn { regex } { special-group-unknown }
-  { Unknown~special~group~`#1~...'~in~a~regular~expression. }
+  { Unknown~special~group~'#1~...'~in~a~regular~expression. }
   {
-    The~only~valid~constructions~starting~with~`(?'~are~
-    `(?:~...~)',~`(?|~...~)',~`(?i)',~and~`(?-i)'.
+    The~only~valid~constructions~starting~with~'(?'~are~
+    '(?:~...~)',~'(?|~...~)',~'(?i)',~and~'(?-i)'.
   }
 %    \end{macrocode}
 %
@@ -6041,46 +6248,56 @@
 % Errors in the replacement text.
 %    \begin{macrocode}
 \__msg_kernel_new:nnnn { regex } { replacement-c }
-  { Misused~`\iow_char:N\\c'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\c'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~
-    or~a~brace~group,~not~by~`#1'.
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~
+    or~a~brace~group,~not~by~'#1'.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-u }
-  { Misused~`\iow_char:N\\u'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\u'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\u'~escape~sequence~
+    In~a~replacement~text,~the~'\iow_char:N\\u'~escape~sequence~
     must~be~~followed~by~a~brace~group~holding~the~name~of~the~
     variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-g }
   {
-    Missing~brace~for~the~`\iow_char:N\\g'~construction~
+    Missing~brace~for~the~'\iow_char:N\\g'~construction~
     in~a~replacement~text.
   }
   {
     In~the~replacement~text~for~a~regular~expression~search,~
-    submatches~are~represented~either~as~`\iow_char:N \\g{dd..d}',~
-    or~`\\d',~where~`d'~are~single~digits.~Here,~a~brace~is~missing.
+    submatches~are~represented~either~as~'\iow_char:N \\g{dd..d}',~
+    or~'\\d',~where~'d'~are~single~digits.~Here,~a~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-catcode-end }
   {
-    Missing~character~for~the~`\iow_char:N\\c<category><character>'~
+    Missing~character~for~the~'\iow_char:N\\c<category><character>'~
     construction~in~a~replacement~text.
   }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~representing~
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~representing~
     the~character~category.~Then,~a~character~must~follow.~LaTeX~
     reached~the~end~of~the~replacement~when~looking~for~that.
   }
+\__msg_kernel_new:nnnn { regex } { replacement-catcode-in-cs }
+  {
+    Category~code~'\iow_char:N\\c#1#3'~ignored~inside~
+    '\iow_char:N\\c\{...\}'~in~a~replacement~text.
+  }
+  {
+    In~a~replacement~text,~the~category~codes~of~the~argument~of~
+    '\iow_char:N\\c\{...\}'~are~ignored~when~building~the~control~
+    sequence~name.
+  }
 \__msg_kernel_new:nnnn { regex } { replacement-null-space }
   { TeX~cannot~build~a~space~token~with~character~code~0. }
   {
     You~asked~for~a~character~token~with~category~space,~
     and~character~code~0,~for~instance~through~
-    `\iow_char:N\\cS\iow_char:N\\x00'.~
+    '\iow_char:N\\cS\iow_char:N\\x00'.~
     This~specific~case~is~impossible~and~will~be~replaced~
     by~a~normal~space.
   }
@@ -6090,6 +6307,12 @@
     There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
     missing~right~\int_compare:nTF { #1 = 1 } { brace } { braces } .
   }
+\__msg_kernel_new:nnnn { regex } { replacement-missing-rparen }
+  { Missing~right~parenthesis~inserted~in~replacement~text. }
+  {
+    There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
+    missing~right~\int_compare:nTF { #1 = 1 } { parenthesis } { parentheses } .
+  }
 %    \end{macrocode}
 %
 % \begin{macro}[aux]{\@@_msg_repeated:nnN}
@@ -6136,7 +6359,7 @@
       { \l_@@_max_state_int - 1 }
       {
         \trace:nnx { regex } { #1 }
-          { \iow_char:N \\toks ##1 = { \tex_the:D \tex_toks:D ##1 } }
+          { \iow_char:N \\toks ##1 = { \@@_toks_use:w ##1 } }
       }
   }
 %</trace>

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -47,7 +47,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -192,15 +192,6 @@
 %
 % \section{Internal string functions}
 %
-% \begin{function}{\__str_gset_other:Nn}
-%   \begin{syntax}
-%     \cs{__str_gset_other:Nn} \meta{tl~var} \Arg{token list}
-%   \end{syntax}
-%   Converts the \meta{token list} to an \meta{other string}, where
-%   spaces have category code \enquote{other}, and assigns the result to
-%   the \meta{tl~var}, globally.
-% \end{function}
-%
 % \begin{function}{\__str_hexadecimal_use:NTF}
 %   \begin{syntax}
 %     \cs{__str_hexadecimal_use:NTF} \meta{token} \Arg{true code} \Arg{false code}
@@ -216,17 +207,6 @@
 %   \end{texnote}
 % \end{function}
 %
-% \begin{function}[EXP]{\__str_output_byte:n}
-%   \begin{syntax}
-%     \cs{__str_output_byte:n} \Arg{intexpr}
-%   \end{syntax}
-%   Expands to a character token with category other and character code
-%   equal to the value of \meta{intexpr}.  The value of \meta{intexpr}
-%   must be in the range $[-1, 255]$, and any value outside this range
-%   results in undefined behaviour.  The special value $-1$ is used to
-%   produce an empty result.
-% \end{function}
-%
 % \section{Possibilities, and things to do}
 %
 % Encoding/escaping-related tasks.
@@ -272,7 +252,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{l3str-convert}{2017/04/01}{}
+\ProvidesExplPackage{l3str-convert}{2017/05/13}{}
   {L3 Experimental string encoding conversions}
 \RequirePackage{l3tl-analysis,l3tl-build}
 %    \end{macrocode}
@@ -330,20 +310,6 @@
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{macro}{\c_@@_ascii_min_int, \c_@@_ascii_max_control_int, \c_@@_ascii_max_int}
-%    \begin{macrocode}
-\int_const:Nn \c_@@_ascii_min_int { 0 }
-\int_const:Nn \c_@@_ascii_max_control_int { 31 }
-\int_const:Nn \c_@@_ascii_max_int { 127 }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\c_@@_ascii_lower_int}
-%    \begin{macrocode}
-\int_const:Nn \c_@@_ascii_lower_int { `a - `A }
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{variable}{\g_@@_alias_prop}
 %   To avoid needing one file per encoding/escaping alias, we keep track
 %   of those in a property list.
@@ -387,48 +353,6 @@
 %    \end{macrocode}
 % \end{variable}
 %
-% \subsubsection{Escaping spaces}
-% ^^A todo: use char_generate in this file
-% \begin{macro}[int]{\@@_gset_other:Nn}
-% \begin{macro}[aux,EXP]{\@@_gset_other_loop:w}
-% \begin{macro}[aux,EXP]{\@@_gset_other_end:w}
-%   This function could be done by using \cs{@@_to_other:n} within
-%   an \texttt{x}-expansion, but that would take a time quadratic in the
-%   size of the string. Instead, we can \enquote{leave the result behind
-%     us} in the input stream, to be captured into the expanding
-%   assignment. This gives us a linear time.
-%    \begin{macrocode}
-\group_begin:
-\char_set_lccode:nn { `\* } { `\  }
-\char_set_lccode:nn { `\A } { `\A }
-\tex_lowercase:D
-  {
-    \group_end:
-    \cs_new_protected:Npn \@@_gset_other:Nn #1#2
-      {
-        \tl_gset:Nx #1
-          {
-            \exp_after:wN \@@_gset_other_loop:w \tl_to_str:n {#2} ~ %
-            A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_stop
-          }
-      }
-    \cs_new:Npn \@@_gset_other_loop:w
-      #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 ~
-      {
-        \if_meaning:w A #9
-          \@@_gset_other_end:w
-        \fi:
-        #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * #9
-        \@@_gset_other_loop:w *
-      }
-    \cs_new:Npn \@@_gset_other_end:w \fi: #1 * A #2 \q_stop
-      { \fi: #1 }
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
 % \subsection{String conditionals}
 %
 % \begin{macro}[EXP]{\@@_if_contains_char:NNT, \@@_if_contains_char:NNTF}
@@ -544,12 +468,12 @@
 %   an empty result for the input $-1$.
 %    \begin{macrocode}
 \group_begin:
-  \tl_set:Nx \l__str_internal_tl { \tl_to_str:n { 0123456789ABCDEF } }
-   \tl_map_inline:Nn \l__str_internal_tl
+  \tl_set:Nx \l_@@_internal_tl { \tl_to_str:n { 0123456789ABCDEF } }
+   \tl_map_inline:Nn \l_@@_internal_tl
      {
-        \tl_map_inline:Nn \l__str_internal_tl
+        \tl_map_inline:Nn \l_@@_internal_tl
           {
-            \tl_const:cx { c__str_byte_ \int_eval:n {"#1##1} _tl }
+            \tl_const:cx { c_@@_byte_ \int_eval:n {"#1##1} _tl }
                { \char_generate:nn { "#1##1 } { 12 } #1 ##1 }
           }
      }
@@ -783,7 +707,7 @@
   {
     \group_begin:
       #1
-      \@@_gset_other:Nn \g_@@_result_tl {#4}
+      \tl_gset:Nx \g_@@_result_tl { \@@_to_other_fast:n {#4} }
       \exp_after:wN \@@_convert:wwwnn
         \tl_to_str:n {#5} /// \q_stop
         { decode } { unescape }
@@ -951,7 +875,7 @@
           #1
         \fi:
       \else:
-        \@@_output_byte:n { `#1 + \c_@@_ascii_lower_int }
+        \@@_output_byte:n { `#1 + `a - `A }
       \fi:
     \fi:
     \@@_convert_lowercase_alphanum_loop:N

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -47,7 +47,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -163,7 +163,7 @@
 %
 %    \begin{macrocode}
 %<*package>
-\ProvidesExplPackage{l3str-format}{2017/04/01}{}
+\ProvidesExplPackage{l3str-format}{2017/05/13}{}
   {L3 Experimental string formatting}
 \RequirePackage{l3str}
 %</package>

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins	2017-05-14 22:40:58 UTC (rev 44351)
@@ -1,6 +1,6 @@
 \iffalse meta-comment
 
-File l3str.ins Copyright (C) 2011,2013,2015,2016 The LaTeX3 Project
+File l3str.ins Copyright (C) 2011,2013,2015-2017 The LaTeX3 Project
 
 It may be distributed and/or modified under the conditions of the
 LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -32,7 +32,7 @@
 
 \preamble
 
-Copyright (C) 2011-2016 The LaTeX3 Project
+Copyright (C) 2011-2017 The LaTeX3 Project
 
 It may be distributed and/or modified under the conditions of
 the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -57,6 +57,7 @@
 \generate{\file{l3tl-analysis.sty}  {\from{l3tl-analysis.dtx}  {package}}}
 \generate{\file{l3tl-build.sty}     {\from{l3tl-build.dtx}     {package}}}
 \generate{\file{l3regex-trace.sty}  {\from{l3regex.dtx}  {package,trace}}}
+\generate{\file{l3intarray.sty}     {\from{l3intarray.dtx}     {package}}}
 
 % Escapings.
 \generate{%

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -46,7 +46,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -171,7 +171,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{l3tl-analysis}{2017/04/01}{}
+\ProvidesExplPackage{l3tl-analysis}{2017/05/13}{}
   {L3 Experimental token list analysis}
 %    \end{macrocode}
 %
@@ -390,15 +390,17 @@
 %   must appear in its string representation. The string is shortened
 %   a little by making the escape character unprintable. The active
 %   space must be disabled separately (the loop skips over it otherwise),
-%   and we end the loop by feeding an odd non-\texttt{N}-type
-%   argument to the looping macro.
+%   and we end the loop by feeding an odd non-\texttt{N}-type argument
+%   to the looping macro.  For \pTeX{} and \upTeX{} we skip characters
+%   beyond $[0,255]$ because \tn{lccode} only allows those values.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_setup:n #1
   {
     \int_set:Nn \tex_escapechar:D { -1 }
     \exp_after:wN \@@_disable_loop:N
-      \tl_to_str:n {#1} { ~ } { ? ~ \__prg_break: }
+      \tl_to_str:n {#1} { ~ } { ? \__prg_break: }
     \__prg_break_point:
+    \scan_stop:
   }
 \group_begin:
   \char_set_catcode_active:N \^^@
@@ -408,6 +410,20 @@
       \tex_lowercase:D { \tex_let:D ^^@ } \tex_undefined:D
       \@@_disable_loop:N
     }
+  \bool_lazy_or:nnT
+    { \sys_if_engine_ptex_p: }
+    { \sys_if_engine_uptex_p: }
+    {
+      \cs_gset_protected:Npn \@@_disable_loop:N #1
+        {
+          \use_none:n #1 \scan_stop:
+          \if_int_compare:w 256 > `#1 \exp_stop_f:
+            \tex_lccode:D 0 = `#1 ~
+            \tex_lowercase:D { \tex_let:D ^^@ } \tex_undefined:D
+          \fi:
+          \@@_disable_loop:N
+        }
+    }
 \group_end:
 %    \end{macrocode}
 % \end{macro}

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-build.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-build.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-build.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{l3tl-build}{Support package l3kernel too old}
@@ -60,7 +60,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -150,7 +150,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{l3tl-build}{2017/04/01}{}
+\ProvidesExplPackage{l3tl-build}{2017/05/13}{}
   {L3 Experimental token list construction}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -54,7 +54,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -113,10 +113,6 @@
 % Before any alignment can take place, coffins must be created and
 % their contents must be created. All coffin operations are local
 % to the current \TeX{} group with the exception of coffin creation.
-% Coffins are also \enquote{color safe}: in contrast to the code-level
-% \cs{box_\ldots} functions there is no need to add additional grouping
-% to coffins when dealing with color.
-%
 % \begin{function}{\NewCoffin}
 %   \begin{syntax}
 %     \cs{NewCoffin} \meta{coffin}
@@ -677,7 +673,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xcoffins}{2017/04/01}{}
+\ProvidesExplPackage{xcoffins}{2017/05/13}{}
   {L3 Experimental design level coffins}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -24,8 +24,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{l3galley}{Support package l3kernel too old}
@@ -59,7 +59,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -146,9 +146,8 @@
 %     \cs{galley_level:}
 %   \end{syntax}
 %   Sets up a vertical box to contain a new galley level. The box should
-%   be \enquote{color safe}, which is automatic for \LaTeX3 coffins but
-%   must be included manually (using \cs{color_group_begin:} and
-%   \cs{color_group_end:}) in \enquote{raw} vertical boxes.
+%   include \enquote{wrapper} group (be \enquote{color safe}): this is
+%   automatically true for all \LaTeX3 boxes and coffins.
 % \end{function}
 %
 % \subsection{Measure}
@@ -686,7 +685,7 @@
 %
 %    \begin{macrocode}
 %<*package>
-\ProvidesExplPackage{l3galley}{2017/04/01}{}
+\ProvidesExplPackage{l3galley}{2017/05/13}{}
   {L3 Experimental galley code}
 %</package>
 %    \end{macrocode}
@@ -1285,7 +1284,7 @@
 \cs_new_protected:Npn \galley_par:n #1
   {
     \s__par_omit
-    \bool_if:nF \g_@@_begin_level_bool
+    \bool_if:NF \g_@@_begin_level_bool
       {
         #1
         \galley_par:

Modified: trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -45,7 +45,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -732,7 +732,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xgalley}{2017/04/01}{}
+\ProvidesExplPackage{xgalley}{2017/05/13}{}
   {L3 Experimental galley}
 \RequirePackage{xparse,xtemplate,l3galley}
 %    \end{macrocode}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -21,7 +21,7 @@
 % for those people who are interested.
 %
 %<*driver|generic|package>
-\def\ExplFileDate{2017/04/01}%
+\def\ExplFileDate{2017/05/13}%
 %</driver|generic|package>
 %<*driver>
 \documentclass[full]{l3doc}
@@ -49,7 +49,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -1292,11 +1292,9 @@
                 \sys_if_output_pdf:TF
                   { pdfmode }
                   {
-                    \bool_if:nTF
-                      {
-                        \sys_if_engine_pdftex_p: ||
-                        \sys_if_engine_luatex_p:
-                      }
+                    \bool_lazy_or:nnTF
+                      { \sys_if_engine_pdftex_p: }
+                      { \sys_if_engine_luatex_p: }
                       { dvips }
                       { dvipdfmx }
                   }
@@ -1417,7 +1415,7 @@
 % \begin{macro}
 %   {
 %     \box_rotate:Nn,
-%     \box_resize:Nnn,
+%     \box_resize_to_wd_and_ht_plus_dp:Nnn,
 %     \box_resize_to_ht_plus_dp:Nn,
 %     \box_resize_to_wd:Nn,
 %     \box_scale:Nnn
@@ -1444,7 +1442,7 @@
       }
     \cs_set_protected:Npn \box_rotate:Nn #1#2
       { \hbox_set:Nn #1 { \rotatebox {#2} { \box_use:N #1 } } }
-    \cs_set_protected:Npn \box_resize:Nnn #1#2#3
+    \cs_set_protected:Npn \box_resize_to_wd_and_ht_plus_dp:Nnn #1#2#3
       {
         \hbox_set:Nn #1
           {
@@ -1470,15 +1468,13 @@
               { \box_use:N #1 }
           }
       }
-    \cs_set_protected:Npn \box_scale:Nnn #1#2#3
+    \cs_set_protected:Npn \__box_scale_aux:N #1
       {
-        \hbox_set:Nn #1
-          {
-            \exp_last_unbraced:Nx \scalebox
-              { { \fp_eval:n {#2} } [ \fp_eval:n {#3} ] }
-              { \box_use:N #1 }
-          }
+        \exp_last_unbraced:Nx \scalebox
+          { { \fp_use:N \l__box_scale_x_fp } [ \fp_use:N \l__box_scale_y_fp ] }
+          { \box_use:N #1 }
       }
+    \cs_set_protected:Npn \color_ensure_current: { \set at color }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1678,11 +1674,6 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% Deactivate writing module information to the log.
-%    \begin{macrocode}
-\protected\def\GetIdInfoLog{}
-%    \end{macrocode}
-%
 % For driver loading in generic mode, there are no options: pick the most
 % appropriate case! To allow this loading to take place a temporary
 % definition of \cs{ProvidesExplFile} is provided

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -21,7 +21,7 @@
 % for those people who are interested.
 %
 %<*driver|package>
-% \begin{macro}[deprecated = 2017-03-19]{\GetIdInfo}
+% \begin{macro}{\GetIdInfo}
 % \begin{macro}[aux]{\GetIdInfoAuxI, \GetIdInfoAuxII, \GetIdInfoAuxIII}
 %   The idea here is to extract out the information needed from a standard
 %   \textsc{svn} \texttt{Id} line, but without a line that will get
@@ -139,7 +139,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -187,11 +187,30 @@
 %   the package identifier line.
 % \end{function}
 %
+% \begin{function}[updated = 2012-06-04]{\GetIdInfo}
+%   \begin{syntax}
+%     |\RequirePackage{l3bootstrap}|
+%     \cs{GetIdInfo} |$Id:| \meta{SVN info field} |$| \Arg{description}
+%   \end{syntax}
+%   Extracts all information from a SVN field. Spaces are not
+%   ignored in these fields. The information pieces are stored in
+%   separate control sequences with \cs{ExplFileName} for the part of the
+%   file name leading up to the period, \cs{ExplFileDate} for date,
+%   \cs{ExplFileVersion} for version and \cs{ExplFileDescription} for the
+%   description.
+% \end{function}
+%
 % To summarize: Every single package using this syntax should identify
 % itself using one of the above methods. Special care is taken so that
 % every package or class file loaded with \tn{RequirePackage} or similar
 % are loaded with usual \LaTeXe{} category codes and the \LaTeX3 category code
-% scheme is reloaded when needed afterwards.
+% scheme is reloaded when needed afterwards. See implementation for
+% details. If you use the \cs{GetIdInfo} command you can use the
+% information when loading a package with
+% \begin{verbatim}
+%   \ProvidesExplPackage{\ExplFileName}
+%     {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+% \end{verbatim}
 %
 % \subsection{Internal functions and variables}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -335,9 +335,14 @@
 %   group levels.
 % \end{function}
 %
+% \section{Boxes and color}
+%
+% All \LaTeX{}3 boxes are \enquote{color safe}: a color set inside the box
+% will not apply after the end of the box has occurred.
+%
 % \section{Horizontal mode boxes}
 %
-% \begin{function}{\hbox:n}
+% \begin{function}[updated = 2017-04-05]{\hbox:n}
 %   \begin{syntax}
 %     \cs{hbox:n} \Arg{contents}
 %   \end{syntax}
@@ -345,7 +350,7 @@
 %   width and then includes this box in the current list for typesetting.
 % \end{function}
 %
-% \begin{function}{\hbox_to_wd:nn}
+% \begin{function}[updated = 2017-04-05]{\hbox_to_wd:nn}
 %   \begin{syntax}
 %     \cs{hbox_to_wd:nn} \Arg{dimexpr} \Arg{contents}
 %   \end{syntax}
@@ -354,7 +359,7 @@
 %   typesetting.
 % \end{function}
 %
-% \begin{function}{\hbox_to_zero:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_to_zero:n}
 %   \begin{syntax}
 %     \cs{hbox_to_zero:n} \Arg{contents}
 %   \end{syntax}
@@ -362,7 +367,8 @@
 %   and then includes this box in the current list for typesetting.
 % \end{function}
 %
-% \begin{function}{\hbox_set:Nn, \hbox_set:cn, \hbox_gset:Nn, \hbox_gset:cn}
+% \begin{function}[updated = 2017-04-05]
+%   {\hbox_set:Nn, \hbox_set:cn, \hbox_gset:Nn, \hbox_gset:cn}
 %   \begin{syntax}
 %     \cs{hbox_set:Nn} \meta{box} \Arg{contents}
 %   \end{syntax}
@@ -370,7 +376,7 @@
 %   result inside the \meta{box}.
 % \end{function}
 %
-% \begin{function}
+% \begin{function}[updated = 2017-04-05]
 %   {
 %     \hbox_set_to_wd:Nnn,  \hbox_set_to_wd:cnn,
 %     \hbox_gset_to_wd:Nnn, \hbox_gset_to_wd:cnn
@@ -382,7 +388,7 @@
 %   and then stores the result inside the \meta{box}.
 % \end{function}
 %
-% \begin{function}{\hbox_overlap_right:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_overlap_right:n}
 %   \begin{syntax}
 %     \cs{hbox_overlap_right:n} \Arg{contents}
 %   \end{syntax}
@@ -391,7 +397,7 @@
 %   point.
 % \end{function}
 %
-% \begin{function}{\hbox_overlap_left:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_overlap_left:n}
 %   \begin{syntax}
 %     \cs{hbox_overlap_left:n} \Arg{contents}
 %   \end{syntax}
@@ -400,7 +406,7 @@
 %   point.
 % \end{function}
 %
-% \begin{function}
+% \begin{function}[updated = 2017-04-05]
 %   {
 %     \hbox_set:Nw, \hbox_set:cw,
 %     \hbox_set_end:,
@@ -451,18 +457,15 @@
 % is that of the first item added. These tend to have a large depth and
 % small height, although the latter will typically be non-zero.
 %
-% \begin{function}[updated = 2011-12-18]{\vbox:n}
+% \begin{function}[updated = 2017-04-05]{\vbox:n}
 %   \begin{syntax}
 %     \cs{vbox:n} \Arg{contents}
 %   \end{syntax}
 %   Typesets the \meta{contents} into a vertical box of natural height
 %   and includes this box in the current list for typesetting.
-%   \begin{texnote}
-%     This is the \TeX{} primitive \tn{vbox}.
-%   \end{texnote}
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]{\vbox_top:n}
+% \begin{function}[updated = 2017-04-05]{\vbox_top:n}
 %   \begin{syntax}
 %     \cs{vbox_top:n} \Arg{contents}
 %   \end{syntax}
@@ -470,12 +473,9 @@
 %   and includes this box in the current list for typesetting. The
 %   baseline of the box will be equal to that of the \emph{first}
 %   item added to the box.
-%   \begin{texnote}
-%     This is the \TeX{} primitive \tn{vtop}.
-%   \end{texnote}
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]{\vbox_to_ht:nn}
+% \begin{function}[updated = 2017-04-05]{\vbox_to_ht:nn}
 %   \begin{syntax}
 %     \cs{vbox_to_ht:nn} \Arg{dimexpr} \Arg{contents}
 %   \end{syntax}
@@ -484,7 +484,7 @@
 %   typesetting.
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]{\vbox_to_zero:n}
+% \begin{function}[updated = 2017-04-05]{\vbox_to_zero:n}
 %   \begin{syntax}
 %     \cs{vbox_to_zero:n} \Arg{contents}
 %   \end{syntax}
@@ -492,7 +492,7 @@
 %   and then includes this box in the current list for typesetting.
 % \end{function}
 %
-%  \begin{function}[updated = 2011-12-18]
+%  \begin{function}[updated = 2017-04-05]
 %    {\vbox_set:Nn, \vbox_set:cn, \vbox_gset:Nn, \vbox_gset:cn}
 %   \begin{syntax}
 %     \cs{vbox_set:Nn} \meta{box} \Arg{contents}
@@ -501,7 +501,7 @@
 %   result inside the \meta{box}.
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]
+% \begin{function}[updated = 2017-04-05]
 %   {\vbox_set_top:Nn, \vbox_set_top:cn, \vbox_gset_top:Nn, \vbox_gset_top:cn}
 %   \begin{syntax}
 %     \cs{vbox_set_top:Nn} \meta{box} \Arg{contents}
@@ -511,7 +511,7 @@
 %   to that of the \emph{first} item added to the box.
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]
+% \begin{function}[updated = 2017-04-05]
 %   {
 %     \vbox_set_to_ht:Nnn,  \vbox_set_to_ht:cnn,
 %     \vbox_gset_to_ht:Nnn, \vbox_gset_to_ht:cnn
@@ -523,7 +523,7 @@
 %   \meta{dimexpr} and then stores the result inside the \meta{box}.
 % \end{function}
 %
-% \begin{function}[updated = 2011-12-18]
+% \begin{function}[updated = 2017-04-058]
 %  {
 %    \vbox_set:Nw, \vbox_set:cw,
 %    \vbox_set_end:,
@@ -575,6 +575,162 @@
 %   \end{texnote}
 % \end{function}
 %
+% \subsection{Affine transformations}
+%
+% Affine transformations are changes which (informally) preserve straight
+% lines. Simple translations are affine transformations, but are better handled
+% in \TeX{} by doing the translation first, then inserting an unmodified box.
+% On the other hand, rotation and resizing of boxed material can best be
+% handled by modifying boxes. These transformations are described here.
+%
+% \begin{function}[added = 2017-04-04]
+%   {\box_autosize_to_wd_and_ht:Nnn, \box_autosize_to_wd_and_ht:Nnn}
+%   \begin{syntax}
+%     \cs{box_autosize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to fit within the given \meta{x-size} (horizontally)
+%   and \meta{y-size} (vertically); both of the sizes are dimension
+%   expressions. The \meta{y-size} is the height only: it does not include any
+%   depth. The updated \meta{box} will be an |hbox|, irrespective of the nature
+%   of the \meta{box} before the resizing is applied. The final size of the
+%   \meta{box} will be the smaller of \Arg{x-size} and \Arg{y-size},
+%   \emph{i.e.}~the result will fit within the dimensions specified. Negative
+%   sizes will cause the material in the \meta{box} to be reversed in direction,
+%   but the reference point of the \meta{box} will be unchanged. Thus a negative
+%   \meta{y-size} will result in the \meta{box} having a depth dependent on the
+%   height of the original and \emph{vice versa}. The resizing applies within
+%   the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-04]
+%   {\box_autosize_to_wd_and_ht_plus_dp:Nnn, \box_autosize_to_wd_and_ht_plus_dp:Nnn}
+%   \begin{syntax}
+%     \cs{box_autosize_to_wd_and_ht_plus_dp:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to fit within the given \meta{x-size} (horizontally)
+%   and \meta{y-size} (vertically); both of the sizes are dimension
+%   expressions. The \meta{y-size} is the total vertical size (height plus
+%   depth). The updated \meta{box} will be an |hbox|, irrespective of the nature
+%   of the \meta{box} before the resizing is applied. The final size of the
+%   \meta{box} will be the smaller of \Arg{x-size} and \Arg{y-size},
+%   \emph{i.e.}~the result will fit within the dimensions specified. Negative
+%   sizes will cause the material in the \meta{box} to be reversed in direction,
+%   but the reference point of the \meta{box} will be unchanged. Thus a negative
+%   \meta{y-size} will result in the \meta{box} having a depth dependent on the
+%   height of the original and \emph{vice versa}. The resizing applies within
+%   the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}
+%   {\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
+%   \begin{syntax}
+%     \cs{box_resize_to_ht:Nn} \meta{box} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to \meta{y-size} (vertically), scaling the horizontal
+%   size by the same amount; \meta{y-size} is a dimension expression. The
+%   \meta{y-size} is the height only: it does not include any depth. The updated
+%   \meta{box} will be an |hbox|, irrespective of the nature of the \meta{box}
+%   before the resizing is applied. A negative \meta{y-size} will cause the
+%   material in the \meta{box} to be reversed in direction, but the reference
+%   point of the \meta{box} will be unchanged. Thus a negative \meta{y-size}
+%   will result in the \meta{box} having a depth dependent on the height of the
+%   original and \emph{vice versa}. The resizing applies within the current
+%   \TeX{} group level.
+% \end{function}
+%
+% \begin{function}
+%   {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
+%   \begin{syntax}
+%     \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to \meta{y-size} (vertically), scaling the horizontal
+%   size by the same amount; \meta{y-size} is a dimension expression. The
+%   \meta{y-size} is the total vertical size (height plus depth). The updated
+%   \meta{box} will be an |hbox|, irrespective of the nature of the \meta{box}
+%   before the resizing is applied. A negative \meta{y-size} will cause
+%   the material in the \meta{box} to be reversed in direction, but the
+%   reference point of the \meta{box} will be unchanged. Thus a negative
+%   \meta{y-size} will result in the \meta{box} having a depth dependent on the
+%   height of the original and \emph{vice versa}. The resizing applies within
+%   the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
+%   \begin{syntax}
+%     \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to \meta{x-size} (horizontally), scaling the vertical
+%   size by the same amount; \meta{x-size} is a dimension expression. The updated
+%   \meta{box} will be an |hbox|, irrespective of the nature of the \meta{box}
+%   before the resizing is applied. A negative \meta{x-size} will cause the
+%   material in the \meta{box} to be reversed in direction, but the reference
+%   point of the \meta{box} will be unchanged. Thus a negative \meta{x-size}
+%   will result in the \meta{box} having a depth dependent on the height of the
+%   original and \emph{vice versa}. The resizing applies within the current
+%   \TeX{} group level.
+% \end{function}
+%
+% \begin{function}[added = 2014-07-03]
+%   {\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
+%   \begin{syntax}
+%     \cs{box_resize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to \meta{x-size} (horizontally) and \meta{y-size}
+%   (vertically): both of the sizes are dimension expressions. The
+%   \meta{y-size} is the height only and does not include any depth. The updated
+%   \meta{box} will be an |hbox|, irrespective of the nature of the \meta{box}
+%   before the resizing is applied. Negative sizes will cause the material in
+%   the \meta{box} to be reversed in direction, but the reference point of the
+%   \meta{box} will be unchanged. Thus a negative \meta{y-size} will result in
+%   the \meta{box} having a depth dependent on the height of the original and
+%   \emph{vice versa}. The resizing applies within the current \TeX{} group
+%   level.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-06]
+%   {\box_resize_to_wd_and_ht_plus_dp:Nnn, \box_resize_to_wd_and_ht_plus_dp:cnn}
+%   \begin{syntax}
+%     \cs{box_resize_to_wd_and_ht_plus_dp:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
+%   \end{syntax}
+%   Resizes the \meta{box} to \meta{x-size} (horizontally) and \meta{y-size}
+%   (vertically): both of the sizes are dimension expressions. The
+%   \meta{y-size} is the total vertical size (height plus depth). The updated
+%   \meta{box} will be an |hbox|, irrespective of the nature of the \meta{box}
+%   before the resizing is applied. Negative sizes will cause the material in
+%   the \meta{box} to be reversed in direction, but the reference point of the
+%   \meta{box} will be unchanged. Thus a negative \meta{y-size} will result in
+%   the \meta{box} having a depth dependent on the height of the original and
+%   \emph{vice versa}. The resizing applies within the current \TeX{} group
+%   level.
+% \end{function}
+%
+% \begin{function}{\box_rotate:Nn, \box_rotate:cn}
+%   \begin{syntax}
+%     \cs{box_rotate:Nn} \meta{box} \Arg{angle}
+%   \end{syntax}
+%   Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about
+%   its reference point. The reference point of the updated box will be moved
+%   horizontally such that it is at the left side of the smallest rectangle
+%   enclosing the rotated material. The updated \meta{box} will be an |hbox|,
+%   irrespective of the nature of the \meta{box} before the rotation is applied.
+%   The rotation applies within the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}{\box_scale:Nnn, \box_scale:cnn}
+%   \begin{syntax}
+%     \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale}
+%   \end{syntax}
+%   Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in
+%   the horizontal and vertical directions, respectively (both scales are
+%   integer expressions). The updated \meta{box} will be an |hbox|, irrespective
+%   of the nature of the \meta{box} before the scaling is applied. Negative
+%   scalings will cause the material in the \meta{box} to be reversed in
+%   direction, but the reference point of the \meta{box} will be unchanged.
+%   Thus a negative \meta{y-scale} will result in the \meta{box} having a depth
+%   dependent on the height of the original and \emph{vice versa}. The resizing
+%   applies within the current \TeX{} group level.
+% \end{function}
+%
 % \section{Primitive box conditionals}
 %
 % \begin{function}[EXP]{\if_hbox:N}
@@ -976,7 +1132,8 @@
 % \testfile{m3box002.lvt}
 %   Put a horizontal box directly into the input stream.
 %    \begin{macrocode}
-\cs_new_protected:Npn \hbox:n #1 { \tex_hbox:D \scan_stop: {#1} }
+\cs_new_protected:Npn \hbox:n #1
+  { \tex_hbox:D \scan_stop: { \group_begin: #1 \group_end: } }
 %    \end{macrocode}
 %  \end{macro}
 %
@@ -985,7 +1142,7 @@
 % \testfile*
 %    \begin{macrocode}
 \cs_new_protected:Npn \hbox_set:Nn #1#2
-  { \tex_setbox:D #1 \tex_hbox:D {#2} }
+  { \tex_setbox:D #1 \tex_hbox:D { \group_begin: #2 \group_end: } }
 \cs_new_protected:Npn \hbox_gset:Nn { \tex_global:D \hbox_set:Nn }
 \cs_generate_variant:Nn \hbox_set:Nn { c }
 \cs_generate_variant:Nn \hbox_gset:Nn { c }
@@ -999,7 +1156,10 @@
 %   Storing material in a horizontal box with a specified width.
 %    \begin{macrocode}
 \cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3
-  { \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end: {#3} }
+  {
+    \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end:
+      { \group_begin: #3 \group_end: }
+  }
 \cs_new_protected:Npn \hbox_gset_to_wd:Nnn
   { \tex_global:D \hbox_set_to_wd:Nnn }
 \cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c }
@@ -1016,13 +1176,21 @@
 %    environment definitions.
 %    \begin{macrocode}
 \cs_new_protected:Npn \hbox_set:Nw  #1
-  { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token }
+  {
+    \tex_setbox:D #1 \tex_hbox:D
+      \c_group_begin_token
+        \group_begin:
+  }
 \cs_new_protected:Npn \hbox_gset:Nw
   { \tex_global:D \hbox_set:Nw }
 \cs_generate_variant:Nn \hbox_set:Nw  { c }
 \cs_generate_variant:Nn \hbox_gset:Nw { c }
-\cs_new_eq:NN \hbox_set_end:  \c_group_end_token
-\cs_new_eq:NN \hbox_gset_end: \c_group_end_token
+\cs_new_protected:Npn \hbox_set_end:
+  {
+      \group_end:
+    \c_group_end_token
+  }
+\cs_new_eq:NN \hbox_gset_end: \hbox_set_end:
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1034,8 +1202,12 @@
 %   Put a horizontal box directly into the input stream.
 %    \begin{macrocode}
 \cs_new_protected:Npn \hbox_to_wd:nn #1#2
-   { \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end: {#2} }
-\cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_dim {#1} }
+   {
+     \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end:
+       { \group_begin: #2 \group_end: }
+   }
+\cs_new_protected:Npn \hbox_to_zero:n #1
+  { \tex_hbox:D to \c_zero_dim { \group_begin: #1 \group_end: } }
 %    \end{macrocode}
 %  \end{macro}
 %  \end{macro}
@@ -1076,8 +1248,10 @@
 % \TestFiles{m3box003.lvt}
 %   Put a vertical box directly into the input stream.
 %    \begin{macrocode}
-\cs_new_protected:Npn \vbox:n #1     { \tex_vbox:D { #1 \par } }
-\cs_new_protected:Npn \vbox_top:n #1 { \tex_vtop:D { #1 \par } }
+\cs_new_protected:Npn \vbox:n #1
+  { \tex_vbox:D { \group_begin: #1 \par \group_end: } }
+\cs_new_protected:Npn \vbox_top:n #1
+  { \tex_vtop:D { \group_begin: #1 \par \group_end: } }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1088,9 +1262,15 @@
 %   Put a vertical box directly into the input stream.
 %    \begin{macrocode}
 \cs_new_protected:Npn \vbox_to_ht:nn #1#2
-  { \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end: { #2 \par } }
+  {
+    \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end:
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_to_zero:n #1
-  { \tex_vbox:D to \c_zero_dim { #1 \par } }
+  {
+    \tex_vbox:D to \c_zero_dim
+      { \group_begin: #1 \par \group_end: }
+  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1101,7 +1281,10 @@
 %   Storing material in a vertical box with a natural height.
 %    \begin{macrocode}
 \cs_new_protected:Npn \vbox_set:Nn #1#2
-  { \tex_setbox:D #1 \tex_vbox:D { #2 \par } }
+  {
+    \tex_setbox:D #1 \tex_vbox:D
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_gset:Nn  { \tex_global:D \vbox_set:Nn }
 \cs_generate_variant:Nn \vbox_set:Nn  { c }
 \cs_generate_variant:Nn \vbox_gset:Nn { c }
@@ -1116,7 +1299,10 @@
 %   point at the baseline of the first object in the box.
 %    \begin{macrocode}
 \cs_new_protected:Npn \vbox_set_top:Nn #1#2
-  { \tex_setbox:D #1 \tex_vtop:D { #2 \par } }
+  {
+    \tex_setbox:D #1 \tex_vtop:D
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_gset_top:Nn
   { \tex_global:D \vbox_set_top:Nn }
 \cs_generate_variant:Nn \vbox_set_top:Nn { c }
@@ -1133,7 +1319,7 @@
 \cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3
   {
     \tex_setbox:D #1 \tex_vbox:D to \__dim_eval:w #2 \__dim_eval_end:
-      { #3 \par }
+      { \group_begin: #3 \par \group_end: }
   }
 \cs_new_protected:Npn \vbox_gset_to_ht:Nnn
   { \tex_global:D \vbox_set_to_ht:Nnn }
@@ -1151,7 +1337,11 @@
 %   environment definitions.
 %    \begin{macrocode}
 \cs_new_protected:Npn \vbox_set:Nw #1
-  { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token }
+  {
+    \tex_setbox:D #1 \tex_vbox:D
+      \c_group_begin_token
+        \group_begin:
+  }
 \cs_new_protected:Npn \vbox_gset:Nw
   { \tex_global:D \vbox_set:Nw }
 \cs_generate_variant:Nn \vbox_set:Nw  { c }
@@ -1158,7 +1348,8 @@
 \cs_generate_variant:Nn \vbox_gset:Nw { c }
 \cs_new_protected:Npn \vbox_set_end:
   {
-    \par
+        \par
+      \group_end:
     \c_group_end_token
   }
 \cs_new_eq:NN \vbox_gset_end: \vbox_set_end:
@@ -1189,7 +1380,551 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \subsection{Affine transformations}
+%
+% \begin{variable}{\l_@@_angle_fp}
+%   When rotating boxes, the angle itself may be needed by the
+%   engine-dependent code. This is done using the \pkg{fp} module so
+%   that the value is tidied up properly.
 %    \begin{macrocode}
+\fp_new:N \l_@@_angle_fp
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
+%   These are used to hold the calculated sine and cosine values while
+%   carrying out a rotation.
+%    \begin{macrocode}
+\fp_new:N \l_@@_cos_fp
+\fp_new:N \l_@@_sin_fp
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+%   {\l_@@_top_dim, \l_@@_bottom_dim, \l_@@_left_dim, \l_@@_right_dim}
+%   These are the positions of the four edges of a box before
+%   manipulation.
+%    \begin{macrocode}
+\dim_new:N \l_@@_top_dim
+\dim_new:N \l_@@_bottom_dim
+\dim_new:N \l_@@_left_dim
+\dim_new:N \l_@@_right_dim
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+%  {
+%    \l_@@_top_new_dim,  \l_@@_bottom_new_dim ,
+%    \l_@@_left_new_dim, \l_@@_right_new_dim
+%  }
+%   These are the positions of the four edges of a box after
+%   manipulation.
+%    \begin{macrocode}
+\dim_new:N \l_@@_top_new_dim
+\dim_new:N \l_@@_bottom_new_dim
+\dim_new:N \l_@@_left_new_dim
+\dim_new:N \l_@@_right_new_dim
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_internal_box}
+%   Scratch space, but also needed by some parts of the driver.
+%    \begin{macrocode}
+\box_new:N \l_@@_internal_box
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\box_rotate:Nn}
+% \begin{macro}[aux]{\@@_rotate:N}
+% \begin{macro}[aux]{\@@_rotate_x:nnN, \@@_rotate_y:nnN}
+% \begin{macro}[aux]
+%   {
+%     \@@_rotate_quadrant_one:,   \@@_rotate_quadrant_two:,
+%     \@@_rotate_quadrant_three:, \@@_rotate_quadrant_four:
+%   }
+%   Rotation of a box starts with working out the relevant sine and
+%   cosine. The actual rotation is in an auxiliary to keep the flow slightly
+%   clearer
+%    \begin{macrocode}
+\cs_new_protected:Npn \box_rotate:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l_@@_angle_fp {#2}
+        \fp_set:Nn \l_@@_sin_fp { sind ( \l_@@_angle_fp ) }
+        \fp_set:Nn \l_@@_cos_fp { cosd ( \l_@@_angle_fp ) }
+        \@@_rotate:N #1
+      }
+  }
+%    \end{macrocode}
+%   The edges of the box are then recorded: the left edge will
+%   always be at zero. Rotation of the four edges then takes place: this is
+%   most efficiently done on a quadrant by quadrant basis.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_rotate:N #1
+  {
+    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l_@@_left_dim
+%    \end{macrocode}
+%   The next step is to work out the $x$ and $y$ coordinates of vertices of
+%   the rotated box in relation to its original coordinates. The box can be
+%   visualized with vertices $B$, $C$, $D$ and $E$ is illustrated
+%   (Figure~\ref{fig:l3candidates:rotation}). The vertex $O$ is the reference point
+%   on the baseline, and in this implementation is also the centre of rotation.
+%   \begin{figure}
+%     \centering
+%     \setlength{\unitlength}{3pt}^^A
+%     \begin{picture}(34,36)(12,44)
+%       \thicklines
+%       \put(20,52){\dashbox{1}(20,21){}}
+%       \put(20,80){\line(0,-1){36}}
+%       \put(12,58){\line(1, 0){34}}
+%       \put(41,59){A}
+%       \put(40,74){B}
+%       \put(21,74){C}
+%       \put(21,49){D}
+%       \put(40,49){E}
+%       \put(21,59){O}
+%     \end{picture}
+%     \caption{Co-ordinates of a box prior to rotation.}
+%     \label{fig:l3candidates:rotation}
+%   \end{figure}
+%   The formulae are, for a point $P$ and angle $\alpha$:
+%   \[
+%     \begin{array}{l}
+%       P'_x = P_x - O_x \\
+%       P'_y = P_y - O_y \\
+%       P''_x =  ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\
+%       P''_y =  ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\
+%       P'''_x = P''_x + O_x + L_x \\
+%       P'''_y = P''_y + O_y
+%    \end{array}
+%   \]
+%   The \enquote{extra} horizontal translation $L_x$ at the end is calculated
+%   so that the leftmost point of the resulting box has $x$-coordinate $0$.
+%   This is desirable as \TeX{} boxes must have the reference point at
+%   the left edge of the box. (As $O$ is always $(0,0)$, this part of the
+%   calculation is omitted here.)
+%    \begin{macrocode}
+    \fp_compare:nNnTF \l_@@_sin_fp > \c_zero_fp
+      {
+        \fp_compare:nNnTF \l_@@_cos_fp > \c_zero_fp
+          { \@@_rotate_quadrant_one: }
+          { \@@_rotate_quadrant_two: }
+      }
+      {
+        \fp_compare:nNnTF \l_@@_cos_fp < \c_zero_fp
+          { \@@_rotate_quadrant_three: }
+          { \@@_rotate_quadrant_four: }
+      }
+%    \end{macrocode}
+%   The position of the box edges are now known, but the box at this
+%   stage be misplaced relative to the current \TeX{} reference point. So the
+%   content of the box is moved such that the reference point of the
+%   rotated box will be in the same place as the original.
+%    \begin{macrocode}
+    \hbox_set:Nn \l_@@_internal_box { \box_use:N #1 }
+    \hbox_set:Nn \l_@@_internal_box
+      {
+        \tex_kern:D -\l_@@_left_new_dim
+        \hbox:n
+          {
+            \__driver_box_use_rotate:Nn
+              \l_@@_internal_box
+              \l_@@_angle_fp
+          }
+      }
+%    \end{macrocode}
+%   Tidy up the size of the box so that the material is actually inside
+%   the bounding box. The result can then be used to reset the original
+%   box.
+%    \begin{macrocode}
+    \box_set_ht:Nn \l_@@_internal_box {  \l_@@_top_new_dim }
+    \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
+    \box_set_wd:Nn \l_@@_internal_box
+      { \l_@@_right_new_dim - \l_@@_left_new_dim }
+    \box_use:N \l_@@_internal_box
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%   These functions take a general point $(|#1|, |#2|)$ and rotate its
+%   location about the origin, using the previously-set sine and cosine
+%   values. Each function gives only one component of the location of the
+%   updated point. This is because for rotation of a box each step needs
+%   only one value, and so performance is gained by avoiding working
+%   out both $x'$ and $y'$ at the same time. Contrast this with
+%   the equivalent function in the \pkg{l3coffins} module, where both parts
+%   are needed.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_rotate_x:nnN #1#2#3
+  {
+    \dim_set:Nn #3
+      {
+        \fp_to_dim:n
+          {
+              \l_@@_cos_fp * \dim_to_fp:n {#1}
+            - \l_@@_sin_fp * \dim_to_fp:n {#2}
+          }
+      }
+  }
+\cs_new_protected:Npn \@@_rotate_y:nnN #1#2#3
+  {
+    \dim_set:Nn #3
+      {
+        \fp_to_dim:n
+          {
+              \l_@@_sin_fp * \dim_to_fp:n {#1}
+            + \l_@@_cos_fp * \dim_to_fp:n {#2}
+          }
+      }
+  }
+%    \end{macrocode}
+%   Rotation of the edges is done using a different formula for each
+%   quadrant. In every case, the top and bottom edges only need the
+%   resulting $y$-values, whereas the left and right edges need the
+%   $x$-values. Each case is a question of picking out which corner
+%   ends up at with the maximum top, bottom, left and right value. Doing
+%   this by hand means a lot less calculating and avoids lots of
+%   comparisons.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_rotate_quadrant_one:
+  {
+    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
+      \l_@@_top_new_dim
+    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
+      \l_@@_bottom_new_dim
+    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_top_dim
+      \l_@@_left_new_dim
+    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
+      \l_@@_right_new_dim
+  }
+\cs_new_protected:Npn \@@_rotate_quadrant_two:
+  {
+    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
+      \l_@@_top_new_dim
+    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
+      \l_@@_bottom_new_dim
+    \@@_rotate_x:nnN \l_@@_right_dim  \l_@@_top_dim
+      \l_@@_left_new_dim
+    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_bottom_dim
+      \l_@@_right_new_dim
+  }
+\cs_new_protected:Npn \@@_rotate_quadrant_three:
+  {
+    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
+      \l_@@_top_new_dim
+    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
+      \l_@@_bottom_new_dim
+    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
+      \l_@@_left_new_dim
+    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_top_dim
+      \l_@@_right_new_dim
+  }
+\cs_new_protected:Npn \@@_rotate_quadrant_four:
+  {
+    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
+      \l_@@_top_new_dim
+    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
+      \l_@@_bottom_new_dim
+    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_bottom_dim
+      \l_@@_left_new_dim
+    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim
+      \l_@@_right_new_dim
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_scale_x_fp, \l_@@_scale_y_fp}
+%   Scaling is potentially-different in the two axes.
+%    \begin{macrocode}
+\fp_new:N \l_@@_scale_x_fp
+\fp_new:N \l_@@_scale_y_fp
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}
+%   {\box_resize_to_wd_and_ht_plus_dp:Nnn, \box_resize_to_wd_and_ht_plus_dp:cnn}
+% \begin{macro}[aux]{\@@_resize_set_corners:N}
+% \begin{macro}[aux]{\@@_resize:N}
+% \begin{macro}[aux]{\@@_resize:NNN}
+%   Resizing a box starts by working out the various dimensions of the
+%   existing box.
+%    \begin{macrocode}
+\cs_new_protected:Npn \box_resize_to_wd_and_ht_plus_dp:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \@@_resize_set_corners:N #1
+%    \end{macrocode}
+%   The $x$-scaling and resulting box size is easy enough to work
+%   out: the dimension is that given as |#2|, and the scale is simply the
+%   new width divided by the old one.
+%    \begin{macrocode}
+        \fp_set:Nn \l_@@_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
+%    \end{macrocode}
+%   The $y$-scaling needs both the height and the depth of the current box.
+%    \begin{macrocode}
+        \fp_set:Nn \l_@@_scale_y_fp
+          {
+              \dim_to_fp:n {#3}
+            / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
+          }
+%    \end{macrocode}
+%   Hand off to the auxiliary which does the rest of the work.
+%    \begin{macrocode}
+        \@@_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd_and_ht_plus_dp:Nnn { c }
+\cs_new_protected:Npn \@@_resize_set_corners:N #1
+  {
+    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l_@@_left_dim
+  }
+%    \end{macrocode}
+%   With at least one real scaling to do, the next phase is to find the new
+%   edge co-ordinates. In the $x$~direction this is relatively easy: just
+%   scale the right edge. In the $y$~direction, both dimensions have to be
+%   scaled, and this again needs the absolute scale value.
+%   Once that is all done, the common resize/rescale code can be employed.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_resize:N #1
+  {
+    \@@_resize:NNN \l_@@_right_new_dim
+      \l_@@_scale_x_fp \l_@@_right_dim
+    \@@_resize:NNN \l_@@_bottom_new_dim
+      \l_@@_scale_y_fp \l_@@_bottom_dim
+    \@@_resize:NNN \l_@@_top_new_dim
+      \l_@@_scale_y_fp \l_@@_top_dim
+    \@@_resize_common:N #1
+  }
+\cs_new_protected:Npn \@@_resize:NNN #1#2#3
+  {
+    \dim_set:Nn #1
+      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
+% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
+% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
+% \begin{macro}{\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
+%   Scaling to a (total) height or to a width is a simplified version of the main
+%   resizing operation, with the scale simply copied between the two parts. The
+%   internal auxiliary is called using the scaling value twice, as the sign for
+%   both parts is needed (as this allows the same internal code to be used as
+%   for the general case).
+%    \begin{macrocode}
+\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \@@_resize_set_corners:N #1
+        \fp_set:Nn \l_@@_scale_y_fp
+          {
+              \dim_to_fp:n {#2}
+            / \dim_to_fp:n { \l_@@_top_dim }
+          }
+        \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
+        \@@_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
+\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \@@_resize_set_corners:N #1
+        \fp_set:Nn \l_@@_scale_y_fp
+          {
+              \dim_to_fp:n {#2}
+            / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
+          }
+        \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
+        \@@_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \@@_resize_set_corners:N #1
+        \fp_set:Nn \l_@@_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
+        \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp
+        \@@_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \@@_resize_set_corners:N #1
+        \fp_set:Nn \l_@@_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
+        \fp_set:Nn \l_@@_scale_y_fp
+          {
+              \dim_to_fp:n {#3}
+            / \dim_to_fp:n { \l_@@_top_dim }
+          }
+        \@@_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\box_scale:Nnn, \box_scale:cnn}
+% \begin{macro}[aux]{\@@_scale_aux:N}
+%   When scaling a box, setting the scaling itself is easy enough. The
+%   new dimensions are also relatively easy to find, allowing only for
+%   the need to keep them positive in all cases. Once that is done then
+%   after a check for the trivial scaling a hand-off can be made to the
+%   common code. The code here is split into two as this allows sharing
+%   with the auto-resizing functions.
+%    \begin{macrocode}
+\cs_new_protected:Npn \box_scale:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l_@@_scale_x_fp {#2}
+        \fp_set:Nn \l_@@_scale_y_fp {#3}
+        \@@_scale_aux:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_scale:Nnn { c }
+\cs_new_protected:Npn \@@_scale_aux:N #1
+  {
+    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l_@@_left_dim
+    \dim_set:Nn \l_@@_top_new_dim
+      { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_top_dim }
+    \dim_set:Nn \l_@@_bottom_new_dim
+      { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_bottom_dim }
+    \dim_set:Nn \l_@@_right_new_dim
+      { \fp_abs:n { \l_@@_scale_x_fp } \l_@@_right_dim }
+    \@@_resize_common:N #1
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {
+%     \box_autosize_to_wd_and_ht:Nnn         ,
+%     \box_autosize_to_wd_and_ht:cnn         ,
+%     \box_autosize_to_wd_and_ht_plus_dp:cnn ,
+%     \box_autosize_to_wd_and_ht_plus_dp:Nnn
+%   }
+% \begin{macro}[aux]{\@@_autosize:Nnnn}
+%   Although autosizing a box uses dimensions, it has more in common in
+%   implementation with scaling. As such, most of the real work here is
+%   done elsewhere.
+%    \begin{macrocode}
+\cs_new_protected:Npn \box_autosize_to_wd_and_ht:Nnn #1#2#3
+  { \@@_autosize:Nnnn #1 {#2} {#3} { \box_ht:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht:Nnn { c }
+\cs_new_protected:Npn \box_autosize_to_wd_and_ht_plus_dp:Nnn #1#2#3
+  { \@@_autosize:Nnnn #1 {#2} {#3} { \box_ht:N #1 + \box_dp:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht_plus_dp:Nnn { c }
+\cs_new_protected:Npn \@@_autosize:Nnnn #1#2#3#4
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l_@@_scale_x_fp { ( #2 ) / \box_wd:N #1 }
+        \fp_set:Nn \l_@@_scale_y_fp { ( #3 ) / ( #4 ) }
+        \fp_compare:nNnTF \l_@@_scale_x_fp > \l_@@_scale_y_fp
+          { \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp }
+          { \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp }
+        \@@_scale_aux:N #1
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_resize_common:N}
+%   The main resize function places in input into a box which will start
+%   of with zero width, and includes the handles for engine rescaling.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_resize_common:N #1
+  {
+    \hbox_set:Nn \l_@@_internal_box
+      {
+        \__driver_box_use_scale:Nnn
+          #1
+          \l_@@_scale_x_fp
+          \l_@@_scale_y_fp
+      }
+%    \end{macrocode}
+%   The new height and depth can be applied directly.
+%    \begin{macrocode}
+    \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp
+      {
+        \box_set_ht:Nn \l_@@_internal_box { \l_@@_top_new_dim }
+        \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
+      }
+      {
+        \box_set_dp:Nn \l_@@_internal_box { \l_@@_top_new_dim }
+        \box_set_ht:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
+      }
+%    \end{macrocode}
+%   Things are not quite as obvious for the width, as the reference point
+%   needs to remain unchanged. For positive scaling factors resizing the
+%   box is all that is needed. However, for case of a negative scaling
+%   the material must be shifted such that the reference point ends up in
+%   the right place.
+%    \begin{macrocode}
+    \fp_compare:nNnTF \l_@@_scale_x_fp < \c_zero_fp
+      {
+        \hbox_to_wd:nn { \l_@@_right_new_dim }
+          {
+            \tex_kern:D \l_@@_right_new_dim
+            \box_use:N \l_@@_internal_box
+            \tex_hss:D
+          }
+      }
+      {
+        \box_set_wd:Nn \l_@@_internal_box { \l_@@_right_new_dim }
+        \hbox:n
+          {
+            \tex_kern:D \c_zero_dim
+            \box_use:N \l_@@_internal_box
+            \tex_hss:D
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Deprecated functions}
+%
+% \begin{macro}{\box_resize:Nnn, \box_resize:cnn}
+%    \begin{macrocode}
+\cs_new_eq:NN \box_resize:Nnn \box_resize_to_wd_and_ht_plus_dp:Nnn
+\cs_new_eq:NN \box_resize:cnn \box_resize_to_wd_and_ht_plus_dp:cnn
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
 %</initex|package>
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -42,7 +42,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -84,125 +84,6 @@
 %
 % \section{Additions to \pkg{l3box}}
 %
-% \subsection{Affine transformations}
-%
-% Affine transformations are changes which (informally) preserve straight
-% lines. Simple translations are affine transformations, but are better handled
-% in \TeX{} by doing the translation first, then inserting an unmodified box.
-% On the other hand, rotation and resizing of boxed material can best be
-% handled by modifying boxes. These transformations are described here.
-%
-% \begin{function}{\box_resize:Nnn, \box_resize:cnn}
-%   \begin{syntax}
-%     \cs{box_resize:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
-%   \end{syntax}
-%   Resize the \meta{box} to \meta{x-size} horizontally and \meta{y-size}
-%   vertically (both of the sizes are dimension expressions).
-%   The \meta{y-size} is the vertical size (height plus depth) of
-%   the box. The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box}  before the resizing is applied. Negative sizes will
-%   cause the material in the \meta{box} to be reversed in direction, but the
-%   reference point of the \meta{box} will be unchanged.
-%   Thus negative $y$-sizes will result in a box a depth dependent on the
-%   height of the original box a height dependent on the depth.
-%   The resizing applies within the current \TeX{} group level.
-% \end{function}
-%
-% \begin{function}
-%   {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
-%   \begin{syntax}
-%     \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size}
-%   \end{syntax}
-%   Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal
-%   size by the same amount (\meta{y-size} is a dimension expression).
-%   The \meta{y-size} is the vertical size (height plus depth) of
-%   the box.
-%   The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box}  before the resizing is applied. A negative size will
-%   cause the material in the \meta{box} to be reversed in direction, but the
-%   reference point of the \meta{box} will be unchanged.
-%   Thus negative $y$-sizes will result in a box with depth dependent on the
-%   height of the original box and height dependent on the depth of the original.
-%   The resizing applies within the current \TeX{} group level.
-% \end{function}
-%
-% \begin{function}
-%   {\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
-%   \begin{syntax}
-%     \cs{box_resize_to_ht:Nn} \meta{box} \Arg{y-size}
-%   \end{syntax}
-%   Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal
-%   size by the same amount (\meta{y-size} is a dimension expression).
-%   The \meta{y-size} is the height only, not including depth, of
-%   the box.
-%   The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box}  before the resizing is applied.
-%   A negative size will
-%   cause the material in the \meta{box} to be reversed in direction, but the
-%   reference point of the \meta{box} will be unchanged.
-%   Thus negative $y$-sizes will result in a box with depth dependent on the
-%   height of the original box and height dependent on the depth of the original.
-%   The resizing applies within the current \TeX{} group level.
-% \end{function}
-%
-% \begin{function}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
-%   \begin{syntax}
-%     \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size}
-%   \end{syntax}
-%   Resize the \meta{box} to \meta{x-size} horizontally, scaling the vertical
-%   size by the same amount (\meta{x-size} is a dimension expression).
-%   The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box}  before the resizing is applied. A negative size will
-%   cause the material in the \meta{box} to be reversed in direction, but the
-%   reference point of the \meta{box} will be unchanged.
-%   Thus negative $y$-sizes will result in a box a depth dependent on the
-%   height of the original box a height dependent on the depth.
-%   The resizing applies within the current \TeX{} group level.
-% \end{function}
-%
-% \begin{function}[added = 2014-07-03]
-%   {\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
-%   \begin{syntax}
-%     \cs{box_resize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
-%   \end{syntax}
-%   Resize the \meta{box} to a \emph{height} of
-%   \meta{x-size} horizontally and \meta{y-size}
-%   vertically (both of the sizes are dimension expressions).
-%   The \meta{y-size} is the \emph{height} of the box, ignoring any depth.
-%   The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box}  before the resizing is applied. Negative sizes will
-%   cause the material in the \meta{box} to be reversed in direction, but the
-%   reference point of the \meta{box} will be unchanged.
-% \end{function}
-%
-% \begin{function}{\box_rotate:Nn, \box_rotate:cn}
-%   \begin{syntax}
-%     \cs{box_rotate:Nn} \meta{box} \Arg{angle}
-%   \end{syntax}
-%   Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about
-%   its reference point. The reference point of the updated box will be moved
-%   horizontally such that it is at the left side of the smallest rectangle
-%   enclosing the rotated material.
-%   The updated \meta{box} will be an hbox, irrespective of the nature
-%   of the \meta{box} before the rotation is applied. The rotation applies
-%   within the current \TeX{} group level.
-% \end{function}
-%
-% \begin{function}{\box_scale:Nnn, \box_scale:cnn}
-%   \begin{syntax}
-%     \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale}
-%   \end{syntax}
-%   Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in
-%   the horizontal and vertical directions, respectively (both scales are
-%   integer expressions). The updated \meta{box} will be an hbox, irrespective
-%   of the nature of the \meta{box} before the scaling is applied. Negative
-%   scalings will cause the material in the \meta{box} to be reversed in
-%   direction, but the reference point of the \meta{box} will be unchanged.
-%   Thus negative $y$-scales will result in a box a depth dependent on the
-%   height of the original box a height dependent on the depth.
-%   The resizing applies within the current \TeX{} group level.
-% \end{function}
-%
 % \subsection{Viewing part of a box}
 %
 % \begin{function}{\box_clip:N, \box_clip:c}
@@ -592,6 +473,39 @@
 %   warning message of some sort.
 % \end{function}
 %
+% \section{Additions to \pkg{l3sys}}
+%
+% \begin{function}[added = 2017-04-12, EXP, pTF]{\sys_if_rand_exist:}
+%   \begin{syntax}
+%     \cs{sys_if_rand_exist_p:}
+%     \cs{sys_if_rand_exist:TF} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Tests if the engine has a pseudo-random number generator.  Currently
+%   this is the case in \pdfTeX{} and \LuaTeX{}.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-12, EXP]{\sys_rand_seed:}
+%   \begin{syntax}
+%     \cs{sys_rand_seed:}
+%   \end{syntax}
+%   Expands to the current value of the engine's random seed, a
+%   non-negative integer.  In engines without random number support this
+%   expands to $0$.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-12]{\sys_gset_rand_seed:n}
+%   \begin{syntax}
+%     \cs{sys_gset_rand_seed:n} \Arg{intexpr}
+%   \end{syntax}
+%   Sets the seed for the engine's pseudo-random number generator to the
+%   \meta{integer expression}.  The assignment is global.  This random
+%   seed affects all \cs[no-index]{\ldots{}_rand} functions (such as
+%   \cs{int_rand:nn} or \cs{clist_rand_item:n}) as well as other
+%   packages relying on the engine's random number generator.  Currently
+%   only the absolute value of the seed is used.  In engines without
+%   random number support this produces an error.
+% \end{function}
+%
 % \section{Additions to \pkg{l3tl}}
 %
 % \begin{function}[EXP,pTF]{\tl_if_single_token:n}
@@ -947,515 +861,6 @@
 %<@@=box>
 %    \end{macrocode}
 %
-% \subsection{Affine transformations}
-%
-% \begin{variable}{\l_@@_angle_fp}
-%   When rotating boxes, the angle itself may be needed by the
-%   engine-dependent code. This is done using the \pkg{fp} module so
-%   that the value is tidied up properly.
-%    \begin{macrocode}
-\fp_new:N \l_@@_angle_fp
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
-%   These are used to hold the calculated sine and cosine values while
-%   carrying out a rotation.
-%    \begin{macrocode}
-\fp_new:N \l_@@_cos_fp
-\fp_new:N \l_@@_sin_fp
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}
-%   {\l_@@_top_dim, \l_@@_bottom_dim, \l_@@_left_dim, \l_@@_right_dim}
-%   These are the positions of the four edges of a box before
-%   manipulation.
-%    \begin{macrocode}
-\dim_new:N \l_@@_top_dim
-\dim_new:N \l_@@_bottom_dim
-\dim_new:N \l_@@_left_dim
-\dim_new:N \l_@@_right_dim
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}
-%  {
-%    \l_@@_top_new_dim,  \l_@@_bottom_new_dim ,
-%    \l_@@_left_new_dim, \l_@@_right_new_dim
-%  }
-%   These are the positions of the four edges of a box after
-%   manipulation.
-%    \begin{macrocode}
-\dim_new:N \l_@@_top_new_dim
-\dim_new:N \l_@@_bottom_new_dim
-\dim_new:N \l_@@_left_new_dim
-\dim_new:N \l_@@_right_new_dim
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_internal_box}
-%   Scratch space, but also needed by some parts of the driver.
-%    \begin{macrocode}
-\box_new:N \l_@@_internal_box
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\box_rotate:Nn}
-% \begin{macro}[aux]{\@@_rotate:N}
-% \begin{macro}[aux]{\@@_rotate_x:nnN, \@@_rotate_y:nnN}
-% \begin{macro}[aux]
-%   {
-%     \@@_rotate_quadrant_one:,   \@@_rotate_quadrant_two:,
-%     \@@_rotate_quadrant_three:, \@@_rotate_quadrant_four:
-%   }
-%   Rotation of a box starts with working out the relevant sine and
-%   cosine. The actual rotation is in an auxiliary to keep the flow slightly
-%   clearer
-%    \begin{macrocode}
-\cs_new_protected:Npn \box_rotate:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \fp_set:Nn \l_@@_angle_fp {#2}
-          \fp_set:Nn \l_@@_sin_fp { sind ( \l_@@_angle_fp ) }
-          \fp_set:Nn \l_@@_cos_fp { cosd ( \l_@@_angle_fp ) }
-          \@@_rotate:N #1
-        \group_end:
-    }
-  }
-%    \end{macrocode}
-%   The edges of the box are then recorded: the left edge will
-%   always be at zero. Rotation of the four edges then takes place: this is
-%   most efficiently done on a quadrant by quadrant basis.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_rotate:N #1
-  {
-    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
-    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
-    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
-    \dim_zero:N \l_@@_left_dim
-%    \end{macrocode}
-%   The next step is to work out the $x$ and $y$ coordinates of vertices of
-%   the rotated box in relation to its original coordinates. The box can be
-%   visualized with vertices $B$, $C$, $D$ and $E$ is illustrated
-%   (Figure~\ref{fig:l3candidates:rotation}). The vertex $O$ is the reference point
-%   on the baseline, and in this implementation is also the centre of rotation.
-%   \begin{figure}
-%     \centering
-%     \setlength{\unitlength}{3pt}^^A
-%     \begin{picture}(34,36)(12,44)
-%       \thicklines
-%       \put(20,52){\dashbox{1}(20,21){}}
-%       \put(20,80){\line(0,-1){36}}
-%       \put(12,58){\line(1, 0){34}}
-%       \put(41,59){A}
-%       \put(40,74){B}
-%       \put(21,74){C}
-%       \put(21,49){D}
-%       \put(40,49){E}
-%       \put(21,59){O}
-%     \end{picture}
-%     \caption{Co-ordinates of a box prior to rotation.}
-%     \label{fig:l3candidates:rotation}
-%   \end{figure}
-%   The formulae are, for a point $P$ and angle $\alpha$:
-%   \[
-%     \begin{array}{l}
-%       P'_x = P_x - O_x \\
-%       P'_y = P_y - O_y \\
-%       P''_x =  ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\
-%       P''_y =  ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\
-%       P'''_x = P''_x + O_x + L_x \\
-%       P'''_y = P''_y + O_y
-%    \end{array}
-%   \]
-%   The \enquote{extra} horizontal translation $L_x$ at the end is calculated
-%   so that the leftmost point of the resulting box has $x$-coordinate $0$.
-%   This is desirable as \TeX{} boxes must have the reference point at
-%   the left edge of the box. (As $O$ is always $(0,0)$, this part of the
-%   calculation is omitted here.)
-%    \begin{macrocode}
-    \fp_compare:nNnTF \l_@@_sin_fp > \c_zero_fp
-      {
-        \fp_compare:nNnTF \l_@@_cos_fp > \c_zero_fp
-          { \@@_rotate_quadrant_one: }
-          { \@@_rotate_quadrant_two: }
-      }
-      {
-        \fp_compare:nNnTF \l_@@_cos_fp < \c_zero_fp
-          { \@@_rotate_quadrant_three: }
-          { \@@_rotate_quadrant_four: }
-      }
-%    \end{macrocode}
-%   The position of the box edges are now known, but the box at this
-%   stage be misplaced relative to the current \TeX{} reference point. So the
-%   content of the box is moved such that the reference point of the
-%   rotated box will be in the same place as the original.
-%    \begin{macrocode}
-    \hbox_set:Nn \l_@@_internal_box { \box_use:N #1 }
-    \hbox_set:Nn \l_@@_internal_box
-      {
-        \tex_kern:D -\l_@@_left_new_dim
-        \hbox:n
-          {
-            \__driver_box_use_rotate:Nn
-              \l_@@_internal_box
-              \l_@@_angle_fp
-          }
-      }
-%    \end{macrocode}
-%   Tidy up the size of the box so that the material is actually inside
-%   the bounding box. The result can then be used to reset the original
-%   box.
-%    \begin{macrocode}
-    \box_set_ht:Nn \l_@@_internal_box {  \l_@@_top_new_dim }
-    \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
-    \box_set_wd:Nn \l_@@_internal_box
-      { \l_@@_right_new_dim - \l_@@_left_new_dim }
-    \box_use:N \l_@@_internal_box
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%   These functions take a general point $(|#1|, |#2|)$ and rotate its
-%   location about the origin, using the previously-set sine and cosine
-%   values. Each function gives only one component of the location of the
-%   updated point. This is because for rotation of a box each step needs
-%   only one value, and so performance is gained by avoiding working
-%   out both $x'$ and $y'$ at the same time. Contrast this with
-%   the equivalent function in the \pkg{l3coffins} module, where both parts
-%   are needed.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_rotate_x:nnN #1#2#3
-  {
-    \dim_set:Nn #3
-      {
-        \fp_to_dim:n
-          {
-              \l_@@_cos_fp * \dim_to_fp:n {#1}
-            - \l_@@_sin_fp * \dim_to_fp:n {#2}
-          }
-      }
-  }
-\cs_new_protected:Npn \@@_rotate_y:nnN #1#2#3
-  {
-    \dim_set:Nn #3
-      {
-        \fp_to_dim:n
-          {
-              \l_@@_sin_fp * \dim_to_fp:n {#1}
-            + \l_@@_cos_fp * \dim_to_fp:n {#2}
-          }
-      }
-  }
-%    \end{macrocode}
-%   Rotation of the edges is done using a different formula for each
-%   quadrant. In every case, the top and bottom edges only need the
-%   resulting $y$-values, whereas the left and right edges need the
-%   $x$-values. Each case is a question of picking out which corner
-%   ends up at with the maximum top, bottom, left and right value. Doing
-%   this by hand means a lot less calculating and avoids lots of
-%   comparisons.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_rotate_quadrant_one:
-  {
-    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
-      \l_@@_top_new_dim
-    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
-      \l_@@_bottom_new_dim
-    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_top_dim
-      \l_@@_left_new_dim
-    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
-      \l_@@_right_new_dim
-  }
-\cs_new_protected:Npn \@@_rotate_quadrant_two:
-  {
-    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
-      \l_@@_top_new_dim
-    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
-      \l_@@_bottom_new_dim
-    \@@_rotate_x:nnN \l_@@_right_dim  \l_@@_top_dim
-      \l_@@_left_new_dim
-    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_bottom_dim
-      \l_@@_right_new_dim
-  }
-\cs_new_protected:Npn \@@_rotate_quadrant_three:
-  {
-    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
-      \l_@@_top_new_dim
-    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
-      \l_@@_bottom_new_dim
-    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
-      \l_@@_left_new_dim
-    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_top_dim
-      \l_@@_right_new_dim
-  }
-\cs_new_protected:Npn \@@_rotate_quadrant_four:
-  {
-    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
-      \l_@@_top_new_dim
-    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
-      \l_@@_bottom_new_dim
-    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_bottom_dim
-      \l_@@_left_new_dim
-    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim
-      \l_@@_right_new_dim
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{variable}{\l_@@_scale_x_fp, \l_@@_scale_y_fp}
-%   Scaling is potentially-different in the two axes.
-%    \begin{macrocode}
-\fp_new:N \l_@@_scale_x_fp
-\fp_new:N \l_@@_scale_y_fp
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\box_resize:Nnn, \box_resize:cnn}
-% \begin{macro}[aux]{\@@_resize_set_corners:N}
-% \begin{macro}[aux]{\@@_resize:N}
-% \begin{macro}[aux]{\@@_resize:NNN}
-%   Resizing a box starts by working out the various dimensions of the
-%   existing box.
-%    \begin{macrocode}
-\cs_new_protected:Npn \box_resize:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \@@_resize_set_corners:N #1
-%    \end{macrocode}
-%   The $x$-scaling and resulting box size is easy enough to work
-%   out: the dimension is that given as |#2|, and the scale is simply the
-%   new width divided by the old one.
-%    \begin{macrocode}
-          \fp_set:Nn \l_@@_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
-%    \end{macrocode}
-%   The $y$-scaling needs both the height and the depth of the current box.
-%    \begin{macrocode}
-          \fp_set:Nn \l_@@_scale_y_fp
-            {
-                \dim_to_fp:n {#3}
-              / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
-            }
-%    \end{macrocode}
-%   Hand off to the auxiliary which does the rest of the work.
-%    \begin{macrocode}
-          \@@_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize:Nnn { c }
-\cs_new_protected:Npn \@@_resize_set_corners:N #1
-  {
-    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
-    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
-    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
-    \dim_zero:N \l_@@_left_dim
-  }
-%    \end{macrocode}
-%   With at least one real scaling to do, the next phase is to find the new
-%   edge co-ordinates. In the $x$~direction this is relatively easy: just
-%   scale the right edge. In the $y$~direction, both dimensions have to be
-%   scaled, and this again needs the absolute scale value.
-%   Once that is all done, the common resize/rescale code can be employed.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_resize:N #1
-  {
-    \@@_resize:NNN \l_@@_right_new_dim
-      \l_@@_scale_x_fp \l_@@_right_dim
-    \@@_resize:NNN \l_@@_bottom_new_dim
-      \l_@@_scale_y_fp \l_@@_bottom_dim
-    \@@_resize:NNN \l_@@_top_new_dim
-      \l_@@_scale_y_fp \l_@@_top_dim
-    \@@_resize_common:N #1
-  }
-\cs_new_protected:Npn \@@_resize:NNN #1#2#3
-  {
-    \dim_set:Nn #1
-      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
-% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
-% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
-% \begin{macro}{\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
-%   Scaling to a (total) height or to a width is a simplified version of the main
-%   resizing operation, with the scale simply copied between the two parts. The
-%   internal auxiliary is called using the scaling value twice, as the sign for
-%   both parts is needed (as this allows the same internal code to be used as
-%   for the general case).
-%    \begin{macrocode}
-\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \@@_resize_set_corners:N #1
-          \fp_set:Nn \l_@@_scale_y_fp
-            {
-                \dim_to_fp:n {#2}
-              / \dim_to_fp:n { \l_@@_top_dim }
-            }
-          \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
-          \@@_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
-\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \@@_resize_set_corners:N #1
-          \fp_set:Nn \l_@@_scale_y_fp
-            {
-                \dim_to_fp:n {#2}
-              / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
-            }
-          \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
-          \@@_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
-\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \@@_resize_set_corners:N #1
-          \fp_set:Nn \l_@@_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
-          \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp
-          \@@_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
-\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \@@_resize_set_corners:N #1
-          \fp_set:Nn \l_@@_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
-          \fp_set:Nn \l_@@_scale_y_fp
-            {
-                \dim_to_fp:n {#3}
-              / \dim_to_fp:n { \l_@@_top_dim }
-            }
-          \@@_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\box_scale:Nnn, \box_scale:cnn}
-%   When scaling a box, setting the scaling itself is easy enough. The
-%   new dimensions are also relatively easy to find, allowing only for
-%   the need to keep them positive in all cases. Once that is done then
-%   after a check for the trivial scaling a hand-off can be made to the
-%   common code. The dimension scaling operations are carried out using
-%   the \TeX{} mechanism as it avoids needing to use too many \texttt{fp}
-%   operations.
-%    \begin{macrocode}
-\cs_new_protected:Npn \box_scale:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \fp_set:Nn \l_@@_scale_x_fp {#2}
-          \fp_set:Nn \l_@@_scale_y_fp {#3}
-          \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
-          \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
-          \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
-          \dim_zero:N \l_@@_left_dim
-          \dim_set:Nn \l_@@_top_new_dim
-            { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_top_dim }
-          \dim_set:Nn \l_@@_bottom_new_dim
-            { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_bottom_dim }
-          \dim_set:Nn \l_@@_right_new_dim
-              { \fp_abs:n { \l_@@_scale_x_fp } \l_@@_right_dim }
-           \@@_resize_common:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_scale:Nnn { c }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_resize_common:N}
-%   The main resize function places in input into a box which will start
-%   of with zero width, and includes the handles for engine rescaling.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_resize_common:N #1
-  {
-    \hbox_set:Nn \l_@@_internal_box
-      {
-        \__driver_box_use_scale:Nnn
-          #1
-          \l_@@_scale_x_fp
-          \l_@@_scale_y_fp
-      }
-%    \end{macrocode}
-%   The new height and depth can be applied directly.
-%    \begin{macrocode}
-    \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp
-      {
-        \box_set_ht:Nn \l_@@_internal_box { \l_@@_top_new_dim }
-        \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
-      }
-      {
-        \box_set_dp:Nn \l_@@_internal_box { \l_@@_top_new_dim }
-        \box_set_ht:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
-      }
-%    \end{macrocode}
-%   Things are not quite as obvious for the width, as the reference point
-%   needs to remain unchanged. For positive scaling factors resizing the
-%   box is all that is needed. However, for case of a negative scaling
-%   the material must be shifted such that the reference point ends up in
-%   the right place.
-%    \begin{macrocode}
-    \fp_compare:nNnTF \l_@@_scale_x_fp < \c_zero_fp
-      {
-        \hbox_to_wd:nn { \l_@@_right_new_dim }
-          {
-            \tex_kern:D \l_@@_right_new_dim
-            \box_use:N \l_@@_internal_box
-            \tex_hss:D
-          }
-      }
-      {
-        \box_set_wd:Nn \l_@@_internal_box { \l_@@_right_new_dim }
-        \hbox:n
-          {
-            \tex_kern:D \c_zero_dim
-            \box_use:N \l_@@_internal_box
-            \tex_hss:D
-          }
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
 % \subsection{Viewing part of a box}
 %
 % \begin{macro}{\box_clip:N, \box_clip:c}
@@ -1960,7 +1365,7 @@
           \dim_to_fp:n {#3}
         / \dim_to_fp:n { \coffin_ht:N #1 + \coffin_dp:N #1 }
       }
-    \box_resize:Nnn #1 {#2} {#3}
+    \box_resize_to_wd_and_ht_plus_dp:Nnn #1 {#2} {#3}
     \@@_resize_common:Nnn #1 {#2} {#3}
   }
 \cs_generate_variant:Nn \coffin_resize:Nnn { c }
@@ -2142,8 +1547,8 @@
 %   Mapping to an input stream can be done on either a token or a string
 %   basis, hence the set up. Within that, there is a check to avoid reading
 %   past the end of a file, hence the two applications of \cs{ior_if_eof:N}.
-%   This mapping cannot be nested as the stream has only one \enquote{current
-%   line}.
+%   This mapping cannot be nested with twice the same stream, as the
+%   stream has only one \enquote{current line}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \ior_map_inline:Nn
   { \@@_map_inline:NNn \ior_get:NN }
@@ -2157,7 +1562,7 @@
   }
 \cs_new_protected:Npn \@@_map_inline:NNNn #1#2#3#4
   {
-    \cs_set:Npn #1 ##1 {#4}
+    \cs_gset_protected:Npn #1 ##1 {#4}
     \ior_if_eof:NF #3 { \@@_map_inline_loop:NNN #1#2#3 }
     \__prg_break_point:Nn \ior_map_break:
       { \int_gdecr:N \g__prg_map_int }
@@ -2567,11 +1972,43 @@
       }
   }
 %    \end{macrocode}
-%  \end{macro}
+% \end{macro}
 %
-%  \subsection{Additions to \pkg{l3tl}}
+% \subsection{Additions to \pkg{l3sys}}
 %
+% \begin{macro}[EXP, pTF]{\sys_if_rand_exist:}
+%   Currently, randomness exists under \pdfTeX{} and \LuaTeX{}.
 %    \begin{macrocode}
+\cs_if_exist:NTF \pdftex_uniformdeviate:D
+  {
+    \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
+      { \prg_return_true: }
+  }
+  {
+    \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
+      { \prg_return_false: }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\sys_rand_seed:}
+%   Unpack the primitive.
+%    \begin{macrocode}
+\cs_new:Npn \sys_rand_seed: { \tex_the:D \pdftex_randomseed:D }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\sys_gset_rand_seed:n}
+%   The primitive always assigns the seed globally.
+%    \begin{macrocode}
+\cs_new_protected:Npn \sys_gset_rand_seed:n #1
+  { \pdftex_setrandomseed:D \__int_eval:w #1 \__int_eval_end: }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Additions to \pkg{l3tl}}
+%
+%    \begin{macrocode}
 %<@@=tl>
 %    \end{macrocode}
 %
@@ -3697,11 +3134,10 @@
 % octets, so that is taken as read.
 %    \begin{macrocode}
 \group_begin:
-  \bool_if:nT
+  \bool_lazy_or:nnT
+    { \sys_if_engine_pdftex_p: }
+    { \sys_if_engine_uptex_p: }
     {
-      \sys_if_engine_pdftex_p: || \sys_if_engine_uptex_p:
-    }
-    {
       \cs_set_protected:Npn \@@_loop:nn #1#2
         {
           \quark_if_recursion_tail_stop:n {#1}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -1553,7 +1553,8 @@
     \clist_if_empty:NF #1
       {
         \int_gincr:N \g__prg_map_int
-        \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
+        \cs_gset_protected:cpn
+          { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
         \exp_last_unbraced:Nco \@@_map_function:Nw
           { __prg_map_ \int_use:N \g__prg_map_int :w }
           #1 , \q_recursion_tail ,

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -359,10 +359,10 @@
 %   place, of course.
 %    \begin{macrocode}
 \prop_new:N \c_@@_corners_prop
-\prop_put:Nnn \c_@@_corners_prop { tl } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c_@@_corners_prop { tr } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c_@@_corners_prop { bl } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c_@@_corners_prop { br } { { 0 pt } { 0 pt } }
+\prop_put:Nnn \c_@@_corners_prop { tl } { { 0pt } { 0pt } }
+\prop_put:Nnn \c_@@_corners_prop { tr } { { 0pt } { 0pt } }
+\prop_put:Nnn \c_@@_corners_prop { bl } { { 0pt } { 0pt } }
+\prop_put:Nnn \c_@@_corners_prop { br } { { 0pt } { 0pt } }
 %    \end{macrocode}
 % \end{variable}
 %
@@ -371,11 +371,11 @@
 %   based values.
 %    \begin{macrocode}
 \prop_new:N \c_@@_poles_prop
-\tl_set:Nn \l_@@_internal_tl { { 0 pt } { 0 pt } { 0 pt } { 1000 pt } }
+\tl_set:Nn \l_@@_internal_tl { { 0pt } { 0pt } { 0pt } { 1000pt } }
 \prop_put:Nno \c_@@_poles_prop { l }  { \l_@@_internal_tl }
 \prop_put:Nno \c_@@_poles_prop { hc } { \l_@@_internal_tl }
 \prop_put:Nno \c_@@_poles_prop { r }  { \l_@@_internal_tl }
-\tl_set:Nn \l_@@_internal_tl { { 0 pt } { 0 pt } { 1000 pt } { 0 pt } }
+\tl_set:Nn \l_@@_internal_tl { { 0pt } { 0pt } { 1000pt } { 0pt } }
 \prop_put:Nno \c_@@_poles_prop { b }  { \l_@@_internal_tl }
 \prop_put:Nno \c_@@_poles_prop { vc } { \l_@@_internal_tl }
 \prop_put:Nno \c_@@_poles_prop { t }  { \l_@@_internal_tl }
@@ -535,10 +535,8 @@
       {
         \hbox_set:Nn #1
           {
-            \color_group_begin:
-              \color_ensure_current:
-              #2
-            \color_group_end:
+            \color_ensure_current:
+            #2
           }
         \@@_reset_structure:N #1
         \@@_update_poles:N #1
@@ -569,9 +567,7 @@
             \dim_set_eq:NN \linewidth   \tex_hsize:D
             \dim_set_eq:NN \columnwidth \tex_hsize:D
 %</package>
-            \color_group_begin:
-              #3
-            \color_group_end:
+            #3
           }
         \@@_reset_structure:N #1
         \@@_update_poles:N #1
@@ -579,13 +575,13 @@
         \vbox_set_top:Nn \l_@@_internal_box { \vbox_unpack:N #1 }
         \@@_set_pole:Nnx #1 { T }
           {
-            { 0 pt }
+            { 0pt }
             {
               \dim_eval:n
                 { \box_ht:N #1 - \box_ht:N \l_@@_internal_box }
             }
-            { 1000 pt }
-            { 0 pt }
+            { 1000pt }
+            { 0pt }
           }
         \box_clear:N \l_@@_internal_box
       }
@@ -603,10 +599,9 @@
   {
     \@@_if_exist:NT #1
       {
-        \hbox_set:Nw #1 \color_group_begin: \color_ensure_current:
+        \hbox_set:Nw #1 \color_ensure_current:
           \cs_set_protected:Npn \hcoffin_set_end:
             {
-                \color_group_end:
               \hbox_set_end:
               \@@_reset_structure:N #1
               \@@_update_poles:N #1
@@ -634,10 +629,8 @@
             \dim_set_eq:NN \linewidth   \tex_hsize:D
             \dim_set_eq:NN \columnwidth \tex_hsize:D
 %</package>
-          \color_group_begin:
           \cs_set_protected:Npn \vcoffin_set_end:
             {
-                \color_group_end:
               \vbox_set_end:
               \@@_reset_structure:N #1
               \@@_update_poles:N #1
@@ -645,13 +638,13 @@
               \vbox_set_top:Nn \l_@@_internal_box { \vbox_unpack:N #1 }
               \@@_set_pole:Nnx #1 { T }
                 {
-                  { 0 pt }
+                  { 0pt }
                   {
                     \dim_eval:n
                       { \box_ht:N #1 - \box_ht:N \l_@@_internal_box }
                   }
-                  { 1000 pt }
-                  { 0 pt }
+                  { 1000pt }
+                  { 0pt }
                 }
               \box_clear:N \l_@@_internal_box
             }
@@ -738,7 +731,7 @@
       {
         \__msg_kernel_error:nnxx { kernel } { unknown-coffin-pole }
           {#2} { \token_to_str:N #1 }
-        \tl_set:Nn #3 { { 0 pt } { 0 pt } { 0 pt } { 0 pt } }
+        \tl_set:Nn #3 { { 0pt } { 0pt } { 0pt } { 0pt } }
       }
   }
 %    \end{macrocode}
@@ -793,8 +786,8 @@
       {
         \@@_set_pole:Nnx #1 {#2}
           {
-            { 0 pt } { \dim_eval:n {#3} }
-            { 1000 pt } { 0 pt }
+            { 0pt } { \dim_eval:n {#3} }
+            { 1000pt } { 0pt }
           }
       }
   }
@@ -804,8 +797,8 @@
       {
         \@@_set_pole:Nnx #1 {#2}
           {
-            { \dim_eval:n {#3} } { 0 pt }
-            { 0 pt } { 1000 pt }
+            { \dim_eval:n {#3} } { 0pt }
+            { 0pt } { 1000pt }
           }
       }
   }
@@ -827,11 +820,11 @@
 \cs_new_protected:Npn \@@_update_corners:N #1
   {
     \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { tl }
-      { { 0 pt } { \dim_eval:n { \box_ht:N #1 } } }
+      { { 0pt } { \dim_eval:n { \box_ht:N #1 } } }
     \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { tr }
       { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { \box_ht:N #1 } } }
     \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { bl }
-      { { 0 pt } { \dim_eval:n { - \box_dp:N #1 } } }
+      { { 0pt } { \dim_eval:n { -\box_dp:N #1 } } }
     \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } { br }
       { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { -\box_dp:N #1 } } }
   }
@@ -850,33 +843,33 @@
     \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { hc }
       {
         { \dim_eval:n { 0.5 \box_wd:N #1 } }
-        { 0 pt } { 0 pt } { 1000 pt }
+        { 0pt } { 0pt } { 1000pt }
       }
     \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { r }
       {
         { \dim_eval:n { \box_wd:N #1 } }
-        { 0 pt } { 0 pt } { 1000 pt }
+        { 0pt } { 0pt } { 1000pt }
       }
     \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { vc }
       {
-        { 0 pt }
+        { 0pt }
         { \dim_eval:n { ( \box_ht:N #1 - \box_dp:N #1 ) / 2 } }
-        { 1000 pt }
-        { 0 pt }
+        { 1000pt }
+        { 0pt }
       }
     \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { t }
       {
-        { 0 pt }
+        { 0pt }
         { \dim_eval:n { \box_ht:N #1 } }
-        { 1000 pt }
-        { 0 pt }
+        { 1000pt }
+        { 0pt }
       }
     \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } { b }
       {
-        { 0 pt }
-        { \dim_eval:n { - \box_dp:N #1 } }
-        { 1000 pt }
-        { 0 pt }
+        { 0pt }
+        { \dim_eval:n { -\box_dp:N #1 } }
+        { 1000pt }
+        { 0pt }
       }
   }
 %    \end{macrocode}
@@ -1116,9 +1109,9 @@
 %   those from the two parent coffins are needed.
 %    \begin{macrocode}
    \@@_reset_structure:N \l_@@_aligned_coffin
-    \prop_clear:c
-      { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _ prop }
-    \@@_update_poles:N \l_@@_aligned_coffin
+   \prop_clear:c
+     { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _ prop }
+   \@@_update_poles:N \l_@@_aligned_coffin
 %    \end{macrocode}
 %   The structures of the parent coffins are now transferred to the new
 %   coffin, which requires that the appropriate offsets are applied. That
@@ -1126,16 +1119,16 @@
 %    \begin{macrocode}
     \dim_compare:nNnTF \l_@@_offset_x_dim < \c_zero_dim
       {
-        \@@_offset_poles:Nnn #1 { -\l_@@_offset_x_dim } { 0 pt }
-        \@@_offset_poles:Nnn #4 { 0 pt } { \l_@@_offset_y_dim }
-        \@@_offset_corners:Nnn #1 { -\l_@@_offset_x_dim } { 0 pt }
-        \@@_offset_corners:Nnn #4 { 0 pt } { \l_@@_offset_y_dim }
+        \@@_offset_poles:Nnn #1 { -\l_@@_offset_x_dim } { 0pt }
+        \@@_offset_poles:Nnn #4 { 0pt } { \l_@@_offset_y_dim }
+        \@@_offset_corners:Nnn #1 { -\l_@@_offset_x_dim } { 0pt }
+        \@@_offset_corners:Nnn #4 { 0pt } { \l_@@_offset_y_dim }
       }
       {
-        \@@_offset_poles:Nnn #1 { 0 pt } { 0 pt }
+        \@@_offset_poles:Nnn #1 { 0pt } { 0pt }
         \@@_offset_poles:Nnn #4
           { \l_@@_offset_x_dim } { \l_@@_offset_y_dim }
-        \@@_offset_corners:Nnn #1 { 0 pt } { 0 pt }
+        \@@_offset_corners:Nnn #1 { 0pt } { 0pt }
         \@@_offset_corners:Nnn #4
           { \l_@@_offset_x_dim } { \l_@@_offset_y_dim }
       }
@@ -1170,7 +1163,7 @@
       { l_@@_corners_ \__int_value:w \l_@@_aligned_coffin _prop }
       { l_@@_corners_ \__int_value:w #1 _prop }
     \@@_update_poles:N  \l_@@_aligned_coffin
-    \@@_offset_poles:Nnn #1 { 0 pt } { 0 pt }
+    \@@_offset_poles:Nnn #1 { 0pt } { 0pt }
     \@@_offset_poles:Nnn #4
       { \l_@@_offset_x_dim } { \l_@@_offset_y_dim }
     \@@_update_vertical_poles:NNN #1 #4 \l_@@_aligned_coffin
@@ -1307,11 +1300,11 @@
     \dim_compare:nNnTF {#2} < {#6}
       {
         \@@_set_pole:Nnx #9 { T }
-          { { 0 pt } {#6} { 1000 pt } { 0 pt } }
+          { { 0pt } {#6} { 1000pt } { 0pt } }
       }
       {
         \@@_set_pole:Nnx #9 { T }
-          { { 0 pt } {#2} { 1000 pt } { 0 pt } }
+          { { 0pt } {#2} { 1000pt } { 0pt } }
       }
   }
 \cs_new_protected:Npn \@@_update_B:nnnnnnnnN #1#2#3#4#5#6#7#8#9
@@ -1319,11 +1312,11 @@
     \dim_compare:nNnTF {#2} < {#6}
       {
         \@@_set_pole:Nnx #9 { B }
-          { { 0 pt } {#2}  { 1000 pt } { 0 pt } }
+          { { 0pt } {#2}  { 1000pt } { 0pt } }
       }
       {
         \@@_set_pole:Nnx #9 { B }
-          { { 0 pt } {#6} { 1000 pt } { 0 pt } }
+          { { 0pt } {#6} { 1000pt } { 0pt } }
       }
   }
 %    \end{macrocode}
@@ -1412,7 +1405,7 @@
 %   displaying handles.
 %    \begin{macrocode}
 \dim_new:N  \l_@@_display_offset_dim
-\dim_set:Nn \l_@@_display_offset_dim { 2 pt }
+\dim_set:Nn \l_@@_display_offset_dim { 2pt }
 %    \end{macrocode}
 % \end{variable}
 %
@@ -1463,15 +1456,15 @@
     \hcoffin_set:Nn \l_@@_display_pole_coffin
       {
 %<*initex>
-        \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO
+        \hbox:n { \tex_vrule:D width 1pt height 1pt \scan_stop: } % TODO
 %</initex>
 %<*package>
         \color {#4}
-        \rule { 1 pt } { 1 pt }
+        \rule { 1pt } { 1pt }
 %</package>
       }
     \coffin_attach_mark:NnnNnnnn #1 {#2} {#3}
-      \l_@@_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt }
+      \l_@@_display_pole_coffin { hc } { vc } { 0pt } { 0pt }
     \hcoffin_set:Nn \l_@@_display_coord_coffin
       {
 %<*initex>
@@ -1493,7 +1486,7 @@
           {
             \coffin_attach_mark:NnnNnnnn #1 {#2} {#3}
               \l_@@_display_coord_coffin { l } { vc }
-                { 1 pt } { 0 pt }
+                { 1pt } { 0pt }
           }
           {
             \exp_last_unbraced:No \@@_mark_handle_aux:nnnnNnn
@@ -1532,11 +1525,11 @@
     \hcoffin_set:Nn \l_@@_display_pole_coffin
       {
 %<*initex>
-        \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO
+        \hbox:n { \tex_vrule:D width 1pt height 1pt \scan_stop: } % TODO
 %</initex>
 %<*package>
         \color {#2}
-        \rule { 1 pt } { 1 pt }
+        \rule { 1pt } { 1pt }
 %</package>
       }
     \prop_set_eq:Nc \l_@@_display_poles_prop
@@ -1574,7 +1567,7 @@
             \dim_set:Nn \l_@@_display_y_dim { \l_@@_y_dim }
             \@@_display_attach:Nnnnn
               \l_@@_display_pole_coffin { hc } { vc }
-              { 0 pt } { 0 pt }
+              { 0pt } { 0pt }
             \hcoffin_set:Nn \l_@@_display_coord_coffin
               {
 %<*initex>
@@ -1596,7 +1589,7 @@
                   {
                     \@@_display_attach:Nnnnn
                       \l_@@_display_coord_coffin { l } { vc }
-                      { 1 pt } { 0 pt }
+                      { 1pt } { 0pt }
                   }
                   {
                     \exp_last_unbraced:No

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -94,7 +94,7 @@
 \cs_new_eq:NN \color_group_begin: \group_begin:
 \cs_new_protected:Npn \color_group_end:
   {
-      \tex_par:D
+      \par
     \group_end:
   }
 %    \end{macrocode}
@@ -104,34 +104,9 @@
 %   A driver-independent wrapper for setting the foreground color to the
 %   current color \enquote{now}.
 %    \begin{macrocode}
-%<*initex>
 \cs_new_protected:Npn \color_ensure_current:
   { \__driver_color_ensure_current: }
-%</initex>
 %    \end{macrocode}
-%   In package mode, the driver code may not be loaded. To keep down
-%   dependencies, if there is no driver code available and no \cs{set at color}
-%   then color is not in use and this function can be a no-op.
-%    \begin{macrocode}
-%<*package>
-\cs_new_protected:Npn \color_ensure_current: { }
-\AtBeginDocument
-  {
-    \cs_if_exist:NTF \__driver_color_ensure_current:
-      {
-        \cs_set_protected:Npn \color_ensure_current:
-          { \__driver_color_ensure_current: }
-      }
-      {
-        \cs_if_exist:NT \set at color
-          {
-            \cs_set_protected:Npn \color_ensure_current:
-              { \set at color }
-          }
-      }
-  }
-%</package>
-%    \end{macrocode}
 % \end{macro}
 %
 %    \begin{macrocode}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -140,6 +140,8 @@
     \@@_error:Nnn \tl_to_lowercase:n { } { 2017-12-31 }
     \@@_error:Nnn \tl_to_uppercase:n { } { 2017-12-31 }
     \@@_error:Nnn \ior_get_str:NN { \ior_str_get:NN } { 2017-12-31 }
+    \@@_error:Nnn \box_resize:Nnn { \box_resize_to_wd_and_ht_plus_dp:Nnn } { 2018-12-31 }
+    \@@_error:Nnn \box_resize:cnn { \box_resize_to_wd_and_ht_plus_dp:cnn } { 2018-12-31 }
     \@@_error:Nnn \c_minus_one { - 1 } { 2018-12-31 }
     \@@_error:Nnn \sort_ordered: { \sort_return_same: } { 2018-12-31 }
     \@@_error:Nnn \sort_reversed: { \sort_return_swapped: } { 2018-12-31 }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -70,7 +70,7 @@
 % This isn't included in the typeset documentation because it's a bit
 % ugly:
 %<*class>
-\ProvidesExplClass{l3doc}{2017/04/01}{}
+\ProvidesExplClass{l3doc}{2017/05/13}{}
   {L3 Experimental documentation class}
 %</class>
 % \fi
@@ -77,7 +77,7 @@
 %
 % \title{The \cls{l3doc} class}
 % \author{\Team}
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 % \maketitle
 % \tableofcontents
 %
@@ -2254,7 +2254,7 @@
       \clist_clear:N \l_@@_function_label_clist
       \tl_set:Nn \l_@@_override_module_tl { \q_no_value }
       \char_set_catcode_active:N \<
-      \cs_set_protected:Npn < ##1 > { \meta {##1} }
+      \cs_set_protected_nopar:Npn < ##1 > { \meta {##1} }
   }
 \group_end:
 %    \end{macrocode}
@@ -4370,5 +4370,3 @@
 % \end{implementation}
 %
 % \PrintIndex
-%
-% \endinput

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -61,7 +61,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -45,7 +45,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -64,8 +64,8 @@
 %   \item \texttt{dvipdfmx}: The \texttt{dvipdfmx} program, which works in
 %     conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode.
 %   \item \texttt{dvisvgm}:  The \texttt{dvisvgm} program, which works in
-%     conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode to create SVG
-%     output.
+%     conjugation with \pdfTeX{} or \LuaTeX{} when run in DVI mode as well
+%     as with (u)p\TeX{} and \XeTeX{}.
 %   \item \texttt{xdvipdfmx}: The driver used by \XeTeX{}.
 % \end{itemize}
 %
@@ -551,6 +551,93 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+%   The general method is to save the current location, define a clipping path
+%   equivalent to the bounding box, then insert the content at the current
+%   position and in a zero width box. The \enquote{real} width is then made up
+%   using a horizontal skip before tidying up. There are other approaches that
+%   can be taken (for example using XForm objects), but the logic here shares
+%   as much code as possible and uses the same conversions (and so same
+%   rounding errors) in all cases.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
+  {
+    \@@_scope_begin:
+    \@@_literal:n
+      {
+        0~
+        \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
+        \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+        \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
+        re~W~n
+      }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+    \skip_horizontal:n { \box_wd:N #1 }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_box_use_rotate:Nn}
+% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
+%   Rotations are set using an affine transformation matrix which therefore
+%   requires sine/cosine values not the angle itself. We store the rounded
+%   values to avoid rounding twice. There are also a couple of comparisons to
+%   ensure that |-0| is not written to the output, as this avoids any issues
+%   with problematic display programs.  Note that numbers are compared to~$0$
+%   after rounding.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+  {
+    \@@_scope_begin:
+    \box_set_wd:Nn #1 \c_zero_dim
+    \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
+    \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
+      { \fp_zero:N \l_@@_cos_fp }
+    \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
+    \@@_matrix:n
+      {
+        \fp_use:N \l_@@_cos_fp \c_space_tl
+        \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
+          { 0~0 }
+          {
+            \fp_use:N \l_@@_sin_fp
+            \c_space_tl
+            \fp_eval:n { -\l_@@_sin_fp }
+          }
+        \c_space_tl
+        \fp_use:N \l_@@_cos_fp
+      }
+   \box_use:N #1
+   \@@_scope_end:
+  }
+\fp_new:N \l_@@_cos_fp
+\fp_new:N \l_@@_sin_fp
+%    \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}{\@@_box_use_scale:Nnn}
+%   The same idea as for rotation but without the complexity of signs and
+%   cosines.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
+  {
+    \@@_scope_begin:
+    \@@_matrix:n
+      {
+        \fp_eval:n { round ( #2 , 5 ) } ~
+        0~0~
+        \fp_eval:n { round ( #3 , 5 ) }
+      }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsubsection{Color}
 %
 % \begin{variable}{\l_@@_current_color_tl}
@@ -623,7 +710,9 @@
 %
 % \begin{macro}[int]{\@@_literal:n}
 %   Equivalent to \texttt{pdf:content} but favored as the link to
-%   the \pdfTeX{} primitive approach is clearer.
+%   the \pdfTeX{} primitive approach is clearer. Some higher-level operations
+%   use |\tex_special:D| directly: see the later comments on where this is
+%   useful.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_literal:n #1
   { \tex_special:D { pdf:literal~ #1 } }
@@ -631,25 +720,83 @@
 % \end{macro}
 %
 % \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
-%   Scoping is done using direct PDF operations here.
+%   Scoping is done using the driver-specific specials.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_scope_begin:
-  { \@@_literal:n { q } }
+  { \tex_special:D { x:gsave } }
 \cs_new_protected:Npn \@@_scope_end:
-  { \@@_literal:n { Q } }
+  { \tex_special:D { x:grestore } }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_matrix:n}
-%   With \texttt{(x)dvipdfmx} the matrix has to include a translation
-%   part: that is always zero and so is built in here so that the same
-%   internal interface works for all PDF-related drivers.
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+%   The code here is idential to that for \texttt{pdfmode}: unlike rotation and
+%   scaling, there is no higher-level support in the driver for clipping.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_matrix:n #1
-  { \@@_literal:n { #1 \c_space_tl 0~0~cm } }
+\cs_new_protected:Npn \@@_box_use_clip:N #1
+  {
+    \@@_scope_begin:
+    \@@_literal:n
+      {
+        0~
+        \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
+        \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+        \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
+        re~W~n
+      }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+    \skip_horizontal:n { \box_wd:N #1 }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[int]{\@@_box_use_rotate:Nn}
+%   Rotating in \texttt{(x)}dvipdmfx can be implemented using either PDF or
+%   driver-specific code. The former approach however is not \enquote{aware}
+%   of the content of boxes: this means that any links embded will not be
+%   adjusted by the rotation. As such, the driver-native approach is prefered:
+%   the code therefore is similar (though not identical) to the \texttt{dvips}
+%   version (notice the rotation angle here is positive). As for
+%   \texttt{dvips}, zero rotation is written as |0| not |-0|.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+  {
+    \@@_scope_begin:
+    \tex_special:D
+      {
+        x:rotate~
+        \fp_compare:nNnTF {#2} = \c_zero_fp
+          { 0 }
+          { \fp_eval:n { round ( #2 , 5 ) } }
+      }
+    \box_use:N #1
+    \@@_scope_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_box_use_scale:Nnn}
+%   Much the same idea for scaling: use the higher-level driver operation to allow
+%   for box content.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
+  {
+    \@@_scope_begin:
+    \tex_special:D
+      {
+        x:scale~
+        \fp_eval:n { round ( #2 , 5 ) } ~
+        \fp_eval:n { round ( #3 , 5 ) }
+      }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsubsection{Color}
 %
 % \begin{variable}{\l_@@_current_color_tl}
@@ -724,103 +871,15 @@
 %</xdvipdfmx>
 %    \end{macrocode}
 %
-% \subsection{Common code for PDF production}
+% \subsection{Drawing commands: \texttt{pdfmode} and \texttt{(x)dvipdfmx}}
 %
-% As all of the drivers which understand PDF-targeted specials act in much
-% the same way there is a lot of shared code. Rather than try to DocStrip it
-% interspersed with the above, we collect all of it here.
+% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
+% and undertand a shared set of specials for drawing commands.
 %
 %    \begin{macrocode}
 %<*dvipdfmx|pdfmode|xdvipdfmx>
 %    \end{macrocode}
 %
-% \subsubsection{Box operations}
-%
-% \begin{macro}{\@@_box_use_clip:N}
-%   The general method is to save the current location, define a clipping path
-%   equivalent to the bounding box, then insert the content at the current
-%   position and in a zero width box. The \enquote{real} width is then made up
-%   using a horizontal skip before tidying up. There are other approaches that
-%   can be taken (for example using XForm objects), but the logic here shares
-%   as much code as possible and uses the same conversions (and so same
-%   rounding errors) in all cases.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
-  {
-    \@@_scope_begin:
-    \@@_literal:n
-      {
-        0~
-        \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
-        \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
-        \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
-        re~W~n
-      }
-    \hbox_overlap_right:n { \box_use:N #1 }
-    \@@_scope_end:
-    \skip_horizontal:n { \box_wd:N #1 }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_box_use_rotate:Nn}
-% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
-%   Rotations are set using an affine transformation matrix which therefore
-%   requires sine/cosine values not the angle itself. We store the rounded
-%   values to avoid rounding twice. There are also a couple of comparisons to
-%   ensure that |-0| is not written to the output, as this avoids any issues
-%   with problematic display programs.  Note that numbers are compared to~$0$
-%   after rounding.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
-  {
-    \@@_scope_begin:
-    \box_set_wd:Nn #1 \c_zero_dim
-    \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
-    \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
-      { \fp_zero:N \l_@@_cos_fp }
-    \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
-    \@@_matrix:n
-      {
-        \fp_use:N \l_@@_cos_fp \c_space_tl
-        \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
-          { 0~0 }
-          {
-            \fp_use:N \l_@@_sin_fp
-            \c_space_tl
-            \fp_eval:n { -\l_@@_sin_fp }
-          }
-        \c_space_tl
-        \fp_use:N \l_@@_cos_fp
-      }
-   \box_use:N #1
-   \@@_scope_end:
-  }
-\fp_new:N \l_@@_cos_fp
-\fp_new:N \l_@@_sin_fp
-%    \end{macrocode}
-% \end{variable}
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_scale:Nnn}
-%   The same idea as for rotation but without the complexity of signs and
-%   cosines.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
-  {
-    \@@_scope_begin:
-    \@@_matrix:n
-      {
-        \fp_eval:n { round ( #2 , 5 ) } ~
-        0~0~
-        \fp_eval:n { round ( #3 , 5 ) }
-      }
-    \hbox_overlap_right:n { \box_use:N #1 }
-    \@@_scope_end:
-  }
-%    \end{macrocode}
-% \end{macro}
-%
 % \subsection{Drawing}
 %
 % \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3final.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3final.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3final.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -98,11 +98,9 @@
 % (The primitives have to be available at point of use not just at point of
 % definition so a compatibility layer is hard to arrange here.)
 %    \begin{macrocode}
-\bool_if:nTF
-  {
-       \sys_if_engine_luatex_p:
-    || \sys_if_engine_xetex_p:
-  }
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
 %    \end{macrocode}
 % Unicode engines: make these two invalid (this happens after \TeX{}
 % has read and thrown away their use in the following).
@@ -261,12 +259,10 @@
     \tex_everyjob:D
       {
         \tex_the:D \tex_everyjob:D
-        \bool_if:nTF
+        \bool_lazy_or:nnTF
+          { \sys_if_engine_luatex_p: }
+          { \sys_if_engine_xetex_p: }
           {
-             \sys_if_engine_luatex_p: ||
-             \sys_if_engine_xetex_p:
-          }
-          {
             \tex_font:D \exp_not:c { TU/lmr/m/n/10 }
               = "[lmroman10-regular.otf]/OT" \scan_stop:
             \exp_not:c { TU/lmr/m/n/10 }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -376,21 +376,39 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}{\fp_step_inline:nnnn}
+% \begin{macro}{\fp_step_inline:nnnn, \fp_step_variable:nnnNn}
+% \begin{macro}[aux]{\@@_step:NNnnnn}
 %   As for \cs{int_step_inline:nnnn}, create a global function and apply it,
 %   following up with a break point.
 %    \begin{macrocode}
-\cs_new_protected:Npn \fp_step_inline:nnnn #1#2#3#4
+\cs_new_protected:Npn \fp_step_inline:nnnn
   {
     \int_gincr:N \g__prg_map_int
-    \cs_gset_protected:cpn { __prg_map_ \int_use:N \g__prg_map_int :w }
-      ##1 {#4}
-    \fp_step_function:nnnc {#1} {#2} {#3}
+    \exp_args:NNc \@@_step:NNnnnn
+      \cs_gset_protected:Npn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
+  }
+\cs_new_protected:Npn \fp_step_variable:nnnNn #1#2#3#4#5
+  {
+    \int_gincr:N \g__prg_map_int
+    \exp_args:NNc \@@_step:NNnnnn
+      \cs_gset_protected:Npx
+      { __prg_map_ \int_use:N \g__prg_map_int :w }
+      {#1} {#2} {#3}
+      {
+        \tl_set:Nn \exp_not:N #4 {##1}
+        \exp_not:n {#5}
+      }
+  }
+\cs_new_protected:Npn \@@_step:NNnnnn #1#2#3#4#5#6
+  {
+    #1 #2 ##1 {#6}
+    \fp_step_function:nnnN {#3} {#4} {#5} #2
     \__prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__prg_map_int }
   }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
 %    \begin{macrocode}
 \__msg_kernel_new:nnn { kernel } { fp-bad-step }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -986,15 +986,23 @@
 %   the unknown word could be a mistyped function as well as a mistyped
 %   constant, so there is no way to tell whether to look for arguments;
 %   we do not.
+%   The standard requires \enquote{inf} and \enquote{infinity} and
+%   \enquote{nan} to be recognized regardless of case, but we probably
+%   don't want to allow every \pkg{l3fp} word to have an arbitrary
+%   mixture of lower and upper case, so we test and use a
+%   differently-named control sequence.
 %    \begin{macrocode}
 \cs_new:Npn \@@_parse_word:Nw #1#2;
   {
     \cs_if_exist_use:cF { @@_parse_word_#2:N }
       {
-        \__msg_kernel_expandable_error:nnn
-          { kernel } { unknown-fp-word } {#2}
-        \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
-        \@@_parse_infix:NN
+        \cs_if_exist_use:cF { @@_parse_caseless_ \str_fold_case:n {#2} :N }
+          {
+            \__msg_kernel_expandable_error:nnn
+              { kernel } { unknown-fp-word } {#2}
+            \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
+            \@@_parse_infix:NN
+          }
       }
       #1
   }
@@ -1924,6 +1932,21 @@
 %
 % \begin{macro}[aux, EXP]
 %   {
+%     \@@_parse_caseless_inf:N,
+%     \@@_parse_caseless_infinity:N,
+%     \@@_parse_caseless_nan:N
+%   }
+%   Copies of \cs[no-index]{@@_parse_word_\ldots{}:N} commands, to allow
+%   arbitrary case as mandated by the standard.
+%    \begin{macrocode}
+\cs_new_eq:NN \@@_parse_caseless_inf:N \@@_parse_word_inf:N
+\cs_new_eq:NN \@@_parse_caseless_infinity:N \@@_parse_word_inf:N
+\cs_new_eq:NN \@@_parse_caseless_nan:N \@@_parse_word_nan:N
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+%   {
 %     \@@_parse_word_pt:N , \@@_parse_word_in:N ,
 %     \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N ,
 %     \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N ,

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -38,7 +38,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -47,7 +47,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -573,6 +573,20 @@
 %   \meta{code} should define a function of one argument~(|#1|).
 % \end{function}
 %
+% \begin{function}[added = 2017-04-12]{\fp_step_variable:nnnNn}
+%   \begin{syntax}
+%     \cs{fp_step_variable:nnnNn} \\
+%     ~~\Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code}
+%   \end{syntax}
+%   This function first evaluates the \meta{initial value}, \meta{step}
+%   and \meta{final value}, all of which should be floating point expressions.
+%   Then for each \meta{value} from the \meta{initial value} to the
+%   \meta{final value} in turn (using \meta{step} between each
+%   \meta{value}), the \meta{code} is inserted into the input stream,
+%   with the \meta{tl~var} defined as the current \meta{value}.  Thus
+%   the \meta{code} should make use of the \meta{tl~var}.
+% \end{function}
+%
 % \section{Some useful constants, and scratch variables}
 %
 % \begin{variable}[added = 2012-05-08]{\c_zero_fp, \c_minus_zero_fp}
@@ -1029,8 +1043,8 @@
 %   Computes the sine, cosine, tangent, cotangent, cosecant, or secant
 %   of the \meta{fpexpr} given in radians.  For arguments given in
 %   degrees, see \texttt{sind}, \texttt{cosd}, \emph{etc.}  Note that
-%   since $\pi$~is irrational, $\operatorname{sin}(8pi)$ is not quite
-%   zero, while its analog $\operatorname{sind}(8\times 180)$ is exactly
+%   since $\pi$~is irrational, $\operatorname{sin}(8\mathrm{pi})$ is not quite
+%   zero, while its analogue $\operatorname{sind}(8\times 180)$ is exactly
 %   zero.  The trigonometric functions are undefined for
 %   an argument of $\pm\infty$, leading to the \enquote{invalid
 %     operation} exception.  Additionally, evaluating tangent,
@@ -1052,8 +1066,8 @@
 %   Computes the sine, cosine, tangent, cotangent, cosecant, or secant
 %   of the \meta{fpexpr} given in degrees.  For arguments given in
 %   radians, see \texttt{sin}, \texttt{cos}, \emph{etc.}  Note that
-%   since $\pi$~is irrational, $\operatorname{sin}(8pi)$ is not quite
-%   zero, while its analog $\operatorname{sind}(8\times 180)$ is exactly
+%   since $\pi$~is irrational, $\operatorname{sin}(8\mathrm{pi})$ is not quite
+%   zero, while its analogue $\operatorname{sind}(8\times 180)$ is exactly
 %   zero.  The trigonometric functions are undefined for
 %   an argument of $\pm\infty$, leading to the \enquote{invalid
 %     operation} exception.  Additionally, evaluating tangent,

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -1322,7 +1322,7 @@
 %   code seen with token list variables.
 %    \begin{macrocode}
 \cs_new_protected:Npn \int_set:Nn #1#2
-  { #1 ~ \@@_eval:w #2\@@_eval_end: }
+  { #1 ~ \@@_eval:w #2 \@@_eval_end: }
 \cs_new_protected:Npn \int_gset:Nn { \tex_global:D \int_set:Nn }
 \cs_generate_variant:Nn \int_set:Nn  { c }
 \cs_generate_variant:Nn \int_gset:Nn { c }
@@ -1757,7 +1757,7 @@
   {
     \int_gincr:N \g__prg_map_int
     \exp_args:NNc \@@_step:NNnnnn
-      \cs_gset:Npn
+      \cs_gset_protected:Npn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
   }
 \cs_new_protected:Npn \int_step_variable:nnnNn #1#2#3#4#5
@@ -1764,7 +1764,7 @@
   {
     \int_gincr:N \g__prg_map_int
     \exp_args:NNc \@@_step:NNnnnn
-      \cs_gset:Npx
+      \cs_gset_protected:Npx
       { __prg_map_ \int_use:N \g__prg_map_int :w }
       {#1}{#2}{#3}
       {

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3oldmodules.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3oldmodules.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3oldmodules.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -42,7 +42,7 @@
 % }
 %
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -149,5 +149,4 @@
 %    \end{macrocode}
 %
 % \end{implementation}
-%
-% \endinput
+

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -1065,6 +1065,8 @@
 %   of the form \cs{@@_pair:wn} \meta{key} \cs{s_@@} \Arg{value}, there
 %   are a leading and a trailing tokens, but both are equal to
 %   \cs{scan_stop:}, hence have no effect in such inline mapping.
+%   Such \cs{scan_stop:} could have affected ligatures if they appeared
+%   during the mapping.
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_map_inline:Nn #1#2
   {
@@ -1071,7 +1073,7 @@
     \cs_gset_eq:cN
       { __prg_map_ \int_use:N \g__prg_map_int :wn } \@@_pair:wn
     \int_gincr:N \g__prg_map_int
-    \cs_gset:Npn \@@_pair:wn ##1 \s_@@ ##2 {#2}
+    \cs_gset_protected:Npn \@@_pair:wn ##1 \s_@@ ##2 {#2}
     #1
     \__prg_break_point:Nn \prop_map_break:
       {

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -641,5 +641,3 @@
 % \end{implementation}
 %
 % \PrintIndex
-%
-% \endinput

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -42,7 +42,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -418,7 +418,7 @@
 %
 % \section{String manipulation}
 %
-% \begin{function}[rEXP, added = 2015-03-01]
+% \begin{function}[EXP, added = 2015-03-01]
 %    {
 %      \str_lower_case:n, \str_lower_case:f,
 %      \str_upper_case:n, \str_upper_case:f

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -218,12 +218,10 @@
   }
 \cs_if_exist:NT \ptex_kanjiskip:D
   {
-    \bool_if:nTF
+    \bool_lazy_and:nnTF
+      { \cs_if_exist_p:N \uptex_disablecjktoken:D }
+      { \int_compare_p:nNn { \ptex_jis:D "2121 } = { "3000 } }
       {
-        \cs_if_exist_p:N \uptex_disablecjktoken:D &&
-        \int_compare_p:nNn { \ptex_jis:D "2121 } = { "3000 }
-      }
-      {
         \cs_gset_eq:NN \sys_if_engine_uptex:T  \use:n
         \cs_gset_eq:NN \sys_if_engine_uptex:F  \use_none:n
         \cs_gset_eq:NN \sys_if_engine_uptex:TF \use_i:nn

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -2211,7 +2211,8 @@
 \cs_new_protected:Npn \tl_map_inline:nn #1#2
   {
     \int_gincr:N \g__prg_map_int
-    \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
+    \cs_gset_protected:cpn
+      { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
     \exp_args:Nc \@@_map_function:Nn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
       #1 \q_recursion_tail

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,7 +41,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{l3keys2e}{Support package l3kernel too old}
@@ -60,7 +60,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -131,7 +131,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{l3keys2e}{2017/04/01}{}
+\ProvidesExplPackage{l3keys2e}{2017/05/13}{}
   {LaTeX2e option processing using LaTeX3 keys}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{xfpu}{Support package l3kernel too old}
@@ -62,7 +62,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -143,7 +143,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xfp}{2017/04/01}{}
+\ProvidesExplPackage{xfp}{2017/05/13}{}
   {L3 Floating point unit}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -24,8 +24,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{xfrac}{Support package l3kernel too old}
@@ -63,7 +63,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -533,7 +533,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xfrac}{2017/04/01}{}
+\ProvidesExplPackage{xfrac}{2017/05/13}{}
   {L3 Experimental split-level fractions}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -27,8 +27,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{xparse}{Support package l3kernel too old}
@@ -67,7 +67,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -179,12 +179,12 @@
 %     |-NoValue-| if not present.
 %   \item[G] As for \texttt{g} but returns \meta{default} if no value
 %     is given: \texttt{G}\marg{default}.
-%   \item[e] An optional set of \emph{embellishments}, each of which requires a
-%     \emph{value}. If a key is not present, |-NoValue-| is returned.
-%     The returned data is a token list comprising one braced entry per key,
-%     ordered as for the key list in the argument specification.  Given as
-%     \texttt{e}\marg{tokens}.  All \meta{tokens} must be distinct.
-%     \emph{This is an experimental type}.
+%   \item[e] A set of optional \emph{embellishments}, each of which
+%     requires a \emph{value}: \texttt{e}\marg{tokens}.  If an
+%     embellishment is not present, |-NoValue-| is returned.  Each
+%     embellishment gives one argument, ordered as for the list of
+%     \meta{tokens} in the argument specification.  All \meta{tokens}
+%     must be distinct.  \emph{This is an experimental type}.
 %   \item[E] As for \texttt{e} but returns one or more \meta{defaults}
 %     if values are not given: \texttt{E}\marg{tokens}\marg{defaults}. See
 %     Section~\ref{sec:embellishment} for more details.
@@ -776,7 +776,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xparse}{2017/04/01}{}
+\ProvidesExplPackage{xparse}{2017/05/13}{}
   {L3 Experimental document command parser}
 %    \end{macrocode}
 %
@@ -828,9 +828,10 @@
 % \end{variable}
 %
 % \begin{variable}{\l_@@_current_arg_int}
-%   The number of the current argument being set up: this is used for creating
-%   the expandable auxiliary functions, and also to indicate if all arguments
-%   are \texttt{m}-type.
+%   The number of the current argument being set up: this is used to
+%   make sure there are at most 9 arguments, then for creating the
+%   expandable auxiliary functions and knowing how many arguments the
+%   code function should take.
 %    \begin{macrocode}
 \int_new:N \l_@@_current_arg_int
 %    \end{macrocode}
@@ -1292,7 +1293,7 @@
 % \end{macro}
 %
 % \begin{macro}{\@@_defaults:}
-% \begin{macro}[aux]{\@@_defaults_def:, \@@_defaults_def:nn, \@@_defaults_def:nnn, \@@_defaults_def_aux:nn}
+% \begin{macro}[aux]{\@@_defaults_def:, \@@_defaults_def:nn, \@@_defaults_def:nnn}
 % \begin{macro}[aux]{\@@_defaults_aux:,  \@@_defaults_error:w}
 %   First construct \cs{@@_tmp:w} (see below) that will receive
 %   the arguments found so far and determine default values for any
@@ -1332,13 +1333,7 @@
 %   |{#|\meta{arg number}|}| for arguments found in the input (whose
 %   default will not be used) and otherwise
 %   |{|\cs{exp_not:n}\Arg{default}|}| for arguments whose default will
-%   be used.  The case of \texttt{E}-type arguments, detected by
-%   \cs{tl_if_head_is_group:nTF}, is special because we may need to
-%   partly use an argument found in the input and partly some default.
-%   This case is delayed until \cs{@@_tmp:w} is called: then we
-%   map through the original argument and its corresponding list of
-%   defaults; for each item (corresponding to one embellishment) if a
-%   value has already been found use it otherwise use the default.
+%   be used.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_defaults_def:
   {
@@ -1357,36 +1352,18 @@
   }
 \cs_new_protected:Npn \@@_defaults_def:nnn #1#2#3
   {
-    \tl_if_head_is_group:nTF {#3}
+    \tl_put_right:Nx \l_@@_tmpa_tl
       {
-        \tl_put_right:Nn \l_@@_tmpa_tl
-          {
+        {
+          \exp_not:N \exp_not:n
             {
-              \exp_args:Nf \@@_tl_mapthread_function:nnN
-                { \tl_item:Nn \l_@@_args_tl {#1} }
-                {#3}
-                \@@_defaults_def_aux:nn
+              \@@_if_no_value:nTF {#2}
+                { \exp_not:o {#3} }
+                { \exp_not:n { ## #1 } }
             }
-          }
+        }
       }
-      {
-        \@@_if_no_value:nTF {#2}
-          {
-            \tl_put_right:Nx \l_@@_tmpa_tl
-              { { \exp_not:N \exp_not:n { \exp_not:o {#3} } } }
-          }
-          {
-            \tl_put_right:Nn \l_@@_tmpa_tl
-              { { \exp_not:n { ## #1 } } }
-          }
-      }
   }
-\cs_new:Npn \@@_defaults_def_aux:nn #1#2
-  {
-    \@@_if_no_value:nTF {#1}
-      { { \exp_not:n {#2} } }
-      { { \exp_not:n {#1} } }
-  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1442,7 +1419,6 @@
 % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nnnNNn}
 % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nnw}
 % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nw}
-% \begin{macro}[EXP,aux]{\@@_end_expandable_defaults_E:nnw}
 %   Followed by a function |#1| to determine default values (or |?| if
 %   there are no defaults), the code
 %   |#2|, arguments that have been grabbed, then \cs{q_@@} and two generic
@@ -1485,29 +1461,10 @@
   }
 \cs_new:Npn \@@_end_expandable_defaults:nnw #1#2
   {
-    \tl_if_head_is_group:nTF {#1}
-      {
-        \@@_end_expandable_defaults_E:nnw { }
-          #1 \q_nil \q_mark
-          #2 \q_nil
-      }
-      {
-        \@@_if_no_value:nTF {#2}
-          { \exp_args:No \@@_end_expandable_defaults:nw {#1} }
-          { \@@_end_expandable_defaults:nw {#2} }
-      }
+    \@@_if_no_value:nTF {#2}
+      { \exp_args:No \@@_end_expandable_defaults:nw {#1} }
+      { \@@_end_expandable_defaults:nw {#2} }
   }
-\cs_new:Npn \@@_end_expandable_defaults_E:nnw #1#2#3 \q_mark #4
-  {
-    \quark_if_nil:nTF {#2}
-      { \@@_end_expandable_defaults:nw {#1} }
-      {
-        \@@_if_no_value:nTF {#4}
-          { \@@_end_expandable_defaults_E:nnw { #1 {#2} } }
-          { \@@_end_expandable_defaults_E:nnw { #1 {#4} } }
-        #3 \q_mark
-      }
-  }
 \cs_new:Npn \@@_end_expandable_defaults:nw
     #1#2 \@@_end_expandable_defaults:nnnNNn #3
   { #2 \@@_end_expandable_defaults:nnnNNn { #3 {#1} } }
@@ -1518,7 +1475,6 @@
 % \end{macro}
 % \end{macro}
 % \end{macro}
-% \end{macro}
 %
 % \subsection{Normalizing the argument specifications}
 %
@@ -1715,7 +1671,9 @@
 %   forbidden types for expandable commands.  For \texttt{E}-type
 %   require that there is at least one embellishment, that each one is a
 %   single token, and that there aren't more optional arguments than
-%   embellishments.  Then store the data in \cs{l_@@_arg_spec_tl}, and
+%   embellishments; also remember that each embellishment counts as one
+%   argument for \cs{l_@@_current_arg_int}.  Then in each case
+%   store the data in \cs{l_@@_arg_spec_tl}, and
 %   for later checks store in \cs{l_@@_last_delimiters_tl} the tokens
 %   whose presence determines whether there is an optional argument (for
 %   braces store |{}|, seen later as an empty delimiter).
@@ -1741,6 +1699,7 @@
     \@@_add_arg_spec:n { E {#1} {#2} }
     \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \bool_set_false:N \l_@@_grab_expandably_bool
+    \int_add:Nn \l_@@_current_arg_int { \tl_count:n {#1} - 1 }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_E_unique_check:w #1#2 \q_stop
@@ -1993,7 +1952,6 @@
 \cs_new_protected:Npn \@@_prepare_signature_bypass:N #1
   {
     \quark_if_recursion_tail_stop:N #1
-    \int_incr:N \l_@@_current_arg_int
     \use:c
       {
          @@_add
@@ -2015,11 +1973,12 @@
 % type.  All of the functions then call the loop function
 % \cs{@@_prepare_signature:N}.  Default values of arguments are
 % collected by \cs{@@_add_default:n} rather than being stored with the
-% argument.
+% argument; this function and \cs{@@_add_default:} are also responsible
+% for keeping track of \cs{l_@@_current_arg_int}.
 %
 % \begin{macro}{\@@_add_type_+:w}
-%   Making the next argument long means setting the flag and knocking one back
-%   off the total argument count. The \texttt{m} arguments are recorded here as
+%   Making the next argument long means setting the flag. The \texttt{m}
+%   arguments are recorded here as
 %   this has to be done for every case where there is then a long argument.
 %    \begin{macrocode}
 \cs_new_protected:cpn { @@_add_type_+:w }
@@ -2027,7 +1986,6 @@
     \@@_flush_m_args:
     \bool_set_true:N \l_@@_long_bool
     \bool_set_true:N \l_@@_prefixed_bool
-    \int_decr:N \l_@@_current_arg_int
     \@@_prepare_signature_bypass:N
   }
 %    \end{macrocode}
@@ -2044,7 +2002,6 @@
     \@@_flush_m_args:
     \bool_set_true:N \l_@@_prefixed_bool
     \bool_set_true:N \l_@@_process_some_bool
-    \int_decr:N \l_@@_current_arg_int
     \tl_put_left:Nn \l_@@_process_one_tl { {#1} }
     \@@_prepare_signature_bypass:N
   }
@@ -2214,7 +2171,7 @@
 %   the signature is done here. For mandatory arguments, the only question
 %   is whether to add a long grabber. For optional arguments, there is
 %   also a check to see if any mandatory arguments are still to be added.
-%   This is used to determine whether to skip spaces or not where
+%   This is used to determine whether to skip spaces or not when
 %   searching for the argument.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_add_grabber_mandatory:N #1
@@ -2253,16 +2210,14 @@
 % \end{macro}
 %
 % \begin{macro}{\@@_add_default:n, \@@_add_default:, \@@_add_default_E:nn}
-% \begin{macro}[aux]{\@@_add_default_E_aux:n}
 %   Store the default value of an argument, or rather code that gives
 %   that default value (it may involve other arguments).  This is
 %   \cs{c_@@_no_value_tl} for arguments with no actual default or with
-%   default |-NoValue-|; \cs{prg_do_nothing:} followed by a default
-%   value for most others, and a token list of braced arguments for
-%   \texttt{E}-type arguments.  For \texttt{E}-type arguments, pad the
-%   defaults |#2| with some |{-NoValue-}| until there are as many as
-%   embellishments~|#1|.  These functions are also used when defining
-%   expandable commands.
+%   default |-NoValue-|; and (in a brace group) \cs{prg_do_nothing:}
+%   followed by a default value for others.  For \texttt{E}-type
+%   arguments, pad the defaults |#2| with some \cs{c_@@_no_value_tl}
+%   until there are as many as embellishments~|#1|.  These functions are
+%   also used when defining expandable commands.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_add_default:n #1
   {
@@ -2269,29 +2224,25 @@
     \@@_if_no_value:nTF {#1}
       { \@@_add_default: }
       {
+        \int_incr:N \l_@@_current_arg_int
         \bool_set_true:N \l_@@_defaults_bool
         \tl_put_right:Nn \l_@@_defaults_tl { { \prg_do_nothing: #1 } }
       }
   }
 \cs_new_protected:Npn \@@_add_default:
-  { \tl_put_right:Nn \l_@@_defaults_tl { \c_@@_no_value_tl } }
+  {
+    \int_incr:N \l_@@_current_arg_int
+    \tl_put_right:Nn \l_@@_defaults_tl { \c_@@_no_value_tl }
+  }
 \cs_new_protected:Npn \@@_add_default_E:nn #1#2
   {
-    \bool_set_true:N \l_@@_defaults_bool
-    \tl_put_right:Nx \l_@@_defaults_tl
-      {
-        {
-          \tl_map_function:nN {#2} \@@_add_default_E_aux:n
-          \prg_replicate:nn
-            { \tl_count:n {#1} - \tl_count:n {#2} }
-            { { \c_@@_no_value_tl } }
-        }
-      }
+    \tl_map_function:nN {#2} \@@_add_default:n
+    \prg_replicate:nn
+      { \tl_count:n {#1} - \tl_count:n {#2} }
+      { \@@_add_default: }
   }
-\cs_new:Npn \@@_add_default_E_aux:n #1 { \exp_not:n { {#1} } }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
 % \subsection{Setting up expandable types}
 %
@@ -2310,7 +2261,6 @@
 \cs_new_protected:cpn { @@_add_expandable_type_+:w }
   {
     \bool_set_true:N \l_@@_long_bool
-    \int_decr:N \l_@@_current_arg_int
     \@@_prepare_signature:N
   }
 %    \end{macrocode}
@@ -2377,7 +2327,7 @@
 %   the auxiliary and the token in \cs{l_@@_tmpb_tl}, before appending
 %   the whole set of these pairs to the signature, and an equal number
 %   of |-NoValue-| markers (regardless of the default values of
-%   arguments).
+%   arguments).  Set the current argument appropriately.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_add_expandable_type_E:w #1#2
   {
@@ -2766,18 +2716,14 @@
     \tl_set:Nn \l_@@_signature_tl {#2}
     \cs_set_protected:Npn \@@_grab_E_finalise:
       {
-        \tl_clear:N \l_@@_tmpa_tl
         \tl_map_inline:nn {#1}
           {
             \prop_get:NnNF \l_@@_tmp_prop {####1} \l_@@_tmpb_tl
               { \tl_set_eq:NN \l_@@_tmpb_tl \c_@@_no_value_tl }
-            \tl_set:Nx \l_@@_tmpa_tl
-              {
-                \exp_not:V \l_@@_tmpa_tl
-                { \exp_not:V \l_@@_tmpb_tl }
-              }
+            \tl_put_right:Nx \l_@@_args_tl
+              { { \exp_not:V \l_@@_tmpb_tl } }
           }
-        \@@_add_arg:V \l_@@_tmpa_tl
+        \l_@@_signature_tl \@@_run_code:
       }
     \@@_grab_E_loop:nnN {#4} { } #1 \q_recursion_tail \q_recursion_stop
   }
@@ -3570,7 +3516,7 @@
 \cs_new:Npn \@@_expandable_grab_E_find:nnw #1#2#3 \q_nil #4 \q_@@ #5#6#7#8
   { \@@_expandable_grab_E_aux:w {#1} { #2 {#8} #3 } #4 \q_@@ #5 #6 #7 }
 \cs_new:Npn \@@_expandable_grab_E_end:nnw #1#2#3 \q_@@ #4#5#6
-  { #3 {#2} \q_@@ #4 #5 {#1} }
+  { #3 #2 \q_@@ #4 #5 {#1} }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}

Modified: trunk/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx	2017-05-14 22:40:58 UTC (rev 44351)
@@ -27,8 +27,8 @@
 %<*driver|package>
 % The version of expl3 required is tested as early as possible, as
 % some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2017/04/01]
-%<package>\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+%<package>\@ifpackagelater{expl3}{2017/05/13}
 %<package>  {}
 %<package>  {%
 %<package>    \PackageError{xtemplate}{Support package l3kernel too old}
@@ -63,7 +63,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
 %
 % \maketitle
 %
@@ -682,7 +682,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\ProvidesExplPackage{xtemplate}{2017/04/01}{}
+\ProvidesExplPackage{xtemplate}{2017/05/13}{}
   {L3 Experimental prototype document functions}
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/tex/latex/l3build/l3build.lua
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3build/l3build.lua	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3build/l3build.lua	2017-05-14 22:40:58 UTC (rev 44351)
@@ -22,8 +22,8 @@
 
 --]]
 
--- Version information: should be identical to that in l3build.dtx
-release_date = "2017/04/01"
+-- Version information
+release_date = "2017/05/13"
 
 -- "module" is a deprecated function in Lua 5.2: as we want the name
 -- for other purposes, and it should eventually be 'free', simply
@@ -38,7 +38,7 @@
 
 -- Sanity check
 if module == "" and bundle == "" then
-  if string.match(arg[0], ".*l3build%.lua$") then
+  if string.match(arg[0], "l3build%.lua$") then
     print(
       "\n"
         .. "Error: Call l3build using a configuration file, not directly.\n"
@@ -57,7 +57,7 @@
 maindir     = maindir or "."
 
 -- Substructure for tests and support files
-testfiledir = testfiledir or "testfiles" -- Set to "" to cancel any tests
+testfiledir = testfiledir or "testfiles"
 testsuppdir = testsuppdir or testfiledir .. "/support"
 supportdir  = supportdir  or maindir .. "/support"
 
@@ -113,7 +113,7 @@
 -- Executable names plus following options
 typesetexe = typesetexe or "pdflatex"
 unpackexe  = unpackexe  or "tex"
-zipexe     = "zip"
+zipexe     = zipexe     or "zip"
 
 checkopts   = checkopts   or "-interaction=nonstopmode"
 cmdchkopts  = cmdchkopts  or "-interaction=batchmode"
@@ -128,7 +128,6 @@
 
 -- Enable access to trees outside of the repo
 -- As these may be set false, a more elaborate test than normal is needed
--- here
 if checksearch == nil then
   checksearch = true
 end
@@ -156,8 +155,8 @@
 checkruns    = checkruns    or 1
 epoch        = epoch        or 1463734800
 maxprintline = maxprintline or 79
-packtdszip   = packtdszip   or false -- Not actually needed but clearer
-scriptname   = scriptname   or "build.lua" -- Script used in each directory
+packtdszip   = packtdszip   or false
+scriptname   = scriptname   or "build.lua"
 typesetcmds  = typesetcmds  or ""
 versionform  = versionform  or ""
 
@@ -171,11 +170,50 @@
 psext  = psext  or ".ps"
 tlgext = tlgext or ".tlg"
 
--- Run time options
--- These are parsed into a global table, and all optional args
--- are made available as a related global var
+-- File operations are aided by the LuaFileSystem module
+local lfs = require("lfs")
 
-function argparse()
+-- Local access to functions
+local assert           = assert
+local ipairs           = ipairs
+local next             = next
+local print            = print
+local select           = select
+local tonumber         = tonumber
+local close            = io.close
+local lines            = io.lines
+local open             = io.open
+local output           = io.output
+local stderr           = io.stderr
+local write            = io.write
+local set_program_name = kpse.set_program_name
+local var_value        = kpse.var_value
+local lfs_attributes   = lfs.attributes
+local lfs_dir          = lfs.dir
+local os_date          = os.date
+local execute          = os.execute
+local exit             = os.exit
+local getenv           = os.getenv
+local os_remove        = os.remove
+local os_type          = os.type
+local luatex_revision  = status.luatex_revision
+local luatex_version   = status.luatex_version
+local char             = string.char
+local find             = string.find
+local format           = string.format
+local gmatch           = string.gmatch
+local gsub             = string.gsub
+local len              = string.len
+local match            = string.match
+local sub              = string.sub
+local concat           = table.concat
+local insert           = table.insert
+local utf8_char        = unicode.utf8.char
+
+-- Parse command line options
+-- This is done as a function (rather than do ... end) as it allows early
+-- termination (break)
+local function argparse()
   local result = { }
   local files  = { }
   local long_options =
@@ -212,6 +250,7 @@
       release     = true,
       testfiledir = true
     }
+  local args = args
   -- arg[1] is a special case: must be a command or "-h"/"--help"
   -- Deal with this by assuming help and storing only apparently-valid
   -- input
@@ -219,7 +258,7 @@
   result["target"] = "help"
   if a then
     -- No options are allowed in position 1, so filter those out
-    if not string.match(a, "^%-") then
+    if not match(a, "^%-") then
       result["target"] = a
     end
   end
@@ -231,7 +270,7 @@
   local function remainder(num)
     local files = { }
     for i = num, #arg do
-      table.insert(files, arg[i])
+      insert(files, arg[i])
     end
     return files
   end
@@ -247,25 +286,26 @@
       break
     end
     -- Look for optionals
-    local opt, optarg
+    local opt
+    local optarg
     local opts
     -- Look for and option and get it into a variable
-    if string.match(a, "^%-") then
-      if string.match(a, "^%-%-") then
+    if match(a, "^%-") then
+      if match(a, "^%-%-") then
         opts = long_options
-        local pos = string.find(a, "=", 1, true)
+        local pos = find(a, "=", 1, true)
         if pos then
-          opt    = string.sub(a, 3, pos - 1)
-          optarg = string.sub(a, pos + 1)
+          opt    = sub(a, 3, pos - 1)
+          optarg = sub(a, pos + 1)
         else
-          opt = string.sub(a,3)
+          opt = sub(a, 3)
         end
       else
         opts = short_options
-        opt  = string.sub(a, 2, 2)
+        opt  = sub(a, 2, 2)
         -- Only set optarg if it is there
         if #a > 2 then
-          optarg = string.sub(a, 3)
+          optarg = sub(a, 3)
         end
       end
       -- Now check that the option is valid and sort out the argument
@@ -277,25 +317,24 @@
         if reqarg and not optarg then
           optarg = arg[i + 1]
           if not optarg then
-            io.stderr:write("Missing value for option " .. a .."\n")
+            stderr:write("Missing value for option " .. a .."\n")
             return {"help"}
           end
           i = i + 1
         end
         if not reqarg and optarg then
-          io.stderr:write("Value not allowed for option " .. a .."\n")
+          stderr:write("Value not allowed for option " .. a .."\n")
           return {"help"}
         end
       else
-        io.stderr:write("Unknown option " .. a .."\n")
+        stderr:write("Unknown option " .. a .."\n")
         return {"help"}
       end
       -- Store the result
       if optarg then
         local opts = result[optname] or { }
-        local match
-        for match in string.gmatch(optarg, "([^,%s]+)") do
-          table.insert(opts, match)
+        for hit in gmatch(optarg, "([^,%s]+)") do
+          insert(opts, hit)
         end
         result[optname] = opts
       else
@@ -312,15 +351,14 @@
   return result
 end
 
-userargs = argparse()
+options = argparse()
 
-optdate    = userargs["date"]
-optengines = userargs["engine"]
-opthalt    = userargs["halt"]
-opthelp    = userargs["help"]
-optpdf     = userargs["pdf"]
-optquiet   = userargs["quiet"]
-optrelease = userargs["release"]
+local optdate    = options["date"]
+local optengines = options["engine"]
+local opthalt    = options["halt"]
+local optpdf     = options["pdf"]
+local optquiet   = options["quiet"]
+local optrelease = options["release"]
 
 -- Convert a file glob into a pattern for use by e.g. string.gub
 -- Based on https://github.com/davidm/lua-glob-pattern
@@ -353,7 +391,7 @@
   (end license)
 
 --]]
-function glob_to_pattern(glob)
+local function glob_to_pattern(glob)
 
   local pattern = "^" -- pattern being built
   local i = 0 -- index in glob
@@ -361,13 +399,13 @@
 
   -- escape pattern char
   local function escape(char)
-    return string.match(char, "^%w$") and char or "%" .. char
+    return match(char, "^%w$") and char or "%" .. char
   end
 
   -- Convert tokens.
   while true do
     i = i + 1
-    char = string.sub(glob, i, i)
+    char = sub(glob, i, i)
     if char == "" then
       pattern = pattern .. "$"
       break
@@ -380,7 +418,7 @@
       print("[...] syntax not supported in globs!")
     elseif char == "\\" then
       i = i + 1
-      char = string.sub(glob, i, i)
+      char = sub(glob, i, i)
       if char == "" then
         pattern = pattern .. "\\$"
         break
@@ -393,53 +431,42 @@
   return pattern
 end
 
--- File operation support
--- Much of this is OS-dependent as Lua offers a very limited range of file
--- operations 'natively'.
-
 -- Detect the operating system in use
 -- Support items are defined here for cases where a single string can cover
 -- both Windows and Unix cases: more complex situations are handled inside
 -- the support functions
-if os.type == "windows" then
-  os_ascii    = "@echo."
-  os_cmpexe   = os.getenv("cmpexe") or "fc /b"
-  os_cmpext   = os.getenv("cmpext") or ".cmp"
-  os_concat   = "&"
-  os_diffext  = os.getenv("diffext") or ".fc"
-  os_diffexe  = os.getenv("diffexe") or "fc /n"
-  os_grepexe  = "findstr /r"
-  os_newline  = "\n"
-  if tonumber(status.luatex_version) < 100 or
-     (tonumber(status.luatex_version) == 100
-       and tonumber(status.luatex_revision) < 4) then
+os_concat  = ";"
+os_null    = "/dev/null"
+os_pathsep = ":"
+os_setenv  = "export"
+os_yes     = "printf 'y\\n%.0s' {1..200}"
+local os_ascii   = "echo \"\""
+local os_cmpexe  = getenv("cmpexe") or "cmp"
+local os_cmpext  = getenv("cmpext") or ".cmp"
+local os_diffext = getenv("diffext") or ".diff"
+local os_diffexe = getenv("diffexe") or "diff -c --strip-trailing-cr"
+local os_grepexe = "grep"
+local os_newline = "\n"
+if os_type == "windows" then
+  os_ascii   = "@echo."
+  os_cmpexe  = getenv("cmpexe") or "fc /b"
+  os_cmpext  = getenv("cmpext") or ".cmp"
+  os_concat  = "&"
+  os_diffext = getenv("diffext") or ".fc"
+  os_diffexe = getenv("diffexe") or "fc /n"
+  os_grepexe = "findstr /r"
+  os_newline = "\n"
+  if tonumber(luatex_version) < 100 or
+     (tonumber(luatex_version) == 100
+       and tonumber(luatex_revision) < 4) then
     os_newline = "\r\n"
   end
-  os_null     = "nul"
-  os_pathsep  = ";"
-  os_setenv   = "set"
-  os_windows  = true
-  os_yes      = "for /l %I in (1,1,200) do @echo y"
-else
-  os_ascii    = "echo \"\""
-  os_cmpexe   = os.getenv("cmpexe") or "cmp"
-  os_cmpext   = os.getenv("cmpext") or ".cmp"
-  os_concat   = ";"
-  os_diffext  = os.getenv("diffext") or ".diff"
-  os_diffexe  = os.getenv("diffexe") or "diff -c --strip-trailing-cr"
-  os_grepexe  = "grep"
-  os_newline  = "\n"
-  os_null     = "/dev/null"
-  os_pathsep  = ":"
-  os_setenv   = "export"
-  os_windows  = false
-  os_yes      = "printf 'y\\n%.0s' {1..200}"
+  os_null    = "nul"
+  os_pathsep = ";"
+  os_setenv  = "set"
+  os_yes     = "for /l %I in (1,1,200) do @echo y"
 end
 
--- File operations are aided by the LuaFileSystem module, which is available
--- within texlua
-lfs = require("lfs")
-
 -- For cleaning out a directory, which also ensures that it exists
 function cleandir(dir)
   local errorlevel = mkdir(dir)
@@ -454,20 +481,20 @@
   local errorlevel
   for _,i in ipairs(filelist(source, glob)) do
     local source = source .. "/" .. i
-    if os_windows then
-      if lfs.attributes(source)["mode"] == "directory" then
-        errorlevel = os.execute(
+    if os_type == "windows" then
+      if lfs_attributes(source)["mode"] == "directory" then
+        errorlevel = execute(
           "xcopy /y /e /i " .. unix_to_win(source) .. " "
              .. unix_to_win(dest .. "/" .. i) .. " > nul"
         )
       else
-        errorlevel = os.execute(
+        errorlevel = execute(
           "xcopy /y " .. unix_to_win(source) .. " "
              .. unix_to_win(dest) .. " > nul"
         )
       end
     else
-      errorlevel = os.execute("cp -rf " .. source .. " " .. dest)
+      errorlevel = execute("cp -rf " .. source .. " " .. dest)
     end
     if errorlevel ~=0 then
       return errorlevel
@@ -479,11 +506,11 @@
 -- OS-dependent test for a directory
 function direxists(dir)
   local errorlevel
-  if os_windows then
+  if os_type == "windows" then
     errorlevel =
-      os.execute("if not exist \"" .. unix_to_win(dir) .. "\" exit 1")
+      execute("if not exist \"" .. unix_to_win(dir) .. "\" exit 1")
   else
-    errorlevel = os.execute("[ -d " .. dir .. " ]")
+    errorlevel = execute("[ -d " .. dir .. " ]")
   end
   if errorlevel ~= 0 then
     return false
@@ -492,9 +519,9 @@
 end
 
 function fileexists(file)
-  local f = io.open(file, "r")
+  local f = open(file, "r")
   if f ~= nil then
-    io.close(f)
+    close(f)
     return true
   else
     return false
@@ -503,7 +530,6 @@
 
 -- Generate a table containing all file names of the given glob or all files
 -- if absent
--- Not actually OS-dependent but in the same area
 function filelist(path, glob)
   local files = { }
   local pattern
@@ -511,14 +537,14 @@
     pattern = glob_to_pattern(glob)
   end
   if direxists(path) then
-    for entry in lfs.dir(path) do
+    for entry in lfs_dir(path) do
       if pattern then
-        if string.match(entry, pattern) then
-          table.insert(files, entry)
+        if match(entry, pattern) then
+          insert(files, entry)
         end
       else
         if entry ~= "." and entry ~= ".." then
-          table.insert(files, entry)
+          insert(files, entry)
         end
       end
     end
@@ -527,48 +553,34 @@
 end
 
 function mkdir(dir)
-  if os_windows then
+  if os_type == "windows" then
     -- Windows (with the extensions) will automatically make directory trees
     -- but issues a warning if the dir already exists: avoid by including a test
     local dir = unix_to_win(dir)
-    return os.execute(
+    return execute(
       "if not exist "  .. dir .. "\\nul " .. "mkdir " .. dir
     )
   else
-    return os.execute("mkdir -p " .. dir)
+    return execute("mkdir -p " .. dir)
   end
 end
 
--- Find the relationship between two directories
-function relpath(target, source)
-  -- A shortcut for the case where the two are the same
-  if target == source then
-    return ""
-  end
-  local resultdir = ""
-  local trimpattern = "^[^/]*/"
-  -- Trim off identical leading directories
-  while
-    (string.match(target, trimpattern) or "X") ==
-    (string.match(target, trimpattern) or "Y") do
-    target = string.gsub(target, trimpattern, "")
-    source = string.gsub(source, trimpattern, "")
-  end
-  -- Go up from the source
-  for i = 0, select(2, string.gsub(target, "/", "")) do
-    resultdir = resultdir .. "../"
-  end
-  -- Return the relative part plus the unique part of the target
-  return resultdir .. target
+-- Return an absolute path from a relative one
+function abspath(path)
+  local oldpwd = lfs.currentdir()
+  lfs.chdir(path)
+  local result = lfs.currentdir()
+  lfs.chdir(oldpwd)
+  return result
 end
 
 -- Rename
 function ren(dir, source, dest)
   local dir = dir .. "/"
-  if os_windows then
-    return os.execute("ren " .. unix_to_win(dir) .. source .. " " .. dest)
+  if os_type == "windows" then
+    return execute("ren " .. unix_to_win(dir) .. source .. " " .. dest)
   else
-    return os.execute("mv " .. dir .. source .. " " .. dir .. dest)
+    return execute("mv " .. dir .. source .. " " .. dir .. dest)
   end
 end
 
@@ -575,9 +587,9 @@
 -- Remove file(s) based on a glob
 function rm(source, glob)
   for _,i in ipairs(filelist(source, glob)) do
-    os.remove(source .. "/" .. i)
+    os_remove(source .. "/" .. i)
   end
-  -- os.remove doesn't give a sensible errorlevel
+  -- os_remove doesn't give a sensible errorlevel
   return 0
 end
 
@@ -585,21 +597,21 @@
 function rmdir(dir)
   -- First, make sure it exists to avoid any errors
   mkdir(dir)
-  if os_windows then
-    return os.execute("rmdir /s /q " .. unix_to_win(dir))
+  if os_type == "windows" then
+    return execute("rmdir /s /q " .. unix_to_win(dir))
   else
-    return os.execute("rm -r " .. dir)
+    return execute("rm -r " .. dir)
   end
 end
 
 -- Run a command in a given directory
 function run(dir, cmd)
-  return os.execute("cd " .. dir .. os_concat .. cmd)
+  return execute("cd " .. dir .. os_concat .. cmd)
 end
 
 -- Deal with the fact that Windows and Unix use different path separators
 function unix_to_win(path)
-  return string.gsub(path, "/", "\\")
+  return gsub(path, "/", "\\")
 end
 
 --
@@ -607,7 +619,19 @@
 --
 
 -- Do some subtarget for all modules in a bundle
-function allmodules(target)
+local function allmodules(target)
+  local date = ""
+  if optdate then
+    date = " --date=" .. optdate[1]
+  end
+  local engines = ""
+  if optengines then
+    engines = " --engine=" .. concat(optengines, ",")
+  end
+  local release = ""
+  if optrelease then
+    release = " --release=" .. optrelease[1]
+  end
   for _,i in ipairs(modules) do
     print(
       "Running script " .. scriptname .. " with target \"" .. target
@@ -614,18 +638,6 @@
         .. "\" for module "
         .. i
     )
-    local date = ""
-    if optdate then
-      date = " --date=" .. optdate[1]
-    end
-    local engines = ""
-    if optengines then
-      engines = " --engine=" .. table.concat(optengines, ",")
-    end
-    local release = ""
-    if optrelease then
-      release = " --release=" .. optrelease[1]
-    end
     local errorlevel = run(
       i,
       "texlua " .. scriptname .. " " .. target
@@ -645,7 +657,7 @@
 
 -- Set up the check system files: needed for checking one or more tests and
 -- for saving the test files
-function checkinit()
+local function checkinit()
   cleandir(testdir)
   depinstall(checkdeps)
   -- Copy dependencies to the test directory itself: this makes the paths
@@ -669,7 +681,7 @@
   for _,i in ipairs(checksuppfiles) do
     cp(i, supportdir, testdir)
   end
-  os.execute(os_ascii .. ">" .. testdir .. "/ascii.tcx")
+  execute(os_ascii .. ">" .. testdir .. "/ascii.tcx")
 end
 
 -- Copy files to the main CTAN release directory
@@ -709,18 +721,18 @@
         moduledir = module
       end
     end
-    local installdir = tdsdir .. "/" .. dest .. "/" .. moduledir
     -- Convert the file table(s) to a list of individual files
     local filenames = { }
     for _,i in ipairs(files) do
       for _,j in ipairs(i) do
         for _,k in ipairs(filelist(source, j)) do
-          table.insert(filenames, k)
+          insert(filenames, k)
         end
       end
     end
     -- The target is only created if there are actual files to install
     if next(filenames) ~= nil then
+      local installdir = tdsdir .. "/" .. dest .. "/" .. moduledir
       mkdir(installdir)
       for _,i in ipairs(filenames) do
         cp(i, source, installdir)
@@ -753,7 +765,7 @@
 
 -- Convert the raw log file into one for comparison/storage: keeps only
 -- the 'business' part from the tests and removes system-dependent stuff
-function formatlog(logfile, newfile, engine)
+local function formatlog(logfile, newfile, engine)
   local maxprintline = maxprintline
   if engine == "luatex" or engine == "luajittex" then
     maxprintline = maxprintline + 1 -- Deal with an out-by-one error
@@ -760,14 +772,14 @@
   end
   local function killcheck(line)
       -- Skip lines containing file dates
-      if string.match(line, "[^<]%d%d%d%d/%d%d/%d%d") then
+      if match(line, "[^<]%d%d%d%d/%d%d/%d%d") then
         return true
       elseif
       -- Skip \openin/\openout lines in web2c 7.x
       -- As Lua doesn't allow "(in|out)", a slightly complex approach:
       -- do a substitution to check the line is exactly what is required!
-        string.match(
-          string.gsub(line, "^\\openin", "\\openout"), "^\\openout%d%d? = "
+        match(
+          gsub(line, "^\\openin", "\\openout"), "^\\openout%d%d? = "
         ) then
         return true
       end
@@ -777,13 +789,13 @@
   local function normalize(line, lastline)
     -- Zap line numbers from \show, \showbox, \box_show and the like:
     -- do this before wrapping lines
-    line = string.gsub(line, "^l%.%d+ ", "l. ...")
+    line = gsub(line, "^l%.%d+ ", "l. ...")
     -- Also from lua stack traces.
-    line = string.gsub(line, "lua:%d+: in function", "lua:...: in function")
+    line = gsub(line, "lua:%d+: in function", "lua:...: in function")
     -- Allow for wrapped lines: preserve the content and wrap
     -- Skip lines that have an explicit marker for truncation
-    if string.len(line) == maxprintline  and
-       not string.match(line, "%.%.%.$") then
+    if len(line) == maxprintline  and
+       not match(line, "%.%.%.$") then
       return "", (lastline or "") .. line
     end
     local line = (lastline or "") .. line
@@ -792,10 +804,10 @@
     -- This needs to extract the base name from the log name,
     -- and one to allow for the case that there might be "-" chars
     -- in the name (other cases are ignored)
-    line = string.gsub(
+    line = gsub(
       line,
-      string.gsub(
-        string.match("/" .. logfile, ".*/(.*)%" .. logext .. "$"),
+      gsub(
+        match("/" .. logfile, ".*/(.*)%" .. logext .. "$"),
         "-",
         "%%-"
       ),
@@ -802,67 +814,66 @@
       ""
     )
     -- Zap ./ at begin of filename
-    line = string.gsub(line, "%(%.%/", "(")
+    line = gsub(line, "%(%.%/", "(")
     -- Zap paths if places other than 'here' are accessible
     if checksearch then
       local pattern = "%w?:?/[^ ]*/([^/%(%)]*%.%w*)"
       -- Files loaded from TeX: all start ( -- )
-      line = string.gsub(line, "%(" .. pattern, "(../%1")
+      line = gsub(line, "%(" .. pattern, "(../%1")
       -- luaotfload files start with keywords
-      line = string.gsub(line, "from " .. pattern .. "%(", "from. ./%1(")
-      line = string.gsub(line, ": " .. pattern .. "%)", ": ../%1)")
+      line = gsub(line, "from " .. pattern .. "%(", "from. ./%1(")
+      line = gsub(line, ": " .. pattern .. "%)", ": ../%1)")
     end
     -- Deal with the fact that "(.aux)" may have still a leading space
-    line = string.gsub(line, "^ %(%.aux%)", "(.aux)")
+    line = gsub(line, "^ %(%.aux%)", "(.aux)")
     -- Merge all of .fd data into one line so will be removed later
-    if string.match(line, "^ *%([%.%/%w]+%.fd[^%)]*$") then
+    if match(line, "^ *%([%.%/%w]+%.fd[^%)]*$") then
       lastline = (lastline or "") .. line
       return "", (lastline or "") .. line
     end
     -- TeX90/XeTeX knows only the smaller set of dimension units
-    line = string.gsub(
+    line = gsub(
       line,
       "cm, mm, dd, cc, bp, or sp", "cm, mm, dd, cc, nd, nc, bp, or sp"
     )
     -- Normalise a case where fixing a TeX bug changes the message text
-    line = string.gsub(line, "\\csname\\endcsname ", "\\csname\\endcsname")
+    line = gsub(line, "\\csname\\endcsname ", "\\csname\\endcsname")
     -- Zap "on line <num>" and replace with "on line ..."
     -- Two similar cases, Lua patterns mean we need to do them separately
-    line = string.gsub(line, "on line %d*", "on line ...")
-    line = string.gsub(line, "on input line %d*", "on input line ...")
+    line = gsub(line, "on line %d*", "on line ...")
+    line = gsub(line, "on input line %d*", "on input line ...")
     -- Tidy up to ^^ notation
     for i = 0, 31 do
-      line = string.gsub(line, string.char(i), "^^" .. string.char(64 + i))
+      line = gsub(line, char(i), "^^" .. char(64 + i))
     end
     -- Remove 'normal' direction information on boxes with (u)pTeX
-    line = string.gsub(line, ",? yoko direction,?", "")
+    line = gsub(line, ",? yoko direction,?", "")
     -- Remove the \special line that in DVI mode keeps PDFs comparable
-    if string.match(line, "^%.*\\special%{pdf: docinfo << /Creator") then
+    if match(line, "^%.*\\special%{pdf: docinfo << /Creator") then
       return ""
     end
     -- Remove the \special line possibly present in DVI mode for paper size
-    if string.match(line, "^%.*\\special%{papersize") then
+    if match(line, "^%.*\\special%{papersize") then
       return ""
     end
     -- Remove ConTeXt stuff
-    if string.match(line, "^backend         >") or
-       string.match(line, "^close source    >") or
-       string.match(line, "^mkiv lua stats  >") or
-       string.match(line, "^pages           >") or
-       string.match(line, "^system          >") or
-       string.match(line, "^used file       >") or
-       string.match(line, "^used option     >") or
-       string.match(line, "^used structure  >") then
+    if match(line, "^backend         >") or
+       match(line, "^close source    >") or
+       match(line, "^mkiv lua stats  >") or
+       match(line, "^pages           >") or
+       match(line, "^system          >") or
+       match(line, "^used file       >") or
+       match(line, "^used option     >") or
+       match(line, "^used structure  >") then
        return ""
     end
     -- A tidy-up to keep LuaTeX and other engines in sync
-    local utf8_char = unicode.utf8.char
-    line = string.gsub(line, utf8_char(127), "^^?")
+    line = gsub(line, utf8_char(127), "^^?")
     -- Unicode engines display chars in the upper half of the 8-bit range:
     -- tidy up to match pdfTeX if an ASCII engine is in use
     if next(asciiengines) then
       for i = 128, 255 do
-        line = string.gsub(line, utf8_char(i), "^^" .. string.format("%02x", i))
+        line = gsub(line, utf8_char(i), "^^" .. format("%02x", i))
       end
     end
     return line, lastline
@@ -872,10 +883,10 @@
   local prestart = true
   local skipping = false
   -- Read the entire log file as a binary: deals with ^@/^[, etc.
-  local file = assert(io.open(logfile, "rb"))
-  local contents = string.gsub(file:read("*all") .. "\n", "\r\n", "\n")
-  io.close(file)
-  for line in string.gmatch(contents, "([^\n]*)\n") do
+  local file = assert(open(logfile, "rb"))
+  local contents = gsub(file:read("*all") .. "\n", "\r\n", "\n")
+  close(file)
+  for line in gmatch(contents, "([^\n]*)\n") do
     if line == "START-TEST-LOG" then
       prestart = false
     elseif line == "END-TEST-LOG" then
@@ -882,64 +893,64 @@
       break
     elseif line == "OMIT" then
       skipping = true
-    elseif string.match(line, "^%)?TIMO$") then
+    elseif match(line, "^%)?TIMO$") then
       skipping = false
     elseif not prestart and not skipping then
       line, lastline = normalize(line, lastline)
-      if not string.match(line, "^ *$") and not killcheck(line) then
+      if not match(line, "^ *$") and not killcheck(line) then
         newlog = newlog .. line .. os_newline
       end
     end
   end
-  local newfile = io.open(newfile, "w")
-  io.output(newfile)
-  io.write(newlog)
-  io.close(newfile)
+  local newfile = open(newfile, "w")
+  output(newfile)
+  write(newlog)
+  close(newfile)
 end
 
 -- Additional normalization for LuaTeX
-function formatlualog(logfile, newfile)
+local function formatlualog(logfile, newfile)
   local function normalize(line, lastline, dropping)
     -- Find \discretionary or \whatsit lines:
     -- These may come back later
-    if string.match(line, "^%.+\\discretionary$")                or
-       string.match(line, "^%.+\\discretionary %(penalty 50%)$") or
-       string.match(line, "^%.+\\discretionary50%|$")            or
-       string.match(line, "^%.+\\discretionary50%| replacing $") or
-       string.match(line, "^%.+\\whatsit$")                      then
+    if match(line, "^%.+\\discretionary$")                or
+       match(line, "^%.+\\discretionary %(penalty 50%)$") or
+       match(line, "^%.+\\discretionary50%|$")            or
+       match(line, "^%.+\\discretionary50%| replacing $") or
+       match(line, "^%.+\\whatsit$")                      then
       return "", line
     end
     -- For \mathon, we always need this line but the next
     -- may be affected
-    if string.match(line, "^%.+\\mathon$") then
+    if match(line, "^%.+\\mathon$") then
       return line, line
     end
     -- LuaTeX has a flexible output box
-    line = string.gsub(line,"\\box\\outputbox", "\\box255")
+    line = gsub(line,"\\box\\outputbox", "\\box255")
     -- LuaTeX identifies spaceskip glue
-    line = string.gsub(line,"%(\\spaceskip%) ", " ")
+    line = gsub(line,"%(\\spaceskip%) ", " ")
     -- Remove 'display' at end of display math boxes:
     -- LuaTeX omits this as it includes direction in all cases
-    line = string.gsub(line, "(\\hbox%(.*), display$", "%1")
+    line = gsub(line, "(\\hbox%(.*), display$", "%1")
     -- Remove 'normal' direction information on boxes:
     -- any bidi/vertical stuff will still show
-    line = string.gsub(line, ", direction TLT", "")
+    line = gsub(line, ", direction TLT", "")
     -- Find glue setting and round out the last place
     local function round_digits(l, m)
-      return string.gsub(
+      return gsub(
         l,
         m .. " (%-?)%d+%.%d+",
         m .. " %1"
-          .. string.format(
+          .. format(
             "%.3f",
-            string.match(line, m .. " %-?(%d+%.%d+)") or 0
+            match(line, m .. " %-?(%d+%.%d+)") or 0
           )
       )
     end
-    if string.match(line, "glue set %-?%d+%.%d+") then
+    if match(line, "glue set %-?%d+%.%d+") then
       line = round_digits(line, "glue set")
     end
-    if string.match(
+    if match(
         line, "glue %-?%d+%.%d+ plus %-?%d+%.%d+ minus %-?%d+%.%d+$"
       )
       then
@@ -948,9 +959,9 @@
       line = round_digits(line, "minus")
     end
     -- LuaTeX writes ^^M as a new line, which we lose
-    line = string.gsub(line, "%^%^M", "")
+    line = gsub(line, "%^%^M", "")
     -- Remove U+ notation in the "Missing character" message
-    line = string.gsub(
+    line = gsub(
         line,
         "Missing character: There is no (%^%^..) %(U%+(....)%)",
         "Missing character: There is no %1"
@@ -957,26 +968,26 @@
       )
     -- A function to handle the box prefix part
     local function boxprefix(s)
-      return string.gsub(string.match(s, "^(%.+)"), "%.", "%%.")
+      return gsub(match(s, "^(%.+)"), "%.", "%%.")
     end
     -- 'Recover' some discretionary data
-    if string.match(lastline, "^%.+\\discretionary %(penalty 50%)$") and
-       string.match(line, boxprefix(lastline) .. "%.= ") then
-       return string.gsub(line, "%.= ", ""),""
+    if match(lastline, "^%.+\\discretionary %(penalty 50%)$") and
+       match(line, boxprefix(lastline) .. "%.= ") then
+       return gsub(line, "%.= ", ""),""
     end
     -- Where the last line was a discretionary, looks for the
     -- info one level in about what it represents
-    if string.match(lastline, "^%.+\\discretionary$")                or
-       string.match(lastline, "^%.+\\discretionary %(penalty 50%)$") or
-       string.match(lastline, "^%.+\\discretionary50%|$")            or
-       string.match(lastline, "^%.+\\discretionary50%| replacing $") then
+    if match(lastline, "^%.+\\discretionary$")                or
+       match(lastline, "^%.+\\discretionary %(penalty 50%)$") or
+       match(lastline, "^%.+\\discretionary50%|$")            or
+       match(lastline, "^%.+\\discretionary50%| replacing $") then
       local prefix = boxprefix(lastline)
-      if string.match(line, prefix .. "%.") or
-         string.match(line, prefix .. "%|") then
-         if string.match(lastline, " replacing $") and
+      if match(line, prefix .. "%.") or
+         match(line, prefix .. "%|") then
+         if match(lastline, " replacing $") and
             not dropping then
            -- Modify the return line
-           return string.gsub(line, "^%.", ""), lastline, true
+           return gsub(line, "^%.", ""), lastline, true
          else
            return "", lastline, true
          end
@@ -986,11 +997,11 @@
           return line, ""
         else
           -- Not quite a normal discretionary
-          if string.match(lastline, "^%.+\\discretionary50%|$") then
-            lastline =  string.gsub(lastline, "50%|$", "")
+          if match(lastline, "^%.+\\discretionary50%|$") then
+            lastline =  gsub(lastline, "50%|$", "")
           end
           -- Remove some info that TeX90 lacks
-          lastline = string.gsub(lastline, " %(penalty 50%)$", "")
+          lastline = gsub(lastline, " %(penalty 50%)$", "")
           -- A normal (TeX90) discretionary:
           -- add with the line break reintroduced
           return lastline .. os_newline .. line, ""
@@ -999,13 +1010,13 @@
     end
     -- Look for another form of \discretionary, replacing a "-"
     pattern = "^%.+\\discretionary replacing *$"
-    if string.match(line, pattern) then
+    if match(line, pattern) then
       return "", line
     else
-      if string.match(lastline, pattern) then
+      if match(lastline, pattern) then
         local prefix = boxprefix(lastline)
-        if string.match(line, prefix .. "%.\\kern") then
-          return string.gsub(line, "^%.", ""), lastline, true
+        if match(line, prefix .. "%.\\kern") then
+          return gsub(line, "^%.", ""), lastline, true
         elseif dropping then
           return "", ""
         else
@@ -1015,26 +1026,26 @@
     end
     -- For \mathon, if the current line is an empty \hbox then
     -- drop it
-    if string.match(lastline, "^%.+\\mathon$") then
+    if match(lastline, "^%.+\\mathon$") then
       local prefix = boxprefix(lastline)
-      if string.match(line, prefix .. "\\hbox%(0%.0%+0%.0%)x0%.0$") then
+      if match(line, prefix .. "\\hbox%(0%.0%+0%.0%)x0%.0$") then
         return "", ""
       end
     end
     -- Various \local... things that other engines do not do:
     -- Only remove the no-op versions
-    if string.match(line, "^%.+\\localpar$")                or
-       string.match(line, "^%.+\\localinterlinepenalty=0$") or
-       string.match(line, "^%.+\\localbrokenpenalty=0$")    or
-       string.match(line, "^%.+\\localleftbox=null$")       or
-       string.match(line, "^%.+\\localrightbox=null$")      then
+    if match(line, "^%.+\\localpar$")                or
+       match(line, "^%.+\\localinterlinepenalty=0$") or
+       match(line, "^%.+\\localbrokenpenalty=0$")    or
+       match(line, "^%.+\\localleftbox=null$")       or
+       match(line, "^%.+\\localrightbox=null$")      then
        return "", ""
     end
     -- Older LuaTeX versions set the above up as a whatsit
     -- (at some stage this can therefore go)
-    if string.match(lastline, "^%.+\\whatsit$") then
+    if match(lastline, "^%.+\\whatsit$") then
       local prefix = boxprefix(lastline)
-      if string.match(line, prefix .. "%.") then
+      if match(line, prefix .. "%.") then
         return "", lastline, true
       else
         -- End of a \whatsit block
@@ -1044,44 +1055,44 @@
     -- Wrap some cases that can be picked out
     -- In some places LuaTeX does use max_print_line, then we
     -- get into issues with different wrapping approaches
-    if string.len(line) == maxprintline then
+    if len(line) == maxprintline then
       return "", lastline .. line
-    elseif string.len(lastline) == maxprintline then
-      if string.match(line, "\\ETC%.%}$") then
+    elseif len(lastline) == maxprintline then
+      if match(line, "\\ETC%.%}$") then
         -- If the line wrapped at \ETC we might have lost a space
         return lastline
-          .. ((string.match(line, "^\\ETC%.%}$") and " ") or "")
+          .. ((match(line, "^\\ETC%.%}$") and " ") or "")
           .. line, ""
-      elseif string.match(line, "^%}%}%}$") then
+      elseif match(line, "^%}%}%}$") then
         return lastline .. line, ""
       else
         return lastline .. os_newline .. line, ""
       end
     -- Return all of the text for a wrapped (multi)line
-    elseif string.len(lastline) > maxprintline then
+    elseif len(lastline) > maxprintline then
       return lastline .. line, ""
     end
     -- Remove spaces at the start of lines: deals with the fact that LuaTeX
     -- uses a different number to the other engines
-    return string.gsub(line, "^%s+", ""), ""
+    return gsub(line, "^%s+", ""), ""
   end
   local newlog = ""
   local lastline = ""
   local dropping = false
   -- Read the entire log file as a binary: deals with ^@/^[, etc.
-  local file = assert(io.open(logfile, "rb"))
-  local contents = string.gsub(file:read("*all") .. "\n", "\r\n", "\n")
-  io.close(file)
-  for line in string.gmatch(contents, "([^\n]*)\n") do
+  local file = assert(open(logfile, "rb"))
+  local contents = gsub(file:read("*all") .. "\n", "\r\n", "\n")
+  close(file)
+  for line in gmatch(contents, "([^\n]*)\n") do
     line, lastline, dropping = normalize(line, lastline, dropping)
-    if not string.match(line, "^ *$") then
+    if not match(line, "^ *$") then
       newlog = newlog .. line .. os_newline
     end
   end
-  local newfile = io.open(newfile, "w")
-  io.output(newfile)
-  io.write(newlog)
-  io.close(newfile)
+  local newfile = open(newfile, "w")
+  output(newfile)
+  write(newlog)
+  close(newfile)
 end
 
 -- Look for files, directory by directory, and return the first existing
@@ -1100,13 +1111,13 @@
 function listmodules()
   local modules = { }
   local exclmodules = exclmodules or { }
-  for entry in lfs.dir(".") do
+  for entry in lfs_dir(".") do
     if entry ~= "." and entry ~= ".." then
-      local attr = lfs.attributes(entry)
+      local attr = lfs_attributes(entry)
       assert(type(attr) == "table")
       if attr.mode == "directory" then
         if not exclmodules[entry] then
-          table.insert(modules, entry)
+          insert(modules, entry)
         end
       end
     end
@@ -1167,7 +1178,7 @@
         "Error: failed to find " .. pdfext .. ", " .. tlgext .. " or "
           .. lveext .. " file for " .. name .. "!"
       )
-      os.exit(1)
+      exit(1)
     end
     runtest(name, engine, true, lveext, true)
     pdffile = testdir .. "/" .. testname .. pdfext
@@ -1181,8 +1192,8 @@
     for _,v in pairs({pdffile, tlgfile}) do
       if v then
         cp(
-          string.match(v, ".*/(.*)"),
-          string.match(v, "(.*)/.*"),
+          match(v, ".*/(.*)"),
+          match(v, "(.*)/.*"),
           testdir
         )
       end
@@ -1189,11 +1200,11 @@
     end
   end
   if pdffile then
-    local pdffile = string.match(pdffile, ".*/(.*)")
+    local pdffile = match(pdffile, ".*/(.*)")
     ren(
       testdir,
       pdffile,
-      string.gsub(pdffile, pdfext .. "$", ".ref" .. pdfext)
+      gsub(pdffile, pdfext .. "$", ".ref" .. pdfext)
     )
     return true
   else
@@ -1212,14 +1223,14 @@
   if not refpdffile then
     return
   end
-  if os_windows then
+  if os_type == "windows" then
     refpdffile = unix_to_win(refpdffile)
   end
-  errorlevel = os.execute(
+  errorlevel = execute(
     os_cmpexe .. " " .. refpdffile .. " " .. pdffile .. " > " .. cmpfile
   )
   if errorlevel == 0 then
-    os.remove(cmpfile)
+    os_remove(cmpfile)
   end
   return errorlevel
 end
@@ -1233,18 +1244,18 @@
   if not tlgfile then
     return
   end
-  if os_windows then
+  if os_type == "windows" then
     tlgfile = unix_to_win(tlgfile)
   end
   -- Do additional log formatting if the engine is LuaTeX, there is no
   -- LuaTeX-specific .tlg file and the default engine is not LuaTeX
   if engine == "luatex"
-    and not string.match(tlgfile, "%.luatex" .. "%" .. tlgext)
+    and not match(tlgfile, "%.luatex" .. "%" .. tlgext)
     and stdengine ~= "luatex"
     and stdengine ~= "luajittex"
     then
     local luatlgfile = testdir .. "/" .. name .. ".luatex" ..  tlgext
-    if os_windows then
+    if os_type == "windows" then
       luatlgfile = unix_to_win(luatlgfile)
     end
     formatlualog(tlgfile, luatlgfile)
@@ -1252,11 +1263,11 @@
     -- This allows code sharing below: we only need the .tlg name in one place
     tlgfile = luatlgfile
   end
-  errorlevel = os.execute(
+  errorlevel = execute(
     os_diffexe .. " " .. tlgfile .. " " .. logfile .. " > " .. difffile
   )
   if errorlevel == 0 then
-    os.remove(difffile)
+    os_remove(difffile)
   end
   return errorlevel
 end
@@ -1272,31 +1283,31 @@
   local realengine = engine
   local format
   if
-    string.match(checkformat, "tex$") and
-    not string.match(engine, checkformat) then
-    format = " -fmt=" .. string.gsub(engine, "(.*)tex$", "%1") .. checkformat
+    match(checkformat, "tex$") and
+    not match(engine, checkformat) then
+    format = " -fmt=" .. gsub(engine, "(.*)tex$", "%1") .. checkformat
   else
     format = ""
   end
   -- Special casing for e-LaTeX format
   if
-    string.match(checkformat, "^latex$") and
-    string.match(engine, "^etex$") then
+    match(checkformat, "^latex$") and
+    match(engine, "^etex$") then
     format = " -fmt=latex"
   end
   -- Special casing for (u)pTeX LaTeX formats
   if
-    string.match(checkformat, "^latex$") and
-    string.match(engine, "^u?ptex$") then
+    match(checkformat, "^latex$") and
+    match(engine, "^u?ptex$") then
     realengine = "e" .. engine
   end
   -- Special casing for XeTeX engine
   local checkopts = checkopts
-  if string.match(engine, "xetex") and not makepdf then
+  if match(engine, "xetex") and not makepdf then
     checkopts = checkopts .. " -no-pdf"
   end
   -- Special casing for ConTeXt
-  if string.match(checkformat, "^context$") then
+  if match(checkformat, "^context$") then
     format = ""
     if engine == "luatex" or engine == "luajittex" then
       realengine = "context"
@@ -1306,7 +1317,7 @@
       realengine = "texexec --xetex"
     else
       print("Engine incompatible with format")
-      os.exit(1)
+      exit(1)
     end
   end
   local logfile = testdir .. "/" .. name .. logext
@@ -1349,12 +1360,12 @@
   formatlog(logfile, newfile, engine)
   -- Store secondary files for this engine
   for _,i in ipairs(filelist(testdir, name .. ".???")) do
-    local ext = string.match(i, "%....")
+    local ext = match(i, "%....")
     if ext ~= lvtext and ext ~= tlgext and ext ~= lveext and ext ~= logext then
       if not fileexists(testsuppdir .. "/" .. i) then
         ren(
-          testdir, i, string.gsub(
-            i, string.gsub(name, "%-", "%%-"), name .. "." .. engine
+          testdir, i, gsub(
+            i, gsub(name, "%-", "%%-"), name .. "." .. engine
           )
         )
       end
@@ -1368,7 +1379,7 @@
 end
 
 function dvitopdf(name, dir, engine, hide)
-  if string.match(engine, "^u?ptex$") then
+  if match(engine, "^u?ptex$") then
     run(
       dir,
       os_setenv .. " SOURCE_DATE_EPOCH=" .. epoch
@@ -1392,10 +1403,16 @@
 
 -- Strip the extension from a file name (if present)
 function stripext(file)
-  local name = string.match(file, "^(.*)%.")
+  local name = match(file, "^(.*)%.")
   return name or file
 end
 
+-- Strip the path from a file name (if present)
+function basename(file)
+  local name = match(file, "^.*/([^/]*)$")
+  return name or file
+end
+
 -- Look for a test: could be in the testfiledir or the unpackdir
 function testexists(test)
   return(locate({testfiledir, unpackdir}, {test .. lvtext}))
@@ -1411,7 +1428,7 @@
     run(
       typesetdir,
       os_setenv .. " " .. envvar .. "=." .. os_pathsep
-        .. relpath(localdir, typesetdir)
+        .. abspath(localdir)
         .. (typesetsearch and os_pathsep or "") ..
       os_concat ..
       command
@@ -1433,7 +1450,7 @@
     -- LaTeX always generates an .aux file, so there is a need to
     -- look inside it for a \citation line
     local grep
-    if os_windows then
+    if os_type == "windows" then
       grep = "\\\\"
     else
      grep = "\\\\\\\\"
@@ -1452,7 +1469,7 @@
         runtool(
           "BIBINPUTS",
           os_setenv .. " BSTINPUTS=." .. os_pathsep
-            .. relpath(localdir, typesetdir)
+            .. abspath(localdir)
             .. (typesetsearch and os_pathsep or "") ..
           os_concat ..
           bibtexexe .. " " .. bibtexopts .. " " .. name
@@ -1488,11 +1505,11 @@
 end
 
 function typesetpdf(file)
-  local name = stripext(file)
+  local name = stripext(basename(file))
   print("Typesetting " .. name)
   local errorlevel = typeset(file)
   if errorlevel == 0 then
-    os.remove(name .. ".pdf")
+    os_remove(name .. ".pdf")
     cp(name .. ".pdf", typesetdir, ".")
   else
     print(" ! Compilation failed")
@@ -1505,7 +1522,7 @@
   if errorlevel ~= 0 then
     return errorlevel
   else
-    local name = stripext(file)
+    local name = stripext(basename(file))
     errorlevel = biber(name) + bibtex(name)
     if errorlevel == 0 then
       local function cycle(name)
@@ -1572,7 +1589,7 @@
     -- No names passed: find all test files
     if not next(names) then
       for _,i in pairs(filelist(testfiledir, "*" .. lvtext)) do
-        table.insert(names, stripext(i))
+        insert(names, stripext(i))
       end
       for _,i in ipairs(filelist(unpackdir, "*" .. lvtext)) do
         if fileexists(testfiledir .. "/" .. i) then
@@ -1579,7 +1596,7 @@
           print("Duplicate test file: " .. i)
           return 1
         else
-          table.insert(names, stripext(i))
+          insert(names, stripext(i))
         end
       end
     end
@@ -1623,7 +1640,7 @@
   for _,i in ipairs(filelist(testdir, "*" .. os_diffext)) do
     print("  - " .. testdir .. "/" .. i)
     print("")
-    local f = io.open(testdir .. "/" .. i,"r")
+    local f = open(testdir .. "/" .. i,"r")
     local content = f:read("*all")
     f:close()
     print("-----------------------------------------------------------------------------------")
@@ -1678,8 +1695,8 @@
   for _,i in ipairs(typesetsuppfiles) do
     cp(i, supportdir, testdir)
   end
-  local engine = string.gsub(stdengine, "tex$", "latex")
-  local localdir = relpath(localdir, testdir)
+  local engine = gsub(stdengine, "tex$", "latex")
+  local localdir = abspath(localdir)
   print("Checking source files")
   for _,i in ipairs(cmdchkfiles) do
     for _,j in ipairs(filelist(".", i)) do
@@ -1693,9 +1710,9 @@
           " \"\\PassOptionsToClass{check}{l3doc} \\input " .. j .. "\""
           .. " > " .. os_null
       )
-      for line in io.lines(testdir .. "/" .. stripext(j) .. ".cmds") do
-        if string.match(line, "^%!") then
-          print("   - " .. string.match(line, "^%! (.*)"))
+      for line in lines(testdir .. "/" .. stripext(j) .. ".cmds") do
+        if match(line, "^%!") then
+          print("   - " .. match(line, "^%! (.*)"))
         end
       end
     end
@@ -1793,7 +1810,7 @@
     for _,i in ipairs(include) do
       for _,j in ipairs(filelist(".", i)) do
         if not excludelist[j] then
-          table.insert(includelist, j)
+          insert(includelist, j)
         end
       end
     end
@@ -1805,7 +1822,7 @@
     -- Work out what PDF files are available
     pdffiles = { }
     for _,i in ipairs(typesetfiles) do
-      table.insert(pdffiles, (string.gsub(i, "%.%w+$", ".pdf")))
+      insert(pdffiles, (gsub(i, "%.%w+$", ".pdf")))
     end
     typesetlist = excludelist(typesetfiles, {sourcefiles})
     sourcelist = excludelist(
@@ -1834,22 +1851,24 @@
   unpack()
   -- Main loop for doc creation
   for _,i in ipairs(typesetfiles) do
-    for _,j in ipairs(filelist(".", i)) do
-      -- Allow for command line selection of files
-      local typeset = true
-      if files and next(files) then
-        typeset = false
-        for _,k in ipairs(files) do
-          if k == stripext(j) then
-            typeset = true
-            break
+    for _, dir in ipairs({unpackdir, typesetdir}) do
+      for _,j in ipairs(filelist(dir, i)) do
+        -- Allow for command line selection of files
+        local typeset = true
+        if files and next(files) then
+          typeset = false
+          for _,k in ipairs(files) do
+            if k == stripext(j) then
+              typeset = true
+              break
+            end
           end
         end
-      end
-      if typeset then
-        local errorlevel = typesetpdf(j)
-        if errorlevel ~= 0 then
-          return errorlevel
+        if typeset then
+          local errorlevel = typesetpdf(abspath(dir) .. "/" .. j)
+          if errorlevel ~= 0 then
+            return errorlevel
+          end
         end
       end
     end
@@ -1863,8 +1882,8 @@
   if errorlevel ~= 0 then
     return errorlevel
   end
-  kpse.set_program_name("latex")
-  local texmfhome = kpse.var_value("TEXMFHOME")
+  set_program_name("latex")
+  local texmfhome = var_value("TEXMFHOME")
   local installdir = texmfhome .. "/tex/" .. moduledir
   errorlevel = cleandir(installdir)
   if errorlevel ~= 0 then
@@ -1928,13 +1947,13 @@
     function setversion_update_line(line, date, release)
       -- No real regex so do it one type at a time
       for _,i in pairs({"Class", "File", "Package"}) do
-        if string.match(
+        if match(
           line,
           "^\\Provides" .. i .. "{[a-zA-Z0-9%-%.]+}%[[^%]]*%]$"
         ) then
-          line = string.gsub(line, "%[%d%d%d%d/%d%d/%d%d", "["
-            .. string.gsub(date, "%-", "/"))
-          line = string.gsub(
+          line = gsub(line, "%[%d%d%d%d/%d%d/%d%d", "["
+            .. gsub(date, "%-", "/"))
+          line = gsub(
             line, "(%[%d%d%d%d/%d%d/%d%d) [^ ]*", "%1 " .. release
           )
           break
@@ -1946,14 +1965,14 @@
     function setversion_update_line(line, date, release)
       -- No real regex so do it one type at a time
       for _,i in pairs({"Class", "File", "Package"}) do
-        if string.match(
+        if match(
           line,
           "^\\ProvidesExpl" .. i .. " *{[a-zA-Z0-9%-%.]+}"
         ) then
-          line = string.gsub(
+          line = gsub(
             line,
             "{%d%d%d%d/%d%d/%d%d}( *){[^}]*}",
-            "{" .. string.gsub(date, "%-", "/") .. "}%1{" .. release .. "}"
+            "{" .. gsub(date, "%-", "/") .. "}%1{" .. release .. "}"
           )
           break
         end
@@ -1962,10 +1981,10 @@
     end
   elseif versionform == "filename" then
     function setversion_update_line(line, date, release)
-      if string.match(line, "^\\def\\filedate{%d%d%d%d/%d%d/%d%d}$") then
-        line = "\\def\\filedate{" .. string.gsub(date, "%-", "/") .. "}"
+      if match(line, "^\\def\\filedate{%d%d%d%d/%d%d/%d%d}$") then
+        line = "\\def\\filedate{" .. gsub(date, "%-", "/") .. "}"
       end
-      if string.match(line, "^\\def\\fileversion{[^}]+}$") then
+      if match(line, "^\\def\\fileversion{[^}]+}$") then
         line = "\\def\\fileversion{" .. release .. "}"
       end
       return line
@@ -1972,10 +1991,10 @@
     end
   elseif versionform == "ExplFileDate" then
     function setversion_update_line(line, date, release)
-      if string.match(line, "^\\def\\ExplFileDate{%d%d%d%d/%d%d/%d%d}$") then
-        line = "\\def\\ExplFileDate{" .. string.gsub(date, "%-", "/") .. "}"
+      if match(line, "^\\def\\ExplFileDate{%d%d%d%d/%d%d/%d%d}$") then
+        line = "\\def\\ExplFileDate{" .. gsub(date, "%-", "/") .. "}"
       end
-      if string.match(line, "^\\def\\ExplFileVersion{[^}]+}$") then
+      if match(line, "^\\def\\ExplFileVersion{[^}]+}$") then
         line = "\\def\\ExplFileVersion{" .. release .. "}"
       end
       return line
@@ -1988,36 +2007,36 @@
   return line
 end
 
-function setversion()
-  local function rewrite(file, date, version)
+function setversion(dir)
+  local function rewrite(dir, file, date, release)
     local changed = false
-    local lines = ""
-    for line in io.lines(file) do
-      local newline = setversion_update_line(line, date, version)
+    local result = ""
+    for line in lines(dir .. "/" .. file) do
+      local newline = setversion_update_line(line, date, release)
       if newline ~= line then
         line = newline
         changed = true
       end
-      lines = lines .. line .. os_newline
+      result = result .. line .. os_newline
     end
     if changed then
       -- Avoid adding/removing end-of-file newline
-      local f = io.open(file, "rb")
+      local f = open(dir .. "/" .. file, "rb")
       local content = f:read("*all")
-      io.close(f)
-      if not string.match(content, os_newline .. "$") then
-        string.gsub(lines, os_newline .. "$", "")
+      close(f)
+      if not match(content, os_newline .. "$") then
+        gsub(result, os_newline .. "$", "")
       end
       -- Write the new file
-      ren(".", file, file .. bakext)
-      local f = io.open(file, "w")
-      io.output(f)
-      io.write(lines)
-      io.close(f)
-      rm(".", file .. bakext)
+      ren(dir, file, file .. bakext)
+      local f = open(dir .. "/" .. file, "w")
+      output(f)
+      write(result)
+      close(f)
+      rm(dir, file .. bakext)
     end
   end
-  local date = os.date("%Y-%m-%d")
+  local date = os_date("%Y-%m-%d")
   if optdate then
     date = optdate[1] or date
   end
@@ -2025,9 +2044,10 @@
   if optrelease then
     release = optrelease[1] or release
   end
+  local dir = dir or "."
   for _,i in pairs(versionfiles) do
-    for _,j in pairs(filelist(".", i)) do
-      rewrite(j, date, release)
+    for _,j in pairs(filelist(dir, i)) do
+      rewrite(dir, j, date, release)
     end
   end
   return 0
@@ -2083,10 +2103,10 @@
       -- This 'yes' business is needed to pass a series of "y\n" to
       -- TeX if \askforoverwrite is true
       -- That is all done using a file as it's the only way on Windows and
-      -- on Unix the "yes" command can't be used inside os.execute (it never
+      -- on Unix the "yes" command can't be used inside execute (it never
       -- stops, which confuses Lua)
-      os.execute(os_yes .. ">>" .. localdir .. "/yes")
-      local localdir = relpath(localdir, unpackdir)
+      execute(os_yes .. ">>" .. localdir .. "/yes")
+      local localdir = abspath(localdir)
       errorlevel = run(
         unpackdir,
         os_setenv .. " TEXINPUTS=." .. os_pathsep
@@ -2107,7 +2127,7 @@
 function version()
   print(
     "\n"
-    .. "l3build Release " .. string.gsub(release_date, "/", "-") .. "\n"
+    .. "l3build Release " .. gsub(release_date, "/", "-") .. "\n"
   )
 end
 
@@ -2187,9 +2207,9 @@
     end
   end
   if errorlevel ~= 0 then
-    os.exit(1)
+    exit(1)
   else
-    os.exit(0)
+    exit(0)
   end
 end
 
@@ -2197,9 +2217,9 @@
 main = main or stdmain
 
 -- Pick up and read any per-run testfiledir
-if userargs["testfiledir"] then
-  if #userargs["testfiledir"] == 1 then
-    testfiledir = userargs["testfiledir"][1]
+if options["testfiledir"] then
+  if #options["testfiledir"] == 1 then
+    testfiledir = options["testfiledir"][1]
     if fileexists(testfiledir .. "/config.lua") then
       dofile(testfiledir .. "/config.lua")
     end
@@ -2210,4 +2230,4 @@
 end
 
 -- Call the main function
-main(userargs["target"], userargs["files"])
+main(options["target"], options["files"])

Added: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3intarray.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3intarray.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3intarray.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -0,0 +1,104 @@
+%%
+%% This is file `l3intarray.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3intarray.dtx  (with options: `package')
+%% 
+%% Copyright (C) 2011-2017 The LaTeX3 Project
+%% 
+%% It may be distributed and/or modified under the conditions of
+%% the LaTeX Project Public License (LPPL), either version 1.3c of
+%% this license or (at your option) any later version.  The latest
+%% version of this license is in the file:
+%% 
+%%    http://www.latex-project.org/lppl.txt
+%% 
+%% This file is part of the "l3experimental bundle" (The Work in LPPL)
+%% and all files in that bundle must be distributed together.
+%% 
+%% File: l3intarray.dtx Copyright (C) 2017 The LaTeX3 Project
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
+  {}
+  {%
+    \PackageError{l3intarray}{Support package l3kernel too old}
+      {%
+        Please install an up to date version of l3kernel\MessageBreak
+        using your TeX package manager or from CTAN.\MessageBreak
+        \MessageBreak
+        Loading l3intarray will abort!%
+      }%
+    \endinput
+  }
+\ProvidesExplPackage{l3intarray}{2017/05/13}{}
+  {L3 Experimental low-level arrays of small integers}
+\int_new:N \g__intarray_font_int
+\cs_new_protected:Npn \__intarray_new:Nn #1#2
+  {
+    \__chk_if_free_cs:N #1
+    \int_gincr:N \g__intarray_font_int
+    \tex_global:D \tex_font:D #1 = cmr10~at~ \g__intarray_font_int sp \scan_stop:
+    \tex_hyphenchar:D #1 = \int_eval:n {#2} \scan_stop:
+    \int_compare:nNnT { \tex_hyphenchar:D #1 } > 0
+      { \tex_fontdimen:D \tex_hyphenchar:D #1 #1 = 0 sp \scan_stop: }
+    \int_step_inline:nnnn { 1 } { 1 } { 8 }
+      { \tex_fontdimen:D ##1 #1 = 0 sp \scan_stop: }
+  }
+\cs_new:Npn \__intarray_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 }
+\cs_new_protected:Npn \__intarray_gset_fast:Nnn #1#2#3
+  { \tex_fontdimen:D \int_eval:n {#2} #1 = \int_eval:n {#3} sp \scan_stop: }
+\cs_new_protected:Npn \__intarray_gset:Nnn #1#2#3
+  {
+    \exp_args:Nff \__intarray_gset_aux:Nnn #1
+      { \int_eval:n {#2} } { \int_eval:n {#3} }
+  }
+\cs_new_protected:Npn \__intarray_gset_aux:Nnn #1#2#3
+  {
+    \int_compare:nTF { 1 <= #2 <= \__intarray_count:N #1 }
+      {
+        \int_compare:nTF { - \c_max_dim <= \int_abs:n {#3} <= \c_max_dim }
+          { \__intarray_gset_fast:Nnn #1 {#2} {#3} }
+          {
+            \__msg_kernel_error:nnxxxx { intarray } { overflow }
+              { \token_to_str:N #1 } {#2} {#3}
+              { \int_compare:nNnT {#3} < 0 { - } \__int_value:w \c_max_dim }
+            \__intarray_gset_fast:Nnn #1 {#2}
+              { \int_compare:nNnT {#3} < 0 { - } \c_max_dim }
+          }
+      }
+      {
+        \__msg_kernel_error:nnxxx { intarray } { out-of-bounds }
+          { \token_to_str:N #1 } {#2} { \__intarray_count:N #1 }
+      }
+  }
+\cs_new:Npn \__intarray_item_fast:Nn #1#2
+  { \__int_value:w \tex_fontdimen:D \int_eval:n {#2} #1 }
+\cs_new:Npn \__intarray_item:Nn #1#2
+  { \exp_args:Nf \__intarray_item_aux:Nn #1 { \int_eval:n {#2} } }
+\cs_new:Npn \__intarray_item_aux:Nn #1#2
+  {
+    \int_compare:nTF { 1 <= #2 <= \__intarray_count:N #1 }
+      { \__intarray_item_fast:Nn #1 {#2} }
+      {
+        \__msg_kernel_expandable_error:nnnnn { intarray } { out-of-bounds }
+          { \token_to_str:N #1 } {#2} { \__intarray_count:N #1 }
+        0
+      }
+  }
+\__msg_kernel_new:nnnn { intarray } { overflow }
+  { Integers~larger~than~2^{30}-1~cannot~be~stored~in~arrays. }
+  {
+    An~attempt~was~made~to~store~#3~at~position~#2~in~the~array~'#1'.~
+    The~largest~allowed~value~#4~will~be~used~instead.
+  }
+\__msg_kernel_new:nnnn { intarray } { out-of-bounds }
+  { Access~to~an~entry~beyond~an~array's~bounds. }
+  {
+    An~attempt~was~made~to~access~or~store~data~at~position~#2~of~the~
+    array~'#1',~but~this~array~has~entries~at~positions~from~1~to~#3.
+  }
+%% 
+%%
+%% End of file `l3intarray.sty'.


Property changes on: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3intarray.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3regex.dtx  (with options: `package,trace')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -19,8 +19,8 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: l3regex.dtx Copyright (C) 2011-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{l3regex}{Support package l3kernel too old}
@@ -32,10 +32,46 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{l3regex}{2017/04/01}{}
+\ProvidesExplPackage{l3regex}{2017/05/13}{}
   {L3 Experimental regular expressions}
-\RequirePackage{l3tl-build, l3tl-analysis, l3str-convert}
+\RequirePackage{l3tl-build, l3tl-analysis, l3intarray}
 \cs_generate_variant:Nn \tl_to_str:n { V }
+\cs_new_protected:Npn \__regex_standard_escapechar:
+  { \int_set:Nn \tex_escapechar:D { `\\ } }
+\cs_new:Npn \__regex_toks_use:w { \tex_the:D \tex_toks:D }
+\cs_new_protected:Npn \__regex_toks_clear:N #1
+  { \tex_toks:D #1 { } }
+\cs_new_eq:NN \__regex_toks_set:Nn \tex_toks:D
+\cs_new_protected:Npn \__regex_toks_set:No #1
+  { \__regex_toks_set:Nn #1 \exp_after:wN }
+\cs_new_protected:Npn \__regex_toks_memcpy:NNn #1#2#3
+  {
+    \prg_replicate:nn {#3}
+      {
+        \tex_toks:D #1 = \tex_toks:D #2
+        \int_incr:N #1
+        \int_incr:N #2
+      }
+  }
+\cs_new_protected:Npn \__regex_toks_put_left:Nx #1#2
+  {
+    \cs_set:Npx \__regex_tmp:w { #2 }
+    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+      { \exp_after:wN \__regex_tmp:w \tex_the:D \tex_toks:D #1 }
+  }
+\cs_new_protected:Npn \__regex_toks_put_right:Nx #1#2
+  {
+    \cs_set:Npx \__regex_tmp:w {#2}
+    \tex_toks:D #1 \exp_after:wN
+      { \tex_the:D \tex_toks:D \exp_after:wN #1 \__regex_tmp:w }
+  }
+\cs_new_protected:Npn \__regex_toks_put_right:Nn #1#2
+  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
+\cs_new:Npn \__regex_current_cs_to_str:
+  {
+    \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
+    \tex_the:D \tex_toks:D \l__regex_current_pos_int
+  }
 \cs_new:Npn \__regex_tmp:w { }
 \tl_new:N   \l__regex_internal_a_tl
 \tl_new:N   \l__regex_internal_b_tl
@@ -50,8 +86,15 @@
     \__regex_branch:n
       { \__regex_class:NnnnN \c_true_bool { } { 1 } { 0 } \c_true_bool }
   }
+\__intarray_new:Nn \g__regex_charcode_intarray { 65536 }
+\__intarray_new:Nn \g__regex_catcode_intarray { 65536 }
+\__intarray_new:Nn \g__regex_balance_intarray { 65536 }
 \int_new:N \l__regex_balance_int
 \tl_new:N \l__regex_cs_name_tl
+\int_const:Nn \c__regex_ascii_min_int { 0 }
+\int_const:Nn \c__regex_ascii_max_control_int { 31 }
+\int_const:Nn \c__regex_ascii_max_int { 127 }
+\int_const:Nn \c__regex_ascii_lower_int { `a - `A }
 \cs_new_protected:Npn \__regex_break_true:w
    #1 \__regex_break_point:TF #2 #3 {#2}
 \cs_new_protected:Npn \__regex_break_point:TF #1 #2 { #2 }
@@ -108,12 +151,12 @@
     \if_int_compare:w \l__regex_current_char_int > `Z \exp_stop_f:
       \if_int_compare:w \l__regex_current_char_int > `z \exp_stop_f: \else:
         \if_int_compare:w \l__regex_current_char_int < `a \exp_stop_f: \else:
-          \int_sub:Nn \l__regex_case_changed_char_int { \c__str_ascii_lower_int }
+          \int_sub:Nn \l__regex_case_changed_char_int { \c__regex_ascii_lower_int }
         \fi:
       \fi:
     \else:
       \if_int_compare:w \l__regex_current_char_int < `A \exp_stop_f: \else:
-        \int_add:Nn \l__regex_case_changed_char_int { \c__str_ascii_lower_int }
+        \int_add:Nn \l__regex_case_changed_char_int { \c__regex_ascii_lower_int }
       \fi:
     \fi:
   }
@@ -152,12 +195,7 @@
     \int_compare:nNnTF \l__regex_current_catcode_int = 0
       {
         \tl_set:Nx \l__regex_internal_a_tl
-          {
-            \scan_stop:
-            \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
-            \tex_the:D \tex_toks:D \l__regex_current_pos_int
-            \scan_stop:
-          }
+          { \scan_stop: \__regex_current_cs_to_str: \scan_stop: }
         \tl_if_in:noTF { \scan_stop: #1 \scan_stop: } \l__regex_internal_a_tl
           { \__regex_break_true:w } { }
       }
@@ -168,12 +206,7 @@
     \int_compare:nNnT \l__regex_current_catcode_int = 0
       {
         \group_begin:
-          \tl_set:Nx \l__regex_cs_name_tl
-            {
-              \exp_after:wN \exp_after:wN
-              \exp_after:wN \cs_to_str:N
-              \tex_the:D \tex_toks:D \l__regex_current_pos_int
-            }
+          \tl_set:Nx \l__regex_cs_name_tl { \__regex_current_cs_to_str: }
           \__regex_single_match:
           \__regex_disable_submatches:
           \__regex_build_for_cs:n {#1}
@@ -222,16 +255,16 @@
 \cs_new_protected:Npn \__regex_posix_ascii:
   {
     \__regex_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_int
+      \c__regex_ascii_min_int
+      \c__regex_ascii_max_int
   }
 \cs_new_eq:NN \__regex_posix_blank: \__regex_prop_h:
 \cs_new_protected:Npn \__regex_posix_cntrl:
   {
     \__regex_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_control_int
-    \__regex_item_caseful_equal:n \c__str_ascii_max_int
+      \c__regex_ascii_min_int
+      \c__regex_ascii_max_control_int
+    \__regex_item_caseful_equal:n \c__regex_ascii_max_int
   }
 \cs_new_eq:NN \__regex_posix_digit: \__regex_prop_d:
 \cs_new_protected:Npn \__regex_posix_graph:
@@ -268,8 +301,8 @@
       \cs_set:Npn \__regex_escape_unescaped:N ##1 { #1 }
       \cs_set:Npn \__regex_escape_escaped:N ##1 { #2 }
       \cs_set:Npn \__regex_escape_raw:N ##1 { #3 }
-      \int_set:Nn \tex_escapechar:D { `\\ }
-      \__str_gset_other:Nn \g__regex_internal_tl { #4 }
+      \__regex_standard_escapechar:
+      \tl_gset:Nx \g__regex_internal_tl { \__str_to_other_fast:n {#4} }
       \tl_set:Nx \l__regex_internal_b_tl
         {
           \exp_after:wN \__regex_escape_loop:N \g__regex_internal_tl
@@ -323,36 +356,19 @@
   }
 \cs_new:Npn \__regex_escape_x_end:w #1 ;
   {
-    \int_compare:nNnTF {#1} > \c__str_max_byte_int
-      { \__regex_escape_x_large:n {#1} }
+    \int_compare:nNnTF {#1} > \c_max_char_int
       {
+        \if_false: { \fi: }
+        \__tl_build_one:o \l__regex_internal_b_tl
+        \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
+        \tl_set:Nx \l__regex_internal_b_tl
+          { \if_false: } \fi:
+      }
+      {
         \exp_last_unbraced:Nf \__regex_escape_raw:N
-          { \__str_output_byte:n {#1} }
+          { \char_generate:nn {#1} { 12 } }
       }
   }
-\group_begin:
-  \char_set_catcode_other:n { 0 }
-  \cs_new:Npn \__regex_escape_x_large:n #1
-    {
-      \if_false: { \fi: }
-      \__tl_build_one:o \l__regex_internal_b_tl
-      \int_compare:nNnTF {#1} > \c_max_char_int
-        {
-          \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
-          \tl_set:Nx \l__regex_internal_b_tl
-            { \if_false: } \fi:
-        }
-        {
-          \char_set_lccode:nn { 0 } {#1}
-          \tex_lowercase:D
-            {
-              \tl_set:Nx \l__regex_internal_b_tl
-                { \if_false: } \fi:
-                \__regex_escape_raw:N ^^@
-            }
-        }
-    }
-\group_end:
 \cs_new:Npn \__regex_escape_x_test:N #1
   {
     \str_if_eq_x:nnTF {#1} { break } { ; }
@@ -370,7 +386,7 @@
     \if_charcode:w \c_left_brace_str #1
       \exp_after:wN \__regex_escape_x_loop:N
     \else:
-      \__str_hexadecimal_use:NTF #1
+      \__regex_hexadecimal_use:NTF #1
         { \exp_after:wN \__regex_escape_x:N }
         { ; \exp_after:wN \__regex_escape_loop:N \exp_after:wN #1 }
     \fi:
@@ -379,7 +395,7 @@
   {
     \str_if_eq_x:nnTF {#1} { break } { ; }
       {
-        \__str_hexadecimal_use:NTF #1
+        \__regex_hexadecimal_use:NTF #1
           { ; \__regex_escape_loop:N }
           { ; \__regex_escape_loop:N #1 }
       }
@@ -389,7 +405,7 @@
     \str_if_eq_x:nnTF {#1} { break }
       { ; \__regex_escape_x_loop_error:n { } {#1} }
       {
-        \__str_hexadecimal_use:NTF #1
+        \__regex_hexadecimal_use:NTF #1
           { \__regex_escape_x_loop:N }
           {
             \token_if_eq_charcode:NNTF \c_space_token #1
@@ -412,11 +428,32 @@
     \tl_set:Nx \l__regex_internal_b_tl
       { \if_false: } \fi: \__regex_escape_loop:N #1
   }
+\prg_new_conditional:Npnn \__regex_hexadecimal_use:N #1 { TF }
+  {
+    \if_int_compare:w 1 < "1 \token_to_str:N #1 \exp_stop_f:
+      #1 \prg_return_true:
+    \else:
+      \if_case:w \__int_eval:w
+          \exp_after:wN ` \token_to_str:N #1 - `a
+        \__int_eval_end:
+           A
+      \or: B
+      \or: C
+      \or: D
+      \or: E
+      \or: F
+      \else:
+        \prg_return_false:
+        \exp_after:wN \use_none:n
+      \fi:
+      \prg_return_true:
+    \fi:
+  }
 \prg_new_conditional:Npnn \__regex_char_if_special:N #1 { TF }
   {
     \if_int_compare:w `#1 > `Z \exp_stop_f:
       \if_int_compare:w `#1 > `z \exp_stop_f:
-        \if_int_compare:w `#1 < \c__str_ascii_max_int
+        \if_int_compare:w `#1 < \c__regex_ascii_max_int
           \prg_return_true: \else: \prg_return_false: \fi:
       \else:
         \if_int_compare:w `#1 < `a \exp_stop_f:
@@ -607,7 +644,7 @@
 \cs_new_protected:Npn \__regex_compile:n #1
   {
     \__regex_compile:w
-      \int_set:Nn \tex_escapechar:D { `\\ }
+      \__regex_standard_escapechar:
       \int_set_eq:NN \l__regex_mode_int \c__regex_outer_mode_int
       \__regex_escape_use:nnnn
         {
@@ -1201,7 +1238,7 @@
   {
     \if_int_odd:w \__int_eval:w \l__regex_catcodes_int / #1 \__int_eval_end:
     \else:
-      \tex_advance:D \l__regex_catcodes_int #1
+      \int_add:Nn \l__regex_catcodes_int {#1}
     \fi:
   }
 \cs_new_protected:Npn \__regex_compile_c_lbrack_end:
@@ -1329,8 +1366,8 @@
   }
 \cs_new_protected:Npn \__regex_compile_u_in_cs:
   {
-    \exp_args:NNo \__str_gset_other:Nn \g__regex_internal_tl
-      { \l__regex_internal_a_tl }
+    \tl_gset:Nx \g__regex_internal_tl
+      { \exp_args:No \__str_to_other_fast:n { \l__regex_internal_a_tl } }
     \__tl_build_one:x
       {
         \tl_map_function:NN \g__regex_internal_tl
@@ -1522,6 +1559,7 @@
       { control~sequence~ \seq_use:Nn \l__regex_internal_seq { ~or~ } }
   }
 \int_new:N  \l__regex_min_state_int
+\int_set:Nn \l__regex_min_state_int { 1 }
 \int_new:N  \l__regex_max_state_int
 \int_new:N  \l__regex_left_state_int
 \int_new:N  \l__regex_right_state_int
@@ -1536,7 +1574,7 @@
 \cs_new_protected:Npn \__regex_build:N #1
   {
     \trace_push:nnn { regex } { 1 } { __regex_build }
-    \int_set:Nn \tex_escapechar:D { `\\ }
+    \__regex_standard_escapechar:
     \int_zero:N \l__regex_capturing_group_int
     \int_set_eq:NN \l__regex_max_state_int \l__regex_min_state_int
     \__regex_build_new_state:
@@ -1581,20 +1619,6 @@
     \seq_pop:NN \l__regex_right_state_seq \l__regex_internal_a_tl
     \int_set:Nn \l__regex_right_state_int \l__regex_internal_a_tl
   }
-\cs_new_protected:Npn \__regex_toks_put_left:Nx #1#2
-  {
-    \cs_set:Npx \__regex_tmp:w { #2 }
-    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
-      { \exp_after:wN \__regex_tmp:w \tex_the:D \tex_toks:D #1 }
-  }
-\cs_new_protected:Npn \__regex_toks_put_right:Nx #1#2
-  {
-    \cs_set:Npx \__regex_tmp:w {#2}
-    \tex_toks:D #1 \exp_after:wN
-      { \tex_the:D \tex_toks:D \exp_after:wN #1 \__regex_tmp:w }
-  }
-\cs_new_protected:Npn \__regex_toks_put_right:Nn #1#2
-  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
 \cs_new_protected:Npn \__regex_build_transition_left:NNN #1#2#3
   { \__regex_toks_put_left:Nx  #2 { #1 { \int_eval:n { #3 - #2 } } } }
 \cs_new_protected:Npn \__regex_build_transition_right:nNn #1#2#3
@@ -1609,7 +1633,7 @@
         M=\int_use:N \l__regex_max_state_int ~ -> ~
         \int_eval:n { \l__regex_max_state_int + 1 }
       }
-    \tex_toks:D \l__regex_max_state_int { }
+    \__regex_toks_clear:N \l__regex_max_state_int
     \int_set_eq:NN \l__regex_left_state_int \l__regex_right_state_int
     \int_set_eq:NN \l__regex_right_state_int \l__regex_max_state_int
     \int_incr:N \l__regex_max_state_int
@@ -1776,15 +1800,12 @@
           ( #1 - 1 )
           * ( \l__regex_internal_b_int - \l__regex_internal_a_int )
         }
-      \tex_advance:D \l__regex_right_state_int \l__regex_internal_c_int
-      \tex_advance:D \l__regex_max_state_int   \l__regex_internal_c_int
-      \prg_replicate:nn \l__regex_internal_c_int
-        {
-          \tex_toks:D \l__regex_internal_b_int
-            = \tex_toks:D \l__regex_internal_a_int
-          \int_incr:N \l__regex_internal_a_int
-          \int_incr:N \l__regex_internal_b_int
-        }
+      \int_add:Nn \l__regex_right_state_int { \l__regex_internal_c_int }
+      \int_add:Nn \l__regex_max_state_int   { \l__regex_internal_c_int }
+      \__regex_toks_memcpy:NNn
+        \l__regex_internal_b_int
+        \l__regex_internal_a_int
+        \l__regex_internal_c_int
     \fi:
   }
 \cs_new_protected:Npn \__regex_group_repeat:nnN #1#2#3
@@ -1912,6 +1933,8 @@
 \int_new:N \l__regex_step_int
 \int_new:N \l__regex_min_active_int
 \int_new:N \l__regex_max_active_int
+\__intarray_new:Nn \g__regex_state_active_intarray { 65536 }
+\__intarray_new:Nn \g__regex_thread_state_intarray { 65536 }
 \tl_new:N \l__regex_every_match_tl
 \bool_new:N \l__regex_fresh_thread_bool
 \bool_new:N \l__regex_empty_success_bool
@@ -1935,12 +1958,13 @@
     \bool_gset_false:N \g__regex_success_bool
     \int_step_inline:nnnn
       \l__regex_min_state_int { 1 } { \l__regex_max_state_int - 1 }
-      { \tex_dimen:D ##1 ~ 1 sp \scan_stop: }
+      { \__intarray_gset_fast:Nnn \g__regex_state_active_intarray {##1} { 1 } }
     \int_set_eq:NN \l__regex_min_active_int \l__regex_max_state_int
     \int_zero:N \l__regex_step_int
     \int_set_eq:NN \l__regex_success_pos_int \l__regex_min_pos_int
-    \int_set:Nn \l__regex_submatch_int
+    \int_set:Nn \l__regex_min_submatch_int
       { 2 * \l__regex_max_state_int }
+    \int_set_eq:NN \l__regex_submatch_int \l__regex_min_submatch_int
     \bool_set_false:N \l__regex_empty_success_bool
     \__regex_match_once:
     \trace_pop:nnx { regex } { 1 } { __regex_match }
@@ -1982,7 +2006,7 @@
   }
 \cs_new_protected:Npn \__regex_match_loop:
   {
-    \tex_advance:D \l__regex_step_int 2 \exp_stop_f:
+    \int_add:Nn \l__regex_step_int { 2 }
     \int_incr:N \l__regex_current_pos_int
     \int_set_eq:NN \l__regex_last_char_int \l__regex_current_char_int
     \int_set_eq:NN \l__regex_case_changed_char_int \c_max_int
@@ -1990,8 +2014,11 @@
     \use:x
       {
         \int_set_eq:NN \l__regex_max_active_int \l__regex_min_active_int
-        \exp_after:wN \__regex_match_one_active:w
-          \int_use:N \l__regex_min_active_int ;
+        \int_step_function:nnnN
+          { \l__regex_min_active_int }
+          { 1 }
+          { \l__regex_max_active_int - 1 }
+          \__regex_match_one_active:n
       }
     \__prg_break_point:
     \bool_set_false:N \l__regex_fresh_thread_bool %^^A was arg of break_point:n
@@ -2001,25 +2028,21 @@
       \fi:
     \fi:
   }
-\cs_new:Npn \__regex_match_one_active:w #1;
+\cs_new:Npn \__regex_match_one_active:n #1
   {
-    \if_int_compare:w #1 < \l__regex_max_active_int
-      \__regex_use_state_and_submatches:nn
-        { \__int_value:w \tex_skip:D #1 }
-        { \tex_the:D \tex_toks:D #1 }
-      \exp_after:wN \__regex_match_one_active:w
-        \__int_value:w \__int_eval:w #1 + 1 \exp_after:wN ;
-    \fi:
+    \__regex_use_state_and_submatches:nn
+      { \__intarray_item_fast:Nn \g__regex_thread_state_intarray {#1} }
+      { \__regex_toks_use:w #1 }
   }
 \cs_new_protected:Npn \__regex_query_set:nnn #1#2#3
   {
-    \tex_muskip:D \l__regex_current_pos_int
-      = \etex_gluetomu:D
-        #3 sp
-        plus #2 sp
-        minus \l__regex_balance_int sp
-      \scan_stop:
-    \tex_toks:D \l__regex_current_pos_int {#1}
+    \__intarray_gset_fast:Nnn \g__regex_charcode_intarray
+      { \l__regex_current_pos_int } {#3}
+    \__intarray_gset_fast:Nnn \g__regex_catcode_intarray
+      { \l__regex_current_pos_int } {#2}
+    \__intarray_gset_fast:Nnn \g__regex_balance_intarray
+      { \l__regex_current_pos_int } { \l__regex_balance_int }
+    \__regex_toks_set:Nn \l__regex_current_pos_int {#1}
     \int_incr:N \l__regex_current_pos_int
     \if_case:w #2 \exp_stop_f:
     \or: \int_incr:N \l__regex_balance_int
@@ -2029,23 +2052,27 @@
 \cs_new_protected:Npn \__regex_query_get:
   {
     \l__regex_current_char_int
-      = \etex_mutoglue:D \tex_muskip:D \l__regex_current_pos_int
-    \l__regex_current_catcode_int = \etex_gluestretch:D
-      \etex_mutoglue:D \tex_muskip:D \l__regex_current_pos_int
+      = \__intarray_item_fast:Nn \g__regex_charcode_intarray
+          { \l__regex_current_pos_int } \scan_stop:
+    \l__regex_current_catcode_int
+      = \__intarray_item_fast:Nn \g__regex_catcode_intarray
+          { \l__regex_current_pos_int } \scan_stop:
   }
 \cs_new_protected:Npn \__regex_use_state:
   {
     \trace:nnx { regex } { 2 } { state~\int_use:N \l__regex_current_state_int }
-    \tex_dimen:D \l__regex_current_state_int
-      = \l__regex_step_int sp \scan_stop:
-    \tex_the:D \tex_toks:D \l__regex_current_state_int
-    \tex_dimen:D \l__regex_current_state_int
-      = \__int_eval:w \l__regex_step_int + 1 \__int_eval_end: sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g__regex_state_active_intarray
+      { \l__regex_current_state_int } { \l__regex_step_int }
+    \__regex_toks_use:w \l__regex_current_state_int
+    \__intarray_gset_fast:Nnn \g__regex_state_active_intarray
+      { \l__regex_current_state_int } { \l__regex_step_int + 1 }
   }
 \cs_new_protected:Npn \__regex_use_state_and_submatches:nn #1 #2
   {
     \int_set:Nn \l__regex_current_state_int {#1}
-    \if_int_compare:w \tex_dimen:D \l__regex_current_state_int
+    \if_int_compare:w
+        \__intarray_item_fast:Nn \g__regex_state_active_intarray
+          { \l__regex_current_state_int }
                       < \l__regex_step_int
       \tl_set:Nn \l__regex_current_submatches_prop {#2}
       \exp_after:wN \__regex_use_state:
@@ -2070,7 +2097,10 @@
         \int_add:Nn \l__regex_current_state_int {#2}
         \exp_not:n
           {
-            \if_int_compare:w \tex_dimen:D \l__regex_current_state_int #1
+            \if_int_compare:w
+                \__intarray_item_fast:Nn \g__regex_state_active_intarray
+                  { \l__regex_current_state_int }
+                #1
               \exp_after:wN \__regex_use_state:
             \fi:
           }
@@ -2088,12 +2118,13 @@
 \cs_new_protected:Npn \__regex_store_state:n #1
   {
     \__regex_store_submatches:
-    \tex_skip:D \l__regex_max_active_int = #1 sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g__regex_thread_state_intarray
+      { \l__regex_max_active_int } {#1}
     \int_incr:N \l__regex_max_active_int
   }
 \cs_new_protected:Npn \__regex_store_submatches:
   {
-    \tex_toks:D \l__regex_max_active_int \exp_after:wN
+    \__regex_toks_set:No \l__regex_max_active_int
       { \l__regex_current_submatches_prop }
   }
 \cs_new_protected:Npn \__regex_disable_submatches:
@@ -2120,6 +2151,8 @@
       }
   }
 \int_new:N \l__regex_replacement_csnames_int
+\tl_new:N \l__regex_replacement_category_tl
+\seq_new:N \l__regex_replacement_category_seq
 \tl_new:N \l__regex_balance_tl
 \cs_new:Npn \__regex_replacement_balance_one_match:n #1
   { - \__regex_submatch_balance:n {#1} }
@@ -2126,8 +2159,8 @@
 \cs_new:Npn \__regex_replacement_do_one_match:n #1
   {
     \__regex_query_range:nn
-      { \etex_glueshrink:D \tex_skip:D #1 }
-      { \tex_skip:D #1 }
+      { \__intarray_item_fast:Nn \g__regex_submatch_prev_intarray {#1} }
+      { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
   }
 \cs_new:Npn \__regex_replacement_exp_not:N #1 { \exp_not:n {#1} }
 \cs_new:Npn \__regex_query_range:nn #1#2
@@ -2143,7 +2176,7 @@
     \else:
       \exp_after:wN \__prg_break:
     \fi:
-    \tex_the:D \tex_toks:D #1 \exp_stop_f:
+    \__regex_toks_use:w #1 \exp_stop_f:
     \exp_after:wN \__regex_query_range_loop:ww
       \__int_value:w \__int_eval:w #1 + 1 ; #2 ;
   }
@@ -2150,15 +2183,28 @@
 \cs_new:Npn \__regex_query_submatch:n #1
   {
     \__regex_query_range:nn
-      { \tex_skip:D \__int_eval:w #1 }
-      { \etex_gluestretch:D \tex_skip:D \__int_eval:w #1 }
+      { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
+      { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} }
   }
 \cs_new_protected:Npn \__regex_submatch_balance:n #1
   {
-    \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D
-      \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1
-      - \tex_muskip:D \tex_skip:D #1
-    \scan_stop:
+    \__int_eval:w
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g__regex_balance_intarray
+            { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} }
+        }
+      -
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g__regex_balance_intarray
+            { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
+        }
+    \__int_eval_end:
   }
 \cs_new_protected:Npn \__regex_replacement:n #1
   {
@@ -2169,10 +2215,14 @@
       \__regex_escape_use:nnnn
         {
           \if_charcode:w \c_right_brace_str ##1
-            \__regex_replacement_rbrace:N \else: \__tl_build_one:n \fi: ##1
+            \__regex_replacement_rbrace:N
+          \else:
+            \__regex_replacement_normal:n
+          \fi:
+          ##1
         }
         { \__regex_replacement_escaped:N ##1 }
-        { \__tl_build_one:n ##1 }
+        { \__regex_replacement_normal:n ##1 }
         {#1}
       \prg_do_nothing: \prg_do_nothing:
       \if_int_compare:w \l__regex_replacement_csnames_int > 0 \exp_stop_f:
@@ -2181,6 +2231,12 @@
         \__tl_build_one:x
           { \prg_replicate:nn \l__regex_replacement_csnames_int \cs_end: }
       \fi:
+      \seq_if_empty:NF \l__regex_replacement_category_seq
+        {
+          \__msg_kernel_error:nnx { regex } { replacement-missing-rparen }
+            { \seq_count:N \l__regex_replacement_category_seq }
+          \seq_clear:N \l__regex_replacement_category_seq
+        }
       \cs_gset:Npx \__regex_replacement_balance_one_match:n ##1
         {
           + \int_use:N \l__regex_balance_int
@@ -2196,11 +2252,27 @@
     \cs_set:Npn \__regex_replacement_do_one_match:n ##1
       {
         \__regex_query_range:nn
-          { \etex_glueshrink:D \tex_skip:D ##1 }
-          { \tex_skip:D ##1 }
+          { \__intarray_item_fast:Nn \g__regex_submatch_prev_intarray {##1} }
+          { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {##1} }
         #1
       }
   }
+\cs_new_protected:Npn \__regex_replacement_normal:n #1
+  {
+    \tl_if_empty:NTF \l__regex_replacement_category_tl
+      { \__tl_build_one:n {#1} }
+      { % (
+        \token_if_eq_charcode:NNTF #1 )
+          {
+            \seq_pop:NN \l__regex_replacement_category_seq
+              \l__regex_replacement_category_tl
+          }
+          {
+            \use:c { __regex_replacement_c_ \l__regex_replacement_category_tl :w }
+              \__regex_replacement_normal:n {#1}
+          }
+      }
+  }
 \cs_new_protected:Npn \__regex_replacement_escaped:N #1
   {
     \cs_if_exist_use:cF { __regex_replacement_#1:w }
@@ -2208,7 +2280,8 @@
         \if_int_compare:w 1 < 1#1 \exp_stop_f:
           \__regex_replacement_put_submatch:n {#1}
         \else:
-          \__tl_build_one:o { \token_to_str:N #1 }
+          \exp_args:No \__regex_replacement_normal:n
+            { \token_to_str:N #1 }
         \fi:
       }
   }
@@ -2224,28 +2297,26 @@
   }
 \cs_new_protected:Npn \__regex_replacement_g:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \int_zero:N \l__regex_internal_a_int
-        \__regex_replacement_g_digits:NN
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \__regex_replacement_normal:n \c_left_brace_str }
+      { \l__regex_internal_a_int = \__regex_replacement_g_digits:NN }
       { \__regex_replacement_error:NNN g #1 #2 }
   }
-\cs_new_protected:Npn \__regex_replacement_g_digits:NN #1#2
+\cs_new:Npn \__regex_replacement_g_digits:NN #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \__regex_replacement_normal:n
       {
         \if_int_compare:w 1 < 1#2 \exp_stop_f:
-          \int_set:Nn \l__regex_internal_a_int
-            { 10 * \l__regex_internal_a_int + #2 }
+          #2
           \exp_after:wN \use_i:nnn
           \exp_after:wN \__regex_replacement_g_digits:NN
         \else:
+          \exp_stop_f:
           \exp_after:wN \__regex_replacement_error:NNN
           \exp_after:wN g
         \fi:
       }
       {
+        \exp_stop_f:
         \if_meaning:w \__regex_replacement_rbrace:N #1
           \exp_args:No \__regex_replacement_put_submatch:n
             { \int_use:N \l__regex_internal_a_int }
@@ -2259,34 +2330,31 @@
   }
 \cs_new_protected:Npn \__regex_replacement_c:w #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \__regex_replacement_normal:n
       {
-        \cs_if_exist_use:cF { __regex_replacement_c_#2:w }
-          { \__regex_replacement_error:NNN c #1#2 }
+        \exp_after:wN \token_if_eq_charcode:NNTF \c_left_brace_str #2
+          { \__regex_replacement_cu_aux:Nw \__regex_replacement_exp_not:N }
+          {
+            \cs_if_exist:cTF { __regex_replacement_c_#2:w }
+              { \__regex_replacement_cat:NNN #2 }
+              { \__regex_replacement_error:NNN c #1#2 }
+          }
       }
       { \__regex_replacement_error:NNN c #1#2 }
   }
-\cs_new_protected:cpn { __regex_replacement_c_ \c_left_brace_str :w }
+\cs_new_protected:Npn \__regex_replacement_cu_aux:Nw #1
   {
     \if_case:w \l__regex_replacement_csnames_int
-      \__tl_build_one:n
-        { \exp_not:n { \exp_after:wN \__regex_replacement_exp_not:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN #1 \cs:w } }
     \else:
-      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
     \fi:
     \int_incr:N \l__regex_replacement_csnames_int
   }
 \cs_new_protected:Npn \__regex_replacement_u:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \if_case:w \l__regex_replacement_csnames_int
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } }
-        \else:
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
-        \fi:
-        \int_incr:N \l__regex_replacement_csnames_int
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \__regex_replacement_normal:n \c_left_brace_str }
+      { \__regex_replacement_cu_aux:Nw \exp_not:V }
       { \__regex_replacement_error:NNN u #1#2 }
   }
 \cs_new_protected:Npn \__regex_replacement_rbrace:N #1
@@ -2295,18 +2363,36 @@
       \__tl_build_one:n \cs_end:
       \int_decr:N \l__regex_replacement_csnames_int
     \else:
-      \__tl_build_one:n #1
+      \__regex_replacement_normal:n {#1}
     \fi:
   }
+\cs_new_protected:Npn \__regex_replacement_cat:NNN #1#2#3
+  {
+    \token_if_eq_meaning:NNTF \prg_do_nothing: #3
+      { \__msg_kernel_error:nn { regex } { replacement-catcode-end } }
+      {
+        \int_compare:nNnTF { \l__regex_replacement_csnames_int } > 0
+          {
+            \__msg_kernel_error:nnnn
+              { regex } { replacement-catcode-in-cs } {#1} {#3}
+            #2 #3
+          }
+          {
+            \str_if_eq:nnTF { #2 #3 } { \__regex_replacement_normal:n ( } % )
+              {
+                \seq_push:NV \l__regex_replacement_category_seq
+                  \l__regex_replacement_category_tl
+                \tl_set:Nn \l__regex_replacement_category_tl {#1}
+              }
+              { \use:c { __regex_replacement_c_#1:w } #2 #3 }
+          }
+      }
+  }
 \group_begin:
   \cs_new_protected:Npn \__regex_replacement_char:nNN #1#2#3
     {
-      \if_meaning:w \prg_do_nothing: #3
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \tex_lccode:D 0 = `#3 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {#1} }
-      \fi:
+      \tex_lccode:D 0 = `#3 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {#1} }
     }
   \char_set_catcode_active:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_A:w
@@ -2351,15 +2437,11 @@
     }
   \cs_new_protected:Npn \__regex_replacement_c_S:w #1#2
     {
-      \if_meaning:w \prg_do_nothing: #2
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \if_int_compare:w `#2 = 0 \exp_stop_f:
-          \__msg_kernel_error:nn { regex } { replacement-null-space }
-        \fi:
-        \tex_lccode:D `\ = `#2 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {~} }
+      \if_int_compare:w `#2 = 0 \exp_stop_f:
+        \__msg_kernel_error:nn { regex } { replacement-null-space }
       \fi:
+      \tex_lccode:D `\ = `#2 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {~} }
     }
   \char_set_catcode_alignment:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_T:w
@@ -2433,8 +2515,12 @@
 \int_new:N \l__regex_match_count_int
 \flag_new:n { __regex_begin }
 \flag_new:n { __regex_end }
+\int_new:N \l__regex_min_submatch_int
 \int_new:N \l__regex_submatch_int
 \int_new:N \l__regex_zeroth_submatch_int
+\__intarray_new:Nn \g__regex_submatch_prev_intarray { 65536 }
+\__intarray_new:Nn \g__regex_submatch_begin_intarray { 65536 }
+\__intarray_new:Nn \g__regex_submatch_end_intarray { 65536 }
 \cs_new_protected:Npn \__regex_return:
   {
     \if_meaning:w \c_true_bool \g__regex_success_bool
@@ -2488,15 +2574,29 @@
         {
           \if_int_compare:w \l__regex_start_pos_int < \l__regex_success_pos_int
             \__regex_extract:
-            \tex_skip:D \l__regex_zeroth_submatch_int
-              = \l__regex_start_pos_int sp
-                plus \tex_skip:D \l__regex_zeroth_submatch_int \scan_stop:
+            \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+              { \l__regex_zeroth_submatch_int } { 0 }
+            \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+              { \l__regex_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray
+                  { \l__regex_zeroth_submatch_int }
+              }
+            \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+              { \l__regex_zeroth_submatch_int }
+              { \l__regex_start_pos_int }
           \fi:
         }
       #1
       \__regex_match:n {#2}
-      \tex_skip:D \l__regex_submatch_int
-        = \l__regex_start_pos_int sp plus \l__regex_max_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+        { \l__regex_submatch_int } { 0 }
+      \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+        { \l__regex_submatch_int }
+        { \l__regex_max_pos_int }
+      \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+        { \l__regex_submatch_int }
+        { \l__regex_start_pos_int }
       \int_incr:N \l__regex_submatch_int
       \if_meaning:w \c_true_bool \l__regex_empty_success_bool
         \if_int_compare:w \l__regex_start_pos_int = \l__regex_max_pos_int
@@ -2514,7 +2614,7 @@
         {
           \s__seq
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             { 1 }
             { \l__regex_submatch_int - 1 }
             \__regex_extract_seq_aux:n
@@ -2560,7 +2660,12 @@
       \int_set_eq:NN \l__regex_zeroth_submatch_int \l__regex_submatch_int
       \prg_replicate:nn \l__regex_capturing_group_int
         {
-          \tex_skip:D \l__regex_submatch_int 0 sp \scan_stop:
+          \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+            { \l__regex_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+            { \l__regex_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+            { \l__regex_submatch_int } { 0 }
           \int_incr:N \l__regex_submatch_int
         }
       \prop_map_inline:Nn \l__regex_success_submatches_prop
@@ -2572,21 +2677,14 @@
           \fi:
           \__int_eval:w \l__regex_zeroth_submatch_int + ##1 {##2}
         }
-      \tex_skip:D \l__regex_zeroth_submatch_int
-        = \tex_the:D \tex_skip:D \l__regex_zeroth_submatch_int
-          minus \l__regex_start_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+        { \l__regex_zeroth_submatch_int } { \l__regex_start_pos_int }
     \fi:
   }
 \cs_new_protected:Npn \__regex_extract_b:wn #1 < #2
-  {
-    \tex_skip:D #1 = #2 sp
-      plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray {#1} {#2} }
 \cs_new_protected:Npn \__regex_extract_e:wn #1 > #2
-  {
-    \tex_skip:D #1
-      = 1 \tex_skip:D #1 plus #2 sp \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray {#1} {#2} }
 \cs_new_protected:Npn \__regex_replace_once:nnN #1#2#3
   {
     \group_begin:
@@ -2607,7 +2705,10 @@
           {
             \__regex_replacement_do_one_match:n { \l__regex_zeroth_submatch_int }
             \__regex_query_range:nn
-              { \etex_gluestretch:D \tex_skip:D \l__regex_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g__regex_submatch_end_intarray
+                  { \l__regex_zeroth_submatch_int }
+              }
               { \l__regex_max_pos_int }
           }
         \__regex_group_end_replace:N #3
@@ -2624,7 +2725,7 @@
         {
           0
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             \l__regex_capturing_group_int
             { \l__regex_submatch_int - 1 }
             \__regex_replacement_balance_one_match:n
@@ -2632,7 +2733,7 @@
       \tl_set:Nx \l__regex_internal_a_tl
         {
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             \l__regex_capturing_group_int
             { \l__regex_submatch_int - 1 }
             \__regex_replacement_do_one_match:n
@@ -2668,38 +2769,38 @@
       }
   }
 \__msg_kernel_new:nnnn { regex } { trailing-backslash }
-  { Trailing~escape~character~`\iow_char:N\\'. }
+  { Trailing~escape~character~'\iow_char:N\\'. }
   {
     A~regular~expression~or~its~replacement~text~ends~with~
-    the~escape~character~`\iow_char:N\\'.~It~will~be~ignored.
+    the~escape~character~'\iow_char:N\\'.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { x-missing-rbrace }
-  { Missing~closing~brace~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Missing~closing~brace~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{...#1'.~
+    '\iow_char:N\\x\{...#1'.~
     The~closing~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { x-overflow }
-  { Character~code~`#1'~too~large~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Character~code~'#1'~too~large~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
+    '\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
     The~character~code~#1~is~larger~than~
     the~maximum~value~\int_use:N \c_max_char_int.
   }
 \__msg_kernel_new:nnnn { regex } { invalid-quantifier }
-  { Braced~quantifier~`#1'~may~not~be~followed~by~`#2'. }
+  { Braced~quantifier~'#1'~may~not~be~followed~by~'#2'. }
   {
-    The~character~`#2'~is~invalid~in~the~braced~quantifier~`#1'.~
-    The~only~valid~quantifiers~are~`*',~`?',~`+',~`{<int>}',~
-    `{<min>,}'~and~`{<min>,<max>}',~optionally~followed~by~`?'.
+    The~character~'#2'~is~invalid~in~the~braced~quantifier~'#1'.~
+    The~only~valid~quantifiers~are~'*',~'?',~'+',~'{<int>}',~
+    '{<min>,}'~and~'{<min>,<max>}',~optionally~followed~by~'?'.
   }
 \__msg_kernel_new:nnnn { regex } { missing-rbrack }
   { Missing~right~bracket~inserted~in~regular~expression. }
   {
     LaTeX~was~given~a~regular~expression~where~a~character~class~
-    was~started~with~`[',~but~the~matching~`]'~is~missing.
+    was~started~with~'[',~but~the~matching~']'~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { missing-rparen }
   {
@@ -2719,7 +2820,7 @@
   }
 \__msg_kernel_new:nnnn { regex } { bad-escape }
   {
-    Invalid~escape~`\iow_char:N\\#1'~
+    Invalid~escape~'\iow_char:N\\#1'~
     \__regex_if_in_cs:TF { within~a~control~sequence. }
       {
         \__regex_if_in_class:TF
@@ -2728,102 +2829,102 @@
       }
   }
   {
-    The~escape~sequence~`\iow_char:N\\#1'~may~not~appear~
+    The~escape~sequence~'\iow_char:N\\#1'~may~not~appear~
     \__regex_if_in_cs:TF
       {
         within~a~control~sequence~test~introduced~by~
-        `\iow_char:N\\c\iow_char:N\{'.
+        '\iow_char:N\\c\iow_char:N\{'.
       }
       {
         \__regex_if_in_class:TF
           { within~a~character~class~ }
-          { following~a~category~test~such~as~`\iow_char:N\\cL'~ }
+          { following~a~category~test~such~as~'\iow_char:N\\cL'~ }
         because~it~does~not~match~exactly~one~character.
       }
   }
 \__msg_kernel_new:nnnn { regex } { range-missing-end }
-  { Invalid~end-point~for~range~`#1-#2'~in~character~class. }
+  { Invalid~end-point~for~range~'#1-#2'~in~character~class. }
   {
-    The~end-point~`#2'~of~the~range~`#1-#2'~may~not~serve~as~an~
+    The~end-point~'#2'~of~the~range~'#1-#2'~may~not~serve~as~an~
     end-point~for~a~range:~alphanumeric~characters~should~not~be~
     escaped,~and~non-alphanumeric~characters~should~be~escaped.
   }
 \__msg_kernel_new:nnnn { regex } { range-backwards }
-  { Range~`[#1-#2]'~out~of~order~in~character~class. }
+  { Range~'[#1-#2]'~out~of~order~in~character~class. }
   {
-    In~ranges~of~characters~`[x-y]'~appearing~in~character~classes,~
+    In~ranges~of~characters~'[x-y]'~appearing~in~character~classes,~
     the~first~character~code~must~not~be~larger~than~the~second.~
-    Here,~`#1'~has~character~code~\int_eval:n {`#1},~while~
-    `#2'~has~character~code~\int_eval:n {`#2}.
+    Here,~'#1'~has~character~code~\int_eval:n {`#1},~while~
+    '#2'~has~character~code~\int_eval:n {`#2}.
   }
 \__msg_kernel_new:nnnn { regex } { c-bad-mode }
-  { Invalid~nested~`\iow_char:N\\c'~escape~in~regular~expression. }
+  { Invalid~nested~'\iow_char:N\\c'~escape~in~regular~expression. }
   {
-    The~`\iow_char:N\\c'~escape~cannot~be~used~within~
-    a~control~sequence~test~`\iow_char:N\\c{...}'.~
-    To~combine~several~category~tests,~use~`\iow_char:N\\c[...]'.
+    The~'\iow_char:N\\c'~escape~cannot~be~used~within~
+    a~control~sequence~test~'\iow_char:N\\c{...}'.~
+    To~combine~several~category~tests,~use~'\iow_char:N\\c[...]'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\c'~escape. }
   {
     LaTeX~was~given~a~regular~expression~where~a~
-    `\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
-    with~a~closing~brace~`\iow_char:N\}'.
+    '\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
+    with~a~closing~brace~'\iow_char:N\}'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrack }
-  { Missing~right~bracket~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~bracket~inserted~for~'\iow_char:N\\c'~escape. }
   {
-    A~construction~`\iow_char:N\\c[...'~appears~in~a~
-    regular~expression,~but~the~closing~`]'~is~not~present.
+    A~construction~'\iow_char:N\\c[...'~appears~in~a~
+    regular~expression,~but~the~closing~']'~is~not~present.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-category }
-  { Invalid~character~`#1'~following~`\iow_char:N\\c'~escape. }
+  { Invalid~character~'#1'~following~'\iow_char:N\\c'~escape. }
   {
-    In~regular~expressions,~the~`\iow_char:N\\c'~escape~sequence~
+    In~regular~expressions,~the~'\iow_char:N\\c'~escape~sequence~
     may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~
     capital~letter~representing~a~character~category,~namely~
-    one~of~`ABCDELMOPSTU'.
+    one~of~'ABCDELMOPSTU'.
   }
 \__msg_kernel_new:nnnn { regex } { c-trailing }
-  { Trailing~category~code~escape~`\iow_char:N\\c'... }
+  { Trailing~category~code~escape~'\iow_char:N\\c'... }
   {
-    A~regular~expression~ends~with~`\iow_char:N\\c'~followed~
+    A~regular~expression~ends~with~'\iow_char:N\\c'~followed~
     by~a~letter.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-lbrace }
-  { Missing~left~brace~following~`\iow_char:N\\u'~escape. }
+  { Missing~left~brace~following~'\iow_char:N\\u'~escape. }
   {
-    The~`\iow_char:N\\u'~escape~sequence~must~be~followed~by~
+    The~'\iow_char:N\\u'~escape~sequence~must~be~followed~by~
     a~brace~group~with~the~name~of~the~variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\u'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\u'~escape. }
   {
     LaTeX~
     \str_if_eq_x:nnTF { } {#2}
       { reached~the~end~of~the~string~ }
-      { encountered~an~escaped~alphanumeric~character `\iow_char:N\\#2'~ }
-    when~parsing~the~argument~of~an~`\iow_char:N\\u\iow_char:N\{...\}'~escape.
+      { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ }
+    when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape.
   }
 \__msg_kernel_new:nnnn { regex } { posix-unsupported }
-  { POSIX~collating~element~`[#1 ~ #1]'~not~supported. }
+  { POSIX~collating~element~'[#1 ~ #1]'~not~supported. }
   {
-    The~`[.foo.]'~and~`[=bar=]'~syntaxes~have~a~special~meaning~
+    The~'[.foo.]'~and~'[=bar=]'~syntaxes~have~a~special~meaning~
     in~POSIX~regular~expressions.~This~is~not~supported~by~LaTeX.~
     Maybe~you~forgot~to~escape~a~left~bracket~in~a~character~class?
   }
 \__msg_kernel_new:nnnn { regex } { posix-unknown }
-  { POSIX~class~`[:#1:]'~unknown. }
+  { POSIX~class~'[:#1:]'~unknown. }
   {
-    `[:#1:]'~is~not~among~the~known~POSIX~classes~
-    `[:alnum:]',~`[:alpha:]',~`[:ascii:]',~`[:blank:]',~
-    `[:cntrl:]',~`[:digit:]',~`[:graph:]',~`[:lower:]',~
-    `[:print:]',~`[:punct:]',~`[:space:]',~`[:upper:]',~
-    `[:word:]',~and~`[:xdigit:]'.
+    '[:#1:]'~is~not~among~the~known~POSIX~classes~
+    '[:alnum:]',~'[:alpha:]',~'[:ascii:]',~'[:blank:]',~
+    '[:cntrl:]',~'[:digit:]',~'[:graph:]',~'[:lower:]',~
+    '[:print:]',~'[:punct:]',~'[:space:]',~'[:upper:]',~
+    '[:word:]',~and~'[:xdigit:]'.
   }
 \__msg_kernel_new:nnnn { regex } { posix-missing-close }
-  { Missing~closing~`:]'~for~POSIX~class. }
-  { The~POSIX~syntax~`#1'~must~be~followed~by~`:]',~not~`#2'. }
+  { Missing~closing~':]'~for~POSIX~class. }
+  { The~POSIX~syntax~'#1'~must~be~followed~by~':]',~not~'#2'. }
 \__msg_kernel_new:nnnn { regex } { result-unbalanced }
   { Missing~brace~inserted~when~#1. }
   {
@@ -2833,58 +2934,68 @@
     #2~left,~#3~right.
   }
 \__msg_kernel_new:nnnn { regex } { unknown-option }
-  { Unknown~option~`#1'~for~regular~expressions. }
+  { Unknown~option~'#1'~for~regular~expressions. }
   {
-    The~only~available~option~is~`case-insensitive',~toggled~by~
-    `(?i)'~and~`(?-i)'.
+    The~only~available~option~is~'case-insensitive',~toggled~by~
+    '(?i)'~and~'(?-i)'.
   }
 \__msg_kernel_new:nnnn { regex } { special-group-unknown }
-  { Unknown~special~group~`#1~...'~in~a~regular~expression. }
+  { Unknown~special~group~'#1~...'~in~a~regular~expression. }
   {
-    The~only~valid~constructions~starting~with~`(?'~are~
-    `(?:~...~)',~`(?|~...~)',~`(?i)',~and~`(?-i)'.
+    The~only~valid~constructions~starting~with~'(?'~are~
+    '(?:~...~)',~'(?|~...~)',~'(?i)',~and~'(?-i)'.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-c }
-  { Misused~`\iow_char:N\\c'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\c'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~
-    or~a~brace~group,~not~by~`#1'.
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~
+    or~a~brace~group,~not~by~'#1'.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-u }
-  { Misused~`\iow_char:N\\u'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\u'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\u'~escape~sequence~
+    In~a~replacement~text,~the~'\iow_char:N\\u'~escape~sequence~
     must~be~~followed~by~a~brace~group~holding~the~name~of~the~
     variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-g }
   {
-    Missing~brace~for~the~`\iow_char:N\\g'~construction~
+    Missing~brace~for~the~'\iow_char:N\\g'~construction~
     in~a~replacement~text.
   }
   {
     In~the~replacement~text~for~a~regular~expression~search,~
-    submatches~are~represented~either~as~`\iow_char:N \\g{dd..d}',~
-    or~`\\d',~where~`d'~are~single~digits.~Here,~a~brace~is~missing.
+    submatches~are~represented~either~as~'\iow_char:N \\g{dd..d}',~
+    or~'\\d',~where~'d'~are~single~digits.~Here,~a~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-catcode-end }
   {
-    Missing~character~for~the~`\iow_char:N\\c<category><character>'~
+    Missing~character~for~the~'\iow_char:N\\c<category><character>'~
     construction~in~a~replacement~text.
   }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~representing~
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~representing~
     the~character~category.~Then,~a~character~must~follow.~LaTeX~
     reached~the~end~of~the~replacement~when~looking~for~that.
   }
+\__msg_kernel_new:nnnn { regex } { replacement-catcode-in-cs }
+  {
+    Category~code~'\iow_char:N\\c#1#3'~ignored~inside~
+    '\iow_char:N\\c\{...\}'~in~a~replacement~text.
+  }
+  {
+    In~a~replacement~text,~the~category~codes~of~the~argument~of~
+    '\iow_char:N\\c\{...\}'~are~ignored~when~building~the~control~
+    sequence~name.
+  }
 \__msg_kernel_new:nnnn { regex } { replacement-null-space }
   { TeX~cannot~build~a~space~token~with~character~code~0. }
   {
     You~asked~for~a~character~token~with~category~space,~
     and~character~code~0,~for~instance~through~
-    `\iow_char:N\\cS\iow_char:N\\x00'.~
+    '\iow_char:N\\cS\iow_char:N\\x00'.~
     This~specific~case~is~impossible~and~will~be~replaced~
     by~a~normal~space.
   }
@@ -2894,6 +3005,12 @@
     There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
     missing~right~\int_compare:nTF { #1 = 1 } { brace } { braces } .
   }
+\__msg_kernel_new:nnnn { regex } { replacement-missing-rparen }
+  { Missing~right~parenthesis~inserted~in~replacement~text. }
+  {
+    There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
+    missing~right~\int_compare:nTF { #1 = 1 } { parenthesis } { parentheses } .
+  }
 \cs_new:Npn \__regex_msg_repeated:nnN #1#2#3
   {
     \str_if_eq_x:nnF { #1 #2 } { 1 0 }
@@ -2918,7 +3035,7 @@
       { \l__regex_max_state_int - 1 }
       {
         \trace:nnx { regex } { #1 }
-          { \iow_char:N \\toks ##1 = { \tex_the:D \tex_toks:D ##1 } }
+          { \iow_char:N \\toks ##1 = { \__regex_toks_use:w ##1 } }
       }
   }
 %% 

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3regex.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -19,8 +19,8 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: l3regex.dtx Copyright (C) 2011-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{l3regex}{Support package l3kernel too old}
@@ -32,10 +32,46 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{l3regex}{2017/04/01}{}
+\ProvidesExplPackage{l3regex}{2017/05/13}{}
   {L3 Experimental regular expressions}
-\RequirePackage{l3tl-build, l3tl-analysis, l3str-convert}
+\RequirePackage{l3tl-build, l3tl-analysis, l3intarray}
 \cs_generate_variant:Nn \tl_to_str:n { V }
+\cs_new_protected:Npn \__regex_standard_escapechar:
+  { \int_set:Nn \tex_escapechar:D { `\\ } }
+\cs_new:Npn \__regex_toks_use:w { \tex_the:D \tex_toks:D }
+\cs_new_protected:Npn \__regex_toks_clear:N #1
+  { \tex_toks:D #1 { } }
+\cs_new_eq:NN \__regex_toks_set:Nn \tex_toks:D
+\cs_new_protected:Npn \__regex_toks_set:No #1
+  { \__regex_toks_set:Nn #1 \exp_after:wN }
+\cs_new_protected:Npn \__regex_toks_memcpy:NNn #1#2#3
+  {
+    \prg_replicate:nn {#3}
+      {
+        \tex_toks:D #1 = \tex_toks:D #2
+        \int_incr:N #1
+        \int_incr:N #2
+      }
+  }
+\cs_new_protected:Npn \__regex_toks_put_left:Nx #1#2
+  {
+    \cs_set:Npx \__regex_tmp:w { #2 }
+    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+      { \exp_after:wN \__regex_tmp:w \tex_the:D \tex_toks:D #1 }
+  }
+\cs_new_protected:Npn \__regex_toks_put_right:Nx #1#2
+  {
+    \cs_set:Npx \__regex_tmp:w {#2}
+    \tex_toks:D #1 \exp_after:wN
+      { \tex_the:D \tex_toks:D \exp_after:wN #1 \__regex_tmp:w }
+  }
+\cs_new_protected:Npn \__regex_toks_put_right:Nn #1#2
+  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
+\cs_new:Npn \__regex_current_cs_to_str:
+  {
+    \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
+    \tex_the:D \tex_toks:D \l__regex_current_pos_int
+  }
 \cs_new:Npn \__regex_tmp:w { }
 \tl_new:N   \l__regex_internal_a_tl
 \tl_new:N   \l__regex_internal_b_tl
@@ -50,8 +86,15 @@
     \__regex_branch:n
       { \__regex_class:NnnnN \c_true_bool { } { 1 } { 0 } \c_true_bool }
   }
+\__intarray_new:Nn \g__regex_charcode_intarray { 65536 }
+\__intarray_new:Nn \g__regex_catcode_intarray { 65536 }
+\__intarray_new:Nn \g__regex_balance_intarray { 65536 }
 \int_new:N \l__regex_balance_int
 \tl_new:N \l__regex_cs_name_tl
+\int_const:Nn \c__regex_ascii_min_int { 0 }
+\int_const:Nn \c__regex_ascii_max_control_int { 31 }
+\int_const:Nn \c__regex_ascii_max_int { 127 }
+\int_const:Nn \c__regex_ascii_lower_int { `a - `A }
 \cs_new_protected:Npn \__regex_break_true:w
    #1 \__regex_break_point:TF #2 #3 {#2}
 \cs_new_protected:Npn \__regex_break_point:TF #1 #2 { #2 }
@@ -108,12 +151,12 @@
     \if_int_compare:w \l__regex_current_char_int > `Z \exp_stop_f:
       \if_int_compare:w \l__regex_current_char_int > `z \exp_stop_f: \else:
         \if_int_compare:w \l__regex_current_char_int < `a \exp_stop_f: \else:
-          \int_sub:Nn \l__regex_case_changed_char_int { \c__str_ascii_lower_int }
+          \int_sub:Nn \l__regex_case_changed_char_int { \c__regex_ascii_lower_int }
         \fi:
       \fi:
     \else:
       \if_int_compare:w \l__regex_current_char_int < `A \exp_stop_f: \else:
-        \int_add:Nn \l__regex_case_changed_char_int { \c__str_ascii_lower_int }
+        \int_add:Nn \l__regex_case_changed_char_int { \c__regex_ascii_lower_int }
       \fi:
     \fi:
   }
@@ -152,12 +195,7 @@
     \int_compare:nNnTF \l__regex_current_catcode_int = 0
       {
         \tl_set:Nx \l__regex_internal_a_tl
-          {
-            \scan_stop:
-            \exp_after:wN \exp_after:wN \exp_after:wN \cs_to_str:N
-            \tex_the:D \tex_toks:D \l__regex_current_pos_int
-            \scan_stop:
-          }
+          { \scan_stop: \__regex_current_cs_to_str: \scan_stop: }
         \tl_if_in:noTF { \scan_stop: #1 \scan_stop: } \l__regex_internal_a_tl
           { \__regex_break_true:w } { }
       }
@@ -168,12 +206,7 @@
     \int_compare:nNnT \l__regex_current_catcode_int = 0
       {
         \group_begin:
-          \tl_set:Nx \l__regex_cs_name_tl
-            {
-              \exp_after:wN \exp_after:wN
-              \exp_after:wN \cs_to_str:N
-              \tex_the:D \tex_toks:D \l__regex_current_pos_int
-            }
+          \tl_set:Nx \l__regex_cs_name_tl { \__regex_current_cs_to_str: }
           \__regex_single_match:
           \__regex_disable_submatches:
           \__regex_build_for_cs:n {#1}
@@ -222,16 +255,16 @@
 \cs_new_protected:Npn \__regex_posix_ascii:
   {
     \__regex_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_int
+      \c__regex_ascii_min_int
+      \c__regex_ascii_max_int
   }
 \cs_new_eq:NN \__regex_posix_blank: \__regex_prop_h:
 \cs_new_protected:Npn \__regex_posix_cntrl:
   {
     \__regex_item_caseful_range:nn
-      \c__str_ascii_min_int
-      \c__str_ascii_max_control_int
-    \__regex_item_caseful_equal:n \c__str_ascii_max_int
+      \c__regex_ascii_min_int
+      \c__regex_ascii_max_control_int
+    \__regex_item_caseful_equal:n \c__regex_ascii_max_int
   }
 \cs_new_eq:NN \__regex_posix_digit: \__regex_prop_d:
 \cs_new_protected:Npn \__regex_posix_graph:
@@ -267,8 +300,8 @@
       \cs_set:Npn \__regex_escape_unescaped:N ##1 { #1 }
       \cs_set:Npn \__regex_escape_escaped:N ##1 { #2 }
       \cs_set:Npn \__regex_escape_raw:N ##1 { #3 }
-      \int_set:Nn \tex_escapechar:D { `\\ }
-      \__str_gset_other:Nn \g__regex_internal_tl { #4 }
+      \__regex_standard_escapechar:
+      \tl_gset:Nx \g__regex_internal_tl { \__str_to_other_fast:n {#4} }
       \tl_set:Nx \l__regex_internal_b_tl
         {
           \exp_after:wN \__regex_escape_loop:N \g__regex_internal_tl
@@ -321,36 +354,19 @@
   }
 \cs_new:Npn \__regex_escape_x_end:w #1 ;
   {
-    \int_compare:nNnTF {#1} > \c__str_max_byte_int
-      { \__regex_escape_x_large:n {#1} }
+    \int_compare:nNnTF {#1} > \c_max_char_int
       {
+        \if_false: { \fi: }
+        \__tl_build_one:o \l__regex_internal_b_tl
+        \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
+        \tl_set:Nx \l__regex_internal_b_tl
+          { \if_false: } \fi:
+      }
+      {
         \exp_last_unbraced:Nf \__regex_escape_raw:N
-          { \__str_output_byte:n {#1} }
+          { \char_generate:nn {#1} { 12 } }
       }
   }
-\group_begin:
-  \char_set_catcode_other:n { 0 }
-  \cs_new:Npn \__regex_escape_x_large:n #1
-    {
-      \if_false: { \fi: }
-      \__tl_build_one:o \l__regex_internal_b_tl
-      \int_compare:nNnTF {#1} > \c_max_char_int
-        {
-          \__msg_kernel_error:nnx { regex } { x-overflow } {#1}
-          \tl_set:Nx \l__regex_internal_b_tl
-            { \if_false: } \fi:
-        }
-        {
-          \char_set_lccode:nn { 0 } {#1}
-          \tex_lowercase:D
-            {
-              \tl_set:Nx \l__regex_internal_b_tl
-                { \if_false: } \fi:
-                \__regex_escape_raw:N ^^@
-            }
-        }
-    }
-\group_end:
 \cs_new:Npn \__regex_escape_x_test:N #1
   {
     \str_if_eq_x:nnTF {#1} { break } { ; }
@@ -368,7 +384,7 @@
     \if_charcode:w \c_left_brace_str #1
       \exp_after:wN \__regex_escape_x_loop:N
     \else:
-      \__str_hexadecimal_use:NTF #1
+      \__regex_hexadecimal_use:NTF #1
         { \exp_after:wN \__regex_escape_x:N }
         { ; \exp_after:wN \__regex_escape_loop:N \exp_after:wN #1 }
     \fi:
@@ -377,7 +393,7 @@
   {
     \str_if_eq_x:nnTF {#1} { break } { ; }
       {
-        \__str_hexadecimal_use:NTF #1
+        \__regex_hexadecimal_use:NTF #1
           { ; \__regex_escape_loop:N }
           { ; \__regex_escape_loop:N #1 }
       }
@@ -387,7 +403,7 @@
     \str_if_eq_x:nnTF {#1} { break }
       { ; \__regex_escape_x_loop_error:n { } {#1} }
       {
-        \__str_hexadecimal_use:NTF #1
+        \__regex_hexadecimal_use:NTF #1
           { \__regex_escape_x_loop:N }
           {
             \token_if_eq_charcode:NNTF \c_space_token #1
@@ -410,11 +426,32 @@
     \tl_set:Nx \l__regex_internal_b_tl
       { \if_false: } \fi: \__regex_escape_loop:N #1
   }
+\prg_new_conditional:Npnn \__regex_hexadecimal_use:N #1 { TF }
+  {
+    \if_int_compare:w 1 < "1 \token_to_str:N #1 \exp_stop_f:
+      #1 \prg_return_true:
+    \else:
+      \if_case:w \__int_eval:w
+          \exp_after:wN ` \token_to_str:N #1 - `a
+        \__int_eval_end:
+           A
+      \or: B
+      \or: C
+      \or: D
+      \or: E
+      \or: F
+      \else:
+        \prg_return_false:
+        \exp_after:wN \use_none:n
+      \fi:
+      \prg_return_true:
+    \fi:
+  }
 \prg_new_conditional:Npnn \__regex_char_if_special:N #1 { TF }
   {
     \if_int_compare:w `#1 > `Z \exp_stop_f:
       \if_int_compare:w `#1 > `z \exp_stop_f:
-        \if_int_compare:w `#1 < \c__str_ascii_max_int
+        \if_int_compare:w `#1 < \c__regex_ascii_max_int
           \prg_return_true: \else: \prg_return_false: \fi:
       \else:
         \if_int_compare:w `#1 < `a \exp_stop_f:
@@ -605,7 +642,7 @@
 \cs_new_protected:Npn \__regex_compile:n #1
   {
     \__regex_compile:w
-      \int_set:Nn \tex_escapechar:D { `\\ }
+      \__regex_standard_escapechar:
       \int_set_eq:NN \l__regex_mode_int \c__regex_outer_mode_int
       \__regex_escape_use:nnnn
         {
@@ -1199,7 +1236,7 @@
   {
     \if_int_odd:w \__int_eval:w \l__regex_catcodes_int / #1 \__int_eval_end:
     \else:
-      \tex_advance:D \l__regex_catcodes_int #1
+      \int_add:Nn \l__regex_catcodes_int {#1}
     \fi:
   }
 \cs_new_protected:Npn \__regex_compile_c_lbrack_end:
@@ -1327,8 +1364,8 @@
   }
 \cs_new_protected:Npn \__regex_compile_u_in_cs:
   {
-    \exp_args:NNo \__str_gset_other:Nn \g__regex_internal_tl
-      { \l__regex_internal_a_tl }
+    \tl_gset:Nx \g__regex_internal_tl
+      { \exp_args:No \__str_to_other_fast:n { \l__regex_internal_a_tl } }
     \__tl_build_one:x
       {
         \tl_map_function:NN \g__regex_internal_tl
@@ -1520,6 +1557,7 @@
       { control~sequence~ \seq_use:Nn \l__regex_internal_seq { ~or~ } }
   }
 \int_new:N  \l__regex_min_state_int
+\int_set:Nn \l__regex_min_state_int { 1 }
 \int_new:N  \l__regex_max_state_int
 \int_new:N  \l__regex_left_state_int
 \int_new:N  \l__regex_right_state_int
@@ -1533,7 +1571,7 @@
   }
 \cs_new_protected:Npn \__regex_build:N #1
   {
-    \int_set:Nn \tex_escapechar:D { `\\ }
+    \__regex_standard_escapechar:
     \int_zero:N \l__regex_capturing_group_int
     \int_set_eq:NN \l__regex_max_state_int \l__regex_min_state_int
     \__regex_build_new_state:
@@ -1573,20 +1611,6 @@
     \seq_pop:NN \l__regex_right_state_seq \l__regex_internal_a_tl
     \int_set:Nn \l__regex_right_state_int \l__regex_internal_a_tl
   }
-\cs_new_protected:Npn \__regex_toks_put_left:Nx #1#2
-  {
-    \cs_set:Npx \__regex_tmp:w { #2 }
-    \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
-      { \exp_after:wN \__regex_tmp:w \tex_the:D \tex_toks:D #1 }
-  }
-\cs_new_protected:Npn \__regex_toks_put_right:Nx #1#2
-  {
-    \cs_set:Npx \__regex_tmp:w {#2}
-    \tex_toks:D #1 \exp_after:wN
-      { \tex_the:D \tex_toks:D \exp_after:wN #1 \__regex_tmp:w }
-  }
-\cs_new_protected:Npn \__regex_toks_put_right:Nn #1#2
-  { \tex_toks:D #1 \exp_after:wN { \tex_the:D \tex_toks:D #1 #2 } }
 \cs_new_protected:Npn \__regex_build_transition_left:NNN #1#2#3
   { \__regex_toks_put_left:Nx  #2 { #1 { \int_eval:n { #3 - #2 } } } }
 \cs_new_protected:Npn \__regex_build_transition_right:nNn #1#2#3
@@ -1593,7 +1617,7 @@
   { \__regex_toks_put_right:Nx #2 { #1 { \int_eval:n { #3 - #2 } } } }
 \cs_new_protected:Npn \__regex_build_new_state:
   {
-    \tex_toks:D \l__regex_max_state_int { }
+    \__regex_toks_clear:N \l__regex_max_state_int
     \int_set_eq:NN \l__regex_left_state_int \l__regex_right_state_int
     \int_set_eq:NN \l__regex_right_state_int \l__regex_max_state_int
     \int_incr:N \l__regex_max_state_int
@@ -1756,15 +1780,12 @@
           ( #1 - 1 )
           * ( \l__regex_internal_b_int - \l__regex_internal_a_int )
         }
-      \tex_advance:D \l__regex_right_state_int \l__regex_internal_c_int
-      \tex_advance:D \l__regex_max_state_int   \l__regex_internal_c_int
-      \prg_replicate:nn \l__regex_internal_c_int
-        {
-          \tex_toks:D \l__regex_internal_b_int
-            = \tex_toks:D \l__regex_internal_a_int
-          \int_incr:N \l__regex_internal_a_int
-          \int_incr:N \l__regex_internal_b_int
-        }
+      \int_add:Nn \l__regex_right_state_int { \l__regex_internal_c_int }
+      \int_add:Nn \l__regex_max_state_int   { \l__regex_internal_c_int }
+      \__regex_toks_memcpy:NNn
+        \l__regex_internal_b_int
+        \l__regex_internal_a_int
+        \l__regex_internal_c_int
     \fi:
   }
 \cs_new_protected:Npn \__regex_group_repeat:nnN #1#2#3
@@ -1892,6 +1913,8 @@
 \int_new:N \l__regex_step_int
 \int_new:N \l__regex_min_active_int
 \int_new:N \l__regex_max_active_int
+\__intarray_new:Nn \g__regex_state_active_intarray { 65536 }
+\__intarray_new:Nn \g__regex_thread_state_intarray { 65536 }
 \tl_new:N \l__regex_every_match_tl
 \bool_new:N \l__regex_fresh_thread_bool
 \bool_new:N \l__regex_empty_success_bool
@@ -1912,12 +1935,13 @@
     \bool_gset_false:N \g__regex_success_bool
     \int_step_inline:nnnn
       \l__regex_min_state_int { 1 } { \l__regex_max_state_int - 1 }
-      { \tex_dimen:D ##1 ~ 1 sp \scan_stop: }
+      { \__intarray_gset_fast:Nnn \g__regex_state_active_intarray {##1} { 1 } }
     \int_set_eq:NN \l__regex_min_active_int \l__regex_max_state_int
     \int_zero:N \l__regex_step_int
     \int_set_eq:NN \l__regex_success_pos_int \l__regex_min_pos_int
-    \int_set:Nn \l__regex_submatch_int
+    \int_set:Nn \l__regex_min_submatch_int
       { 2 * \l__regex_max_state_int }
+    \int_set_eq:NN \l__regex_submatch_int \l__regex_min_submatch_int
     \bool_set_false:N \l__regex_empty_success_bool
     \__regex_match_once:
   }
@@ -1958,7 +1982,7 @@
   }
 \cs_new_protected:Npn \__regex_match_loop:
   {
-    \tex_advance:D \l__regex_step_int 2 \exp_stop_f:
+    \int_add:Nn \l__regex_step_int { 2 }
     \int_incr:N \l__regex_current_pos_int
     \int_set_eq:NN \l__regex_last_char_int \l__regex_current_char_int
     \int_set_eq:NN \l__regex_case_changed_char_int \c_max_int
@@ -1966,8 +1990,11 @@
     \use:x
       {
         \int_set_eq:NN \l__regex_max_active_int \l__regex_min_active_int
-        \exp_after:wN \__regex_match_one_active:w
-          \int_use:N \l__regex_min_active_int ;
+        \int_step_function:nnnN
+          { \l__regex_min_active_int }
+          { 1 }
+          { \l__regex_max_active_int - 1 }
+          \__regex_match_one_active:n
       }
     \__prg_break_point:
     \bool_set_false:N \l__regex_fresh_thread_bool %^^A was arg of break_point:n
@@ -1977,25 +2004,21 @@
       \fi:
     \fi:
   }
-\cs_new:Npn \__regex_match_one_active:w #1;
+\cs_new:Npn \__regex_match_one_active:n #1
   {
-    \if_int_compare:w #1 < \l__regex_max_active_int
-      \__regex_use_state_and_submatches:nn
-        { \__int_value:w \tex_skip:D #1 }
-        { \tex_the:D \tex_toks:D #1 }
-      \exp_after:wN \__regex_match_one_active:w
-        \__int_value:w \__int_eval:w #1 + 1 \exp_after:wN ;
-    \fi:
+    \__regex_use_state_and_submatches:nn
+      { \__intarray_item_fast:Nn \g__regex_thread_state_intarray {#1} }
+      { \__regex_toks_use:w #1 }
   }
 \cs_new_protected:Npn \__regex_query_set:nnn #1#2#3
   {
-    \tex_muskip:D \l__regex_current_pos_int
-      = \etex_gluetomu:D
-        #3 sp
-        plus #2 sp
-        minus \l__regex_balance_int sp
-      \scan_stop:
-    \tex_toks:D \l__regex_current_pos_int {#1}
+    \__intarray_gset_fast:Nnn \g__regex_charcode_intarray
+      { \l__regex_current_pos_int } {#3}
+    \__intarray_gset_fast:Nnn \g__regex_catcode_intarray
+      { \l__regex_current_pos_int } {#2}
+    \__intarray_gset_fast:Nnn \g__regex_balance_intarray
+      { \l__regex_current_pos_int } { \l__regex_balance_int }
+    \__regex_toks_set:Nn \l__regex_current_pos_int {#1}
     \int_incr:N \l__regex_current_pos_int
     \if_case:w #2 \exp_stop_f:
     \or: \int_incr:N \l__regex_balance_int
@@ -2005,22 +2028,26 @@
 \cs_new_protected:Npn \__regex_query_get:
   {
     \l__regex_current_char_int
-      = \etex_mutoglue:D \tex_muskip:D \l__regex_current_pos_int
-    \l__regex_current_catcode_int = \etex_gluestretch:D
-      \etex_mutoglue:D \tex_muskip:D \l__regex_current_pos_int
+      = \__intarray_item_fast:Nn \g__regex_charcode_intarray
+          { \l__regex_current_pos_int } \scan_stop:
+    \l__regex_current_catcode_int
+      = \__intarray_item_fast:Nn \g__regex_catcode_intarray
+          { \l__regex_current_pos_int } \scan_stop:
   }
 \cs_new_protected:Npn \__regex_use_state:
   {
-    \tex_dimen:D \l__regex_current_state_int
-      = \l__regex_step_int sp \scan_stop:
-    \tex_the:D \tex_toks:D \l__regex_current_state_int
-    \tex_dimen:D \l__regex_current_state_int
-      = \__int_eval:w \l__regex_step_int + 1 \__int_eval_end: sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g__regex_state_active_intarray
+      { \l__regex_current_state_int } { \l__regex_step_int }
+    \__regex_toks_use:w \l__regex_current_state_int
+    \__intarray_gset_fast:Nnn \g__regex_state_active_intarray
+      { \l__regex_current_state_int } { \l__regex_step_int + 1 }
   }
 \cs_new_protected:Npn \__regex_use_state_and_submatches:nn #1 #2
   {
     \int_set:Nn \l__regex_current_state_int {#1}
-    \if_int_compare:w \tex_dimen:D \l__regex_current_state_int
+    \if_int_compare:w
+        \__intarray_item_fast:Nn \g__regex_state_active_intarray
+          { \l__regex_current_state_int }
                       < \l__regex_step_int
       \tl_set:Nn \l__regex_current_submatches_prop {#2}
       \exp_after:wN \__regex_use_state:
@@ -2045,7 +2072,10 @@
         \int_add:Nn \l__regex_current_state_int {#2}
         \exp_not:n
           {
-            \if_int_compare:w \tex_dimen:D \l__regex_current_state_int #1
+            \if_int_compare:w
+                \__intarray_item_fast:Nn \g__regex_state_active_intarray
+                  { \l__regex_current_state_int }
+                #1
               \exp_after:wN \__regex_use_state:
             \fi:
           }
@@ -2063,12 +2093,13 @@
 \cs_new_protected:Npn \__regex_store_state:n #1
   {
     \__regex_store_submatches:
-    \tex_skip:D \l__regex_max_active_int = #1 sp \scan_stop:
+    \__intarray_gset_fast:Nnn \g__regex_thread_state_intarray
+      { \l__regex_max_active_int } {#1}
     \int_incr:N \l__regex_max_active_int
   }
 \cs_new_protected:Npn \__regex_store_submatches:
   {
-    \tex_toks:D \l__regex_max_active_int \exp_after:wN
+    \__regex_toks_set:No \l__regex_max_active_int
       { \l__regex_current_submatches_prop }
   }
 \cs_new_protected:Npn \__regex_disable_submatches:
@@ -2095,6 +2126,8 @@
       }
   }
 \int_new:N \l__regex_replacement_csnames_int
+\tl_new:N \l__regex_replacement_category_tl
+\seq_new:N \l__regex_replacement_category_seq
 \tl_new:N \l__regex_balance_tl
 \cs_new:Npn \__regex_replacement_balance_one_match:n #1
   { - \__regex_submatch_balance:n {#1} }
@@ -2101,8 +2134,8 @@
 \cs_new:Npn \__regex_replacement_do_one_match:n #1
   {
     \__regex_query_range:nn
-      { \etex_glueshrink:D \tex_skip:D #1 }
-      { \tex_skip:D #1 }
+      { \__intarray_item_fast:Nn \g__regex_submatch_prev_intarray {#1} }
+      { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
   }
 \cs_new:Npn \__regex_replacement_exp_not:N #1 { \exp_not:n {#1} }
 \cs_new:Npn \__regex_query_range:nn #1#2
@@ -2118,7 +2151,7 @@
     \else:
       \exp_after:wN \__prg_break:
     \fi:
-    \tex_the:D \tex_toks:D #1 \exp_stop_f:
+    \__regex_toks_use:w #1 \exp_stop_f:
     \exp_after:wN \__regex_query_range_loop:ww
       \__int_value:w \__int_eval:w #1 + 1 ; #2 ;
   }
@@ -2125,15 +2158,28 @@
 \cs_new:Npn \__regex_query_submatch:n #1
   {
     \__regex_query_range:nn
-      { \tex_skip:D \__int_eval:w #1 }
-      { \etex_gluestretch:D \tex_skip:D \__int_eval:w #1 }
+      { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
+      { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} }
   }
 \cs_new_protected:Npn \__regex_submatch_balance:n #1
   {
-    \etex_glueshrink:D \etex_mutoglue:D \etex_muexpr:D
-      \tex_muskip:D \etex_gluestretch:D \tex_skip:D #1
-      - \tex_muskip:D \tex_skip:D #1
-    \scan_stop:
+    \__int_eval:w
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g__regex_balance_intarray
+            { \__intarray_item_fast:Nn \g__regex_submatch_end_intarray {#1} }
+        }
+      -
+      \int_compare:nNnTF
+        { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} } = 0
+        { 0 }
+        {
+          \__intarray_item_fast:Nn \g__regex_balance_intarray
+            { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {#1} }
+        }
+    \__int_eval_end:
   }
 \cs_new_protected:Npn \__regex_replacement:n #1
   {
@@ -2143,10 +2189,14 @@
       \__regex_escape_use:nnnn
         {
           \if_charcode:w \c_right_brace_str ##1
-            \__regex_replacement_rbrace:N \else: \__tl_build_one:n \fi: ##1
+            \__regex_replacement_rbrace:N
+          \else:
+            \__regex_replacement_normal:n
+          \fi:
+          ##1
         }
         { \__regex_replacement_escaped:N ##1 }
-        { \__tl_build_one:n ##1 }
+        { \__regex_replacement_normal:n ##1 }
         {#1}
       \prg_do_nothing: \prg_do_nothing:
       \if_int_compare:w \l__regex_replacement_csnames_int > 0 \exp_stop_f:
@@ -2155,6 +2205,12 @@
         \__tl_build_one:x
           { \prg_replicate:nn \l__regex_replacement_csnames_int \cs_end: }
       \fi:
+      \seq_if_empty:NF \l__regex_replacement_category_seq
+        {
+          \__msg_kernel_error:nnx { regex } { replacement-missing-rparen }
+            { \seq_count:N \l__regex_replacement_category_seq }
+          \seq_clear:N \l__regex_replacement_category_seq
+        }
       \cs_gset:Npx \__regex_replacement_balance_one_match:n ##1
         {
           + \int_use:N \l__regex_balance_int
@@ -2169,11 +2225,27 @@
     \cs_set:Npn \__regex_replacement_do_one_match:n ##1
       {
         \__regex_query_range:nn
-          { \etex_glueshrink:D \tex_skip:D ##1 }
-          { \tex_skip:D ##1 }
+          { \__intarray_item_fast:Nn \g__regex_submatch_prev_intarray {##1} }
+          { \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray {##1} }
         #1
       }
   }
+\cs_new_protected:Npn \__regex_replacement_normal:n #1
+  {
+    \tl_if_empty:NTF \l__regex_replacement_category_tl
+      { \__tl_build_one:n {#1} }
+      { % (
+        \token_if_eq_charcode:NNTF #1 )
+          {
+            \seq_pop:NN \l__regex_replacement_category_seq
+              \l__regex_replacement_category_tl
+          }
+          {
+            \use:c { __regex_replacement_c_ \l__regex_replacement_category_tl :w }
+              \__regex_replacement_normal:n {#1}
+          }
+      }
+  }
 \cs_new_protected:Npn \__regex_replacement_escaped:N #1
   {
     \cs_if_exist_use:cF { __regex_replacement_#1:w }
@@ -2181,7 +2253,8 @@
         \if_int_compare:w 1 < 1#1 \exp_stop_f:
           \__regex_replacement_put_submatch:n {#1}
         \else:
-          \__tl_build_one:o { \token_to_str:N #1 }
+          \exp_args:No \__regex_replacement_normal:n
+            { \token_to_str:N #1 }
         \fi:
       }
   }
@@ -2197,28 +2270,26 @@
   }
 \cs_new_protected:Npn \__regex_replacement_g:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \int_zero:N \l__regex_internal_a_int
-        \__regex_replacement_g_digits:NN
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \__regex_replacement_normal:n \c_left_brace_str }
+      { \l__regex_internal_a_int = \__regex_replacement_g_digits:NN }
       { \__regex_replacement_error:NNN g #1 #2 }
   }
-\cs_new_protected:Npn \__regex_replacement_g_digits:NN #1#2
+\cs_new:Npn \__regex_replacement_g_digits:NN #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \__regex_replacement_normal:n
       {
         \if_int_compare:w 1 < 1#2 \exp_stop_f:
-          \int_set:Nn \l__regex_internal_a_int
-            { 10 * \l__regex_internal_a_int + #2 }
+          #2
           \exp_after:wN \use_i:nnn
           \exp_after:wN \__regex_replacement_g_digits:NN
         \else:
+          \exp_stop_f:
           \exp_after:wN \__regex_replacement_error:NNN
           \exp_after:wN g
         \fi:
       }
       {
+        \exp_stop_f:
         \if_meaning:w \__regex_replacement_rbrace:N #1
           \exp_args:No \__regex_replacement_put_submatch:n
             { \int_use:N \l__regex_internal_a_int }
@@ -2232,34 +2303,31 @@
   }
 \cs_new_protected:Npn \__regex_replacement_c:w #1#2
   {
-    \token_if_eq_meaning:NNTF #1 \__tl_build_one:n
+    \token_if_eq_meaning:NNTF #1 \__regex_replacement_normal:n
       {
-        \cs_if_exist_use:cF { __regex_replacement_c_#2:w }
-          { \__regex_replacement_error:NNN c #1#2 }
+        \exp_after:wN \token_if_eq_charcode:NNTF \c_left_brace_str #2
+          { \__regex_replacement_cu_aux:Nw \__regex_replacement_exp_not:N }
+          {
+            \cs_if_exist:cTF { __regex_replacement_c_#2:w }
+              { \__regex_replacement_cat:NNN #2 }
+              { \__regex_replacement_error:NNN c #1#2 }
+          }
       }
       { \__regex_replacement_error:NNN c #1#2 }
   }
-\cs_new_protected:cpn { __regex_replacement_c_ \c_left_brace_str :w }
+\cs_new_protected:Npn \__regex_replacement_cu_aux:Nw #1
   {
     \if_case:w \l__regex_replacement_csnames_int
-      \__tl_build_one:n
-        { \exp_not:n { \exp_after:wN \__regex_replacement_exp_not:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN #1 \cs:w } }
     \else:
-      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:N \cs:w } }
+      \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
     \fi:
     \int_incr:N \l__regex_replacement_csnames_int
   }
 \cs_new_protected:Npn \__regex_replacement_u:w #1#2
   {
-    \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
-      {
-        \if_case:w \l__regex_replacement_csnames_int
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } }
-        \else:
-          \__tl_build_one:n { \exp_not:n { \exp_after:wN \tl_to_str:V \cs:w } }
-        \fi:
-        \int_incr:N \l__regex_replacement_csnames_int
-      }
+    \str_if_eq_x:nnTF { #1#2 } { \__regex_replacement_normal:n \c_left_brace_str }
+      { \__regex_replacement_cu_aux:Nw \exp_not:V }
       { \__regex_replacement_error:NNN u #1#2 }
   }
 \cs_new_protected:Npn \__regex_replacement_rbrace:N #1
@@ -2268,18 +2336,36 @@
       \__tl_build_one:n \cs_end:
       \int_decr:N \l__regex_replacement_csnames_int
     \else:
-      \__tl_build_one:n #1
+      \__regex_replacement_normal:n {#1}
     \fi:
   }
+\cs_new_protected:Npn \__regex_replacement_cat:NNN #1#2#3
+  {
+    \token_if_eq_meaning:NNTF \prg_do_nothing: #3
+      { \__msg_kernel_error:nn { regex } { replacement-catcode-end } }
+      {
+        \int_compare:nNnTF { \l__regex_replacement_csnames_int } > 0
+          {
+            \__msg_kernel_error:nnnn
+              { regex } { replacement-catcode-in-cs } {#1} {#3}
+            #2 #3
+          }
+          {
+            \str_if_eq:nnTF { #2 #3 } { \__regex_replacement_normal:n ( } % )
+              {
+                \seq_push:NV \l__regex_replacement_category_seq
+                  \l__regex_replacement_category_tl
+                \tl_set:Nn \l__regex_replacement_category_tl {#1}
+              }
+              { \use:c { __regex_replacement_c_#1:w } #2 #3 }
+          }
+      }
+  }
 \group_begin:
   \cs_new_protected:Npn \__regex_replacement_char:nNN #1#2#3
     {
-      \if_meaning:w \prg_do_nothing: #3
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \tex_lccode:D 0 = `#3 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {#1} }
-      \fi:
+      \tex_lccode:D 0 = `#3 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {#1} }
     }
   \char_set_catcode_active:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_A:w
@@ -2324,15 +2410,11 @@
     }
   \cs_new_protected:Npn \__regex_replacement_c_S:w #1#2
     {
-      \if_meaning:w \prg_do_nothing: #2
-        \__msg_kernel_error:nn { regex } { replacement-catcode-end }
-      \else:
-        \if_int_compare:w `#2 = 0 \exp_stop_f:
-          \__msg_kernel_error:nn { regex } { replacement-null-space }
-        \fi:
-        \tex_lccode:D `\ = `#2 \scan_stop:
-        \tex_lowercase:D { \__tl_build_one:n {~} }
+      \if_int_compare:w `#2 = 0 \exp_stop_f:
+        \__msg_kernel_error:nn { regex } { replacement-null-space }
       \fi:
+      \tex_lccode:D `\ = `#2 \scan_stop:
+      \tex_lowercase:D { \__tl_build_one:n {~} }
     }
   \char_set_catcode_alignment:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_T:w
@@ -2406,8 +2488,12 @@
 \int_new:N \l__regex_match_count_int
 \flag_new:n { __regex_begin }
 \flag_new:n { __regex_end }
+\int_new:N \l__regex_min_submatch_int
 \int_new:N \l__regex_submatch_int
 \int_new:N \l__regex_zeroth_submatch_int
+\__intarray_new:Nn \g__regex_submatch_prev_intarray { 65536 }
+\__intarray_new:Nn \g__regex_submatch_begin_intarray { 65536 }
+\__intarray_new:Nn \g__regex_submatch_end_intarray { 65536 }
 \cs_new_protected:Npn \__regex_return:
   {
     \if_meaning:w \c_true_bool \g__regex_success_bool
@@ -2461,15 +2547,29 @@
         {
           \if_int_compare:w \l__regex_start_pos_int < \l__regex_success_pos_int
             \__regex_extract:
-            \tex_skip:D \l__regex_zeroth_submatch_int
-              = \l__regex_start_pos_int sp
-                plus \tex_skip:D \l__regex_zeroth_submatch_int \scan_stop:
+            \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+              { \l__regex_zeroth_submatch_int } { 0 }
+            \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+              { \l__regex_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g__regex_submatch_begin_intarray
+                  { \l__regex_zeroth_submatch_int }
+              }
+            \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+              { \l__regex_zeroth_submatch_int }
+              { \l__regex_start_pos_int }
           \fi:
         }
       #1
       \__regex_match:n {#2}
-      \tex_skip:D \l__regex_submatch_int
-        = \l__regex_start_pos_int sp plus \l__regex_max_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+        { \l__regex_submatch_int } { 0 }
+      \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+        { \l__regex_submatch_int }
+        { \l__regex_max_pos_int }
+      \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+        { \l__regex_submatch_int }
+        { \l__regex_start_pos_int }
       \int_incr:N \l__regex_submatch_int
       \if_meaning:w \c_true_bool \l__regex_empty_success_bool
         \if_int_compare:w \l__regex_start_pos_int = \l__regex_max_pos_int
@@ -2487,7 +2587,7 @@
         {
           \s__seq
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             { 1 }
             { \l__regex_submatch_int - 1 }
             \__regex_extract_seq_aux:n
@@ -2533,7 +2633,12 @@
       \int_set_eq:NN \l__regex_zeroth_submatch_int \l__regex_submatch_int
       \prg_replicate:nn \l__regex_capturing_group_int
         {
-          \tex_skip:D \l__regex_submatch_int 0 sp \scan_stop:
+          \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray
+            { \l__regex_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray
+            { \l__regex_submatch_int } { 0 }
+          \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+            { \l__regex_submatch_int } { 0 }
           \int_incr:N \l__regex_submatch_int
         }
       \prop_map_inline:Nn \l__regex_success_submatches_prop
@@ -2545,21 +2650,14 @@
           \fi:
           \__int_eval:w \l__regex_zeroth_submatch_int + ##1 {##2}
         }
-      \tex_skip:D \l__regex_zeroth_submatch_int
-        = \tex_the:D \tex_skip:D \l__regex_zeroth_submatch_int
-          minus \l__regex_start_pos_int sp \scan_stop:
+      \__intarray_gset_fast:Nnn \g__regex_submatch_prev_intarray
+        { \l__regex_zeroth_submatch_int } { \l__regex_start_pos_int }
     \fi:
   }
 \cs_new_protected:Npn \__regex_extract_b:wn #1 < #2
-  {
-    \tex_skip:D #1 = #2 sp
-      plus \etex_gluestretch:D \tex_skip:D #1 \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g__regex_submatch_begin_intarray {#1} {#2} }
 \cs_new_protected:Npn \__regex_extract_e:wn #1 > #2
-  {
-    \tex_skip:D #1
-      = 1 \tex_skip:D #1 plus #2 sp \scan_stop:
-  }
+  { \__intarray_gset_fast:Nnn \g__regex_submatch_end_intarray {#1} {#2} }
 \cs_new_protected:Npn \__regex_replace_once:nnN #1#2#3
   {
     \group_begin:
@@ -2580,7 +2678,10 @@
           {
             \__regex_replacement_do_one_match:n { \l__regex_zeroth_submatch_int }
             \__regex_query_range:nn
-              { \etex_gluestretch:D \tex_skip:D \l__regex_zeroth_submatch_int }
+              {
+                \__intarray_item_fast:Nn \g__regex_submatch_end_intarray
+                  { \l__regex_zeroth_submatch_int }
+              }
               { \l__regex_max_pos_int }
           }
         \__regex_group_end_replace:N #3
@@ -2597,7 +2698,7 @@
         {
           0
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             \l__regex_capturing_group_int
             { \l__regex_submatch_int - 1 }
             \__regex_replacement_balance_one_match:n
@@ -2605,7 +2706,7 @@
       \tl_set:Nx \l__regex_internal_a_tl
         {
           \int_step_function:nnnN
-            { 2 * \l__regex_max_state_int }
+            { \l__regex_min_submatch_int }
             \l__regex_capturing_group_int
             { \l__regex_submatch_int - 1 }
             \__regex_replacement_do_one_match:n
@@ -2641,38 +2742,38 @@
       }
   }
 \__msg_kernel_new:nnnn { regex } { trailing-backslash }
-  { Trailing~escape~character~`\iow_char:N\\'. }
+  { Trailing~escape~character~'\iow_char:N\\'. }
   {
     A~regular~expression~or~its~replacement~text~ends~with~
-    the~escape~character~`\iow_char:N\\'.~It~will~be~ignored.
+    the~escape~character~'\iow_char:N\\'.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { x-missing-rbrace }
-  { Missing~closing~brace~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Missing~closing~brace~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{...#1'.~
+    '\iow_char:N\\x\{...#1'.~
     The~closing~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { x-overflow }
-  { Character~code~`#1'~too~large~in~`\iow_char:N\\x'~hexadecimal~sequence. }
+  { Character~code~'#1'~too~large~in~'\iow_char:N\\x'~hexadecimal~sequence. }
   {
     You~wrote~something~like~
-    `\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
+    '\iow_char:N\\x\{\int_to_Hex:n{#1}\}'.~
     The~character~code~#1~is~larger~than~
     the~maximum~value~\int_use:N \c_max_char_int.
   }
 \__msg_kernel_new:nnnn { regex } { invalid-quantifier }
-  { Braced~quantifier~`#1'~may~not~be~followed~by~`#2'. }
+  { Braced~quantifier~'#1'~may~not~be~followed~by~'#2'. }
   {
-    The~character~`#2'~is~invalid~in~the~braced~quantifier~`#1'.~
-    The~only~valid~quantifiers~are~`*',~`?',~`+',~`{<int>}',~
-    `{<min>,}'~and~`{<min>,<max>}',~optionally~followed~by~`?'.
+    The~character~'#2'~is~invalid~in~the~braced~quantifier~'#1'.~
+    The~only~valid~quantifiers~are~'*',~'?',~'+',~'{<int>}',~
+    '{<min>,}'~and~'{<min>,<max>}',~optionally~followed~by~'?'.
   }
 \__msg_kernel_new:nnnn { regex } { missing-rbrack }
   { Missing~right~bracket~inserted~in~regular~expression. }
   {
     LaTeX~was~given~a~regular~expression~where~a~character~class~
-    was~started~with~`[',~but~the~matching~`]'~is~missing.
+    was~started~with~'[',~but~the~matching~']'~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { missing-rparen }
   {
@@ -2692,7 +2793,7 @@
   }
 \__msg_kernel_new:nnnn { regex } { bad-escape }
   {
-    Invalid~escape~`\iow_char:N\\#1'~
+    Invalid~escape~'\iow_char:N\\#1'~
     \__regex_if_in_cs:TF { within~a~control~sequence. }
       {
         \__regex_if_in_class:TF
@@ -2701,102 +2802,102 @@
       }
   }
   {
-    The~escape~sequence~`\iow_char:N\\#1'~may~not~appear~
+    The~escape~sequence~'\iow_char:N\\#1'~may~not~appear~
     \__regex_if_in_cs:TF
       {
         within~a~control~sequence~test~introduced~by~
-        `\iow_char:N\\c\iow_char:N\{'.
+        '\iow_char:N\\c\iow_char:N\{'.
       }
       {
         \__regex_if_in_class:TF
           { within~a~character~class~ }
-          { following~a~category~test~such~as~`\iow_char:N\\cL'~ }
+          { following~a~category~test~such~as~'\iow_char:N\\cL'~ }
         because~it~does~not~match~exactly~one~character.
       }
   }
 \__msg_kernel_new:nnnn { regex } { range-missing-end }
-  { Invalid~end-point~for~range~`#1-#2'~in~character~class. }
+  { Invalid~end-point~for~range~'#1-#2'~in~character~class. }
   {
-    The~end-point~`#2'~of~the~range~`#1-#2'~may~not~serve~as~an~
+    The~end-point~'#2'~of~the~range~'#1-#2'~may~not~serve~as~an~
     end-point~for~a~range:~alphanumeric~characters~should~not~be~
     escaped,~and~non-alphanumeric~characters~should~be~escaped.
   }
 \__msg_kernel_new:nnnn { regex } { range-backwards }
-  { Range~`[#1-#2]'~out~of~order~in~character~class. }
+  { Range~'[#1-#2]'~out~of~order~in~character~class. }
   {
-    In~ranges~of~characters~`[x-y]'~appearing~in~character~classes,~
+    In~ranges~of~characters~'[x-y]'~appearing~in~character~classes,~
     the~first~character~code~must~not~be~larger~than~the~second.~
-    Here,~`#1'~has~character~code~\int_eval:n {`#1},~while~
-    `#2'~has~character~code~\int_eval:n {`#2}.
+    Here,~'#1'~has~character~code~\int_eval:n {`#1},~while~
+    '#2'~has~character~code~\int_eval:n {`#2}.
   }
 \__msg_kernel_new:nnnn { regex } { c-bad-mode }
-  { Invalid~nested~`\iow_char:N\\c'~escape~in~regular~expression. }
+  { Invalid~nested~'\iow_char:N\\c'~escape~in~regular~expression. }
   {
-    The~`\iow_char:N\\c'~escape~cannot~be~used~within~
-    a~control~sequence~test~`\iow_char:N\\c{...}'.~
-    To~combine~several~category~tests,~use~`\iow_char:N\\c[...]'.
+    The~'\iow_char:N\\c'~escape~cannot~be~used~within~
+    a~control~sequence~test~'\iow_char:N\\c{...}'.~
+    To~combine~several~category~tests,~use~'\iow_char:N\\c[...]'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\c'~escape. }
   {
     LaTeX~was~given~a~regular~expression~where~a~
-    `\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
-    with~a~closing~brace~`\iow_char:N\}'.
+    '\iow_char:N\\c\iow_char:N\{...'~construction~was~not~ended~
+    with~a~closing~brace~'\iow_char:N\}'.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-rbrack }
-  { Missing~right~bracket~inserted~for~`\iow_char:N\\c'~escape. }
+  { Missing~right~bracket~inserted~for~'\iow_char:N\\c'~escape. }
   {
-    A~construction~`\iow_char:N\\c[...'~appears~in~a~
-    regular~expression,~but~the~closing~`]'~is~not~present.
+    A~construction~'\iow_char:N\\c[...'~appears~in~a~
+    regular~expression,~but~the~closing~']'~is~not~present.
   }
 \__msg_kernel_new:nnnn { regex } { c-missing-category }
-  { Invalid~character~`#1'~following~`\iow_char:N\\c'~escape. }
+  { Invalid~character~'#1'~following~'\iow_char:N\\c'~escape. }
   {
-    In~regular~expressions,~the~`\iow_char:N\\c'~escape~sequence~
+    In~regular~expressions,~the~'\iow_char:N\\c'~escape~sequence~
     may~only~be~followed~by~a~left~brace,~a~left~bracket,~or~a~
     capital~letter~representing~a~character~category,~namely~
-    one~of~`ABCDELMOPSTU'.
+    one~of~'ABCDELMOPSTU'.
   }
 \__msg_kernel_new:nnnn { regex } { c-trailing }
-  { Trailing~category~code~escape~`\iow_char:N\\c'... }
+  { Trailing~category~code~escape~'\iow_char:N\\c'... }
   {
-    A~regular~expression~ends~with~`\iow_char:N\\c'~followed~
+    A~regular~expression~ends~with~'\iow_char:N\\c'~followed~
     by~a~letter.~It~will~be~ignored.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-lbrace }
-  { Missing~left~brace~following~`\iow_char:N\\u'~escape. }
+  { Missing~left~brace~following~'\iow_char:N\\u'~escape. }
   {
-    The~`\iow_char:N\\u'~escape~sequence~must~be~followed~by~
+    The~'\iow_char:N\\u'~escape~sequence~must~be~followed~by~
     a~brace~group~with~the~name~of~the~variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { u-missing-rbrace }
-  { Missing~right~brace~inserted~for~`\iow_char:N\\u'~escape. }
+  { Missing~right~brace~inserted~for~'\iow_char:N\\u'~escape. }
   {
     LaTeX~
     \str_if_eq_x:nnTF { } {#2}
       { reached~the~end~of~the~string~ }
-      { encountered~an~escaped~alphanumeric~character `\iow_char:N\\#2'~ }
-    when~parsing~the~argument~of~an~`\iow_char:N\\u\iow_char:N\{...\}'~escape.
+      { encountered~an~escaped~alphanumeric~character '\iow_char:N\\#2'~ }
+    when~parsing~the~argument~of~an~'\iow_char:N\\u\iow_char:N\{...\}'~escape.
   }
 \__msg_kernel_new:nnnn { regex } { posix-unsupported }
-  { POSIX~collating~element~`[#1 ~ #1]'~not~supported. }
+  { POSIX~collating~element~'[#1 ~ #1]'~not~supported. }
   {
-    The~`[.foo.]'~and~`[=bar=]'~syntaxes~have~a~special~meaning~
+    The~'[.foo.]'~and~'[=bar=]'~syntaxes~have~a~special~meaning~
     in~POSIX~regular~expressions.~This~is~not~supported~by~LaTeX.~
     Maybe~you~forgot~to~escape~a~left~bracket~in~a~character~class?
   }
 \__msg_kernel_new:nnnn { regex } { posix-unknown }
-  { POSIX~class~`[:#1:]'~unknown. }
+  { POSIX~class~'[:#1:]'~unknown. }
   {
-    `[:#1:]'~is~not~among~the~known~POSIX~classes~
-    `[:alnum:]',~`[:alpha:]',~`[:ascii:]',~`[:blank:]',~
-    `[:cntrl:]',~`[:digit:]',~`[:graph:]',~`[:lower:]',~
-    `[:print:]',~`[:punct:]',~`[:space:]',~`[:upper:]',~
-    `[:word:]',~and~`[:xdigit:]'.
+    '[:#1:]'~is~not~among~the~known~POSIX~classes~
+    '[:alnum:]',~'[:alpha:]',~'[:ascii:]',~'[:blank:]',~
+    '[:cntrl:]',~'[:digit:]',~'[:graph:]',~'[:lower:]',~
+    '[:print:]',~'[:punct:]',~'[:space:]',~'[:upper:]',~
+    '[:word:]',~and~'[:xdigit:]'.
   }
 \__msg_kernel_new:nnnn { regex } { posix-missing-close }
-  { Missing~closing~`:]'~for~POSIX~class. }
-  { The~POSIX~syntax~`#1'~must~be~followed~by~`:]',~not~`#2'. }
+  { Missing~closing~':]'~for~POSIX~class. }
+  { The~POSIX~syntax~'#1'~must~be~followed~by~':]',~not~'#2'. }
 \__msg_kernel_new:nnnn { regex } { result-unbalanced }
   { Missing~brace~inserted~when~#1. }
   {
@@ -2806,58 +2907,68 @@
     #2~left,~#3~right.
   }
 \__msg_kernel_new:nnnn { regex } { unknown-option }
-  { Unknown~option~`#1'~for~regular~expressions. }
+  { Unknown~option~'#1'~for~regular~expressions. }
   {
-    The~only~available~option~is~`case-insensitive',~toggled~by~
-    `(?i)'~and~`(?-i)'.
+    The~only~available~option~is~'case-insensitive',~toggled~by~
+    '(?i)'~and~'(?-i)'.
   }
 \__msg_kernel_new:nnnn { regex } { special-group-unknown }
-  { Unknown~special~group~`#1~...'~in~a~regular~expression. }
+  { Unknown~special~group~'#1~...'~in~a~regular~expression. }
   {
-    The~only~valid~constructions~starting~with~`(?'~are~
-    `(?:~...~)',~`(?|~...~)',~`(?i)',~and~`(?-i)'.
+    The~only~valid~constructions~starting~with~'(?'~are~
+    '(?:~...~)',~'(?|~...~)',~'(?i)',~and~'(?-i)'.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-c }
-  { Misused~`\iow_char:N\\c'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\c'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~
-    or~a~brace~group,~not~by~`#1'.
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~
+    or~a~brace~group,~not~by~'#1'.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-u }
-  { Misused~`\iow_char:N\\u'~command~in~a~replacement~text. }
+  { Misused~'\iow_char:N\\u'~command~in~a~replacement~text. }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\u'~escape~sequence~
+    In~a~replacement~text,~the~'\iow_char:N\\u'~escape~sequence~
     must~be~~followed~by~a~brace~group~holding~the~name~of~the~
     variable~to~use.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-g }
   {
-    Missing~brace~for~the~`\iow_char:N\\g'~construction~
+    Missing~brace~for~the~'\iow_char:N\\g'~construction~
     in~a~replacement~text.
   }
   {
     In~the~replacement~text~for~a~regular~expression~search,~
-    submatches~are~represented~either~as~`\iow_char:N \\g{dd..d}',~
-    or~`\\d',~where~`d'~are~single~digits.~Here,~a~brace~is~missing.
+    submatches~are~represented~either~as~'\iow_char:N \\g{dd..d}',~
+    or~'\\d',~where~'d'~are~single~digits.~Here,~a~brace~is~missing.
   }
 \__msg_kernel_new:nnnn { regex } { replacement-catcode-end }
   {
-    Missing~character~for~the~`\iow_char:N\\c<category><character>'~
+    Missing~character~for~the~'\iow_char:N\\c<category><character>'~
     construction~in~a~replacement~text.
   }
   {
-    In~a~replacement~text,~the~`\iow_char:N\\c'~escape~sequence~
-    can~be~followed~by~one~of~the~letters~`ABCDELMOPSTU'~representing~
+    In~a~replacement~text,~the~'\iow_char:N\\c'~escape~sequence~
+    can~be~followed~by~one~of~the~letters~'ABCDELMOPSTU'~representing~
     the~character~category.~Then,~a~character~must~follow.~LaTeX~
     reached~the~end~of~the~replacement~when~looking~for~that.
   }
+\__msg_kernel_new:nnnn { regex } { replacement-catcode-in-cs }
+  {
+    Category~code~'\iow_char:N\\c#1#3'~ignored~inside~
+    '\iow_char:N\\c\{...\}'~in~a~replacement~text.
+  }
+  {
+    In~a~replacement~text,~the~category~codes~of~the~argument~of~
+    '\iow_char:N\\c\{...\}'~are~ignored~when~building~the~control~
+    sequence~name.
+  }
 \__msg_kernel_new:nnnn { regex } { replacement-null-space }
   { TeX~cannot~build~a~space~token~with~character~code~0. }
   {
     You~asked~for~a~character~token~with~category~space,~
     and~character~code~0,~for~instance~through~
-    `\iow_char:N\\cS\iow_char:N\\x00'.~
+    '\iow_char:N\\cS\iow_char:N\\x00'.~
     This~specific~case~is~impossible~and~will~be~replaced~
     by~a~normal~space.
   }
@@ -2867,6 +2978,12 @@
     There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
     missing~right~\int_compare:nTF { #1 = 1 } { brace } { braces } .
   }
+\__msg_kernel_new:nnnn { regex } { replacement-missing-rparen }
+  { Missing~right~parenthesis~inserted~in~replacement~text. }
+  {
+    There~ \int_compare:nTF { #1 = 1 } { was } { were } ~ #1~
+    missing~right~\int_compare:nTF { #1 = 1 } { parenthesis } { parentheses } .
+  }
 \cs_new:Npn \__regex_msg_repeated:nnN #1#2#3
   {
     \str_if_eq_x:nnF { #1 #2 } { 1 0 }

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-convert.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-convert.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-convert.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -20,7 +20,7 @@
 %% 
 %% File: l3str-convert.dtx Copyright (C) 2013-2017 The LaTeX3 Project
 \RequirePackage{expl3}
-\ProvidesExplPackage{l3str-convert}{2017/04/01}{}
+\ProvidesExplPackage{l3str-convert}{2017/05/13}{}
   {L3 Experimental string encoding conversions}
 \RequirePackage{l3tl-analysis,l3tl-build}
 \cs_if_exist:NF \use_ii_i:nn
@@ -31,10 +31,6 @@
 \tl_new:N \g__str_result_tl
 \int_const:Nn \c__str_replacement_char_int { "FFFD }
 \int_const:Nn \c__str_max_byte_int { 255 }
-\int_const:Nn \c__str_ascii_min_int { 0 }
-\int_const:Nn \c__str_ascii_max_control_int { 31 }
-\int_const:Nn \c__str_ascii_max_int { 127 }
-\int_const:Nn \c__str_ascii_lower_int { `a - `A }
 \prop_new:N \g__str_alias_prop
 \prop_gput:Nnn \g__str_alias_prop { latin1 } { iso88591 }
 \prop_gput:Nnn \g__str_alias_prop { latin2 } { iso88592 }
@@ -54,32 +50,6 @@
 \bool_new:N \g__str_error_bool
 \flag_new:n { str_byte }
 \flag_new:n { str_error }
-\group_begin:
-\char_set_lccode:nn { `\* } { `\  }
-\char_set_lccode:nn { `\A } { `\A }
-\tex_lowercase:D
-  {
-    \group_end:
-    \cs_new_protected:Npn \__str_gset_other:Nn #1#2
-      {
-        \tl_gset:Nx #1
-          {
-            \exp_after:wN \__str_gset_other_loop:w \tl_to_str:n {#2} ~ %
-            A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_stop
-          }
-      }
-    \cs_new:Npn \__str_gset_other_loop:w
-      #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 ~
-      {
-        \if_meaning:w A #9
-          \__str_gset_other_end:w
-        \fi:
-        #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * #9
-        \__str_gset_other_loop:w *
-      }
-    \cs_new:Npn \__str_gset_other_end:w \fi: #1 * A #2 \q_stop
-      { \fi: #1 }
-  }
 \prg_new_conditional:Npnn \__str_if_contains_char:NN #1#2 { T , TF }
   {
     \exp_after:wN \__str_if_contains_char_aux:NN \exp_after:wN #2
@@ -245,7 +215,7 @@
   {
     \group_begin:
       #1
-      \__str_gset_other:Nn \g__str_result_tl {#4}
+      \tl_gset:Nx \g__str_result_tl { \__str_to_other_fast:n {#4} }
       \exp_after:wN \__str_convert:wwwnn
         \tl_to_str:n {#5} /// \q_stop
         { decode } { unescape }
@@ -335,7 +305,7 @@
           #1
         \fi:
       \else:
-        \__str_output_byte:n { `#1 + \c__str_ascii_lower_int }
+        \__str_output_byte:n { `#1 + `a - `A }
       \fi:
     \fi:
     \__str_convert_lowercase_alphanum_loop:N

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88591.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88591.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88591.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88591')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885910.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885910.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885910.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885910')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885911.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885911.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885911.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885911')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885913.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885913.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885913.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885913')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885914.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885914.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885914.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885914')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885915.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885915.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885915.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885915')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885916.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885916.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso885916.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso885916')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88592.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88592.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88592.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88592')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88593.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88593.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88593.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88593')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88594.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88594.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88594.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88594')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88595.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88595.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88595.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88595')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88596.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88596.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88596.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88596')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88597.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88597.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88597.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88597')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88598.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88598.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88598.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88598')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88599.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88599.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-iso88599.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `iso88599')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf16.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf16.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf16.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `utf16')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf32.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf32.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf32.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `utf32')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf8.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf8.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-enc-utf8.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `utf8')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-hex.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-hex.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-hex.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `hex')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-name.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-name.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-name.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `name')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-string.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-string.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-string.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `string')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-url.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-url.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-esc-url.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-convert.dtx  (with options: `url')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3str-format.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -20,7 +20,7 @@
 %% 
 %% File: l3str-format.dtx Copyright (C) 2012-2013,2015-2017 The LaTeX3 Project
 \RequirePackage{expl3}
-\ProvidesExplPackage{l3str-format}{2017/04/01}{}
+\ProvidesExplPackage{l3str-format}{2017/05/13}{}
   {L3 Experimental string formatting}
 \RequirePackage{l3str}
 \cs_generate_variant:Nn \use:nn { nf }

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-analysis.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3tl-analysis.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -20,7 +20,7 @@
 %% 
 %% File: l3tl-analysis.dtx Copyright (C) 2011-2012,2015-2017 The LaTeX3 Project
 \RequirePackage{expl3}
-\ProvidesExplPackage{l3tl-analysis}{2017/04/01}{}
+\ProvidesExplPackage{l3tl-analysis}{2017/05/13}{}
   {L3 Experimental token list analysis}
 \__scan_new:N \s__tl
 \tl_new:N \l__tl_analysis_internal_tl
@@ -67,8 +67,9 @@
   {
     \int_set:Nn \tex_escapechar:D { -1 }
     \exp_after:wN \__tl_analysis_disable_loop:N
-      \tl_to_str:n {#1} { ~ } { ? ~ \__prg_break: }
+      \tl_to_str:n {#1} { ~ } { ? \__prg_break: }
     \__prg_break_point:
+    \scan_stop:
   }
 \group_begin:
   \char_set_catcode_active:N \^^@
@@ -78,6 +79,20 @@
       \tex_lowercase:D { \tex_let:D ^^@ } \tex_undefined:D
       \__tl_analysis_disable_loop:N
     }
+  \bool_lazy_or:nnT
+    { \sys_if_engine_ptex_p: }
+    { \sys_if_engine_uptex_p: }
+    {
+      \cs_gset_protected:Npn \__tl_analysis_disable_loop:N #1
+        {
+          \use_none:n #1 \scan_stop:
+          \if_int_compare:w 256 > `#1 \exp_stop_f:
+            \tex_lccode:D 0 = `#1 ~
+            \tex_lowercase:D { \tex_let:D ^^@ } \tex_undefined:D
+          \fi:
+          \__tl_analysis_disable_loop:N
+        }
+    }
 \group_end:
 \cs_new_protected:Npn \__tl_analysis_a:n #1
   {

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/l3str/l3tl-build.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -6,7 +6,7 @@
 %%
 %% l3tl-build.dtx  (with options: `package')
 %% 
-%% Copyright (C) 2011-2016 The LaTeX3 Project
+%% Copyright (C) 2011-2017 The LaTeX3 Project
 %% 
 %% It may be distributed and/or modified under the conditions of
 %% the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -19,8 +19,8 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: l3tl-build.dtx Copyright (C) 2011-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{l3tl-build}{Support package l3kernel too old}
@@ -32,7 +32,7 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{l3tl-build}{2017/04/01}{}
+\ProvidesExplPackage{l3tl-build}{2017/05/13}{}
   {L3 Experimental token list construction}
 \int_new:N \l__tl_build_start_index_int
 \int_new:N \l__tl_build_index_int

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -20,7 +20,7 @@
 %% 
 %% File: xcoffins.dtx Copyright(C) 2010-2012,2014,2016,2017 The LaTeX3 Project
 \RequirePackage{xparse}
-\ProvidesExplPackage{xcoffins}{2017/04/01}{}
+\ProvidesExplPackage{xcoffins}{2017/05/13}{}
   {L3 Experimental design level coffins}
 \keys_define:nn { coffin }
   {

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -20,8 +20,8 @@
 %% 
 %% File: l3galley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
 %%                              (C) 2010-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{l3galley}{Support package l3kernel too old}
@@ -33,7 +33,7 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{l3galley}{2017/04/01}{}
+\ProvidesExplPackage{l3galley}{2017/05/13}{}
   {L3 Experimental galley code}
 \int_new:N \l__galley_tmp_int
 \seq_new:N \g__galley_tmpa_seq
@@ -274,7 +274,7 @@
 \cs_new_protected:Npn \galley_par:n #1
   {
     \s__par_omit
-    \bool_if:nF \g__galley_begin_level_bool
+    \bool_if:NF \g__galley_begin_level_bool
       {
         #1
         \galley_par:

Modified: trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -21,7 +21,7 @@
 %% File: xgalley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
 %%                             (C) 2010-2012,2014,2016-2017 The LaTeX3 Project
 \RequirePackage{xparse}
-\ProvidesExplPackage{xgalley}{2017/04/01}{}
+\ProvidesExplPackage{xgalley}{2017/05/13}{}
   {L3 Experimental galley}
 \RequirePackage{xparse,xtemplate,l3galley}
 \clist_new:N \l__galley_tmpa_clist

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2017-05-14 22:40:58 UTC (rev 44351)
@@ -58,7 +58,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx Copyright (C) 1990-2017 The LaTeX3 Project
-\def\ExplFileDate{2017/04/01}%
+\def\ExplFileDate{2017/05/13}%
 \begingroup
   \def\next{\endgroup}%
   \expandafter\ifx\csname PackageError\endcsname\relax
@@ -3064,7 +3064,8 @@
 \cs_new_protected:Npn \tl_map_inline:nn #1#2
   {
     \int_gincr:N \g__prg_map_int
-    \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
+    \cs_gset_protected:cpn
+      { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
     \exp_args:Nc \__tl_map_function:Nn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
       #1 \q_recursion_tail
@@ -4788,7 +4789,7 @@
 \cs_generate_variant:Nn \int_gincr:N { c }
 \cs_generate_variant:Nn \int_gdecr:N { c }
 \cs_new_protected:Npn \int_set:Nn #1#2
-  { #1 ~ \__int_eval:w #2\__int_eval_end: }
+  { #1 ~ \__int_eval:w #2 \__int_eval_end: }
 \cs_new_protected:Npn \int_gset:Nn { \tex_global:D \int_set:Nn }
 \cs_generate_variant:Nn \int_set:Nn  { c }
 \cs_generate_variant:Nn \int_gset:Nn { c }
@@ -5005,7 +5006,7 @@
   {
     \int_gincr:N \g__prg_map_int
     \exp_args:NNc \__int_step:NNnnnn
-      \cs_gset:Npn
+      \cs_gset_protected:Npn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
   }
 \cs_new_protected:Npn \int_step_variable:nnnNn #1#2#3#4#5
@@ -5012,7 +5013,7 @@
   {
     \int_gincr:N \g__prg_map_int
     \exp_args:NNc \__int_step:NNnnnn
-      \cs_gset:Npx
+      \cs_gset_protected:Npx
       { __prg_map_ \int_use:N \g__prg_map_int :w }
       {#1}{#2}{#3}
       {
@@ -6307,7 +6308,8 @@
     \clist_if_empty:NF #1
       {
         \int_gincr:N \g__prg_map_int
-        \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
+        \cs_gset_protected:cpn
+          { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
         \exp_last_unbraced:Nco \__clist_map_function:Nw
           { __prg_map_ \int_use:N \g__prg_map_int :w }
           #1 , \q_recursion_tail ,
@@ -7474,7 +7476,7 @@
     \cs_gset_eq:cN
       { __prg_map_ \int_use:N \g__prg_map_int :wn } \__prop_pair:wn
     \int_gincr:N \g__prg_map_int
-    \cs_gset:Npn \__prop_pair:wn ##1 \s__prop ##2 {#2}
+    \cs_gset_protected:Npn \__prop_pair:wn ##1 \s__prop ##2 {#2}
     #1
     \__prg_break_point:Nn \prop_map_break:
       {
@@ -11329,10 +11331,13 @@
   {
     \cs_if_exist_use:cF { __fp_parse_word_#2:N }
       {
-        \__msg_kernel_expandable_error:nnn
-          { kernel } { unknown-fp-word } {#2}
-        \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
-        \__fp_parse_infix:NN
+        \cs_if_exist_use:cF { __fp_parse_caseless_ \str_fold_case:n {#2} :N }
+          {
+            \__msg_kernel_expandable_error:nnn
+              { kernel } { unknown-fp-word } {#2}
+            \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
+            \__fp_parse_infix:NN
+          }
       }
       #1
   }
@@ -11823,6 +11828,9 @@
 \__fp_tmp:w { deg } \c_one_degree_fp
 \__fp_tmp:w { true } \c_one_fp
 \__fp_tmp:w { false } \c_zero_fp
+\cs_new_eq:NN \__fp_parse_caseless_inf:N \__fp_parse_word_inf:N
+\cs_new_eq:NN \__fp_parse_caseless_infinity:N \__fp_parse_word_inf:N
+\cs_new_eq:NN \__fp_parse_caseless_nan:N \__fp_parse_word_nan:N
 \cs_set_protected:Npn \__fp_tmp:w #1 #2
   {
     \cs_new:cpn { __fp_parse_word_#1:N }
@@ -12512,13 +12520,29 @@
       }
   }
 \cs_generate_variant:Nn \__fp_step:NnnnnN { Nf }
-\cs_new_protected:Npn \fp_step_inline:nnnn #1#2#3#4
+\cs_new_protected:Npn \fp_step_inline:nnnn
   {
     \int_gincr:N \g__prg_map_int
-    \cs_gset_protected:cpn { __prg_map_ \int_use:N \g__prg_map_int :w }
-      ##1 {#4}
-    \fp_step_function:nnnc {#1} {#2} {#3}
+    \exp_args:NNc \__fp_step:NNnnnn
+      \cs_gset_protected:Npn
       { __prg_map_ \int_use:N \g__prg_map_int :w }
+  }
+\cs_new_protected:Npn \fp_step_variable:nnnNn #1#2#3#4#5
+  {
+    \int_gincr:N \g__prg_map_int
+    \exp_args:NNc \__fp_step:NNnnnn
+      \cs_gset_protected:Npx
+      { __prg_map_ \int_use:N \g__prg_map_int :w }
+      {#1} {#2} {#3}
+      {
+        \tl_set:Nn \exp_not:N #4 {##1}
+        \exp_not:n {#5}
+      }
+  }
+\cs_new_protected:Npn \__fp_step:NNnnnn #1#2#3#4#5#6
+  {
+    #1 #2 ##1 {#6}
+    \fp_step_function:nnnN {#3} {#4} {#5} #2
     \__prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__prg_map_int }
   }
 \__msg_kernel_new:nnn { kernel } { fp-bad-step }
@@ -16320,29 +16344,45 @@
       }
   }
 \cs_generate_variant:Nn \__box_show:NNnn { NNff }
-\cs_new_protected:Npn \hbox:n #1 { \tex_hbox:D \scan_stop: {#1} }
+\cs_new_protected:Npn \hbox:n #1
+  { \tex_hbox:D \scan_stop: { \group_begin: #1 \group_end: } }
 \cs_new_protected:Npn \hbox_set:Nn #1#2
-  { \tex_setbox:D #1 \tex_hbox:D {#2} }
+  { \tex_setbox:D #1 \tex_hbox:D { \group_begin: #2 \group_end: } }
 \cs_new_protected:Npn \hbox_gset:Nn { \tex_global:D \hbox_set:Nn }
 \cs_generate_variant:Nn \hbox_set:Nn { c }
 \cs_generate_variant:Nn \hbox_gset:Nn { c }
 \cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3
-  { \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end: {#3} }
+  {
+    \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end:
+      { \group_begin: #3 \group_end: }
+  }
 \cs_new_protected:Npn \hbox_gset_to_wd:Nnn
   { \tex_global:D \hbox_set_to_wd:Nnn }
 \cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c }
 \cs_generate_variant:Nn \hbox_gset_to_wd:Nnn { c }
 \cs_new_protected:Npn \hbox_set:Nw  #1
-  { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token }
+  {
+    \tex_setbox:D #1 \tex_hbox:D
+      \c_group_begin_token
+        \group_begin:
+  }
 \cs_new_protected:Npn \hbox_gset:Nw
   { \tex_global:D \hbox_set:Nw }
 \cs_generate_variant:Nn \hbox_set:Nw  { c }
 \cs_generate_variant:Nn \hbox_gset:Nw { c }
-\cs_new_eq:NN \hbox_set_end:  \c_group_end_token
-\cs_new_eq:NN \hbox_gset_end: \c_group_end_token
+\cs_new_protected:Npn \hbox_set_end:
+  {
+      \group_end:
+    \c_group_end_token
+  }
+\cs_new_eq:NN \hbox_gset_end: \hbox_set_end:
 \cs_new_protected:Npn \hbox_to_wd:nn #1#2
-   { \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end: {#2} }
-\cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_dim {#1} }
+   {
+     \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end:
+       { \group_begin: #2 \group_end: }
+   }
+\cs_new_protected:Npn \hbox_to_zero:n #1
+  { \tex_hbox:D to \c_zero_dim { \group_begin: #1 \group_end: } }
 \cs_new_protected:Npn \hbox_overlap_left:n  #1
   { \hbox_to_zero:n { \tex_hss:D #1 } }
 \cs_new_protected:Npn \hbox_overlap_right:n #1
@@ -16351,19 +16391,33 @@
 \cs_new_eq:NN \hbox_unpack_clear:N \tex_unhbox:D
 \cs_generate_variant:Nn \hbox_unpack:N { c }
 \cs_generate_variant:Nn \hbox_unpack_clear:N { c }
-\cs_new_protected:Npn \vbox:n #1     { \tex_vbox:D { #1 \par } }
-\cs_new_protected:Npn \vbox_top:n #1 { \tex_vtop:D { #1 \par } }
+\cs_new_protected:Npn \vbox:n #1
+  { \tex_vbox:D { \group_begin: #1 \par \group_end: } }
+\cs_new_protected:Npn \vbox_top:n #1
+  { \tex_vtop:D { \group_begin: #1 \par \group_end: } }
 \cs_new_protected:Npn \vbox_to_ht:nn #1#2
-  { \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end: { #2 \par } }
+  {
+    \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end:
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_to_zero:n #1
-  { \tex_vbox:D to \c_zero_dim { #1 \par } }
+  {
+    \tex_vbox:D to \c_zero_dim
+      { \group_begin: #1 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_set:Nn #1#2
-  { \tex_setbox:D #1 \tex_vbox:D { #2 \par } }
+  {
+    \tex_setbox:D #1 \tex_vbox:D
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_gset:Nn  { \tex_global:D \vbox_set:Nn }
 \cs_generate_variant:Nn \vbox_set:Nn  { c }
 \cs_generate_variant:Nn \vbox_gset:Nn { c }
 \cs_new_protected:Npn \vbox_set_top:Nn #1#2
-  { \tex_setbox:D #1 \tex_vtop:D { #2 \par } }
+  {
+    \tex_setbox:D #1 \tex_vtop:D
+      { \group_begin: #2 \par \group_end: }
+  }
 \cs_new_protected:Npn \vbox_gset_top:Nn
   { \tex_global:D \vbox_set_top:Nn }
 \cs_generate_variant:Nn \vbox_set_top:Nn { c }
@@ -16371,7 +16425,7 @@
 \cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3
   {
     \tex_setbox:D #1 \tex_vbox:D to \__dim_eval:w #2 \__dim_eval_end:
-      { #3 \par }
+      { \group_begin: #3 \par \group_end: }
   }
 \cs_new_protected:Npn \vbox_gset_to_ht:Nnn
   { \tex_global:D \vbox_set_to_ht:Nnn }
@@ -16378,7 +16432,11 @@
 \cs_generate_variant:Nn \vbox_set_to_ht:Nnn  { c }
 \cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c }
 \cs_new_protected:Npn \vbox_set:Nw #1
-  { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token }
+  {
+    \tex_setbox:D #1 \tex_vbox:D
+      \c_group_begin_token
+        \group_begin:
+  }
 \cs_new_protected:Npn \vbox_gset:Nw
   { \tex_global:D \vbox_set:Nw }
 \cs_generate_variant:Nn \vbox_set:Nw  { c }
@@ -16385,7 +16443,8 @@
 \cs_generate_variant:Nn \vbox_gset:Nw { c }
 \cs_new_protected:Npn \vbox_set_end:
   {
-    \par
+        \par
+      \group_end:
     \c_group_end_token
   }
 \cs_new_eq:NN \vbox_gset_end: \vbox_set_end:
@@ -16395,21 +16454,322 @@
 \cs_generate_variant:Nn \vbox_unpack_clear:N { c }
 \cs_new_protected:Npn \vbox_set_split_to_ht:NNn #1#2#3
   { \tex_setbox:D #1 \tex_vsplit:D #2 to \__dim_eval:w #3 \__dim_eval_end: }
+\fp_new:N \l__box_angle_fp
+\fp_new:N \l__box_cos_fp
+\fp_new:N \l__box_sin_fp
+\dim_new:N \l__box_top_dim
+\dim_new:N \l__box_bottom_dim
+\dim_new:N \l__box_left_dim
+\dim_new:N \l__box_right_dim
+\dim_new:N \l__box_top_new_dim
+\dim_new:N \l__box_bottom_new_dim
+\dim_new:N \l__box_left_new_dim
+\dim_new:N \l__box_right_new_dim
+\box_new:N \l__box_internal_box
+\cs_new_protected:Npn \box_rotate:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l__box_angle_fp {#2}
+        \fp_set:Nn \l__box_sin_fp { sind ( \l__box_angle_fp ) }
+        \fp_set:Nn \l__box_cos_fp { cosd ( \l__box_angle_fp ) }
+        \__box_rotate:N #1
+      }
+  }
+\cs_new_protected:Npn \__box_rotate:N #1
+  {
+    \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l__box_left_dim
+    \fp_compare:nNnTF \l__box_sin_fp > \c_zero_fp
+      {
+        \fp_compare:nNnTF \l__box_cos_fp > \c_zero_fp
+          { \__box_rotate_quadrant_one: }
+          { \__box_rotate_quadrant_two: }
+      }
+      {
+        \fp_compare:nNnTF \l__box_cos_fp < \c_zero_fp
+          { \__box_rotate_quadrant_three: }
+          { \__box_rotate_quadrant_four: }
+      }
+    \hbox_set:Nn \l__box_internal_box { \box_use:N #1 }
+    \hbox_set:Nn \l__box_internal_box
+      {
+        \tex_kern:D -\l__box_left_new_dim
+        \hbox:n
+          {
+            \__driver_box_use_rotate:Nn
+              \l__box_internal_box
+              \l__box_angle_fp
+          }
+      }
+    \box_set_ht:Nn \l__box_internal_box {  \l__box_top_new_dim }
+    \box_set_dp:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
+    \box_set_wd:Nn \l__box_internal_box
+      { \l__box_right_new_dim - \l__box_left_new_dim }
+    \box_use:N \l__box_internal_box
+  }
+\cs_new_protected:Npn \__box_rotate_x:nnN #1#2#3
+  {
+    \dim_set:Nn #3
+      {
+        \fp_to_dim:n
+          {
+              \l__box_cos_fp * \dim_to_fp:n {#1}
+            - \l__box_sin_fp * \dim_to_fp:n {#2}
+          }
+      }
+  }
+\cs_new_protected:Npn \__box_rotate_y:nnN #1#2#3
+  {
+    \dim_set:Nn #3
+      {
+        \fp_to_dim:n
+          {
+              \l__box_sin_fp * \dim_to_fp:n {#1}
+            + \l__box_cos_fp * \dim_to_fp:n {#2}
+          }
+      }
+  }
+\cs_new_protected:Npn \__box_rotate_quadrant_one:
+  {
+    \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim
+      \l__box_top_new_dim
+    \__box_rotate_y:nnN \l__box_left_dim  \l__box_bottom_dim
+      \l__box_bottom_new_dim
+    \__box_rotate_x:nnN \l__box_left_dim  \l__box_top_dim
+      \l__box_left_new_dim
+    \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim
+      \l__box_right_new_dim
+  }
+\cs_new_protected:Npn \__box_rotate_quadrant_two:
+  {
+    \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim
+      \l__box_top_new_dim
+    \__box_rotate_y:nnN \l__box_left_dim  \l__box_top_dim
+      \l__box_bottom_new_dim
+    \__box_rotate_x:nnN \l__box_right_dim  \l__box_top_dim
+      \l__box_left_new_dim
+    \__box_rotate_x:nnN \l__box_left_dim   \l__box_bottom_dim
+      \l__box_right_new_dim
+  }
+\cs_new_protected:Npn \__box_rotate_quadrant_three:
+  {
+    \__box_rotate_y:nnN \l__box_left_dim  \l__box_bottom_dim
+      \l__box_top_new_dim
+    \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim
+      \l__box_bottom_new_dim
+    \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim
+      \l__box_left_new_dim
+    \__box_rotate_x:nnN \l__box_left_dim   \l__box_top_dim
+      \l__box_right_new_dim
+  }
+\cs_new_protected:Npn \__box_rotate_quadrant_four:
+  {
+    \__box_rotate_y:nnN \l__box_left_dim  \l__box_top_dim
+      \l__box_top_new_dim
+    \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim
+      \l__box_bottom_new_dim
+    \__box_rotate_x:nnN \l__box_left_dim  \l__box_bottom_dim
+      \l__box_left_new_dim
+    \__box_rotate_x:nnN \l__box_right_dim \l__box_top_dim
+      \l__box_right_new_dim
+  }
+\fp_new:N \l__box_scale_x_fp
+\fp_new:N \l__box_scale_y_fp
+\cs_new_protected:Npn \box_resize_to_wd_and_ht_plus_dp:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \__box_resize_set_corners:N #1
+        \fp_set:Nn \l__box_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
+        \fp_set:Nn \l__box_scale_y_fp
+          {
+              \dim_to_fp:n {#3}
+            / \dim_to_fp:n { \l__box_top_dim - \l__box_bottom_dim }
+          }
+        \__box_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd_and_ht_plus_dp:Nnn { c }
+\cs_new_protected:Npn \__box_resize_set_corners:N #1
+  {
+    \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l__box_left_dim
+  }
+\cs_new_protected:Npn \__box_resize:N #1
+  {
+    \__box_resize:NNN \l__box_right_new_dim
+      \l__box_scale_x_fp \l__box_right_dim
+    \__box_resize:NNN \l__box_bottom_new_dim
+      \l__box_scale_y_fp \l__box_bottom_dim
+    \__box_resize:NNN \l__box_top_new_dim
+      \l__box_scale_y_fp \l__box_top_dim
+    \__box_resize_common:N #1
+  }
+\cs_new_protected:Npn \__box_resize:NNN #1#2#3
+  {
+    \dim_set:Nn #1
+      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
+  }
+\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \__box_resize_set_corners:N #1
+        \fp_set:Nn \l__box_scale_y_fp
+          {
+              \dim_to_fp:n {#2}
+            / \dim_to_fp:n { \l__box_top_dim }
+          }
+        \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp
+        \__box_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
+\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \__box_resize_set_corners:N #1
+        \fp_set:Nn \l__box_scale_y_fp
+          {
+              \dim_to_fp:n {#2}
+            / \dim_to_fp:n { \l__box_top_dim - \l__box_bottom_dim }
+          }
+        \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp
+        \__box_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
+  {
+    \hbox_set:Nn #1
+      {
+        \__box_resize_set_corners:N #1
+        \fp_set:Nn \l__box_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
+        \fp_set_eq:NN \l__box_scale_y_fp \l__box_scale_x_fp
+        \__box_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \__box_resize_set_corners:N #1
+        \fp_set:Nn \l__box_scale_x_fp
+          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
+        \fp_set:Nn \l__box_scale_y_fp
+          {
+              \dim_to_fp:n {#3}
+            / \dim_to_fp:n { \l__box_top_dim }
+          }
+        \__box_resize:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
+\cs_new_protected:Npn \box_scale:Nnn #1#2#3
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l__box_scale_x_fp {#2}
+        \fp_set:Nn \l__box_scale_y_fp {#3}
+        \__box_scale_aux:N #1
+      }
+  }
+\cs_generate_variant:Nn \box_scale:Nnn { c }
+\cs_new_protected:Npn \__box_scale_aux:N #1
+  {
+    \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
+    \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
+    \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
+    \dim_zero:N \l__box_left_dim
+    \dim_set:Nn \l__box_top_new_dim
+      { \fp_abs:n { \l__box_scale_y_fp } \l__box_top_dim }
+    \dim_set:Nn \l__box_bottom_new_dim
+      { \fp_abs:n { \l__box_scale_y_fp } \l__box_bottom_dim }
+    \dim_set:Nn \l__box_right_new_dim
+      { \fp_abs:n { \l__box_scale_x_fp } \l__box_right_dim }
+    \__box_resize_common:N #1
+  }
+\cs_new_protected:Npn \box_autosize_to_wd_and_ht:Nnn #1#2#3
+  { \__box_autosize:Nnnn #1 {#2} {#3} { \box_ht:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht:Nnn { c }
+\cs_new_protected:Npn \box_autosize_to_wd_and_ht_plus_dp:Nnn #1#2#3
+  { \__box_autosize:Nnnn #1 {#2} {#3} { \box_ht:N #1 + \box_dp:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht_plus_dp:Nnn { c }
+\cs_new_protected:Npn \__box_autosize:Nnnn #1#2#3#4
+  {
+    \hbox_set:Nn #1
+      {
+        \fp_set:Nn \l__box_scale_x_fp { ( #2 ) / \box_wd:N #1 }
+        \fp_set:Nn \l__box_scale_y_fp { ( #3 ) / ( #4 ) }
+        \fp_compare:nNnTF \l__box_scale_x_fp > \l__box_scale_y_fp
+          { \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp }
+          { \fp_set_eq:NN \l__box_scale_y_fp \l__box_scale_x_fp }
+        \__box_scale_aux:N #1
+      }
+  }
+\cs_new_protected:Npn \__box_resize_common:N #1
+  {
+    \hbox_set:Nn \l__box_internal_box
+      {
+        \__driver_box_use_scale:Nnn
+          #1
+          \l__box_scale_x_fp
+          \l__box_scale_y_fp
+      }
+    \fp_compare:nNnTF \l__box_scale_y_fp > \c_zero_fp
+      {
+        \box_set_ht:Nn \l__box_internal_box { \l__box_top_new_dim }
+        \box_set_dp:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
+      }
+      {
+        \box_set_dp:Nn \l__box_internal_box { \l__box_top_new_dim }
+        \box_set_ht:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
+      }
+    \fp_compare:nNnTF \l__box_scale_x_fp < \c_zero_fp
+      {
+        \hbox_to_wd:nn { \l__box_right_new_dim }
+          {
+            \tex_kern:D \l__box_right_new_dim
+            \box_use:N \l__box_internal_box
+            \tex_hss:D
+          }
+      }
+      {
+        \box_set_wd:Nn \l__box_internal_box { \l__box_right_new_dim }
+        \hbox:n
+          {
+            \tex_kern:D \c_zero_dim
+            \box_use:N \l__box_internal_box
+            \tex_hss:D
+          }
+      }
+  }
+\cs_new_eq:NN \box_resize:Nnn \box_resize_to_wd_and_ht_plus_dp:Nnn
+\cs_new_eq:NN \box_resize:cnn \box_resize_to_wd_and_ht_plus_dp:cnn
 %% File: l3coffins.dtx Copyright(C) 2010-2017 The LaTeX3 Project
 \box_new:N \l__coffin_internal_box
 \dim_new:N \l__coffin_internal_dim
 \tl_new:N  \l__coffin_internal_tl
 \prop_new:N \c__coffin_corners_prop
-\prop_put:Nnn \c__coffin_corners_prop { tl } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c__coffin_corners_prop { tr } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c__coffin_corners_prop { bl } { { 0 pt } { 0 pt } }
-\prop_put:Nnn \c__coffin_corners_prop { br } { { 0 pt } { 0 pt } }
+\prop_put:Nnn \c__coffin_corners_prop { tl } { { 0pt } { 0pt } }
+\prop_put:Nnn \c__coffin_corners_prop { tr } { { 0pt } { 0pt } }
+\prop_put:Nnn \c__coffin_corners_prop { bl } { { 0pt } { 0pt } }
+\prop_put:Nnn \c__coffin_corners_prop { br } { { 0pt } { 0pt } }
 \prop_new:N \c__coffin_poles_prop
-\tl_set:Nn \l__coffin_internal_tl { { 0 pt } { 0 pt } { 0 pt } { 1000 pt } }
+\tl_set:Nn \l__coffin_internal_tl { { 0pt } { 0pt } { 0pt } { 1000pt } }
 \prop_put:Nno \c__coffin_poles_prop { l }  { \l__coffin_internal_tl }
 \prop_put:Nno \c__coffin_poles_prop { hc } { \l__coffin_internal_tl }
 \prop_put:Nno \c__coffin_poles_prop { r }  { \l__coffin_internal_tl }
-\tl_set:Nn \l__coffin_internal_tl { { 0 pt } { 0 pt } { 1000 pt } { 0 pt } }
+\tl_set:Nn \l__coffin_internal_tl { { 0pt } { 0pt } { 1000pt } { 0pt } }
 \prop_put:Nno \c__coffin_poles_prop { b }  { \l__coffin_internal_tl }
 \prop_put:Nno \c__coffin_poles_prop { vc } { \l__coffin_internal_tl }
 \prop_put:Nno \c__coffin_poles_prop { t }  { \l__coffin_internal_tl }
@@ -16478,10 +16838,8 @@
       {
         \hbox_set:Nn #1
           {
-            \color_group_begin:
-              \color_ensure_current:
-              #2
-            \color_group_end:
+            \color_ensure_current:
+            #2
           }
         \__coffin_reset_structure:N #1
         \__coffin_update_poles:N #1
@@ -16498,9 +16856,7 @@
             \dim_set:Nn \tex_hsize:D {#2}
             \dim_set_eq:NN \linewidth   \tex_hsize:D
             \dim_set_eq:NN \columnwidth \tex_hsize:D
-            \color_group_begin:
-              #3
-            \color_group_end:
+            #3
           }
         \__coffin_reset_structure:N #1
         \__coffin_update_poles:N #1
@@ -16508,13 +16864,13 @@
         \vbox_set_top:Nn \l__coffin_internal_box { \vbox_unpack:N #1 }
         \__coffin_set_pole:Nnx #1 { T }
           {
-            { 0 pt }
+            { 0pt }
             {
               \dim_eval:n
                 { \box_ht:N #1 - \box_ht:N \l__coffin_internal_box }
             }
-            { 1000 pt }
-            { 0 pt }
+            { 1000pt }
+            { 0pt }
           }
         \box_clear:N \l__coffin_internal_box
       }
@@ -16524,10 +16880,9 @@
   {
     \__coffin_if_exist:NT #1
       {
-        \hbox_set:Nw #1 \color_group_begin: \color_ensure_current:
+        \hbox_set:Nw #1 \color_ensure_current:
           \cs_set_protected:Npn \hcoffin_set_end:
             {
-                \color_group_end:
               \hbox_set_end:
               \__coffin_reset_structure:N #1
               \__coffin_update_poles:N #1
@@ -16545,10 +16900,8 @@
           \dim_set:Nn \tex_hsize:D {#2}
             \dim_set_eq:NN \linewidth   \tex_hsize:D
             \dim_set_eq:NN \columnwidth \tex_hsize:D
-          \color_group_begin:
           \cs_set_protected:Npn \vcoffin_set_end:
             {
-                \color_group_end:
               \vbox_set_end:
               \__coffin_reset_structure:N #1
               \__coffin_update_poles:N #1
@@ -16556,13 +16909,13 @@
               \vbox_set_top:Nn \l__coffin_internal_box { \vbox_unpack:N #1 }
               \__coffin_set_pole:Nnx #1 { T }
                 {
-                  { 0 pt }
+                  { 0pt }
                   {
                     \dim_eval:n
                       { \box_ht:N #1 - \box_ht:N \l__coffin_internal_box }
                   }
-                  { 1000 pt }
-                  { 0 pt }
+                  { 1000pt }
+                  { 0pt }
                 }
               \box_clear:N \l__coffin_internal_box
             }
@@ -16598,7 +16951,7 @@
       {
         \__msg_kernel_error:nnxx { kernel } { unknown-coffin-pole }
           {#2} { \token_to_str:N #1 }
-        \tl_set:Nn #3 { { 0 pt } { 0 pt } { 0 pt } { 0 pt } }
+        \tl_set:Nn #3 { { 0pt } { 0pt } { 0pt } { 0pt } }
       }
   }
 \cs_new_protected:Npn \__coffin_reset_structure:N #1
@@ -16628,8 +16981,8 @@
       {
         \__coffin_set_pole:Nnx #1 {#2}
           {
-            { 0 pt } { \dim_eval:n {#3} }
-            { 1000 pt } { 0 pt }
+            { 0pt } { \dim_eval:n {#3} }
+            { 1000pt } { 0pt }
           }
       }
   }
@@ -16639,8 +16992,8 @@
       {
         \__coffin_set_pole:Nnx #1 {#2}
           {
-            { \dim_eval:n {#3} } { 0 pt }
-            { 0 pt } { 1000 pt }
+            { \dim_eval:n {#3} } { 0pt }
+            { 0pt } { 1000pt }
           }
       }
   }
@@ -16652,11 +17005,11 @@
 \cs_new_protected:Npn \__coffin_update_corners:N #1
   {
     \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { tl }
-      { { 0 pt } { \dim_eval:n { \box_ht:N #1 } } }
+      { { 0pt } { \dim_eval:n { \box_ht:N #1 } } }
     \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { tr }
       { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { \box_ht:N #1 } } }
     \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { bl }
-      { { 0 pt } { \dim_eval:n { - \box_dp:N #1 } } }
+      { { 0pt } { \dim_eval:n { -\box_dp:N #1 } } }
     \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { br }
       { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { -\box_dp:N #1 } } }
   }
@@ -16665,33 +17018,33 @@
     \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { hc }
       {
         { \dim_eval:n { 0.5 \box_wd:N #1 } }
-        { 0 pt } { 0 pt } { 1000 pt }
+        { 0pt } { 0pt } { 1000pt }
       }
     \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { r }
       {
         { \dim_eval:n { \box_wd:N #1 } }
-        { 0 pt } { 0 pt } { 1000 pt }
+        { 0pt } { 0pt } { 1000pt }
       }
     \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { vc }
       {
-        { 0 pt }
+        { 0pt }
         { \dim_eval:n { ( \box_ht:N #1 - \box_dp:N #1 ) / 2 } }
-        { 1000 pt }
-        { 0 pt }
+        { 1000pt }
+        { 0pt }
       }
     \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { t }
       {
-        { 0 pt }
+        { 0pt }
         { \dim_eval:n { \box_ht:N #1 } }
-        { 1000 pt }
-        { 0 pt }
+        { 1000pt }
+        { 0pt }
       }
     \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { b }
       {
-        { 0 pt }
-        { \dim_eval:n { - \box_dp:N #1 } }
-        { 1000 pt }
-        { 0 pt }
+        { 0pt }
+        { \dim_eval:n { -\box_dp:N #1 } }
+        { 1000pt }
+        { 0pt }
       }
   }
 \cs_new_protected:Npn \__coffin_calculate_intersection:Nnn #1#2#3
@@ -16816,21 +17169,21 @@
           { \tex_kern:D -\l__coffin_internal_dim }
       }
    \__coffin_reset_structure:N \l__coffin_aligned_coffin
-    \prop_clear:c
-      { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _ prop }
-    \__coffin_update_poles:N \l__coffin_aligned_coffin
+   \prop_clear:c
+     { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _ prop }
+   \__coffin_update_poles:N \l__coffin_aligned_coffin
     \dim_compare:nNnTF \l__coffin_offset_x_dim < \c_zero_dim
       {
-        \__coffin_offset_poles:Nnn #1 { -\l__coffin_offset_x_dim } { 0 pt }
-        \__coffin_offset_poles:Nnn #4 { 0 pt } { \l__coffin_offset_y_dim }
-        \__coffin_offset_corners:Nnn #1 { -\l__coffin_offset_x_dim } { 0 pt }
-        \__coffin_offset_corners:Nnn #4 { 0 pt } { \l__coffin_offset_y_dim }
+        \__coffin_offset_poles:Nnn #1 { -\l__coffin_offset_x_dim } { 0pt }
+        \__coffin_offset_poles:Nnn #4 { 0pt } { \l__coffin_offset_y_dim }
+        \__coffin_offset_corners:Nnn #1 { -\l__coffin_offset_x_dim } { 0pt }
+        \__coffin_offset_corners:Nnn #4 { 0pt } { \l__coffin_offset_y_dim }
       }
       {
-        \__coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt }
+        \__coffin_offset_poles:Nnn #1 { 0pt } { 0pt }
         \__coffin_offset_poles:Nnn #4
           { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim }
-        \__coffin_offset_corners:Nnn #1 { 0 pt } { 0 pt }
+        \__coffin_offset_corners:Nnn #1 { 0pt } { 0pt }
         \__coffin_offset_corners:Nnn #4
           { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim }
       }
@@ -16850,7 +17203,7 @@
       { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _prop }
       { l__coffin_corners_ \__int_value:w #1 _prop }
     \__coffin_update_poles:N  \l__coffin_aligned_coffin
-    \__coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt }
+    \__coffin_offset_poles:Nnn #1 { 0pt } { 0pt }
     \__coffin_offset_poles:Nnn #4
       { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim }
     \__coffin_update_vertical_poles:NNN #1 #4 \l__coffin_aligned_coffin
@@ -16935,11 +17288,11 @@
     \dim_compare:nNnTF {#2} < {#6}
       {
         \__coffin_set_pole:Nnx #9 { T }
-          { { 0 pt } {#6} { 1000 pt } { 0 pt } }
+          { { 0pt } {#6} { 1000pt } { 0pt } }
       }
       {
         \__coffin_set_pole:Nnx #9 { T }
-          { { 0 pt } {#2} { 1000 pt } { 0 pt } }
+          { { 0pt } {#2} { 1000pt } { 0pt } }
       }
   }
 \cs_new_protected:Npn \__coffin_update_B:nnnnnnnnN #1#2#3#4#5#6#7#8#9
@@ -16947,11 +17300,11 @@
     \dim_compare:nNnTF {#2} < {#6}
       {
         \__coffin_set_pole:Nnx #9 { B }
-          { { 0 pt } {#2}  { 1000 pt } { 0 pt } }
+          { { 0pt } {#2}  { 1000pt } { 0pt } }
       }
       {
         \__coffin_set_pole:Nnx #9 { B }
-          { { 0 pt } {#6} { 1000 pt } { 0 pt } }
+          { { 0pt } {#6} { 1000pt } { 0pt } }
       }
   }
 \cs_new_protected:Npn \coffin_typeset:Nnnnn #1#2#3#4#5
@@ -17003,7 +17356,7 @@
 \prop_put:Nnn \l__coffin_display_handles_prop { Br }
   { { b } { l } { 1 } { -1 } }
 \dim_new:N  \l__coffin_display_offset_dim
-\dim_set:Nn \l__coffin_display_offset_dim { 2 pt }
+\dim_set:Nn \l__coffin_display_offset_dim { 2pt }
 \dim_new:N \l__coffin_display_x_dim
 \dim_new:N \l__coffin_display_y_dim
 \prop_new:N \l__coffin_display_poles_prop
@@ -17014,10 +17367,10 @@
     \hcoffin_set:Nn \l__coffin_display_pole_coffin
       {
         \color {#4}
-        \rule { 1 pt } { 1 pt }
+        \rule { 1pt } { 1pt }
       }
     \coffin_attach_mark:NnnNnnnn #1 {#2} {#3}
-      \l__coffin_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt }
+      \l__coffin_display_pole_coffin { hc } { vc } { 0pt } { 0pt }
     \hcoffin_set:Nn \l__coffin_display_coord_coffin
       {
         \color {#4}
@@ -17034,7 +17387,7 @@
           {
             \coffin_attach_mark:NnnNnnnn #1 {#2} {#3}
               \l__coffin_display_coord_coffin { l } { vc }
-                { 1 pt } { 0 pt }
+                { 1pt } { 0pt }
           }
           {
             \exp_last_unbraced:No \__coffin_mark_handle_aux:nnnnNnn
@@ -17059,7 +17412,7 @@
     \hcoffin_set:Nn \l__coffin_display_pole_coffin
       {
         \color {#2}
-        \rule { 1 pt } { 1 pt }
+        \rule { 1pt } { 1pt }
       }
     \prop_set_eq:Nc \l__coffin_display_poles_prop
       { l__coffin_poles_ \__int_value:w #1 _prop }
@@ -17090,7 +17443,7 @@
             \dim_set:Nn \l__coffin_display_y_dim { \l__coffin_y_dim }
             \__coffin_display_attach:Nnnnn
               \l__coffin_display_pole_coffin { hc } { vc }
-              { 0 pt } { 0 pt }
+              { 0pt } { 0pt }
             \hcoffin_set:Nn \l__coffin_display_coord_coffin
               {
                 \color {#6}
@@ -17107,7 +17460,7 @@
                   {
                     \__coffin_display_attach:Nnnnn
                       \l__coffin_display_coord_coffin { l } { vc }
-                      { 1 pt } { 0 pt }
+                      { 1pt } { 0pt }
                   }
                   {
                     \exp_last_unbraced:No
@@ -17205,25 +17558,11 @@
 \cs_new_eq:NN \color_group_begin: \group_begin:
 \cs_new_protected:Npn \color_group_end:
   {
-      \tex_par:D
+      \par
     \group_end:
   }
-\cs_new_protected:Npn \color_ensure_current: { }
-\AtBeginDocument
-  {
-    \cs_if_exist:NTF \__driver_color_ensure_current:
-      {
-        \cs_set_protected:Npn \color_ensure_current:
-          { \__driver_color_ensure_current: }
-      }
-      {
-        \cs_if_exist:NT \set at color
-          {
-            \cs_set_protected:Npn \color_ensure_current:
-              { \set at color }
-          }
-      }
-  }
+\cs_new_protected:Npn \color_ensure_current:
+  { \__driver_color_ensure_current: }
 %% File: l3sys.dtx Copyright (C) 2015-2017 The LaTeX3 Project
 \str_const:Nx \c_sys_jobname_str { \tex_jobname:D }
 \int_const:Nn \c_sys_minute_int
@@ -17258,12 +17597,10 @@
   }
 \cs_if_exist:NT \ptex_kanjiskip:D
   {
-    \bool_if:nTF
+    \bool_lazy_and:nnTF
+      { \cs_if_exist_p:N \uptex_disablecjktoken:D }
+      { \int_compare_p:nNn { \ptex_jis:D "2121 } = { "3000 } }
       {
-        \cs_if_exist_p:N \uptex_disablecjktoken:D &&
-        \int_compare_p:nNn { \ptex_jis:D "2121 } = { "3000 }
-      }
-      {
         \cs_gset_eq:NN \sys_if_engine_uptex:T  \use:n
         \cs_gset_eq:NN \sys_if_engine_uptex:F  \use_none:n
         \cs_gset_eq:NN \sys_if_engine_uptex:TF \use_i:nn
@@ -17359,6 +17696,8 @@
     \__deprecation_error:Nnn \tl_to_lowercase:n { } { 2017-12-31 }
     \__deprecation_error:Nnn \tl_to_uppercase:n { } { 2017-12-31 }
     \__deprecation_error:Nnn \ior_get_str:NN { \ior_str_get:NN } { 2017-12-31 }
+    \__deprecation_error:Nnn \box_resize:Nnn { \box_resize_to_wd_and_ht_plus_dp:Nnn } { 2018-12-31 }
+    \__deprecation_error:Nnn \box_resize:cnn { \box_resize_to_wd_and_ht_plus_dp:cnn } { 2018-12-31 }
     \__deprecation_error:Nnn \c_minus_one { - 1 } { 2018-12-31 }
     \__deprecation_error:Nnn \sort_ordered: { \sort_return_same: } { 2018-12-31 }
     \__deprecation_error:Nnn \sort_reversed: { \sort_return_swapped: } { 2018-12-31 }
@@ -17366,297 +17705,6 @@
     \cs_set_eq:NN \deprecation_error: \scan_stop:
   }
 %% File: l3candidates.dtx Copyright (C) 2012-2017 The LaTeX3 Project
-\fp_new:N \l__box_angle_fp
-\fp_new:N \l__box_cos_fp
-\fp_new:N \l__box_sin_fp
-\dim_new:N \l__box_top_dim
-\dim_new:N \l__box_bottom_dim
-\dim_new:N \l__box_left_dim
-\dim_new:N \l__box_right_dim
-\dim_new:N \l__box_top_new_dim
-\dim_new:N \l__box_bottom_new_dim
-\dim_new:N \l__box_left_new_dim
-\dim_new:N \l__box_right_new_dim
-\box_new:N \l__box_internal_box
-\cs_new_protected:Npn \box_rotate:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \fp_set:Nn \l__box_angle_fp {#2}
-          \fp_set:Nn \l__box_sin_fp { sind ( \l__box_angle_fp ) }
-          \fp_set:Nn \l__box_cos_fp { cosd ( \l__box_angle_fp ) }
-          \__box_rotate:N #1
-        \group_end:
-    }
-  }
-\cs_new_protected:Npn \__box_rotate:N #1
-  {
-    \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
-    \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
-    \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
-    \dim_zero:N \l__box_left_dim
-    \fp_compare:nNnTF \l__box_sin_fp > \c_zero_fp
-      {
-        \fp_compare:nNnTF \l__box_cos_fp > \c_zero_fp
-          { \__box_rotate_quadrant_one: }
-          { \__box_rotate_quadrant_two: }
-      }
-      {
-        \fp_compare:nNnTF \l__box_cos_fp < \c_zero_fp
-          { \__box_rotate_quadrant_three: }
-          { \__box_rotate_quadrant_four: }
-      }
-    \hbox_set:Nn \l__box_internal_box { \box_use:N #1 }
-    \hbox_set:Nn \l__box_internal_box
-      {
-        \tex_kern:D -\l__box_left_new_dim
-        \hbox:n
-          {
-            \__driver_box_use_rotate:Nn
-              \l__box_internal_box
-              \l__box_angle_fp
-          }
-      }
-    \box_set_ht:Nn \l__box_internal_box {  \l__box_top_new_dim }
-    \box_set_dp:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
-    \box_set_wd:Nn \l__box_internal_box
-      { \l__box_right_new_dim - \l__box_left_new_dim }
-    \box_use:N \l__box_internal_box
-  }
-\cs_new_protected:Npn \__box_rotate_x:nnN #1#2#3
-  {
-    \dim_set:Nn #3
-      {
-        \fp_to_dim:n
-          {
-              \l__box_cos_fp * \dim_to_fp:n {#1}
-            - \l__box_sin_fp * \dim_to_fp:n {#2}
-          }
-      }
-  }
-\cs_new_protected:Npn \__box_rotate_y:nnN #1#2#3
-  {
-    \dim_set:Nn #3
-      {
-        \fp_to_dim:n
-          {
-              \l__box_sin_fp * \dim_to_fp:n {#1}
-            + \l__box_cos_fp * \dim_to_fp:n {#2}
-          }
-      }
-  }
-\cs_new_protected:Npn \__box_rotate_quadrant_one:
-  {
-    \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim
-      \l__box_top_new_dim
-    \__box_rotate_y:nnN \l__box_left_dim  \l__box_bottom_dim
-      \l__box_bottom_new_dim
-    \__box_rotate_x:nnN \l__box_left_dim  \l__box_top_dim
-      \l__box_left_new_dim
-    \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim
-      \l__box_right_new_dim
-  }
-\cs_new_protected:Npn \__box_rotate_quadrant_two:
-  {
-    \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim
-      \l__box_top_new_dim
-    \__box_rotate_y:nnN \l__box_left_dim  \l__box_top_dim
-      \l__box_bottom_new_dim
-    \__box_rotate_x:nnN \l__box_right_dim  \l__box_top_dim
-      \l__box_left_new_dim
-    \__box_rotate_x:nnN \l__box_left_dim   \l__box_bottom_dim
-      \l__box_right_new_dim
-  }
-\cs_new_protected:Npn \__box_rotate_quadrant_three:
-  {
-    \__box_rotate_y:nnN \l__box_left_dim  \l__box_bottom_dim
-      \l__box_top_new_dim
-    \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim
-      \l__box_bottom_new_dim
-    \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim
-      \l__box_left_new_dim
-    \__box_rotate_x:nnN \l__box_left_dim   \l__box_top_dim
-      \l__box_right_new_dim
-  }
-\cs_new_protected:Npn \__box_rotate_quadrant_four:
-  {
-    \__box_rotate_y:nnN \l__box_left_dim  \l__box_top_dim
-      \l__box_top_new_dim
-    \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim
-      \l__box_bottom_new_dim
-    \__box_rotate_x:nnN \l__box_left_dim  \l__box_bottom_dim
-      \l__box_left_new_dim
-    \__box_rotate_x:nnN \l__box_right_dim \l__box_top_dim
-      \l__box_right_new_dim
-  }
-\fp_new:N \l__box_scale_x_fp
-\fp_new:N \l__box_scale_y_fp
-\cs_new_protected:Npn \box_resize:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \__box_resize_set_corners:N #1
-          \fp_set:Nn \l__box_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
-          \fp_set:Nn \l__box_scale_y_fp
-            {
-                \dim_to_fp:n {#3}
-              / \dim_to_fp:n { \l__box_top_dim - \l__box_bottom_dim }
-            }
-          \__box_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize:Nnn { c }
-\cs_new_protected:Npn \__box_resize_set_corners:N #1
-  {
-    \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
-    \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
-    \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
-    \dim_zero:N \l__box_left_dim
-  }
-\cs_new_protected:Npn \__box_resize:N #1
-  {
-    \__box_resize:NNN \l__box_right_new_dim
-      \l__box_scale_x_fp \l__box_right_dim
-    \__box_resize:NNN \l__box_bottom_new_dim
-      \l__box_scale_y_fp \l__box_bottom_dim
-    \__box_resize:NNN \l__box_top_new_dim
-      \l__box_scale_y_fp \l__box_top_dim
-    \__box_resize_common:N #1
-  }
-\cs_new_protected:Npn \__box_resize:NNN #1#2#3
-  {
-    \dim_set:Nn #1
-      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
-  }
-\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \__box_resize_set_corners:N #1
-          \fp_set:Nn \l__box_scale_y_fp
-            {
-                \dim_to_fp:n {#2}
-              / \dim_to_fp:n { \l__box_top_dim }
-            }
-          \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp
-          \__box_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
-\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \__box_resize_set_corners:N #1
-          \fp_set:Nn \l__box_scale_y_fp
-            {
-                \dim_to_fp:n {#2}
-              / \dim_to_fp:n { \l__box_top_dim - \l__box_bottom_dim }
-            }
-          \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp
-          \__box_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
-\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \__box_resize_set_corners:N #1
-          \fp_set:Nn \l__box_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
-          \fp_set_eq:NN \l__box_scale_y_fp \l__box_scale_x_fp
-          \__box_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
-\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \__box_resize_set_corners:N #1
-          \fp_set:Nn \l__box_scale_x_fp
-            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l__box_right_dim } }
-          \fp_set:Nn \l__box_scale_y_fp
-            {
-                \dim_to_fp:n {#3}
-              / \dim_to_fp:n { \l__box_top_dim }
-            }
-          \__box_resize:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
-\cs_new_protected:Npn \box_scale:Nnn #1#2#3
-  {
-    \hbox_set:Nn #1
-      {
-        \group_begin:
-          \fp_set:Nn \l__box_scale_x_fp {#2}
-          \fp_set:Nn \l__box_scale_y_fp {#3}
-          \dim_set:Nn \l__box_top_dim    {  \box_ht:N #1 }
-          \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 }
-          \dim_set:Nn \l__box_right_dim  {  \box_wd:N #1 }
-          \dim_zero:N \l__box_left_dim
-          \dim_set:Nn \l__box_top_new_dim
-            { \fp_abs:n { \l__box_scale_y_fp } \l__box_top_dim }
-          \dim_set:Nn \l__box_bottom_new_dim
-            { \fp_abs:n { \l__box_scale_y_fp } \l__box_bottom_dim }
-          \dim_set:Nn \l__box_right_new_dim
-              { \fp_abs:n { \l__box_scale_x_fp } \l__box_right_dim }
-           \__box_resize_common:N #1
-        \group_end:
-      }
-  }
-\cs_generate_variant:Nn \box_scale:Nnn { c }
-\cs_new_protected:Npn \__box_resize_common:N #1
-  {
-    \hbox_set:Nn \l__box_internal_box
-      {
-        \__driver_box_use_scale:Nnn
-          #1
-          \l__box_scale_x_fp
-          \l__box_scale_y_fp
-      }
-    \fp_compare:nNnTF \l__box_scale_y_fp > \c_zero_fp
-      {
-        \box_set_ht:Nn \l__box_internal_box { \l__box_top_new_dim }
-        \box_set_dp:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
-      }
-      {
-        \box_set_dp:Nn \l__box_internal_box { \l__box_top_new_dim }
-        \box_set_ht:Nn \l__box_internal_box { -\l__box_bottom_new_dim }
-      }
-    \fp_compare:nNnTF \l__box_scale_x_fp < \c_zero_fp
-      {
-        \hbox_to_wd:nn { \l__box_right_new_dim }
-          {
-            \tex_kern:D \l__box_right_new_dim
-            \box_use:N \l__box_internal_box
-            \tex_hss:D
-          }
-      }
-      {
-        \box_set_wd:Nn \l__box_internal_box { \l__box_right_new_dim }
-        \hbox:n
-          {
-            \tex_kern:D \c_zero_dim
-            \box_use:N \l__box_internal_box
-            \tex_hss:D
-          }
-      }
-  }
 \cs_new_protected:Npn \box_clip:N #1
   { \hbox_set:Nn #1 { \__driver_box_use_clip:N #1 } }
 \cs_generate_variant:Nn \box_clip:N { c }
@@ -17925,7 +17973,7 @@
           \dim_to_fp:n {#3}
         / \dim_to_fp:n { \coffin_ht:N #1 + \coffin_dp:N #1 }
       }
-    \box_resize:Nnn #1 {#2} {#3}
+    \box_resize_to_wd_and_ht_plus_dp:Nnn #1 {#2} {#3}
     \__coffin_resize_common:Nnn #1 {#2} {#3}
   }
 \cs_generate_variant:Nn \coffin_resize:Nnn { c }
@@ -18037,7 +18085,7 @@
   }
 \cs_new_protected:Npn \__ior_map_inline:NNNn #1#2#3#4
   {
-    \cs_set:Npn #1 ##1 {#4}
+    \cs_gset_protected:Npn #1 ##1 {#4}
     \ior_if_eof:NF #3 { \__ior_map_inline_loop:NNN #1#2#3 }
     \__prg_break_point:Nn \ior_map_break:
       { \int_gdecr:N \g__prg_map_int }
@@ -18245,6 +18293,18 @@
         #2
       }
   }
+\cs_if_exist:NTF \pdftex_uniformdeviate:D
+  {
+    \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
+      { \prg_return_true: }
+  }
+  {
+    \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
+      { \prg_return_false: }
+  }
+\cs_new:Npn \sys_rand_seed: { \tex_the:D \pdftex_randomseed:D }
+\cs_new_protected:Npn \sys_gset_rand_seed:n #1
+  { \pdftex_setrandomseed:D \__int_eval:w #1 \__int_eval_end: }
 \prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF }
   {
     \tl_if_head_is_N_type:nTF {#1}
@@ -18934,11 +18994,10 @@
   \__tl_tmp:w \c__unicode_I_ogonek_tl  { 012E }
 \group_end:
 \group_begin:
-  \bool_if:nT
+  \bool_lazy_or:nnT
+    { \sys_if_engine_pdftex_p: }
+    { \sys_if_engine_uptex_p: }
     {
-      \sys_if_engine_pdftex_p: || \sys_if_engine_uptex_p:
-    }
-    {
       \cs_set_protected:Npn \__tl_loop:nn #1#2
         {
           \quark_if_recursion_tail_stop:n {#1}

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2017-05-14 22:40:58 UTC (rev 44351)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx Copyright (C) 1990-2017 The LaTeX3 Project
-\def\ExplFileDate{2017/04/01}%
+\def\ExplFileDate{2017/05/13}%
 \let\ExplLoaderFileDate\ExplFileDate
 \begingroup
   \def\tempa{LaTeX2e}%
@@ -73,7 +73,6 @@
   \expandafter\endinput
 \fi
 \cs_set_eq:NN \__iow_wrap_set:Nx \tl_set:Nx
-\protected\def\GetIdInfoLog{}
 \cs_set_protected:Npn \ProvidesExplFile
   {
     \group_begin:

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx Copyright (C) 1990-2017 The LaTeX3 Project
-\def\ExplFileDate{2017/04/01}%
+\def\ExplFileDate{2017/05/13}%
 \let\ExplLoaderFileDate\ExplFileDate
 \ProvidesPackage{expl3}
   [%
@@ -95,11 +95,9 @@
                 \sys_if_output_pdf:TF
                   { pdfmode }
                   {
-                    \bool_if:nTF
-                      {
-                        \sys_if_engine_pdftex_p: ||
-                        \sys_if_engine_luatex_p:
-                      }
+                    \bool_lazy_or:nnTF
+                      { \sys_if_engine_pdftex_p: }
+                      { \sys_if_engine_luatex_p: }
                       { dvips }
                       { dvipdfmx }
                   }
@@ -226,7 +224,7 @@
       }
     \cs_set_protected:Npn \box_rotate:Nn #1#2
       { \hbox_set:Nn #1 { \rotatebox {#2} { \box_use:N #1 } } }
-    \cs_set_protected:Npn \box_resize:Nnn #1#2#3
+    \cs_set_protected:Npn \box_resize_to_wd_and_ht_plus_dp:Nnn #1#2#3
       {
         \hbox_set:Nn #1
           {
@@ -252,15 +250,13 @@
               { \box_use:N #1 }
           }
       }
-    \cs_set_protected:Npn \box_scale:Nnn #1#2#3
+    \cs_set_protected:Npn \__box_scale_aux:N #1
       {
-        \hbox_set:Nn #1
-          {
-            \exp_last_unbraced:Nx \scalebox
-              { { \fp_eval:n {#2} } [ \fp_eval:n {#3} ] }
-              { \box_use:N #1 }
-          }
+        \exp_last_unbraced:Nx \scalebox
+          { { \fp_use:N \l__box_scale_x_fp } [ \fp_use:N \l__box_scale_y_fp ] }
+          { \box_use:N #1 }
       }
+    \cs_set_protected:Npn \color_ensure_current: { \set at color }
   }
   {
     \group_begin:

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3basics.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3bootstrap.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3box.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3box.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3box.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3box.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3candidates.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3clist.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3coffins.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3coffins.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3coffins.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3coffins.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3color.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3color.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3color.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3color.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls	2017-05-14 22:40:58 UTC (rev 44351)
@@ -20,7 +20,7 @@
 %% 
 %% File: l3doc.dtx Copyright (C) 1990-2017 The LaTeX3 project
 \RequirePackage{expl3,xparse,calc}
-\ProvidesExplClass{l3doc}{2017/04/01}{}
+\ProvidesExplClass{l3doc}{2017/05/13}{}
   {L3 Experimental documentation class}
 \clist_new:N \g_docinput_clist
 \seq_new:N \g_doc_functions_seq
@@ -892,7 +892,7 @@
       \clist_clear:N \l__codedoc_function_label_clist
       \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
       \char_set_catcode_active:N \<
-      \cs_set_protected:Npn < ##1 > { \meta {##1} }
+      \cs_set_protected_nopar:Npn < ##1 > { \meta {##1} }
   }
 \group_end:
 \cs_new_protected:Npn \__codedoc_function_reset:

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -25,26 +25,9 @@
 \cs_new_protected:Npn \__driver_literal:n #1
   { \tex_special:D { pdf:literal~ #1 } }
 \cs_new_protected:Npn \__driver_scope_begin:
-  { \__driver_literal:n { q } }
+  { \tex_special:D { x:gsave } }
 \cs_new_protected:Npn \__driver_scope_end:
-  { \__driver_literal:n { Q } }
-\cs_new_protected:Npn \__driver_matrix:n #1
-  { \__driver_literal:n { #1 \c_space_tl 0~0~cm } }
-\tl_new:N \l__driver_current_color_tl
-\tl_set:Nn \l__driver_current_color_tl { [ 0 ] }
-\AtBeginDocument
-  {
-    \@ifpackageloaded { color }
-      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
-      { }
-  }
-\cs_new_protected:Npn \__driver_color_ensure_current:
-  {
-    \tex_special:D { pdf:bcolor~\l__driver_current_color_tl }
-    \group_insert_after:N \__driver_color_reset:
-  }
-\cs_new_protected:Npn \__driver_color_reset:
-  { \tex_special:D { pdf:ecolor } }
+  { \tex_special:D { x:grestore } }
 \cs_new_protected:Npn \__driver_box_use_clip:N #1
   {
     \__driver_scope_begin:
@@ -63,41 +46,43 @@
 \cs_new_protected:Npn \__driver_box_use_rotate:Nn #1#2
   {
     \__driver_scope_begin:
-    \box_set_wd:Nn #1 \c_zero_dim
-    \fp_set:Nn \l__driver_cos_fp { round ( cosd ( #2 ) , 5 ) }
-    \fp_compare:nNnT \l__driver_cos_fp = \c_zero_fp
-      { \fp_zero:N \l__driver_cos_fp }
-    \fp_set:Nn \l__driver_sin_fp { round ( sind ( #2 ) , 5 ) }
-    \__driver_matrix:n
+    \tex_special:D
       {
-        \fp_use:N \l__driver_cos_fp \c_space_tl
-        \fp_compare:nNnTF \l__driver_sin_fp = \c_zero_fp
-          { 0~0 }
-          {
-            \fp_use:N \l__driver_sin_fp
-            \c_space_tl
-            \fp_eval:n { -\l__driver_sin_fp }
-          }
-        \c_space_tl
-        \fp_use:N \l__driver_cos_fp
+        x:rotate~
+        \fp_compare:nNnTF {#2} = \c_zero_fp
+          { 0 }
+          { \fp_eval:n { round ( #2 , 5 ) } }
       }
-   \box_use:N #1
-   \__driver_scope_end:
+    \box_use:N #1
+    \__driver_scope_end:
   }
-\fp_new:N \l__driver_cos_fp
-\fp_new:N \l__driver_sin_fp
 \cs_new_protected:Npn \__driver_box_use_scale:Nnn #1#2#3
   {
     \__driver_scope_begin:
-    \__driver_matrix:n
+    \tex_special:D
       {
+        x:scale~
         \fp_eval:n { round ( #2 , 5 ) } ~
-        0~0~
         \fp_eval:n { round ( #3 , 5 ) }
       }
     \hbox_overlap_right:n { \box_use:N #1 }
     \__driver_scope_end:
   }
+\tl_new:N \l__driver_current_color_tl
+\tl_set:Nn \l__driver_current_color_tl { [ 0 ] }
+\AtBeginDocument
+  {
+    \@ifpackageloaded { color }
+      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
+      { }
+  }
+\cs_new_protected:Npn \__driver_color_ensure_current:
+  {
+    \tex_special:D { pdf:bcolor~\l__driver_current_color_tl }
+    \group_insert_after:N \__driver_color_reset:
+  }
+\cs_new_protected:Npn \__driver_color_reset:
+  { \tex_special:D { pdf:ecolor } }
 \cs_new_eq:NN \__driver_draw_literal:n \__driver_literal:n
 \cs_generate_variant:Nn \__driver_draw_literal:n { x }
 \cs_new_protected:Npn \__driver_draw_begin:

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3expan.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3file.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3file.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3file.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3file.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3fp.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3int.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3int.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3int.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3int.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3keys.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3msg.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3names.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3names.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3names.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3names.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -48,31 +48,6 @@
       { \pdftex_pdfsetmatrix:D }
         {#1}
   }
-\tl_new:N \l__driver_current_color_tl
-\tl_set:Nn \l__driver_current_color_tl { 0~g~0~G }
-\AtBeginDocument
-  {
-    \@ifpackageloaded { color }
-      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
-      { }
-  }
-\int_new:N \l__driver_color_stack_int
-\cs_new_protected:Npx \__driver_color_ensure_current:
-  {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D colorstack }
-      { \pdftex_pdfcolorstack:D }
-        \exp_not:N \l__driver_color_stack_int push
-          { \exp_not:N \l__driver_current_color_tl }
-    \group_insert_after:N \exp_not:N \__driver_color_reset:
-  }
-\cs_new_protected:Npx \__driver_color_reset:
-  {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D colorstack }
-      { \pdftex_pdfcolorstack:D }
-        \exp_not:N \l__driver_color_stack_int pop \scan_stop:
-  }
 \cs_new_protected:Npn \__driver_box_use_clip:N #1
   {
     \__driver_scope_begin:
@@ -126,6 +101,31 @@
     \hbox_overlap_right:n { \box_use:N #1 }
     \__driver_scope_end:
   }
+\tl_new:N \l__driver_current_color_tl
+\tl_set:Nn \l__driver_current_color_tl { 0~g~0~G }
+\AtBeginDocument
+  {
+    \@ifpackageloaded { color }
+      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
+      { }
+  }
+\int_new:N \l__driver_color_stack_int
+\cs_new_protected:Npx \__driver_color_ensure_current:
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D colorstack }
+      { \pdftex_pdfcolorstack:D }
+        \exp_not:N \l__driver_color_stack_int push
+          { \exp_not:N \l__driver_current_color_tl }
+    \group_insert_after:N \exp_not:N \__driver_color_reset:
+  }
+\cs_new_protected:Npx \__driver_color_reset:
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D colorstack }
+      { \pdftex_pdfcolorstack:D }
+        \exp_not:N \l__driver_color_stack_int pop \scan_stop:
+  }
 \cs_new_eq:NN \__driver_draw_literal:n \__driver_literal:n
 \cs_generate_variant:Nn \__driver_draw_literal:n { x }
 \cs_new_protected:Npn \__driver_draw_begin:

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3prg.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3prop.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3quark.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3seq.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3skip.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3sort.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3sort.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3sort.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -41,6 +41,7 @@
   \old at liii@module at name{This package is obsolete ---
    use 'expl3' instead}
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3sort.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3str.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3str.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3str.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3str.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3tl.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3token.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3token.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3token.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -44,6 +44,7 @@
    use 'expl3' instead}
   \@ehc
 \RequirePackage{expl3}
+
 %% 
 %%
 %% End of file `l3token.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def	2017-05-14 22:40:58 UTC (rev 44351)
@@ -25,40 +25,9 @@
 \cs_new_protected:Npn \__driver_literal:n #1
   { \tex_special:D { pdf:literal~ #1 } }
 \cs_new_protected:Npn \__driver_scope_begin:
-  { \__driver_literal:n { q } }
+  { \tex_special:D { x:gsave } }
 \cs_new_protected:Npn \__driver_scope_end:
-  { \__driver_literal:n { Q } }
-\cs_new_protected:Npn \__driver_matrix:n #1
-  { \__driver_literal:n { #1 \c_space_tl 0~0~cm } }
-\tl_new:N \l__driver_current_color_tl
-\tl_set:Nn \l__driver_current_color_tl { [ 0 ] }
-\AtBeginDocument
-  {
-    \@ifpackageloaded { color }
-      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
-      { }
-  }
-\cs_new_protected:Npn \__driver_color_ensure_current:
-  {
-    \tex_special:D { pdf:bcolor~\l__driver_current_color_tl }
-    \group_insert_after:N \__driver_color_reset:
-  }
-\cs_new_protected:Npn \__driver_color_reset:
-  { \tex_special:D { pdf:ecolor } }
-\AtBeginDocument
-  {
-    \@ifpackageloaded { color }
-      {
-        \cs_set_protected:Npn \__driver_color_ensure_current:
-          {
-            \tex_special:D { color~push~\l__driver_current_color_tl }
-            \group_insert_after:N \__driver_color_reset:
-          }
-        \cs_set_protected:Npn \__driver_color_reset:
-          { \tex_special:D { color~pop } }
-      }
-      { }
-  }
+  { \tex_special:D { x:grestore } }
 \cs_new_protected:Npn \__driver_box_use_clip:N #1
   {
     \__driver_scope_begin:
@@ -77,41 +46,57 @@
 \cs_new_protected:Npn \__driver_box_use_rotate:Nn #1#2
   {
     \__driver_scope_begin:
-    \box_set_wd:Nn #1 \c_zero_dim
-    \fp_set:Nn \l__driver_cos_fp { round ( cosd ( #2 ) , 5 ) }
-    \fp_compare:nNnT \l__driver_cos_fp = \c_zero_fp
-      { \fp_zero:N \l__driver_cos_fp }
-    \fp_set:Nn \l__driver_sin_fp { round ( sind ( #2 ) , 5 ) }
-    \__driver_matrix:n
+    \tex_special:D
       {
-        \fp_use:N \l__driver_cos_fp \c_space_tl
-        \fp_compare:nNnTF \l__driver_sin_fp = \c_zero_fp
-          { 0~0 }
-          {
-            \fp_use:N \l__driver_sin_fp
-            \c_space_tl
-            \fp_eval:n { -\l__driver_sin_fp }
-          }
-        \c_space_tl
-        \fp_use:N \l__driver_cos_fp
+        x:rotate~
+        \fp_compare:nNnTF {#2} = \c_zero_fp
+          { 0 }
+          { \fp_eval:n { round ( #2 , 5 ) } }
       }
-   \box_use:N #1
-   \__driver_scope_end:
+    \box_use:N #1
+    \__driver_scope_end:
   }
-\fp_new:N \l__driver_cos_fp
-\fp_new:N \l__driver_sin_fp
 \cs_new_protected:Npn \__driver_box_use_scale:Nnn #1#2#3
   {
     \__driver_scope_begin:
-    \__driver_matrix:n
+    \tex_special:D
       {
+        x:scale~
         \fp_eval:n { round ( #2 , 5 ) } ~
-        0~0~
         \fp_eval:n { round ( #3 , 5 ) }
       }
     \hbox_overlap_right:n { \box_use:N #1 }
     \__driver_scope_end:
   }
+\tl_new:N \l__driver_current_color_tl
+\tl_set:Nn \l__driver_current_color_tl { [ 0 ] }
+\AtBeginDocument
+  {
+    \@ifpackageloaded { color }
+      { \tl_set:Nn \l__driver_current_color_tl { \current at color } }
+      { }
+  }
+\cs_new_protected:Npn \__driver_color_ensure_current:
+  {
+    \tex_special:D { pdf:bcolor~\l__driver_current_color_tl }
+    \group_insert_after:N \__driver_color_reset:
+  }
+\cs_new_protected:Npn \__driver_color_reset:
+  { \tex_special:D { pdf:ecolor } }
+\AtBeginDocument
+  {
+    \@ifpackageloaded { color }
+      {
+        \cs_set_protected:Npn \__driver_color_ensure_current:
+          {
+            \tex_special:D { color~push~\l__driver_current_color_tl }
+            \group_insert_after:N \__driver_color_reset:
+          }
+        \cs_set_protected:Npn \__driver_color_reset:
+          { \tex_special:D { color~pop } }
+      }
+      { }
+  }
 \cs_new_eq:NN \__driver_draw_literal:n \__driver_literal:n
 \cs_generate_variant:Nn \__driver_draw_literal:n { x }
 \cs_new_protected:Npn \__driver_draw_begin:

Modified: trunk/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -19,8 +19,8 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: l3keys2e.dtx (C) Copyright 2009,2011-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{l3keys2e}{Support package l3kernel too old}
@@ -32,7 +32,7 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{l3keys2e}{2017/04/01}{}
+\ProvidesExplPackage{l3keys2e}{2017/05/13}{}
   {LaTeX2e option processing using LaTeX3 keys}
 \cs_generate_variant:Nn \clist_put_right:Nn { Nv }
 \cs_generate_variant:Nn \keys_if_exist:nnT  { nx }

Modified: trunk/Master/texmf-dist/tex/latex/l3packages/xfp/xfp.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3packages/xfp/xfp.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3packages/xfp/xfp.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -19,8 +19,8 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: xfp.dtx (C) Copyright 2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{xfpu}{Support package l3kernel too old}
@@ -33,7 +33,7 @@
     \endinput
   }
 \RequirePackage{xparse}
-\ProvidesExplPackage{xfp}{2017/04/01}{}
+\ProvidesExplPackage{xfp}{2017/05/13}{}
   {L3 Floating point unit}
 \NewExpandableDocumentCommand \fpeval { m } { \fp_eval:n {#1} }
 %% 

Modified: trunk/Master/texmf-dist/tex/latex/l3packages/xfrac/xfrac.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3packages/xfrac/xfrac.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3packages/xfrac/xfrac.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -20,8 +20,8 @@
 %% 
 %% File: xfrac.dtx Copyright (C) 2004, 2008-2010 Morten Hoegholm
 %%                           (C) 2011,2012,2014-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{xfrac}{Support package l3kernel too old}
@@ -34,7 +34,7 @@
     \endinput
   }
 \RequirePackage{amstext,graphicx,l3keys2e,textcomp,xparse,xtemplate}
-\ProvidesExplPackage{xfrac}{2017/04/01}{}
+\ProvidesExplPackage{xfrac}{2017/05/13}{}
   {L3 Experimental split-level fractions}
 \keys_define:nn { xfrac }
   {

Modified: trunk/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %%                  (C) Copyright 2004-2008 Frank Mittelbach,
 %%                      The LaTeX3 Project
 %%                  (C) Copyright 2009-2017 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{xparse}{Support package l3kernel too old}
@@ -36,7 +36,7 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{xparse}{2017/04/01}{}
+\ProvidesExplPackage{xparse}{2017/05/13}{}
   {L3 Experimental document command parser}
 \tl_const:Nx \c__xparse_no_value_tl
   { \char_generate:nn { `\- } { 11 } NoValue- }
@@ -285,36 +285,18 @@
   }
 \cs_new_protected:Npn \__xparse_defaults_def:nnn #1#2#3
   {
-    \tl_if_head_is_group:nTF {#3}
+    \tl_put_right:Nx \l__xparse_tmpa_tl
       {
-        \tl_put_right:Nn \l__xparse_tmpa_tl
-          {
+        {
+          \exp_not:N \exp_not:n
             {
-              \exp_args:Nf \__xparse_tl_mapthread_function:nnN
-                { \tl_item:Nn \l__xparse_args_tl {#1} }
-                {#3}
-                \__xparse_defaults_def_aux:nn
+              \__xparse_if_no_value:nTF {#2}
+                { \exp_not:o {#3} }
+                { \exp_not:n { ## #1 } }
             }
-          }
+        }
       }
-      {
-        \__xparse_if_no_value:nTF {#2}
-          {
-            \tl_put_right:Nx \l__xparse_tmpa_tl
-              { { \exp_not:N \exp_not:n { \exp_not:o {#3} } } }
-          }
-          {
-            \tl_put_right:Nn \l__xparse_tmpa_tl
-              { { \exp_not:n { ## #1 } } }
-          }
-      }
   }
-\cs_new:Npn \__xparse_defaults_def_aux:nn #1#2
-  {
-    \__xparse_if_no_value:nTF {#1}
-      { { \exp_not:n {#2} } }
-      { { \exp_not:n {#1} } }
-  }
 \cs_new_protected:Npn \__xparse_args_process:
   {
     \tl_clear:N \l__xparse_args_ii_tl
@@ -367,29 +349,10 @@
   }
 \cs_new:Npn \__xparse_end_expandable_defaults:nnw #1#2
   {
-    \tl_if_head_is_group:nTF {#1}
-      {
-        \__xparse_end_expandable_defaults_E:nnw { }
-          #1 \q_nil \q_mark
-          #2 \q_nil
-      }
-      {
-        \__xparse_if_no_value:nTF {#2}
-          { \exp_args:No \__xparse_end_expandable_defaults:nw {#1} }
-          { \__xparse_end_expandable_defaults:nw {#2} }
-      }
+    \__xparse_if_no_value:nTF {#2}
+      { \exp_args:No \__xparse_end_expandable_defaults:nw {#1} }
+      { \__xparse_end_expandable_defaults:nw {#2} }
   }
-\cs_new:Npn \__xparse_end_expandable_defaults_E:nnw #1#2#3 \q_mark #4
-  {
-    \quark_if_nil:nTF {#2}
-      { \__xparse_end_expandable_defaults:nw {#1} }
-      {
-        \__xparse_if_no_value:nTF {#4}
-          { \__xparse_end_expandable_defaults_E:nnw { #1 {#2} } }
-          { \__xparse_end_expandable_defaults_E:nnw { #1 {#4} } }
-        #3 \q_mark
-      }
-  }
 \cs_new:Npn \__xparse_end_expandable_defaults:nw
     #1#2 \__xparse_end_expandable_defaults:nnnNNn #3
   { #2 \__xparse_end_expandable_defaults:nnnNNn { #3 {#1} } }
@@ -506,6 +469,7 @@
     \__xparse_add_arg_spec:n { E {#1} {#2} }
     \tl_put_right:Nn \l__xparse_last_delimiters_tl {#1}
     \bool_set_false:N \l__xparse_grab_expandably_bool
+    \int_add:Nn \l__xparse_current_arg_int { \tl_count:n {#1} - 1 }
     \__xparse_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \__xparse_normalize_E_unique_check:w #1#2 \q_stop
@@ -672,7 +636,6 @@
 \cs_new_protected:Npn \__xparse_prepare_signature_bypass:N #1
   {
     \quark_if_recursion_tail_stop:N #1
-    \int_incr:N \l__xparse_current_arg_int
     \use:c
       {
          __xparse_add
@@ -685,7 +648,6 @@
     \__xparse_flush_m_args:
     \bool_set_true:N \l__xparse_long_bool
     \bool_set_true:N \l__xparse_prefixed_bool
-    \int_decr:N \l__xparse_current_arg_int
     \__xparse_prepare_signature_bypass:N
   }
 \cs_new_protected:cpn { __xparse_add_type_>:w } #1
@@ -693,7 +655,6 @@
     \__xparse_flush_m_args:
     \bool_set_true:N \l__xparse_prefixed_bool
     \bool_set_true:N \l__xparse_process_some_bool
-    \int_decr:N \l__xparse_current_arg_int
     \tl_put_left:Nn \l__xparse_process_one_tl { {#1} }
     \__xparse_prepare_signature_bypass:N
   }
@@ -814,30 +775,26 @@
     \__xparse_if_no_value:nTF {#1}
       { \__xparse_add_default: }
       {
+        \int_incr:N \l__xparse_current_arg_int
         \bool_set_true:N \l__xparse_defaults_bool
         \tl_put_right:Nn \l__xparse_defaults_tl { { \prg_do_nothing: #1 } }
       }
   }
 \cs_new_protected:Npn \__xparse_add_default:
-  { \tl_put_right:Nn \l__xparse_defaults_tl { \c__xparse_no_value_tl } }
+  {
+    \int_incr:N \l__xparse_current_arg_int
+    \tl_put_right:Nn \l__xparse_defaults_tl { \c__xparse_no_value_tl }
+  }
 \cs_new_protected:Npn \__xparse_add_default_E:nn #1#2
   {
-    \bool_set_true:N \l__xparse_defaults_bool
-    \tl_put_right:Nx \l__xparse_defaults_tl
-      {
-        {
-          \tl_map_function:nN {#2} \__xparse_add_default_E_aux:n
-          \prg_replicate:nn
-            { \tl_count:n {#1} - \tl_count:n {#2} }
-            { { \c__xparse_no_value_tl } }
-        }
-      }
+    \tl_map_function:nN {#2} \__xparse_add_default:n
+    \prg_replicate:nn
+      { \tl_count:n {#1} - \tl_count:n {#2} }
+      { \__xparse_add_default: }
   }
-\cs_new:Npn \__xparse_add_default_E_aux:n #1 { \exp_not:n { {#1} } }
 \cs_new_protected:cpn { __xparse_add_expandable_type_+:w }
   {
     \bool_set_true:N \l__xparse_long_bool
-    \int_decr:N \l__xparse_current_arg_int
     \__xparse_prepare_signature:N
   }
 \cs_new_protected:Npn \__xparse_add_expandable_type_D:w
@@ -1091,18 +1048,14 @@
     \tl_set:Nn \l__xparse_signature_tl {#2}
     \cs_set_protected:Npn \__xparse_grab_E_finalise:
       {
-        \tl_clear:N \l__xparse_tmpa_tl
         \tl_map_inline:nn {#1}
           {
             \prop_get:NnNF \l__xparse_tmp_prop {####1} \l__xparse_tmpb_tl
               { \tl_set_eq:NN \l__xparse_tmpb_tl \c__xparse_no_value_tl }
-            \tl_set:Nx \l__xparse_tmpa_tl
-              {
-                \exp_not:V \l__xparse_tmpa_tl
-                { \exp_not:V \l__xparse_tmpb_tl }
-              }
+            \tl_put_right:Nx \l__xparse_args_tl
+              { { \exp_not:V \l__xparse_tmpb_tl } }
           }
-        \__xparse_add_arg:V \l__xparse_tmpa_tl
+        \l__xparse_signature_tl \__xparse_run_code:
       }
     \__xparse_grab_E_loop:nnN {#4} { } #1 \q_recursion_tail \q_recursion_stop
   }
@@ -1540,7 +1493,7 @@
 \cs_new:Npn \__xparse_expandable_grab_E_find:nnw #1#2#3 \q_nil #4 \q__xparse #5#6#7#8
   { \__xparse_expandable_grab_E_aux:w {#1} { #2 {#8} #3 } #4 \q__xparse #5 #6 #7 }
 \cs_new:Npn \__xparse_expandable_grab_E_end:nnw #1#2#3 \q__xparse #4#5#6
-  { #3 {#2} \q__xparse #4 #5 {#1} }
+  { #3 #2 \q__xparse #4 #5 {#1} }
 \cs_new:Npn \__xparse_expandable_grab_m:w #1 \q__xparse #2#3
   { #3 { \__xparse_expandable_grab_m_aux:wNn #1 \q__xparse #2 #3 } }
 \cs_new:Npn \__xparse_expandable_grab_m_long:w #1 \q__xparse #2#3

Modified: trunk/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty	2017-05-14 22:39:49 UTC (rev 44350)
+++ trunk/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty	2017-05-14 22:40:58 UTC (rev 44351)
@@ -23,8 +23,8 @@
 %%                     (C) Copyright 2004-2010 Frank Mittelbach,
 %%                         The LaTeX3 Project
 %%                     (C) Copyright 2011-2016 The LaTeX3 Project
-\RequirePackage{expl3}[2017/04/01]
-\@ifpackagelater{expl3}{2017/04/01}
+\RequirePackage{expl3}[2017/05/13]
+\@ifpackagelater{expl3}{2017/05/13}
   {}
   {%
     \PackageError{xtemplate}{Support package l3kernel too old}
@@ -36,7 +36,7 @@
       }%
     \endinput
   }
-\ProvidesExplPackage{xtemplate}{2017/04/01}{}
+\ProvidesExplPackage{xtemplate}{2017/05/13}{}
   {L3 Experimental prototype document functions}
 \tl_const:Nn \c__xtemplate_code_root_tl      { template~code~>~ }
 \tl_const:Nn \c__xtemplate_defaults_root_tl  { template~defaults~>~ }



More information about the tex-live-commits mailing list